[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 5558 - (download) (as text) (annotate)
Thu Oct 4 16:57:34 2007 UTC (12 years, 4 months ago) by sh002i
File size: 52704 byte(s)
typo

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

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9