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