--- loncom/interface/printout.pl 2008/03/10 22:42:28 1.131
+++ loncom/interface/printout.pl 2008/08/27 01:38:10 1.137
@@ -1,7 +1,7 @@
#!/usr/bin/perl
# CGI-script to run LaTeX, dvips, ps2ps, ps2pdf etc.
#
-# $Id: printout.pl,v 1.131 2008/03/10 22:42:28 www Exp $
+# $Id: printout.pl,v 1.137 2008/08/27 01:38:10 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -43,7 +43,12 @@ use LONCAPA::Configuration;
use strict;
-my $busy_wait_timeout = 300;
+my $busy_wait_timeout = 30;
+
+sub debug {
+ my ($text) = @_;
+ print "$text
\n";
+}
# Determine if a user is operating as a student for this course/domain.
#Parameters:
@@ -165,170 +170,128 @@ 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 $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/; - - 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(''.$body_log_file.''."\n"; - if ($body_log_file=~m/!\s+Emergency stop/) { - my $whereitbegins = rindex $body_log_file,'STAMPOFPASSEDRESOURCESTART'; - my $whereitends = rindex $body_log_file,'STAMPOFPASSEDRESOURCEEND'; - my $badresource; - my $badtext; - if ($whereitbegins!=-1 and $whereitends!=-1) { - $badtext = substr($body_log_file,$whereitbegins+26, $whereitends-$whereitbegins-26); - $whereitbegins = rindex $badtext,'located in'; - if ($whereitbegins != -1) { - - $badresource = substr($badtext, $whereitbegins+27, - length($badtext) - $whereitbegins - 48); - # print "
"; - - my $sygnal = 0; - for (my $i=0;$i<=$#content_of_file;$i++) { - if ($content_of_file[$i]=~m/^Runaway argument?/ or $content_of_file[$i]=~m/^!/) { - $sygnal = 1; - } - if ($content_of_file[$i]=~m/Here is how much of/) { - $sygnal = 0; - } - if ($sygnal) { - print "$content_of_file[$i]"; - } - } - print "\n"; - # print "
'.$body_tex_file.''."\n"; - print "
'.$body_tex_file.''."\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"; @@ -847,6 +590,66 @@ sub busy_wait_command { close(CMD); } +# Make the dvi file (or rather try to), from the latex file and the +# various bits and pieces that control how the latex file is processed: +# LaTeX is run as many times a needed to make this all happen... this may +# result in several runs of LaTeX that just are errors if the LaTeX is +# bad, but the printing subsystem is _supposed_ to not do that. +# +# Parameters: +# name_file - Name of the LaTeX file to process. +# dvi_file - Name of resulting dvi file. +# tableofcontents - "yes" if we are supposed to make a table of contents. +# tableofindex - "yes" if we are suposed to make an index. +# status_statement - Part of the status statement for ths status window. +# prog_state - Reference to the program state hash. +# busy_wait_timeout- Seconds without any progress that imply a problem. +# +# +sub make_dvi_file { + my ($name_file, + $dvi_file, + $tableofcontents, + $tableofindex, + $status_statement, + $prog_state, + $busy_wait_timeout) = @_; + + + &busy_wait_command("latex $name_file 1>/dev/null 2>/dev/null", + "for $status_statement now LaTeXing file", + $prog_state,$dvi_file, $busy_wait_timeout); + + # If the tableof contents was requested, we need to run + # LaTex a couple more times to get all the references sorted out. + + 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, $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,$busy_wait_timeout); + } + + # And makeindex and another run of LaTeX to incorporate it if the index + # is enabled. + + + if ($tableofindex eq 'yes') { + my $idxname=$name_file; + $idxname=~s/\.tex$/\.idx/; + &busy_wait_command("makeindex $idxname", + "making index file", + $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, $busy_wait_timeout); + } + +} + + # Repagninate # What we need to do: # - Count the number of pages in each student. @@ -1033,3 +836,258 @@ 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); + } + } + } + +} +# +# Analyze a LaTeX logfile producing appropriate output on error and +# returning a boolean to let the caller know if, in our opinion, it's +# worth continuing on to produce the PDF file. +# +# Parameters: +# logfilename - Name of the logfile. +# texfile - Name of the LaTeX file that was being processed. +# advanced_role - True if the user is privileged with respect to the printout +# (e.g. is the course coordinator or some such thing). +# Returns: +# 1 - Caller is advised to continue to create the PDF. +# 0 - Caller need not bother creating the PDF. +# Side Effects: +# Messages are printed to describe any errors that have been encountered. +# NOTE: +# The current policy is to assume that if LaTeX decided to insert some text +# it has salvaged the resource and the resource can be printed.. in that case +# a message is emitted from this sub. +# +sub analyze_logfile { + my ($logfilename, $texfile, $advanced_role) = @_; + + my $temporary_file=IO::File->new($logfilename) || die "Couldn't open log file $logfilename for reading: $!\n"; + my @content_of_file = <$temporary_file>; + close $temporary_file; + my $body_log_file = join(' ',@content_of_file); + $logfilename =~ s/\.log$/\.html/; + $temporary_file = IO::File->new('>'.$logfilename); + print $temporary_file '
'.$body_log_file.''."\n"; + if ($body_log_file=~m/!\s+Emergency stop/) { + my $whereitbegins = rindex $body_log_file,'STAMPOFPASSEDRESOURCESTART'; + my $whereitends = rindex $body_log_file,'STAMPOFPASSEDRESOURCEEND'; + my $badresource; + my $badtext; + if ($whereitbegins!=-1 and $whereitends!=-1) { + $badtext = substr($body_log_file,$whereitbegins+26, $whereitends-$whereitbegins-26); + $whereitbegins = rindex $badtext,'located in'; + if ($whereitbegins != -1) { + + $badresource = substr($badtext, $whereitbegins+27, + length($badtext) - $whereitbegins - 48); + # print "
"; + + my $sygnal = 0; + for (my $i=0;$i<=$#content_of_file;$i++) { + if ($content_of_file[$i]=~m/^Runaway argument?/ or $content_of_file[$i]=~m/^!/) { + $sygnal = 1; + } + if ($content_of_file[$i]=~m/Here is how much of/) { + $sygnal = 0; + } + if ($sygnal) { + print "$content_of_file[$i]"; + } + } + print "\n"; + # print "
'.$body_tex_file.''."\n"; + print "
" + .&mt('A message has been sent to the instructor describing this failure.') + ."
"; + my $help_text = &Apache::loncommon::help_open_topic("Print_Resource", &mt('Help on printing')); + print ("$help_text"); + + } + + # Either way, an emergency stop does not allow us to continue so: + + return 0; + + # The branch of code below is taken if it appears that + # there was no emergency stop but LaTeX had to correct the + # input file to run. + # In that case we need to provide error feedback, as the correction >may< not be + # sufficient, we can let the game continue as there's a dvi file to process. + + } elsif ($body_log_file=~m/'.$body_tex_file.''."\n"; + print "