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