[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 1050 - (download) (as text) (annotate)
Fri Jun 6 21:39:42 2003 UTC (16 years, 7 months ago) by sh002i
File size: 45293 byte(s)
moved PG modules and macro files from webwork-modperl to pg
-sam

    1 #!/usr/local/bin/webwork-perl
    2 
    3 
    4 ####################################################################
    5 # Copyright @ 1995-1999 University of Rochester
    6 # All Rights Reserved
    7 ####################################################################
    8 
    9 ####################################################################
   10 #
   11 #  dangerousMacros.pl contains macros with potentially dangerous commands
   12 #  such as require and eval.  They can reference disk files for reading and
   13 #  writing and can create links.  It may be necessary to modify certain addresses
   14 #  in this file to make the scripts run in different environments.
   15 #
   16 #
   17 
   18 =head1 NAME
   19 
   20    dangerousMacros.pl --- located in the courseScripts directory
   21 
   22 =head1 SYNPOSIS
   23 
   24   loadMacros(macrofile1,macrofile2,...)
   25 
   26   insertGraph(graphObject);
   27     returns a path to the file containing the graph image.
   28 
   29   tth(texString)
   30     returns an HTML version of the tex code passed to it.
   31 
   32   alias(pathToFile);
   33     returns URL which links to that file
   34 
   35 
   36 =head1 DESCRIPTION
   37 
   38 
   39 C<dangerousMacros.pl> contains macros with potentially dangerous commands
   40 such as require and eval.  They can reference disk files for reading and
   41 writing and can create links.  It may be necessary to modify certain addresses
   42 in this file to make the scripts run properly in different environments.
   43 
   44 C<dangerousMacros.pl> is loaded and reinitialized
   45 every time a new problem is rendered.
   46 
   47 =cut
   48 
   49 
   50 ######## Dangerous macros#########
   51 ## The macros in this file are defined while the safe compartment is wide open.
   52 ## Be careful!
   53 #########################################
   54 
   55 
   56 =head2 Sharing modules:
   57 
   58 Most modules are loaded by dangerousMacros.pl
   59 
   60 The modules must be loaded using require (not use) since the courseScriptsDirectory is
   61 defined at run time.
   62 
   63 
   64  The following considerations come into play.
   65 
   66   * One needs to limit the access to modules for safety -- hence only
   67    modules in the F<courseScriptsDirectory> can be loaded.
   68 
   69   * Loading them in dangerousMacros.pl is wasteful, since the modules
   70    would need to be reloaded everytime a new safe compartment is created.
   71      (I believe that using require takes care of this.)
   72 
   73   * Loading GD within a safeCompartment creates infinite recurrsion in AUTOLOAD (probably a bug)
   74    hence this module is loaded by translate.pl and then shared with
   75    the safe compartment.
   76 
   77   * Other modules loaded by translate.pl are C<Exporter> and C<DynaLoader.
   78 
   79   * PGrandom is loaded by F<PG.pl> , since it is needed there.
   80 
   81 
   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 sub _dangerousMacros_init {
   99 }
  100 
  101 sub _dangerousMacros_export {
  102   my @EXPORT= (
  103       '&_dangerousMacros_init',
  104     '&alias',
  105     '&compile_file',
  106     '&insertGraph',
  107     '&loadMacros',
  108     '&HEADER_TEXT',
  109     '&sourceAlias',
  110     '&tth',
  111   );
  112   @EXPORT;
  113 }
  114 
  115 
  116 =head2 loadMacros
  117 
  118 C<loadMacros(macrofile1,macrofile2,...)>
  119 
  120 loadMacros takes a list of file names and evaluates the contents of each file.  This is used to load macros
  121 which define and augment the PG language.  The macro files are first searched for in the macro
  122 directory of the course C<($macroDirectory)> and then, if not found, in the WeBWorK courseScripts
  123 directory C<($courseScriptsDirectory)> where the default behavior of the PG language is defined.
  124 
  125 An individual course can modify the PG language, B<for that course only>, by
  126 duplicating one of the macro files in the courseScripts directory and placing this
  127 file in the macro directory for the course. The new file in the course
  128 macro directory will now be used instead of the file in the courseScripts directory.
  129 
  130 The new file in the course macro directory can by modified by adding macros or modifying existing macros.
  131 
  132 I< Modifying macros is for users with some experience.>
  133 
  134 Modifying existing macros might break other standard macros or problems which depend on the
  135 unmodified behavior of these macors so do this with great caution.
  136 In addition problems which use new macros defined in these files or which depend on the
  137 modified behavior of existing macros will not work in other courses unless the macros are also
  138 transferred to the new course.  It helps to document the  problems by indicating any special macros
  139 which the problems require.
  140 
  141 There is no facility for modifying or overloading a single macro.  The entire file containing the macro
  142 must be overloaded.
  143 
  144 Modifications to files in the course macros directory affect only that course,
  145 they will not interfere with the normal behavior of B<WeBWorK> in other courses.
  146 
  147 
  148 
  149 =cut
  150 
  151 # Global variables used
  152 #   ${main::macroDirectory}
  153 # ${main::courseScriptsDirectory}
  154 # Global macros used
  155 # None
  156 
  157 # Because of the need to use the directory variables it is tricky to define this
  158 # in translate.pl since, as currently written, the directories are not available
  159 # at that time.  Perhaps if I rewrite translate as an object that method will work.
  160 
  161 # The only difficulty with defining loadMacros inside the Safe compartment is that
  162 # the error reporting does not work with syntax errors.
  163 # A kludge using require works around this problem
  164 
  165 
  166 my ($macroDirectory,
  167   $courseScriptsDirectory,
  168   $templateDirectory,
  169   $scriptDirectory,
  170   );
  171 
  172 sub loadMacros {
  173     my @files = @_;
  174     my $fileName;
  175     ###############################################################################
  176   # At this point the directories have been defined from %envir and we can define
  177   # the directories for this file
  178   ###############################################################################
  179 
  180     $macroDirectory = eval('$main::macroDirectory') unless defined($macroDirectory);
  181     $courseScriptsDirectory = eval('$main::courseScriptsDirectory') unless defined($courseScriptsDirectory);
  182     $templateDirectory = eval('$main::courseScriptsDirectory') unless defined($templateDirectory);
  183     $scriptDirectory = eval('$main::scriptDirectory') unless defined($scriptDirectory);
  184 
  185     # Hack to handle those problems where DOCUMENT() comes after loadMacros.
  186     unless (defined( $main::externalTTHPath) and $main::externalTTHPath) {
  187       warn "WARNING::Please make sure that the DOCUMENT() statement comes before<BR>\n" .
  188            " the loadMacros() statement in the problem template.<p>" .
  189            " The externalTTHPath variable |$main::externalTTHPath| was\n".
  190            " not defined which usually indicates the problem above.<br>\n";
  191 
  192     }
  193     #warn "running load macros";
  194     while (@files) {
  195         $fileName = shift @files;
  196         next  if ($fileName =~ /^PG.pl$/) ;    # the PG.pl macro package is already loaded.
  197 
  198         my $macro_file_name = $fileName;
  199     $macro_file_name =~s/\.pl//;  # trim off the extension
  200     $macro_file_name =~s/\.pg//;  # sometimes the extension is .pg (e.g. CAPA files)
  201     my $init_subroutine_name = "_${macro_file_name}_init";
  202       my $macro_file_loaded;
  203     #no strict;
  204     ###############################################################################
  205     # For some reason the "no stict" which works on webwork-db doesn't work on
  206     # webwork.  For this reason the constuction &{$init_subroutine_name}
  207     # was abandoned and replaced by eval.  This is considerably more dangerous
  208     # since one could hide something nasty in a file name.
  209     #  Keep an eye on this ???
  210     # webwork-db used perl 5.6.1 and webwork used perl 5.6.0  It seems
  211     # unlikely that this was the problem. Otherwise all files seemed to
  212     # be the same.
  213     ###############################################################################
  214 
  215     local($temp::rf_init_subroutine);
  216     eval qq{ \$temp::rf_init_subroutine = \\&main::$init_subroutine_name;};
  217     #warn "loadMacros: defining \$temp::rf_init_subroutine ",$temp::rf_init_subroutine;
  218 
  219     $macro_file_loaded  = defined($temp::rf_init_subroutine) && defined( &{$temp::rf_init_subroutine} );
  220 
  221         # macros are searched for first in the $macroDirectory of the course
  222         # and then in the webwork  $courseScripts directory.
  223         unless ($macro_file_loaded) {
  224           #print STDERR "loadMacros: loading macro file $fileName\n";
  225       if (-r "${main::macroDirectory}$fileName") {
  226         compile_file("${main::macroDirectory}$fileName");
  227 
  228       } elsif (-r  "${main::courseScriptsDirectory}$fileName" ) {
  229          compile_file("${main::courseScriptsDirectory}$fileName");
  230       } else {
  231         die "Can't locate macro file via path: |${main::macroDirectory}$fileName| or |${main::courseScriptsDirectory}$fileName|";
  232       }
  233     }
  234     # Try again to define the initialization subroutine.
  235     eval qq{ \$temp::rf_init_subroutine = \\&main::$init_subroutine_name;};
  236     #warn "loadMacros: defining \$temp::rf_init_subroutine ",$temp::rf_init_subroutine;
  237 
  238     if ( defined($temp::rf_init_subroutine) and defined( &{$temp::rf_init_subroutine} ) ) {
  239         #print " &$init_subroutine_name defined = ", $macro_file_loaded,"\n";
  240       &{$temp::rf_init_subroutine}();  #initialize file
  241       #print "initializing $init_subroutine_name\n";
  242     }
  243 
  244   }
  245 }
  246 
  247 # errors in compiling macros is not always being reported.
  248 sub compile_file {
  249   my $filePath = shift;
  250   local(*MACROFILE);
  251   local($/);
  252   $/ = undef;   # allows us to treat the file as a single line
  253   open(MACROFILE, "<$filePath") || die "Cannot open file: $filePath";
  254   my $string = <MACROFILE>;
  255   my ($result,$error,$fullerror) = PG_restricted_eval($string);
  256   if ($error) {    # the $fullerror report has formatting and is never empty
  257     $fullerror =~ s/\(eval \d+\)/ $filePath\n/;   # attempt to insert file name instead of eval number
  258     die "Error detected while loading $filePath:\n$fullerror";
  259 
  260   }
  261 
  262   close(MACROFILE);
  263 
  264 }
  265 
  266 # This creates on the fly graphs
  267 
  268 =head2 insertGraph
  269 
  270   $filePath = insertGraph(graphObject);
  271       returns a path to the file containing the graph image.
  272 
  273 insertGraph(graphObject) writes a gif file to the C<html/tmp/gif> directory of the current course.
  274 The file name
  275 is obtained from the graphObject.  Warnings are issued if errors occur while writing to
  276 the file.
  277 
  278 The permissions and ownership of the file are controlled by C<$main::tmp_file_permission>
  279 and C<$main::numericalGroupID>.
  280 
  281 B<Returns:>   A string containing the full path to the temporary file containing the GIF image.
  282 
  283 
  284 
  285 InsertGraph draws the object $graph, stores it in "${tempDirectory}gif/$gifName.gif (or .png)" where
  286 the $imageName is obtained from the graph object.  ConvertPath and surePathToTmpFile are used to insure
  287 that the correct directory separators are used for the platform and that the necessary directories
  288 are created if they are not already present.
  289 
  290 The directory address to the file is the result.  This is most often used in the construct
  291 
  292   TEXT(alias(insertGraph($graph)) );
  293 
  294 where alias converts the directory address to a URL when serving HTML pages and insures that
  295 an eps file is generated when creating TeX code for downloading.
  296 
  297 =cut
  298 
  299 # Global variables used:
  300 # $main::tmp_file_permission,
  301 # $main::numericalGroupID
  302 
  303 #Global macros used:
  304 #   &convertPath
  305 #   &surePathToTmpFile
  306 
  307 sub insertGraph {
  308         # Convert the image to GIF and print it on standard output
  309   my $graph = shift;
  310   my $extension = ($WWPlot::use_png) ? '.png' : '.gif';
  311   my $fileName = $graph->imageName  . $extension;
  312   my $filePath = convertPath("gif/$fileName");
  313   $filePath = &surePathToTmpFile( $filePath );
  314   #createFile($filePath, $main::tmp_file_permission, $main::numericalGroupID);
  315   local(*OUTPUT);  # create local file handle so it won't overwrite other open files.
  316   open(OUTPUT, ">$filePath")||warn ("$0","Can't open $filePath<BR>","");
  317   chmod( 0777, $filePath);
  318   print OUTPUT $graph->draw|| warn("$0","Can't print graph to $filePath<BR>","");
  319   close(OUTPUT)||warn("$0","Can't close $filePath<BR>","");
  320   $filePath;
  321 }
  322 
  323 
  324 
  325 =head2 tth
  326 
  327   tth(texString)
  328       returns an HTML version of the tex code passed to it.
  329 
  330 This macro sends the texString to the filter program C<tth> created by Ian Hutchinson.
  331 The tth program was created by Ian Hutchinson and is freely available
  332 for B<non-commerical purposes> at the C<tth> main site: C<http://hutchinson.belmont.ma.us/tth/>.
  333 
  334 The purpose of C<tth> is to translate text in the TeX or Latex markup language into
  335 HTML markup as best as possible.  Some symbols, such as square root symbols are not
  336 translated completely.  Macintosh users must use the "MacRoman" encoding (available in 4.0 and
  337 higher browsers) in order to view the symbols correctly.  WeBWorK attempts to force Macintosh
  338 browsers to use this encoding when such a browser is detected.
  339 
  340 The contents of the file C<tthPreamble.tex> in the courses template directory are prepended
  341 to each string.  This allows one to define TeX macros which can be used in every problem.
  342 Currently there is no default C<tthPreamble.tex> file, so if the file is not present in the
  343 course template directory no TeX macro definitions are prepended.  C<tth> already understands most
  344 Latex commands, but will not, in general know I<AMS-Latex> commands.  Additional information
  345 on C<tth> is available at the C<tth> main site.
  346 
  347 This macro contains code which is system dependent and may need to be modified
  348 to run on different systems.
  349 
  350 =for html
  351 The link to <CODE>tth</CODE> for <STRONG>non-commerical</STRONG> is
  352 <A HREF="http://hutchinson.belmont.ma.us/tth/">http://hutchinson.belmont.ma.us/tth/</A>.
  353 Binaries for many operating systems are available as well as the source code.  Links
  354 describing how to obtain <CODE>tth</CODE> for commerical use are also available on this page.
  355 
  356 =cut
  357 
  358 
  359 
  360 # This file allows the tth display.
  361 # Global variables:
  362 # ${main::templateDirectory}tthPreamble.tex   # location of any preamble TeX commands for tth
  363 #   ${main::templateDirectory}
  364 #   ${main::scriptDirectory}tth        # path to tth application
  365 # Global macros:
  366 #   None
  367 
  368 my ($tthPreambleFile, $tthPreambleContents); # the contents of this file will not change during problem compilation
  369                                              # it only needs to be read once
  370 sub tth {
  371   my $inputString = shift;
  372 
  373   # read the contents of the tthPreamble.tex file, unless it has already been read
  374   unless ( defined( $tthPreambleContents) ) {
  375     $tthPreambleFile = "${main::templateDirectory}tthPreamble.tex" if ( -r "${main::templateDirectory}tthPreamble.tex" );
  376     if ( defined($tthPreambleFile) )   {
  377       local(*TTHIN);
  378       open (TTHIN, "${main::templateDirectory}tthPreamble.tex") || die "Can't open file ${main::templateDirectory}tthPreamble.tex";
  379       #my @tthPreambleArray = <TTHIN>;
  380       local($/);
  381       $/ = undef;
  382       $tthPreambleContents = <TTHIN>;#join("",@tthPreambleArray);
  383       close(TTHIN);
  384 
  385       $tthPreambleContents =~ s/(.)\n/$1%\n/g;  # thanks to Jim Martino
  386                                                 # each line in the definition file
  387                                                 # should end with a % to prevent
  388                                                 # adding supurious paragraphs to output.
  389 
  390       $tthPreambleContents .="%\n";             # solves the problem if the file doesn't end with a return.
  391 
  392     } else {
  393       $tthPreambleContents = "";
  394     }
  395   }
  396 
  397     $inputString = $tthPreambleContents . $inputString;
  398     $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.
  399 
  400   # $tthpath is now taken from $Global::externalTTHPath via %envir.
  401     my $tthpath     = $envir{externalTTHPath};
  402     my $out;
  403 
  404     if (-x $tthpath ) {
  405       my $tthcmd      = "$tthpath -L -f5 -r 2>/dev/null " . $inputString;
  406       if (open(TTH, "$tthcmd   |")) {
  407           local($/);
  408       $/ = undef;
  409       $out = <TTH>;
  410       $/ = "\n";
  411       close(TTH);
  412       }else {
  413           $out = "<BR>there has been an error in executing $tthcmd<BR>";
  414       }
  415   } else {
  416     $out = "<BR> Can't execute the program tth at |$tthpath|<BR>";
  417     }
  418 
  419     $out;
  420 }
  421 
  422 # ----- ----- ----- -----
  423 
  424 =head2 math2img
  425 
  426 math2img(texString) - returns an IMG tag pointing to an image version of the supplied TeX
  427 
  428 =cut
  429 
  430 my $math2imgCount = 0;
  431 
  432 sub math2img {
  433   my $tex = shift;
  434   my $mode = shift;
  435 
  436   my $sourcePath = $envir{templateDirectory} . "/" . $envir{fileName};
  437   my $tempFile = "m2i/$envir{studentLogin}.$envir{setNumber}.$envir{probNum}."
  438     . $math2imgCount++ . ".png";
  439   my $tempPath = surePathToTmpFile($tempFile); #my $tempPath = "$envir{tempDirectory}$tempFile";
  440   my $tempURL = "$envir{tempURL}/$tempFile";
  441 
  442   my $forceRefresh = $envir{refreshMath2img};
  443   my $imageMissing = not -e $tempPath;
  444   my $imageStale   = (stat $sourcePath)[9] > (stat $tempPath)[9];
  445   if ($forceRefresh or $imageMissing or $imageStale) {
  446     # image file doesn't exist, or source file is newer then image file
  447     #warn "math2img: refreshMath2img forcing image generation for $tempFile\n" if $forceRefresh;
  448     #warn "math2img: $tempFile doesn't exist, so generating it\n" if $imageMissing;
  449     #warn "math2img: source file (", (stat $sourcePath)[9], ") is newer than image file (",
  450     # (stat $tempPath)[9], ") so re-generating image\n" if $imageStale;
  451     if (-e tempPath) {
  452       unlink $tempPath or die "Failed to delete stale math2img file $tempPath: $!";
  453     }
  454     dvipng(
  455       $envir{dvipngTempDir}, $envir{externalLaTeXPath},
  456       $envir{externalDvipngPath}, $tex, $tempPath
  457     );
  458   }
  459 
  460   if (-e $tempPath) {
  461     return "<img align=\"middle\" src=\"$tempURL\" alt=\"$tex\">"            if $mode eq "inline";
  462     return "<div align=\"center\"><img src=\"$tempURL\" alt=\"$tex\"></div>" if $mode eq "display";
  463   } else {
  464     return "<b>[math2img failed]</b>";
  465     # it might be nice to call tth here as a fallback instead:
  466     #return tth($tex);
  467   }
  468 };
  469 
  470 ## dvipngTempDir externalLaTeXPath, externalDvipngPath
  471 #sub dvipng {
  472 # my ($tex, $targetPath) = @_;
  473 #
  474 # # create a temporary directory for tex to shit in
  475 # my $wd = $envir{dvipngTempDir};
  476 # my $texFile  = "$wd/equation.tex";
  477 # my $dviFile  = "$wd/equation.dvi";
  478 # my $dviFile2 = "$wd/equationequation.dvi";
  479 # my $dviCall  = "equation";
  480 # my $pngFile  = "$wd/equation1.png";
  481 #
  482 # die "dvipng working directory $wd doesn't exist -- caller should have created it for us!\n"
  483 #   unless -e $wd;
  484 #
  485 # # write the tex file
  486 # local *TEX;
  487 # open TEX, ">", $texFile;
  488 # print TEX <<'EOF';
  489 #% BEGIN HEADER
  490 #\batchmode
  491 #\documentclass[12pt]{article}
  492 #\usepackage{amsmath,amsfonts,amssymb}
  493 #\def\gt{>}
  494 #\def\lt{<}
  495 #\usepackage[active,textmath,displaymath]{preview}
  496 #\begin{document}
  497 #% END HEADER
  498 #EOF
  499 # print TEX "\\( \\displaystyle{$tex} \\)\n";
  500 # print TEX <<'EOF';
  501 #% BEGIN FOOTER
  502 #\end{document}
  503 #% END FOOTER
  504 #EOF
  505 # close TEX;
  506 #
  507 # # call latex
  508 # my $latex = $envir{externalLaTeXPath};
  509 # system "cd $wd && $latex $texFile";
  510 #
  511 # return 0 unless -e $dviFile;
  512 #
  513 # # change the name of the DVI file to get around dvipng's crackheadedness
  514 # system "/bin/mv", $dviFile, $dviFile2;
  515 #
  516 # # call dvipng
  517 # my $dvipng = $envir{externalDvipngPath};
  518 # system "cd $wd && $dvipng $dviCall" and die "dvipng:dvipng failed: $!";
  519 #
  520 # return 0 unless -e $pngFile;
  521 #
  522 # system "/bin/mv", $pngFile, $targetPath and die "Failed to mv: $!\n";
  523 #}
  524 
  525 # ----- ----- ----- -----
  526 
  527 =head2  alias
  528 
  529   alias(pathToFile);
  530     returns A string describing the URL which links to GIF or html file
  531             (in HTML and Latex2HTML modes).
  532             or a path to the appropriate eps version of a GIF file
  533              (TeX Mode)
  534 
  535 
  536 
  537 C<alias> allows you to refer to auxiliary files which are in a directory along with
  538 the problem definition.  In addition alias creates an eps copy of GIF files when
  539 downloading hard copy (TeX mode).
  540 
  541 As a rule auxiliary files that are used by
  542 a number of problems in a course should be placed in C<html/gif> or C<html>
  543 or in a subdirectory of the C<html> directory,
  544 while auxiliary files which are used in only one problem should be placed in
  545 the same directory as the problem in order to make the problem more portable.
  546 
  547 
  548 
  549 =over 4
  550 
  551 =item  Files in the html subdirectory
  552 
  553 B<When not in TeX mode:>
  554 
  555 If the file lies under the C<html> subdirectory, then the approriate URL for the file is created.
  556 Since the C<html> subdirectory is already accessible to the webserver no other changes need to be made.
  557 The file path for this type of file should be the complete file path. The path should
  558 start with the prefix defined in $Global:htmlDirectory.
  559 
  560 B<When in TeX mode:>
  561 
  562 
  563 GIF files will be translated into an eps file (using system dependent code)
  564 and placed in the directory C<tmp/eps>.  The full path to this file is returned
  565 for use by TeX in producing the hard copy. (This should work even in a chrooted
  566 environment.) in producing the hard copy.   (This should work even in a chrooted
  567 environment.)
  568 
  569 The conversion is done by a system dependent script
  570 called C<gif2eps> which should be in the scripts directory
  571 
  572 The URL's for the other files are produced as in non-tex mode
  573 but will of course not be active.
  574 
  575 =item  Files in the tmp subdirectory
  576 
  577 B<When not in TeX mode:>
  578 
  579 If the file lies under the C<tmp> subdirectory, then the approriate URL for the file is created.
  580 Since the C<tmp> subdirectory is already accessible to the webserver no other changes need to be made.
  581 The file path for this type of file should be the complete file path. The path should
  582 start with the prefix defined in $Global:tempDirectory.
  583 
  584 B<When in TeX mode:>
  585 
  586 
  587 GIF files will be translated into an eps file (using system dependent code)
  588 and placed in the directory C<tmp/eps>.  The full path to this file is returned
  589 for use by TeX in producing the hard copy.  (This should work even in a chrooted
  590 environment.)
  591 
  592 The conversion is done by a system dependent script
  593 called C<gif2eps> which should be in the scripts directory
  594 
  595 The URL's for the other files are produced as in non-tex mode
  596 but will of course not be active.
  597 
  598 =item Files in the course template subdirectory:
  599 
  600 B<When not in TeX mode:>
  601 
  602 If the file lies under the course templates subdirectory,
  603 it is assumed to lie in subdirectory rooted in the directory
  604 containing the problem template file.
  605 An alias is created under the C<html/tmp/gif> or
  606 C<html/tmp/html> directory and linked to the original file.
  607 The file path for this type of file is a relative
  608 path rooted at the directory containing the problem template file.
  609 
  610 B<When in TeX mode:>
  611 
  612 GIF files will be translated into an eps file (using system dependent code)
  613 and placed in the directory C<html/tmp/eps>.  The full path to this file is returned
  614 for use by TeX in producing the hard copy.   (This should work even in a chrooted
  615 environment.)
  616 
  617 The conversion is done by a system dependent script
  618 called C<gif2eps> which should be in the scripts directory
  619 
  620 The URL's for the other files are produced as in non-tex mode
  621 but will of course not be active.
  622 
  623 =back
  624 
  625 =cut
  626 
  627 
  628 
  629 # Currently gif, html and types are supported.
  630 #
  631 # If the auxiliary file path has not extension then the extension .gif isassumed.
  632 #
  633 # If the auxiliary file path leads to a file in the ${Global::htmlDirectory}
  634 # no changes are made to the file path.
  635 #
  636 # If the auxiliary file path is not complete, than it is assumed that it refers
  637 # to a subdirectoy of the directory containing the problem..
  638 #
  639 # The output is either the correct URL for the file
  640 # or (in TeX mode) the complete path to the eps version of the file
  641 # and can be used as input into the image macro.
  642 #
  643 # surePathToTmpFile takes a path and outputs the complete path:
  644 # ${main::htmlDirectory}/tmp/path
  645 # It insures that all of the directories in the path have been created,
  646 # but does not create the
  647 # final file.
  648 
  649 # For postscript printing, alias generates an eps version of the gif image and places
  650 # it in the directory eps.  This slows down downloading postscript versions somewhat,
  651 # but not excessivevly.
  652 # Alias does not do any garbage collection, so files and alias may accumulate and
  653 # need to be removed manually or by a reaper daemon.
  654 
  655 
  656 # Global variables used:
  657 #  $main::fileName  # the full path to the current problem template file
  658 #  $main::htmlDirectory
  659 #  $main::htmlURL
  660 #  $main::tempDirectory
  661 #  $main::tempURL
  662 #  $main::studentLogin
  663 #  $main::psvnNumber
  664 #  $main::setNumber
  665 #  $main::probNum
  666 #  $main::displayMode
  667 
  668 # Global macros used
  669 # gif2eps   An external file called by system
  670 # surePathToTmpFile
  671 # convertPath
  672 # directoryFromPath
  673 
  674 
  675 # This subroutine  has commands which will not work on non-UNIX environments.
  676 # system("cat $gifSourceFile  | /usr/math/bin/giftopnm | /usr/math/bin/pnmdepth 1 | /usr/math/bin/pnmtops -noturn>$adr_output") &&
  677 
  678 
  679 # local constants $User, $psvn $setNumber $probNum $displayMode
  680 
  681 sub sourceAlias {
  682   my $path_to_file = shift;
  683   my $user = $main::inputs_ref->{user};
  684   $user = " " unless defined($user);
  685     my $out = "source.pl?probSetKey=$main::psvn".
  686         "&amp;probNum=$main::probNum" .
  687         "&amp;Mode=$main::displayMode" .
  688         "&amp;course=". $main::courseName .
  689         "&amp;user=" . $user .
  690       "&amp;displayPath=$path_to_file" .
  691         "&amp;key=". $main::sessionKey;
  692 
  693    $out;
  694 }
  695 
  696 
  697 sub alias {
  698   # input is a path to the original auxiliary file
  699     #my $fileName = $main::fileName;
  700   #my $htmlDirectory = $main::htmlDirectory;
  701   #my $htmlURL = $main::htmlURL;
  702   #my $tempDirectory = $main::tempDirectory;
  703   #my $tempURL =  $main::tempURL;
  704   #my $studentLogin =  $main::studentLogin;
  705   #my $psvnNumber =  $main::psvnNumber;
  706   #my $setNumber =  $main::setNumber;
  707   #my $probNum =  $main::probNum;
  708   #my $displayMode =  $main::displayMode;
  709 
  710 
  711   my $aux_file_path = shift @_;
  712   warn "Empty string used as input into the function alias" unless $aux_file_path;
  713 
  714   # problem specific data
  715   warn "The path to the current problem file template is not defined." unless $main::fileName;
  716   warn "The current studentLogin is not defined " unless $main::studentLogin;
  717   warn "The current problem set number is not defined" if $main::setNumber eq ""; # allow for sets equal to 0
  718   warn "The current problem number is not defined"  if $main::probNum eq "";
  719   warn "The current problem set version number (psvn) is not defined" unless $main::psvnNumber;
  720   warn "The displayMode is not defined" unless $main::displayMode;
  721 
  722   # required macros
  723   warn "The macro &surePathToTmpFile can't be found" unless defined(&surePathToTmpFile);
  724   warn "The macro &convertPath can't be found" unless defined(&convertPath);
  725   warn "The macro &directoryFromPath can't be found" unless defined(&directoryFromPath);
  726   warn "Can't execute the gif2eps script at ${main::externalGif2EpsPath}" unless ( -x "${main::externalGif2EpsPath}" );
  727   warn "Can't execute the png2eps script at ${main::externalPng2EpsPath}" unless ( -x "${main::externalPng2EpsPath}" );
  728 
  729   # required directory addresses (and URL address)
  730   warn "htmlDirectory is not defined in $main::htmlDirectory" unless $main::htmlDirectory;
  731   warn "htmlURL is not defined in \$main::htmlURL" unless $main::htmlURL;
  732   warn "tempURL is not defined in \$main::tempURL" unless $main::tempURL;
  733   #warn "The scripts directory is not defined in \$main::scriptDirectory" unless $main::scriptDirectory;
  734     # with the creation of externalGif2EpsPath and externalPng2EpsPath, the scripts directory is no longer used
  735 
  736   # determine extension, if there is one
  737   # if extension exists, strip and use the value for $ext
  738   # files without extensions are considered to be picture files:
  739 
  740   my $ext;
  741   if ($aux_file_path =~ s/\.([^\.]*)$// ) {
  742     $ext = $1;
  743   } else {
  744     warn "This file name $aux_file_path did not have an extension.<BR> " .
  745          "Every file name used as an argument to alias must have an extension.<BR> " .
  746          "The permissable extensions are .gif, .png, and .html .<BR>";
  747     $ext  = "gif";
  748   }
  749 
  750   # $adr_output is a url in HTML and Latex2HTML modes
  751   # and a complete path in TEX mode.
  752   my $adr_output;
  753 
  754   # in order to facilitate maintenance of this macro the routines for handling
  755   # different file types are defined separately.  This involves some redundancy
  756   # in the code but it makes it easier to define special handling for a new file
  757   # type, (but harder to change the behavior for all of the file types at once
  758   # (sigh)  ).
  759 
  760 
  761   if ($ext eq 'html') {
  762     ################################################################################
  763     # .html FILES in HTML, HTML_tth, HTML_dpng, HTML_img and Latex2HTML mode
  764     ################################################################################
  765 
  766     # No changes are made for auxiliary files in the
  767     # ${Global::htmlDirectory} subtree.
  768     if ( $aux_file_path =~ m|^$main::tempDirectory| ) {
  769       $adr_output = $aux_file_path;
  770       $adr_output =~ s|$main::tempDirectory|$main::tempURL/|;
  771       $adr_output .= ".$ext";
  772     } elsif ($aux_file_path =~ m|^$main::htmlDirectory| ) {
  773       $adr_output = $aux_file_path;
  774       $adr_output =~ s|$main::htmlDirectory|$main::htmlURL|;
  775       $adr_output .= ".$ext";
  776     } else {
  777       # HTML files not in the htmlDirectory are assumed under live under the
  778       # templateDirectory in the same directory as the problem.
  779       # Create an alias file (link) in the directory html/tmp/html which
  780       # points to the original file and return the URL of this alias.
  781       # Create all of the subdirectories of html/tmp/html which are needed
  782       # using sure file to path.
  783 
  784       # $fileName is obtained from environment for PGeval
  785       # it gives the  full path to the current problem
  786       my $filePath = directoryFromPath($main::fileName);
  787       my $htmlFileSource = convertPath("$main::templateDirectory${filePath}$aux_file_path.html");
  788       my $link = "html/$main::studentLogin-$main::psvnNumber-set$main::setNumber-prob$main::probNum-$aux_file_path.$ext";
  789       my $linkPath = surePathToTmpFile($link);
  790       $adr_output = "${main::tempURL}$link";
  791       if (-e $htmlFileSource) {
  792         if (-e $linkPath) {
  793           unlink($linkPath) || warn "Unable to unlink alias file at |$linkPath|";
  794           # destroy the old link.
  795         }
  796         symlink( $htmlFileSource, $linkPath)
  797               || warn "The macro alias cannot create a link from |$linkPath|  to |$htmlFileSource| <BR>" ;
  798       } else {
  799         warn("The macro alias cannot find an HTML file at: |$htmlFileSource|");
  800       }
  801     }
  802   } elsif ($ext eq 'gif') {
  803     if ( $main::displayMode eq 'HTML' ||
  804          $main::displayMode eq 'HTML_tth'||
  805          $main::displayMode eq 'HTML_dpng'||
  806          $main::displayMode eq 'HTML_img'||
  807          $main::displayMode eq 'Latex2HTML')  {
  808       ################################################################################
  809       # .gif FILES in HTML, HTML_tth, HTML_dpng, HTML_img, and Latex2HTML modes
  810       ################################################################################
  811 
  812       #warn "tempDirectory is $main::tempDirectory";
  813       #warn "file Path for auxiliary file is $aux_file_path";
  814 
  815       # No changes are made for auxiliary files in the htmlDirectory or in the tempDirectory subtree.
  816       if ( $aux_file_path =~ m|^$main::tempDirectory| ) {
  817         $adr_output = $aux_file_path;
  818         $adr_output =~ s|$main::tempDirectory|$main::tempURL|;
  819         $adr_output .= ".$ext";
  820         #warn "adress out is $adr_output";
  821       } elsif ($aux_file_path =~ m|^$main::htmlDirectory| ) {
  822         $adr_output = $aux_file_path;
  823         $adr_output =~ s|$main::htmlDirectory|$main::htmlURL|;
  824         $adr_output .= ".$ext";
  825       } else {
  826         # files not in the htmlDirectory sub tree are assumed to live under the templateDirectory
  827         # subtree in the same directory as the problem.
  828 
  829         # For a gif file the alias macro creates an alias under the html/images directory
  830         # which points to the gif file in the problem directory.
  831         # All of the subdirectories of html/tmp/gif which are needed are also created.
  832         my $filePath = directoryFromPath($main::fileName);
  833 
  834         # $fileName is obtained from environment for PGeval
  835         # it gives the full path to the current problem
  836         my $gifSourceFile = convertPath("$main::templateDirectory${filePath}$aux_file_path.gif");
  837         #my $link = "gif/$main::studentLogin-$main::psvnNumber-set$main::setNumber-prob$main::probNum-$aux_file_path.$ext";
  838         my $link = "gif/$main::setNumber-prob$main::probNum-$aux_file_path.$ext";
  839 
  840         my $linkPath = surePathToTmpFile($link);
  841         $adr_output = "${main::tempURL}$link";
  842         #warn "linkPath is $linkPath";
  843         #warn "adr_output is $adr_output";
  844         if (-e $gifSourceFile) {
  845           if (-e $linkPath) {
  846             unlink($linkPath) || warn "Unable to unlink old alias file at $linkPath";
  847           }
  848           symlink($gifSourceFile, $linkPath)
  849             || warn "The macro alias cannot create a link from |$linkPath|  to |$gifSourceFile| <BR>" ;
  850         } else {
  851           warn("The macro alias cannot find a GIF file at: |$gifSourceFile|");
  852         }
  853       }
  854     } elsif ($main::displayMode eq 'TeX') {
  855       ################################################################################
  856       # .gif FILES in TeX mode
  857       ################################################################################
  858 
  859       if ($envir{texDisposition} eq "pdf") {
  860         # We're going to create PDF files with our TeX (using pdflatex), so we
  861         # need images in PNG format.
  862 
  863         my $gifFilePath;
  864 
  865         if ($aux_file_path =~ m/^$main::htmlDirectory/ or $aux_file_path =~ m/^$main::tempDirectory/) {
  866           # we've got a full pathname to a file
  867           $gifFilePath = "$aux_file_path.gif";
  868         } else {
  869           # we assume the file is in the same directory as the problem source file
  870           $gifFilePath = $main::templateDirectory . directoryFromPath($main::fileName) . "$aux_file_path.gif";
  871         }
  872 
  873         my $gifFileName = fileFromPath($gifFilePath);
  874 
  875         $gifFileName =~ /^(.*)\.gif$/;
  876         my $pngFilePath = surePathToTmpFile("$main::tempDirectory/png/$1.png");
  877         my $returnCode = system "$envir{externalGif2PngPath} $gifFilePath $pngFilePath";
  878 
  879         if ($returnCode or not -e $pngFilePath) {
  880           die "failed to convert gif->png with $envir{externalGif2PngPath}: $!\n";
  881         }
  882 
  883         $adr_output = $pngFilePath;
  884       } else {
  885         # Since we're not creating PDF files, we're probably just using a plain
  886         # vanilla latex. Hence, we need EPS images.
  887 
  888         ################################################################################
  889         # This is statement used below is system dependent.
  890         # Notice that the range of colors is restricted when converting to postscript to keep the files small
  891         # "cat $gifSourceFile  | /usr/math/bin/giftopnm | /usr/math/bin/pnmtops -noturn > $adr_output"
  892         # "cat $gifSourceFile  | /usr/math/bin/giftopnm | /usr/math/bin/pnmdepth 1 | /usr/math/bin/pnmtops -noturn > $adr_output"
  893         ################################################################################
  894         if ($aux_file_path =~  m|^$main::htmlDirectory|  or $aux_file_path =~  m|^$main::tempDirectory|)  {
  895           # To serve an eps file copy an eps version of the gif file to the subdirectory of eps/
  896           my $linkPath = directoryFromPath($main::fileName);
  897 
  898           my $gifSourceFile = "$aux_file_path.gif";
  899           my $gifFileName = fileFromPath($gifSourceFile);
  900           $adr_output = surePathToTmpFile("$main::tempDirectory/eps/$main::studentLogin-$main::psvnNumber-$gifFileName.eps") ;
  901 
  902           if (-e $gifSourceFile) {
  903             #system("cat $gifSourceFile  | /usr/math/bin/giftopnm | /usr/math/bin/pnmdepth 1 | /usr/math/bin/pnmtops -noturn>$adr_output")
  904             system("${main::externalGif2EpsPath} $gifSourceFile $adr_output" )
  905               && die "Unable to create eps file:\n |$adr_output| from file\n |$gifSourceFile|\n in problem $main::probNum " .
  906                      "using the system dependent script\n |${main::externalGif2EpsPath}| \n";
  907           } else {
  908             die "|$gifSourceFile| cannot be found.  Problem number: |$main::probNum|";
  909           }
  910         } else {
  911           # To serve an eps file copy an eps version of the gif file to  a subdirectory of eps/
  912           my $filePath = directoryFromPath($main::fileName);
  913           my $gifSourceFile = "${main::templateDirectory}${filePath}$aux_file_path.gif";
  914           #print "content-type: text/plain \n\nfileName = $fileName and aux_file_path =$aux_file_path<BR>";
  915           $adr_output = surePathToTmpFile("eps/$main::studentLogin-$main::psvnNumber-set$main::setNumber-prob$main::probNum-$aux_file_path.eps");
  916 
  917           if (-e $gifSourceFile) {
  918             #system("cat $gifSourceFile  | /usr/math/bin/giftopnm | /usr/math/bin/pnmdepth 1 | /usr/math/bin/pnmtops -noturn>$adr_output") &&
  919             #warn "Unable to create eps file: |$adr_output|\n from file\n |$gifSourceFile|\n in problem $main::probNum";
  920             #warn "Help ${main::externalGif2EpsPath}" unless -x "${main::externalGif2EpsPath}";
  921             system("${main::externalGif2EpsPath} $gifSourceFile $adr_output" )
  922               && die "Unable to create eps file:\n |$adr_output| from file\n |$gifSourceFile|\n in problem $main::probNum " .
  923                      "using the system dependent script\n |${main::externalGif2EpsPath}| \n ";
  924           }  else {
  925             die "|$gifSourceFile| cannot be found.  Problem number: |$main::probNum|";
  926           }
  927         }
  928       }
  929     } else {
  930       wwerror("Error in alias: dangerousMacros.pl","unrecognizable displayMode = $main::displayMode","");
  931     }
  932   } elsif ($ext eq 'png') {
  933     if ( $main::displayMode eq 'HTML' ||
  934          $main::displayMode eq 'HTML_tth'||
  935          $main::displayMode eq 'HTML_dpng'||
  936          $main::displayMode eq 'HTML_img'||
  937          $main::displayMode eq 'Latex2HTML')  {
  938       ################################################################################
  939       # .png FILES in HTML, HTML_tth, HTML_dpng, HTML_img, and Latex2HTML modes
  940       ################################################################################
  941 
  942       #warn "tempDirectory is $main::tempDirectory";
  943       #warn "file Path for auxiliary file is $aux_file_path";
  944 
  945       # No changes are made for auxiliary files in the htmlDirectory or in the tempDirectory subtree.
  946       if ( $aux_file_path =~ m|^$main::tempDirectory| ) {
  947       $adr_output = $aux_file_path;
  948         $adr_output =~ s|$main::tempDirectory|$main::tempURL|;
  949         $adr_output .= ".$ext";
  950         #warn "adress out is $adr_output";
  951       } elsif ($aux_file_path =~ m|^$main::htmlDirectory| ) {
  952         $adr_output = $aux_file_path;
  953         $adr_output =~ s|$main::htmlDirectory|$main::htmlURL|;
  954         $adr_output .= ".$ext";
  955       } else {
  956         # files not in the htmlDirectory sub tree are assumed to live under the templateDirectory
  957         # subtree in the same directory as the problem.
  958 
  959         # For a png file the alias macro creates an alias under the html/images directory
  960         # which points to the png file in the problem directory.
  961         # All of the subdirectories of html/tmp/gif which are needed are also created.
  962         my $filePath = directoryFromPath($main::fileName);
  963 
  964         # $fileName is obtained from environment for PGeval
  965         # it gives the full path to the current problem
  966         my $pngSourceFile = convertPath("$main::templateDirectory${filePath}$aux_file_path.png");
  967         my $link = "gif/$main::studentLogin-$main::psvnNumber-set$main::setNumber-prob$main::probNum-$aux_file_path.$ext";
  968         my $linkPath = surePathToTmpFile($link);
  969         $adr_output = "${main::tempURL}$link";
  970         #warn "linkPath is $linkPath";
  971         #warn "adr_output is $adr_output";
  972         if (-e $pngSourceFile) {
  973           if (-e $linkPath) {
  974             unlink($linkPath) || warn "Unable to unlink old alias file at $linkPath";
  975           }
  976           symlink($pngSourceFile, $linkPath)
  977           || warn "The macro alias cannot create a link from |$linkPath|  to |$pngSourceFile| <BR>" ;
  978         } else {
  979           warn("The macro alias cannot find a PNG file at: |$pngSourceFile|");
  980         }
  981       }
  982     } elsif ($main::displayMode eq 'TeX') {
  983       ################################################################################
  984       # .png FILES in TeX mode
  985       ################################################################################
  986 
  987       if ($envir{texDisposition} eq "pdf") {
  988         # We're going to create PDF files with our TeX (using pdflatex), so we
  989         # need images in PNG format. what luck! they're already in PDF format!
  990 
  991         my $pngFilePath;
  992 
  993         if ($aux_file_path =~ m/^$main::htmlDirectory/ or $aux_file_path =~ m/^$main::tempDirectory/) {
  994           # we've got a full pathname to a file
  995           $pngFilePath = "$aux_file_path.png";
  996         } else {
  997           # we assume the file is in the same directory as the problem source file
  998           $pngFilePath = $main::templateDirectory . directoryFromPath($main::fileName) . "$aux_file_path.png";
  999         }
 1000 
 1001         $adr_output = $pngFilePath;
 1002       } else {
 1003         # Since we're not creating PDF files, we're probably just using a plain
 1004         # vanilla latex. Hence, we need EPS images.
 1005 
 1006         ################################################################################
 1007         # This is statement used below is system dependent.
 1008         # Notice that the range of colors is restricted when converting to postscript to keep the files small
 1009         # "cat $pngSourceFile  | /usr/math/bin/pngtopnm | /usr/math/bin/pnmtops -noturn > $adr_output"
 1010         # "cat $pngSourceFile  | /usr/math/bin/pngtopnm | /usr/math/bin/pnmdepth 1 | /usr/math/bin/pnmtops -noturn > $adr_output"
 1011         ################################################################################
 1012 
 1013         if ($aux_file_path =~  m|^$main::htmlDirectory|  or $aux_file_path =~  m|^$main::tempDirectory|)  {
 1014           # To serve an eps file copy an eps version of the png file to the subdirectory of eps/
 1015           my $linkPath = directoryFromPath($main::fileName);
 1016 
 1017           my $pngSourceFile = "$aux_file_path.png";
 1018           my $pngFileName = fileFromPath($pngSourceFile);
 1019           $adr_output = surePathToTmpFile("$main::tempDirectory/eps/$main::studentLogin-$main::psvnNumber-$pngFileName.eps") ;
 1020 
 1021           if (-e $pngSourceFile) {
 1022             #system("cat $pngSourceFile  | /usr/math/bin/pngtopnm | /usr/math/bin/pnmdepth 1 | /usr/math/bin/pnmtops -noturn>$adr_output")
 1023             system("${main::externalPng2EpsPath} $pngSourceFile $adr_output" )
 1024               && die "Unable to create eps file:\n |$adr_output| from file\n |$pngSourceFile|\n in problem $main::probNum " .
 1025                      "using the system dependent script\n |${main::externalPng2EpsPath}| \n";
 1026           } else {
 1027             die "|$pngSourceFile| cannot be found.  Problem number: |$main::probNum|";
 1028           }
 1029         } else {
 1030           # To serve an eps file copy an eps version of the png file to  a subdirectory of eps/
 1031           my $filePath = directoryFromPath($main::fileName);
 1032           my $pngSourceFile = "${main::templateDirectory}${filePath}$aux_file_path.png";
 1033           #print "content-type: text/plain \n\nfileName = $fileName and aux_file_path =$aux_file_path<BR>";
 1034           $adr_output = surePathToTmpFile("eps/$main::studentLogin-$main::psvnNumber-set$main::setNumber-prob$main::probNum-$aux_file_path.eps") ;
 1035           if (-e $pngSourceFile) {
 1036             #system("cat $pngSourceFile  | /usr/math/bin/pngtopnm | /usr/math/bin/pnmdepth 1 | /usr/math/bin/pnmtops -noturn>$adr_output") &&
 1037             #warn "Unable to create eps file: |$adr_output|\n from file\n |$pngSourceFile|\n in problem $main::probNum";
 1038             #warn "Help ${main::externalPng2EpsPath}" unless -x "${main::externalPng2EpsPath}";
 1039             system("${main::externalPng2EpsPath} $pngSourceFile $adr_output" )
 1040               && die "Unable to create eps file:\n |$adr_output| from file\n |$pngSourceFile|\n in problem $main::probNum " .
 1041                      "using the system dependent script\n |${main::externalPng2EpsPath}| \n ";
 1042           } else {
 1043             die "|$pngSourceFile| cannot be found.  Problem number: |$main::probNum|";
 1044           }
 1045         }
 1046       }
 1047     } else {
 1048       wwerror("Error in alias: dangerousMacros.pl","unrecognizable displayMode = $main::displayMode","");
 1049     }
 1050   } else { # $ext is not recognized
 1051     ################################################################################
 1052     # FILES  with unrecognized file extensions in any display modes
 1053     ################################################################################
 1054 
 1055     warn "Error in the macro alias. Alias does not understand how to process files with extension $ext.  (Path ot problem file is  $main::fileName) ";
 1056   }
 1057 
 1058   warn "The macro alias was unable to form a URL for some auxiliary file used in this problem." unless $adr_output;
 1059   return $adr_output;
 1060 }
 1061 
 1062 
 1063 
 1064 
 1065 
 1066 # Experiments
 1067 
 1068 # It is important that these subroutines using sort are evaluated before
 1069 # the problem template is evaluated.
 1070 # Once the problem template has a "my $a;" susequent sort routines will not work.
 1071 #
 1072 # PGsort can be used as a slightly slower but safer sort within problems.
 1073 
 1074 
 1075 
 1076 =head2 PGsort
 1077 
 1078 Because of the way sort is optimized in Perl, the symbols $a and $b
 1079 have special significance.
 1080 
 1081 C<sort {$a<=>$b} @list>
 1082 C<sort {$a cmp $b} @list>
 1083 
 1084 sorts the list numerically and lexically respectively.
 1085 
 1086 If C<my $a;> is used in a problem, before the sort routine is defined in a macro, then
 1087 things get badly confused.  To correct this, the following macros are defined in
 1088 dangerougMacros.pl which is evaluated before the problem template is read.
 1089 
 1090   PGsort sub { $_[0] <=> $_[1] }, @list;
 1091   PGsort sub { $_[0] cmp $_[1] }, @list;
 1092 
 1093 provide slightly slower, but safer, routines for the PG language. (The subroutines
 1094 for ordering are B<required>. Note the commas!)
 1095 
 1096 =cut
 1097 
 1098 
 1099 
 1100 # sub PGsort {
 1101 #   my $sort_order = shift;
 1102 #   die "Must supply an ordering function with PGsort: PGsort sub {\$a cmp \$b }, \@list\n" unless ref($sort_order) eq 'CODE';
 1103 #   sort {&$sort_order($a,$b)} @_;
 1104 # }
 1105 # Moved to translate.pl
 1106 # For some reason it still caused
 1107 # trouble here when there was
 1108 # more than one ans_eval in ANS()
 1109 # No-one knows why?
 1110 
 1111 # This allows the use of i for  imaginary numbers
 1112 #  one can write   3 +2i rather than 3+2i()
 1113 #
 1114 
 1115 sub i;
 1116 
 1117 1;  # required to load properly

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9