line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package TeX::AutoTeX::File; |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
# |
4
|
|
|
|
|
|
|
# $Id: File.pm,v 1.36.2.5 2011/01/22 04:53:23 thorstens Exp $ |
5
|
|
|
|
|
|
|
# $Revision: 1.36.2.5 $ |
6
|
|
|
|
|
|
|
# $Source: /cvsroot/arxivlib/arXivLib/lib/TeX/AutoTeX/File.pm,v $ |
7
|
|
|
|
|
|
|
# |
8
|
|
|
|
|
|
|
# $Date: 2011/01/22 04:53:23 $ |
9
|
|
|
|
|
|
|
# $Author: thorstens $ |
10
|
|
|
|
|
|
|
# |
11
|
|
|
|
|
|
|
|
12
|
2
|
|
|
2
|
|
11
|
use strict; |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
700
|
|
13
|
|
|
|
|
|
|
### use warnings; |
14
|
2
|
|
|
2
|
|
13
|
use Carp; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
203
|
|
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
our ($VERSION) = '$Revision: 1.36.2.5 $' =~ m{ \$Revision: \s+ (\S+) }x; |
17
|
|
|
|
|
|
|
|
18
|
2
|
|
|
2
|
|
12
|
use Scalar::Util qw(weaken); |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
156
|
|
19
|
|
|
|
|
|
|
|
20
|
2
|
|
|
2
|
|
1193
|
use TeX::AutoTeX::Exception; |
|
2
|
|
|
|
|
6
|
|
|
2
|
|
|
|
|
17
|
|
21
|
2
|
|
|
2
|
|
1586
|
use TeX::AutoTeX::HyperTeX; |
|
2
|
|
|
|
|
8
|
|
|
2
|
|
|
|
|
80
|
|
22
|
2
|
|
|
2
|
|
1287
|
use TeX::AutoTeX::PostScript; |
|
2
|
|
|
|
|
5
|
|
|
2
|
|
|
|
|
71
|
|
23
|
2
|
|
|
|
|
355
|
use TeX::AutoTeX::Config qw( |
24
|
|
|
|
|
|
|
$CRYPT |
25
|
|
|
|
|
|
|
$DVIPS |
26
|
|
|
|
|
|
|
$TEXCHR |
27
|
|
|
|
|
|
|
$DIRECTIVE_FILE |
28
|
|
|
|
|
|
|
%TEX_BINARIES |
29
|
|
|
|
|
|
|
$TEX_PATH |
30
|
2
|
|
|
2
|
|
20
|
); |
|
2
|
|
|
|
|
5
|
|
31
|
|
|
|
|
|
|
|
32
|
2
|
|
|
2
|
|
1643
|
use arXiv::FileGuess qw(guess_file_type is_tex_type type_name); |
|
2
|
|
|
|
|
5514
|
|
|
2
|
|
|
|
|
13261
|
|
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
sub new { |
35
|
0
|
|
|
0
|
1
|
|
my ($class, $fileset, $filename) = @_; |
36
|
|
|
|
|
|
|
|
37
|
0
|
|
|
|
|
|
my $self = { |
38
|
|
|
|
|
|
|
flags => {}, |
39
|
|
|
|
|
|
|
dvi_flags => q{}, |
40
|
|
|
|
|
|
|
fileset => $fileset, |
41
|
|
|
|
|
|
|
binaries => {%TEX_BINARIES}, |
42
|
|
|
|
|
|
|
untaint_regexp => qr/[^&\s;]+/, |
43
|
|
|
|
|
|
|
}; |
44
|
0
|
0
|
0
|
|
|
|
if ($filename =~ /^($self->{untaint_regexp})$/ && $filename !~ /^\./) { |
45
|
0
|
|
|
|
|
|
$self->{filename} = $1; # untaint |
46
|
|
|
|
|
|
|
} else { |
47
|
0
|
|
|
|
|
|
throw TeX::AutoTeX::InvNameException("Invalid filename: '$filename'."); |
48
|
|
|
|
|
|
|
} |
49
|
0
|
|
|
|
|
|
weaken $self->{fileset}; |
50
|
0
|
|
|
|
|
|
bless $self, $class; |
51
|
|
|
|
|
|
|
} |
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
sub filename { |
54
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
55
|
0
|
|
|
|
|
|
return $self->{filename}; |
56
|
|
|
|
|
|
|
} |
57
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
sub type { |
59
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
60
|
|
|
|
|
|
|
# we cache the value |
61
|
0
|
0
|
|
|
|
|
$self->{type} = $self->determine_type() if !defined $self->{type}; |
62
|
0
|
|
|
|
|
|
return $self->{type}; |
63
|
|
|
|
|
|
|
} |
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
sub determine_type { |
66
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
67
|
|
|
|
|
|
|
|
68
|
0
|
0
|
|
|
|
|
return 'TYPE_README' if $self->{filename} eq $DIRECTIVE_FILE; |
69
|
0
|
|
|
|
|
|
my $fullname = "$self->{fileset}->{dir}/$self->{filename}"; |
70
|
0
|
0
|
|
|
|
|
return 'TYPE_DIRECTORY' if -d $fullname; |
71
|
0
|
|
|
|
|
|
my ($type, $texformat, $error) = guess_file_type($fullname); |
72
|
0
|
0
|
|
|
|
|
$self->{fileset}->{log}->error($error) if $error; |
73
|
0
|
0
|
|
|
|
|
$self->{tex_format} = lc $texformat if defined $texformat; |
74
|
0
|
|
|
|
|
|
return $type; |
75
|
|
|
|
|
|
|
} |
76
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
sub filetype_name { |
78
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
79
|
0
|
|
|
|
|
|
return arXiv::FileGuess::type_name($self->type()); |
80
|
|
|
|
|
|
|
} |
81
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
sub type_is_tex { |
83
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
84
|
0
|
|
|
|
|
|
return arXiv::FileGuess::is_tex_type($self->type()); |
85
|
|
|
|
|
|
|
} |
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
sub assign_tex_priority { |
88
|
|
|
|
|
|
|
# TS: 12/2010 |
89
|
|
|
|
|
|
|
# trying to solve the dependency tree in general is equivalent to the halting problem |
90
|
|
|
|
|
|
|
# these are heuristics that work in practice on the material arXiv deals with, |
91
|
|
|
|
|
|
|
# but they are also easily fooled |
92
|
|
|
|
|
|
|
|
93
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
94
|
0
|
0
|
|
|
|
|
if ($self->{flags}->{toplevelfile}){ |
95
|
0
|
|
|
|
|
|
return 4; |
96
|
|
|
|
|
|
|
} |
97
|
|
|
|
|
|
|
# FileGuess incorrectly identifies some files (especially style files) |
98
|
|
|
|
|
|
|
# as tex files that aren't. |
99
|
0
|
0
|
0
|
|
|
|
if (!$self->type_is_tex() |
|
|
|
0
|
|
|
|
|
100
|
|
|
|
|
|
|
|| $self->{filename} eq 'auto_gen_ps.log' |
101
|
|
|
|
|
|
|
|| $self->{filename} =~ /\.(?:sty|st|cls)$/i){ |
102
|
0
|
|
|
|
|
|
return 0; |
103
|
|
|
|
|
|
|
} |
104
|
|
|
|
|
|
|
# take advantage of logic in arXiv::FileGuess |
105
|
0
|
0
|
|
|
|
|
if (0 <= index $self->{type}, 'priority2') { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
106
|
0
|
|
|
|
|
|
return 1; |
107
|
|
|
|
|
|
|
} elsif (0 <= index $self->{type}, 'priority') { |
108
|
0
|
|
|
|
|
|
return 2; |
109
|
|
|
|
|
|
|
} elsif ('_MAC' eq substr $self->{type}, -4) { |
110
|
0
|
|
|
|
|
|
return 3; |
111
|
|
|
|
|
|
|
} |
112
|
|
|
|
|
|
|
# rate based on filename and contents |
113
|
0
|
0
|
|
|
|
|
open(my $CURRENTFILE, '<', "$self->{fileset}->{dir}/$self->{filename}") |
114
|
|
|
|
|
|
|
|| $self->{fileset}->{log}->error("Could not open '$self->{filename}': $!"); |
115
|
0
|
|
|
|
|
|
my $docstycls = 0; |
116
|
|
|
|
|
|
|
# grant higher priority to files that end with tex-related extension |
117
|
0
|
0
|
|
|
|
|
$docstycls++ if $self->{filename} =~ /\.(?:la)?tex$/i; |
118
|
0
|
|
|
|
|
|
while (<$CURRENTFILE>) { |
119
|
0
|
0
|
|
|
|
|
if (/^\s*\\document(?:style|class)/){ |
120
|
0
|
|
|
|
|
|
$docstycls++; |
121
|
0
|
|
|
|
|
|
last; |
122
|
|
|
|
|
|
|
} |
123
|
|
|
|
|
|
|
} |
124
|
0
|
|
|
|
|
|
while (<$CURRENTFILE>) { |
125
|
0
|
0
|
|
|
|
|
if (/^\s*\\begin\s*\{\s*document\s*\}/){ |
126
|
0
|
|
|
|
|
|
$docstycls++; |
127
|
0
|
|
|
|
|
|
last; |
128
|
|
|
|
|
|
|
} |
129
|
|
|
|
|
|
|
} |
130
|
0
|
0
|
|
|
|
|
close $CURRENTFILE or $self->{fileset}->{log}->verbose("couldn't close file: $!"); |
131
|
0
|
|
|
|
|
|
return $docstycls; |
132
|
|
|
|
|
|
|
} |
133
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
sub type_override { |
135
|
0
|
|
|
0
|
1
|
|
my ($self, $type) = @_; |
136
|
0
|
0
|
|
|
|
|
if (my $override = $self->{fileset}->override($type)) { |
137
|
0
|
|
|
|
|
|
$self->{type} = $override; |
138
|
0
|
|
|
|
|
|
$self->{fileset}->{log}->verbose(<<"EOM"); |
139
|
|
|
|
|
|
|
Directive file has overriden $self->{filename}'s type to be '$type' ($override). |
140
|
|
|
|
|
|
|
EOM |
141
|
0
|
|
|
|
|
|
return; |
142
|
|
|
|
|
|
|
} |
143
|
0
|
|
|
|
|
|
$self->{fileset}->{log}->verbose(<<"EOW"); |
144
|
|
|
|
|
|
|
Directive file wanted to override $self->{filename}'s type as '$type', |
145
|
|
|
|
|
|
|
but this type has no override. |
146
|
|
|
|
|
|
|
EOW |
147
|
0
|
|
|
|
|
|
return 1; |
148
|
|
|
|
|
|
|
} |
149
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
sub set_flag { |
151
|
0
|
|
|
0
|
1
|
|
my ($self, $flag) = @_; |
152
|
0
|
|
|
|
|
|
return $self->{flags}->{$flag} = 1; |
153
|
|
|
|
|
|
|
} |
154
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
sub check_flag { |
156
|
0
|
|
|
0
|
1
|
|
my ($self, $flag) = @_; |
157
|
0
|
|
|
|
|
|
return exists $self->{flags}->{$flag}; |
158
|
|
|
|
|
|
|
} |
159
|
|
|
|
|
|
|
|
160
|
|
|
|
|
|
|
sub set_dvi_flags { |
161
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
162
|
0
|
|
|
|
|
|
return $self->{dvi_flags} = shift; |
163
|
|
|
|
|
|
|
} |
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
sub get_dvi_flags { |
166
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
167
|
0
|
|
|
|
|
|
return $self->{dvi_flags}; |
168
|
|
|
|
|
|
|
} |
169
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
sub process { |
171
|
0
|
|
|
0
|
1
|
|
my ($self, $process) = @_; |
172
|
|
|
|
|
|
|
|
173
|
0
|
|
|
|
|
|
my $result; |
174
|
0
|
0
|
|
|
|
|
if ($self->type_is_tex()) { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
175
|
0
|
|
|
|
|
|
$result = $self->process_tex($process); |
176
|
|
|
|
|
|
|
} elsif ($self->type() eq 'TYPE_ENCRYPTED') { |
177
|
0
|
|
|
|
|
|
$result = $self->process_encrypted($process); |
178
|
|
|
|
|
|
|
} elsif ($self->type() eq 'TYPE_DVI') { |
179
|
0
|
|
|
|
|
|
$result = $self->process_dvitype($process); |
180
|
|
|
|
|
|
|
} |
181
|
0
|
|
|
|
|
|
return $result; |
182
|
|
|
|
|
|
|
} |
183
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
sub process_tex { |
185
|
0
|
|
|
0
|
1
|
|
my ($self, $process) = @_; |
186
|
|
|
|
|
|
|
|
187
|
0
|
|
|
|
|
|
my $log = $self->{fileset}->{log}; |
188
|
0
|
|
|
|
|
|
my $dir = $self->{fileset}->{dir}; |
189
|
|
|
|
|
|
|
|
190
|
0
|
|
|
|
|
|
my $tex_passes = 4; |
191
|
0
|
|
|
|
|
|
my ($new_type, $dont_hyper, $try_amslplain) = |
192
|
|
|
|
|
|
|
TeX::AutoTeX::HyperTeX::copy_source_from_hyper( |
193
|
|
|
|
|
|
|
$self->type(), |
194
|
|
|
|
|
|
|
$self->{filename}, |
195
|
|
|
|
|
|
|
$dir, |
196
|
|
|
|
|
|
|
$log, |
197
|
|
|
|
|
|
|
$self->{fileset}->{local_hyper_transform} |
198
|
|
|
|
|
|
|
); |
199
|
0
|
0
|
|
|
|
|
if ($self->{type} ne $new_type) { |
200
|
0
|
|
|
|
|
|
$log->verbose(<<"EOM"); |
201
|
|
|
|
|
|
|
Changing type from '$self->{type}' to '$new_type' on recommendation of |
202
|
|
|
|
|
|
|
TeX::AutoTeX::HyperTeX::copy_source_from_hyper. |
203
|
|
|
|
|
|
|
EOM |
204
|
0
|
|
|
|
|
|
$self->{type} = $new_type; |
205
|
|
|
|
|
|
|
} |
206
|
|
|
|
|
|
|
|
207
|
0
|
0
|
|
|
|
|
my $try_hyper = $dont_hyper ? 0 : !$process->{nohypertex}; |
208
|
0
|
0
|
|
|
|
|
$log->verbose('Will not attempt to use hypertex.') unless $try_hyper; |
209
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
# initalize @to_try with the different formats in the order we want to try them |
211
|
0
|
|
|
|
|
|
my @to_try; |
212
|
0
|
0
|
0
|
|
|
|
if ($process->{branch} eq '3' || $process->{branch} =~ m{texlive/}) { |
|
|
0
|
|
|
|
|
|
213
|
0
|
0
|
0
|
|
|
|
if ($self->type() eq 'TYPE_LATEX' || $self->type() eq 'TYPE_LATEX2e') { |
|
|
0
|
|
|
|
|
|
214
|
0
|
0
|
|
|
|
|
@to_try = map {$try_hyper ? ("h$_", $_) : $_ } qw(latex pdflatex tex); |
|
0
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
} elsif ($self->type() eq 'TYPE_PDFLATEX') { |
216
|
0
|
0
|
|
|
|
|
@to_try = map {$try_hyper ? ("h$_", $_) : $_ } qw(pdflatex tex); |
|
0
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
} else { |
218
|
|
|
|
|
|
|
# we always try tex, in case of amslplain or such |
219
|
0
|
0
|
|
|
|
|
@to_try = $try_hyper ? qw(htex tex) : 'tex'; |
220
|
|
|
|
|
|
|
# we always try latex, not just tex, because sometimes latex papers are misidentified as tex |
221
|
0
|
0
|
|
|
|
|
push @to_try, $try_hyper ? qw(hlatex latex) : 'latex'; |
222
|
|
|
|
|
|
|
} |
223
|
|
|
|
|
|
|
} elsif ($process->{branch} eq '2') { |
224
|
|
|
|
|
|
|
# deal with legacy stuff |
225
|
0
|
0
|
|
|
|
|
if (exists $self->{tex_format}) { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
226
|
0
|
0
|
|
|
|
|
if ($self->{tex_format} eq 'bigtex') { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
227
|
0
|
|
|
|
|
|
$log->verbose('Using bigtex'); |
228
|
0
|
|
|
|
|
|
$self->{binaries}->{HTEX} = $self->{binaries}->{TEX} = $self->{binaries}->{BIGTEX}; |
229
|
|
|
|
|
|
|
} elsif ($self->{tex_format} eq 'biglatex') { |
230
|
0
|
|
|
|
|
|
$log->verbose('Using biglatex'); |
231
|
0
|
|
|
|
|
|
$self->{binaries}->{HLATEX2E} = $self->{binaries}->{LATEX2E} = $self->{binaries}->{BIGLATEX}; |
232
|
|
|
|
|
|
|
} elsif ($self->{tex_format} eq 'latex209') { |
233
|
0
|
0
|
|
|
|
|
@to_try = $try_hyper? qw(hlatex209 latex209) : 'latex209'; |
234
|
|
|
|
|
|
|
} elsif ($self->{tex_format} eq 'latex') { |
235
|
0
|
0
|
|
|
|
|
@to_try = $try_hyper ? qw(hlatex2e hlatex209 latex2e latex209) : qw(latex2e latex209); |
236
|
|
|
|
|
|
|
} |
237
|
|
|
|
|
|
|
} elsif ($self->type() eq 'TYPE_LATEX') { |
238
|
0
|
0
|
|
|
|
|
@to_try = $try_hyper ? qw(hlatex2e hlatex209 latex2e latex209) : qw(latex2e latex209); |
239
|
|
|
|
|
|
|
} elsif ($self->type() eq 'TYPE_LATEX2e') { |
240
|
0
|
0
|
|
|
|
|
@to_try = $try_hyper ? qw(hlatex2e latex2e) : 'latex2e'; |
241
|
|
|
|
|
|
|
} |
242
|
|
|
|
|
|
|
# under some circumstances, what looked like latex files are actually |
243
|
|
|
|
|
|
|
# tex files with amsart. |
244
|
0
|
0
|
|
|
|
|
if ($try_amslplain) { |
245
|
0
|
0
|
|
|
|
|
push @to_try, $try_hyper ? qw(hamslplain amslplain) : 'amslplain'; |
246
|
|
|
|
|
|
|
} |
247
|
0
|
0
|
|
|
|
|
if (@to_try == 0) { |
248
|
|
|
|
|
|
|
# we always try latex, not just tex, because sometimes latex papers are misidentified as tex |
249
|
0
|
0
|
|
|
|
|
@to_try = map { $try_hyper ? ("h$_", $_) : $_ } qw(tex latex2e); |
|
0
|
|
|
|
|
|
|
250
|
|
|
|
|
|
|
} else { |
251
|
0
|
0
|
|
|
|
|
push @to_try, $try_hyper ? qw(htex tex) : 'tex'; |
252
|
|
|
|
|
|
|
} |
253
|
|
|
|
|
|
|
} else { |
254
|
0
|
|
|
|
|
|
$log->verbose('unknown TeX branch'); |
255
|
|
|
|
|
|
|
} |
256
|
|
|
|
|
|
|
|
257
|
0
|
|
|
|
|
|
my $failed = 0; |
258
|
0
|
|
|
|
|
|
my %written = (); |
259
|
0
|
|
|
|
|
|
foreach my $tex_type (@to_try) { |
260
|
0
|
0
|
|
|
|
|
if ('h' eq substr $tex_type, 0, 1) { |
261
|
0
|
|
|
|
|
|
$self->swap_source('hyper'); |
262
|
|
|
|
|
|
|
} else { |
263
|
0
|
|
|
|
|
|
$self->swap_source('nohyper'); |
264
|
|
|
|
|
|
|
} |
265
|
|
|
|
|
|
|
|
266
|
0
|
|
|
|
|
|
my ($stime, $program, $old_format); |
267
|
|
|
|
|
|
|
# get the appropriate program name from the variables set in TeX::AutoTeX::Config |
268
|
0
|
0
|
|
|
|
|
if ($tex_type =~ /amslplain/) { |
269
|
0
|
|
|
|
|
|
$old_format = $self->{tex_format}; |
270
|
0
|
|
|
|
|
|
$self->{tex_format} = 'amslplain'; |
271
|
0
|
0
|
|
|
|
|
if ('h' eq substr $tex_type, 0, 1) { |
272
|
0
|
|
|
|
|
|
$program = $self->{binaries}->{HTEX}; |
273
|
|
|
|
|
|
|
} else { |
274
|
0
|
|
|
|
|
|
$program = $self->{binaries}->{TEX}; |
275
|
|
|
|
|
|
|
} |
276
|
|
|
|
|
|
|
} else { |
277
|
0
|
|
|
|
|
|
$program = $self->{binaries}->{uc($tex_type)}; |
278
|
|
|
|
|
|
|
} |
279
|
0
|
0
|
|
|
|
|
if (! $self->{fileset}->{utime}) {# set mtime and atime on all (non-dot-)files in CWD back 10 seconds |
280
|
0
|
|
|
|
|
|
my $setbacktime = time() - 10; |
281
|
|
|
|
|
|
|
### {#TS: extensive logging |
282
|
|
|
|
|
|
|
### my @allfiles = glob("*"); |
283
|
|
|
|
|
|
|
### local $" = "]\n\t["; |
284
|
|
|
|
|
|
|
### $log->verbose("current file contents:\n\t[@allfiles]"); |
285
|
|
|
|
|
|
|
### } |
286
|
0
|
0
|
|
|
|
|
opendir my $CDIR, $dir or $log->verbose("opening directory '$dir' for reading failed: $!"); |
287
|
0
|
|
|
|
|
|
my $numfiles = utime $setbacktime, $setbacktime, |
288
|
0
|
|
|
|
|
|
map { "$dir/$_" } |
289
|
0
|
0
|
|
|
|
|
map { /^($self->{untaint_regexp})$/o } |
290
|
0
|
|
|
|
|
|
grep { !/^\./ && -f "$dir/$_" } |
291
|
|
|
|
|
|
|
readdir $CDIR; |
292
|
0
|
0
|
|
|
|
|
closedir $CDIR or $log->verbose("closing directory $dir failed: $!"); |
293
|
|
|
|
|
|
|
#TS Note: |
294
|
|
|
|
|
|
|
# if we don't reset (a|m)time each time the loop processes a new file |
295
|
|
|
|
|
|
|
# the .with_hyper and .without_hyper files will not have proper stat |
296
|
|
|
|
|
|
|
# values and will be removed. if we globally reset (a|m)time, things go |
297
|
|
|
|
|
|
|
# awry with inclusion checking. Therefore make sure to reset utime in |
298
|
|
|
|
|
|
|
# swap_source for hyper files in HyperTeX.pm. |
299
|
0
|
|
|
|
|
|
$self->{fileset}->{utime}++; |
300
|
|
|
|
|
|
|
} |
301
|
0
|
|
|
|
|
|
$stime = time; |
302
|
0
|
|
|
|
|
|
$failed = $self->run_tex_attempt($program, $tex_passes, $process, $stime, \%written, $tex_type); |
303
|
0
|
0
|
|
|
|
|
if ($tex_type =~ /amslplain/) { |
304
|
0
|
|
|
|
|
|
$self->{tex_format} = $old_format; |
305
|
|
|
|
|
|
|
} |
306
|
0
|
|
|
|
|
|
$self->clean_aux_files($stime); |
307
|
0
|
0
|
|
|
|
|
if (!$failed) { |
308
|
0
|
|
|
|
|
|
my $logfile = $self->basename() . '.log'; |
309
|
0
|
0
|
|
|
|
|
unlink "$dir/$logfile" or |
310
|
|
|
|
|
|
|
$log->error("Could not remove file '$logfile'."); |
311
|
0
|
|
|
|
|
|
last; |
312
|
|
|
|
|
|
|
} |
313
|
|
|
|
|
|
|
} |
314
|
0
|
0
|
|
|
|
|
if ($failed) { |
315
|
0
|
|
|
|
|
|
$log->verbose("We failed utterly to process the TeX file '$self->{filename}'"); |
316
|
|
|
|
|
|
|
} |
317
|
|
|
|
|
|
|
# ensure that no copies of the tex file are left behind |
318
|
0
|
|
|
|
|
|
unlink map {"$dir/$self->{filename}.$_"} qw(with_hyper without_hyper); |
|
0
|
|
|
|
|
|
|
319
|
0
|
|
|
|
|
|
return $failed; |
320
|
|
|
|
|
|
|
} |
321
|
|
|
|
|
|
|
|
322
|
|
|
|
|
|
|
sub process_encrypted { |
323
|
0
|
|
|
0
|
1
|
|
my ($self, $process) = @_; |
324
|
|
|
|
|
|
|
|
325
|
0
|
|
|
|
|
|
my $log = $self->{fileset}->{log}; |
326
|
0
|
|
|
|
|
|
my $dir = $self->{fileset}->{dir}; |
327
|
0
|
|
|
|
|
|
my $file = $self->{filename}; |
328
|
|
|
|
|
|
|
|
329
|
0
|
|
|
|
|
|
$log->verbose( "Decrypting file '$file'"); |
330
|
0
|
|
|
|
|
|
my $newfile = $file; |
331
|
0
|
0
|
|
|
|
|
if ('.cry' ne lc substr $newfile, -4, 4, q{}) { |
332
|
|
|
|
|
|
|
# throw exception |
333
|
0
|
|
|
|
|
|
$log->error("filename '$file' does not end in '.cry'."); |
334
|
|
|
|
|
|
|
} |
335
|
|
|
|
|
|
|
|
336
|
|
|
|
|
|
|
# arXiv specific |
337
|
0
|
|
|
|
|
|
my $key = $process->{decryption_key}; |
338
|
0
|
|
|
|
|
|
$log->verbose("running: '$CRYPT $newfile $key'"); |
339
|
|
|
|
|
|
|
|
340
|
|
|
|
|
|
|
# ensure proper path so that correct programs decry and cipher are found |
341
|
0
|
0
|
|
|
|
|
if (index($ENV{PATH}, $TEX_PATH) != 0) { |
342
|
0
|
|
|
|
|
|
local $ENV{PATH} = "$TEX_PATH/bin:" . $ENV{PATH}; |
343
|
|
|
|
|
|
|
} |
344
|
0
|
|
|
|
|
|
my $fullname = "$dir/$newfile"; |
345
|
|
|
|
|
|
|
# The following two lines are necessary to get decry to work |
346
|
|
|
|
|
|
|
{ |
347
|
0
|
|
|
|
|
|
open my $OUTFH, '>', $fullname; close $OUTFH; |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
348
|
0
|
|
|
|
|
|
chmod oct(666), $fullname; |
349
|
|
|
|
|
|
|
} |
350
|
0
|
|
|
|
|
|
$log->verbose("path is: '$ENV{PATH}'"); |
351
|
0
|
|
0
|
|
|
|
my $response = `$CRYPT $fullname $key` || "[no response, exit code $?]"; |
352
|
0
|
0
|
|
|
|
|
if ($?) { |
353
|
0
|
|
|
|
|
|
$log->error("$CRYPT error response: '$response'"); |
354
|
|
|
|
|
|
|
} |
355
|
0
|
0
|
0
|
|
|
|
if (! -T $fullname || -z _) { |
356
|
0
|
|
|
|
|
|
$log->error("'$file' didn't decrypt to a text file."); |
357
|
|
|
|
|
|
|
} |
358
|
0
|
0
|
|
|
|
|
unlink "$dir/$file" or $log->error("unable to remove '$file': $!"); |
359
|
0
|
|
|
|
|
|
return; |
360
|
|
|
|
|
|
|
} |
361
|
|
|
|
|
|
|
|
362
|
|
|
|
|
|
|
sub process_dvitype { |
363
|
0
|
|
|
0
|
1
|
|
my ($self, $process) = @_; |
364
|
|
|
|
|
|
|
|
365
|
0
|
|
|
|
|
|
my $log = $self->{fileset}->{log}; |
366
|
0
|
|
|
|
|
|
my $dir = $self->{fileset}->{dir}; |
367
|
0
|
|
|
|
|
|
my $file = $self->{filename}; |
368
|
|
|
|
|
|
|
|
369
|
0
|
0
|
|
|
|
|
my $dvi_flags = $process->{branch} =~ m{texlive/}? '-R2' : '-R'; |
370
|
0
|
0
|
|
|
|
|
$dvi_flags .= " $self->{dvi_flags}" if $self->{dvi_flags}; |
371
|
0
|
0
|
|
|
|
|
$dvi_flags .= ' -t landscape' if $self->{flags}->{landscape}; |
372
|
0
|
0
|
|
|
|
|
$dvi_flags .= $self->{flags}->{keepcomments}? ' -K0' : ' -K1'; |
373
|
|
|
|
|
|
|
|
374
|
0
|
|
|
|
|
|
my $response; |
375
|
0
|
0
|
|
|
|
|
my $setenv = qq{export HOME=/tmp @{[$ENV{TEXMFCNF}? "TEXMFCNF=$ENV{TEXMFCNF}": q{}]} PATH=$process->{tex_env_path}}; |
|
0
|
|
|
|
|
|
|
376
|
0
|
|
|
|
|
|
my $crdir = substr $dir, length $TEX_PATH; |
377
|
0
|
|
|
|
|
|
while (1) { |
378
|
0
|
|
|
|
|
|
$log->verbose(" ~~~~~~~~~~~ Processing file '$file'"); |
379
|
0
|
|
|
|
|
|
my $dvipscommand = qq#$TEXCHR $TEX_PATH "($setenv; cd $crdir && $DVIPS $dvi_flags -z '$file' -o )" 2>&1#; |
380
|
0
|
|
|
|
|
|
$log->verbose('Running: ' . substr $dvipscommand, length "$TEXCHR $TEX_PATH "); |
381
|
0
|
|
|
|
|
|
my $dvipstime = time; |
382
|
0
|
|
|
|
|
|
$response = `$dvipscommand`; |
383
|
0
|
0
|
|
|
|
|
last if !$?; |
384
|
0
|
|
|
|
|
|
$log->verbose("$DVIPS $dvi_flags -z produced an error: $?\nResponse was $response\nRetrying without '-z'"); |
385
|
0
|
0
|
0
|
|
|
|
if (-e "$dir/head.tmp" && -e "$dir/body.tmp") { |
386
|
0
|
|
|
|
|
|
unlink "$dir/head.tmp", "$dir/body.tmp"; |
387
|
0
|
|
|
|
|
|
$log->verbose('removed dvips leftover head.tmp and body.tmp'); |
388
|
|
|
|
|
|
|
} |
389
|
|
|
|
|
|
|
# dvips -z may have core-dumped. remove only newly generated core file(s) |
390
|
0
|
0
|
|
|
|
|
if (my @corefiles = glob "$dir/core\.[0-9]*") { |
391
|
0
|
|
|
|
|
|
@corefiles = |
392
|
0
|
0
|
|
|
|
|
map { m/(.*)/ } |
393
|
0
|
|
|
|
|
|
grep { m{^$dir/core\.\d+$} && (stat "$dir/$_")[9] >= $dvipstime } |
394
|
|
|
|
|
|
|
@corefiles; |
395
|
0
|
0
|
|
|
|
|
if (@corefiles) { |
396
|
0
|
|
|
|
|
|
unlink @corefiles; |
397
|
0
|
|
|
|
|
|
$log->verbose("removed one or more core files: @corefiles"); |
398
|
|
|
|
|
|
|
} |
399
|
|
|
|
|
|
|
} |
400
|
0
|
|
|
|
|
|
$dvipscommand = qq#$TEXCHR $TEX_PATH "($setenv; cd $crdir && $DVIPS $dvi_flags '$file' -o )" 2>&1#; |
401
|
0
|
|
|
|
|
|
$log->verbose('Running: ' . substr $dvipscommand, length "$TEXCHR $TEX_PATH "); |
402
|
0
|
|
|
|
|
|
$response = `$dvipscommand`; |
403
|
0
|
0
|
|
|
|
|
last if !$?; |
404
|
0
|
|
|
|
|
|
$log->verbose("$DVIPS $dvi_flags produced an error: $?\nResponse was $response."); |
405
|
0
|
|
|
|
|
|
$log->error('Failed to produce postscript from dvi.'); |
406
|
|
|
|
|
|
|
} |
407
|
0
|
|
|
|
|
|
$log->verbose("dvi(h)ps said ...\n$response."); |
408
|
|
|
|
|
|
|
|
409
|
0
|
|
|
|
|
|
my %commondvipsheaders; |
410
|
0
|
|
|
|
|
|
@commondvipsheaders{qw( |
411
|
|
|
|
|
|
|
tex.pro |
412
|
|
|
|
|
|
|
texc.pro |
413
|
|
|
|
|
|
|
texps.pro |
414
|
|
|
|
|
|
|
hps.pro |
415
|
|
|
|
|
|
|
special.pro |
416
|
|
|
|
|
|
|
color.pro |
417
|
|
|
|
|
|
|
finclude.pro |
418
|
|
|
|
|
|
|
alt-rule.pro |
419
|
|
|
|
|
|
|
head.tmp |
420
|
|
|
|
|
|
|
body.tmp |
421
|
|
|
|
|
|
|
8r.enc |
422
|
|
|
|
|
|
|
texnansi.enc |
423
|
|
|
|
|
|
|
)} = (); |
424
|
|
|
|
|
|
|
|
425
|
0
|
|
|
|
|
|
while ($response =~ m{<(?:\.//?)*([^><\n]+)>}g) { |
426
|
0
|
|
|
|
|
|
my $included = $1; |
427
|
0
|
0
|
|
|
|
|
if ($included !~ m{^/}){ |
428
|
0
|
0
|
0
|
|
|
|
if (-e "$dir/$included") { |
|
|
0
|
|
|
|
|
|
429
|
0
|
|
|
|
|
|
$self->{fileset}->new_File($included)->set_flag('used_by_dvips'); |
430
|
0
|
|
|
|
|
|
$log->verbose("'$included' no longer required ... it's in the postscript file."); |
431
|
|
|
|
|
|
|
} elsif (!(exists $commondvipsheaders{$included} || '.pfb' eq substr $included, -4)) { |
432
|
0
|
|
|
|
|
|
$log->verbose("'$included' was apparently included, but cannot be deleted, because it cannot be found in cwd."); |
433
|
|
|
|
|
|
|
} |
434
|
|
|
|
|
|
|
} |
435
|
|
|
|
|
|
|
} |
436
|
0
|
|
|
|
|
|
my $psfile = $file; |
437
|
0
|
|
|
|
|
|
substr $psfile, -3, 3, 'ps'; |
438
|
|
|
|
|
|
|
# Change %%Title if wanted |
439
|
0
|
0
|
|
|
|
|
if (my $stampref = $process->get_stamp()) { |
440
|
0
|
|
|
|
|
|
TeX::AutoTeX::PostScript::fix_ps_title( |
441
|
|
|
|
|
|
|
$psfile, |
442
|
|
|
|
|
|
|
$dir, |
443
|
|
|
|
|
|
|
$stampref->[0], |
444
|
|
|
|
|
|
|
$log |
445
|
|
|
|
|
|
|
); |
446
|
0
|
|
|
|
|
|
TeX::AutoTeX::PostScript::stamp_postscript( |
447
|
|
|
|
|
|
|
$psfile, |
448
|
|
|
|
|
|
|
$dir, |
449
|
|
|
|
|
|
|
$stampref, |
450
|
|
|
|
|
|
|
$log |
451
|
|
|
|
|
|
|
); |
452
|
|
|
|
|
|
|
} |
453
|
0
|
|
|
|
|
|
$self->{fileset}->new_File($psfile)->set_flag('main_postscript'); |
454
|
|
|
|
|
|
|
|
455
|
0
|
|
|
|
|
|
return; |
456
|
|
|
|
|
|
|
} |
457
|
|
|
|
|
|
|
|
458
|
|
|
|
|
|
|
sub slurp_log { |
459
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
460
|
0
|
|
|
|
|
|
my $log = $self->basename() . '.log'; |
461
|
|
|
|
|
|
|
|
462
|
0
|
0
|
|
|
|
|
open(my $LOG, '<', "$self->{fileset}->{dir}/$log") |
463
|
|
|
|
|
|
|
|| $self->{fileset}->{log}->error("Could not open log file '$log' produced by (la)tex."); |
464
|
0
|
|
|
|
|
|
local $/ = undef; |
465
|
0
|
|
|
|
|
|
my $log_contents = <$LOG>; |
466
|
0
|
|
|
|
|
|
close $LOG; |
467
|
0
|
|
|
|
|
|
return \$log_contents; |
468
|
|
|
|
|
|
|
} |
469
|
|
|
|
|
|
|
|
470
|
|
|
|
|
|
|
sub clean_aux_files { |
471
|
0
|
|
|
0
|
1
|
|
my ($self, $stime) = @_; |
472
|
|
|
|
|
|
|
|
473
|
0
|
0
|
|
|
|
|
opendir(my $WORKING_DIR, $self->{fileset}->{dir}) |
474
|
|
|
|
|
|
|
|| $self->{fileset}->{log}->error("Can't open processing directory: $!"); |
475
|
0
|
0
|
0
|
|
|
|
if (my @auxfiles = |
|
0
|
0
|
|
|
|
|
|
476
|
|
|
|
|
|
|
grep { /\.aux$/ && -f "$self->{fileset}->{dir}/$_" && (stat(_))[9] >= $stime } |
477
|
|
|
|
|
|
|
readdir $WORKING_DIR) { |
478
|
|
|
|
|
|
|
my $numauxfiles = unlink( |
479
|
|
|
|
|
|
|
map { "$self->{fileset}->{dir}/$_" } |
480
|
0
|
|
0
|
|
|
|
map { m/(.*)/ } |
481
|
|
|
|
|
|
|
@auxfiles |
482
|
|
|
|
|
|
|
) |
483
|
|
|
|
|
|
|
|| $self->{fileset}->{log}->error("Could not remove one of the auxfiles: @auxfiles."); |
484
|
0
|
|
|
|
|
|
$self->{fileset}->{log}->verbose("unlinked $numauxfiles '.aux' files"); |
485
|
|
|
|
|
|
|
} |
486
|
0
|
|
|
|
|
|
closedir($WORKING_DIR); |
487
|
0
|
|
|
|
|
|
return; |
488
|
|
|
|
|
|
|
} |
489
|
|
|
|
|
|
|
|
490
|
|
|
|
|
|
|
sub swap_source { |
491
|
0
|
|
|
0
|
1
|
|
my ($self, $hyper) = @_; |
492
|
|
|
|
|
|
|
|
493
|
0
|
|
|
|
|
|
my $file = $self->{filename}; |
494
|
0
|
|
|
|
|
|
my $dir = $self->{fileset}->{dir}; |
495
|
|
|
|
|
|
|
|
496
|
|
|
|
|
|
|
# remove aux files if any |
497
|
0
|
|
|
|
|
|
my $basename = $self->basename(); |
498
|
0
|
|
|
|
|
|
foreach my $auxfile (grep {-e "$dir/$_"} map {"$basename.$_"} qw(aux lot lof toc)) { |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
499
|
0
|
0
|
|
|
|
|
unlink "$dir/$auxfile" or $self->{fileset}->{log}->error("failed to remove '$auxfile'."); |
500
|
0
|
|
|
|
|
|
$self->{fileset}->{log}->verbose("removed aux file '$auxfile'"); |
501
|
|
|
|
|
|
|
} |
502
|
|
|
|
|
|
|
|
503
|
|
|
|
|
|
|
# remove the existing file to be processed, then link the |
504
|
|
|
|
|
|
|
# with/without hyper version to it |
505
|
0
|
0
|
|
|
|
|
unlink "$dir/$file" or $self->{fileset}->{log}->error("failed to remove '$file'."); |
506
|
|
|
|
|
|
|
|
507
|
|
|
|
|
|
|
# note that (hard-)linking does not change atime or mtime |
508
|
0
|
0
|
|
|
|
|
if ($hyper eq 'hyper') { |
509
|
0
|
0
|
|
|
|
|
link "$dir/$file.with_hyper", "$dir/$file" |
510
|
|
|
|
|
|
|
or $self->{fileset}->{log}->verbose("failed to rename '$file'"); |
511
|
|
|
|
|
|
|
} else { |
512
|
0
|
0
|
|
|
|
|
link "$dir/$file.without_hyper", "$dir/$file" |
513
|
|
|
|
|
|
|
or $self->{fileset}->{log}->verbose("failed to rename '$file'"); |
514
|
|
|
|
|
|
|
} |
515
|
0
|
|
|
|
|
|
return; |
516
|
|
|
|
|
|
|
} |
517
|
|
|
|
|
|
|
|
518
|
|
|
|
|
|
|
sub run_tex_attempt { |
519
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
520
|
0
|
|
|
|
|
|
my ($program, $tex_passes, $process, $stime, $written, $tex_type) = @_; |
521
|
|
|
|
|
|
|
|
522
|
0
|
|
|
|
|
|
my $log = $self->{fileset}->{log}; |
523
|
|
|
|
|
|
|
|
524
|
0
|
0
|
|
|
|
|
if (!defined $TEXCHR) { |
525
|
0
|
|
|
|
|
|
throw TeX::AutoTeX::TexChrException('TEXCHR not set.'); |
526
|
|
|
|
|
|
|
} |
527
|
0
|
0
|
0
|
|
|
|
if ($process->{branch} eq '2' && !defined $ENV{TEXMFCNF}) { |
528
|
0
|
|
|
|
|
|
throw TeX::AutoTeX::TexMFCnfException('TEXMFCNF not set for /2 branch.'); |
529
|
|
|
|
|
|
|
} |
530
|
|
|
|
|
|
|
#TS: find the source of STDIN input to be used. this was historically used for |
531
|
|
|
|
|
|
|
# macros which required user input -- e.g. big or little (b/l) |
532
|
0
|
|
|
|
|
|
my $latex_input = $self->basename() . '.inp'; |
533
|
0
|
0
|
|
|
|
|
my $feeder = -e "$self->{fileset}->{dir}/$latex_input" ? qq{'$latex_input'} : '/dev/null'; |
534
|
|
|
|
|
|
|
|
535
|
0
|
|
0
|
|
|
|
my $tex_format = $self->{tex_format} || q{}; |
536
|
0
|
|
|
|
|
|
my $escaped_tex_format = q{}; |
537
|
|
|
|
|
|
|
|
538
|
0
|
0
|
0
|
|
|
|
if (!$tex_format && $tex_type eq 'htex') { |
539
|
0
|
|
|
|
|
|
$tex_format = 'htex'; |
540
|
|
|
|
|
|
|
} |
541
|
0
|
0
|
0
|
|
|
|
if ($tex_format !~ /209$/ && $tex_type =~ /209/) { |
542
|
0
|
|
|
|
|
|
$tex_format .= '209'; |
543
|
|
|
|
|
|
|
} |
544
|
0
|
0
|
0
|
|
|
|
if ($tex_format =~ /^latex209/ && $program =~ /^h/) { |
545
|
0
|
|
|
|
|
|
$tex_format = 'hlatex209'; |
546
|
|
|
|
|
|
|
} |
547
|
0
|
0
|
|
|
|
|
if ($tex_format){ |
548
|
|
|
|
|
|
|
## TS: FIXME |
549
|
|
|
|
|
|
|
## static lookup table instead of (convoluted) regexp. should go into |
550
|
|
|
|
|
|
|
## TeX::AutoTeX::Config? here is the list of all formats available in |
551
|
|
|
|
|
|
|
## arXiv's tex installation. For texlive 2009 and newer arXiv doesn't |
552
|
|
|
|
|
|
|
## build custom formats any longer. |
553
|
0
|
|
|
|
|
|
my %known_formats; |
554
|
0
|
|
|
|
|
|
@{$known_formats{'3'}}{qw( |
|
0
|
|
|
|
|
|
|
555
|
|
|
|
|
|
|
amstex |
556
|
|
|
|
|
|
|
htex |
557
|
|
|
|
|
|
|
tex |
558
|
|
|
|
|
|
|
latex |
559
|
|
|
|
|
|
|
biglatex |
560
|
|
|
|
|
|
|
pdfamstex |
561
|
|
|
|
|
|
|
pdflatex |
562
|
|
|
|
|
|
|
pdftex |
563
|
|
|
|
|
|
|
)} = (); |
564
|
|
|
|
|
|
|
|
565
|
0
|
|
|
|
|
|
@{$known_formats{'2'}}{qw( |
|
0
|
|
|
|
|
|
|
566
|
|
|
|
|
|
|
amslatex1.1 |
567
|
|
|
|
|
|
|
amslplain |
568
|
|
|
|
|
|
|
amstex |
569
|
|
|
|
|
|
|
biglatex |
570
|
|
|
|
|
|
|
bigtex |
571
|
|
|
|
|
|
|
cp-aa |
572
|
|
|
|
|
|
|
hlatex209 |
573
|
|
|
|
|
|
|
hlatex2e |
574
|
|
|
|
|
|
|
hlatex |
575
|
|
|
|
|
|
|
hlplain |
576
|
|
|
|
|
|
|
hplain |
577
|
|
|
|
|
|
|
htex |
578
|
|
|
|
|
|
|
latex209 |
579
|
|
|
|
|
|
|
latex2e |
580
|
|
|
|
|
|
|
latex |
581
|
|
|
|
|
|
|
lplain |
582
|
|
|
|
|
|
|
plain |
583
|
|
|
|
|
|
|
tex |
584
|
|
|
|
|
|
|
texsis |
585
|
|
|
|
|
|
|
)} = (); |
586
|
|
|
|
|
|
|
|
587
|
0
|
0
|
|
|
|
|
if (exists $known_formats{$process->{branch}}{$tex_format}) { |
588
|
0
|
|
|
|
|
|
$log->verbose("Using format file $tex_format"); |
589
|
0
|
|
|
|
|
|
$escaped_tex_format = q{&} . $tex_format; |
590
|
|
|
|
|
|
|
# escape (&) in $tex_format and remove double quotes |
591
|
|
|
|
|
|
|
# TS: where would those come from after the lookup table replaced older code? |
592
|
0
|
|
|
|
|
|
$escaped_tex_format =~ s/&/\\\&/g; |
593
|
0
|
|
|
|
|
|
$escaped_tex_format =~ s/"//g; # " |
594
|
|
|
|
|
|
|
} else { |
595
|
0
|
|
|
|
|
|
$log->verbose("'$tex_format' is not a valid TeX format; will ignore."); |
596
|
|
|
|
|
|
|
} |
597
|
|
|
|
|
|
|
} |
598
|
|
|
|
|
|
|
|
599
|
0
|
0
|
|
|
|
|
my $setenv = qq{export HOME=/tmp @{[$ENV{TEXMFCNF}? "TEXMFCNF=$ENV{TEXMFCNF}": q{}]} PATH=$process->{tex_env_path}}; |
|
0
|
|
|
|
|
|
|
600
|
0
|
0
|
|
|
|
|
$log->verbose(qq{TEXMFCNF is @{[$ENV{TEXMFCNF}? "set to: '$ENV{TEXMFCNF}'": 'unset.']}}); |
|
0
|
|
|
|
|
|
|
601
|
0
|
|
|
|
|
|
my $crdir = substr $self->{fileset}->{dir}, length $TEX_PATH; |
602
|
0
|
|
|
|
|
|
my $runtexcommand = qq#$TEXCHR $TEX_PATH "($setenv; cd $crdir && $program $escaped_tex_format '$self->{filename}' < $feeder)" 2>&1#; |
603
|
|
|
|
|
|
|
|
604
|
0
|
|
|
|
|
|
my $passes = 0; |
605
|
0
|
|
|
|
|
|
my $rerun = 0; |
606
|
0
|
|
|
|
|
|
my $extra_pass = 0; |
607
|
0
|
|
|
|
|
|
my $xfontcreate = 0; |
608
|
0
|
|
|
|
|
|
my $lastlog_ref; |
609
|
|
|
|
|
|
|
my $failed; |
610
|
|
|
|
|
|
|
|
611
|
0
|
|
|
|
|
|
my @ORDER = qw(first second third fourth fifth sixth seventh); |
612
|
|
|
|
|
|
|
|
613
|
|
|
|
|
|
|
PASSES: |
614
|
0
|
|
|
|
|
|
while ($passes < $tex_passes) { |
615
|
0
|
|
|
|
|
|
$log->verbose(" ~~~~~~~~~~~ Running $tex_type for the $ORDER[$passes] time ~~~~~~~~"); |
616
|
0
|
|
|
|
|
|
$log->verbose('Running: ' . substr $runtexcommand, length "$TEXCHR $TEX_PATH "); |
617
|
0
|
|
|
|
|
|
my $out = `$runtexcommand`; |
618
|
0
|
|
|
|
|
|
$log->verbose($out); |
619
|
0
|
|
|
|
|
|
$lastlog_ref = $self->slurp_log(); |
620
|
|
|
|
|
|
|
|
621
|
|
|
|
|
|
|
# TS: This is due to peculiarities of feynmf and similar dynamical font |
622
|
|
|
|
|
|
|
# creation. If we get an error exit status from latex then we need to |
623
|
|
|
|
|
|
|
# check for new font files and possibly rerun. Only do this once, in |
624
|
|
|
|
|
|
|
# case the non-zero exit status is due to some problem other than |
625
|
|
|
|
|
|
|
# font-creation and persistent, otherwise this could loop indefinitely. |
626
|
0
|
0
|
|
|
|
|
if ($?) { |
627
|
0
|
0
|
0
|
|
|
|
if (!$xfontcreate && $self->extra_fontcreation_pass($stime)) { |
628
|
0
|
|
|
|
|
|
$xfontcreate++; |
629
|
0
|
|
|
|
|
|
redo PASSES; |
630
|
|
|
|
|
|
|
} else { |
631
|
|
|
|
|
|
|
#the message below is slightly misleading because $program for |
632
|
|
|
|
|
|
|
#latex2e hyper/nohyper is the same. |
633
|
0
|
|
|
|
|
|
$log->verbose("$program '$self->{filename}' failed."); |
634
|
0
|
|
|
|
|
|
$self->trash_tex_aux_files($stime, $written); |
635
|
0
|
|
|
|
|
|
my $dvi = $self->basename() . '.dvi'; |
636
|
0
|
0
|
|
|
|
|
if (-e "$self->{fileset}->{dir}/$dvi") { |
637
|
0
|
|
|
|
|
|
$log->verbose("removing leftover dvi file '$dvi'"); |
638
|
0
|
0
|
|
|
|
|
unlink "$self->{fileset}->{dir}/$dvi" or |
639
|
|
|
|
|
|
|
$log->verbose("Could not remove file '$dvi'."); |
640
|
|
|
|
|
|
|
} |
641
|
0
|
|
|
|
|
|
$failed = 1; |
642
|
0
|
|
|
|
|
|
last; |
643
|
|
|
|
|
|
|
} |
644
|
|
|
|
|
|
|
} |
645
|
|
|
|
|
|
|
|
646
|
0
|
0
|
0
|
|
|
|
if ($passes == 0 && ($tex_type eq 'hlatex2e' || |
|
|
|
0
|
|
|
|
|
647
|
|
|
|
|
|
|
$tex_type eq 'latex2e' || |
648
|
|
|
|
|
|
|
$tex_type =~ /h?pdflatex/o)) { |
649
|
0
|
0
|
|
|
|
|
if (0 <= index ${$lastlog_ref}, 'LaTeX Warning: Writing file `') { |
|
0
|
|
|
|
|
|
|
650
|
0
|
|
|
|
|
|
while(${$lastlog_ref} =~ /LaTeX Warning: Writing file \`([^']*)\'\./g) { # ')){ |
|
0
|
|
|
|
|
|
|
651
|
0
|
|
|
|
|
|
$written->{$1}++; |
652
|
|
|
|
|
|
|
} |
653
|
|
|
|
|
|
|
} |
654
|
|
|
|
|
|
|
} |
655
|
|
|
|
|
|
|
|
656
|
|
|
|
|
|
|
# TS: added $tex_format b/c otherwise &amslplain will only be processed twice |
657
|
0
|
0
|
0
|
|
|
|
if ($tex_type =~ /latex/i || $tex_format) { |
658
|
0
|
0
|
0
|
|
|
|
if (0 <= index(${$lastlog_ref}, q{Label(s) may have changed. Rerun}) || |
|
0
|
|
0
|
|
|
|
|
|
0
|
|
0
|
|
|
|
|
659
|
0
|
|
|
|
|
|
0 <= index(${$lastlog_ref}, q{Warning: Citation(s) may have changed.}) || |
660
|
0
|
|
|
|
|
|
0 <= index(${$lastlog_ref}, q{Table widths have changed. Rerun LaTeX.}) || |
661
|
|
|
|
|
|
|
0 <= index(${$lastlog_ref}, q{Rerun to get citations correct.}) |
662
|
|
|
|
|
|
|
) { |
663
|
0
|
|
|
|
|
|
$rerun = 1; |
664
|
|
|
|
|
|
|
} else { |
665
|
0
|
|
|
|
|
|
$rerun = $self->extra_pass($stime); |
666
|
|
|
|
|
|
|
} |
667
|
|
|
|
|
|
|
} else { |
668
|
0
|
|
|
|
|
|
$rerun = 0; |
669
|
|
|
|
|
|
|
} |
670
|
|
|
|
|
|
|
# TS: this seems to be contraproductive to the $tex_passes=4 for &amslplain |
671
|
|
|
|
|
|
|
# and possibly others |
672
|
0
|
0
|
0
|
|
|
|
last unless $rerun || $passes == 0; |
673
|
0
|
|
|
|
|
|
$passes++; |
674
|
|
|
|
|
|
|
} # End of while ($passes < $tex_passes) |
675
|
|
|
|
|
|
|
|
676
|
0
|
0
|
0
|
|
|
|
if ($passes == $tex_passes && $rerun) { |
677
|
0
|
|
|
|
|
|
$log->verbose("WARNING: Reached max number of passes, possibly failed to get CROSS-REFERENCES right."); |
678
|
|
|
|
|
|
|
} |
679
|
0
|
|
|
|
|
|
$self->trash_tex_aux_files($stime, $written); |
680
|
0
|
|
|
|
|
|
return $failed; |
681
|
|
|
|
|
|
|
} |
682
|
|
|
|
|
|
|
|
683
|
|
|
|
|
|
|
sub extra_pass { |
684
|
0
|
|
|
0
|
1
|
|
my ($self, $younger_than) = @_; |
685
|
|
|
|
|
|
|
|
686
|
0
|
|
|
|
|
|
opendir my $CDIR, $self->{fileset}->{dir}; |
687
|
0
|
0
|
0
|
|
|
|
my $tocloflot = |
688
|
0
|
|
|
|
|
|
grep {/\.(?:toc|lof|lot)$/ && -f "$self->{fileset}->{dir}/$_" && ((stat(_))[9] >= $younger_than)} |
689
|
|
|
|
|
|
|
readdir $CDIR; |
690
|
0
|
|
|
|
|
|
closedir $CDIR; |
691
|
0
|
0
|
|
|
|
|
if ($tocloflot) { |
692
|
|
|
|
|
|
|
#TS: here a toc/lof/lot will always lead to max number of runs |
693
|
|
|
|
|
|
|
# this is more robust than attempting to keep it to minimum |
694
|
|
|
|
|
|
|
# in particular since a long toc etc. can lead to a shift between |
695
|
|
|
|
|
|
|
# 3rd and 4th pass without any indication of such in the log |
696
|
|
|
|
|
|
|
|
697
|
0
|
|
|
|
|
|
$self->{fileset}->{log}->verbose('LaTeX wrote a .toc, .lof, or .lot file - running extra passes'); |
698
|
0
|
|
|
|
|
|
return 1; |
699
|
|
|
|
|
|
|
} |
700
|
0
|
|
|
|
|
|
return 0; |
701
|
|
|
|
|
|
|
} |
702
|
|
|
|
|
|
|
|
703
|
|
|
|
|
|
|
sub extra_fontcreation_pass { |
704
|
0
|
|
|
0
|
1
|
|
my ($self, $younger_than) = @_; |
705
|
|
|
|
|
|
|
|
706
|
0
|
|
|
|
|
|
opendir my $CDIR, $self->{fileset}->{dir}; |
707
|
0
|
0
|
0
|
|
|
|
my $mftfm = |
708
|
0
|
|
|
|
|
|
grep {/\.(?:mf|tfm)$/ && -f "$self->{fileset}->{dir}/$_" && ((stat(_))[9] >= $younger_than)} |
709
|
|
|
|
|
|
|
readdir $CDIR; |
710
|
0
|
|
|
|
|
|
closedir $CDIR; |
711
|
0
|
0
|
|
|
|
|
if ($mftfm) { |
712
|
0
|
|
|
|
|
|
$self->{fileset}->{log}->verbose(<<"EOM"); |
713
|
|
|
|
|
|
|
LaTeX wrote a .tfm or .mf file -- this indicates feynmf or similar dynamic font generation. |
714
|
|
|
|
|
|
|
Ignoring non-zero exit status and starting over retaining the new font files! |
715
|
|
|
|
|
|
|
EOM |
716
|
0
|
|
|
|
|
|
return 1; |
717
|
|
|
|
|
|
|
} |
718
|
0
|
|
|
|
|
|
return 0; |
719
|
|
|
|
|
|
|
} |
720
|
|
|
|
|
|
|
|
721
|
|
|
|
|
|
|
sub trash_tex_aux_files { |
722
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
723
|
0
|
|
|
|
|
|
my ($younger_than, $written) = @_; |
724
|
|
|
|
|
|
|
|
725
|
0
|
|
|
|
|
|
my $dir = $self->{fileset}->{dir}; |
726
|
0
|
|
|
|
|
|
opendir(my $TEMPDIR, $dir); |
727
|
0
|
|
|
|
|
|
my @files = |
728
|
0
|
0
|
0
|
|
|
|
map {/^(.*)$/} # untaint |
|
|
|
0
|
|
|
|
|
729
|
0
|
|
|
|
|
|
grep {!/^\./ # no dot files |
730
|
|
|
|
|
|
|
&& !/\.(mf|log)$/ # need metafont files and associated log for labels |
731
|
|
|
|
|
|
|
&& -f "$dir/$_" # recently modified files only |
732
|
|
|
|
|
|
|
&& (stat(_))[9] >= $younger_than} |
733
|
|
|
|
|
|
|
readdir $TEMPDIR; |
734
|
0
|
|
|
|
|
|
closedir $TEMPDIR; |
735
|
|
|
|
|
|
|
|
736
|
0
|
|
|
|
|
|
foreach my $file (@files) { |
737
|
|
|
|
|
|
|
# Warn about files written by latex but still delete them. |
738
|
|
|
|
|
|
|
# We do not want people to include figures by dumping them out |
739
|
|
|
|
|
|
|
# from the tex file using the LaTeX2e filecontents environment. |
740
|
|
|
|
|
|
|
# Simeon-21Jul2000 |
741
|
0
|
0
|
|
|
|
|
if ($written->{$file}) { |
742
|
0
|
|
|
|
|
|
$self->{fileset}->{log}->verbose("TeX wrote out '$file', going to delete it as we don't permit filecontents inclusion of figures."); |
743
|
0
|
|
|
|
|
|
delete $written->{$file}; |
744
|
|
|
|
|
|
|
} |
745
|
0
|
|
|
|
|
|
my $fmt = $self->{fileset}->new_File($file)->type(); |
746
|
0
|
0
|
|
|
|
|
next if grep {$fmt eq 'TYPE_' . $_} qw(DVI POSTSCRIPT PDF); |
|
0
|
|
|
|
|
|
|
747
|
|
|
|
|
|
|
|
748
|
0
|
|
|
|
|
|
my $age = (stat("$dir/$file"))[9]; #TS FIXME: expensive stat for logging |
749
|
0
|
|
|
|
|
|
$self->{fileset}->{log}->verbose("Removing (La)TeX AUX file called '$file' ($age >= $younger_than)"); |
750
|
0
|
0
|
|
|
|
|
unlink "$dir/$file" |
751
|
|
|
|
|
|
|
or $self->{fileset}->{log}->error("failed to remove '$file': $!"); |
752
|
|
|
|
|
|
|
} |
753
|
0
|
|
|
|
|
|
return 0; |
754
|
|
|
|
|
|
|
} |
755
|
|
|
|
|
|
|
|
756
|
|
|
|
|
|
|
####################################################################### |
757
|
|
|
|
|
|
|
# basename() |
758
|
|
|
|
|
|
|
# takes filename from AutoTeX::File object, removes its extension if it has |
759
|
|
|
|
|
|
|
# one, caches and returns result. |
760
|
|
|
|
|
|
|
# a special case is a filename ending in '.'. in this |
761
|
|
|
|
|
|
|
# context, it should also be removed. |
762
|
|
|
|
|
|
|
# substr/rindex is 3x faster than regexp s/\.[^.]*$//; |
763
|
|
|
|
|
|
|
|
764
|
|
|
|
|
|
|
sub basename { |
765
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
766
|
0
|
0
|
|
|
|
|
if (!defined $self->{basename}) { |
767
|
0
|
0
|
|
|
|
|
if (0 < index $self->{filename}, q{.}) { |
768
|
0
|
|
|
|
|
|
$self->{basename} = substr $self->{filename}, 0, rindex($self->{filename}, q{.}); |
769
|
|
|
|
|
|
|
} else { |
770
|
0
|
|
|
|
|
|
$self->{basename} = $self->{filename}; |
771
|
|
|
|
|
|
|
} |
772
|
|
|
|
|
|
|
} |
773
|
0
|
|
|
|
|
|
return $self->{basename}; |
774
|
|
|
|
|
|
|
} |
775
|
|
|
|
|
|
|
|
776
|
|
|
|
|
|
|
1; |
777
|
|
|
|
|
|
|
|
778
|
|
|
|
|
|
|
__END__ |