| #! /usr/bin/perl |
| |
| # texi2any: Texinfo converter. |
| # |
| # Copyright 2010, 2011, 2012, 2013, 2014, 2015, 2016 |
| # Free Software Foundation, Inc. |
| # |
| # This program is free software; you can redistribute it and/or modify |
| # it under the terms of the GNU General Public License as published by |
| # the Free Software Foundation; either version 3 of the License, |
| # or (at your option) any later version. |
| # |
| # This program is distributed in the hope that it will be useful, |
| # but WITHOUT ANY WARRANTY; without even the implied warranty of |
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| # GNU General Public License for more details. |
| # |
| # You should have received a copy of the GNU General Public License |
| # along with this program. If not, see <http://www.gnu.org/licenses/>. |
| # |
| # Original author: Patrice Dumas <pertusus@free.fr> |
| # Parts (also from Patrice Dumas) come from texi2html.pl or texi2html.init. |
| |
| # for POSIX::setlocale and File::Spec |
| require 5.00405; |
| |
| use strict; |
| |
| # for file names portability |
| use File::Spec; |
| # to determine the path separator and null file |
| use Config; |
| # for dirname and fileparse |
| use File::Basename; |
| #use Cwd; |
| use Getopt::Long qw(GetOptions); |
| # for carp |
| #use Carp; |
| |
| Getopt::Long::Configure("gnu_getopt"); |
| |
| # This big BEGIN block deals with finding modules and |
| # some dependencies that we ship |
| # * in source or |
| # * installed or |
| # * installed relative to the script |
| BEGIN |
| { |
| # emulate -w |
| $^W = 1; |
| my ($real_command_name, $command_directory, $command_suffix) |
| = fileparse($0, '.pl'); |
| my $updir = File::Spec->updir(); |
| |
| # These are substituted by the Makefile to create "texi2any". |
| my $datadir = '/usr/local/google/home/pgynther/clients/buildroot/output/host/usr/share'; |
| my $package = 'texinfo'; |
| my $packagedir = '/usr/local/google/home/pgynther/clients/buildroot/output/host/usr/lib/texinfo'; |
| |
| if ($datadir eq '@' .'datadir@' or $package eq '@' . 'PACKAGE@' |
| or $packagedir eq '@' .'pkglibdir@' |
| or defined($ENV{'TEXINFO_DEV_SOURCE'}) |
| and $ENV{'TEXINFO_DEV_SOURCE'} ne '0') |
| { |
| # Use uninstalled modules |
| |
| # To find Texinfo::ModulePath |
| if (!defined($ENV{'top_builddir'})) { |
| $ENV{'top_builddir'} = File::Spec->catdir($command_directory, $updir); |
| } |
| unshift @INC, File::Spec->catdir($ENV{'top_builddir'}, 'tp'); |
| |
| if (defined($ENV{'top_srcdir'})) { |
| my $lib_dir = File::Spec->catdir($ENV{'top_srcdir'}, 'tp'); |
| unshift @INC, $lib_dir; |
| } |
| |
| require Texinfo::ModulePath; |
| Texinfo::ModulePath::init(); |
| } else { |
| # Look for modules in their installed locations. |
| |
| my $lib_dir = File::Spec->catdir($datadir, $package); |
| |
| # try to make package relocatable, will only work if |
| # standard relative paths are used |
| if (! -f File::Spec->catfile($lib_dir, 'Texinfo', 'Parser.pm') |
| and -f File::Spec->catfile($command_directory, $updir, 'share', |
| 'texinfo', 'Texinfo', 'Parser.pm')) { |
| $lib_dir = File::Spec->catdir($command_directory, $updir, |
| 'share', 'texinfo'); |
| } |
| unshift @INC, $lib_dir; |
| |
| require Texinfo::ModulePath; |
| Texinfo::ModulePath::init($lib_dir, $packagedir); |
| } |
| } # end BEGIN |
| |
| BEGIN { |
| my $enable_xs = 'no'; |
| if ($enable_xs eq 'no') { |
| package Texinfo::Convert::Paragraph; |
| our $disable_XS; |
| $disable_XS = 1; |
| } |
| } |
| |
| use Locale::Messages; |
| use Texinfo::Common; |
| use Texinfo::Convert::Converter; |
| |
| my ($real_command_name, $command_directory, $command_suffix) |
| = fileparse($0, '.pl'); |
| |
| # this associates the command line options to the arrays set during |
| # command line parsing. |
| my @css_files = (); |
| my @css_refs = (); |
| my $cmdline_options = { 'CSS_FILES' => \@css_files, |
| 'CSS_REFS' => \@css_refs }; |
| |
| # determine the path separators |
| my $path_separator = $Config{'path_sep'}; |
| $path_separator = ':' if (!defined($path_separator)); |
| my $quoted_path_separator = quotemeta($path_separator); |
| |
| # Paths and file names |
| my $curdir = File::Spec->curdir(); |
| my $updir = File::Spec->updir(); |
| |
| # set by configure, prefix for the sysconfdir and so on |
| # This could be used in the eval |
| my $prefix = '/usr/local/google/home/pgynther/clients/buildroot/output/host/usr'; |
| my $datarootdir; |
| my $sysconfdir; |
| my $pkgdatadir; |
| my $datadir; |
| |
| my $fallback_prefix = File::Spec->catdir(File::Spec->rootdir(), 'usr', 'local'); |
| |
| # We need to eval as $prefix has to be expanded. However when we haven't |
| # run configure @sysconfdir will be expanded as an array, thus we verify |
| # whether configure was run or not |
| if ('/usr/local/google/home/pgynther/clients/buildroot/output/host/etc' ne '@' . 'sysconfdir@') { |
| $sysconfdir = eval '"/usr/local/google/home/pgynther/clients/buildroot/output/host/etc"'; |
| } else { |
| $sysconfdir = File::Spec->catdir($fallback_prefix, 'etc'); |
| } |
| |
| if ('/usr/local/google/home/pgynther/clients/buildroot/output/host/usr/share' ne '@' . 'datarootdir@') { |
| $datarootdir = eval '"/usr/local/google/home/pgynther/clients/buildroot/output/host/usr/share"'; |
| } else { |
| $datarootdir = File::Spec->catdir($fallback_prefix, 'share'); |
| } |
| |
| if ('/usr/local/google/home/pgynther/clients/buildroot/output/host/usr/share' ne '@' . 'datadir@' and 'texinfo' ne '@' . 'PACKAGE@') { |
| $datadir = eval '"/usr/local/google/home/pgynther/clients/buildroot/output/host/usr/share"'; |
| my $package = 'texinfo'; |
| $pkgdatadir = File::Spec->catdir($datadir, $package); |
| } else { |
| $datadir = File::Spec->catdir($fallback_prefix, 'share'); |
| $pkgdatadir = File::Spec->catdir($datadir, 'texinfo'); |
| } |
| |
| # work-around in case libintl-perl do not do it itself |
| # see http://www.gnu.org/software/gettext/manual/html_node/The-LANGUAGE-variable.html#The-LANGUAGE-variable |
| |
| if ((defined($ENV{"LC_ALL"}) and $ENV{"LC_ALL"} =~ /^(C|POSIX)$/) |
| or (defined($ENV{"LANG"}) and $ENV{"LANG"} =~ /^(C|POSIX)$/)) { |
| delete $ENV{"LANGUAGE"} if defined($ENV{"LANGUAGE"}); |
| } |
| |
| |
| #my $messages_textdomain = 'texinfo'; |
| my $messages_textdomain = 'texinfo'; |
| $messages_textdomain = 'texinfo' if ($messages_textdomain eq '@'.'PACKAGE@'); |
| my $strings_textdomain = 'texinfo' . '_document'; |
| $strings_textdomain = 'texinfo_document' |
| if ($strings_textdomain eq '@'.'PACKAGE@' . '_document'); |
| |
| sub __($) { |
| my $msgid = shift; |
| return Locale::Messages::dgettext($messages_textdomain, $msgid); |
| } |
| |
| sub __p($$) { |
| my $context = shift; |
| my $msgid = shift; |
| return Locale::Messages::dpgettext($messages_textdomain, $context, $msgid); |
| } |
| |
| my $srcdir; |
| if (defined($ENV{'top_srcdir'})) { |
| $srcdir = File::Spec->catdir($ENV{'top_srcdir'}, 'tp'); |
| } else { |
| $srcdir = $command_directory; |
| } |
| |
| my $libsrcdir = File::Spec->catdir($srcdir, 'maintain'); |
| |
| |
| # we want a reliable way to switch locale, so we don't use the system |
| # gettext. |
| Locale::Messages->select_package('gettext_pp'); |
| |
| #my @search_locale_dirs = ("$datadir/locale", (map $_ . '/LocaleData', @INC), |
| # qw (/usr/share/locale /usr/local/share/locale)); |
| my @search_locale_dirs = (); |
| |
| if (($command_suffix eq '.pl' and !(defined($ENV{'TEXINFO_DEV_SOURCE'}) |
| and $ENV{'TEXINFO_DEV_SOURCE'} eq 0)) or $ENV{'TEXINFO_DEV_SOURCE'}) { |
| # in case of build from the source directory, out of source build, |
| # this helps to locate the locales. |
| my $locales_dir_found = 0; |
| @search_locale_dirs = ( |
| File::Spec->catdir($libsrcdir, $updir, 'LocaleData'), |
| File::Spec->catdir($curdir, 'LocaleData'), |
| File::Spec->catdir($updir, $updir, $updir, 'tp', 'LocaleData'), |
| File::Spec->catdir($updir, $updir, 'tp', 'LocaleData')); |
| foreach my $locales_dir (@search_locale_dirs) { |
| if (-d $locales_dir) { |
| Locale::Messages::bindtextdomain ($strings_textdomain, $locales_dir); |
| # the messages in this domain are not regenerated automatically, |
| # only when calling ./maintain/regenerate_perl_module_files.sh |
| Locale::Messages::bindtextdomain ($messages_textdomain, $locales_dir); |
| $locales_dir_found = 1; |
| last; |
| } |
| } |
| if (!$locales_dir_found) { |
| warn "Locales dir for document strings not found (@search_locale_dirs)\n"; |
| } |
| } else { |
| Locale::Messages::bindtextdomain ($strings_textdomain, |
| File::Spec->catdir($datadir, 'locale')); |
| Locale::Messages::bindtextdomain ($messages_textdomain, |
| File::Spec->catdir($datadir, 'locale')); |
| } |
| |
| #Locale::Messages::bindtextdomain ($messages_textdomain, |
| # File::Spec->catdir($datadir, 'locale')); |
| |
| |
| # Version setting is complicated, because we cope with |
| # * script with configure values substituted or not |
| # * script shipped as part of texinfo or as a standalone perl module |
| |
| # When shipped as a perl modules, $hardcoded_version is set to undef here |
| # by a sed one liner. The consequence is that configure.ac is not used |
| # to retrieve the version number. |
| # Otherwise this is only used as a safety value, and should never be used |
| # in practice as a regexp extracts the version from configure.ac. |
| my $hardcoded_version = "0.00-hardcoded"; |
| # Version set in configure.ac |
| my $configured_version = '6.1'; |
| if ($configured_version eq '@' . 'PACKAGE_VERSION@') { |
| # if not configured, and $hardcoded_version is set search for the version |
| # in configure.ac |
| if (defined($hardcoded_version)) { |
| if (open (CONFIGURE, |
| "< ".File::Spec->catfile($srcdir, $updir, 'configure.ac'))) { |
| while (<CONFIGURE>) { |
| if (/^AC_INIT\(\[[^\]]+\]\s*,\s*\[([^\]]+)\]\s*,/) { |
| $configured_version = "$1+dev"; # +dev to distinguish from installed |
| last; |
| } |
| } |
| close (CONFIGURE); |
| } |
| # This should never be used, but is a safety value |
| $configured_version = $hardcoded_version if (!defined($configured_version)); |
| } else { |
| # used in the standalone perl module, as $hardcoded_version is undef |
| # and it should never be configured in that setup |
| require Texinfo::Parser; |
| $configured_version = $Texinfo::Parser::VERSION; |
| } |
| } |
| my $configured_package = 'texinfo'; |
| $configured_package = 'Texinfo' if ($configured_package eq '@' . 'PACKAGE@'); |
| my $configured_name = 'GNU Texinfo'; |
| $configured_name = $configured_package |
| if ($configured_name eq '@' .'PACKAGE_NAME@'); |
| my $configured_name_version = "$configured_name $configured_version"; |
| my $configured_url = 'http://www.gnu.org/software/texinfo/'; |
| $configured_url = 'http://www.gnu.org/software/texinfo/' |
| if ($configured_url eq '@' .'PACKAGE_URL@'); |
| |
| my $texinfo_dtd_version = '6.0'; |
| # $hardcoded_version is undef for a standalone perl module |
| if ($texinfo_dtd_version eq '@' . 'TEXINFO_DTD_VERSION@') { |
| $texinfo_dtd_version = undef; |
| if (defined($hardcoded_version)) { |
| if (open (CONFIGURE, |
| "< ".File::Spec->catfile($srcdir, $updir, 'configure.ac'))) { |
| while (<CONFIGURE>) { |
| if (/^TEXINFO_DTD_VERSION=([0-9]\S*)/) { |
| $texinfo_dtd_version = "$1"; |
| last; |
| } |
| } |
| close (CONFIGURE); |
| } |
| } |
| } |
| # Used in case it is not hardcoded in configure and for standalone perl module |
| $texinfo_dtd_version = $configured_version |
| if (!defined($texinfo_dtd_version)); |
| |
| # defaults for options relevant in the main program, not undef, and also |
| # defaults for all the converters. |
| # Other relevant options (undef) are NO_WARN FORCE OUTFILE |
| # Others are set in the converters (SHOW_MENU). |
| my $converter_default_options = { |
| 'ERROR_LIMIT' => 100, |
| 'TEXI2DVI' => 'texi2dvi', |
| 'PACKAGE_VERSION' => $configured_version, |
| 'PACKAGE' => $configured_package, |
| 'PACKAGE_NAME' => $configured_name, |
| 'PACKAGE_AND_VERSION' => $configured_name_version, |
| 'PACKAGE_URL' => $configured_url, |
| 'PROGRAM' => $real_command_name, |
| 'TEXINFO_DTD_VERSION' => $texinfo_dtd_version, |
| }; |
| |
| # determine configuration directories. |
| |
| my $conf_file_name = 'Config' ; |
| my $texinfo_htmlxref = 'htmlxref.cnf'; |
| |
| # directories for texinfo configuration files |
| my @language_config_dirs = File::Spec->catdir($curdir, '.texinfo'); |
| push @language_config_dirs, File::Spec->catdir($ENV{'HOME'}, '.texinfo') |
| if (defined($ENV{'HOME'})); |
| push @language_config_dirs, File::Spec->catdir($sysconfdir, 'texinfo') |
| if (defined($sysconfdir)); |
| push @language_config_dirs, File::Spec->catdir($datadir, 'texinfo') |
| if (defined($datadir)); |
| my @texinfo_config_dirs = ($curdir, @language_config_dirs); |
| |
| my @program_config_dirs; |
| my @program_init_dirs; |
| |
| my $program_name = 'texi2any'; |
| @program_config_dirs = ($curdir, File::Spec->catdir($curdir, ".$program_name")); |
| push @program_config_dirs, File::Spec->catdir($ENV{'HOME'}, ".$program_name") |
| if (defined($ENV{'HOME'})); |
| push @program_config_dirs, File::Spec->catdir($sysconfdir, $program_name) |
| if (defined($sysconfdir)); |
| push @program_config_dirs, File::Spec->catdir($datadir, $program_name) |
| if (defined($datadir)); |
| |
| @program_init_dirs = @program_config_dirs; |
| foreach my $texinfo_config_dir (@language_config_dirs) { |
| push @program_init_dirs, File::Spec->catdir($texinfo_config_dir, 'init'); |
| } |
| |
| # Namespace for configuration |
| { |
| package Texinfo::Config; |
| |
| #use Carp; |
| |
| # passed from main program |
| my $cmdline_options; |
| my $default_options; |
| # used in main program |
| our $options = {}; |
| |
| sub _load_config($$) { |
| $default_options = shift; |
| $cmdline_options = shift; |
| #print STDERR "cmdline_options: ".join('|',keys(%$cmdline_options))."\n"; |
| } |
| |
| sub _load_init_file($) { |
| my $file = shift; |
| require Texinfo::Convert::HTML; |
| eval { require($file) ;}; |
| my $e = $@; |
| if ($e ne '') { |
| main::document_warn(sprintf(main::__("error loading %s: %s\n"), |
| $file, $e)); |
| } |
| } |
| |
| # FIXME: maybe use an opaque return status that can be used to retrieve |
| # an error message? |
| sub set_from_init_file($$) { |
| my $var = shift; |
| my $value = shift; |
| if (!Texinfo::Common::valid_option($var)) { |
| # carp may be better, but infortunately, it points to the routine that |
| # loads the file, and not to the init file. |
| main::document_warn(sprintf(main::__("%s: unknown variable %s"), |
| 'set_from_init_file', $var)); |
| return 0; |
| } elsif (Texinfo::Common::obsolete_option($var)) { |
| main::document_warn(sprintf(main::__("%s: obsolete variable %s\n"), |
| 'set_from_init_file', $var)); |
| } |
| return 0 if (defined($cmdline_options->{$var})); |
| delete $default_options->{$var}; |
| $options->{$var} = $value; |
| return 1; |
| } |
| |
| sub set_from_cmdline($$) { |
| my $var = shift; |
| my $value = shift; |
| delete $options->{$var}; |
| delete $default_options->{$var}; |
| if (!Texinfo::Common::valid_option($var)) { |
| main::document_warn(sprintf(main::__("%s: unknown variable %s\n"), |
| 'set_from_cmdline', $var)); |
| return 0; |
| } elsif (Texinfo::Common::obsolete_option($var)) { |
| main::document_warn(sprintf(main::__("obsolete variable %s\n"), |
| 'set_from_cmdline', $var)); |
| } |
| $cmdline_options->{$var} = $value; |
| return 1; |
| } |
| |
| # This also could get and set some @-command results. |
| # FIXME But it does not take into account what happens during conversion, |
| # for that something like $converter->get_conf(...) has to be used. |
| sub get_conf($) { |
| my $var = shift; |
| if (exists($cmdline_options->{$var})) { |
| return $cmdline_options->{$var}; |
| } elsif (exists($options->{$var})) { |
| return $options->{$var}; |
| } elsif (exists($default_options->{$var})) { |
| return $default_options->{$var}; |
| } else { |
| return undef; |
| } |
| } |
| |
| } |
| # back in main program namespace |
| |
| # file: file name to locate. It can be a file path. |
| # directories: a reference on a array containing a list of directories to |
| # search the file in. |
| # all_files: if true collect all the files with that name, otherwise stop |
| # at first match. |
| sub locate_init_file($$$) |
| { |
| my $file = shift; |
| my $directories = shift; |
| my $all_files = shift; |
| |
| if (File::Spec->file_name_is_absolute($file)) { |
| return $file if (-e $file and -r $file); |
| } else { |
| my @files; |
| foreach my $dir (@$directories) { |
| next unless (-d $dir); |
| my $possible_file = File::Spec->catfile($dir, $file); |
| if ($all_files) { |
| push (@files, $possible_file) |
| if (-e $possible_file and -r $possible_file); |
| } else { |
| return $possible_file if (-e $possible_file and -r $possible_file); |
| } |
| } |
| return @files if ($all_files); |
| } |
| return undef; |
| } |
| |
| sub locate_and_load_init_file($$) |
| { |
| my $filename = shift; |
| my $directories = shift; |
| |
| my $file = locate_init_file($filename, $directories, 0); |
| if (defined($file)) { |
| Texinfo::Config::_load_init_file($file); |
| } else { |
| document_warn(sprintf(__("could not read init file %s"), $filename)); |
| } |
| } |
| |
| # read initialization files |
| foreach my $file (locate_init_file($conf_file_name, |
| [ reverse(@program_config_dirs) ], 1)) { |
| Texinfo::Config::_load_init_file($file); |
| } |
| |
| sub set_from_cmdline($$) { |
| return &Texinfo::Config::set_from_cmdline(@_); |
| } |
| |
| sub set_from_init_file($$) { |
| return &Texinfo::Config::set_from_init_file(@_); |
| } |
| |
| sub get_conf($) { |
| return &Texinfo::Config::get_conf(@_); |
| } |
| |
| my @input_file_suffixes = ('.txi','.texinfo','.texi','.txinfo',''); |
| |
| my @texi2dvi_args = (); |
| |
| my $format = 'info'; |
| # this is the format associated with the output format, which is replaced |
| # when the output format changes. It may also be removed if there is the |
| # corresponding --no-ifformat. |
| my $default_expanded_format = [ $format ]; |
| my @conf_dirs = (); |
| my @include_dirs = (); |
| my @prepend_dirs = (); |
| |
| # options for all the files |
| my $parser_default_options = {'expanded_formats' => [], |
| 'values' => {'txicommandconditionals' => 1}, |
| 'gettext' => \&__, |
| 'pgettext' => \&__p,}; |
| |
| Texinfo::Config::_load_config($converter_default_options, $cmdline_options); |
| |
| sub set_expansion($$) { |
| my $region = shift; |
| my $set = shift; |
| $set = 1 if (!defined($set)); |
| if ($set) { |
| push @{$parser_default_options->{'expanded_formats'}}, $region |
| unless (grep {$_ eq $region} @{$parser_default_options->{'expanded_formats'}}); |
| } else { |
| @{$parser_default_options->{'expanded_formats'}} = |
| grep {$_ ne $region} @{$parser_default_options->{'expanded_formats'}}; |
| @{$default_expanded_format} |
| = grep {$_ ne $region} @{$default_expanded_format}; |
| } |
| } |
| |
| my $format_from_command_line = 0; |
| |
| my %format_command_line_names = ( |
| 'xml' => 'texinfoxml', |
| ); |
| |
| my %formats_table = ( |
| 'info' => { |
| 'nodes_tree' => 1, |
| 'floats' => 1, |
| 'module' => 'Texinfo::Convert::Info' |
| }, |
| 'plaintext' => { |
| 'nodes_tree' => 1, |
| 'floats' => 1, |
| 'split' => 1, |
| 'module' => 'Texinfo::Convert::Plaintext' |
| }, |
| 'html' => { |
| 'nodes_tree' => 1, |
| 'floats' => 1, |
| 'split' => 1, |
| 'internal_links' => 1, |
| 'simple_menu' => 1, |
| 'move_index_entries_after_items' => 1, |
| 'no_warn_non_empty_parts' => 1, |
| 'module' => 'Texinfo::Convert::HTML' |
| }, |
| 'texinfoxml' => { |
| 'nodes_tree' => 1, |
| 'module' => 'Texinfo::Convert::TexinfoXML', |
| 'floats' => 1, |
| }, |
| 'texinfosxml' => { |
| 'nodes_tree' => 1, |
| 'module' => 'Texinfo::Convert::TexinfoSXML', |
| 'floats' => 1, |
| }, |
| 'ixinsxml' => { |
| 'nodes_tree' => 1, |
| 'module' => 'Texinfo::Convert::IXINSXML' |
| }, |
| 'docbook' => { |
| 'move_index_entries_after_items' => 1, |
| 'no_warn_non_empty_parts' => 1, |
| 'module' => 'Texinfo::Convert::DocBook' |
| }, |
| 'pdf' => { |
| 'texi2dvi_format' => 1, |
| }, |
| 'ps' => { |
| 'texi2dvi_format' => 1, |
| }, |
| 'dvi' => { |
| 'texi2dvi_format' => 1, |
| }, |
| 'dvipdf' => { |
| 'texi2dvi_format' => 1, |
| }, |
| 'debugcount' => { |
| 'nodes_tree' => 1, |
| 'floats' => 1, |
| 'module' => 'DebugTexinfo::DebugCount' |
| }, |
| 'debugtree' => { |
| 'split' => 1, |
| 'module' => 'DebugTexinfo::DebugTree' |
| }, |
| 'textcontent' => { |
| 'converter' => sub{Texinfo::Convert::TextContent->converter(@_)}, |
| }, |
| 'rawtext' => { |
| 'converter' => sub{Texinfo::Convert::Text->converter(@_)}, |
| }, |
| 'plaintexinfo' => { |
| 'converter' => sub{Texinfo::Convert::PlainTexinfo->converter(@_)}, |
| }, |
| 'parse' => { |
| }, |
| 'structure' => { |
| 'nodes_tree' => 1, |
| 'floats' => 1, |
| 'split' => 1, |
| }, |
| ); |
| |
| my $call_texi2dvi = 0; |
| |
| # previous_format should be in argument if there is a possibility of error. |
| # as a fallback, the $format global variable is used. |
| sub set_format($;$$) |
| { |
| my $set_format = shift; |
| my $previous_format = shift; |
| $previous_format = $format if (!defined($previous_format)); |
| my $do_not_override_command_line = shift; |
| |
| my $new_format; |
| if ($format_command_line_names{$set_format}) { |
| $new_format = $format_command_line_names{$set_format}; |
| } else { |
| $new_format = $set_format; |
| } |
| my $expanded_format = $set_format; |
| if (!$formats_table{$new_format}) { |
| document_warn(sprintf(__("ignoring unrecognized TEXINFO_OUTPUT_FORMAT value `%s'\n"), |
| $new_format)); |
| $new_format = $previous_format; |
| } else { |
| if ($format_from_command_line and $do_not_override_command_line) { |
| $new_format = $previous_format; |
| } else { |
| if ($formats_table{$new_format}->{'texi2dvi_format'}) { |
| $call_texi2dvi = 1; |
| push @texi2dvi_args, '--'.$new_format; |
| $expanded_format = 'tex'; |
| } |
| if ($Texinfo::Common::texinfo_output_formats{$expanded_format}) { |
| if ($expanded_format eq 'plaintext') { |
| $default_expanded_format = [$expanded_format, 'info'] |
| } else { |
| $default_expanded_format = [$expanded_format] |
| } |
| } |
| $format_from_command_line = 1 |
| unless ($do_not_override_command_line); |
| } |
| } |
| return $new_format; |
| } |
| |
| sub set_global_format($) |
| { |
| my $set_format = shift; |
| $format = set_format($set_format); |
| } |
| |
| sub document_warn($) { |
| return if (get_conf('NO_WARN')); |
| my $text = shift; |
| chomp ($text); |
| warn(sprintf(__p("program name: warning: warning_message", |
| "%s: warning: %s\n"), $real_command_name, $text)); |
| } |
| |
| sub _exit($$) |
| { |
| my $error_count = shift; |
| my $opened_files = shift; |
| |
| if ($error_count and $opened_files and !get_conf('FORCE')) { |
| while (@$opened_files) { |
| my $opened_file = shift (@$opened_files); |
| unlink ($opened_file); |
| } |
| } |
| exit (1) if ($error_count and (!get_conf('FORCE') |
| or $error_count > get_conf('ERROR_LIMIT'))); |
| } |
| |
| sub handle_errors($$$) |
| { |
| my $self = shift; |
| my $error_count = shift; |
| my $opened_files = shift; |
| my ($errors, $new_error_count) = $self->errors(); |
| $error_count += $new_error_count if ($new_error_count); |
| foreach my $error_message (@$errors) { |
| warn $error_message->{'error_line'} if ($error_message->{'type'} eq 'error' |
| or !get_conf('NO_WARN')); |
| } |
| |
| _exit($error_count, $opened_files); |
| return $error_count; |
| } |
| |
| |
| sub _get_converter_default($) |
| { |
| my $option = shift; |
| return $Texinfo::Convert::Converter::all_converters_defaults{$option} |
| if (defined($Texinfo::Convert::Converter::all_converters_defaults{$option})); |
| return undef; |
| } |
| |
| sub makeinfo_help() |
| { |
| my $makeinfo_help = |
| sprintf(__("Usage: %s [OPTION]... TEXINFO-FILE...\n"), |
| $real_command_name . $command_suffix) |
| ."\n". |
| __("Translate Texinfo source documentation to various other formats, by default |
| Info files suitable for reading online with Emacs or standalone GNU Info. |
| |
| This program is commonly installed as both `makeinfo' and `texi2any'; |
| the behavior is identical, and does not depend on the installed name.\n") |
| ."\n"; |
| $makeinfo_help .= sprintf(__("General options: |
| --document-language=STR locale to use in translating Texinfo keywords |
| for the output document (default C). |
| --error-limit=NUM quit after NUM errors (default %d). |
| --force preserve output even if errors. |
| --help display this help and exit. |
| --no-validate suppress node cross-reference validation. |
| --no-warn suppress warnings (but not errors). |
| --conf-dir=DIR search also for initialization files in DIR. |
| --init-file=FILE load FILE to modify the default behavior. |
| -c, --set-customization-variable VAR=VAL set customization variable VAR |
| to value VAL. |
| -v, --verbose explain what is being done. |
| --version display version information and exit.\n"), |
| get_conf('ERROR_LIMIT')) |
| ."\n"; |
| $makeinfo_help .= __("Output format selection (default is to produce Info): |
| --docbook output Docbook XML rather than Info. |
| --html output HTML rather than Info. |
| --plaintext output plain text rather than Info. |
| --xml output Texinfo XML rather than Info. |
| --dvi, --dvipdf, --ps, --pdf call texi2dvi to generate given output, |
| after checking validity of TEXINFO-FILE.\n") |
| ."\n"; |
| $makeinfo_help .= __("General output options: |
| -E, --macro-expand=FILE output macro-expanded source to FILE, |
| ignoring any \@setfilename. |
| --no-headers suppress node separators, Node: lines, and menus |
| from Info output (thus producing plain text) |
| or from HTML (thus producing shorter output). |
| Also, if producing Info, write to |
| standard output by default. |
| --no-split suppress any splitting of the output; |
| generate only one output file. |
| --[no-]number-sections output chapter and sectioning numbers; |
| default is on. |
| -o, --output=DEST output to DEST. |
| With split output, create DEST as a directory |
| and put the output files there. |
| With non-split output, if DEST is already |
| a directory or ends with a /, |
| put the output file there. |
| Otherwise, DEST names the output file.\n") |
| ."\n"; |
| $makeinfo_help .= sprintf(__("Options for Info and plain text: |
| --disable-encoding do not output accented and special characters |
| in Info output based on \@documentencoding. |
| --enable-encoding override --disable-encoding (default). |
| --fill-column=NUM break Info lines at NUM characters (default %d). |
| --footnote-style=STYLE output footnotes in Info according to STYLE: |
| `separate' to put them in their own node; |
| `end' to put them at the end of the node, in |
| which they are defined (this is the default). |
| --paragraph-indent=VAL indent Info paragraphs by VAL spaces (default %d). |
| If VAL is `none', do not indent; if VAL is |
| `asis', preserve existing indentation. |
| --split-size=NUM split Info files at size NUM (default %d).\n"), |
| _get_converter_default('fillcolumn'), |
| _get_converter_default('paragraphindent'), |
| _get_converter_default('SPLIT_SIZE')) |
| ."\n"; |
| $makeinfo_help .= __("Options for HTML: |
| --css-include=FILE include FILE in HTML <style> output; |
| read stdin if FILE is -. |
| --css-ref=URL generate CSS reference to URL. |
| --internal-links=FILE produce list of internal links in FILE. |
| --split=SPLIT split at SPLIT, where SPLIT may be `chapter', |
| `section' or `node'. |
| --transliterate-file-names use file names in ASCII transliteration. |
| --node-files produce redirection files for nodes and |
| anchors; default is set only if split.\n") |
| ."\n"; |
| $makeinfo_help .= __("Options for XML and Docbook: |
| --output-indent=VAL does nothing, retained for compatibility.\n") |
| ."\n"; |
| $makeinfo_help .= __("Options for DVI/PS/PDF: |
| --Xopt=OPT pass OPT to texi2dvi; can be repeated.\n") |
| ."\n"; |
| $makeinfo_help .= __("Input file options: |
| --commands-in-node-names does nothing, retained for compatibility. |
| -D VAR define the variable VAR, as with \@set. |
| -D 'VAR VAL' define VAR to VAL (one shell argument). |
| -I DIR append DIR to the \@include search path. |
| -P DIR prepend DIR to the \@include search path. |
| -U VAR undefine the variable VAR, as with \@clear.\n") |
| ."\n"; |
| $makeinfo_help .= __("Conditional processing in input: |
| --ifdocbook process \@ifdocbook and \@docbook even if |
| not generating Docbook. |
| --ifhtml process \@ifhtml and \@html even if not generating HTML. |
| --ifinfo process \@ifinfo even if not generating Info. |
| --ifplaintext process \@ifplaintext even if not generating plain text. |
| --iftex process \@iftex and \@tex. |
| --ifxml process \@ifxml and \@xml. |
| --no-ifdocbook do not process \@ifdocbook and \@docbook text. |
| --no-ifhtml do not process \@ifhtml and \@html text. |
| --no-ifinfo do not process \@ifinfo text. |
| --no-ifplaintext do not process \@ifplaintext text. |
| --no-iftex do not process \@iftex and \@tex text. |
| --no-ifxml do not process \@ifxml and \@xml text. |
| |
| Also, for the --no-ifFORMAT options, do process \@ifnotFORMAT text.\n") |
| ."\n"; |
| $makeinfo_help .= __(" The defaults for the \@if... conditionals depend on the output format: |
| if generating Docbook, --ifdocbook is on and the others are off; |
| if generating HTML, --ifhtml is on and the others are off; |
| if generating Info, --ifinfo is on and the others are off; |
| if generating plain text, --ifplaintext is on and the others are off; |
| if generating XML, --ifxml is on and the others are off.\n") |
| ."\n"; |
| $makeinfo_help .= __("Examples: |
| makeinfo foo.texi write Info to foo's \@setfilename |
| makeinfo --html foo.texi write HTML to \@setfilename |
| makeinfo --xml foo.texi write Texinfo XML to \@setfilename |
| makeinfo --docbook foo.texi write Docbook XML to \@setfilename |
| makeinfo --plaintext foo.texi write plain text to standard output |
| makeinfo --pdf foo.texi write PDF using texi2dvi |
| |
| makeinfo --html --no-headers foo.texi write html without node lines, menus |
| makeinfo --number-sections foo.texi write Info with numbered sections |
| makeinfo --no-split foo.texi write one Info file however big\n") |
| ."\n"; |
| $makeinfo_help .= __("Email bug reports to bug-texinfo\@gnu.org, |
| general questions and discussion to help-texinfo\@gnu.org. |
| Texinfo home page: http://www.gnu.org/software/texinfo/") ."\n"; |
| return $makeinfo_help; |
| } |
| |
| my $Xopt_arg_nr = 0; |
| my $latex2html_file = 'latex2html.pm'; |
| |
| my $result_options = Getopt::Long::GetOptions ( |
| 'help|h' => sub { print makeinfo_help(); exit 0; }, |
| 'version|V' => sub {print "$program_name (GNU texinfo) $configured_version\n\n"; |
| printf __("Copyright (C) %s Free Software Foundation, Inc. |
| License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> |
| This is free software: you are free to change and redistribute it. |
| There is NO WARRANTY, to the extent permitted by law.\n"), "2016"; |
| exit 0;}, |
| 'macro-expand|E=s' => sub { set_from_cmdline('MACRO_EXPAND', $_[1]); }, |
| 'ifhtml!' => sub { set_expansion('html', $_[1]); }, |
| 'ifinfo!' => sub { set_expansion('info', $_[1]); }, |
| 'ifxml!' => sub { set_expansion('xml', $_[1]); }, |
| 'ifdocbook!' => sub { set_expansion('docbook', $_[1]); }, |
| 'iftex!' => sub { set_expansion('tex', $_[1]); }, |
| 'ifplaintext!' => sub { set_expansion('plaintext', $_[1]); }, |
| 'I=s' => sub { push @texi2dvi_args, ('-'.$_[0], $_[1]); |
| push @include_dirs, split(/$quoted_path_separator/, $_[1]); }, |
| 'conf-dir=s' => sub { push @conf_dirs, split(/$quoted_path_separator/, $_[1]); }, |
| 'P=s' => sub { unshift @prepend_dirs, split(/$quoted_path_separator/, $_[1]); }, |
| 'number-sections!' => sub { set_from_cmdline('NUMBER_SECTIONS', $_[1]); }, |
| 'number-footnotes!' => sub { set_from_cmdline('NUMBER_FOOTNOTES', $_[1]); }, |
| 'node-files!' => sub { set_from_cmdline('NODE_FILES', $_[1]); }, |
| 'footnote-style=s' => sub { |
| if ($_[1] eq 'end' or $_[1] eq 'separate') { |
| set_from_cmdline('footnotestyle', $_[1]); |
| } else { |
| die sprintf(__("%s: --footnote-style arg must be `separate' or `end', not `%s'.\n"), $real_command_name, $_[1]); |
| } |
| }, |
| 'split=s' => sub { my $split = $_[1]; |
| my @messages |
| = Texinfo::Common::warn_unknown_split($_[1], \&__); |
| if (@messages) { |
| foreach my $message (@messages) { |
| document_warn($message); |
| } |
| $split = 'node'; |
| } |
| set_from_cmdline('SPLIT', $split); }, |
| 'no-split' => sub { set_from_cmdline('SPLIT', ''); |
| set_from_cmdline('SPLIT_SIZE', undef);}, |
| 'headers!' => sub { set_from_cmdline('HEADERS', $_[1]); |
| set_from_cmdline('SHOW_MENU', $_[1]); |
| $format = 'plaintext' if (!$_[1] and $format eq 'info'); }, |
| 'output|out|o=s' => sub { |
| my $var = 'OUTFILE'; |
| if ($_[1] =~ m:/$: or -d $_[1]) { |
| set_from_cmdline($var, undef); |
| $var = 'SUBDIR'; |
| } |
| set_from_cmdline($var, $_[1]); |
| set_from_cmdline('OUT', $_[1]); |
| push @texi2dvi_args, '-o', $_[1]; |
| }, |
| 'no-validate|no-pointer-validate' => sub { |
| set_from_cmdline('novalidate',$_[1]); |
| $parser_default_options->{'novalidate'} = $_[1]; |
| }, |
| 'no-warn' => sub { set_from_cmdline('NO_WARN', $_[1]); }, |
| 'verbose|v!' => sub {set_from_cmdline('VERBOSE', $_[1]); |
| push @texi2dvi_args, '--verbose'; }, |
| 'document-language=s' => sub { |
| set_from_cmdline('documentlanguage', $_[1]); |
| $parser_default_options->{'documentlanguage'} = $_[1]; |
| my @messages |
| = Texinfo::Common::warn_unknown_language($_[1], \&__); |
| foreach my $message (@messages) { |
| document_warn($message); |
| } |
| }, |
| 'D=s' => sub { |
| my $var = $_[1]; |
| my @field = split (/\s+/, $var, 2); |
| if (@field == 1) { |
| $parser_default_options->{'values'}->{$var} = 1; |
| } else { |
| $parser_default_options->{'values'}->{$field[0]} = $field[1]; |
| } |
| }, |
| 'U=s' => sub {delete $parser_default_options->{'values'}->{$_[1]};}, |
| 'init-file=s' => sub { |
| locate_and_load_init_file($_[1], [ @conf_dirs, @program_init_dirs ]); |
| }, |
| 'set-customization-variable|c=s' => sub { |
| my $var_val = $_[1]; |
| if ($var_val =~ s/^(\w+)\s*=?\s*//) { |
| my $var = $1; |
| my $value = $var_val; |
| if ($value =~ /^undef$/i) { |
| $value = undef; |
| } |
| # special format |
| if ($var eq 'TEXINFO_OUTPUT_FORMAT') { |
| $format = set_format($value, $format, 1); |
| } elsif ($var eq 'TEXI2HTML') { |
| $format = set_format('html'); |
| $parser_default_options->{'values'}->{'texi2html'} = 1; |
| } |
| set_from_cmdline($var, $value); |
| # FIXME do that here or when all command line options are processed? |
| if ($var eq 'L2H' and get_conf('L2H')) { |
| locate_and_load_init_file($latex2html_file, |
| [ @conf_dirs, @program_init_dirs ]); |
| } |
| } |
| }, |
| 'css-include=s' => \@css_files, |
| 'css-ref=s' => \@css_refs, |
| 'transliterate-file-names!' => |
| sub {set_from_cmdline('TRANSLITERATE_FILE_NAMES', $_[1]);}, |
| 'error-limit|e=i' => sub { set_from_cmdline('ERROR_LIMIT', $_[1]); }, |
| 'split-size=s' => sub {set_from_cmdline('SPLIT_SIZE', $_[1])}, |
| 'paragraph-indent|p=s' => sub { |
| my $value = $_[1]; |
| if ($value =~ /^([0-9]+)$/ or $value eq 'none' or $value eq 'asis') { |
| set_from_cmdline('paragraphindent', $_[1]); |
| } else { |
| die sprintf(__("%s: --paragraph-indent arg must be numeric/`none'/`asis', not `%s'.\n"), |
| $real_command_name, $value); |
| } |
| }, |
| 'fill-column|f=i' => sub {set_from_cmdline('FILLCOLUMN',$_[1]);}, |
| 'enable-encoding' => sub {set_from_cmdline('ENABLE_ENCODING',$_[1]); |
| $parser_default_options->{'ENABLE_ENCODING'} = $_[1];}, |
| 'disable-encoding' => sub {set_from_cmdline('ENABLE_ENCODING', 0); |
| $parser_default_options->{'ENABLE_ENCODING'} = 0;}, |
| 'internal-links=s' => sub {set_from_cmdline('INTERNAL_LINKS', $_[1]);}, |
| 'force|F' => sub {set_from_cmdline('FORCE', $_[1]);}, |
| 'commands-in-node-names' => sub { ;}, |
| 'output-indent=i' => sub { ;}, |
| 'reference-limit=i' => sub { ;}, |
| 'Xopt=s' => sub {push @texi2dvi_args, $_[1]; $Xopt_arg_nr++}, |
| 'silent|quiet' => sub {set_from_cmdline('SILENT', $_[1]); |
| push @texi2dvi_args, '--'.$_[0];}, |
| |
| 'plaintext' => sub {$format = set_format($_[0].'');}, |
| 'html' => sub {$format = set_format($_[0].'');}, |
| 'info' => sub {$format = set_format($_[0].'');}, |
| 'docbook' => sub {$format = set_format($_[0].'');}, |
| 'xml' => sub {$format = set_format($_[0].'');}, |
| 'dvi' => sub {$format = set_format($_[0].'');}, |
| 'dvipdf' => sub {$format = set_format($_[0].'');}, |
| 'ps' => sub {$format = set_format($_[0].'');}, |
| 'pdf' => sub {$format = set_format($_[0].'');}, |
| 'debug=i' => sub {set_from_cmdline('DEBUG', $_[1]); |
| $parser_default_options->{'DEBUG'} = $_[1]; |
| push @texi2dvi_args, '--'.$_[0]; }, |
| ); |
| |
| exit 1 if (!$result_options); |
| |
| # For tests, set some strings to values not changing with releases |
| my %test_conf = ( |
| 'PACKAGE_VERSION' => '', |
| 'PACKAGE' => 'texinfo', |
| 'PACKAGE_NAME' => 'texinfo', |
| 'PACKAGE_AND_VERSION' => 'texinfo', |
| 'PACKAGE_URL' => 'http://www.gnu.org/software/texinfo/', |
| # maybe don't set this? |
| 'PROGRAM' => 'texi2any', |
| ); |
| if (get_conf('TEST')) { |
| foreach my $conf (keys (%test_conf)) { |
| $converter_default_options->{$conf} = $test_conf{$conf}; |
| } |
| } |
| |
| |
| my %format_names = ( |
| 'info' => 'Info', |
| 'html' => 'HTML', |
| 'docbook' => 'DocBook', |
| 'texinfoxml' => 'Texinfo XML', |
| 'plaintext' => 'Plain Text', |
| ); |
| |
| sub format_name($) |
| { |
| my $format = shift; |
| if ($format_names{$format}) { |
| return $format_names{$format}; |
| } else { |
| return $format; |
| } |
| } |
| |
| |
| if (defined($ENV{'TEXINFO_OUTPUT_FORMAT'}) |
| and $ENV{'TEXINFO_OUTPUT_FORMAT'} ne '') { |
| $format = set_format($ENV{'TEXINFO_OUTPUT_FORMAT'}, $format, 1); |
| } |
| |
| if ($call_texi2dvi) { |
| if (defined(get_conf('OUT')) and @ARGV > 1) { |
| die sprintf(__('%s: when generating %s, only one input FILE may be specified with -o'."\n"), |
| $real_command_name, format_name($format)); |
| } |
| } elsif($Xopt_arg_nr) { |
| document_warn(__('--Xopt option without printed output')); |
| } |
| |
| require Texinfo::Parser; |
| require Texinfo::Structuring; |
| # Avoid loading these modules until down here to speed up the case |
| # when they are not needed. |
| |
| my %tree_transformations; |
| if (get_conf('TREE_TRANSFORMATIONS')) { |
| my @transformations = split /,/, get_conf('TREE_TRANSFORMATIONS'); |
| foreach my $transformation (@transformations) { |
| if (Texinfo::Common::valid_tree_transformation($transformation)) { |
| $tree_transformations{$transformation} = 1; |
| } else { |
| document_warn(sprintf(__('unknown tree transformation %s'), |
| $transformation)); |
| } |
| } |
| } |
| |
| if (get_conf('SPLIT') and !$formats_table{$format}->{'split'}) { |
| document_warn(sprintf(__('ignoring splitting for format %s'), |
| format_name($format))); |
| set_from_cmdline('SPLIT', ''); |
| } |
| |
| foreach my $expanded_format (@{$default_expanded_format}) { |
| push @{$parser_default_options->{'expanded_formats'}}, $expanded_format |
| unless (grep {$_ eq $expanded_format} @{$parser_default_options->{'expanded_formats'}}); |
| } |
| |
| my $converter_class; |
| my %converter_defaults; |
| |
| if (defined($formats_table{$format}->{'module'})) { |
| # Speed up initialization by only loading the module we need. |
| eval "require $formats_table{$format}->{'module'};" |
| or die "$@"; |
| eval '$formats_table{$format}->{\'converter\'} = sub{'. |
| $formats_table{$format}->{'module'} |
| .'->converter(@_)};'; |
| } |
| |
| # This gets the class right, even though there is a sub... |
| if (defined($formats_table{$format}->{'converter'})) { |
| $converter_class = ref(&{$formats_table{$format}->{'converter'}}); |
| %converter_defaults = $converter_class->converter_defaults(); |
| } |
| |
| # FIXME should this be set when the --set is set too? The corresponding |
| # code is ready above, but commented out. |
| # using no warnings is wrong, but a way to avoid a spurious warning. |
| no warnings 'once'; |
| foreach my $parser_settable_option ( |
| keys(%Texinfo::Parser::default_customization_values)) { |
| if (defined(get_conf($parser_settable_option))) { |
| $parser_default_options->{$parser_settable_option} |
| = get_conf($parser_settable_option); |
| } elsif (defined($converter_class) |
| and defined($converter_defaults{$parser_settable_option})) { |
| $parser_default_options->{$parser_settable_option} |
| = $converter_defaults{$parser_settable_option}; |
| } |
| } |
| |
| ## using no warnings is wrong, but a way to avoid a spurious warning. |
| #no warnings 'once'; |
| # The configuration options are upper-cased when considered as |
| # customization variables, and lower-cased when passed to the Parser |
| foreach my $parser_option (map {uc($_)} |
| (keys (%Texinfo::Common::default_parser_state_configuration))) { |
| $parser_default_options->{lc($parser_option)} = get_conf($parser_option) |
| if (defined(get_conf($parser_option))); |
| } |
| |
| |
| # Main processing, process all the files given on the command line |
| |
| my @input_files = @ARGV; |
| # use STDIN if not a tty, like makeinfo does |
| @input_files = ('-') if (!scalar(@input_files) and !-t STDIN); |
| die sprintf(__("%s: missing file argument.\n"), $real_command_name) |
| .sprintf(__("Try `%s --help' for more information.\n"), $real_command_name) |
| unless (scalar(@input_files) >= 1); |
| |
| my $file_number = -1; |
| my @opened_files = (); |
| my %unclosed_files; |
| my $error_count = 0; |
| # main processing |
| while(@input_files) { |
| $file_number++; |
| my $input_file_arg = shift(@input_files); |
| my $input_file_name; |
| # try to concatenate with different suffixes. The last suffix is '' |
| # such that the plain file name is checked. |
| foreach my $suffix (@input_file_suffixes) { |
| if (-e $input_file_arg.$suffix) { |
| $input_file_name = $input_file_arg.$suffix; |
| last; |
| } |
| } |
| # in case no file was found, still set the file name |
| $input_file_name = $input_file_arg if (!defined($input_file_name)); |
| |
| my ($input_filename, $input_directory, $suffix) = fileparse($input_file_name); |
| if (!defined($input_directory) or $input_directory eq '') { |
| $input_directory = $curdir; |
| } |
| |
| my $input_file_base = $input_file_name; |
| $input_file_base =~ s/\.te?x(i|info)?$//; |
| |
| my @htmlxref_dirs; |
| if (get_conf('TEST')) { |
| # to have reproducible tests, do not use system or user |
| # directories if TEST is set. |
| @htmlxref_dirs = File::Spec->catdir($curdir, '.texinfo'); |
| } else { |
| @htmlxref_dirs = @language_config_dirs; |
| } |
| if ($input_directory ne '.' and $input_directory ne '') { |
| unshift @htmlxref_dirs, $input_directory; |
| } |
| unshift @htmlxref_dirs, '.'; |
| my @texinfo_htmlxref_files |
| = locate_init_file ($texinfo_htmlxref, \@htmlxref_dirs, 1); |
| |
| my $parser_options = { %$parser_default_options }; |
| |
| $parser_options->{'include_directories'} = [@include_dirs]; |
| my @prependended_include_directories = ('.'); |
| push @prependended_include_directories, $input_directory |
| if ($input_directory ne '.'); |
| unshift @{$parser_options->{'include_directories'}}, |
| @prependended_include_directories; |
| unshift @{$parser_options->{'include_directories'}}, @prepend_dirs; |
| |
| my $parser = Texinfo::Parser::parser($parser_options); |
| my $tree = $parser->parse_texi_file($input_file_name); |
| |
| #my $global_commands = $parser->global_commands_information(); |
| #print STDERR join('|', keys(%$global_commands))."\n"; |
| |
| if (!defined($tree) or $format eq 'parse') { |
| handle_errors($parser, $error_count, \@opened_files); |
| next; |
| } |
| |
| if (defined(get_conf('DUMP_TREE')) |
| or (get_conf('DEBUG') and get_conf('DEBUG') >= 10)) { |
| # this is very wrong, but a way to avoid a spurious warning. |
| no warnings 'once'; |
| local $Data::Dumper::Purity = 1; |
| no warnings 'once'; |
| local $Data::Dumper::Indent = 1; |
| print STDERR Data::Dumper->Dump([$tree]); |
| } |
| |
| if ($tree_transformations{'fill_gaps_in_sectioning'}) { |
| my ($filled_contents, $added_sections) |
| = Texinfo::Structuring::fill_gaps_in_sectioning($tree); |
| if (!defined($filled_contents)) { |
| document_warn(__("fill_gaps_in_sectioning transformation return no result. No section?")); |
| } else { |
| $tree->{'contents'} = $filled_contents; |
| } |
| } |
| if ((get_conf('SIMPLE_MENU') |
| and $formats_table{$format}->{'simple_menu'}) |
| or $tree_transformations{'simple_menus'}) { |
| $parser->Texinfo::Structuring::set_menus_to_simple_menu(); |
| } |
| |
| if (defined(get_conf('MACRO_EXPAND')) and $file_number == 0) { |
| require Texinfo::Convert::Texinfo; |
| my $texinfo_text = Texinfo::Convert::Texinfo::convert($tree, 1); |
| #print STDERR "$texinfo_text\n"; |
| my $macro_expand_file = get_conf('MACRO_EXPAND'); |
| my $macro_expand_fh = Texinfo::Common::open_out($parser, |
| $macro_expand_file, $parser->{'INPUT_PERL_ENCODING'}); |
| |
| my $error_macro_expand_file; |
| if (defined($macro_expand_fh)) { |
| print $macro_expand_fh $texinfo_text; |
| if (!close($macro_expand_fh)) { |
| document_warn(sprintf(__("error on closing macro expand file %s: %s\n"), |
| $macro_expand_file, $!)); |
| $error_macro_expand_file = 1; |
| } |
| $parser->Texinfo::Convert::Converter::register_close_file($macro_expand_file); |
| } else { |
| document_warn(sprintf(__("could not open %s for writing: %s\n"), |
| $macro_expand_file, $!)); |
| $error_macro_expand_file = 1; |
| } |
| |
| if ($error_macro_expand_file) { |
| $error_count++; |
| _exit($error_count, \@opened_files); |
| } |
| } |
| if (get_conf('DUMP_TEXI') or $formats_table{$format}->{'texi2dvi_format'}) { |
| handle_errors($parser, $error_count, \@opened_files); |
| next; |
| } |
| |
| if ($formats_table{$format}->{'move_index_entries_after_items'} |
| or $tree_transformations{'move_index_entries_after_items'}) { |
| Texinfo::Common::move_index_entries_after_items_in_tree($tree); |
| } |
| |
| if ($tree_transformations{'insert_nodes_for_sectioning_commands'}) { |
| my ($modified_contents, $added_nodes) |
| = Texinfo::Structuring::insert_nodes_for_sectioning_commands($parser, $tree); |
| if (!defined($modified_contents)) { |
| document_warn(__( |
| "insert_nodes_for_sectioning_commands transformation return no result. No section?")); |
| } else { |
| $tree->{'contents'} = $modified_contents; |
| } |
| } |
| |
| Texinfo::Structuring::associate_internal_references($parser); |
| # every format needs the sectioning structure |
| # FIXME this adjusts the level of sectioning commands. Maybe should be |
| # done before dumping the tree? |
| my $structure = Texinfo::Structuring::sectioning_structure($parser, $tree); |
| |
| if ($structure |
| and !$formats_table{$format}->{'no_warn_non_empty_parts'}) { |
| Texinfo::Structuring::warn_non_empty_parts($parser); |
| } |
| |
| if ($tree_transformations{'complete_tree_nodes_menus'}) { |
| Texinfo::Structuring::complete_tree_nodes_menus($parser, $tree); |
| } elsif (!$parser->{'validatemenus'}) { |
| Texinfo::Structuring::add_missing_menus($parser, $tree); |
| } |
| |
| if ($tree_transformations{'indent_menu_descriptions'}) { |
| Texinfo::Convert::Plaintext::indent_menu_descriptions(undef, $parser); |
| } |
| |
| if ($tree_transformations{'regenerate_master_menu'}) { |
| Texinfo::Structuring::regenerate_master_menu($parser); |
| } |
| |
| # this can be done for every format, since information is already gathered |
| my $floats = $parser->floats_information(); |
| |
| my $top_node; |
| if ($formats_table{$format}->{'nodes_tree'}) { |
| $top_node = Texinfo::Structuring::nodes_tree($parser); |
| } |
| if ($formats_table{$format}->{'floats'}) { |
| Texinfo::Structuring::number_floats($floats); |
| } |
| $error_count = handle_errors($parser, $error_count, \@opened_files); |
| |
| if ($format eq 'structure') { |
| next; |
| } |
| |
| if ($file_number != 0) { |
| delete $cmdline_options->{'OUTFILE'} if exists($cmdline_options->{'OUTFILE'}); |
| delete $cmdline_options->{'OUT'} if exists($cmdline_options->{'OUT'}); |
| delete $cmdline_options->{'PREFIX'} if exists($cmdline_options->{'PREFIX'}); |
| delete $cmdline_options->{'SUBDIR'} |
| if (exists($cmdline_options->{'SUBDIR'}) and get_conf('SPLIT')); |
| } |
| my $converter_options = { %$converter_default_options, |
| %$cmdline_options, |
| %$Texinfo::Config::options }; |
| |
| $converter_options->{'parser'} = $parser; |
| $converter_options->{'output_format'} = $format; |
| $converter_options->{'htmlxref_files'} = \@texinfo_htmlxref_files; |
| my $converter = &{$formats_table{$format}->{'converter'}}($converter_options); |
| $converter->output($tree); |
| push @opened_files, $converter->converter_opened_files(); |
| handle_errors($converter, $error_count, \@opened_files); |
| my $converter_unclosed_files = $converter->converter_unclosed_files(); |
| if ($converter_unclosed_files) { |
| foreach my $unclosed_file (keys(%$converter_unclosed_files)) { |
| if ($unclosed_file eq '-') { |
| $unclosed_files{$unclosed_file} |
| = $converter_unclosed_files->{$unclosed_file}; |
| } else { |
| if (!close($converter_unclosed_files->{$unclosed_file})) { |
| warn(sprintf(__("%s: error on closing %s: %s\n"), |
| $real_command_name, $unclosed_file, $!)); |
| $error_count++; |
| _exit($error_count, \@opened_files); |
| } |
| } |
| } |
| } |
| |
| if (defined(get_conf('INTERNAL_LINKS')) and $file_number == 0 |
| and $formats_table{$format}->{'internal_links'}) { |
| my $internal_links_text |
| = $converter->output_internal_links(); |
| # always create a file, even if empty. |
| $internal_links_text = '' if (!defined($internal_links_text)); |
| my $internal_links_file = get_conf('INTERNAL_LINKS'); |
| my $internal_links_fh = Texinfo::Common::open_out($converter, |
| $internal_links_file); |
| my $error_internal_links_file; |
| if (defined ($internal_links_fh)) { |
| print $internal_links_fh $internal_links_text; |
| |
| if (!close ($internal_links_fh)) { |
| warn(sprintf(__("%s: error on closing internal links file %s: %s\n"), |
| $real_command_name, $internal_links_file, $!)); |
| $error_internal_links_file = 1; |
| } |
| $converter->register_close_file($internal_links_file); |
| } else { |
| warn(sprintf(__("%s: could not open %s for writing: %s\n"), |
| $real_command_name, $internal_links_file, $!)); |
| $error_internal_links_file = 1; |
| } |
| if ($error_internal_links_file) { |
| $error_count++; |
| _exit($error_count, \@opened_files); |
| } |
| } |
| if (defined(get_conf('SORT_ELEMENT_COUNT')) and $file_number == 0) { |
| my $converter_element_count_file |
| = Texinfo::Convert::TextContent->converter($converter_options); |
| my $use_sections = (! $formats_table{$format}->{'nodes_tree'} |
| or (defined($converter->get_conf('USE_NODES')) |
| and !$converter->get_conf('USE_NODES'))); |
| my ($sorted_name_counts_array, $sort_element_count_text) |
| = Texinfo::Convert::Converter::sort_element_counts( |
| $converter_element_count_file, $tree, $use_sections, |
| get_conf('SORT_ELEMENT_COUNT_WORDS')); |
| |
| my $sort_element_count_file = get_conf('SORT_ELEMENT_COUNT'); |
| my $sort_element_count_fh = Texinfo::Common::open_out($converter, |
| $sort_element_count_file); |
| my $error_sort_element_count_file; |
| if (defined ($sort_element_count_fh)) { |
| print $sort_element_count_fh $sort_element_count_text; |
| |
| if (!close ($sort_element_count_fh)) { |
| warn(sprintf(__("%s: error on closing internal links file %s: %s\n"), |
| $real_command_name, $sort_element_count_file, $!)); |
| $error_sort_element_count_file = 1; |
| } |
| $converter->register_close_file($sort_element_count_file); |
| } else { |
| warn(sprintf(__("%s: could not open %s for writing: %s\n"), |
| $real_command_name, $sort_element_count_file, $!)); |
| $error_sort_element_count_file = 1; |
| } |
| if ($error_sort_element_count_file) { |
| $error_count++; |
| _exit($error_count, \@opened_files); |
| } |
| } |
| } |
| |
| foreach my $unclosed_file (keys(%unclosed_files)) { |
| if (!close($unclosed_files{$unclosed_file})) { |
| warn(sprintf(__("%s: error on closing %s: %s\n"), |
| $real_command_name, $unclosed_file, $!)); |
| $error_count++; |
| _exit($error_count, \@opened_files); |
| } |
| } |
| |
| if ($call_texi2dvi) { |
| if (get_conf('DEBUG') or get_conf('VERBOSE')) { |
| print STDERR "EXEC ".join('|', (get_conf('TEXI2DVI'), @texi2dvi_args, @ARGV)) |
| ."\n"; |
| } |
| exec { get_conf('TEXI2DVI') } (get_conf('TEXI2DVI'), @texi2dvi_args, @ARGV); |
| } |
| |
| 1; |