texi2any.pl 53 KB

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