# autolatex - Main.pm # Copyright (C) 1998-16 Stephane Galland # # 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 2 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; see the file COPYING. If not, write to # the Free Software Foundation, Inc., 59 Temple Place - Suite 330, # Boston, MA 02111-1307, USA. =pod =head1 NAME Main.pm - Main program =head1 FUNCTIONS The provided functions are: =over 4 =cut package AutoLaTeX::Core::Main; $VERSION = '37.0'; $COPYRIGHT_YEAR = '2016'; @ISA = ('Exporter'); @EXPORT = qw( &analyzeCommandLineOptions &mainProgram &detectMainTeXFile ) ; @EXPORT_OK = qw(); require 5.014; use strict; use utf8; use vars qw(@ISA @EXPORT @EXPORT_OK $VERSION $COPYRIGHT_YEAR); use Getopt::Long; use File::Basename; use AutoLaTeX::Core::Util; use AutoLaTeX::Core::Config; use AutoLaTeX::Core::OS; use AutoLaTeX::Core::IntUtils; use AutoLaTeX::TeX::DocumentDetector; #------------------------------------------------------ # # FUNCTION: analyze the command line options and update the configuration accordingly # #------------------------------------------------------ sub analyzeCommandLineOptions(\%) { printDbg(_T("Reading command line options")); my $realcfg = $_[0]; $_[0]->{'__private__'}{'CLI.warning level'} = 1; $_[0]->{'__private__'}{'config.command line'} = {}; my $cfg = \%{$_[0]->{'__private__'}{'config.command line'}}; my $debugLevel = getDebugLevel(); Getopt::Long::Configure ("bundling"); if (!GetOptions( 'auto!' => sub { $cfg->{'generation.generate images'} = ($_[1] ? 'yes' : 'no'); }, 'asyncview!' => sub { $cfg->{'viewer.asynchronous run'} = ($_[1] ? 'yes' : 'no'); }, 'imgdirectory=s' => sub { $cfg->{'generation.image directory'} = $_[1]; }, 'continuous:i' => sub { my $duration = int($_[1]); $duration = 0 if ($duration<0); $realcfg->{'__private__'}{'action.continuous mode'} = $duration; $cfg->{'viewer.asynchronous run'} = 'true'; }, 'nocontinuous' => sub { delete $realcfg->{'__private__'}{'action.continuous mode'}; }, 'createconfig:s' => \$realcfg->{'__private__'}{'action.create config file'}, 'createist' => \$realcfg->{'__private__'}{'action.create ist file'}, 'debug' => \$realcfg->{'__private__'}{'action.create ist file'}, 'defaultist' => sub { $cfg->{'generation.makeindex style'} = '@system'; }, 'directory=s' => sub { if (!$realcfg->{'__private__'}{'action.input directories'}) { $realcfg->{'__private__'}{'action.input directories'} = []; } push @{$realcfg->{'__private__'}{'action.input directories'}}, $_[1]; }, 'dvi' => sub { $cfg->{'generation.generation type'} = 'dvi'; }, 'biblio!' => sub { $cfg->{'generation.biblio'} = ($_[1] ? 'yes' : 'no'); $realcfg->{'__private__'}{'CLI.biblio'} = ($_[1] ? 'yes' : 'no'); # For makeflat action }, 'exclude=s' => sub { foreach my $module (split /\s*,\s*/,$_[1]) { $module =~ s/[^a-zA-Z0-9_+-]+//g; $cfg->{lc("$module").".include module"} = 'no'; } }, 'f=s' => \$realcfg->{'__private__'}{'input.latex file'}, 'file=s' => \$realcfg->{'__private__'}{'input.latex file'}, 'file-line-warning' => \$realcfg->{'__private__'}{'CLI.is extended tex warnings'}, 'fixconfig:s' => sub { $realcfg->{'__private__'}{'action.fix config file'} = $_[1]; $realcfg->{'__private__'}{'action.fix config file'} = File::Spec->rel2abs($realcfg->{'__private__'}{'action.fix config file'}) if ($realcfg->{'__private__'}{'action.fix config file'}); }, 'gloss!' => sub { $cfg->{'generation.makeglossaries'} = ($_[1] ? 'yes' : 'no'); }, 'help|?' => sub { showManual(getAutoLaTeXDocDir(),"autolatex.pod"); }, 'I=s@' => sub { if (!$cfg->{'generation.translator include path'}) { $cfg->{'generation.translator include path'} = []; } push @{$cfg->{'generation.translator include path'}}, $_[1]; }, 'include=s' => sub { my $sep = getPathListSeparator(); foreach my $module (split /\s*$sep\s*/,$_[1]) { $module =~ s/[^a-zA-Z0-9_+-]+//g; $cfg->{lc("$module").".include module"} = 'yes'; } }, 'index:s' => sub { if ($_[1]) { $cfg->{'generation.makeindex style'} = $_[1]; } else { $cfg->{'generation.makeindex style'} = ['@detect','@none']; } }, 'latex' => sub { $cfg->{'generation.tex compiler'} = 'latex'; }, 'lualatex' => sub { $cfg->{'generation.tex compiler'} = 'lualatex'; }, 'noindex' => sub { delete $cfg->{'generation.makeindex style'}; }, 'noview' => sub { $cfg->{'viewer.view'} = 'no'; }, 'pdf' => sub { $cfg->{'generation.generation type'} = 'pdf'; }, 'pdflatex' => sub { $cfg->{'generation.tex compiler'} = 'pdflatex'; }, 'postcompilationruns=i' => sub { my $number = int($_[1]); $number = 1 if ($number<1); $cfg->{'generation.post compilation runs'} = $number; }, 'progress:s' => sub { if ($_[1] eq 'n') { $realcfg->{'__private__'}{'action.show progress'} = 'n'; } else { $realcfg->{'__private__'}{'action.show progress'} = 'r'; } }, 'ps' => sub { $cfg->{'generation.generation type'} = 'ps'; }, 'quiet' => sub { $debugLevel = 0; }, 'search-project-from=s' => sub { $realcfg->{'__private__'}{'action.search project from'} = $_[1]; }, 'set=s%' => sub { $cfg->{'generation.set'}{$_[1]} = $_[2]; }, 'stdout' => sub { redirectToSTDOUT(); }, 'stderr' => sub { redirectToSTDERR(); }, 'synctex!' => sub { $cfg->{'generation.synctex'} = ($_[1] ? 'yes' : 'no'); }, 'xelatex' => sub { $cfg->{'generation.tex compiler'} = 'xelatex'; }, 'v+' => \$debugLevel, 'version' => sub { if (getAutoLaTeXLaunchingName() ne getAutoLaTeXName()) { print formatText(_T("{} {} ({}) - {} platform\n(c) 1998-{} Stephane GALLAND (under GPL)\n"), getAutoLaTeXLaunchingName(), getAutoLaTeXVersion(), getAutoLaTeXName(), getOperatingSystem(), $COPYRIGHT_YEAR); } else { print formatText(_T("{} {} - {} platform\n(c) 1998-{} Stephane GALLAND (under GPL)\n"), getAutoLaTeXLaunchingName(), getAutoLaTeXVersion(), getOperatingSystem(), $COPYRIGHT_YEAR); } exit(0); }, 'view:s' => sub { $cfg->{'viewer.view'} = 'yes'; if ($_[1]) { $cfg->{'viewer.viewer'} = $_[1]; } }, 'W' => sub { $realcfg->{'__private__'}{'CLI.warning level'}++; }, 'Wall' => sub { $realcfg->{'__private__'}{'CLI.warning level'} = 2; }, 'Wnone' => sub { $realcfg->{'__private__'}{'CLI.warning level'} = 0; }, )) { exit(255); } setDebugLevel($debugLevel); } #------------------------------------------------------ # # FUNCTION: Seach for a TeX main file in the current directory # # Requires $_[0]->{__private__}{output.directory} # Set $_[0]->{__private__}{input.latex file} # #------------------------------------------------------ sub detectMainTeXFile(\%) { my $configuration = shift; local *DIR; opendir(*DIR,$configuration->{'__private__'}{'output.directory'}) or printErr($configuration->{'__private__'}{'output.directory'}.":","$!"); my @texfiles = (); while (my $subfile = readdir(*DIR)) { if ((!isIgnorableDirectory($subfile)) && $subfile =~ /\.tex$/i && $subfile ne 'autolatex_autogenerated.tex') { push @texfiles, "$subfile"; } } closedir(*DIR); if (@texfiles==1) { my $basename = pop @texfiles; $configuration->{'__private__'}{'input.latex file'} = File::Spec->catfile( $configuration->{'__private__'}{'output.directory'}, $basename); printDbg(formatText(_T("Selecting TeX file '{}'"), $basename)); } else { printDbg(formatText(_T("Detecting several TeX files: {}"),join(' ',@texfiles))); # Issue #9: try to detect the file with the \documentclass my @documents = (); foreach my $file (@texfiles) { if (isLaTeXDocument($file)) { push @documents, $file; } } if (@documents==1) { my $basename = pop @documents; $configuration->{'__private__'}{'input.latex file'} = File::Spec->catfile( $configuration->{'__private__'}{'output.directory'}, $basename); printDbg(formatText(_T("Selecting TeX file '{}'"), $basename)); } } } #------------------------------------------------------ # # FUNCTION: Main program # #------------------------------------------------------ sub mainProgram(;$) { my $exitOnError = shift; $exitOnError = 1 if (!defined($exitOnError)); # Get system and user configurations my %configuration = readConfiguration(); # Put the internationalization values in the configuration $configuration{'__private__'}{'internationalization'}{'locale'} = getCurrentLocale(); $configuration{'__private__'}{'internationalization'}{'language'} = getCurrentLanguage(); $configuration{'__private__'}{'internationalization'}{'codeset'} = getCurrentCodeset(); $configuration{'__private__'}{'internationalization'}{'domains'} = getActiveTextDomains(); # Analyze and apply the command line analyzeCommandLineOptions(%configuration); # -- Bug fix: avoid the "No TeX file found" error message to be # displayed when a non-generation action was requested # on the command line if (($exitOnError)&& (($configuration{'__private__'}{'action.fix config file'})|| ($configuration{'__private__'}{'action.create config file'})|| ($configuration{'__private__'}{'action.create ist file'}))) { $exitOnError = 0; } # Search for the root directory if ($configuration{'__private__'}{'action.search project from'}) { my $file = $configuration{'__private__'}{'action.search project from'}; if (-e "$file" && ! -d "$file") { $file = dirname($file); } $file = File::Spec->rel2abs($file); my $autolatex_dir = undef; my $parent = dirname($file); while (!$autolatex_dir && $parent && $file && $parent ne $file) { my $cfgFile = getProjectConfigFilename($file); if (-e "$cfgFile") { $autolatex_dir = $file; } $file = $parent; $parent = dirname($file); } if ($autolatex_dir && -d "$autolatex_dir") { chdir($autolatex_dir) or printErr("$autolatex_dir: $!"); } } # detect main TeX file $configuration{'__private__'}{'output.directory'} = File::Spec->curdir(); $configuration{'__private__'}{'output.latex basename'} = undef; if (!$configuration{'__private__'}{'input.latex file'}) { detectMainTeXFile(%configuration); } # read project's configuration { my $projectConfigFilename = getProjectConfigFilename($configuration{'__private__'}{'output.directory'}); if ( -f "$projectConfigFilename") { readConfigFile("$projectConfigFilename",%configuration); # Remove the main intput filename if (exists $configuration{'generation.main file'}) { if (!$configuration{'__private__'}{'input.latex file'}) { $configuration{'__private__'}{'input.latex file'} = basename($configuration{'generation.main file'}); printDbg(formatText(_T("Detecting TeX file from project's configuration: '{}'"),$configuration{'__private__'}{'input.latex file'})); } delete $configuration{'generation.main file'}; } $configuration{'__private__'}{'input.project directory'} = dirname("$projectConfigFilename"); } } if (!$configuration{'__private__'}{'input.latex file'}) { $configuration{'__private__'}{'input.latex file'} = 'Main.tex'; } # final project main file management if ($configuration{'__private__'}{'input.latex file'}) { # check its value if (-f $configuration{'__private__'}{'input.latex file'}) { $configuration{'__private__'}{'output.directory'} = dirname($configuration{'__private__'}{'input.latex file'}); $configuration{'__private__'}{'output.latex basename'} = basename($configuration{'__private__'}{'input.latex file'}); $configuration{'__private__'}{'output.latex basename'} =~ s/\.tex$//i; } elsif (-f $configuration{'__private__'}{'input.latex file'}.".tex") { $configuration{'__private__'}{'input.latex file'} .= ".tex"; $configuration{'__private__'}{'output.directory'} = dirname($configuration{'__private__'}{'input.latex file'}); $configuration{'__private__'}{'output.latex basename'} = basename($configuration{'__private__'}{'input.latex file'}); } } if ($configuration{'__private__'}{'input.latex file'}) { printDbg(formatText(_T("Using TeX file '{}'"),$configuration{'__private__'}{'input.latex file'})); } elsif ($exitOnError) { printErr(formatText(_T("No LaTeX file found nor specified for the directory '{}'.\n You must specify one on the command line option -f, or set the the variable 'generation.main file' in your configuration file, rename one of your files 'Main.tex'."), $configuration{'__private__'}{'output.directory'})); } # now apply the command line options into the configuration { printDbg(_T("Applying command line options")); if ($configuration{'__private__'}{'config.command line'}) { while (my ($k,$v) = each(%{$configuration{'__private__'}{'config.command line'}})) { if (isArray($v)) { if (!$configuration{"$k"}) { $configuration{"$k"} = $v; } elsif (isHash($configuration{"$k"})) { for(my $i=0; $i<$#{$v}; $i=$i+2) { $configuration{"$k"}{$v->[$i]} = $v->[$i+1]; } } elsif (isArray($configuration{"$k"})) { push @{$configuration{"$k"}}, @{$v}; } else { unshift @{$v}, $configuration{"$k"}; $configuration{"$k"} = $v; } } elsif (isHash($v)) { if (!$configuration{"$k"}) { $configuration{"$k"} = $v; } elsif (isArray($configuration{"$k"})) { push @{$configuration{"$k"}}, @{$v}; } elsif (isHash($configuration{"$k"})) { while (my ($key,$val) = each(%{$v})) { $configuration{"$k"}{$key} = $val; } } else { $v->{$configuration{"$k"}} = undef; $configuration{"$k"} = $v; } } else { $configuration{"$k"} = $v; } } if ($configuration{'generation.set'}) { while (my ($k,$v) = each(%{$configuration{'generation.set'}})) { $configuration{$k} = $v; } delete $configuration{'generation.set'} } delete $configuration{'__private__'}{'config.command line'}; } } # check MakeIndex parameters if ($configuration{'generation.makeindex style'}) { if (!isArray($configuration{'generation.makeindex style'})) { $configuration{'generation.makeindex style'} = [$configuration{'generation.makeindex style'}]; } foreach my $isttype (@{$configuration{'generation.makeindex style'}}) { if ($isttype) { if ($isttype eq '@detect') { # Seach for a MakeIndex style file in the current directory local *DIR; opendir(*DIR,$configuration{'__private__'}{'output.directory'}) or printErr($configuration{'__private__'}{'output.directory'}.":","$!"); my @istfiles = (); while (my $subfile = readdir(*DIR)) { if (!isIgnorableDirectory($subfile) && $subfile =~ /\.ist$/i) { push @istfiles, File::Spec->catfile( $configuration{'__private__'}{'output.directory'}, "$subfile"); } } closedir(*DIR); if (@istfiles==1) { $configuration{'__private__'}{'output.ist file'} = File::Spec->rel2abs(pop @istfiles); printDbg(formatText(_T("Selecting project's style for MakeIndex: {}"), $configuration{'__private__'}{'output.ist file'})); } else { delete $configuration{'__private__'}{'output.ist file'}; printDbg(formatText(_T("Unable to selected a project's style for MakeIndex: no file or too many .ist files in directory {}"), $configuration{'__private__'}{'output.directory'})); } } elsif ($isttype eq '@system') { $configuration{'__private__'}{'output.ist file'} = getSystemISTFilename(); printDbg(formatText(_T("Selecting the system default style for MakeIndex"))); } elsif ($isttype eq '@none') { delete $configuration{'__private__'}{'output.ist file'}; printDbg(formatText(_T("Unselecting any style for MakeIndex"))); } if (($configuration{'__private__'}{'output.ist file'})&& (-r $configuration{'__private__'}{'output.ist file'})) { last; } else { delete $configuration{'__private__'}{'output.ist file'}; } } } } # set the project's directory if never set before if (!$configuration{'__private__'}{'input.project directory'} && $configuration{'__private__'}{'input.latex file'}) { $configuration{'__private__'}{'input.project directory'} = File::Spec->rel2abs(dirname($configuration{'__private__'}{'input.latex file'})); } # Set the directory of the pictures to a default value if not defined in # the configuration nor given on the CLI if (! defined($configuration{'generation.image directory'})) { $configuration{'generation.image directory'} = $configuration{'__private__'}{'input.project directory'}; } return %configuration; } 1; __END__ =back =head1 BUG REPORT AND FEEDBACK To report bugs, provide feedback, suggest new features, etc. visit the AutoLaTeX Project management page at or send email to the author at L. =head1 LICENSE S =head1 COPYRIGHT Sgalland@arakhne.orgE> =head1 SEE ALSO L