[system] / trunk / pg / macros / dangerousMacros.pl Repository:
ViewVC logotype

View of /trunk/pg/macros/dangerousMacros.pl

Parent Directory Parent Directory | Revision Log Revision Log


Revision 5663 - (download) (as text) (annotate)
Thu May 8 00:37:31 2008 UTC (11 years, 9 months ago) by sh002i
File size: 54638 byte(s)
add "my" and "our" specifiers to ^variable definitions. (This breaks
compatibility with the current version of ww-symbol-map, but it is the
format that the upcoming version will use. I hope to commit that new
version soon but testing is taking longer than expected.)

    1 ################################################################################
    2 # WeBWorK Online Homework Delivery System
    3 # Copyright  2000-2007 The WeBWorK Project, http://openwebwork.sf.net/
    4 # $CVSHeader: pg/macros/dangerousMacros.pl,v 1.51 2008/05/03 17:43:29 sh002i Exp $
    5 #
    6 # This program is free software; you can redistribute it and/or modify it under
    7 # the terms of either: (a) the GNU General Public License as published by the
    8 # Free Software Foundation; either version 2, or (at your option) any later
    9 # version, or (b) the "Artistic License" which comes with this package.
   10 #
   11 # This program is distributed in the hope that it will be useful, but WITHOUT
   12 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   13 # FOR A PARTICULAR PURPOSE.  See either the GNU General Public License or the
   14 # Artistic License for more details.
   15 ################################################################################
   16 
   17 =head1 NAME
   18 
   19 dangerousMacros.pl - Macros which require elevated permissions to execute.
   20 
   21 =head1 SYNPOSIS
   22 
   23   loadMacros(macrofile1,macrofile2,...)
   24 
   25   insertGraph(graphObject); # returns a path to the file containing the graph image.
   26 
   27   tth(texString); # returns an HTML version of the tex code passed to it.
   28 
   29   alias(pathToFile); # returns URL which links to that file
   30 
   31 =head1 DESCRIPTION
   32 
   33 dangerousMacros.pl contains macros that use potentially dangerous functions like
   34 require and eval. They can reference disk files for reading and writing, create
   35 links, and execute commands. It may be necessary to modify certain addresses in
   36 this file to make the scripts run properly in different environments.
   37 
   38 This file is loaded implicitly every time a new problem is rendered.
   39 
   40 =for comment
   41 
   42 FIXME this information belongs in global.conf where modules to load are listed.
   43 I don't see why this shows up here.
   44 
   45 =head2 Sharing modules
   46 
   47 Most modules are loaded by dangerousMacros.pl
   48 
   49 The modules must be loaded using require (not use) since the
   50 courseScriptsDirectory is defined at run time.
   51 
   52 The following considerations come into play.
   53 
   54 =over
   55 
   56 =item *
   57 
   58 One needs to limit the access to modules for safety -- hence only modules in the
   59 F<courseScriptsDirectory> can be loaded.
   60 
   61 =item *
   62 
   63 Loading them in dangerousMacros.pl is wasteful, since the modules would need to
   64 be reloaded everytime a new safe compartment is created. (I believe that using
   65 require takes care of this.)
   66 
   67 =item *
   68 
   69 Loading GD within a safeCompartment creates infinite recurrsion in AUTOLOAD
   70 (probably a bug) hence this module is loaded by translate.pl and then shared
   71 with the safe compartment.
   72 
   73 =item *
   74 
   75 Other modules loaded by translate.pl are C<Exporter> and C<DynaLoader>.
   76 
   77 =item *
   78 
   79 PGrandom is loaded by F<PG.pl>, since it is needed there.
   80 
   81 =back
   82 
   83 The module name spaces loaded in dangerousMacros are:
   84 
   85   PGrandom (if not previously loaded)
   86   WWPlot
   87   Fun
   88   Label
   89   Circle
   90 
   91 in addition the subroutine &evaluate_units is shared from the module Units.
   92 
   93 =cut
   94 
   95 BEGIN {
   96   be_strict(); # an alias for use strict.  This means that all global variable must contain main:: as a prefix.
   97 
   98 }
   99 
  100 # ^variable my $debugON
  101 my $debugON = 0;
  102 
  103 # grab read only variables from the current safe compartment
  104 
  105 # ^variable my $macrosPath
  106 my ($macrosPath,
  107     # ^variable my $pwd
  108     $pwd,
  109     # ^variable my $appletPath
  110     $appletPath,
  111     # ^variable my $server_root_url
  112     $server_root_url,
  113   # ^variable my $templateDirectory
  114   $templateDirectory,
  115   # ^variable my $scriptDirectory
  116   $scriptDirectory,
  117   # ^variable my $externalTTHPath
  118   $externalTTHPath,
  119   );
  120 
  121 # ^function _dangerousMacros_init
  122 # ^uses %envir
  123 # ^uses $macrosPath
  124 # ^uses $pwd
  125 # ^uses $appletPath
  126 # ^uses $server_root_url
  127 # ^uses $templateDirectory
  128 # ^uses $scriptDirectory
  129 # ^uses $externalTTHPath
  130 # ^uses $debugON
  131 sub _dangerousMacros_init {   #use  envir instead of local variables?
  132     # will allow easy addition of new directories -- is this too liberal? do some pg directories need to be protected?
  133     $macrosPath               = eval('$main::envir{pgDirectories}{macrosPath}');
  134     # will allow easy addition of new directories -- is this too liberal? do some pg directories need to be protected?
  135     $pwd                      = eval('$main::envir{fileName}'); $pwd =~ s!/[^/]*$!!;
  136     $appletPath               = eval('$main::envir{pgDirectories}{appletPath}');
  137     $server_root_url          = eval('$main::envir{server_root_url}');
  138 
  139     $templateDirectory        = eval('$main::envir{templateDirectory}');
  140     $scriptDirectory          = eval('$main::envir{scriptDirectory}');
  141     $externalTTHPath          = eval('$main::envir{externalTTHPath}');
  142     $pwd = $templateDirectory.$pwd unless substr($pwd,0,1) eq '/';
  143     $pwd =~ s!/tmpEdit/!/!;
  144     warn "dangerousmacros initialized" if $debugON;
  145     warn eval(q! "dangerousmacros.pl externalTTHPath is ".$main::externalTTHPath;!) if $debugON;
  146     warn eval(q! "dangerousmacros.pl:  The envir variable $main::{envir} is".join(" ",%main::envir)!) if $debugON;
  147 }
  148 
  149 # ^function _dangerousMacros_export
  150 sub _dangerousMacros_export {
  151   my @EXPORT= (
  152       '&_dangerousMacros_init',
  153     '&alias',
  154     '&compile_file',
  155     '&insertGraph',
  156     '&loadMacros',
  157     '&HEADER_TEXT',
  158     '&sourceAlias',
  159     '&tth',
  160   );
  161   @EXPORT;
  162 }
  163 
  164 
  165 =head2 loadMacros
  166 
  167   loadMacros(@macroFiles)
  168 
  169 loadMacros takes a list of file names and evaluates the contents of each file.
  170 This is used to load macros which define and augment the PG language. The macro
  171 files are searched for in the directories specified by the array referenced by
  172 $macrosPath, which by default is the current course's macros directory followed
  173 by WeBWorK's pg/macros directory. The latter is where the default behaviour of
  174 the PG language is defined. The default path is set in the global.conf file.
  175 
  176 Macro files named PG.pl, IO.pl, or dangerousMacros.pl will be loaded with no
  177 opcode restrictions, hence any code in those files will be able to execute
  178 privileged operations. This is true no matter which macro directory the file is
  179 in. For example, if $macrosPath contains the path to a problem library macros
  180 directory which contains a PG.pl file, this file will be loaded and allowed to
  181 engage in privileged behavior.
  182 
  183 =head3 Overloading macro files
  184 
  185 An individual course can modify the PG language, for that course only, by
  186 duplicating one of the macro files in the system-wide macros directory and
  187 placing this file in the macros directory for the course. The new file in the
  188 course's macros directory will now be used instead of the file in the
  189 system-wide macros directory.
  190 
  191 The new file in the course macros directory can by modified by adding macros or
  192 modifying existing macros.
  193 
  194 =head3 Modifying existing macros
  195 
  196 I<Modifying macros is for users with some experience.>
  197 
  198 Modifying existing macros might break other standard macros or problems which
  199 depend on the unmodified behavior of these macors so do this with great caution.
  200 In addition problems which use new macros defined in these files or which depend
  201 on the modified behavior of existing macros will not work in other courses
  202 unless the macros are also transferred to the new course.  It helps to document
  203 the  problems by indicating any special macros which the problems require.
  204 
  205 There is no facility for modifying or overloading a single macro. The entire
  206 file containing the macro must be overloaded.
  207 
  208 Modifications to files in the course macros directory affect only that course,
  209 they will not interfere with the normal behavior of WeBWorK in other courses.
  210 
  211 =cut
  212 
  213 # Global variables used
  214 #   ${main::macrosPath}
  215 # Global macros used
  216 # None
  217 
  218 # Because of the need to use the directory variables it is tricky to define this
  219 # in translate.pl since, as currently written, the directories are not available
  220 # at that time.  Perhaps if I rewrite translate as an object that method will work.
  221 
  222 # The only difficulty with defining loadMacros inside the Safe compartment is that
  223 # the error reporting does not work with syntax errors.
  224 # A kludge using require works around this problem
  225 
  226 
  227 # ^function loadMacros
  228 # ^uses time_it
  229 # ^uses $debugON
  230 # ^uses $externalTTHPath
  231 # ^uses findMacroFile
  232 sub loadMacros {
  233     my @files = @_;
  234     my $fileName;
  235     eval {main::time_it("begin load macros");};
  236     ###############################################################################
  237   # At this point the directories have been defined from %envir and we can define
  238   # the directories for this file
  239   ###############################################################################
  240 
  241   # special case inits
  242   foreach my $file ('PG.pl','dangerousMacros.pl','IO.pl') {
  243       my $macro_file_name = $file;
  244     $macro_file_name =~s/\.pl//;  # trim off the extension
  245     $macro_file_name =~s/\.pg//;  # sometimes the extension is .pg (e.g. CAPA files)
  246     my $init_subroutine_name = "_${macro_file_name}_init";
  247       my $init_subroutine  = eval { \&{$init_subroutine_name} };
  248     use strict;
  249         my $macro_file_loaded = defined($init_subroutine);
  250         warn "dangerousMacros: macro init $init_subroutine_name defined |$init_subroutine| |$macro_file_loaded|" if $debugON;
  251     if ( defined($init_subroutine) && defined( &{$init_subroutine} ) ) {
  252 
  253         warn "dangerousMacros:  initializing $macro_file_name"  if $debugON;
  254         &$init_subroutine();
  255     }
  256   }
  257     unless (defined( $externalTTHPath)){
  258       warn "WARNING::Please make sure that the DOCUMENT() statement comes before<BR>\n" .
  259            " the loadMacros() statement in the problem template.<p>" .
  260            " The externalTTHPath variable |$externalTTHPath| was\n".
  261            " not defined which usually indicates the problem above.<br>\n";
  262 
  263     }
  264     #warn "running load macros";
  265     while (@files) {
  266         $fileName = shift @files;
  267         next  if ($fileName =~ /^PG.pl$/) ;    # the PG.pl macro package is already loaded.
  268 
  269         my $macro_file_name = $fileName;
  270     $macro_file_name =~s/\.pl//;  # trim off the extension
  271     $macro_file_name =~s/\.pg//;  # sometimes the extension is .pg (e.g. CAPA files)
  272     my $init_subroutine_name = "_${macro_file_name}_init";
  273     $init_subroutine_name =~ s![^a-zA-Z0-9_]!_!g;  # remove dangerous chars
  274 
  275     ###############################################################################
  276     # For some reason the "no stict" which works on webwork-db doesn't work on
  277     # webwork.  For this reason the constuction &{$init_subroutine_name}
  278     # was abandoned and replaced by eval.  This is considerably more dangerous
  279     # since one could hide something nasty in a file name.
  280     #  Keep an eye on this ???
  281     # webwork-db used perl 5.6.1 and webwork used perl 5.6.0
  282     ###############################################################################
  283 
  284     # compile initialization subroutine. (5.6.0 version)
  285 
  286 
  287 #   eval( q{ \$init_subroutine = \\&main::}.$init_subroutine_name);
  288 #   warn "dangerousMacros: failed to compile $init_subroutine_name. $@" if $@;
  289 
  290 
  291     ###############################################################################
  292     #compile initialization subroutine. (5.6.1 version) also works with 5.6.0
  293 
  294 #     no strict;
  295     my $init_subroutine  = eval { \&{'main::'.$init_subroutine_name} };
  296 #     use strict;
  297 
  298     ###############################################################################
  299 
  300         # macros are searched for in the directories listed in the $macrosPath array reference.
  301 
  302         my $macro_file_loaded = defined($init_subroutine) && defined(&$init_subroutine);
  303         warn "dangerousMacros: macro init $init_subroutine_name defined |$init_subroutine| |$macro_file_loaded|"  if $debugON;
  304         unless ($macro_file_loaded) {
  305           warn "loadMacros: loading macro file $fileName\n" if $debugON;
  306     my $filePath = findMacroFile($fileName);
  307     #### (check for renamed files here?) ####
  308     if ($filePath) {compile_file($filePath)}
  309     else {
  310       die "Can't locate macro file |$fileName| via path: |".join("|, |",@{$macrosPath})."|";
  311     }
  312     }
  313     ###############################################################################
  314     # Try again to define the initialization subroutine. (5.6.0 version)
  315 
  316 #   eval( q{ \$init_subroutine = \\&main::}.$init_subroutine_name );
  317 #   warn "dangerousMacros: failed to compile $init_subroutine_name. $@" if $@;
  318 #   $init_subroutine = $temp::rf_init_subroutine;
  319     ###############################################################################
  320     # Try again to define the initialization subroutine. (5.6.1 version) also works with 5.6.0
  321 
  322 #     no strict;
  323     $init_subroutine  = eval { \&{'main::'.$init_subroutine_name} };
  324 #     use strict;
  325     ###############################################################################
  326     #warn "loadMacros: defining \$temp::rf_init_subroutine ",$temp::rf_init_subroutine;
  327        $macro_file_loaded = defined($init_subroutine) && defined(&$init_subroutine);
  328        warn "dangerousMacros: macro init $init_subroutine_name defined |$init_subroutine| |$macro_file_loaded|" if $debugON;
  329 
  330     if ( defined($init_subroutine) && defined( &{$init_subroutine} ) ) {
  331         warn "dangerousMacros:  initializing $macro_file_name" if $debugON;
  332         &$init_subroutine();
  333     }
  334     #warn "main:: contains <br>\n $macro_file_name ".join("<br>\n $macro_file_name ", %main::);
  335   }
  336   eval{main::time_it("end load macros");};
  337 }
  338 
  339 #
  340 #  Look for a macro file in the directories specified in the macros path
  341 #
  342 
  343 # ^function findMacroFile
  344 # ^uses $macrosPath
  345 # ^uses $pwd
  346 sub findMacroFile {
  347   my $fileName = shift;
  348   my $filePath;
  349   foreach my $dir (@{$macrosPath}) {
  350     $filePath = "$dir/$fileName";
  351     $filePath =~ s!^\.\.?/!$pwd/!;
  352     return $filePath if (-r $filePath);
  353   }
  354   return;  # no file found
  355 }
  356 
  357 # ^function check_url
  358 # ^uses %envir
  359 sub check_url {
  360   my $url  = shift;
  361   return undef if $url =~ /;/;   # make sure we can't get a second command in the url
  362   #FIXME -- check for other exploits of the system call
  363   #FIXME -- ALARM feature so that the response cannot be held up for too long.
  364   #FIXME doesn't seem to work with relative addresses.
  365   #FIXME  Can we get the machine name of the server?
  366 
  367    my $check_url_command = $envir{externalCheckUrl};
  368    my $response = system("$check_url_command $url");
  369   return ($response) ? 0 : 1; # 0 indicates success, 256 is failure possibly more checks can be made
  370 }
  371 
  372 # ^variable our %appletCodebaseLocations
  373 our %appletCodebaseLocations = ();
  374 # ^function findAppletCodebase
  375 # ^uses %appletCodebaseLocations
  376 # ^uses $appletPath
  377 # ^uses $server_root_url
  378 # ^uses check_url
  379 sub findAppletCodebase {
  380   my $fileName = shift;  # probably the name of a jar file
  381   return $appletCodebaseLocations{$fileName}    #check cache first
  382     if defined($appletCodebaseLocations{$fileName})
  383       and $appletCodebaseLocations{$fileName} =~/\S/;
  384 
  385   foreach my $appletLocation (@{$appletPath}) {
  386     if ($appletLocation =~ m|^/|) {
  387       $appletLocation = "$server_root_url$appletLocation";
  388     }
  389     my $url = "$appletLocation/$fileName";
  390     if (check_url($url)) {
  391         $appletCodebaseLocations{$fileName} = $appletLocation; #update cache
  392       return $appletLocation   # return codebase part of url
  393     }
  394   }
  395   return "Error: $fileName not found at ". join(",  ", @{$appletPath} );  # no file found
  396 }
  397 # errors in compiling macros is not always being reported.
  398 # ^function compile_file
  399 # ^uses @__eval__
  400 # ^uses PG_restricted_eval
  401 # ^uses $__files__
  402 sub compile_file {
  403   my $filePath = shift;
  404   warn "loading $filePath" if $debugON;
  405   local(*MACROFILE);
  406   local($/);
  407   $/ = undef;   # allows us to treat the file as a single line
  408   open(MACROFILE, "<$filePath") || die "Cannot open file: $filePath";
  409   my $string = 'BEGIN {push @__eval__, __FILE__};' . "\n" . <MACROFILE>;
  410   my ($result,$error,$fullerror) = &PG_restricted_eval($string);
  411   eval ('$main::__files__->{pop @main::__eval__} = $filePath');
  412   if ($error) {    # the $fullerror report has formatting and is never empty
  413                 # this is now handled by PG_errorMessage() in the PG translator
  414     #$fullerror =~ s/\(eval \d+\)/ $filePath\n/;   # attempt to insert file name instead of eval number
  415     die "Error detected while loading $filePath:\n$fullerror";
  416 
  417   }
  418 
  419   close(MACROFILE);
  420 
  421 }
  422 
  423 # This creates on the fly graphs
  424 
  425 =head2 insertGraph
  426 
  427   # returns a path to the file containing the graph image.
  428   $filePath = insertGraph($graphObject);
  429 
  430 insertGraph writes a GIF or PNG image file to the gif subdirectory of the
  431 current course's HTML temp directory. The file name is obtained from the graph
  432 object. Warnings are issued if errors occur while writing to the file.
  433 
  434 Returns a string containing the full path to the temporary file containing the
  435 image. This is most often used in the construct
  436 
  437   TEXT(alias(insertGraph($graph)));
  438 
  439 where alias converts the directory address to a URL when serving HTML pages and
  440 insures that an EPS file is generated when creating TeX code for downloading.
  441 
  442 =cut
  443 
  444 # ^function insertGraph
  445 # ^uses $WWPlot::use_png
  446 # ^uses convertPath
  447 # ^uses surePathToTmpFile
  448 # ^uses PG_restricted_eval
  449 # ^uses $refreshCachedImages
  450 # ^uses $templateDirectory
  451 # ^uses %envir
  452 sub insertGraph {
  453         # Convert the image to GIF and print it on standard output
  454   my $graph = shift;
  455   my $extension = ($WWPlot::use_png) ? '.png' : '.gif';
  456   my $fileName = $graph->imageName  . $extension;
  457   my $filePath = convertPath("gif/$fileName");
  458   $filePath = &surePathToTmpFile( $filePath );
  459   my $refreshCachedImages = PG_restricted_eval(q!$refreshCachedImages!);
  460   # Check to see if we already have this graph, or if we have to make it
  461   if( not -e $filePath # does it exist?
  462     or ((stat "$templateDirectory"."$main::envir{fileName}")[9] > (stat $filePath)[9]) # source has changed
  463     or $graph->imageName =~ /Undefined_Set/ # problems from SetMaker and its ilk should always be redone
  464     or $refreshCachedImages
  465   ) {
  466     #createFile($filePath, $main::tmp_file_permission, $main::numericalGroupID);
  467     local(*OUTPUT);  # create local file handle so it won't overwrite other open files.
  468     open(OUTPUT, ">$filePath")||warn ("$0","Can't open $filePath<BR>","");
  469     chmod( 0777, $filePath);
  470     print OUTPUT $graph->draw|| warn("$0","Can't print graph to $filePath<BR>","");
  471     close(OUTPUT)||warn("$0","Can't close $filePath<BR>","");
  472   }
  473   $filePath;
  474 }
  475 
  476 =head2 [DEPRECATED] tth
  477 
  478   # returns an HTML version of the TeX code passed to it.
  479   tth($texString);
  480 
  481 This macro sends $texString to the filter program TtH, a TeX to HTML translator
  482 written by Ian Hutchinson. TtH is available free of change non-commerical
  483 use at L<http://hutchinson.belmont.ma.us/tth/>.
  484 
  485 The purpose of TtH is to translate text in the TeX or LaTeX markup language into
  486 HTML markup as best as possible.  Some symbols, such as square root symbols are
  487 not translated completely.  Macintosh users must use the "MacRoman" encoding
  488 (available in 4.0 and higher browsers) in order to view the symbols correctly.
  489 WeBWorK attempts to force Macintosh browsers to use this encoding when such a
  490 browser is detected.
  491 
  492 The contents of the file F<tthPreamble.tex> in the courses template directory
  493 are prepended to each string.  This allows one to define TeX macros which can be
  494 used in every problem. Currently there is no default F<tthPreamble.tex> file, so
  495 if the file is not present in the course template directory no TeX macro
  496 definitions are prepended. TtH already understands most LaTeX commands, but will
  497 not in general know AMS-LaTeX commands.
  498 
  499 This macro contains code which is system dependent and may need to be modified
  500 to run on different systems.
  501 
  502 =cut
  503 
  504 # the contents of this file will not change during problem compilation it
  505 # only needs to be read once. however, the contents of the file may change,
  506 # and indeed the file refered to may change, between rendering passes. thus,
  507 # we need to keep track of the file name and the mtime as well.
  508 # ^variable my $tthPreambleFile
  509 # ^variable my $tthPreambleMtime
  510 # ^variable my $tthPreambleContents
  511 my ($tthPreambleFile, $tthPreambleMtime, $tthPreambleContents);
  512 
  513 # ^function tth
  514 # ^uses $templateDirectory
  515 # ^uses $envir{externalTTHPath}
  516 # ^uses $tthPreambleFile
  517 # ^uses $tthPreambleMtime
  518 # ^uses $tthPreambleContents
  519 sub tth {
  520   my $inputString = shift;
  521 
  522   my $thisFile = "${templateDirectory}tthPreamble.tex" if -r "${templateDirectory}tthPreamble.tex";
  523 
  524   if (defined $thisFile) {
  525     my $thisMtime = (stat $thisFile)[9];
  526     my $load =
  527       # load preamble if we haven't loaded it ever
  528       (not defined $tthPreambleFile or not defined $tthPreambleMtime or not defined $tthPreambleContents)
  529         ||
  530       # load if the file path has changed
  531       ($tthPreambleFile ne $thisFile)
  532         ||
  533       # load if the file has been modified
  534       ($tthPreambleMtime < $thisMtime);
  535 
  536     if ($load) {
  537       local(*TTHIN);
  538       open (TTHIN, "${templateDirectory}tthPreamble.tex") || die "Can't open file ${templateDirectory}tthPreamble.tex";
  539       local($/);
  540       $/ = undef;
  541       $tthPreambleContents = <TTHIN>;
  542       close(TTHIN);
  543 
  544       $tthPreambleContents =~ s/(.)\n/$1%\n/g;  # thanks to Jim Martino
  545                                                 # each line in the definition file
  546                                                 # should end with a % to prevent
  547                                                 # adding supurious paragraphs to output.
  548 
  549       $tthPreambleContents .="%\n";             # solves the problem if the file doesn't end with a return.
  550     }
  551   } else {
  552     $tthPreambleContents = "";
  553   }
  554 
  555     $inputString = $tthPreambleContents . $inputString;
  556     $inputString    = "<<END_OF_TTH_INPUT_STRING;\n\n\n" . $inputString . "\nEND_OF_TTH_INPUT_STRING\necho \"\" >/dev/null"; #it's not clear why another command is needed.
  557 
  558   # $tthpath is now taken from $Global::externalTTHPath via %envir.
  559     my $tthpath     = $envir{externalTTHPath};
  560     my $out;
  561 
  562     if (-x $tthpath ) {
  563       my $tthcmd      = "$tthpath -L -f5 -u -r  2>/dev/null " . $inputString;
  564       if (open(TTH, "$tthcmd   |")) {
  565           local($/);
  566       $/ = undef;
  567       $out = <TTH>;
  568       $/ = "\n";
  569       close(TTH);
  570       }else {
  571           $out = "<BR>there has been an error in executing $tthcmd<BR>";
  572       }
  573   } else {
  574     $out = "<BR> Can't execute the program tth at |$tthpath|<BR>";
  575     }
  576 
  577     $out;
  578 }
  579 
  580 # possible solution to the tth font problem?  Works only for iCab.
  581 # ^function symbolConvert
  582 sub symbolConvert {
  583   my  $string = shift;
  584   $string =~ s/\x5C/\&#092;/g;    #\      92                       &#092;
  585   $string =~ s/\x7B/\&#123;/g;    #{      123                       &#123;
  586   $string =~ s/\x7D/\&#125;/g;    #}      125                       &#125;
  587   $string =~ s/\xE7/\&#193;/g;    #      231                       &#193;
  588   $string =~ s/\xE6/\&#202;/g;    #      230                       &#202;
  589   $string =~ s/\xE8/\&#203;/g;    #      232                       &#203;
  590   $string =~ s/\xF3/\&#219;/g;    #      243                       &#219;
  591   $string =~ s/\xA5/\&bull;/g;    #      165                       &bull;
  592   $string =~ s/\xB2/\&le;/g;      #      178                       &le;
  593   $string =~ s/\xB3/\&ge;/g;      #      179                       &ge;
  594   $string =~ s/\xB6/\&part;/g;    #      182                       &part;
  595   $string =~ s/\xCE/\&#338;/g;    #      206                       &#338;
  596   $string =~ s/\xD6/\&#732/g;     #      214                       &#732;
  597   $string =~ s/\xD9/\&Yuml;/g;    #      217                       &Yuml;
  598   $string =~ s/\xDA/\&frasl;/g;   #      218                       &frasl;
  599   $string =~ s/\xF5/\&#305;/g;    #      245                       &#305
  600   $string =~ s/\xF6/\&#710;/g;    #      246                       &#710;
  601   $string =~ s/\xF7/\&#193;/g;    #      247                       &#193;
  602   $string =~ s/\xF8/\&#175;/g;    #      248                       &#175;
  603   $string =~ s/\xF9/\&#728;/g;    #      249                       &#728;
  604   $string =~ s/\xFA/\&#729;/g;    #      250                       &#729;
  605   $string =~ s/\xFB/\&#730;;/g;   #      251                       &#730;
  606   $string;
  607 }
  608 
  609 # ----- ----- ----- -----
  610 
  611 =head2 [DEPRECATED] math2img
  612 
  613   # returns an IMG tag pointing to an image version of the supplied TeX
  614   math2img($texString);
  615 
  616 This macro was used by the HTML_img display mode, which no longer exists.
  617 
  618 =cut
  619 
  620 # ^variable my $math2imgCount
  621 my $math2imgCount = 0;
  622 
  623 # ^function math2img
  624 # ^uses $math2imgCount
  625 # ^uses $envir{templateDirectory}
  626 # ^uses $envir{fileName}
  627 # ^uses $envir{studentLogin}
  628 # ^uses $envir{setNumber}
  629 # ^uses $envir{probNum}
  630 # ^uses $envir{tempURL}
  631 # ^uses $envir{refreshMath2img}
  632 # ^uses $envir{dvipngTempDir}
  633 # ^uses $envir{externalLaTeXPath}
  634 # ^uses $envir{externalDvipngPath}
  635 sub math2img {
  636   my $tex = shift;
  637   my $mode = shift;
  638 
  639   my $sourcePath = $envir{templateDirectory} . "/" . $envir{fileName};
  640   my $tempFile = "m2i/$envir{studentLogin}.$envir{setNumber}.$envir{probNum}."
  641     . $math2imgCount++ . ".png";
  642   my $tempPath = surePathToTmpFile($tempFile); #my $tempPath = "$envir{tempDirectory}$tempFile";
  643   my $tempURL = "$envir{tempURL}/$tempFile";
  644   my $forceRefresh = $envir{refreshMath2img};
  645   my $imageMissing = not -e $tempPath;
  646   my $imageStale   = (stat $sourcePath)[9] > (stat $tempPath)[9] if -e $tempPath;
  647   if ($forceRefresh or $imageMissing or $imageStale) {
  648     # image file doesn't exist, or source file is newer then image file
  649     #warn "math2img: refreshMath2img forcing image generation for $tempFile\n" if $forceRefresh;
  650     #warn "math2img: $tempFile doesn't exist, so generating it\n" if $imageMissing;
  651     #warn "math2img: source file (", (stat $sourcePath)[9], ") is newer than image file (",
  652     # (stat $tempPath)[9], ") so re-generating image\n" if $imageStale;
  653     if (-e $tempPath) {
  654       unlink $tempPath or die "Failed to delete stale math2img file $tempPath: $!";
  655     }
  656     dvipng(
  657       $envir{dvipngTempDir}, $envir{externalLaTeXPath},
  658       $envir{externalDvipngPath}, $tex, $tempPath
  659     );
  660   }
  661 
  662   if (-e $tempPath) {
  663     return "<img align=\"middle\" src=\"$tempURL\" alt=\"$tex\">"            if $mode eq "inline";
  664     return "<div align=\"center\"><img src=\"$tempURL\" alt=\"$tex\"></div>" if $mode eq "display";
  665   } else {
  666     return "<b>[math2img failed]</b>";
  667     # it might be nice to call tth here as a fallback instead:
  668     #return tth($tex);
  669   }
  670 };
  671 
  672 =head2 [DEPRECATED] dvipng
  673 
  674   dvipng($working_directory, $latex_path, $dvipng_path, $tex_string, $target_path)
  675 
  676 This macro was used by the HTML_img display mode, which no longer exists.
  677 
  678 =cut
  679 
  680 # copied from IO.pm for backward compatibility with WeBWorK1.8;
  681 # ^function dvipng
  682 sub dvipng($$$$$) {
  683   my (
  684     $wd,        # working directory, for latex and dvipng garbage
  685                 # (must already exist!)
  686     $latex,     # path to latex binary
  687     $dvipng,    # path to dvipng binary
  688     $tex,       # tex string representing equation
  689     $targetPath # location of resulting image file
  690   ) = @_;
  691 
  692   my $dvipngBroken = 0;
  693 
  694   my $texFile  = "$wd/equation.tex";
  695   my $dviFile  = "$wd/equation.dvi";
  696   my $dviFile2 = "$wd/equationequation.dvi";
  697   my $dviCall  = "equation";
  698   my $pngFile  = "$wd/equation1.png";
  699 
  700   unless (-e $wd) {
  701     die "dvipng working directory $wd doesn't exist -- caller should have created it for us!\n";
  702     return 0;
  703   }
  704 
  705   # write the tex file
  706   local *TEX;
  707   open TEX, ">", $texFile or warn "Failed to create $texFile: $!";
  708   print TEX <<'EOF';
  709 % BEGIN HEADER
  710 \batchmode
  711 \documentclass[12pt]{article}
  712 \usepackage{amsmath,amsfonts,amssymb}
  713 \def\gt{>}
  714 \def\lt{<}
  715 \usepackage[active,textmath,displaymath]{preview}
  716 \begin{document}
  717 % END HEADER
  718 EOF
  719   print TEX "\\( \\displaystyle{$tex} \\)\n";
  720   print TEX <<'EOF';
  721 % BEGIN FOOTER
  722 \end{document}
  723 % END FOOTER
  724 EOF
  725   close TEX;
  726 
  727   # call latex
  728   system "cd $wd && $latex $texFile > /dev/null"
  729     and warn "Failed to call $latex with $texFile: $!";
  730 
  731   unless (-e $dviFile) {
  732     warn "Failed to generate DVI file $dviFile";
  733     return 0;
  734   }
  735 
  736   if ($dvipngBroken) {
  737     # change the name of the DVI file to get around dvipng's
  738     # crackheadedness. This is no longer needed with the newest
  739     # version of dvipng (10 something)
  740     system "/bin/mv", $dviFile, $dviFile2;
  741   }
  742 
  743   # call dvipng -- using warn instead of die passes some extra information
  744   # back to the user the complete warning is still printed in the apache
  745   # error log and a simple message (math2img failed) is returned to the
  746   # webpage.
  747   my $cmdout;
  748   $cmdout = system "cd $wd && $dvipng $dviCall > /dev/null"
  749     and warn "Failed to call$dvipng with $dviCall: $! with signal $cmdout";
  750 
  751   unless (-e $pngFile) {
  752     warn "Failed to create PNG file $pngFile";
  753     return 0;
  754   }
  755 
  756   $cmdout = system "/bin/mv", $pngFile, $targetPath and warn "Failed to mv: /bin/mv  $pngFile $targetPath $!. Call returned $cmdout. \n";
  757 }
  758 
  759 
  760 # ----- ----- ----- -----
  761 
  762 =head2  alias
  763 
  764   # In HTML modes, returns the URL of a web-friendly version of the specified file.
  765   # In TeX mode, returns the path to a TeX-friendly version of the specified file.
  766   alias($pathToFile);
  767 
  768 alias allows you to refer to auxiliary files which are in a directory along with
  769 the problem definition. In addition alias creates an EPS version of GIF or PNG
  770 files when called in TeX mode.
  771 
  772 As a rule auxiliary files that are used by a number of problems in a course
  773 should be placed in C<html/gif> or C<html> or in a subdirectory of the C<html>
  774 directory, while auxiliary files which are used in only one problem should be
  775 placed in the same directory as the problem in order to make the problem more
  776 portable.
  777 
  778 =head3 Specific behavior of the alias macro
  779 
  780 =head4 Files in the html subdirectory
  781 
  782 =over
  783 
  784 =item When not in TeX mode
  785 
  786 If the file lies under the F<html> subdirectory, then the approriate URL for the
  787 file is returned. Since the F<html> subdirectory is already accessible to the
  788 webserver no other changes need to be made. The file path for this type of file
  789 should be the complete file path. The path should start with the prefix defined
  790 in $courseDirs{html_temp} in global.conf.
  791 
  792 =item When in TeX mode
  793 
  794 GIF and PNG files will be translated into EPS files and placed in the directory
  795 F<tmp/eps>. The full path to this file is returned for use by TeX in producing
  796 the hard copy. The conversion is done by a system dependent commands defined in
  797 F<global.conf> $externalPrograms{gif2eps} (for GIF images) or
  798 $externalPrograms{png2eps} (for PNG images). The URLs for the other files are
  799 produced as in non-TeX mode but will of course not be usable to TeX.
  800 
  801 =back
  802 
  803 =head4 Files in the tmp subdirectory
  804 
  805 =over
  806 
  807 =item When not in TeX mode
  808 
  809 If the file lies under the F<tmp> subdirectory, then the approriate URL for the
  810 file is created. Since the F<tmp> subdirectory is already accessible to the
  811 webserver no other changes need to be made. The file path for this type of file
  812 should be the complete file path. The path should start with the prefix defined
  813 in $courseDirs{html_temp} in global.conf.
  814 
  815 =item When in TeX mode
  816 
  817 GIF and PNG files will be translated into EPS files and placed in the directory
  818 F<tmp/eps>. The full path to this file is returned for use by TeX in producing
  819 the hard copy. The conversion is done by a system dependent commands defined in
  820 F<global.conf> $externalPrograms{gif2eps} (for GIF images) or
  821 $externalPrograms{png2eps} (for PNG images). The URLs for the other files are
  822 produced as in non-TeX mode but will of course not be usable to TeX.
  823 
  824 =back
  825 
  826 =head4 Files in the course template subdirectory
  827 
  828 =over
  829 
  830 =item When not in TeX mode
  831 
  832 If the file lies under the course templates subdirectory, it is assumed to lie
  833 in subdirectory rooted in the directory containing the problem template file. An
  834 alias is created under the F<html/tmp/gif> or F<html/tmp/html> directory and
  835 linked to the original file. The file path for this type of file is a relative
  836 path rooted at the directory containing the problem template file.
  837 
  838 =item When in TeX mode
  839 
  840 GIF and PNG files will be translated into EPS files and placed in the directory
  841 F<tmp/eps>. The full path to this file is returned for use by TeX in producing
  842 the hard copy. The conversion is done by a system dependent commands defined in
  843 F<global.conf> $externalPrograms{gif2eps} (for GIF images) or
  844 $externalPrograms{png2eps} (for PNG images). The URLs for the other files are
  845 produced as in non-TeX mode but will of course not be usable to TeX.
  846 
  847 =back
  848 
  849 =cut
  850 
  851 # Currently gif, html and types are supported.
  852 #
  853 # If the auxiliary file path has not extension then the extension .gif isassumed.
  854 #
  855 # If the auxiliary file path leads to a file in the ${Global::htmlDirectory}
  856 # no changes are made to the file path.
  857 #
  858 # If the auxiliary file path is not complete, than it is assumed that it refers
  859 # to a subdirectoy of the directory containing the problem..
  860 #
  861 # The output is either the correct URL for the file
  862 # or (in TeX mode) the complete path to the eps version of the file
  863 # and can be used as input into the image macro.
  864 #
  865 # surePathToTmpFile takes a path and outputs the complete path:
  866 # ${main::htmlDirectory}/tmp/path
  867 # It insures that all of the directories in the path have been created,
  868 # but does not create the
  869 # final file.
  870 
  871 # For postscript printing, alias generates an eps version of the gif image and places
  872 # it in the directory eps.  This slows down downloading postscript versions somewhat,
  873 # but not excessivevly.
  874 # Alias does not do any garbage collection, so files and alias may accumulate and
  875 # need to be removed manually or by a reaper daemon.
  876 
  877 # This subroutine  has commands which will not work on non-UNIX environments.
  878 # system("cat $gifSourceFile  | /usr/math/bin/giftopnm | /usr/math/bin/pnmdepth 1 | /usr/math/bin/pnmtops -noturn>$adr_output") &&
  879 
  880 # ^function alias
  881 # ^uses %envir
  882 # ^uses $envir{fileName}
  883 # ^uses $envir{htmlDirectory}
  884 # ^uses $envir{htmlURL}
  885 # ^uses $envir{tempDirectory}
  886 # ^uses $envir{tempURL}
  887 # ^uses $envir{studentLogin}
  888 # ^uses $envir{psvnNumber}
  889 # ^uses $envir{setNumber}
  890 # ^uses $envir{probNum}
  891 # ^uses $envir{displayMode}
  892 # ^uses $envir{externalGif2EpsPath}
  893 # ^uses $envir{externalPng2EpsPath}
  894 # ^uses &surePathToTmpFile
  895 # ^uses &convertPath
  896 # ^uses &directoryFromPath
  897 # ^uses &fileFromPath
  898 # ^uses $envir{texDisposition}
  899 sub alias {
  900   # input is a path to the original auxiliary file
  901   my $envir               = eval(q!\%main::envir!);  # get the current root environment
  902     my $fileName            = $envir->{fileName};
  903   my $htmlDirectory       = $envir->{htmlDirectory};
  904   my $htmlURL             = $envir->{htmlURL};
  905   my $tempDirectory       = $envir->{tempDirectory};
  906   my $tempURL             = $envir->{tempURL};
  907   my $studentLogin        = $envir->{studentLogin};
  908   my $psvnNumber          = $envir->{psvnNumber};
  909   my $setNumber           = $envir->{setNumber};
  910   my $probNum             = $envir->{probNum};
  911   my $displayMode         = $envir->{displayMode};
  912     my $externalGif2EpsPath = $envir->{externalGif2EpsPath};
  913     my $externalPng2EpsPath = $envir->{externalPng2EpsPath};
  914 
  915   my $aux_file_path = shift @_;
  916   warn "Empty string used as input into the function alias" unless $aux_file_path;
  917   #
  918   #  Find auxiliary files even when the main file is in tempates/tmpEdit
  919   #
  920   $fileName =~ s!(^|/)tmpEdit/!\1!;
  921 
  922   # problem specific data
  923   warn "The path to the current problem file template is not defined."     unless $fileName;
  924   warn "The current studentLogin is not defined "                          unless $studentLogin;
  925   warn "The current problem set number is not defined"                     if $setNumber eq ""; # allow for sets equal to 0
  926   warn "The current problem number is not defined"                         if $probNum eq "";
  927   warn "The current problem set version number (psvn) is not defined"      unless defined($psvnNumber);
  928   warn "The displayMode is not defined"                                    unless $displayMode;
  929 
  930   # required macros
  931   warn "The macro &surePathToTmpFile can't be found" unless defined(&surePathToTmpFile);
  932   warn "The macro &convertPath can't be found" unless defined(&convertPath);
  933   warn "The macro &directoryFromPath can't be found" unless defined(&directoryFromPath);
  934   # warn "The webwork server does not have permission to execute the gif2eps script at  ${externalGif2EpsPath}." unless ( -x "${externalGif2EpsPath}" );
  935   # warn "The webwork server does not have permission to execute the png2eps script at ${externalPng2EpsPath}." unless ( -x "${externalPng2EpsPath}" );
  936 
  937   # required directory addresses (and URL address)
  938   warn "htmlDirectory is not defined in $htmlDirectory" unless $htmlDirectory;
  939   warn "htmlURL is not defined in \$htmlURL" unless $htmlURL;
  940   warn "tempURL is not defined in \$tempURL" unless $tempURL;
  941 
  942   # determine extension, if there is one
  943   # if extension exists, strip and use the value for $ext
  944   # files without extensions are considered to be picture files:
  945 
  946   my $ext;
  947   if ($aux_file_path =~ s/\.([^\.]*)$// ) {
  948     $ext = $1;
  949   } else {
  950     warn "This file name $aux_file_path did not have an extension.<BR> " .
  951          "Every file name used as an argument to alias must have an extension.<BR> " .
  952          "The permissable extensions are .gif, .png, and .html .<BR>";
  953     $ext  = "gif";
  954   }
  955 
  956   # $adr_output is a url in HTML and Latex2HTML modes
  957   # and a complete path in TEX mode.
  958   my $adr_output;
  959 
  960   # in order to facilitate maintenance of this macro the routines for handling
  961   # different file types are defined separately.  This involves some redundancy
  962   # in the code but it makes it easier to define special handling for a new file
  963   # type, (but harder to change the behavior for all of the file types at once
  964   # (sigh)  ).
  965 
  966 
  967   if ($ext eq 'html') {
  968     ################################################################################
  969     # .html FILES in HTML, HTML_tth, HTML_dpng, HTML_img, etc. and Latex2HTML mode
  970     ################################################################################
  971 
  972     # No changes are made for auxiliary files in the
  973     # ${Global::htmlDirectory} subtree.
  974     if ( $aux_file_path =~ m|^$tempDirectory| ) {
  975       $adr_output = $aux_file_path;
  976       $adr_output =~ s|$tempDirectory|$tempURL/|;
  977       $adr_output .= ".$ext";
  978     } elsif ($aux_file_path =~ m|^$htmlDirectory| ) {
  979       $adr_output = $aux_file_path;
  980       $adr_output =~ s|$htmlDirectory|$htmlURL|;
  981       $adr_output .= ".$ext";
  982     } else {
  983       # HTML files not in the htmlDirectory are assumed under live under the
  984       # templateDirectory in the same directory as the problem.
  985       # Create an alias file (link) in the directory html/tmp/html which
  986       # points to the original file and return the URL of this alias.
  987       # Create all of the subdirectories of html/tmp/html which are needed
  988       # using sure file to path.
  989 
  990       # $fileName is obtained from environment for PGeval
  991       # it gives the  full path to the current problem
  992       my $filePath = directoryFromPath($fileName);
  993       my $htmlFileSource = convertPath("$templateDirectory${filePath}$aux_file_path.html");
  994       my $link = "html/$studentLogin-$psvnNumber-set$setNumber-prob$probNum-$aux_file_path.$ext";
  995       my $linkPath = surePathToTmpFile($link);
  996       $adr_output = "${tempURL}$link";
  997       if (-e $htmlFileSource) {
  998         if (-e $linkPath) {
  999           unlink($linkPath) || warn "Unable to unlink alias file at |$linkPath|";
 1000           # destroy the old link.
 1001         }
 1002         symlink( $htmlFileSource, $linkPath)
 1003               || warn "The macro alias cannot create a link from |$linkPath|  to |$htmlFileSource| <BR>" ;
 1004       } else {
 1005         warn("The macro alias cannot find an HTML file at: |$htmlFileSource|");
 1006       }
 1007     }
 1008   } elsif ($ext eq 'gif') {
 1009     if ( $displayMode eq 'HTML' ||
 1010          $displayMode eq 'HTML_tth'||
 1011          $displayMode eq 'HTML_dpng'||
 1012          $displayMode eq 'HTML_asciimath'||
 1013          $displayMode eq 'HTML_LaTeXMathML'||
 1014          $displayMode eq 'HTML_jsMath'||
 1015          $displayMode eq 'HTML_img'||
 1016          $displayMode eq 'Latex2HTML')  {
 1017       ################################################################################
 1018       # .gif FILES in HTML, HTML_tth, HTML_dpng, HTML_img, and Latex2HTML modes
 1019       ################################################################################
 1020 
 1021       #warn "tempDirectory is $tempDirectory";
 1022       #warn "file Path for auxiliary file is $aux_file_path";
 1023 
 1024       # No changes are made for auxiliary files in the htmlDirectory or in the tempDirectory subtree.
 1025       if ( $aux_file_path =~ m|^$tempDirectory| ) {
 1026         $adr_output = $aux_file_path;
 1027         $adr_output =~ s|$tempDirectory|$tempURL|;
 1028         $adr_output .= ".$ext";
 1029         #warn "adress out is $adr_output";
 1030       } elsif ($aux_file_path =~ m|^$htmlDirectory| ) {
 1031         $adr_output = $aux_file_path;
 1032         $adr_output =~ s|$htmlDirectory|$htmlURL|;
 1033         $adr_output .= ".$ext";
 1034       } else {
 1035         # files not in the htmlDirectory sub tree are assumed to live under the templateDirectory
 1036         # subtree in the same directory as the problem.
 1037 
 1038         # For a gif file the alias macro creates an alias under the html/images directory
 1039         # which points to the gif file in the problem directory.
 1040         # All of the subdirectories of html/tmp/gif which are needed are also created.
 1041         my $filePath = directoryFromPath($fileName);
 1042 
 1043         # $fileName is obtained from environment for PGeval
 1044         # it gives the full path to the current problem
 1045         my $gifSourceFile = convertPath("$templateDirectory${filePath}$aux_file_path.gif");
 1046         #my $link = "gif/$studentLogin-$psvnNumber-set$setNumber-prob$probNum-$aux_file_path.$ext";
 1047 
 1048         #  Make file names work in Library Browser when the images in several
 1049         #  files have the same names.
 1050         my $libFix = "";
 1051         if ($setNumber eq "Undefined_Set") {
 1052           $libFix = $fileName;
 1053           $libFix =~ s!.*/!!; $libFix =~ s!\.pg(\..*)?$!!;
 1054           $libFix =~ s![^a-zA-Z0-9._-]!!g;
 1055           $libFix .= '-';
 1056         }
 1057 
 1058         my $link = "gif/$setNumber-prob$probNum-$libFix$aux_file_path.$ext";
 1059 
 1060         my $linkPath = surePathToTmpFile($link);
 1061         $adr_output = "${tempURL}$link";
 1062         #warn "linkPath is $linkPath";
 1063         #warn "adr_output is $adr_output";
 1064         if (-e $gifSourceFile) {
 1065           if (-e $linkPath) {
 1066             unlink($linkPath) || warn "Unable to unlink old alias file at $linkPath";
 1067           }
 1068           symlink($gifSourceFile, $linkPath)
 1069             || warn "The macro alias cannot create a link from |$linkPath|  to |$gifSourceFile| <BR>" ;
 1070         } else {
 1071           warn("The macro alias cannot find a GIF file at: |$gifSourceFile|");
 1072         }
 1073       }
 1074     } elsif ($displayMode eq 'TeX') {
 1075       ################################################################################
 1076       # .gif FILES in TeX mode
 1077       ################################################################################
 1078 
 1079       if ($envir{texDisposition} eq "pdf") {
 1080         # We're going to create PDF files with our TeX (using pdflatex), so we
 1081         # need images in PNG format.
 1082 
 1083         my $gifFilePath;
 1084 
 1085         if ($aux_file_path =~ m/^$htmlDirectory/ or $aux_file_path =~ m/^$tempDirectory/) {
 1086           # we've got a full pathname to a file
 1087           $gifFilePath = "$aux_file_path.gif";
 1088         } else {
 1089           # we assume the file is in the same directory as the problem source file
 1090           $gifFilePath = $templateDirectory . directoryFromPath($fileName) . "$aux_file_path.gif";
 1091         }
 1092 
 1093         my $gifFileName = fileFromPath($gifFilePath);
 1094 
 1095         $gifFileName =~ /^(.*)\.gif$/;
 1096 #       my $pngFilePath = surePathToTmpFile("${tempDirectory}png/$probNum-$1.png");
 1097         my $pngFilePath = surePathToTmpFile("${tempDirectory}png/$setNumber-$probNum-$1.png");
 1098         my $returnCode = system "cat $gifFilePath | $envir{externalGif2PngPath} > $pngFilePath";
 1099 
 1100         if ($returnCode or not -e $pngFilePath) {
 1101           die "failed to convert $gifFilePath to $pngFilePath using gif->png with $envir{externalGif2PngPath}: $!\n";
 1102         }
 1103 
 1104         $adr_output = $pngFilePath;
 1105       } else {
 1106         # Since we're not creating PDF files, we're probably just using a plain
 1107         # vanilla latex. Hence, we need EPS images.
 1108 
 1109         ################################################################################
 1110         # This is statement used below is system dependent.
 1111         # Notice that the range of colors is restricted when converting to postscript to keep the files small
 1112         # "cat $gifSourceFile  | /usr/math/bin/giftopnm | /usr/math/bin/pnmtops -noturn > $adr_output"
 1113         # "cat $gifSourceFile  | /usr/math/bin/giftopnm | /usr/math/bin/pnmdepth 1 | /usr/math/bin/pnmtops -noturn > $adr_output"
 1114         ################################################################################
 1115         if ($aux_file_path =~  m|^$htmlDirectory|  or $aux_file_path =~  m|^$tempDirectory|)  {
 1116           # To serve an eps file copy an eps version of the gif file to the subdirectory of eps/
 1117           my $linkPath = directoryFromPath($fileName);
 1118 
 1119           my $gifSourceFile = "$aux_file_path.gif";
 1120           my $gifFileName = fileFromPath($gifSourceFile);
 1121           $adr_output = surePathToTmpFile("$tempDirectory/eps/$studentLogin-$psvnNumber-$gifFileName.eps") ;
 1122 
 1123           if (-e $gifSourceFile) {
 1124             #system("cat $gifSourceFile  | /usr/math/bin/giftopnm | /usr/math/bin/pnmdepth 1 | /usr/math/bin/pnmtops -noturn>$adr_output")
 1125             system("cat $gifSourceFile | ${externalGif2EpsPath} > $adr_output" )
 1126               && die "Unable to create eps file:\n |$adr_output| from file\n |$gifSourceFile|\n in problem $probNum " .
 1127                      "using the system dependent script\n |${externalGif2EpsPath}| \n";
 1128           } else {
 1129             die "|$gifSourceFile| cannot be found.  Problem number: |$probNum|";
 1130           }
 1131         } else {
 1132           # To serve an eps file copy an eps version of the gif file to  a subdirectory of eps/
 1133           my $filePath = directoryFromPath($fileName);
 1134           my $gifSourceFile = "${templateDirectory}${filePath}$aux_file_path.gif";
 1135           #print "content-type: text/plain \n\nfileName = $fileName and aux_file_path =$aux_file_path<BR>";
 1136           $adr_output = surePathToTmpFile("eps/$studentLogin-$psvnNumber-set$setNumber-prob$probNum-$aux_file_path.eps");
 1137 
 1138           if (-e $gifSourceFile) {
 1139             #system("cat $gifSourceFile  | /usr/math/bin/giftopnm | /usr/math/bin/pnmdepth 1 | /usr/math/bin/pnmtops -noturn>$adr_output") &&
 1140             #warn "Unable to create eps file: |$adr_output|\n from file\n |$gifSourceFile|\n in problem $probNum";
 1141             #warn "Help ${:externalGif2EpsPath}" unless -x "${main::externalGif2EpsPath}";
 1142             system("cat $gifSourceFile | ${externalGif2EpsPath} > $adr_output" )
 1143               && die "Unable to create eps file:\n |$adr_output| from file\n |$gifSourceFile|\n in problem $probNum " .
 1144                      "using the system dependent commands \n |${externalGif2EpsPath}| \n ";
 1145           }  else {
 1146             die "|$gifSourceFile| cannot be found.  Problem number: |$probNum|";
 1147           }
 1148         }
 1149       }
 1150     } else {
 1151       die "Error in alias: dangerousMacros.pl: unrecognizable displayMode = $displayMode";
 1152     }
 1153   } elsif ($ext eq 'png') {
 1154     if ( $displayMode eq 'HTML' ||
 1155          $displayMode eq 'HTML_tth'||
 1156          $displayMode eq 'HTML_dpng'||
 1157          $displayMode eq 'HTML_asciimath'||
 1158          $displayMode eq 'HTML_LaTeXMathML'||
 1159          $displayMode eq 'HTML_jsMath'||
 1160          $displayMode eq 'HTML_img'||
 1161          $displayMode eq 'Latex2HTML')  {
 1162       ################################################################################
 1163       # .png FILES in HTML, HTML_tth, HTML_dpng, HTML_img, etc. and Latex2HTML modes
 1164       ################################################################################
 1165 
 1166       #warn "tempDirectory is $tempDirectory";
 1167       #warn "file Path for auxiliary file is $aux_file_path";
 1168 
 1169       # No changes are made for auxiliary files in the htmlDirectory or in the tempDirectory subtree.
 1170       if ( $aux_file_path =~ m|^$tempDirectory| ) {
 1171       $adr_output = $aux_file_path;
 1172         $adr_output =~ s|$tempDirectory|$tempURL|;
 1173         $adr_output .= ".$ext";
 1174         #warn "adress out is $adr_output";
 1175       } elsif ($aux_file_path =~ m|^$htmlDirectory| ) {
 1176         $adr_output = $aux_file_path;
 1177         $adr_output =~ s|$htmlDirectory|$htmlURL|;
 1178         $adr_output .= ".$ext";
 1179       } else {
 1180         # files not in the htmlDirectory sub tree are assumed to live under the templateDirectory
 1181         # subtree in the same directory as the problem.
 1182 
 1183         # For a png file the alias macro creates an alias under the html/images directory
 1184         # which points to the png file in the problem directory.
 1185         # All of the subdirectories of html/tmp/gif which are needed are also created.
 1186         my $filePath = directoryFromPath($fileName);
 1187 
 1188         # $fileName is obtained from environment for PGeval
 1189         # it gives the full path to the current problem
 1190         my $pngSourceFile = convertPath("$templateDirectory${filePath}$aux_file_path.png");
 1191         my $link = "gif/$studentLogin-$psvnNumber-set$setNumber-prob$probNum-$aux_file_path.$ext";
 1192         my $linkPath = surePathToTmpFile($link);
 1193         $adr_output = "${tempURL}$link";
 1194         #warn "linkPath is $linkPath";
 1195         #warn "adr_output is $adr_output";
 1196         if (-e $pngSourceFile) {
 1197           if (-e $linkPath) {
 1198             unlink($linkPath) || warn "Unable to unlink old alias file at $linkPath";
 1199           }
 1200           symlink($pngSourceFile, $linkPath)
 1201           || warn "The macro alias cannot create a link from |$linkPath|  to |$pngSourceFile| <BR>" ;
 1202         } else {
 1203           warn("The macro alias cannot find a PNG file at: |$pngSourceFile|");
 1204         }
 1205       }
 1206     } elsif ($displayMode eq 'TeX') {
 1207       ################################################################################
 1208       # .png FILES in TeX mode
 1209       ################################################################################
 1210 
 1211       if ($envir{texDisposition} eq "pdf") {
 1212         # We're going to create PDF files with our TeX (using pdflatex), so we
 1213         # need images in PNG format. what luck! they're already in PDF format!
 1214 
 1215         my $pngFilePath;
 1216 
 1217         if ($aux_file_path =~ m/^$htmlDirectory/ or $aux_file_path =~ m/^$tempDirectory/) {
 1218           # we've got a full pathname to a file
 1219           $pngFilePath = "$aux_file_path.png";
 1220         } else {
 1221           # we assume the file is in the same directory as the problem source file
 1222           $pngFilePath = $templateDirectory . directoryFromPath($fileName) . "$aux_file_path.png";
 1223         }
 1224 
 1225         $adr_output = $pngFilePath;
 1226       } else {
 1227         # Since we're not creating PDF files, we're probably just using a plain
 1228         # vanilla latex. Hence, we need EPS images.
 1229 
 1230         ################################################################################
 1231         # This is statement used below is system dependent.
 1232         # Notice that the range of colors is restricted when converting to postscript to keep the files small
 1233         # "cat $pngSourceFile  | /usr/math/bin/pngtopnm | /usr/math/bin/pnmtops -noturn > $adr_output"
 1234         # "cat $pngSourceFile  | /usr/math/bin/pngtopnm | /usr/math/bin/pnmdepth 1 | /usr/math/bin/pnmtops -noturn > $adr_output"
 1235         ################################################################################
 1236 
 1237         if ($aux_file_path =~  m|^$htmlDirectory|  or $aux_file_path =~  m|^$tempDirectory|)  {
 1238           # To serve an eps file copy an eps version of the png file to the subdirectory of eps/
 1239           my $linkPath = directoryFromPath($fileName);
 1240 
 1241           my $pngSourceFile = "$aux_file_path.png";
 1242           my $pngFileName = fileFromPath($pngSourceFile);
 1243           $adr_output = surePathToTmpFile("$tempDirectory/eps/$studentLogin-$psvnNumber-$pngFileName.eps") ;
 1244 
 1245           if (-e $pngSourceFile) {
 1246             #system("cat $pngSourceFile  | /usr/math/bin/pngtopnm | /usr/math/bin/pnmdepth 1 | /usr/math/bin/pnmtops -noturn>$adr_output")
 1247             system("cat $pngSourceFile | ${externalPng2EpsPath} > $adr_output" )
 1248               && die "Unable to create eps file:\n |$adr_output| from file\n |$pngSourceFile|\n in problem $probNum " .
 1249                      "using the system dependent commands\n |${externalPng2EpsPath}| \n";
 1250           } else {
 1251             die "|$pngSourceFile| cannot be found.  Problem number: |$probNum|";
 1252           }
 1253         } else {
 1254           # To serve an eps file copy an eps version of the png file to  a subdirectory of eps/
 1255           my $filePath = directoryFromPath($fileName);
 1256           my $pngSourceFile = "${templateDirectory}${filePath}$aux_file_path.png";
 1257           #print "content-type: text/plain \n\nfileName = $fileName and aux_file_path =$aux_file_path<BR>";
 1258           $adr_output = surePathToTmpFile("eps/$studentLogin-$psvnNumber-set$setNumber-prob$probNum-$aux_file_path.eps") ;
 1259           if (-e $pngSourceFile) {
 1260             #system("cat $pngSourceFile  | /usr/math/bin/pngtopnm | /usr/math/bin/pnmdepth 1 | /usr/math/bin/pnmtops -noturn>$adr_output") &&
 1261             #warn "Unable to create eps file: |$adr_output|\n from file\n |$pngSourceFile|\n in problem $probNum";
 1262             #warn "Help ${externalPng2EpsPath}" unless -x "${externalPng2EpsPath}";
 1263             system("cat $pngSourceFile | ${externalPng2EpsPath} > $adr_output" )
 1264               && die "Unable to create eps file:\n |$adr_output| from file\n |$pngSourceFile|\n in problem $probNum " .
 1265                      "using the system dependent commands\n |${externalPng2EpsPath}| \n ";
 1266           } else {
 1267             die "|$pngSourceFile| cannot be found.  Problem number: |$probNum|";
 1268           }
 1269         }
 1270       }
 1271     } else {
 1272       warn  "Error in alias: dangerousMacros.pl","unrecognizable displayMode = $displayMode","";
 1273     }
 1274   } else { # $ext is not recognized
 1275     ################################################################################
 1276     # FILES  with unrecognized file extensions in any display modes
 1277     ################################################################################
 1278 
 1279     warn "Error in the macro alias. Alias does not understand how to process files with extension $ext.  (Path ot problem file is  $fileName) ";
 1280   }
 1281 
 1282   warn "The macro alias was unable to form a URL for some auxiliary file used in this problem." unless $adr_output;
 1283   return $adr_output;
 1284 }
 1285 
 1286 =head2 sourceAlias
 1287 
 1288   sourceAlias($path_to_PG_file);
 1289 
 1290 Returns a relative URL to the F<source.pl> script, which may be installed in a
 1291 course's F<html> directory to allow formatted viewing of the problem source.
 1292 
 1293 =cut
 1294 
 1295 # ^function sourceAlias
 1296 # ^uses PG_restricted_eval
 1297 # ^uses %envir
 1298 # ^uses $envir{inputs_ref}
 1299 # ^uses $envir{psvn}
 1300 # ^uses $envir{probNum}
 1301 # ^uses $envir{displayMode}
 1302 # ^uses $envir{courseName}
 1303 # ^uses $envir{sessionKey}
 1304 sub sourceAlias {
 1305   my $path_to_file = shift;
 1306   my $envir        =  PG_restricted_eval(q!\%main::envir!);
 1307   my $user         = $envir->{inputs_ref}->{user};
 1308   $user            = " " unless defined($user);
 1309     my $out = 'source.pl?probSetKey='  . $envir->{psvn}.
 1310           '&amp;probNum='          . $envir->{probNum} .
 1311           '&amp;Mode='             . $envir->{displayMode} .
 1312           '&amp;course='           . $envir->{courseName} .
 1313           '&amp;user='             . $user .
 1314         '&amp;displayPath='      . $path_to_file .
 1315           '&amp;key='              . $envir->{sessionKey};
 1316 
 1317    $out;
 1318 }
 1319 
 1320 
 1321 #
 1322 #  Some constants that can be used in perl experssions
 1323 #
 1324 
 1325 # ^function i
 1326 # ^uses $_parser_loaded
 1327 # ^uses &Complex::i
 1328 # ^uses &Value::Package
 1329 sub i () {
 1330   #  check if Parser.pl is loaded, otherwise use Complex package
 1331   if (!eval(q!$main::_parser_loaded!)) {return Complex::i}
 1332   return Value->Package("Formula")->new('i')->eval;
 1333 }
 1334 
 1335 # ^function j
 1336 # ^uses $_parser_loaded
 1337 # ^uses &Value::Package
 1338 sub j () {
 1339   if (!eval(q!$main::_parser_loaded!)) {return 'j'}
 1340   Value->Package("Formula")->new('j')->eval;
 1341 }
 1342 
 1343 # ^function k
 1344 # ^uses $_parser_loaded
 1345 # ^uses &Value::Package
 1346 sub k () {
 1347   if (!eval(q!$main::_parser_loaded!)) {return 'k'}
 1348   Value->Package("Formula")->new('k')->eval;
 1349 }
 1350 
 1351 # ^function pi
 1352 # ^uses &Value::Package
 1353 sub pi () {Value->Package("Formula")->new('pi')->eval}
 1354 
 1355 # ^function Infinity
 1356 # ^uses &Value::Package
 1357 sub Infinity () {Value->Package("Infinity")->new()}
 1358 
 1359 1;

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9