--- loncom/interface/printout.pl 2007/10/11 22:49:49 1.128
+++ loncom/interface/printout.pl 2008/03/18 10:29:56 1.134
@@ -1,7 +1,7 @@
#!/usr/bin/perl
# CGI-script to run LaTeX, dvips, ps2ps, ps2pdf etc.
#
-# $Id: printout.pl,v 1.128 2007/10/11 22:49:49 albertel Exp $
+# $Id: printout.pl,v 1.134 2008/03/18 10:29:56 foxr Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -43,6 +43,7 @@ use LONCAPA::Configuration;
use strict;
+my $busy_wait_timeout = 30;
# Determine if a user is operating as a student for this course/domain.
#Parameters:
@@ -164,145 +165,79 @@ END
}
my %perlvar=%{&LONCAPA::Configuration::read_conf('loncapa.conf')};
- &Apache::lonlocal::get_language_handle();
- &Apache::loncommon::content_type(undef,'text/html');
+&Apache::lonlocal::get_language_handle();
+&Apache::loncommon::content_type(undef,'text/html');
$env{'request.noversionuri'} = '/cgi-bin/printout.pl';
- print(&Apache::loncommon::start_page('Creating PDF'));
+print(&Apache::loncommon::start_page('Creating PDF'));
+
+my $identifier = $ENV{'QUERY_STRING'};
+my $texfile = $env{'cgi.'.$identifier.'.file'};
+my $laystyle = $env{'cgi.'.$identifier.'.layout'};
+my $numberofcolumns = $env{'cgi.'.$identifier.'.numcol'};
+my $paper = $env{'cgi.'.$identifier.'.paper'};
+my $selectionmade = $env{'cgi.'.$identifier.'.selection'};
+my $tableofcontents = $env{'cgi.'.$identifier.'.tableofcontents'};
+my $tableofindex = $env{'cgi.'.$identifier.'.tableofindex'};
+my $advanced_role = $env{'cgi.'.$identifier.'.role'};
+my $number_of_files = $env{'cgi.'.$identifier.'.numberoffiles'}+1;
+my $student_names = $env{'cgi.'.$identifier.'.studentnames'};
+my $backref = &Apache::lonnet::unescape($env{'cgi.'.$identifier.'.backref'});
+
+
+my @names_pack=();
+if ($student_names=~/_END_/) {
+ @names_pack=split(/_ENDPERSON_/,$student_names);
+}
+if ($backref) {
+ print('
'.&mt("[_1]Return[_2] to editing resource.",
+ "","").'
');
+}
+my $figfile = $texfile;
+$figfile =~ s/^(.*_printout)_\d+_\d+_\d+\.tex/$1\.dat/;
+my $duefile = $texfile;
+$duefile =~ s/^(.*_printout)_\d+_\d+_\d+\.tex/$1\.due/;
+
+
+#-------------------------------------------------------------------------------------
+#
+# Each print may have associated with it a file that contains a set of figures
+# that need to be converted to .eps from whatever form they were in when included
+# in the resource. The name of the figure file is in $figfile. If it exists,
+# it contains the names of the files that need to be converted, one per line.
+#
+
+if (-e $figfile) {
+ # print "$figfile exists\n";
+ my %done_conversion;
+ my $temporary_file=IO::File->new($figfile) || die "Couldn't open fig file $figfile for reading: $!\n";
+ my @content_of_file = <$temporary_file>;
+ close $temporary_file;
+ my $noteps;
+ my %prog_state;
+ if ($advanced_role) { %prog_state=&Apache::lonhtmlcommon::Create_PrgWin('','Converting Images to EPS','Picture Conversion Status',$#content_of_file,'inline','80'); }
+ print('
');
+ foreach my $not_eps (@content_of_file) {
+ chomp($not_eps);
+ if ($not_eps ne '') {
+ $not_eps=~s|\/\.\/|\/|g;
+ if (!$done_conversion{$not_eps}) { # Only convert multiple includes once.
+ &convert_figure($not_eps);
+ $done_conversion{$not_eps} = 1;
+ }
+ }
+ }
+ if ($advanced_role) {
+ &Apache::lonhtmlcommon::Close_PrgWin('',\%prog_state);
+ }
+ unlink($figfile);
+}
+# End of figure conversion section:
+#
+#--------------------------------------------------------------------------------------------
+
- my $identifier = $ENV{'QUERY_STRING'};
- my $texfile = $env{'cgi.'.$identifier.'.file'};
- my $laystyle = $env{'cgi.'.$identifier.'.layout'};
- my $numberofcolumns = $env{'cgi.'.$identifier.'.numcol'};
- my $paper = $env{'cgi.'.$identifier.'.paper'};
- my $selectionmade = $env{'cgi.'.$identifier.'.selection'};
- my $tableofcontents = $env{'cgi.'.$identifier.'.tableofcontents'};
- my $tableofindex = $env{'cgi.'.$identifier.'.tableofindex'};
- my $advanced_role = $env{'cgi.'.$identifier.'.role'};
- my $number_of_files = $env{'cgi.'.$identifier.'.numberoffiles'}+1;
- my $student_names = $env{'cgi.'.$identifier.'.studentnames'};
- my $backref = &Apache::lonnet::unescape($env{'cgi.'.$identifier.'.backref'});
-
- my @names_pack=();
- if ($student_names=~/_END_/) {
- @names_pack=split(/_ENDPERSON_/,$student_names);
- }
- if ($backref) {
- print(''.&mt("[_1]Return[_2] to editing resource.",
- "","").'
');
- }
- my $figfile = $texfile;
- $figfile =~ s/^(.*_printout)_\d+_\d+_\d+\.tex/$1\.dat/;
- my $duefile = $texfile;
- $duefile =~ s/^(.*_printout)_\d+_\d+_\d+\.tex/$1\.due/;
- #do we have figures?
- # print "Figure file: $figfile\n";
- if (-e $figfile) {
- # print "$figfile exists\n";
- my %done_conversion;
- my $temporary_file=IO::File->new($figfile) || die "Couldn't open fig file $figfile for reading: $!\n";
- my @content_of_file = <$temporary_file>;
- close $temporary_file;
- my $noteps;
- my %prog_state;
- if ($advanced_role) { %prog_state=&Apache::lonhtmlcommon::Create_PrgWin('','Coverting Images to EPS','Picture Conversion Status',$#content_of_file,'inline','80'); }
- print('
');
- foreach my $not_eps (@content_of_file) {
- chomp($not_eps);
- if ($not_eps ne '') {
- # print "Converting $not_eps"; # Debugging.
- my $status_statement='EPS picture for '.$not_eps;
- # print "$status_statement\n";
- $not_eps=~s|\/\.\/|\/|g;
- my $eps_f = $not_eps;
- # $eps_f =~ s/\.[^.]*$/\.eps/i;
- if ($eps_f=~/\/home\/([^\/]+)\/public_html\//) {
- $eps_f=~s/\/home\/([^\/]+)\/public_html/$1/;
- $eps_f = $perlvar{'lonPrtDir'}.'/'.$eps_f;
- } elsif ($eps_f=~/$perlvar{'lonDocRoot'}\/res\//) {
- $eps_f=~m/$perlvar{'lonDocRoot'}\/res\/(.+)/;
- $eps_f = $perlvar{'lonPrtDir'}.'/'.$1;
- } elsif ($eps_f=~/$perlvar{'lonUsersDir'}\//) {
- $eps_f=~/$perlvar{'lonUsersDir'}\/([^\/]+)\/\w\/\w\/\w\/(.+)/;
- $eps_f = $perlvar{'lonPrtDir'}.'/'.$1.'/'.$2;
- }
- $eps_f =~ s/ /\_/g; # Spaces are problematic for system commands and LaTeX.
- #
- # If the file is already an .eps or .ps file,
- # We really just need to copy it from where it was to prtspool
- # but with the spaces substituted to _'s.
- #
- my ($nsname,$path, $sext) = &fileparse($eps_f, qr/\.(ps|eps)/i);
- if ($sext =~/ps$/i) {
- # print "$not_eps is a postscript file. copy to $path\n";
- &File::Path::mkpath($path,0,0777);
- #print("Made path: $path");
- #$not_eps =~ s/^\s+//;
- #$not_eps =~ s/\s+$//;
- #$not_eps =~ s/ /\__/g;
- #print("Copying $not_eps to $eps_f\n");
- copy("$not_eps", "$eps_f");
- # print "Copy complete\n";
- } else {
-
- $eps_f .= '.eps'; # Just append the eps ext.
- my $path=$eps_f;
- $path =~ s/\/([^\/]+)\.eps$//;
- # print "Final file path: $path "; # Debugging
- &File::Path::mkpath($path,0,0777);
- $not_eps =~ s/^\s+//;
- $not_eps =~ s/\s+$//;
- $not_eps =~ s/ /\\ /g;
- if ( exists($done_conversion{$not_eps})) { next; }
- if ($advanced_role) {
- my $prettyname=$not_eps;
- $prettyname=~s|/home/([^/]+)/public_html|/priv/$1|;
- $prettyname=~s|$perlvar{'lonDocRoot'}/|/|;
- &Apache::lonhtmlcommon::Update_PrgWin('',\%prog_state,
- 'Converting to EPS '.$prettyname);
- }
- $done_conversion{$not_eps}=1;
- # print "Converting $not_eps -> $eps_f"; # Debugging
- system("convert $not_eps $eps_f");
- # check is eps exist in prtspool
- if (not -e $eps_f) {
- # converting an animated gif creates either:
- # anim.gif.eps.0
- # or
- # anim.gif-0.eps
- for (my $i=0;$i<10000;$i++) {
- if (-e $eps_f.'.'.$i) {
- rename($eps_f.'.'.$i, $eps_f);
- last;
- }
- my $anim_eps = $eps_f;
- $anim_eps =~ s/(\.[^.]*)\.eps$/$1-$i\.eps/i;
- if (-e $anim_eps) {
- rename($anim_eps, $eps_f);
- last;
- }
- }
- }
-
- # imagemagick 6.2.0-6.2.7 fails to properly handle
- # convert anim.gif anim.gif.eps
- # it creates anim.eps instead.
- if (not -e $eps_f) {
- my $eps_f2 = $eps_f;
- $eps_f2 =~ s/\.[^.]*\.eps$/\.eps/i;
- if(-e $eps_f2) {
- rename($eps_f2,$eps_f);
- }
- }
- }
- }
- }
- if ($advanced_role) {
- &Apache::lonhtmlcommon::Close_PrgWin('',\%prog_state);
- }
- unlink($figfile);
- }
#print "$texfile\n"; #name of the tex file for debugging only
my @texfile=($texfile);
if ($number_of_files>1) {
@@ -376,17 +311,17 @@ foreach $texfile (@texfile) {
my $name_file = $2;
my $path_file = $1.'/';
chdir $path_file;
- my $dvi_file= $name_file; $dvi_file =~ s/\.tex/$name_range\.dvi/;
+ my $dvi_file= $name_file; $dvi_file =~ s/\.tex$/\.dvi/;
&busy_wait_command("latex $name_file 1>/dev/null 2>/dev/null",
"for $status_statement now LaTeXing file",
- \%prog_state,$dvi_file);
+ \%prog_state,$dvi_file, $busy_wait_timeout);
if ($tableofcontents eq 'yes') {
&busy_wait_command("latex $name_file 1>/dev/null 2>/dev/null",
"for $status_statement First LaTeX of file for table of contents",
- \%prog_state,$dvi_file);
+ \%prog_state,$dvi_file, $busy_wait_timeout);
&busy_wait_command("latex $name_file 1>/dev/null 2>/dev/null",
"for $status_statement Second LaTeX of file for table of contents",
- \%prog_state,$dvi_file);
+ \%prog_state,$dvi_file,$busy_wait_timeout);
} #to create table of contents
my $idxname=$name_file;
$idxname=~s/\.tex$/\.idx/;
@@ -396,7 +331,7 @@ foreach $texfile (@texfile) {
\%prog_state,$idxname);
&busy_wait_command("latex $name_file 1>/dev/null 2>/dev/null",
"for $status_statement now LaTeXing file for index section",
- \%prog_state,$dvi_file);
+ \%prog_state,$dvi_file, $busy_wait_timeout);
} #to create index
#Do we have a latex error in the log file?
my $logfilename = $texfile; $logfilename =~ s/\.tex$/\.log/;
@@ -448,7 +383,7 @@ foreach $texfile (@texfile) {
$logfilename=~s{^\Q$perlvar{'lonPrtDir'}\E}{/prtspool};
print "Your log file ";
print "\n";
- #link tooriginal LaTeX file (included according Michael Hamlin desire)
+ #link to original LaTeX file
my $tex_temporary_file=IO::File->new($texfile) || die "Couldn't open tex file $texfile for reading: $!\n";
my @tex_content_of_file = <$tex_temporary_file>;
close $tex_temporary_file;
@@ -512,14 +447,14 @@ foreach $texfile (@texfile) {
#
&busy_wait_command("latex $latex_file 1>/dev/null 2>/dev/null",
"for $status_statement first latex to repaginate",
- \%prog_state, $name_file);
+ \%prog_state, $name_file,$busy_wait_timeout);
if ($tableofcontents eq 'yes') {
&busy_wait_command("latex $latex_file 1>/dev/null 2>/dev/null",
"for $status_statement second latex to repaginate",
- \%prog_state, $name_file);
+ \%prog_state, $name_file,$busy_wait_timeout);
&busy_wait_command("latex $latex_file 1>/dev/null 2>/dev/null",
"for $status_statement third latex to repaginate",
- \%prog_state, $name_file);
+ \%prog_state, $name_file,$busy_wait_timeout);
}
if ($tableofindex eq 'yes') {
my $idxname = $latex_file;
@@ -529,7 +464,7 @@ foreach $texfile (@texfile) {
\%prog_state, $idxname);
&busy_wait_command("latex $latex_file 1>/dev/null 2>/dev/null",
"for $status_statement now Recreting index (latex)",
- \%prog_state, $dvi_file);
+ \%prog_state, $dvi_file,$busy_wait_timeout);
}
&busy_wait_command("$comma $name_file 1>/dev/null 2>/dev/null",
@@ -619,7 +554,7 @@ foreach $texfile (@texfile) {
$logfilename=~s{^\Q$perlvar{'lonPrtDir'}\E}{/prtspool};
print "Your log file ";
print "\n";
- #link tooriginal LaTeX file (included according Michael Hamlin desire)
+ #link to original LaTeX file
my $tex_temporary_file=IO::File->new($texfile) || die "Couldn't open tex file $texfile for reading: $!\n";
my @tex_content_of_file = <$tex_temporary_file>;
close $tex_temporary_file;
@@ -685,14 +620,14 @@ foreach $texfile (@texfile) {
&repaginate($new_name_file, $latex_file, $numberofcolumns);
&busy_wait_command("latex $latex_file 1>/dev/null 2>/dev/null",
"for $status_statement first latex to repaginate",
- \%prog_state, $name_file);
+ \%prog_state, $name_file, $busy_wait_timeout);
if ($tableofcontents eq 'yes') {
&busy_wait_command("latex $latex_file 1>/dev/null 2>/dev/null",
"for $status_statement second latex to repaginate",
- \%prog_state, $name_file);
+ \%prog_state, $name_file, $busy_wait_timeout);
&busy_wait_command("latex $latex_file 1>/dev/null 2>/dev/null",
"for $status_statement third latex to repaginate",
- \%prog_state, $name_file);
+ \%prog_state, $name_file, $busy_wait_timeout);
}
if ($tableofindex eq 'yes') {
my $idxname = $latex_file;
@@ -702,7 +637,7 @@ foreach $texfile (@texfile) {
\%prog_state, $idxname);
&busy_wait_command("latex $latex_file 1>/dev/null 2>/dev/null",
"for $status_statement now Recreting index (latex)",
- \%prog_state, $dvi_file);
+ \%prog_state, $dvi_file, $busy_wait_timeout);
}
&busy_wait_command("$comma $name_file 1>/dev/null 2>/dev/null",
"for $status_statement dvips to repaginate",
@@ -794,9 +729,17 @@ my $done;
sub REAPER {
$done=1;
}
-
+#
+# Execute a command updating the status window as the command's
+# output file builds up (at intervals of a second).
+#
+# If the timeout argument defined, then if that many seconds
+# elapses without an increase in the size of the output file,
+# the command will be killed (this deals with the case when
+# latex crawls into an infinite loop).
+#
sub busy_wait_command {
- my ($command,$message,$progress_win,$output_file)=@_;
+ my ($command,$message,$progress_win,$output_file, $timeout)=@_;
$SIG{CHLD} = \&REAPER;
$done=0;
@@ -804,12 +747,30 @@ sub busy_wait_command {
if ($advanced_role) {
&Apache::lonhtmlcommon::Update_PrgWin('',$progress_win,$message);
}
+ my $last_size = 0;
+ my $unchanged_time = 0;
while(!$done) {
sleep 1;
my $extra_msg;
if ($output_file) {
my $size=(stat($output_file))[7];
$extra_msg=", $size bytes generated";
+ if ($size == $last_size) {
+ $unchanged_time++;
+ if ($timeout && ($unchanged_time > $timeout)) {
+ print "Operation timed out!
\n";
+ print "Executing $command, the output file $output_file did not grow\n";
+ print "after $timeout seconds. This may indicate $command\n";
+ print "is in an infinite loop.\n";
+ print "See if printing fewer copies helps. Please contact LON-CAPA\n";
+ print "support about this in any event.";
+ print "
";
+ kill(9, $pid); # Reaper will do the rest...I hope there's errors in the log.
+ }
+ } else {
+ $last_size = $size;
+ $unchanged_time = 0;
+ }
}
if ($advanced_role) {
&Apache::lonhtmlcommon::Update_PrgWin('',$progress_win,
@@ -1006,3 +967,89 @@ sub create_missing_fonts {
}
}
+#
+# Convert a figure file to encapsulated postscript:
+# At present, this is using a lot of file scoped globals to pass data around.
+# Parameters:
+# not_eps - The name of the file to convert which, presumably, is not
+# already an eps file.
+#
+sub convert_figure {
+ my ($not_eps) = @_;
+
+ my $status_statement='EPS picture for '.$not_eps;
+ my $eps_f = $not_eps;
+
+ if ($eps_f=~/\/home\/([^\/]+)\/public_html\//) {
+ $eps_f=~s/\/home\/([^\/]+)\/public_html/$1/;
+ } elsif ($eps_f=~/$perlvar{'lonDocRoot'}\/res\//) {
+ $eps_f=~ s/$perlvar{'lonDocRoot'}\/res\/(.+)/$1/;
+ } elsif ($eps_f=~/$perlvar{'lonUsersDir'}\//) {
+ $eps_f=~ s/$perlvar{'lonUsersDir'}\/([^\/]+)\/\w\/\w\/\w\/(.+)/$1\/$2/;
+ }
+
+ $eps_f = $perlvar{'lonPrtDir'}.'/'.$eps_f;
+
+ # Spaces are problematic for system commands and LaTeX, replace with _
+
+ $eps_f =~ s/ /\_/g;
+
+ #
+ # If the file is already an .eps or .ps file (eps_f still has the original
+ # file type),
+ # We really just need to copy it from where it was to prtspool
+ # but with the spaces substituted to _'s.
+ #
+ my ($nsname,$path, $sext) = &fileparse($eps_f, qr/\.(ps|eps)/i);
+ if ($sext =~/ps$/i) {
+ &File::Path::mkpath($path,0,0777);
+ copy("$not_eps", "$eps_f");
+ } else {
+
+ $eps_f .= '.eps'; # Just append the eps ext.
+ my $path= &dirname($eps_f);
+ &File::Path::mkpath($path,0,0777);
+ $not_eps =~ s/^\s+//;
+ $not_eps =~ s/\s+$//;
+ $not_eps =~ s/ /\\ /g;
+ if ($advanced_role) {
+ my $prettyname=$not_eps;
+ $prettyname=~s|/home/([^/]+)/public_html|/priv/$1|;
+ $prettyname=~s|$perlvar{'lonDocRoot'}/|/|;
+ &Apache::lonhtmlcommon::Update_PrgWin('',\%prog_state,
+ 'Converting to EPS '.$prettyname);
+ }
+ system("convert $not_eps $eps_f");
+
+ if (not -e $eps_f) {
+ # converting an animated gif creates either:
+ # anim.gif.eps.0
+ # or
+ # anim.gif-0.eps
+ for (my $i=0;$i<10000;$i++) {
+ if (-e $eps_f.'.'.$i) {
+ rename($eps_f.'.'.$i, $eps_f);
+ last;
+ }
+ my $anim_eps = $eps_f;
+ $anim_eps =~ s/(\.[^.]*)\.eps$/$1-$i\.eps/i;
+ if (-e $anim_eps) {
+ rename($anim_eps, $eps_f);
+ last;
+ }
+ }
+ }
+
+ # imagemagick 6.2.0-6.2.7 fails to properly handle
+ # convert anim.gif anim.gif.eps
+ # it creates anim.eps instead.
+ if (not -e $eps_f) {
+ my $eps_f2 = $eps_f;
+ $eps_f2 =~ s/\.[^.]*\.eps$/\.eps/i;
+ if(-e $eps_f2) {
+ rename($eps_f2,$eps_f);
+ }
+ }
+ }
+
+}