[system] / trunk / pg / macros / dangerousMacros.pl Repository: Repository Listing bbplugincoursesdistsnplrochestersystemwww

# Annotation of /trunk/pg/macros/dangerousMacros.pl

 1 : sh002i 1050 #!/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 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 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 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 and C , 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 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, 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 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 \n" . 188 : " the loadMacros() statement in the problem template. " . 189 : " The externalTTHPath variable |$main::externalTTHPath| was\n". 190 : " not defined which usually indicates the problem above.
\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 = ; 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 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 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 ",""); 317 : chmod( 0777,$filePath); 318 : print OUTPUT $graph->draw|| warn("$0","Can't print graph to $filePath ",""); 319 : close(OUTPUT)||warn("$0","Can't close $filePath ",""); 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 created by Ian Hutchinson. 331 : The tth program was created by Ian Hutchinson and is freely available 332 : for B at the C main site: C. 333 : 334 : The purpose of C 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 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 file, so if the file is not present in the 343 : course template directory no TeX macro definitions are prepended. C already understands most 344 : Latex commands, but will not, in general know I commands. Additional information 345 : on C is available at the C 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 tth for non-commerical is 352 : http://hutchinson.belmont.ma.us/tth/. 353 : Binaries for many operating systems are available as well as the source code. Links 354 : describing how to obtain tth 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 = ; 380 : local($/); 381 : $/ = undef; 382 :$tthPreambleContents = ;#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 = "</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 = ; 410 :$/ = "\n"; 411 : close(TTH); 412 : }else { 413 : $out = " there has been an error in executing$tthcmd
"; 414 : } 415 : } else { 416 : $out = " Can't execute the program tth at |$tthpath|
"; 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 "" if $mode eq "inline"; 462 : return " " if$mode eq "display"; 463 : } else { 464 : return "[math2img failed]"; 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 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 or C 543 : or in a subdirectory of the C 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 554 : 555 : If the file lies under the C subdirectory, then the approriate URL for the file is created. 556 : Since the C 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 561 : 562 : 563 : GIF files will be translated into an eps file (using system dependent code) 564 : and placed in the directory C. 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 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 578 : 579 : If the file lies under the C subdirectory, then the approriate URL for the file is created. 580 : Since the C 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 585 : 586 : 587 : GIF files will be translated into an eps file (using system dependent code) 588 : and placed in the directory C. 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 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 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 or 606 : C 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 611 : 612 : GIF files will be translated into an eps file (using system dependent code) 613 : and placed in the directory C. 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 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 : "&probNum=$main::probNum" . 687 : "&Mode=$main::displayMode" . 688 : "&course=".$main::courseName . 689 : "&user=" . $user . 690 : "&displayPath=$path_to_file" . 691 : "&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. " . 745 : "Every file name used as an argument to alias must have an extension. " . 746 : "The permissable extensions are .gif, .png, and .html . "; 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| " ; 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| " ; 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 "; 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| " ; 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
"; 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$b} @list> 1082 : C 1083 : 1084 : sorts the list numerically and lexically respectively. 1085 : 1086 : If C 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. 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