[system] / trunk / webwork-modperl / lib / WeBWorK / PG / Translator.pm Repository:
ViewVC logotype

Diff of /trunk/webwork-modperl/lib/WeBWorK/PG/Translator.pm

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

Revision 1248 Revision 1249
11use Safe; 11use Safe;
12use Net::SMTP; 12use Net::SMTP;
13use WeBWorK::Utils qw(runtime_use); 13use WeBWorK::Utils qw(runtime_use);
14use WeBWorK::PG::IO; 14use WeBWorK::PG::IO;
15 15
16
16# loading GD within the Safe compartment has occasionally caused infinite recursion 17# loading GD within the Safe compartment has occasionally caused infinite recursion
17# Putting these use statements here seems to avoid this problem 18# Putting these use statements here seems to avoid this problem
18# It is not clear that this is essential once things are working properly. 19# It is not clear that this is essential once things are working properly.
19#use Exporter; 20#use Exporter;
20#use DynaLoader; 21#use DynaLoader;
91 92
92=cut 93=cut
93 94
94sub evaluate_modules { 95sub evaluate_modules {
95 my $self = shift; 96 my $self = shift;
97 my @modules = @_;
96 local $SIG{__DIE__} = "DEFAULT"; # we're going to be eval()ing code 98 local $SIG{__DIE__} = "DEFAULT"; # we're going to be eval()ing code
97 foreach (@_) { 99 foreach (@modules) {
98 #warn "attempting to load $_\n"; 100 #warn "attempting to load $_\n";
99 # ensure that the name is in fact a base name 101 # ensure that the name is in fact a base name
100 s/\.pm$// and warn "fixing your broken package name: $_.pm => $_"; 102 s/\.pm$// and warn "fixing your broken package name: $_.pm => $_";
101 # call runtime_use on the package name 103 # call runtime_use on the package name
102 # don't worry -- runtime_use won't load a package twice! 104 # don't worry -- runtime_use won't load a package twice!
104 warn "Failed to evaluate module $_: $@" if $@; 106 warn "Failed to evaluate module $_: $@" if $@;
105 # record this in the appropriate place 107 # record this in the appropriate place
106 push @{$self->{ra_included_modules}}, "\%${_}::"; 108 push @{$self->{ra_included_modules}}, "\%${_}::";
107 } 109 }
108} 110}
109 111# old code for runtime_use
112# if ( -r "${courseScriptsDirectory}${module_name}.pm" ) {
113# eval(qq! require "${courseScriptsDirectory}${module_name}.pm"; import ${module_name};! );
114# warn "Errors in including the module ${courseScriptsDirectory}$module_name.pm $@" if $@;
115# } else {
116# eval(qq! require "${module_name}.pm"; import ${module_name};! );
117# warn "Errors in including either the module $module_name.pm or ${courseScriptsDirectory}${module_name}.pm $@" if $@;
118# }
110=head2 load_extra_packages 119=head2 load_extra_packages
111 120
112 Usage: $obj -> load_extra_packages('AlgParserWithImplicitExpand', 121 Usage: $obj -> load_extra_packages('AlgParserWithImplicitExpand',
113 'Expr','ExprWithImplicitExpand'); 122 'Expr','ExprWithImplicitExpand');
114 123
235# 2, there is no longer a global namespace. To get around this, IO functions 244# 2, there is no longer a global namespace. To get around this, IO functions
236# which need access to course-specific data are now defined in the IO.pl macro 245# which need access to course-specific data are now defined in the IO.pl macro
237# file, which has access to the problem environment. Several entries have been 246# file, which has access to the problem environment. Several entries have been
238# added to the problem environment to support this move. 247# added to the problem environment to support this move.
239# 248#
249
250
251# Useful for timing portions of the translating process
252# The timer $WeBWorK::timer0 is defined in the module WeBWorK.pm
253# You must make sure that the code in that script for initialzing the
254# timer is active.
255
256sub time_it {
257 my $msg = shift;
258 $WeBWorK::timer0->continue($msg) if defined($WeBWorK::timer0);
259}
260
240my %shared_subroutine_hash = ( 261my %shared_subroutine_hash = (
262 'time_it' => 'Translator',
241 '&PG_answer_eval' => 'Translator', 263 '&PG_answer_eval' => 'Translator',
242 '&PG_restricted_eval' => 'Translator', 264 '&PG_restricted_eval' => 'Translator',
243 '&be_strict' => 'Translator', 265 '&be_strict' => 'Translator',
244 '&PGsort' => 'Translator', 266 '&PGsort' => 'Translator',
245 '&dumpvar' => 'Translator', 267 '&dumpvar' => 'Translator',
250 #'&surePathToTmpFile' => 'IO', # moved to IO.pl 272 #'&surePathToTmpFile' => 'IO', # moved to IO.pl
251 '&fileFromPath' => 'IO', 273 '&fileFromPath' => 'IO',
252 '&directoryFromPath' => 'IO', 274 '&directoryFromPath' => 'IO',
253 '&createFile' => 'IO', 275 '&createFile' => 'IO',
254 '&createDirectory' => 'IO', 276 '&createDirectory' => 'IO',
255 '&getImageDimmensions' => 'IO', 277# '&getImageDimmensions' => 'IO',
256 '&dvipng' => 'IO', 278# '&dvipng' => 'IO',
257); 279);
258 280
259sub initialize { 281sub initialize {
260 my $self = shift; 282 my $self = shift;
261 my $safe_cmpt = $self->{safe}; 283 my $safe_cmpt = $self->{safe};
268 #local($rf_answer_eval) = sub { $self->PG_answer_eval(@_); }; 290 #local($rf_answer_eval) = sub { $self->PG_answer_eval(@_); };
269 #local($rf_restricted_eval) = sub { $self->PG_restricted_eval(@_); }; 291 #local($rf_restricted_eval) = sub { $self->PG_restricted_eval(@_); };
270 #$safe_cmpt -> share('$rf_answer_eval'); 292 #$safe_cmpt -> share('$rf_answer_eval');
271 #$safe_cmpt -> share('$rf_restricted_eval'); 293 #$safe_cmpt -> share('$rf_restricted_eval');
272 use strict; 294 use strict;
273 295
274 # ra_included_modules is now populated independantly of @class_modules:
275 #$self->{ra_included_modules} = [@class_modules];
276
277 $safe_cmpt -> share_from('main', $self->{ra_included_modules} ); 296 $safe_cmpt -> share_from('main', $self->{ra_included_modules} );
278 # the above line will get changed when we fix the PG modules thing. heh heh. 297 # the above line will get changed when we fix the PG modules thing. heh heh.
298}
299
300
301################################################################
302# Preloading the macro files
303################################################################
304
305# Preloading the macro files can significantly speed up the translation process.
306# Files are read into a separate safe compartment (typically Safe::Root1::)
307# This means that all non-explicit subroutine references and those explicitly prefixed by main::
308# are prefixed by Safe::Root1::
309# These subroutines (but not the constants) are then explicitly exported to the current
310# safe compartment Safe::Rootx::
311
312# Although they are not large, it is important to import PG.pl and dangerousMacros.pl into the
313# cached safe compartment as well. This is because a call in PGbasicmacros.pl to NEW_ANSWER_NAME
314# which is defined in PG.pl would actually be a call to Safe::Root1::NEW_ANSWER_NAME since
315# PGbasicmacros is compiled into the SAfe::Root1:: compartment. If PG.pl has only been compiled into
316# the current Safe compartment, this call will fail. There are many calls between PG.pl, dangerousMacros,
317# PGbasicmacros and PGanswermacros so it is easiest to have all of them defined in Safe::Root1::
318# There subroutines are still available in the current safe compartment.
319# Sharing the hash %Safe::Root1:: in the current compartment means that any references to Safe::Root1::NEW_ANSWER_NAME
320# will be found as long as NEW_ANSWER_NAME has been defined in Safe::Root1::
321#
322# Constants and references to subroutines in other macro files have to be handled carefully in preloaded files.
323# For example a call to main::display_matrix (defined in PGmatrixmacros.pl) will become Safe::Root1::display_matrix and
324# will fail since PGmatrixmacros.pl is loaded only into the current safe compartment Safe::Rootx::.
325# The value of main:: has to be evaluated at runtime in order to make this work. Hence something like
326# my $temp_code = eval('\&main::display_matrix');
327# &$temp_code($matrix_object_to_be_displayed);
328# in PGanswermacros.pl
329# would reference the run time value of main::, namely Safe::Rootx::
330# There may be a clearer or more efficient way to obtain the runtime value of main::
331
332
333sub pre_load_macro_files {
334 time_it("Begin pre_load_macro_files");
335 my $self = shift;
336 my $cached_safe_cmpt = shift;
337 my $dirName = shift;
338 my @fileNameList = @_;
339 my $debugON = 0; # This helps with debugging the loading of macro files
340
341################################################################
342# prepare safe_cache
343################################################################
344 $cached_safe_cmpt -> share(keys %shared_subroutine_hash);
345 no strict;
346 local(%envir) = %{ $self ->{envir} };
347 $cached_safe_cmpt -> share('%envir');
348 use strict;
349 $cached_safe_cmpt -> share_from('main', $self->{ra_included_modules} );
350 $cached_safe_cmpt->mask(Opcode::full_opset()); # allow no operations
351 $cached_safe_cmpt->permit(qw( :default ));
352 $cached_safe_cmpt->permit(qw(time)); # used to determine whether solutions are visible.
353 $cached_safe_cmpt->permit(qw( atan2 sin cos exp log sqrt ));
354
355 # just to make sure we'll deny some things specifically
356 $cached_safe_cmpt->deny(qw(entereval));
357 $cached_safe_cmpt->deny(qw ( unlink symlink system exec ));
358 $cached_safe_cmpt->deny(qw(print require));
359
360################################################################
361# read in macro files
362################################################################
363
364 foreach my $fileName (@fileNameList) {
365 # determine whether the file has already been loaded by checking for
366 # subroutine named _${macro_file_name}_init
367 my $macro_file_name = $fileName;
368 $macro_file_name =~s/\.pl//; # trim off the extension
369 $macro_file_name =~s/\.pg//; # sometimes the extension is .pg (e.g. CAPA files)
370 my $init_subroutine_name = "_${macro_file_name}_init";
371 my $macro_file_loaded = defined(&{$cached_safe_cmpt->root."::$init_subroutine_name"}) ? 1 : 0;
372
373
374 if ( $macro_file_loaded ) {
375 warn "$macro_file_name is already loaded" if $debugON;
376 }else {
377 warn "reading and evaluating $macro_file_name from $dirName/$fileName" if $debugON;
378 ### read in file
379 my $filePath = "$dirName/$fileName";
380 local(*MACROFILE);
381 local($/);
382 $/ = undef; # allows us to treat the file as a single line
383 open(MACROFILE, "<$filePath") || die "Cannot open file: $filePath";
384 my $string = <MACROFILE>;
385 close(MACROFILE);
386
387
388################################################################
389# Evaluate macro files
390################################################################
391# FIXME The following hardwired behavior should be modifiable
392# either in the procedure call or in global.conf:
393#
394# PG.pl, IO.pl and dangerousMacros.pl are loaded without restriction
395# All other files are loaded with restriction
396#
397 my $store_mask;
398 if ($fileName =~ /PG.pl|dangerousMacros.pl|IO.pl/) {
399 $store_mask = $cached_safe_cmpt->mask();
400 $cached_safe_cmpt ->mask(Opcode::empty_opset());
401 }
402 $cached_safe_cmpt -> reval("package main;\n" .$string);
403 warn "preload Macros: errors in compiling $macro_file_name:<br> $@" if $@;
404 if ($fileName eq 'PG.pl') {
405 $cached_safe_cmpt ->mask($store_mask);
406 warn "mask restored after $fileName" if $debugON;
407 }
408
409
410 }
411 }
412
413################################################################################
414# load symbol table
415################################################################################
416 warn "begin loading symbol table " if $debugON;
417 no strict 'refs';
418 my %symbolHash = %{$cached_safe_cmpt->root.'::'};
419 use strict 'refs';
420 my @subroutine_names;
421
422 foreach my $name (keys %symbolHash) {
423 # weed out internal symbols
424 next if $name =~ /^(INC|_|__ANON__|main::)$/;
425 if ( defined(&{*{$symbolHash{$name}}}) ) {
426# warn "subroutine $name" if $debugON;;
427 push(@subroutine_names, "&$name");
428 }
429 }
430
431 warn "Loading symbols into active safe compartment:<br> ", join(" ",sort @subroutine_names) if $debugON;
432 $self->{safe} -> share_from($cached_safe_cmpt->root,[@subroutine_names]);
433
434 # Also need to share the cached safe compartment symbol hash in the current safe compartment.
435 # This is necessary because the macro files have been read into the cached safe compartment
436 # So all subroutines have the implied names Safe::Root1::subroutine
437 # When they call each other we need to make sure that they can reach each other
438 # through the Safe::Root1 symbol table.
439
440 $self->{safe} -> share('%'.$cached_safe_cmpt->root.'::');
441 warn 'Sharing '.'%'. $cached_safe_cmpt->root. '::' if $debugON;
442 time_it("End pre_load_macro_files");
443 # return empty string.
444 '';
279} 445}
280 446
281sub environment{ 447sub environment{
282 my $self = shift; 448 my $self = shift;
283 my $envirref = shift; 449 my $envirref = shift;

Legend:
Removed from v.1248  
changed lines
  Added in v.1249

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9