1#! @PERL@ --
2# perl
3'di ';
4'ig 00 ';
5#+##############################################################################
6#
7# texi2html: Program to transform Texinfo documents to HTML
8#
9#    Copyright (C) 1999-2010  Patrice Dumas <pertusus@free.fr>,
10#                             Derek Price <derek@ximbiot.com>,
11#                             Adrian Aichner <adrian@xemacs.org>,
12#                           & others.
13#
14#    This program is free software; you can redistribute it and/or modify
15#    it under the terms of the GNU General Public License as published by
16#    the Free Software Foundation; either version 2 of the License, or
17#    (at your option) any later version.
18#
19#    This program is distributed in the hope that it will be useful,
20#    but WITHOUT ANY WARRANTY; without even the implied warranty of
21#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22#    GNU General Public License for more details.
23#
24#    You should have received a copy of the GNU General Public License
25#    along with this program; if not, write to the Free Software
26#    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
27#    02110-1301  USA
28#
29# Some error messages come from texinfo (makeinfo), so copyright holder
30# is the FSF or the individual who wrote them. All come from before the
31# switch of texinfo to GPLv3+.
32#
33#-##############################################################################
34# The man page for this program is included at the end of this file and can be
35# viewed using the command 'nroff -man texi2html'.
36
37# for POSIX::setlocale and File::Spec
38require 5.00405;
39# Perl pragma to restrict unsafe constructs
40use strict;
41# used in case of tests, to revert to "C" locale.
42use POSIX qw(setlocale LC_ALL LC_CTYPE);
43# used to obtain the name of the current working directory
44use Cwd;
45# Used to find the parent directory of this script.
46use File::Basename;
47# used to find a relative path back to the current working directory
48use File::Spec;
49# to determine the path separator and null file
50use Config;
51
52#use encoding::warnings;
53# for translations
54#use encoding 'utf8';
55#use utf8;
56
57#
58# According to
59# larry.jones@sdrc.com (Larry Jones)
60# this pragma is not present in perl5.004_02:
61#
62# Perl pragma to control optional warnings
63# use warnings;
64
65# determine the path separators
66my $path_separator = $Config{'path_sep'};
67$path_separator = ':' if (!defined($path_separator));
68my $quoted_path_separator = quotemeta($path_separator);
69
70#++##########################################################################
71#
72# NOTE FOR DEBUGGING THIS SCRIPT:
73# You can run 'perl -x texi2html.pl' directly, provided you have the script
74# in the same directory with, or the environment variable T2H_HOME set to
75# the directory containing, the texi2html.init, T2h_i18n.pm, translations.pl,
76# l2h.init, & T2h_l2h.pm files.  Ditto makeinfo.pl, if you make it a
77# symlink to texi2html.pl.
78#
79#--##########################################################################
80my $T2H_HOME = defined $ENV{T2H_HOME} ? $ENV{T2H_HOME} : dirname $0;
81if ($0 =~ /\.pl$/)
82{
83    # Issue a warning in debugging mode if $T2H_HOME is set but isn't
84    # accessible.
85    if (!-e $T2H_HOME)
86    { warn "T2H_HOME ($T2H_HOME) does not exist."; }
87    elsif (!-d $T2H_HOME)
88    { warn "T2H_HOME ($T2H_HOME) is not a directory."; }
89    elsif (!-x $T2H_HOME)
90    { warn "T2H_HOME ($T2H_HOME) is not accessible."; }
91}
92
93# CVS version:
94# $Id: texi2html.pl,v 1.393 2010/06/30 22:01:27 pertusus Exp $
95
96# FIXME. Change for texinfo, and also simplify.
97
98# Homepage:
99my $T2H_HOMEPAGE = "http://www.nongnu.org/texi2html/";
100
101# Authors (appears in comments):
102my $T2H_AUTHORS = <<EOT;
103texi2html was written by:
104            Lionel Cons <Lionel.Cons\@cern.ch> (original author)
105            Karl Berry  <karl\@freefriends.org>
106            Olaf Bachmann <obachman\@mathematik.uni-kl.de>
107            and many others.
108Maintained by: Many creative people.
109Send bugs and suggestions to <texi2html-bug\@nongnu.org>
110EOT
111
112# Version: set in configure.in
113my $THISVERSION = '@PACKAGE_VERSION@';
114my $THISPROG = "texi2html $THISVERSION"; # program name and version
115
116#+++########################################################################
117#                                                                          #
118# Paths and file names                                                     #
119#                                                                          #
120#---########################################################################
121
122# set by configure, prefix for the sysconfdir and so on
123my $prefix = '@prefix@';
124my $datarootdir;# = '@datarootdir@';
125my $sysconfdir;
126my $pkgdatadir;
127my $datadir;
128
129# We need to eval as $prefix has to be expanded. However when we haven't
130# run configure @sysconfdir will be expanded as an array, thus we verify
131# whether configure was run or not
132if ('@sysconfdir@' ne '@' . 'sysconfdir@')
133{
134    $sysconfdir = eval '"@sysconfdir@"';
135}
136else
137{
138    $sysconfdir = "/usr/local/etc";
139}
140
141if ('@datarootdir@' ne '@' . 'datarootdir@')
142{
143    $datarootdir = eval '"@datarootdir@"';
144}
145else
146{
147    $datarootdir = "/usr/local/share";
148}
149
150if ('@datadir@' ne '@' . 'datadir@')
151{
152    $pkgdatadir = eval '"@datadir@/@PACKAGE@"';
153    $datadir = eval '"@datadir@"';
154}
155else
156{
157    $pkgdatadir = "/usr/local/share/texi2html";
158    $datadir = "/usr/local/share";
159}
160
161my $target_prefix = "t_h";
162
163
164
165#+++########################################################################
166#                                                                          #
167# Constants                                                                #
168#                                                                          #
169#---########################################################################
170
171my $DEBUG_MENU   =  1;
172my $DEBUG_INDEX =  2;
173my $DEBUG_TEXI  =  4;
174my $DEBUG_MACROS =  8;
175my $DEBUG_FORMATS   = 16;
176my $DEBUG_ELEMENTS  = 32;
177my $DEBUG_USER  = 64;
178my $DEBUG_L2H   = 128;
179
180my $VARRE = '[\w\-]+';          # RE for a variable name
181
182my $MAX_LEVEL = 4;
183my $MIN_LEVEL = 1;
184
185#+++########################################################################
186#                                                                          #
187# Command name and default format                                          #
188#                                                                          #
189#---########################################################################
190
191my $real_command_name = $0;
192$real_command_name =~ s/.*\///;
193$real_command_name =~ s/\.pl$//;
194
195my %command_format = (
196 'texi2html' => 'html',
197 'makeinfo' => 'info',
198 'texi2any' => 'raw-text',
199);
200
201# Config files
202
203my $i18n_dir = 'i18n'; # name of the directory containing the per language files
204my $conf_file_name = 'Config' ;
205my $texinfo_htmlxref = 'htmlxref.cnf';
206
207# directories for texinfo configuration files
208my @texinfo_config_dirs = ('./.texinfo');
209push @texinfo_config_dirs, "$ENV{'HOME'}/.texinfo" if (defined($ENV{'HOME'}));
210push @texinfo_config_dirs, "$sysconfdir/texinfo" if (defined($sysconfdir));
211push @texinfo_config_dirs, "$datadir/texinfo" if (defined($datadir));
212
213my @program_config_dirs;
214my @program_init_dirs;
215
216# program name dependent initializations: config directories and default
217# format.
218sub set_config_init_dirs_output($)
219{
220  my $program_name = shift;
221  if (!defined($command_format{$program_name}))
222  {
223    # user can make any link to set $0, or use --program with an unknown name.
224    # In that case the default is to use texi2any
225    $program_name = 'texi2any';
226  }
227  my $default_output_format = $command_format{$program_name};
228
229
230  # directories for config files
231  @program_config_dirs = ('./');
232  push @program_config_dirs, "$ENV{'HOME'}/.$program_name/" if (defined($ENV{'HOME'}));
233  push @program_config_dirs, "$sysconfdir/$program_name/" if (defined($sysconfdir));
234  push @program_config_dirs, "$datadir/$program_name" if (defined($datadir));
235
236  # directories for init files
237  @program_init_dirs = @program_config_dirs;
238  # common directories for all command names
239  foreach my $texinfo_config_dir (@texinfo_config_dirs)
240  {
241    push @program_init_dirs, "${texinfo_config_dir}/init/";
242  }
243  $Texi2HTML::Config::DEFAULT_OUTPUT_FORMAT = $default_output_format;
244  $Texi2HTML::Config::COMMAND_NAME = $program_name;
245  Texi2HTML::Config::t2h_default_load_format($default_output_format, 0);
246}
247
248#+++###########################################################################
249#                                                                             #
250# Initialization                                                              #
251# Some declarations, some functions that are GPL and therefore cannot be in   #
252# texi2html.init, some functions that are not to be customized.               #
253# Pasted content of File $(srcdir)/texi2html.init: Default initializations    #
254#                                                                             #
255#---###########################################################################
256{
257package Texi2HTML::Config;
258
259use Config;
260
261# customization options variables
262
263use vars qw(
264$DEBUG
265$PREFIX
266$VERBOSE
267$SUBDIR
268$IDX_SUMMARY
269$SPLIT
270$SPLIT_SIZE
271$SHORT_REF
272@EXPAND
273$TOP
274$DOCTYPE
275$FRAMESET_DOCTYPE
276$ERROR_LIMIT
277$CHECK
278$TEST
279$DUMP_TEXI
280$MACRO_EXPAND
281$CAPTION_STYLE
282$USE_ISO
283$TOP_FILE
284$TOC_FILE
285$FRAMES
286$SHOW_MENU
287$SHOW_TITLE
288$NUMBER_SECTIONS
289$NUMBER_FOOTNOTES
290$USE_NODES
291$USE_SECTIONS
292$USE_NODE_TARGET
293$USE_UNICODE
294$USE_UNIDECODE
295$TRANSLITERATE_FILE_NAMES
296$NODE_FILES
297$NODE_FILENAMES
298$NODE_NAME_IN_MENU
299$NODE_NAME_IN_INDEX
300$AVOID_MENU_REDUNDANCY
301$HEADERS
302$NO_WARN
303$FORCE
304$MONOLITHIC
305$SHORTEXTN
306$EXTENSION
307$OUT
308$NOVALIDATE
309$DEF_TABLE
310$DOCUMENTLANGUAGE
311$CONTENTS
312$SHORTCONTENTS
313$FOOTNOTESTYLE
314$FILLCOLUMN
315$SETCONTENTSAFTERTITLEPAGE
316$SETSHORTCONTENTSAFTERTITLEPAGE
317$KBDINPUTSTYLE
318$FRENCHSPACING
319$ALLOWCODEBREAKS
320$SETFILENAME
321$TOC_LINKS
322$L2H
323$L2H_L2H
324$L2H_SKIP
325$L2H_TMP
326$L2H_CLEAN
327$L2H_FILE
328$L2H_HTML_VERSION
329$EXTERNAL_DIR
330@INCLUDE_DIRS
331@PREPEND_DIRS
332@CONF_DIRS
333$IGNORE_PREAMBLE_TEXT
334@CSS_FILES
335@CSS_REFS
336$INLINE_CONTENTS
337$INLINE_INSERTCOPYING
338$PARAGRAPHINDENT
339$FIRSTPARAGRAPHINDENT
340$ENABLE_ENCODING
341$INTERNAL_LINKS
342$DEFAULT_OUTPUT_FORMAT
343$OUTPUT_FORMAT
344$COMMAND_NAME
345@COMMANDS
346);
347
348# customization variables
349use vars qw(
350$ENCODING_NAME
351$DOCUMENT_ENCODING
352$OUT_ENCODING
353$IN_ENCODING
354$DEFAULT_ENCODING
355$MENU_PRE_STYLE
356$MENU_PRE_COMPLEX_FORMAT
357$EXAMPLE_INDENT_CELL
358$SMALL_EXAMPLE_INDENT_CELL
359$SMALL_FONT_SIZE
360$SMALL_RULE
361$DEFAULT_RULE
362$MIDDLE_RULE
363$BIG_RULE
364$TOP_HEADING
365$INDEX_CHAPTER
366$SPLIT_INDEX
367$USE_MENU_DIRECTIONS
368$USE_UP_FOR_ADJACENT_NODES
369$AFTER_BODY_OPEN
370$PRE_BODY_CLOSE
371$EXTRA_HEAD
372$VERTICAL_HEAD_NAVIGATION
373$WORDS_IN_PAGE
374$ICONS
375$UNNUMBERED_SYMBOL_IN_MENU
376$SIMPLE_MENU
377$MENU_SYMBOL
378$MENU_ENTRY_COLON
379$INDEX_ENTRY_COLON
380$USE_ACCESSKEY
381$USE_REL_REV
382$USE_LINKS
383$OPEN_QUOTE_SYMBOL
384$CLOSE_QUOTE_SYMBOL
385$NO_NUMBER_FOOTNOTE_SYMBOL
386$NO_BULLET_LIST_STYLE
387$NO_BULLET_LIST_ATTRIBUTE
388$NO_BULLET_LIST_CLASS
389$TOP_NODE_FILE
390$TOP_NODE_FILE_TARGET
391$TOP_NODE_UP
392$NODE_FILE_EXTENSION
393$STDIN_DOCU_NAME
394$STDOUT_DOCU_NAME
395$BEFORE_OVERVIEW
396$AFTER_OVERVIEW
397$BEFORE_TOC_LINES
398$AFTER_TOC_LINES
399$NEW_CROSSREF_STYLE
400$TOP_HEADING_AT_BEGINNING
401$USE_NUMERIC_ENTITY
402$USE_SETFILENAME
403$USE_SETFILENAME_EXTENSION
404$SEPARATE_DESCRIPTION
405$IGNORE_BEFORE_SETFILENAME
406$OVERVIEW_LINK_TO_TOC
407$COMPLETE_IMAGE_PATHS
408$DATE
409%ACTIVE_ICONS
410%NAVIGATION_TEXT
411%PASSIVE_ICONS
412%BUTTONS_NAME
413%BUTTONS_GOTO
414%BUTTONS_EXAMPLE
415%BUTTONS_ACCESSKEY
416%BUTTONS_REL
417%BUTTONS_TEXT
418@T2H_FORMAT_EXPAND
419@CHAPTER_BUTTONS
420@MISC_BUTTONS
421@SECTION_BUTTONS
422@SECTION_FOOTER_BUTTONS
423@NODE_FOOTER_BUTTONS
424@TOP_BUTTONS
425@LINKS_BUTTONS
426@IMAGE_EXTENSIONS
427@INPUT_FILE_SUFFIXES
428$ENABLE_ENCODING_USE_ENTITY
429$PROGRAM_NAME_IN_FOOTER
430$HEADER_IN_TABLE
431$DATE_IN_HEADER
432$COMPLEX_FORMAT_IN_TABLE
433$USE_TITLEPAGE_FOR_TITLE
434$INLINE_CSS_STYLE
435$NO_CSS
436$I18N_PERL_HASH
437$USE_NLS
438);
439
440# customization variables which may be guessed in the script
441#our $ADDRESS;
442use vars qw(
443$BODYTEXT
444$CSS_LINES
445$DOCUMENT_DESCRIPTION
446$EXTERNAL_CROSSREF_SPLIT
447);
448
449# I18n
450use vars qw(
451$I
452$LANGUAGES
453);
454
455# customizable subroutines references
456use vars qw(
457$print_section
458$one_section
459$end_section
460$print_Top_header
461$print_Top_footer
462$print_Top
463$print_Toc
464$print_Overview
465$print_Footnotes
466$print_About
467$print_misc_header
468$print_misc_footer
469$print_misc
470$print_section_header
471$print_section_footer
472$print_chapter_header
473$print_chapter_footer
474$print_element_header
475$print_page_head
476$print_page_foot
477$print_head_navigation
478$print_foot_navigation
479$print_title
480$button_icon_img
481$button_formatting
482$print_navigation
483$about_body
484$print_frame
485$print_toc_frame
486$toc_body
487$contents
488$internal_links
489$shortcontents
490$titlepage
491$insertcopying
492$css_lines
493$print_redirection_page
494$translate_names
495$init_out
496$finish_out
497$node_file_name
498$element_file_name
499$node_target_name
500$element_target_name
501$placed_target_file_name
502$inline_contents
503$program_string
504
505$preserve_misc_command
506$misc_command_line
507$misc_command_line_texi
508$protect_text
509$anchor
510$anchor_label
511$element_label
512$misc_element_label
513$def_item
514$def
515$menu
516$menu_command
517$menu_link
518$menu_description
519$menu_comment
520$simple_menu_link
521$ref_beginning
522$info_ref
523$book_ref
524$external_href
525$external_ref
526$internal_ref
527$table_item
528$table_line
529$row
530$cell
531$list_item
532$comment
533$def_line
534$def_line_no_texi
535$heading_no_texi
536$raw
537$raw_no_texi
538$heading
539$element_heading
540$heading_text
541$heading_text_preformatted
542$paragraph
543$preformatted
544$empty_preformatted
545$foot_line_and_ref
546$foot_section
547$image
548$image_files
549$index_entry_label
550$index_entry
551$index_entry_command
552$index_letter
553$print_index
554$printindex
555$index_summary
556$summary_letter
557$complex_format
558$cartouche
559$sp
560$definition_category
561$definition_index_entry
562$table_list
563$copying_comment
564$documentdescription
565$index_summary_file_entry
566$index_summary_file_end
567$index_summary_file_begin
568$style
569$line_command
570$format
571$normal_text
572$empty_line
573$unknown
574$unknown_style
575$float
576$caption_shortcaption
577$caption_shortcaption_command
578$listoffloats
579$listoffloats_entry
580$listoffloats_caption
581$listoffloats_float_style
582$listoffloats_style
583$acronym_like
584$quotation
585$quotation_prepend_text
586$paragraph_style_command
587$heading_texi
588$index_element_heading_texi
589$format_list_item_texi
590$begin_format_texi
591$begin_style_texi
592$begin_paragraph_texi
593$tab_item_texi
594$footnote_texi
595$colon_command
596$simple_command
597$thing_command
598$begin_special_region
599$end_special_region
600
601$PRE_ABOUT
602$AFTER_ABOUT
603);
604
605# hash which entries might be redefined by the user
606use vars qw(
607$complex_format_map
608%complex_format_map
609%accent_map
610%def_map
611%format_map
612%simple_map
613%simple_map_pre
614%simple_map_texi
615%simple_map_math
616%style_map
617%style_map_pre
618%style_map_math
619%style_map_texi
620%simple_format_simple_map_texi
621%simple_format_style_map_texi
622%simple_format_texi_map
623%line_command_map
624%command_type
625%paragraph_style
626%stop_paragraph_command
627%format_code_style
628%region_formats_kept
629%texi_formats_map
630%things_map
631%pre_map
632%math_map
633%texi_map
634%sorting_things_map
635%unicode_map
636%unicode_diacritical
637%transliterate_map
638%transliterate_accent_map
639%no_transliterate_map
640%ascii_character_map
641%default_simple_map
642%default_things_map
643%default_texi_map
644%default_style_map
645%default_style_map_pre
646%default_style_map_texi
647%default_simple_format_style_map_texi
648%numeric_entity_map
649%perl_charset_to_html
650%misc_pages_targets
651%misc_command
652%no_paragraph_commands
653%css_map
654%format_in_paragraph
655%special_list_commands
656%accent_letters
657%unicode_accents
658%special_accents
659%inter_item_commands
660$def_always_delimiters
661$def_in_type_delimiters
662$def_argument_separator_delimiters
663%colon_command_punctuation_characters
664$punctuation_characters
665$after_punctuation_characters
666@command_handler_setup
667@command_handler_init
668@command_handler_names
669@command_handler_process
670@command_handler_output
671@command_handler_finish
672%command_handler
673%special_style
674%null_device_file
675%language_codes
676%region_codes
677%deprecated_commands
678%output_format_names
679%canonical_texinfo_encodings
680@text_substitutions_normal
681@text_substitutions_texi
682@text_substitutions_simple_format
683@text_substitutions_pre
684%htmlxref_entries
685);
686
687# deprecated
688use vars qw(
689$address
690%iso_symbols
691%simple_map_pre_math
692%simple_map_texi_math
693$ENCODING
694$CENTER_IMAGE
695$HREF_DIR_INSTEAD_FILE
696$EXPAND
697$USE_GLOSSARY
698$INVISIBLE_MARK
699);
700
701# subject to change
702use vars qw(
703%makeinfo_encoding_to_map
704%makeinfo_unicode_to_eight_bit
705%eight_bit_to_unicode
706%t2h_encoding_aliases
707);
708
709# FIXME i18n ?
710%output_format_names = (
711  'info' => 'Info',
712  'html' => 'HTML',
713  'docbook' => 'Docbook XML',
714  'xml' => 'Texinfo XML',
715  'plaintext' => 'plain text',
716  'raw-text' => 'raw text',
717);
718
719sub load($)
720{
721    my $file = shift;
722    # If required like other init files, the functions would be redefined
723    # and the format dependent stuff wouldn't be loaded. Having the
724    # formats loaded could be worked around, for example there could be
725    # a variable that, and if the variable is defined a function reference
726    # should be called right after the require. There is no real
727    # workaround for having the function redefined, though.
728    foreach my $output_format (keys(%output_format_names))
729    {
730      if ($file =~ /\/$output_format\.init$/)
731      {
732         t2h_default_load_format($output_format, 1);
733         return 1;
734      }
735    }
736    eval { require($file) ;};
737    if ($@ ne '')
738    {
739        print STDERR "error loading $file: $@\n";
740        return 0;
741    }
742    return 1;
743}
744
745
746sub set_conf($$;$)
747{
748    my $name = shift;
749    my $value = shift;
750    my $not_global = shift;
751
752    unless ($not_global)
753    {
754       if (defined($value))
755       {
756          $Texi2HTML::GLOBAL{$name} = $value;
757       }
758       else
759       {
760          delete $Texi2HTML::GLOBAL{$name};
761       }
762       return 1;
763    }
764    return 0 if (defined($Texi2HTML::GLOBAL{$name}));
765    if (defined($value))
766    {
767       $Texi2HTML::THISDOC{$name} = $value;
768    }
769    else
770    {
771       delete $Texi2HTML::THISDOC{$name};
772    }
773    return 1;
774}
775
776my %config_map = (
777   'paragraphindent' => \$PARAGRAPHINDENT,
778   'firstparagraphindent' => \$FIRSTPARAGRAPHINDENT,
779   'footnotestyle' => \$FOOTNOTESTYLE,
780   'fillcolumn' => \$FILLCOLUMN,
781   'documentlanguage' => \$DOCUMENTLANGUAGE,
782   'novalidate' => \$NOVALIDATE,
783   'SPLIT' => \$SPLIT,
784   'SPLIT_SIZE' => \$SPLIT_SIZE,
785   'contents' => \$CONTENTS,
786   'shortcontents' => \$SHORTCONTENTS,
787   'doctype' => \$DOCTYPE,
788   'headers' => \$HEADERS,
789   'DOCUMENT_ENCODING' => \$DOCUMENT_ENCODING,
790   'IN_ENCODING' => \$IN_ENCODING,
791   'setcontentsaftertitlepage' => \$SETCONTENTSAFTERTITLEPAGE,
792   'setshortcontentsaftertitlepage'  => \$SETSHORTCONTENTSAFTERTITLEPAGE,
793   'kbdinputstyle' => \$KBDINPUTSTYLE,
794   'frenchspacing' => \$FRENCHSPACING,
795   'allowcodebreaks' => \$ALLOWCODEBREAKS,
796   'setfilename' => \$SETFILENAME,
797   'use_nls' => \$USE_NLS,
798);
799
800sub get_conf($)
801{
802    my $name = shift;
803    return $Texi2HTML::THISDOC{$name} if (defined($Texi2HTML::THISDOC{$name}));
804    return $Texi2HTML::GLOBAL{$name} if (defined($Texi2HTML::GLOBAL{$name}));
805    return ${$config_map{$name}} if (defined($config_map{$name}));
806    # there is no default value for many @-commmands, like headings....
807    #print STDERR "Unknown conf string: $name\n";
808}
809
810# manage expanded sections
811sub set_expansion($$)
812{
813    my $region = shift;
814    my $set = shift;
815    $set = 1 if (!defined($set));
816    if ($set)
817    {
818         push (@EXPAND, $region) unless (grep {$_ eq $region} @EXPAND);
819    }
820    else
821    {
822         @EXPAND = grep {$_ ne $region} @EXPAND;
823         @T2H_FORMAT_EXPAND = grep {$_ ne $region} @T2H_FORMAT_EXPAND;
824    }
825}
826
827# needed in this namespace for translations
828$I = \&Texi2HTML::I18n::get_string;
829sub gdt($;$$)
830{
831    return &main::gdt(@_);
832}
833
834sub __($)
835{
836    return &main::__(@_);
837}
838
839sub __p($$)
840{
841    return &main::__p(@_);
842}
843
844sub N__($)
845{
846    return $_[0];
847}
848
849#
850# Function refs covered by the GPL as part of the texi2html.pl original
851# code. As such they cannot appear in texi2html.init which is public
852# domain (at least the things coded by me, and, if I'm not wrong also the
853# things coded by Olaf -- Pat).
854#
855
856sub HTML_DEFAULT_shortcontents($$)
857{
858    my $elements_list = shift;
859    my $stoc_file = shift;
860    return unless (Texi2HTML::Config::get_conf('shortcontents') or $FRAMES);
861    my $ul_class = '';
862    $ul_class = $NO_BULLET_LIST_CLASS if ($NUMBER_SECTIONS);
863    my @result = ();
864    foreach my $element (@$elements_list)
865    {
866        next if ($element->{'tag'} eq 'top' or $element->{'toc_level'} != 1);
867        my $dest_for_stoc = $element->{'file'};
868        my $dest_target_for_stoc = $element->{'target'};
869        if ($Texi2HTML::Config::OVERVIEW_LINK_TO_TOC)
870        {
871            $dest_for_stoc = $Texi2HTML::THISDOC{'toc_file'};
872            $dest_target_for_stoc = $element->{'tocid'};
873        }
874        $dest_for_stoc = '' if ($dest_for_stoc eq $stoc_file);
875        my $text = $element->{'text'};
876        my $stoc_entry = "<li>" . &$anchor ($element->{'stocid'}, "$dest_for_stoc#$dest_target_for_stoc",$text);
877        push(@result, $stoc_entry. "</li>\n");
878    }
879    if (@result)
880    {
881        unshift @result, html_default_attribute_class('ul', $ul_class) .">\n";
882        push @result, "</ul>\n";
883        unshift @result, $BEFORE_OVERVIEW;
884        push @result, $AFTER_OVERVIEW;
885    }
886    return \@result;
887}
888
889
890sub HTML_DEFAULT_contents($$)
891{
892    my $elements_list = shift;
893    my $toc_file = shift;
894
895    return unless (Texi2HTML::Config::get_conf('contents'));
896
897    my $current_level = 0;
898    my $ul_class = '';
899    $ul_class = $NO_BULLET_LIST_CLASS if ($NUMBER_SECTIONS);
900    my @result = ();
901    foreach my $element (@$elements_list)
902    {
903        next if ($element->{'tag'} eq 'top');
904        my $ind = '  ' x $current_level;
905        my $level = $element->{'toc_level'};
906        print STDERR "Bug no toc_level for ($element) $element->{'texi'}\n" if (!defined ($level));
907        if ($level > $current_level)
908        {
909            while ($level > $current_level)
910            {
911                $current_level++;
912                my $ln = "\n$ind".html_default_attribute_class('ul', $ul_class).">\n";
913                $ind = '  ' x $current_level;
914                push(@result, $ln);
915            }
916        }
917        elsif ($level < $current_level)
918        {
919            while ($level < $current_level)
920            {
921                $current_level--;
922                $ind = '  ' x $current_level;
923                my $line = "</li>\n$ind</ul>";
924                $line .=  "</li>" if ($level == $current_level);
925                push(@result, "$line\n");
926            }
927        }
928        else
929        {
930            push(@result, "</li>\n");
931        }
932        my $dest_for_toc = $element->{'file'};
933        my $dest_for_stoc = $element->{'file'};
934        my $dest_target_for_stoc = $element->{'target'};
935        $dest_for_toc = '' if ($dest_for_toc eq $toc_file);
936        my $text = $element->{'text'};
937        my $toc_entry = "<li>" . &$anchor ($element->{'tocid'}, "$dest_for_toc#$element->{'target'}",$text);
938        push (@result, $ind . $toc_entry);
939    }
940    while (0 < $current_level)
941    {
942        $current_level--;
943        my $ind = '  ' x $current_level;
944        push(@result, "</li>\n$ind</ul>\n");
945    }
946    if (@result)
947    {
948        unshift @result, $BEFORE_TOC_LINES;
949        push @result, $AFTER_TOC_LINES;
950    }
951    return \@result;
952}
953
954#$toc_body                 = \&T2H_GPL_toc_body;
955#$style                    = \&T2H_GPL_style;
956#$format                   = \&T2H_GPL_format;
957#$printindex               = \&t2h_GPL_default_printindex;
958#$summary_letter           = \&t2h_default_summary_letter;
959
960
961sub T2H_GPL_style($$$$$$$$$$)
962{                           # known style
963    my $style = shift;
964    my $command = shift;
965    my $text = shift;
966    my $args = shift;
967    my $no_close = shift;
968    my $no_open = shift;
969    my $line_nr = shift;
970    my $state = shift;
971    my $style_stack = shift;
972    my $kept_line_nrs = shift;
973
974    my $do_quotes = 0;
975    my $use_attribute = 0;
976    my $use_begin_end = 0;
977    my $inline_attribute = 0;
978    if (ref($style) eq 'HASH')
979    {
980        #print STDERR "GPL_STYLE $command ($style)\n";
981        #print STDERR " @$args\n";
982        if (ref($style->{'args'}) ne 'ARRAY')
983        {
984            print STDERR "BUG: args not an array for command `$command'\n";
985        }
986        $do_quotes = $style->{'quote'};
987        if (defined($style->{'function'}))
988        {
989            $text = &{$style->{'function'}}($command, $args, $style_stack, $state, $line_nr, $kept_line_nrs);
990        }
991        elsif (@{$style->{'args'}} == 1)
992        {
993            if (defined($style->{'inline_attribute'}))
994            {
995                $style = $style->{'inline_attribute'};
996                $use_attribute = 1;
997                $inline_attribute = 1;
998            }
999            elsif (defined($style->{'attribute'}))
1000            {
1001                $style = $style->{'attribute'};
1002                $use_attribute = 1;
1003            }
1004            #$text = $args->[0];
1005        }
1006    }
1007    else
1008    {
1009        if ($style =~ s/^\"//)
1010        {                       # add quotes
1011            $do_quotes = 1;
1012        }
1013        if ($style =~ s/^\&//)
1014        {                       # custom
1015            $style = 'Texi2HTML::Config::' . $style;
1016            eval "\$text = &$style(\$text, \$command, \$style_stack)";
1017        }
1018        elsif ($style ne '')
1019        {
1020            $use_attribute = 1;
1021        }
1022        else
1023        {                       # no style
1024        }
1025    }
1026    if ($use_attribute)
1027    {
1028        my ($attribute_text, $class);
1029        ($style, $class, $attribute_text) = html_default_parse_attribute ($style);
1030        $text = html_default_attribute_class($style, $class) . "$attribute_text>" . "$text" if (!$no_open or $inline_attribute);
1031        $text .= "</$style>" if (!$no_close or $inline_attribute);
1032        if ($do_quotes)
1033        {
1034             $text = $OPEN_QUOTE_SYMBOL . "$text" if (!$no_open);
1035             $text .= $CLOSE_QUOTE_SYMBOL if (!$no_close);
1036        }
1037    }
1038    if (ref($style) eq 'HASH')
1039    {
1040        if (defined($style->{'begin'}) and !$no_open)
1041        {
1042             $text = $style->{'begin'} . $text;
1043        }
1044        if (defined($style->{'end'}) and !$no_close)
1045        {
1046            $text = $text . $style->{'end'};
1047        }
1048        if (defined($style->{'inline_begin'}))
1049        {
1050             $text = $style->{'inline_begin'} . $text;
1051        }
1052        if (defined($style->{'inline_end'}))
1053        {
1054            $text = $text . $style->{'inline_end'};
1055        }
1056    }
1057    if ($do_quotes and !$use_attribute)
1058    {
1059        $text = $OPEN_QUOTE_SYMBOL . "$text" if (!$no_open);
1060        $text .= $CLOSE_QUOTE_SYMBOL if (!$no_close);
1061    }
1062    return $text;
1063}
1064
1065sub T2H_GPL_format($$$)
1066{
1067    my $tag = shift;
1068    my $element = shift;
1069    my $text = shift;
1070    return '' if (!defined($element) or ($text !~ /\S/));
1071    return $text if ($element eq '');
1072    my $attribute_text = '';
1073    if ($element =~ /^(\w+)(\s+.*)/)
1074    {
1075        $element = $1;
1076        $attribute_text = $2;
1077    }
1078    return "<${element}$attribute_text>\n" . $text. "</$element>\n";
1079}
1080
1081# for each index holds the letters split as determined by SPLIT_INDEX.
1082my %t2h_default_index_letters_array;
1083# equivalent of doc_nr, but with files (and hence numbers) added when
1084# a split index leads to an additional element and a file is created.
1085my $t2h_default_file_number;
1086# this is an increasing number to construct the id for each newly
1087# created index element.
1088my $t2h_default_index_id_nr;
1089# this holds the file name associated with an element file, such
1090# as to follow the splitting coming from the main program, and also use
1091# the newly generated files.
1092my %t2h_default_seen_files;
1093# holds the elements and indices that are split to easily set the
1094# directions after they are done in the main program.
1095my $t2h_default_element_split_printindices;
1096
1097# construct a hash of index names holding the letter grouped how they will
1098# be split.
1099sub t2h_default_init_split_indices()
1100{
1101    push @command_handler_process, \&t2h_default_index_rearrange_directions;
1102    %t2h_default_index_letters_array = ();
1103    %t2h_default_seen_files = ();
1104    $t2h_default_element_split_printindices = undef;
1105    $t2h_default_index_id_nr = 0;
1106    $t2h_default_file_number = 0;
1107
1108    foreach my $index_name(keys %{$Texi2HTML::THISDOC{'index_letters_array'}})
1109    {
1110        my $entries_count = 0;
1111        my @letters = ();
1112        foreach my $letter_entry (@{$Texi2HTML::THISDOC{'index_letters_array'}->{$index_name}})
1113        {
1114          push @letters, $letter_entry;
1115          $entries_count += scalar(@{$letter_entry->{'entries'}});
1116          # Don't split if document is not split
1117          if (get_conf('SPLIT') and $SPLIT_INDEX and $entries_count >= $SPLIT_INDEX)
1118          {
1119            push @{$t2h_default_index_letters_array{$index_name}}, [ @letters ];
1120            @letters = ();
1121            $entries_count = 0;
1122          }
1123        }
1124        push @{$t2h_default_index_letters_array{$index_name}}, [ @letters ] if (scalar(@letters));
1125    }
1126}
1127
1128sub t2h_default_associate_index_element($$$$)
1129{
1130  my $element = shift;
1131  my $is_top = shift;
1132  my $docu_name = shift;
1133  my $use_node_file = shift;
1134
1135  my $default_element_file = $element->{'file'};
1136
1137  # redo the file naming -- the doc_nr part -- in case new elements were
1138  # inserted upon index split. But respect the default splitting to keep
1139  # the elements that are associated with the same file in the same file,
1140  # or the added file.
1141  if (!$use_node_file or $t2h_default_seen_files{$default_element_file})
1142  {
1143    my $file;
1144    if ($t2h_default_seen_files{$default_element_file})
1145    {
1146      $file = $t2h_default_seen_files{$default_element_file};
1147    }
1148    else
1149    {
1150      if ($is_top eq 'top')
1151      { # this is the element_top, so we keep docu_top as associated file.
1152        # this, in fact, is not necessary since the element_top is never
1153        # associated with another element, but who knows.
1154         $t2h_default_seen_files{$default_element_file} = $default_element_file;
1155      }
1156      else
1157      {
1158        $file = "${docu_name}_$t2h_default_file_number";
1159        $file .= '.' . $Texi2HTML::THISDOC{'extension'} if
1160           (defined($Texi2HTML::THISDOC{'extension'}));
1161        $t2h_default_seen_files{$default_element_file} = $file;
1162      }
1163      $t2h_default_file_number++;
1164    }
1165    $element->{'file'} = $file if (defined($file));
1166  }
1167
1168  my $level = $element->{'level'};
1169
1170  # Even if, without USE_SECTION, output can be split at chapter or
1171  # section we don't split indices accordingly. We don't want to add
1172  # more cases where users want split indices, this was a very difficult
1173  # to maintain feature from the beginning.
1174  #$level = $element->{'with_section'}->{'level'} if (!defined($level) and
1175  #    defined($element->{'with_section'}));
1176
1177  # if the element is not the level of splitting, then we don't split.
1178  # also if 'top' is set we don't split since the formatting is different
1179  # in that case and the result would be quite unpredictable.
1180  return if ($element->{'top'} or ((get_conf('SPLIT') ne 'node')
1181      and (!defined($level) or $level > $Texi2HTML::THISDOC{'split_level'})));
1182
1183  #print STDERR "Doing printindices for $element $element->{'texi'}, file $element->{'file'} (@{$element->{'place'}})\n";
1184
1185
1186  # iterate over the @places of the element, which includes associated nodes,
1187  # associated elements, anchors, footnotes, floats, index entries,
1188  # printindices (including the element command itself, be it a @node or
1189  # a sectioning @-command).
1190  # during the iteration, split printindices that needs it, and reassociate
1191  # other placed elements with files and elements.
1192
1193  my $current_element = $element;
1194  my @places = @{$element->{'place'}};
1195  @{$element->{'place'}} = ();
1196
1197  foreach my $place (@places)
1198  {
1199    my ($printindex, $printindex_to_split, $index_name);
1200
1201    # determines if the placed thing is a printindex to be split
1202    if ($place->{'command'} and $place->{'command'} eq 'printindex')
1203    {
1204        $printindex = $place;
1205        $index_name = $printindex->{'name'};
1206        # ! empty index
1207        if (exists($t2h_default_index_letters_array{$index_name}) and
1208        # split index
1209         scalar(@{$t2h_default_index_letters_array{$index_name}} > 1)
1210         # the condition defined($printindex->{'associated_element'} implies
1211         # that we don't split printindex before first element, otherwise
1212         # there will be a need to begin document without a first element
1213         # which would be annoying.
1214         and defined($printindex->{'associated_element'}))
1215        {
1216            $printindex_to_split = 1;
1217        }
1218    }
1219
1220    # this is a non split printindex or any other placed thing.
1221    if (!$printindex_to_split)
1222    {
1223       push @{$current_element->{'place'}}, $place;
1224       # don't remodify the original element file, it was set right at the
1225       # beginning of the function.
1226       $place->{'file'} = $current_element->{'file'} if ($place ne $element);
1227       # the 'element_ref' has to be reset. Otherwise, $place->{'element_ref'}
1228       # will appear as a new element and trigger closing the file and
1229       # opening a new one.
1230       $place->{'element_ref'} = $current_element if ($place->{'element_ref'} and $current_element ne $element);
1231       # this resets the element associated with a printindex.
1232       if ($place->{'associated_element'} and $current_element ne $element)
1233       {
1234           $place->{'associated_element'} = $current_element;
1235       }
1236       next;
1237    }
1238
1239    # now split the index
1240
1241    my @letter_groups = ();
1242    my @letters_split = @{$t2h_default_index_letters_array{$index_name}};
1243    foreach my $letters_split (@letters_split)
1244    {
1245        push @letter_groups, {'letters' => [@$letters_split]};
1246    }
1247
1248    $letter_groups[0]->{'element'} = $current_element;
1249
1250    # besides preparing the new elements corresponding with split indices,
1251    # they are recorded for later directions rearrangements in
1252    # t2h_default_index_rearrange_directions.
1253
1254    # this weird construct is there because the element used as a key is
1255    # converted to a string by perl, losing its meaning as a reference,
1256    # the reference must be recorded explicitly
1257    $t2h_default_element_split_printindices->{$element}->{'element'} = $element;
1258    push @{$t2h_default_element_split_printindices->{$element}->{'printindices'}}, $printindex;
1259    #print STDERR "Setting $element, $element->{'texi'}, $printindex $printindex->{'name'} as a split element\n";
1260    foreach my $split_group (@letter_groups)
1261    {
1262        my $first_letter = $split_group->{'letters'}->[0]->{'letter'};
1263        my $last_letter = $split_group->{'letters'}->[-1]->{'letter'};
1264        if (!$split_group->{'element'})
1265        { # this is not the first letters group, which is already associated
1266          # with an element, a new element is done.
1267
1268          # construct new element name
1269          my $letters_heading;
1270          if ($last_letter ne $first_letter)
1271          {
1272            $letters_heading = &$normal_text("$first_letter -- $last_letter");
1273          }
1274          else
1275          {
1276            $letters_heading = &$normal_text("$first_letter");
1277          }
1278          my ($name, $simple);
1279          my $texi = "ADDED ELEMENT $element->{'texi'}: $letters_heading";
1280          if (!defined($element->{'text'}))
1281          {
1282            my $element_heading_texi = &$heading_texi($element->{'tag'}, $element->{'texi'}, $element->{'number'});
1283
1284            my $index_heading_texi = &$index_element_heading_texi(
1285                 $element_heading_texi,
1286                 $element->{'tag'},
1287                 $element->{'texi'},
1288                 $element->{'number'},
1289                 $first_letter, $last_letter);
1290            $name = main::substitute_line($index_heading_texi, sprintf(__p("\@sectionning_command index page","\@%s index page"), $element->{'tag'}));
1291            $simple = main::simple_format(undef,undef,"simple_format \@$element->{'tag'} index page", $index_heading_texi);
1292          }
1293          else
1294          { # should never happen, at this point 'text' is always undefined.
1295            $name = "$element->{'text'}: $letters_heading";
1296            $simple = "$element->{'simple_format'}: $letters_heading";
1297          }
1298
1299          #file and id
1300          my $relative_file = $Texi2HTML::THISDOC{'file_base_name'} . '_' . $t2h_default_file_number;
1301          $t2h_default_file_number++;
1302          $relative_file .= '.' . $Texi2HTML::THISDOC{'extension'} if
1303             (defined($Texi2HTML::THISDOC{'extension'}));
1304          my $id = "index_split-$t2h_default_index_id_nr";
1305          $t2h_default_index_id_nr++;
1306
1307          my $new_element = { 'file' => $relative_file, 'id' => $id, 'target' => $id, 'text' => $name, 'texi' => $texi, 'seen' => 1, 'simple_format' => $simple };
1308          # to avoid crashing when there is a filename collision.
1309          main::add_file($new_element->{'file'});
1310
1311          $split_group->{'element'} = $new_element;
1312          $current_element = $new_element;
1313          #print STDERR "Added file $new_element->{'file'} ($new_element, $new_element->{'id'}) for $new_element->{'texi'} ($first_letter:$last_letter)\n";
1314        }
1315        else
1316        { # this is the first index split, it is still associated with the element
1317          #print STDERR "No file added for ($first_letter:$last_letter)\n";
1318        }
1319    }
1320    $t2h_default_seen_files{$default_element_file} = $current_element->{'file'};
1321    $printindex->{'split_groups'} = \@letter_groups;
1322    #print STDERR "$index_name processed for $element, $element->{'texi'} (@{$printindex->{'split_groups'}})\n";
1323  }
1324}
1325
1326# set directions for added elements now that they are done in the
1327# main program for all the other elements.
1328sub t2h_default_index_rearrange_directions()
1329{
1330  return if (!defined($t2h_default_element_split_printindices));
1331  foreach my $element_string (keys(%$t2h_default_element_split_printindices))
1332  {
1333    my $element = $t2h_default_element_split_printindices->{$element_string}->{'element'};
1334    my $current_element = $element;
1335    #print STDERR " E Processing $element_string,$current_element $current_element->{'texi'}\n";
1336    foreach my $printindex (@{$t2h_default_element_split_printindices->{$element_string}->{'printindices'}})
1337    {
1338      #print STDERR "  I Processing $printindex $printindex->{'name'} (@{$printindex->{'split_groups'}})\n";
1339      foreach my $split_group (@{$printindex->{'split_groups'}})
1340      {
1341        my $first_letter = $split_group->{'letters'}->[0]->{'letter'};
1342        my $last_letter = $split_group->{'letters'}->[-1]->{'letter'};
1343
1344        my $new_element = $split_group->{'element'};
1345        next if ($current_element eq $new_element);
1346        #print STDERR "   G Processing ($first_letter:$last_letter) in $element->{'texi'}, index $printindex->{'name'}: $new_element->{'texi'}\n";
1347        $new_element->{'This'} = $new_element;
1348        if ($current_element->{'Forward'})
1349        {
1350          $current_element->{'Forward'}->{'Back'} = $new_element;
1351          $new_element->{'Forward'} = $current_element->{'Forward'};
1352        }
1353        $current_element->{'Forward'} = $new_element;
1354        $new_element->{'Back'} = $current_element;
1355        if ($current_element->{'Following'})
1356        {
1357#print STDERR "F: C($current_element): $current_element->{'texi'}, N($new_element): $new_element->{'texi'} -- C->F: $current_element->{'Following'}->{'texi'}\n";
1358          $new_element->{'Following'} = $current_element->{'Following'};
1359          $current_element->{'Following'} = $new_element;
1360        }
1361        foreach my $key ('FastForward', 'FastBack', 'Up', 'tag_level', 'tag',
1362            'level', 'node')
1363        {
1364          $new_element->{$key} = $element->{$key} if (defined($element->{$key}));
1365        }
1366        $new_element->{'this'} = $new_element;
1367        $new_element->{'element_ref'} = $new_element;
1368        $current_element = $new_element;
1369      }
1370    }
1371  }
1372}
1373
1374# not needed to initialize it for a document, since it is reset
1375# in index_summary
1376my $t2h_symbol_indices = 0;
1377
1378# format a letter appearing in a summary for an index. The letter links to
1379# the place where the index elements beginning with this letter are (called
1380# a letter entry).
1381#
1382# arguments:
1383# letter
1384# file where the target letter entry is
1385# identifier for the target letter entry
1386
1387sub html_default_summary_letter($$$$$$$)
1388{
1389   my $letter = shift;
1390   my $file = shift;
1391   my $default_identifier = shift;
1392   my $index_element_id = shift;
1393   my $number = shift;
1394   my $index_element = shift;
1395   my $index_name = shift;
1396
1397   return '' if ($letter =~ /^\s*$/);
1398   my $is_symbol = $letter !~ /^[A-Za-z]/;
1399   my $identifier = $default_identifier;
1400
1401   if ($NEW_CROSSREF_STYLE)
1402   {
1403      if ($is_symbol)
1404      {
1405         $t2h_symbol_indices++;
1406         $identifier = $index_element_id . "_${index_name}_symbol-$t2h_symbol_indices";
1407      }
1408      else
1409      {
1410         $identifier = $index_element_id . "_${index_name}_letter-${letter}";
1411      }
1412   }
1413   my $result = &$anchor('', $file . '#' . $identifier, '<b>' . &$protect_text($letter) . '</b>', 'class="summary-letter"');
1414   return $result unless ($NEW_CROSSREF_STYLE);
1415   return ($result, $identifier, $is_symbol);
1416}
1417
1418# this replaces do_index_page
1419# args should be:
1420# index_name
1421# printindex
1422sub t2h_GPL_default_printindex($$)
1423{
1424  my $index_name = shift;
1425  my $printindex = shift;
1426  # could be cross verified with argument
1427
1428  my $identifier_index_nr = 0;
1429  my @split_letters;
1430
1431  if (defined($printindex->{'split_groups'}) and scalar(@{$printindex->{'split_groups'}}))
1432  {
1433    @split_letters = @{$printindex->{'split_groups'}};
1434  }
1435  elsif (defined($Texi2HTML::THISDOC{'index_letters_array'}->{$index_name}) and scalar(@{$Texi2HTML::THISDOC{'index_letters_array'}->{$index_name}}))
1436  {
1437    my $element = $printindex->{'associated_element'};
1438    # this happens for printindex before the first element.
1439    if (!defined($element))
1440    {
1441       $element =  {'file' => '', 'id' => "$printindex->{'region'}_printindex"};
1442    }
1443    elsif (defined($element->{'element_ref'}))
1444    {
1445        $element = $element->{'element_ref'};
1446    }
1447    @split_letters = ({ 'letters' => $Texi2HTML::THISDOC{'index_letters_array'}->{$index_name}, 'element' => $element});
1448  }
1449  else
1450  {
1451    return '';
1452  }
1453
1454  foreach my $split_group (@split_letters)
1455  {
1456    #do summmary
1457    my @non_alpha = ();
1458    my @alpha = ();
1459    #print STDERR "$index_name @{$split_group->{'letters'}}\n";
1460    # letter_id could be done once for all instead of for each split_group
1461    # and outside of t2h_default_summary_letter (or t2h_default_summary_letter
1462    # could be simplified and inlined
1463    my %letter_id;
1464    foreach my $summary_split_group (@split_letters)
1465    {
1466      foreach my $letter_entry (@{$summary_split_group->{'letters'}})
1467      {
1468        my $letter = $letter_entry->{'letter'};
1469        my $dest_file = '';
1470
1471        ####################################### debug
1472        if (!defined($summary_split_group->{'element'}))
1473        {
1474            main::msg_debug ("index $index_name, letter $letter, element for summary_split_group $summary_split_group not defined");
1475        }
1476        elsif (!defined($summary_split_group->{'element'}->{'id'}))
1477        {
1478           main::msg_debug ("index $index_name, letter $letter, element $summary_split_group->{'element'} `$summary_split_group->{'element'}->{'texi'}', id undef");
1479        }
1480        ####################################### end debug
1481        $dest_file = $summary_split_group->{'element'}->{'file'}
1482           if ($summary_split_group ne $split_group);
1483        my $index_element_id = $summary_split_group->{'element'}->{'id'};
1484        my $default_identifier = $index_element_id . "_$identifier_index_nr";
1485        #print STDERR "$split_group $summary_split_group $summary_split_group->{'element'} $summary_split_group->{'element'}->{'id'}  $identifier_index_nr $index_element_id $default_identifier\n";
1486        $identifier_index_nr++;
1487        my ($result, $identifier, $is_symbol) =
1488          &$summary_letter($letter, $dest_file, $default_identifier, $index_element_id, '', '', $index_name);
1489        $identifier = $default_identifier if (!defined($identifier));
1490        $letter_id{$letter} = $identifier;
1491        $is_symbol = $letter !~ /^[A-Za-z]/ if (!defined($is_symbol));
1492
1493        if ($result ne '')
1494        {
1495          if ($is_symbol)
1496          {
1497            push @non_alpha, $result;
1498          }
1499          else
1500          {
1501            push @alpha, $result;
1502          }
1503        }
1504      }
1505    }
1506    my $summary = &$index_summary(\@alpha, \@non_alpha);
1507
1508    # reset symbols numbering
1509    $t2h_symbol_indices = 0;
1510
1511    my $letters_text = '';
1512    foreach my $letter_entry (@{$split_group->{'letters'}})
1513    {
1514      my $letter = $letter_entry->{'letter'};
1515      my $entries_text = '';
1516      foreach my $index_entry_ref (@{$letter_entry->{'entries'}})
1517      {
1518        my ($text_href, $entry_file, $element_file, $entry_target,
1519          $entry_element_target, $formatted_entry, $element_href,
1520          $entry_element_text, $in_region_not_in_output)
1521          =  main::get_index_entry_infos($index_entry_ref, $split_group->{'element'});
1522        $entries_text .= &$index_entry ($text_href, $formatted_entry, $element_href, $entry_element_text, $entry_file, $element_file, $entry_target, $entry_element_target, $in_region_not_in_output, $index_entry_ref);
1523      }
1524      $letters_text .= &$index_letter ($letter, $letter_id{$letter}, $entries_text)
1525    }
1526    my $index_text = &$print_index($letters_text, $index_name);
1527    $split_group->{'text'} = $summary . $index_text . $summary;
1528#    print STDERR "    ---> $index_name @{$split_group->{'letters'}}
1529#     * elt:   $split_group->{'element'}->{'id'}, $split_group->{'element'}->{'file'}, $split_group->{'element'}->{'name'}
1530#     * directions: B: $split_group->{'element'}->{'Back'}->{'name'}, F: $split_group->{'element'}->{'Forward'}->{'name'}, FB: $split_group->{'element'}->{'FastBack'}->{'name'}, FF: $split_group->{'element'}->{'FastForward'}->{'name'}
1531#     * text
1532#
1533#$split_group->{'text'}
1534#
1535#";
1536  }
1537  my $current_page = shift @split_letters;
1538  if (!scalar(@split_letters))
1539  {
1540    return $current_page->{'text'};
1541  }
1542
1543  while (1)
1544  {
1545    # print the index letters
1546    push @{$Texi2HTML::THIS_SECTION}, $current_page->{'text'};
1547
1548    $current_page = shift @split_letters;
1549    last if (!defined($current_page));
1550
1551    # there is no need to begin first element if not already done, since
1552    # the index is not split if not already in an element.
1553    # end the previous element
1554    main::finish_element ($Texi2HTML::THISDOC{'FH'}, $Texi2HTML::THIS_ELEMENT, $Texi2HTML::THIS_ELEMENT->{'Forward'}, 0);
1555
1556    # do the new element beginning
1557    $Texi2HTML::THIS_ELEMENT = $current_page->{'element'};
1558    my $new_element = $Texi2HTML::THIS_ELEMENT;
1559    main::unref_file($new_element->{'file'});
1560    main::do_element_directions($new_element);
1561    my $do_page_head = main::open_out_file($new_element->{'file'});
1562    if ($do_page_head)
1563    {
1564      &$print_page_head($Texi2HTML::THISDOC{'FH'});
1565      &$print_chapter_header($Texi2HTML::THISDOC{'FH'}, $new_element) if Texi2HTML::Config::get_conf('SPLIT') eq 'chapter';
1566      &$print_section_header($Texi2HTML::THISDOC{'FH'}, $new_element) if Texi2HTML::Config::get_conf('SPLIT') eq 'section';
1567    }
1568    # almost nothing of this is used in the default html output
1569    @{$Texi2HTML::THIS_SECTION} = &$element_heading($new_element, $new_element->{'tag'}, $new_element->{'texi'},
1570       $new_element->{'text'}, 0, 0, $new_element->{'this'}, 1, 0, 0, "\@$new_element->{'tag'} $new_element->{'texi'}",
1571       $new_element->{'id'}, $new_element);
1572
1573  }
1574  return '';
1575}
1576
1577# leave this within comments, and keep the require statement
1578# This way, you can directly run texi2html.pl,
1579# if $T2H_HOME/documentlanguages.pl exists.
1580#
1581# @T2H_DOCUMENT_LANGUAGES@
1582
1583require "$T2H_HOME/documentlanguages.pl"
1584    if ($0 =~ /\.pl$/ &&
1585        -e "$T2H_HOME/documentlanguages.pl" && -r "$T2H_HOME/documentlanguages.pl");
1586
1587# leave this within comments, and keep the require statement
1588# This way, you can directly run texi2html.pl, if
1589# $T2H_HOME/texi2html.init exists.
1590
1591# @INIT@
1592
1593require "$T2H_HOME/texi2html.init"
1594    if ($0 =~ /\.pl$/ &&
1595        -e "$T2H_HOME/texi2html.init" && -r "$T2H_HOME/texi2html.init");
1596
1597# @INIT_HTML@
1598
1599require "$T2H_HOME/formats/html.init"
1600    if ($0 =~ /\.pl$/ &&
1601        -e "$T2H_HOME/formats/html.init" && -r "$T2H_HOME/formats/html.init");
1602
1603# @INIT_INFO@
1604
1605require "$T2H_HOME/formats/info.init"
1606    if ($0 =~ /\.pl$/ &&
1607        -e "$T2H_HOME/formats/info.init" && -r "$T2H_HOME/formats/info.init");
1608
1609# @INIT_DOCBOOK@
1610
1611require "$T2H_HOME/formats/docbook.init"
1612    if ($0 =~ /\.pl$/ &&
1613        -e "$T2H_HOME/formats/docbook.init" && -r "$T2H_HOME/formats/docbook.init");
1614
1615# @INIT_XML@
1616
1617require "$T2H_HOME/formats/xml.init"
1618    if ($0 =~ /\.pl$/ &&
1619        -e "$T2H_HOME/formats/xml.init" && -r "$T2H_HOME/formats/xml.init");
1620
1621# @INIT_PLAINTEXT@
1622
1623require "$T2H_HOME/formats/plaintext.init"
1624    if ($0 =~ /\.pl$/ &&
1625        -e "$T2H_HOME/formats/plaintext.init" && -r "$T2H_HOME/formats/plaintext.init");
1626
1627my $translation_file = 'translations.pl'; # file containing all the translations
1628my $T2H_OBSOLETE_STRINGS;
1629
1630# leave this within comments, and keep the require statement
1631# This way, you can directly run texi2html.pl,
1632# if $T2H_HOME/translations.pl exists.
1633#
1634# @T2H_TRANSLATIONS_FILE@
1635
1636require "$T2H_HOME/$translation_file"
1637    if ($0 =~ /\.pl$/ &&
1638        -e "$T2H_HOME/$translation_file" && -r "$T2H_HOME/$translation_file");
1639
1640
1641# these are unlikely to be used by users, as they are essentially
1642# used to follow the html external refs specification in texinfo
1643sub t2h_cross_manual_normal_text($$$$$$$;$)
1644{
1645    my $text = shift;
1646    my $in_raw_text = shift;
1647    my $in_preformatted = shift;
1648    my $in_code =shift;
1649    my $in_math = shift;
1650    my $in_simple =shift;
1651    my $style_stack = shift;
1652    my $state = shift;
1653
1654    $text = uc($text) if (in_small_caps($style_stack));
1655    return $text if ($USE_UNICODE);
1656    return t2h_no_unicode_cross_manual_normal_text($text, 0);
1657}
1658
1659sub t2h_cross_manual_normal_text_transliterate($$$$$$$;$)
1660{
1661    my $text = shift;
1662    my $in_raw_text = shift;
1663    my $in_preformatted = shift;
1664    my $in_code =shift;
1665    my $in_math = shift;
1666    my $in_simple =shift;
1667    my $style_stack = shift;
1668    my $state = shift;
1669
1670    $text = uc($text) if (in_small_caps($style_stack));
1671    return $text if ($USE_UNICODE);
1672    return t2h_no_unicode_cross_manual_normal_text($text, 1);
1673}
1674
1675sub t2h_no_unicode_cross_manual_normal_text($$)
1676{
1677    # if there is no unicode support, we do all the transformations here
1678    my $text = shift;
1679    my $transliterate = shift;
1680    my $result = '';
1681
1682    my $encoding = get_conf('DOCUMENT_ENCODING');
1683    if (defined($encoding) and exists($t2h_encoding_aliases{$encoding}))
1684    {
1685        $encoding = $t2h_encoding_aliases{$encoding};
1686    }
1687
1688    while ($text ne '')
1689    {
1690        if ($text =~ s/^([A-Za-z0-9]+)//o)
1691        {
1692             $result .= $1;
1693        }
1694        elsif ($text =~ s/^ //o)
1695        {
1696             $result .= '-';
1697        }
1698        elsif ($text =~ s/^(.)//o)
1699        {
1700             if (exists($ascii_character_map{$1}))
1701             {
1702                 $result .= '_' . lc($ascii_character_map{$1});
1703             }
1704             else
1705             {
1706                  my $character = $1;
1707                  my $charcode = uc(sprintf("%02x",ord($1)));
1708                  my $done = 0;
1709                  if (defined($encoding) and exists($eight_bit_to_unicode{$encoding})
1710                      and exists($eight_bit_to_unicode{$encoding}->{$charcode}))
1711                  {
1712                      $done = 1;
1713                      my $unicode_point =  $eight_bit_to_unicode{$encoding}->{$charcode};
1714                      if (!$transliterate)
1715                      {
1716                           $result .= '_' . lc($unicode_point);
1717                      }
1718                      elsif (exists($transliterate_map{$unicode_point}))
1719                      {
1720                           $result .= $transliterate_map{$unicode_point};
1721                      }
1722                      elsif (exists($unicode_diacritical{$unicode_point}))
1723                      {
1724                           $result .= '';
1725                      }
1726                      else
1727                      {
1728                          $done = 0;
1729                      }
1730                  }
1731
1732                  if (!$done)
1733                  { # wild guess that work for latin1, and thus, should fail
1734                      $result .= '_' . '00' . lc($charcode);
1735                  }
1736             }
1737        }
1738        else
1739        {
1740             msg_debug("Bug: unknown character in cross ref (likely in infinite loop)");
1741             msg_debug("Text: !!$text!!");
1742             sleep 1;
1743        }
1744    }
1745
1746    return $result;
1747}
1748
1749sub t2h_nounicode_cross_manual_accent($$$)
1750{
1751    my $accent = shift;
1752    my $args = shift;
1753    my $style_stack = shift;
1754
1755    my $text = $args->[0];
1756
1757    if ($accent eq 'dotless')
1758    {
1759        if (($text eq 'i') and (!defined($style_stack->[-1]) or (!defined($unicode_accents{$style_stack->[-1]})) or ($style_stack->[-1] eq 'tieaccent')))
1760        {
1761             return "_0131";
1762        }
1763        #return "\x{}" if ($text eq 'j'); # not found !
1764        return $text;
1765    }
1766    return '_' . lc($unicode_accents{$accent}->{$text})
1767        if (defined($unicode_accents{$accent}->{$text}));
1768    return ($text . '_' . lc($unicode_diacritical{$accent}))
1769        if (defined($unicode_diacritical{$accent}));
1770    return ascii_accents($text, $accent);
1771}
1772
1773sub t2h_transliterate_cross_manual_accent($$)
1774{
1775    my $accent = shift;
1776    my $args = shift;
1777
1778    my $text = $args->[0];
1779
1780    if (exists($unicode_accents{$accent}->{$text}) and
1781        exists ($transliterate_map{$unicode_accents{$accent}->{$text}}))
1782    {
1783         return $transliterate_map{$unicode_accents{$accent}->{$text}};
1784    }
1785    return $text;
1786}
1787
1788
1789} # end package Texi2HTML::Config
1790
1791# set the defaults based on real command name
1792set_config_init_dirs_output($real_command_name);
1793
1794use vars qw(
1795%value
1796%alias
1797);
1798
1799# variables which might be redefined by the user but aren't likely to be
1800# they seem to be in the main namespace
1801use vars qw(
1802%index_names
1803%index_prefix_to_name
1804%predefined_index
1805%valid_index
1806%reference_sec2level
1807%code_style_map
1808%forbidden_index_name
1809);
1810
1811# Some global variables are set in the script, and used in the subroutines
1812# they are in the Texi2HTML namespace, thus prefixed with Texi2HTML::.
1813# see texi2html.init for details.
1814
1815#+++############################################################################
1816#                                                                              #
1817# Pasted content of File $(srcdir)/MySimple.pm: Command-line processing        #
1818#                                                                              #
1819#---############################################################################
1820
1821# leave this within comments, and keep the require statement
1822# This way, you can directly run texi2html.pl, if $T2H_HOME/MySimple.pm
1823# exists.
1824
1825# @MYSIMPLE@
1826
1827require "$T2H_HOME/MySimple.pm"
1828    if ($0 =~ /\.pl$/ &&
1829        -e "$T2H_HOME/MySimple.pm" && -r "$T2H_HOME/MySimple.pm");
1830
1831#+++########################################################################
1832#                                                                          #
1833# Pasted content of File $(srcdir)/T2h_i18n.pm: Internationalisation       #
1834#                                                                          #
1835#---########################################################################
1836
1837# leave this within comments, and keep the require statement
1838# This way, you can directly run texi2html.pl, if $T2H_HOME/T2h_i18n.pm
1839# exists.
1840
1841{
1842# @T2H_I18N@
1843require "$T2H_HOME/T2h_i18n.pm"
1844    if ($0 =~ /\.pl$/ &&
1845        -e "$T2H_HOME/T2h_i18n.pm" && -r "$T2H_HOME/T2h_i18n.pm");
1846}
1847
1848
1849#########################################################################
1850#
1851# latex2html code
1852#
1853#---######################################################################
1854
1855{
1856# leave this within comments, and keep the require statement
1857# This way, you can directly run texi2html.pl, if $ENV{T2H_HOME}/T2h_l2h.pm
1858# exists.
1859
1860# @T2H_L2H@
1861
1862require "$T2H_HOME/T2h_l2h.pm"
1863    if ($0 =~ /\.pl$/ &&
1864        -e "$T2H_HOME/T2h_l2h.pm" && -r "$T2H_HOME/T2h_l2h.pm");
1865
1866}
1867
1868{
1869package Texi2HTML::LaTeX2HTML::Config;
1870
1871# latex2html variables
1872# These variables are not used. They are here for information only, and
1873# an example of config file for latex2html file is included.
1874my $ADDRESS;
1875my $ANTI_ALIAS;
1876my $ANTI_ALIAS_TEXT;
1877my $ASCII_MODE;
1878my $AUTO_LINK;
1879my $AUTO_PREFIX;
1880my $CHILDLINE;
1881my $DEBUG;
1882my $DESTDIR;
1883my $DVIPS = 'dvips';
1884my $ERROR;
1885my $EXTERNAL_FILE;
1886my $EXTERNAL_IMAGES;
1887my $EXTERNAL_UP_LINK;
1888my $EXTERNAL_UP_TITLE;
1889my $FIGURE_SCALE_FACTOR;
1890my $HTML_VERSION;
1891my $IMAGES_ONLY;
1892my $INFO;
1893my $LINE_WIDTH;
1894my $LOCAL_ICONS;
1895my $LONG_TITLES;
1896my $MATH_SCALE_FACTOR;
1897my $MAX_LINK_DEPTH;
1898my $MAX_SPLIT_DEPTH;
1899my $NETSCAPE_HTML;
1900my $NOLATEX;
1901my $NO_FOOTNODE;
1902my $NO_IMAGES;
1903my $NO_NAVIGATION;
1904my $NO_SIMPLE_MATH;
1905my $NO_SUBDIR;
1906my $PAPERSIZE;
1907my $PREFIX;
1908my $PS_IMAGES;
1909my $REUSE;
1910my $SCALABLE_FONTS;
1911my $SHORTEXTN;
1912my $SHORT_INDEX;
1913my $SHOW_SECTION_NUMBERS;
1914my $SPLIT;
1915my $TEXDEFS;
1916my $TITLE;
1917my $TITLES_LANGUAGE;
1918my $TMP;
1919my $VERBOSE;
1920my $WORDS_IN_NAVIGATION_PANEL_TITLES;
1921my $WORDS_IN_PAGE;
1922
1923# @T2H_L2H_INIT@
1924}
1925
1926package main;
1927
1928if (!defined(Texi2HTML::Config::get_conf('use_nls')))
1929{
1930   my $use_nls = ('@USE_NLS@' eq 'yes' or $0 =~ /\.pl$/);
1931   Texi2HTML::Config::set_conf('use_nls', $use_nls);
1932}
1933
1934# prepare the gettext-like framework. To be noted that Locales::TextDomain
1935# canot be used, since it cannot be used dynamically through a reuires.
1936# Fortunately, Locales::TextDomain is a thin layer above Locales::Messages.
1937
1938my $strings_textdomain = '@PACKAGE@' . '_document';
1939$strings_textdomain = 'texi2html_document' if ($strings_textdomain eq '@'.'PACKAGE@' . '_document');
1940my $messages_textdomain = '@PACKAGE@';
1941$messages_textdomain = 'texi2html' if ($messages_textdomain eq '@'.'PACKAGE@');
1942
1943#my $messages_textdomain = 'texinfo';
1944
1945if (Texi2HTML::Config::get_conf('use_nls'))
1946{
1947    if ($0 =~ /\.pl$/)
1948    { # use in-source libintl when testing
1949        unshift @INC, "$T2H_HOME/lib/libintl-perl/lib";
1950    }
1951    elsif ($ENV{T2H_SOURCE_LIBINTL})
1952    {
1953        unshift @INC, $ENV{T2H_SOURCE_LIBINTL};
1954    }
1955    elsif ('@USE_EXTERNAL_LIBINTL@' ne 'yes')
1956    {
1957        unshift @INC, "$pkgdatadir/lib/libintl-perl/lib";
1958    }
1959    else
1960    {
1961        eval {
1962            require Locale::Messages;
1963        };
1964        if ($@)
1965        {
1966            unshift @INC, "$pkgdatadir/lib/libintl-perl/lib";
1967        }
1968    }
1969    # gettext-like translations
1970    #require Locale::TextDomain;
1971    require Locale::Messages;
1972    # we want a reliable way to switch locale, so we don't use the system
1973    # gettext.
1974    Locale::Messages->select_package ('gettext_pp');
1975    if ($0 =~ /\.pl$/)
1976    {
1977         # in case of out of source build, the locales directory should
1978         # be two levels below. $T2H_HOME is in srcdir.
1979         foreach my $locales_dir ("$T2H_HOME/locales", "../../locales")
1980         {
1981             if (-d $locales_dir)
1982             {
1983                  Locale::Messages::bindtextdomain ($strings_textdomain, $locales_dir);
1984                  last;
1985             }
1986        }
1987    }
1988    else
1989    { # match where gettext installs
1990        Locale::Messages::bindtextdomain ($strings_textdomain, "$datadir/locale");
1991    }
1992    # simply bind error messages to the installation directory.
1993    # Messages should be untranslated for tests.
1994    Locale::Messages::bindtextdomain ($messages_textdomain, "$datadir/locale");
1995}
1996else
1997{
1998    unshift @INC, "$pkgdatadir/lib/libintl-perl/lib";
1999    require Locale::Messages;
2000}
2001
2002sub __($)
2003{
2004    my $msgid = shift;
2005    return Locale::Messages::dgettext($messages_textdomain, $msgid);
2006}
2007
2008sub __p($$)
2009{
2010    my $context = shift;
2011    my $msgid = shift;
2012    return Locale::Messages::dpgettext($messages_textdomain, $context, $msgid);
2013}
2014
2015sub N__($)
2016{
2017    return $_[0];
2018}
2019
2020#
2021# flush stdout and stderr after every write
2022#
2023select(STDERR);
2024$| = 1;
2025select(STDOUT);
2026$| = 1;
2027
2028my $I = \&Texi2HTML::I18n::get_string;
2029
2030########################################################################
2031#
2032# Global variable initialization
2033#
2034########################################################################
2035#
2036# pre-defined indices
2037#
2038
2039%index_prefix_to_name = ();
2040
2041%index_names =
2042(
2043 'cp' => { 'prefixes' => {'cp' => 0,'c' => 0}},
2044 'fn' => { 'prefixes' => {'fn' => 1, 'f' => 1}},
2045 'vr' => { 'prefixes' => {'vr' => 1, 'v' => 1}},
2046 'ky' => { 'prefixes' => {'ky' => 1, 'k' => 1}},
2047 'pg' => { 'prefixes' => {'pg' => 1, 'p' => 1}},
2048 'tp' => { 'prefixes' => {'tp' => 1, 't' => 1}}
2049);
2050
2051foreach my $name(keys(%index_names))
2052{
2053    foreach my $prefix (keys %{$index_names{$name}->{'prefixes'}})
2054    {
2055        $forbidden_index_name{$prefix} = 1;
2056        $index_prefix_to_name{$prefix} = $name;
2057    }
2058}
2059
2060foreach my $other_forbidden_index_name ('info','ps','pdf','htm',
2061   'log','aux','dvi','texi','txi','texinfo','tex','bib')
2062{
2063    $forbidden_index_name{$other_forbidden_index_name} = 1;
2064}
2065
2066# commands with ---, -- '' and `` preserved
2067# usefull with the old interface
2068
2069%code_style_map = (
2070           'code'    => 1,
2071           'command' => 1,
2072           'env'     => 1,
2073           'file'    => 1,
2074           'kbd'     => 1,
2075           'option'  => 1,
2076           'samp'    => 1,
2077           'verb'    => 1,
2078);
2079
2080my @element_directions = ('Up', 'Forward', 'Back', 'Next', 'Prev',
2081'SectionNext', 'SectionPrev', 'SectionUp', 'FastForward', 'FastBack',
2082'This', 'NodeUp', 'NodePrev', 'NodeNext', 'Following', 'NextFile', 'PrevFile',
2083'ToplevelNext', 'ToplevelPrev');
2084$::simple_map_ref = \%Texi2HTML::Config::simple_map;
2085$::simple_map_math_ref = \%Texi2HTML::Config::simple_map_math;
2086#$::simple_map_pre_ref = \%Texi2HTML::Config::simple_map_pre;
2087$::simple_map_texi_ref = \%Texi2HTML::Config::simple_map_texi;
2088$::style_map_ref = \%Texi2HTML::Config::style_map;
2089$::style_map_pre_ref = \%Texi2HTML::Config::style_map_pre;
2090$::style_map_math_ref = \%Texi2HTML::Config::style_map_math;
2091$::style_map_texi_ref = \%Texi2HTML::Config::style_map_texi;
2092$::things_map_ref = \%Texi2HTML::Config::things_map;
2093$::pre_map_ref = \%Texi2HTML::Config::pre_map;
2094$::texi_map_ref = \%Texi2HTML::Config::texi_map;
2095
2096#print STDERR "MAPS: $::simple_map_ref $::simple_map_pre_ref $::simple_map_texi_ref $::style_map_ref $::style_map_pre_ref $::style_map_texi_ref $::things_map_ref $::pre_map_ref $::texi_map_ref\n";
2097
2098# delete from hash if we are using the new interface
2099foreach my $code (keys(%code_style_map))
2100{
2101    delete ($code_style_map{$code})
2102       if (ref($::style_map_ref->{$code}) eq 'HASH');
2103}
2104
2105# no paragraph in these commands
2106my %no_paragraph_macro = (
2107           'xref'         => 1,
2108           'ref'          => 1,
2109           'pxref'        => 1,
2110           'inforef'      => 1,
2111           'anchor'       => 1,
2112);
2113
2114
2115#
2116# texinfo section names to level
2117#
2118my %reference_sec2level = (
2119	      'top', 0,
2120	      'chapter', 1,
2121	      'unnumbered', 1,
2122	      'chapheading', 1,
2123	      'appendix', 1,
2124	      'section', 2,
2125	      'unnumberedsec', 2,
2126	      'heading', 2,
2127	      'appendixsec', 2,
2128	      'subsection', 3,
2129	      'unnumberedsubsec', 3,
2130	      'subheading', 3,
2131	      'appendixsubsec', 3,
2132	      'subsubsection', 4,
2133	      'unnumberedsubsubsec', 4,
2134	      'subsubheading', 4,
2135	      'appendixsubsubsec', 4,
2136         );
2137
2138# the reverse mapping. There is an entry for each sectioning command.
2139# The value is a ref on an array containing at each index the corresponding
2140# sectioning command name.
2141my %level2sec;
2142{
2143    my $sections = [ ];
2144    my $appendices = [ ];
2145    my $unnumbered = [ ];
2146    my $headings = [ ];
2147    foreach my $command (keys (%reference_sec2level))
2148    {
2149        if ($command =~ /^appendix/)
2150        {
2151            $level2sec{$command} = $appendices;
2152        }
2153        elsif ($command =~ /^unnumbered/ or $command eq 'top')
2154        {
2155            $level2sec{$command} = $unnumbered;
2156        }
2157        elsif ($command =~ /section$/ or $command eq 'chapter')
2158        {
2159            $level2sec{$command} = $sections;
2160        }
2161        else
2162        {
2163            $level2sec{$command} = $headings;
2164        }
2165        $level2sec{$command}->[$reference_sec2level{$command}] = $command;
2166    }
2167}
2168
2169# out of the main hierarchy
2170$reference_sec2level{'part'} = 0;
2171# this are synonyms
2172$reference_sec2level{'appendixsection'} = 2;
2173# sec2level{'majorheading'} is also 1 and not 0
2174$reference_sec2level{'majorheading'} = 1;
2175$reference_sec2level{'chapheading'} = 1;
2176$reference_sec2level{'centerchap'} = 1;
2177
2178sub stop_paragraph_command($)
2179{
2180   my $command = shift;
2181   return 1 if ($Texi2HTML::Config::stop_paragraph_command{$command} or defined($reference_sec2level{$command}));
2182}
2183
2184sub set_no_line_macro($$)
2185{
2186   my $macro = shift;
2187   my $value = shift;
2188   $Texi2HTML::Config::no_paragraph_commands{$macro} = $value
2189      unless defined($Texi2HTML::Config::no_paragraph_commands{$macro});
2190}
2191
2192# those macros aren't considered as beginning a paragraph
2193foreach my $no_line_macro ('alias', 'macro', 'unmacro', 'rmacro',
2194 'titlefont', 'include', 'copying', 'end copying', 'tab', 'item',
2195 'itemx', '*', 'float', 'end float', 'caption', 'shortcaption', 'cindex',
2196 'image')
2197{
2198    set_no_line_macro($no_line_macro, 1);
2199}
2200
2201foreach my $key (keys(%Texi2HTML::Config::misc_command), keys(%reference_sec2level))
2202{
2203    set_no_line_macro($key, 1);
2204}
2205
2206# a hash associating a format @thing / @end thing with the type of the format
2207# 'complex_format' 'simple_format' 'deff' 'list' 'menu' 'paragraph_format'
2208my %format_type = ();
2209
2210foreach my $simple_format (keys(%Texi2HTML::Config::format_map))
2211{
2212   $format_type{$simple_format} = 'simple_format';
2213}
2214foreach my $paragraph_style (keys(%Texi2HTML::Config::paragraph_style))
2215{
2216   $format_type{$paragraph_style} = 'paragraph_format';
2217}
2218# FIXME $complex_format_map obsoleted in nov 2009
2219foreach my $complex_format (keys(%$Texi2HTML::Config::complex_format_map),
2220    keys(%Texi2HTML::Config::complex_format_map))
2221{
2222   $format_type{$complex_format} = 'complex_format';
2223}
2224foreach my $table (('table', 'ftable', 'vtable'))
2225{
2226   $format_type{$table} = 'table';
2227}
2228$format_type{'multitable'} = 'multitable';
2229foreach my $def_format (keys(%Texi2HTML::Config::def_map))
2230{
2231   $format_type{$def_format} = 'deff';
2232}
2233$format_type{'itemize'} = 'list';
2234$format_type{'enumerate'} = 'list';
2235
2236$format_type{'menu'} = 'menu';
2237$format_type{'detailmenu'} = 'menu';
2238$format_type{'direntry'} = 'menu';
2239
2240$format_type{'cartouche'} = 'cartouche';
2241
2242$format_type{'float'} = 'float';
2243
2244$format_type{'quotation'} = 'quotation';
2245$format_type{'smallquotation'} = 'quotation';
2246
2247$format_type{'group'} = 'group';
2248
2249my @special_regions = ('titlepage', 'copying', 'documentdescription');
2250foreach my $region (@special_regions)
2251{
2252   $format_type{$region} = 'region';
2253}
2254
2255foreach my $key (keys(%format_type))
2256{
2257   set_no_line_macro($key, 1);
2258   set_no_line_macro("end $key", 1);
2259}
2260
2261foreach my $macro (keys(%Texi2HTML::Config::format_in_paragraph))
2262{
2263   set_no_line_macro($macro, 1);
2264   set_no_line_macro("end $macro", 1);
2265}
2266
2267# fake format at the bottom of the stack
2268$format_type{'noformat'} = '';
2269
2270# fake formats are formats used internally within other formats
2271# we associate them with a real format, for the error messages
2272my %fake_format = (
2273     'line' => 'table',
2274     'term' => 'table',
2275     'item' => 'list or table',
2276     'row' => 'multitable row',
2277     'cell' => 'multitable cell',
2278     'deff_item' => 'definition command',
2279     'menu_comment' => 'menu',
2280     'menu_description' => 'menu',
2281  );
2282
2283foreach my $key (keys(%fake_format))
2284{
2285    $format_type{$key} = 'fake';
2286}
2287
2288# raw formats which are expanded especially
2289my @raw_regions = ('html', 'tex', 'xml', 'docbook');
2290foreach my $format (keys(%Texi2HTML::Config::texi_formats_map))
2291{
2292    push @raw_regions, $format if ($Texi2HTML::Config::texi_formats_map{$format} eq 'raw');
2293}
2294
2295# The css formats are associated with complex format commands, and associated
2296# with the 'pre_style' key
2297# FIXME $complex_format_map obsoleted in nov 2009
2298foreach my $complex_format (keys(%$Texi2HTML::Config::complex_format_map))
2299{
2300    next if (defined($Texi2HTML::Config::complex_format_map->{$complex_format}->{'pre_style'}));
2301    $Texi2HTML::Config::complex_format_map->{$complex_format}->{'pre_style'} = '';
2302    $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"}));
2303}
2304
2305# The css formats are associated with complex format commands, and associated
2306# with the 'pre_style' key
2307foreach my $complex_format (keys(%Texi2HTML::Config::complex_format_map))
2308{
2309    next if (defined($Texi2HTML::Config::complex_format_map{$complex_format}->{'pre_style'}));
2310    $Texi2HTML::Config::complex_format_map{$complex_format}->{'pre_style'} = '';
2311    $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"}));
2312}
2313
2314
2315
2316#+++############################################################################
2317#                                                                              #
2318# Argument parsing, initialisation                                             #
2319#                                                                              #
2320#---############################################################################
2321
2322# shorthand for Texi2HTML::Config::VERBOSE
2323my $T2H_VERBOSE;
2324my $T2H_DEBUG;
2325
2326sub line_warn($$);
2327sub document_warn($);
2328sub file_line_warn($$;$);
2329sub cmdline_warn ($);
2330
2331my $T2H_FAILURE_TEXT = sprintf(__("Try `%s --help' for more information.\n"), $real_command_name);
2332
2333#print STDERR "" . gdt('test i18n: \' , \a \\ %% %{unknown}a %known % %{known}  \\', { 'known' => 'a known string', 'no' => 'nope'}); exit 0;
2334
2335# file:        file name to locate. It can be a file path.
2336# all_files:   if true collect all the files with that name, otherwise stop
2337#              at first match.
2338# directories: a reference on a array containing a list of directories to
2339#              search the file in. default is
2340#              @Texi2HTML::Config::CONF_DIRS, @program_config_dirs.
2341sub locate_init_file($;$$)
2342{
2343    my $file = shift;
2344    my $all_files = shift;
2345    my $directories = shift;
2346
2347    if (!defined($directories))
2348    {
2349       if ($all_files)
2350       {
2351           $directories = [ @program_config_dirs ];
2352       }
2353       else
2354       {
2355           $directories = [ @Texi2HTML::Config::CONF_DIRS, @program_init_dirs ];
2356       }
2357    }
2358
2359    if ($file =~ /^\//)
2360    {
2361         return $file if (-e $file and -r $file);
2362    }
2363    else
2364    {
2365         my @files;
2366         foreach my $dir (@$directories)
2367         {
2368              next unless (-d "$dir");
2369              if ($all_files)
2370              {
2371                  push (@files, "$dir/$file") if (-e "$dir/$file" and -r "$dir/$file");
2372              }
2373              else
2374              {
2375                  return "$dir/$file" if (-e "$dir/$file" and -r "$dir/$file");
2376              }
2377         }
2378         return @files if ($all_files);
2379    }
2380    return undef;
2381}
2382
2383# called on -init-file
2384sub load_init_file
2385{
2386    # First argument is option
2387    shift;
2388    # second argument is value of options
2389    my $init_file = shift;
2390    my $file;
2391    if ($file = locate_init_file($init_file))
2392    {
2393        print STDERR "# reading initialization file from $file\n"
2394            if ($T2H_VERBOSE);
2395        # require the file in the Texi2HTML::Config namespace
2396        return (Texi2HTML::Config::load($file));
2397    }
2398    else
2399    {
2400        document_error ("Can't read init file $init_file");
2401        return 0;
2402    }
2403}
2404
2405sub set_date($)
2406{
2407    my $language = shift;
2408    if (!$Texi2HTML::Config::TEST)
2409    {
2410        print STDERR "# Setting date in $language\n" if ($T2H_DEBUG);
2411        $Texi2HTML::THISDOC{'today'} = Texi2HTML::I18n::pretty_date($language);  # like "20 September 1993";
2412    }
2413    else
2414    {
2415        $Texi2HTML::THISDOC{'today'} = 'a sunny day';
2416    }
2417    $Texi2HTML::THISDOC{'today'} = $Texi2HTML::Config::DATE
2418        if (defined($Texi2HTML::Config::DATE));
2419    $::things_map_ref->{'today'} = $Texi2HTML::THISDOC{'today'};
2420    $::pre_map_ref->{'today'} = $Texi2HTML::THISDOC{'today'};
2421    $::texi_map_ref->{'today'} = $Texi2HTML::THISDOC{'today'};
2422}
2423
2424sub warn_unknown_language($;$)
2425{
2426    my $lang = shift;
2427    my $line_nr = shift;
2428
2429    my $lang_code = $lang;
2430    my $region_code;
2431
2432    if ($lang =~ /^([a-z]+)_([A-Z]+)/)
2433    {
2434        $lang_code = $1;
2435        $region_code = $2;
2436    }
2437
2438    if (! $Texi2HTML::Config::language_codes{$lang_code})
2439    {
2440        msg_warn(sprintf(__("%s is not a valid language code"), $lang_code), $line_nr);
2441    }
2442    if (defined($region_code) and ! $Texi2HTML::Config::region_codes{$region_code})
2443    {
2444        msg_warn(sprintf(__("%s is not a valid region code"), $region_code), $line_nr);
2445    }
2446}
2447
2448# Called on --document-language, at the beginning of each pass and
2449# when a @documentlanguage appears
2450sub set_document_language ($$;$)
2451{
2452    my $lang = shift;
2453    my $silent = shift;
2454    my $line_nr = shift;
2455
2456    my @langs = ($lang);
2457
2458#    my $lang_code = $lang;
2459#    my $region_code;
2460
2461    my $main_lang;
2462
2463    if ($lang =~ /^([a-z]+)_([A-Z]+)/)
2464    {
2465        $main_lang = $1;
2466#        $region_code = $2;
2467#        $lang_code = $main_lang;
2468        push @langs, $main_lang;
2469    }
2470
2471#    if (!$silent)
2472#    {
2473#        if (! $Texi2HTML::Config::language_codes{$lang_code})
2474#        { # i18n
2475#            msg_warn("$lang_code is not a valid language code.", $line_nr);
2476#        }
2477#        if (defined($region_code) and ! $Texi2HTML::Config::region_codes{$region_code})
2478#        { # i18n
2479#            msg_warn("$region_code is not a valid region code.", $line_nr);
2480#        }
2481#    }
2482    # Always succeed if using a gettext-like environment
2483    if (!$Texi2HTML::Config::I18N_PERL_HASH)
2484    {
2485        set_date($lang);
2486        return 1;
2487    }
2488
2489    my @files = locate_init_file("$i18n_dir/$lang.thl", 1);
2490    if (! scalar(@files) and defined($main_lang))
2491    {
2492        @files = locate_init_file("$i18n_dir/$main_lang.thl", 1);
2493    }
2494
2495    foreach  my $file (@files)
2496    {
2497        Texi2HTML::Config::load($file);
2498    }
2499    foreach my $language (@langs)
2500    {
2501        if (Texi2HTML::I18n::set_language($language))
2502        {
2503            print STDERR "# using '$language' as document language\n" if ($T2H_VERBOSE);
2504            # since it may be different from get_conf('documentlanguage'),
2505            # we record it.
2506            # Currently this is not used anywhere, not sure what the value
2507            # really corresponds with.
2508            $Texi2HTML::THISDOC{'current_language'} = $language;
2509            set_date($language);
2510            return 1;
2511        }
2512    }
2513    return 0;
2514}
2515
2516
2517# manage footnote style
2518sub set_footnote_style($$;$)
2519{
2520    my $value = shift;
2521    my $from_command_line = shift;
2522    my $line_nr = shift;
2523    my $command = 'footnotestyle';
2524    if ($value eq 'end' or $value eq 'separate')
2525    {
2526         Texi2HTML::Config::set_conf($command, $value, !$from_command_line);
2527    }
2528    elsif ($from_command_line)
2529    {
2530         die sprintf(__("%s: --footnote-style arg must be `separate' or `end', not `%s'.\n"), $real_command_name, $value);
2531         # the T2H_FAILURE_TEXT is output by getOption, seems to catch die
2532    }
2533    else
2534    {
2535         line_error (sprintf(__("\@%s arg must be `separate' or `end', not `%s'"), $command, $value), $line_nr);
2536    }
2537}
2538
2539
2540# find the encoding alias.
2541# with encoding support (USE_UNICODE), may return undef if no alias was found
2542sub encoding_alias($;$$)
2543{
2544    my $encoding = shift;
2545    my $line_nr = shift;
2546    my $context_string = shift;
2547    return undef if (!defined($encoding) or $encoding eq '');
2548    if ($Texi2HTML::Config::USE_UNICODE)
2549    {
2550         my $result_encoding = Encode::resolve_alias($encoding);
2551         if (! $result_encoding)
2552         {
2553              msg_warn(sprintf(__("unrecognized encoding name `%s'"), $encoding), $line_nr, $context_string);
2554              return undef;
2555         }
2556         if (defined($Texi2HTML::Config::t2h_encoding_aliases{$result_encoding}))
2557         {
2558             $result_encoding = $Texi2HTML::Config::t2h_encoding_aliases{$result_encoding};
2559         }
2560         print STDERR "# Using encoding $result_encoding\n" if ($T2H_VERBOSE);
2561         return $result_encoding;
2562    }
2563    else
2564    {
2565         if (exists($Texi2HTML::Config::t2h_encoding_aliases{$encoding}))
2566         {
2567             $encoding = $Texi2HTML::Config::t2h_encoding_aliases{$encoding};
2568             document_warn (__("Document encoding is utf8, but there is no unicode support")) if ($encoding eq 'utf-8');
2569             return $encoding;
2570         }
2571         msg_warn(sprintf(__("Encoding %s certainly poorly supported"), $encoding), $line_nr);
2572         return $encoding;
2573    }
2574}
2575
2576# libintl converts between encodings but doesn't decode them into the
2577# perl internal format.
2578sub encode_i18n_string($$)
2579{
2580   my $string = shift;
2581   my $encoding = shift;
2582   if ($encoding ne 'us-ascii' and $Texi2HTML::Config::USE_UNICODE
2583        and Encode::resolve_alias($encoding))
2584   {
2585      return Encode::decode($encoding, $string);
2586   }
2587   return $string;
2588}
2589
2590sub gdt($;$$)
2591{
2592    my $message = shift;
2593    my $context = shift;
2594    my $state = shift;
2595
2596    # FIXME this should be done only once, for @documentencoding
2597    my $encoding = lc(Texi2HTML::Config::get_conf('DOCUMENT_ENCODING'));
2598    if (defined($encoding) and $encoding ne '' and exists($Texi2HTML::Config::t2h_encoding_aliases{$encoding}))
2599    {
2600       $encoding = $Texi2HTML::Config::t2h_encoding_aliases{$encoding};
2601    }
2602    $encoding = 'us-ascii' if (!defined($encoding) or $encoding eq '');
2603
2604    return &$I($message, $context, $state) if ($Texi2HTML::Config::I18N_PERL_HASH);
2605    # if set, use substitute_text instead of substitute_line
2606    my $allow_paragraph = $state->{'allow_paragraph'};
2607    # if duplicate is passed, it means that we are in the text and so should
2608    # use the main state
2609    if (defined($state) and $state->{'duplicate'} and defined($Texi2HTML::THISDOC{'state'}))
2610    {
2611        $state = main::duplicate_formatting_state($Texi2HTML::THISDOC{'state'});
2612    }
2613
2614    my $result;
2615    # taken from libintl perl, copyright Guido. sub __expand. Overall not
2616    # enough code taken form Guido right now to be copyrightable.
2617    my $re = join '|', map { quotemeta $_ } keys %$context if (defined($context) and ref($context));
2618
2619    if (Texi2HTML::Config::get_conf('use_nls'))
2620    {
2621       my $saved_LANGUAGE = $ENV{'LANGUAGE'};
2622
2623       Locale::Messages::textdomain($strings_textdomain);
2624
2625
2626       Locale::Messages::bind_textdomain_codeset($strings_textdomain, $encoding) if ($encoding ne 'us-ascii');
2627       Locale::Messages::bind_textdomain_filter($strings_textdomain, \&encode_i18n_string, $encoding);
2628
2629       my $lang = Texi2HTML::Config::get_conf('documentlanguage');
2630       my @langs = ($lang);
2631       if ($lang =~ /^([a-z]+)_([A-Z]+)/)
2632       {
2633           my $main_lang = $1;
2634           my $region_code = $2;
2635           push @langs, $main_lang;
2636       }
2637
2638       my $locales = '';
2639       foreach my $language (@langs)
2640       {
2641           $locales .= "$language.$encoding:";
2642           #$locales .= "$language:";
2643           # always try us-ascii, the charset should always be a subset of
2644           # all charset, and should resort to @-commands if needed for non
2645           # ascii characters
2646           if ($encoding ne 'us-ascii')
2647           {
2648               $locales .= "$language.us-ascii:";
2649           }
2650       }
2651       $locales =~ s/:$//;
2652       #print STDERR "$locales\n";
2653       Locale::Messages::nl_putenv("LANGUAGE=$locales");
2654
2655       if (!defined($context) or ref($context))
2656       {
2657            $result = Locale::Messages::gettext($message);
2658       }
2659       else
2660       {
2661            $result = Locale::Messages::pgettext($context, $message);
2662       }
2663       Locale::Messages::textdomain($messages_textdomain);
2664       # old perl complains 'Use of uninitialized value in scalar assignment'
2665       if (!defined($saved_LANGUAGE))
2666       {
2667          delete ($ENV{'LANGUAGE'});
2668       }
2669       else
2670       {
2671          $ENV{'LANGUAGE'} = $saved_LANGUAGE;
2672       }
2673    }
2674
2675    # now perform the argument substitutions
2676    if ($state->{'keep_texi'})
2677    {
2678         # next line taken from libintl perl, copyright Guido. sub __expand
2679         $result =~ s/\{($re)\}/defined $context->{$1} ? $context->{$1} : "{$1}"/ge if (defined($re));
2680         return $result;
2681    }
2682    if (defined($re))
2683    {
2684         # next line taken from libintl perl, copyright Guido. sub __expand
2685         $result =~ s/\{($re)\}/\@internal_translation_open_brace\{\}$1\@internal_translation_close_brace\{\}/g;
2686         foreach my $map (\%Texi2HTML::Config::things_map, \%Texi2HTML::Config::pre_map,  \%Texi2HTML::Config::texi_map, \%Texi2HTML::Config::simple_format_texi_map)
2687         {
2688             $map->{'internal_translation_open_brace'} = '{';
2689             $map->{'internal_translation_close_brace'} = '}';
2690         }
2691    }
2692    if ($allow_paragraph)
2693    {
2694        delete $state->{'allow_paragraph'};
2695        $result = substitute_text ($state, undef, __("translation"), ($result));
2696    }
2697    else
2698    {
2699        $result = substitute_line ($result, __("translation"), $state);
2700    }
2701    if (defined($re))
2702    {
2703         $result =~ s/\{($re)\}/defined $context->{$1} ? $context->{$1} : "{$1}"/ge;
2704         foreach my $map (\%Texi2HTML::Config::things_map, \%Texi2HTML::Config::pre_map,  \%Texi2HTML::Config::texi_map, \%Texi2HTML::Config::simple_format_texi_map)
2705         {
2706               delete $map->{'internal_translation_open_brace'};
2707               delete $map->{'internal_translation_close_brace'};
2708         }
2709    }
2710    return $result;
2711}
2712
2713my %nodes;             # nodes hash. The key is the texi node name
2714my %cross_reference_nodes;  # normalized node names arrays
2715
2716#
2717# %value hold texinfo variables, see also -D, -U, @set and @clear.
2718# we predefine html (the output format) and texi2html (the translator)
2719# it is initialized with %value_initial at the beginning of the
2720# document parsing and filled and emptied as @set and @clear are
2721# encountered
2722my %value_initial =
2723      (
2724          'html' => 1,
2725          'texi2html' => $THISVERSION,
2726      );
2727
2728#
2729# _foo: internal variables to track @foo
2730#
2731foreach my $key ('_author', '_title', '_subtitle', '_shorttitlepage',
2732	 '_settitle', '_titlefont')
2733{
2734    $value_initial{$key} = '';            # prevent -w warnings
2735}
2736
2737
2738sub unicode_to_protected($)
2739{
2740    my $text = shift;
2741    my $result = '';
2742    while ($text ne '')
2743    {
2744        if ($text =~ s/^([A-Za-z0-9]+)//o)
2745        {
2746             $result .= $1;
2747        }
2748        elsif ($text =~ s/^ //o)
2749        {
2750             $result .= '-';
2751        }
2752        elsif ($text =~ s/^(.)//o)
2753        {
2754             my $char = $1;
2755             if (exists($Texi2HTML::Config::ascii_character_map{$char}))
2756             {
2757                 $result .= '_' . lc($Texi2HTML::Config::ascii_character_map{$char});
2758             }
2759             else
2760             {
2761                 if (ord($char) <= hex(0xFFFF))
2762                 {
2763                     $result .= '_' . lc(sprintf("%04x",ord($char)));
2764                 }
2765                 else
2766                 {
2767                     $result .= '__' . lc(sprintf("%06x",ord($char)));
2768                 }
2769             }
2770        }
2771        else
2772        {
2773             print STDERR "Bug: unknown character in a cross ref (likely in infinite loop)\n";
2774             print STDERR "Text: !!$text!!\n";
2775             sleep 1;
2776        }
2777    }
2778    return $result;
2779}
2780
2781sub unicode_to_transliterate($)
2782{
2783    my $text = shift;
2784    if (chomp($text))
2785    {
2786       print STDERR "Strange: end of line to transliterate: $text\n";
2787    }
2788    my $result = '';
2789    while ($text ne '')
2790    {
2791        if ($text =~ s/^([A-Za-z0-9 ]+)//o)
2792        {
2793             $result .= $1;
2794        }
2795        elsif ($text =~ s/^(.)//o)
2796        {
2797             my $char = $1;
2798             if (exists($Texi2HTML::Config::ascii_character_map{$char}))
2799             {
2800                 $result .= $char;
2801             }
2802             elsif (ord($char) <= hex(0xFFFF) and exists($Texi2HTML::Config::transliterate_map{uc(sprintf("%04x",ord($char)))}))
2803             {
2804                 $result .= $Texi2HTML::Config::transliterate_map{uc(sprintf("%04x",ord($char)))};
2805             }
2806             elsif (ord($char) <= hex(0xFFFF) and exists($Texi2HTML::Config::unicode_diacritical{uc(sprintf("%04x",ord($char)))}))
2807             {
2808                 $result .= '';
2809             }
2810             # in this case, we want to avoid calling unidecode, as we are sure
2811             # that there is no useful transliteration of the unicode character
2812             # instead we want to keep it as is.
2813             # This is the case, for example, for @exclamdown, is corresponds
2814             # with x00a1, but unidecode transliterates it to a !, we want
2815             # to avoid that and keep x00a1.
2816             elsif (ord($char) <= hex(0xFFFF) and exists($Texi2HTML::Config::no_transliterate_map{uc(sprintf("%04x",ord($char)))}))
2817             {
2818                 $result .= $char;
2819             }
2820             else
2821             {
2822                 if ($Texi2HTML::Config::USE_UNIDECODE)
2823                 {
2824                      $result .= unidecode($char);
2825                 }
2826                 else
2827                 {
2828                      $result .= $char;
2829                 }
2830             }
2831        }
2832        else
2833        {
2834             print STDERR "Bug: unknown character in cross ref transliteration (likely in infinite loop)\n";
2835             print STDERR "Text: !!$text!!\n";
2836             sleep 1;
2837        }
2838    }
2839    return $result;
2840}
2841
2842# used both for command line and @-command argument checking
2843sub set_paragraphindent($$;$$)
2844{
2845   my $value = shift;
2846   my $from_command_line = shift;
2847   my $line_nr = shift;
2848   my $pass = shift;
2849   my $command = 'paragraphindent';
2850
2851   if ($value =~ /^([0-9]+)$/ or $value eq 'none' or $value eq 'asis')
2852   {
2853       Texi2HTML::Config::set_conf($command, $value, !$from_command_line);
2854   }
2855   elsif ($from_command_line)
2856   {
2857       die sprintf(__("%s: --paragraph-indent arg must be numeric/`none'/`asis', not `%s'.\n"), $real_command_name, $value);
2858   }
2859   elsif ($pass == 1)
2860   {
2861       line_error (sprintf(__("\@paragraphindent arg must be numeric/`none'/`asis', not `%s'"), $value), $line_nr);
2862   }
2863}
2864
2865# T2H_OPTIONS is a hash whose keys are the (long) names of valid
2866# command-line options and whose values are a hash with the following keys:
2867# type    ==> one of !|=i|:i|=s|:s (see Getopt::Long for more info)
2868# linkage ==> ref to scalar, array, or subroutine (see Getopt::Long for more info)
2869# verbose ==> short description of option (displayed by -h)
2870# noHelp  ==> if 1 -> for "not so important options": only print description on -h 1
2871#                2 -> for obsolete options: only print description on -h 2
2872my $T2H_OPTIONS;
2873$T2H_OPTIONS -> {'debug'} =
2874{
2875 type => '=i',
2876 linkage => \$Texi2HTML::Config::DEBUG,
2877 verbose => 'output HTML with debuging information',
2878};
2879
2880$T2H_OPTIONS -> {'doctype'} =
2881{
2882 type => '=s',
2883 linkage => sub {Texi2HTML::Config::set_conf('doctype', $_[1]);},
2884 verbose => 'document type which is output in header of HTML files',
2885 noHelp => 1
2886};
2887
2888$T2H_OPTIONS -> {'frameset-doctype'} =
2889{
2890 type => '=s',
2891 linkage => \$Texi2HTML::Config::FRAMESET_DOCTYPE,
2892 verbose => 'document type for HTML frameset documents',
2893 noHelp => 1
2894};
2895
2896$T2H_OPTIONS -> {'test'} =
2897{
2898 type => '!',
2899 linkage => \$Texi2HTML::Config::TEST,
2900 verbose => 'use predefined information to avoid differences with reference files',
2901 noHelp => 1
2902};
2903
2904$T2H_OPTIONS -> {'dump-texi'} =
2905{
2906 type => '!',
2907 linkage => \$Texi2HTML::Config::DUMP_TEXI,
2908 verbose => 'dump the output of first pass into a file with extension passfirst and exit',
2909 noHelp => 1
2910};
2911
2912$T2H_OPTIONS -> {'macro-expand|E'} =
2913{
2914 type => '=s',
2915 linkage => \$Texi2HTML::Config::MACRO_EXPAND,
2916 verbose => 'output macro expanded source in <file>',
2917};
2918
2919$T2H_OPTIONS -> {'ifhtml'} =
2920{
2921 type => '!',
2922 linkage => sub { Texi2HTML::Config::set_expansion('html', $_[1]); },
2923 verbose => "expand ifhtml and html sections",
2924};
2925
2926$T2H_OPTIONS -> {'ifinfo'} =
2927{
2928 type => '!',
2929 linkage => sub { Texi2HTML::Config::set_expansion('info', $_[1]); },
2930 verbose => "expand ifinfo",
2931};
2932
2933$T2H_OPTIONS -> {'ifxml'} =
2934{
2935 type => '!',
2936 linkage => sub { Texi2HTML::Config::set_expansion('xml', $_[1]); },
2937 verbose => "expand ifxml and xml sections",
2938};
2939
2940$T2H_OPTIONS -> {'ifdocbook'} =
2941{
2942 type => '!',
2943 linkage => sub { Texi2HTML::Config::set_expansion('docbook', $_[1]); },
2944 verbose => "expand ifdocbook and docbook sections",
2945};
2946
2947$T2H_OPTIONS -> {'iftex'} =
2948{
2949 type => '!',
2950 linkage => sub { Texi2HTML::Config::set_expansion('tex', $_[1]); },
2951 verbose => "expand iftex and tex sections",
2952};
2953
2954$T2H_OPTIONS -> {'ifplaintext'} =
2955{
2956 type => '!',
2957 linkage => sub { Texi2HTML::Config::set_expansion('plaintext', $_[1]); },
2958 verbose => "expand ifplaintext sections",
2959};
2960
2961$T2H_OPTIONS -> {'iso'} =
2962{
2963 type => 'iso',
2964 linkage => sub {Texi2HTML::Config::t2h_default_set_iso_symbols ($_[1]);},
2965 verbose => 'if set, entities are used for special symbols (like copyright, etc...) and quotes',
2966 noHelp => 1,
2967};
2968
2969$T2H_OPTIONS -> {'I'} =
2970{
2971 type => '=s',
2972 linkage => \@Texi2HTML::Config::INCLUDE_DIRS,
2973 verbose => 'append $s to the @include search path',
2974};
2975
2976$T2H_OPTIONS -> {'conf-dir'} =
2977{
2978 type => '=s',
2979 linkage => \@Texi2HTML::Config::CONF_DIRS,
2980 verbose => 'append $s to the init file directories',
2981};
2982
2983$T2H_OPTIONS -> {'P'} =
2984{
2985 type => '=s',
2986 linkage => sub {unshift (@Texi2HTML::Config::PREPEND_DIRS, $_[1]);},
2987 verbose => 'prepend $s to the @include search path',
2988};
2989
2990$T2H_OPTIONS -> {'top-file'} =
2991{
2992 type => '=s',
2993 linkage => \$Texi2HTML::Config::TOP_FILE,
2994 verbose => 'use $s as top file, instead of <docname>.html',
2995};
2996
2997$T2H_OPTIONS -> {'toc-file'} =
2998{
2999 type => '=s',
3000 linkage => \$Texi2HTML::Config::TOC_FILE,
3001 verbose => 'use $s as ToC file, instead of <docname>_toc.html',
3002};
3003
3004$T2H_OPTIONS -> {'frames'} =
3005{
3006 type => '!',
3007 linkage => \$Texi2HTML::Config::FRAMES,
3008 verbose => 'output files which use HTML 4.0 frames (experimental)',
3009 noHelp => 1,
3010};
3011
3012$T2H_OPTIONS -> {'menu'} =
3013{
3014 type => '!',
3015 linkage => \$Texi2HTML::Config::SHOW_MENU,
3016 verbose => 'output Texinfo menus',
3017};
3018
3019$T2H_OPTIONS -> {'number-sections'} =
3020{
3021 type => '!',
3022 linkage => \$Texi2HTML::Config::NUMBER_SECTIONS,
3023 verbose => 'output chapter and sectioning numbers.',
3024};
3025
3026$T2H_OPTIONS -> {'number-footnotes'} =
3027{
3028 type => '!',
3029 linkage => \$Texi2HTML::Config::NUMBER_FOOTNOTES,
3030 verbose => 'output footnote numbers.',
3031};
3032
3033$T2H_OPTIONS -> {'use-nodes'} =
3034{
3035 type => '!',
3036 linkage => \$Texi2HTML::Config::USE_NODES,
3037 verbose => 'use nodes for sectioning',
3038};
3039
3040$T2H_OPTIONS -> {'node-files'} =
3041{
3042 type => '!',
3043 linkage => \$Texi2HTML::Config::NODE_FILES,
3044 verbose => 'produce one file per node for cross references'
3045};
3046
3047$T2H_OPTIONS -> {'footnote-style|s'} =
3048{
3049 type => '=s',
3050 linkage => sub {set_footnote_style ($_[1], 1);},
3051 verbose => 'output footnotes separate|end',
3052};
3053
3054$T2H_OPTIONS -> {'toc-links'} =
3055{
3056 type => '!',
3057 linkage => \$Texi2HTML::Config::TOC_LINKS,
3058 verbose => 'create links from headings to toc entries'
3059};
3060
3061$T2H_OPTIONS -> {'split'} =
3062{
3063 type => '=s',
3064 linkage => \$Texi2HTML::Config::SPLIT,
3065 verbose => 'split document on section|chapter|node else no splitting',
3066};
3067
3068$T2H_OPTIONS -> {'no-split'} =
3069{
3070 type => '!',
3071 linkage => sub {$Texi2HTML::Config::SPLIT = ''; $Texi2HTML::Config::SPLIT_SIZE = undef;},
3072 verbose => 'no splitting of document',
3073 noHelp => 1,
3074};
3075
3076$T2H_OPTIONS -> {'headers'} =
3077{
3078 type => '!',
3079 linkage => sub {
3080    Texi2HTML::Config::set_conf('headers', $_[1]);
3081    Texi2HTML::Config::t2h_default_load_format('plaintext', 1)
3082        if (!$_[1] and defined($Texi2HTML::Config::OUTPUT_FORMAT) and $Texi2HTML::Config::OUTPUT_FORMAT eq 'info');
3083 },
3084 verbose => 'output navigation headers for each section',
3085};
3086
3087$T2H_OPTIONS -> {'subdir'} =
3088{
3089 type => '=s',
3090 linkage => \$Texi2HTML::Config::SUBDIR,
3091 verbose => 'put files in directory $s, not $cwd',
3092 noHelp => 1,
3093};
3094
3095$T2H_OPTIONS -> {'short-ext'} =
3096{
3097 type => '!',
3098 linkage => \$Texi2HTML::Config::SHORTEXTN,
3099 verbose => 'use "htm" extension for output HTML files',
3100};
3101
3102$T2H_OPTIONS -> {'prefix'} =
3103{
3104 type => '=s',
3105 linkage => \$Texi2HTML::Config::PREFIX,
3106 verbose => 'use as prefix for output files, instead of <docname>',
3107};
3108
3109$T2H_OPTIONS -> {'output|out|o'} =
3110{
3111 type => '=s',
3112 linkage => \$Texi2HTML::Config::OUT,
3113 verbose => 'output goes to $s (directory if split)',
3114};
3115
3116$T2H_OPTIONS -> {'no-validate|no-pointer-validate'} =
3117{
3118 type => '',
3119 linkage => sub {Texi2HTML::Config::set_conf('novalidate',$_[1])},
3120 verbose => 'suppress node cross-reference validation',
3121};
3122
3123$T2H_OPTIONS -> {'no-warn'} =
3124{
3125 type => '',
3126 linkage => \$Texi2HTML::Config::NO_WARN,
3127 verbose => 'suppress warnings (but not errors).'
3128};
3129
3130$T2H_OPTIONS -> {'short-ref'} =
3131{
3132 type => '!',
3133 linkage => \$Texi2HTML::Config::SHORT_REF,
3134 verbose => 'if set, references are without section numbers',
3135};
3136
3137$T2H_OPTIONS -> {'idx-sum'} =
3138{
3139 type => '!',
3140 linkage => \$Texi2HTML::Config::IDX_SUMMARY,
3141 verbose => 'if set, also output index summary',
3142 noHelp  => 1,
3143};
3144
3145$T2H_OPTIONS -> {'def-table'} =
3146{
3147 type => '!',
3148 linkage => \$Texi2HTML::Config::DEF_TABLE,
3149 verbose => 'if set, \@def.. are converted using tables.',
3150 noHelp  => 1,
3151};
3152
3153$T2H_OPTIONS -> {'verbose'} = 0;
3154$T2H_OPTIONS -> {'verbose|v'} =
3155{
3156 type => '!',
3157 linkage=> \$Texi2HTML::Config::VERBOSE,
3158 verbose => 'print progress info to stdout',
3159};
3160
3161$T2H_OPTIONS -> {'document-language'} =
3162{
3163 type => '=s',
3164 linkage => sub {
3165        warn_unknown_language ($_[1]);
3166        Texi2HTML::Config::set_conf('documentlanguage', $_[1])
3167    },
3168 verbose => 'use $s as document language',
3169};
3170
3171$T2H_OPTIONS -> {'ignore-preamble-text'} =
3172{
3173  type => '!',
3174  linkage => \$Texi2HTML::Config::IGNORE_PREAMBLE_TEXT,
3175  verbose => 'if set, ignore the text before @node and sectioning commands',
3176  noHelp => 1,
3177};
3178
3179$T2H_OPTIONS -> {'html-xref-prefix'} =
3180{
3181 type => '=s',
3182 linkage => \$Texi2HTML::Config::EXTERNAL_DIR,
3183 verbose => '$s is the base dir for external manual references',
3184 noHelp => 1,
3185};
3186
3187$T2H_OPTIONS -> {'l2h'} =
3188{
3189 type => '!',
3190 linkage => \$Texi2HTML::Config::L2H,
3191 verbose => 'if set, uses latex2html for @math and @tex',
3192};
3193
3194$T2H_OPTIONS -> {'l2h-l2h'} =
3195{
3196 type => '=s',
3197 linkage => \$Texi2HTML::Config::L2H_L2H,
3198 verbose => 'program to use for latex2html translation',
3199 noHelp => 1,
3200};
3201
3202$T2H_OPTIONS -> {'l2h-skip'} =
3203{
3204 type => '!',
3205 linkage => \$Texi2HTML::Config::L2H_SKIP,
3206 verbose => 'if set, tries to reuse previously latex2html output',
3207 noHelp => 1,
3208};
3209
3210$T2H_OPTIONS -> {'l2h-tmp'} =
3211{
3212 type => '=s',
3213 linkage => \$Texi2HTML::Config::L2H_TMP,
3214 verbose => 'if set, uses $s as temporary latex2html directory',
3215 noHelp => 1,
3216};
3217
3218$T2H_OPTIONS -> {'l2h-file'} =
3219{
3220 type => '=s',
3221 linkage => \$Texi2HTML::Config::L2H_FILE,
3222 verbose => 'if set, uses $s as latex2html init file',
3223 noHelp => 1,
3224};
3225
3226
3227$T2H_OPTIONS -> {'l2h-clean'} =
3228{
3229 type => '!',
3230 linkage => \$Texi2HTML::Config::L2H_CLEAN,
3231 verbose => 'if set, do not keep intermediate latex2html files for later reuse',
3232 noHelp => 1,
3233};
3234
3235$T2H_OPTIONS -> {'D'} =
3236{
3237 type => '=s',
3238 linkage => sub {$value_initial{$_[1]} = 1;},
3239 verbose => 'equivalent to Texinfo "@set $s 1"',
3240 noHelp => 1,
3241};
3242
3243$T2H_OPTIONS -> {'U'} =
3244{
3245 type => '=s',
3246 linkage => sub {delete $value_initial{$_[1]};},
3247 verbose => 'equivalent to Texinfo "@clear $s"',
3248 noHelp => 1,
3249};
3250
3251$T2H_OPTIONS -> {'init-file'} =
3252{
3253 type => '=s',
3254 linkage => \&load_init_file,
3255 verbose => 'load init file $s'
3256};
3257
3258$T2H_OPTIONS -> {'css-include'} =
3259{
3260 type => '=s',
3261 linkage => \@Texi2HTML::Config::CSS_FILES,
3262 verbose => 'use css file $s'
3263};
3264
3265$T2H_OPTIONS -> {'css-ref'} =
3266{
3267 type => '=s',
3268 linkage => \@Texi2HTML::Config::CSS_REFS,
3269 verbose => 'generate reference to the CSS URL $s'
3270};
3271
3272$T2H_OPTIONS -> {'transliterate-file-names'} =
3273{
3274 type => '!',
3275 linkage=> \$Texi2HTML::Config::TRANSLITERATE_FILE_NAMES,
3276 verbose => 'produce file names in ASCII transliteration',
3277};
3278
3279$T2H_OPTIONS -> {'error-limit|e'} =
3280{
3281 type => '=i',
3282 linkage => \$Texi2HTML::Config::ERROR_LIMIT,
3283 verbose => 'quit after NUM errors (default 1000).',
3284};
3285
3286$T2H_OPTIONS -> {'split-size'} =
3287{
3288 type => '=s',
3289 linkage => \$Texi2HTML::Config::SPLIT_SIZE,
3290 verbose => 'split Info files at size s (default 300000).',
3291};
3292
3293$T2H_OPTIONS -> {'paragraph-indent|p'} =
3294{
3295 type => '=s',
3296 linkage => sub {set_paragraphindent($_[1], 1);},
3297 'verbose' => "indent Info paragraphs by VAL spaces (default 3).
3298                              If VAL is `none', do not indent; if VAL is
3299                                `asis', preserve existing indentation.",
3300};
3301
3302$T2H_OPTIONS -> {'fill-column|f'} =
3303{
3304 type => '=i',
3305 linkage => sub {Texi2HTML::Config::set_conf('fillcolumn',$_[1]);},
3306 'verbose' => "break Info lines at NUM characters (default 72).",
3307};
3308
3309$T2H_OPTIONS -> {'enable-encoding'} =
3310{
3311 type => '',
3312 linkage => \$Texi2HTML::Config::ENABLE_ENCODING,
3313 verbose => 'override --disable-encoding (default in Info).',
3314};
3315
3316$T2H_OPTIONS -> {'disable-encoding'} =
3317{
3318 type => '',
3319 linkage => sub {$Texi2HTML::Config::ENABLE_ENCODING = 0},
3320 verbose => 'do not output accented and special characters
3321                                in Info output based on @documentencoding.',
3322};
3323
3324$T2H_OPTIONS -> {'internal-links'} =
3325{
3326 type => '=s',
3327 linkage => \$Texi2HTML::Config::INTERNAL_LINKS,
3328 verbose => 'produce list of internal links in FILE.'
3329};
3330
3331$T2H_OPTIONS -> {'force|F'} =
3332{ type => '!',
3333 linkage => \$Texi2HTML::Config::FORCE,
3334 verbose => 'preserve output even if errors.'
3335};
3336
3337$T2H_OPTIONS -> {'monolithic'} =
3338{
3339 type => '!',
3340 linkage => \$Texi2HTML::Config::MONOLITHIC,
3341 verbose => 'output only one file including ToC, About...',
3342 noHelp => 1
3343};
3344
3345$T2H_OPTIONS -> {'commands-in-node-names'} =
3346{
3347 type => '!',
3348 verbose => 'Always set',
3349 noHelp => 1
3350};
3351
3352$T2H_OPTIONS -> {'output-indent'} =
3353{
3354 type => '=i',
3355 verbose => 'This option used to indent XML, it is ignored'
3356};
3357
3358$T2H_OPTIONS -> {'program'} =
3359{
3360 type => '=s',
3361 linkage => sub {set_config_init_dirs_output($_[1]);},
3362 'verbose' => 'Call as $s, setting corresponding defaults'
3363};
3364
3365#$T2H_OPTIONS -> {'command'} =
3366#{
3367# type => '=s',
3368# linkage => \@Texi2HTML::Config::COMMANDS,
3369# verbose => 'insert CMD in copy of input file'
3370#};
3371
3372
3373foreach my $output_format (keys(%Texi2HTML::Config::output_format_names))
3374{
3375  next if (defined($Texi2HTML::Config::DEFAULT_OUTPUT_FORMAT) and $output_format eq $Texi2HTML::Config::DEFAULT_OUTPUT_FORMAT);
3376  $T2H_OPTIONS -> {$output_format} =
3377  {
3378    type => '',
3379    linkage => sub {Texi2HTML::Config::t2h_default_load_format($_[0], 1);},
3380    verbose => "output $Texi2HTML::Config::output_format_names{$output_format} rather than $Texi2HTML::Config::output_format_names{$Texi2HTML::Config::DEFAULT_OUTPUT_FORMAT}.",
3381  }
3382}
3383
3384$T2H_OPTIONS -> {$Texi2HTML::Config::DEFAULT_OUTPUT_FORMAT} =
3385{
3386  type => '',
3387  linkage => sub {Texi2HTML::Config::t2h_default_load_format($_[0], 1);},
3388  verbose => "output default format.",
3389  noHelp => 2
3390};
3391
3392##
3393## obsolete cmd line options
3394##
3395my $T2H_OBSOLETE_OPTIONS;
3396
3397# actually a noop, since it is not used anywhere
3398$T2H_OBSOLETE_OPTIONS -> {'invisible'} =
3399{
3400 type => '=s',
3401 linkage => \$Texi2HTML::Config::INVISIBLE_MARK,
3402 verbose => 'use text in invisble anchor',
3403 noHelp  => 2,
3404};
3405
3406$T2H_OBSOLETE_OPTIONS -> {'expand'} =
3407{
3408 type => '=s',
3409 linkage => sub {Texi2HTML::Config::set_expansion($_[1], 1);},
3410 verbose => 'Expand <s> section of texinfo source',
3411 noHelp => 1,
3412};
3413
3414$T2H_OBSOLETE_OPTIONS -> {'no-expand'} =
3415{
3416 type => '=s',
3417 linkage => sub {Texi2HTML::Config::set_expansion ($_[1], 0);},
3418 verbose => 'Don\'t expand the given section of texinfo source',
3419};
3420
3421$T2H_OBSOLETE_OPTIONS -> {'noexpand'} =
3422{
3423 type => '=s',
3424 linkage => $T2H_OBSOLETE_OPTIONS->{'no-expand'}->{'linkage'},
3425 verbose => $T2H_OBSOLETE_OPTIONS->{'no-expand'}->{'verbose'},
3426 noHelp  => 1,
3427};
3428
3429$T2H_OBSOLETE_OPTIONS -> {'out-file'} =
3430{
3431 type => '=s',
3432 linkage => sub {$Texi2HTML::Config::OUT = $_[1]; $Texi2HTML::Config::SPLIT = '';},
3433 verbose => 'if set, all HTML output goes into file $s, obsoleted by "-output" with different semantics',
3434 noHelp => 2
3435};
3436
3437$T2H_OBSOLETE_OPTIONS -> {'lang'} =
3438{
3439 type => '=s',
3440 linkage => sub {Texi2HTML::Config::set_conf('documentlanguage', $_[1])},
3441 verbose => 'obsolete, use "--document-language" instead',
3442 noHelp => 2
3443};
3444
3445$T2H_OBSOLETE_OPTIONS -> {'separated-footnotes'} =
3446{
3447 type => '!',
3448 linkage => sub {my $style = 'separate'; $style = 'end' if !$_[1]; set_footnote_style ($style, 1);},
3449 verbose => 'obsolete, use "--footnote-style" instead',
3450 noHelp => 2
3451};
3452
3453$T2H_OBSOLETE_OPTIONS -> {'Verbose'} =
3454{
3455 type => '!',
3456 linkage=> \$Texi2HTML::Config::VERBOSE,
3457 verbose => 'obsolete, use "--verbose" instead',
3458 noHelp => 2
3459};
3460
3461
3462$T2H_OBSOLETE_OPTIONS -> {init_file} =
3463{
3464 type => '=s',
3465 linkage => \&load_init_file,
3466 verbose => 'obsolete, use "-init-file" instead',
3467 noHelp => 2
3468};
3469
3470$T2H_OBSOLETE_OPTIONS -> {l2h_clean} =
3471{
3472 type => '!',
3473 linkage => \$Texi2HTML::Config::L2H_CLEAN,
3474 verbose => 'obsolete, use "-l2h-clean" instead',
3475 noHelp => 2,
3476};
3477
3478$T2H_OBSOLETE_OPTIONS -> {l2h_l2h} =
3479{
3480 type => '=s',
3481 linkage => \$Texi2HTML::Config::L2H_L2H,
3482 verbose => 'obsolete, use "-l2h-l2h" instead',
3483 noHelp => 2
3484};
3485
3486$T2H_OBSOLETE_OPTIONS -> {l2h_skip} =
3487{
3488 type => '!',
3489 linkage => \$Texi2HTML::Config::L2H_SKIP,
3490 verbose => 'obsolete, use "-l2h-skip" instead',
3491 noHelp => 2
3492};
3493
3494$T2H_OBSOLETE_OPTIONS -> {l2h_tmp} =
3495{
3496 type => '=s',
3497 linkage => \$Texi2HTML::Config::L2H_TMP,
3498 verbose => 'obsolete, use "-l2h-tmp" instead',
3499 noHelp => 2
3500};
3501
3502$T2H_OBSOLETE_OPTIONS -> {out_file} =
3503{
3504 type => '=s',
3505 linkage => sub {$Texi2HTML::Config::OUT = $_[1]; $Texi2HTML::Config::SPLIT = '';},
3506 verbose => 'obsolete, use "-out-file" instead',
3507 noHelp => 2
3508};
3509
3510$T2H_OBSOLETE_OPTIONS -> {short_ref} =
3511{
3512 type => '!',
3513 linkage => \$Texi2HTML::Config::SHORT_REF,
3514 verbose => 'obsolete, use "-short-ref" instead',
3515 noHelp => 2
3516};
3517
3518$T2H_OBSOLETE_OPTIONS -> {idx_sum} =
3519{
3520 type => '!',
3521 linkage => \$Texi2HTML::Config::IDX_SUMMARY,
3522 verbose => 'obsolete, use "-idx-sum" instead',
3523 noHelp  => 2
3524};
3525
3526$T2H_OBSOLETE_OPTIONS -> {def_table} =
3527{
3528 type => '!',
3529 linkage => \$Texi2HTML::Config::DEF_TABLE,
3530 verbose => 'obsolete, use "-def-table" instead',
3531 noHelp  => 2
3532};
3533
3534$T2H_OBSOLETE_OPTIONS -> {short_ext} =
3535{
3536 type => '!',
3537 linkage => \$Texi2HTML::Config::SHORTEXTN,
3538 verbose => 'obsolete, use "-short-ext" instead',
3539 noHelp  => 2
3540};
3541
3542$T2H_OBSOLETE_OPTIONS -> {sec_nav} =
3543{
3544 type => '!',
3545 linkage => sub {Texi2HTML::Config::set_conf('headers', $_[1]);},
3546 verbose => 'obsolete, use "-headers" instead',
3547 noHelp  => 2
3548};
3549
3550$T2H_OBSOLETE_OPTIONS -> {'sec-nav'} =
3551{
3552 type => '!',
3553 linkage => sub {Texi2HTML::Config::set_conf('headers', $_[1]);},
3554 verbose => 'obsolete, use "--header" instead',
3555 noHelp  => 2
3556};
3557
3558$T2H_OBSOLETE_OPTIONS -> {top_file} =
3559{
3560 type => '=s',
3561 linkage => \$Texi2HTML::Config::TOP_FILE,
3562 verbose => 'obsolete, use "-top-file" instead',
3563 noHelp  => 2
3564};
3565
3566$T2H_OBSOLETE_OPTIONS -> {toc_file} =
3567{
3568 type => '=s',
3569 linkage => \$Texi2HTML::Config::TOC_FILE,
3570 verbose => 'obsolete, use "-toc-file" instead',
3571 noHelp  => 2
3572};
3573
3574$T2H_OBSOLETE_OPTIONS -> {glossary} =
3575{
3576 type => '!',
3577 linkage => \$Texi2HTML::Config::USE_GLOSSARY,
3578 verbose => "this does nothing",
3579 noHelp  => 2,
3580};
3581
3582$T2H_OBSOLETE_OPTIONS -> {check} =
3583{
3584 type => '!',
3585 linkage => sub {exit 0;},
3586 verbose => "exit without doing anything",
3587 noHelp  => 2,
3588};
3589
3590$T2H_OBSOLETE_OPTIONS -> {dump_texi} =
3591{
3592 type => '!',
3593 linkage => \$Texi2HTML::Config::DUMP_TEXI,
3594 verbose => 'obsolete, use "-dump-texi" instead',
3595 noHelp => 1
3596};
3597
3598$T2H_OBSOLETE_OPTIONS -> {frameset_doctype} =
3599{
3600 type => '=s',
3601 linkage => \$Texi2HTML::Config::FRAMESET_DOCTYPE,
3602 verbose => 'obsolete, use "-frameset-doctype" instead',
3603 noHelp => 2
3604};
3605
3606$T2H_OBSOLETE_OPTIONS -> {'no-section_navigation'} =
3607{
3608 type => '!',
3609 linkage => sub {Texi2HTML::Config::set_conf('headers', 0);},
3610 verbose => 'obsolete, use -nosec_nav',
3611 noHelp => 2,
3612};
3613my $use_acc; # not used
3614$T2H_OBSOLETE_OPTIONS -> {use_acc} =
3615{
3616 type => '!',
3617 linkage => \$use_acc,
3618 verbose => 'obsolete, set to true unconditionnaly',
3619 noHelp => 2
3620};
3621$T2H_OBSOLETE_OPTIONS -> {expandinfo} =
3622{
3623 type => '!',
3624 linkage => sub {push @Texi2HTML::Config::EXPAND, 'info';},
3625 verbose => 'obsolete, use "--ifinfo" instead',
3626 noHelp => 2,
3627};
3628$T2H_OBSOLETE_OPTIONS -> {expandtex} =
3629{
3630 type => '!',
3631 linkage => sub {push @Texi2HTML::Config::EXPAND, 'tex';},
3632 verbose => 'obsolete, use "--iftex" instead',
3633 noHelp => 2,
3634};
3635$T2H_OBSOLETE_OPTIONS -> {split_node} =
3636{
3637 type => '!',
3638 linkage => sub{$Texi2HTML::Config::SPLIT = 'section';},
3639 verbose => 'obsolete, use "-split section" instead',
3640 noHelp => 2,
3641};
3642$T2H_OBSOLETE_OPTIONS -> {split_chapter} =
3643{
3644 type => '!',
3645 linkage => sub{$Texi2HTML::Config::SPLIT = 'chapter';},
3646 verbose => 'obsolete, use "-split chapter" instead',
3647 noHelp => 2,
3648};
3649$T2H_OBSOLETE_OPTIONS -> {no_verbose} =
3650{
3651 type => '!',
3652 linkage => sub {$Texi2HTML::Config::VERBOSE = 0;},
3653 verbose => 'obsolete, use -noverbose instead',
3654 noHelp => 2,
3655};
3656$T2H_OBSOLETE_OPTIONS -> {output_file} =
3657{
3658 type => '=s',
3659 linkage => sub {$Texi2HTML::Config::OUT = $_[1]; $Texi2HTML::Config::SPLIT = '';},
3660 verbose => 'obsolete, use --out-file instead',
3661 noHelp => 2
3662};
3663
3664$T2H_OBSOLETE_OPTIONS -> {section_navigation} =
3665{
3666 type => '!',
3667 linkage => sub {Texi2HTML::Config::set_conf('headers', $_[1]);},
3668 verbose => 'obsolete, use --sec-nav instead',
3669 noHelp => 2,
3670};
3671
3672# read initialzation from $sysconfdir/texi2htmlrc or $HOME/.texi2htmlrc
3673# (this is obsolete). Obsoleted in 1.68 (March 20 2004).
3674my @rc_files = ();
3675push @rc_files, "$sysconfdir/texi2htmlrc" if defined($sysconfdir);
3676push @rc_files, "$ENV{'HOME'}/.texi2htmlrc" if (defined($ENV{'HOME'}));
3677foreach my $i (@rc_files)
3678{
3679    if (-e $i and -r $i)
3680    {
3681        print STDERR "# reading initialization file from $i\n"
3682	    if ($T2H_VERBOSE);
3683        print STDERR "Reading config from $i is obsolete, use texi2html/$conf_file_name instead\n";
3684        Texi2HTML::Config::load($i);
3685    }
3686}
3687
3688# read initialization files
3689foreach my $file (locate_init_file($conf_file_name, 1))
3690{
3691    print STDERR "# reading initialization file from $file\n" if ($T2H_VERBOSE);
3692    Texi2HTML::Config::load($file);
3693}
3694
3695
3696#+++############################################################################
3697#                                                                              #
3698# parse command-line options
3699#                                                                              #
3700#---############################################################################
3701
3702# options known by makeinfo (+version, help and if*)
3703my @makeinfo_options = ('error-limit', 'document-language',
3704'force', 'help', 'no-validate', 'no-warn', 'verbose', 'docbook', 'html',
3705'xml', 'plaintext', 'macro-expand', 'headers', 'no-split',
3706'number-sections', 'output', 'disable-encoding', 'enable-encoding',
3707'fill-column', 'footnote-style', 'paragraph-indent', 'split-size',
3708'css-include', 'css-ref', 'internal-links', 'transliterate-file-names',
3709'output-indent', 'number-footnotes', 'D', 'I', 'P', 'U');
3710
3711# always used, even though they are not in makeinfo in C.
3712# dump-texi', 'debug', 'test' are for debugging.
3713# split is in makeinfo in C, as --no-split.
3714# 'conf-dir', 'init-file' options have to be taken into account for proper
3715# functionning.
3716my @basic_options = ('dump-texi', 'debug', 'test', 'conf-dir', 'init-file',
3717'split', 'program');
3718
3719#      --command=CMD           insert CMD in copy of input file
3720my $makeinfo_help =
3721sprintf(__("Usage: %s [OPTION]... TEXINFO-FILE...\n"), $real_command_name)
3722."\n".
3723__("Translate Texinfo source documentation to various other formats, by default
3724Info files suitable for reading online with Emacs or standalone GNU Info.\n")
3725."\n";
3726$makeinfo_help .= sprintf(__("General options:
3727      --error-limit=NUM       quit after NUM errors (default %d).
3728      --document-language=STR locale to use in translating Texinfo keywords
3729                                for the output document (default C).
3730      --force                 preserve output even if errors.
3731      --help                  display this help and exit.
3732      --no-validate           suppress node cross-reference validation.
3733      --no-warn               suppress warnings (but not errors).
3734  -v, --verbose               explain what is being done.
3735      --version               display version information and exit.\n"), $Texi2HTML::Config::ERROR_LIMIT)
3736."\n";
3737$makeinfo_help .= __("Output format selection (default is to produce Info):
3738      --docbook               output Docbook XML rather than Info.
3739      --html                  output HTML rather than Info.
3740      --xml                   output Texinfo XML rather than Info.
3741      --plaintext             output plain text rather than Info.\n")
3742."\n";
3743$makeinfo_help .= __("General output options:
3744  -E, --macro-expand=FILE     output macro-expanded source to FILE,
3745                                ignoring any \@setfilename.
3746      --no-headers            suppress node separators, Node: lines, and menus
3747                                from Info output (thus producing plain text)
3748                                or from HTML (thus producing shorter output);
3749                                also, write to standard output by default.
3750      --no-split              suppress the splitting of Info or HTML output,
3751                                generate only one output file.
3752      --number-sections       output chapter and sectioning numbers.
3753  -o, --output=FILE           output to FILE (or directory if split HTML).\n")
3754."\n";
3755$makeinfo_help .= sprintf(__("Options for Info and plain text:
3756      --disable-encoding      do not output accented and special characters
3757                                in Info output based on \@documentencoding.
3758      --enable-encoding       override --disable-encoding (default).
3759      --fill-column=NUM       break Info lines at NUM characters (default %d).
3760      --footnote-style=STYLE  output footnotes in Info according to STYLE:
3761                                `separate' to put them in their own node;
3762                                `end' to put them at the end of the node, in
3763                                which they are defined (this is the default).
3764      --paragraph-indent=VAL  indent Info paragraphs by VAL spaces (default %d).
3765                                If VAL is `none', do not indent; if VAL is
3766                                `asis', preserve existing indentation.
3767      --split-size=NUM        split Info files at size NUM (default %d).\n"),
3768  $Texi2HTML::Config::FILLCOLUMN, $Texi2HTML::Config::PARAGRAPHINDENT, $Texi2HTML::Config::SPLIT_SIZE)
3769."\n";
3770$makeinfo_help .= __("Options for HTML:
3771      --css-include=FILE      include FILE in HTML <style> output;
3772                                read stdin if FILE is -.
3773      --css-ref=URL           generate reference to a CSS file.
3774      --internal-links=FILE   produce list of internal links in FILE.
3775      --transliterate-file-names
3776                              produce file names in ASCII transliteration.\n")
3777."\n";
3778# This is ignored, so remove it from help
3779#Options for XML and Docbook:
3780#      --output-indent=VAL     indent XML elements by VAL spaces (default 2).
3781#                                If VAL is 0, ignorable whitespace is dropped.
3782#
3783$makeinfo_help .= __("Input file options:
3784      --commands-in-node-names  allow \@ commands in node names.
3785  -D VAR                        define the variable VAR, as with \@set.
3786  -I DIR                        append DIR to the \@include search path.
3787  -P DIR                        prepend DIR to the \@include search path.
3788  -U VAR                        undefine the variable VAR, as with \@clear.\n")
3789."\n";
3790$makeinfo_help .= __("Conditional processing in input:
3791  --ifdocbook       process \@ifdocbook and \@docbook even if
3792                      not generating Docbook.
3793  --ifhtml          process \@ifhtml and \@html even if not generating HTML.
3794  --ifinfo          process \@ifinfo even if not generating Info.
3795  --ifplaintext     process \@ifplaintext even if not generating plain text.
3796  --iftex           process \@iftex and \@tex; implies --no-split.
3797  --ifxml           process \@ifxml and \@xml.
3798  --no-ifdocbook    do not process \@ifdocbook and \@docbook text.
3799  --no-ifhtml       do not process \@ifhtml and \@html text.
3800  --no-ifinfo       do not process \@ifinfo text.
3801  --no-ifplaintext  do not process \@ifplaintext text.
3802  --no-iftex        do not process \@iftex and \@tex text.
3803  --no-ifxml        do not process \@ifxml and \@xml text.
3804
3805  Also, for the --no-ifFORMAT options, do process \@ifnotFORMAT text.\n")
3806."\n";
3807$makeinfo_help .= __("  The defaults for the \@if... conditionals depend on the output format:
3808  if generating HTML, --ifhtml is on and the others are off;
3809  if generating Info, --ifinfo is on and the others are off;
3810  if generating plain text, --ifplaintext is on and the others are off;
3811  if generating XML, --ifxml is on and the others are off.\n")
3812."\n";
3813$makeinfo_help .= __("Examples:
3814  makeinfo foo.texi                      write Info to foo's \@setfilename
3815  makeinfo --html foo.texi               write HTML to \@setfilename
3816  makeinfo --xml foo.texi                write Texinfo XML to \@setfilename
3817  makeinfo --docbook foo.texi            write DocBook XML to \@setfilename
3818  makeinfo --no-headers foo.texi         write plain text to standard output
3819
3820  makeinfo --html --no-headers foo.texi  write html without node lines, menus
3821  makeinfo --number-sections foo.texi    write Info with numbered sections
3822  makeinfo --no-split foo.texi           write one Info file however big\n")
3823."\n";
3824$makeinfo_help .= __("Email bug reports to bug-texinfo\@gnu.org,
3825general questions and discussion to help-texinfo\@gnu.org.
3826Texinfo home page: http://www.gnu.org/software/texinfo/") ."\n";
3827
3828# parsing like texi2html:
3829
3830
3831my $T2H_USAGE_TEXT = <<EOT;
3832Usage: texi2html  [OPTIONS] TEXINFO-FILE
3833Translates Texinfo source documentation to HTML.
3834EOT
3835
3836
3837my $options = new Getopt::MySimple;
3838
3839$T2H_OPTIONS -> {'help'} = 0;
3840$T2H_OPTIONS -> {'help|h'} =
3841{
3842 type => ':i',
3843 default => '',
3844 linkage => sub {$options->helpOptions($_[1]);
3845    print "\nSend bugs and suggestions to <texi2html-bug\@nongnu.org>\n";
3846    exit (0);},
3847 verbose => "print help and exit"
3848};
3849
3850# this avoids getOptions defining twice 'help' and 'version'.
3851$T2H_OBSOLETE_OPTIONS->{'help'} = 0;
3852$T2H_OBSOLETE_OPTIONS->{'version'} = 0;
3853$T2H_OBSOLETE_OPTIONS->{'verbose'} = 0;
3854
3855
3856if ($real_command_name eq 'texi2html')
3857{
3858  # some older version of GetOpt::Long don't have
3859  # Getopt::Long::Configure("pass_through")
3860  eval {Getopt::Long::Configure("pass_through");};
3861  my $Configure_failed = $@ && <<EOT;
3862**WARNING: Parsing of obsolete command-line options could have failed.
3863           Consider to use only documented command-line options (run
3864           'texi2html --help 2' for a complete list) or upgrade to perl
3865           version 5.005 or higher.
3866EOT
3867  if (! $options->getOptions($T2H_OPTIONS, $T2H_USAGE_TEXT, "$THISVERSION\n"))
3868  {
3869     print STDERR "$Configure_failed" if $Configure_failed;
3870     die $T2H_FAILURE_TEXT;
3871  }
3872  if (@ARGV > 1)
3873  {
3874     eval {Getopt::Long::Configure("no_pass_through");};
3875     if (! $options->getOptions($T2H_OBSOLETE_OPTIONS, $T2H_USAGE_TEXT, "$THISVERSION\n"))
3876     {
3877        print STDERR "$Configure_failed" if $Configure_failed;
3878        die $T2H_FAILURE_TEXT;
3879      }
3880  }
3881}
3882else
3883{
3884   # changes how command lines are parsed, for example -init file.init
3885   # doesn't work anymore.
3886   Getopt::Long::Configure("gnu_getopt");
3887   my $opts;
3888   my @types;
3889   foreach my $key (keys(%$T2H_OPTIONS))
3890   {
3891      next unless ($T2H_OPTIONS->{$key});
3892      my $primary = $key;
3893      $primary =~ s/\|.*//;
3894      next if ($primary eq 'version' or $primary eq 'help');
3895      next if ($real_command_name eq 'makeinfo' and ! grep {$primary eq $_} (@makeinfo_options, @basic_options) and $primary !~ /^if/);
3896      $opts->{$primary} = $T2H_OPTIONS->{$key}->{'linkage'} if defined($T2H_OPTIONS->{$key}->{'linkage'});
3897      push @types, "$key$T2H_OPTIONS->{$key}->{'type'}";
3898   }
3899   $opts->{'version'} = sub {
3900      print "$real_command_name (GNU texinfo) $THISVERSION\n\n";
3901
3902      printf __("Copyright (C) %s Free Software Foundation, Inc.
3903License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
3904This is free software: you are free to change and redistribute it.
3905There is NO WARRANTY, to the extent permitted by law.\n"), '2008';
3906      exit 0;
3907   };
3908   $opts->{'help'} = sub {
3909      print "$makeinfo_help";
3910      exit 0;
3911   };
3912   push @types, ('version|V', 'help|h');
3913   #foreach my $key (sort(keys(%$opts)))
3914   #{
3915   #   #print STDERR "$key, $opts->{$key}\n";
3916   #   print "$key\n";
3917   #}
3918   #print STDERR "@types\n";
3919   my $result_options = Getopt::Long::GetOptions ($opts, @types);
3920}
3921
3922if (! $Texi2HTML::THISDOC{'format_from_command_line'} and defined($ENV{'TEXINFO_OUTPUT_FORMAT'}) and $ENV{'TEXINFO_OUTPUT_FORMAT'} ne '')
3923{
3924  if (! Texi2HTML::Config::t2h_default_load_format($ENV{'TEXINFO_OUTPUT_FORMAT'}, 0))
3925  {
3926      warn sprintf(__("%s: Ignoring unrecognized TEXINFO_OUTPUT_FORMAT value `%s'.\n"), $real_command_name, $ENV{'TEXINFO_OUTPUT_FORMAT'});
3927  }
3928}
3929
3930# $T2H_DEBUG and $T2H_VERBOSE are shorthands
3931$T2H_DEBUG = $Texi2HTML::Config::DEBUG;
3932$T2H_VERBOSE = $Texi2HTML::Config::VERBOSE;
3933
3934#
3935# read texi2html extensions (if any)
3936# It is obsolete (obsoleted by -init-file). we keep it for backward
3937# compatibility.
3938my $extensions = 'texi2html.ext';  # extensions in working directory
3939if (-f $extensions)
3940{
3941    print STDERR "# reading extensions from $extensions\n" if $T2H_VERBOSE;
3942    require($extensions);
3943}
3944my $progdir;
3945($progdir = $0) =~ s/[^\/]+$//;
3946if ($progdir && ($progdir ne './'))
3947{
3948    $extensions = "${progdir}texi2html.ext"; # extensions in texi2html directory
3949    if (-f $extensions)
3950    {
3951	print STDERR "# reading extensions from $extensions\n" if $T2H_VERBOSE;
3952	require($extensions);
3953    }
3954}
3955
3956
3957#+++############################################################################
3958#                                                                              #
3959# evaluation of cmd line options
3960#                                                                              #
3961#---############################################################################
3962
3963# set the default 'args' entry to normal for each style hash (and each command
3964# within)
3965my $name_index = -1;
3966my @hash_names = ('style_map', 'style_map_pre', 'style_map_texi', 'simple_format_style_map_texi');
3967foreach my $hash (\%Texi2HTML::Config::style_map, \%Texi2HTML::Config::style_map_pre, \%Texi2HTML::Config::style_map_texi, \%Texi2HTML::Config::simple_format_style_map_texi)
3968{
3969    $name_index++;
3970    my $name = $hash_names[$name_index]; # name associated with hash ref
3971    foreach my $style (keys(%{$hash}))
3972    {
3973        next unless (ref($hash->{$style}) eq 'HASH');
3974        $hash->{$style}->{'args'} = ['normal'] if (!exists($hash->{$style}->{'args'}));
3975        die "Bug: args not defined, but existing, for $style in $name" if (!defined($hash->{$style}->{'args'}));
3976#print STDERR "DEFAULT($name, $hash) add normal as arg for $style ($hash->{$style}), $hash->{$style}->{'args'}\n";
3977    }
3978}
3979
3980# setup hashes used for html manual cross references in texinfo
3981my %cross_ref_texi_map = %Texi2HTML::Config::default_texi_map;
3982my %cross_transliterate_texi_map = %cross_ref_texi_map;
3983
3984my %cross_ref_simple_map_texi = %Texi2HTML::Config::default_simple_map;
3985$cross_ref_simple_map_texi{"*"} = ' ';
3986
3987my %cross_ref_style_map_texi = ();
3988my %cross_transliterate_style_map_texi = ();
3989Texi2HTML::Config::t2h_default_copy_style_map(\%Texi2HTML::Config::default_style_map_texi, \%cross_ref_style_map_texi);
3990Texi2HTML::Config::t2h_default_copy_style_map(\%Texi2HTML::Config::default_style_map_texi, \%cross_transliterate_style_map_texi);
3991
3992
3993
3994# Fill in the %style_type hash, a hash associating style @-comand with
3995# the type, 'accent', real 'style', 'simple_style', or 'special'.
3996# 'simple_style' styles don't extend accross lines.
3997my %style_type = ();
3998my @simple_styles = ('ctrl', 'w', 'url','uref','indicateurl','email',
3999    'titlefont');
4000foreach my $style (keys(%Texi2HTML::Config::style_map))
4001{
4002    if (exists $Texi2HTML::Config::command_type{$style})
4003    {
4004        $style_type{$style} = $Texi2HTML::Config::command_type{$style};
4005        next;
4006    }
4007    if (ref($Texi2HTML::Config::style_map{$style} eq 'HASH'))
4008    {
4009        $style_type{$style} = $Texi2HTML::Config::style_map{$style}->{'type'}
4010          if (exists($Texi2HTML::Config::style_map{$style}->{'type'}));
4011    }
4012    else
4013    {
4014        $style_type{$style} = 'simple_style' if (grep {$_ eq $style} @simple_styles);
4015    }
4016    $style_type{$style} = 'style' unless (defined($style_type{$style}));
4017}
4018
4019foreach my $accent (keys(%Texi2HTML::Config::unicode_accents), 'tieaccent', 'dotless')
4020{
4021    if (exists $Texi2HTML::Config::command_type{$accent})
4022    {
4023        $style_type{$accent} = $Texi2HTML::Config::command_type{$accent};
4024        next;
4025    }
4026    $style_type{$accent} = 'accent';
4027}
4028
4029
4030
4031
4032foreach my $special ('footnote', 'ref', 'xref', 'pxref', 'inforef', 'anchor', 'image', 'hyphenation')
4033{
4034    if (exists $Texi2HTML::Config::command_type{$special})
4035    {
4036        $style_type{$special} = $Texi2HTML::Config::command_type{$special};
4037        next;
4038    }
4039    $style_type{$special} = 'special';
4040}
4041
4042# retro compatibility for $Texi2HTML::Config::EXPAND
4043push (@Texi2HTML::Config::EXPAND, $Texi2HTML::Config::EXPAND) if ($Texi2HTML::Config::EXPAND);
4044
4045push (@Texi2HTML::Config::EXPAND, @Texi2HTML::Config::T2H_FORMAT_EXPAND);
4046
4047# correct %Texi2HTML::Config::texi_formats_map based on command line and init
4048# variables
4049$Texi2HTML::Config::texi_formats_map{'menu'} = 'normal' if ($Texi2HTML::Config::SHOW_MENU);
4050
4051foreach my $expanded (@Texi2HTML::Config::EXPAND)
4052{
4053    $Texi2HTML::Config::texi_formats_map{"if$expanded"} = 1 if (exists($Texi2HTML::Config::texi_formats_map{"if$expanded"}));
4054    next unless (exists($Texi2HTML::Config::texi_formats_map{$expanded}));
4055    if (grep {$_ eq $expanded} @raw_regions)
4056    {
4057         $Texi2HTML::Config::texi_formats_map{$expanded} = 'raw';
4058    }
4059    else
4060    {
4061         $Texi2HTML::Config::texi_formats_map{$expanded} = 'normal';
4062    }
4063}
4064
4065# don't set set_no_line_macro for raw EXPAND formats
4066foreach my $key (keys(%Texi2HTML::Config::texi_formats_map))
4067{
4068    unless ($Texi2HTML::Config::texi_formats_map{$key} eq 'raw')
4069    {
4070        set_no_line_macro($key, 1);
4071        set_no_line_macro("end $key", 1);
4072    }
4073}
4074
4075# the remaining (not in @EXPAND) raw formats are set as 'raw' such that
4076# they are propagated to formatting functions, but
4077# they don't start paragraphs or preformatted.
4078foreach my $raw (@raw_regions)
4079{
4080    if (!defined($Texi2HTML::Config::texi_formats_map{$raw}))
4081    {
4082        $Texi2HTML::Config::texi_formats_map{$raw} = 'raw';
4083        $Texi2HTML::Config::format_in_paragraph{$raw} = 1;
4084        set_no_line_macro($raw, 1);
4085        set_no_line_macro("end $raw", 1);
4086    }
4087}
4088
4089# handle ifnot regions
4090foreach my $region (keys (%Texi2HTML::Config::texi_formats_map))
4091{
4092    next if ($region =~ /^ifnot/);
4093    if ($Texi2HTML::Config::texi_formats_map{$region} and $region =~ /^if(\w+)$/)
4094    {
4095        $Texi2HTML::Config::texi_formats_map{"ifnot$1"} = 0;
4096    }
4097}
4098
4099if ($T2H_VERBOSE)
4100{
4101    print STDERR "# Expanded: ";
4102    foreach my $text_macro (keys(%Texi2HTML::Config::texi_formats_map))
4103    {
4104        print STDERR "$text_macro " if ($Texi2HTML::Config::texi_formats_map{$text_macro});
4105    }
4106    print STDERR "\n";
4107}
4108
4109# This is kept in that file although it is html formatting as it seems to
4110# be rather obsolete
4111$Texi2HTML::Config::INVISIBLE_MARK = '<img src="invisible.xbm" alt="">' if $Texi2HTML::Config::INVISIBLE_MARK eq 'xbm';
4112
4113$T2H_DEBUG |= $DEBUG_TEXI if ($Texi2HTML::Config::DUMP_TEXI);
4114
4115# no user provided USE_UNICODE, use configure provided
4116if (!defined($Texi2HTML::Config::USE_UNICODE))
4117{
4118    $Texi2HTML::Config::USE_UNICODE = '@USE_UNICODE@';
4119}
4120
4121# no user provided nor configured, run time test
4122if ($Texi2HTML::Config::USE_UNICODE eq 'unknown' or $Texi2HTML::Config::USE_UNICODE eq '@' .'USE_UNICODE@')
4123{
4124    eval {
4125        require Encode;
4126        require Unicode::Normalize;
4127        Encode->import('encode');
4128    };
4129    if ($@)
4130    {
4131        $Texi2HTML::Config::USE_UNICODE = 0
4132    }
4133    else
4134    {
4135        $Texi2HTML::Config::USE_UNICODE = 1;
4136    }
4137}
4138
4139if ($Texi2HTML::Config::USE_UNICODE)
4140{
4141    require Encode;
4142    require Unicode::Normalize;
4143    Encode->import('encode');
4144
4145    # use EastAsianWidth if USE_UNICODE is set
4146    if ($0 =~ /\.pl$/)
4147    { # use in-source EastAsianWidth when testing
4148        unshift @INC, "$T2H_HOME/lib/Unicode-EastAsianWidth/lib";
4149    }
4150    elsif ($ENV{T2H_SOURCE_EASTASIANWIDTH})
4151    {
4152        unshift @INC, $ENV{T2H_SOURCE_EASTASIANWIDTH};
4153    }
4154    elsif ('@USE_EXTERNAL_EASTASIANWIDTH@' ne 'yes')
4155    {
4156        unshift @INC, "$pkgdatadir/lib/Unicode-EastAsianWidth/lib";
4157    }
4158    else
4159    {
4160        eval {
4161            require Unicode::EastAsianWidth;
4162        };
4163        if ($@)
4164        {
4165            unshift @INC, "$pkgdatadir/lib/Unicode-EastAsianWidth/lib";
4166        }
4167    }
4168    # unicode east asian character width tables.
4169    require Unicode::EastAsianWidth;
4170}
4171
4172# no user provided USE_UNIDECODE, use configure provided
4173if (!defined($Texi2HTML::Config::USE_UNIDECODE))
4174{
4175    $Texi2HTML::Config::USE_UNIDECODE = '@USE_UNIDECODE@';
4176}
4177
4178# no user provided nor configured, run time test
4179if ($Texi2HTML::Config::USE_UNIDECODE eq 'unknown' or $Texi2HTML::Config::USE_UNIDECODE eq '@' .'USE_UNIDECODE@')
4180{
4181    $Texi2HTML::Config::USE_UNIDECODE = 1;
4182    eval {
4183        require Text::Unidecode;
4184        Text::Unidecode->import('unidecode');
4185    };
4186    $Texi2HTML::Config::USE_UNIDECODE = 0 if ($@);
4187}
4188
4189if ($Texi2HTML::Config::USE_UNIDECODE)
4190{
4191    require Text::Unidecode;
4192    Text::Unidecode->import('unidecode');
4193}
4194
4195print STDERR "# USE_UNICODE $Texi2HTML::Config::USE_UNICODE, USE_UNIDECODE $Texi2HTML::Config::USE_UNIDECODE \n"
4196  if ($T2H_VERBOSE);
4197
4198# Construct hashes used for cross references generation
4199# Do it now as the user may have changed $USE_UNICODE
4200
4201foreach my $key (keys(%Texi2HTML::Config::unicode_map))
4202{
4203    if ($Texi2HTML::Config::unicode_map{$key} ne '')
4204    {
4205        if ($Texi2HTML::Config::USE_UNICODE)
4206        {
4207             my $char_nr = hex($Texi2HTML::Config::unicode_map{$key});
4208             #$cross_ref_texi_map{$key} = chr(hex($Texi2HTML::Config::unicode_map{$key}));
4209             #$cross_ref_texi_map{$key} = pack("U0U*",hex($Texi2HTML::Config::unicode_map{$key}));
4210             if ($char_nr > 126 and $char_nr < 255)
4211             {
4212                 $cross_ref_texi_map{$key} = Encode::decode("iso-8859-1", chr($char_nr));
4213             }
4214             else
4215             {
4216                 $cross_ref_texi_map{$key} = chr($char_nr);
4217             }
4218             # cross_transliterate_texi_map is only used if
4219             # USE_UNIDECODE is unset and TRANSLITERATE_FILE_NAMES is set
4220             if (exists ($Texi2HTML::Config::transliterate_map{$Texi2HTML::Config::unicode_map{$key}}))
4221             {
4222                $cross_transliterate_texi_map{$key} = $Texi2HTML::Config::transliterate_map{$Texi2HTML::Config::unicode_map{$key}};
4223             }
4224             else
4225             {
4226                 $cross_transliterate_texi_map{$key} = $cross_ref_texi_map{$key};
4227             }
4228        }
4229        else
4230        {
4231            $cross_ref_texi_map{$key} = '_' . lc($Texi2HTML::Config::unicode_map{$key});
4232             # cross_transliterate_texi_map is used if TRANSLITERATE_FILE_NAMES is set
4233             if (exists ($Texi2HTML::Config::transliterate_map{$Texi2HTML::Config::unicode_map{$key}}))
4234             {
4235                 $cross_transliterate_texi_map{$key} = $Texi2HTML::Config::transliterate_map{$Texi2HTML::Config::unicode_map{$key}};
4236             }
4237             else
4238             {
4239                  $cross_transliterate_texi_map{$key} = '_' . lc($Texi2HTML::Config::unicode_map{$key});
4240             }
4241        }
4242    }
4243}
4244#if ($Texi2HTML::Config::USE_UNICODE and $Texi2HTML::Config::TRANSLITERATE_FILE_NAMES
4245if ($Texi2HTML::Config::TRANSLITERATE_FILE_NAMES and (
4246    ($Texi2HTML::Config::USE_UNICODE and ! $Texi2HTML::Config::USE_UNIDECODE)
4247    or !$Texi2HTML::Config::USE_UNICODE))
4248{
4249    foreach my $key (keys (%Texi2HTML::Config::transliterate_accent_map))
4250    {
4251        $Texi2HTML::Config::transliterate_map{$key} = $Texi2HTML::Config::transliterate_accent_map{$key};
4252    }
4253}
4254
4255foreach my $key (keys(%cross_ref_style_map_texi))
4256{
4257    if ($style_type{$key} eq 'accent'
4258        and (ref($cross_ref_style_map_texi{$key}) eq 'HASH'))
4259    {
4260        if ($Texi2HTML::Config::USE_UNICODE)
4261        {
4262             $cross_ref_style_map_texi{$key}->{'function'} = \&Texi2HTML::Config::t2h_utf8_accent;
4263        }
4264        else
4265        {
4266             $cross_ref_style_map_texi{$key}->{'function'} = \&Texi2HTML::Config::t2h_nounicode_cross_manual_accent;
4267        }
4268        # this is only used if TRANSLITERATE_FILE_NAMES is set and USE_UNICODE
4269        # or USE_UNIDECODE is not set
4270        $cross_transliterate_style_map_texi{$key}->{'function'} = \&Texi2HTML::Config::t2h_transliterate_cross_manual_accent;
4271    }
4272}
4273
4274if ($Texi2HTML::Config::L2H and defined($Texi2HTML::Config::OUTPUT_FORMAT) and $Texi2HTML::Config::OUTPUT_FORMAT eq 'html')
4275{
4276   push @Texi2HTML::Config::command_handler_init, \&Texi2HTML::LaTeX2HTML::init;
4277   push @Texi2HTML::Config::command_handler_process, \&Texi2HTML::LaTeX2HTML::latex2html;
4278   # do it here once to have something ready for special regions
4279   push @Texi2HTML::Config::command_handler_process, \&Texi2HTML::LaTeX2HTML::init_from_html;
4280   # do it here once more in case the file was modified (see mediawiki.init)
4281   push @Texi2HTML::Config::command_handler_output, \&Texi2HTML::LaTeX2HTML::init_from_html;
4282   push @Texi2HTML::Config::command_handler_finish, \&Texi2HTML::LaTeX2HTML::finish;
4283   $Texi2HTML::Config::command_handler{'math'} =
4284     { 'init' => \&Texi2HTML::LaTeX2HTML::to_latex,
4285       'expand' => \&Texi2HTML::LaTeX2HTML::do_tex
4286     };
4287   $Texi2HTML::Config::command_handler{'tex'} =
4288     { 'init' => \&Texi2HTML::LaTeX2HTML::to_latex,
4289       'expand' => \&Texi2HTML::LaTeX2HTML::do_tex
4290     };
4291}
4292
4293if ($Texi2HTML::Config::ENABLE_ENCODING)
4294{
4295   if ($Texi2HTML::Config::USE_UNICODE)
4296   {
4297      Texi2HTML::Config::t2h_enable_encoding_load();
4298   }
4299   else
4300   { # FIXME: only warn if ENABLE_ENCODING is set on the command line
4301      #warn "** --enable-encoding requires utf-8 support\n";
4302   }
4303}
4304
4305# for all files. This won't be overriden by @documentencoding, this is not
4306# what is done in general.
4307Texi2HTML::Config::set_conf('IN_ENCODING', $Texi2HTML::Config::IN_ENCODING);
4308Texi2HTML::Config::set_conf('DOCUMENT_ENCODING', $Texi2HTML::Config::DOCUMENT_ENCODING);
4309
4310# Backward compatibility for deprecated $Texi2HTML::Config::ENCODING
4311$Texi2HTML::Config::ENCODING_NAME = $Texi2HTML::Config::ENCODING
4312  if (!defined($Texi2HTML::Config::ENCODING_NAME) and defined($Texi2HTML::Config::ENCODING));
4313
4314# APA: There's got to be a better way:
4315if ($Texi2HTML::Config::TEST)
4316{
4317    # to generate files similar to reference ones to be able to check for
4318    # real changes we use these dummy values if -test is given
4319    $THISPROG = 'texi2html';
4320    setlocale( LC_ALL, "C" );
4321}
4322
4323$Texi2HTML::GLOBAL{'debug_l2h'} = 1 if ($T2H_DEBUG & $DEBUG_L2H);
4324
4325# parse texinfo cnf file for external manual specifications. This was
4326# discussed on texinfo list but not in makeinfo for now.
4327my @texinfo_htmlxref_files = locate_init_file ($texinfo_htmlxref, 1, \@texinfo_config_dirs);
4328
4329foreach my $file (@texinfo_htmlxref_files)
4330{
4331    print STDERR "html refs config file: $file\n" if ($T2H_DEBUG);
4332    unless (open (HTMLXREF, $file))
4333    {
4334         document_warn("Cannot open html refs config file ${file}: $!");
4335         next;
4336    }
4337    my $line_nr = 0;
4338    my %variables;
4339    while (my $hline = <HTMLXREF>)
4340    {
4341        my $line = $hline;
4342        $line_nr++;
4343        next if $hline =~ /^\s*#/;
4344        #$hline =~ s/[#]\s.*//;
4345        $hline =~ s/^\s*//;
4346        next if $hline =~ /^\s*$/;
4347        chomp ($hline);
4348        if ($hline =~ s/^(\w+)\s*=\s*//)
4349        {
4350           # handle variables
4351           my $var = $1;
4352           my $re = join '|', map { quotemeta $_ } keys %variables;
4353           $hline =~ s/\$\{($re)\}/defined $variables{$1} ? $variables{$1} : "\${$1}"/ge;
4354           $variables{$var} = $hline;
4355           next;
4356        }
4357        my @htmlxref = split /\s+/, $hline;
4358        my $manual = shift @htmlxref;
4359        my $split_or_mono = shift @htmlxref;
4360#print STDERR "$split_or_mono $Texi2HTML::Config::htmlxref_entries{$split_or_mono} $line_nr\n";
4361        if (!defined($split_or_mono))
4362        {
4363            file_line_warn(__("Missing type"), $file, $line_nr);
4364            next;
4365        }
4366        elsif (!defined($Texi2HTML::Config::htmlxref_entries{$split_or_mono}))
4367        {
4368            file_line_warn(sprintf(__("Unrecognized type: %s"), $split_or_mono), $file, $line_nr);
4369            next;
4370        }
4371        my $href = shift @htmlxref;
4372        next if (exists($Texi2HTML::GLOBAL{'htmlxref'}->{$manual}->{$split_or_mono}) and exists($Texi2HTML::GLOBAL{'htmlxref'}->{$manual}->{$split_or_mono}->{'href'}));
4373
4374        if (defined($href))
4375        {
4376            my $re = join '|', map { quotemeta $_ } keys %variables;
4377            $href =~ s/\$\{($re)\}/defined $variables{$1} ? $variables{$1} : "\${$1}"/ge;
4378            $href =~ s/\/*$// if ($split_or_mono ne 'mono');
4379            $Texi2HTML::GLOBAL{'htmlxref'}->{$manual}->{$split_or_mono}->{'href'} = $href;
4380        }
4381        else
4382        {
4383            $Texi2HTML::GLOBAL{'htmlxref'}->{$manual}->{$split_or_mono} = {};
4384        }
4385    }
4386    close (HTMLXREF);
4387}
4388
4389if ($T2H_DEBUG)
4390{
4391    foreach my $manual (keys(%{$Texi2HTML::GLOBAL{'htmlxref'}}))
4392    {
4393         foreach my $split (keys(%Texi2HTML::Config::htmlxref_entries))
4394         {
4395              my $href = 'NO';
4396              next unless (exists($Texi2HTML::GLOBAL{'htmlxref'}->{$manual}->{$split}));
4397              $href = $Texi2HTML::GLOBAL{'htmlxref'}->{$manual}->{$split}->{'href'} if
4398                  exists($Texi2HTML::GLOBAL{'htmlxref'}->{$manual}->{$split}->{'href'});
4399              print STDERR "$manual: $split, href: $href\n";
4400         }
4401    }
4402}
4403
4404# resulting files splitting
4405if ($Texi2HTML::Config::SPLIT =~ /section/i)
4406{
4407    $Texi2HTML::Config::SPLIT = 'section';
4408}
4409elsif ($Texi2HTML::Config::SPLIT =~ /node/i)
4410{
4411    $Texi2HTML::Config::SPLIT = 'node';
4412}
4413elsif ($Texi2HTML::Config::SPLIT =~ /chapter/i)
4414{
4415    $Texi2HTML::Config::SPLIT = 'chapter';
4416}
4417else
4418{
4419    $Texi2HTML::Config::SPLIT = '';
4420}
4421
4422$Texi2HTML::Config::SPLIT_INDEX = 0 unless $Texi2HTML::Config::SPLIT;
4423$Texi2HTML::Config::NODE_FILENAMES = 1 if ((!defined($Texi2HTML::Config::NODE_FILENAMES) and $Texi2HTML::Config::SPLIT eq 'node') or $Texi2HTML::Config::NODE_FILES);
4424
4425# Something like backward compatibility. This would make sense to keep
4426# it ad-infinitum since the meaning of --out and --subdir are different.
4427if ($Texi2HTML::Config::SPLIT and defined($Texi2HTML::Config::SUBDIR)
4428    and ($Texi2HTML::Config::SUBDIR ne '') and
4429   (!defined($Texi2HTML::Config::OUT) or ($Texi2HTML::Config::OUT eq '')))
4430{
4431    $Texi2HTML::Config::OUT = $Texi2HTML::Config::SUBDIR;
4432}
4433
4434die "output to STDOUT and split or frames incompatible\n"
4435    if (($Texi2HTML::Config::SPLIT or $Texi2HTML::Config::FRAMES) and defined($Texi2HTML::Config::OUT) and $Texi2HTML::Config::OUT eq '-');
4436
4437if ($Texi2HTML::Config::SPLIT and defined($Texi2HTML::Config::OUT) and ($Texi2HTML::Config::OUT eq '.'))
4438{# This is to avoid trouble with latex2html
4439    $Texi2HTML::Config::OUT = '';
4440}
4441
4442@Texi2HTML::Config::INCLUDE_DIRS = split(/$quoted_path_separator/,join($path_separator,@Texi2HTML::Config::INCLUDE_DIRS));
4443@Texi2HTML::Config::PREPEND_DIRS = split(/$quoted_path_separator/,join($path_separator,@Texi2HTML::Config::PREPEND_DIRS));
4444
4445my @include_dirs_orig = @Texi2HTML::Config::INCLUDE_DIRS;
4446
4447@Texi2HTML::Config::CONF_DIRS = split(/$quoted_path_separator/,join($path_separator,@Texi2HTML::Config::CONF_DIRS));
4448# extension
4449$Texi2HTML::GLOBAL{'extension'} = $Texi2HTML::Config::EXTENSION;
4450if ($Texi2HTML::Config::SHORTEXTN)
4451{
4452   $Texi2HTML::GLOBAL{'extension'} = "htm";
4453}
4454
4455my $global_pass; # track the phases of processing for debugging output purposes
4456
4457#
4458# file name business
4459#
4460
4461my @created_directories = ();
4462
4463my $docu_dir;            # directory of the document
4464my $docu_name;           # basename of the document
4465my $docu_rdir;           # directory for the output
4466my $docu_toc;            # document's table of contents
4467my $docu_stoc;           # document's short toc
4468my $docu_foot;           # document's footnotes
4469my $docu_about;          # about this document
4470my $docu_top;            # document top
4471my $docu_doc;            # document (or document top of split)
4472my $docu_frame;          # main frame file
4473my $docu_toc_frame;      # toc frame file
4474my $path_to_working_dir; # relative path leading to the working
4475                         # directory from the document directory
4476my $docu_doc_file;
4477my $docu_toc_file;
4478my $docu_stoc_file;
4479my $docu_foot_file;
4480my $docu_about_file;
4481my $docu_top_file;
4482my $docu_frame_file;
4483my $docu_toc_frame_file;
4484
4485sub set_docu_names($$)
4486{
4487   my $docu_base_name = shift;
4488   my $file_nr = shift;
4489   if ($docu_base_name =~ /(.*\/)/)
4490   {
4491      $docu_dir = $1;
4492      chop($docu_dir);
4493      $docu_name = $docu_base_name;
4494      $docu_name =~ s/.*\///;
4495   }
4496   else
4497   {
4498      $docu_dir = '.';
4499      $docu_name = $docu_base_name;
4500   }
4501
4502   @Texi2HTML::Config::INCLUDE_DIRS = @include_dirs_orig;
4503   my @prependended_include_directories = ('.');
4504   push @prependended_include_directories, $Texi2HTML::THISDOC{'input_directory'} if ($Texi2HTML::THISDOC{'input_directory'} ne '.');
4505   # as Karl said, adding the destination directory is confusing.
4506   #push @prependended_include_directories, $docu_dir if ($docu_dir ne '.' and $docu_dir ne $Texi2HTML::THISDOC{'input_directory'});
4507   unshift(@Texi2HTML::Config::INCLUDE_DIRS, @prependended_include_directories);
4508   unshift(@Texi2HTML::Config::INCLUDE_DIRS, @Texi2HTML::Config::PREPEND_DIRS);
4509# AAAA
4510   if ($Texi2HTML::Config::PREFIX and ($file_nr == 0))
4511   {
4512      $docu_name = $Texi2HTML::Config::PREFIX;
4513   }
4514   elsif ($docu_name eq '-')
4515   {
4516      $docu_name = $Texi2HTML::Config::STDIN_DOCU_NAME;
4517   }
4518
4519# subdir
4520   $docu_rdir = '';
4521   my $null_output;
4522   if (defined($Texi2HTML::Config::OUT) and ($file_nr == 0) and $Texi2HTML::Config::null_device_file{$Texi2HTML::Config::OUT})
4523   { # this overrides the setting for this file.
4524      $Texi2HTML::THISDOC{'SPLIT'} = '';
4525      $Texi2HTML::THISDOC{'SPLIT_SIZE'} = undef;
4526      $null_output = 1;
4527      $path_to_working_dir = $docu_rdir;
4528   }
4529   if (!$null_output)
4530   {
4531      if (Texi2HTML::Config::get_conf('SPLIT'))
4532      {
4533         if (defined($Texi2HTML::Config::OUT) and ($file_nr == 0))
4534         {
4535            $docu_rdir = $Texi2HTML::Config::OUT;
4536         }
4537         else
4538         {
4539            $docu_rdir = $docu_name;
4540         }
4541         if ($docu_rdir ne '')
4542         {
4543            $docu_rdir =~ s|/*$||;
4544            $docu_rdir .= '/';
4545         }
4546      }
4547      else
4548      {
4549         my $out_file;
4550# AAAA
4551      # even if the out file is not set by OUT, in case it is not the first
4552      # file, the out directory is still used. This is only used to determine
4553      # the directory, the out file itself is set below
4554         if (defined($Texi2HTML::Config::OUT) and $Texi2HTML::Config::OUT ne '')
4555         {
4556            $out_file = $Texi2HTML::Config::OUT;
4557         }
4558         else
4559         {
4560            $out_file = $docu_name;
4561         }
4562
4563         if ($out_file =~ m|(.*)/|)
4564         {# there is a leading directories
4565            $docu_rdir = "$1/";
4566         }
4567      }
4568
4569      if ($docu_rdir ne '')
4570      {
4571         unless (-d $docu_rdir)
4572         {
4573            if ( mkdir($docu_rdir, oct(755)))
4574            {
4575               print STDERR "# created directory $docu_rdir\n" if ($T2H_VERBOSE);
4576               push @created_directories, $docu_rdir;
4577            }
4578            else
4579            {
4580               document_error (sprintf(__("Can't create directory `%s': %s"), $docu_rdir, $!), 1);
4581            }
4582        }
4583        print STDERR "# putting result files into directory $docu_rdir\n" if ($T2H_VERBOSE);
4584      }
4585      else
4586      {
4587         print STDERR "# putting result files into current directory \n" if ($T2H_VERBOSE);
4588      }
4589      # We don't use "./" as $docu_rdir when $docu_rdir is the current directory
4590      # because it is problematic for latex2html. To test writability with -w,
4591      # however we need a real directory.
4592      my $result_rdir = $docu_rdir;
4593      $result_rdir = "." if ($docu_rdir eq '');
4594      unless (-w $result_rdir)
4595      {
4596         $docu_rdir = 'current directory' if ($docu_rdir eq '');
4597         document_error ("$docu_rdir not writable", 1);
4598      }
4599
4600      # relative path leading to the working directory from the document directory
4601      $path_to_working_dir = $docu_rdir;
4602      if ($docu_rdir ne '')
4603      {
4604         my $cwd = cwd;
4605         my $docu_path = $docu_rdir;
4606         $docu_path = $cwd . '/' . $docu_path unless ($docu_path =~ /^\//);
4607         my @result = ();
4608         # this code simplify the paths. The cwd is absolute, while in the
4609         # document path there may be some .., a .. is removed with the
4610         # previous path element, such that something like
4611         # /cwd/directory/../somewhere/
4612         # leads to
4613         # /cwd/somewhere/
4614         # with directory/.. removed
4615         foreach my $element (split /\//, File::Spec->canonpath($docu_path))
4616         {
4617            if ($element eq '')
4618            {
4619               push @result, '';
4620            }
4621            elsif ($element eq '..')
4622            {
4623               if (@result and ($result[-1] eq ''))
4624               {
4625                  print STDERR "Too much .. in absolute file name\n";
4626               }
4627               elsif (@result and ($result[-1] ne '..'))
4628               {
4629                  pop @result;
4630               }
4631               else
4632               {
4633                  push @result, $element;
4634               }
4635            }
4636            else
4637            {
4638               push @result, $element;
4639            }
4640         }
4641         $path_to_working_dir = File::Spec->abs2rel($cwd, join ('/', @result));
4642         # this should not be needed given what canonpath does
4643         $path_to_working_dir =~ s:/*$::;
4644         $path_to_working_dir .= '/' unless($path_to_working_dir eq '');
4645      }
4646   }
4647
4648   my $docu_ext = $Texi2HTML::THISDOC{'extension'};
4649   # out_dir is undocummented, should never be used, use destination_directory
4650   $Texi2HTML::THISDOC{'out_dir'} = $docu_rdir;
4651
4652   $Texi2HTML::THISDOC{'destination_directory'} = $docu_rdir;
4653   $Texi2HTML::THISDOC{'file_base_name'} = $docu_name;
4654
4655   $docu_doc = $docu_name . (defined($docu_ext) ? ".$docu_ext" : ""); # document's contents
4656   if (Texi2HTML::Config::get_conf('SPLIT') and $Texi2HTML::Config::NODE_FILENAMES)
4657   {
4658      if (defined($Texi2HTML::Config::TOP_NODE_FILE))
4659      {
4660         $docu_doc = $Texi2HTML::Config::TOP_NODE_FILE;
4661         if (defined($Texi2HTML::Config::NODE_FILE_EXTENSION) and $Texi2HTML::Config::NODE_FILE_EXTENSION ne '')
4662         {
4663            $docu_doc .= ".$Texi2HTML::Config::NODE_FILE_EXTENSION";
4664         }
4665      }
4666   }
4667   if (Texi2HTML::Config::get_conf('SPLIT'))
4668   {
4669# AAAA
4670      if (defined($Texi2HTML::Config::TOP_FILE) and ($Texi2HTML::Config::TOP_FILE ne '') and ($file_nr == 0))
4671      {
4672         $docu_top = $Texi2HTML::Config::TOP_FILE;
4673      }
4674   }
4675   else
4676   {
4677# AAAA
4678      if (defined($Texi2HTML::Config::OUT) and ($file_nr == 0))
4679      {
4680         my $out_file = $Texi2HTML::Config::OUT;
4681         if ($out_file eq '-')
4682         {
4683            $Texi2HTML::THISDOC{'SPLIT'} = '';
4684            $Texi2HTML::THISDOC{'SPLIT_SIZE'} = undef;
4685         }
4686         $out_file =~ s|.*/|| unless ($null_output);
4687         $docu_doc = $out_file if ($out_file !~ /^\s*$/);
4688      }
4689   }
4690
4691   if (defined $Texi2HTML::Config::element_file_name)
4692   {
4693      my $docu_doc_set = &$Texi2HTML::Config::element_file_name
4694        (undef, 'doc', $docu_name);
4695      $docu_doc = $docu_doc_set if (defined($docu_doc_set));
4696   }
4697   $docu_top = $docu_doc if (!defined($docu_top));
4698
4699   if (Texi2HTML::Config::get_conf('SPLIT') or !$Texi2HTML::Config::MONOLITHIC)
4700   {
4701      if (defined $Texi2HTML::Config::element_file_name)
4702      {
4703         $docu_toc = &$Texi2HTML::Config::element_file_name
4704            (undef, 'toc', $docu_name);
4705         $docu_stoc = &$Texi2HTML::Config::element_file_name
4706            (undef, 'stoc', $docu_name);
4707         $docu_foot = &$Texi2HTML::Config::element_file_name
4708            (undef, 'foot', $docu_name);
4709         $docu_about = &$Texi2HTML::Config::element_file_name
4710            (undef, 'about', $docu_name);
4711	# $docu_top may be overwritten later.
4712      }
4713      if (!defined($docu_toc))
4714      {
4715         my $default_toc = "${docu_name}_toc";
4716         $default_toc .= ".$docu_ext" if (defined($docu_ext));
4717# AAAA
4718      if (defined($Texi2HTML::Config::TOC_FILE) and ($Texi2HTML::Config::TOC_FILE ne '') and ($file_nr == 0))
4719         {
4720            $docu_toc = $Texi2HTML::Config::TOC_FILE;
4721         }
4722         else
4723         {
4724            $docu_toc = $default_toc;
4725         }
4726      }
4727      if (!defined($docu_stoc))
4728      {
4729         $docu_stoc  = "${docu_name}_ovr";
4730         $docu_stoc .= ".$docu_ext" if (defined($docu_ext));
4731      }
4732      if (!defined($docu_foot))
4733      {
4734         $docu_foot  = "${docu_name}_fot";
4735         $docu_foot .= ".$docu_ext" if (defined($docu_ext));
4736      }
4737      if (!defined($docu_about))
4738      {
4739         $docu_about = "${docu_name}_abt";
4740         $docu_about .= ".$docu_ext" if (defined($docu_ext));
4741      }
4742   }
4743   else
4744   {
4745      $docu_toc = $docu_foot = $docu_stoc = $docu_about = $docu_doc;
4746   }
4747
4748   # Note that file extension has already been added here.
4749   if ($Texi2HTML::Config::FRAMES)
4750   {
4751      if (defined $Texi2HTML::Config::element_file_name)
4752      {
4753         $docu_frame = &$Texi2HTML::Config::element_file_name
4754            (undef, 'frame', $docu_name);
4755         $docu_toc_frame = &$Texi2HTML::Config::element_file_name
4756           (undef, 'toc_frame', $docu_name);
4757      }
4758   }
4759
4760   if (!defined($docu_frame))
4761   {
4762      $docu_frame = "${docu_name}_frame";
4763      $docu_frame .= ".$docu_ext" if (defined($docu_ext));
4764   }
4765   if (!defined($docu_toc_frame))
4766   {
4767      $docu_toc_frame  = "${docu_name}_toc_frame";
4768      $docu_toc_frame .= ".$docu_ext" if (defined($docu_ext));
4769   }
4770
4771   if ($T2H_VERBOSE)
4772   {
4773      print STDERR "# Files and directories:\n";
4774      print STDERR "# rdir($docu_rdir) path_to_working_dir($path_to_working_dir)\n";
4775      print STDERR "# doc($docu_doc) top($docu_top) toc($docu_toc) stoc($docu_stoc)\n";
4776      print STDERR "# foot($docu_foot) about($docu_about) frame($docu_toc) toc_frame($docu_toc_frame)\n";
4777   }
4778
4779   $docu_doc_file = "$docu_rdir$docu_doc";
4780   $docu_toc_file  = "$docu_rdir$docu_toc";
4781   $docu_stoc_file = "$docu_rdir$docu_stoc";
4782   $docu_foot_file = "$docu_rdir$docu_foot";
4783   $docu_about_file = "$docu_rdir$docu_about";
4784   $docu_top_file  = "$docu_rdir$docu_top";
4785   $docu_frame_file = "$docu_rdir$docu_frame";
4786   $docu_toc_frame_file = "$docu_rdir$docu_toc_frame";
4787
4788# For use in init files
4789   $Texi2HTML::THISDOC{'filename'}->{'top'} = $docu_top;
4790   $Texi2HTML::THISDOC{'filename'}->{'foot'} = $docu_foot;
4791   $Texi2HTML::THISDOC{'filename'}->{'stoc'} = $docu_stoc;
4792   $Texi2HTML::THISDOC{'filename'}->{'about'} = $docu_about;
4793   $Texi2HTML::THISDOC{'filename'}->{'toc'} = $docu_toc;
4794   $Texi2HTML::THISDOC{'filename'}->{'toc_frame'} = $docu_toc_frame;
4795   $Texi2HTML::THISDOC{'filename'}->{'frame'} = $docu_frame;
4796}
4797
4798sub var_to_str($)
4799{
4800    return 'UNDEF' if (!defined($_[0]));
4801    return $_[0];
4802}
4803
4804#
4805# Common initializations
4806#
4807
4808sub texinfo_initialization($)
4809{
4810    my $pass = shift;
4811
4812    # set the translations now. This means at the beginning of each pass.
4813    # Do it silently, except during the last pass.
4814    my $lang = Texi2HTML::Config::get_conf('documentlanguage');
4815    my $silent_lang = 1 if ($pass != 2);
4816    if (!set_document_language($lang, $silent_lang))
4817    {
4818       document_warn ("Translations for '$lang' not found. Using 'en'.") unless ($silent_lang);
4819       set_document_language('en', $silent_lang);
4820    }
4821    # All the initialization used the informations still there at the
4822    # end of the previous pass.
4823    # Now we reset everything, such that things are used when they happen.
4824    # also reset the @set/@clear values.
4825    %value = %value_initial;
4826    foreach my $init_mac ('everyheading', 'everyfooting', 'evenheading',
4827        'evenfooting', 'oddheading', 'oddfooting', 'headings',
4828        'allowcodebreaks', 'frenchspacing', 'exampleindent',
4829        'firstparagraphindent', 'paragraphindent', 'clickstyle',
4830        'novalidate', 'documentlanguage')
4831    {
4832        Texi2HTML::Config::set_conf($init_mac, undef, 1);
4833    }
4834}
4835
4836#+++###########################################################################
4837#                                                                             #
4838# Pass texi: read source, handle variable, ignored text,                      #
4839#                                                                             #
4840#---###########################################################################
4841
4842#my @lines = ();             # whole document
4843#my @lines_numbers = ();     # line number, originating file associated with
4844                            # whole document
4845my $macros = undef;         # macros. reference on a hash
4846my %info_enclose = ();      # macros defined with definfoenclose
4847my @floats = ();            # floats list
4848my %floats = ();            # floats by style
4849
4850sub initialise_state_texi($)
4851{
4852    my $state = shift;
4853    $state->{'texi'} = 1;           # for substitute_text and close_stack:
4854                                    # 1 if pass_texi/scan_texi is to be used
4855    $state->{'macro_inside'} = 0 unless(defined($state->{'macro_inside'}));
4856    $state->{'ifvalue_inside'} = 0 unless(defined($state->{'ifvalue_inside'}));
4857    $state->{'arg_expansion'} = 0 unless(defined($state->{'arg_expansion'}));
4858    $state->{'files_stack'} = [] unless(defined($state->{'files_stack'}));
4859}
4860
4861
4862sub pass_texi($)
4863{
4864    my $input_file_name = shift;
4865    #my $texi_line_number = { 'file_name' => '', 'line_nr' => 0, 'macro' => '' };
4866
4867    my @lines = ();             # whole document
4868    my @lines_numbers = ();     # line number, originating file associated with
4869                                # whole document
4870    my @first_lines = ();
4871    my $first_lines = 1;        # is it the first lines
4872    my $state = {};
4873                                # holds the informations about the context
4874                                # to pass it down to the functions
4875    my @command_line_lines = @Texi2HTML::Config::COMMANDS;
4876    initialise_state_texi($state);
4877    my $texi_line_number;
4878    ($texi_line_number, $state->{'input_spool'}) =
4879          open_file($input_file_name, '', $state->{'files_stack'});
4880    my @stack;
4881    my $text;
4882    my $cline;
4883 INPUT_LINE: while (1)
4884    {
4885        ($cline, $state->{'input_spool'}) = next_line($texi_line_number, $state->{'files_stack'});
4886        last if (!defined($cline));
4887        #
4888        # remove the lines preceding \input or an @-command
4889        #
4890        if ($first_lines)
4891        {
4892            if ($cline =~ /^\\input/)
4893            {
4894                push @first_lines, $cline;
4895                $first_lines = 0;
4896                next;
4897            }
4898            if ($cline =~ /^\s*\@/)
4899            {
4900                $first_lines = 0;
4901            }
4902            else
4903            {
4904                push @first_lines, $cline;
4905                next;
4906            }
4907        }
4908	#print STDERR "PASS_TEXI($texi_line_number->{'line_nr'})$cline";
4909        my $chomped_line = $cline;
4910        if (scan_texi ($cline, \$text, \@stack, $state, $texi_line_number) and chomp($chomped_line))
4911        {
4912        #print STDERR "==> new page (line_nr $texi_line_number->{'line_nr'},$texi_line_number->{'file_name'},$texi_line_number->{'macro'})\n";
4913            push (@lines_numbers, { 'file_name' => $texi_line_number->{'file_name'},
4914                  'line_nr' => $texi_line_number->{'line_nr'},
4915                  'macro' => $texi_line_number->{'macro'} });
4916        }
4917        #dump_stack (\$text, \@stack, $state);
4918        if ($state->{'bye'})
4919        {
4920            #dump_stack(\$text, \@stack, $state);
4921            # close stack after bye
4922            #print STDERR "close stack after bye\n";
4923            close_stack_texi(\$text, \@stack, $state, $texi_line_number);
4924            #dump_stack(\$text, \@stack, $state);
4925        }
4926        next if (@stack);
4927        $cline = $text;
4928        $text = '';
4929        if (!defined($cline))
4930        {
4931            msg_debug ("\$cline undefined after scan_texi", $texi_line_number);
4932            next unless ($state->{'bye'});
4933        }
4934        push @lines, split_lines($cline);
4935        last if ($state->{'bye'});
4936    }
4937    # close stack at the end of pass texi
4938    #print STDERR "close stack at the end of pass texi\n";
4939    close_stack_texi(\$text, \@stack, $state, $texi_line_number);
4940    push @lines, split_lines($text);
4941    print STDERR "# end of pass texi\n" if $T2H_VERBOSE;
4942    return (\@lines, \@first_lines, \@lines_numbers);
4943}
4944
4945#+++###########################################################################
4946#                                                                             #
4947# Pass structure: parse document structure                                    #
4948#                                                                             #
4949#---###########################################################################
4950
4951sub initialise_state_structure($)
4952{
4953    my $state = shift;
4954    $state->{'structure'} = 1;      # for substitute_text and close_stack:
4955                                    # 1 if pass_structure/scan_structure is
4956                                    # to be used
4957    $state->{'menu'} = 0;           # number of opened menus
4958    $state->{'detailmenu'} = 0;     # number of opened detailed menus
4959    $state->{'direntry'} = 0;     # number of opened direntry
4960    $state->{'sectionning_base'} = 0;         # current base sectioning level
4961    $state->{'table_stack'} = [ "no table" ]; # a stack of opened tables/lists
4962    # seems to be only debug
4963    if (exists($state->{'region_lines'}) and !defined($state->{'region_lines'}))
4964    {
4965        delete ($state->{'region_lines'});
4966        print STDERR "Bug: state->{'region_lines'} exists but undef.\n";
4967    }
4968}
4969# This is a virtual element for things appearing before @node and
4970# sectioning commands
4971my $element_before_anything;
4972
4973#
4974# initial counters. Global variables for pass_structure.
4975#
4976my $document_idx_num;
4977my $document_sec_num;
4978my $document_head_num;
4979my $document_anchor_num;
4980
4981# section to level hash taking into account raise and lower sections.
4982# Reset at document beginning
4983my %sec2level;
4984# initial state for the special regions.
4985my %region_initial_state;
4986my %region_lines;
4987my %region_line_nrs;
4988
4989# This is a place for index entries, anchors and so on appearing in
4990# copying or documentdescription
4991my $no_element_associated_place;
4992
4993
4994my @nodes_list;             # nodes in document reading order
4995                            # each member is a reference on a hash
4996my @sections_list;          # sections in reading order
4997                            # each member is a reference on a hash
4998my @all_elements;           # sectioning elements (nodes and sections)
4999                            # in reading order. Each member is a reference
5000                            # on a hash which also appears in %nodes,
5001                            # @sections_list @nodes_list, @elements_list
5002my @elements_list;          # all the resulting elements in document order
5003my %sections;               # sections hash. The key is the section number
5004my %headings;               # headings hash. The key is the heading number
5005my $section_top;            # @top section
5006my $element_top;            # Top element
5007my $node_top;               # Top node
5008my $node_first;             # First node
5009my $element_index;          # element with first index
5010my $element_chapter_index;  # chapter with first index
5011my $element_first;          # first element
5012my $element_last;           # last element
5013my %special_commands;       # hash for the commands specially handled
5014                            # by the user
5015
5016# element for content and shortcontent if on a separate page
5017my %content_element;
5018my %reference_content_element =
5019   (
5020     'contents' => { 'id' => $Texi2HTML::Config::misc_pages_targets{'Contents'},
5021         'target' => $Texi2HTML::Config::misc_pages_targets{'Contents'},
5022         'contents' => 1, 'texi' => '_contents' },
5023     'shortcontents' => {
5024        'id' => $Texi2HTML::Config::misc_pages_targets{'Overview'},
5025        'target' => $Texi2HTML::Config::misc_pages_targets{'Overview'},
5026        'shortcontents' => 1, 'texi' => '_shortcontents' },
5027   );
5028
5029# holds content elements located with @*contents commands
5030my %all_content_elements;
5031
5032# common code for headings and sections
5033sub new_section_heading($$$$)
5034{
5035    my $command = shift;
5036    my $name = shift;
5037    my $state = shift;
5038    my $line_nr = shift;
5039
5040    $name = trim_comment_spaces ($name, "\@$command", $line_nr);
5041    $name = normalise_texi_space($name);
5042    $name = '' if (!defined($name));
5043    # no increase if in @copying and the like. Also no increase if it is top
5044    # since top has number 0.
5045    my $docid;
5046    my $num;
5047
5048    my $section_ref = { 'texi' => $name,
5049       'level' => $sec2level{$command},
5050       'tag' => $command,
5051    };
5052    return $section_ref;
5053}
5054
5055sub scan_line_separators($$$;$)
5056{
5057    my $line = shift;
5058    my $separators = shift;
5059    my $context = shift;
5060    my $line_nr = shift;
5061
5062    my @command_stack;
5063    my $result = '';
5064    while (1)
5065    {
5066        # macro_regexp
5067        if ($line =~ s/^([^{}\@$separators]*)\@(["'~\@\}\{,\.!\?\s\*\-\^`=:\|\/\\])// or $line =~ s/^([^{}\@$separators]*)\@([a-zA-Z][\w-]*)//)
5068        {
5069            $result .= $1;
5070            my $command = $2;
5071            $command = $alias{$command} if (exists($alias{$command}));
5072            if (defined($Texi2HTML::Config::misc_command{$command}))
5073            {
5074               if ($command ne 'c' and $command ne 'comment')
5075               { # misc commands other than comments are kept as-is, only
5076                 # comments are removed.
5077                   my ($text, $args);
5078                   ($line, $text, $args) = &$Texi2HTML::Config::preserve_misc_command($line, $command);
5079                   $result .= "\@$command".$text;
5080                   next;
5081               }
5082               else
5083               {
5084                   $line =~ s/.*//;
5085                   return ($result, $line, undef);
5086               }
5087            }
5088            $result .= "\@$command";
5089            if ($line =~ s/^{//)
5090            {
5091                push @command_stack, $command;
5092                $result .= '{';
5093            }
5094            if ($command eq 'verb')
5095            {
5096               if ($line =~ s/^(.)//)
5097               {
5098                  my $char = $1;
5099                  my $verb_char = quotemeta($char);
5100                  if ($line =~ s/^(.*?${verb_char}\})//)
5101                  {
5102                     $result .= $char.$1;
5103                  }
5104                  else
5105                  {
5106                     $line =~ s/^(.*)//;
5107                     $result .= $char . $1;
5108                     return ($result, $line, undef);
5109                  }
5110               }
5111               else
5112               {
5113                  return ($result, $line, undef);
5114               }
5115               pop @command_stack;
5116            }
5117        }
5118        elsif ($line =~ s/^([^\{\}$separators]*)([{}])//)
5119        {
5120            $result .= $1 . $2;
5121            my $brace = $2;
5122            if (@command_stack and $brace eq '}')
5123            {
5124                pop @command_stack;
5125            }
5126        }
5127        elsif ($separators ne '' and $line =~ s/^([^${separators}]*)([$separators])//)
5128        {
5129            $result .= $1;
5130            my $separator = $2;
5131            if (@command_stack)
5132            {
5133                $result .= $separator;
5134            }
5135            else
5136            {
5137                return ($result, $line, $separator);
5138            }
5139        }
5140        else
5141        {
5142            $result .= $line;
5143            $line = '';
5144            return ($result, $line, undef);
5145        }
5146    }
5147}
5148
5149sub trim_comment_spaces($$;$)
5150{
5151    my $line = shift;
5152    my $context = shift;
5153    my $line_nr = shift;
5154
5155    if(!defined($line))
5156    {
5157        msg_debug("trim_comment_spaces: $context: line undef", $line_nr);
5158        return undef;
5159    }
5160    my ($arg, $remaining, $separator) = scan_line_separators ($line, '', $context, $line_nr);
5161    #msg_debug ("trim_comment_spaces: $context: arg undef. $line", $line_nr) if (!defined($arg));
5162    #msg_debug ("trim_comment_spaces: $context: $arg !!! $line", $line_nr);
5163    return $arg if (!defined($arg));
5164    return  trim_around_spaces($arg);
5165}
5166
5167# argument may be the number of arguments when the commas in the last
5168# argument has no specific meaning. When it is undef it means that
5169# all the arguments have to be parsed
5170sub parse_line_arguments($$$;$)
5171{
5172    my $line = shift;
5173    my $arg_total_nr = shift;
5174    my $context = shift;
5175    my $line_nr = shift;
5176
5177    my @args;
5178    my $arg_nr = 0;
5179    my $remaining = $line;
5180
5181    while (!defined($arg_total_nr) or $arg_nr < $arg_total_nr -1)
5182    {
5183        my ($arg, $separator);
5184        ($arg, $remaining, $separator) = scan_line_separators($remaining, ',', $context, $line_nr);
5185        push @args, trim_around_spaces($arg) if (defined($arg));
5186        return @args if (!defined($separator) or !defined($remaining) or !defined($arg));
5187        $arg_nr++;
5188    }
5189    if (defined($arg_total_nr))
5190    {
5191        my ($last_arg, $separator);
5192        ($last_arg, $remaining, $separator) = scan_line_separators($remaining, '', $context, $line_nr);
5193        push @args, trim_around_spaces($last_arg) if (defined($last_arg));
5194    }
5195    return @args;
5196}
5197
5198sub pass_structure($$)
5199{
5200    my $texi_lines = shift;
5201    my $lines_numbers = shift;
5202
5203    my @doc_lines;              # whole document
5204    my @doc_numbers;            # whole document line numbers and file names
5205
5206    my $state = {};
5207                                # holds the informations about the context
5208                                # to pass it down to the functions
5209    initialise_state_structure($state);
5210    $state->{'heading_element'} = $element_before_anything;
5211    $state->{'current_element'} = $element_before_anything;
5212    $state->{'place'} = $element_before_anything->{'place'};
5213    my @stack;
5214    my $text;
5215    my $line_nr;
5216
5217    while (@$texi_lines or $state->{'in_deff_line'})
5218    {
5219        my $cline = shift @$texi_lines;
5220        my $chomped_line = $cline;
5221        if (@$texi_lines and !chomp($chomped_line))
5222        {
5223             $texi_lines->[0] = $cline . $texi_lines->[0];
5224             next;
5225        }
5226        # !defined($cline) may happen if $state->{'in_deff_line'} is true
5227        # but there is no more line, in case the last end of line is
5228        # protected
5229        $line_nr = shift (@$lines_numbers) unless (!defined($cline));
5230
5231        if ($state->{'in_deff_line'})
5232        { # line stored in $state->{'in_deff_line'} was protected by @
5233          # and can be concatenated with the next line
5234            if (defined($cline))
5235            {
5236                $cline = $state->{'in_deff_line'} . $cline;
5237            }
5238            else
5239            {# end of line protected at the very end of the file
5240             # in that case there is also no line_nr anymore.
5241                $cline = $state->{'in_deff_line'};
5242            }
5243            delete $state->{'in_deff_line'};
5244        }
5245
5246        #print STDERR "PASS_STRUCTURE($line_nr->{'line_nr'}. raw:".var_to_str($state->{'raw'}).", verb:".var_to_str($state->{'verb'})."): $cline";
5247        if (!$state->{'raw'} and !$state->{'verb'})
5248        {
5249            my $tag = '';
5250            if ($cline =~ /^\s*\@(\w+)\b/)
5251            {
5252                $tag = $1;
5253            }
5254
5255            #
5256            # analyze the tag
5257            #
5258            if ($tag and $tag eq 'node' or (defined($sec2level{$tag}) and ($tag !~ /heading/)) or ($tag eq 'insertcopying' and $Texi2HTML::Config::INLINE_INSERTCOPYING))
5259            {
5260                my @added_lines = ($cline);
5261                my @added_numbers = ($line_nr);
5262                if ($tag eq 'node' or defined($sec2level{$tag}))
5263                {# in pass structure node shouldn't appear in formats
5264                    close_stack_structure(\$text, \@stack, $state, $line_nr);
5265                    if (exists($state->{'region_lines'}))
5266                    {
5267                        push @{$region_lines{$state->{'region_lines'}->{'format'}}}, split_lines($text);
5268                        push @doc_lines, split_lines($text) if ($Texi2HTML::Config::region_formats_kept{$state->{'region_lines'}->{'format'}});
5269                        $state->{'region_lines'}->{'number'} = 0;
5270                        close_region($state);
5271                    }
5272                    else
5273                    {
5274                        push @doc_lines, split_lines($text);
5275                    }
5276                    $text = '';
5277                }
5278                if ($tag eq 'node')
5279                {
5280                    my $node_ref;
5281                    my $auto_directions;
5282                    my $node_line = $cline;
5283                    $node_line =~ s/^\@node\s*//;
5284                    my @node_res = parse_line_arguments($node_line, undef, '@node', $line_nr);
5285                    @node_res = normalise_node_array (\@node_res);
5286                    # even for empty nodes, @nodes_res has one element.
5287                    #line_error (sprintf(__("Error scanning %s"), $cline), $line_nr) if (@node_res < 1);
5288                    $auto_directions = 1 if (scalar(@node_res) == 1);
5289                    if (@node_res > 4)
5290                    {
5291                        line_warn(__("Superfluous arguments for node"), $line_nr);
5292                    }
5293                    my ($node, $node_next, $node_prev, $node_up) = @node_res;
5294                    if (defined($node) and ($node ne ''))
5295                    {
5296                        if (exists($nodes{$node}) and defined($nodes{$node})
5297                             and $nodes{$node}->{'seen'})
5298                        {
5299                            line_error (sprintf(__("Node `%s' previously defined %s"), $node, format_line_number($nodes{$node}->{'line_nr'})), $line_nr);
5300                            next;
5301                        }
5302                        elsif ($node =~ /^\(.+\)/)
5303                        {
5304                            line_error (sprintf(__("Syntax for an external node used for `%s'"), $node), $line_nr);
5305                            next;
5306                        }
5307                        else
5308                        {
5309                            if (exists($nodes{$node}) and defined($nodes{$node}))
5310                            { # node appeared in a menu
5311                                $node_ref = $nodes{$node};
5312                            }
5313                            else
5314                            {
5315                                $node_ref = {};
5316                                $nodes{$node} = $node_ref;
5317                            }
5318                            $node_ref->{'node'} = 1;
5319                            $node_ref->{'tag'} = 'node';
5320                            $node_ref->{'tag_level'} = 'node';
5321                            $node_ref->{'texi'} = $node;
5322                            $node_ref->{'seen'} = 1;
5323                            $node_ref->{'automatic_directions'} = $auto_directions;
5324                            $node_ref->{'place'} = [];
5325                            $node_ref->{'current_place'} = [];
5326                            $node_ref->{'line_nr'} = $line_nr;
5327                            merge_element_before_anything($node_ref);
5328                            $node_ref->{'index_names'} = [];
5329                            $state->{'place'} = $node_ref->{'current_place'};
5330                            $state->{'heading_element'} = $node_ref;
5331                            $state->{'current_element'} = $node_ref;
5332                            $state->{'node_ref'} = $node_ref;
5333                            $state->{'menu_in_node'} = 0;
5334                            # makeinfo treats differently case variants of
5335                            # top in nodes and anchors and in refs commands and
5336                            # refs from nodes.
5337                            if ($node =~ /^top$/i)
5338                            {
5339                                if (!defined($node_top))
5340                                {
5341                                    $node_top = $node_ref;
5342                                    $node_top->{'texi'} = 'Top';
5343                                    delete $nodes{$node};
5344                                    $nodes{$node_top->{'texi'}} = $node_ref;
5345                                }
5346                                else
5347                                { # All the refs are going to point to the first Top
5348                                    line_warn ("Top node already exists", $line_nr);
5349                                }
5350                            }
5351                            unless (@nodes_list)
5352                            {
5353                                $node_first = $node_ref;
5354                            }
5355                            push (@nodes_list, $node_ref);
5356                            push @all_elements, $node_ref;
5357                        }
5358                    }
5359                    else
5360                    {
5361                        line_error ("Empty node", $line_nr);
5362                        next;
5363                    }
5364
5365                    if (defined($node_next) and ($node_next ne ''))
5366                    {
5367                        $node_ref->{'node_next'} = $node_next;
5368                    }
5369                    if (defined($node_prev) and ($node_prev ne ''))
5370                    {
5371                        $node_ref->{'node_prev'} = $node_prev;
5372                    }
5373                    if (defined($node_up) and ($node_up ne ''))
5374                    {
5375                        $node_ref->{'node_up'} = $node_up;
5376                    }
5377                }
5378                elsif (defined($sec2level{$tag}))
5379                { # section
5380                    if ($cline =~ /^\@$tag\s*(.*)$/)
5381                    {
5382                        my $name = $1;
5383                        my $section_ref = new_section_heading($tag, $name, $state, $line_nr);
5384                        $document_sec_num++ if ($tag ne 'top');
5385
5386                        $section_ref->{'sec_num'} = $document_sec_num;
5387                        $section_ref->{'id'} = "SEC$document_sec_num";
5388                        $section_ref->{'seen'} = 1;
5389                        $section_ref->{'index_names'} = [];
5390                        $section_ref->{'current_place'} = [];
5391                        $section_ref->{'place'} = [];
5392                        $section_ref->{'section'} = 1;
5393                        $section_ref->{'line_nr'} = $line_nr;
5394
5395                        if ($tag eq 'top')
5396                        {
5397                            $section_ref->{'number'} = '';
5398                            $section_ref->{'id'} = "SEC_Top";
5399                            $section_ref->{'sec_num'} = 0;
5400                            if (defined($section_top))
5401                            {
5402                               line_error ("\@top already exists", $line_nr);
5403                               $sections{0} = $section_ref;
5404                            }
5405                            else
5406                            {
5407                               $sections{0.1} = $section_ref;
5408                            }
5409                            $section_top = $section_ref;
5410                        }
5411                        else
5412                        {
5413                            $sections{$section_ref->{'sec_num'}} = $section_ref;
5414                        }
5415                        merge_element_before_anything($section_ref);
5416                        if ($state->{'node_ref'})
5417                        {
5418                            $section_ref->{'node_ref'} = $state->{'node_ref'};
5419                            push @{$state->{'node_ref'}->{'sections'}}, $section_ref;
5420                        }
5421                        if ($state->{'node_ref'} and !exists($state->{'node_ref'}->{'with_section'}))
5422                        {
5423                            my $node_ref = $state->{'node_ref'};
5424                            $section_ref->{'with_node'} = $node_ref;
5425                            $section_ref->{'titlefont'} = $node_ref->{'titlefont'};
5426                            $node_ref->{'with_section'} = $section_ref;
5427                        }
5428                        if (! $name and $section_ref->{'level'})
5429                        {
5430                            line_warn (sprintf(__("\@%s requires an argument"), $tag), $line_nr);
5431                        }
5432                        push @sections_list, $section_ref;
5433                        push @all_elements, $section_ref;
5434                        $state->{'heading_element'} = $section_ref;
5435                        $state->{'current_element'} = $section_ref;
5436                        $state->{'place'} = $section_ref->{'current_place'};
5437                        ################# debug
5438                        my $node_ref = "NO NODE";
5439                        my $node_texi ='';
5440                        if ($state->{'node_ref'})
5441                        {
5442                            $node_ref = $state->{'node_ref'};
5443                            $node_texi = $state->{'node_ref'}->{'texi'};
5444                        }
5445                        print STDERR "# pass_structure node($node_ref)$node_texi, tag \@$tag($section_ref->{'level'}) ref $section_ref, num,id $section_ref->{'sec_num'},$section_ref->{'id'}\n   $name\n"
5446                           if $T2H_DEBUG & $DEBUG_ELEMENTS;
5447                        ################# end debug
5448                    }
5449                }
5450                elsif ($cline =~ /^\@insertcopying\s*/)
5451                {
5452                    @added_lines = @{$region_lines{'copying'}};
5453                    @added_numbers = @{$region_line_nrs{'copying'}};
5454                    unshift (@$texi_lines, @added_lines);
5455                    unshift (@$lines_numbers, @added_numbers);
5456                    next;
5457                }
5458                if (exists($state->{'region_lines'}))
5459                {
5460                    push @{$region_lines{$state->{'region_lines'}->{'format'}}}, @added_lines;
5461                    if ($Texi2HTML::Config::region_formats_kept{$state->{'region_lines'}->{'format'}})
5462                    { # the region is kept in the document in addition with
5463                      # being put in the appropriate region_lines entry.
5464                        push @doc_lines, @added_lines;
5465                        push @doc_numbers, @added_numbers;
5466                    }
5467                }
5468                else
5469                {
5470                    push @doc_lines, @added_lines;
5471                    push @doc_numbers, @added_numbers;
5472                }
5473                next;
5474            }
5475        }
5476        if (scan_structure ($cline, \$text, \@stack, $state, $line_nr))
5477        {
5478            if (!exists($state->{'region_lines'}) or $Texi2HTML::Config::region_formats_kept{$state->{'region_lines'}->{'format'}})
5479            {
5480                 push (@doc_numbers, $line_nr);
5481            }
5482            if (exists($state->{'region_lines'}))
5483            {
5484                 push @{$region_line_nrs{$state->{'region_lines'}->{'format'}}}, $line_nr unless ($state->{'region_lines'}->{'first_line'});
5485            }
5486        }
5487        next if (scalar(@stack) or $state->{'in_deff_line'});
5488        $cline = $text;
5489        $text = '';
5490        next if (!defined($cline));
5491        if ($state->{'region_lines'})
5492        {
5493            # the first line is like @copying, it is not put in the region
5494            # lines
5495            push @{$region_lines{$state->{'region_lines'}->{'format'}}}, split_lines($cline) unless ($state->{'region_lines'}->{'first_line'});
5496            delete $state->{'region_lines'}->{'first_line'};
5497            push @doc_lines, split_lines($cline) if ($Texi2HTML::Config::region_formats_kept{$state->{'region_lines'}->{'format'}});
5498        }
5499        else
5500        {
5501            push @doc_lines, split_lines($cline);
5502        }
5503    }
5504    if (@stack)
5505    {# close stack at the end of pass structure
5506        close_stack_structure(\$text, \@stack, $state, $line_nr);
5507        if ($text)
5508        {
5509            if (!exists($state->{'region_lines'}) or $Texi2HTML::Config::region_formats_kept{$state->{'region_lines'}->{'format'}})
5510            {
5511                push @doc_lines, split_lines($text);
5512            }
5513            if (exists($state->{'region_lines'}))
5514            {
5515                push @{$region_lines{$state->{'region_lines'}->{'format'}}},
5516                   split_lines($text);
5517            }
5518        }
5519    }
5520    #line_warn ("Expected $state->{'region_lines'}->{'number'} \@end $state->{'region_lines'}->{'format'}", $line_nr) if (exists($state->{'region_lines'}));
5521    line_error (sprintf(__("Expected \@end %s"), $state->{'region_lines'}->{'format'}), $line_nr) if (exists($state->{'region_lines'}));
5522    print STDERR "# end of pass structure\n" if $T2H_VERBOSE;
5523    # To remove once they are handled
5524    #print STDERR "No node nor section, texi2html won't be able to place things rightly\n" if ($element_before_anything->{'place'} and @{$element_before_anything->{'place'}});
5525    return (\@doc_lines, \@doc_numbers);
5526}
5527
5528# split line at end of line and put each resulting line in an array
5529# FIXME there must be a more perlish way to do it... Not a big deal
5530# as long as it work
5531sub split_lines($)
5532{
5533   my $line = shift;
5534   my @result = ();
5535   return @result if (!defined($line));
5536   my $i = 0;
5537   while ($line ne '')
5538   {
5539       $result[$i] = '';
5540       $line =~ s/^(.*)//;
5541       $result[$i] .= $1;
5542       $result[$i] .= "\n" if ($line =~ s/^\n//);
5543       #print STDERR "$i: $result[$i]";
5544       $i++;
5545   }
5546   return @result;
5547}
5548
5549# handle @documentlanguage
5550sub do_documentlanguage($$$$)
5551{
5552    my $command = shift;
5553    my $line = shift;
5554    my $silent = shift;
5555    my $line_nr = shift;
5556    my $language_change_succes = 0;
5557    if ($line =~ s/\s+(\w+)\s*//)
5558    {
5559        my $lang = $1;
5560        my $prev_lang = Texi2HTML::Config::get_conf('documentlanguage');
5561        # This won't be done if the documentlanguage was set on the command line
5562        if (Texi2HTML::Config::set_conf('documentlanguage', $lang, 1))
5563        {
5564            warn_unknown_language ($lang, $line_nr) unless ($silent);
5565            $language_change_succes = set_document_language($lang, $silent, $line_nr);
5566            if (!$language_change_succes)
5567            { # reset previous documentlanguage
5568                Texi2HTML::Config::set_conf('documentlanguage', $prev_lang, 1);
5569                line_warn (sprintf(__("Translations for `%s' not found. Reverting to `%s'"),$lang, $prev_lang), $line_nr) unless ($silent);
5570            }
5571        }
5572        # FIXME warn about stuff remaining on the line?
5573    }
5574    return $language_change_succes;
5575}
5576
5577# actions that should be done in more than one pass. In fact most are not
5578# to be done in pass_texi. The $pass argument is the number of the pass,
5579# 0 for pass_texi, 1 for pass_structure, 2 for pass_text
5580sub common_misc_commands($$$$)
5581{
5582    my $command = shift;
5583    my $line = shift;
5584    my $pass = shift;
5585    my $line_nr = shift;
5586
5587    # for error messages
5588    my $cline = $line;
5589    chomp($cline);
5590    $cline =~ s/^\s*//;
5591
5592    # track variables
5593    if ($command eq 'set')
5594    {
5595        if ($line =~ /^(\s+)($VARRE)(\s+)(.*)$/)
5596        {
5597             $value{$2} = $4;
5598        }
5599        else
5600        {
5601             line_error (sprintf(__("%c%s requires a name"), ord('@'), $command), $line_nr) if (!$pass);
5602        }
5603    }
5604    elsif ($command eq 'clear')
5605    {
5606        if ($line =~ /^(\s+)($VARRE)/)
5607        {
5608            delete $value{$2};
5609        }
5610        else
5611        {
5612             line_error (sprintf(__("%c%s requires a name"), ord('@'), $command), $line_nr) if (!$pass);
5613        }
5614    }
5615    elsif ($command eq 'clickstyle')
5616    {
5617        if ($line =~ s/^\s+@([^\s\{\}\@]+)(\{\})?\s*//)
5618        {
5619            $Texi2HTML::THISDOC{$command} = $1;
5620            # FIXME warn about what remains on the line?
5621        }
5622        else
5623        {
5624            line_error (sprintf(__("\@%s should only accept a \@-command as argument, not `%s'"), $command, $cline), $line_nr) if ($pass == 1);
5625        }
5626    }
5627    elsif ($command eq 'novalidate')
5628    {
5629        Texi2HTML::Config::set_conf($command, 1, 1);
5630    }
5631    if ($pass)
5632    { # these commands are only taken into account here in pass_structure 1
5633      # and pass_text 2
5634        if ($command eq 'setfilename')
5635        {
5636            my $filename = trim_comment_spaces($line, "\@$command");
5637            $filename = substitute_line($filename, "\@$command",{'code_style' => 1, 'remove_texi' => 1});
5638            if ($filename ne '')
5639            {
5640                Texi2HTML::Config::set_conf($command, $filename, 1);
5641            }
5642        }
5643        elsif ($command eq 'paragraphindent')
5644        {
5645            if ($line =~ /\s+([\w\-]+)[^\w\-]/)
5646            {
5647               set_paragraphindent ($1, 0, $line_nr, $pass);
5648            }
5649            else
5650            {
5651               set_paragraphindent ($line, 0, $line_nr, $pass);
5652            }
5653        }
5654        elsif ($command eq 'firstparagraphindent')
5655        {
5656            if (($line =~ /^\s+(none)[^\w\-]/) or ($line =~ /^\s+(insert)[^\w\-]/))
5657            {
5658                Texi2HTML::Config::set_conf($command, $1, 1);
5659            }
5660            else
5661            {
5662                line_error (sprintf(__("\@firstparagraphindent arg must be `none' or `insert', not `%s'"), $cline), $line_nr) if ($pass == 1);
5663            }
5664        }
5665        elsif ($command eq 'exampleindent')
5666        {
5667            if ($line =~ /^\s+([0-9]+)/)
5668            {
5669                $Texi2HTML::THISDOC{$command} = $1;
5670            }
5671            elsif ($line =~ /^\s+(asis)[^\w\-]/)
5672            {
5673                $Texi2HTML::THISDOC{$command} = $1;
5674            }
5675            else
5676            {
5677                line_error (sprintf(__("\@exampleindent arg must be numeric/`asis', not `%s'"), $cline), $line_nr) if ($pass == 1);
5678            }
5679        }
5680        elsif ($command eq 'frenchspacing')
5681        {
5682            if (($line =~ /^\s+(on)[^\w\-]/) or ($line =~ /^\s+(off)[^\w\-]/))
5683            {
5684                Texi2HTML::Config::set_conf($command, $1, 1);
5685            }
5686            else
5687            {
5688                line_error (sprintf(__("Expected \@%s on or off, not `%s'"), $command, $cline), $line_nr) if ($pass == 1);
5689            }
5690        }
5691        elsif ($command eq 'kbdinputstyle')
5692        {
5693            if ($line =~ /\s+([a-z]+)/ and ($1 eq 'code' or $1 eq 'example' or $1 eq 'distinct'))
5694            {
5695                Texi2HTML::Config::set_conf($command, $1, 1);
5696            }
5697            else
5698            {
5699                line_error (sprintf(__("\@kbdinputstyle arg must be `code'/`example'/`distinct', not `%s'"), $cline), $line_nr) if ($pass == 1);
5700            }
5701        }
5702        elsif (grep {$command eq $_} ('everyheading', 'everyfooting',
5703              'evenheading', 'evenfooting', 'oddheading', 'oddfooting'))
5704        { # FIXME have a _texi and without texi, and without texi,
5705          # and expand rightly @this*? And use @| to separate, and give
5706          # an array for user consumption? This should be done for each new
5707          # chapter, section, and page. What is a page is not necessarily
5708          # well defined in html, however...
5709          # @thisfile is the @include file. Should be in $line_nr.
5710
5711          # Also if that command appears in the texi, the error message is
5712          # Unknown command `@evenheading'
5713          # It could be better.
5714            my $arg = $line;
5715            $arg =~ s/^\s+//;
5716            $Texi2HTML::THISDOC{$command} = $arg;
5717        }
5718        elsif ($command eq 'allowcodebreaks')
5719        {
5720            if (($line =~ /^\s+(true)[^\w\-]/) or ($line =~ /^\s+(false)[^\w\-]/))
5721            {
5722                Texi2HTML::Config::set_conf($command, $1, 1);
5723            }
5724            else
5725            {
5726                line_error (sprintf(__("\@allowcodebreaks arg must be `true' or `false', not `%s'"), $cline), $line_nr) if ($pass == 1);
5727            }
5728        }
5729        elsif ($command eq 'headings')
5730        {
5731            my $valid_arg = 0;
5732            foreach my $possible_arg (('off','on','single','double',
5733                          'singleafter','doubleafter'))
5734            {
5735                if ($line =~ /^\s+($possible_arg)[^\w\-]/)
5736                {
5737                    $valid_arg = 1;
5738                    $Texi2HTML::THISDOC{$command} = $possible_arg;
5739                    last;
5740                }
5741            }
5742            unless ($valid_arg)
5743            {
5744                line_error (sprintf(__("Bad argument to \@%s: %s"), $command, $cline), $line_nr) if ($pass == 1);
5745            }
5746        }
5747        elsif ($command eq 'documentlanguage')
5748        {
5749            if (do_documentlanguage($command, $line, $pass -1, $line_nr))
5750            {
5751                &$Texi2HTML::Config::translate_names();
5752                set_special_names();
5753            }
5754        }
5755    }
5756}
5757
5758sub misc_command_texi($$$$)
5759{
5760   my $line = shift;
5761   my $command = shift;
5762   my $state = shift;
5763   my $line_nr = shift;
5764   my $text;
5765   my $args;
5766   my $cline = $line;
5767
5768   if (!$state->{'ignored'} and !$state->{'arg_expansion'})
5769   {
5770      if ($command eq 'documentencoding')
5771      {  # FIXME accept more characters, like @?
5772         if ($cline =~ s/^(\s+)([\w\-]+)//)
5773         {
5774            my $encoding = $2;
5775            $Texi2HTML::THISDOC{'documentencoding'} = $encoding;
5776            line_warn(sprintf(__("Encoding %s is not a canonical texinfo encoding"), $encoding), $line_nr)
5777                if (!$Texi2HTML::Config::canonical_texinfo_encodings{lc($encoding)});
5778            if (Texi2HTML::Config::set_conf('DOCUMENT_ENCODING', $Texi2HTML::THISDOC{'documentencoding'}, 1))
5779            {
5780               my $from_encoding;
5781               if (!defined($Texi2HTML::Config::IN_ENCODING))
5782               {
5783                  $from_encoding = encoding_alias($encoding, $line_nr);
5784                  Texi2HTML::Config::set_conf('IN_ENCODING', $from_encoding, 1)
5785                     if (defined($from_encoding));
5786               }
5787               if (defined($from_encoding) and $Texi2HTML::Config::USE_UNICODE)
5788               {
5789                  foreach my $file (@{$state->{'files_stack'}})
5790                  {
5791                     binmode($file->{'fh'}, ":encoding($from_encoding)");
5792                  }
5793               }
5794            }
5795            #FIXME error if garbage remains on the line?
5796         }
5797         else
5798         {
5799            line_error(sprintf(__("\@%s arg must be an encoding"), $command), $line_nr);
5800         }
5801      }
5802      elsif ($command eq 'alias')
5803      {
5804          if ($line =~ /(\s+)([a-zA-Z][\w-]*)(\s*=\s*)([a-zA-Z][\w-]*)(\s*)/)
5805          {
5806               $alias{$2} = $4;
5807          }
5808          else
5809          {
5810               line_error (sprintf(__("Bad argument to \@%s"), $command), $line_nr);
5811          }
5812      }
5813      elsif ($command eq 'definfoenclose')
5814      {
5815          if ($cline =~ s/^\s+([a-z][\w\-]*)\s*,\s*([^\s]+)\s*,\s*([^\s]+)//)
5816          {
5817             $info_enclose{$1} = [ $2, $3 ];
5818          }
5819          else
5820          {
5821             line_error (sprintf(__("Bad argument to \@%s"), $command), $line_nr);
5822          } # FIXME warn about garbage remaining on the line?
5823      }
5824      else
5825      {
5826          if ($command eq 'setfilename' and $Texi2HTML::Config::USE_SETFILENAME)
5827          { # a double setfillename is removed before calling misc_command_texi
5828             my $filename = trim_comment_spaces($line, "\@$command");
5829             $filename = substitute_line($filename, "\@$command",{'code_style' => 1, 'remove_texi' => 1}, $line_nr);
5830             if ($filename ne '')
5831             {
5832                 Texi2HTML::Config::set_conf($command, $filename, 1);
5833                 # remove extension
5834                 $filename =~ s/\.[^\.]*$//;
5835                 init_with_file_name ($filename) if ($filename ne '');
5836             }
5837          }
5838          # in reality, do only set, clear and clickstyle.
5839          # though we should never go there for clickstyle...
5840          common_misc_commands($command, $line, 0, $line_nr);
5841      }
5842   }
5843
5844   ($line, $text, $args) = &$Texi2HTML::Config::preserve_misc_command($line, $command);
5845   return ($line, $text);
5846}
5847
5848sub new_content_element($)
5849{
5850   my $command = shift;
5851   $command = 'shortcontents' if ($command ne 'contents');
5852   my $element;
5853   foreach my $key (keys(%{$reference_content_element{$command}}))
5854   {
5855      $element->{$key} = $reference_content_element{$command}->{$key};
5856   }
5857   return $element;
5858}
5859
5860# handle misc commands and misc command args
5861sub misc_command_structure($$$$)
5862{
5863    my $line = shift;
5864    my $command = shift;
5865    my $state = shift;
5866    my $line_nr = shift;
5867    my $text;
5868    my $args;
5869    # for error messages
5870    my $cline = $line;
5871    chomp $cline;
5872    $cline =~ s/^\s*//;
5873
5874    if ($command eq 'lowersections')
5875    {
5876        my ($sec, $level);
5877        while (($sec, $level) = each %sec2level)
5878        {
5879            $sec2level{$sec} = $level + 1 if ($reference_sec2level{$sec} > 0);
5880        }
5881        $state->{'sectionning_base'}--;
5882    }
5883    elsif ($command eq 'raisesections')
5884    {
5885        my ($sec, $level);
5886        while (($sec, $level) = each %sec2level)
5887        {
5888            $sec2level{$sec} = $level - 1 if ($reference_sec2level{$sec} > 0);
5889        }
5890        $state->{'sectionning_base'}++;
5891    }
5892    elsif (($command eq 'contents') or ($command eq 'summarycontents') or ($command eq 'shortcontents'))
5893    {
5894        if ($command ne 'contents')
5895        {
5896            $command = 'shortcontents';
5897        }
5898        Texi2HTML::Config::set_conf($command, 1, 1);
5899        my $new_content_element = new_content_element($command);
5900        push @{$state->{'place'}}, $new_content_element;
5901        push @{$all_content_elements{$command}}, $new_content_element;
5902    }
5903    elsif ($command eq 'dircategory')
5904    {
5905        my $arg = trim_comment_spaces ($line, "\@$command");
5906        $Texi2HTML::THISDOC{"${command}_texi"} = $arg;
5907        $Texi2HTML::THISDOC{$command} = substitute_line($arg, "\@$command");
5908    }
5909    elsif (grep {$_ eq $command} ('settitle','shorttitlepage','title'))
5910    {
5911        my $arg = trim_comment_spaces($line, "\@$command");
5912        $Texi2HTML::THISDOC{$command . '_texi'} = $arg;
5913        $Texi2HTML::THISDOC{$command . '_line_nr'} = $line_nr;
5914
5915        # FIXME backward compatibility. Obsoleted in nov 2009.
5916        $value{"_$command"} = $arg;
5917        if ($command eq 'title')
5918        { # FIXME This was obsoleted in jun 2007
5919            $Texi2HTML::THISDOC{"${command}s_texi"} = [ $arg ];
5920        }
5921    }
5922    elsif (grep {$_ eq $command} ('author','subtitle'))
5923    {
5924        my $arg = trim_comment_spaces($line, "\@$command");
5925        $Texi2HTML::THISDOC{$command . '_texi'} .= $arg . "\n";
5926        if ($state->{'region'} and $state->{'region'} eq 'titlepage')
5927        {
5928           push @{$Texi2HTML::THISDOC{"${command}s_texi"}}, $arg;
5929           push @{$Texi2HTML::THISDOC{"${command}s_line_nr"}}, $line_nr;
5930        }
5931        #chomp($arg);
5932
5933        # FIXME backward compatibility. Obsoleted in nov 2009.
5934        $value{"_$command"} .= $arg . "\n";
5935    }
5936    elsif ($command eq 'synindex' || $command eq 'syncodeindex')
5937    {
5938        if ($line =~ /^\s+(\w+)\s+(\w+)/)
5939        {
5940            my $index_from = $1;
5941            my $index_to = $2;
5942            line_error (sprintf(__("Unknown from index `%s' in \@%s"), $index_from, $command), $line_nr)
5943                unless $index_names{$index_from};
5944            line_error (sprintf(__("Unknown to index name `%s' in \@%s"), $index_to, $command), $line_nr)
5945                unless $index_names{$index_to};
5946            if ($index_names{$index_from} and $index_names{$index_to})
5947            {
5948                my $in_code = 0;
5949                $in_code = 1 if ($command eq 'syncodeindex');
5950                my $current_to = $index_to;
5951                while ($current_to ne $index_from and $Texi2HTML::THISDOC{'merged_index'}->{$current_to})
5952                {
5953                    $current_to = $Texi2HTML::THISDOC{'merged_index'}->{$current_to};
5954                }
5955                if ($current_to ne $index_from)
5956                {
5957                    foreach my $prefix (keys(%{$index_names{$index_from}->{'prefixes'}}))
5958                    {
5959                        $index_names{$current_to}->{'prefixes'}->{$prefix} = $in_code;
5960                        $index_prefix_to_name{$prefix} = $current_to;
5961                    }
5962                    $Texi2HTML::THISDOC{'merged_index'}->{$index_from} = $current_to;
5963                }
5964                push @{$Texi2HTML::THISDOC{$command}}, [$index_from,$index_to];
5965            }
5966        }
5967        else
5968        {
5969            line_error (sprintf(__("Bad argument to \@%s: %s"), $command, $cline), $line_nr);
5970        }
5971    }
5972    elsif ($command eq 'defindex' || $command eq 'defcodeindex')
5973    {
5974        if ($line =~ /^\s+(\w+)\s*$/)
5975        {
5976            my $name = $1;
5977            if ($forbidden_index_name{$name})
5978            {
5979                line_error(sprintf(__("Reserved index name %s"),$name), $line_nr);
5980            }
5981            else
5982            {
5983                my $in_code = 0;
5984                $in_code = 1 if ($command eq 'defcodeindex');
5985                # FIXME this leads to spurious error message in hello_nodes
5986                #if (defined($index_names{$name}))
5987                #{
5988                #    line_error(sprintf(__("Index `%s' already exists"),$name), $line_nr);
5989                #}
5990                $index_names{$name}->{'prefixes'}->{$name} = $in_code;
5991                $index_prefix_to_name{$name} = $name;
5992                push @{$Texi2HTML::THISDOC{$command}}, $name;
5993            }
5994        }
5995        else
5996        {
5997            line_error (sprintf(__("Bad argument to \@%s: %s"), $command, $cline), $line_nr);
5998        }
5999    }
6000    elsif (grep {$_ eq $command} ('everyheadingmarks','everyfootingmarks',
6001        'evenheadingmarks','oddheadingmarks','evenfootingmarks','oddfootingmarks'))
6002    {
6003        if (($line =~ /^\s+(top)[^\w\-]/) or ($line =~ /^\s+(bottom)[^\w\-]/))
6004        {
6005            $Texi2HTML::THISDOC{$command} = $1;
6006        }
6007        else
6008        {
6009            line_error (sprintf(__("\@%s arg must be `top' or `bottom', not `%s'"), $command, $cline), $line_nr);
6010        }
6011    }
6012    elsif ($command eq 'fonttextsize')
6013    {
6014        if (($line =~ /^\s+(10)[^\w\-]/) or ($line =~ /^\s+(11)[^\w\-]/))
6015        {
6016            $Texi2HTML::THISDOC{$command} = $1;
6017        }
6018        else
6019        {
6020            line_error (sprintf(__("Only \@%s 10 or 11 is supported, not `%s'"),$command, $cline), $line_nr);
6021        }
6022    }
6023    elsif ($command eq 'pagesizes')
6024    {
6025        if ($line =~ /^\s+(.*)\s*$/)
6026        {
6027            $Texi2HTML::THISDOC{$command} = $1;
6028        }
6029    }
6030    elsif ($command eq 'footnotestyle')
6031    {
6032        if ($line =~ /^\s+([a-z]+)[^\w\-]/)
6033        {
6034            set_footnote_style ($1, 0, $line_nr);
6035        }
6036        else
6037        {
6038            set_footnote_style ($line, 0, $line_nr);
6039        }
6040    }
6041    elsif ($command eq 'setchapternewpage')
6042    {
6043        if (($line =~ /^\s+(on)[^\w\-]/) or ($line =~ /^\s+(off)[^\w\-]/)
6044                or ($line =~ /^\s+(odd)[^\w\-]/))
6045        {
6046            $Texi2HTML::THISDOC{$command} = $1;
6047        }
6048        else
6049        {
6050            line_error (sprintf(__("\@%s arg must be `on', `off' or `odd', not `%s'"), $command, $cline), $line_nr);
6051        }
6052    }
6053    elsif ($command eq 'setcontentsaftertitlepage' or $command eq 'setshortcontentsaftertitlepage')
6054    {
6055        Texi2HTML::Config::set_conf($command, 1, 1);
6056    }
6057    elsif ($command eq 'need')
6058    { # only a warning
6059        unless (($line =~ /^\s+([0-9]+(\.[0-9]*)?)[^\w\-]/) or
6060                 ($line =~ /^\s+(\.[0-9]+)[^\w\-]/))
6061        {
6062            line_error (sprintf(__("Bad argument to \@%s: %s"), $command, $cline), $line_nr);
6063        }
6064    }
6065    else
6066    {
6067        common_misc_commands($command, $line, 1, $line_nr);
6068    }
6069
6070    ($text, $line, $args) = &$Texi2HTML::Config::preserve_misc_command($line, $command);
6071    return ($text, $line);
6072}
6073
6074sub set_special_names()
6075{
6076    $Texi2HTML::NAME{'About'} = gdt('About This Document');
6077    $Texi2HTML::NAME{'Contents'} = gdt('Table of Contents');
6078    $Texi2HTML::NAME{'Overview'} = gdt('Short Table of Contents');
6079    $Texi2HTML::NAME{'Footnotes'} = gdt('Footnotes');
6080    $Texi2HTML::NO_TEXI{'About'} = gdt('About This Document', {}, {'remove_texi' => 1} );
6081    $Texi2HTML::NO_TEXI{'Contents'} = gdt('Table of Contents', {}, {'remove_texi' => 1} );
6082    $Texi2HTML::NO_TEXI{'Overview'} = gdt('Short Table of Contents', {}, {'remove_texi' => 1} );
6083    $Texi2HTML::NO_TEXI{'Footnotes'} = gdt('Footnotes', {}, {'remove_texi' => 1} );
6084    $Texi2HTML::SIMPLE_TEXT{'About'} = gdt('About This Document', {}, {'simple_format' => 1});
6085    $Texi2HTML::SIMPLE_TEXT{'Contents'} = gdt('Table of Contents',{},  {'simple_format' => 1});
6086    $Texi2HTML::SIMPLE_TEXT{'Overview'} = gdt('Short Table of Contents', {}, {'simple_format' => 1});
6087    $Texi2HTML::SIMPLE_TEXT{'Footnotes'} = gdt('Footnotes', {},{'simple_format' => 1});
6088}
6089
6090sub enter_author_command($$$$$$)
6091{
6092    my $command = shift;
6093    my $texi = shift;
6094    my $text = shift;
6095    my $stack = shift;
6096    my $state = shift;
6097    my $line_nr = shift;
6098    $texi = trim_comment_spaces($texi, "\@$command");
6099    if ($command eq 'author')
6100    {
6101        my $top_format = top_stack($stack, 2);
6102        if (defined($top_format) and $format_type{$top_format->{'format'}} eq 'quotation')
6103        {
6104            push @{$top_format->{'quote_authors'}}, {'author_texi' => $texi, 'author_text' => $text};
6105        }
6106        elsif (!$state->{'region'} or $state->{'region'} ne 'titlepage')
6107        {
6108            line_warn (sprintf(__("\@%s not meaningful outside `\@titlepage' and `\@quotation' environments"), $command), $line_nr);
6109        }
6110    }
6111}
6112
6113# return the line after removing things according to misc_command map.
6114# if the skipped command has an effect it is done here
6115# this is used during pass_text
6116sub misc_command_text($$$$$$)
6117{
6118    my $line = shift;
6119    my $command = shift;
6120    my $stack = shift;
6121    my $state = shift;
6122    my $text = shift;
6123    my $line_nr = shift;
6124    my ($skipped, $remaining, $args, $result);
6125
6126    # The strange condition associated with 'keep_texi' is
6127    # there because for an argument appearing on an @itemize
6128    # line (we're in 'check_item'), meant to be prepended to an
6129    # @item we don't want to keep @c or @comment as otherwise it
6130    # eats the @item line. Other commands could do that too but
6131    # then the user deserves what he gets.
6132    if ($state->{'keep_texi'} and
6133        (!$state->{'check_item'} or ($command ne 'c' and $command ne 'comment')))
6134    {
6135        ($remaining, $skipped, $args) = &$Texi2HTML::Config::preserve_misc_command($line, $command);
6136        add_prev($text, $stack, "\@$command". $skipped);
6137        return $remaining;
6138    }
6139
6140    ($remaining, $skipped, $args) = &$Texi2HTML::Config::preserve_misc_command($line, $command);
6141
6142    if ($state->{'remove_texi'})
6143    {
6144        ($command, $line, $result) = &$Texi2HTML::Config::misc_command_line_texi($command, $line, $args, $stack, $state);
6145    }
6146    else
6147    {
6148        ($command, $line, $result) = &$Texi2HTML::Config::misc_command_line($command, $line, $args, $stack, $state);
6149    }
6150
6151    enter_author_command ($command, $line, $result, $stack, $state, $line_nr);
6152
6153    # for error messages
6154    my $cline = $line;
6155    $cline =~ s/^\s*//;
6156    chomp $cline;
6157
6158    # if it is true the command args are kept so the user can modify how
6159    # they are skipped and handle them as unknown @-commands. Nowadays, it is
6160    # not that interesting since using misc_command_line above should do
6161    # about the same more simply.
6162    my $keep = $Texi2HTML::Config::misc_command{$command}->{'keep'};
6163
6164    if ($command eq 'sp')
6165    {
6166        my $sp_number;
6167        if ($line =~ /^\s+(\d+)\s/)
6168        {
6169            $sp_number = $1;
6170        }
6171        elsif ($line =~ /(\s*)$/)
6172        {
6173            $sp_number = '';
6174        }
6175        else
6176        {
6177            line_error (sprintf(__("\@sp requires a positive numeric argument, not `%s'"), $cline), $line_nr);
6178        }
6179        $sp_number = 1 if ($sp_number eq '');
6180        if (!$state->{'remove_texi'})
6181        {
6182            add_prev($text, $stack, &$Texi2HTML::Config::sp($sp_number, $state->{'preformatted'}));
6183        }
6184    }
6185    elsif($command eq 'verbatiminclude' and !$keep)
6186    {
6187        if ($line =~ /\s+(.+)/)
6188        {
6189            my $arg = $1;
6190            $arg = trim_around_spaces($arg);
6191            my $file_name = substitute_line($arg, "\@$command", {'code_style' => 1});
6192            my $file = locate_include_file($file_name);
6193            if (defined($file))
6194            {
6195                if (!open(VERBINCLUDE, $file))
6196                {
6197                    line_error (sprintf(__("Cannot read %s: %s"), $file, $!), $line_nr);
6198                }
6199                else
6200                {
6201                    my $verb_text = '';
6202                    while (my $verb_line = <VERBINCLUDE>)
6203                    {
6204                        $verb_text .= $verb_line;
6205                    }
6206
6207                    if ($state->{'remove_texi'})
6208                    {
6209                        add_prev ($text, $stack, &$Texi2HTML::Config::raw_no_texi('verbatiminclude', $verb_text));
6210                    }
6211                    else
6212                    {
6213                        add_prev($text, $stack, &$Texi2HTML::Config::raw('verbatiminclude', $verb_text, $line_nr));
6214                    }
6215                    close VERBINCLUDE;
6216                }
6217            }
6218            else
6219            {
6220                line_error (sprintf(__("\@%s: Cannot find %s"), $command, $file_name), $line_nr);
6221            }
6222        }
6223        else
6224        {
6225            line_error (sprintf(__("Bad argument to \@%s: %s"), $command, $cline), $line_nr);
6226        }
6227    }
6228    elsif ($command eq 'indent' or $command eq 'noindent')
6229    {
6230        $state->{'paragraph_indent'} = $command;
6231    }
6232    else
6233    {
6234        common_misc_commands($command, $line, 2, $line_nr);
6235    }
6236
6237    return ($skipped.$remaining, $result) if ($keep);
6238    return ($remaining, $result);
6239}
6240
6241# merge the things appearing before the first @node or sectioning command
6242# (held by element_before_anything) with the current element
6243# do that only once.
6244sub merge_element_before_anything($)
6245{
6246    my $element = shift;
6247    if (exists($element_before_anything->{'place'}))
6248    {
6249        $element->{'current_place'} = $element_before_anything->{'place'};
6250        delete $element_before_anything->{'place'};
6251        foreach my $placed_thing (@{$element->{'current_place'}})
6252        {
6253            $placed_thing->{'element'} = $element if (exists($placed_thing->{'element'}));
6254        }
6255    }
6256    # this is certainly redundant with the above condition, but cleaner
6257    # that way
6258    if (exists($element_before_anything->{'titlefont'}))
6259    {
6260        $element->{'titlefont'} = $element_before_anything->{'titlefont'};
6261        delete $element_before_anything->{'titlefont'};
6262    }
6263}
6264
6265# find menu_prev, menu_up... for a node in menu
6266sub menu_entry_texi($$$)
6267{
6268    my $node = shift;
6269    my $state = shift;
6270    my $line_nr = shift;
6271    return if ($state->{'direntry'});
6272    my $node_menu_ref = {};
6273    if (exists($nodes{$node}))
6274    {
6275        $node_menu_ref = $nodes{$node};
6276    }
6277    else
6278    {
6279        $nodes{$node} = $node_menu_ref;
6280        $node_menu_ref->{'texi'} = $node;
6281        $node_menu_ref->{'external_node'} = 1 if ($node =~ /^\(.+\)/);
6282    }
6283    return if ($state->{'detailmenu'});
6284    if ($state->{'node_ref'})
6285    {
6286        if ($node_menu_ref->{'menu_up'} and !$node_menu_ref->{'external_node'})
6287        {
6288           # This is not an error. This is used a lot in real life manuals
6289           #line_warn ("Double entry in menu for `$node' (also below `$node_menu_ref->{'menu_up'}->{'texi'}')", $line_nr);
6290        }
6291        $node_menu_ref->{'menu_up'} = $state->{'node_ref'};
6292        $node_menu_ref->{'menu_up_hash'}->{$state->{'node_ref'}->{'texi'}} = 1;
6293    }
6294    if ($state->{'prev_menu_node'})
6295    {
6296        $node_menu_ref->{'menu_prev'} = $state->{'prev_menu_node'};
6297        $state->{'prev_menu_node'}->{'menu_next'} = $node_menu_ref;
6298    }
6299    elsif ($state->{'node_ref'} and !$state->{'node_ref'}->{'menu_child'})
6300    {
6301        $state->{'node_ref'}->{'menu_child'} = $node_menu_ref;
6302    }
6303    $state->{'prev_menu_node'} = $node_menu_ref;
6304}
6305
6306my @index_labels;                  # array corresponding with @?index commands
6307                                   # constructed during pass_structure, used to
6308                                   # put labels in pass_text
6309my @unknown_index_index_entries;   # array of index entries not associated
6310                                   # with any index
6311
6312sub sorted_line($)
6313{
6314   my $line = shift;
6315   $::texi_map_ref = \%Texi2HTML::Config::sorting_things_map;
6316   my $result = remove_texi($line);
6317   $::texi_map_ref = \%Texi2HTML::Config::texi_map;
6318   return $result;
6319}
6320
6321sub prepare_indices()
6322{
6323    #print STDERR "Do splitting of index letters, once.\n";
6324
6325    foreach my $index_name(keys %{$Texi2HTML::THISDOC{'index_entries_array'}})
6326    {
6327        #print STDERR "$Texi2HTML::THISDOC{'index_entries_array'}->{$index_name}) letters\n";
6328        my %letters_hash;
6329        foreach my $index_entry (@{$Texi2HTML::THISDOC{'index_entries_array'}->{$index_name}})
6330        {
6331          my $key = sorted_line($index_entry->{'texi'});
6332          $index_entry->{'key'} = $key;
6333          my $letter = uc(substr($key, 0, 1));
6334          push @{$letters_hash{$letter}}, $index_entry;
6335        }
6336
6337        # use cmp if only letters or only symbols, otherwise symbols before
6338        # letters
6339        foreach my $letter (sort {
6340           ((($a =~ /^[[:alpha:]]/ and $b =~ /^[[:alpha:]]/) or
6341            ($a !~ /^[[:alpha:]]/ and $b !~ /^[[:alpha:]]/)) && $a cmp $b)
6342             || ($a =~ /^[[:alpha:]]/ && 1) || -1 } (keys %letters_hash))
6343        {
6344          # FIXME sort without uc?
6345          # This sorts the entries for a given letter
6346          my @sorted_letter_entries = (sort {uc($a->{'key'}) cmp uc($b->{'key'})} (@{$letters_hash{$letter}}));
6347
6348          push @{$Texi2HTML::THISDOC{'index_letters_array'}->{$index_name}}, { 'letter' => $letter, 'entries' => \@sorted_letter_entries };
6349        }
6350    }
6351
6352    # generate the keys for index sorting also for the entries not
6353    # associated with an index.
6354    foreach my $index_entry_without_index (@unknown_index_index_entries)
6355    {
6356       my $key = sorted_line($index_entry_without_index->{'texi'});
6357       $index_entry_without_index->{'key'} = $key;
6358    }
6359    Texi2HTML::Config::t2h_default_init_split_indices();
6360}
6361
6362# This function is used to construct link names from node names as
6363# specified for texinfo
6364sub cross_manual_links()
6365{
6366    my @all_index_entries;
6367    foreach my $index_name (sort(keys(%{$Texi2HTML::THISDOC{'index_entries_array'}})))
6368    {
6369       push @all_index_entries, @{$Texi2HTML::THISDOC{'index_entries_array'}->{$index_name}};
6370    }
6371    print STDERR "# Doing ".scalar(keys(%nodes))." cross manual links ".
6372      scalar(@all_index_entries). " index entries\n"
6373       if ($T2H_DEBUG);
6374    $::simple_map_texi_ref = \%cross_ref_simple_map_texi;
6375    $::style_map_texi_ref = \%cross_ref_style_map_texi;
6376    $::texi_map_ref = \%cross_ref_texi_map;
6377    my $normal_text_kept = $Texi2HTML::Config::normal_text;
6378    $Texi2HTML::Config::normal_text = \&Texi2HTML::Config::t2h_cross_manual_normal_text;
6379    my $style_kept = $Texi2HTML::Config::style;
6380    $Texi2HTML::Config::style = \&Texi2HTML::Config::T2H_GPL_style;
6381
6382    foreach my $key (keys(%nodes))
6383    {
6384        my $node = $nodes{$key};
6385        #print STDERR "CROSS_MANUAL:$key,$node\n";
6386        if (!defined($node->{'texi'}))
6387        {
6388            ###################### debug section
6389            foreach my $key (keys(%$node))
6390            {
6391                #print STDERR "$key:$node->{$key}!!!\n";
6392            }
6393            ###################### end debug section
6394        }
6395        else
6396        {
6397            $node->{'cross_manual_target'} = remove_texi($node->{'texi'});
6398            if ($node->{'cross_manual_target'} !~ /\S/)
6399            {
6400                line_error (sprintf(__("Empty node name after expansion `%s'"), $node->{'texi'}), $node->{'line_nr'});
6401                $node->{'cross_manual_target'} = 't_0';
6402                $node->{'cross_manual_file'} = 't_0';
6403            }
6404            elsif ($Texi2HTML::Config::USE_UNICODE)
6405            {
6406                $node->{'cross_manual_target'} = Unicode::Normalize::NFC($node->{'cross_manual_target'});
6407                if ($Texi2HTML::Config::TRANSLITERATE_FILE_NAMES and $Texi2HTML::Config::USE_UNIDECODE)
6408                {
6409                     $node->{'cross_manual_file'} =
6410                       unicode_to_protected(unicode_to_transliterate($node->{'cross_manual_target'}));
6411                }
6412                $node->{'cross_manual_target'} =
6413                    unicode_to_protected($node->{'cross_manual_target'});
6414            }
6415#print STDERR "CROSS_MANUAL_TARGET $node->{'cross_manual_target'}\n";
6416            unless ($node->{'external_node'})
6417            {
6418                if (exists($cross_reference_nodes{$node->{'cross_manual_target'}}))
6419                {
6420                    my $other_node_array = $cross_reference_nodes{$node->{'cross_manual_target'}};
6421                    my $node_seen;
6422                    foreach my $other_node (@{$other_node_array})
6423                    { # find the first node seen for the error message
6424                        $node_seen = $other_node;
6425                        last if ($nodes{$other_node}->{'seen'})
6426                    }
6427                    my $other_node_line_nr = $nodes{$node_seen}->{'line_nr'};
6428                    if (defined($other_node_line_nr))
6429                    {
6430                        msg_error ("Node equivalent with `$node->{'texi'}' already used `$node_seen' ".format_line_number($other_node_line_nr), $node->{'line_nr'});
6431                    }
6432                    else
6433                    {
6434                        msg_error ("Node equivalent with `$node->{'texi'}' already used `$node_seen'", $node->{'line_nr'});
6435                    }
6436                    push @{$other_node_array}, $node->{'texi'};
6437                }
6438                else
6439                {
6440                    push @{$cross_reference_nodes{$node->{'cross_manual_target'}}}, $node->{'texi'};
6441                }
6442            }
6443        }
6444    }
6445
6446
6447    if ($Texi2HTML::Config::TRANSLITERATE_FILE_NAMES and
6448         (!$Texi2HTML::Config::USE_UNICODE or !$Texi2HTML::Config::USE_UNIDECODE))
6449    {
6450        $::style_map_texi_ref = \%cross_transliterate_style_map_texi;
6451        $::texi_map_ref = \%cross_transliterate_texi_map;
6452        $Texi2HTML::Config::normal_text = \&Texi2HTML::Config::t2h_cross_manual_normal_text_transliterate if (!$Texi2HTML::Config::USE_UNICODE);
6453
6454        foreach my $key (keys(%nodes))
6455        {
6456            my $node = $nodes{$key};
6457            #print STDERR "TRANSLITERATE:$key,$node\n";
6458            if (defined($node->{'texi'}))
6459            {
6460                 $node->{'cross_manual_file'} = remove_texi($node->{'texi'});
6461                 if ($node->{'cross_manual_file'} !~ /\S/)
6462                 {
6463                    $node->{'cross_manual_file'} = 't_0';
6464                 }
6465                 elsif ($Texi2HTML::Config::USE_UNICODE)
6466                 {
6467                    $node->{'cross_manual_file'} = unicode_to_protected(unicode_to_transliterate($node->{'cross_manual_file'}));
6468                 }
6469            }
6470        }
6471
6472        foreach my $entry (@all_index_entries, values(%sections), values(%headings))
6473        {
6474            #print STDERR "TRANSLITERATE($entry) $entry->{'texi'}\n";
6475            $entry->{'cross'} = remove_texi($entry->{'texi'});
6476            $entry->{'cross'} = unicode_to_protected(unicode_to_transliterate($entry->{'cross'})) if ($Texi2HTML::Config::USE_UNICODE);
6477        }
6478    }
6479    else
6480    {
6481        foreach my $entry (@all_index_entries, values(%sections), values(%headings))
6482        {
6483            $entry->{'cross'} = remove_texi($entry->{'texi'});
6484            if ($Texi2HTML::Config::USE_UNICODE)
6485            {
6486                $entry->{'cross'} = Unicode::Normalize::NFC($entry->{'cross'});
6487                if ($Texi2HTML::Config::TRANSLITERATE_FILE_NAMES and $Texi2HTML::Config::USE_UNIDECODE) # USE_UNIDECODE is redundant
6488                {
6489                     $entry->{'cross'} =
6490                       unicode_to_protected(unicode_to_transliterate($entry->{'cross'}));
6491                }
6492                else
6493                {
6494                     $entry->{'cross'} =
6495                        unicode_to_protected($entry->{'cross'});
6496                }
6497            }
6498        }
6499    }
6500
6501    $Texi2HTML::Config::normal_text = $normal_text_kept;
6502    $Texi2HTML::Config::style = $style_kept;
6503    $::simple_map_texi_ref = \%Texi2HTML::Config::simple_map_texi;
6504    $::style_map_texi_ref = \%Texi2HTML::Config::style_map_texi;
6505    $::texi_map_ref = \%Texi2HTML::Config::texi_map;
6506}
6507
6508# This function is used to construct a link name from a node name as
6509# specified for texinfo
6510sub cross_manual_line($;$)
6511{
6512    my $text = shift;
6513    my $transliterate = shift;
6514#print STDERR "cross_manual_line $text\n";
6515#print STDERR "remove_texi text ". remove_texi($text)."\n\n\n";
6516    if ($text !~ /\S/)
6517    {
6518       # special case for empty node/ref
6519       return ('t_0', 't_0');
6520    }
6521    $::simple_map_texi_ref = \%cross_ref_simple_map_texi;
6522    $::style_map_texi_ref = \%cross_ref_style_map_texi;
6523    $::texi_map_ref = \%cross_ref_texi_map;
6524    my $normal_text_kept = $Texi2HTML::Config::normal_text;
6525    $Texi2HTML::Config::normal_text = \&Texi2HTML::Config::t2h_cross_manual_normal_text;
6526    my $style_kept = $Texi2HTML::Config::style;
6527    $Texi2HTML::Config::style = \&Texi2HTML::Config::T2H_GPL_style;
6528
6529    my ($cross_ref_target, $cross_ref_file);
6530    if ($Texi2HTML::Config::USE_UNICODE)
6531    {
6532         $cross_ref_target = Unicode::Normalize::NFC(remove_texi($text));
6533         if ($transliterate and $Texi2HTML::Config::USE_UNIDECODE)
6534         {
6535             $cross_ref_file =
6536                unicode_to_protected(unicode_to_transliterate($cross_ref_target));
6537         }
6538         $cross_ref_target = unicode_to_protected($cross_ref_target);
6539    }
6540    else
6541    {
6542         $cross_ref_target = remove_texi($text);
6543    }
6544
6545    if ($transliterate and
6546         (!$Texi2HTML::Config::USE_UNICODE or !$Texi2HTML::Config::USE_UNIDECODE))
6547    {
6548         $::style_map_texi_ref = \%cross_transliterate_style_map_texi;
6549         $::texi_map_ref = \%cross_transliterate_texi_map;
6550         $Texi2HTML::Config::normal_text = \&Texi2HTML::Config::t2h_cross_manual_normal_text_transliterate if (!$Texi2HTML::Config::USE_UNICODE);
6551         $cross_ref_file = remove_texi($text);
6552         $cross_ref_file = unicode_to_protected(unicode_to_transliterate($cross_ref_file))
6553               if ($Texi2HTML::Config::USE_UNICODE);
6554    }
6555
6556    $Texi2HTML::Config::normal_text = $normal_text_kept;
6557    $Texi2HTML::Config::style = $style_kept;
6558    $::simple_map_texi_ref = \%Texi2HTML::Config::simple_map_texi;
6559    $::style_map_texi_ref = \%Texi2HTML::Config::style_map_texi;
6560    $::texi_map_ref = \%Texi2HTML::Config::texi_map;
6561#print STDERR "\n\ncross_ref $cross_ref\n";
6562    unless ($transliterate)
6563    {
6564        return $cross_ref_target;
6565    }
6566#    print STDERR "$text|$cross_ref_target|$cross_ref_file\n";
6567    return ($cross_ref_target, $cross_ref_file);
6568}
6569
6570sub equivalent_nodes($)
6571{
6572    my $name = shift;
6573#print STDERR "equivalent_nodes $name\n";
6574    my $node = normalise_node($name);
6575    $name = cross_manual_line($node);
6576#print STDERR "equivalent_nodes `$node' `$name'\n";
6577    my @equivalent_nodes = ();
6578    if (exists($cross_reference_nodes{$name}))
6579    {
6580        @equivalent_nodes = grep {$_ ne $node} @{$cross_reference_nodes{$name}};
6581    }
6582    return @equivalent_nodes;
6583}
6584
6585sub do_place_target_file($$$)
6586{
6587   my $place = shift;
6588   my $element = shift;
6589   my $context = shift;
6590
6591   $place->{'file'} = $element->{'file'} unless defined($place->{'file'});
6592   $place->{'target'} = $element->{'target'} unless defined($place->{'target'});
6593   if (defined($Texi2HTML::Config::placed_target_file_name))
6594   {
6595      my ($target, $id, $file) = &$Texi2HTML::Config::placed_target_file_name($place,$element,$place->{'target'}, $place->{'id'}, $place->{'file'},$context);
6596      $place->{'target'} = $target if (defined($target));
6597      $place->{'file'} = $file if (defined($file));
6598      $place->{'id'} = $id if (defined($id));
6599   }
6600}
6601
6602sub do_node_target_file($$)
6603{
6604    my $node = shift;
6605    my $type_of_node = shift;
6606    my $node_file = &$Texi2HTML::Config::node_file_name($node,$type_of_node);
6607    $node->{'node_file'} = $node_file if (defined($node_file));
6608    if (defined($Texi2HTML::Config::node_target_name))
6609    {
6610        my ($target,$id) = &$Texi2HTML::Config::node_target_name($node,$node->{'target'},$node->{'id'}, $type_of_node);
6611        $node->{'target'} = $target if (defined($target));
6612        $node->{'id'} = $id if (defined($id));
6613    }
6614}
6615
6616sub do_element_targets($;$)
6617{
6618   my $element = shift;
6619   my $use_node_file = shift;
6620   my $is_top = '';
6621
6622   $is_top = 'top' if (defined($element_top) and ($element eq $element_top or (defined($element->{'with_node'}) and $element->{'with_node'} eq $element_top)));
6623
6624   if ($Texi2HTML::Config::SPLIT_INDEX and Texi2HTML::Config::get_conf('SPLIT'))
6625   {
6626      Texi2HTML::Config::t2h_default_associate_index_element($element, $is_top, $docu_name, $use_node_file);
6627   }
6628
6629   if (defined($Texi2HTML::Config::element_file_name))
6630   {
6631      my $previous_file_name = $element->{'file'};
6632      my $filename =
6633          &$Texi2HTML::Config::element_file_name ($element, $is_top, $docu_name);
6634      if (defined($filename))
6635      {
6636         foreach my $place (@{$element->{'place'}})
6637         {
6638            $place->{'file'} = $filename if (defined($place->{'file'}) and ($place->{'file'} eq $previous_file_name));
6639         }
6640         $element->{'file'} = $filename;
6641         if ($is_top)
6642         { # reset these variables, although they aren't used much, they may be
6643           # used in file name comparisons
6644            $docu_top = $filename;
6645            $docu_top_file = "$docu_rdir$docu_top";
6646         }
6647      }
6648   }
6649   print STDERR "file !defined for element $element->{'texi'}\n" if (!defined($element->{'file'}));
6650   if (defined($Texi2HTML::Config::element_target_name))
6651   {
6652       my ($target,$id) = &$Texi2HTML::Config::element_target_name($element, $element->{'target'}, $element->{'id'});
6653       $element->{'target'} = $target if (defined($target));
6654       $element->{'id'} = $id if (defined($id));
6655   }
6656   foreach my $place(@{$element->{'place'}})
6657   {
6658      do_place_target_file($place, $element, '');
6659   }
6660}
6661
6662sub add_t2h_element($$$)
6663{
6664    my $element = shift;
6665    my $elements_list = shift;
6666    my $prev_element = shift;
6667
6668    push @$elements_list, $element;
6669    $element->{'element_ref'} = $element;
6670    $element->{'this'} = $element;
6671
6672    if (defined($prev_element))
6673    {
6674        $element->{'back'} = $prev_element;
6675        $prev_element->{'forward'} = $element;
6676    }
6677    push @{$element->{'place'}}, $element;
6678    push @{$element->{'place'}}, @{$element->{'current_place'}};
6679    return $element;
6680}
6681
6682sub add_t2h_dependent_element ($$)
6683{
6684    my $element = shift;
6685    my $element_ref = shift;
6686    $element->{'element_ref'} = $element_ref;
6687    $element_index = $element_ref if ($element_index and ($element_index eq $element));
6688    push @{$element_ref->{'place'}}, $element;
6689    push @{$element_ref->{'place'}}, @{$element->{'current_place'}};
6690}
6691
6692my %files = ();   # keys are files. This is used to avoid reusing an already
6693                  # used file name
6694my @opened_files = (); # all the files opened by the program to remove
6695                       # them if FORCE is not set and an error occured
6696my %printed_indices = (); # value is true for an index name not empty and
6697                          # printed
6698# This is a virtual element used to have the right hrefs for index entries
6699# and anchors in footnotes.
6700my $footnote_element;
6701
6702# find next, prev, up, back, forward, fastback, fastforward
6703# find element id and file
6704# split index pages
6705# associate placed items (items which have links to them) with the right
6706# file and id
6707# associate nodes with sections
6708sub rearrange_elements()
6709{
6710    print STDERR "# find sections levels and toplevel\n"
6711        if ($T2H_DEBUG & $DEBUG_ELEMENTS);
6712
6713    my $toplevel = 4;
6714
6715    # correct level if raisesections or lowersections overflowed
6716    # and find toplevel level
6717    # use %sections and %headings to modify also the headings
6718    foreach my $section (values(%sections), values(%headings))
6719    {
6720        my $level = $section->{'level'};
6721        if ($level > $MAX_LEVEL)
6722        {
6723             $section->{'level'} = $MAX_LEVEL;
6724        }
6725        # second condition is for @top and @part
6726        elsif ($level < $MIN_LEVEL and ($reference_sec2level{$section->{'tag'}} >= $MIN_LEVEL))
6727        {
6728             $section->{'level'} = $MIN_LEVEL;
6729        }
6730        else
6731        {
6732             $section->{'level'} = $level;
6733        }
6734        $section->{'toc_level'} = $section->{'level'};
6735        # This is for top
6736        $section->{'toc_level'} = $MIN_LEVEL if ($section->{'level'} < $MIN_LEVEL);
6737        # find the new tag corresponding with the level of the section
6738        if ($section->{'tag'} !~ /heading/ and ($level ne $reference_sec2level{$section->{'tag'}}))
6739        {
6740             $section->{'tag_level'} = $level2sec{$section->{'tag'}}->[$section->{'level'}];
6741        }
6742        else
6743        {
6744             $section->{'tag_level'} = $section->{'tag'};
6745        }
6746        $toplevel = $section->{'level'} if (($section->{'level'} < $toplevel) and ($section->{'level'} > 0 and ($section->{'tag'} !~ /heading/)));
6747        print STDERR "# section level $level: $section->{'texi'}\n" if ($T2H_DEBUG & $DEBUG_ELEMENTS);
6748    }
6749
6750    print STDERR "# find sections structure, construct section numbers (toplevel=$toplevel)\n"
6751        if ($T2H_DEBUG & $DEBUG_ELEMENTS);
6752    my $in_appendix = 0;
6753    # these arrays have an element per sectioning level.
6754    my @previous_numbers = ();   # holds the number of the previous sections
6755                                 # at the same and upper levels
6756    my @previous_sections = ();  # holds the ref of the previous sections
6757    my $previous_toplevel;
6758    my @pending_parts;           # parts yet to be associated with the
6759                                 # following element
6760
6761    foreach my $section (@sections_list)
6762    {
6763        ########################### debug
6764        print STDERR "BUG: node or section_ref defined for section $section->{'texi'}\n"
6765            if (exists($section->{'node'}) or exists($section->{'section_ref'}));
6766        print STDERR "Bug level undef for ($section) $section->{'texi'}\n" if (!defined($section->{'level'}));
6767        ########################### end debug
6768
6769        # associate with first node if it is a section appearing before
6770        # the first node
6771        $section->{'node_ref'} = $nodes_list[0] if ($nodes_list[0] and !$section->{'node_ref'});
6772
6773        # a part doesn't really make up an element, it is associated with the
6774        # next sectioning element instead.
6775        if ($section->{'tag'} eq 'part')
6776        {
6777           push @pending_parts, $section;
6778        }
6779        elsif (@pending_parts)
6780        {
6781           if ($section->{'tag'} ne 'top')
6782           {
6783              foreach my $part (@pending_parts)
6784              {
6785                 $part->{'part_section_ref'} = $section;
6786                 if (!$section->{'with_part'})
6787                 {
6788                    $section->{'with_part'} = $part;
6789                    $part->{'part_with_section'} = $section;
6790                 }
6791                 # if a node is associated with the part, reassociate it with
6792                 # the chapter
6793                 if ($part->{'with_node'} and !$section->{'with_node'})
6794                 {
6795                    $section->{'with_node'} = $part->{'with_node'};
6796                    delete $part->{'with_node'};
6797                    $section->{'with_node'}->{'with_section'} = $section;
6798                 }
6799              }
6800           }
6801           @pending_parts = ();
6802        }
6803
6804        # we track the toplevel next and previous because there is no
6805        # strict child parent relationship between chapters and top. Indeed
6806        # a chapter may appear before @top, it may be better to consider them
6807        # on the same toplevel.
6808        if ($section->{'level'} <= $toplevel)
6809        {
6810            $section->{'toplevel'} = 1;
6811            if (defined($previous_toplevel))
6812            {
6813                $previous_toplevel->{'toplevelnext'} = $section;
6814                $section->{'toplevelprev'} = $previous_toplevel;
6815            }
6816            # part is not used as previous_toplevel since toplevel directions
6817            # are used to move between chapters (and top)
6818            $previous_toplevel = $section if ($section->{'tag'} ne 'part');
6819            # In fact this is only useful for toplevel elements appearing
6820            # before @top, the other have their sectionup reset up below
6821            # based on the sectioning commands hierarchy.
6822            if (defined($section_top) and $section ne $section_top)
6823            {
6824                $section->{'sectionup'} = $section_top;
6825            }
6826        }
6827        # undef things under that section level
6828        my $section_level = $section->{'level'};
6829        for (my $level = $section_level + 1; $level < $MAX_LEVEL + 1 ; $level++)
6830        {
6831            $previous_numbers[$level] = undef unless ($section->{'tag'} =~ /unnumbered/ or $section->{'tag'} eq 'centerchap');
6832            $previous_sections[$level] = undef;
6833        }
6834        my $number_set;
6835        # find number at the current level
6836        if ($section->{'tag'} =~ /appendix/ and !$in_appendix)
6837        {
6838            $previous_numbers[$toplevel] = 'A';
6839            $in_appendix = 1;
6840            $number_set = 1 if ($section->{'level'} <= $toplevel);
6841            $section->{'appendix_beginning'} = 1;
6842        }
6843        if (!defined($previous_numbers[$section->{'level'}]) and !$number_set)
6844        {
6845            if ($section->{'tag'} =~ /unnumbered/ or $section->{'tag'} eq 'centerchap')
6846            {
6847                $previous_numbers[$section->{'level'}] = undef;
6848            }
6849            else
6850            {
6851                $previous_numbers[$section->{'level'}] = 1;
6852            }
6853        }
6854        elsif ($section->{'tag'} !~ /unnumbered/ and $section->{'tag'} ne 'centerchap' and !$number_set)
6855        {
6856            $previous_numbers[$section->{'level'}]++;
6857        }
6858        # construct the section number
6859        $section->{'number'} = '';
6860
6861        unless ($section->{'tag'} =~ /unnumbered/ or $section->{'tag'} eq 'centerchap' or $section->{'tag'} eq 'top' or $section->{'tag'} eq 'part')
6862        {
6863            my $level = $section->{'level'};
6864            while ($level > $toplevel)
6865            {
6866                my $number = $previous_numbers[$level];
6867                $number = 0 if (!defined($number));
6868                if ($section->{'number'})
6869                {
6870                    $section->{'number'} = "$number.$section->{'number'}";
6871                }
6872                else
6873                {
6874                    $section->{'number'} = $number;
6875                }
6876                $level--;
6877            }
6878            my $toplevel_number = $previous_numbers[$toplevel];
6879            $toplevel_number = 0 if (!defined($toplevel_number));
6880
6881            if ($section->{'number'})
6882            { # not toplevel
6883                $section->{'number'} = "$toplevel_number.$section->{'number'}";
6884            }
6885            else
6886            { # toplevel
6887                $section->{'number'} = $toplevel_number;
6888                if ($section->{'tag'} =~ /appendix/)
6889                {# i18n
6890                    $section->{'plain_number'} = $section->{'number'};
6891                    $section->{'number'} = "Appendix $section->{'number'}";
6892                }
6893            }
6894        }
6895        $section->{'plain_number'} = $section->{'number'} if (!defined($section->{'plain_number'}));
6896        # find the previous section
6897        if (defined($previous_sections[$section->{'level'}]))
6898        {
6899            my $prev_section = $previous_sections[$section->{'level'}];
6900            $section->{'sectionprev'} = $prev_section;
6901            $prev_section->{'sectionnext'} = $section;
6902        }
6903        # find the up section
6904        my $level = $section->{'level'} - 1;
6905        while (!defined($previous_sections[$level]) and ($level >= 0))
6906        {
6907            $level--;
6908        }
6909        # The second conditions ensures that a @part is stopped by
6910        # the first @appendix command.
6911        if (defined($previous_sections[$level])
6912           and !($section->{'appendix_beginning'} and $previous_sections[$level]->{'tag'} eq 'part' and $previous_sections[$level]->{'part_section_ref'} ne $section))
6913        {
6914            # toplevel elements have already their up set to the top element,
6915            # it is overwriten here for most cases -- this leads to a different
6916            # sectionup if there are parts, for instance.
6917            # as a side note, it is not touched upon if the element appears
6918            # before @top.
6919            $section->{'sectionup'} = $previous_sections[$level];
6920            # 'child' is the first child.
6921            if (!$section->{'sectionup'}->{'child'})
6922            {
6923                $section->{'sectionup'}->{'child'} = $section;
6924            }
6925            else
6926            {
6927                # 'childnext' is the next child of a an element. it may
6928                # be different from 'sectionnext' when the elemnt are not
6929                # at the same level, for example
6930                # @chapter chapter
6931                # @subsection subsection (certainly wrong)
6932                # @section section (not next of subsection, but childnext)
6933                $section->{'sectionup'}->{'section_childs'}->[-1]->{'childnext'} = $section if (defined($section->{'sectionup'}->{'section_childs'}));
6934            }
6935            push @{$section->{'sectionup'}->{'section_childs'}}, $section;
6936        }
6937        $previous_sections[$section->{'level'}] = $section;
6938        # This is what is used in the .init file.
6939        $section->{'up'} = $section->{'sectionup'};
6940        # Not used but documented.
6941        $section->{'next'} = $section->{'sectionnext'};
6942        $section->{'prev'} = $section->{'sectionprev'};
6943
6944        ############################# debug
6945        my $up = "NO_UP";
6946        $up = $section->{'sectionup'} if (defined($section->{'sectionup'}));
6947        print STDERR "# numbering section ($section->{'level'}): $section->{'number'}: (up: $up) $section->{'texi'}\n"
6948            if ($T2H_DEBUG & $DEBUG_ELEMENTS);
6949        ############################# end debug
6950    }
6951
6952    # at that point there are still some node structures that are not
6953    # in %nodes, (the external nodes, and unknown nodes in case
6954    # novalidate is true) so we cannot find the id. The consequence is that
6955    # some node equivalent with another node may not be catched during
6956    # that pass. We mark the nodes that have directions for unreferenced
6957    # nodes and make a second pass for these nodes afterwards.
6958    my @nodes_with_unknown_directions = ();
6959
6960    my %node_directions = (
6961         'node_prev' => 'nodeprev',
6962         'node_next' => 'nodenext',
6963         'node_up' => 'nodeup');
6964    # handle nodes
6965    # the node_prev... are texinfo strings, find the associated node references
6966    print STDERR "# Resolve nodes directions\n" if ($T2H_DEBUG & $DEBUG_ELEMENTS);
6967    foreach my $node (@nodes_list)
6968    {
6969        foreach my $direction (keys(%node_directions))
6970        {
6971            if (defined($node->{$direction}))
6972            {
6973                if ($nodes{$node->{$direction}} and $nodes{$node->{$direction}}->{'seen'})
6974                {
6975                     $node->{$node_directions{$direction}} = $nodes{$node->{$direction}};
6976                }
6977                elsif (($node->{$direction} =~ /^\(.*\)/) or Texi2HTML::Config::get_conf('novalidate'))
6978                { # ref to an external node
6979                    if (exists($nodes{$node->{$direction}}))
6980                    {
6981                        $node->{$node_directions{$direction}} = $nodes{$node->{$direction}};
6982                    }
6983                    else
6984                    {
6985                        my $node_ref = { 'texi' => $node->{$direction} };
6986                        $node_ref->{'external_node'} = 1 if ($node->{$direction} =~ /^\(.*\)/);
6987                        $nodes{$node->{$direction}} = $node_ref;
6988                        $node->{$node_directions{$direction}} = $node_ref;
6989                    }
6990                }
6991                else
6992                {
6993                     push @nodes_with_unknown_directions, $node;
6994                }
6995            }
6996        }
6997    }
6998
6999    # Find cross manual links as explained on the texinfo mailing list
7000    # The  specification is such that cross manual links formatting should
7001    # be insensitive to the manual split
7002    cross_manual_links();
7003
7004    my %direction_texts = (
7005      'node_prev' => 'Prev',,
7006      'node_next' => 'Next',
7007      'node_up' => 'Up'
7008    );
7009    # Now it is possible to find the unknown directions that are equivalent
7010    # (have same node id) than an existing node
7011    foreach my $node (@nodes_with_unknown_directions)
7012    {
7013        foreach my $direction (keys(%node_directions))
7014        {
7015            if (defined($node->{$direction}) and !$node->{$node_directions{$direction}})
7016            {
7017                line_error (sprintf(__("%s reference to nonexistent `%s'"),$direction_texts{$direction}, $node->{$direction}), $node->{'line_nr'}); # for `$node->{'texi'}'"
7018                my @equivalent_nodes = equivalent_nodes($node->{$direction});
7019                my $node_seen;
7020                foreach my $equivalent_node (@equivalent_nodes)
7021                {
7022                    if ($nodes{$equivalent_node}->{'seen'})
7023                    {
7024                        $node_seen = $equivalent_node;
7025                        last;
7026                    }
7027                }
7028                if (defined($node_seen))
7029                {
7030                    document_warn ("---> but equivalent node `$node_seen' found");
7031                    $node->{$node_directions{$direction}} = $nodes{$node_seen};
7032                }
7033            }
7034        }
7035    }
7036
7037    # nodes are attached to the section preceding them if not already
7038    # associated with a section.
7039    # a @part should never have nodes associated, if it is associated
7040    # with a chapter, instead the chapter pointed on by part_section_ref is
7041    # used.
7042    my $current_section = $sections_list[0];
7043    $current_section = $current_section->{'part_section_ref'} if ($current_section and $current_section->{'part_section_ref'});
7044    foreach my $element (@all_elements)
7045    {
7046        if ($element->{'node'})
7047        {
7048            if ($element->{'with_section'})
7049            { # the node is associated with a section
7050                $element->{'section_ref'} = $element->{'with_section'};
7051            }
7052            elsif (defined($current_section))
7053            {# node appearing after a section, but not before another section,
7054             # or appearing before any section
7055                $element->{'section_ref'} = $current_section;
7056                push @{$current_section->{'node_childs'}}, $element;
7057            }
7058        }
7059        else
7060        {
7061            $current_section = $element;
7062            $current_section = $element->{'part_section_ref'} if ($element->{'part_section_ref'});
7063        }
7064    }
7065
7066    print STDERR "# Complete nodes next prev and up based on menus and sections\n"
7067        if ($T2H_DEBUG & $DEBUG_ELEMENTS);
7068    # set the default id based on the node number
7069    my $node_nr = 1;
7070    # find the node* directions
7071    # find the directions corresponding with sections
7072    # and set 'up' for the node
7073    foreach my $node (@nodes_list)
7074    {
7075        # first a warning if the node and the equivalent nodes don't
7076        # appear in menus.
7077        # Don't warn for the top node, and the first node if there is no
7078        # top node.
7079        if ((($node_top and $node ne $node_top) or (!$node_top and $node ne $node_first)) and !$node->{'menu_up'} and $Texi2HTML::Config::SHOW_MENU)
7080        {
7081            my @equivalent_nodes = equivalent_nodes($node->{'texi'});
7082            my $found = 0;
7083            foreach my $equivalent_node (@equivalent_nodes)
7084            {
7085                if (($nodes{$equivalent_node} eq $node_first) or $nodes{$equivalent_node}->{'menu_up'})
7086                {
7087                   $found = 1;
7088                   last;
7089                }
7090            }
7091            unless ($found)
7092            { # makeinfo has also
7093              # "`%s' has no Up field (perhaps incorrect sectioning?)"
7094              # but it is not useful since the up will always be set if
7095              # the node appears in a menu so the following error message
7096              # is enough
7097                line_warn (sprintf(__("unreferenced node `%s'"), $node->{'texi'}), $node->{'line_nr'});
7098            }
7099        }
7100
7101        # use values deduced from menus to complete missing up, next, prev
7102        # or from sectioning commands if automatic sectioning
7103        if (!$node->{'nodeup'})
7104        {
7105            if (defined($node_top) and ($node eq $node_top) and $node->{'automatic_directions'})
7106            { # Top node has a special up, which is (dir) by default
7107                my $top_nodeup = $Texi2HTML::Config::TOP_NODE_UP;
7108                if (exists($nodes{$top_nodeup}))
7109                {
7110                    $node->{'nodeup'} = $nodes{$top_nodeup};
7111                }
7112                else
7113                {
7114                    my $node_ref = { 'texi' => $top_nodeup };
7115                    $node_ref->{'external_node'} = 1;
7116                    $nodes{$top_nodeup} = $node_ref;
7117                    $node->{'nodeup'} = $node_ref;
7118                }
7119            }
7120            elsif ($node->{'automatic_directions'})
7121            {
7122                if ($node->{'with_section'})
7123                {
7124                    # ignore the up if it is a @part. If the sectioning is
7125                    # correct, the element is toplevel and will be handled
7126                    # by the next condition.
7127                    if ($node->{'with_section'}->{'sectionup'} and !$node->{'with_section'}->{'sectionup'}->{'part_section_ref'})
7128                    {
7129                        $node->{'nodeup'} = get_node($node->{'with_section'}->{'sectionup'});
7130                    }
7131                    elsif ($node->{'with_section'}->{'toplevel'} and defined($section_top) and ($node->{'with_section'} ne $section_top))
7132                    {
7133                        $node->{'nodeup'} = get_node($section_top);
7134                    }
7135                    print STDERR "# Deducing from section node_up $node->{'nodeup'}->{'texi'} for $node->{'texi'}\n" if ($T2H_DEBUG & $DEBUG_ELEMENTS and defined($node->{'nodeup'}));
7136                }
7137                elsif ($node->{'menu_up'})
7138                {
7139                    $node->{'nodeup'} = $node->{'menu_up'};
7140                    print STDERR "# Deducing from menu node_up $node->{'menu_up'}->{'texi'} for $node->{'texi'}\n" if ($T2H_DEBUG & $DEBUG_ELEMENTS);
7141                }
7142            }
7143        }
7144
7145        if ($node->{'nodeup'} and !$node->{'nodeup'}->{'external_node'})
7146        {
7147            # We detect when the up node has no menu entry for that node, as
7148            # there may be infinite loops when finding following node (see below)
7149            unless (defined($node->{'menu_up_hash'}) and ($node->{'menu_up_hash'}->{$node->{'nodeup'}->{'texi'}}))
7150            {
7151                line_error(sprintf(__("Node `%s' lacks menu item for `%s' despite being its Up target"), $node->{'nodeup'}->{'texi'}, $node->{'texi'}), $node->{'nodeup'}->{'line_nr'}) if ($Texi2HTML::Config::SHOW_MENU);
7152                push @{$node->{'up_not_in_menu'}}, $node->{'nodeup'}->{'texi'};
7153            }
7154        }
7155        # check that the up is in one of the menus
7156        if ($Texi2HTML::Config::SHOW_MENU and $node->{'nodeup'} and $node->{'menu_up'})
7157        {
7158            my @equivalent_nodes = equivalent_nodes($node->{'nodeup'}->{'texi'});
7159            my $found = 0;
7160            foreach my $equivalent_node ($node->{'nodeup'}->{'texi'}, @equivalent_nodes)
7161            {
7162                if ($node->{'menu_up_hash'}->{$equivalent_node})
7163                {
7164                   $found = 1;
7165                   last;
7166                }
7167            }
7168            unless ($found)
7169            {
7170                line_warn (sprintf(__("For `%s', up in menu `%s' and up `%s' don't match"), $node->{'texi'}, $node->{'menu_up'}->{'texi'}, $node->{'nodeup'}->{'texi'}), $node->{'line_nr'});
7171            }
7172
7173        }
7174
7175        # Find next node if not already found
7176        if ($node->{'nodenext'})
7177        {
7178            # doing the following would be wrong:
7179            #$node->{'nodenext'}->{'nodeprev'} = $node if (!defined($node->{'nodenext'}->{'nodeprev'}));
7180        }
7181        elsif ($node->{'texi'} eq 'Top' and $node->{'automatic_directions'})
7182        { # special case as said in the texinfo manual
7183            if ($node->{'menu_child'})
7184            {
7185                $node->{'nodenext'} = $node->{'menu_child'};
7186                $node->{'menu_child'}->{'nodeprev'} = $node;
7187            }
7188        }
7189        elsif ($node->{'automatic_directions'})
7190        {
7191            if (defined($node->{'with_section'}))
7192            {
7193                my $next;
7194                my $warn_for_next_not_in_menu = 1;
7195                my $section = $node->{'with_section'};
7196                if ($section->{'sectionnext'})
7197                {
7198                    $next = get_node($section->{'sectionnext'});
7199                }
7200                # we use toplevelnext, mostly for chapters associated with
7201                # @part. But we don't want to have the @top as prev for
7202                # a @chapter or the like
7203                elsif ($section->{'toplevelnext'} and $section->{'toplevelnext'} ne $section_top)
7204                {
7205                    $next = get_node($section->{'toplevelnext'});
7206                }
7207                elsif ($Texi2HTML::Config::USE_UP_FOR_ADJACENT_NODES)
7208                { # makeinfo don't do that. So this is conditionnal.
7209                  # Also no warning, because it is expected that the
7210                  # next found out with the up is not the next in menu.
7211                    $warn_for_next_not_in_menu = 0;
7212                    while (defined($section->{'sectionup'}) and !defined($section->{'sectionnext'}))
7213                    {
7214                        $section = $section->{'sectionup'};
7215                    }
7216                    if (defined($section->{'sectionnext'}))
7217                    {
7218                        $next = get_node($section->{'sectionnext'});
7219                    }
7220                }
7221                if (defined($next) and $Texi2HTML::Config::SHOW_MENU and $warn_for_next_not_in_menu)
7222                {
7223                    line_warn (sprintf(__("No node following `%s' in menu, but `%s' follows in sectioning"), $node->{'texi'}, $next->{'texi'}), $node->{'line_nr'}) if (!defined($node->{'menu_next'}));
7224                    line_warn (sprintf(__("Node following `%s' in menu `%s' and in sectioning `%s' differ"), $node->{'texi'}, $node->{'menu_next'}->{'texi'}, $next->{'texi'}), $node->{'line_nr'})
7225                       if (defined($node->{'menu_next'}) and $next ne $node->{'menu_next'});
7226                }
7227                $node->{'nodenext'} = $next;
7228            }
7229            elsif ($node->{'menu_next'})
7230            {
7231                $node->{'nodenext'} = $node->{'menu_next'};
7232            }
7233        }
7234
7235        # Find prev node
7236        if ($node->{'nodeprev'})
7237        {
7238            # doing the following would be wrong:
7239            #$node->{'nodeprev'}->{'nodenext'} = $node if (!defined($node->{'nodeprev'}->{'nodenext'}));
7240        }
7241        elsif ($node->{'automatic_directions'})
7242        {
7243            if (defined($node->{'with_section'}))
7244            {
7245                my $section = $node->{'with_section'};
7246                if ($section->{'sectionprev'})
7247                {
7248                    $node->{'nodeprev'} = get_node($section->{'sectionprev'});
7249                }
7250                # we use toplevelprev, mostly for chapters associated with
7251                # @part. But we don't want to have the @top as prev for
7252                # a @chapter or the like
7253                elsif ($section->{'toplevelprev'} and $section->{'toplevelprev'} ne $section_top)
7254                {
7255                    $node->{'nodeprev'} = get_node($section->{'toplevelprev'});
7256                }
7257                elsif ($Texi2HTML::Config::USE_UP_FOR_ADJACENT_NODES and defined($section->{'sectionup'}))
7258                { # makeinfo don't do that
7259                    $node->{'nodeprev'} = get_node($section->{'sectionup'});
7260                }
7261            }
7262            elsif ($node->{'menu_prev'})
7263            {
7264                $node->{'nodeprev'} = $node->{'menu_prev'};
7265            }
7266            # the prev node is the parent node
7267            elsif ($node->{'menu_up'} and ($node->{'menu_up'}->{'menu_child'} eq $node) and $Texi2HTML::Config::USE_UP_FOR_ADJACENT_NODES)
7268            {
7269                $node->{'nodeprev'} = $node->{'menu_up'};
7270            }
7271        }
7272
7273        # the following node is the node following in node reading order
7274        # it is thus first the child, else the next, else the next following
7275        # the up
7276        if ($node->{'menu_child'})
7277        {
7278            $node->{'following'} = $node->{'menu_child'};
7279        }
7280        elsif ($node->{'automatic_directions'} and defined($node->{'with_section'}) and defined($node->{'with_section'}->{'child'}))
7281        {
7282            $node->{'following'} = get_node($node->{'with_section'}->{'child'});
7283        }
7284        elsif (defined($node->{'nodenext'}))
7285        {
7286            $node->{'following'} = $node->{'nodenext'};
7287        }
7288	else
7289        {
7290            my $up = $node->{'nodeup'};
7291            # in order to avoid infinite recursion in case the up node is the
7292            # node itself we use the up node as following when there isn't
7293            # a correct menu structure, here and also below.
7294            $node->{'following'} = $up if (defined($up) and grep {$_ eq $up->{'texi'}} @{$node->{'up_not_in_menu'}});
7295            while ((!defined($node->{'following'})) and (defined($up)))
7296            {
7297                if (($node_top) and ($up eq $node_top))
7298                { # if we are at Top, Top is following
7299                    $node->{'following'} = $node_top;
7300                    $up = undef;
7301                }
7302                if (defined($up->{'nodenext'}))
7303                {
7304                    $node->{'following'} = $up->{'nodenext'};
7305                }
7306                elsif (defined($up->{'nodeup'}))
7307                {
7308                    if (! grep { $_ eq $up->{'nodeup'}->{'texi'} } @{$node->{'up_not_in_menu'}})
7309                    {
7310                        $up = $up->{'nodeup'};
7311                    }
7312                    else
7313                    { # in that case we can go into a infinite loop
7314                        $node->{'following'} = $up->{'nodeup'};
7315                    }
7316                }
7317                else
7318                {
7319                    $up = undef;
7320                }
7321            }
7322        }
7323        # copy the direction of the associated section.
7324        if (defined($node->{'with_section'}))
7325        {
7326            my $section = $node->{'with_section'};
7327            foreach my $direction ('sectionnext', 'sectionprev', 'sectionup')
7328            {
7329                $node->{$direction} = $section->{$direction}
7330                  if (defined($section->{$direction}));
7331            }
7332        }
7333        # 'up' is used in .init files. It is almost sectionup, but not
7334        # exactly, it allows to have something relevant whether elements
7335        # are nodes or sections -- just like Back and Forward. So it
7336        # should certainly be kept.
7337        if (defined($node->{'sectionup'}))
7338        {
7339            $node->{'up'} = $node->{'sectionup'};
7340        }
7341        elsif (defined($node->{'nodeup'}) and
7342             (!$node_top or ($node ne $node_top)))
7343        {
7344            $node->{'up'} = $node->{'nodeup'};
7345        }
7346        # 'next' not used but documented.
7347        if (defined($node->{'sectionnext'}))
7348        {
7349            $node->{'next'} = $node->{'sectionnext'};
7350        }
7351        if (defined($node->{'sectionprev'}))
7352        {
7353            $node->{'prev'} = $node->{'sectionprev'};
7354        }
7355
7356        # default id for nodes. Should be overriden later.
7357        $node->{'id'} = 'NOD' . $node_nr;
7358        $node_nr++;
7359    }
7360
7361    # do node directions for sections.
7362    foreach my $section (@sections_list)
7363    {
7364        # If the element is not a node, then all the node directions are copied
7365        # if there is an associated node
7366        if (defined($section->{'with_node'}))
7367        {
7368            $section->{'nodenext'} = $section->{'with_node'}->{'nodenext'};
7369            $section->{'nodeprev'} = $section->{'with_node'}->{'nodeprev'};
7370            $section->{'menu_next'} = $section->{'with_node'}->{'menu_next'};
7371            $section->{'menu_prev'} = $section->{'with_node'}->{'menu_prev'};
7372            $section->{'menu_child'} = $section->{'with_node'}->{'menu_child'};
7373            $section->{'menu_up'} = $section->{'with_node'}->{'menu_up'};
7374            $section->{'nodeup'} = $section->{'with_node'}->{'nodeup'};
7375            $section->{'following'} = $section->{'with_node'}->{'following'};
7376        }
7377    }
7378
7379    my $only_nodes = 0;
7380    my $only_sections = 0;
7381
7382    # for legibility
7383    my $use_nodes = $Texi2HTML::Config::USE_NODES;
7384    my $use_sections = $Texi2HTML::Config::USE_SECTIONS;
7385
7386    $only_nodes = 1 if (
7387         (!scalar(@sections_list) and
7388            ($use_nodes or (!$use_sections and !defined($use_nodes))))
7389      or ($use_nodes and !$use_sections)
7390    );
7391    $only_sections = 1 if (!$only_nodes and !$use_nodes and ($use_sections or !defined($use_sections)));
7392    #print STDERR "USE_NODES $use_nodes, USE_SECTIONS $use_sections. only_nodes: $only_nodes, only_sections $only_sections\n";
7393
7394    my $prev_element;
7395    print STDERR "# Build the elements list only_nodes: $only_nodes, only_sections $only_sections\n" if ($T2H_DEBUG & $DEBUG_ELEMENTS);
7396    foreach my $element (@all_elements)
7397    {
7398        if ($element->{'node'})
7399        {
7400            if ($element->{'section_ref'} and ($only_sections or (!$only_nodes and $element->{'with_section'})))
7401            {
7402                add_t2h_dependent_element ($element, $element->{'section_ref'});
7403                #$element->{'toc_level'} = $element->{'section_ref'}->{'toc_level'};
7404            }
7405            elsif (!$only_sections)
7406            {
7407                $prev_element = add_t2h_element($element, \@elements_list, $prev_element);
7408            }
7409            else # $only_section and !$section_ref. This should only
7410                 # happen when there are no sections
7411            {
7412                #print STDERR "node $element->{'texi'} not associated with an element\n";
7413            }
7414        }
7415        else
7416        {
7417            my $part_element = $element->{'part_section_ref'};
7418            if (($element->{'node_ref'} or ($part_element and $part_element->{'node_ref'})) and $only_nodes)
7419            {
7420                my $element_with_node = $element;
7421                $element_with_node = $part_element if ($part_element);
7422                add_t2h_dependent_element ($element, $element_with_node->{'node_ref'});
7423            }
7424            elsif (!$only_nodes)
7425            {
7426                if ($part_element)
7427                {
7428                    add_t2h_dependent_element ($element, $part_element);
7429                }
7430                else
7431                {
7432                    $prev_element = add_t2h_element($element, \@elements_list, $prev_element);
7433                }
7434            }
7435            else
7436            { # no node, and $only_nodes
7437                #print STDERR "$element->{'tag'} $element->{'texi'} not associated with an element\n";
7438            }
7439        }
7440    }
7441
7442    # find texi2html specific directions and elements that are not texinfo
7443    # language features.
7444    #
7445    # Maybe Config hooks should be used at that point (up to index
7446    # preparation)
7447    #
7448    # find first, last and top elements
7449    if (@elements_list)
7450    {
7451        $element_first = $elements_list[0];
7452        print STDERR "# element first: $element_first->{'texi'}\n" if ($T2H_DEBUG & $DEBUG_ELEMENTS);
7453        # It is the last element before indices split, which may add new
7454        # elements
7455        $element_last = $elements_list[-1];
7456    }
7457    else
7458    {
7459        print STDERR "# \@elements_list is empty\n" if ($T2H_DEBUG & $DEBUG_ELEMENTS);
7460    }
7461    print STDERR "# top node: $node_top->{'texi'}\n" if (defined($node_top) and
7462        ($T2H_DEBUG & $DEBUG_ELEMENTS));
7463
7464    # Remark: there are many subtle distinctions among the elements that
7465    # have a flavor of being at top. First there are the texinfo top
7466    # elements (if present), namely $section_top for the @top element
7467    # and $node_top for the @node Top element (and both may be associated).
7468
7469    # Then there is $element_top, set up just below. In addition to
7470    # $section_top and $node_top, the section associated with $node_top
7471    # and the first element may be used. $element_top is used to determine
7472    # file splitting and file names, since it is always associated with
7473    # $docu_top file.
7474
7475    # The $element_top may have 'top' set, in case it is a node or @top.
7476    # In that case, special formatting is done, like using print_Top and
7477    # similar.
7478
7479    # Similarly with element_top, some other nodes than $node_top may
7480    # get associated with the top node filename without being considered
7481    # as top otherwise (this is done below).
7482
7483    if (defined($section_top) and $section_top->{'this'})
7484    {
7485    # element top is the element with @top.
7486        $element_top = $section_top;
7487    }
7488    elsif (defined($node_top) and $node_top->{'this'})
7489    {
7490    # otherwise top node may be the element_top
7491        $element_top = $node_top;
7492    }
7493    elsif (defined($node_top) and defined($node_top->{'with_section'}) and $node_top->{'with_section'}->{'this'})
7494    {
7495        # next, the element associated with the @node Top may be
7496        # the $element_top. In that case $element_top->{'top'} won't be set
7497        $element_top = $node_top->{'with_section'};
7498    }
7499    elsif (defined($element_first))
7500    {
7501    # If there is no @top section no top node associated with an element,
7502    # first element is used
7503         $element_top = $element_first;
7504    }
7505
7506    # Rather arbitrarily, 'top' is set for nodes as top elements
7507    # and @top. This triggers specific formatting, like calling
7508    # print_Top and similar things.
7509    if (defined($element_top))
7510    {
7511        $element_top->{'top'} = 1 if ($element_top->{'node'} or $element_top->{'tag'} eq 'top');
7512        print STDERR "# element top: $element_top->{'texi'}\n" if ($element_top and
7513           ($T2H_DEBUG & $DEBUG_ELEMENTS));
7514    }
7515
7516    print STDERR "# find fastback and fastforward\n"
7517       if ($T2H_DEBUG & $DEBUG_ELEMENTS);
7518    foreach my $element (@elements_list)
7519    { # nodes are ignored here, although their associated sectioning
7520      # command may be taken into account.
7521        my $up = get_top($element);
7522        next unless (defined($up));
7523        # take the opportunity to set the first chapter with index
7524        $element_chapter_index = $up if ($element_index and ($element_index eq $element));
7525        # fastforward is the next element on same level than the upper parent
7526        # element.
7527        if (exists ($up->{'toplevelnext'}))
7528        {
7529            $element->{'fastforward'} = $up->{'toplevelnext'}
7530        }
7531        # if the element isn't at the highest level, fastback is the
7532        # highest parent element
7533        if ($up and ($up ne $element))
7534        {
7535            $element->{'fastback'} = $up;
7536        }
7537        elsif ($element->{'toplevel'})
7538        {
7539             # the element is a top level element, we adjust the next
7540            # toplevel element fastback
7541            $element->{'fastforward'}->{'fastback'} = $element if ($element->{'fastforward'});
7542        }
7543    }
7544
7545    # set 'reference_element' which is used each time there is a cross ref
7546    # to that node (xref and menu entry), to do the href, and also the
7547    # element heading text.
7548    # It is the section associated with the node if there are only sections.
7549    # Since in the default case the target is the node target, even for
7550    # sections, this, in fact shouldn't lead to a different target, unless
7551    # the node and the section don't have the same file associated, which could
7552    # only happen with indices split. The heading text will be different, though.
7553    # The node name should also always be passed to the formatting functions
7554    # such that it is always possible for the formatting to chose the node
7555    # heading over the element heading selected using 'reference_element'.
7556    if ($only_sections)
7557    {
7558        foreach my $node(@nodes_list)
7559        {
7560            if ($node->{'with_section'})
7561            {
7562                $node->{'reference_element'} = $node->{'with_section'};
7563            }
7564        }
7565    }
7566    # the symmetric is not done for sections, since there is no crossref
7567    # to sections in texinfo (only to anchors and nodes), so that when
7568    # there is a link to an element (in Toc, for instance),
7569    # there is no reason to want to have the node (though, once again,
7570    # the href is almost surely the same than what would be with the node,
7571    # the heading would be different).
7572
7573    # end texi2html added directions
7574
7575    # do human readable id
7576    print STDERR "# find float id\n"
7577       if ($T2H_DEBUG & $DEBUG_ELEMENTS);
7578    foreach my $float (@floats)
7579    {
7580        $float->{'style_id'} = cross_manual_line($float->{'style_texi'});
7581        my $float_style = { };
7582        if (exists($floats{$float->{'style_id'}}))
7583        {
7584            $float_style = $floats{$float->{'style_id'}};
7585        }
7586        else
7587        {
7588            $floats{$float->{'style_id'}} = $float_style;
7589        }
7590        push @{$float_style->{'floats'}}, $float;
7591        $float->{'absolute_nr'} = scalar(@{$float_style->{'floats'}});
7592        my $up = get_top($float->{'element'});
7593        if (defined($up) and (!defined($float_style->{'current_chapter'}) or ($up->{'texi'} ne $float_style->{'current_chapter'})))
7594        {
7595            $float_style->{'current_chapter'} = $up->{'texi'};
7596            $float_style->{'nr_in_chapter'} = 1;
7597        }
7598        else
7599        {
7600            $float_style->{'nr_in_chapter'}++;
7601        }
7602        if (defined($up) and $up->{'toplevel'} and $up->{'number'} ne '')
7603        {
7604            $float->{'chapter_nr'} = $up->{'plain_number'};
7605            $float->{'nr'} = $float->{'chapter_nr'} . "." . $float_style->{'nr_in_chapter'};
7606        }
7607        else
7608        {
7609            $float->{'nr'} = $float->{'absolute_nr'};
7610        }
7611    }
7612
7613    print STDERR "# do human-readable index entries id\n"
7614       if ($T2H_DEBUG & $DEBUG_ELEMENTS);
7615    if ($Texi2HTML::Config::NEW_CROSSREF_STYLE)
7616    {
7617        foreach my $entry_region (sort(keys(%{$Texi2HTML::THISDOC{'index_entries_region_array'}})))
7618        {
7619            foreach my $index_entry (@{$Texi2HTML::THISDOC{'index_entries_region_array'}->{$entry_region}})
7620            {
7621                my $region = '';
7622                $region = "$index_entry->{'region'}-" if (defined($index_entry->{'region'}) and $index_entry->{'region'} ne '');
7623                my $index_id = "index-" . $region .$index_entry->{'cross'};
7624                my $index = 1;
7625                # $index > 0 should prevent integer overflow, hopefully
7626                while (exists($cross_reference_nodes{$index_id}) and $index > 0)
7627                {
7628                    $index_id = "index-" . $region . $index_entry->{'cross'} . "-" .$index;
7629                    $index++;
7630                }
7631                $index_entry->{'id'} = $index_id;
7632                $index_entry->{'target'} = $index_id;
7633                my $texi_entry = "index-".$region.$index_entry->{'texi'};
7634                $texi_entry .= "-".$index if ($index > 1);
7635                push @{$cross_reference_nodes{$index_id}}, $texi_entry;
7636            }
7637        }
7638    }
7639
7640
7641    if ($Texi2HTML::Config::NEW_CROSSREF_STYLE)
7642    {
7643        foreach my $key (keys(%nodes))
7644        {
7645            my $node = $nodes{$key};
7646            next if ($node->{'external_node'});
7647            $node->{'id'} = node_to_id($node->{'cross_manual_target'});
7648            # FIXME if NEW_CROSSREF_STYLE false is it done for anchors?
7649            $node->{'target'} = $node->{'id'};
7650        }
7651    }
7652
7653    # use %sections and %headings to modify also the headings
7654    foreach my $section (values(%sections), values(%headings))
7655    {
7656        if ($Texi2HTML::Config::NEW_CROSSREF_STYLE and ($section->{'cross'} =~ /\S/))
7657        {
7658            my $section_cross = $section->{'cross'};
7659            if (defined($section->{'region'}))
7660            { # for headings appearing in special regions like @copying...
7661                $section_cross = "${target_prefix}-$section->{'region'}_$section_cross";
7662            }
7663            $section->{'cross_manual_target'} = $section_cross;
7664
7665            my $index = 1;
7666            # $index > 0 should prevent integer overflow, hopefully
7667            while (exists($cross_reference_nodes{$section->{'cross_manual_target'}}) and $index > 0)
7668            {
7669                $section->{'cross_manual_target'} = $section_cross . "-" .$index;
7670                $index++;
7671            }
7672            my $texi_entry = $section->{'texi'};
7673            $texi_entry .= "-".$index if ($index > 1);
7674            push @{$cross_reference_nodes{$section->{'cross_manual_target'}}}, $texi_entry;
7675            $section->{'id'} = node_to_id($section->{'cross_manual_target'});
7676        }
7677    }
7678    # use the associated @part as target if there is an associated part.
7679    # do it separately to be sure that all the parts have an id.
7680    foreach my $section (values(%sections), values(%headings))
7681    {
7682        my $target = $section;
7683        $target = $section->{'with_part'} if ($section->{'with_part'});
7684        if ($Texi2HTML::Config::USE_NODE_TARGET and $target->{'with_node'})
7685        {
7686            $section->{'target'} = $target->{'with_node'}->{'target'};
7687        }
7688        else
7689        {
7690            $section->{'target'} = $target->{'id'};
7691        }
7692    }
7693
7694    # construct human readable tocid
7695    foreach my $section (values(%sections))
7696    {
7697        if ($Texi2HTML::Config::NEW_CROSSREF_STYLE and ($section->{'cross'} =~ /\S/))
7698        {
7699            foreach my $toc_id (['tocid','toc'], ['stocid', 'stoc'])
7700            {
7701                my $id_string = $toc_id->[0];
7702                my $prefix_string = $toc_id->[1];
7703                my $cross_string = '-' . $section->{'cross_manual_target'};
7704                $section->{$id_string} = $prefix_string . $cross_string;
7705                my $index = 1;
7706                # $index > 0 should prevent integer overflow, hopefully
7707                while (exists($cross_reference_nodes{$section->{$id_string}}) and $index > 0)
7708                {
7709                    $section->{$id_string} = $prefix_string . "-" .$index .$cross_string;
7710                    $index++;
7711                }
7712                my $texi_entry = $prefix_string.'-'.$section->{'texi'};
7713                $texi_entry = $prefix_string .'-'.$index.'-'.$section->{'texi'}  if ($index > 1);
7714                push @{$cross_reference_nodes{$section->{$id_string}}}, $texi_entry;
7715            }
7716        }
7717    }
7718    if (!$Texi2HTML::Config::NEW_CROSSREF_STYLE)
7719    {
7720        my $tocnr = 1;
7721        foreach my $element (@elements_list)
7722        {
7723            $element->{'tocid'} = 'TOC' . $tocnr;
7724            $tocnr++;
7725        }
7726    }
7727
7728    # Set file names
7729    # Find node file names and file names for nodes considered as elements
7730    my $node_as_top;
7731    if ($node_top)
7732    {
7733        $node_as_top = $node_top;
7734    }
7735    # following possibilities lead to some node being considered
7736    # as top for the purpose of setting the file node, but not as node_top
7737    elsif ($element_top->{'with_node'})
7738    {
7739        $node_as_top = $element_top->{'with_node'};
7740    }
7741    else
7742    {
7743        $node_as_top = $node_first;
7744    }
7745    if ($node_as_top)
7746    {
7747        do_node_target_file($node_as_top, 'top');
7748    }
7749    foreach my $key (keys(%nodes))
7750    {
7751        my $node = $nodes{$key};
7752        next if (defined($node_as_top) and ($node eq $node_as_top));
7753        do_node_target_file($node,'');
7754    }
7755
7756    print STDERR "# split(".Texi2HTML::Config::get_conf('SPLIT').") and set files\n"
7757       if ($T2H_DEBUG & $DEBUG_ELEMENTS);
7758    # find document nr and document file for sections and nodes.
7759    # Split according to Texi2HTML::Config::SPLIT.
7760    # find file and id for placed elements (anchors, index entries, headings)
7761    if (Texi2HTML::Config::get_conf('SPLIT'))
7762    {
7763        $Texi2HTML::THISDOC{'split_level'} = $toplevel;
7764        my $doc_nr = -1;
7765        if (Texi2HTML::Config::get_conf('SPLIT') eq 'section')
7766        {
7767            $Texi2HTML::THISDOC{'split_level'} = 2 if ($toplevel <= 2);
7768        }
7769        my $previous_file;
7770        my $previous_is_top = 0;
7771        foreach my $element (@elements_list)
7772        {
7773            print STDERR "# Splitting (".Texi2HTML::Config::get_conf('SPLIT').":$Texi2HTML::THISDOC{'split_level'}) $element->{'texi'}\n" if ($T2H_DEBUG & $DEBUG_ELEMENTS);
7774            my $new_file = 0;
7775            if (
7776               (!defined($previous_file)) or
7777               (Texi2HTML::Config::get_conf('SPLIT') eq 'node') or
7778               (
7779                 defined($element->{'level'}) and ($element->{'level'} <= $Texi2HTML::THISDOC{'split_level'})
7780               ) or
7781               (
7782                 !defined($element->{'level'}) and defined($element->{'with_section'}) and ($element->{'with_section'}->{'level'} <= $Texi2HTML::THISDOC{'split_level'})
7783               ) or
7784               ( # top file after another file
7785                 (defined($previous_file) and ($element eq $element_top)
7786                  and ($previous_file ne $docu_top))
7787               ) # element following top element is always considered to be
7788                 # in a different file.
7789               or ($previous_is_top)
7790              )
7791            {
7792                $new_file = 1;
7793                $doc_nr++;
7794            }
7795            $previous_is_top = 0 if ($previous_is_top);
7796
7797            $element->{'doc_nr'} = $doc_nr;
7798            $element->{'file'} = "${docu_name}_$doc_nr"
7799                . (defined($Texi2HTML::THISDOC{'extension'}) ? ".$Texi2HTML::THISDOC{'extension'}" : '');
7800            my $use_node_file = 0;
7801            if ($element eq $element_top)
7802            { # the top element
7803                $element->{'file'} = $docu_top;
7804                $previous_is_top = 1;
7805            }
7806            elsif ($Texi2HTML::Config::NODE_FILENAMES)
7807            {
7808                $use_node_file = 1;
7809                if ($new_file)
7810                {
7811                    my $node = get_node($element);
7812                    if ($node and defined($node->{'node_file'}))
7813                    {
7814                        $element->{'file'} = $node->{'node_file'};
7815                    }
7816                    elsif ($element->{'cross'} =~ /\S/)
7817                    { # use the canonicalized/transliterated section file name.
7818                        $element->{'file'} = $element->{'cross'}
7819                         . (defined($Texi2HTML::THISDOC{'extension'}) ? ".$Texi2HTML::THISDOC{'extension'}" : '');
7820                    }
7821                    # The remaining case is for sectioning elements with empty
7822                    # headings and no node associated. They will have a name
7823                    # with numbers, like "${docu_name}_$doc_nr", they may
7824                    # collide with split indices names
7825                }
7826                else
7827                {
7828                    $element->{'file'} = $previous_file;
7829                }
7830            }
7831            $previous_file = $element->{'file'};
7832            do_element_targets($element, $use_node_file);
7833            print STDERR "# [$doc_nr] add_file($use_node_file,$new_file,".var_to_str($previous_file).") $element->{'file'} for $element->{'texi'}\n" if ($T2H_DEBUG & $DEBUG_ELEMENTS);
7834            add_file($element->{'file'});
7835        }
7836    }
7837    else
7838    { # not split
7839        add_file($docu_doc);
7840        foreach my $element(@elements_list)
7841        {
7842            $element->{'file'} = $docu_doc;
7843            $element->{'doc_nr'} = 0;
7844            do_element_targets($element);
7845        }
7846    }
7847    # 'pathological' cases. No texinfo sectioning element at all or no
7848    # texi2html sectioning elements
7849    if (!@elements_list)
7850    {
7851        if (@all_elements)
7852        {
7853            # in fact this happens only if there is no top element, but still
7854            # sections, so only if USE_SECTIONS = 0 and there is no node.
7855            #document_warn ("No elements available for splitting") if (Texi2HTML::Config::get_conf('SPLIT'));
7856            foreach my $element (@all_elements)
7857            {
7858                #print STDERR "# no \@elements_list. Processing $element->{'texi'}\n";
7859                $element->{'file'} = $docu_doc;
7860                $element->{'doc_nr'} = 0;
7861                push @{$element->{'place'}}, @{$element->{'current_place'}};
7862                do_element_targets($element,$Texi2HTML::Config::NODE_FILENAMES);
7863                print STDERR "# no \@elements_list, setting $element->{'file'} for $element->{'texi'}\n" if ($T2H_DEBUG & $DEBUG_ELEMENTS);
7864            }
7865            add_file($docu_doc);
7866        }
7867        else
7868        {
7869            #document_warn ("No elements at all") if (Texi2HTML::Config::get_conf('SPLIT'));
7870            $element_before_anything->{'file'} = $docu_doc;
7871            $element_before_anything->{'doc_nr'} = 0;
7872            do_element_targets($element_before_anything,$Texi2HTML::Config::NODE_FILENAMES);
7873            print STDERR "# no element at all, setting $element_before_anything->{'file'} for $element_before_anything->{'texi'}\n" if ($T2H_DEBUG & $DEBUG_ELEMENTS);
7874        }
7875    }
7876
7877    # correct the id and file for the things placed in footnotes
7878    foreach my $place(@{$footnote_element->{'place'}})
7879    {
7880        do_place_target_file ($place, $footnote_element, 'footnotes');
7881    }
7882    # if setcontentsaftertitlepage is set, the contents should be associated
7883    # with the titlepage. That's what is done there.
7884    push @$no_element_associated_place, $content_element{'contents'}
7885      if (Texi2HTML::Config::get_conf('contents') and $Texi2HTML::THISDOC{'setcontentsaftertitlepage'});
7886    push @$no_element_associated_place, $content_element{'shortcontents'}
7887      if (Texi2HTML::Config::get_conf('shortcontents') and $Texi2HTML::THISDOC{'setshortcontentsaftertitlepage'});
7888    # correct the id and file for the things placed in regions (copying...)
7889    foreach my $place(@$no_element_associated_place)
7890    {
7891#print STDERR "entry $place->{'entry'} texi $place->{'texi'}\n";
7892        $place->{'element'} = $element_top if (exists($place->{'element'}));
7893        do_place_target_file ($place, $element_top, 'no_associated_element');
7894    }
7895
7896    # determine contents element and files
7897    foreach my $content_type(keys(%content_element))
7898    {
7899        # with set*aftertitlepage, there will always be a href to Contents
7900        # or Overview pointing to the top element, even if there is no
7901        # titlepage outputed.
7902        if (!scalar(@{$all_content_elements{$content_type}}))
7903        {
7904            if  ($Texi2HTML::Config::INLINE_CONTENTS)
7905            {
7906                print STDERR "# No content $content_type\n" if ($T2H_DEBUG & $DEBUG_ELEMENTS);
7907                $content_element{$content_type} = undef;
7908            }
7909        }
7910        elsif ($Texi2HTML::Config::INLINE_CONTENTS and !Texi2HTML::Config::get_conf('set' . $content_type .'aftertitlepage'))
7911        { # use the last element for references in case there is more than one
7912            $content_element{$content_type} = $all_content_elements{$content_type}->[-1];
7913        }
7914    }
7915    my ($toc_file, $stoc_file);
7916    $toc_file = $docu_toc;
7917    $stoc_file = $docu_stoc;
7918    if ($Texi2HTML::Config::INLINE_CONTENTS)
7919    {
7920        $toc_file = $content_element{'contents'}->{'file'} if (defined($content_element{'contents'}));
7921        $stoc_file = $content_element{'shortcontents'}->{'file'} if (defined($content_element{'shortcontents'}));
7922    }
7923    $Texi2HTML::THISDOC{'toc_file'} = $toc_file;
7924    $Texi2HTML::THISDOC{'stoc_file'} = $stoc_file;
7925
7926    print STDERR "# find NextFile and PrevFile\n"
7927       if ($T2H_DEBUG & $DEBUG_ELEMENTS);
7928    foreach my $element (@elements_list)
7929    {
7930        my $current_element = $element;
7931        my $file = $current_element->{'file'};
7932        my $previous_file;
7933        while ($current_element->{'back'})
7934        {
7935#print STDERR "Back $current_element->{'texi'}\n";
7936            $current_element = $current_element->{'back'};
7937            if ($current_element->{'file'} ne $file)
7938            {
7939                $previous_file = $current_element->{'file'};
7940                last;
7941            }
7942        }
7943        if (defined($previous_file))
7944        {
7945            while ($current_element->{'back'})
7946            {
7947                if ($current_element->{'back'}->{'file'} ne $previous_file)
7948                {
7949                    last;
7950                }
7951                $current_element = $current_element->{'back'};
7952            }
7953            $element->{'prevfile'} = $current_element;
7954        }
7955
7956        $current_element = $element;
7957        while ($current_element->{'forward'})
7958        {
7959#print STDERR "Fwd $current_element->{'texi'}\n";
7960            $current_element = $current_element->{'forward'};
7961            if ($current_element->{'file'} ne $file)
7962            {
7963                 $element->{'nextfile'} = $current_element;
7964            }
7965        }
7966    }
7967    # convert directions in direction with first letter in all caps, to be
7968    # consistent with the convention used in the .init file.
7969    foreach my $element (@elements_list)
7970    {
7971        foreach my $direction (@element_directions)
7972        {
7973            my $direction_no_caps = $direction;
7974            $direction_no_caps =~ tr/A-Z/a-z/;
7975            $element->{$direction} = $element->{$direction_no_caps};
7976        }
7977    }
7978
7979    ########################### debug prints
7980    foreach my $file (keys(%files))
7981    {
7982        last unless ($T2H_DEBUG & $DEBUG_ELEMENTS);
7983        print STDERR "$file: counter $files{$file}->{'counter'}\n";
7984    }
7985    my $output_elements = \@elements_list;
7986    if (!scalar(@elements_list) and ($T2H_DEBUG & $DEBUG_ELEMENTS))
7987    {
7988        print STDERR "No elements_list, no texi2html elements\n";
7989        $output_elements = \@all_elements;
7990    }
7991    foreach my $element ((@$output_elements, $footnote_element))
7992    {
7993        last unless ($T2H_DEBUG & $DEBUG_ELEMENTS);
7994        my $is_toplevel = 'not toplevel';
7995        $is_toplevel = 'toplevel' if ($element->{'toplevel'});
7996        print STDERR "$element ";
7997        if ($element->{'node'})
7998        {
7999            print STDERR "node($element->{'id'}, $is_toplevel, doc_nr $element->{'doc_nr'}($element->{'file'})) $element->{'texi'}:\n";
8000            print STDERR "  section_ref: $element->{'section_ref'}->{'texi'}\n" if (defined($element->{'section_ref'}));
8001            print STDERR "  with_section: $element->{'with_section'}->{'texi'}\n" if (defined($element->{'with_section'}));
8002        }
8003        elsif ($element->{'footnote'})
8004        {
8005            print STDERR "footnotes($element->{'id'}, file $element->{'file'})\n";
8006        }
8007        else
8008        {
8009            my $number = "UNNUMBERED";
8010            $number = $element->{'number'} if ($element->{'number'});
8011            print STDERR "$number ($element->{'id'}, $is_toplevel, level $element->{'level'}-$element->{'toc_level'}, doc_nr $element->{'doc_nr'}($element->{'file'})) $element->{'texi'}:\n";
8012            print STDERR "  with_node: $element->{'with_node'}->{'texi'}\n" if (defined($element->{'with_node'}));
8013            print STDERR "  node_ref: $element->{'node_ref'}->{'texi'}\n" if (defined($element->{'node_ref'}));
8014        }
8015
8016        if (!$element->{'footnote'})
8017        {
8018            if (!defined($files{$element->{'file'}}))
8019            {
8020               die "Bug: files{\$element->{'file'}} undef element $element->{'texi'}, file $element->{'file'}.";
8021            }
8022            print STDERR "  file: $element->{'file'} $files{$element->{'file'}}, counter $files{$element->{'file'}}->{'counter'}\n";
8023        }
8024        print STDERR "  level: $element->{'level'}\n" if (defined($element->{'level'}));
8025        print STDERR "  TOP($toplevel) " if ($element->{'top'});
8026        print STDERR "  u: $element->{'up'}->{'texi'}\n" if (defined($element->{'up'}));
8027        print STDERR "  ch: $element->{'child'}->{'texi'}\n" if (defined($element->{'child'}));
8028        print STDERR "  fb: $element->{'fastback'}->{'texi'}\n" if (defined($element->{'fastback'}));
8029        print STDERR "  b: $element->{'back'}->{'texi'}\n" if (defined($element->{'back'}));
8030        print STDERR "  p: $element->{'prev'}->{'texi'}\n" if (defined($element->{'prev'}));
8031        print STDERR "  u: $element->{'sectionup'}->{'texi'}\n" if (defined($element->{'sectionup'}));
8032        print STDERR "  n: $element->{'sectionnext'}->{'texi'}\n" if (defined($element->{'sectionnext'}));
8033	print STDERR "  t_n: $element->{'toplevelnext'}->{'texi'}\n" if (defined($element->{'toplevelnext'}));
8034	print STDERR "  t_p: $element->{'toplevelprev'}->{'texi'}\n" if (defined($element->{'toplevelprev'}));
8035        print STDERR "  n_u: $element->{'nodeup'}->{'texi'}\n" if (defined($element->{'nodeup'}));
8036        print STDERR "  f: $element->{'forward'}->{'texi'}\n" if (defined($element->{'forward'}));
8037        print STDERR "  follow: $element->{'following'}->{'texi'}\n" if (defined($element->{'following'}));
8038	print STDERR "  m_p: $element->{'menu_prev'}->{'texi'}\n" if (defined($element->{'menu_prev'}));
8039	print STDERR "  m_n: $element->{'menu_next'}->{'texi'}\n" if (defined($element->{'menu_next'}));
8040	print STDERR "  m_u: $element->{'menu_up'}->{'texi'}\n" if (defined($element->{'menu_up'}));
8041	print STDERR "  m_ch: $element->{'menu_child'}->{'texi'}\n" if (defined($element->{'menu_child'}));
8042        print STDERR "  ff: $element->{'fastforward'}->{'texi'}\n" if (defined($element->{'fastforward'}));
8043        print STDERR "  n_f: $element->{'nextfile'}->{'texi'}\n" if (defined($element->{'nextfile'}));
8044        print STDERR "  p_f: $element->{'prevfile'}->{'texi'}\n" if (defined($element->{'prevfile'}));
8045        my $section_childs = '';
8046        if (defined($element->{'section_childs'}))
8047        {
8048            foreach my $child (@{$element->{'section_childs'}})
8049            {
8050                $section_childs .= "$child->{'texi'}|";
8051            }
8052        }
8053        print STDERR "  s_chs: $section_childs\n" if ($section_childs ne '');
8054        my $node_childs = '';
8055        if (defined($element->{'node_childs'}))
8056        {
8057            foreach my $child (@{$element->{'node_childs'}})
8058            {
8059                $node_childs .= "$child->{'texi'}|";
8060            }
8061        }
8062        print STDERR "  n_chs: $node_childs\n" if ($node_childs ne '');
8063
8064        if (defined($element->{'menu_up_hash'}))
8065        {
8066            print STDERR "  parent nodes:\n";
8067            foreach my $menu_up (keys%{$element->{'menu_up_hash'}})
8068            {
8069                print STDERR "   $menu_up ($element->{'menu_up_hash'}->{$menu_up})\n";
8070            }
8071        }
8072        print STDERR "  places: $element->{'place'}\n";
8073        foreach my $place(@{$element->{'place'}})
8074        {
8075            if (!$place->{'entry'} and !$place->{'float'} and !$place->{'texi'} and !$place->{'contents'} and !$place->{'shortcontents'} and (!defined($place->{'command'} or $place->{'command'} ne 'printindex')))
8076            {
8077                 print STDERR "BUG: unknown placed stuff ========\n";
8078                 foreach my $key (keys(%$place))
8079                 {
8080                      print STDERR "$key: $place->{$key}\n";
8081                 }
8082                 print STDERR "==================================\n";
8083            }
8084            elsif ($place->{'entry'})
8085            {
8086                print STDERR "    index($place): $place->{'entry'} ($place->{'id'}, $place->{'file'})\n";
8087            }
8088            elsif ($place->{'anchor'})
8089            {
8090                print STDERR "    anchor: $place->{'texi'} ($place->{'id'}, $place->{'file'})\n";
8091            }
8092            elsif ($place->{'float'})
8093            {
8094                if (defined($place->{'texi'}))
8095                {
8096                    print STDERR "    float($place): $place->{'texi'} ($place->{'id'}, $place->{'file'})\n";
8097                }
8098                else
8099                {
8100                    print STDERR "    float($place): NO LABEL ($place->{'id'}, $place->{'file'})\n";
8101                }
8102            }
8103            elsif ($place->{'contents'})
8104            {
8105                print STDERR "    contents\n";
8106            }
8107            elsif ($place->{'shortcontents'})
8108            {
8109                print STDERR "    shortcontents\n";
8110            }
8111            elsif (defined($place->{'command'}) and $place->{'command'} eq 'printindex')
8112            {
8113                print STDERR "    printindex $place->{'name'}\n";
8114            }
8115            else
8116            {
8117                print STDERR "    heading: $place->{'texi'} ($place->{'id'}, $place->{'file'})\n";
8118            }
8119        }
8120    }
8121    ########################### end debug prints
8122}
8123
8124sub add_file($)
8125{
8126    my  $file = shift;
8127    if ($files{$file})
8128    {
8129         $files{$file}->{'counter'}++;
8130    }
8131    else
8132    {
8133         $files{$file} = {
8134           'counter' => 1,
8135           'relative_foot_num' => 0,
8136           'foot_lines' => []
8137         };
8138    }
8139}
8140
8141# find parent element which is a toplevel element
8142sub get_top($)
8143{
8144   my $element = shift;
8145   if ($element->{'node'})
8146   {
8147      if (defined($element->{'section_ref'}))
8148      {
8149         $element = $element->{'section_ref'};
8150      }
8151      else
8152      {
8153         return undef;
8154      }
8155   }
8156   return undef if ($element eq $element_before_anything);
8157   my $up = $element;
8158   while (!$up->{'toplevel'} and $up->{'tag'} ne 'top')
8159   {
8160       if (!defined($up->{'sectionup'}))
8161       {
8162           # If there is no section, it is normal not to have toplevel element,
8163           # and it is also the case if there is a low level element before
8164           # a top level element
8165           return undef;
8166       }
8167       $up = $up->{'sectionup'};
8168   }
8169   return $up;
8170}
8171
8172sub get_node($)
8173{
8174    my $element = shift;
8175    return undef if (!defined($element));
8176    return $element if ($element->{'node'});
8177    return $element->{'with_node'} if ($element->{'with_node'});
8178}
8179
8180sub do_section_names($$)
8181{
8182    my $number = shift;
8183    my $section = shift;
8184    my $texi = &$Texi2HTML::Config::heading_texi($section->{'tag'}, $section->{'texi'}, $section->{'number'});
8185    $section->{'text'} = substitute_line($texi, "\@$section->{'tag'}", undef, $section->{'line_nr'});
8186    # no need for translation since there is no line number it should never
8187    # appear in error messages.
8188    $section->{'text_nonumber'} = substitute_line($section->{'texi'}, "\@$section->{'tag'} no number");
8189    # backward compatibility
8190    # Removed from doc in nov 2009
8191    $section->{'name'} = $section->{'text_nonumber'};
8192    $section->{'no_texi'} = remove_texi($texi);
8193    $section->{'simple_format'} = simple_format(undef,undef,"\@$section->{'tag'} simple_format", $texi);
8194    $section->{'heading_texi'} = $texi;
8195}
8196
8197# get the html names from the texi for all elements
8198sub do_names()
8199{
8200   print STDERR "# Doing ". scalar(keys(%nodes)) . " nodes, ".
8201       scalar(keys(%sections)) . " sections, " .
8202       scalar(keys(%headings)) . " headings in ". $#elements_list .
8203       " elements\n" if ($T2H_DEBUG);
8204   # for nodes and anchors we haven't any state defined
8205   # This seems right, however, as we don't want @refs or @footnotes
8206   # or @anchors within nodes, section commands or anchors.
8207   $global_pass = '2 node names';
8208   foreach my $node (keys(%nodes))
8209   {
8210       my $texi = &$Texi2HTML::Config::heading_texi($nodes{$node}->{'tag'},
8211          $nodes{$node}->{'texi'}, undef);
8212       my $command = 'node';
8213       $command = $nodes{$node}->{'tag'} if ($nodes{$node}->{'tag'});
8214       $nodes{$node}->{'text'} = substitute_line ($texi, "\@$command", {'code_style' => 1}, $nodes{$node}->{'line_nr'});
8215       $nodes{$node}->{'text_nonumber'} = $nodes{$node}->{'text'};
8216       # backward compatibility -> maybe used to have the name without code_style ?
8217       # Removed from doc in nov 2009
8218       $nodes{$node}->{'name'} = substitute_line($texi, "\@$command name");
8219       $nodes{$node}->{'no_texi'} = remove_texi($texi);
8220       $nodes{$node}->{'simple_format'} = simple_format(undef, undef, "\@$command simple_format", $texi);
8221       $nodes{$node}->{'heading_texi'} = $texi;
8222
8223       ################# debug
8224       # if $nodes{$node}->{'external_node'} and $nodes{$node}->{'seen'}
8225       # this is a bug, since there are checks that the node hasn't an
8226       # external node syntax.
8227       msg_debug ("$nodes{$node}->{'texi'} is external and was seen",  $nodes{$node}->{'line_nr'}) if ($nodes{$node}->{'seen'} and $nodes{$node}->{'external_node'});
8228       ################# end debug
8229   }
8230   $global_pass = '2 section names';
8231   foreach my $number (keys(%sections))
8232   {
8233       do_section_names($number, $sections{$number});
8234   }
8235   $global_pass = '2 heading names';
8236   foreach my $number (keys(%headings))
8237   {
8238       do_section_names($number, $headings{$number});
8239   }
8240   print STDERR "# Names done\n" if ($T2H_DEBUG);
8241}
8242
8243
8244#+++############################################################################
8245#                                                                              #
8246# Stuff related to Index generation                                            #
8247#                                                                              #
8248#---############################################################################
8249
8250# called during pass_structure
8251sub enter_index_entry($$$$$)
8252{
8253    my $prefix = shift;
8254    my $line_nr = shift;
8255    my $entry = shift;
8256    my $command = shift;
8257    my $state = shift;
8258
8259    my $heading_element = $state->{'heading_element'};
8260    my $current_element = $state->{'current_element'};
8261    my $place = $state->{'place'};
8262    my $region = $state->{'region'};
8263
8264    my $index_name = $index_prefix_to_name{$prefix};
8265    if (!defined($index_name))
8266    {
8267        line_error (sprintf(__("Unknown index `%s'"), $prefix), $line_nr);
8268    }
8269    if ($current_element eq $element_before_anything)
8270    {
8271        #line_warn ("Index entry before document: \@${prefix}index $entry", $line_nr);
8272        line_error (sprintf(__("Entry for index `%s' outside of any node"), $index_name), $line_nr);
8273    }
8274    $entry = trim_comment_spaces ($entry, "index entry in \@$command", $line_nr);
8275    # beware that the texinfo could be non empty, but the no_texi be empty.
8276    # So the $no_texi should be used to determine whether the entry is
8277    # empty or not.
8278    my $no_texi = remove_texi($entry);
8279
8280    my $id;
8281    # don't add a specific index target if the index entry is in a special
8282    # region like @copying or the like or the index is not defined
8283    if (!defined($region))
8284    {
8285        $region = 'document';
8286        # No id if the index is unknown.
8287        $id = 'IDX' . ++$document_idx_num if (defined($index_name));
8288    }
8289    my $target = $id;
8290
8291    # entry will later be in @code for code-like index entry. texi stays
8292    # the same.
8293    my $index_entry = {
8294           'entry'    => $entry,
8295           'texi'     => $entry,
8296           'element'  => $heading_element,
8297           'real_element'  => $current_element,
8298           'prefix'   => $prefix,
8299           'id'       => $id,
8300           'target'   => $target,
8301           'command'  => $command,
8302           'region'   => $state->{'region'},
8303           'line_nr'  => $line_nr,
8304           'index_name' => $index_name
8305    };
8306
8307    my $id_text = $id;
8308    $id_text = 'NO ID' if (!defined($id));
8309    print STDERR "# in $region enter \@$command ${prefix}index($no_texi) [$entry] with id $id_text ($index_entry)\n"
8310        if ($T2H_DEBUG & $DEBUG_INDEX);
8311
8312    $index_entry->{'entry'} = '@code{'.$index_entry->{'entry'}.'}'
8313       if (defined($index_name) and
8314        defined($index_names{$index_name}->{'prefixes'}) and
8315        $index_names{$index_name}->{'prefixes'}->{$prefix}
8316        and $no_texi =~ /\S/);
8317
8318    push @$place, $index_entry;
8319
8320    #msg_debug("enter_index_entry: region $region, index_entry $index_entry, \@$command, texi `$entry'", $line_nr);
8321
8322    # don't add the index entry to the list of index entries used for index
8323    # entry formatting, if the index entry appears in a region like copying
8324    # currently this is only used for debugging purposes, since the
8325    # index entries lists are broken by region now.
8326    push @index_labels, $index_entry unless (defined($state->{'region'}));
8327
8328    # these lists are used to retrieve index entries in pass 3
8329    push @{$Texi2HTML::THISDOC{'index_entries'}->{$region}->{$entry}->{'entries'}}, $index_entry;
8330    if (defined($index_name))
8331    {
8332        # this is used for @printindex
8333        push @{$Texi2HTML::THISDOC{'index_entries_array'}->{$index_name}}, $index_entry;
8334        # this is used for targets
8335        push @{$Texi2HTML::THISDOC{'index_entries_region_array'}->{$region}}, $index_entry;
8336    }
8337    else
8338    {
8339        push @unknown_index_index_entries, $index_entry;
8340    }
8341}
8342
8343# these variables are global, so great care should be taken with
8344# state->{'multiple_state'}, ->{'region'}, ->{'region_pass'} and
8345# {'outside_document'}.
8346my $global_head_num = 0;       # heading index. it is global for the main doc,
8347                               # and taken from the state if in multiple_pass.
8348my $global_foot_num = 0;
8349my $global_relative_foot_num = 0;
8350my @foot_lines = ();           # footnotes
8351my $copying_comment = '';      # comment constructed from text between
8352                               # @copying and @end copying with licence
8353my %acronyms_like = ();        # acronyms or similar commands associated texts
8354                               # the key are the commands, the values are
8355                               # hash references associating shorthands to
8356                               # texts.
8357
8358# detailmenu    number of opened detailed menus
8359sub fill_state($)
8360{
8361    my $state = shift;
8362    foreach my $key ('preformatted', 'code_style', 'math_style', 'keep_texi',
8363      'keep_nr',  'detailmenu', 'direntry', 'sec_num', 'menu', 'multiple_pass')
8364    {
8365        $state->{$key} = 0 unless exists($state->{$key});
8366    }
8367
8368    $state->{'paragraph_style'} = [ '' ] unless exists($state->{'paragraph_style'});
8369    $state->{'preformatted_stack'} = [ '' ] unless exists($state->{'preformatted_stack'});
8370    $state->{'command_stack'} = [] unless exists($state->{'command_stack'});
8371    $state->{'quotation_stack'} = [] unless exists($state->{'quotation_stack'});
8372    # if there is no $state->{'element'} the first element is used
8373    if ((!$state->{'element'} or $state->{'element'}->{'before_anything'}) and (@elements_list))
8374    {
8375        $state->{'element'} = $elements_list[0];
8376    }
8377    # this is consistent with what is done in rearrange_elements
8378    $state->{'element'} = {'file' => $docu_doc, 'texi' => 'VIRTUAL ELEMENT'} if (!$state->{'element'});
8379}
8380
8381sub do_element_directions ($)
8382{
8383   my $this_element = shift;
8384   #print STDERR "Doing hrefs for $this_element->{'texi'} First ";
8385   $Texi2HTML::HREF{'First'} = href($element_first, $this_element->{'file'});
8386   #print STDERR "Last ";
8387   $Texi2HTML::HREF{'Last'} = href($element_last, $this_element->{'file'});
8388   #print STDERR "Index ";
8389   $Texi2HTML::HREF{'Index'} = href($element_chapter_index, $this_element->{'file'}) if (defined($element_chapter_index));
8390   #print STDERR "Top ";
8391   $Texi2HTML::HREF{'Top'} = href($element_top, $this_element->{'file'});
8392   if ($Texi2HTML::Config::INLINE_CONTENTS)
8393   {
8394      $Texi2HTML::HREF{'Contents'} = href($content_element{'contents'}, $this_element->{'file'});
8395      $Texi2HTML::HREF{'Overview'} = href($content_element{'shortcontents'}, $this_element->{'file'});
8396   }
8397   else
8398   {
8399      $Texi2HTML::HREF{'Contents'} = file_target_href($Texi2HTML::THISDOC{'toc_file'}, $this_element->{'file'}, $content_element{'contents'}->{'target'}) if (@{$Texi2HTML::TOC_LINES} and defined($content_element{'contents'}));
8400      $Texi2HTML::HREF{'Overview'} = file_target_href($Texi2HTML::THISDOC{'stoc_file'}, $this_element->{'file'}, $content_element{'shortcontents'}->{'target'}) if (@{$Texi2HTML::OVERVIEW} and defined($content_element{'shortcontents'}));
8401   }
8402   if ($Texi2HTML::THISDOC{'do_about'})
8403   {
8404      $Texi2HTML::HREF{'About'} = file_target_href($docu_about, $this_element->{'file'}, $Texi2HTML::Config::misc_pages_targets{'About'});
8405   }
8406   $Texi2HTML::HREF{'Footnotes'} = file_target_href($docu_foot, $this_element->{'file'}, $Texi2HTML::Config::misc_pages_targets{'Footnotes'});
8407   foreach my $direction (@element_directions)
8408   {
8409      my $elem = $this_element->{$direction};
8410      $Texi2HTML::NODE{$direction} = undef;
8411      $Texi2HTML::HREF{$direction} = undef;
8412      $Texi2HTML::NAME{$direction} = undef;
8413      #print STDERR "$direction \n";
8414      next unless (defined($elem));
8415      if ($elem->{'node'} or $elem->{'external_node'} or !$elem->{'seen'})
8416      {
8417         $Texi2HTML::NODE{$direction} = $elem->{'text'};
8418      }
8419      elsif ($elem->{'with_node'})
8420      {
8421         $Texi2HTML::NODE{$direction} = $elem->{'with_node'}->{'text'};
8422      }
8423      if (!$elem->{'seen'})
8424      {
8425         $Texi2HTML::HREF{$direction} = do_external_href($elem->{'texi'});
8426      }
8427      else
8428      {
8429         $Texi2HTML::HREF{$direction} = href($elem, $this_element->{'file'});
8430      }
8431      $Texi2HTML::NAME{$direction} = $elem->{'text'};
8432      $Texi2HTML::NO_TEXI{$direction} = $elem->{'no_texi'};
8433      $Texi2HTML::SIMPLE_TEXT{$direction} = $elem->{'simple_format'};
8434      #print STDERR "$direction ($this_element->{'texi'}): \n  NO_TEXI: $Texi2HTML::NO_TEXI{$direction}\n  NAME $Texi2HTML::NAME{$direction}\n  NODE $Texi2HTML::NODE{$direction}\n  HREF $Texi2HTML::HREF{$direction}\n\n";
8435   }
8436   #print STDERR "\nDone hrefs for $this_element->{'texi'}\n";
8437}
8438
8439sub open_out_file($)
8440{
8441  my $new_file = shift;
8442  my $do_page_head = 0;
8443  # if the filehandle is closed, with fileno undef, open_out
8444  # is called with the second argument true, which leads to opening
8445  # the file in append mode, to avoid overwriting the previous
8446  # file.
8447  if ($files{$new_file}->{'filehandle'} and defined(fileno($files{$new_file}->{'filehandle'})))
8448  {
8449    $Texi2HTML::THISDOC{'FH'} = $files{$new_file}->{'filehandle'};
8450  }
8451  else
8452  {
8453    my $known_file = 0;
8454    if ($files{$new_file}->{'filehandle'})
8455    {
8456       $known_file = 1;
8457       document_warn ("The file $new_file was already closed and is reopened");
8458    }
8459    $Texi2HTML::THISDOC{'FH'} = open_out("$docu_rdir$new_file", $known_file);
8460#print STDERR "OPEN $docu_rdir$file, $Texi2HTML::THISDOC{'FH'}". scalar($Texi2HTML::THISDOC{'FH'})."\n";
8461    $files{$new_file}->{'filehandle'} = $Texi2HTML::THISDOC{'FH'};
8462    $do_page_head = !$known_file;
8463  }
8464  return $do_page_head;
8465}
8466
8467sub set_line_nr_in_stack($$$)
8468{
8469   my $state = shift;
8470   my $stack = shift;
8471   my $line_nr = shift;
8472
8473   if ($state->{'keep_texi'} and defined($line_nr))
8474   {
8475        my $stack_index = $#$stack;
8476        while ($stack_index >= 0 and defined($stack->[$stack_index]->{'keep_line_nr'}))
8477        {
8478            push @{$stack->[$stack_index]->{'keep_line_nr'}}, $line_nr;
8479            $stack_index --;
8480        }
8481    }
8482}
8483
8484sub unref_file($)
8485{
8486    my $file = shift;
8487    $files{$file}->{'counter'}--;
8488    print STDERR "# Unref file $file, remaining counter $files{$file}->{'counter'}\n"
8489                 if ($T2H_DEBUG & $DEBUG_ELEMENTS);
8490
8491}
8492
8493sub pass_text($$)
8494{
8495    my $doc_lines = shift;
8496    my $doc_numbers = shift;
8497    my %state;
8498    fill_state(\%state);
8499    my @stack;
8500    my $text = '';
8501    my $doc_nr;
8502    my $in_doc = 0;
8503    my @text =();
8504    my $one_section = 1 if (@elements_list <= 1);
8505
8506    push_state(\%state);
8507
8508    $global_pass = '3 prepare names';
8509    set_special_names();
8510    $footnote_element->{'text'} = $Texi2HTML::NAME{'Footnotes'};
8511    # We set titlefont only if the titlefont appeared in the top element
8512    if (defined($element_top->{'titlefont'}))
8513    {
8514         $Texi2HTML::THISDOC{'titlefont_texi'} = $element_top->{'titlefont'};
8515         # backward compatibility nov 2009
8516         $value{'_titlefont'} = $element_top->{'titlefont'};
8517    }
8518
8519    # prepare %Texi2HTML::THISDOC
8520    $Texi2HTML::THISDOC{'command_stack'} = $state{'command_stack'};
8521
8522    #foreach my $texi_cmd (('shorttitlepage', 'settitle', 'author', 'title',
8523    #       'subtitle'))
8524    #{
8525    #    $Texi2HTML::THISDOC{$texi_cmd . '_texi'} = $value{'_' . $texi_cmd};
8526    #}
8527    $Texi2HTML::THISDOC{'top_texi'} = $section_top->{'texi'} if (defined($section_top));
8528
8529    $Texi2HTML::THISDOC{'fulltitle_texi'} = '';
8530    foreach my $possible_fulltitle('settitle', 'title', 'shorttitlepage', 'top', 'titlefont')
8531    {
8532        if (defined($Texi2HTML::THISDOC{$possible_fulltitle . '_texi'}) and $Texi2HTML::THISDOC{$possible_fulltitle . '_texi'} =~ /\S/)
8533        {
8534            $Texi2HTML::THISDOC{'fulltitle_texi'} = $Texi2HTML::THISDOC{$possible_fulltitle . '_texi'};
8535            last;
8536        }
8537    }
8538    $Texi2HTML::THISDOC{'simpletitle_texi'} = '';
8539    foreach my $possible_simpletitle('settitle', 'shorttitlepage')
8540    {
8541        if (defined($Texi2HTML::THISDOC{$possible_simpletitle . '_texi'}) and $Texi2HTML::THISDOC{$possible_simpletitle . '_texi'} =~ /\S/)
8542        {
8543            $Texi2HTML::THISDOC{'simpletitle_texi'} = $Texi2HTML::THISDOC{$possible_simpletitle . '_texi'};
8544            last;
8545        }
8546    }
8547
8548    foreach my $doc_thing (('shorttitlepage', 'settitle', 'author',
8549           'titlefont', 'subtitle', 'title', 'fulltitle', 'simpletitle'))
8550    {
8551        my $thing_texi = $Texi2HTML::THISDOC{$doc_thing . '_texi'};
8552        $Texi2HTML::THISDOC{$doc_thing} = substitute_line($thing_texi, "\@$doc_thing", undef, $Texi2HTML::THISDOC{$doc_thing . '_line_nr'});
8553        $Texi2HTML::THISDOC{$doc_thing . '_no_texi'} =
8554           remove_texi($thing_texi);
8555        $Texi2HTML::THISDOC{$doc_thing . '_simple_format'} =
8556           simple_format(undef, undef, "simple_format \@$doc_thing", $thing_texi);
8557    }
8558
8559
8560    # find the triplet (Top name, Top with texi removed, Top simply formatted)
8561    # the corresponding href is used a lot but these are only used because
8562    # they are used in LINKS_BUTTONS...
8563
8564    my $element_top_Top = [undef,undef,undef];
8565    my $node_top_Top = [undef,undef,undef];
8566    # Preferred Top name is the element_top name if it is not the @node Top
8567    # the @node Top may also be used, but before fulltitle is tried
8568    if (defined($element_top))
8569    {
8570        if ($element_top->{'node'} and $element_top->{'texi'} =~ /^Top$/i)
8571        {
8572           $node_top_Top = [ $element_top->{'text'}, $element_top->{'no_texi'}, $element_top->{'simple_format'} ];
8573        }
8574        else
8575        {
8576           $element_top_Top = [ $element_top->{'text'}, $element_top->{'no_texi'}, $element_top->{'simple_format'} ];
8577        }
8578    }
8579    # FIXME remove fulltitle?
8580    foreach my $possible_top (
8581       [substitute_line($Texi2HTML::Config::TOP_HEADING, '$TOP_HEADING'),
8582        remove_texi($Texi2HTML::Config::TOP_HEADING),
8583        simple_format(undef, undef, 'simple_format $TOP_HEADING', $Texi2HTML::Config::TOP_HEADING)],
8584       $element_top_Top,
8585       [$Texi2HTML::THISDOC{'fulltitle'},
8586        $Texi2HTML::THISDOC{'fulltitle_no_texi'},
8587        $Texi2HTML::THISDOC{'fulltitle_simple_format'}],
8588       $node_top_Top
8589      )
8590    {
8591        if (defined($possible_top->[0]) and $possible_top->[0] =~ /\S/)
8592        {
8593           ($Texi2HTML::NAME{'Top'}, $Texi2HTML::NO_TEXI{'Top'}, $Texi2HTML::SIMPLE_TEXT{'Top'}) = @$possible_top;
8594           last;
8595        }
8596    }
8597
8598    $Texi2HTML::THISDOC{'program'} = $THISPROG;
8599    $Texi2HTML::THISDOC{'program_homepage'} = $T2H_HOMEPAGE;
8600    $Texi2HTML::THISDOC{'program_authors'} = $T2H_AUTHORS;
8601    foreach my $command (('authors', 'subtitles', 'titles'))
8602    {
8603        $Texi2HTML::THISDOC{$command} = [];
8604        my $i;
8605        for ($i = 0; $i < $#{$Texi2HTML::THISDOC{$command .'_texi'}} + 1; $i++)
8606        {
8607            my $texi_line = $Texi2HTML::THISDOC{$command .'_texi'}->[$i];
8608            my $command_line_nr = $Texi2HTML::THISDOC{$command .'_line_nr'}->[$i];
8609            chomp ($texi_line);
8610            $Texi2HTML::THISDOC{$command}->[$i] = substitute_line($texi_line, "\@$command", undef, $command_line_nr);
8611            #print STDERR "$command:$i: $Texi2HTML::THISDOC{$command}->[$i]\n";
8612        }
8613    }
8614
8615    $Texi2HTML::THISDOC{'do_about'} = 1 unless (defined($Texi2HTML::THISDOC{'do_about'}) or $one_section or (not Texi2HTML::Config::get_conf('SPLIT') and not Texi2HTML::Config::get_conf('headers')));
8616
8617    $Texi2HTML::NAME{'First'} = $element_first->{'text'};
8618    $Texi2HTML::NAME{'Last'} = $element_last->{'text'};
8619    $Texi2HTML::NAME{'Index'} = $element_chapter_index->{'text'} if (defined($element_chapter_index));
8620    $Texi2HTML::NAME{'Index'} = $Texi2HTML::Config::INDEX_CHAPTER if ($Texi2HTML::Config::INDEX_CHAPTER ne '');
8621
8622    $Texi2HTML::NO_TEXI{'First'} = $element_first->{'no_texi'};
8623    $Texi2HTML::NO_TEXI{'Last'} = $element_last->{'no_texi'};
8624    $Texi2HTML::NO_TEXI{'Index'} = $element_chapter_index->{'no_texi'} if (defined($element_chapter_index));
8625    $Texi2HTML::SIMPLE_TEXT{'First'} = $element_first->{'simple_format'};
8626    $Texi2HTML::SIMPLE_TEXT{'Last'} = $element_last->{'simple_format'};
8627    $Texi2HTML::SIMPLE_TEXT{'Index'} = $element_chapter_index->{'simple_format'} if (defined($element_chapter_index));
8628
8629    # We do the regions formatting here, even if they never appear.
8630    # so we should be very carefull to take into accout 'outside_document' to
8631    # avoid messing with information that has to be set in the main document.
8632    # FIXME also the error messages will appear even though the corresponding
8633    # texinfo is never used. Since no state is passed to the do_special_region_lines
8634    # 'outside_document' will be true. Also 'multiple_pass' is equal to -1
8635    # for this case.
8636    $global_pass = '3 prepare regions';
8637
8638    my ($region_text, $region_no_texi, $region_simple_format);
8639    ($region_text, $region_no_texi, $region_simple_format) = do_special_region_lines('documentdescription');
8640    &$Texi2HTML::Config::documentdescription($region_lines{'documentdescription'}, $region_text, $region_no_texi, $region_simple_format);
8641
8642    # do copyright notice inserted in comment at the beginning of the files
8643    ($region_text, $region_no_texi, $region_simple_format) = do_special_region_lines('copying');
8644    $copying_comment = &$Texi2HTML::Config::copying_comment($region_lines{'copying'}, $region_text, $region_no_texi, $region_simple_format);
8645
8646    $Texi2HTML::THISDOC{'copying_comment'} = $copying_comment;
8647    # must be after toc_body, but before titlepage
8648    foreach my $command ('contents', 'shortcontents')
8649    {
8650        next if (!defined($content_element{$command}));
8651        my $toc_lines = &$Texi2HTML::Config::inline_contents(undef, $command, $content_element{$command}, \@sections_list);
8652        @{$Texi2HTML::THISDOC{'inline_contents'}->{$command}} = @$toc_lines if (defined($toc_lines));
8653    }
8654
8655    ($region_text, $region_no_texi, $region_simple_format) = do_special_region_lines('titlepage');
8656
8657    &$Texi2HTML::Config::titlepage($region_lines{'titlepage'}, $region_text, $region_no_texi, $region_simple_format);
8658
8659    $global_pass = '3';
8660    &$Texi2HTML::Config::init_out();
8661
8662    # FIXME It is not clear whether it should be here or before
8663    # command_handler_output calls. After, it means that
8664    # command_handler_output may modify the initializations. Before
8665    # it allows to look at the values from the preceding pass.
8666    texinfo_initialization(2);
8667
8668    foreach my $handler(@Texi2HTML::Config::command_handler_output)
8669    {
8670        &$handler;
8671    }
8672
8673    ############################################################################
8674    # print frame and frame toc file
8675    #
8676    if ( $Texi2HTML::Config::FRAMES )
8677    {
8678        my $FH = open_out($docu_frame_file);
8679        print STDERR "# Creating frame in $docu_frame_file ...\n" if $T2H_VERBOSE;
8680        &$Texi2HTML::Config::print_frame($FH, $docu_toc_frame_file, $docu_top_file);
8681        close_out($FH, $docu_frame_file);
8682
8683        $FH = open_out($docu_toc_frame_file);
8684        print STDERR "# Creating toc frame in $docu_frame_file ...\n" if $T2H_VERBOSE;
8685        &$Texi2HTML::Config::print_toc_frame($FH, $Texi2HTML::OVERVIEW);
8686        close_out($FH, $docu_toc_frame_file);
8687    }
8688
8689
8690
8691    ############################################################################
8692    # Start processing the document
8693    #
8694
8695    #my $FH;
8696    my $line_nr;
8697    my $current_file;
8698    my $first_section = 0; # 1 if it is the first section of a page
8699    my $previous_is_top = 0; # 1 if it is the element following the top element
8700
8701    my $cline;
8702    # this is true for the state that goes through the document
8703    $state{'inside_document'} = 1;
8704    while (@$doc_lines)
8705    {
8706        $cline = shift @$doc_lines;
8707        my $chomped_line = $cline;
8708        if (!chomp($chomped_line) and @$doc_lines)
8709        { # if the line has no end of line it is concatenated with the next
8710          # this shouldn't happen anymore. And will certainly mess up
8711          # line counting. Let it be a bug.
8712          msg_debug ("no end of line line passed in doc_line",$line_nr);
8713             $doc_lines->[0] = $cline . $doc_lines->[0];
8714             next;
8715        }
8716        $line_nr = shift (@$doc_numbers);
8717        $Texi2HTML::THISDOC{'line_nr'} = $line_nr;
8718        print STDERR "BUG: line_nr not defined in pass_text. cline: $cline" if (!defined($cline));
8719	#dump_stack(\$text, \@stack, \%state);
8720
8721        # make sure the current state from here is $Texi2HTML::THIS_ELEMENT
8722        # in case it was set by the user.
8723        $state{'element'} = $Texi2HTML::THIS_ELEMENT if (defined($Texi2HTML::THIS_ELEMENT));
8724	#print STDERR "PASS_TEXT($line_nr->{'line_nr'})$cline";
8725        if (!$state{'raw'} and !$state{'verb'})
8726        {
8727            my $tag = '';
8728            $tag = $1 if ($cline =~ /^\@(\w+)/);
8729            if ($tag eq 'setfilename' and $Texi2HTML::Config::IGNORE_BEFORE_SETFILENAME)
8730            {
8731                if (defined($Texi2HTML::THIS_ELEMENT))
8732                {
8733                    line_warn (sprintf(__("\@%s after the first element"), $tag), $line_nr);
8734                }
8735                else
8736                {
8737                    @{$Texi2HTML::THIS_SECTION} = ();
8738                }
8739            }
8740
8741            if (($tag eq 'node') or (defined($sec2level{$tag}) and ($tag !~ /heading/)))
8742            {
8743                # in pass text node and section shouldn't appear in formats
8744			#print STDERR "close_stack before \@$tag\n";
8745			#print STDERR "text!$text%" if (! @stack);
8746                close_stack(\$text, \@stack, \%state, $line_nr);
8747                msg_debug ("text undef", $line_nr) if (!defined($text));
8748                push @{$Texi2HTML::THIS_SECTION}, $text if ($text ne '');
8749                $text = '';
8750
8751                $state{'sec_num'}++ if ($sec2level{$tag} and ($tag ne 'top'));
8752                my $new_element;
8753                my $current_element;
8754
8755                # handle node and structuring elements
8756                $current_element = shift (@all_elements);
8757                ########################## begin debug section
8758                if (!defined($current_element))
8759                {
8760                    msg_debug ("No element left for $cline", $line_nr);
8761                }
8762                if ($current_element->{'node'})
8763                {
8764                    print STDERR 'NODE ' . "$current_element->{'texi'}($current_element->{'file'})" if ($T2H_DEBUG & $DEBUG_ELEMENTS);
8765                    print STDERR "($current_element->{'section_ref'}->{'texi'})" if ($current_element->{'section_ref'} and ($T2H_DEBUG & $DEBUG_ELEMENTS));
8766                }
8767                else
8768                {
8769                    print STDERR 'SECTION ' . $current_element->{'texi'} if ($T2H_DEBUG & $DEBUG_ELEMENTS);
8770                }
8771                print STDERR ": $cline" if ($T2H_DEBUG & $DEBUG_ELEMENTS);
8772                ########################## end debug section
8773
8774                # The element begins a new section if there is no previous
8775                # or the reference element is not the same
8776                if (defined($current_element->{'element_ref'}) and (!$Texi2HTML::THIS_ELEMENT or ($current_element->{'element_ref'} ne $Texi2HTML::THIS_ELEMENT)))
8777                {
8778                    $new_element = $current_element->{'element_ref'};
8779
8780                    ########################### debug
8781                    my $old = 'NO_OLD';
8782                    $old = $Texi2HTML::THIS_ELEMENT->{'texi'} if (defined($Texi2HTML::THIS_ELEMENT));
8783                    print STDERR "NEW: $new_element->{'texi'}, OLD: $old\n" if ($T2H_DEBUG & $DEBUG_ELEMENTS);
8784                    ########################### end debug
8785                    # print the element that just finished
8786                    if ($Texi2HTML::THIS_ELEMENT)
8787                    {
8788                        finish_element($Texi2HTML::THISDOC{'FH'}, $Texi2HTML::THIS_ELEMENT, $new_element, $first_section);
8789                        $first_section = 0;
8790                        $previous_is_top = 0 if (!$Texi2HTML::THIS_ELEMENT->{'top'});
8791                        @{$Texi2HTML::THIS_SECTION} = ();
8792                    }
8793                    else
8794                    {
8795                        print STDERR "# Writing elements:" if ($T2H_VERBOSE);
8796                        if ($Texi2HTML::Config::IGNORE_PREAMBLE_TEXT)
8797                        {
8798                             @{$Texi2HTML::THIS_SECTION} = ();
8799                        }
8800                        # remove empty for the first document lines
8801                        shift @{$Texi2HTML::THIS_SECTION} while (@{$Texi2HTML::THIS_SECTION} and ($Texi2HTML::THIS_SECTION->[0] =~ /^\s*$/));
8802                        my $title = &$Texi2HTML::Config::print_title();
8803                        unshift @{$Texi2HTML::THIS_SECTION}, $title if (defined($title) and $title ne '');
8804                    }
8805                    # begin new element
8806                    $Texi2HTML::THIS_ELEMENT = $new_element;
8807                    $state{'element'} = $Texi2HTML::THIS_ELEMENT;
8808
8809                    do_element_directions($Texi2HTML::THIS_ELEMENT);
8810                    unref_file ($Texi2HTML::THIS_ELEMENT->{'file'});
8811                    #if (!defined($previous_file) or ($Texi2HTML::THIS_ELEMENT->{'file'} ne $previous_file))
8812                    if (!defined($current_file) or ($Texi2HTML::THIS_ELEMENT->{'file'} ne $current_file))
8813                    {
8814                        $current_file = $Texi2HTML::THIS_ELEMENT->{'file'};
8815                        print STDERR "\n" if ($T2H_VERBOSE and !$T2H_DEBUG);
8816                        print STDERR "# Writing to $docu_rdir$current_file " if $T2H_VERBOSE;
8817                        my $do_page_head = open_out_file($current_file);
8818                        if ($Texi2HTML::THIS_ELEMENT->{'top'})
8819                        {
8820                             &$Texi2HTML::Config::print_Top_header($Texi2HTML::THISDOC{'FH'}, $do_page_head);
8821                             $previous_is_top = 1;
8822                        }
8823                        else
8824                        {
8825                             &$Texi2HTML::Config::print_page_head($Texi2HTML::THISDOC{'FH'}) if ($do_page_head);
8826                             &$Texi2HTML::Config::print_chapter_header($Texi2HTML::THISDOC{'FH'}, $Texi2HTML::THIS_ELEMENT) if Texi2HTML::Config::get_conf('SPLIT') eq 'chapter';
8827                             &$Texi2HTML::Config::print_section_header($Texi2HTML::THISDOC{'FH'}, $Texi2HTML::THIS_ELEMENT) if Texi2HTML::Config::get_conf('SPLIT') eq 'section';
8828                        }
8829                        $first_section = 1;
8830                    }
8831                    print STDERR "." if ($T2H_VERBOSE);
8832                    print STDERR "\n" if ($T2H_DEBUG);
8833                }
8834
8835                my $cmd_line = $cline;
8836                $cmd_line =~ s/\@$tag\s*//;
8837
8838                ######################## begin debug
8839                msg_debug ("Element $current_element current_element->{'tag_level'} not defined", $line_nr)
8840                   if (!defined($current_element->{'tag_level'}));
8841                msg_debug ("Element $current_element $tag ne ".var_to_str($current_element->{'tag'}), $line_nr)
8842                   if ($tag ne 'node' and (!defined($current_element->{'tag'}) or $tag ne $current_element->{'tag'}));
8843                msg_debug ("Element $current_element ".var_to_str($current_element->{'tag'})." is not a node, but tag is a node", $line_nr)
8844                  if ($tag eq 'node' and !$current_element->{'node'});
8845                ######################## end debug
8846
8847                my $heading_formatted = &$Texi2HTML::Config::element_heading($current_element, $tag, $cmd_line, substitute_line($cmd_line, "\@$tag"), undef, $one_section, $current_element->{'this'}, $first_section, $current_element->{'top'}, $previous_is_top, $cline, $current_element->{'id'}, $new_element);
8848                push @{$Texi2HTML::THIS_SECTION}, $heading_formatted if (defined($heading_formatted) and ($heading_formatted ne ''));
8849                next;
8850            }
8851        }
8852
8853        set_line_nr_in_stack(\%state, \@stack, $line_nr);
8854        scan_line($cline, \$text, \@stack, \%state, $line_nr);
8855
8856	#print STDERR "after scan_line: $cline";
8857	#dump_stack(\$text, \@stack, \%state);
8858        next if (@stack);
8859        if ($text ne '')
8860        {
8861            push @{$Texi2HTML::THIS_SECTION}, $text;
8862            $text = '';
8863        }
8864    }
8865    # close stack at the end of pass text
8866    close_stack(\$text, \@stack, \%state, $line_nr);
8867    if (defined($text))
8868    {
8869        push @{$Texi2HTML::THIS_SECTION}, $text;
8870    }
8871    print STDERR "\n" if ($T2H_VERBOSE);
8872
8873    # if no sections, then simply print document as is
8874    if ($one_section)
8875    {
8876        # may happen if there are 0 sections
8877        if (! defined($Texi2HTML::THISDOC{'FH'}))
8878        {
8879          open_out_file($docu_doc);
8880          &$Texi2HTML::Config::print_page_head($Texi2HTML::THISDOC{'FH'});
8881          shift @{$Texi2HTML::THIS_SECTION} while (@{$Texi2HTML::THIS_SECTION} and ($Texi2HTML::THIS_SECTION->[0] =~ /^\s*$/));
8882          my $title = &$Texi2HTML::Config::print_title();
8883          unshift @{$Texi2HTML::THIS_SECTION}, $title if (defined($title) and $title ne '');
8884        }
8885        if (@foot_lines)
8886        {
8887            &$Texi2HTML::Config::foot_section (\@foot_lines);
8888            push @{$Texi2HTML::THIS_SECTION}, @foot_lines;
8889        }
8890        print STDERR "# Write the section $Texi2HTML::THIS_ELEMENT->{'texi'}\n" if ($T2H_VERBOSE);
8891        &$Texi2HTML::Config::one_section($Texi2HTML::THISDOC{'FH'}, $Texi2HTML::THIS_ELEMENT);
8892        close_out($Texi2HTML::THISDOC{'FH'}, $docu_doc_file);
8893        # no misc element is done
8894        return;
8895    }
8896
8897    finish_element ($Texi2HTML::THISDOC{'FH'}, $Texi2HTML::THIS_ELEMENT, undef, $first_section);
8898
8899    ############################################################################
8900    # Print ToC, Overview, Footnotes
8901    #
8902    foreach my $direction (@element_directions)
8903    {
8904        $Texi2HTML::HREF{$direction} = undef;
8905        delete $Texi2HTML::HREF{$direction};
8906        # it is better to undef in case the references to these hash entries
8907        # are used, as if deleted, the
8908        # references are still refering to the old, undeleted element
8909        # (we could do both)
8910        $Texi2HTML::NAME{$direction} = undef;
8911        $Texi2HTML::NO_TEXI{$direction} = undef;
8912        $Texi2HTML::SIMPLE_TEXT{$direction} = undef;
8913        $Texi2HTML::NODE{$direction} = undef;
8914
8915        $Texi2HTML::THIS_ELEMENT = undef;
8916    }
8917    my $about_body;
8918    $about_body = &$Texi2HTML::Config::about_body() if (defined($Texi2HTML::Config::about_body));
8919    # @foot_lines is emptied in finish_element if footnotestyle separate
8920    my %misc_page_infos = (
8921       'Footnotes' => { 'file' => $docu_foot_file,
8922          'relative_file' => $docu_foot,
8923          'process' => $Texi2HTML::Config::print_Footnotes,
8924          'section' => \@foot_lines },
8925       'Contents' => { 'file' => $docu_toc_file,
8926           'relative_file' => $docu_toc,
8927           'process' => $Texi2HTML::Config::print_Toc,
8928           'section' => $Texi2HTML::TOC_LINES },
8929       'Overview' => { 'file' => $docu_stoc_file,
8930           'relative_file' => $docu_stoc,
8931           'process' => $Texi2HTML::Config::print_Overview,
8932           'section' => $Texi2HTML::OVERVIEW },
8933       'About' => { 'file' => $docu_about_file,
8934           'relative_file' => $docu_about,
8935            'process' => $Texi2HTML::Config::print_About,
8936            'section' => [$about_body] }
8937    );
8938    $misc_page_infos{'Footnotes'}->{'do'} = 1 if (@foot_lines);
8939    $misc_page_infos{'Contents'}->{'do'} = 1 if
8940       (@{$Texi2HTML::TOC_LINES} and !$Texi2HTML::Config::INLINE_CONTENTS and (!Texi2HTML::Config::get_conf('setcontentsaftertitlepage') or !$Texi2HTML::Config::USE_TITLEPAGE_FOR_TITLE));
8941    $misc_page_infos{'Overview'}->{'do'} = 1 if
8942       (@{$Texi2HTML::OVERVIEW} and !$Texi2HTML::Config::INLINE_CONTENTS and (!Texi2HTML::Config::get_conf('setshortcontentsaftertitlepage') or !$Texi2HTML::Config::USE_TITLEPAGE_FOR_TITLE));
8943    $misc_page_infos{'About'}->{'do'} = 1 if ($about_body and $Texi2HTML::THISDOC{'do_about'});
8944
8945    foreach my $misc_page('Footnotes', 'Contents', 'Overview', 'About')
8946    {
8947        next unless ($misc_page_infos{$misc_page}->{'do'});
8948        my $file = $misc_page_infos{$misc_page}->{'file'};
8949        my $relative_file = $misc_page_infos{$misc_page}->{'relative_file'};
8950        print STDERR "# writing $misc_page in $file\n" if $T2H_VERBOSE;
8951        my $saved_FH;
8952        my $open_new = 0;
8953        if ($relative_file ne $docu_doc)
8954        {
8955            $saved_FH = $Texi2HTML::THISDOC{'FH'};
8956            # Use open_out_file not to overwrite a file that the user would have
8957            # created
8958            open_out_file ($relative_file);
8959            print STDERR "# Opening $file for $misc_page\n" if $T2H_VERBOSE;
8960            $open_new = 1;
8961        }
8962        else
8963        {
8964            print STDERR "# writing $misc_page in current file\n" if $T2H_VERBOSE;
8965        }
8966        foreach my $href_page (keys(%misc_page_infos))
8967        {
8968            $Texi2HTML::HREF{$href_page} = file_target_href(
8969               $misc_page_infos{$href_page}->{'relative_file'}, $relative_file,
8970               $Texi2HTML::Config::misc_pages_targets{$href_page})
8971                 if ($misc_page_infos{$href_page}->{'do'});
8972        }
8973        #print STDERR "Doing hrefs for $misc_page First ";
8974        $Texi2HTML::HREF{'First'} = href($element_first, $relative_file);
8975        #print STDERR "Last ";
8976        $Texi2HTML::HREF{'Last'} = href($element_last, $relative_file);
8977        #print STDERR "Index ";
8978        $Texi2HTML::HREF{'Index'} = href($element_chapter_index, $relative_file) if (defined($element_chapter_index));
8979        #print STDERR "Top ";
8980        $Texi2HTML::HREF{'Top'} = href($element_top, $relative_file);
8981        if ($Texi2HTML::Config::INLINE_CONTENTS)
8982        {
8983            $Texi2HTML::HREF{'Contents'} = href($content_element{'contents'}, $relative_file);
8984            $Texi2HTML::HREF{'Overview'} = href($content_element{'shortcontents'}, $relative_file);
8985        }
8986        $Texi2HTML::HREF{$misc_page} = '#' . $Texi2HTML::Config::misc_pages_targets{$misc_page};
8987        $Texi2HTML::HREF{'This'} = $Texi2HTML::HREF{$misc_page};
8988        $Texi2HTML::NAME{'This'} = $Texi2HTML::NAME{$misc_page};
8989        $Texi2HTML::NO_TEXI{'This'} = $Texi2HTML::NO_TEXI{$misc_page};
8990        $Texi2HTML::SIMPLE_TEXT{'This'} = $Texi2HTML::SIMPLE_TEXT{$misc_page};
8991        $Texi2HTML::THIS_SECTION = $misc_page_infos{$misc_page}->{'section'}
8992            if defined($misc_page_infos{$misc_page}->{'section'});
8993        &{$misc_page_infos{$misc_page}->{'process'}}($Texi2HTML::THISDOC{'FH'}, $open_new, $misc_page);
8994
8995        if ($open_new)
8996        {
8997            close_out($Texi2HTML::THISDOC{'FH'}, $file);
8998            $Texi2HTML::THISDOC{'FH'} = $saved_FH;
8999        }
9000    }
9001
9002    unless (Texi2HTML::Config::get_conf('SPLIT'))
9003    {
9004        &$Texi2HTML::Config::print_page_foot($Texi2HTML::THISDOC{'FH'});
9005        # this leaves the possibility for external code to close the file
9006        # without erroring out
9007        close_out ($Texi2HTML::THISDOC{'FH'}, $docu_doc_file) if (fileno($Texi2HTML::THISDOC{'FH'}));
9008    }
9009    pop_state();
9010}
9011
9012# print section, close file if needed.
9013sub finish_element($$$$)
9014{
9015    my $FH = shift;
9016    my $element = shift;
9017    my $new_element = shift;
9018    my $first_section = shift;
9019#print STDERR "FINISH_ELEMENT($FH)($element->{'texi'})[$element->{'file'}] counter $files{$element->{'file'}}->{'counter'}\n";
9020
9021    # handle foot notes
9022    if (Texi2HTML::Config::get_conf('SPLIT') and scalar(@foot_lines)
9023        and (Texi2HTML::Config::get_conf('footnotestyle') eq 'end')
9024        and  (! $new_element or
9025        ($element and ($new_element->{'file'} ne $element->{'file'})))
9026       )
9027    {
9028        if ($files{$element->{'file'}}->{'counter'})
9029        {# there are other elements in that page we are not on its foot
9030            $files{$element->{'file'}}->{'relative_foot_num'}
9031               = $global_relative_foot_num;
9032            push @{$files{$element->{'file'}}->{'foot_lines'}},
9033                @foot_lines;
9034        }
9035        else
9036        {# we output the footnotes as we are at the file end
9037             unshift @foot_lines, @{$files{$element->{'file'}}->{'foot_lines'}};
9038             &$Texi2HTML::Config::foot_section (\@foot_lines);
9039             push @{$Texi2HTML::THIS_SECTION}, @foot_lines;
9040        }
9041        if ($new_element)
9042        {
9043            $global_relative_foot_num =
9044               $files{$new_element->{'file'}}->{'relative_foot_num'};
9045        }
9046        @foot_lines = ();
9047    }
9048
9049    if ($element->{'top'})
9050    {
9051        ############### debug
9052        #print STDERR "TOP $element->{'texi'}, @{$Texi2HTML::THIS_SECTION}\n";
9053        die "element->{'top'} $element ne element_top $element_top" if ($element ne $element_top);
9054        print STDERR "# Doing element top\n"
9055           if ($T2H_DEBUG & $DEBUG_ELEMENTS);
9056        print STDERR "[Top]" if ($T2H_VERBOSE);
9057        ############### end debug
9058
9059        &$Texi2HTML::Config::print_Top($FH, $element->{'titlefont'}, $element);
9060        my $end_page = 0;
9061        if (Texi2HTML::Config::get_conf('SPLIT'))
9062        {
9063            if ($files{$element->{'file'}}->{'counter'} == 0)
9064            {
9065                $end_page = 1;
9066            }
9067        }
9068        &$Texi2HTML::Config::print_Top_footer($FH, $end_page, $element);
9069        close_out($FH, $docu_top_file) if ($end_page);
9070    }
9071    else
9072    {
9073        print STDERR "# do element $element->{'texi'}\n"
9074           if ($T2H_DEBUG & $DEBUG_ELEMENTS);
9075        &$Texi2HTML::Config::print_section($FH, $first_section, 0, $element);
9076        ################# debug
9077        my $new_elem_file = 'NO ELEM => no file';
9078        $new_elem_file = $new_element->{'file'} if (defined($new_element));
9079        print STDERR "# FILES new: $new_elem_file old(".fileno($FH)."): $element->{'file'}\n"
9080           if ($T2H_DEBUG & $DEBUG_ELEMENTS);
9081        ################# end debug
9082        if (defined($new_element) and ($new_element->{'file'} ne $element->{'file'}))
9083        {
9084            print STDERR "# End of section with change in file(".fileno($FH).") $element->{'file'} -> $new_element->{'file'}\n"
9085                 if ($T2H_DEBUG & $DEBUG_ELEMENTS);
9086             if (!$files{$element->{'file'}}->{'counter'})
9087             {
9088                 &$Texi2HTML::Config::print_chapter_footer($FH, $element) if (Texi2HTML::Config::get_conf('SPLIT') eq 'chapter');
9089                 &$Texi2HTML::Config::print_section_footer($FH, $element) if (Texi2HTML::Config::get_conf('SPLIT') eq 'section');
9090                 print STDERR "# Close file(".fileno($FH).") after $element->{'texi'}\n"
9091                     if ($T2H_DEBUG & $DEBUG_ELEMENTS);
9092                 &$Texi2HTML::Config::print_page_foot($FH);
9093                 close_out($FH, "$docu_rdir$element->{'file'}");
9094             }
9095             else
9096             {
9097                 print STDERR "# Counter $files{$element->{'file'}}->{'counter'} ne 0, file(".fileno($FH).") $element->{'file'}\n"
9098                     if ($T2H_DEBUG & $DEBUG_ELEMENTS);
9099             }
9100        }
9101        elsif (!defined($new_element))
9102        {
9103            print STDERR "# End of last section, file(".fileno($FH).") $element->{'file'}, counter $files{$element->{'file'}}->{'counter'}\n"
9104                 if ($T2H_DEBUG & $DEBUG_ELEMENTS);
9105            if (Texi2HTML::Config::get_conf('SPLIT'))
9106            { # end of last splitted section
9107                &$Texi2HTML::Config::print_chapter_footer($FH, $element) if (Texi2HTML::Config::get_conf('SPLIT') eq 'chapter');
9108                &$Texi2HTML::Config::print_section_footer($FH, $element) if (Texi2HTML::Config::get_conf('SPLIT') eq 'section');
9109                &$Texi2HTML::Config::print_page_foot($FH);
9110                close_out($FH, "$docu_rdir$element->{'file'}");
9111            }
9112            else
9113            { # end of last unsplit section
9114                &$Texi2HTML::Config::end_section($FH, 1, $element);
9115            }
9116        }
9117        elsif ($new_element->{'top'})
9118        {
9119            print STDERR "# Section followed by Top, file(".fileno($FH).") counter $files{$element->{'file'}}->{'counter'}\n"
9120                     if ($T2H_DEBUG & $DEBUG_ELEMENTS);
9121            &$Texi2HTML::Config::end_section($FH, 1, $element);
9122        }
9123        else
9124        { # end of section followed by another one
9125            print STDERR "# Section followed by another one, file(".fileno($FH).") counter $files{$element->{'file'}}->{'counter'}\n"
9126                     if ($T2H_DEBUG & $DEBUG_ELEMENTS);
9127            &$Texi2HTML::Config::end_section($FH, 0, $element);
9128        }
9129    }
9130}
9131
9132# write to files with name the node name for cross manual references.
9133sub do_node_files()
9134{
9135    foreach my $key (keys(%nodes))
9136    {
9137        my $node = $nodes{$key};
9138        next unless ($node->{'node_file'});
9139        my $redirection_file = $docu_doc;
9140        $redirection_file = $node->{'file'} if (Texi2HTML::Config::get_conf('SPLIT'));
9141        if (!$redirection_file)
9142        {
9143             print STDERR "Bug: file for redirection for `$node->{'texi'}' don't exist\n" unless (Texi2HTML::Config::get_conf('novalidate') or !$node->{'seen'});
9144             next;
9145        }
9146        next if ($redirection_file eq $node->{'node_file'});
9147        my $file = "${docu_rdir}$node->{'node_file'}";
9148        $Texi2HTML::NODE{'This'} = $node->{'text'};
9149        $Texi2HTML::NO_TEXI{'This'} = $node->{'no_texi'};
9150        $Texi2HTML::SIMPLE_TEXT{'This'} = $node->{'simple_format'};
9151        $Texi2HTML::NAME{'This'} = $node->{'text'};
9152        my $href_file = $node->{'file'};
9153        if (!defined($href_file))
9154        {
9155           if (Texi2HTML::Config::get_conf('novalidate'))
9156           {
9157               $href_file = '';
9158           }
9159           else
9160           {
9161               msg_debug ("Undefined file for `$node->{'texi'}' in do_node_files");
9162           }
9163        }
9164        $Texi2HTML::HREF{'This'} = "$href_file#$node->{'id'}";
9165        my $redirect = &$Texi2HTML::Config::print_redirection_page ();
9166        if (defined($redirect))
9167        {
9168           my $NODEFILE = open_out ($file);
9169           print $NODEFILE "$redirect";
9170           close $NODEFILE || document_error ("Can't close $file: $!", 1);
9171        }
9172    }
9173}
9174
9175#+++############################################################################
9176#                                                                              #
9177# Low level functions                                                          #
9178#                                                                              #
9179#---############################################################################
9180
9181sub locate_include_file($)
9182{
9183    my $file = shift;
9184
9185    # APA: Don't implicitely search ., to conform with the docs!
9186
9187    # if file begins with /, ./ or ../ don't search in -I (Karl)
9188    if ($file =~ m,^(/|\./|\.\./),)
9189    {
9190        return "$file" if (-e "$file" && -r "$file");
9191        return undef;
9192    }
9193    foreach my $dir (@Texi2HTML::Config::INCLUDE_DIRS)
9194    {
9195        return "$dir/$file" if (-e "$dir/$file" && -r "$dir/$file");
9196    }
9197    return undef;
9198}
9199
9200sub open_file($$$)
9201{
9202    my $name = shift;
9203#    my $line_number = shift;
9204    my $macro = shift;
9205    my $files_stack = shift;
9206
9207    my $line_number;
9208    my $input_spool;
9209
9210    local *FH;
9211    if (open(*FH, "<$name"))
9212    {
9213        my $in_encoding = Texi2HTML::Config::get_conf('IN_ENCODING');
9214        if (defined($in_encoding) and $Texi2HTML::Config::USE_UNICODE)
9215        {
9216            binmode(*FH, ":encoding($in_encoding)");
9217        }
9218        my $file = { 'fh' => *FH,
9219           'input_spool' => { 'spool' => [],
9220                              'macro' => '' },
9221           'name' => $name,
9222           'line_nr' => 0 };
9223        unshift(@$files_stack, $file);
9224        $input_spool = $file->{'input_spool'};
9225        $line_number->{'file_name'} = $name;
9226        $line_number->{'line_nr'} = 1;
9227        $line_number->{'macro'} = $macro;
9228    }
9229    else
9230    {
9231        document_error ("Can't read file $name: $!", 1);
9232    }
9233    return ($line_number, $input_spool);
9234}
9235
9236my %filehandles = ();
9237
9238sub open_out($;$)
9239{
9240    my $file = shift;
9241    my $append = shift;
9242    local *FILE;
9243#print STDERR "open_out $file $Texi2HTML::THISDOC{'OUT_ENCODING'}\n";
9244    if ($file eq '-')
9245    {
9246        binmode(STDOUT, ":encoding($Texi2HTML::THISDOC{'OUT_ENCODING'})") if (defined($Texi2HTML::THISDOC{'OUT_ENCODING'}) and $Texi2HTML::Config::USE_UNICODE);
9247        return \*STDOUT;
9248    }
9249
9250    my $mode = '>';
9251    $mode = '>>' if ($append);
9252    unless (open(FILE, $mode, $file))
9253    {
9254        document_error ("could not open $file for writing: $!", 1);
9255    }
9256    push @opened_files, $file;
9257    if (defined($Texi2HTML::THISDOC{'OUT_ENCODING'}) and $Texi2HTML::Config::USE_UNICODE)
9258    {
9259        if ($Texi2HTML::THISDOC{'OUT_ENCODING'} eq 'utf8' or $Texi2HTML::THISDOC{'OUT_ENCODING'} eq 'utf-8-strict')
9260        {
9261            binmode(FILE, ':utf8');
9262        }
9263	else
9264        {
9265            binmode(FILE, ':bytes');
9266            #binmode(FILE, ":encoding($Texi2HTML::THISDOC{'OUT_ENCODING'})");
9267        }
9268        # FIXME is it useful when in utf8?
9269        binmode(FILE, ":encoding($Texi2HTML::THISDOC{'OUT_ENCODING'})");
9270    }
9271    $file =~ s/^(\.[\/]+)*//;
9272    $filehandles{fileno(*FILE)} = $file;
9273    return *FILE;
9274}
9275
9276sub close_out($$)
9277{
9278    my $FH = shift;
9279    my $file = shift;
9280    return if (defined($file) and $file eq '-');
9281    $file =~ s/^(\.[\/]+)*//;
9282    my $fileno = fileno($FH);
9283#print STDERR "close_out $file $fileno\n";
9284    if (!defined($fileno))
9285    {
9286       msg_debug("fileno not defined for $file")
9287    }
9288    elsif (defined($filehandles{$fileno}) and $filehandles{$fileno} ne $file)
9289    {
9290       #msg_debug("filehandles{$fileno} $filehandles{$fileno} and file $file different")
9291    }
9292    close ($FH) || document_error ("Error when closing $file: $!");
9293}
9294
9295sub next_line($$)
9296{
9297    my $line_number = shift;
9298    my $files_stack = shift;
9299    my $input_spool;
9300    while (@$files_stack)
9301    {
9302        my $file = $files_stack->[0];
9303        $line_number->{'file_name'} = $file->{'name'};
9304        $input_spool = $file->{'input_spool'};
9305        if (@{$input_spool->{'spool'}})
9306        {
9307             $line_number->{'macro'} = $file->{'input_spool'}->{'macro'};
9308             $line_number->{'line_nr'} = $file->{'line_nr'};
9309             my $line = shift(@{$input_spool->{'spool'}});
9310             print STDERR "# unspooling $line" if ($T2H_DEBUG & $DEBUG_MACROS);
9311             return($line, $input_spool);
9312        }
9313        else
9314        {
9315             $file->{'input_spool'}->{'macro'} = '';
9316             $line_number->{'macro'} = '';
9317        }
9318        my $fh = $file->{'fh'};
9319        no strict "refs";
9320        my $line = <$fh>;
9321        use strict "refs";
9322        my $chomped_line = $line;
9323        $file->{'line_nr'}++ if (defined($line) and chomp($chomped_line));
9324        $line_number->{'line_nr'} = $file->{'line_nr'};
9325        # do that right now, before any other treatement
9326        $line =~ s/\x{7F}.*\s*// if (defined($line));
9327        return($line, $input_spool) if (defined($line));
9328        no strict "refs";
9329        close($fh);
9330        use strict "refs";
9331        shift(@$files_stack);
9332    }
9333    return(undef, $input_spool);
9334}
9335
9336sub check_die(;$)
9337{
9338   my $always_die = shift;
9339
9340   if (!$Texi2HTML::Config::FORCE)
9341   {
9342       if (@opened_files == 1)
9343       {
9344           warn sprintf(__("%s: Removing output file `%s' due to errors; use --force to preserve.\n"), $real_command_name, $opened_files[0]);
9345       }
9346       elsif (@opened_files > 1)
9347       {
9348           warn sprintf(__("%s: Removing output files due to errors; use --force to preserve.\n"), $real_command_name);
9349       }
9350       foreach my $file (@opened_files)
9351       {
9352          unlink ($file);
9353       }
9354       foreach my $dir (@created_directories)
9355       {
9356          rmdir ($dir);
9357       }
9358   }
9359   if ($always_die or !$Texi2HTML::Config::FORCE)
9360   {
9361       exit (1);
9362   }
9363}
9364
9365sub file_line_warn($$;$)
9366{
9367   return if ($Texi2HTML::Config::NO_WARN);
9368   my $text = shift;
9369   chomp($text);
9370   my $file = shift;
9371   my $line_nr = shift;
9372
9373   if (!defined($line_nr))
9374   {
9375      warn "$file: $text\n";
9376   }
9377   else
9378   {
9379      warn "$file:$line_nr: $text\n";
9380   }
9381}
9382
9383sub document_warn ($)
9384{
9385   return if ($Texi2HTML::Config::NO_WARN);
9386   my $text = shift;
9387   chomp ($text);
9388   warn sprintf(__p("warning: warning_message", "warning: %s\n"), $text);
9389}
9390
9391my $error_nrs = 0;
9392sub check_errors()
9393{
9394   $error_nrs ++;
9395    die __("Too many errors!  Gave up.\n") if ($error_nrs >= $Texi2HTML::Config::ERROR_LIMIT);
9396}
9397
9398sub msg_debug($;$)
9399{
9400   my $text = shift;
9401   chomp ($text);
9402   my $line_number = shift;
9403   if (defined($line_number))
9404   {
9405       warn "!! $text " . format_line_number($line_number) . "\n";
9406   }
9407   else
9408   {
9409       warn "!! $text\n";
9410   }
9411}
9412
9413sub cmdline_warn ($)
9414{
9415   my $text = shift;
9416   #chomp ($text);
9417   warn sprintf(__p("command_name: warning_message", "%s: %s"), $real_command_name, $text);
9418}
9419
9420# seems not to be used
9421sub cmdline_error ($)
9422{
9423   my $text = shift;
9424   #chomp ($text);
9425   warn sprintf(__p("command_name: error_message", "%s: %s"), $real_command_name, $text);
9426}
9427
9428sub document_error($;$)
9429{
9430   my $text = shift;
9431   chomp ($text);
9432   my $die = shift;
9433   warn ("$text\n");
9434   check_die ($die);
9435   check_errors();
9436}
9437
9438# echo an error
9439sub msg_error($;$)
9440{
9441    my $text = shift;
9442    my $line_number = shift;
9443    if (defined($line_number))
9444    {
9445         line_error ($text, $line_number);
9446    }
9447    else
9448    {
9449        document_error ($text);
9450    }
9451}
9452
9453# echo a warning
9454sub msg_warn($;$$)
9455{
9456    my $text = shift;
9457    my $line_number = shift;
9458    my $context_string = shift;
9459
9460    if (defined($line_number))
9461    {
9462         line_warn ($text, $line_number);
9463    }
9464    elsif (defined($context_string))
9465    {
9466        document_warn ("$text (in $context_string)");
9467    }
9468    else
9469    {
9470        document_warn ($text);
9471    }
9472}
9473
9474# echo a warning associated with a line in the document
9475sub line_warn($$)
9476{
9477    return if ($Texi2HTML::Config::NO_WARN);
9478    my $text = shift;
9479    chomp ($text);
9480    my $line_number = shift;
9481    return if (!defined($line_number));
9482    my $file = $line_number->{'file_name'};
9483    # otherwise out of source build fail since the file names are different
9484    $file =~ s/^.*\/// if ($Texi2HTML::Config::TEST);
9485    if ($line_number->{'macro'} ne '')
9486    {
9487        warn sprintf(__("%s:%d: warning: %s (via \@%s)\n"), $file, $line_number->{'line_nr'}, $text, $line_number->{'macro'});
9488    }
9489    else
9490    {
9491        warn sprintf(__("%s:%d: warning: %s\n"), $file, $line_number->{'line_nr'}, $text);
9492    }
9493}
9494
9495sub line_error($$)
9496{
9497    my $text = shift;
9498    chomp ($text);
9499    my $line_number = shift;
9500    if (defined($line_number))
9501    {
9502       my $file = $line_number->{'file_name'};
9503       $file =~ s/^.*\/// if ($Texi2HTML::Config::TEST);
9504       my $macro_text = '';
9505       $macro_text = " (via \@$line_number->{'macro'})" if ($line_number->{'macro'} ne '');
9506       warn "$file:$line_number->{'line_nr'}: $text$macro_text\n";
9507       check_die();
9508    }
9509    check_errors();
9510}
9511
9512sub format_line_number(;$)
9513{
9514    my $line_number = shift;
9515    $line_number = $Texi2HTML::THISDOC{'line_nr'} if (!defined($line_number));
9516    my $macro_text = '';
9517    #$line_number = undef;
9518    return '' unless (defined($line_number));
9519    my $print_filename = ($line_number->{'file_name'} ne $Texi2HTML::THISDOC{'input_file_name'});
9520    if ($line_number->{'macro'} ne '')
9521    {
9522        if ($print_filename)
9523        {
9524            return sprintf(__("(in %s l. %d via \@%s)"), $line_number->{'file_name'}, $line_number->{'line_nr'}, $line_number->{'macro'});
9525        }
9526        else
9527        {
9528            return sprintf(__("(l. %d via \@%s)"), $line_number->{'line_nr'}, $line_number->{'macro'});
9529        }
9530    }
9531    elsif ($print_filename)
9532    {
9533        return sprintf(__("(in %s l. %d)"), $line_number->{'file_name'}, $line_number->{'line_nr'});
9534    }
9535    else
9536    {
9537        return sprintf(__("(l. %d)"), $line_number->{'line_nr'});
9538    }
9539}
9540
9541# to debug, dump the result of pass_texi and pass_structure in a file
9542sub dump_texi($$;$$)
9543{
9544    my $lines = shift;
9545    my $pass = shift;
9546    my $numbers = shift;
9547    my $file = shift;
9548    $file = "$docu_rdir$docu_name" . ".pass$pass" if (!defined($file));
9549    my $FH = open_out($file);
9550    print STDERR "# Dump texi\n" if ($T2H_VERBOSE);
9551    my $index = 0;
9552    foreach my $line (@$lines)
9553    {
9554        my $number_information = '';
9555        my $chomped_line = $line;
9556        # if defined, it means that an output of the file is asked for
9557        if (defined($numbers))
9558        {
9559           my $basefile = $numbers->[$index]->{'file_name'};
9560           $basefile = 'no file' if (!defined($basefile));
9561           $basefile =~ s|.*/||;
9562           my $macro_name = $numbers->[$index]->{'macro'};
9563           $macro_name = '' if (!defined($macro_name));
9564           my $line_number = $numbers->[$index]->{'line_nr'};
9565           $line_number = '' if (!defined($line_number));
9566           $number_information = "${basefile}($macro_name,$line_number) ";
9567        }
9568        print $FH "${number_information}$line";
9569        $index++ if (chomp($chomped_line));
9570    }
9571    close_out ($FH, $file);
9572}
9573
9574
9575# return next tag on the line
9576sub next_tag($)
9577{
9578    my $line = shift;
9579    # macro_regexp
9580    if ($line =~ /^\s*\@(["'~\@\}\{,\.!\?\s\*\-\^`=:\|\/\\])/o or $line =~ /^\s*\@([a-zA-Z][\w-]*)/)
9581    {
9582        return ($1);
9583    }
9584    return '';
9585}
9586
9587sub next_end_tag($)
9588{
9589    my $line = shift;
9590    if ($line =~ /^\s*\@end\s+([a-zA-Z][\w-]*)/)
9591    {
9592        return $1;
9593    }
9594    return '';
9595}
9596
9597sub next_tag_or_end_tag($)
9598{
9599    my $line = shift;
9600    my $next_tag = next_tag($line);
9601    return $next_tag if (defined($next_tag) and $next_tag ne '');
9602    return next_end_tag($line);
9603}
9604
9605sub top_stack($;$)
9606{
9607    my $stack = shift;
9608    my $ignore_para = shift;
9609
9610    my $index = scalar (@$stack);
9611    return undef unless ($index);
9612
9613    return $stack->[-1] unless ($ignore_para);
9614    if ($ignore_para == 1)
9615    {
9616       if (exists($stack->[-1]->{'format'}) and ($stack->[-1]->{'format'} eq 'paragraph' or $stack->[-1]->{'format'} eq 'preformatted'))
9617       {
9618          if (exists($stack->[-2]))
9619          {
9620              return $stack->[-2];
9621          }
9622          else
9623          {
9624              return undef;
9625          }
9626       }
9627       else
9628       {
9629          return $stack->[-1];
9630       }
9631    }
9632    else
9633    {
9634        while ($index and
9635          (
9636           (exists($stack->[$index-1]->{'format'})
9637            and ($stack->[$index-1]->{'format'} eq 'paragraph' or $stack->[$index-1]->{'format'} eq 'preformatted'))
9638           or (exists($stack->[$index-1]->{'style'}))
9639          ))
9640       {
9641           $index--;
9642       }
9643    }
9644    return undef unless ($index);
9645    return $stack->[$index-1];
9646}
9647
9648# return the next element with balanced {}
9649sub next_bracketed($$$;$)
9650{
9651    my $line = shift;
9652    my $command = shift;
9653    my $line_nr = shift;
9654    my $report = shift;
9655    my $opened_braces = 0;
9656    my $result = '';
9657    my $spaces;
9658#print STDERR "next_bracketed  $line";
9659    if ($line =~ /^(\s*)$/)
9660    {
9661        return ('','',$1);
9662    }
9663    while ($line !~ /^\s*$/)
9664    {
9665#print STDERR "next_bracketed($opened_braces): $result !!! $line";
9666        if (!$opened_braces)
9667        { # beginning of item
9668            $line =~ s/^(\s*)//;
9669            $spaces = $1;
9670            #if ($line =~ s/^([^\{\}\s]+)//)
9671            if ($line =~ s/^([^\{\}]+?)(\s+)/$2/ or $line =~ s/^([^\{\}]+?)$//)
9672            {
9673                $result = $1;
9674                $result = trim_around_spaces($result);
9675                return ($result, $line, $spaces);
9676            }
9677            elsif ($line =~ s/^([^\{\}]+?)([\{\}])/$2/)
9678            {
9679                $result = $1;
9680            }
9681        }
9682        elsif($line =~ s/^([^\{\}]+)//)
9683        {
9684            $result .= $1;
9685        }
9686        if ($line =~ s/^([\{\}])//)
9687        {
9688            my $brace = $1;
9689            $opened_braces++ if ($brace eq '{');
9690            $opened_braces-- if ($brace eq '}');
9691
9692            if ($opened_braces < 0)
9693            {
9694                line_error(sprintf(__("Too much '}' in \@%s"), $command), $line_nr) if ($report);
9695                $opened_braces = 0;
9696                #next;
9697            }
9698            $result .= $brace;
9699            return ($result, $line, $spaces) if ($opened_braces == 0);
9700        }
9701    }
9702    if ($opened_braces)
9703    {
9704        line_error(sprintf(__("Missing `}' on \@%s line"), $command), $line_nr) if ($report);
9705        return ($result, '', $spaces);
9706        #return ($result . ( '}' x $opened_braces), '', $spaces);
9707    }
9708    msg_debug ("BUG: at the end of next_bracketed", $line_nr);
9709    return undef;
9710}
9711
9712# def prams are also split at @-commands if not in brackets
9713sub next_def_param($$$;$)
9714{
9715    my $line = shift;
9716    my $command = shift;
9717    my $line_nr = shift;
9718    my $report = shift;
9719    my ($item, $spaces);
9720    ($item, $line, $spaces) = next_bracketed($line, $command, $line_nr, $report);
9721    return ($item, $line, $spaces) if (!defined($item));
9722    if ($item =~ /^\{/)
9723    {
9724        $item =~ s/^\{(.*)\}$/$1/;
9725    }
9726    else
9727    {
9728        my $delimeter_quoted = quotemeta($Texi2HTML::Config::def_argument_separator_delimiters);
9729        if ($item =~ s/^([^\@$delimeter_quoted]+)//)
9730        {
9731            $line = $item . $line;
9732            $item = $1;
9733        }
9734        elsif ($item =~ s/^([$delimeter_quoted])//)
9735        {
9736            $line = $item . $line;
9737            $item = $1;
9738        }
9739        elsif ($item =~ s/^(\@[^\@\{]+)(\@)/$2/)
9740        {
9741            $line = $item . $line;
9742            $item = $1;
9743        }
9744    }
9745    return ($item, $line, $spaces);
9746}
9747
9748# do a href using file and id and taking care of ommitting file if it is
9749# the same
9750# element: structuring element to point to
9751# file: current file
9752sub href($$;$)
9753{
9754    my $element = shift;
9755    my $file = shift;
9756    my $line_nr = shift;
9757    return '' unless defined($element);
9758    my $href = '';
9759    msg_debug("Bug: $element->{'texi'}, target undef", $line_nr) if (!defined($element->{'target'}));
9760    msg_debug("Bug: $element->{'texi'}, file undef", $line_nr) if (!defined($element->{'file'}));
9761    msg_debug("Bug: file undef in href", $line_nr) if (!defined($file));
9762    $href .= $element->{'file'} if (defined($element->{'file'}) and $file ne $element->{'file'});
9763    $href .= "#$element->{'target'}" if (defined($element->{'target'}));
9764    return $href;
9765}
9766
9767sub file_target_href($$$)
9768{
9769    my $dest_file = shift;
9770    my $orig_file = shift;
9771    my $target = shift;
9772    my $href = '';
9773    $href .= $dest_file if (defined($dest_file) and ($dest_file ne $orig_file));
9774    $href .= "#$target" if (defined($target));
9775    return $href;
9776}
9777
9778sub trim_around_spaces($)
9779{
9780   my $text = shift;
9781   $text =~ s/^\s*//;
9782   $text =~ s/(\s)\s*$/$1/;
9783   if ($text =~ /(\@+)\s$/)
9784   {
9785      my $arobases = $1;
9786      if ((length($arobases) % 2) == 0)
9787      {
9788          $text =~ s/\s$//;
9789      }
9790   }
9791   else
9792   {
9793      $text =~ s/\s$//;
9794   }
9795   return $text;
9796}
9797
9798sub normalise_space($)
9799{
9800   return undef unless (defined ($_[0]));
9801   my $text = shift;
9802   $text =~ s/\s+/ /go;
9803   $text =~ s/ $//;
9804   $text =~ s/^ //;
9805   return $text;
9806}
9807
9808
9809sub normalise_texi_space($)
9810{
9811   return undef unless (defined ($_[0]));
9812   my $text = shift;
9813   $text = trim_around_spaces($text);
9814   $text =~ s/\s+/ /go;
9815   return $text;
9816}
9817
9818sub normalise_node($)
9819{
9820    return undef unless (defined ($_[0]));
9821    my $text = shift;
9822    $text = normalise_texi_space($text);
9823    $text =~ s/^top$/Top/i;
9824    return $text;
9825}
9826
9827sub normalise_node_array($)
9828{
9829    my $array = shift;
9830    my @result;
9831    foreach my $node (@$array)
9832    {
9833       push @result, normalise_node($node);
9834    }
9835    return @result;
9836}
9837
9838sub do_anchor_label($$$$)
9839{
9840    my $command = shift;
9841    #my $anchor = shift;
9842    my $args = shift;
9843    my $anchor = $args->[0];
9844    my $style_stack = shift;
9845    my $state = shift;
9846    my $line_nr = shift;
9847
9848    #msg_debug("do_anchor_label $state->{'region'} m_p $state->{'multiple_pass'} remove $state->{'remove_texi'} `$anchor'", $line_nr);
9849
9850    $anchor = normalise_node($anchor);
9851    if ((defined($state->{'multiple_pass'}) and $state->{'multiple_pass'} > 0) or $state->{'outside_document'})
9852    {
9853       # no warning when outside of document.
9854       line_warn(sprintf(__("Anchor `%s' ignored in %s expanded more than once"),$anchor, $state->{'region'}), $line_nr) unless ($state->{'outside_document'} or defined($state->{'expansion'}));
9855       return '';
9856    }
9857
9858    if (!exists($nodes{$anchor}) or !defined($nodes{$anchor}->{'id'}))
9859    {
9860        msg_debug("Unknown anchor `$anchor'", $line_nr);
9861    }
9862    return &$Texi2HTML::Config::anchor_label($nodes{$anchor}->{'id'}, $anchor, $nodes{$anchor}, $state->{'expansion'});
9863}
9864
9865sub get_format_command($)
9866{
9867    my $format = shift;
9868    my $command = '';
9869    my $format_name = '';
9870    my $term = 0;
9871    my $item_nr;
9872    my $paragraph_number;
9873    my $enumerate_type;
9874    my $number;
9875
9876    $command = $format->{'command'} if (defined($format->{'command'}));
9877    $format_name =  $format->{'format'} if (defined($format->{'format'}));
9878
9879    return ($format_name,$command,\$format->{'paragraph_number'},$term,
9880        $format->{'item_nr'}, $format->{'spec'}, $format->{'number'},
9881        $format->{'stack_at_beginning'});
9882}
9883
9884sub do_paragraph($$;$)
9885{
9886    my $text = shift;
9887    my $state = shift;
9888    my $stack = shift;
9889
9890    if (!defined ($state->{'paragraph_context'}))
9891    {
9892        msg_debug ("paragraph_context undef", $Texi2HTML::THISDOC{'line_nr'});
9893        dump_stack (undef, $stack, $state);
9894    }
9895
9896    my ($format, $paragraph_command, $paragraph_number, $term, $item_nr,
9897        $enumerate_type, $number, $stack_at_beginning)
9898         = get_format_command ($state->{'paragraph_context'});
9899    delete $state->{'paragraph_context'};
9900
9901    my $indent_style = '';
9902    if (exists($state->{'paragraph_indent'}))
9903    {
9904        $indent_style = $state->{'paragraph_indent'};
9905        $state->{'paragraph_indent'} = undef;
9906        delete $state->{'paragraph_indent'};
9907    }
9908    my $paragraph_command_formatted;
9909    $state->{'paragraph_nr'}--;
9910    (print STDERR "Bug text undef in do_paragraph", return '') unless defined($text);
9911    my $align = '';
9912    $align = $state->{'paragraph_style'}->[-1] if ($state->{'paragraph_style'}->[-1]);
9913
9914    if ($paragraph_command and !exists($Texi2HTML::Config::special_list_commands{$format}->{$paragraph_command}))
9915    {
9916        $paragraph_command_formatted = substitute_line("\@$paragraph_command\{\}", "paragraph \@$format \@$paragraph_command", duplicate_formatting_state($state));
9917    }
9918    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);
9919}
9920
9921sub do_preformatted($$;$)
9922{
9923    my $text = shift;
9924    my $state = shift;
9925    my $stack = shift;
9926
9927    if (!defined ($state->{'preformatted_context'}))
9928    {
9929        msg_debug ("preformatted_context undef", $Texi2HTML::THISDOC{'line_nr'});
9930        dump_stack (undef, $stack, $state);
9931    }
9932
9933    my ($format, $leading_command, $preformatted_number, $term, $item_nr,
9934        $enumerate_type, $number,$stack_at_beginning)
9935        = get_format_command($state->{'preformatted_context'});
9936    delete ($state->{'preformatted_context'});
9937    my $leading_command_formatted;
9938    my $pre_style = '';
9939    my $class = '';
9940    $pre_style = $state->{'preformatted_stack'}->[-1]->{'pre_style'} if ($state->{'preformatted_stack'}->[-1]->{'pre_style'});
9941    $class = $state->{'preformatted_stack'}->[-1]->{'class'};
9942    print STDERR "BUG: !state->{'preformatted_stack'}->[-1]->{'class'}\n" unless ($class);
9943    if (defined($leading_command) and $leading_command ne '' and !exists($Texi2HTML::Config::special_list_commands{$format}->{$leading_command}))
9944    {
9945        $leading_command_formatted = substitute_line("\@$leading_command\{\}", "preformatted \@$format \@$leading_command", duplicate_formatting_state($state));
9946    }
9947    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);
9948}
9949
9950sub do_external_href($)
9951{
9952    # node_id is a unique node identifier with only letters, digits, - and _
9953    # node_xhtml_id is almost the same, but xhtml id can only begin with
9954    # letters, so a prefix has to be appended
9955    my $texi_node = shift;
9956    my $file = '';
9957    my $node_file = '';
9958    my $node_id = '';
9959    my $node_xhtml_id = '';
9960
9961#print STDERR "do_external_href $texi_node\n";
9962
9963    if ($texi_node =~ s/^\((.+?)\)//)
9964    {
9965         $file = $1;
9966    }
9967    $texi_node = normalise_node($texi_node);
9968    if ($texi_node ne '')
9969    {
9970         if (exists($nodes{$texi_node}) and ($nodes{$texi_node}->{'cross_manual_target'}))
9971         {
9972               $node_id = $nodes{$texi_node}->{'cross_manual_target'};
9973               if ($Texi2HTML::Config::TRANSLITERATE_FILE_NAMES)
9974               {
9975                   $node_file = $nodes{$texi_node}->{'cross_manual_file'};
9976               }
9977         }
9978         else
9979         {
9980              if ($Texi2HTML::Config::TRANSLITERATE_FILE_NAMES)
9981              {
9982                  ($node_id, $node_file) = cross_manual_line($texi_node,1);
9983              }
9984              else
9985              {
9986                  $node_id = cross_manual_line($texi_node);
9987              }
9988         }
9989         $node_xhtml_id = node_to_id($node_id);
9990         $node_file = $node_id unless ($Texi2HTML::Config::TRANSLITERATE_FILE_NAMES);
9991    }
9992    return &$Texi2HTML::Config::external_href($texi_node, $node_file,
9993        $node_xhtml_id, $file);
9994}
9995
9996# transform node for cross ref name to id suitable for xhtml: an xhtml id
9997# must begin with a letter.
9998sub node_to_id($)
9999{
10000    my $cross_ref_node_name = shift;
10001    $cross_ref_node_name =~ s/^([0-9_])/g_t$1/;
10002    return $cross_ref_node_name;
10003}
10004
10005# return an empty string if the command is not a index command, the prefix
10006# if it is one
10007sub index_command_prefix($)
10008{
10009   my $command = shift;
10010   return $1 if ($command =~ /^(\w+?)index/ and ($1 ne 'print') and ($1 ne 'syncode') and ($1 ne 'syn') and ($1 ne 'def') and ($1 ne 'defcode'));
10011   return '';
10012}
10013
10014# return 1 if the following tag shouldn't begin a line
10015sub no_line($)
10016{
10017    my $line = shift;
10018    my $next_tag = next_tag($line);
10019    return 1 if (($line =~ /^\s*$/) or $Texi2HTML::Config::no_paragraph_commands{$next_tag} or
10020       ($Texi2HTML::Config::no_paragraph_commands{'cindex'} and (index_command_prefix($next_tag) ne '')) or
10021       (($line =~ /^\@end\s+(\w+)/) and  $Texi2HTML::Config::no_paragraph_commands{"end $1"}) or
10022        ($next_tag =~ /^special_(\w+)_(\d+)$/ and $Texi2HTML::Config::no_paragraph_commands{$1})
10023     );
10024    return 0;
10025}
10026
10027sub no_paragraph($$)
10028{
10029    my $state = shift;
10030    my $line = shift;
10031    return ($state->{'paragraph_context'} or $state->{'preformatted'} or $state->{'remove_texi'} or no_line($line) or $state->{'no_paragraph'});
10032}
10033
10034# We restart the preformatted format which was stopped
10035# by the format if in preformatted, and start a paragraph
10036# for the text following the end of the format, if needed
10037sub begin_paragraph_after_command($$$$)
10038{
10039    my $state = shift;
10040    my $stack = shift;
10041    my $command = shift;
10042    my $text_following = shift;
10043
10044    #if (($state->{'preformatted'}
10045    #       and !$Texi2HTML::Config::format_in_paragraph{$command})
10046    if ($state->{'preformatted'}
10047        or (!no_paragraph($state,$text_following)))
10048    {
10049        begin_paragraph($stack, $state);
10050    }
10051}
10052
10053# handle raw formatting, ignored regions...
10054# called from scan_texi, so only in first pass.
10055sub do_text_macro($$$$$)
10056{
10057    my $type = shift;
10058    my $line = shift;
10059    my $state = shift;
10060    my $stack = shift;
10061    my $line_nr = shift;
10062    my $value;
10063    #print STDERR "do_text_macro $type\n";
10064
10065    if ($Texi2HTML::Config::texi_formats_map{$type} eq 'raw')
10066    {
10067        $state->{'raw'} = $type;
10068        #print STDERR "RAW\n";
10069        if ($state->{'raw'})
10070        {
10071             push @$stack, { 'style' => $type, 'text' => '' };
10072        }
10073    }
10074    elsif ($Texi2HTML::Config::texi_formats_map{$type} eq 'value')
10075    {
10076        if (($line =~ s/(\s+)($VARRE)$//) or ($line =~ s/(\s+)($VARRE)(\s)//))
10077        {
10078            $value = $1 . $2;
10079            $value .= $3 if defined($3);
10080            if ($state->{'ignored'})
10081            {
10082                if ($type eq $state->{'ignored'})
10083                {
10084                    $state->{'ifvalue_inside'}++;
10085                }
10086                # if 'ignored' we don't care about the command as long as
10087                # the nesting is correct
10088                return ($line,'');
10089            }
10090            my $open_ignored_ifvalue = 0;
10091            if ($type eq 'ifclear')
10092            {
10093                if (defined($value{$2}))
10094                {
10095                    $open_ignored_ifvalue = 1;
10096                }
10097                else
10098                {
10099                    push @{$state->{'text_macro_stack'}}, $type;
10100                }
10101            }
10102            elsif ($type eq 'ifset')
10103            {
10104                unless (defined($value{$2}))
10105                {
10106                    $open_ignored_ifvalue = 1;
10107                }
10108                else
10109                {
10110                    push @{$state->{'text_macro_stack'}}, $type;
10111                }
10112            }
10113            if ($open_ignored_ifvalue)
10114            {
10115                $state->{'ignored'} = $type;
10116                $state->{'ifvalue'} = $type;
10117                $state->{'ifvalue_inside'} = 1;
10118                # We add at the top of the stack to be able to close all
10119                # opened comands when closing the ifset/ifclear (and ignore
10120                # everything that is in those commands)
10121                push @$stack, { 'style' => 'ifvalue', 'text' => '' };
10122            }
10123        }
10124        else
10125        { # we accept a lone @ifset or @ifclear if it is nested in an @if*
10126            if ($state->{'ifvalue'} and $type eq $state->{'ifvalue'})
10127            {
10128                $state->{'ifvalue_inside'}++;
10129                return ($line,'');
10130            }
10131            line_error (sprintf(__("%c%s requires a name"), ord('@'), $type), $line_nr) unless ($state->{'ignored'});
10132        }
10133    }
10134    elsif (not $Texi2HTML::Config::texi_formats_map{$type})
10135    { # ignored text
10136        $state->{'ignored'} = $type;
10137        #print STDERR "IGNORED\n";
10138    }
10139    else
10140    {
10141        push @{$state->{'text_macro_stack'}}, $type unless($state->{'ignored'}) ;
10142    }
10143    my $text = "\@$type";
10144    $text .= $value if defined($value);
10145    return ($line, $text);
10146}
10147
10148# do regions handled specially, for example tex or math going through latex2html
10149sub init_special($$)
10150{
10151    my $style = shift;
10152    my $text = shift;
10153    if (defined($Texi2HTML::Config::command_handler{$style}) and
10154       defined($Texi2HTML::Config::command_handler{$style}->{'init'}))
10155    {
10156        $special_commands{$style}->{'count'} = 0 if (!defined($special_commands{$style}));
10157        if ($Texi2HTML::Config::command_handler{$style}->{'init'}($style,$text,
10158               $special_commands{$style}->{'count'} +1))
10159        {
10160            $special_commands{$style}->{'count'}++;
10161            return "\@special_${style}_".$special_commands{$style}->{'count'}."{}";
10162        }
10163        return '';
10164    }
10165}
10166
10167sub reset_index_entries($)
10168{
10169    my $region = shift;
10170    if (defined($Texi2HTML::THISDOC{'index_entries'}->{$region}))
10171    {
10172       foreach my $entry (values(%{$Texi2HTML::THISDOC{'index_entries'}->{$region}}))
10173       {
10174          if (scalar(@{$entry->{'entries'}}) > 1)
10175          {
10176              $entry->{'index'} = 0;
10177          }
10178       }
10179    }
10180    if (defined($Texi2HTML::THISDOC{'indices_numbers'}->{$region}))
10181    {
10182       foreach my $index_name (keys(%{$Texi2HTML::THISDOC{'indices_numbers'}->{$region}}))
10183       {
10184          $Texi2HTML::THISDOC{'indices_numbers'}->{$region}->{$index_name} = undef;
10185       }
10186    }
10187}
10188
10189# FIXME we cannot go through the commands too 'often'. The error messages
10190# are duplicated and global stuff is changed.
10191# -> identify what is global
10192# -> use local state
10193sub do_special_region_lines($;$$)
10194{
10195    my $region = shift;
10196    my $state = shift;
10197    my $line_nr = shift;
10198
10199    # this case covers something like
10200    # @copying
10201    # @insertcopying
10202    # @end copying
10203    if (defined($state) and exists($state->{'region'}) and ($region eq $state->{'region'}))
10204    {
10205         line_error(sprintf(__("Region %s inside region %s is not allowed"), $region, $state->{'region'}), $line_nr);
10206         return ('','', '');
10207    }
10208
10209    print STDERR "# do_special_region_lines for region $region ['multiple_pass','region_pass']: ($region_initial_state{$region}->{'multiple_pass'}, $region_initial_state{$region}->{'region_pass'})" if ($T2H_DEBUG);
10210    if (!defined($state))
10211    {
10212        $state = {};
10213        fill_state($state);
10214        $state->{'outside_document'} = 1;
10215        print STDERR " outside document\n" if ($T2H_DEBUG);
10216    }
10217    elsif (!$state->{'outside_document'})
10218    {
10219        $region_initial_state{$region}->{'multiple_pass'}++;
10220        print STDERR " multiple pass $region_initial_state{$region}->{'multiple_pass'}\n" if ($T2H_DEBUG);
10221    }
10222    else
10223    {
10224        print STDERR " in $state->{'region'}, outside document\n" if ($T2H_DEBUG);
10225    }
10226
10227    return ('','','') unless @{$region_lines{$region}};
10228
10229    my @result;
10230
10231    foreach my $context ('normal', 'remove_texi', 'simple_format')
10232    {
10233        print STDERR "# $context\n" if ($T2H_DEBUG);
10234        my $new_state = duplicate_formatting_state($state);
10235        reset_index_entries($region);
10236        foreach my $key (keys(%{$region_initial_state{$region}}))
10237        {
10238            $new_state->{$key} = $region_initial_state{$region}->{$key};
10239        }
10240        $new_state->{'remove_texi'} = 1 if ($context eq 'remove_texi');
10241
10242        &$Texi2HTML::Config::begin_special_region($region,$new_state,$region_lines{$region})
10243            if (defined($Texi2HTML::Config::begin_special_region));
10244
10245
10246        my $line_numbers;
10247        my $context_string = "$region ($region_initial_state{$region}->{'multiple_pass'}, $region_initial_state{$region}->{'region_pass'})";
10248        if ($context eq 'normal')
10249        { # the line numbers are given only for the normal context, therefore
10250          # there will be error messages only in that case
10251           $line_numbers = [ @{$region_line_nrs{$region}} ];
10252        }
10253        else
10254        {
10255           $context_string = "$context $context_string";
10256        }
10257
10258        my $result;
10259        if ($context ne 'simple_format')
10260        {
10261           $result = substitute_text($new_state, $line_numbers,
10262             $context_string, @{$region_lines{$region}});
10263        }
10264        else
10265        {
10266           $result = simple_format($new_state, $line_numbers,
10267             $context_string, @{$region_lines{$region}});
10268        }
10269        $result = &$Texi2HTML::Config::end_special_region($region,$new_state,$result)
10270           if (defined($Texi2HTML::Config::end_special_region));
10271
10272        push @result, $result;
10273        $region_initial_state{$region}->{'region_pass'}++;
10274    }
10275
10276    return @result;
10277}
10278
10279sub do_insertcopying($$)
10280{
10281    my $state = shift;
10282    my $line_nr = shift;
10283    my ($text, $comment, $simple_formatted) = do_special_region_lines('copying', $state, $line_nr);
10284    return &$Texi2HTML::Config::insertcopying($text, $comment, $simple_formatted);
10285}
10286
10287sub get_deff_index($$$$)
10288{
10289    my $tag = shift;
10290    my $line = shift;
10291    my $line_nr = shift;
10292    my $warn = shift;
10293
10294    $tag =~ s/x$//;
10295    my ($command, $style, $category, $name, $type, $class, $arguments, $args_array, $args_type_array);
10296    ($command, $style, $category, $name, $type, $class, $arguments, $args_array, $args_type_array) = parse_def($tag, $line, $line_nr, $warn);
10297    $name = &$Texi2HTML::Config::definition_index_entry($name, $class, $style, $command);
10298    return ($style, '') if (!defined($name) or ($name =~ /^\s*$/));
10299    return ($style, $name, $arguments);
10300}
10301
10302sub parse_def($$$;$)
10303{
10304    my $command = shift;
10305    my $line = shift;
10306    my $line_nr = shift;
10307    my $report = shift;
10308
10309    my $format = $command;
10310
10311    if (!ref ($Texi2HTML::Config::def_map{$command}))
10312    {
10313        # substitute shortcuts for definition commands
10314        my $substituted = $Texi2HTML::Config::def_map{$command};
10315        $substituted =~ s/(\w+)//;
10316        $format = $1;
10317        $line = $substituted . $line;
10318    }
10319#print STDERR "PARSE_DEF($command,$format) $line";
10320    my ($category, $name, $type, $class, $arguments);
10321    my @arguments = ();
10322    my @args = @{$Texi2HTML::Config::def_map{$format}};
10323    my $style = shift @args;
10324    my @arg_types = ();
10325    while (@args and $args[0] ne 'arg' and $args[0] ne 'argtype')
10326    {
10327        my $arg = shift @args;
10328        # backward compatibility, it was possible to have a { in front.
10329        $arg =~  s/^\{//;
10330        my ($item, $spaces);
10331        ($item, $line, $spaces) = next_def_param($line, $command, $line_nr, $report);
10332        last if (!defined($item));
10333        if ($arg eq 'category')
10334        {
10335            $category = $item;
10336        }
10337        elsif ($arg eq 'name')
10338        {
10339            $name = $item;
10340        }
10341        elsif ($arg eq 'type')
10342        {
10343            $type = $item;
10344        }
10345        elsif ($arg eq 'class')
10346        {
10347            $class = $item;
10348        }
10349        push @arg_types, $arg;
10350        push @arguments, $item;
10351    }
10352    my $line_remaining = $line;
10353    $line = '';
10354    my $arg_and_type = 1;
10355    foreach my $arg (@args)
10356    {
10357        if ($arg eq 'arg')
10358        {
10359            $arg_and_type = 0;
10360            last;
10361        }
10362        elsif ($arg eq 'argtype')
10363        {
10364            last;
10365        }
10366    }
10367
10368    my $always_delimiter_quoted = quotemeta($Texi2HTML::Config::def_always_delimiters);
10369    my $in_type_delimiter_quoted = quotemeta($Texi2HTML::Config::def_in_type_delimiters);
10370    my $after_type = 0;
10371    while ($line_remaining !~ /^\s*$/)
10372    {
10373        my ($item, $spaces);
10374        ($item, $line_remaining,$spaces) = next_def_param($line_remaining, $command, $line_nr);
10375        if ($item =~ /^([$always_delimiter_quoted])/ or (!$arg_and_type and  $item =~ /^([$in_type_delimiter_quoted].*)/))
10376        {
10377           $item = $1;
10378           push @arg_types, 'delimiter';
10379           $after_type = 0;
10380        }
10381        elsif (!$arg_and_type or $item =~ /^\@/ or $after_type)
10382        {
10383           push @arg_types, 'param';
10384           $after_type = 0;
10385        }
10386        elsif ($item =~ /^([$in_type_delimiter_quoted])/)
10387        {
10388           push @arg_types, 'delimiter';
10389        }
10390        else
10391        {
10392           push @arg_types, 'paramtype';
10393           $after_type = 1;
10394        }
10395        $spaces = ' ' if ($spaces);
10396        $line .= $spaces . $item;
10397        push @arguments, $spaces .$item;
10398    }
10399#print STDERR "PARSE_DEF (style $style, category $category, name $name, type $type, class $class, line $line)\n";
10400    return ($format, $style, $category, $name, $type, $class, $line, \@arguments, \@arg_types);
10401}
10402
10403sub begin_paragraph($$)
10404{
10405    my $stack = shift;
10406    my $state = shift;
10407
10408    my $command = { };
10409    my $top_format = top_format($stack);
10410    if (defined($top_format))
10411    {
10412        $command = $top_format;
10413    }
10414    $command->{'stack_at_beginning'} = [ @{$state->{'command_stack'}} ];
10415    my $paragraph_or_preformatted = 'paragraph';
10416    if ($state->{'preformatted'})
10417    {
10418        $paragraph_or_preformatted = 'preformatted';
10419        $state->{'preformatted_context'} = $command;
10420    }
10421    else
10422    {
10423       $state->{'paragraph_context'} = $command;
10424       $state->{'paragraph_nr'}++;
10425    }
10426    push @$stack, {'format' => $paragraph_or_preformatted, 'text' => '' };
10427    # FIXME give line, and modify line?
10428    &$Texi2HTML::Config::begin_paragraph_texi($paragraph_or_preformatted,
10429      $state->{'paragraph_macros'}, $command, $state, $stack)
10430        if (defined($Texi2HTML::Config::begin_paragraph_texi));
10431    # if there are macros which weren't closed when the previous
10432    # paragraph was closed we reopen them here
10433    push @$stack, @{$state->{'paragraph_macros'}} if $state->{'paragraph_macros'};
10434    delete $state->{'paragraph_macros'};
10435}
10436
10437sub parse_format_command($$)
10438{
10439    my $line = shift;
10440    my $tag = shift;
10441    my $command = '';
10442
10443    my $orig_line = $line;
10444    # macro_regexp
10445    if ($line =~ s/^\s*\@([A-Za-z][\w-]*)(\{\})?\s*$//)
10446    {
10447         $command = $1;
10448         $command = $alias{$command} if (exists($alias{$command}));
10449    }
10450    return ('', $command) if ($line =~ /^\s*$/);
10451    chomp $line;
10452    $line = substitute_text ({'keep_nr' => 1, 'keep_texi' => 1, 'check_item' => $tag}, undef, "parse_format_command", $line);
10453    return ($line, $command);
10454}
10455
10456sub parse_enumerate($)
10457{
10458    my $line = shift;
10459    my $spec;
10460    if ($line =~ /^\s*(\w)\b/ and ($1 ne '_'))
10461    {
10462        $spec = $1;
10463        $line =~ s/^\s*(\w)\s*//;
10464    }
10465    return ($line, $spec);
10466}
10467
10468sub parse_multitable($$)
10469{
10470    my $line = shift;
10471    my $line_nr = shift;
10472    # first find the table width
10473    my $table_width = 0;
10474    my $fractions;
10475    my $elements;
10476    if ($line =~ s/^\s+\@columnfractions\s+//)
10477    {
10478        @$fractions = split /\s+/, $line;
10479        $table_width = scalar(@$fractions);
10480        foreach my $fraction (@$fractions)
10481        {
10482            unless ($fraction =~ /^(\d*\.\d+)|(\d+)\.?$/)
10483            {
10484                line_error (sprintf(__("column fraction not a number: %s"), $fraction), $line_nr);
10485            }
10486        }
10487    }
10488    else
10489    {
10490        my $element;
10491        my $line_orig = $line;
10492        while ($line !~ /^\s*$/)
10493        {
10494            my $spaces;
10495            ($element, $line, $spaces) = next_bracketed($line, 'multitable', $line_nr, 1);
10496            if ($element =~ /^\{/)
10497            {
10498                $table_width++;
10499                $element =~ s/^\{//;
10500                $element =~ s/\}\s*$//;
10501                push @$elements, $element;
10502            }
10503            else
10504            {
10505                line_warn (sprintf(__("ignoring stray text `%s' after \@multitable"), $element), $line_nr);
10506            }
10507        }
10508    }
10509    return ($table_width, $fractions, $elements);
10510}
10511
10512sub end_format($$$$$)
10513{
10514    my $text = shift;
10515    my $stack = shift;
10516    my $state = shift;
10517    my $format = shift;
10518    my $line_nr = shift;
10519    #msg_debug ("END FORMAT $format", $line_nr);
10520    #dump_stack($text, $stack, $state);
10521    #sleep 1;
10522    if ($format_type{$format} eq 'menu')
10523    {
10524        $state->{$format}--;
10525        if ($state->{$format} < 0)
10526        { # FIXME currently happens, see invalid/not_closed_in_menu.texi
10527             line_error(sprintf(__("Too many %s closed"), $format), $line_nr);
10528             #print STDERR "Bug, $format counter negative: $state->{$format}\n";
10529             #dump_stack($text, $stack, $state);
10530             #exit 1;
10531             $state->{$format} = 0;
10532        }
10533        close_menu_comment($text, $stack, $state, "\@end $format", $line_nr);
10534    }
10535
10536    if ($format_type{$format} eq 'list')
10537    { # those functions return if they detect an inapropriate context
10538        add_item($text, $stack, $state, $line_nr); # handle lists
10539    }
10540    elsif ($format eq 'multitable')
10541    {
10542        add_row($text, $stack, $state, $line_nr); # handle multitable
10543    }
10544    elsif ($format_type{$format} eq 'table')
10545    {
10546        add_term($text, $stack, $state, $line_nr); # handle table
10547        add_line($text, $stack, $state, $line_nr); # handle table
10548    }
10549
10550    #print STDERR "END_FORMAT\n";
10551    #dump_stack($text, $stack, $state);
10552
10553    # set to 1 if there is a mismatch between the closed format and format
10554    # opened before
10555    my $format_mismatch = 0;
10556    # set to 1 in normal menu context after an end menu or detailmenu
10557    my $begin_menu_comment_after_end_format = 0;
10558
10559    my $format_ref = pop @$stack;
10560
10561    ######################### debug
10562    if (!defined($format_ref->{'text'}))
10563    {
10564        push @$stack, $format_ref;
10565        print STDERR "Bug: text undef in end_format $format\n";
10566        dump_stack($text, $stack, $state);
10567        pop @$stack;
10568    }
10569    ######################### end debug
10570
10571    if ($region_lines{$format})
10572    {
10573        ######################### debug
10574        if ($format ne $state->{'region_lines'}->{'format'})
10575        {
10576            msg_debug ("Bug: mismatched region `$format' ne `$state->{'region_lines'}->{'format'}'");
10577        }
10578        ######################### end debug
10579        $state->{'region_lines'}->{'number'}--;
10580        if ($state->{'region_lines'}->{'number'} == 0)
10581        {
10582            close_region($state);
10583        }
10584    }
10585
10586    if ($format_type{$format} eq 'table' or $format_type{$format} eq 'list' or $format eq 'multitable')
10587    {
10588        if ($format_ref->{'format'} ne $format)
10589        { # for example vtable closing a table. Cannot be known
10590          # before if in a cell
10591             $format_mismatch = 1;
10592             line_error (sprintf(__("`\@end' expected `%s', but saw `%s'"), $format_ref->{'format'}, $format), $line_nr);
10593
10594        }
10595        if (!$format_ref->{'empty_first'} and $format_ref->{'item_nr'} == 0)
10596        {
10597             line_warn (sprintf(__("\@%s has text but no \@item"),$format_ref->{'format'}), $line_nr);
10598        }
10599    }
10600
10601    if (defined($Texi2HTML::Config::def_map{$format}))
10602    {
10603        close_stack($text, $stack, $state, $line_nr, 'deff_item')
10604           unless ($format_ref->{'format'} eq 'deff_item');
10605        add_prev($text, $stack, &$Texi2HTML::Config::def_item($format_ref->{'text'}, $format_ref->{'only_inter_commands'}, $format_ref->{'orig_command'}));
10606        $format_ref = pop @$stack; # pop deff
10607        ######################################### debug
10608        if (!defined($format_ref->{'format'}) or !defined($Texi2HTML::Config::def_map{$format_ref->{'format'}}))
10609        {
10610             print STDERR "Bug: not a def* under deff_item\n";
10611             push (@$stack, $format_ref);
10612             dump_stack($text, $stack, $state);
10613             pop @$stack;
10614        }
10615        ######################################### end debug
10616        elsif ($format_ref->{'format'} ne $format)
10617        {
10618             $format_mismatch = 1;
10619             line_error (sprintf(__("`\@end' expected `%s', but saw `%s'"), $format_ref->{'format'}, $format), $line_nr);
10620        }
10621        add_prev($text, $stack, &$Texi2HTML::Config::def($format_ref->{'text'}, $format_ref->{'orig_format'}));
10622    }
10623    elsif ($format eq 'float')
10624    {
10625        unless (defined($state->{'float'}))
10626        {
10627            msg_debug("state->{'float'} not defined in float", $line_nr);
10628            next;
10629        }
10630        my ($caption_lines, $shortcaption_lines) = &$Texi2HTML::Config::caption_shortcaption($state->{'float'});
10631        my ($caption_text, $shortcaption_text);
10632        my $caption_state = duplicate_formatting_state($state);
10633        push @{$caption_state->{'command_stack'}}, 'caption';
10634        $caption_text = substitute_text($caption_state, undef, '@caption in @end float',  @$caption_lines) if (defined($caption_lines));
10635
10636        my $shortcaption_state = duplicate_formatting_state($state);
10637        push @{$shortcaption_state->{'command_stack'}}, 'shortcaption';
10638        $shortcaption_text = substitute_text($shortcaption_state, undef, '@shortcaption in @end float', @$shortcaption_lines) if (defined($shortcaption_lines));
10639        add_prev($text, $stack, &$Texi2HTML::Config::float($format_ref->{'text'}, $state->{'float'}, $caption_text, $shortcaption_text));
10640        delete $state->{'float'};
10641    }
10642    # FIXME $complex_format_map obsoleted in nov 2009
10643    elsif ((exists ($Texi2HTML::Config::complex_format_map->{$format})
10644         or exists ($Texi2HTML::Config::complex_format_map{$format}))
10645      and ($format_type{$format} ne 'menu' or $Texi2HTML::Config::SIMPLE_MENU))
10646    {
10647        $state->{'preformatted'}--;
10648        pop @{$state->{'preformatted_stack'}};
10649        my $complex_format;
10650        if (exists ($Texi2HTML::Config::complex_format_map->{$format}))
10651        {
10652            $complex_format = $Texi2HTML::Config::complex_format_map->{$format};
10653        }
10654        else
10655        {
10656            $complex_format = $Texi2HTML::Config::complex_format_map{$format};
10657        }
10658        # debug
10659        if (!defined($complex_format->{'begin'}))
10660        {
10661            msg_debug ("Bug undef $format_ref->{'format'}" . "->{'begin'} (for $format...)", $line_nr);
10662            dump_stack ($text, $stack, $state);
10663        }
10664        if ($fake_format{$format_ref->{'format'}} and $format_ref->{'text'} =~ /^\s*$/)
10665        {
10666           # discard empty fake formats
10667        }
10668        #print STDERR "before $format\n";
10669        #dump_stack ($text, $stack, $state);
10670        else
10671        {
10672            add_prev($text, $stack, &$Texi2HTML::Config::complex_format($format_ref->{'format'}, $format_ref->{'text'}));
10673        }
10674        #print STDERR "after $format\n";
10675        #dump_stack ($text, $stack, $state);
10676    }
10677    elsif ($format_type{$format} eq 'table' or $format_type{$format} eq 'list' or $format eq 'multitable')
10678    {
10679        if (exists ($Texi2HTML::Config::format_map{$format}))
10680        { # table or list has a simple format
10681            add_prev($text, $stack, end_simple_format($format_ref->{'format'}, $format_ref->{'text'}, $state));
10682        }
10683        else
10684        { # table or list handler defined by the user
10685            add_prev($text, $stack, &$Texi2HTML::Config::table_list($format_ref->{'format'}, $format_ref->{'text'}, $format_ref->{'command'}, $format_ref->{'formatted_command'}, $format_ref->{'item_nr'}, $format_ref->{'spec'}, $format_ref->{'prepended'}, $format_ref->{'prepended_formatted'}, $format_ref->{'columnfractions'}, $format_ref->{'prototype_row'}, $format_ref->{'prototype_lengths'}, $format_ref->{'max_columns'}));
10686        }
10687    }
10688    elsif ($format_type{$format} eq 'quotation')
10689    {
10690        my $quotation_args = pop @{$state->{'quotation_stack'}};
10691        #add_prev($text, $stack, &$Texi2HTML::Config::quotation($format, $format_ref->{'text'}, $quotation_args->{'text'}, $quotation_args->{'text_texi'}));
10692        add_prev($text, $stack, &$Texi2HTML::Config::quotation($format, $format_ref->{'text'}, $format_ref->{'argument_text'}, $format_ref->{'argument_texi'}, $format_ref->{'quote_authors'}));
10693    }
10694    elsif ($Texi2HTML::Config::paragraph_style{$format})
10695    {
10696        if ($state->{'paragraph_style'}->[-1] eq $format)
10697        {
10698            pop @{$state->{'paragraph_style'}};
10699        }
10700        if ($fake_format{$format_ref->{'format'}} and $format_ref->{'text'} =~ /^\s*$/)
10701        {
10702           # discard empty fake formats
10703        }
10704        else
10705        {
10706            add_prev($text, $stack, &$Texi2HTML::Config::paragraph_style_command($format_ref->{'format'},$format_ref->{'text'}));
10707        }
10708    }
10709    elsif (exists($Texi2HTML::Config::format_map{$format}))
10710    {
10711        if ($fake_format{$format_ref->{'format'}} and $format_ref->{'text'} =~ /^\s*$/)
10712        {
10713           # discard empty fake formats
10714        }
10715        else
10716        {
10717            add_prev($text, $stack, end_simple_format($format_ref->{'format'}, $format_ref->{'text'}, $state));
10718        }
10719    }
10720    elsif ($format_type{$format} eq 'cartouche')
10721    {
10722        add_prev($text, $stack, &$Texi2HTML::Config::cartouche($format_ref->{'text'},$state->{'command_stack'}));
10723    }
10724    elsif ($format_type{$format} eq 'menu')
10725    {
10726    # it should be short-circuited if $Texi2HTML::Config::SIMPLE_MENU
10727        if ($state->{'preformatted'})
10728        {
10729            # remove the fake complex style
10730            $state->{'preformatted'}--;
10731            pop @{$state->{'preformatted_stack'}};
10732        }
10733
10734        # backward compatibility with 1.78 jun 2007
10735        if (defined($Texi2HTML::Config::menu))
10736        {
10737           if ($format eq 'menu')
10738           {
10739               add_prev($text, $stack, &$Texi2HTML::Config::menu($format_ref->{'text'}));
10740           }
10741           elsif ($format eq 'detailmenu') # detailmenu
10742           {
10743               add_prev($text, $stack, $format_ref->{'text'});
10744           }
10745           else # direntry
10746           {
10747           }
10748        }
10749        else
10750        {
10751           add_prev($text, $stack, &$Texi2HTML::Config::menu_command($format, $format_ref->{'text'}, $state->{'preformatted'}));
10752        }
10753        $begin_menu_comment_after_end_format = 1;
10754    }
10755    else
10756    {
10757        line_warn(sprintf(__("Unknown format %s"), $format), $line_nr);
10758    }
10759
10760    # fake formats are not on the command_stack
10761    return 1 if ($fake_format{$format_ref->{'format'}});
10762    # special case for center as it is at the bottom of the stack
10763    my $removed_from_stack;
10764    if ($format eq 'center')
10765    {
10766        $removed_from_stack = shift @{$state->{'command_stack'}};
10767    }
10768    else
10769    {
10770        $removed_from_stack = pop @{$state->{'command_stack'}};
10771    }
10772    if ($removed_from_stack ne $format and !$format_mismatch)
10773    {
10774        #line_error ("Bug: removed_from_stack $removed_from_stack ne format $format", $line_nr);
10775        # it may not be a bug. Consider, for example a @code{in code
10776        # @end cartouche
10777        # The @code is closed when the paragraph is closed by
10778        # @end cartouche but not really closed since it might have been
10779        # a multiple paragraph @code. So it is not removed from
10780        # command_stack but still have disapeared from the stack!
10781        line_error(sprintf(__("mismatched \@end %s with \@%s"), $format, $removed_from_stack), $line_nr);
10782    }
10783    if ($begin_menu_comment_after_end_format and $state->{'menu'})
10784    {
10785        begin_format($text, $stack, $state, 'menu_comment', '', $line_nr);
10786        return 0;
10787    }
10788    return 1;
10789}
10790
10791sub push_complex_format_style($$$$)
10792{
10793    my $command = shift;
10794    my $complex_format = shift;
10795    my $state = shift;
10796    my $line_nr = shift;
10797    my $class = $command;
10798
10799    if (!defined($state->{'preformatted_stack'}))
10800    {
10801       msg_debug ("'preformatted_stack' not defined in push_complex_format_style", $line_nr);
10802    }
10803
10804    $class = $complex_format->{'class'} if (defined($complex_format->{'class'}));
10805    my $format_style = {'pre_style' =>$complex_format->{'pre_style'}, 'class' => $class, 'command' => $command };
10806    if (defined($complex_format->{'style'}))
10807    {
10808        $format_style->{'style'} = $complex_format->{'style'};
10809    }
10810    else
10811    {
10812        if ($state->{'preformatted'} and defined($state->{'preformatted_stack'}->[-1]->{'style'}))
10813        {
10814            $format_style->{'style'} = $state->{'preformatted_stack'}->[-1]->{'style'};
10815        }
10816        my $index = scalar(@{$state->{'preformatted_stack'}}) -1;
10817        # since preformatted styles are not nested, the preformatted format
10818        # of the first format with style has to be used
10819        if ($index > 0)
10820        {
10821            while ($index)
10822            {
10823                if ($state->{'preformatted_stack'}->[$index]->{'style'})
10824                {
10825                    $format_style->{'class'} = $state->{'preformatted_stack'}->[$index]->{'class'} if (defined($state->{'preformatted_stack'}->[$index]->{'class'}));
10826                    last;
10827                }
10828                $index--;
10829            }
10830        }
10831    }
10832    $state->{'preformatted'}++;
10833    push @{$state->{'preformatted_stack'}}, $format_style;
10834}
10835
10836sub prepare_state_multiple_pass($$)
10837{
10838    my $command = shift;
10839    my $state = shift;
10840    my $return_state = {
10841          'multiple_pass' => 1,
10842          'element' => $state->{'element'},
10843          'outside_document' => $state->{'outside_document'},
10844          'new_state' => 1
10845         };
10846    if (defined($command))
10847    {
10848        $return_state->{'expansion'} = $command;
10849        $return_state->{'command_stack'} = ["$command"];
10850    }
10851    else
10852    {
10853        msg_debug("prepare_state_multiple_pass command not defined");
10854    }
10855    return $return_state;
10856}
10857
10858sub begin_format($$$$$$);
10859
10860sub begin_format($$$$$$)
10861{
10862    my $text = shift;
10863    my $stack = shift;
10864    my $state = shift;
10865    my $macro = shift;
10866    my $line = shift;
10867    my $line_nr = shift;
10868    #msg_debug ("BEGIN FORMAT $macro",$line_nr);
10869
10870    my $in_term;
10871    my $top_format = top_stack($stack, 2);
10872    $in_term = 1 if (defined($top_format->{'format'}) and $top_format->{'format'} eq 'term');
10873
10874    if ($format_type{$macro} eq 'menu')
10875    {
10876        if ($state->{'menu'})
10877        {
10878            # there should not be any paragraph/preformatted to close
10879            # if the comment or the description were closed since they
10880            # close it
10881            if (! close_menu_comment($text, $stack, $state, "\@$macro", $line_nr)
10882               and !close_menu_description($text, $stack, $state, "\@$macro", $line_nr))
10883            {
10884               close_paragraph($text, $stack, $state, "\@$macro", $line_nr);
10885            }
10886        }
10887        else
10888        {
10889            close_paragraph($text, $stack, $state, "\@$macro", $line_nr);
10890        }
10891        $state->{$macro}++;
10892    }
10893    elsif (!$in_term)
10894    {
10895        close_paragraph($text, $stack, $state, "\@$macro", $line_nr);
10896    }
10897
10898    # close def_item if this is a matching @def*x command
10899    if (defined($Texi2HTML::Config::def_map{$macro}))
10900    {
10901        my $top_format = top_format($stack);
10902        if (defined($top_format) and ("$top_format->{'format'}x" eq $macro))
10903        {
10904          # this is a matching @DEFx command.
10905             my $deff_item = pop @$stack;
10906             add_prev($text, $stack,
10907                &$Texi2HTML::Config::def_item($deff_item->{'text'}, $deff_item->{'only_inter_commands'}, $deff_item->{'orig_command'}));
10908             #print STDERR "DEFx $macro\n";
10909        }
10910        elsif ($macro =~ /x$/)
10911        {
10912            my $base_def_command = $macro;
10913            $base_def_command =~ s/x$//;
10914            line_error(sprintf(__("Must be in `\@%s' environment to use `\@%s'"), $base_def_command, $macro), $line_nr);
10915        }
10916    }
10917
10918    $line = &$Texi2HTML::Config::begin_format_texi($macro, $line, $state)
10919        unless($fake_format{$macro});
10920
10921    push (@{$state->{'command_stack'}}, $macro) unless ($fake_format{$macro});
10922    if ($region_lines{$macro})
10923    {
10924        open_region($macro,$state);
10925    }
10926    # A deff like macro
10927    if (defined($Texi2HTML::Config::def_map{$macro}))
10928    {
10929        my $top_format = top_format($stack);
10930        my $orig_command = $macro;
10931        if (defined($top_format) and ("$top_format->{'format'}x" eq $macro))
10932        {
10933          # this is a matching @DEFx command.
10934          # the @DEFx macro has been put at the top of the
10935          # command_stack, although there is no real format opening
10936             pop @{$state->{'command_stack'}};
10937             $macro =~ s/x$//o;
10938             #print STDERR "DEFx $macro\n";
10939        }
10940        else
10941        {
10942             # a new @def.
10943             $macro =~ s/x$//o;
10944             # we remove what is on the stack and put it back,
10945             # to make sure that it is the form without x.
10946             pop @{$state->{'command_stack'}};
10947             push @{$state->{'command_stack'}}, $macro;
10948             #print STDERR "DEF begin $macro\n";
10949             $top_format = { 'format' => $macro, 'text' => '', 'orig_format' =>$orig_command};
10950             push @$stack, $top_format;
10951        }
10952        #print STDERR "BEGIN_DEFF $macro\n";
10953        #dump_stack ($text, $stack, $state);
10954
10955        my ($command, $style, $category, $name, $type, $class, $args_array, $args_type_array);
10956        ($command, $style, $category, $name, $type, $class, $line, $args_array, $args_type_array) = parse_def($macro, $line, $line_nr);
10957        my $class_name_texi = &$Texi2HTML::Config::definition_index_entry($name, $class, $style, $command);
10958
10959        #print STDERR "AFTER parse_def $line";
10960        my @formatted_args = ();
10961        my $arguments = '';
10962        my %formatted_arguments = ();
10963        my @types = @$args_type_array;
10964        my $arg_nr = 0;
10965        my $previous_type;
10966        foreach my $arg (@$args_array)
10967        {
10968            $arg_nr++;
10969            my $type = shift @types;
10970            my $substitution_state = duplicate_formatting_state($state);
10971            # all @def* arguments are in code_style
10972            $substitution_state->{'code_style'}++;
10973            push @formatted_args, substitute_line($arg, sprintf(__("\@%s (argument nr %d)"), $macro, $arg_nr), $substitution_state, $line_nr);
10974            if (grep {$_ eq $type} ('param', 'paramtype', 'delimiter'))
10975            {
10976                $arguments .= $formatted_args[-1];
10977            }
10978            else
10979            {
10980                $formatted_arguments{$type} = $formatted_args[-1];
10981            }
10982
10983            $previous_type = $type;
10984        }
10985        $name = $formatted_arguments{'name'};
10986        $category = $formatted_arguments{'category'};
10987        $type = $formatted_arguments{'type'};
10988        $class = $formatted_arguments{'class'};
10989
10990        $name = '' if (!defined($name));
10991        $category = '' if (!defined($category));
10992
10993        my $class_category = &$Texi2HTML::Config::definition_category($category, $class, $style, $command);
10994        my $class_name = &$Texi2HTML::Config::definition_index_entry($name, $class, $style, $command);
10995        my ($index_entry, $formatted_index_entry, $index_label) = do_index_entry_label($macro, $state, $line_nr, $class_name_texi, $line);
10996        add_prev($text, $stack, &$Texi2HTML::Config::def_line($class_category, $name, $type, $arguments, $index_label, \@formatted_args, $args_type_array, $args_array, $command, $class_name, $category, $class, $style, $orig_command));
10997        $line = '';
10998        push @$stack, { 'format' => 'deff_item', 'text' => '', 'only_inter_commands' => 1, 'format_ref' => $top_format, 'orig_command' => $orig_command};
10999        begin_paragraph_after_command($state, $stack, $macro, $line);
11000    }
11001    # FIXME $complex_format_map obsoleted in nov 2009
11002    elsif ((exists ($Texi2HTML::Config::complex_format_map->{$macro})
11003         or exists ($Texi2HTML::Config::complex_format_map{$macro}))
11004      and ($format_type{$macro} ne 'menu' or $Texi2HTML::Config::SIMPLE_MENU))
11005    { # handle menu if SIMPLE_MENU. see texi2html.init
11006        my $complex_format;
11007        if (exists ($Texi2HTML::Config::complex_format_map->{$macro}))
11008        {
11009            $complex_format = $Texi2HTML::Config::complex_format_map->{$macro};
11010        }
11011        else
11012        {
11013            $complex_format = $Texi2HTML::Config::complex_format_map{$macro};
11014        }
11015        my $format = { 'format' => $macro, 'text' => '', 'pre_style' => $complex_format->{'pre_style'} };
11016        push_complex_format_style($macro, $complex_format, $state, $line_nr);
11017        push @$stack, $format;
11018
11019        begin_paragraph($stack, $state);
11020    }
11021    elsif ($Texi2HTML::Config::paragraph_style{$macro})
11022    {
11023
11024        push (@$stack, { 'format' => $macro, 'text' => '' });
11025        begin_paragraph_after_command($state,$stack,$macro,$line) unless ($in_term);
11026        push @{$state->{'paragraph_style'}}, $macro;
11027        if ($macro eq 'center')
11028        {
11029            # @center may be in a weird state with regard with
11030            # nesting, so we put it on the bottom of the stack
11031            pop @{$state->{'command_stack'}};
11032            unshift @{$state->{'command_stack'}}, $macro;
11033            # for similar reasons, we may have a bad stack nesting
11034            # which results in } after a closing.
11035            # The following isn't really true anymore, I think: for example
11036            # @center @samp{something @center end of samp}
11037            # resulted to samp being kept in the 'command_stack'
11038
11039        }
11040    }
11041    elsif ($format_type{$macro} eq 'list' or $format_type{$macro} eq 'table' or $macro eq 'multitable')
11042    {
11043        my $format;
11044        #print STDERR "LIST_TABLE $macro\n";
11045        #dump_stack($text, $stack, $state);
11046        if ($macro eq 'itemize' or $format_type{$macro} eq 'table')
11047        {
11048            my $command;
11049            my $prepended;
11050            ($prepended, $command) = parse_format_command($line,$macro);
11051            if (($command eq '') and ($macro ne 'itemize'))
11052            {
11053                $command = 'asis';
11054                line_error(sprintf(__("%s requires an argument: the formatter for %citem"), $macro, ord('@')), $line_nr);
11055            }
11056            my $prepended_formatted;
11057            $prepended_formatted = substitute_line($prepended, sprintf(__("prepended for \@%s"), $macro), prepare_state_multiple_pass('item', $state)) if (defined($prepended));
11058            $format = { 'format' => $macro, 'text' => '', 'command' => $command, 'prepended' => $prepended, 'prepended_formatted' => $prepended_formatted };
11059            $line = '';
11060        }
11061        elsif ($macro eq 'enumerate')
11062        {
11063            my $spec;
11064            ($line, $spec) = parse_enumerate ($line);
11065            $spec = 1 if (!defined($spec));
11066            $format = { 'format' => $macro, 'text' => '', 'spec' => $spec };
11067        }
11068        elsif ($macro eq 'multitable')
11069        {
11070            my ($max_columns, $fractions, $prototype_row) = parse_multitable ($line, $line_nr);
11071            if (!$max_columns)
11072            {
11073                line_warn (__("empty multitable"), $line_nr);
11074                $max_columns = 0;
11075            }
11076            my @prototype_lengths = ();
11077            if (defined($prototype_row))
11078            {
11079                my $prototype_nr = 0;
11080                foreach my $prototype (@$prototype_row)
11081                {
11082                   $prototype_nr++;
11083                   push @prototype_lengths, 2+Texi2HTML::Config::t2h_default_string_width(substitute_line($prototype, sprintf(__("\@columnfraction (argument nr %d)"), $prototype_nr), prepare_state_multiple_pass('columnfractions', $state)));
11084                }
11085            }
11086            $format = { 'format' => $macro, 'text' => '', 'max_columns' => $max_columns, 'columnfractions' => $fractions, 'prototype_row' => $prototype_row, 'prototype_lengths' => \@prototype_lengths, 'cell' => 1 };
11087        }
11088        $format->{'first'} = 1;
11089        $format->{'item_nr'} = 0;
11090        $format->{'paragraph_number'} = 0;
11091        push @$stack, $format;
11092        if ($format_type{$macro} eq 'table')
11093        {
11094            push @$stack, { 'format' => 'line', 'text' => '', 'format_ref' => $format, 'only_inter_commands' => 1};
11095        }
11096        elsif ($macro eq 'multitable')
11097        {
11098            push @$stack, { 'format' => 'row', 'text' => '', 'format_ref' => $format, 'item_cmd' => $macro };
11099            push @$stack, { 'format' => 'cell', 'text' => '', 'format_ref' => $format, 'only_inter_commands' => 1};
11100        }
11101        if ($format_type{$macro} eq 'list')
11102        {
11103            push @$stack, { 'format' => 'item', 'text' => '', 'format_ref' => $format, 'only_inter_commands' => 1};
11104        }
11105        begin_paragraph_after_command($state,$stack,$macro,$line)
11106           if ($macro ne 'multitable');
11107        return '' unless ($macro eq 'enumerate');
11108    }
11109    elsif ($macro eq 'float' or $format_type{$macro} eq 'quotation')
11110    {
11111        push @$stack, {'format' => $macro, 'text' => '' };
11112        if ($macro eq 'float')
11113        {
11114
11115             my @args = parse_line_arguments($line, 2, "\@$macro");
11116             do_float_line ($macro, \@args, $state->{'style_stack'}, $state, $line_nr);
11117        }
11118        elsif ($format_type{$macro} eq 'quotation')
11119        {
11120             my @args = parse_line_arguments($line, 1, "\@$macro", $line_nr);
11121             do_quotation_line ($macro, $stack->[-1], \@args, $state->{'style_stack'}, $state, $line_nr);
11122
11123        }
11124
11125        $line = '';
11126        if ($state->{'preformatted'})
11127        { # inconditionally begin a preformatted section if needed
11128            begin_paragraph($stack, $state);
11129        }
11130        #dump_stack($text, $stack, $state);
11131    }
11132    # keep this one at the end as there are some other formats
11133    # which are also in format_map
11134    elsif (defined($Texi2HTML::Config::format_map{$macro}) or ($format_type{$macro} eq 'cartouche'))
11135    {
11136        push @$stack, { 'format' => $macro, 'text' => '' };
11137        $state->{'code_style'}++ if ($Texi2HTML::Config::format_code_style{$macro});
11138        begin_paragraph_after_command($state,$stack,$macro,$line);
11139    }
11140    elsif ($format_type{$macro} eq 'menu')
11141    {
11142        # if $Texi2HTML::Config::SIMPLE_MENU we won't get there
11143        # as the menu is a complex format in that case, so it
11144        # is handled above
11145        push @$stack, { 'format' => $macro, 'text' => '' };
11146        if ($state->{'preformatted'})
11147        {
11148        # add a fake complex style in order to have a given pre style
11149            push_complex_format_style('menu',
11150              $Texi2HTML::Config::MENU_PRE_COMPLEX_FORMAT, $state, $line_nr);
11151            begin_paragraph_after_command($state,$stack,$macro,$line);
11152        }
11153        else
11154        {
11155            begin_format($text, $stack, $state, 'menu_comment', $line, $line_nr);
11156        }
11157    }
11158    # this is useful for @center, and also if there was something on the
11159    # line after a format that isn't there anymore, like
11160    # @format   @c
11161    # if @center line is empty we don't remove the end of line
11162    $line =~ s/^\s*// unless ($macro eq 'center' and $line =~ /^\s*$/);
11163    return $line;
11164}
11165
11166sub do_text($;$)
11167{
11168    my $text = shift;
11169    my $state = shift;
11170    return $text if ($state->{'keep_texi'});
11171    my $remove_texi = 1 if ($state->{'remove_texi'} and !$state->{'simple_format'});
11172    my $preformatted_style = 0;
11173    if ($state->{'preformatted'})
11174    {
11175        $preformatted_style = $state->{'preformatted_stack'}->[-1]->{'style'};
11176    }
11177    return (&$Texi2HTML::Config::normal_text($text, $remove_texi, $preformatted_style, $state->{'code_style'}, $state->{'math_style'}, $state->{'simple_format'},$state->{'command_stack'}, $state));
11178}
11179
11180sub end_simple_format($$$)
11181{
11182    my $command = shift;
11183    my $text = shift;
11184    my $state = shift;
11185
11186    my $element = $Texi2HTML::Config::format_map{$command};
11187
11188    my $result = &$Texi2HTML::Config::format($command, $element, $text);
11189    $state->{'code_style'}-- if ($Texi2HTML::Config::format_code_style{$command});
11190    return $result;
11191}
11192
11193# only get there if not in SIMPLE_MENU and not in preformatted and
11194# right in @menu
11195sub close_menu_comment($$$$$)
11196{
11197    my $text = shift;
11198    my $stack = shift;
11199    my $state = shift;
11200    my $reason = shift;
11201    my $line_nr = shift;
11202
11203    my $top_format = top_stack($stack,2);
11204    if (defined($top_format->{'format'}) and $top_format->{'format'} eq 'menu_comment')
11205    { # this is needed to avoid empty menu-comments <tr>...<pre></pre>
11206        abort_empty_preformatted($stack, $state);
11207
11208        close_paragraph($text, $stack, $state, $reason, $line_nr);
11209        end_format($text, $stack, $state, 'menu_comment', $line_nr);
11210        return 1;
11211    }
11212}
11213
11214# never get there if in $SIMPLE_MENU
11215# the last arg is used only if in description and an empty line may
11216# stop it and begin a menu_comment
11217sub close_menu_description($$$$$;$)
11218{
11219    my $text = shift;
11220    my $stack = shift;
11221    my $state = shift;
11222    my $reason = shift;
11223    my $line_nr = shift;
11224    my $line = shift;
11225
11226    my $top_format = top_stack($stack,1);
11227    if (!$state->{'preformatted'})
11228    {
11229       $top_format = top_stack($stack);
11230    }
11231
11232    if (defined($top_format->{'format'}) and $top_format->{'format'} eq 'menu_description' and (!defined($line) or $line =~ /^\s*$/) )
11233    {
11234        close_paragraph($text, $stack, $state, $reason, $line_nr) if ($state->{'preformatted'});
11235        my $descr = pop(@$stack);
11236        add_prev($text, $stack, do_menu_description($descr, $state));
11237        print STDERR "# close_menu: close description\n" if ($T2H_DEBUG & $DEBUG_MENU);
11238        $state->{'code_style'}-- if ($Texi2HTML::Config::format_code_style{'menu_description'});
11239        return 1;
11240    }
11241}
11242
11243# Format menu link
11244# FIXME also pass node and name?
11245sub do_menu_link($$$)
11246{
11247    my $state = shift;
11248    my $line_nr = shift;
11249    my $menu_entry = shift;
11250
11251    my $file = $state->{'element'}->{'file'};
11252    my $node_name = normalise_node($menu_entry->{'node'});
11253    # normalise_node is used in fact to determine if name is empty.
11254    # It is not passed down to the function reference.
11255    my $name = normalise_node($menu_entry->{'name'});
11256
11257    # there is one substitution with spaces kept, and one with spaces
11258    # normalized. In every cases nodes are in code_style
11259    my $node_substitution_state = duplicate_formatting_state($state);
11260    my $name_substitution_state = duplicate_formatting_state($state);
11261    my $node_normalized_substitution_state = duplicate_formatting_state($state);
11262    $node_substitution_state->{'code_style'} = 1;
11263    $node_normalized_substitution_state->{'code_style'} = 1;
11264    $name_substitution_state->{'code_style'} = 1 if ($Texi2HTML::Config::format_code_style{'menu_name'});
11265    my $node_formatted = substitute_line($menu_entry->{'node'}, __("node name in menu"), $node_substitution_state, $line_nr);
11266    my $node_normalized_formatted = substitute_line($node_name, __("normalized node name in menu"), $node_normalized_substitution_state);
11267
11268    my $name_formatted;
11269    my $has_name = 0;
11270    if (defined($name) and $name ne '')
11271    {
11272        $name_formatted = substitute_line($menu_entry->{'name'}, __("menu entry name"), $name_substitution_state, $line_nr);
11273        $has_name = 1;
11274    }
11275    else
11276    {
11277        my $node_as_name = $menu_entry->{'node'};
11278        $node_as_name =~ s/^\s*//;
11279        $name_formatted = substitute_line($node_as_name, __("node name in menu"), $name_substitution_state);
11280    }
11281
11282    my $entry = '';
11283    my $href;
11284
11285    my $element;
11286    if ($state->{'direntry'})
11287    {
11288        $href = do_external_href($node_name);
11289    }
11290    else
11291    {
11292        $element = $nodes{$node_name};
11293    }
11294
11295    # menu points to an unknown node
11296    if (defined($element) and !$element->{'seen'})
11297    {
11298        if ($menu_entry->{'node'} =~ /^\s*\(.*\)/o or Texi2HTML::Config::get_conf('novalidate'))
11299        {
11300            # menu entry points to another info manual or invalid nodes
11301            # and novalidate is set
11302            #$href = $nodes{$node_name}->{'file'};
11303            $href = do_external_href($node_name);
11304        }
11305        else
11306        {
11307            line_error (sprintf(__("Menu reference to nonexistent node `%s'"), $node_name), $line_nr);
11308            # try to find an equivalent node
11309            my @equivalent_nodes = equivalent_nodes($node_name);
11310            my $node_seen;
11311            foreach my $equivalent_node (@equivalent_nodes)
11312            {
11313                if ($nodes{$equivalent_node}->{'seen'})
11314                {
11315                    $node_seen = $equivalent_node;
11316                    last;
11317                }
11318            }
11319            if (defined($node_seen))
11320            {
11321                document_warn("---> but equivalent node `$node_seen' found");
11322                $element = $nodes{$node_seen};
11323            }
11324        }
11325    }
11326
11327    # the original node or an equivalent node was seen
11328    if (defined($element) and $element->{'seen'})
11329    {
11330        if ($element->{'reference_element'})
11331        {
11332            $element = $element->{'reference_element'};
11333        }
11334
11335        #print STDERR "SUBHREF in menu for `$element->{'texi'}'\n";
11336        $href = href($element, $file, $line_nr);
11337        if (! $element->{'node'})
11338        {
11339            $entry = $element->{'text'}; # this is the section/node name
11340            $entry = "$Texi2HTML::Config::MENU_SYMBOL $entry" if (($entry ne '') and (!defined($element->{'number'}) or ($element->{'number'} =~ /^\s*$/)) and $Texi2HTML::Config::UNNUMBERED_SYMBOL_IN_MENU);
11341        }
11342    }
11343    # save the element used for the href for the description
11344    $menu_entry->{'menu_reference_element'} = $element;
11345
11346    return &$Texi2HTML::Config::menu_link($entry, $state, $href, $node_formatted, $name_formatted, $menu_entry->{'ending'}, $has_name, $state->{'command_stack'}, $state->{'preformatted'}, $node_normalized_formatted);
11347}
11348
11349sub do_menu_description($$)
11350{
11351    my $descr = shift;
11352    my $state = shift;
11353    my $text = $descr->{'text'};
11354    my $menu_entry = $descr->{'menu_entry'};
11355
11356    my $element = $menu_entry->{'menu_reference_element'};
11357
11358    ############# debug
11359    # this is not a bug if element is not defined in direntry
11360    print STDERR "Bug: !defined(element) in do_menu_description\n" if (!defined($element) and ($state->{'menu'} or $state->{'detailmenu'}));
11361    ############# end debug
11362    my $element_text = '';
11363    $element_text = $element->{'text_nonumber'} if (defined($element));
11364
11365    return &$Texi2HTML::Config::menu_description($text, duplicate_formatting_state($state),$element_text, $state->{'command_stack'}, $state->{'preformatted'});
11366}
11367
11368sub do_xref($$$$)
11369{
11370    my $macro = shift;
11371    my $args = shift;
11372    my $style_stack = shift;
11373    my $state = shift;
11374    my $line_nr = shift;
11375
11376    my $result = '';
11377    my @args = @$args;
11378
11379    my $j;
11380    for ($j = 0; $j <= $#$args; $j++)
11381    {
11382        $args[$j] = normalise_texi_space($args[$j]);
11383    #     print STDERR " ($j)$args[$j]\n";
11384    }
11385    #print STDERR "DO_XREF: $macro\n";
11386    if ($macro eq 'inforef')
11387    {
11388        if ((@args < 1) or $args[0] eq '')
11389        {
11390            line_error (sprintf(__("First argument to \@%s may not be empty"), $macro), $line_nr);
11391            return '';
11392        }
11393    }
11394
11395    my $node_texi = $args[0];
11396    $node_texi = normalise_node($node_texi);
11397
11398    #print STDERR "XREF: (@args)\n";
11399    my $i;
11400    my $new_state = duplicate_formatting_state($state);
11401    $new_state->{'keep_texi'} = 0;
11402    $new_state->{'keep_nr'} = 0;
11403
11404    my $remove_texi = $new_state->{'remove_texi'};
11405
11406    my @formatted_args;
11407    for ($i = 0; $i < 5; $i++)
11408    {
11409        $args[$i] = '' if (!defined($args[$i]));
11410        my $in_file_style;
11411        $in_file_style = 1 if ($i == 2 and $macro eq 'inforef' or $i == 3 and $macro ne 'inforef');
11412        $new_state->{'code_style'}++ if ($in_file_style or $i == 0);
11413        $new_state->{'remove_texi'} = 1 if ($in_file_style);
11414        $formatted_args[$i] = substitute_line($args[$i], sprintf(__("\@%s (argument nr %d)"), $macro, $i), $new_state, $line_nr);
11415        $new_state->{'code_style'}-- if ($in_file_style or $i == 0);
11416        $new_state->{'remove_texi'} = $remove_texi if ($in_file_style);
11417    }
11418
11419
11420    my ($file_texi, $file);
11421    if ($macro eq 'inforef')
11422    {
11423       $file_texi = $args[2];
11424       $file = $formatted_args[2];
11425    }
11426    else
11427    {
11428       $file_texi = $args[3];
11429       $file = $formatted_args[3];
11430    }
11431    # Remark: makeinfo has this odd error message if the file is empty:
11432    # warning (_("Empty file name for HTML cross reference in `%s'")
11433    # This seems to be spurious.
11434
11435    # can be an argument or extracted from the node name
11436    my $file_arg_or_node_texi = $file_texi;
11437    my $file_arg_or_node = $file;
11438
11439    my $node_name;
11440    # the file in parenthesis is removed from node_without_file_texi if needed
11441    my $node_without_file_texi = $node_texi;
11442    # node with file, like (file)node
11443    my $node_and_file_texi;
11444    # the file in parenthesis present with the node
11445    my ($file_of_node_texi, $file_of_node);
11446    if ($node_without_file_texi =~ s/^\(([^\)]+)\)\s*//)
11447    {
11448       $file_of_node_texi = $1;
11449       $file_of_node = substitute_line($file_of_node_texi, sprintf(__p("\@*ref", "\@%s node file"), $macro), $new_state);
11450       $node_name = substitute_line($node_without_file_texi, sprintf(__p("\@*ref", "\@%s node name"), $macro), $new_state);
11451       $file_arg_or_node_texi = $file_of_node_texi if ($file_arg_or_node_texi eq '');
11452       $file_arg_or_node = $file_of_node if ($file_arg_or_node eq '');
11453       # the file argument takes precedence
11454       $node_and_file_texi = "($file_arg_or_node_texi)$node_without_file_texi";
11455    }
11456    else
11457    {
11458        # normalized node name
11459        $new_state->{'code_style'}++;
11460        $node_name = substitute_line($node_without_file_texi, sprintf(__p("\@*ref", "\@%s node name"), $macro), $new_state);
11461        $new_state->{'code_style'}--;
11462        if (defined ($file_texi) and $file_texi ne '')
11463        {
11464            $node_and_file_texi = "($file_texi)$node_texi";
11465        }
11466    }
11467
11468    my $node_and_file;
11469    if (defined($node_and_file_texi))
11470    {
11471       $node_and_file = substitute_line($node_and_file_texi, sprintf(__p("\@*ref","\@%s node with file name"), $macro), $new_state);
11472    }
11473    else
11474    {
11475       $node_and_file_texi = $node_texi;
11476       $node_and_file = $node_name;
11477    }
11478
11479    my $cross_ref_texi = $args[1];
11480    my $cross_ref = $formatted_args[1];
11481
11482    my ($manual_texi, $section_texi, $manual, $section);
11483    if ($macro ne 'inforef')
11484    {
11485        $manual_texi = $args[4];
11486        $section_texi = $args[2];
11487        $manual = $formatted_args[4];
11488        $section = $formatted_args[2];
11489    }
11490    else
11491    {
11492        $manual = $section = '';
11493    }
11494
11495    #print STDERR "XREF: (@args)\n";
11496
11497    if (($macro eq 'inforef') or ($file_arg_or_node_texi ne '') or ($manual_texi ne ''))
11498    {# external ref
11499        my $href = '';
11500        if ($file_arg_or_node_texi ne '')
11501        {
11502            $href = do_external_href($node_and_file_texi);
11503        }
11504        else
11505        {
11506            $node_and_file = '';
11507        }
11508        #my $section_or_node = '';
11509        #if ($manual ne '')
11510        #{
11511        #    $section_or_node = $node_name;
11512        #    if ($section ne '')
11513        #    {
11514        #        $section_or_node = $section;
11515        #    }
11516        #}
11517        #$result = &$Texi2HTML::Config::external_ref($macro, $section_or_node, $manual, $node_and_file, $href, $cross_ref, \@args, \@formatted_args);
11518        $result = &$Texi2HTML::Config::external_ref($macro, $section, $manual, $file_arg_or_node, $href, $cross_ref, \@args, \@formatted_args, $node_name);
11519    }
11520    else
11521    {
11522        my $element = $nodes{$node_without_file_texi};
11523        if ($element and $element->{'seen'})
11524        {
11525            if ($element->{'reference_element'})
11526            {
11527                $element = $element->{'reference_element'};
11528            }
11529            my $file = '';
11530            if (defined($state->{'element'}))
11531            {
11532                $file = $state->{'element'}->{'file'};
11533            }
11534            else
11535            {
11536                line_warn (sprintf(__("\@%s not in text (in anchor, node, section...)"), $macro), $line_nr);
11537                # if Texi2HTML::Config::SPLIT the file is '' which ensures
11538                # a href with the file name. if ! Texi2HTML::Config::SPLIT
11539                # the 2 file will be the same thus there won't be the file name
11540                $file = $element->{'file'} unless (Texi2HTML::Config::get_conf('SPLIT'));
11541            }
11542	    #print STDERR "SUBHREF in ref to node `$node_texi'";
11543            my $href = href($element, $file, $line_nr);
11544            my $section_or_cross_ref = $section;
11545            $section_or_cross_ref = $cross_ref if ($section eq '');
11546            if ($element->{'float'} and $section_or_cross_ref eq '')
11547            {
11548                my $style = substitute_line(&$Texi2HTML::Config::listoffloats_float_style($element->{'style_texi'}, $element), __("\@listoffloats \@float type"));
11549                $section_or_cross_ref = $style if (defined($style));
11550            }
11551            my $name = $section_or_cross_ref;
11552            my $short_name = $section_or_cross_ref;
11553            if ($section_or_cross_ref eq '')
11554            {
11555                # FIXME maybe one should use 'text' instead of 'text_nonumber'
11556                # However the real fix would be to have an internal_ref call
11557                # with more informations
11558                $name = $element->{'text_nonumber'};
11559                $short_name = $node_name;
11560            }
11561            $result = &$Texi2HTML::Config::internal_ref ($macro, $href, $short_name, $name, $element->{'section'}, \@args, \@formatted_args, $element);
11562        }
11563        else
11564        {
11565           if (($node_texi eq '') or (! Texi2HTML::Config::get_conf('novalidate')))
11566           {
11567               line_error (sprintf(__("\@%s reference to nonexistent node `%s'"), $macro, $node_texi), $line_nr);
11568               my $text = '';
11569               for (my $i = 0; $i < @$args -1; $i++)
11570               {
11571                    $text .= $args->[$i] .',';
11572               }
11573               $text .= $args->[-1];
11574               $result = "\@$macro"."{${text}}";
11575           }
11576           else
11577           {
11578               #$result = &$Texi2HTML::Config::external_ref($macro, '', '', $node_name, do_external_href($node_texi), $cross_ref, \@args, \@formatted_args);
11579               $result = &$Texi2HTML::Config::external_ref($macro, '', '', '', do_external_href($node_texi), $cross_ref, \@args, \@formatted_args, $node_name);
11580           }
11581        }
11582    }
11583    return $result;
11584}
11585
11586sub do_acronym_like($$$$$)
11587{
11588    my $command = shift;
11589    my $args = shift;
11590    my $acronym_texi = shift @$args;
11591    my $explanation = shift @$args;
11592    my $style_stack = shift;
11593    my $state = shift;
11594    my $line_nr = shift;
11595
11596    my $explanation_lines;
11597    my $explanation_text;
11598    my $explanation_simple_format;
11599
11600    if (defined($explanation))
11601    {
11602        $explanation = trim_around_spaces($explanation);
11603        $explanation = undef if ($explanation eq '');
11604    }
11605    $acronym_texi = trim_around_spaces($acronym_texi);
11606
11607    return '' if ($acronym_texi eq '');
11608
11609    my $with_explanation = 0;
11610    my $normalized_text =  cross_manual_line(normalise_node($acronym_texi));
11611    if (defined($explanation))
11612    {
11613        $with_explanation = 1;
11614        $acronyms_like{$command}->{$normalized_text} = $explanation;
11615    }
11616    elsif (exists($acronyms_like{$command}->{$normalized_text}))
11617    {
11618        $explanation = $acronyms_like{$command}->{$normalized_text};
11619    }
11620
11621    if (defined($explanation))
11622    {
11623         @$explanation_lines = map {$_ = $_."\n"} split (/\n/, $explanation);
11624         my $text = '';
11625         foreach my $line(@$explanation_lines)
11626         {
11627              $line .= ' ' if (chomp ($line));
11628              $text .= $line
11629         }
11630         $text =~ s/ $//;
11631         $explanation_simple_format = simple_format($state, [ $line_nr ], "simple_format \@$command explanation", $text);
11632         $explanation_text = substitute_line($text, sprintf(__p("\@abbr or \@acronym", "\@%s explanation"), $command), duplicate_formatting_state($state), $line_nr);
11633    }
11634    return &$Texi2HTML::Config::acronym_like($command, $acronym_texi, substitute_line($acronym_texi, "\@$command", duplicate_formatting_state($state), $line_nr),
11635       $with_explanation, $explanation_lines, $explanation_text, $explanation_simple_format);
11636}
11637
11638sub do_caption_shortcaption($$$$$$)
11639{
11640    my $command = shift;
11641    my $args = shift;
11642    my $text_texi = $args->[0];
11643    my $style_stack = shift;
11644    my $state = shift;
11645    my $line_nr = shift;
11646    my $kept_line_nrs = shift;
11647
11648    if (!exists($state->{'float'}))
11649    {
11650         line_error(sprintf(__("\@%s not meaningful outside `\@float' environment"), $command), $line_nr);
11651         return '';
11652    }
11653    my $float = $state->{'float'};
11654    my @texi_lines = map {$_ = $_."\n"} split (/\n/, $text_texi);
11655    $float->{"${command}_texi"} = \@texi_lines;
11656    if (defined($kept_line_nrs))
11657    {
11658       $float->{"${command}_keep_line_nr"} = [ @$kept_line_nrs ];
11659       msg_debug ("Empty $kept_line_nrs", $line_nr) unless (@{$kept_line_nrs});
11660    }
11661    else
11662    {
11663        $float->{"${command}_keep_line_nr"} = [ $line_nr ];
11664        msg_debug("do_caption_shortcaption $command, $float, kept_line_nrs not defined", $line_nr);
11665    }
11666    #print STDERR "GGGGGGG @$kept_line_nrs\n";
11667    return  &$Texi2HTML::Config::caption_shortcaption_command($command,
11668       substitute_text(prepare_state_multiple_pass($command, $state), $kept_line_nrs, "\@$command in do_caption_shortcaption", @texi_lines), \@texi_lines, $float);
11669}
11670
11671# function called when a @float is encountered. Don't do any output
11672# but prepare $state->{'float'}
11673sub do_float_line($$$$$)
11674{
11675    my $command = shift;
11676    my $args = shift;
11677    my $style_stack = shift;
11678    my $state = shift;
11679    my $line_nr = shift;
11680
11681    my @args = @$args;
11682    my $style_texi = shift @args;
11683    my $label_texi = shift @args;
11684
11685    $style_texi = undef if (defined($style_texi) and $style_texi=~/^\s*$/);
11686    $label_texi = undef if (defined($label_texi) and $label_texi=~/^\s*$/);
11687
11688    $style_texi = normalise_texi_space($style_texi) if (defined($style_texi));
11689
11690    if (defined($label_texi))
11691    { # the float is considered as a node as it may be a target for refs.
11692      # it was entered as a node in the pass_structure and the float
11693      # line was parsed at that time
11694         $state->{'float'} = $nodes{normalise_node($label_texi)};
11695         #msg_debug("float: $state->{'float'}, $state->{'float'}->{'texi'}", $line_nr);
11696    }
11697    else
11698    { # a float without label. It can't be the target for refs.
11699         $state->{'float'} = { 'float' => 1 };
11700         if (defined($style_texi))
11701         {
11702              $state->{'float'}->{'style_texi'} = $style_texi;
11703              $state->{'float'}->{'style_id'} =
11704                  cross_manual_line($state->{'float'}->{'style_texi'});
11705         }
11706         #print STDERR "float: (no label) $state->{'float'}\n";
11707    }
11708    $state->{'float'}->{'style'} = substitute_line($state->{'float'}->{'style_texi'}, __("\@float style"), undef, $line_nr);
11709    return '';
11710}
11711
11712sub do_quotation_line($$$$$$)
11713{
11714    my $command = shift;
11715    my $format_ref = shift;
11716    my $args = shift;
11717    my @args = @$args;
11718    my $text_texi = shift @args;
11719    my $style_stack = shift;
11720    my $state = shift;
11721    my $line_nr = shift;
11722    my $text;
11723
11724    $text_texi = undef if (defined($text_texi) and $text_texi=~ /^\s*$/);
11725    if (defined($text_texi))
11726    {
11727         $text_texi = trim_around_spaces($text_texi);
11728         $text = substitute_line($text_texi, sprintf(__p("\@*quotation", "\@%s argument"), $command), duplicate_formatting_state($state), $line_nr);
11729         #$text =~ s/\s*$//;
11730    }
11731    my $quotation_args = { 'text' => $text, 'text_texi' => $text_texi };
11732    push @{$state->{'quotation_stack'}}, $quotation_args;
11733    $format_ref->{'argument_text'} = $text;
11734    $format_ref->{'argument_texi'} = $text_texi;
11735    $state->{'prepend_text'} = &$Texi2HTML::Config::quotation_prepend_text($command, $text_texi);
11736    return '';
11737}
11738
11739sub do_footnote($$$$$$)
11740{
11741    my $command = shift;
11742    my $args = shift;
11743    my $text = $args->[0];
11744    my $style_stack = shift;
11745    my $doc_state = shift;
11746    my $line_nr = shift;
11747    my $kept_line_nrs = shift;
11748
11749    $text .= "\n";
11750    $text = &$Texi2HTML::Config::footnote_texi($text, $doc_state, $style_stack)
11751        if (defined($Texi2HTML::Config::footnote_texi));
11752
11753    my $foot_state = duplicate_state($doc_state);
11754    fill_state($foot_state);
11755    push @{$foot_state->{'command_stack'}}, 'footnote';
11756
11757    push_state($foot_state);
11758
11759    my ($foot_num, $relative_foot_num);
11760    my $special_place;
11761    if (!defined($foot_state->{'expansion'}) and !defined($foot_state->{'region'}))
11762    {
11763        $foot_num = \$global_foot_num;
11764        $relative_foot_num = \$global_relative_foot_num;
11765    }
11766    else
11767    {
11768        $special_place = $foot_state->{'expansion'};
11769        $special_place = $foot_state->{'region'} if (!defined($special_place));
11770        $foot_num = \$doc_state->{'foot_num'};
11771        $relative_foot_num = \$doc_state->{'relative_foot_num'};
11772    }
11773    $$foot_num++;
11774    $$relative_foot_num++;
11775
11776    my $docid  = "DOCF$$foot_num";
11777    my $footid = "FOOT$$foot_num";
11778    if (defined($special_place))
11779    {
11780        $docid = $target_prefix . $special_place . "_$docid";
11781        $footid = $target_prefix . $special_place . "_$footid";
11782    }
11783    my $from_file = $docu_doc;
11784    if ($doc_state->{'element'})
11785    {
11786        $from_file = $doc_state->{'element'}->{'file'};
11787    }
11788
11789    if (Texi2HTML::Config::get_conf('footnotestyle') eq 'separate')
11790    {
11791        $foot_state->{'element'} = $footnote_element;
11792    }
11793
11794    $foot_state->{'footnote_number_in_doc'} = $$foot_num;
11795    $foot_state->{'footnote_number_in_page'} = $$relative_foot_num;
11796    $foot_state->{'footnote_footnote_id'} = $footid;
11797    $foot_state->{'footnote_place_id'} = $docid;
11798    $foot_state->{'footnote_document_file'} = $from_file;
11799    $foot_state->{'footnote_footnote_file'} = $foot_state->{'element'}->{'file'};
11800    $foot_state->{'footnote_document_state'} = $doc_state;
11801
11802    # FIXME use split_lines ? It seems to work like it is now ?
11803    msg_debug ("No line nnumbers in footnote", $line_nr) if (!defined($kept_line_nrs) or !@$kept_line_nrs);
11804    my @lines;
11805    if (defined($text))
11806    {
11807        @lines = substitute_text($foot_state, $kept_line_nrs, '@footnote', map {$_ = $_."\n"} split (/\n/, $text));
11808    }
11809    my ($foot_lines, $foot_label) = &$Texi2HTML::Config::foot_line_and_ref($$foot_num,
11810         $$relative_foot_num, $footid, $docid, $from_file, $foot_state->{'element'}->{'file'}, \@lines, $doc_state);
11811    if ($doc_state->{'outside_document'} or (defined($doc_state->{'multiple_pass'}) and $doc_state->{'multiple_pass'} > 0))
11812    {
11813#print STDERR "multiple_pass $doc_state->{'multiple_pass'}, 'outside_document' $doc_state->{'outside_document'}\n";
11814#print STDERR "REGION FOOTNOTE($$foot_num): $doc_state->{'region'} ($doc_state->{'region_pass'})\n";
11815        $region_initial_state{$doc_state->{'region'}}->{'footnotes'}->{$$foot_num}->{$doc_state->{'region_pass'}} = $foot_lines if (defined($doc_state->{'region'}));
11816    }
11817    else
11818    {
11819#print STDERR "GLOBAL FOOTNOTE($$foot_num)\n";
11820         push(@foot_lines, @{$foot_lines});
11821    }
11822    pop_state();
11823    return $foot_label;
11824}
11825
11826sub do_image($$$$$)
11827{
11828    # replace images
11829    my $command = shift;
11830    my $args = shift;
11831    my $style_stack = shift;
11832    my $state = shift;
11833    my $line_nr = shift;
11834    my @args;
11835    foreach my $arg (@$args)
11836    {
11837       $arg = trim_around_spaces($arg) if (defined($arg));
11838       push @args, $arg;
11839    }
11840    my $base = substitute_line($args[0], __("\@image base name"),{'code_style' => 1, 'remove_texi' => 1});
11841    my $base_simple = substitute_line($args[0], __("\@image base name"), {'simple_format' => 1, 'code_style' => 1});
11842    if ($base eq '')
11843    {
11844         line_error ("\@image missing filename argument", $line_nr);
11845         return '';
11846    }
11847    $args[4] = '' if (!defined($args[4]));
11848    $args[3] = '' if (!defined($args[3]));
11849    my $image;
11850    my $extension = substitute_line($args[4], __("\@image extension"), {'code_style' => 1, 'remove_texi' => 1});
11851    my $extension_simple = substitute_line($args[4], __("\@image extension"), {'simple_format' => 1, 'code_style' => 1});
11852    my ($file_name, $image_name, $simple_file_name);
11853    my @file_locations;
11854    my @file_names = &$Texi2HTML::Config::image_files($base,$extension,$args[0],$args[4]);
11855#    $image = locate_include_file("$base.$args[4]") if ($args[4] ne '');
11856    foreach my $file (@file_names)
11857    {
11858        my $simple_file = substitute_line($file->[1], __("\@image file name"), {'simple_format' => 1, 'code_style' => 1});
11859        if ($image = locate_include_file($file->[0]))
11860        {
11861            if (!defined($file_name))
11862            {
11863                $file_name = $file->[0];
11864                $image_name = $image;
11865                $simple_file_name = $simple_file;
11866            }
11867            push @file_locations, [$file, $image, $simple_file];
11868        }
11869        else
11870        {
11871            push @file_locations, [$file, undef, $simple_file];
11872        }
11873    }
11874    $image_name = '' if (!defined($image_name));
11875    $simple_file_name = '' if (!defined($simple_file_name));
11876
11877    my $alt;
11878    if ($args[3] =~ /\S/)
11879    {
11880        $alt = substitute_line($args[3], __("\@image alt text"), {'simple_format' => 1}, $line_nr);
11881    }
11882    return &$Texi2HTML::Config::image($path_to_working_dir . $image_name,
11883        $base,
11884        $state->{'preformatted'}, $file_name, $alt, $args[1], $args[2],
11885        $args[3], $extension, $path_to_working_dir, $image_name,
11886        $state->{'paragraph_context'}, \@file_locations, $base_simple,
11887        $extension_simple, $simple_file_name, $line_nr);
11888}
11889
11890# usefull if we want to duplicate only the global state, nothing related with
11891# formatting
11892sub duplicate_state($)
11893{
11894    my $state = shift;
11895    my $new_state = { 'element' => $state->{'element'},
11896         'multiple_pass' => $state->{'multiple_pass'},
11897         'region_pass' => $state->{'region_pass'},
11898         'region' => $state->{'region'},
11899         'expansion' => $state->{'expansion'},
11900         'sec_num' => $state->{'sec_num'},
11901         'outside_document' => $state->{'outside_document'},
11902         'inside_document' => $state->{'inside_document'},
11903         'duplicated' => 1
11904    };
11905    return $new_state;
11906}
11907
11908# duplicate global and formatting state.
11909sub duplicate_formatting_state($)
11910{
11911    my $state = shift;
11912    my $new_state = duplicate_state($state);
11913
11914    # Things passed here should be things that are not emptied/set to 0 by
11915    # any command. Also they shouldn't need anything to be on the
11916    # stack. This rules out paragraphs, for example.
11917    foreach my $format_key ('preformatted', 'code_style', 'keep_texi',
11918          'keep_nr', 'preformatted_stack')
11919    {
11920        $new_state->{$format_key} = $state->{$format_key};
11921    }
11922# this is needed for preformatted
11923    my $command_stack = $state->{'command_stack'};
11924    $command_stack = [] if (!defined($command_stack));
11925    $new_state->{'command_stack'} = [ @$command_stack ];
11926    $new_state->{'preformatted_context'} = {'stack_at_beginning' => [ @$command_stack ]};
11927    $new_state->{'code_style'} = 0 if (!defined($new_state->{'code_style'}));
11928    return $new_state;
11929}
11930
11931sub expand_macro($$$$$)
11932{
11933    my $name = shift;
11934    my $args = shift;
11935    my $end_line = shift;
11936    my $line_nr = shift;
11937    my $state = shift;
11938
11939    # we dont expand macros when in ignored environment.
11940    return if ($state->{'ignored'});
11941
11942    die "Bug end_line not defined" if (!defined($end_line));
11943
11944    my $index = 0;
11945    foreach my $arg (@$args)
11946    { # expand @macros in arguments. It is complicated because we must be
11947      # carefull not to expand macros in @ignore section or the like, and
11948      # still keep every single piece of text (including the @ignore macros).
11949        $args->[$index] = substitute_text({'texi' => 1, 'arg_expansion' => 1}, undef, "expand_macro in $name", split_lines($arg));
11950        $index++;
11951    }
11952    # retrieve the macro definition
11953    my $macrobody = $macros->{$name}->{'body'};
11954    my $formal_args = $macros->{$name}->{'args'};
11955    my $args_index =  $macros->{$name}->{'args_index'};
11956
11957    my $i;
11958    for ($i=0; $i<=$#$formal_args; $i++)
11959    {
11960        $args->[$i] = "" unless (defined($args->[$i]));
11961        print STDERR "# arg($i): $args->[$i]\n" if ($T2H_DEBUG & $DEBUG_MACROS);
11962    }
11963    line_error (sprintf(__("Macro `%s' called with too many args"), $name), $line_nr) if (defined($args->[$i + 1]));
11964    my $result = '';
11965    while ($macrobody ne '')
11966    {
11967        if ($macrobody =~ s/^([^\\]*)\\//o)
11968        {
11969            $result .= $1 if defined($1);
11970            if ($macrobody =~ s/^\\//)
11971            {
11972                $result .= '\\';
11973            }
11974            elsif ($macrobody =~ s/^(\@end\sr?macro)$// or $macrobody =~ s/^(\@end\sr?macro\s)// or $macrobody =~ s/^(\@r?macro\s+\w+\s*.*)//)
11975            { # \ protect @end macro
11976                $result .= $1;
11977            }
11978            elsif ($macrobody =~ s/^([^\\]*)\\//)
11979            {
11980               my $arg = $1;
11981               if (defined($args_index->{$arg}))
11982               {
11983                   $result .= $args->[$args_index->{$arg}];
11984               }
11985               else
11986               {
11987                   line_error (sprintf(__("\\ in macro expansion followed `%s' instead of parameter name or \\"), $arg), $macros->{$name}->{'line_nr'});
11988                   $result .= '\\' . $arg;
11989               }
11990            }
11991            next;
11992        }
11993        $result .= $macrobody;
11994        last;
11995    }
11996    my @result = split(/^/m, $result);
11997    # for a completly empty macro, $result = '', and the split leads
11998    # to an empty array, so add back an empty string
11999    @result = ('') if (!scalar(@result));
12000    # Add the result of the macro expansion back to the input_spool.
12001    # Set the macro name if in the outer macro
12002    if ($state->{'arg_expansion'})
12003    { # in that case we are in substitute_text for an arg
12004        unshift @{$state->{'spool'}}, (@result, $end_line);
12005    }
12006    else
12007    {
12008        #$result[-1].=$end_line;
12009#foreach my $res (@result)
12010#{
12011#   print STDERR "RESULT:$res";
12012#}
12013#print STDERR "#########end->$end_line";
12014        my $last_line = $result[-1];
12015        if (chomp($last_line))
12016        {
12017            push @result, $end_line;
12018        }
12019        else
12020        {
12021            $result[-1] .= $end_line;
12022        }
12023        unshift @{$state->{'input_spool'}->{'spool'}}, (@result); #, $end_line);
12024        $state->{'input_spool'}->{'macro'} = $name if ($state->{'input_spool'}->{'macro'} eq '');
12025    }
12026    if ($T2H_DEBUG & $DEBUG_MACROS)
12027    {
12028        print STDERR "# macro expansion result:\n";
12029        #print STDERR "$first_line";
12030        foreach my $line (@result)
12031        {
12032            print STDERR "$line";
12033        }
12034        print STDERR "# macro expansion result end\n";
12035    }
12036}
12037
12038sub do_index_summary_file($$)
12039{
12040    my $name = shift;
12041    my $docu_name = shift;
12042    &$Texi2HTML::Config::index_summary_file_begin ($name, $printed_indices{$name}, $docu_name);
12043    print STDERR "# writing $name index summary for $docu_name\n" if $T2H_VERBOSE;
12044
12045    foreach my $letter_entries (@{$Texi2HTML::THISDOC{'index_letters_array'}->{$name}})
12046    {
12047      foreach my $entry (@{$letter_entries->{'entries'}})
12048      {
12049        #my $entry = $entries->{$key};
12050        my $indexed_element = $entry->{'element'};
12051        my $entry_element = $indexed_element;
12052        $entry_element = $entry_element->{'element_ref'} if (defined($entry_element->{'element_ref'}));
12053        my $origin_href = $entry->{'file'};
12054   #print STDERR "$entry $entry->{'entry'}, real elem $indexed_element->{'texi'}, section $entry_element->{'texi'}, real $indexed_element->{'file'}, entry file $entry->{'file'}\n";
12055        if ($entry->{'target'})
12056        {
12057             $origin_href .= '#' . $entry->{'target'};
12058        }
12059        else
12060        {
12061            $origin_href .= '#' . $indexed_element->{'target'};
12062        }
12063        &$Texi2HTML::Config::index_summary_file_entry ($name,
12064          $entry->{'key'}, $origin_href,
12065          substitute_line($entry->{'entry'}, "\@$entry->{'command'}"), $entry->{'entry'},
12066          href($entry_element, ''),
12067          $entry_element->{'text'},
12068          $printed_indices{$name},
12069          $docu_name);
12070       }
12071    }
12072    &$Texi2HTML::Config::index_summary_file_end ($name, $printed_indices{$name}, $docu_name);
12073}
12074
12075sub get_index_entry_infos($$;$)
12076{
12077    my $entry = shift;
12078    my $element = shift;
12079    my $line_nr = shift;
12080    my $index_heading_element = $entry->{'element'};
12081    my $entry_heading_element = $index_heading_element;
12082    my $real_index_element = $entry->{'real_element'};
12083
12084    if (!defined($entry->{'real_element'}))
12085    {
12086        print STDERR "BUG: entry->{'real_element'} not defined\n";
12087    }
12088    # we always use the associated element_ref, instead of the original
12089    # element
12090    $entry_heading_element = $entry_heading_element->{'element_ref'}
12091        if (defined($entry_heading_element->{'element_ref'}));
12092    if ($entry->{'real_element'} eq $element_before_anything)
12093    {
12094       $real_index_element = $element_top;
12095    }
12096    else
12097    {
12098       $real_index_element = $entry->{'real_element'}->{'element_ref'};
12099       if (!defined($real_index_element))
12100       { # happens when $USE_NODES = 0 and there are only sections,
12101         # and vice-versa
12102          $real_index_element = $entry->{'real_element'};
12103       }
12104    }
12105
12106    my $origin_href = '';
12107    print STDERR "BUG: entry->{'file'} not defined for `$entry->{'entry'}'\n"
12108       if (!defined($entry->{'file'}));
12109    print STDERR "BUG: element->{'file'} not defined for `$entry->{'entry'}', `$element->{'texi'}'\n"
12110       if (!defined($element->{'file'}));
12111    $origin_href = $entry->{'file'} if ($entry->{'file'} ne $element->{'file'});
12112#print STDERR "$entry $entry->{'entry'}, real heading elem $index_heading_element->{'texi'}, section $entry_element->{'texi'}, real $index_heading_element->{'file'}, entry file $entry->{'file'}\n";
12113    if (defined($entry->{'target'}))
12114    {
12115         $origin_href .= '#' . $entry->{'target'};
12116    }
12117    else
12118    { # this means that the index entry is in a special region like @copying...
12119         $origin_href .= '#' . $index_heading_element->{'target'};
12120    }
12121   #print STDERR "SUBHREF in index entry `$entry->{'entry'}' for `$entry_element->{'texi'}'\n";
12122    return ($origin_href,
12123            $entry->{'file'},
12124            $element->{'file'},
12125            $entry->{'target'},
12126            $index_heading_element->{'target'},
12127            substitute_line($entry->{'entry'}, "\@$entry->{'command'} index infos"),
12128            href($entry_heading_element, $element->{'file'}, $line_nr),
12129            $entry_heading_element->{'text'},
12130            (!$entry->{'seen_in_output'} and defined($entry->{'region'})));
12131}
12132
12133# remove texi commands, replacing with what seems adequate. see simple_map_texi
12134# and texi_map.
12135# Doesn't protect html
12136sub remove_texi(@)
12137{
12138    return substitute_text ({ 'remove_texi' => 1}, undef, undef, @_);
12139}
12140
12141# Same as remove texi but protect text and use special maps for @-commands
12142sub simple_format($$$@)
12143{
12144    my $state = shift;
12145    my $line_nrs = shift;
12146    my $context = shift;
12147    if (!defined($state))
12148    {
12149        $state = {};
12150    }
12151    else
12152    {
12153        $state = duplicate_formatting_state($state);
12154    }
12155    $state->{'remove_texi'} = 1;
12156    $state->{'simple_format'} = 1;
12157    $::simple_map_texi_ref = \%Texi2HTML::Config::simple_format_simple_map_texi;
12158    $::style_map_texi_ref = \%Texi2HTML::Config::simple_format_style_map_texi;
12159    $::texi_map_ref = \%Texi2HTML::Config::simple_format_texi_map;
12160    my $text = substitute_text($state, $line_nrs, $context, @_);
12161    $::simple_map_texi_ref = \%Texi2HTML::Config::simple_map_texi;
12162    $::style_map_texi_ref = \%Texi2HTML::Config::style_map_texi;
12163    $::texi_map_ref = \%Texi2HTML::Config::texi_map;
12164    return $text;
12165}
12166
12167sub index_entry_command_prefix($$$)
12168{
12169    my $command = shift;
12170    my $line = shift;
12171    my $line_nr = shift;
12172    if ($command =~ /^(v|f)table$/)
12173    {
12174       return $1;
12175    }
12176    elsif (defined($Texi2HTML::Config::def_map{$command}))
12177    {
12178       my ($prefix, $entry, $argument) = get_deff_index($command, $line, undef, 0);
12179       return $prefix;
12180    }
12181    my $prefix = index_command_prefix($command);
12182    line_error(sprintf(__("No index prefix found for \@%s"),$command),$line_nr) if ($prefix eq '');
12183    return $prefix;
12184}
12185
12186sub enter_table_index_entry($$$$)
12187{
12188    my $text = shift;
12189    my $stack = shift;
12190    my $state = shift;
12191    my $line_nr = shift;
12192    if ($state->{'item'})
12193    {
12194         my $item_command = $state->{'item'};
12195         delete $state->{'item'};
12196         my $item = pop @$stack;
12197         if ($state->{'table_stack'}->[-1] =~ /^(v|f)table$/)
12198         {
12199             my $index = $1;
12200             enter_index_entry($index, $line_nr,
12201               $item->{'text'}, $state->{'table_stack'}->[-1], $state);
12202         }
12203         add_prev($text, $stack, "\@$item_command" . $item->{'text'});
12204    }
12205}
12206
12207sub end_macro($$$)
12208{
12209    my $state = shift;
12210    my $end_string = shift;
12211    my $remaining_on_the_line = shift;
12212
12213    $state->{'macro_inside'}--;
12214    return (0, undef) if ($state->{'ignored'});
12215    if ($state->{'macro_inside'})
12216    {
12217        $state->{'macro'}->{'body'} .= $end_string;
12218        return (0, undef);
12219    }
12220    my $macro_text = $state->{'macro'}->{'header'} . $state->{'macro'}->{'body'}.$end_string;
12221    chomp $state->{'macro'}->{'body'};
12222    print STDERR "# end macro def. Body:\n$state->{'macro'}->{'body'}"
12223      if ($T2H_DEBUG & $DEBUG_MACROS);
12224    $macros->{$state->{'macro'}->{'name'}} = $state->{'macro'} unless ($state->{'arg_expansion'});
12225    delete $state->{'macro'};
12226    return (1, $macro_text.$remaining_on_the_line) if ($remaining_on_the_line =~ /^\s*$/);
12227    return (0, $macro_text);
12228}
12229
12230sub close_macro_arg($$$)
12231{
12232   my $state = shift;
12233   my $current_line = shift;
12234   my $line_nr = shift;
12235
12236   # balanced } ends the macro call, otherwise it is in the arg
12237   $state->{'macro_depth'}--;
12238   if ($state->{'macro_depth'} == 0)
12239   {
12240#print STDERR "BEFORE: $current_line";
12241      print STDERR "# expanding macro $state->{'macro_name'}\n" if ($T2H_DEBUG & $DEBUG_MACROS);
12242      #$current_line =
12243      expand_macro($state->{'macro_name'}, $state->{'macro_args'}, $current_line, $line_nr, $state);
12244      delete $state->{'macro_name'};
12245      delete $state->{'macro_depth'};
12246      delete $state->{'macro_args'};
12247#print STDERR "AFTER: $current_line";
12248      #return $current_line;
12249      return 1;
12250   }
12251   else
12252   {
12253       print STDERR "# macro call: closing }\n" if ($T2H_DEBUG & $DEBUG_MACROS);
12254       add_text('}', \$state->{'macro_args'}->[-1]);
12255       return undef;
12256   }
12257}
12258
12259sub close_style_texi($$$$;$)
12260{
12261    my $style = shift;
12262    my $text = shift;
12263    my $stack = shift;
12264    my $state = shift;
12265    my $no_close = shift;
12266
12267    $no_close = 0 if (!defined($no_close));
12268
12269    my $result;
12270    if (!defined($style->{'style'}))
12271    {
12272        msg_debug("'style' not defined in close_style_texi ($no_close)");
12273        foreach my $key (keys(%$style))
12274        {
12275            print STDERR "  --> $key: ".var_to_str($style->{$key})."\n";
12276        }
12277    }
12278
12279    if (($style->{'style'} ne '') and exists($info_enclose{$style->{'style'}}) and !$state->{'arg_expansion'})
12280    {
12281        $result = $info_enclose{$style->{'style'}}->[0] . $style->{'text'} . $info_enclose{$style->{'style'}}->[1];
12282    }
12283    elsif ($style->{'style'} ne '')
12284    {
12285        $result = '@' . $style->{'style'} . '{' . $style->{'text'};
12286        $result .= '}' unless ($no_close);
12287    }
12288    else
12289    {
12290        $result = '{' . $style->{'text'};
12291        # don't close { if we are closing stack as we are not
12292        # sure this is a { ... } construct. i.e. we are
12293        # not sure that the user properly closed the matching
12294        # brace, so we don't close it ourselves
12295        $result .= '}' unless ($no_close or $state->{'arg_expansion'});
12296    }
12297    if ($state->{'ignored'})
12298    {# ARG_EXPANSION
12299        print STDERR "# Popped `$style->{'style'}' in ifset/ifclear\n" if ($T2H_DEBUG);
12300    }
12301    else
12302    {
12303        add_prev ($text, $stack, $result);
12304    }
12305}
12306
12307sub close_ignored ($$)
12308{
12309    my $state = shift;
12310    my $stack = shift;
12311    if (($state->{'ifvalue_inside'}) and $state->{'ignored'} eq $state->{'ifvalue'})
12312    {
12313        if ($state->{'ifvalue_inside'} == 1)
12314        {# closing still opened @-commands with braces
12315            pop (@$stack) while (@$stack and $stack->[-1]->{'style'} ne 'ifvalue')
12316        }
12317        pop (@$stack);
12318        $state->{'ifvalue_inside'}--;
12319    }
12320    $state->{'ignored'} = undef;
12321    delete $state->{'ignored'};
12322    # We are stil in the ignored ifset or ifclear section
12323    $state->{'ignored'} = $state->{'ifvalue'} if ($state->{'ifvalue_inside'});
12324    #dump_stack($text, $stack, $state);
12325}
12326
12327
12328# Called in 2 contexts:
12329# * in main document
12330# * from substitute_text, called in turn from arg_expansion. In that case
12331#   'texi' is true, and so is 'arg_expansion'. In that case constructs are
12332#   expanded but no action is performed. Therefore $line_nr is not of use.
12333sub scan_texi($$$$;$)
12334{
12335    my $scanned_line = shift;
12336    my $text = shift;
12337    my $stack = shift;
12338    my $state = shift;
12339    my $line_nr = shift;
12340
12341    die "stack not an array ref"  unless (ref($stack) eq "ARRAY");
12342    my $cline = $scanned_line;
12343
12344    while(1)
12345    {
12346        # scan_texi
12347        #print STDERR "WHILE(t):$cline";
12348        #print STDERR "ARG_EXPANSION: $state->{'arg_expansion'}\n" if ($state->{'arg_expansion'});
12349        #dump_stack($text, $stack, $state);
12350        #print STDERR "ifvalue_inside $state->{'ifvalue_inside'}\n";
12351
12352
12353        # first we handle special cases:
12354        # macro definition: $state->{'macro_inside'}
12355        # macro arguments:  $state->{'macro_name'}
12356        # raw format:       $state->{'raw'}
12357        # @verb:            $state->{'verb'}
12358        # ignored:          $state->{'ignored'}
12359        # and then the remaining text/macros.
12360
12361        # in macro definition
12362        if ($state->{'macro_inside'})
12363        {
12364            if ($cline =~ s/^([^\\\@]*\\)//)
12365            {# protected character or @end macro
12366                 $state->{'macro'}->{'body'} .= $1 unless ($state->{'ignored'});
12367                 if ($cline =~ s/^\\//)
12368                 {
12369                      $state->{'macro'}->{'body'} .= '\\' unless ($state->{'ignored'});
12370                      next;
12371                 }
12372                 # I believe it is correct, although makeinfo don't do that.
12373                 elsif ($cline =~ s/^(\@end\sr?macro)$//o or $cline =~ s/^(\@end\sr?macro\s)//o
12374                      or $cline =~ s/^(\@r?macro\s+\w+\s*.*)//o)
12375                 {
12376                      $state->{'macro'}->{'body'} .= $1 unless ($state->{'ignored'});
12377                      next;
12378                 }
12379            }
12380            #if ($cline =~ s/^(.*?)\@end\sr?macro$//o or $cline =~ s/^(.*?)\@end\sr?macro\s+//o)
12381            if ($cline =~ s/^(\@end\sr?macro)$//o or $cline =~ s/^(\@end\sr?macro\s+)//o)
12382            {
12383                 my ($no_remaining, $result) = end_macro($state, $1, $cline);
12384                 add_prev ($text, $stack, $result) if (defined($result));
12385                 return 1 if ($no_remaining);
12386                 next;
12387            }
12388
12389            elsif($cline =~ /^(\@r?macro\s+\w+\s*.*)/)
12390            {
12391                 $state->{'macro'}->{'body'} .= $cline unless ($state->{'ignored'});
12392                 $state->{'macro_inside'}++;
12393                 #return;
12394                 return 1;
12395            }
12396            elsif ($cline =~ s/^\@(.)//)
12397            {
12398                 $state->{'macro'}->{'body'} .= '@' . $1 unless ($state->{'ignored'});
12399                 next;
12400            }
12401            elsif ($cline =~ s/^\@//)
12402            {
12403                 $state->{'macro'}->{'body'} .= '@' unless ($state->{'ignored'});
12404                 next;
12405            }
12406            else
12407            {
12408                 $cline =~ s/([^\@\\]*)//;
12409                 if ($state->{'ignored'})
12410                 {
12411                     return if ($cline =~ /^$/);
12412                     next;
12413                 }
12414                 $state->{'macro'}->{'body'} .= $1 if (defined($1));
12415                 if ($cline =~ /^$/)
12416                 {
12417                      $state->{'macro'}->{'body'} .= $cline;
12418                      #return;
12419                      return 1;
12420                 }
12421                 next;
12422            }
12423        }
12424        # in macro arguments parsing/expansion. Here \ { } and , if this is a
12425        # multi args macro have a signification, the remaining is passed
12426        # unmodified
12427        if (defined($state->{'macro_name'}))
12428        {
12429            my $special_chars = quotemeta ('\{}');
12430            my $multi_args = 0;
12431            my $formal_args = $macros->{$state->{'macro_name'}}->{'args'};
12432            $multi_args = 1 if ($#$formal_args >= 1);
12433            $special_chars .= quotemeta(',') if ($multi_args);
12434            if ($state->{'macro_args'}->[-1] eq '')
12435            {# remove space at the very beginning
12436                $cline =~ s/^\s*//o;
12437            }
12438            if ($cline =~ s/^([^$special_chars]*)([$special_chars])//)
12439            {
12440                $state->{'macro_args'}->[-1] .= $1 if defined($1);
12441                # \ protects any character in macro arguments
12442                if ($2 eq '\\')
12443                {
12444                    print STDERR "# macro call: protected char\n" if ($T2H_DEBUG & $DEBUG_MACROS);
12445                    if ($cline =~ s/^(.)//)
12446                    {
12447                        $state->{'macro_args'}->[-1] .= $1;
12448                    }
12449                    else
12450                    {
12451                        $state->{'macro_args'}->[-1] .= '\\';
12452                    }
12453                }
12454                elsif ($2 eq ',')
12455                { # in texinfo 4.8.90 a comma in braces is protected
12456                    if ($state->{'macro_depth'} > 1)
12457                    {
12458                        $state->{'macro_args'}->[-1] .= ',';
12459                    }
12460                    else
12461                    { # separate args
12462                        print STDERR "# macro call: new arg\n" if ($T2H_DEBUG & $DEBUG_MACROS);
12463                        $cline =~ s/^\s*//o;
12464                        push @{$state->{'macro_args'}}, '';
12465                    }
12466                }
12467                elsif ($2 eq '}')
12468                {
12469                    #my $macro_result_line = close_macro_arg($state, $cline);
12470                    return if (close_macro_arg($state, $cline, $line_nr));
12471                    #if (defined($macro_result_line))
12472                    #{
12473                    #    $cline = $macro_result_line;
12474                    #    return;
12475                    #}
12476                }
12477                elsif ($2 eq '{')
12478                {
12479                    print STDERR "# macro call: opening {\n" if ($T2H_DEBUG & $DEBUG_MACROS);
12480                    $state->{'macro_depth'}++;
12481                    add_text('{', \$state->{'macro_args'}->[-1]);
12482                }
12483                next;
12484            }
12485            print STDERR "# macro call: end of line\n" if ($T2H_DEBUG & $DEBUG_MACROS);
12486            $state->{'macro_args'}->[-1] .= $cline;
12487            return;
12488        }
12489        # in a raw format, verbatim, tex or html
12490        if ($state->{'raw'})
12491        {
12492            my $tag = $state->{'raw'};
12493
12494            # debugging
12495            if (! @$stack or ($stack->[-1]->{'style'} ne $tag))
12496            {
12497                print STDERR "Bug: raw or special: $tag but not on top of stack\n";
12498                print STDERR "line: $cline";
12499                dump_stack($text, $stack, $state);
12500                exit 1;
12501            }
12502
12503            # macro_regexp
12504            if ($cline =~ /^(.*?)\@end\s([a-zA-Z][\w-]*)/o and ($2 eq $tag))
12505            {
12506                $cline =~ s/^(.*?)(\@end\s$tag)//;
12507            # we add it even if 'ignored', it'll be discarded just below
12508            # with the @end
12509                add_prev ($text, $stack, $1);
12510                my $end = $2;
12511                my $style = pop @$stack;
12512                # if 'arg_expansion' and 'ignored' are both true text
12513                # is ignored.
12514                add_prev ($text, $stack, $style->{'text'} . $end) unless ($state->{'ignored'});
12515                delete $state->{'raw'};
12516                next;
12517            }
12518            else
12519            {# we add it even if 'ignored', it'll be discarded when there is
12520             # the @end
12521                 add_prev ($text, $stack, $cline);
12522                 last;
12523            }
12524        }
12525
12526        # in a @verb{ .. } macro
12527        if (defined($state->{'verb'}))
12528        {
12529            #dump_stack($text, $stack, $state);
12530            my $char = quotemeta($state->{'verb'});
12531            #print STDERR "VERB $char\n";
12532            if ($cline =~ s/^(.*?)$char\}/\}/)
12533            {# we add it even if 'ignored', it'll be discarded when closing
12534                 add_prev($text, $stack, $1 . $state->{'verb'});
12535                 $stack->[-1]->{'text'} = $state->{'verb'} . $stack->[-1]->{'text'};
12536                 delete $state->{'verb'};
12537                 next;
12538            }
12539            else
12540            {# we add it even if 'ignored', it'll be discarded when closing
12541                 add_prev($text, $stack, $cline);
12542                 last;
12543            }
12544        }
12545        # In ignored region
12546        if ($state->{'ignored'})
12547        {
12548            #print STDERR "IGNORED(ifvalue($state->{'ifvalue_inside'})): $state->{'ignored'}\n";
12549            if ($cline =~ /^.*?\@end(\s+)([a-zA-Z]\w+)/)
12550            {
12551                if ($2 eq $state->{'ignored'})
12552                {
12553                    $cline =~ s/^(.*?\@end)(\s+)([a-zA-Z]\w+)//;
12554                    my $end_ignore = $1.$2.$3;
12555                    close_ignored($state, $stack);
12556                    #dump_stack($text, $stack, $state);
12557                    # MACRO_ARG => keep ignored text
12558                    if ($state->{'arg_expansion'})
12559                    {# this may not be very usefull as it'll be remove later
12560                        add_prev ($text, $stack, $end_ignore);
12561                        next;
12562                    }
12563                    return if ($cline =~ /^\s*$/o);
12564                    next;
12565                }
12566            }
12567            add_prev ($text, $stack, $cline) if ($state->{'arg_expansion'});
12568            # we could theoretically continue for ignored commands other
12569            # than ifset or ifclear, however it isn't usefull.
12570            return unless ($state->{'ifvalue_inside'} and ($state->{'ignored'} eq $state->{'ifvalue'}));
12571        }
12572
12573
12574        # an @end tag
12575        # macro_regexp
12576        if ($cline =~ s/^([^{}@]*)\@end(\s+)([a-zA-Z][\w-]*)//)
12577        {
12578            my $leading_text = $1;
12579            my $space = $2;
12580            my $end_tag = $3;
12581            # when 'ignored' we don't open environments that aren't associated
12582            # with ignored regions, so we don't need to close them.
12583            next if ($state->{'ignored'});# ARG_EXPANSION
12584            add_prev($text, $stack, $leading_text);
12585            if (defined($state->{'text_macro_stack'})
12586               and @{$state->{'text_macro_stack'}}
12587               and ($end_tag eq $state->{'text_macro_stack'}->[-1]))
12588            {
12589                pop @{$state->{'text_macro_stack'}};
12590                # we keep menu and titlepage for the following pass
12591                if (($Texi2HTML::Config::texi_formats_map{$end_tag} eq 'normal') or ($region_lines{$end_tag}) or $state->{'arg_expansion'})
12592                {
12593                     add_prev($text, $stack, "\@end${space}$end_tag");
12594                }
12595                else
12596                {
12597                    #print STDERR "End $end_tag\n";
12598                    #dump_stack($text, $stack, $state);
12599                    return if ($cline =~ /^\s*$/);
12600                }
12601            }
12602            elsif ($Texi2HTML::Config::texi_formats_map{$end_tag})
12603            {
12604                line_error (sprintf(__("Unmatched `%c%s'"), ord('@'), 'end'), $line_nr);
12605            }
12606            else # a format that is not handled during the first pass
12607            {# ARG_EXPANSION
12608                add_prev($text, $stack, "\@end${space}$end_tag");
12609            }
12610            next;
12611        }
12612        # macro_regexp
12613        elsif ($cline =~ s/^([^{}@]*)\@(["'~\@\}\{,\.!\?\s\*\-\^`=:\|\/\\])//o or $cline =~ s/^([^{}@]*)\@([a-zA-Z][\w-]*)//o)
12614        {# ARG_EXPANSION
12615            add_prev($text, $stack, $1) unless $state->{'ignored'};
12616            my $command = $2;
12617            # FIXME: if it is an alias, it is substituted below, in the
12618            # diverse add_prev and output of \@$command. Maybe it could be
12619            # kept and only substituted in the last passes?
12620            $command = $alias{$command} if (exists($alias{$command}));
12621	    #print STDERR "MACRO $command\n";
12622            # handle skipped @-commands
12623            $state->{'bye'} = 1 if ($command eq 'bye' and !$state->{'ignored'} and !$state->{'arg_expansion'});
12624            # 'ignored' and 'arg_expansion' are handled in misc_command_texi
12625            # these are the commands in which the @value and @macro
12626            # and @-commands in general should not be expanded
12627            if (defined($Texi2HTML::Config::misc_command{$command}) and
12628                 ($command eq 'c' or $command eq 'comment' or $command eq 'set'
12629                   or $command eq 'clear' or $command eq 'bye' or $command eq 'alias'))
12630            {
12631                my $cmd_arg;
12632                ($cline, $cmd_arg) = misc_command_texi($cline, $command, $state,
12633                       $line_nr);
12634                add_prev ($text, $stack, "\@$command" . $cmd_arg) unless $state->{'ignored'};
12635            }
12636            elsif ($command eq 'setfilename' or $command eq 'documentencoding'
12637                      or $command eq 'definfoenclose' or $command eq 'include')
12638            { # special commands whose arguments will have @macro and
12639              # @value expanded, and that are processed in this pass
12640                if ($state->{'ignored'} or ($line_nr->{'file_name'} ne $Texi2HTML::THISDOC{'input_file_name'} and $command eq 'setfilename'))
12641                { # @setfilename is ignored in @include file as said in the manual
12642                    $cline = '';
12643                }
12644                elsif ($state->{'arg_expansion'})
12645                {
12646                    add_prev($text, $stack, "\@$command" . $cline);
12647                    return;
12648                }
12649                else
12650                {
12651                    $cline =~ s/^(\s+)//;
12652                    my $space = $1;
12653                    # not sure if it happpens at end of line, or with
12654                    # special char following the @-command or only at end of file
12655                    $space = '' if (!defined($space));
12656                    if (!$state->{'line_command'})
12657                    {
12658                        #print STDERR "LINE_COMMAND Start line_command $command, cline $cline";
12659                        $state->{'line_command'} = $command;
12660                        push @$stack, { 'line_command' => $command, 'text' => $space };
12661                    }
12662                    else
12663                    {
12664                        line_error (sprintf(__("\@%s not allowed in argument to \@%s"), $command, $state->{'line_command'}), $line_nr);
12665                        #add_prev($text, $stack, "\@$command" . $space);
12666                        add_prev($text, $stack, $space);
12667                    }
12668                }
12669            }
12670            # pertusus: it seems that value substitution are performed after
12671            # macro argument expansions: if we have
12672            # @set comma ,
12673            # and a call to a macro @macro {arg1 @value{comma} arg2}
12674            # the macro arg is arg1 , arg2 and the comma don't separate
12675            # args. Likewise it seems that the @value are not expanded
12676            # in macro definitions
12677
12678            elsif ($command =~ /^r?macro$/)
12679            { # in 'arg_expansion' (ie within another macro call arguments)
12680              # the macro is parsed as usual, but isn't registered in
12681              # end_macro.
12682                if ($cline =~ /^\s+(\w[\w-]*)\s*(.*)/)
12683                {
12684                    my $name = $1;
12685                    my $args_def = $2;
12686                    unless ($state->{'ignored'} or $state->{'arg_expansion'})
12687                    {
12688                         if (exists($macros->{$name}))
12689                         {
12690                             #line_warn ("macro `$name' already defined " .
12691                             #    format_line_number($macros->{$name}->{'line_nr'}) . " redefined", $line_nr);
12692                             line_warn (sprintf(__("macro `%s' previously defined"), $name), $line_nr);
12693                             line_warn (sprintf(__("here is the previous definition of `%s'"), $name), $macros->{$name}->{'line_nr'});
12694                         }
12695                    }
12696                    $state->{'macro_inside'} = 1;
12697
12698                    next if ($state->{'ignored'});
12699                    my @args = ();
12700                    if ($args_def =~ /^\s*{\s*(.*?)\s*}\s*/)
12701                    {
12702                        @args = split(/\s*,\s*/ , $1)
12703                    }
12704                    # keep the context information of the definition
12705                    my $macro = { 'name' => $name };
12706                    $macro->{'line_nr'} = { 'file_name' => $line_nr->{'file_name'},
12707                         'line_nr' => $line_nr->{'line_nr'}, 'macro' => $line_nr->{'macro'} } if (defined($line_nr));
12708                    $macro->{'args'} = \@args;
12709                    $macro->{'header'} = "\@$command" .$cline;
12710                    my $arg_index = 0;
12711                    my $debug_msg = '';
12712                    foreach my $arg (@args)
12713                    { # when expanding macros, the argument index is retrieved
12714                      # with args_index
12715                        $macro->{'args_index'}->{$arg} = $arg_index;
12716                        $debug_msg .= "$arg($arg_index) ";
12717                        $arg_index++;
12718                    }
12719                    $macro->{'body'} = '';
12720                    $state->{'macro'} = $macro;
12721                    print STDERR "# macro def $name: $debug_msg\n"
12722                         if ($T2H_DEBUG & $DEBUG_MACROS);
12723                }
12724                else
12725                {# it means we have a macro without a name
12726                    line_error (sprintf(__("Macro definition without macro name: %s"), $cline), $line_nr)
12727                        unless ($state->{'ignored'});
12728                }
12729                return 1;
12730            }
12731            elsif (defined($Texi2HTML::Config::texi_formats_map{$command}))
12732            {
12733                my $tag;
12734                ($cline, $tag) = do_text_macro($command, $cline, $state, $stack, $line_nr);
12735                # if it is a raw formatting command or a menu command
12736                # we must keep it for later, unless we are in an 'ignored'.
12737                # if in 'arg_expansion' we keep everything.
12738                my $command_kept;
12739                if ((($state->{'raw'} or ($Texi2HTML::Config::texi_formats_map{$command} eq 'normal') or (exists($region_lines{$command}))) and !$state->{'ignored'}) or $state->{'arg_expansion'})
12740                {
12741                    add_prev($text, $stack, $tag);
12742                    $command_kept = 1;
12743                }
12744                #dump_stack ($text, $stack, $state);
12745                next if $command_kept;
12746                return if ($cline =~ /^\s*$/);
12747            }
12748            elsif ($command eq 'value')
12749            {
12750                if ($cline =~ s/^{($VARRE)}//)
12751                {
12752                    my $value = $1;
12753                    if ($state->{'arg_expansion'})
12754                    {
12755                        add_prev($text, $stack, "\@$command" .'{'. $value .'}');
12756                        next;
12757                    }
12758                    next if ($state->{'ignored'});
12759                    my $expansion;
12760                    if (defined($value{$value}))
12761                    {
12762                        $expansion = $value{$value}
12763                    }
12764                    else
12765                    {
12766                        $expansion = gdt('@{No value for `{value}\'@}', {'value' => $value}, {'keep_texi'=> 1});
12767                        line_warn (sprintf(__("undefined flag: %s"), $value), $line_nr);
12768                    }
12769                    $cline = $expansion . $cline;
12770                }
12771                else
12772                {
12773                    if ($state->{'arg_expansion'})
12774                    {
12775                        add_prev($text, $stack, "\@$command");
12776                        next;
12777                    }
12778                    next if ($state->{'ignored'});
12779                    line_error (__("Bad syntax for \@value"), $line_nr);
12780                }
12781            }
12782            elsif ($command eq 'unmacro')
12783            { #FIXME with 'arg_expansion' should it be passed unmodified ?
12784                if ($state->{'ignored'})
12785                {
12786                    $cline =~ s/^\s+(\w+)//;
12787                }
12788                else
12789                {
12790                    delete $macros->{$1} if ($cline =~ s/^\s+(\w+)//);
12791                }
12792                return if ($cline =~ /^\s*$/);
12793                $cline =~ s/^\s*//;
12794            }
12795            elsif (exists($macros->{$command}))
12796            {# it must be before the handling of {, otherwise it is considered
12797             # to be regular texinfo @-command. Maybe it could be placed higher
12798             # if we want user defined macros to override texinfo @-commands
12799
12800             # in 'ignored' we parse macro defined args anyway as it removes
12801             # some text, but we don't expand the macro
12802
12803                my $ref = $macros->{$command}->{'args'};
12804                my $args_number = $#$ref +1;
12805                # we remove any space/new line before the argument
12806                if ($cline =~ s/^\s*{\s*//)
12807                { # the macro has args
12808                    $state->{'macro_args'} = [ "" ];
12809                    $state->{'macro_name'} = $command;
12810                    $state->{'macro_depth'} = 1;
12811                }
12812                elsif (($args_number >= 2) or ($args_number <1))
12813                { # no brace -> no arg
12814                    #$cline =
12815                    #line_warn("\@$command defined with $args_number arguments should be invoked with {}", $line_nr);
12816                    line_warn(sprintf(__("\@%s defined with zero or more than one argument should be invoked with {}"), $command), $line_nr);
12817                    expand_macro ($command, [], $cline, $line_nr, $state);
12818                    return;
12819                }
12820                else
12821                { # macro with one arg on the line
12822                    chomp $cline;
12823                    #$cline =
12824                    expand_macro ($command, [$cline], "\n", $line_nr, $state);
12825                    return;
12826                }
12827            }
12828            elsif ($cline =~ s/^{//)
12829            {# we add nested commands in a stack. verb is also on the stack
12830             # but handled specifically.
12831             # we add it the comands even in 'ignored' as their result is
12832             # discarded when the closing brace appear, or the ifset or
12833             # iclear is closed.
12834                if ($command eq 'verb')
12835                {
12836                    if ($cline =~ /^$/)
12837                    {
12838                        line_error (sprintf(__("\@%s without associated character"), $command), $line_nr);
12839                    }
12840                    else
12841                    {
12842                        $cline =~ s/^(.)//;
12843                        $state->{'verb'} = $1;
12844                    }
12845                }
12846                if ($state->{'line_command'} and $command eq 'verb')
12847                { # have to close it now to catch if it is not
12848                  # closed at te end of the line. In subsequent passes this
12849                  # is done in scan_line_separator.
12850                    my $result;
12851                    if (defined($state->{'verb'}))
12852                    {
12853                        $result = '@verb{'.$state->{'verb'};
12854                        my $verb_char = quotemeta($state->{'verb'});
12855                        if ($cline =~ s/^(.*?${verb_char}\})//)
12856                        {
12857                            $result .= $1;
12858                        }
12859                        else
12860                        {
12861                            $cline =~ s/^(.*)//;
12862                            $result .= $1;
12863                        }
12864                        delete $state->{'verb'};
12865                    }
12866                    else
12867                    {
12868                        $result = '@verb{'
12869                    }
12870                    add_prev($text, $stack, $result) unless($state->{'ignored'});
12871                }
12872                else
12873                {
12874                    push (@$stack, { 'style' => $command, 'text' => '' });
12875                }
12876            }
12877            else
12878            {
12879                $cline = do_unknown(0, $command, $cline, $text, $stack, $state, $line_nr);
12880            }
12881            next;
12882        }
12883        #elsif(s/^([^{}@]*)\@(.)//o)
12884        elsif($cline =~ s/^([^{}@]*)\@([^\s\}\{\@]*)//o)
12885        {# ARG_EXPANSION
12886            # No need to warn here for @ followed by a character that
12887            # is not in any @-command and it is done later
12888            add_prev($text, $stack, $1) unless($state->{'ignored'});
12889            $cline = do_unknown(0, $2, $cline, $text, $stack, $state, $line_nr);
12890            next;
12891        }
12892        elsif ($cline =~ s/^([^{}]*)([{}])//o)
12893        {
12894         # in ignored section we cannot be sure that there is an @-command
12895         # already opened so we must discard the text.
12896         # ARG_EXPANSION
12897            add_prev($text, $stack, $1) unless($state->{'ignored'});
12898            if ($2 eq '{')
12899            {
12900              # this empty style is for a lone brace.
12901              # we add it even in 'ignored' as it is discarded when the closing
12902              # brace appear, or the ifset or iclear is closed.
12903                push @$stack, { 'style' => '', 'text' => '' };
12904            }
12905            else
12906            {
12907                if (@$stack)
12908                {
12909                    my $style = pop @$stack;
12910                    close_style_texi($style, $text, $stack, $state);
12911                    #print STDERR "MACRO end $style->{'style'} remaining: $cline";
12912                    next;
12913                }
12914                else
12915                {# ARG_EXPANSION
12916                    # we warn in the last pass that there is a } without open
12917                    add_prev ($text, $stack, '}') unless($state->{'ignored'});
12918                }
12919            }
12920        }
12921        else
12922        {# ARG_EXPANSION
12923            #print STDERR "END_LINE $cline";
12924            add_prev($text, $stack, $cline) unless($state->{'ignored'});
12925            if ($state->{'line_command'})
12926            {
12927               if (!scalar(@$stack))
12928               {
12929                   print STDERR "BUG: empty state for $state->{'line_command'}\n";
12930                   return;
12931                   delete $state->{'line_command'};
12932               }
12933               while (!defined($stack->[-1]->{'line_command'}))
12934               {
12935                  my $top = pop @$stack;
12936                  # defer this to later?
12937                  #line_error ("unclosed command in \@$state->{'line_command'}: $top->{'style'}");
12938                  add_prev($text, $stack, "\@$top->{'style'}".'{'.$top->{'text'}.'}');
12939               }
12940               my $command = pop @$stack;
12941               ###################### debug
12942               if (!defined($command) or !defined($command->{'text'}) or
12943                 !defined($command->{'line_command'}) or ($command->{'line_command'} ne $state->{'line_command'}))
12944               {
12945                   msg_debug ("BUG: messed $state->{'line_command'} stack", $line_nr);
12946                   delete $state->{'line_command'};
12947                   return;
12948               }
12949               ###################### end debug
12950               else
12951               {
12952                   delete $state->{'line_command'};
12953                   my $macro = $command->{'line_command'};
12954                   # include are not kept
12955                   if ($macro eq 'include')
12956                   {
12957                    #if (s/^\s+([\/\w.+-]+)//o)
12958                       if ($command->{'text'} =~ s/^(\s+)(.+)//o)
12959                       {
12960                           my $file_name = $2;
12961                           # FIXME scan_line_separators
12962                           $file_name = trim_around_spaces($file_name);
12963                           $file_name = substitute_line($file_name, "\@$macro", {'code_style' => 1, 'remove_texi' => 1});
12964                           my $file = locate_include_file($file_name);
12965                           if (defined($file))
12966                           {
12967                               my ($line_nr_file, $input_spool_file) = open_file($file, $line_nr->{'macro'}, $state->{'files_stack'});
12968                               ($line_nr, $state->{'input_spool'}) = ($line_nr_file, $input_spool_file) if (defined($line_nr_file));
12969                               print STDERR "# including $file\n" if $T2H_VERBOSE;
12970                           }
12971                           else
12972                           {
12973                              line_error (sprintf(__("\@%s: Cannot find %s"), $macro, $file_name), $line_nr);
12974                           }
12975                       }
12976                       else
12977                       {
12978                           line_error (sprintf(__("Bad argument to \@%s: %s"), $macro, $command->{'text'}), $line_nr);
12979                       }
12980                       return;
12981                   }
12982                   else
12983                   { # these are kept (setfilename, documentencoding, definfoenclose)
12984                       if ($macro eq 'setfilename' and $Texi2HTML::Config::USE_SETFILENAME)
12985                       {
12986                           if (defined(Texi2HTML::Config::get_conf ('setfilename')))
12987                           {
12988                               line_error (sprintf(__("\@%s already set"), $macro), $line_nr);
12989                               # the line is removed, because we don't want to reset
12990                               # get_conf('setfilename') between passes, and we don't want
12991                               # the last one to be picked up
12992                               $cline = "\n";
12993                               next;
12994                           }
12995                       }
12996                       my $cmd_arg;
12997                       ($cline, $cmd_arg) = misc_command_texi($command->{'text'},
12998                         $macro, $state, $line_nr);
12999                       add_prev ($text, $stack, "\@$macro" . $cmd_arg);
13000                       next;
13001                   }
13002               }
13003            }
13004            last;
13005        }
13006    }
13007    return undef if ($state->{'ignored'});
13008    return 1;
13009} # end scan_texi
13010
13011sub close_structure_command($$$$)
13012{
13013    my $cmd_ref = shift;
13014    my $state = shift;
13015    my $unclosed_commands = shift;
13016    my $line_nr = shift;
13017    my $result;
13018
13019    #print STDERR "close_structure_command $cmd_ref->{'style'}\n";
13020    # If the anchor is in @titlepage or @copying, it is nevertheless only
13021    # expanded once in pass_structure, during the @copying or @titlepage
13022    # expansion.
13023    # It is not true, however if INLINE_INSERTCOPYING is true.
13024    # See indices/index_special_region.texi tests.
13025    if ($cmd_ref->{'style'} eq 'anchor')
13026    {
13027        my $anchor = $cmd_ref->{'text'};
13028        $anchor = normalise_node($anchor);
13029        #print STDERR "Anchor $anchor\n";
13030        if ($nodes{$anchor})
13031        {# makeinfo error message are the following:
13032         # "Anchor `%s' and node `%s' map to the same file name"
13033         # "This @anchor command ignored; references to it will not work"
13034         # "Rename this anchor or use the `--no-split' option"
13035         #
13036         # "Anchors `%s' and `%s' map to the same file name"
13037         # "Anchor `%s' and node `%s' map to the same file name"
13038         # "@anchor command ignored; references to it will not work"
13039         # "Rename this anchor or use the `--no-split' option"
13040            line_error (sprintf(__("Anchor `%s' previously defined %s"), $anchor, format_line_number($nodes{$anchor}->{'line_nr'})), $line_nr);
13041            return '';
13042        }
13043        elsif ($anchor =~ /^\(.+\)/)
13044        {
13045            line_error (sprintf(__("Syntax for an external node used for `%s'"), $anchor), $line_nr);
13046            return '';
13047        }
13048        $document_anchor_num++;
13049        $nodes{$anchor} = { 'anchor' => 1, 'seen' => 1, 'texi' => $anchor, 'id' => 'ANC' . $document_anchor_num, 'line_nr' => $line_nr, 'tag' => 'anchor'};
13050        push @{$state->{'place'}}, $nodes{$anchor};
13051    }
13052    elsif ($cmd_ref->{'style'} eq 'footnote')
13053    {
13054        if (Texi2HTML::Config::get_conf('footnotestyle') eq 'separate')
13055        {
13056            $state->{'heading_element'} = $state->{'footnote_heading_element'};
13057            $state->{'place'} = $state->{'footnote_place'};
13058        }
13059    }
13060    elsif ($cmd_ref->{'style'} eq 'caption' or $cmd_ref->{'style'}
13061       eq 'shortcaption' and $state->{'float'})
13062    {
13063        my @texi_lines = map {$_ = $_."\n"} split (/\n/, $cmd_ref->{'text'});
13064        $state->{'float'}->{$cmd_ref->{'style'} . "_texi"} = \@texi_lines;
13065    }
13066    if (($cmd_ref->{'style'} eq 'titlefont') and ($cmd_ref->{'text'} =~ /\S/))
13067    {
13068        $state->{'heading_element'}->{'titlefont'} = $cmd_ref->{'text'} unless ((exists($state->{'region'}) and ($state->{'region'} eq 'titlepage')) or defined($state->{'heading_element'}->{'titlefont'})) ;
13069    }
13070    if (defined($Texi2HTML::Config::command_handler{$cmd_ref->{'style'}}))
13071    {
13072        $result = init_special($cmd_ref->{'style'},$cmd_ref->{'text'});
13073        if ($unclosed_commands)
13074        {
13075            $result .= "\n"; # the end of line is eaten by init_special
13076            line_error(sprintf(__("No closing brace for specially handled command %s"), $cmd_ref->{'style'}),$line_nr);
13077        }
13078    }
13079    elsif ($cmd_ref->{'style'})
13080    {
13081        $result = '@' . $cmd_ref->{'style'} . '{' . $cmd_ref->{'text'};
13082        $result .= '}' unless ($unclosed_commands);
13083    }
13084    else
13085    {
13086        $result = '{' . $cmd_ref->{'text'};
13087        # don't close { if we are closing stack as we are not
13088        # sure this is a licit { ... } construct.
13089        $result .= '}' unless ($unclosed_commands);
13090    }
13091    return $result;
13092}
13093
13094sub end_format_structure($$$$$$)
13095{
13096    my $end_tag = shift;
13097    my $text = shift;
13098    my $stack = shift;
13099    my $state = shift;
13100    my $line_nr = shift;
13101    my $remaining_on_line = shift;
13102
13103    if (defined($state->{'text_macro_stack'})
13104       and @{$state->{'text_macro_stack'}}
13105       and ($end_tag eq $state->{'text_macro_stack'}->[-1]))
13106    {
13107        pop @{$state->{'text_macro_stack'}};
13108        if (exists($region_lines{$end_tag}))
13109        { # end a region_line macro, like documentdescription, copying
13110             print STDERR "Bug: end_tag $end_tag ne $state->{'region_lines'}->{'format'}\n"
13111                if ($end_tag ne $state->{'region_lines'}->{'format'});
13112             print STDERR "Bug: end_tag $end_tag ne $state->{'region'}\n"
13113                if ($end_tag ne $state->{'region'});
13114             $state->{'region_lines'}->{'number'}--;
13115             if ($state->{'region_lines'}->{'number'} == 0)
13116             {
13117                 close_region($state);
13118             }
13119             #dump_stack($text, $stack, $state);
13120        }
13121        if (($Texi2HTML::Config::texi_formats_map{$end_tag} eq 'normal') or $Texi2HTML::Config::region_formats_kept{$end_tag})
13122        {
13123             $state->{$end_tag}-- if ($Texi2HTML::Config::texi_formats_map{$end_tag} eq 'normal');
13124             add_prev($text, $stack, "\@end $end_tag");
13125        }
13126        else
13127        {
13128             #print STDERR "End $end_tag\n";
13129             #dump_stack($text, $stack, $state);
13130             return 1 if ($remaining_on_line =~ /^\s*$/);
13131        }
13132    }
13133    elsif ($Texi2HTML::Config::texi_formats_map{$end_tag})
13134    {
13135        line_error (sprintf(__("Unmatched `%c%s'"), ord('@'), 'end'), $line_nr);
13136        #dump_stack($text, $stack, $state);
13137    }
13138    elsif ($end_tag eq 'detailmenu' or $end_tag eq 'direntry')
13139    {
13140        $state->{$end_tag}-- if $state->{$end_tag};
13141        add_prev($text, $stack, "\@end $end_tag");
13142    }
13143    else
13144    {
13145        if ($end_tag eq 'float' and $state->{'float'})
13146        {
13147            delete $state->{'float'};
13148        }
13149        elsif ($end_tag eq $state->{'table_stack'}->[-1])
13150        {
13151            enter_table_index_entry($text, $stack, $state, $line_nr);
13152            pop @{$state->{'table_stack'}};
13153        }
13154        #add end tag
13155        add_prev($text, $stack, "\@end $end_tag");
13156    }
13157    return 0;
13158}
13159
13160sub parse_menu_entry($)
13161{
13162   my $menu_line = shift;
13163   my ($node, $name, $ending, $remaining);
13164
13165   return ($node, $name, $ending, $remaining) unless $menu_line =~ s/^\*//;
13166
13167   my ($before_colon, $separator);
13168   ($before_colon, $remaining, $separator) = scan_line_separators($menu_line, ':', 'menu entry');
13169   if (defined($before_colon) and defined($separator))
13170   {
13171      if ($remaining =~ s/^://)
13172      {
13173          $node = $before_colon;
13174          $ending = '::';
13175      }
13176      elsif ($remaining =~ /\S/)
13177      {
13178          my $after_colon;
13179          $ending = "";
13180          ($after_colon, $remaining, $separator) = scan_line_separators($remaining, '\t,\.', 'menu entry node');
13181          # this certainly corresponds with an error in the node.
13182          # this is considered not to be a menu entry.
13183          return (undef, $name, $ending, $remaining) if (!defined($after_colon));
13184          $node = $after_colon;
13185
13186          while (1)
13187          {
13188              if (!defined($separator) or (defined($separator) and $separator ne '.') or (defined($separator) and (!defined($remaining) or $remaining =~ /^\s/)))
13189              {
13190                  last;
13191              }
13192              $node .= $separator;
13193              my $after_dot;
13194              ($after_dot, $remaining, $separator) = scan_line_separators($remaining, '\t,\.', 'menu entry node');
13195              $after_dot = '' if (!defined($after_dot));
13196              $node .= $after_dot;
13197          }
13198          $name = $before_colon;
13199          $ending = $separator if (defined($separator));
13200          # only spaces after the :, this is not a menu entry:
13201          $node = undef if ($node !~ /\S/);
13202      }
13203   }
13204   # remaining may be defined even if $node isn't.
13205   #print STDERR "\nLLLL $menu_line";
13206   #print STDERR " -->  node:$node, name:$name, ending:$ending -> $remaining";
13207   return ($node, $name, $ending, $remaining);
13208}
13209
13210sub scan_structure($$$$;$)
13211{
13212    my $line = shift;
13213    my $text = shift;
13214    my $stack = shift;
13215    my $state = shift;
13216    my $line_nr = shift;
13217
13218    die "stack not an array ref"  unless (ref($stack) eq "ARRAY");
13219    my $cline = $line;
13220    #print STDERR "SCAN_STRUCTURE: $line";
13221    #dump_stack ($text, $stack, $state);
13222    if (!$state->{'raw'} and (!exists($state->{'region_lines'})))
13223    {
13224        #if (!$state->{'verb'} and $state->{'menu'} and $cline =~ /^\*\s+/o)
13225        if (!$state->{'verb'} and $state->{'menu'})
13226        {
13227        # new menu entry
13228            my ($node, $name, $ending, $remaining) = parse_menu_entry($cline);
13229            if (defined($node))
13230            {
13231                menu_entry_texi(normalise_node($node), $state, $line_nr);
13232            }
13233        }
13234    }
13235
13236    while(1)
13237    {
13238        # scan structure
13239	#dump_stack($text, $stack, $state);
13240	#print STDERR "WHILE(s):$cline";
13241
13242        # as texinfo 4.5
13243        # verbatim might begin at another position than beginning
13244        # of line, and end verbatim might too. To end a verbatim section
13245        # @end verbatim must have exactly one space between end and verbatim
13246        # things following end verbatim are not ignored.
13247        #
13248        # html might begin at another position than beginning
13249        # of line, but @end html must begin the line, and have
13250        # exactly one space. Things following end html are ignored.
13251        # tex and ignore works like html
13252        #
13253        # ifnothtml might begin at another position than beginning
13254        # of line, and @end  ifnothtml might too, there might be more
13255        # than one space between @end and ifnothtml but nothing more on
13256        # the line.
13257        # @end itemize, @end ftable works like @end ifnothtml.
13258        # except that @item on the same line than @end vtable doesn't work
13259        #
13260        # text right after the itemize before an item is displayed.
13261        # @item might be somewhere in a line.
13262        # strangely @item on the same line than @end vtable doesn't work
13263        # there should be nothing else than a command following @itemize...
13264        #
13265        # see more examples in formatting directory
13266
13267        if ($state->{'raw'})
13268        {
13269            my $tag = $state->{'raw'};
13270            ################# debug
13271            if (! @$stack or ($stack->[-1]->{'style'} ne $tag))
13272            {
13273                print STDERR "Bug: raw or special: $tag but not on top of stack\n";
13274                print STDERR "line: $cline";
13275                dump_stack($text, $stack, $state);
13276                exit 1;
13277            }
13278            ################# end debug
13279            if ($tag eq 'macro')
13280            {
13281                if ($cline =~ /^\s*\@macro\s+(\w[\w-]*)\s*(.*)/)
13282                {
13283                    $state->{$tag}++;
13284                }
13285            }
13286            # macro_regexp
13287            if ($cline =~ /^(.*?)\@end\s([a-zA-Z][\w-]*)/o and ($2 eq $tag))
13288            {
13289                $cline =~ s/^(.*?)(\@end\s$tag)//;
13290                add_prev ($text, $stack, $1);
13291                my $end_text = $2;
13292                if ($tag eq 'macro')
13293                {
13294                    $state->{$tag}--;
13295                    if ($state->{$tag})
13296                    {
13297                        add_prev ($text, $stack, $end_text);
13298                        next;
13299                    }
13300                }
13301                delete $state->{'raw'};
13302                my $style = pop @$stack;
13303                if (defined($Texi2HTML::Config::command_handler{$tag}))
13304                { # replace the special region by what init_special give
13305                    if ($style->{'text'} !~ /^\s*$/)
13306                    {
13307                        add_prev ($text, $stack, init_special($style->{'style'}, $style->{'text'}));
13308                    }
13309                }
13310                else
13311                {
13312                    add_prev ($text, $stack, $style->{'text'} . "\@end $tag");
13313                }
13314                next;
13315            }
13316            else
13317            {
13318                add_prev ($text, $stack, $cline);
13319                return if (defined($Texi2HTML::Config::command_handler{$tag}));
13320                last;
13321            }
13322        }
13323
13324        if (defined($state->{'verb'}))
13325        {
13326            my $char = quotemeta($state->{'verb'});
13327            if ($cline =~ s/^(.*?)$char\}/\}/)
13328            {
13329                add_prev($text, $stack, $1 . $state->{'verb'});
13330                $stack->[-1]->{'text'} = $state->{'verb'} . $stack->[-1]->{'text'};
13331                delete $state->{'verb'};
13332                next;
13333            }
13334            else
13335            {
13336                add_prev($text, $stack, $cline);
13337                last;
13338            }
13339        }
13340
13341        # macro_regexp
13342        if ($cline =~ s/^([^{}@]*)\@end\s+([a-zA-Z][\w-]*)//)
13343        {
13344            add_prev($text, $stack, $1);
13345            my $end_tag = $2;
13346            #print STDERR "END STRUCTURE $end_tag\n";
13347            return if (end_format_structure($end_tag, $text, $stack, $state, $line_nr, $cline));
13348            next;
13349        }
13350        # macro_regexp
13351        elsif ($cline =~ s/^([^{}@]*)\@(["'~\@\}\{,\.!\?\s\*\-\^`=:\|\/\\])//o or $cline =~ s/^([^{}@]*)\@([a-zA-Z][\w-]*)//o)
13352        {
13353            add_prev($text, $stack, $1);
13354            my $macro = $2;
13355            #print STDERR "MACRO $macro\n";
13356            $macro = $alias{$macro} if (exists($alias{$macro}));
13357            if (defined($Texi2HTML::Config::deprecated_commands{$macro}))
13358            {
13359              # makeinfo has
13360              # "%c%s is obsolete; use %c%s instead"
13361                if ($Texi2HTML::Config::deprecated_commands{$macro} eq '')
13362                {
13363                   line_warn(sprintf(__("%c%s is obsolete."), ord('@'), $macro), $line_nr);
13364                }
13365                else
13366                {
13367                   line_warn(sprintf(__("%c%s is obsolete; %s"),ord('@'), $macro, __($Texi2HTML::Config::deprecated_commands{$macro})), $line_nr);
13368                }
13369            }
13370            if (defined($Texi2HTML::Config::misc_command{$macro}))
13371            {
13372                my $line;
13373                ($cline, $line) = misc_command_structure($cline, $macro, $state,
13374                      $line_nr);
13375                add_prev ($text, $stack, "\@$macro".$line);
13376                next;
13377            }
13378            elsif ($macro eq 'printindex' and ($cline =~ /^\s+(\w+)/))
13379            {
13380                my $index_name = $1;
13381                if (!exists($index_names{$index_name}))
13382                {
13383                   line_error (sprintf(__("Unknown index `%s' in \@printindex"),$index_name), $line_nr);
13384                }
13385                my $associated_element;
13386                if ($state->{'current_element'} eq $element_before_anything)
13387                {
13388                   line_warn (sprintf(__("Printindex before document beginning: \@printindex %s"), $index_name), $line_nr);
13389                }
13390                else
13391                {
13392                # $element_index is the first element with index
13393                  $element_index = $state->{'current_element'} unless (defined($element_index));
13394                  $associated_element = $state->{'current_element'};
13395                }
13396                my $region = $state->{'region'};
13397                $region = 'document' if (!defined($region));
13398                # FIXME use 'index_name' instead of 'name'
13399                my $printindex = { 'associated_element' => $associated_element, 'name' => $index_name, 'region' => $region, 'command' => 'printindex' };
13400                # prepare association of the index to the element by
13401                # putting it in the current place
13402                push @{$state->{'place'}}, $printindex;
13403                push @{$Texi2HTML::THISDOC{'indices'}->{$region}->{$index_name}}, $printindex;
13404                #print STDERR "PRINTINDEX add($printindex) region $region name $index_name, nr ".scalar(@{$Texi2HTML::THISDOC{'indices'}->{$region}->{$index_name}})."\n";
13405                add_prev ($text, $stack, "\@$macro" .  $cline);
13406                last;
13407            }
13408            elsif ($macro eq 'listoffloats')
13409            {
13410                add_prev ($text, $stack, "\@$macro" .  $cline);
13411                last;
13412            }
13413            elsif ($sec2level{$macro})
13414            {
13415                if ($cline =~ /^\s*(.*)$/)
13416                {
13417                    my $name = $1;
13418                    my $heading_ref = new_section_heading($macro, $name, $state, $line_nr);
13419                    if (exists($state->{'region_lines'}) and $state->{'region_lines'}->{'format'})
13420                    {
13421                        my $region = $state->{'region_lines'}->{'format'};
13422                        $state->{'region_lines'}->{'head_num'}++;
13423                        my $num = $state->{'region_lines'}->{'head_num'};
13424                        $heading_ref->{'id'} = "${target_prefix}${region}_HEAD$num";
13425                        $heading_ref->{'sec_num'} = "${region}_$num";
13426                        $heading_ref->{'region'} = $region;
13427                        $heading_ref->{'region_head_num'} = $num;
13428                    }
13429                    else
13430                    {
13431                        $document_head_num++;
13432                        $heading_ref->{'id'} = "HEAD$document_head_num";
13433                        $heading_ref->{'sec_num'} = $document_head_num;
13434                    }
13435                    # this is only used when there is a index entry after the
13436                    # heading
13437                    $heading_ref->{'target'} = $heading_ref->{'id'};
13438                    $heading_ref->{'heading'} = 1;
13439                    $heading_ref->{'tag_level'} = $macro;
13440                    $heading_ref->{'number'} = '';
13441
13442                    $state->{'heading_element'} = $heading_ref;
13443                    push @{$state->{'place'}}, $heading_ref;
13444                    $headings{$heading_ref->{'sec_num'}} = $heading_ref;
13445                }
13446                add_prev ($text, $stack, "\@$macro" .  $cline);
13447                last;
13448            }
13449            elsif (index_command_prefix($macro) ne '')
13450            { # if we are already in a (v|f)table the construct is quite
13451              # wrong
13452              # FIXME should it be discarded?
13453                if ($state->{'item'})
13454                {
13455                   line_error(sprintf(__("ignored \@%s already in an \@%s entry"), $macro, $state->{'item'}), $line_nr);
13456                   next;
13457                }
13458                my $index_prefix = index_command_prefix($macro);
13459                enter_index_entry($index_prefix, $line_nr, $cline, $macro, $state);
13460                add_prev ($text, $stack, "\@$macro" .  $cline);
13461                last;
13462            }
13463            elsif (defined($Texi2HTML::Config::texi_formats_map{$macro}))
13464            {
13465                my $macro_kept;
13466                #print STDERR "TEXT_MACRO: $macro\n";
13467                if ($Texi2HTML::Config::texi_formats_map{$macro} eq 'raw')
13468                {
13469                    $state->{'raw'} = $macro;
13470                    $state->{$macro}++ if ($macro eq 'macro');
13471                    #print STDERR "RAW\n";
13472                }
13473                elsif ($Texi2HTML::Config::texi_formats_map{$macro} eq 'normal')
13474                {
13475                    if ($macro eq 'menu')
13476                    {
13477                       delete ($state->{'prev_menu_node'});
13478                       if (!$state->{'node_ref'})
13479                       {
13480                          line_error (sprintf(__("\@%s seen before first \@node"), $macro), $line_nr);
13481                          line_error (__("perhaps your \@top node should be wrapped in \@ifnottex rather than \@ifinfo?"), $line_nr);
13482                       }
13483                       if ($state->{'menu_in_node'})
13484                       {
13485                          line_error (sprintf(__("Multiple \@%s"), $macro), $line_nr);
13486                       }
13487                       $state->{'menu_in_node'}++;
13488                    }
13489                    $state->{$macro}++;
13490                    push @{$state->{'text_macro_stack'}}, $macro;
13491                    #print STDERR "MENU (text_macro_stack: @{$state->{'text_macro_stack'}})\n";
13492                }
13493                elsif (exists($region_lines{$macro}))
13494                {
13495                    if (exists($state->{'region_lines'}) and ($state->{'region_lines'}->{'format'} ne $macro))
13496                    {
13497                        line_error(sprintf(__("\@%s not allowed within %s"), $macro, $state->{'region_lines'}->{'format'}), $line_nr);
13498                        next;
13499                    }
13500                    open_region ($macro, $state);
13501                    if ($Texi2HTML::Config::region_formats_kept{$macro})
13502                    {
13503                        add_prev($text, $stack, "\@$macro");
13504                        $macro_kept = 1;
13505                        $state->{'region_lines'}->{'first_line'} = 1;
13506                    }
13507                    push @{$state->{'text_macro_stack'}}, $macro;
13508                }
13509                # if it is a raw formatting command or a menu command
13510                # we must keep it for later
13511                if (($state->{'raw'} and (!defined($Texi2HTML::Config::command_handler{$macro}))) or ($Texi2HTML::Config::texi_formats_map{$macro} eq 'normal'))
13512                {
13513                    add_prev($text, $stack, "\@$macro");
13514                    $macro_kept = 1;
13515                }
13516                if ($state->{'raw'})
13517                {
13518                    push @$stack, { 'style' => $macro, 'text' => '' };
13519                }
13520                next if $macro_kept;
13521                #dump_stack ($text, $stack, $state);
13522                return if ($cline =~ /^\s*$/);
13523            }
13524            elsif ($macro eq 'detailmenu' or $macro eq 'direntry')
13525            {
13526                if ($macro eq 'detailmenu' and !$state->{'node_ref'})
13527                {
13528                   line_error (sprintf(__("\@%s seen before first \@node"), $macro), $line_nr);
13529                }
13530                add_prev ($text, $stack, "\@$macro" .  $cline);
13531                $state->{$macro}++;
13532                last;
13533            }
13534            elsif ($macro eq 'float')
13535            {
13536                my ($style_texi, $label_texi) = parse_line_arguments($cline, 2, "\@$macro", $line_nr);
13537                $style_texi = normalise_texi_space($style_texi);
13538                $label_texi = undef if (defined($label_texi) and ($label_texi =~ /^\s*$/));
13539                if (defined($label_texi))
13540                { # The float may be a target for refs if it has a label
13541                    my $error_with_label = 1;
13542                    $label_texi = normalise_node($label_texi);
13543                    if (exists($nodes{$label_texi}) and defined($nodes{$label_texi})
13544                         and $nodes{$label_texi}->{'seen'})
13545                    {
13546                        line_error (sprintf(__("Float label `%s' previously defined %s"), $label_texi, format_line_number($nodes{$label_texi}->{'line_nr'})), $line_nr);
13547                    }
13548                    elsif ($label_texi =~ /^\(.+\)/)
13549                    {
13550                        line_error (sprintf(__("Syntax for an external node used for `%s'"), $label_texi), $line_nr);
13551                    }
13552                    else
13553                    {
13554                        $error_with_label = 0;
13555                        my $float = { };
13556                        if (exists($nodes{$label_texi}) and defined($nodes{$label_texi}))
13557                        { # float appeared in a menu
13558                            $float = $nodes{$label_texi};
13559                        }
13560                        else
13561                        {
13562                            $nodes{$label_texi} = $float;
13563                        }
13564                        $float->{'float'} = 1;
13565                        $float->{'tag'} = 'float';
13566                        $float->{'texi'} = $label_texi;
13567                        $float->{'seen'} = 1;
13568                        $float->{'id'} = $label_texi;
13569                        $float->{'target'} = $label_texi;
13570#print STDERR "FLOAT: $float $float->{'texi'}, place $state->{'place'}\n";
13571                        push @{$state->{'place'}}, $float;
13572                        $float->{'element'} = $state->{'current_element'};
13573                        $state->{'float'} = $float;
13574                        $float->{'style_texi'} = $style_texi;
13575                        $float->{'line_nr'} = $line_nr;
13576                        push @floats, $float;
13577                    }
13578
13579                    if ($error_with_label)
13580                    {
13581                        while ($cline =~ /,/)
13582                        {
13583                            $cline =~ s/,.*$//;
13584                        }
13585                    }
13586                }
13587                add_prev($text, $stack, "\@$macro" . $cline);
13588                last;
13589            }
13590            elsif (defined($Texi2HTML::Config::def_map{$macro}))
13591            {
13592                # @ may protect end of line in @def. We reconstruct lines here.
13593                # in the texinfo manual is said that spaces after @ collapse
13594                if ($cline =~ /(\@+)\s*$/)
13595                {
13596                    my $at_at_end_of_line = $1;
13597                    if ((length($at_at_end_of_line) % 2) == 1)
13598                    {
13599                        #print STDERR "Line continue $cline";
13600                        my $def_line = $cline;
13601                        $def_line =~ s/\@\s*$//;
13602                        chomp($def_line);
13603                        $state->{'in_deff_line'} = "\@$macro" .$def_line;
13604                        return;
13605                    }
13606                }
13607                #We must enter the index entries
13608                my ($prefix, $entry, $argument) = get_deff_index($macro, $cline, $line_nr,1);
13609                # use deffn instead of deffnx for @-command record
13610                # associated with index entry
13611                my $idx_macro = $macro;
13612                $idx_macro =~ s/x$//;
13613                enter_index_entry($prefix, $line_nr, $entry, $idx_macro, $state)
13614                      if ($prefix);
13615                $cline =~ s/(.*)//;
13616                add_prev($text, $stack, "\@$macro" . $1);
13617            }
13618            elsif ($macro =~ /^itemx?$/)
13619            {
13620                enter_table_index_entry($text, $stack, $state, $line_nr);
13621                if ($state->{'table_stack'}->[-1] =~ /^(v|f)?table$/)
13622                {
13623                    $state->{'item'} = $macro;
13624                    push @$stack, { 'format' => 'index_item', 'text' => '', 'command' => $macro };
13625                }
13626                else
13627                {
13628                   add_prev($text, $stack, "\@$macro");
13629                }
13630            }
13631            elsif ($format_type{$macro} and ($format_type{$macro} eq 'table' or $format_type{$macro} eq 'list' or $macro eq 'multitable'))
13632            { # We must enter the index entries of (v|f)table thus we track
13633              # in which table we are
13634                push @{$state->{'table_stack'}}, $macro;
13635                add_prev($text, $stack, "\@$macro");
13636            }
13637            elsif ($cline =~ s/^{//)
13638            {
13639                if ($macro eq 'verb')
13640                {
13641                    if ($cline =~ /^$/)
13642                    {
13643                        # We already warned in pass texi
13644                    }
13645                    else
13646                    {
13647                        $cline =~ s/^(.)//;
13648                        $state->{'verb'} = $1;
13649                    }
13650                }
13651                elsif ($macro eq 'footnote' and (Texi2HTML::Config::get_conf('footnotestyle') eq 'separate'))
13652                {
13653                    $state->{'footnote_heading_element'} = $state->{'heading_element'};
13654                    $state->{'footnote_place'} = $state->{'place'};
13655                    $state->{'heading_element'} = $footnote_element;
13656                    $state->{'place'} = $footnote_element->{'place'};
13657                }
13658                push (@$stack, { 'style' => $macro, 'text' => '' });
13659            }
13660            else
13661            {
13662                $cline = do_unknown (1, $macro, $cline, $text, $stack, $state, $line_nr);
13663            }
13664            next;
13665        }
13666        #elsif($cline =~ s/^([^{}@]*)\@(.)//o)
13667        elsif($cline =~ s/^([^{}@]*)\@([^\s\}\{\@]*)//o)
13668        {
13669            add_prev($text, $stack, $1);
13670            $cline = do_unknown (1, $2, $cline, $text, $stack, $state, $line_nr);
13671            next;
13672        }
13673        elsif ($cline =~ s/^([^{}]*)([{}])//o)
13674        {
13675            add_prev($text, $stack, $1);
13676            if ($2 eq '{')
13677            {
13678                push @$stack, { 'style' => '', 'text' => '' };
13679            }
13680            else
13681            {
13682                if (@$stack)
13683                {
13684                    my $style = pop @$stack;
13685                    my $result;
13686                    add_prev ($text, $stack,
13687                        close_structure_command($style, $state, 0, $line_nr));
13688                    next;
13689                }
13690                else
13691                {
13692                    # We warn in the last pass
13693                    add_prev ($text, $stack, '}');
13694                }
13695            }
13696        }
13697        else
13698        {
13699            add_prev($text, $stack, $cline);
13700            # in case of user mistake, with an @-command not closed on an @item line
13701            close_stack_structure($text, $stack, $state, $line_nr, 1) if ($state->{'item'});
13702            enter_table_index_entry($text, $stack, $state, $line_nr);
13703            #print STDERR "END_LINE(s) $cline";
13704            #dump_stack($text, $stack, $state);
13705            last;
13706        }
13707    }
13708    return 1;
13709} # end scan_structure
13710
13711sub check_bad_end_argument ($$$)
13712{
13713  my $command = shift;
13714  my $line = shift;
13715  my $line_nr = shift;
13716
13717  if ($line =~ /^(\S+)/)
13718  {
13719    my $symbols = $1;
13720    line_error (sprintf(__("Bad argument `%s' to `\@%s', using `%s'"), "${command}${symbols}", 'end', $command), $line_nr);
13721  }
13722}
13723
13724sub close_style_command($$$$$;$)
13725{
13726  my $text = shift;
13727  my $stack = shift;
13728  my $state = shift;
13729  my $line_nr = shift;
13730  my $line = shift;
13731  # not the end of the style, but the paragraph the style is in is closed
13732  my $no_close = shift;
13733
13734  my $style = pop @$stack;
13735  my $command = $style->{'style'};
13736  my $result;
13737  if (!defined($command))
13738  {
13739     print STDERR "Bug: empty style in pass_text\n";
13740     return ($result, $command);
13741  }
13742  if (ref($::style_map_ref->{$command}) eq 'HASH')
13743  {
13744    push (@{$style->{'args'}}, $style->{'text'});
13745    $style->{'fulltext'} .= $style->{'text'};
13746    if (!defined($style->{'arg_nr'}))
13747    {
13748       msg_debug("Bug: undefined 'arg_nr' for $command", $line_nr);
13749    }
13750    #print STDERR "DEBUG $command ($style->{'arg_nr'})\n";
13751    #my $number = 0;
13752    #foreach my $arg(@{$style->{'args'}})
13753    #{
13754    #  print STDERR "  $number: $arg\n";
13755    #     $number++;
13756    #}
13757    #print STDERR "END DEBUG\n";
13758    $style->{'text'} = $style->{'fulltext'};
13759    $state->{'keep_texi'} = 0 if (
13760     ($::style_map_ref->{$command}->{'args'}->[$style->{'arg_nr'}] eq 'keep')
13761    and ($state->{'keep_nr'} == 1));
13762  }
13763  if ($no_paragraph_macro{$command})
13764  {
13765     $state->{'no_paragraph'}--;
13766     pop @{$state->{'no_paragraph_stack'}};
13767  }
13768  if ($::style_map_ref->{$command} and (defined($style_type{$command})) and ((!$no_close and ($style_type{$command} eq 'style')) or ($style_type{$command} eq 'accent')))
13769  {
13770    my $style_command = pop @{$state->{'command_stack'}};
13771    if ($style_command ne $command)
13772    {
13773      #line_warn ("Bug: $style_command on 'command_stack', not $command", $line_nr);
13774      # This can be a bug in case of bad nesting, see bad_style_nesting.texi
13775      line_warn("Bad nesting of \@$style_command and \@$command", $line_nr);
13776      push @{$state->{'command_stack'}}, $style_command;
13777    ############################ debug
13778      if ($T2H_DEBUG)
13779      {
13780        push @$stack, $style;
13781        print STDERR "Stacks before pop top:\n";
13782        dump_stack($text, $stack, $state);
13783        pop @$stack;
13784    ############################ end debug
13785      }
13786    }
13787  }
13788  if ($state->{'keep_texi'})
13789  { # don't expand @-commands in anchor, refs...
13790    close_arg ($command, $style->{'arg_nr'}, $state);
13791    $result = '@' . $command . '{' . $style->{'text'} . '}';
13792  }
13793  elsif ($::things_map_ref->{$command})
13794  {
13795    $result = do_thing_command ($command, $style->{'text'}, $state, $line_nr);
13796  }
13797  else
13798  {
13799    $result = do_style_command($command, $style->{'text'}, $state, $style->{'args'}, $line_nr, $style->{'no_open'}, $no_close, $style->{'keep_line_nr'});
13800    if ($state->{'code_style'} < 0)
13801    {
13802      msg_debug ("Bug: negative code_style: $state->{'code_style'}, line:$line", $line_nr);
13803    }
13804    if ($state->{'math_style'} < 0)
13805    {
13806      msg_debug ("Bug: negative math_style: $state->{'math_style'}, line:$line", $line_nr);
13807    }
13808  }
13809  return ($result, $command);
13810}
13811
13812sub top_stack_is_menu($)
13813{
13814   my $stack = shift;
13815   my $top_stack = top_stack($stack, 1);
13816   return 0 if (!$format_type{$top_stack->{'format'}} or $format_type{$top_stack->{'format'}} ne 'menu');
13817   return 1;
13818}
13819
13820
13821sub scan_line($$$$;$)
13822{
13823    my $original_line = shift;
13824    my $text = shift;
13825    my $stack = shift;
13826    my $state = shift;
13827    my $line_nr = shift;
13828
13829    die "stack not an array ref"  unless (ref($stack) eq "ARRAY");
13830    my $cline = $original_line;
13831    #msg_debug("SCAN_LINE (@{$state->{'command_stack'}}): $original_line", $line_nr);
13832    #dump_stack($text, $stack, $state);
13833    my $new_menu_entry; # true if there is a new menu entry
13834#    my $menu_description_in_format; # true if we are in a menu description
13835#                                # but in another format section (@table....)
13836
13837    # this can happen currently with quotations
13838    if (defined($state->{'prepend_text'}))
13839    {
13840        $cline = $state->{'prepend_text'} . $cline;
13841        $state->{'prepend_text'} = undef;
13842        delete $state->{'prepend_text'};
13843    }
13844
13845    if (!$state->{'raw'} and !$state->{'verb'} and ($state->{'menu'} or $state->{'direntry'}))
13846    { # new menu entry
13847        my ($node, $name, $ending, $remaining) = parse_menu_entry($cline);
13848        if (defined($node))
13849        {
13850            $cline = $remaining;
13851            print STDERR "# Potential menu entry: $node\n" if ($T2H_DEBUG & $DEBUG_MENU);
13852            $new_menu_entry = 1;
13853            my $menu_entry = { 'name' => $name, 'node' => $node, 'ending' => $ending };
13854            # in SIMPLE_MENU case we don't begin a description, description is
13855            # just some normal (preformatted) text
13856            if ($Texi2HTML::Config::SIMPLE_MENU)
13857            {
13858                add_prev ($text, $stack, do_menu_link($state, $line_nr, $menu_entry));
13859                #dump_stack($text, $stack, $state);
13860            }
13861            else
13862            {
13863                # close description and comment, if they are opened.
13864                #dump_stack($text, $stack, $state);
13865                if (!close_menu_comment($text, $stack, $state, __("new menu entry"), $line_nr)
13866                  and !close_menu_description($text, $stack, $state, __("new menu entry"), $line_nr)
13867                  and $state->{'preformatted'})
13868                {
13869                    close_paragraph($text, $stack, $state, __("new menu entry"), $line_nr);
13870                }
13871                print STDERR "# New menu entry: $node\n" if ($T2H_DEBUG & $DEBUG_MENU);
13872                #dump_stack($text, $stack, $state);
13873                my $fusionned_description = 0;
13874                # fusionned looks better in preformatted. But some formats
13875                # want to always distinguish link and description
13876                if ($Texi2HTML::Config::SEPARATE_DESCRIPTION or !$state->{'preformatted'})
13877                {
13878                    add_prev ($text, $stack, do_menu_link($state, $line_nr, $menu_entry));
13879                }
13880                else
13881                {
13882                    $fusionned_description = 1;
13883                }
13884                push @$stack, {'format' => 'menu_description', 'text' => '', 'menu_entry' => $menu_entry, 'fusionned_description' => $fusionned_description};
13885                $state->{'code_style'}++ if ($Texi2HTML::Config::format_code_style{'menu_description'});
13886                if ($fusionned_description)
13887                {
13888                    begin_paragraph($stack, $state) if $state->{'preformatted'};
13889                    add_prev ($text, $stack, do_menu_link($state, $line_nr, $menu_entry));
13890                }
13891             }
13892        }
13893        # we may be in a menu entry description, we close it
13894        # if there is an empty line, so the last arg is $cline.
13895        # also if right in menu we always open a menu_comment, it
13896        # means that there was no menu entry seen since the menu beginning.
13897        if (!$new_menu_entry and (close_menu_description($text, $stack, $state, "end menu description", $line_nr, $cline) or ($stack->[-1]->{'format'} and $format_type{$stack->[-1]->{'format'}} and $format_type{$stack->[-1]->{'format'}} eq 'menu')))
13898        {
13899            if ($state->{'preformatted'})
13900            {
13901                begin_paragraph($stack, $state);
13902            }
13903            else
13904            {
13905               # only start a menu_comment if right in menu and not in
13906               # a format below a menu because if not right
13907               # in a menu we have no way to distinguish a menu_comment
13908               # and some normal text in the format.
13909               # also it is not started in preformatted environment
13910               begin_format($text, $stack, $state, 'menu_comment', $cline, $line_nr) if ($stack->[-1]->{'format'} and $format_type{$stack->[-1]->{'format'}} and $format_type{$stack->[-1]->{'format'}} eq 'menu');
13911            }
13912        }
13913    }
13914
13915    unless ($state->{'raw'} or $state->{'verb'} or $state->{'keep_texi'})
13916    {
13917    # first the line commands are taken into account
13918        my $next_command = next_tag($cline);
13919        if (defined($next_command) and defined($Texi2HTML::Config::line_command_map{$next_command}))
13920        {
13921            close_paragraph($text, $stack, $state, "\@$next_command", $line_nr, 1) if (stop_paragraph_command($next_command));
13922            my $arg_texi = $cline;
13923            $arg_texi =~ s/^\s*\@$next_command\s*//;
13924            $arg_texi = trim_comment_spaces ($arg_texi, "\@$next_command", $line_nr);
13925            my $arg_line = substitute_line($arg_texi, "\@$next_command", duplicate_formatting_state($state));
13926            add_prev ($text, $stack, &$Texi2HTML::Config::line_command($next_command, $arg_line, $arg_texi, $state));
13927            enter_author_command ($next_command, $arg_texi, $arg_line, $stack, $state, $line_nr);
13928            return '';
13929        }
13930        elsif (defined($next_command) and ($next_command eq 'contents') or ($next_command eq 'summarycontents') or ($next_command eq 'shortcontents'))
13931        {
13932            my $element_tag = $next_command;
13933            $element_tag = 'shortcontents' if ($element_tag ne 'contents');
13934            # at that point the content_element is defined for sure since
13935            # we already saw the tag
13936            if ($Texi2HTML::Config::INLINE_CONTENTS and !Texi2HTML::Config::get_conf('set' . $element_tag . 'aftertitlepage'))
13937            {
13938                my $content_element = shift (@{$all_content_elements{$element_tag}});
13939                my $toc_lines = &$Texi2HTML::Config::inline_contents($Texi2HTML::THISDOC{'FH'}, $element_tag, $content_element, \@sections_list);
13940                add_prev ($text, $stack, join('',@$toc_lines)) if (defined($toc_lines));
13941            }
13942            return '' unless (exists($Texi2HTML::Config::misc_command{$next_command}) and $Texi2HTML::Config::misc_command{$next_command}->{'keep'});
13943        }
13944
13945    # The commands to ignore are ignored now in case after ignoring them
13946    # there is an empty line, to be able to stop the paragraph
13947        #my $leading_spaces = '';
13948
13949        while (1)
13950        {
13951            my $next_tag = next_tag($cline);
13952            close_paragraph($text, $stack, $state, "\@$next_tag", $line_nr, 1) if (stop_paragraph_command($next_tag));
13953            if (defined($next_tag) and defined($Texi2HTML::Config::misc_command{$next_tag}) and !$Texi2HTML::Config::misc_command{$next_tag}->{'keep'})
13954            {
13955                $cline =~ s/^(\s*)\@$next_tag//;
13956                #$leading_spaces .= $1;
13957                add_prev ($text, $stack, do_text($1, $state));
13958                my $result;
13959                ($cline, $result) = misc_command_text($cline, $next_tag, $stack, $state, $text, $line_nr);
13960                add_prev($text, $stack, $result) if (defined($result));
13961            }
13962            else
13963            {
13964                last;
13965            }
13966        }
13967        #add_prev ($text, $stack, $leading_spaces);
13968        return '' if (!defined($cline) or $cline eq '');
13969    }
13970    my $top_stack = top_stack($stack);
13971    if (($top_stack->{'format'} and $top_stack->{'format'} eq 'menu_description') or $state->{'raw'} or $state->{'preformatted'}  or $state->{'no_paragraph'} or $state->{'keep_texi'} or $state->{'remove_texi'})
13972    { # empty lines are left unmodified in these contexts.
13973      # it is also possible to be in preformatted within a menu_description
13974        if ($cline =~ /^\s*$/)
13975        {
13976            if ($state->{'raw'})
13977            {
13978                print STDERR "#within raw $state->{'raw'}(empty line):$cline" if ($T2H_DEBUG & $DEBUG_FORMATS);
13979                add_prev($text, $stack, $cline);
13980            }
13981            else
13982            {
13983                add_prev($text, $stack, do_text($cline,$state));
13984            }
13985            return;
13986        }
13987    }
13988    else
13989    {
13990        if ($cline =~ /^\s*$/)
13991        {
13992            if ($state->{'paragraph_context'})
13993            { # An empty line ends a paragraph
13994                close_paragraph($text, $stack, $state, __("paragraph end"), $line_nr);
13995            }
13996            add_prev($text, $stack, &$Texi2HTML::Config::empty_line($cline,$state));
13997            return 1;
13998        }
13999        else
14000        {
14001            if (!no_paragraph($state,$cline))
14002            { # open a paragraph, unless the line begins with a macro that
14003              # shouldn't trigger a paragraph opening
14004                begin_paragraph($stack, $state);
14005            }
14006        }
14007    }
14008    # we flag specially deff_item and table line that contain only
14009    # inter_item_command, which typically is be @c, @comment, @*index, such
14010    # that the formatter can treat those specifically.
14011    my $top_format = top_stack($stack,2);
14012    if ($top_format->{'only_inter_commands'} and !$state->{'keep_texi'})
14013    {
14014        my $real_format = $top_format->{'format_ref'}->{'format'};
14015        my $next_tag = next_tag($cline);
14016        $next_tag = '' if (!defined($next_tag));
14017        my $next_end_tag = next_end_tag($cline);
14018        $next_end_tag = '' if (!defined($next_end_tag));
14019        #msg_debug("$top_format->{'format'} $next_tag, end $next_end_tag :::$cline");
14020        delete $top_format->{'only_inter_commands'} unless
14021         (
14022          $Texi2HTML::Config::inter_item_commands{$next_tag} or
14023          (index_command_prefix($next_tag) ne '' and $Texi2HTML::Config::inter_item_commands{'cindex'}) or
14024          ($top_format->{'format'} eq 'deff_item' and "${real_format}x" eq $next_tag) or
14025          ($top_format->{'format'} ne 'deff_item' and $next_tag =~ /^itemx?$/) or
14026          ( $next_end_tag eq $real_format )
14027         );
14028          #print STDERR "STILL $top_format->{'only_inter_commands'}\n" if ($top_format->{'only_inter_commands'});
14029    }
14030
14031    while(1)
14032    {
14033        # scan_line
14034        #print STDERR "WHILE(l): $cline|";
14035        #msg_debug("Dump stack in scan_line", $line_nr);
14036        #dump_stack($text, $stack, $state);
14037        # we're in a raw format (html, tex if !L2H, verbatim)
14038        if (defined($state->{'raw'}))
14039        {
14040            (dump_stack($text, $stack, $state), die "Bug for raw ($state->{'raw'})") if (! @$stack or ! ($stack->[-1]->{'style'} eq $state->{'raw'}));
14041            if ($state->{'raw'} eq 'macro')
14042            {
14043                if ($cline =~ /^\s*\@macro\s+(\w[\w-]*)\s*(.*)/)
14044                {
14045                    $state->{$state->{'raw'}}++;
14046                }
14047            }
14048            # macro_regexp
14049            if ($cline =~ /^(.*?)\@end\s([a-zA-Z][\w-]*)/o and ($2 eq $state->{'raw'}))
14050            # don't protect html, it is done by Texi2HTML::Config::raw if needed
14051            {
14052                $cline =~ s/^(.*?)(\@end\s$state->{'raw'})//;
14053                my $remaining = $1;
14054                my $end_text = $2;
14055                if ($state->{'raw'} eq 'macro')
14056                {
14057                    $state->{$state->{'raw'}}--;
14058                    if ($state->{$state->{'raw'}})
14059                    {
14060                        add_prev ($text, $stack, $remaining.$end_text);
14061                        last;
14062                    }
14063                }
14064                check_bad_end_argument ($state->{'raw'}, $cline, $line_nr);
14065                add_prev ($text, $stack, $remaining);
14066                my $style = pop @$stack;
14067                if ($style->{'text'} !~ /^\s*$/)
14068                {
14069                    if ($state->{'keep_texi'})
14070                    {
14071                        add_prev ($text, $stack, $style->{'text'} . "\@end $state->{'raw'}");
14072                    }
14073                    elsif ($state->{'remove_texi'})
14074                    {
14075                        add_prev ($text, $stack, &$Texi2HTML::Config::raw_no_texi($style->{'style'}, $style->{'text'}));
14076                    }
14077                    else
14078                    {
14079                        add_prev($text, $stack, &$Texi2HTML::Config::raw($style->{'style'}, $style->{'text'}, $line_nr));
14080                    }
14081                }
14082                if (!$state->{'keep_texi'} and !$state->{'remove_texi'})
14083                {
14084                    # reopen preformatted if it was interrupted by the raw format
14085                    # if raw format is html the preformatted wasn't interrupted
14086                    begin_paragraph($stack, $state) if ($state->{'preformatted'} and (!$Texi2HTML::Config::format_in_paragraph{$state->{'raw'}}));
14087                    delete $state->{'raw'};
14088                    return if ($cline =~ /^\s*$/);
14089                }
14090                delete $state->{'raw'};
14091                return if (($cline =~ /^\s*$/) and $state->{'remove_texi'});
14092                next;
14093            }
14094            else
14095            {
14096                print STDERR "#within raw $state->{'raw'}:$cline" if ($T2H_DEBUG & $DEBUG_FORMATS);
14097                add_prev ($text, $stack, $cline);
14098                last;
14099            }
14100        }
14101
14102        # we are within a @verb
14103        if (defined($state->{'verb'}))
14104        {
14105            my $char = quotemeta($state->{'verb'});
14106            if ($cline =~ s/^(.*?)$char\}/\}/)
14107            {
14108                 if ($state->{'keep_texi'})
14109                 {
14110                     add_prev($text, $stack, $1 . $state->{'verb'});
14111                     $stack->[-1]->{'text'} = $state->{'verb'} . $stack->[-1]->{'text'};
14112                 }
14113                 else
14114                 {
14115                     add_prev($text, $stack, do_text($1, $state));
14116                 }
14117                 delete $state->{'verb'};
14118                 next;
14119            }
14120            else
14121            {
14122                 add_prev($text, $stack, $cline);
14123                 last;
14124            }
14125        }
14126
14127        # We handle now the end tags
14128        # macro_regexp
14129        if ($cline =~ s/^([^{}@]*)\@end\s+([a-zA-Z][\w-]*)//)
14130        {
14131            my $end_tag = $2;
14132            my $prev_text = $1;
14133            if ($state->{'keep_texi'})
14134            {
14135                add_prev($text, $stack, $prev_text . "\@end $end_tag");
14136                next;
14137            }
14138            elsif ($state->{'remove_texi'})
14139            {
14140                add_prev($text, $stack, $prev_text);
14141                next;
14142            }
14143
14144            add_prev($text, $stack, do_text($prev_text, $state));
14145	    #print STDERR "END_MACRO $end_tag\n";
14146	    #dump_stack ($text, $stack, $state);
14147
14148            # First we test if the stack is not empty.
14149            # Then we test if the end tag is a format tag.
14150            # We then close paragraphs and preformatted at top of the stack.
14151            # We handle the end tag (even when it was not the tag which appears
14152            # on the top of the stack; in that case we close anything
14153            # until that element)
14154            my $top_stack = top_stack($stack);
14155            if (!$top_stack)
14156            {
14157                line_error (sprintf(__("Unmatched `%c%s'"), ord('@'), 'end'), $line_nr);
14158                add_prev($text, $stack, "\@end $end_tag");
14159                next;
14160            }
14161
14162            if (!$format_type{$end_tag})
14163            {
14164                line_warn ("Unknown \@end $end_tag", $line_nr);
14165                add_prev($text, $stack, "\@end $end_tag");
14166                next;
14167            }
14168            check_bad_end_argument ($end_tag, $cline, $line_nr);
14169            if (!close_menu_description($text, $stack, $state, "\@end $end_tag", $line_nr))
14170            {
14171               close_paragraph($text, $stack, $state, "\@end $end_tag", $line_nr);
14172            }
14173
14174            $top_stack = top_stack($stack);
14175            if (!$top_stack or (!defined($top_stack->{'format'})))
14176            {
14177                line_error (sprintf(__("Unmatched `%c%s'"), ord('@'), 'end'), $line_nr);
14178                add_prev($text, $stack, "\@end $end_tag");
14179                dump_stack ($text, $stack, $state) if ($T2H_DEBUG);
14180                next;
14181            }
14182            # Warn if the format on top of stack is not compatible with the
14183            # end tag, and find the end tag.
14184            unless (
14185                ($top_stack->{'format'} eq $end_tag)
14186                or
14187                (
14188                 $format_type{$end_tag} eq 'menu' and
14189                  $top_stack->{'format'} eq 'menu_comment'
14190                ) or
14191                (
14192                 $end_tag eq 'multitable' and $top_stack->{'format'} eq 'cell'
14193                ) or
14194                (
14195                 $format_type{$end_tag} eq 'list' and $top_stack->{'format'} eq 'item'
14196                ) or
14197                (
14198                  $format_type{$end_tag} eq 'table'
14199                  and
14200                  ($top_stack->{'format'} eq 'term' or $top_stack->{'format'} eq 'line')
14201                ) or
14202                (
14203                 defined($Texi2HTML::Config::def_map{$end_tag}) and
14204                 $top_stack->{'format'} eq 'deff_item'
14205                )
14206               )
14207            {
14208                # this is not the right format. We try to close other
14209                # formats to find the format we are searching for.
14210                # First we close paragraphs, as with a wrong $end_format
14211                # they may not be closed properly.
14212
14213                #print STDERR "  MISMATCH got $top_stack->{'format'} waited \@end $end_tag($top_stack->{'format'})\n";
14214                #dump_stack ($text, $stack, $state);
14215                close_paragraph($text, $stack, $state, "\@end $end_tag", $line_nr);
14216                $top_stack = top_stack($stack);
14217                if (!$top_stack or (!defined($top_stack->{'format'})))
14218                {
14219                    line_error (sprintf(__("Unmatched `%c%s'"), ord('@'), 'end'), $line_nr);
14220                    add_prev($text, $stack, "\@end $end_tag");
14221                    # at that point the dump_stack is not very useful, since
14222                    # close_paragraph above may hide interesting info
14223                    dump_stack ($text, $stack, $state) if ($T2H_DEBUG);
14224                    next;
14225                }
14226                my $waited_format = $top_stack->{'format'};
14227                $waited_format = $fake_format{$top_stack->{'format'}} if ($format_type{$top_stack->{'format'}} eq 'fake');
14228                if ($end_tag ne $waited_format)
14229                {
14230                    line_error (sprintf(__("`\@end' expected `%s', but saw `%s'"), $waited_format, $end_tag), $line_nr);
14231                }
14232                else
14233                {
14234                    msg_debug ("\@end is $end_tag, was waiting for $top_stack->{'format'}", $line_nr);
14235                    dump_stack ($text, $stack, $state);
14236                }
14237                close_stack($text, $stack, $state, $line_nr, $end_tag);
14238                # FIXME this is too complex
14239                # an empty preformatted may appear when closing things as
14240                # when closed, formats reopen the preformatted environment
14241                # in case there is some text following, but we know it isn't
14242                # the case here, thus we can close paragraphs.
14243                close_paragraph($text, $stack, $state, "\@end $end_tag");
14244                my $new_top_stack = top_stack($stack);
14245                next unless ($new_top_stack and defined($new_top_stack->{'format'}) and (($new_top_stack->{'format'} eq $end_tag)
14246                   or (($format_type{$new_top_stack->{'format'}} eq 'fake') and ($fake_format{$new_top_stack->{'format'}} eq $format_type{$end_tag}))));
14247            }
14248            # We should now be able to handle the format
14249            if (defined($format_type{$end_tag}))
14250            {# remove the space or new line following the @end command
14251                $cline =~ s/\s//;
14252                if (end_format($text, $stack, $state, $end_tag, $line_nr))
14253                { # if end_format is false, paragraph is already begun
14254                    begin_paragraph_after_command($state,$stack,$end_tag,$cline);
14255                }
14256            }
14257            next;
14258        }
14259        # This is a macro
14260	#elsif (s/^([^{}@]*)\@([a-zA-Z]\w*|["'~\@\}\{,\.!\?\s\*\-\^`=:\/])//o)
14261        # macro_regexp
14262        elsif ($cline =~ s/^([^{},@]*)\@(["'~\@\}\{,\.!\?\s\*\-\^`=:\|\/\\])//o or $cline =~ s/^([^{}@,]*)\@([a-zA-Z][\w-]*)//o)
14263        {
14264            my $before_macro = $1;
14265            my $macro = $2;
14266            $macro = $alias{$macro} if (exists($alias{$macro}));
14267            my $punct;
14268            if (!$state->{'keep_texi'} and $macro eq ':' and $before_macro =~ /(.)$/ and $Texi2HTML::Config::colon_command_punctuation_characters{$1})
14269            {
14270                $before_macro =~ s/(.)$//;
14271                $punct = $1;
14272            }
14273            add_prev($text, $stack, do_text($before_macro, $state));
14274            add_prev($text, $stack, &$Texi2HTML::Config::colon_command($punct)) if (defined($punct));
14275	    #print STDERR "MACRO $macro\n";
14276	    #print STDERR "LINE $cline";
14277	    #dump_stack ($text, $stack, $state);
14278
14279            close_paragraph($text, $stack, $state, "\@$macro", $line_nr, 1) if (stop_paragraph_command($macro) and !$state->{'keep_texi'});
14280
14281            if ($macro eq 'listoffloats' or $macro eq 'printindex')
14282            {
14283                if ($state->{'keep_texi'})
14284                {
14285                    if ($cline =~ s/(.*)//o)
14286                    {
14287                        add_prev($text, $stack, "\@$macro" . $1);
14288                    }
14289                    next;
14290                }
14291                close_paragraph($text, $stack, $state, "\@$macro", $line_nr);
14292                return undef if ($state->{'remove_texi'});
14293                if ($macro eq 'listoffloats')
14294                {
14295                    # remove possible comments
14296                    my $arg = normalise_texi_space(trim_comment_spaces ($cline, "\@$macro", $line_nr));
14297
14298                    my $style_id = cross_manual_line($arg);
14299                    my $style = substitute_line (&$Texi2HTML::Config::listoffloats_style($arg), __("\@listoffloats type"), undef, $line_nr);
14300                    my $style_no_texi = remove_texi (&$Texi2HTML::Config::listoffloats_style($arg));
14301                    if (exists ($floats{$style_id}))
14302                    {
14303                         my @listoffloats_entries = ();
14304                         foreach my $float (@{$floats{$style_id}->{'floats'}})
14305                         {
14306                              my $float_style = substitute_line(&$Texi2HTML::Config::listoffloats_float_style($arg, $float), __("\@listoffloats \@float type"));
14307                              my ($caption_lines, $caption_or_shortcaption) = &$Texi2HTML::Config::listoffloats_caption($float);
14308                              # we set 'multiple_pass', and 'expansion'
14309                              # such that index entries
14310                              # and anchors are not handled one more time;
14311                              # the caption has already been formatted,
14312                              # and these have been handled at the right place
14313                              # FIXME footnotes?
14314                              my $caption = '';
14315                              $caption = substitute_text(prepare_state_multiple_pass($macro, $state), undef, "\@$caption_or_shortcaption in listoffloats", @$caption_lines) if (defined($caption_or_shortcaption));
14316                              push @listoffloats_entries, &$Texi2HTML::Config::listoffloats_entry($arg, $float, $float_style, $caption, href($float, $state->{'element'}->{'file'}, $line_nr));
14317                         }
14318                         add_prev($text, $stack, &$Texi2HTML::Config::listoffloats($arg, $style, \@listoffloats_entries));
14319                    }
14320                    else
14321                    {
14322                         line_warn (sprintf(__("Requested float type `%s' not previously used"), $arg), $line_nr);
14323                    }
14324                }
14325                elsif ($macro eq 'printindex' and $cline =~ s/\s+(\w+)\s*//)
14326                {
14327                    my $index_name = $1;
14328                    my $region = $state->{'region'};
14329                    $region = 'document' if (!defined($region));
14330
14331                    if (!defined($Texi2HTML::THISDOC{'indices'}->{$region}))
14332                    {
14333                      msg_debug ("\@printindex $index_name THISDOC{'indices'}->{$region} not defined", $line_nr);
14334                    }
14335                    elsif (!defined($Texi2HTML::THISDOC{'indices'}->{$region}->{$index_name}))
14336                    {
14337                      msg_debug ("\@printindex $index_name THISDOC{'indices'}->{$region}->{$index_name} not defined", $line_nr);
14338                    }
14339
14340                    if (!defined($Texi2HTML::THISDOC{'indices_numbers'}->{$region}->{$index_name}))
14341                    {
14342                      $Texi2HTML::THISDOC{'indices_numbers'}->{$region}->{$index_name} = -1;
14343                    }
14344                    $Texi2HTML::THISDOC{'indices_numbers'}->{$region}->{$index_name}++;
14345                    my $printindex = $Texi2HTML::THISDOC{'indices'}->{$region}->{$index_name}->[$Texi2HTML::THISDOC{'indices_numbers'}->{$region}->{$index_name}];
14346                    if (!defined($printindex))
14347                    {
14348                      # this printindex hasn't been seen in the previous pass.
14349                      # rint STDERR "Index $index_name not in sync, number $Texi2HTML::THISDOC{'indices_numbers'}->{$index_name} not defined\n";
14350                      line_warn("\@printindex $index_name expanded more than once may lead to wrong references", $line_nr);
14351                      $printindex = $Texi2HTML::THISDOC{'indices'}->{$region}->{$index_name}->[-1];
14352                    }
14353                    elsif ($printindex->{'name'} ne $index_name)
14354                    {
14355                      print STDERR "BUG: THISDOC{'indices'} $printindex->{'name'} ne $index_name\n";
14356                    }
14357                    #print STDERR "PRINTINDEX use($printindex) region $region, name $index_name number $Texi2HTML::THISDOC{'indices_numbers'}->{$region}->{$index_name}\n";
14358                    add_prev($text, $stack, &$Texi2HTML::Config::printindex($index_name, $printindex));
14359                }
14360                else
14361                {
14362                    $cline =~ s/^\s*//;
14363                    chomp ($cline);
14364                    line_error (sprintf(__("Bad argument to \@%s: %s"), $macro, $cline), $line_nr);
14365                }
14366                begin_paragraph ($stack, $state) if ($state->{'preformatted'});
14367                return undef;
14368            }
14369            if (defined($Texi2HTML::Config::misc_command{$macro}))
14370            {
14371                # Handle the misc command
14372                my $result;
14373                ($cline, $result) = misc_command_text($cline, $macro, $stack, $state, $text, $line_nr);
14374                add_prev($text, $stack, $result) if (defined($result));
14375                return unless (defined($cline));
14376                unless ($Texi2HTML::Config::misc_command{$macro}->{'keep'})
14377                {
14378                     begin_paragraph($stack, $state) if
14379                       (!no_paragraph($state,$cline));
14380                     next;
14381                }
14382            }
14383            # This is a @macroname{...} construct. We add it on top of stack
14384            # It will be handled when we encounter the '}'
14385            # There is a special case for def macros as @deffn{def} is licit
14386            if (!$Texi2HTML::Config::def_map{$macro} and $cline =~ s/^{//) #}
14387            {
14388                if ($macro eq 'verb')
14389                {
14390                    if ($cline =~ /^$/)
14391                    {
14392                        # Allready warned
14393                    }
14394                    else
14395                    {
14396                        $cline =~ s/^(.)//;
14397                        $state->{'verb'} = $1;
14398                    }
14399                }
14400                # currently if remove_texi and anchor/ref/footnote
14401                # the text within the command is ignored
14402                # see t2h_remove_command in texi2html.init
14403                my $new_command_ref = { 'style' => $macro, 'text' => '', 'arg_nr' => 0, 'line_nr' => $line_nr };
14404                push (@$stack, $new_command_ref);
14405                if ($no_paragraph_macro{$macro})
14406                {
14407                   $state->{'no_paragraph'}++;
14408                   push @{$state->{'no_paragraph_stack'}}, "\@$macro";
14409                }
14410                open_arg($macro, 0, $state);
14411                if ($state->{'keep_texi'})
14412                {
14413                   $new_command_ref->{'keep_line_nr'} = [ $line_nr ];
14414                }
14415                my $real_style_command = 0;
14416                if (defined($style_type{$macro}) and (($style_type{$macro} eq 'style') or ($style_type{$macro} eq 'accent')))
14417                {
14418                     push (@{$state->{'command_stack'}}, $macro);
14419                     $real_style_command = 1;
14420                     #print STDERR "# Stacked $macro (@{$state->{'command_stack'}})\n" if ($T2H_DEBUG);
14421                }
14422                # FIXME give line, and modify line?
14423                &$Texi2HTML::Config::begin_style_texi($macro, $state, $stack, $real_style_command, $state->{'remove_texi'})
14424                  if (defined($Texi2HTML::Config::begin_style_texi)
14425                      and !($state->{'keep_texi'}));
14426                next;
14427            }
14428
14429            # special case if we are checking itemize line. In that case
14430            # we want to make sure that there is no @item on the @itemize
14431            # line, otherwise it will be added on the front of another @item,
14432            # leading to an infinite loop...
14433
14434            if ($state->{'check_item'} and ($macro =~ /^itemx?$/ or $macro eq 'headitem'))
14435            {
14436                line_error(sprintf(__("\@%s not allowed in argument to \@%s"), $macro, $state->{'check_item'}), $line_nr);
14437                next;
14438            }
14439
14440            # if we're keeping texi unmodified we can do it now
14441            if ($state->{'keep_texi'})
14442            {
14443                # We treat specially formats accepting {} on command line
14444                if ($macro eq 'multitable' or defined($Texi2HTML::Config::def_map{$macro}) or defined($sec2level{$macro}) or $macro eq 'macro')
14445                {
14446                    add_prev($text, $stack, "\@$macro" . $cline);
14447                    $cline = '';
14448                    next;
14449                }
14450
14451                add_prev($text, $stack, "\@$macro");
14452                if ($Texi2HTML::Config::texi_formats_map{$macro} and $Texi2HTML::Config::texi_formats_map{$macro} eq 'raw')
14453                {
14454                    $state->{'raw'} = $macro;
14455                    $state->{$macro}++ if ($macro eq 'macro');
14456                    push (@$stack, {'style' => $macro, 'text' => ''});
14457                }
14458                next;
14459            }
14460
14461            # If we are removing texi, the following macros are not removed
14462            # as is but modified. So they are collected first, as if we were
14463            # in normal text
14464
14465            # a raw macro beginning
14466            if ($Texi2HTML::Config::texi_formats_map{$macro} and $Texi2HTML::Config::texi_formats_map{$macro} eq 'raw')
14467            {
14468                if (!$Texi2HTML::Config::format_in_paragraph{$macro})
14469                { # close paragraph before verbatim (and tex if !L2H)
14470                    close_paragraph($text, $stack, $state, "\@$macro", $line_nr);
14471                }
14472                $state->{'raw'} = $macro;
14473                push (@$stack, {'style' => $macro, 'text' => ''});
14474                $state->{$macro}++ if ($macro eq 'macro');
14475                return if ($cline =~ /^\s*$/ or ($macro eq 'macro'));
14476                next;
14477            }
14478            my $simple_macro = 1;
14479            # An accent macro
14480            if (exists($Texi2HTML::Config::accent_map{$macro}))
14481            {
14482                # the command itself is not in the command stack, since with
14483                # braces, it is already popped when do_simple is called
14484                #push (@{$state->{'command_stack'}}, $macro);
14485                if ($macro =~ /^[a-zA-Z]/)
14486                {
14487                    $cline =~ s/^\s*//;
14488                }
14489                elsif ($cline =~ /^\s/)
14490                {
14491                    line_warn (sprintf(__("Accent command `\@%s' must not be followed by whitespace"), $macro), $line_nr);
14492                }
14493                if ($cline =~ /^\@/)
14494                {
14495                    line_error (sprintf(__("Use braces to give a command as an argument to \@%s"), $macro), $line_nr);
14496                }
14497                if ($cline =~ s/^(\S)//o)
14498                {
14499                    add_prev($text, $stack, do_style_command($macro, $1, $state, [ $1 ], $line_nr, undef, undef, undef));
14500                }
14501                else
14502                { # The accent is at end of line
14503                    # FIXME warn? And test case? Maybe this is catched
14504                    # above, by "Accent command `@%s' must not be followed by whitespace"
14505                    # for commands with letter.
14506                    add_prev($text, $stack, do_text($macro, $state));
14507                }
14508                #pop @{$state->{'command_stack'}};
14509            }
14510            # an @-command which should be like @command{}. We handle it...
14511            elsif ($::things_map_ref->{$macro})
14512            {
14513                line_error (sprintf(__("\@%s expected braces"), $macro), $line_nr);
14514                add_prev($text, $stack, do_thing_command($macro, '', $state, $line_nr));
14515            }
14516            # an @-command like @command
14517            elsif (defined($::simple_map_ref->{$macro}) or ($state->{'math_style'} and defined($::simple_map_math_ref->{$macro})))
14518            {
14519                add_prev($text, $stack, do_simple_command($macro, $state, $line_nr));
14520            }
14521            else
14522            {
14523                $simple_macro = 0;
14524            }
14525            if ($simple_macro)
14526            {# if the macro didn't triggered a paragraph start it might now
14527                begin_paragraph($stack, $state) if
14528                   ($Texi2HTML::Config::no_paragraph_commands{$macro} and !no_paragraph($state,$cline));
14529                next;
14530            }
14531            # the following macros are modified or ignored if we are
14532            # removing texi, and they are not handled like macros in normal text
14533            if ($state->{'remove_texi'})
14534            {
14535                 # handle specially some macros
14536                 if ((index_command_prefix($macro) ne '') or
14537                      ($macro eq 'itemize') or
14538                      ($format_type{$macro} and ($format_type{$macro} eq 'table' or $format_type{$macro} eq 'quotation'))
14539                      or ($macro eq 'multitable'))
14540                 {
14541                      return;
14542                 }
14543                 elsif ($macro eq 'enumerate')
14544                 {
14545                      my $spec;
14546                      ($cline, $spec) = parse_enumerate ($cline);
14547                      return if ($cline =~ /^\s*$/);
14548                      next;
14549                 }
14550                 elsif (defined($Texi2HTML::Config::def_map{$macro}))
14551                 {
14552                     my ($command, $style, $category, $name, $type, $class, $arguments, $args_array);
14553                     ($command, $style, $category, $name, $type, $class, $arguments, $args_array) = parse_def($macro, $cline, $line_nr);
14554                     # FIXME -- --- ''... lead to simple text in texi2html
14555                     # while they are kept as is in html coments by makeinfo
14556                     $category = remove_texi($category) if (defined($category));
14557                     $name = remove_texi($name) if (defined($name));
14558                     $type = remove_texi($type) if (defined($type));
14559                     $class = remove_texi($class) if (defined($class));
14560                     $arguments = remove_texi($arguments) if (defined($arguments));
14561                     chomp($arguments);
14562                     add_prev($text, $stack, &$Texi2HTML::Config::def_line_no_texi($category, $name, $type, $arguments));
14563                     return;
14564                }
14565                elsif (defined($sec2level{$macro}))
14566                { #FIXME  there is certainly more intelligent stuff to do
14567                    my $num;
14568                    if ($state->{'region'})
14569                    {
14570                        $state->{'head_num'}++;
14571                        $num = "$state->{'region'}_$state->{'head_num'}";
14572                    }
14573                    else
14574                    {
14575                        $num = $global_head_num;
14576                    }
14577                    my $heading_element = $headings{$num};
14578                    $cline = trim_comment_spaces ($cline, "\@$macro");
14579                    add_prev($text, $stack, &$Texi2HTML::Config::heading_no_texi($heading_element, $macro, $cline));
14580                    return;
14581                }
14582
14583                # ignore other macros
14584                next;
14585            }
14586
14587            # handle the other macros, we are in the context of normal text
14588            if (defined($sec2level{$macro}))
14589            {
14590                 #dump_stack($text, $stack, $state);
14591                 my $num;
14592                 if ($state->{'region'})
14593                 {
14594                     $state->{'head_num'}++;
14595                     $num = "$state->{'region'}_$state->{'head_num'}";
14596                 }
14597                 else
14598                 {
14599                     $global_head_num++;
14600                     $num = $global_head_num;
14601                 }
14602                 my $heading_element = $headings{$num};
14603                 $cline = trim_comment_spaces($cline, "\@$macro", $line_nr);
14604                 add_prev($text, $stack, &$Texi2HTML::Config::element_label($heading_element->{'id'}, $heading_element, $macro, $cline));
14605                 add_prev($text, $stack, &$Texi2HTML::Config::heading($heading_element, $macro, $cline, substitute_line($cline, "\@$macro"), $state->{'preformatted'}));
14606                 return;
14607            }
14608
14609            if (index_command_prefix($macro) ne '')
14610            {
14611                my $index_name = index_command_prefix($macro);
14612                my $entry_texi = trim_comment_spaces($cline, "\@$macro", $line_nr);
14613                chomp($entry_texi);
14614                # multiple_pass is not really necessary, since it may be the place
14615                # where it is expanded once. However, this ensures that things
14616                # that are ignored with multiple_pass are ignored.
14617                my $entry_text = substitute_line($entry_texi, "\@$macro", prepare_state_multiple_pass($macro, $state));
14618                my ($index_entry, $formatted_index_entry, $index_label) = do_index_entry_label($macro,$state,$line_nr, $entry_texi);
14619
14620                if (defined($index_entry))
14621                {
14622                   msg_debug ("(bug?) Index out of sync `$index_entry->{'texi'}' ne `$entry_texi'", $line_nr) if ($index_entry->{'texi'} ne $entry_texi);
14623                }
14624                add_prev($text, $stack, &$Texi2HTML::Config::index_entry_command($macro, $index_name, $index_label, $entry_texi, $entry_text, $index_entry));
14625                # it eats the end of line and therefore don't start
14626                # table entries nor close @center. These should be stopped
14627                # on the next line, though.
14628                return;
14629            }
14630            if ($macro eq 'insertcopying')
14631            {
14632                #close_paragraph($text, $stack, $state, $line_nr);
14633                add_prev($text, $stack, do_insertcopying($state, $line_nr));
14634                # reopen a preformatted format if it was interrupted by the macro
14635                begin_paragraph ($stack, $state) if ($state->{'preformatted'});
14636                return;
14637            }
14638            if ($macro =~ /^itemx?$/o or ($macro eq 'headitem'))
14639            {
14640		    #print STDERR "ITEM: $cline";
14641		    #dump_stack($text, $stack, $state);
14642                abort_empty_preformatted($stack, $state);
14643                # FIXME let the user be able not to close the paragraph
14644                close_paragraph($text, $stack, $state, "\@$macro", $line_nr);
14645
14646		    #print STDERR "ITEM after close para: $cline";
14647		    #dump_stack($text, $stack, $state);
14648                # these functions return the format if in the right context
14649                my $in_list_enumerate;
14650                my $format;
14651                if ($format = add_item($text, $stack, $state, $line_nr))
14652                { # handle lists
14653                    $in_list_enumerate = 1;
14654                    if ($macro ne 'item')
14655                    {
14656                        line_error (sprintf(__("\@%s not meaningful inside `\@%s' block"), $macro, $format->{'format'}), $line_nr);
14657                    }
14658                }
14659                elsif ($format = add_term($text, $stack, $state, $line_nr))
14660                { # close table term
14661                }
14662                elsif ($format = add_line($text, $stack, $state, $line_nr))
14663                { # close table definition
14664                }
14665                if ($format)
14666                {
14667                    if ($macro eq 'headitem')
14668                    {
14669                        line_error (sprintf(__("\@%s not meaningful inside `\@%s' block"), $macro, $format->{'format'}), $line_nr);
14670                    }
14671                    if (defined($Texi2HTML::Config::tab_item_texi))
14672                    {
14673                        my $resline = &$Texi2HTML::Config::tab_item_texi($macro, $state->{'command_stack'}, $stack, $state, $cline, $line_nr);
14674                        $cline = $resline if (defined($resline));
14675                    }
14676                    if ($in_list_enumerate)
14677                    {
14678                        push (@$stack, { 'format' => 'item', 'text' => '', 'format_ref' => $format, 'item_cmd' => $macro });
14679                        begin_paragraph($stack, $state) if ($state->{'preformatted'} or !no_line($cline));
14680                    }
14681                    else
14682                    {# handle table @item term and restart another one
14683                     # or after table text restart a term
14684                        push (@$stack, { 'format' => 'term', 'text' => '', 'format_ref' => $format, 'item_cmd' => $macro  });
14685                    }
14686                    $format->{'texi_line'} = $cline;
14687                    my ($line, $open_command) = &$Texi2HTML::Config::format_list_item_texi($format->{'format'}, $cline, $format->{'prepended'}, $format->{'command'}, $format->{'number'});
14688                    $cline = $line if (defined($line));
14689                    #if ($open_command)
14690                    #{
14691                    #     open_arg($format->{'command'},0, $state);
14692                    #     $format->{'command_opened'} = 1;
14693                    #}
14694                    $format->{'item_cmd'} = $macro;
14695                    $format->{'texi_line_texi_formatted'} = $cline;
14696                    next;
14697                }
14698                $format = add_row ($text, $stack, $state, $line_nr); # handle multitable
14699                if (!$format)
14700                { # makeinfo has:
14701                  # "@%s not meaningful inside `@%s' block" for menu/quotation...
14702                  # and, if outside of any format
14703                  # "%c%s found outside of an insertion block"
14704                  # The following error message seems better.
14705                    line_error (sprintf(__("\@%s outside of table or list"), $macro), $line_nr);
14706                }
14707                else
14708                {
14709                    push @$stack, {'format' => 'row', 'text' => '', 'item_cmd' => $macro, 'format_ref' => $format };
14710                    push @$stack, {'format' => 'cell', 'text' => '', 'format_ref' => $format};
14711                    $format->{'cell'} = 1;
14712                    if ($format->{'max_columns'})
14713                    {
14714                        if (defined($Texi2HTML::Config::tab_item_texi))
14715                        {
14716                            my $resline = &$Texi2HTML::Config::tab_item_texi($macro, $state->{'command_stack'}, $stack, $state, $cline, $line_nr);
14717                            $cline = $resline if (defined($resline));
14718                        }
14719                        begin_paragraph_after_command($state,$stack,$macro,$cline);
14720                    }
14721                    else
14722                    {
14723                        line_warn (sprintf(__("\@%s in empty multitable"), $macro), $line_nr);
14724                    }
14725                }
14726                next;
14727            }
14728
14729            if ($macro eq 'tab')
14730            {
14731                abort_empty_preformatted($stack, $state);
14732                # FIXME let the user be able not to close the paragraph?
14733                close_paragraph($text, $stack, $state, "\@$macro", $line_nr);
14734
14735                my $format = add_cell ($text, $stack, $state, $line_nr);
14736                if (!$format)
14737                {
14738                    line_error(__("ignoring \@tab outside of multitable"), $line_nr);
14739                }
14740                else
14741                {
14742                    push @$stack, {'format' => 'cell', 'text' => '', 'format_ref' => $format};
14743                    if (!$format->{'max_columns'})
14744                    {
14745                       line_warn (__("ignoring \@tab in empty multitable"), $line_nr);
14746                    }
14747                    elsif ($format->{'cell'} > $format->{'max_columns'})
14748                    {
14749                       line_error (sprintf(__("Too many columns in multitable item (max %d)"), $format->{'max_columns'}), $line_nr);
14750                    }
14751                    else
14752                    {
14753                       if (defined($Texi2HTML::Config::tab_item_texi))
14754                       {
14755                          my $resline = &$Texi2HTML::Config::tab_item_texi($macro, $state->{'command_stack'}, $stack, $state, $cline, $line_nr);
14756                          $cline = $resline if (defined($resline));
14757                       }
14758                    }
14759                }
14760                begin_paragraph_after_command($state,$stack,$macro,$cline);
14761                next;
14762            }
14763            # Macro opening a format (table, list, deff, example...)
14764            if ($format_type{$macro} and ($format_type{$macro} ne 'fake'))
14765            {
14766                my $ignore_center = 0;
14767                # @center is forbidden in @-command with braces, @*table
14768                # @item line, @multitable, or another @center
14769                if ($macro eq 'center' and @$stack)
14770                {
14771                   my $top_stack = top_stack($stack, 1);
14772                   if (exists($top_stack->{'style'}) or (defined($top_stack->{'format'}) and ($top_stack->{'format'} eq 'term' or $top_stack->{'format'} eq 'cell')) or $state->{'preformatted'} or $state->{'paragraph_style'}->[-1] eq 'center')
14773                   {
14774                       $ignore_center = 1;
14775                   }
14776                   #dump_stack ($text, $stack, $state);
14777                }
14778                if ($ignore_center)
14779                {
14780                    line_error(__("\@center should not appear in another format"), $line_nr);
14781                }
14782                else
14783                {
14784                    $cline = begin_format($text, $stack, $state, $macro, $cline, $line_nr);
14785                }
14786                # we keep the end of line for @center, and for formats
14787                # that have cmd_line opened and need to see the end of line
14788                next if (($macro eq 'center') or
14789                   (defined($Texi2HTML::Config::def_map{$macro}))
14790                   or ($macro eq 'float') or ($format_type{$macro} eq 'quotation'));
14791                return if ($cline =~ /^\s*$/);
14792                next;
14793            }
14794            $cline = do_unknown (2, $macro, $cline, $text, $stack, $state, $line_nr);
14795            next;
14796        }
14797        elsif($cline =~ s/^([^{}@,]*)\@([^\s\}\{\@]*)//o)
14798        { # A macro with a character which shouldn't appear in macro name
14799            add_prev($text, $stack, do_text($1, $state));
14800            $cline = do_unknown (2, $2, $cline, $text, $stack, $state, $line_nr);
14801            next;
14802        }
14803        # a brace
14804        elsif ($cline =~ s/^([^{},]*)([{}])//o)
14805        {
14806            my $leading_text = $1;
14807            my $brace = $2;
14808            add_prev($text, $stack, do_text($leading_text, $state));
14809            if (defined($brace) and ($brace eq '{')) #'}'
14810            {
14811                add_prev($text, $stack, do_text('{',$state)); #}
14812                if ($state->{'math_style'})
14813                {
14814                    $state->{'math_brace'}++;
14815                }
14816                else
14817                {
14818                    unless ($state->{'keep_texi'} or $state->{'remove_texi'})
14819                    {
14820                        line_error (sprintf(__("Misplaced %c"), ord('{')), $line_nr);
14821                    }
14822                }
14823            }
14824            elsif (defined($brace) and ($brace eq '}') and
14825                    (!@$stack or (!defined($stack->[-1]->{'style'}))
14826            # braces are allowed in math
14827                    or $state->{'math_brace'}))
14828            {
14829                if ($state->{'keep_texi'})
14830                {
14831                    add_prev($text, $stack, '}');
14832                }
14833                elsif($state->{'math_style'} and $state->{'math_brace'})
14834                {
14835                    add_prev($text, $stack, do_text('}',$state));
14836                    $state->{'math_brace'}--;
14837                }
14838                else
14839                {
14840                    line_error (sprintf(__("Misplaced %c"), ord('}')), $line_nr);
14841                    #dump_stack($text, $stack, $state);
14842                }
14843            }
14844            else
14845            { # A @-command{ ...} is closed
14846                my ($result, $command) = close_style_command($text, $stack, $state, $line_nr, $cline);
14847                add_prev($text, $stack, $result);
14848                if ($Texi2HTML::Config::no_paragraph_commands{$command}
14849                  and !$state->{'keep_texi'} and !no_paragraph($state,$cline))
14850                {
14851                   begin_paragraph($stack, $state);
14852                }
14853            }
14854        }
14855        elsif ($cline =~ s/^([^,]*)[,]//o)
14856        {
14857             add_prev($text, $stack, do_text($1, $state));
14858             if (@$stack and defined($stack->[-1]->{'style'})
14859                  and (ref($::style_map_ref->{$stack->[-1]->{'style'}}) eq 'HASH'))
14860             {
14861                  my $macro = $stack->[-1]->{'style'};
14862                  my $style_args = $::style_map_ref->{$macro}->{'args'};
14863                  if (defined($style_args->[$stack->[-1]->{'arg_nr'} + 1]))
14864                  {
14865                       push (@{$stack->[-1]->{'args'}}, $stack->[-1]->{'text'});
14866                       $stack->[-1]->{'fulltext'} .= $stack->[-1]->{'text'} . do_text(',', $state);
14867                       $stack->[-1]->{'text'} = '';
14868                       close_arg ($macro, $stack->[-1]->{'arg_nr'}, $state);
14869                       $stack->[-1]->{'arg_nr'}++;
14870                       open_arg ($macro, $stack->[-1]->{'arg_nr'}, $state);
14871                       next;
14872                  }
14873             }
14874             add_prev($text, $stack, do_text(',', $state));
14875        }
14876        else
14877        { # no macro nor '}', but normal text
14878            add_prev($text, $stack, do_text($cline, $state));
14879            # @center/line term is closed at the end of line. When a
14880            # @-command which
14881            # keeps the texi as is happens on the @center line, the @center
14882            # is closed at the end of line appearing after the @-command
14883            # closing (for example @ref, @footnote).
14884            last if ($state->{'keep_texi'});
14885            #print STDERR "END_LINE(l):$cline!!!\n";
14886            #dump_stack($text, $stack, $state);
14887            my $maybe_format_to_close = 1;
14888            my $in_table;
14889            while ($maybe_format_to_close)
14890            {
14891               $maybe_format_to_close = 0;
14892               #my $top_format = top_stack($stack, 1);
14893               my $top_format = top_stack($stack, 2);
14894               # the stack cannot easily be used, because there may be
14895               # opened commands in paragraphs if the center is in a
14896               # style command, like
14897               # @b{
14898               # bold
14899               #
14900               # @center centered bold
14901               #
14902               # }
14903               #
14904               # Therefore $state->{'paragraph_style'}->[-1] is used.
14905               #
14906               # The close_stack until 'center' is needed because
14907               # of constructs like
14908               #
14909               # @center something @table
14910               #
14911               # In that case what would be removed from the stack after
14912               # paragraph closing wold not be the @center. Such construct
14913               # is certainly incorrect, though.
14914               #
14915               # when 'closing_center' is true we don't retry to close
14916               # the @center line.
14917               if ($state->{'paragraph_style'}->[-1] eq 'center'
14918                   and !$state->{'closing_center'} and !$state->{'keep_texi'})
14919               {
14920                   $state->{'closing_center'} = 1;
14921                   close_paragraph($text, $stack, $state, "\@center", $line_nr);
14922                   close_stack($text, $stack, $state, $line_nr, 'center');
14923                   delete $state->{'closing_center'};
14924                   my $center = pop @$stack;
14925                   add_prev($text, $stack, &$Texi2HTML::Config::paragraph_style_command('center',$center->{'text'}));
14926                   my $top_paragraph_style = pop @{$state->{'paragraph_style'}};
14927
14928                   # center is at the bottom of the comand_stack because it
14929                   # may be nested in many way
14930                   my $bottom_command_stack = shift @{$state->{'command_stack'}};
14931                   print STDERR "Bug: closing center, top_paragraph_style: $top_paragraph_style, bottom_command_stack: $bottom_command_stack.\n"
14932                      if ($bottom_command_stack ne 'center' or $top_paragraph_style ne 'center');
14933                   $maybe_format_to_close = 1;
14934                   next;
14935               }
14936
14937               # @item line is closed by end of line. In general there should
14938               # not be a paragraph in a term. However it may currently
14939               # happen in construct like
14940               #
14941               # @table @asis
14942               # @item @cindex index entry
14943               # some text still in term, and in paragraph
14944               # Not in term anymore
14945               # ....
14946               #
14947               if (defined($top_format->{'format'}) and $top_format->{'format'} eq 'term')
14948               {
14949                   #close_paragraph($text, $stack, $state, $line_nr)
14950                   #    if ($state->{'paragraph_context'});
14951                   close_stack($text, $stack, $state, $line_nr, 'term');
14952                   $in_table = add_term($text, $stack, $state, $line_nr);
14953                   if ($in_table)
14954                   {
14955                      $maybe_format_to_close = 1;
14956                      next;
14957                   }
14958               }
14959            }
14960            if ($in_table)
14961            {
14962               push (@$stack, { 'format' => 'line', 'text' => '', 'only_inter_commands' => 1, 'format_ref' => $in_table });
14963               begin_paragraph($stack, $state) if ($state->{'preformatted'});
14964            }
14965            last;
14966        }
14967    }
14968    return 1;
14969} # end scan_line
14970
14971sub open_arg($$$)
14972{
14973    my $macro = shift;
14974    my $arg_nr = shift;
14975    my $state = shift;
14976    if (ref($::style_map_ref->{$macro}) eq 'HASH')
14977    {
14978         my $arg = $::style_map_ref->{$macro}->{'args'}->[$arg_nr];
14979         if ($arg eq 'keep')
14980         {
14981             $state->{'keep_nr'}++;
14982             $state->{'keep_texi'} = 1;
14983         }
14984         elsif (!$state->{'keep_texi'})
14985         {
14986             if ($arg eq 'code')
14987             {
14988                 $state->{'code_style'}++;
14989             }
14990             elsif ($arg eq 'math')
14991             {
14992                 $state->{'math_style'}++;
14993                 $state->{'code_style'}++;
14994                 if ($state->{'math_style'} == 1)
14995                 {
14996                     $state->{'math_brace'} = 0;
14997                 }
14998             }
14999         }
15000    }
15001    elsif ($code_style_map{$macro} and !$state->{'keep_texi'})
15002    {
15003         $state->{'code_style'}++;
15004    }
15005}
15006
15007sub close_arg($$$)
15008{
15009    my $macro = shift;
15010    my $arg_nr = shift;
15011    my $state = shift;
15012    if (ref($::style_map_ref->{$macro}) eq 'HASH')
15013    {
15014         my $arg = $::style_map_ref->{$macro}->{'args'}->[$arg_nr];
15015         if ($arg eq 'keep')
15016         {
15017             $state->{'keep_nr'}--;
15018             $state->{'keep_texi'} = 0 if ($state->{'keep_nr'} == 0);
15019         }
15020         elsif (!$state->{'keep_texi'})
15021         {
15022             if ($arg eq 'code')
15023             {
15024                 $state->{'code_style'}--;
15025             }
15026             elsif ($arg eq 'math')
15027             {
15028                 $state->{'math_style'}--;
15029                 $state->{'code_style'}--;
15030             }
15031         }
15032#print STDERR "c $arg_nr $macro $arg $state->{'code_style'}\n";
15033    }
15034    elsif ($code_style_map{$macro} and !$state->{'keep_texi'})
15035    {
15036         $state->{'code_style'}--;
15037    }
15038}
15039
15040# add a special style on the top of the stack. This is used for commands
15041# that extend until the end of the line. Also add an entry in the @-command
15042# hashes for this fakes style.
15043#sub open_cmd_line($$$$$)
15044#{
15045#    my $command = shift;
15046#    my $stack = shift;
15047#    my $state = shift;
15048#    my $args = shift;
15049#    my $function = shift;
15050#    push @$stack, {'style' => 'cmd_line', 'text' => '', 'arg_nr' => 0};
15051#    foreach my $hash (\%Texi2HTML::Config::style_map, \%Texi2HTML::Config::style_map_pre, \%Texi2HTML::Config::style_map_texi, \%Texi2HTML::Config::simple_format_style_map_texi)
15052#    {
15053#         $hash->{'cmd_line'}->{'args'} = $args;
15054#         $hash->{'cmd_line'}->{'function'} = $function;
15055#    }
15056#    $state->{'no_paragraph'}++;
15057#    push @{$state->{'no_paragraph_stack'}}, "\@$command line";
15058##    $state->{'cmd_line'} = 1;
15059#    open_arg ('cmd_line', 0, $state);
15060#}
15061
15062# finish @item line in @*table
15063sub add_term($$$$)
15064{
15065    my $text = shift;
15066    my $stack = shift;
15067    my $state = shift;
15068    my $line_nr = shift;
15069
15070    my $top_format = top_stack($stack,2);
15071
15072    return unless (defined($top_format->{'format'}) and $top_format->{'format'} eq 'term');
15073    #print STDERR "ADD_TERM\n";
15074
15075    my $term = pop @$stack;
15076    my $format = $stack->[-1];
15077    $format->{'paragraph_number'} = 0;
15078    chomp ($term->{'text'});
15079
15080    my ($index_label, $formatted_index_entry);
15081    if ($format->{'format'} =~ /^(f|v)/o)
15082    {
15083        my $index_entry;
15084        ($index_entry, $formatted_index_entry, $index_label) = do_index_entry_label($format->{'format'}, $state,$line_nr, $format->{'texi_line'});
15085        print STDERR "Bug: no index entry for $term->{'text'}\n" unless defined($index_label);
15086    }
15087
15088    my $item_result = &$Texi2HTML::Config::table_item($term->{'text'}, $index_label,$format->{'format'},$format->{'command'}, $state->{'command_stack'}, $term->{'item_cmd'}, $formatted_index_entry);
15089    add_prev($text, $stack, $item_result);
15090    return $format;
15091}
15092
15093sub add_row($$$$)
15094{
15095    my $text = shift;
15096    my $stack = shift;
15097    my $state = shift;
15098    my $line_nr = shift;
15099
15100    my $top_format = top_stack($stack);
15101    # @center a @item
15102    # will lead to row not being closed since a close paragraph doesn't
15103    # end the center.
15104    return unless (defined($top_format->{'format'}) and $top_format->{'format'} eq 'cell');
15105    my $cell = $top_format;
15106    my $format = $stack->[-3];
15107    print STDERR "Bug under row cell row not a multitable\n" if (!defined($format->{'format'}) or $format->{'format'} ne 'multitable');
15108    #print STDERR "ADD_ROW $format->{'item_nr'} first: $format->{'first'}\n";
15109    # dump_stack($text, $stack, $state);
15110
15111    $format->{'item_nr'}++ unless ($format->{'first'});
15112    my $empty_first;
15113    if ($format->{'first'} and $format->{'cell'} == 1 and $stack->[-1]->{'text'} =~ /^\s*$/)
15114    {
15115       $empty_first = 1;
15116       $format->{'empty_first'} = 1;
15117    }
15118    if ($format->{'cell'} > $format->{'max_columns'} or $empty_first)
15119    {
15120       my $cell = pop @$stack;
15121       print STDERR "Bug: not a cell ($cell->{'format'}) in multitable\n" if ($cell->{'format'} ne 'cell');
15122    }
15123    else
15124    {
15125       add_cell($text, $stack, $state);
15126    }
15127    my $row = pop @$stack;
15128    print STDERR "Bug: not a row ($row->{'format'}) in multitable\n" if ($row->{'format'} ne 'row');
15129    if ($format->{'max_columns'} and !$empty_first)
15130    {
15131       # FIXME have the cell count in row and not in table. table could have
15132       # the whole structure, but cell count doesn't make much sense
15133       add_prev($text, $stack, &$Texi2HTML::Config::row($row->{'text'}, $row->{'item_cmd'}, $format->{'columnfractions'}, $format->{'prototype_row'}, $format->{'prototype_lengths'}, $format->{'max_columns'}, $cell->{'only_inter_commands'}, $format->{'first'}));
15134    }
15135
15136    $format->{'first'} = 0 if ($format->{'first'});
15137
15138    return $format;
15139}
15140
15141# FIXME remove and merge, too much double checks and code
15142sub add_cell($$$$)
15143{
15144    my $text = shift;
15145    my $stack = shift;
15146    my $state = shift;
15147    my $line_nr = shift;
15148    my $top_format = top_stack($stack);
15149
15150    #print STDERR "ADD_CELL\n";
15151    return unless (defined($top_format) and $top_format->{'format'} eq 'cell');
15152   # print STDERR "ADD_CELL, really\n";
15153
15154    my $cell = pop @$stack;
15155    my $row = top_stack($stack);
15156    print STDERR "Bug: top_stack of cell not a row\n" if (!defined($row->{'format'}) or ($row->{'format'} ne 'row'));
15157    my $format = $stack->[-2];
15158    print STDERR "Bug under cell row not a multitable\n" if (!defined($format->{'format'}) or $format->{'format'} ne 'multitable');
15159
15160    if ($format->{'first'} and $format->{'cell'} == 1)
15161    {
15162        line_warn(__("\@tab before \@item"), $line_nr);
15163    }
15164
15165    if ($format->{'cell'} <= $format->{'max_columns'})
15166    {
15167        #print STDERR "ADD_CELL, really, really\n";
15168        add_prev($text, $stack, &$Texi2HTML::Config::cell($cell->{'text'}, $row->{'item_cmd'}, $format->{'columnfractions'}, $format->{'prototype_row'}, $format->{'prototype_lengths'}, $format->{'max_columns'}, $cell->{'only_inter_commands'}, $format->{'first'}));
15169    }
15170    $format->{'cell'}++;
15171    $format->{'first'} = 0 if ($format->{'first'});
15172    return $format;
15173}
15174
15175sub add_line($$$$)
15176{
15177    my $text = shift;
15178    my $stack = shift;
15179    my $state = shift;
15180    my $line_nr = shift;
15181    my $top_stack = top_stack($stack);
15182
15183    # if there is something like
15184    # @center centered @item new item
15185    # the item isn't opened since it is in @center, and center isn't closed
15186    # by an @item appearing here (unlike a paragraph).
15187    # the error message is '@item outside of table or list'.
15188    # texi2dvi also has issue, but makeinfo is happy, however it
15189    # produces bad nesting.
15190    return unless(defined($top_stack->{'format'}) and $top_stack->{'format'} eq 'line');
15191    #print STDERR "ADD_LINE\n";
15192    #dump_stack($text, $stack, $state);
15193
15194    my $line = pop @$stack;
15195    my $format = $stack->[-1];
15196    $format->{'paragraph_number'} = 0;
15197    if ($format->{'first'})
15198    {
15199        $format->{'first'} = 0;
15200        # we must have <dd> or <dt> following <dl> thus we do a
15201        # &$Texi2HTML::Config::table_line here too, although it could have
15202        # been a normal paragraph.
15203        if ($line->{'text'} =~ /\S/o)
15204        {
15205           add_prev($text, $stack, &$Texi2HTML::Config::table_line($line->{'text'}, $line->{'only_inter_commands'}, 1));
15206           $format->{'empty_first'} = 1 if ($line->{'only_inter_commands'});
15207        }
15208        else
15209        {
15210           $format->{'empty_first'} = 1;
15211        }
15212    }
15213    else
15214    {
15215        $format->{'item_nr'}++;
15216        add_prev($text, $stack, &$Texi2HTML::Config::table_line($line->{'text'}, $line->{'only_inter_commands'}, 0));
15217    }
15218    return $format;
15219}
15220
15221# finish @enumerate or @itemize @item
15222sub add_item($$$$)
15223{
15224    my $text = shift;
15225    my $stack = shift;
15226    my $state = shift;
15227    my $line_nr = shift;
15228
15229    my $top_stack = top_stack($stack);
15230
15231    return unless (defined($top_stack->{'format'}) and $top_stack->{'format'} eq 'item');
15232    #print STDERR "ADD_ITEM: \n";
15233    #dump_stack($text, $stack, $state);
15234    # as in pre the end of line are kept, we must explicitely abort empty
15235    # preformatted, close_stack doesn't do that.
15236    my $item = pop @$stack;
15237    my $format = $stack->[-1];
15238    #my $item_command = $item->{'format'};
15239    my $item_command = $item->{'item_cmd'};
15240    # first has no associated item, it is more like a 'title'
15241    $item_command = '' if ($format->{'first'});
15242
15243    # debug message if it is the first item (much like a title) although
15244    # there is an item command.
15245    msg_debug("First in $format->{'format'} but item_cmd defined $item->{'item_cmd'}",$line_nr) if ($format->{'first'} and defined($item->{'item_cmd'}));
15246
15247    $format->{'paragraph_number'} = 0;
15248
15249    #dump_stack ($text, $stack, $state);
15250    # the element following ol or ul must be li. Thus even though there
15251    # is no @item we put a normal item.
15252    # don't do an item if it is the first and it is empty
15253    if (!$format->{'first'} or ($item->{'text'} =~ /\S/o))
15254    {
15255        my $formatted_command;
15256        if (defined($format->{'command'}) and $format->{'command'} ne '')# and exists($::things_map_ref->{$format->{'command'}}))
15257        {
15258            $formatted_command = substitute_line("\@$format->{'command'}\{\}", "\@item \@$format->{'command'}", duplicate_formatting_state($state));
15259            $format->{'formatted_command'} = $formatted_command;
15260        }
15261	#chomp($item->{'text'});
15262        add_prev($text, $stack, &$Texi2HTML::Config::list_item($item->{'text'},$format->{'format'},$format->{'command'}, $formatted_command, $format->{'item_nr'}, $format->{'spec'}, $format->{'number'}, $format->{'prepended'}, $format->{'prepended_formatted'}, $item->{'only_inter_commands'}, $format->{'first'},$item_command));
15263    }
15264    else
15265    {
15266        $format->{'empty_first'} = 1;
15267    }
15268    if ($format->{'first'})
15269    {
15270        $format->{'first'} = 0;
15271    }
15272    else
15273    {
15274        $format->{'item_nr'}++;
15275    }
15276
15277    if ($format->{'format'} eq 'enumerate')
15278    {
15279        $format->{'number'} = '';
15280        my $spec = $format->{'spec'};
15281        if ($spec =~ /^[0-9]$/)
15282        {
15283            $format->{'number'} = $spec + $format->{'item_nr'};
15284        }
15285        else
15286        {
15287            my $base_letter = ord('a');
15288            $base_letter = ord('A') if (ucfirst($spec) eq $spec);
15289
15290            my @letter_ords = decompose(ord($spec) - $base_letter + $format->{'item_nr'}, 26);
15291            foreach my $ord (@letter_ords)
15292            {# FIXME we go directly to 'ba' after 'z', and not 'aa'
15293             #because 'ba' is 1,0 and 'aa' is 0,0.
15294                $format->{'number'} = chr($base_letter + $ord) . $format->{'number'};
15295            }
15296        }
15297    }
15298
15299    return $format;
15300}
15301
15302# format ``simple'' macros, that is macros without arg or style macros
15303sub do_simple_command($$$)
15304{
15305    my $macro = shift;
15306    my $state = shift;
15307    my $line_nr = shift;
15308
15309#msg_debug ("DO_SIMPLE $macro $args $arg_nr (@$args)", $line_nr) if (defined($args));
15310    if ($state->{'remove_texi'})
15311    {
15312#print STDERR "DO_SIMPLE remove_texi $macro\n";
15313        return  $::simple_map_texi_ref->{$macro};
15314    }
15315    else
15316    {
15317        return &$Texi2HTML::Config::simple_command($macro, $state->{'preformatted'}, $state->{'math_style'}, $line_nr, $state);
15318    }
15319}
15320
15321sub do_thing_command($$$$)
15322{
15323    my $macro = shift;
15324    my $text = shift;
15325    my $state = shift;
15326    my $line_nr = shift;
15327
15328    if ($state->{'remove_texi'})
15329    {
15330       return  $::texi_map_ref->{$macro}.$text;
15331#print STDERR "DO_SIMPLE remove_texi texi_map $macro\n";
15332    }
15333    else
15334    {
15335        return &$Texi2HTML::Config::thing_command($macro, $text, $state->{'preformatted'}, $state->{'math_style'}, $line_nr, $state);
15336    }
15337}
15338
15339sub do_style_command($$$$$$$$)
15340{
15341    my $macro = shift;
15342    my $text = shift;
15343    my $state = shift;
15344    my $args = shift;
15345    my $line_nr = shift;
15346    my $no_open = shift;
15347    my $no_close = shift;
15348    my $kept_line_nrs = shift;
15349
15350    my $arg_nr = 0;
15351    $arg_nr = @$args - 1 if (defined($args));
15352
15353    if (defined($::style_map_ref->{$macro}))
15354    {
15355        my $style;
15356        my $result;
15357        if ($state->{'remove_texi'})
15358        {
15359#print STDERR "REMOVE $macro, $style_map_texi_ref->{$macro}, fun $style_map_texi_ref->{$macro}->{'function'} remove cmd " . \&Texi2HTML::Config::t2h_remove_command . " ascii acc " . \&t2h_default_accent;
15360            $style = $::style_map_texi_ref->{$macro};
15361        }
15362        elsif ($state->{'math_style'} and defined($::style_map_math_ref->{$macro}))
15363        { # FIXME we are still in math when the @math is closed here, since
15364          # close_arg that does 'math_style'-- is called below.
15365            $style = $::style_map_math_ref->{$macro};
15366        }
15367        elsif ($state->{'preformatted'})
15368        {
15369            if ($macro eq 'kbd' and (Texi2HTML::Config::get_conf('kbdinputstyle') ne 'distinct'))
15370            {
15371                $style = $::style_map_pre_ref->{'code'};
15372            }
15373            else
15374            {
15375                $style = $::style_map_pre_ref->{$macro};
15376            }
15377        }
15378        else
15379        {
15380            # kbd is in code_style, so it is 'code_style' > 1
15381            if ($macro eq 'kbd' and ((Texi2HTML::Config::get_conf('kbdinputstyle') eq 'code') or ($state->{'code_style'} > 1 and Texi2HTML::Config::get_conf('kbdinputstyle') eq 'example')))
15382            {
15383                $style = $::style_map_ref->{'code'};
15384            }
15385            else
15386            {
15387                $style = $::style_map_ref->{$macro};
15388            }
15389        }
15390        if ($macro eq 'dotless')
15391        {
15392           if (scalar(@$args) ne 1)
15393           {
15394               line_error(sprintf(__("%c%s expects a single character `i' or `j' as argument"), ord('@'), $macro), $line_nr);
15395           }
15396           elsif ($args->[0] ne 'i' and $args->[0] ne 'j')
15397           { # FIXME an unformatted arg would have been better. Not a big deal.
15398               line_error (sprintf(__("%c%s expects `i' or `j' as argument, not `%s'"), ord('@'), $macro, $args->[0]), $line_nr);
15399           }
15400        }
15401        if (defined($style))
15402        {                           # known style
15403            $result = &$Texi2HTML::Config::style($style, $macro, $text, $args, $no_close, $no_open, $line_nr, $state, $state->{'command_stack'}, $kept_line_nrs);
15404        }
15405        if (!$no_close)
15406        {
15407            close_arg($macro,$arg_nr, $state);
15408        }
15409        return $result;
15410    }
15411    elsif ($macro =~ /^special_(\w+)_(\d+)$/o)
15412    {
15413        my $style = $1;
15414        my $count = $2;
15415
15416        msg_debug ("Bug? text in \@$macro not empty", $line_nr) if ($text ne '');
15417        if (defined($Texi2HTML::Config::command_handler{$style}) and
15418          defined($Texi2HTML::Config::command_handler{$style}->{'expand'}))
15419        {
15420            my $struct_count = 1+ $special_commands{$style}->{'max'} - $special_commands{$style}->{'count'};
15421            # may happen for text expanded more than once, for example
15422            # in invalid/tex_in_copying
15423            if (($count != $struct_count) and $T2H_DEBUG)
15424            {
15425                msg_debug ("count $count in \@special $style and structure $struct_count differ", $line_nr);
15426            }
15427            $special_commands{$style}->{'count'}--;
15428        }
15429        my $result = $Texi2HTML::Config::command_handler{$style}->{'expand'}
15430              ($style,$count,$state,$text);
15431        $result = '' if (!defined($result));
15432        return $result;
15433    }
15434    # Unknown macro
15435    my $result = '';
15436    my ($done, $result_text, $message) = &$Texi2HTML::Config::unknown_style($macro, $text,$state,$no_close, $no_open);
15437    if ($done)
15438    {
15439        line_warn($message, $line_nr) if (defined($message));
15440        if (defined($result_text))
15441        {
15442            $result = $result_text;
15443        }
15444    }
15445    else
15446    {
15447        unless ($no_open)
15448        { # we warn only if no_open is true, i.e. it is the first time we
15449          # close the macro for a multiline macro
15450            line_error (sprintf(__("Unknown command with braces `\@%s'"), $macro), $line_nr);
15451            $result = do_text("\@$macro") . "{";
15452        }
15453        $result .= $text;
15454        $result .= '}' unless ($no_close);
15455    }
15456    return $result;
15457}
15458
15459sub do_unknown($$$$$$$)
15460{
15461    my $pass = shift;
15462    my $macro = shift;
15463    my $line = shift;
15464    my $text = shift;
15465    my $stack = shift;
15466    my $state = shift;
15467    my $line_nr = shift;
15468    #print STDERR "do_unknown[$pass]($macro) ::: $line";
15469
15470    my ($result_line, $result, $result_text, $message) = &$Texi2HTML::Config::unknown($macro, $line, $pass, $stack,$state);
15471    if ($result)
15472    {
15473         add_prev ($text, $stack, $result_text) if (defined($result_text));
15474         line_warn($message, $line_nr) if (defined($message));
15475         # if $state->{'preformatted'}, assume that the preformatted is
15476         # already opened. Otherwise we may end up opening one each time
15477         # there is an unknown command.
15478         begin_paragraph_after_command($state, $stack, $macro, $result_line)
15479              if (!$state->{'preformatted'});
15480         return $result_line;
15481    }
15482    elsif ($pass == 2)
15483    {
15484         if ($Texi2HTML::Config::style_map{$macro})
15485         {
15486             line_error (sprintf(__("%c%s expected braces"), ord('@'), $macro), $line_nr);
15487         }
15488         else
15489         {
15490             line_error (sprintf(__("Unknown command `%s'"), $macro), $line_nr);
15491         }
15492         add_prev ($text, $stack, do_text("\@$macro"));
15493         return $line;
15494    }
15495    elsif ($pass == 1)
15496    {
15497         add_prev ($text, $stack, "\@$macro");
15498         return $line;
15499    }
15500    elsif ($pass == 0)
15501    {
15502         add_prev ($text, $stack, "\@$macro") unless($state->{'ignored'});
15503         return $line;
15504    }
15505}
15506
15507# used only during @macro processing
15508sub add_text($@)
15509{
15510    my $string = shift;
15511
15512    return if (!defined($string));
15513    foreach my $scalar_ref (@_)
15514    {
15515        next unless defined($scalar_ref);
15516        if (!defined($$scalar_ref))
15517        {
15518            $$scalar_ref = $string;
15519        }
15520        else
15521        {
15522            $$scalar_ref .= $string;
15523        }
15524        return;
15525    }
15526}
15527
15528sub add_prev ($$$)
15529{
15530    my $text = shift;
15531    my $stack = shift;
15532    my $string = shift;
15533
15534    unless (defined($text) and ref($text) eq "SCALAR")
15535    {
15536       die "text not a SCALAR ref: " . ref($text) . "";
15537    }
15538
15539    return if (!defined($string));
15540    if (@$stack)
15541    {
15542        $stack->[-1]->{'text'} .= $string;
15543        return;
15544    }
15545
15546    if (!defined($$text))
15547    {
15548         $$text = $string;
15549    }
15550    else
15551    {
15552         $$text .= $string;
15553    }
15554}
15555
15556sub close_stack_texi($$$$)
15557{
15558    my $text = shift;
15559    my $stack = shift;
15560    my $state = shift;
15561    my $line_nr = shift;
15562
15563
15564    return undef unless (@$stack or $state->{'raw'} or $state->{'macro'} or $state->{'macro_name'} or $state->{'ignored'});
15565
15566    if ($state->{'ignored'})
15567    {
15568        line_error (sprintf(__("Reached eof before matching \@end %s"), $state->{'ignored'}), $line_nr);
15569        close_ignored($state, $stack);
15570    }
15571
15572    if ($state->{'macro'})
15573    {
15574       my ($no_remaining, $result) = end_macro($state, '@end macro', "\n");
15575       add_prev ($text, $stack, $result) if (defined($result));
15576       line_error (sprintf(__("%cend macro not found"), ord('@')), $line_nr);
15577    }
15578    elsif ($state->{'macro_name'})
15579    {
15580       #line_warn ("closing $state->{'macro_name'} ($state->{'macro_depth'} braces missing)", $line_nr);
15581       line_error (sprintf(__("\@%s missing close brace"), $state->{'macro_name'}), $line_nr);
15582       while ($state->{'macro_name'})
15583       {
15584           close_macro_arg($state, '', $line_nr);
15585       }
15586    }
15587    elsif ($state->{'verb'})
15588    {
15589        # warning in next pass
15590        #line_warn ("closing \@verb", $line_nr);
15591        $stack->[-1]->{'text'} = $state->{'verb'} . $stack->[-1]->{'text'};
15592        delete $state->{'verb'};
15593    }
15594    elsif ($state->{'raw'})
15595    {
15596        line_error (sprintf(__("Expected \@end %s"), $state->{'raw'}), $line_nr);
15597        my $style = pop @$stack;
15598        add_prev ($text, $stack, $style->{'text'} . "\@end $state->{'raw'}");
15599        delete $state->{'raw'};
15600    }
15601
15602    my $stack_level = $#$stack + 1;
15603
15604    while ($stack_level--)
15605    {
15606        my $style = pop(@$stack);
15607        # would be better in close_stack_structure
15608        #line_warn ("closing \@-command $style->{'style'}", $line_nr) if ($style->{'style'} ne '');
15609        close_style_texi($style, $text, $stack, $state, 1);
15610    }
15611    #$stack = [ ];
15612}
15613
15614
15615sub close_stack_structure($$$$;$)
15616{
15617    my $text = shift;
15618    my $stack = shift;
15619    my $state = shift;
15620    my $line_nr = shift;
15621    my $close_only_item = shift;
15622    $close_only_item = 0 if (!defined($close_only_item));
15623
15624    return undef unless (@$stack or $state->{'raw'});
15625
15626    #print STDERR "close_stack_structure ($close_only_item)\n";
15627    #dump_stack ($text, $stack, $state);
15628    my $stack_level = $#$stack + 1;
15629    my $string = '';
15630
15631    if ($state->{'verb'})
15632    {
15633        $stack->[-1]->{'text'} = $state->{'verb'} . $stack->[-1]->{'text'};
15634        #$string .= $state->{'verb'};
15635    }
15636
15637    while ($stack_level--)
15638    {
15639        last if ($close_only_item and defined($stack->[-1]->{'format'}));
15640        my $top_stack = pop @$stack;
15641        if ($top_stack->{'format'})
15642        {
15643            my $format = $top_stack->{'format'};
15644            if ($format eq 'index_item')
15645            {
15646                enter_table_index_entry($text, $stack, $state, $line_nr);
15647            }
15648            elsif (!defined($format_type{$format}) or ($format_type{$format} ne 'fake'))
15649            {
15650                end_format_structure($format_type{$format}, $text, $stack, $state, $line_nr, "\n");
15651            }
15652        }
15653        elsif (defined($top_stack->{'style'}))
15654        {
15655            add_prev($text, $stack,
15656              close_structure_command($top_stack, $state, 1, $line_nr));
15657        }
15658    }
15659    #$stack = [ ];
15660}
15661
15662# This is used in pass 2 and 3.
15663sub open_region($$)
15664{
15665    my $command = shift;
15666    my $state = shift;
15667    if (!exists($state->{'region_lines'}))
15668    {
15669    # FIXME 'format' is badly choosen 'region_name' would be much better
15670        $state->{'region_lines'}->{'format'} = $command;
15671        $state->{'region_lines'}->{'number'} = 1;
15672        $state->{'region_lines'}->{'kept_place'} = $state->{'place'};
15673        $state->{'place'} = $no_element_associated_place;
15674        $state->{'region'} = $command;
15675        $state->{'multiple_pass'}++;
15676        $state->{'region_pass'} = 1;
15677    }
15678    else
15679    {
15680        $state->{'region_lines'}->{'number'}++;
15681    }
15682}
15683
15684# close region like @insertcopying, titlepage...
15685# restore $state and delete the structure
15686# This is used in pass 2 and 3.
15687sub close_region($)
15688{
15689    my $state = shift;
15690    $state->{'place'} = $state->{'region_lines'}->{'kept_place'};
15691    $state->{'multiple_pass'}--;
15692    delete $state->{'region_lines'}->{'number'};
15693    delete $state->{'region_lines'}->{'format'};
15694    delete $state->{'region_lines'}->{'kept_place'};
15695    delete $state->{'region_lines'};
15696    delete $state->{'region'};
15697    delete $state->{'region_pass'};
15698}
15699
15700# close the stack, closing @-commands and formats left open.
15701# if a $format is given if $format is encountered the closing stops
15702sub close_stack($$$$;$)
15703{
15704    my $text = shift;
15705    my $stack = shift;
15706    my $state = shift;
15707    my $line_nr = shift;
15708    my $format = shift;
15709
15710    #print STDERR "sub_close_stack\n";
15711    if (@$stack)
15712    {
15713      my $stack_level = $#$stack + 1;
15714
15715      #debugging
15716      #my $print_format = 'NO FORMAT';
15717      #$print_format = $format if ($format);
15718      #msg_debug ("Close_stack:  format $print_format", $line_nr);
15719
15720      while ($stack_level--)
15721      {
15722        if ($stack->[$stack_level]->{'format'})
15723        {
15724            my $stack_format = $stack->[$stack_level]->{'format'};
15725            last if (defined($format) and $stack_format eq $format);
15726            # We silently close paragraphs, preformatted sections and fake formats
15727            if ($stack_format eq 'paragraph')
15728            {
15729                my $paragraph = pop @$stack;
15730                add_prev ($text, $stack, do_paragraph($paragraph->{'text'}, $state, $stack));
15731            }
15732            elsif ($stack_format eq 'preformatted')
15733            {
15734                my $paragraph = pop @$stack;
15735                add_prev ($text, $stack, do_preformatted($paragraph->{'text'}, $state, $stack));
15736            }
15737            else
15738            {
15739                if ($fake_format{$stack_format})
15740                {
15741                    warn "# Closing a fake format `$stack_format'\n" if ($T2H_VERBOSE);
15742                }
15743                elsif ($stack_format ne 'center')
15744                { # we don't warn for center
15745                    line_error (sprintf(__("No matching `%cend %s'"), ord('@'), $stack_format), $line_nr);
15746                    #dump_stack ($text, $stack, $state);
15747                }
15748                if ($state->{'keep_texi'})
15749                {
15750                   add_prev($text, $stack, "\@end $stack_format");
15751                }
15752                elsif (!$state->{'remove_texi'})
15753                {
15754                   end_format($text, $stack, $state, $stack_format, $line_nr)
15755                        unless ($format_type{$stack_format} eq 'fake');
15756                }
15757            }
15758        }
15759        else
15760        {
15761            my $style =  $stack->[$stack_level]->{'style'};
15762            ########################## debug
15763            if (!defined($style))
15764            {
15765                print STDERR "Bug: style not defined, on stack\n";
15766                dump_stack ($text, $stack, $state); # bug
15767            }
15768            ########################## end debug
15769            my $located_line_nr = $line_nr;
15770            # use the beginning of the @-command for the error message
15771            # line number if available.
15772            $located_line_nr = $stack->[$stack_level]->{'line_nr'} if (defined($stack->[$stack_level]->{'line_nr'}));
15773            line_error (sprintf(__("%c%s missing close brace"), ord('@'), $style), $located_line_nr);
15774            my ($result, $command) = close_style_command($text, $stack, $state, $line_nr, '');
15775
15776            add_prev($text, $stack, $result) if (defined($result));
15777        }
15778      }
15779    }
15780
15781    # This tries to avoid cases where the command_stack is not empty
15782    # for a good reason, for example when doing a @def formatting the
15783    # outside command_stack is preserved. Also when expanding for
15784    # example @titleplage or @copying.
15785    # FIXME sort out which cases it is.
15786    return if ($format or (defined($state->{'multiple_pass'}) and $state->{'multiple_pass'} > 0) or $state->{'no_paragraph'});
15787
15788    # The pending style commands are cleared here; And are closed next.
15789    delete $state->{'paragraph_macros'};
15790    # go through the command_stack and warn for each opened style format
15791    # and remove it. Those should be there because there is an opened style
15792    # that was stopped by a paragraph
15793    my @command_stack = @{$state->{'command_stack'}};
15794    @{$state->{'command_stack'}} = ();
15795    while (@command_stack)
15796    {
15797       my $latest_command = pop @command_stack;
15798       if (defined($style_type{$latest_command}) and $style_type{$latest_command} ne 'special')
15799       {
15800          line_error (sprintf(__("%c%s missing close brace"), ord('@'), $latest_command), $line_nr);
15801       }
15802       else
15803       {
15804          unshift @{$state->{'command_stack'}}, $latest_command;
15805       }
15806    }
15807}
15808
15809# given a stack and a list of formats, return true if the stack contains
15810# these formats, first on top
15811sub stack_order($@)
15812{
15813    my $stack = shift;
15814    my $stack_level = $#$stack + 1;
15815    while (@_)
15816    {
15817        my $format = shift;
15818        while ($stack_level--)
15819        {
15820            if ($stack->[$stack_level]->{'format'})
15821            {
15822                if ($stack->[$stack_level]->{'format'} eq $format)
15823                {
15824                    $format = undef;
15825                    last;
15826                }
15827                else
15828                {
15829                    return 0;
15830                }
15831            }
15832        }
15833        return 0 if ($format);
15834    }
15835    return 1;
15836}
15837
15838sub top_format($)
15839{
15840    my $stack = shift;
15841    my $stack_level = $#$stack + 1;
15842    while ($stack_level--)
15843    {
15844        if ($stack->[$stack_level]->{'format'} and !$fake_format{$stack->[$stack_level]->{'format'}})
15845        {
15846             return $stack->[$stack_level];
15847        }
15848    }
15849    return undef;
15850}
15851
15852sub close_paragraph($$$$;$$)
15853{
15854    my $text = shift;
15855    my $stack = shift;
15856    my $state = shift;
15857    my $reason = shift;
15858    my $line_nr = shift;
15859    my $no_preformatted_closing = shift;
15860    #print STDERR "CLOSE_PARAGRAPH\n";
15861    #dump_stack($text, $stack, $state);
15862
15863    #  close until the first format,
15864    #  duplicate stack of styles not closed
15865    my $new_stack;
15866    my $stack_level = $#$stack + 1;
15867
15868    # In general close_paragraph is called because of a end of line, or
15869    # a format is opened or closed, or there is a @tab or @item and other
15870    # similar cases. In most cases there is a paragraph to be closed or
15871    # there are no style opened since most @-commands cause paragraph
15872    # opening and those that don't should not lead to a style opening.
15873    #
15874    # But in term or in @index (and maybe @node, @section, @ref), if
15875    # there is a command opened it won't be closed, since it is in
15876    # 'no_paragraph'. But @-commands that trigger close_paragraph should not
15877    # be called when in those no_paragraph settings.
15878
15879    if ($state->{'no_paragraph'})
15880    { # This plays the role of "Multiline command %c%s used improperly"
15881        line_error(sprintf(__("%s should not appear in %s"), $reason, $state->{'no_paragraph_stack'}->[-1]), $line_nr);
15882    }
15883
15884    while ($stack_level--)
15885    {
15886        last if ($stack->[$stack_level]->{'format'});
15887        my $style = $stack->[$stack_level]->{'style'};
15888
15889        # the !exists($style_type{$style}) condition catches the unknown
15890        # @-commands: by default they are considered as style commands
15891        if (!$state->{'no_paragraph'})
15892        {
15893            if (!exists($style_type{$style}) or $style_type{$style} eq 'style')
15894            {
15895                unshift @$new_stack, { 'style' => $style, 'text' => '', 'no_open' => 1, 'arg_nr' => 0 };
15896            }
15897            elsif (($style_type{$style} eq 'simple_style') or ($style_type{$style} eq 'accent'))
15898            {
15899            }
15900            else
15901            {
15902                # it shouldn't be possible to have 'special' styles, like
15903                # images, footnotes, xrefs, anchors, as
15904                # close_paragraph shouldn't be called with keep_texi
15905                # and when the arguments are expanded, there is a
15906                # substitute_line or similar with a new stack.
15907                msg_debug("BUG: special $style while closing paragraph", $line_nr);
15908            }
15909        }
15910        # if not in a paragraph, the command is simply closed, and not recorded
15911        # in new_stack.
15912        my ($result, $command) = close_style_command($text, $stack, $state, $line_nr, '', (!$state->{'no_paragraph'}));
15913        add_prev($text, $stack, $result) if (defined($result));
15914    }
15915
15916    if (!$state->{'paragraph_context'} and !$state->{'preformatted'} and defined($new_stack) and scalar(@$new_stack))
15917    { # in that case the $new_stack isn't recorded in $state->{'paragraph_macros'}
15918      # and therefore, it is lost
15919       msg_debug ("closing paragraph, but not in paragraph/preformatted, and new_stack not empty", $line_nr);
15920       dump_stack($text, $stack, $state);
15921    }
15922    my $top_stack = top_stack($stack);
15923    if ($top_stack and !defined($top_stack->{'format'}))
15924    { #debug
15925         msg_debug("Bug: no format on top stack", $line_nr);
15926         dump_stack($text, $stack, $state);
15927    }
15928    if ($top_stack and ($top_stack->{'format'} eq 'paragraph'))
15929    {
15930        my $paragraph = pop @$stack;
15931        add_prev($text, $stack, do_paragraph($paragraph->{'text'}, $state, $stack));
15932        $state->{'paragraph_macros'} = $new_stack;
15933        return 1;
15934    }
15935    elsif ($top_stack and ($top_stack->{'format'} eq 'preformatted') and !$no_preformatted_closing)
15936    {
15937        my $paragraph = pop @$stack;
15938        add_prev($text, $stack, do_preformatted($paragraph->{'text'}, $state, $stack));
15939        $state->{'paragraph_macros'} = $new_stack;
15940        return 1;
15941    }
15942    return;
15943}
15944
15945sub abort_empty_preformatted($$)
15946{
15947    my $stack = shift;
15948    my $state = shift;
15949    if (@$stack and $stack->[-1]->{'format'}
15950       and ($stack->[-1]->{'format'} eq 'preformatted')
15951       and ($stack->[-1]->{'text'} !~ /\S/))
15952    {
15953        if (defined($Texi2HTML::Config::empty_preformatted))
15954        {
15955           return if (&$Texi2HTML::Config::empty_preformatted($stack->[-1]->{'text'}));
15956        }
15957        pop @$stack;
15958    }
15959}
15960
15961# for debugging
15962sub dump_stack($$$)
15963{
15964    my $text = shift;
15965    my $stack = shift;
15966    my $state = shift;
15967
15968    if (defined($$text))
15969    {
15970        print STDERR "text: $$text\n";
15971    }
15972    else
15973    {
15974        print STDERR "text: UNDEF\n";
15975    }
15976    my $in_remove = 0;
15977    my $in_simple_format = 0;
15978    my $in_keep = 0;
15979    $in_keep = 1 if ($state->{'keep_texi'});
15980    if (!$in_keep)
15981    {
15982        $in_simple_format = 1 if ($state->{'simple_format'});
15983        $in_remove = 1 if ($state->{'remove_texi'}  and !$in_simple_format);
15984    }
15985    print STDERR "state[$state](k${in_keep}s${in_simple_format}r${in_remove}): ";
15986    foreach my $key (keys(%$state))
15987    {
15988        my $value = 'UNDEF';
15989        $value = $state->{$key} if (defined($state->{$key}));
15990        print STDERR "$key: $value " if (!ref($value));
15991    }
15992    print STDERR "\n";
15993    my $stack_level = $#$stack + 1;
15994    while ($stack_level--)
15995    {
15996        print STDERR " $stack_level-> ";
15997        foreach my $key (keys(%{$stack->[$stack_level]}))
15998        {
15999            my $value = 'UNDEF';
16000            $value = $stack->[$stack_level]->{$key} if
16001                (defined($stack->[$stack_level]->{$key}));
16002            print STDERR "$key: $value ";
16003        }
16004        print STDERR "\n";
16005    }
16006    if (defined($state->{'command_stack'}))
16007    {
16008        print STDERR "command_stack: ";
16009        foreach my $style (@{$state->{'command_stack'}})
16010        {
16011            print STDERR "($style) ";
16012        }
16013        print STDERR "\n";
16014    }
16015    if (defined($state->{'region_lines'}))
16016    {
16017        print STDERR "region_lines($state->{'region_lines'}->{'number'}): $state->{'region_lines'}->{'format'}\n";
16018    }
16019    if (defined($state->{'paragraph_macros'}))
16020    {
16021        print STDERR "paragraph_macros: ";
16022        foreach my $style (@{$state->{'paragraph_macros'}})
16023        {
16024            print STDERR "($style->{'style'})";
16025        }
16026        print STDERR "\n";
16027    }
16028    if (defined($state->{'preformatted_stack'}))
16029    {
16030        print STDERR "preformatted_stack: ";
16031        foreach my $preformatted_style (@{$state->{'preformatted_stack'}})
16032        {
16033            if ($preformatted_style eq '')
16034            {
16035               print STDERR ".";
16036               next;
16037            }
16038            my $pre_style = '';
16039            $pre_style = $preformatted_style->{'pre_style'} if (exists $preformatted_style->{'pre_style'});
16040            my $class = '';
16041            $class = $preformatted_style->{'class'} if (exists $preformatted_style->{'class'});
16042            my $style = '';
16043            $style = $preformatted_style->{'style'} if (exists $preformatted_style->{'style'});
16044            print STDERR "($pre_style, $class,$style)";
16045        }
16046        print STDERR "\n";
16047    }
16048    if (defined($state->{'text_macro_stack'}) and @{$state->{'text_macro_stack'}})
16049    {
16050        print STDERR "text_macro_stack: (@{$state->{'text_macro_stack'}})\n";
16051    }
16052}
16053
16054# for debugging
16055sub print_elements($)
16056{
16057    my $elements = shift;
16058    foreach my $elem(@$elements)
16059    {
16060        if ($elem->{'node'})
16061        {
16062            print STDERR "node-> $elem ";
16063        }
16064        else
16065        {
16066            print STDERR "chap=> $elem ";
16067        }
16068        foreach my $key (keys(%$elem))
16069        {
16070            my $value = "UNDEF";
16071            $value = $elem->{$key} if (defined($elem->{$key}));
16072            print STDERR "$key: $value ";
16073        }
16074        print STDERR "\n";
16075    }
16076}
16077
16078# for debugging
16079sub context_string(;$$$)
16080{
16081   my $state = shift;
16082   my $line_nr = shift;
16083   my $message = shift;
16084
16085   $state = $Texi2HTML::THISDOC{'state'}
16086      if (!defined($state) and defined($Texi2HTML::THISDOC{'state'}));
16087   $line_nr = $Texi2HTML::THISDOC{'line_nr'}
16088      if (!defined($line_nr) and defined($Texi2HTML::THISDOC{'line_nr'}));
16089   my $result = "Pass $global_pass";
16090   my $line_info = ', no line information';
16091   $line_info = ' ' .format_line_number($line_nr) if (defined($line_nr));
16092   $result .= $line_info;
16093   if (!defined($state))
16094   {
16095      $result .= ', no state information';
16096   }
16097   else
16098   {
16099      $result .= ", context $state->{'context'}" if defined($state->{'context'});
16100      my $expand = '';
16101      if ($state->{'keep_texi'})
16102      {
16103         $expand .= ' no expansion';
16104      }
16105      if ($state->{'remove_texi'})
16106      {
16107         $expand .= ' raw';
16108      }
16109      if ($state->{'preformatted'})
16110      {
16111         $expand .= ' preformatted';
16112      }
16113      if ($state->{'code_style'})
16114      {
16115         $expand .= " 'code'";
16116      }
16117      if ($state->{'simple_format'})
16118      {
16119         $expand .= ' simple';
16120      }
16121      $expand = ' normal' if (!$expand);
16122      $result .= ',' . $expand;
16123      if ($state->{'expansion'})
16124      {
16125          $result .= ", \@$state->{'expansion'}";
16126      }
16127      if ($state->{'region'})
16128      {
16129          $result .= ", region $state->{'region'}";
16130      }
16131      if ($state->{'outside_document'})
16132      {
16133          $result .= "; out";
16134      }
16135      if ($state->{'inside_document'})
16136      {
16137          $result .= "; in";
16138      }
16139      if ($state->{'multiple_pass'})
16140      {
16141          $result .= "; multiple $state->{'multiple_pass'}";
16142      }
16143      if ($state->{'new_state'})
16144      {
16145          $result .= "; new";
16146      }
16147      if ($state->{'duplicated'})
16148      {
16149          $result .= "; duplicated";
16150      }
16151   }
16152   $result .= "(in @{$Texi2HTML::THISDOC{'command_stack'}})"
16153     if (defined ($Texi2HTML::THISDOC{'command_stack'}) and @{$Texi2HTML::THISDOC{'command_stack'}});
16154   $result .= ' ' .$message if ($message);
16155   return $result;
16156}
16157
16158
16159my @states_stack = ();
16160
16161sub push_state($)
16162{
16163   my $new_state = shift;
16164   push @states_stack, $new_state;
16165   $Texi2HTML::THISDOC{'state'} = $new_state;
16166}
16167
16168sub pop_state()
16169{
16170   pop @states_stack;
16171   if (@states_stack)
16172   {
16173       $Texi2HTML::THISDOC{'state'} = $states_stack[-1];
16174   }
16175   else
16176   {
16177       $Texi2HTML::THISDOC{'state'} = undef;
16178   }
16179}
16180
16181sub substitute_line($$;$$)
16182{
16183    my $line = shift;
16184    my $context_string = shift;
16185    my $state = shift;
16186    my $line_nr = shift;
16187    $state = {} if (!defined($state));
16188    $state->{'no_paragraph'} = 1;
16189
16190    if (($state->{'inside_document'} or $state->{'outside_document'}) and (!$state->{'duplicated'} and !$state->{'new_state'}))
16191    {
16192        msg_debug("substitute_line with main state in: ".var_to_str($context_string), $line_nr);
16193    }
16194    push @{$state->{'no_paragraph_stack'}}, $context_string;
16195    # this is usefull when called from &$I, and also for image files
16196    return simple_format($state, [ $line_nr ], $context_string, $line) if ($state->{'simple_format'});
16197    return substitute_text($state, [ $line_nr ], $context_string, $line);
16198}
16199
16200sub substitute_text($$$@)
16201{
16202    my $state = shift;
16203    my $line_nrs = shift;
16204    my $context = shift;
16205    my @stack = ();
16206    my $text = '';
16207    my $result = '';
16208    my $line_nr;
16209    if ($state->{'structure'})
16210    {
16211        initialise_state_structure($state);
16212    }
16213    elsif ($state->{'texi'})
16214    { # only in arg_expansion
16215        initialise_state_texi($state);
16216        msg_bug("substitute_text, 'texi' true but not 'arg_expansion'") if (!$state->{'arg_expansion'});
16217    }
16218    else
16219    {
16220#print STDERR "FILL_STATE substitute_text ($state->{'preformatted'}): @_\n";
16221        if (($state->{'inside_document'} or $state->{'outside_document'}) and (!$state->{'duplicated'} and !$state->{'new_state'}))
16222        {
16223            msg_debug("substitute_text with main state in: ".var_to_str($context), $line_nr);
16224        }
16225        fill_state($state);
16226        $state->{'context'} = $context;
16227    }
16228    $state->{'spool'} = [];
16229    #print STDERR "SUBST_TEXT ".var_to_str($context)."\n";
16230    push_state($state);
16231
16232    my $line_nrs_kept = $Texi2HTML::THISDOC{'line_nr'};
16233    $Texi2HTML::THISDOC{'line_nr'} = undef;
16234
16235    while (@_ or @{$state->{'spool'}} or $state->{'in_deff_line'})
16236    {
16237        my $line;
16238        if ($line_nrs and @{$line_nrs})
16239        {
16240             $line_nr = shift @{$line_nrs};
16241             $Texi2HTML::THISDOC{'line_nr'} = $line_nr;
16242        }
16243        if (@{$state->{'spool'}})
16244        {
16245             $line = shift @{$state->{'spool'}};
16246        }
16247        else
16248        {
16249            $line = shift @_;
16250        }
16251        # msg_debug ("SUBSTITUTE_TEXT $line", $line_nr) if (defined($line_nr));
16252        if ($state->{'in_deff_line'})
16253        {
16254            if (defined($line))
16255            {
16256                $line = $state->{'in_deff_line'} . $line;
16257            }
16258            else
16259            {
16260                $line = $state->{'in_deff_line'};
16261            }
16262            delete $state->{'in_deff_line'};
16263        }
16264        else
16265        {
16266            next unless (defined($line));
16267        }
16268        #{ my $p_line = $line; chomp($p_line); print STDERR "SUBST_TEXT $p_line\n"; }
16269        if ($state->{'structure'})
16270        {
16271            scan_structure ($line, \$text, \@stack, $state);
16272        }
16273        elsif ($state->{'texi'})
16274        {
16275            scan_texi ($line, \$text, \@stack, $state);
16276        }
16277        else
16278        {
16279            set_line_nr_in_stack($state, \@stack, $line_nr);
16280            scan_line($line, \$text, \@stack, $state, $line_nr);
16281        }
16282        next if (@stack);
16283        $result .= $text;
16284        $text = '';
16285    }
16286    if ($line_nrs and @{$line_nrs})
16287    {
16288        $line_nr = shift @{$line_nrs};
16289        $Texi2HTML::THISDOC{'line_nr'} = $line_nr;
16290    }
16291    # close stack in substitute_text
16292    if ($state->{'texi'})
16293    {
16294        close_stack_texi(\$text, \@stack, $state, $line_nr);
16295    }
16296    elsif ($state->{'structure'})
16297    {
16298        close_stack_structure(\$text, \@stack, $state, $line_nr);
16299    }
16300    else
16301    {
16302        close_stack(\$text, \@stack, $state, $line_nr);
16303    }
16304    #print STDERR "SUBST_TEXT end\n";
16305    pop_state();
16306    $Texi2HTML::THISDOC{'line_nr'} = $line_nrs_kept;
16307    return $result . $text;
16308}
16309
16310sub print_lines($;$)
16311{
16312    my ($fh, $lines) = @_;
16313    $lines = $Texi2HTML::THIS_SECTION unless $lines;
16314    my @cnt;
16315    my $cnt;
16316    for my $line (@$lines)
16317    {
16318        print $fh $line;
16319	if (defined($Texi2HTML::Config::WORDS_IN_PAGE) and (Texi2HTML::Config::get_conf('SPLIT') eq 'node'))
16320        {
16321            @cnt = split(/\W*\s+\W*/, $line);
16322            $cnt += scalar(@cnt);
16323        }
16324    }
16325    return $cnt;
16326}
16327
16328sub do_index_entry_label($$$$;$)
16329{
16330    my $command = shift;
16331    my $state = shift;
16332    my $line_nr = shift;
16333    my $entry_texi = shift;
16334    # this is only needed for definitions since the whole line is parsed to
16335    # reuse get_deff_index.
16336    my $line = shift;
16337
16338    my $prefix = index_entry_command_prefix($command, $line, $line_nr);
16339    my $index_name = $index_prefix_to_name{$prefix};
16340
16341    msg_debug("do_index_entry_label($command): Undefined entry_texi", $line_nr)
16342       if (!defined($entry_texi));
16343    $entry_texi = trim_comment_spaces($entry_texi, "index label in \@$command", $line_nr);
16344
16345    # index entries are not entered in special regions
16346    my $region = 'document';
16347    $region = $state->{'region'} if (defined($state->{'region'}));
16348
16349    my $entry;
16350    # Can be within a @caption expanded within a listoffloat. In that
16351    # case the 2 conditions on state are not set.
16352    if (defined($state->{'region'}) or !defined($state->{'expansion'}))
16353    {
16354       # index entry on a line that is not searched for index entries, like
16355       # a @def* line
16356       if (!defined($Texi2HTML::THISDOC{'index_entries'}->{$region}) or !defined($Texi2HTML::THISDOC{'index_entries'}->{$region}->{$entry_texi}))
16357       {
16358          line_warn(sprintf(__("Index entry not caught: `%s' in %s"), $entry_texi, $region), $line_nr);
16359       }
16360       else
16361       {
16362          my $entry_ref = $Texi2HTML::THISDOC{'index_entries'}->{$region}->{$entry_texi};
16363          # ============================ debug
16364          if (!defined($entry_ref->{'entries'}))
16365          {
16366              msg_debug("BUG, not defined: {'index_entries'}->{$region}->{$entry_texi}->{'entries'}", $line_nr);
16367          }
16368          # ============================  end debug
16369          if (scalar(@{$entry_ref->{'entries'}}) > 1)
16370          {
16371              if (!defined($entry_ref->{'index'}))
16372              {
16373                  $entry_ref->{'index'} = 0;
16374              }
16375              $entry = $entry_ref->{'entries'}->[$entry_ref->{'index'}];
16376              $entry_ref->{'index'}++;
16377          }
16378          else
16379          {
16380              $entry = $entry_ref->{'entries'}->[0];
16381          }
16382          $entry->{'seen_in_output'} = 1 if (!$state->{'outside_document'});
16383          ############################################# debug
16384          # verify that the old way of getting index entries (in an array) is
16385          # synchronized with the document
16386          if (!$state->{'region'})
16387          {
16388             my $entry_from_array = shift @index_labels;
16389             if ($entry_from_array ne $entry)
16390             {
16391                msg_debug ("entry `$entry->{'texi'}' ne entry_from_array `$entry_from_array->{'texi'}'", $line_nr);
16392             }
16393             if (!defined($entry_from_array))
16394             {
16395                mesg_debug ("Not enough index entries !", $line_nr);
16396             }
16397          }
16398          ############################################# end debug
16399       }
16400    }
16401
16402    if (!defined($entry))
16403    {
16404        # this can happen for listoffloats and caption without being a user
16405        # error. Well, in fact, it could be argued that it is indeed a user
16406        # error, putting an index entry in a snippet that can be expanded
16407        # more than once and is not strictly associated with a node/section.
16408
16409        #print STDERR "Entry for index $index_name not gathered in usual places ($region)\n";
16410        $entry = {
16411          'command' => $command,
16412          'texi' => $entry_texi,
16413          'entry' => $entry_texi,
16414          'prefix' => $prefix,
16415          'index_name' => $index_name,
16416        };
16417        $entry->{'key'} = sorted_line($entry_texi);
16418        $entry->{'entry'} = '@code{'.$entry->{'entry'}.'}'
16419            if (defined($index_name) and
16420             defined($index_names{$index_name}->{'prefixes'}) and
16421             $index_names{$index_name}->{'prefixes'}->{$prefix}
16422             and $entry->{'key'} =~ /\S/);
16423    }
16424
16425    ###################################### debug
16426    else
16427    {
16428         if ($entry->{'prefix'} ne $prefix)
16429         {
16430             msg_debug ("prefix in entry $entry->{'prefix'} ne $prefix from $command", $line_nr);
16431         }
16432    }
16433
16434    if ($command ne $entry->{'command'})
16435    {
16436        # happened with bad texinfo with a line like
16437        # @deffn func aaaa args  @defvr c--ategory d--efvr_name
16438        # now this case is caught above by "Index entry not caught:
16439        msg_debug ("($region) Waiting for index cmd \@$entry->{'command'} got \@$command", $line_nr);
16440    }
16441
16442    if ($entry->{'texi'} ne $entry_texi)
16443    {
16444        msg_debug ("Waiting for index `$entry->{'texi'}', got `$entry_texi'", $line_nr);
16445    }
16446
16447    my $id = 'no id';
16448    $id = $entry->{'id'} if (defined($entry->{'id'}));
16449    print STDERR "(index($index_name) $command) [$entry->{'entry'}] $id\n"
16450        if ($T2H_DEBUG & $DEBUG_INDEX);
16451    ###################################### end debug
16452
16453    #return (undef,'','') if ($state->{'region'});
16454    if ($entry->{'key'} =~ /^\s*$/)
16455    {
16456        line_warn(sprintf(__("Empty index entry for \@%s"), $command), $entry->{'line_nr'});
16457    }
16458    my $formatted_entry = substitute_line($entry->{'entry'}, "\@$command", prepare_state_multiple_pass("${command}_index", $state),$entry->{'line_nr'});
16459    my $formatted_entry_reference = substitute_line($entry->{'texi'}, "\@$command", prepare_state_multiple_pass("${command}_index", $state));
16460    return ($entry, $formatted_entry, &$Texi2HTML::Config::index_entry_label ($entry->{'id'}, $state->{'preformatted'}, $formatted_entry,
16461      $index_name,
16462       $command, $entry->{'texi'}, $formatted_entry_reference,
16463       (!$entry->{'seen_in_output'} and defined($entry->{'region'})),$entry));
16464}
16465
16466# decompose a decimal number on a given base. The algorithm looks like
16467# the division with growing powers (division suivant les puissances
16468# croissantes) ?
16469sub decompose($$)
16470{
16471    my $number = shift;
16472    my $base = shift;
16473    my @result = ();
16474
16475    return (0) if ($number == 0);
16476    my $power = 1;
16477    my $remaining = $number;
16478
16479    while ($remaining)
16480    {
16481         my $factor = $remaining % ($base ** $power);
16482         $remaining -= $factor;
16483         push (@result, $factor / ($base ** ($power - 1)));
16484         $power++;
16485    }
16486    return @result;
16487}
16488
16489# process a css file
16490sub process_css_file ($$)
16491{
16492    my $fh =shift;
16493    my $file = shift;
16494    my $in_rules = 0;
16495    my $in_comment = 0;
16496    my $in_import = 0;
16497    my $in_string = 0;
16498    my $rules = [];
16499    my $imports = [];
16500    my $line_nr = 0;
16501    while (my $line = <$fh>)
16502    {
16503        $line_nr++;
16504	    #print STDERR "Line: $line";
16505        if ($in_rules)
16506        {
16507            push @$rules, $line;
16508            next;
16509        }
16510        my $text = '';
16511        while (1)
16512        {
16513		#sleep 1;
16514		#print STDERR "${text}!in_comment $in_comment in_rules $in_rules in_import $in_import in_string $in_string: $line";
16515             if ($in_comment)
16516             {
16517                 if ($line =~ s/^(.*?\*\/)//)
16518                 {
16519                     $text .= $1;
16520                     $in_comment = 0;
16521                 }
16522                 else
16523                 {
16524                     push @$imports, $text . $line;
16525                     last;
16526                 }
16527             }
16528             elsif (!$in_string and $line =~ s/^\///)
16529             { # what do '\' do here ?
16530                 if ($line =~ s/^\*//)
16531                 {
16532                     $text .= '/*';
16533                     $in_comment = 1;
16534                 }
16535                 else
16536                 {
16537                     push (@$imports, $text. "\n") if ($text ne '');
16538                     push (@$rules, '/' . $line);
16539                     $in_rules = 1;
16540                     last;
16541                 }
16542             }
16543             elsif (!$in_string and $in_import and $line =~ s/^([\"\'])//)
16544             { # strings outside of import start rules
16545                 $text .= "$1";
16546                 $in_string = quotemeta("$1");
16547             }
16548             elsif ($in_string and $line =~ s/^(\\$in_string)//)
16549             {
16550                 $text .= $1;
16551             }
16552             elsif ($in_string and $line =~ s/^($in_string)//)
16553             {
16554                 $text .= $1;
16555                 $in_string = 0;
16556             }
16557             elsif ((! $in_string and !$in_import) and ($line =~ s/^([\\]?\@import)$// or $line =~ s/^([\\]?\@import\s+)//))
16558             {
16559                 $text .= $1;
16560                 $in_import = 1;
16561             }
16562             elsif (!$in_string and $in_import and $line =~ s/^\;//)
16563             {
16564                 $text .= ';';
16565                 $in_import = 0;
16566             }
16567             elsif (($in_import or $in_string) and $line =~ s/^(.)//)
16568             {
16569                  $text .= $1;
16570             }
16571             elsif (!$in_import and $line =~ s/^([^\s])//)
16572             {
16573                  push (@$imports, $text. "\n") if ($text ne '');
16574                  push (@$rules, $1 . $line);
16575                  $in_rules = 1;
16576                  last;
16577             }
16578             elsif ($line =~ s/^(\s)//)
16579             {
16580                  $text .= $1;
16581             }
16582             elsif ($line eq '')
16583             {
16584                  push (@$imports, $text);
16585                  last;
16586             }
16587        }
16588    }
16589    #file_line_warn (__("string not closed in css file"), $file) if ($in_string);
16590    #file_line_warn (__("--css-file ended in comment"), $file) if ($in_comment);
16591    #file_line_warn (__("\@import not finished in css file"), $file)  if ($in_import and !$in_comment and !$in_string);
16592    warn (sprintf(__("%s:%d: string not closed in css file"), $file, $line_nr)) if ($in_string);
16593    warn (sprintf(__("%s:%d: --css-file ended in comment"), $file, $line_nr)) if ($in_comment);
16594    warn (sprintf(__("%s:%d \@import not finished in css file"), $file, $line_nr))  if ($in_import and !$in_comment and !$in_string);
16595    return ($imports, $rules);
16596}
16597
16598sub collect_all_css_files()
16599{
16600   my @css_import_lines;
16601   my @css_rule_lines;
16602
16603  # process css files
16604   return ([],[]) if ($Texi2HTML::Config::NO_CSS);
16605   foreach my $file (@Texi2HTML::Config::CSS_FILES)
16606   {
16607      my $css_file_fh;
16608      my $css_file;
16609      if ($file eq '-')
16610      {
16611         $css_file_fh = \*STDIN;
16612         $css_file = '-';
16613      }
16614      else
16615      {
16616         $css_file = locate_include_file ($file);
16617         unless (defined($css_file))
16618         {
16619            document_warn ("css file $file not found");
16620            next;
16621         }
16622         unless (open (CSSFILE, "$css_file"))
16623         {
16624            warn (sprintf(__("%s: could not open --css-file %s: %s\n"), $real_command_name, $css_file, $!));
16625            next;
16626         }
16627         $css_file_fh = \*CSSFILE;
16628      }
16629      my ($import_lines, $rules_lines);
16630      ($import_lines, $rules_lines) = process_css_file ($css_file_fh, $css_file);
16631      push @css_import_lines, @$import_lines;
16632      push @css_rule_lines, @$rules_lines;
16633   }
16634
16635
16636   if ($T2H_DEBUG & $DEBUG_USER)
16637   {
16638      if (@css_import_lines)
16639      {
16640         print STDERR "# css import lines\n";
16641         foreach my $line (@css_import_lines)
16642         {
16643            print STDERR "$line";
16644         }
16645      }
16646      if (@css_rule_lines)
16647      {
16648         print STDERR "# css rule lines\n";
16649         foreach my $line (@css_rule_lines)
16650         {
16651            print STDERR "$line";
16652         }
16653      }
16654   }
16655   return (\@css_import_lines, \@css_rule_lines);
16656}
16657
16658sub init_with_file_name($)
16659{
16660   my $base_file = shift;
16661   set_docu_names($base_file, $Texi2HTML::THISDOC{'input_file_number'});
16662
16663   foreach my $handler(@Texi2HTML::Config::command_handler_init)
16664   {
16665      &$handler;
16666   }
16667}
16668
16669
16670#######################################################################
16671#
16672# Main processing, process all the files given on the command line
16673#
16674#######################################################################
16675
16676my @input_files = @ARGV;
16677# use STDIN if not a tty, like makeinfo does
16678@input_files = ('-') if (!scalar(@input_files) and !-t STDIN);
16679die sprintf(__("%s: missing file argument.\n"), $real_command_name) .$T2H_FAILURE_TEXT unless (scalar(@input_files) >= 1);
16680
16681my $file_number = 0;
16682# main processing
16683while(@input_files)
16684{
16685   my $input_file_arg = shift(@input_files);
16686
16687   %Texi2HTML::THISDOC = ();
16688   $Texi2HTML::THIS_ELEMENT = undef;
16689
16690   # Otherwise Texi2HTML::THISDOC wouldn't be set in case there was no call
16691   # to set_conf.
16692   foreach my $global_conf_vars('SPLIT', 'SPLIT_SIZE')
16693   {
16694      $Texi2HTML::THISDOC{$global_conf_vars} = Texi2HTML::Config::get_conf($global_conf_vars);
16695   }
16696
16697   foreach my $global_key (keys(%Texi2HTML::GLOBAL))
16698   {
16699      $Texi2HTML::THISDOC{$global_key} = $Texi2HTML::GLOBAL{$global_key};
16700   }
16701
16702   my $input_file_name;
16703   # try to concatenate with different suffixes. The last suffix is ''
16704   # such that the plain file name is checked.
16705   foreach my $suffix (@Texi2HTML::Config::INPUT_FILE_SUFFIXES)
16706   {
16707      $input_file_name = $input_file_arg.$suffix if (-e $input_file_arg.$suffix);
16708   }
16709   # in case no file was found, still set the file name
16710   $input_file_name = $input_file_arg if (!defined($input_file_name));
16711
16712   $Texi2HTML::THISDOC{'input_file_name'} = $input_file_name;
16713   $Texi2HTML::THISDOC{'input_file_number'} = $file_number;
16714   $Texi2HTML::THISDOC{'input_directory'} = '.';
16715   if ($input_file_name =~ /(.*\/)/)
16716   {
16717      $Texi2HTML::THISDOC{'input_directory'} = $1;
16718   }
16719
16720   my $input_file_base = $input_file_name;
16721   $input_file_base =~ s/\.te?x(i|info)?$//;
16722
16723   @{$Texi2HTML::TOC_LINES} = ();            # table of contents
16724   @{$Texi2HTML::OVERVIEW} = ();           # short table of contents
16725   # this could be done here, but perl warns that
16726   # `"Texi2HTML::TITLEPAGE" used only once' and it is reset in
16727   # &$Texi2HTML::Config::titlepage anyway
16728   # $Texi2HTML::TITLEPAGE = undef;
16729   @{$Texi2HTML::THIS_SECTION} = ();
16730
16731   # the reference to these hashes may be used before this point (for example
16732   # see makeinfo.init), so they should be kept as is and the values undef
16733   # but the key should not be deleted because the ref is on the key.
16734   foreach my $hash (\%Texi2HTML::HREF, \%Texi2HTML::NAME, \%Texi2HTML::NODE,
16735        \%Texi2HTML::NO_TEXI, \%Texi2HTML::SIMPLE_TEXT)
16736   {
16737       foreach my $key (keys(%$hash))
16738       {
16739           $hash->{$key} = undef;
16740       }
16741   }
16742
16743   %region_lines = ();
16744   %region_line_nrs = ();
16745   foreach my $region (@special_regions)
16746   {
16747      $region_lines{$region} = [];
16748      $region_line_nrs{$region} = [];
16749   }
16750
16751   @created_directories = ();
16752
16753   $docu_dir = undef;    # directory of the document
16754   $docu_name = undef;   # basename of the document
16755   $docu_rdir = undef;   # directory for the output
16756   $docu_toc = undef;    # document's table of contents
16757   $docu_stoc = undef;   # document's short toc
16758   $docu_foot = undef;   # document's footnotes
16759   $docu_about = undef;  # about this document
16760   $docu_top = undef;    # document top
16761   $docu_doc = undef;    # document (or document top of split)
16762   $docu_frame = undef;  # main frame file
16763   $docu_toc_frame = undef;       # toc frame file
16764   $path_to_working_dir = undef;  # relative path leading to the working
16765                                  # directory from the document directory
16766   $docu_doc_file = undef;
16767   $docu_toc_file = undef;
16768   $docu_stoc_file = undef;
16769   $docu_foot_file = undef;
16770   $docu_about_file = undef;
16771   $docu_top_file = undef;
16772   $docu_frame_file = undef;
16773   $docu_toc_frame_file = undef;
16774
16775   $global_pass = '0';
16776
16777   # done before any processing, this is not necessarily
16778   # the case with command_handler_init
16779   foreach my $handler(@Texi2HTML::Config::command_handler_setup)
16780   {
16781      &$handler;
16782   }
16783
16784   if (!$Texi2HTML::Config::USE_SETFILENAME)
16785   {
16786      init_with_file_name ($input_file_base);
16787   }
16788
16789   # FIXME when to do that?
16790   ($Texi2HTML::THISDOC{'css_import_lines'}, $Texi2HTML::THISDOC{'css_rule_lines'})
16791      = collect_all_css_files();
16792
16793   texinfo_initialization(0);
16794
16795   print STDERR "# reading from $input_file_name\n" if $T2H_VERBOSE;
16796
16797   $macros = undef;         # macros. reference on a hash
16798   %info_enclose = ();      # macros defined with definfoenclose
16799   @floats = ();            # floats list
16800   %floats = ();            # floats by style
16801   %nodes = ();             # nodes hash. The key is the texi node name
16802   %cross_reference_nodes = ();  # normalized node names arrays
16803
16804
16805   $global_pass = '1';
16806   my ($texi_lines, $first_texi_lines, $lines_numbers)
16807        = pass_texi($input_file_name);
16808
16809   if ($Texi2HTML::Config::USE_SETFILENAME and !defined($docu_name))
16810   {
16811      init_with_file_name ($input_file_base);
16812   }
16813
16814   $global_pass = '1 expand macros';
16815   Texi2HTML::Config::t2h_default_set_out_encoding();
16816   dump_texi($texi_lines, 'texi', $lines_numbers) if ($T2H_DEBUG & $DEBUG_TEXI);
16817   if (defined($Texi2HTML::Config::MACRO_EXPAND))
16818   {
16819       my @texi_lines = (@$first_texi_lines, @$texi_lines);
16820       dump_texi(\@texi_lines, '', undef, $Texi2HTML::Config::MACRO_EXPAND);
16821   }
16822
16823   %content_element = ();
16824   foreach my $command('contents', 'shortcontents')
16825   {
16826       $all_content_elements{$command} = [];
16827       foreach my $key (keys(%{$reference_content_element{$command}}))
16828       {
16829           $content_element{$command}->{$key} = $reference_content_element{$command}->{$key};
16830       }
16831   }
16832
16833   %sec2level = %reference_sec2level;
16834
16835   $element_before_anything =
16836   {
16837      'before_anything' => 1,
16838      'place' => [],
16839      'texi' => 'VIRTUAL ELEMENT BEFORE ANYTHING',
16840   };
16841
16842
16843   $footnote_element =
16844   {
16845      'id' => $Texi2HTML::Config::misc_pages_targets{'Footnotes'},
16846      'target' => $Texi2HTML::Config::misc_pages_targets{'Footnotes'},
16847      'file' => $docu_foot,
16848      'footnote' => 1,
16849      'place' => [],
16850   };
16851
16852   %region_initial_state = ();
16853   foreach my $region (@special_regions)
16854   {
16855      $region_initial_state{$region} = { };
16856   }
16857
16858# to determine if a command has to be processed the following are interesting
16859# (and can be faked):
16860# 'region': the name of the special region we are processing
16861# 'region_pass': the number of passes in that specific region (both outside
16862#                of the main document, and in the main document)
16863# 'multiple_pass': the number of pass in the formatting of the region in the
16864#                  main document
16865#                  It is set to 0 the first time the region is seen, before
16866#                  it will be -1, for example when doing the
16867#                  copying_comment, the titlepage... before starting with
16868#                  the document itself.
16869# 'outside_document': set to 1 if outside of the main document formatting
16870
16871   foreach my $key (keys(%region_initial_state))
16872   {
16873      $region_initial_state{$key}->{'multiple_pass'} = -1;
16874      $region_initial_state{$key}->{'region_pass'} = 0;
16875      $region_initial_state{$key}->{'num_head'} = 0;
16876      $region_initial_state{$key}->{'foot_num'} = 0;
16877      $region_initial_state{$key}->{'relative_foot_num'} = 0;
16878      $region_initial_state{$key}->{'region'} = $key;
16879   }
16880
16881   @opened_files = (); # all the files opened by the program to remove
16882                       # them if FORCE is not set and an error occured
16883
16884   texinfo_initialization(1);
16885
16886
16887   $no_element_associated_place = [];
16888
16889   $document_idx_num = 0;
16890   $document_sec_num = 0;
16891   $document_head_num = 0;
16892   $document_anchor_num = 0;
16893
16894   @nodes_list = ();        # nodes in document reading order
16895                            # each member is a reference on a hash
16896   @sections_list = ();     # sections in reading order
16897                            # each member is a reference on a hash
16898   @all_elements = ();      # sectioning elements (nodes and sections)
16899                            # in reading order. Each member is a reference
16900                            # on a hash which also appears in %nodes,
16901                            # @sections_list @nodes_list, @elements_list
16902   @elements_list = ();     # all the resulting elements in document order
16903   %sections = ();          # sections hash. The key is the section number
16904   %headings = ();          # headings hash. The key is the heading number
16905   $section_top = undef;    # @top section
16906   $element_top = undef;    # Top element
16907   $node_top = undef;       # Top node
16908   $node_first = undef;     # First node
16909   $element_index = undef;  # element with first index
16910   $element_chapter_index = undef;  # chapter with first index
16911   $element_first = undef;  # first element
16912   $element_last = undef;   # last element
16913   %special_commands = ();  # hash for the commands specially handled
16914                            # by the user
16915
16916   @index_labels = ();             # array corresponding with @?index commands
16917                                   # constructed during pass_texi, used to
16918                                   # put labels in pass_text
16919                                   # right now it is only used for debugging
16920                                   # purposes.
16921   @unknown_index_index_entries = ();  # holds index entries not associated
16922                                       # with any index
16923   %{$Texi2HTML::THISDOC{'index_entries_array'}} = (); # holds the index
16924                              # entries in order of appearance in the document
16925                              # for each index name.
16926   %{$Texi2HTML::THISDOC{'index_letters_array'}} = (); # holds the sorted
16927                            # index letters for each index name. The sorted
16928                            # letters hold the sorted index entries
16929
16930   $global_pass = 2;
16931   my ($doc_lines, $doc_numbers) = pass_structure($texi_lines, $lines_numbers);
16932
16933   foreach my $handler(@Texi2HTML::Config::command_handler_names)
16934   {
16935       &$handler;
16936   }
16937
16938   if ($T2H_DEBUG & $DEBUG_TEXI)
16939   {
16940      dump_texi($doc_lines, 'first', $doc_numbers);
16941      if (defined($Texi2HTML::Config::MACRO_EXPAND and $Texi2HTML::Config::DUMP_TEXI))
16942      {
16943          my @all_doc_lines = (@$first_texi_lines, @$doc_lines);
16944          #push (@$doc_lines, "\@bye\n");
16945          dump_texi(\@all_doc_lines, '', undef, $Texi2HTML::Config::MACRO_EXPAND . ".first");
16946      }
16947   }
16948   next if ($Texi2HTML::Config::DUMP_TEXI);
16949
16950   foreach my $style (keys(%special_commands))
16951   {
16952      $special_commands{$style}->{'max'} = $special_commands{$style}->{'count'};
16953   }
16954
16955   %files = ();   # keys are files. This is used to avoid reusing an already
16956                  # used file name
16957   %printed_indices = (); # value is true for an index name not empty and
16958                          # printed
16959   $global_pass = '2 prepare indices';
16960   prepare_indices();
16961   $global_pass = '2 element directions';
16962   rearrange_elements();
16963   do_names();
16964
16965   $global_pass = '2-3 user functions';
16966#Texi2HTML::LaTeX2HTML::latex2html();
16967   foreach my $handler(@Texi2HTML::Config::command_handler_process)
16968   {
16969       &$handler;
16970   }
16971
16972# maybe do that later to have more elements ready?
16973   &$Texi2HTML::Config::toc_body(\@sections_list);
16974
16975   &$Texi2HTML::Config::css_lines($Texi2HTML::THISDOC{'css_import_lines'},
16976        $Texi2HTML::THISDOC{'css_rule_lines'});
16977
16978
16979   $global_head_num = 0;       # heading index. it is global for the main doc,
16980                               # and taken from the state if in multiple_pass.
16981   $global_foot_num = 0;
16982   $global_relative_foot_num = 0;
16983   @foot_lines = ();           # footnotes
16984   $copying_comment = '';      # comment constructed from text between
16985                               # @copying and @end copying with licence
16986   %acronyms_like = ();        # acronyms or similar commands associated texts
16987                               # the key are the commands, the values are
16988                               # hash references associating shorthands to
16989                               # texts.
16990   @states_stack = ();
16991
16992   pass_text($doc_lines, $doc_numbers);
16993   print STDERR "BUG: " . scalar(@index_labels) . " index entries pending\n"
16994      if (scalar(@index_labels));
16995   foreach my $special (keys(%special_commands))
16996   {
16997      my $count = $special_commands{$special}->{'count'};
16998      if (($count != 0) and $T2H_VERBOSE)
16999      {
17000         document_warn ("$count special \@$special were not processed.\n");
17001      }
17002   }
17003   if ($Texi2HTML::Config::IDX_SUMMARY)
17004   {
17005      foreach my $entry (keys(%index_names))
17006      {
17007         do_index_summary_file($entry, $docu_name);
17008      }
17009   }
17010   if (defined($Texi2HTML::Config::INTERNAL_LINKS))
17011   {
17012      my $FH = open_out($Texi2HTML::Config::INTERNAL_LINKS);
17013      &$Texi2HTML::Config::internal_links($FH, \@elements_list, $Texi2HTML::THISDOC{'index_letters_array'});
17014      close ($FH);
17015   }
17016   do_node_files() if ($Texi2HTML::Config::NODE_FILES);
17017#l2h_FinishFromHtml() if ($Texi2HTML::Config::L2H);
17018#l2h_Finish() if($Texi2HTML::Config::L2H);
17019#Texi2HTML::LaTeX2HTML::finish();
17020   foreach my $handler(@Texi2HTML::Config::command_handler_finish)
17021   {
17022       &$handler;
17023   }
17024   &$Texi2HTML::Config::finish_out();
17025
17026   print STDERR "# File ($file_number) $input_file_name processed\n" if $T2H_VERBOSE;
17027   $file_number++;
17028}
17029print STDERR "# that's all folks\n" if $T2H_VERBOSE;
17030exit(0);
17031
17032
17033##############################################################################
17034
17035# These next few lines are legal in both Perl and nroff.
17036
17037.00 ;                           # finish .ig
17038
17039'di			\" finish diversion--previous line must be blank
17040.nr nl 0-1		\" fake up transition to first page again
17041.nr % 0			\" start at page 1
17042'; __END__ ############# From here on it's a standard manual page ############
17043    .so @mandir@/man1/texi2html.1
17044