1#! /usr/bin/env perl 2 3# texi2any: Texinfo converter. 4# 5# Copyright 2010-2021 Free Software Foundation, Inc. 6# 7# This program is free software; you can redistribute it and/or modify 8# it under the terms of the GNU General Public License as published by 9# the Free Software Foundation; either version 3 of the License, 10# or (at your option) any later version. 11# 12# This program is distributed in the hope that it will be useful, 13# but WITHOUT ANY WARRANTY; without even the implied warranty of 14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15# GNU General Public License for more details. 16# 17# You should have received a copy of the GNU General Public License 18# along with this program. If not, see <http://www.gnu.org/licenses/>. 19# 20# Original author: Patrice Dumas <pertusus@free.fr> 21# Parts (also from Patrice Dumas) come from texi2html.pl or texi2html.init. 22 23# for POSIX::setlocale and File::Spec 24require 5.00405; 25 26use strict; 27 28# for file names portability 29use File::Spec; 30# to determine the path separator and null file 31use Config; 32# for dirname and fileparse 33use File::Basename; 34#use Cwd; 35use Getopt::Long qw(GetOptions); 36# for carp 37#use Carp; 38 39Getopt::Long::Configure("gnu_getopt"); 40 41my ($real_command_name, $command_directory, $command_suffix); 42 43# This big BEGIN block deals with finding modules and 44# some dependencies that we ship 45# * in source or 46# * installed or 47# * installed relative to the script 48BEGIN 49{ 50 # emulate -w 51 $^W = 1; 52 ($real_command_name, $command_directory, $command_suffix) 53 = fileparse($0, '.pl'); 54 my $updir = File::Spec->updir(); 55 56 # These are substituted by the Makefile to create "texi2any". 57 my $datadir = '@datadir@'; 58 my $package = '@PACKAGE@'; 59 my $packagedir = '@pkglibdir@'; 60 61 if ($datadir eq '@' .'datadir@' 62 or defined($ENV{'TEXINFO_DEV_SOURCE'}) 63 and $ENV{'TEXINFO_DEV_SOURCE'} ne '0') 64 { 65 # Use uninstalled modules 66 67 # To find Texinfo::ModulePath 68 if (defined($ENV{'top_builddir'})) { 69 unshift @INC, File::Spec->catdir($ENV{'top_builddir'}, 'tp'); 70 } else { 71 unshift @INC, File::Spec->catdir($command_directory); 72 } 73 74 require Texinfo::ModulePath; 75 Texinfo::ModulePath::init(undef, undef, 'updirs' => 1); 76 } else { 77 # Look for modules in their installed locations. 78 79 my $lib_dir = File::Spec->catdir($datadir, $package); 80 unshift @INC, $lib_dir; 81 82 require Texinfo::ModulePath; 83 Texinfo::ModulePath::init($lib_dir, $packagedir, 'installed' => 1); 84 } 85} # end BEGIN 86 87# This allows disabling use of XS modules when Texinfo is built. 88BEGIN { 89 my $enable_xs = '@enable_xs@'; 90 if ($enable_xs eq 'no') { 91 package Texinfo::XSLoader; 92 our $disable_XS; 93 $disable_XS = 1; 94 } 95} 96 97use Locale::Messages; 98use Texinfo::Common; 99use Texinfo::Convert::Converter; 100 101# this associates the command line options to the arrays set during 102# command line parsing. 103my @css_files = (); 104my @css_refs = (); 105my $cmdline_options = { 'CSS_FILES' => \@css_files, 106 'CSS_REFS' => \@css_refs }; 107 108# determine the path separators 109my $path_separator = $Config{'path_sep'}; 110$path_separator = ':' if (!defined($path_separator)); 111my $quoted_path_separator = quotemeta($path_separator); 112 113# Paths and file names 114my $curdir = File::Spec->curdir(); 115my $updir = File::Spec->updir(); 116 117# set by configure, prefix for the sysconfdir and so on 118# This could be used in the eval 119my $prefix = '@prefix@'; 120my $datarootdir; 121my $sysconfdir; 122my $pkgdatadir; 123my $datadir; 124 125my $fallback_prefix = File::Spec->catdir(File::Spec->rootdir(), 'usr', 'local'); 126 127# We need to eval as $prefix has to be expanded. However when we haven't 128# run configure @sysconfdir will be expanded as an array, thus we verify 129# whether configure was run or not 130if ('@sysconfdir@' ne '@' . 'sysconfdir@') { 131 $sysconfdir = eval '"@sysconfdir@"'; 132} else { 133 $sysconfdir = File::Spec->catdir($fallback_prefix, 'etc'); 134} 135 136if ('@datarootdir@' ne '@' . 'datarootdir@') { 137 $datarootdir = eval '"@datarootdir@"'; 138} else { 139 $datarootdir = File::Spec->catdir($fallback_prefix, 'share'); 140} 141 142if ('@datadir@' ne '@' . 'datadir@' and '@PACKAGE@' ne '@' . 'PACKAGE@') { 143 $datadir = eval '"@datadir@"'; 144 my $package = '@PACKAGE@'; 145 $pkgdatadir = File::Spec->catdir($datadir, $package); 146} else { 147 $datadir = File::Spec->catdir($fallback_prefix, 'share'); 148 $pkgdatadir = File::Spec->catdir($datadir, 'texinfo'); 149} 150 151# work-around in case libintl-perl do not do it itself 152# see http://www.gnu.org/software/gettext/manual/html_node/The-LANGUAGE-variable.html#The-LANGUAGE-variable 153 154if ((defined($ENV{"LC_ALL"}) and $ENV{"LC_ALL"} =~ /^(C|POSIX)$/) 155 or (defined($ENV{"LANG"}) and $ENV{"LANG"} =~ /^(C|POSIX)$/)) { 156 delete $ENV{"LANGUAGE"} if defined($ENV{"LANGUAGE"}); 157} 158 159 160#my $messages_textdomain = 'texinfo'; 161my $messages_textdomain = '@PACKAGE@'; 162$messages_textdomain = 'texinfo' if ($messages_textdomain eq '@'.'PACKAGE@'); 163my $strings_textdomain = '@PACKAGE@' . '_document'; 164$strings_textdomain = 'texinfo_document' 165 if ($strings_textdomain eq '@'.'PACKAGE@' . '_document'); 166 167 168# we want a reliable way to switch locale, so we don't use the system 169# gettext. 170Locale::Messages->select_package('gettext_pp'); 171 172if ($Texinfo::ModulePath::texinfo_uninstalled) { 173 my $locales_dir = File::Spec->catdir($Texinfo::ModulePath::builddir, 174 'LocaleData'); 175 if (-d $locales_dir) { 176 Locale::Messages::bindtextdomain ($strings_textdomain, $locales_dir); 177 # the messages in this domain are not regenerated automatically, 178 # only when calling ./maintain/regenerate_perl_module_files.sh 179 Locale::Messages::bindtextdomain ($messages_textdomain, $locales_dir); 180 } else { 181 warn "Locales dir for document strings not found\n"; 182 } 183} else { 184 Locale::Messages::bindtextdomain ($strings_textdomain, 185 File::Spec->catdir($datadir, 'locale')); 186 Locale::Messages::bindtextdomain ($messages_textdomain, 187 File::Spec->catdir($datadir, 'locale')); 188} 189 190 191# Version setting is complicated, because we cope with 192# * script with configure values substituted or not 193# * script shipped as part of texinfo or as a standalone perl module 194 195# When shipped as a perl modules, $hardcoded_version is set to undef here 196# by a sed one liner. The consequence is that configure.ac is not used 197# to retrieve the version number. 198# Otherwise this is only used as a safety value, and should never be used 199# in practice as a regexp extracts the version from configure.ac. 200my $hardcoded_version = "0.00-hardcoded"; 201# Version set in configure.ac 202my $configured_version = '@PACKAGE_VERSION@'; 203if ($configured_version eq '@' . 'PACKAGE_VERSION@') { 204 # if not configured, and $hardcoded_version is set search for the version 205 # in configure.ac 206 if (defined($hardcoded_version)) { 207 if (open (CONFIGURE, 208 "< ".File::Spec->catfile($Texinfo::ModulePath::top_srcdir, 209 'configure.ac'))) { 210 while (<CONFIGURE>) { 211 if (/^AC_INIT\(\[[^\]]+\]\s*,\s*\[([^\]]+)\]\s*,/) { 212 $configured_version = "$1+dev"; # +dev to distinguish from installed 213 last; 214 } 215 } 216 close (CONFIGURE); 217 } 218 # This should never be used, but is a safety value 219 $configured_version = $hardcoded_version if (!defined($configured_version)); 220 } else { 221 # used in the standalone perl module, as $hardcoded_version is undef 222 # and it should never be configured in that setup 223 require Texinfo::Common; 224 $configured_version = $Texinfo::Common::VERSION; 225 } 226} 227 228# Compare the version of this file with the version of the modules 229# it is using. If they are different, don't go any further. This 230# can happen if multiple versions of texi2any are installed under a 231# different names, e.g. with the --program-suffix option to 'configure'. 232# The version in Common.pm is checked because that file has been present 233# since Texinfo 5.0 (the first release with texi2any in Perl). 234if ($configured_version ne $Texinfo::Common::VERSION 235 and $configured_version ne $Texinfo::Common::VERSION."+dev") { 236 warn "This is texi2any $configured_version but modules ". 237 "for texi2any $Texinfo::Common::VERSION found!\n"; 238 die "Your installation of Texinfo is broken; aborting.\n"; 239} 240 241 242my $configured_package = '@PACKAGE@'; 243$configured_package = 'Texinfo' if ($configured_package eq '@' . 'PACKAGE@'); 244my $configured_name = '@PACKAGE_NAME@'; 245$configured_name = $configured_package 246 if ($configured_name eq '@' .'PACKAGE_NAME@'); 247my $configured_name_version = "$configured_name $configured_version"; 248my $configured_url = '@PACKAGE_URL@'; 249$configured_url = 'http://www.gnu.org/software/texinfo/' 250 if ($configured_url eq '@' .'PACKAGE_URL@'); 251 252my $texinfo_dtd_version = '@TEXINFO_DTD_VERSION@'; 253# $hardcoded_version is undef for a standalone perl module 254if ($texinfo_dtd_version eq '@' . 'TEXINFO_DTD_VERSION@') { 255 $texinfo_dtd_version = undef; 256 if (defined($hardcoded_version)) { 257 if (open (CONFIGURE, 258 "< ".File::Spec->catfile($Texinfo::ModulePath::top_srcdir, 259 'configure.ac'))) { 260 while (<CONFIGURE>) { 261 if (/^TEXINFO_DTD_VERSION=([0-9]\S*)/) { 262 $texinfo_dtd_version = "$1"; 263 last; 264 } 265 } 266 close (CONFIGURE); 267 } 268 } 269} 270# Used in case it is not hardcoded in configure and for standalone perl module 271$texinfo_dtd_version = $configured_version 272 if (!defined($texinfo_dtd_version)); 273 274# defaults for options relevant in the main program, not undef, and also 275# defaults for all the converters. 276# Other relevant options (undef) are NO_WARN FORCE OUTFILE 277# Others are set in the converters (FORMAT_MENU). 278my $converter_default_options = { 279 'ERROR_LIMIT' => 100, 280 'TEXI2DVI' => 'texi2dvi', 281 'PACKAGE_VERSION' => $configured_version, 282 'PACKAGE' => $configured_package, 283 'PACKAGE_NAME' => $configured_name, 284 'PACKAGE_AND_VERSION' => $configured_name_version, 285 'PACKAGE_URL' => $configured_url, 286 'PROGRAM' => $real_command_name, 287 'TEXINFO_DTD_VERSION' => $texinfo_dtd_version, 288}; 289 290# determine configuration directories. 291 292my $conf_file_name = 'Config' ; 293 294# directories for texinfo configuration files 295my @language_config_dirs = File::Spec->catdir($curdir, '.texinfo'); 296push @language_config_dirs, File::Spec->catdir($ENV{'HOME'}, '.texinfo') 297 if (defined($ENV{'HOME'})); 298push @language_config_dirs, File::Spec->catdir($sysconfdir, 'texinfo') 299 if (defined($sysconfdir)); 300push @language_config_dirs, File::Spec->catdir($datadir, 'texinfo') 301 if (defined($datadir)); 302my @texinfo_config_dirs = ($curdir, @language_config_dirs); 303 304my @program_config_dirs; 305my @program_init_dirs; 306 307my $program_name = 'texi2any'; 308@program_config_dirs = ($curdir, File::Spec->catdir($curdir, ".$program_name")); 309push @program_config_dirs, File::Spec->catdir($ENV{'HOME'}, ".$program_name") 310 if (defined($ENV{'HOME'})); 311push @program_config_dirs, File::Spec->catdir($sysconfdir, $program_name) 312 if (defined($sysconfdir)); 313push @program_config_dirs, File::Spec->catdir($datadir, $program_name) 314 if (defined($datadir)); 315 316@program_init_dirs = @program_config_dirs; 317foreach my $texinfo_config_dir (@language_config_dirs) { 318 push @program_init_dirs, File::Spec->catdir($texinfo_config_dir, 'init'); 319} 320 321# Namespace for configuration 322{ 323package Texinfo::Config; 324 325#use Carp; 326 327# passed from main program 328my $cmdline_options; 329my $default_options; 330# used in main program 331our $options = {}; 332 333sub _load_config($$) { 334 $default_options = shift; 335 $cmdline_options = shift; 336 #print STDERR "cmdline_options: ".join('|',keys(%$cmdline_options))."\n"; 337} 338 339sub _load_init_file($) { 340 my $file = shift; 341 require Texinfo::Convert::HTML; 342 eval { require($file) ;}; 343 my $e = $@; 344 if ($e ne '') { 345 main::document_warn(sprintf(main::__("error loading %s: %s\n"), 346 $file, $e)); 347 } 348} 349 350# FIXME: maybe use an opaque return status that can be used to retrieve 351# an error message? 352sub set_from_init_file($$) { 353 my $var = shift; 354 my $value = shift; 355 if (!Texinfo::Common::valid_option($var)) { 356 # carp may be better, but infortunately, it points to the routine that 357 # loads the file, and not to the init file. 358 main::document_warn(sprintf(main::__("%s: unknown variable %s"), 359 'set_from_init_file', $var)); 360 return 0; 361 } 362 return 0 if (defined($cmdline_options->{$var})); 363 delete $default_options->{$var}; 364 $options->{$var} = $value; 365 return 1; 366} 367 368sub set_from_cmdline($$) { 369 my $var = shift; 370 my $value = shift; 371 delete $options->{$var}; 372 delete $default_options->{$var}; 373 if (!Texinfo::Common::valid_option($var)) { 374 main::document_warn(sprintf(main::__("%s: unknown variable %s\n"), 375 'set_from_cmdline', $var)); 376 return 0; 377 } 378 $cmdline_options->{$var} = $value; 379 return 1; 380} 381 382# This also could get and set some @-command results. 383# FIXME But it does not take into account what happens during conversion, 384# for that something like $converter->get_conf(...) has to be used. 385sub get_conf($) { 386 my $var = shift; 387 if (exists($cmdline_options->{$var})) { 388 return $cmdline_options->{$var}; 389 } elsif (exists($options->{$var})) { 390 return $options->{$var}; 391 } elsif (exists($default_options->{$var})) { 392 return $default_options->{$var}; 393 } else { 394 return undef; 395 } 396} 397 398# to dynamically add options from init files 399sub texinfo_add_valid_option($) 400{ 401 my $option = shift; 402 return Texinfo::Common::add_valid_option($option); 403} 404 405} 406# back in main program namespace 407 408sub locate_and_load_init_file($$) 409{ 410 my $filename = shift; 411 my $directories = shift; 412 413 my $file = Texinfo::Common::locate_init_file($filename, $directories, 0); 414 if (defined($file)) { 415 Texinfo::Config::_load_init_file($file); 416 } else { 417 document_warn(sprintf(__("could not read init file %s"), $filename)); 418 } 419} 420 421# read initialization files 422foreach my $file (Texinfo::Common::locate_init_file($conf_file_name, 423 [ reverse(@program_config_dirs) ], 1)) { 424 Texinfo::Config::_load_init_file($file); 425} 426 427sub set_from_cmdline($$) { 428 return &Texinfo::Config::set_from_cmdline(@_); 429} 430 431sub set_from_init_file($$) { 432 return &Texinfo::Config::set_from_init_file(@_); 433} 434 435sub get_conf($) { 436 return &Texinfo::Config::get_conf(@_); 437} 438 439my @input_file_suffixes = ('.txi','.texinfo','.texi','.txinfo',''); 440 441my @texi2dvi_args = (); 442 443my $format = 'info'; 444# this is the format associated with the output format, which is replaced 445# when the output format changes. It may also be removed if there is the 446# corresponding --no-ifformat. 447my $default_expanded_format = [ $format ]; 448my @conf_dirs = (); 449my @include_dirs = (); 450my @prepend_dirs = (); 451 452# options for all the files 453my $parser_options = {'expanded_formats' => [], 454 'values' => {'txicommandconditionals' => 1}}; 455 456Texinfo::Config::_load_config($converter_default_options, $cmdline_options); 457 458sub set_expansion($$) { 459 my $region = shift; 460 my $set = shift; 461 $set = 1 if (!defined($set)); 462 if ($set) { 463 push @{$parser_options->{'expanded_formats'}}, $region 464 unless (grep {$_ eq $region} @{$parser_options->{'expanded_formats'}}); 465 } else { 466 @{$parser_options->{'expanded_formats'}} = 467 grep {$_ ne $region} @{$parser_options->{'expanded_formats'}}; 468 @{$default_expanded_format} 469 = grep {$_ ne $region} @{$default_expanded_format}; 470 } 471} 472 473my $format_from_command_line = 0; 474 475my %format_command_line_names = ( 476 'xml' => 'texinfoxml', 477); 478 479my %formats_table = ( 480 'info' => { 481 'nodes_tree' => 1, 482 'floats' => 1, 483 'module' => 'Texinfo::Convert::Info' 484 }, 485 'plaintext' => { 486 'nodes_tree' => 1, 487 'floats' => 1, 488 'split' => 1, 489 'module' => 'Texinfo::Convert::Plaintext' 490 }, 491 'html' => { 492 'nodes_tree' => 1, 493 'floats' => 1, 494 'split' => 1, 495 'internal_links' => 1, 496 'simple_menu' => 1, 497 'move_index_entries_after_items' => 1, 498 'relate_index_entries_to_table_entries' => 1, 499 'no_warn_non_empty_parts' => 1, 500 'module' => 'Texinfo::Convert::HTML' 501 }, 502 'texinfoxml' => { 503 'nodes_tree' => 1, 504 'module' => 'Texinfo::Convert::TexinfoXML', 505 'floats' => 1, 506 }, 507 'texinfosxml' => { 508 'nodes_tree' => 1, 509 'module' => 'Texinfo::Convert::TexinfoSXML', 510 'floats' => 1, 511 }, 512 'ixinsxml' => { 513 'nodes_tree' => 1, 514 'module' => 'Texinfo::Convert::IXINSXML' 515 }, 516 'docbook' => { 517 'move_index_entries_after_items' => 1, 518 'no_warn_non_empty_parts' => 1, 519 'module' => 'Texinfo::Convert::DocBook' 520 }, 521 'pdf' => { 522 'texi2dvi_format' => 1, 523 }, 524 'ps' => { 525 'texi2dvi_format' => 1, 526 }, 527 'dvi' => { 528 'texi2dvi_format' => 1, 529 }, 530 'dvipdf' => { 531 'texi2dvi_format' => 1, 532 }, 533 'debugtree' => { 534 'split' => 1, 535 'module' => 'DebugTexinfo::DebugTree' 536 }, 537 'textcontent' => { 538 'module' => 'Texinfo::Convert::TextContent' 539 }, 540 'rawtext' => { 541 'module' => 'Texinfo::Convert::Text' 542 }, 543 'plaintexinfo' => { 544 'module' => 'Texinfo::Convert::PlainTexinfo' 545 }, 546 'parse' => { 547 }, 548 'structure' => { 549 'nodes_tree' => 1, 550 'floats' => 1, 551 'split' => 1, 552 }, 553); 554 555my $call_texi2dvi = 0; 556 557# previous_format should be in argument if there is a possibility of error. 558# as a fallback, the $format global variable is used. 559sub set_format($;$$) 560{ 561 my $set_format = shift; 562 my $previous_format = shift; 563 $previous_format = $format if (!defined($previous_format)); 564 my $do_not_override_command_line = shift; 565 566 my $new_format; 567 if ($format_command_line_names{$set_format}) { 568 $new_format = $format_command_line_names{$set_format}; 569 } else { 570 $new_format = $set_format; 571 } 572 my $expanded_format = $set_format; 573 if (!$formats_table{$new_format}) { 574 document_warn(sprintf(__("ignoring unrecognized TEXINFO_OUTPUT_FORMAT value `%s'\n"), 575 $new_format)); 576 $new_format = $previous_format; 577 } else { 578 if ($format_from_command_line and $do_not_override_command_line) { 579 $new_format = $previous_format; 580 } else { 581 if ($formats_table{$new_format}->{'texi2dvi_format'}) { 582 $call_texi2dvi = 1; 583 push @texi2dvi_args, '--'.$new_format; 584 $expanded_format = 'tex'; 585 } 586 if ($Texinfo::Common::texinfo_output_formats{$expanded_format}) { 587 if ($expanded_format eq 'plaintext') { 588 $default_expanded_format = [$expanded_format, 'info'] 589 } else { 590 $default_expanded_format = [$expanded_format] 591 } 592 } 593 $format_from_command_line = 1 594 unless ($do_not_override_command_line); 595 } 596 } 597 return $new_format; 598} 599 600sub set_global_format($) 601{ 602 my $set_format = shift; 603 $format = set_format($set_format); 604} 605 606sub document_warn($) { 607 return if (get_conf('NO_WARN')); 608 my $text = shift; 609 chomp ($text); 610 warn(sprintf(__p("program name: warning: warning_message", 611 "%s: warning: %s\n"), $real_command_name, $text)); 612} 613 614sub _exit($$) 615{ 616 my $error_count = shift; 617 my $opened_files = shift; 618 619 if ($error_count and $opened_files and !get_conf('FORCE')) { 620 while (@$opened_files) { 621 my $opened_file = shift (@$opened_files); 622 unlink ($opened_file); 623 } 624 } 625 exit (1) if ($error_count and (!get_conf('FORCE') 626 or $error_count > get_conf('ERROR_LIMIT'))); 627} 628 629sub handle_errors($$$) 630{ 631 my $self = shift; 632 my $error_count = shift; 633 my $opened_files = shift; 634 my ($errors, $new_error_count) = $self->errors(); 635 $error_count += $new_error_count if ($new_error_count); 636 foreach my $error_message (@$errors) { 637 warn $error_message->{'error_line'} if ($error_message->{'type'} eq 'error' 638 or !get_conf('NO_WARN')); 639 } 640 641 _exit($error_count, $opened_files); 642 return $error_count; 643} 644 645 646sub _get_converter_default($) 647{ 648 my $option = shift; 649 return $Texinfo::Convert::Converter::all_converters_defaults{$option} 650 if (defined($Texinfo::Convert::Converter::all_converters_defaults{$option})); 651 return undef; 652} 653 654# translation related todo to be done when the string change anyway to 655# avoid requiring translation 656sub makeinfo_help() 657{ 658 # TODO: avoid \n in translated strings. Report from Benno Schulenberg 659 my $makeinfo_help = 660 sprintf(__("Usage: %s [OPTION]... TEXINFO-FILE...\n"), 661 $real_command_name . $command_suffix) 662."\n". 663__("Translate Texinfo source documentation to various other formats, by default 664Info files suitable for reading online with Emacs or standalone GNU Info. 665 666This program is commonly installed as both `makeinfo' and `texi2any'; 667the behavior is identical, and does not depend on the installed name.\n") 668."\n"; 669 # TODO: avoid \n in translated strings, split each option in a translatable 670 # string. Report from Benno Schulenberg 671 $makeinfo_help .= sprintf(__("General options: 672 --document-language=STR locale to use in translating Texinfo keywords 673 for the output document (default C). 674 --error-limit=NUM quit after NUM errors (default %d). 675 --force preserve output even if errors. 676 --help display this help and exit. 677 --no-validate suppress node cross-reference validation. 678 --no-warn suppress warnings (but not errors). 679 --conf-dir=DIR search also for initialization files in DIR. 680 --init-file=FILE load FILE to modify the default behavior. 681 -c, --set-customization-variable VAR=VAL set customization variable VAR 682 to value VAL. 683 -v, --verbose explain what is being done. 684 --version display version information and exit.\n"), 685 get_conf('ERROR_LIMIT')) 686."\n"; 687 # TODO: avoid \n in translated strings, split each option in a translatable 688 # string. Report from Benno Schulenberg 689 $makeinfo_help .= __("Output format selection (default is to produce Info): 690 --docbook output Docbook XML rather than Info. 691 --html output HTML rather than Info. 692 --plaintext output plain text rather than Info. 693 --xml output Texinfo XML rather than Info. 694 --dvi, --dvipdf, --ps, --pdf call texi2dvi to generate given output, 695 after checking validity of TEXINFO-FILE.\n") 696."\n"; 697 # TODO: avoid \n in translated strings, split each option in a translatable 698 # string. Report from Benno Schulenberg 699 $makeinfo_help .= __("General output options: 700 -E, --macro-expand=FILE output macro-expanded source to FILE, 701 ignoring any \@setfilename. 702 --no-headers suppress node separators, Node: lines, and menus 703 from Info output (thus producing plain text) 704 or from HTML (thus producing shorter output). 705 Also, if producing Info, write to 706 standard output by default. 707 --no-split suppress any splitting of the output; 708 generate only one output file. 709 --[no-]number-sections output chapter and sectioning numbers; 710 default is on. 711 -o, --output=DEST output to DEST. 712 With split output, create DEST as a directory 713 and put the output files there. 714 With non-split output, if DEST is already 715 a directory or ends with a /, 716 put the output file there. 717 Otherwise, DEST names the output file.\n") 718."\n"; 719 # TODO: avoid \n in translated strings, split each option in a translatable 720 # string. Report from Benno Schulenberg 721 $makeinfo_help .= sprintf(__("Options for Info and plain text: 722 --disable-encoding do not output accented and special characters 723 in Info output based on \@documentencoding. 724 --enable-encoding override --disable-encoding (default). 725 --fill-column=NUM break Info lines at NUM characters (default %d). 726 --footnote-style=STYLE output footnotes in Info according to STYLE: 727 `separate' to put them in their own node; 728 `end' to put them at the end of the node, in 729 which they are defined (this is the default). 730 --paragraph-indent=VAL indent Info paragraphs by VAL spaces (default %d). 731 If VAL is `none', do not indent; if VAL is 732 `asis', preserve existing indentation. 733 --split-size=NUM split Info files at size NUM (default %d).\n"), 734 _get_converter_default('fillcolumn'), 735 _get_converter_default('paragraphindent'), 736 _get_converter_default('SPLIT_SIZE')) 737."\n"; 738 # TODO: avoid \n in translated strings, split each option in a translatable 739 # string. Report from Benno Schulenberg 740 $makeinfo_help .= __("Options for HTML: 741 --css-include=FILE include FILE in HTML <style> output; 742 read stdin if FILE is -. 743 --css-ref=URL generate CSS reference to URL. 744 --internal-links=FILE produce list of internal links in FILE. 745 --split=SPLIT split at SPLIT, where SPLIT may be `chapter', 746 `section' or `node'. 747 --transliterate-file-names use file names in ASCII transliteration. 748 --node-files produce redirection files for nodes and 749 anchors; default is set only if split.\n") 750."\n"; 751 # TODO: avoid \n in translated strings. Report from Benno Schulenberg 752 $makeinfo_help .= __("Options for XML and Docbook: 753 --output-indent=VAL does nothing, retained for compatibility.\n") 754."\n"; 755 $makeinfo_help .= __("Options for DVI/PS/PDF: 756 --Xopt=OPT pass OPT to texi2dvi; can be repeated.\n") 757."\n"; 758 # TODO: avoid \n in translated strings, split each option in a translatable 759 # string. Report from Benno Schulenberg 760 $makeinfo_help .= __("Input file options: 761 --commands-in-node-names does nothing, retained for compatibility. 762 -D VAR define the variable VAR, as with \@set. 763 -D 'VAR VAL' define VAR to VAL (one shell argument). 764 -I DIR append DIR to the \@include search path. 765 -P DIR prepend DIR to the \@include search path. 766 -U VAR undefine the variable VAR, as with \@clear.\n") 767."\n"; 768 # TODO: avoid \n in translated strings, split each option in a translatable 769 # string. Report from Benno Schulenberg 770 $makeinfo_help .= __("Conditional processing in input: 771 --ifdocbook process \@ifdocbook and \@docbook even if 772 not generating Docbook. 773 --ifhtml process \@ifhtml and \@html even if not generating HTML. 774 --ifinfo process \@ifinfo even if not generating Info. 775 --ifplaintext process \@ifplaintext even if not generating plain text. 776 --iftex process \@iftex and \@tex. 777 --ifxml process \@ifxml and \@xml. 778 --no-ifdocbook do not process \@ifdocbook and \@docbook text. 779 --no-ifhtml do not process \@ifhtml and \@html text. 780 --no-ifinfo do not process \@ifinfo text. 781 --no-ifplaintext do not process \@ifplaintext text. 782 --no-iftex do not process \@iftex and \@tex text. 783 --no-ifxml do not process \@ifxml and \@xml text. 784 785 Also, for the --no-ifFORMAT options, do process \@ifnotFORMAT text.\n") 786."\n"; 787 # TODO: avoid \n in translated strings, split each option in a translatable 788 # string. Report from Benno Schulenberg 789 $makeinfo_help .= __(" The defaults for the \@if... conditionals depend on the output format: 790 if generating Docbook, --ifdocbook is on and the others are off; 791 if generating HTML, --ifhtml is on and the others are off; 792 if generating Info, --ifinfo is on and the others are off; 793 if generating plain text, --ifplaintext is on and the others are off; 794 if generating XML, --ifxml is on and the others are off.\n") 795."\n"; 796 # TODO: avoid \n in translated strings, split each option in a translatable 797 # string. Report from Benno Schulenberg 798 $makeinfo_help .= __("Examples: 799 makeinfo foo.texi write Info to foo's \@setfilename 800 makeinfo --html foo.texi write HTML to \@setfilename 801 makeinfo --xml foo.texi write Texinfo XML to \@setfilename 802 makeinfo --docbook foo.texi write Docbook XML to \@setfilename 803 makeinfo --plaintext foo.texi write plain text to standard output 804 makeinfo --pdf foo.texi write PDF using texi2dvi 805 806 makeinfo --html --no-headers foo.texi write html without node lines, menus 807 makeinfo --number-sections foo.texi write Info with numbered sections 808 makeinfo --no-split foo.texi write one Info file however big\n") 809."\n"; 810 $makeinfo_help .= __("Email bug reports to bug-texinfo\@gnu.org, 811general questions and discussion to help-texinfo\@gnu.org. 812Texinfo home page: http://www.gnu.org/software/texinfo/") ."\n"; 813 return $makeinfo_help; 814} 815 816my $Xopt_arg_nr = 0; 817 818my $result_options = Getopt::Long::GetOptions ( 819 'help|h' => sub { print makeinfo_help(); exit 0; }, 820 'version|V' => sub {print "$program_name (GNU texinfo) $configured_version\n\n"; 821 printf __("Copyright (C) %s Free Software Foundation, Inc. 822License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> 823This is free software: you are free to change and redistribute it. 824There is NO WARRANTY, to the extent permitted by law.\n"), "2021"; 825 exit 0;}, 826 'macro-expand|E=s' => sub { set_from_cmdline('MACRO_EXPAND', $_[1]); }, 827 'ifhtml!' => sub { set_expansion('html', $_[1]); }, 828 'ifinfo!' => sub { set_expansion('info', $_[1]); }, 829 'ifxml!' => sub { set_expansion('xml', $_[1]); }, 830 'ifdocbook!' => sub { set_expansion('docbook', $_[1]); }, 831 'iftex!' => sub { set_expansion('tex', $_[1]); }, 832 'ifplaintext!' => sub { set_expansion('plaintext', $_[1]); }, 833 'I=s' => sub { push @texi2dvi_args, ('-'.$_[0], $_[1]); 834 push @include_dirs, split(/$quoted_path_separator/, $_[1]); }, 835 'conf-dir=s' => sub { push @conf_dirs, split(/$quoted_path_separator/, $_[1]); }, 836 'P=s' => sub { unshift @prepend_dirs, split(/$quoted_path_separator/, $_[1]); }, 837 'number-sections!' => sub { set_from_cmdline('NUMBER_SECTIONS', $_[1]); }, 838 'number-footnotes!' => sub { set_from_cmdline('NUMBER_FOOTNOTES', $_[1]); }, 839 'node-files!' => sub { set_from_cmdline('NODE_FILES', $_[1]); }, 840 'footnote-style=s' => sub { 841 if ($_[1] eq 'end' or $_[1] eq 'separate') { 842 set_from_cmdline('footnotestyle', $_[1]); 843 } else { 844 die sprintf(__("%s: --footnote-style arg must be `separate' or `end', not `%s'.\n"), $real_command_name, $_[1]); 845 } 846 }, 847 'split=s' => sub { my $split = $_[1]; 848 my @messages 849 = Texinfo::Common::warn_unknown_split($_[1]); 850 if (@messages) { 851 foreach my $message (@messages) { 852 document_warn($message); 853 } 854 $split = 'node'; 855 } 856 set_from_cmdline('SPLIT', $split); }, 857 'no-split' => sub { set_from_cmdline('SPLIT', ''); 858 set_from_cmdline('SPLIT_SIZE', undef);}, 859 'headers!' => sub { set_from_cmdline('HEADERS', $_[1]); 860 if (!$_[1]) { 861 set_from_cmdline('FORMAT_MENU', 'nomenu'); 862 } else { 863 # a special value that is modified below when the 864 # output format is known, to be the default for that 865 # format, or 'menu' 866 set_from_cmdline('FORMAT_MENU', 'set_format_menu_from_cmdline_header'); 867 } 868 $format = 'plaintext' if (!$_[1] and $format eq 'info'); }, 869 'output|out|o=s' => sub { 870 my $var = 'OUTFILE'; 871 if ($_[1] =~ m:/$: or -d $_[1]) { 872 set_from_cmdline($var, undef); 873 $var = 'SUBDIR'; 874 } 875 set_from_cmdline($var, $_[1]); 876 push @texi2dvi_args, '-o', $_[1]; 877 }, 878 'no-validate|no-pointer-validate' => sub { 879 set_from_cmdline('novalidate',$_[1]); 880 $parser_options->{'info'}->{'novalidate'} = $_[1]; 881 }, 882 'no-warn' => sub { set_from_cmdline('NO_WARN', $_[1]); }, 883 'verbose|v!' => sub {set_from_cmdline('VERBOSE', $_[1]); 884 push @texi2dvi_args, '--verbose'; }, 885 'document-language=s' => sub { 886 set_from_cmdline('documentlanguage', $_[1]); 887 $parser_options->{'documentlanguage'} = $_[1]; 888 my @messages 889 = Texinfo::Common::warn_unknown_language($_[1]); 890 foreach my $message (@messages) { 891 document_warn($message); 892 } 893 }, 894 'D=s' => sub { 895 my $var = $_[1]; 896 my @field = split (/\s+/, $var, 2); 897 if (@field == 1) { 898 $parser_options->{'values'}->{$var} = 1; 899 push @texi2dvi_args, "--command=\@set $var 1"; 900 } else { 901 $parser_options->{'values'}->{$field[0]} = $field[1]; 902 push @texi2dvi_args, "--command=\@set $field[0] $field[1]"; 903 } 904 }, 905 'U=s' => sub { 906 delete $parser_options->{'values'}->{$_[1]}; 907 push @texi2dvi_args, "--command=\@clear $_[1]"; 908 }, 909 'init-file=s' => sub { 910 locate_and_load_init_file($_[1], [ @conf_dirs, @program_init_dirs ]); 911 }, 912 'set-customization-variable|c=s' => sub { 913 my $var_val = $_[1]; 914 if ($var_val =~ s/^(\w+)\s*=?\s*//) { 915 my $var = $1; 916 my $value = $var_val; 917 if ($value =~ /^undef$/i) { 918 $value = undef; 919 } 920 set_from_cmdline($var, $value); 921 } 922 }, 923 'css-include=s' => \@css_files, 924 'css-ref=s' => \@css_refs, 925 'transliterate-file-names!' => 926 sub {set_from_cmdline('TRANSLITERATE_FILE_NAMES', $_[1]);}, 927 'error-limit|e=i' => sub { set_from_cmdline('ERROR_LIMIT', $_[1]); }, 928 'split-size=s' => sub {set_from_cmdline('SPLIT_SIZE', $_[1])}, 929 'paragraph-indent|p=s' => sub { 930 my $value = $_[1]; 931 if ($value =~ /^([0-9]+)$/ or $value eq 'none' or $value eq 'asis') { 932 set_from_cmdline('paragraphindent', $_[1]); 933 } else { 934 die sprintf(__("%s: --paragraph-indent arg must be numeric/`none'/`asis', not `%s'.\n"), 935 $real_command_name, $value); 936 } 937 }, 938 'fill-column|f=i' => sub {set_from_cmdline('FILLCOLUMN',$_[1]);}, 939 'enable-encoding' => sub {set_from_cmdline('ENABLE_ENCODING',$_[1]); 940 $parser_options->{'ENABLE_ENCODING'} = $_[1];}, 941 'disable-encoding' => sub {set_from_cmdline('ENABLE_ENCODING', 0); 942 $parser_options->{'ENABLE_ENCODING'} = 0;}, 943 'internal-links=s' => sub {set_from_cmdline('INTERNAL_LINKS', $_[1]);}, 944 'force|F' => sub {set_from_cmdline('FORCE', $_[1]);}, 945 'commands-in-node-names' => sub { ;}, 946 'output-indent=i' => sub { ;}, 947 'reference-limit=i' => sub { ;}, 948 'Xopt=s' => sub {push @texi2dvi_args, $_[1]; $Xopt_arg_nr++}, 949 'silent|quiet' => sub { push @texi2dvi_args, '--'.$_[0];}, 950 'plaintext' => sub {$format = set_format($_[0].'');}, 951 'html' => sub {$format = set_format($_[0].'');}, 952 'info' => sub {$format = set_format($_[0].'');}, 953 'docbook' => sub {$format = set_format($_[0].'');}, 954 'xml' => sub {$format = set_format($_[0].'');}, 955 'dvi' => sub {$format = set_format($_[0].'');}, 956 'dvipdf' => sub {$format = set_format($_[0].'');}, 957 'ps' => sub {$format = set_format($_[0].'');}, 958 'pdf' => sub {$format = set_format($_[0].'');}, 959 'debug=i' => sub {set_from_cmdline('DEBUG', $_[1]); 960 $parser_options->{'DEBUG'} = $_[1]; 961 push @texi2dvi_args, '--'.$_[0]; }, 962); 963 964 965 966exit 1 if (!$result_options); 967 968# Change some options depending on the settings of other ones 969sub normalize_config { 970 my $conf = shift; 971 972 if (defined($conf->{'TEXINFO_OUTPUT_FORMAT'})) { 973 $format = set_format($conf->{'TEXINFO_OUTPUT_FORMAT'}, $format, 1); 974 } elsif (defined($conf->{'TEXI2HTML'})) { 975 $format = set_format('html', $format, 1); 976 $parser_options->{'values'}->{'texi2html'} = 1; 977 } 978 if (defined($conf->{'HTML_MATH'}) and $conf->{'HTML_MATH'} eq 'l2h') { 979 $conf->{'L2H'} = 1; 980 } 981} 982 983$cmdline_options->{'include_directories'} = [@include_dirs]; 984 985normalize_config($cmdline_options); 986 987# FIXME do this here or inside format-specific code? 988my $latex2html_file = 'latex2html.pm'; 989if (defined($cmdline_options->{'L2H'})) { 990 locate_and_load_init_file($latex2html_file, 991 [ @conf_dirs, @program_init_dirs ]); 992} 993 994my $tex4ht_file = 'tex4ht.pm'; 995if (defined($cmdline_options->{'HTML_MATH'}) 996 and $cmdline_options->{'HTML_MATH'} eq 't4h') { 997 locate_and_load_init_file($tex4ht_file, 998 [ @conf_dirs, @program_init_dirs ]); 999} 1000 1001# For tests, set some strings to values not changing with releases 1002my %test_conf = ( 1003 'PACKAGE_VERSION' => '', 1004 'PACKAGE' => 'texinfo', 1005 'PACKAGE_NAME' => 'texinfo', 1006 'PACKAGE_AND_VERSION' => 'texinfo', 1007 'PACKAGE_URL' => 'http://www.gnu.org/software/texinfo/', 1008# maybe don't set this? 1009 'PROGRAM' => 'texi2any', 1010); 1011if (get_conf('TEST')) { 1012 foreach my $conf (keys (%test_conf)) { 1013 $converter_default_options->{$conf} = $test_conf{$conf}; 1014 } 1015} 1016 1017 1018my %format_names = ( 1019 'info' => 'Info', 1020 'html' => 'HTML', 1021 'docbook' => 'DocBook', 1022 'texinfoxml' => 'Texinfo XML', 1023 'plaintext' => 'Plain Text', 1024); 1025 1026sub format_name($) 1027{ 1028 my $format = shift; 1029 if ($format_names{$format}) { 1030 return $format_names{$format}; 1031 } else { 1032 return $format; 1033 } 1034} 1035 1036 1037if (defined($ENV{'TEXINFO_OUTPUT_FORMAT'}) 1038 and $ENV{'TEXINFO_OUTPUT_FORMAT'} ne '') { 1039 $format = set_format($ENV{'TEXINFO_OUTPUT_FORMAT'}, $format, 1); 1040} 1041 1042if ($call_texi2dvi) { 1043 if (defined(get_conf('OUTFILE')) and @ARGV > 1) { 1044 die sprintf(__('%s: when generating %s, only one input FILE may be specified with -o'."\n"), 1045 $real_command_name, format_name($format)); 1046 } 1047} elsif($Xopt_arg_nr) { 1048 document_warn(__('--Xopt option without printed output')); 1049} 1050 1051require Texinfo::Parser; 1052require Texinfo::Structuring; 1053require Texinfo::Transformations; 1054# Avoid loading these modules until down here to speed up the case 1055# when they are not needed. 1056 1057my %tree_transformations; 1058if (get_conf('TREE_TRANSFORMATIONS')) { 1059 my @transformations = split /,/, get_conf('TREE_TRANSFORMATIONS'); 1060 foreach my $transformation (@transformations) { 1061 if (Texinfo::Common::valid_tree_transformation($transformation)) { 1062 $tree_transformations{$transformation} = 1; 1063 } else { 1064 document_warn(sprintf(__('unknown tree transformation %s'), 1065 $transformation)); 1066 } 1067 } 1068} 1069 1070if (get_conf('SPLIT') and !$formats_table{$format}->{'split'}) { 1071 document_warn(sprintf(__('ignoring splitting for format %s'), 1072 format_name($format))); 1073 set_from_cmdline('SPLIT', ''); 1074} 1075 1076foreach my $expanded_format (@{$default_expanded_format}) { 1077 push @{$parser_options->{'expanded_formats'}}, $expanded_format 1078 unless (grep {$_ eq $expanded_format} @{$parser_options->{'expanded_formats'}}); 1079} 1080 1081my $converter_class; 1082my %converter_defaults; 1083 1084if (defined($formats_table{$format}->{'module'})) { 1085 # Speed up initialization by only loading the module we need. 1086 eval "require $formats_table{$format}->{'module'};" 1087 or die "$@"; 1088 eval '$formats_table{$format}->{\'converter\'} = sub{'. 1089 $formats_table{$format}->{'module'} 1090 .'->converter(@_)};'; 1091} 1092 1093if (defined($formats_table{$format}->{'module'})) { 1094 $converter_class = $formats_table{$format}->{'module'}; 1095 # $cmdline_options is passed to have TEXI2HTML set for conversion to 1096 # HTML 1097 %converter_defaults = $converter_class->converter_defaults($cmdline_options); 1098 1099 # set FORMAT_MENU to the output format default, if not nomenu 1100 if (defined(get_conf('FORMAT_MENU')) 1101 and get_conf('FORMAT_MENU') eq 'set_format_menu_from_cmdline_header') { 1102 if (defined($converter_defaults{'FORMAT_MENU'}) 1103 and $converter_defaults{'FORMAT_MENU'} ne 'nomenu') { 1104 set_from_cmdline('FORMAT_MENU', $converter_defaults{'FORMAT_MENU'}); 1105 } else { 1106 set_from_cmdline('FORMAT_MENU', 'menu'); 1107 } 1108 } 1109} else { 1110 if (defined(get_conf('FORMAT_MENU')) 1111 and get_conf('FORMAT_MENU') eq 'set_format_menu_from_cmdline_header') { 1112 set_from_cmdline('FORMAT_MENU', 'menu'); 1113 } 1114} 1115 1116# using no warnings is wrong, but a way to avoid a spurious warning. 1117no warnings 'once'; 1118my @parser_settable_options = keys(%Texinfo::Common::default_parser_customization_values); 1119push @parser_settable_options, keys(%Texinfo::Common::default_structure_customization_values); 1120foreach my $parser_settable_option (@parser_settable_options) { 1121 if (defined(get_conf($parser_settable_option))) { 1122 $parser_options->{$parser_settable_option} 1123 = get_conf($parser_settable_option); 1124 } elsif (defined($converter_class) 1125 and defined($converter_defaults{$parser_settable_option})) { 1126 $parser_options->{$parser_settable_option} 1127 = $converter_defaults{$parser_settable_option}; 1128 } 1129} 1130 1131# Copy some of the customization variables into the parser options. 1132# The configuration options are upper-cased when considered as 1133# customization variables, and lower-cased when passed to the Parser. 1134# The customization variables passed here can only be set in perl 1135# customization files, using set_from_init_file(). 1136foreach my $parser_option (map {uc($_)} 1137 (keys (%Texinfo::Common::default_parser_state_configuration))) { 1138 $parser_options->{lc($parser_option)} = get_conf($parser_option) 1139 if (defined(get_conf($parser_option))); 1140} 1141 1142 1143# Main processing, process all the files given on the command line 1144 1145my @input_files = @ARGV; 1146# use STDIN if not a tty, like makeinfo does 1147@input_files = ('-') if (!scalar(@input_files) and !-t STDIN); 1148die sprintf(__("%s: missing file argument.\n"), $real_command_name) 1149 .sprintf(__("Try `%s --help' for more information.\n"), $real_command_name) 1150 unless (scalar(@input_files) >= 1); 1151 1152my $file_number = -1; 1153my @opened_files = (); 1154my %unclosed_files; 1155my $error_count = 0; 1156# main processing 1157while(@input_files) { 1158 $file_number++; 1159 my $input_file_arg = shift(@input_files); 1160 my $input_file_name; 1161 # try to concatenate with different suffixes. The last suffix is '' 1162 # such that the plain file name is checked. 1163 foreach my $suffix (@input_file_suffixes) { 1164 if (-e $input_file_arg.$suffix) { 1165 $input_file_name = $input_file_arg.$suffix; 1166 last; 1167 } 1168 } 1169 # in case no file was found, still set the file name 1170 $input_file_name = $input_file_arg if (!defined($input_file_name)); 1171 1172 my ($input_filename, $input_directory, $suffix) = fileparse($input_file_name); 1173 if (!defined($input_directory) or $input_directory eq '') { 1174 $input_directory = $curdir; 1175 } 1176 1177 my $input_file_base = $input_file_name; 1178 $input_file_base =~ s/\.te?x(i|info)?$//; 1179 1180 my $parser_file_options = { %$parser_options }; 1181 1182 $parser_file_options->{'include_directories'} = [@include_dirs]; 1183 1184 my @prepended_include_directories = ('.'); 1185 push @prepended_include_directories, $input_directory 1186 if ($input_directory ne '.'); 1187 @prepended_include_directories = 1188 (@prepend_dirs, @prepended_include_directories); 1189 1190 unshift @{$parser_file_options->{'include_directories'}}, 1191 @prepended_include_directories; 1192 1193 my $parser = Texinfo::Parser::parser($parser_file_options); 1194 my $tree = $parser->parse_texi_file($input_file_name); 1195 1196 if (defined($tree) 1197 and (defined(get_conf('DUMP_TREE')) 1198 or (get_conf('DEBUG') and get_conf('DEBUG') >= 10))) { 1199 # this is very wrong, but a way to avoid a spurious warning. 1200 no warnings 'once'; 1201 local $Data::Dumper::Purity = 1; 1202 no warnings 'once'; 1203 local $Data::Dumper::Indent = 1; 1204 print STDERR Data::Dumper->Dump([$tree]); 1205 } 1206 if (!defined($tree) or $format eq 'parse') { 1207 handle_errors($parser, $error_count, \@opened_files); 1208 next; 1209 } 1210 1211 1212 if ($tree_transformations{'fill_gaps_in_sectioning'}) { 1213 my ($filled_contents, $added_sections) 1214 = Texinfo::Transformations::fill_gaps_in_sectioning($tree); 1215 if (!defined($filled_contents)) { 1216 document_warn(__("fill_gaps_in_sectioning transformation return no result. No section?")); 1217 } else { 1218 $tree->{'contents'} = $filled_contents; 1219 } 1220 } 1221 if ((get_conf('SIMPLE_MENU') 1222 and $formats_table{$format}->{'simple_menu'}) 1223 or $tree_transformations{'simple_menus'}) { 1224 $parser->Texinfo::Transformations::set_menus_to_simple_menu(); 1225 } 1226 1227 if (defined(get_conf('MACRO_EXPAND')) and $file_number == 0) { 1228 require Texinfo::Convert::Texinfo; 1229 my $texinfo_text = Texinfo::Convert::Texinfo::convert($tree, 1); 1230 #print STDERR "$texinfo_text\n"; 1231 my $macro_expand_file = get_conf('MACRO_EXPAND'); 1232 my $macro_expand_fh = Texinfo::Common::open_out($parser, $macro_expand_file); 1233 1234 my $error_macro_expand_file; 1235 if (defined($macro_expand_fh)) { 1236 print $macro_expand_fh $texinfo_text; 1237 if (!close($macro_expand_fh)) { 1238 document_warn(sprintf(__("error on closing macro expand file %s: %s\n"), 1239 $macro_expand_file, $!)); 1240 $error_macro_expand_file = 1; 1241 } 1242 $parser->Texinfo::Convert::Converter::register_close_file($macro_expand_file); 1243 } else { 1244 document_warn(sprintf(__("could not open %s for writing: %s\n"), 1245 $macro_expand_file, $!)); 1246 $error_macro_expand_file = 1; 1247 } 1248 1249 if ($error_macro_expand_file) { 1250 $error_count++; 1251 _exit($error_count, \@opened_files); 1252 } 1253 } 1254 if (get_conf('DUMP_TEXI') or $formats_table{$format}->{'texi2dvi_format'}) { 1255 handle_errors($parser, $error_count, \@opened_files); 1256 next; 1257 } 1258 1259 if ($formats_table{$format}->{'move_index_entries_after_items'} 1260 or $tree_transformations{'move_index_entries_after_items'}) { 1261 Texinfo::Common::move_index_entries_after_items_in_tree($tree); 1262 } 1263 1264 if ($formats_table{$format}->{'relate_index_entries_to_table_entries'} 1265 or $tree_transformations{'relate_index_entries_to_table_entries'}) { 1266 Texinfo::Common::relate_index_entries_to_table_entries_in_tree($tree); 1267 } 1268 1269 if ($tree_transformations{'insert_nodes_for_sectioning_commands'}) { 1270 my ($modified_contents, $added_nodes) 1271 = Texinfo::Transformations::insert_nodes_for_sectioning_commands($parser, $tree); 1272 if (!defined($modified_contents)) { 1273 document_warn(__( 1274 "insert_nodes_for_sectioning_commands transformation return no result. No section?")); 1275 } else { 1276 $tree->{'contents'} = $modified_contents; 1277 } 1278 } 1279 1280 Texinfo::Structuring::associate_internal_references($parser); 1281 # every format needs the sectioning structure 1282 1283 my $structure = Texinfo::Structuring::sectioning_structure($parser, $tree); 1284 1285 if ($structure 1286 and !$formats_table{$format}->{'no_warn_non_empty_parts'}) { 1287 Texinfo::Structuring::warn_non_empty_parts($parser); 1288 } 1289 1290 if ($tree_transformations{'complete_tree_nodes_menus'}) { 1291 Texinfo::Transformations::complete_tree_nodes_menus($parser, $tree); 1292 } elsif ($tree_transformations{'complete_tree_nodes_missing_menu'}) { 1293 Texinfo::Transformations::complete_tree_nodes_missing_menu($parser, $tree); 1294 } 1295 1296 if ($tree_transformations{'regenerate_master_menu'}) { 1297 Texinfo::Transformations::regenerate_master_menu($parser); 1298 } 1299 1300 # this can be done for every format, since information is already gathered 1301 my $floats = $parser->floats_information(); 1302 1303 my $top_node; 1304 if ($formats_table{$format}->{'nodes_tree'}) { 1305 1306 # it is not get_conf('FORMAT_MENU') but $parser_options as 1307 # $parser_options is set to the output default and then replaced 1308 # with get_conf('FORMAT_MENU') is needed 1309 if ($parser_options->{'FORMAT_MENU'} eq 'menu') { 1310 Texinfo::Structuring::set_menus_node_directions($parser); 1311 } 1312 $top_node = Texinfo::Structuring::nodes_tree($parser); 1313 if ($parser_options->{'FORMAT_MENU'} eq 'menu') { 1314 Texinfo::Structuring::complete_node_tree_with_menus($parser, $top_node); 1315 } 1316 } 1317 if ($formats_table{$format}->{'floats'}) { 1318 Texinfo::Structuring::number_floats($floats); 1319 } 1320 1321 $error_count = handle_errors($parser, $error_count, \@opened_files); 1322 1323 if ($format eq 'structure') { 1324 next; 1325 } 1326 1327 if ($file_number != 0) { 1328 delete $cmdline_options->{'OUTFILE'} if exists($cmdline_options->{'OUTFILE'}); 1329 delete $cmdline_options->{'PREFIX'} if exists($cmdline_options->{'PREFIX'}); 1330 delete $cmdline_options->{'SUBDIR'} 1331 if (exists($cmdline_options->{'SUBDIR'}) and get_conf('SPLIT')); 1332 } 1333 my $converter_options = { %$converter_default_options, 1334 %$cmdline_options, 1335 %$Texinfo::Config::options }; 1336 1337 $converter_options->{'expanded_formats'} = $parser_options->{'expanded_formats'}; 1338 $converter_options->{'parser'} = $parser; 1339 $converter_options->{'output_format'} = $format; 1340 $converter_options->{'language_config_dirs'} = \@language_config_dirs; 1341 unshift @{$converter_options->{'include_directories'}}, 1342 @prepended_include_directories; 1343 1344 my $converter = &{$formats_table{$format}->{'converter'}}($converter_options); 1345 $converter->output($tree); 1346 push @opened_files, $converter->converter_opened_files(); 1347 handle_errors($converter, $error_count, \@opened_files); 1348 my $converter_unclosed_files = $converter->converter_unclosed_files(); 1349 if ($converter_unclosed_files) { 1350 foreach my $unclosed_file (keys(%$converter_unclosed_files)) { 1351 if ($unclosed_file eq '-') { 1352 $unclosed_files{$unclosed_file} 1353 = $converter_unclosed_files->{$unclosed_file}; 1354 } else { 1355 if (!close($converter_unclosed_files->{$unclosed_file})) { 1356 warn(sprintf(__("%s: error on closing %s: %s\n"), 1357 $real_command_name, $unclosed_file, $!)); 1358 $error_count++; 1359 _exit($error_count, \@opened_files); 1360 } 1361 } 1362 } 1363 } 1364 1365 if (defined(get_conf('INTERNAL_LINKS')) and $file_number == 0 1366 and $formats_table{$format}->{'internal_links'}) { 1367 my $internal_links_text 1368 = $converter->output_internal_links(); 1369 # always create a file, even if empty. 1370 $internal_links_text = '' if (!defined($internal_links_text)); 1371 my $internal_links_file = get_conf('INTERNAL_LINKS'); 1372 my $internal_links_fh = Texinfo::Common::open_out($converter, 1373 $internal_links_file); 1374 my $error_internal_links_file; 1375 if (defined ($internal_links_fh)) { 1376 print $internal_links_fh $internal_links_text; 1377 1378 if (!close ($internal_links_fh)) { 1379 warn(sprintf(__("%s: error on closing internal links file %s: %s\n"), 1380 $real_command_name, $internal_links_file, $!)); 1381 $error_internal_links_file = 1; 1382 } 1383 $converter->register_close_file($internal_links_file); 1384 } else { 1385 warn(sprintf(__("%s: could not open %s for writing: %s\n"), 1386 $real_command_name, $internal_links_file, $!)); 1387 $error_internal_links_file = 1; 1388 } 1389 if ($error_internal_links_file) { 1390 $error_count++; 1391 _exit($error_count, \@opened_files); 1392 } 1393 } 1394 if (defined(get_conf('SORT_ELEMENT_COUNT')) and $file_number == 0) { 1395 my $converter_element_count_file 1396 = Texinfo::Convert::TextContent->converter($converter_options); 1397 my $use_sections = (! $formats_table{$format}->{'nodes_tree'} 1398 or (defined($converter->get_conf('USE_NODES')) 1399 and !$converter->get_conf('USE_NODES'))); 1400 my ($sorted_name_counts_array, $sort_element_count_text) 1401 = Texinfo::Convert::Converter::sort_element_counts( 1402 $converter_element_count_file, $tree, $use_sections, 1403 get_conf('SORT_ELEMENT_COUNT_WORDS')); 1404 1405 my $sort_element_count_file = get_conf('SORT_ELEMENT_COUNT'); 1406 my $sort_element_count_fh = Texinfo::Common::open_out($converter, 1407 $sort_element_count_file); 1408 my $error_sort_element_count_file; 1409 if (defined ($sort_element_count_fh)) { 1410 print $sort_element_count_fh $sort_element_count_text; 1411 1412 if (!close ($sort_element_count_fh)) { 1413 warn(sprintf(__("%s: error on closing internal links file %s: %s\n"), 1414 $real_command_name, $sort_element_count_file, $!)); 1415 $error_sort_element_count_file = 1; 1416 } 1417 $converter->register_close_file($sort_element_count_file); 1418 } else { 1419 warn(sprintf(__("%s: could not open %s for writing: %s\n"), 1420 $real_command_name, $sort_element_count_file, $!)); 1421 $error_sort_element_count_file = 1; 1422 } 1423 if ($error_sort_element_count_file) { 1424 $error_count++; 1425 _exit($error_count, \@opened_files); 1426 } 1427 } 1428} 1429 1430foreach my $unclosed_file (keys(%unclosed_files)) { 1431 if (!close($unclosed_files{$unclosed_file})) { 1432 warn(sprintf(__("%s: error on closing %s: %s\n"), 1433 $real_command_name, $unclosed_file, $!)); 1434 $error_count++; 1435 _exit($error_count, \@opened_files); 1436 } 1437} 1438 1439if ($call_texi2dvi) { 1440 if (get_conf('DEBUG') or get_conf('VERBOSE')) { 1441 print STDERR "EXEC ".join('|', (get_conf('TEXI2DVI'), @texi2dvi_args, @ARGV)) 1442 ."\n"; 1443 } 1444 exec { get_conf('TEXI2DVI') } (get_conf('TEXI2DVI'), @texi2dvi_args, @ARGV); 1445} 1446 14471; 1448