[system] / trunk / pg / lib / PGloadfiles.pm Repository:
ViewVC logotype

View of /trunk/pg/lib/PGloadfiles.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 6261 - (download) (as text) (annotate)
Sat May 15 18:41:23 2010 UTC (9 years, 6 months ago) by gage
File size: 17349 byte(s)
added fixes to PGalias.pm and PGcore.pm related to using $self-> in contexts
where the binding was not as expected (e.g.  in 'blah'. $self->{foobar} .'blah' )

Other minor fixes and improvements.

    1 ################################################################################
    2 # WeBWorK Online Homework Delivery System
    3 # Copyright © 2000-2007 The WeBWorK Project, http://openwebwork.sf.net/
    4 # $CVSHeader: pg/lib/PGloadfiles.pm,v 1.1 2010/05/14 11:39:02 gage Exp $
    5 #
    6 # This program is free software; you can redistribute it and/or modify it under
    7 # the terms of either: (a) the GNU General Public License as published by the
    8 # Free Software Foundation; either version 2, or (at your option) any later
    9 # version, or (b) the "Artistic License" which comes with this package.
   10 #
   11 # This program is distributed in the hope that it will be useful, but WITHOUT
   12 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   13 # FOR A PARTICULAR PURPOSE.  See either the GNU General Public License or the
   14 # Artistic License for more details.
   15 ################################################################################
   16 
   17 =head2
   18 
   19 The module name spaces loaded in dangerousMacros are:
   20 
   21   PGrandom (if not previously loaded)
   22   WWPlot
   23   Fun
   24   Label
   25   Circle
   26 
   27 in addition the subroutine &evaluate_units is shared from the module Units.
   28 
   29 =cut
   30 
   31 # BEGIN {
   32 #   be_strict(); # an alias for use strict.  This means that all global variable must contain main:: as a prefix.
   33 #
   34 # }
   35 #
   36 # # ^variable my $debugON
   37 # my $debugON = 0;
   38 #
   39 # # grab read only variables from the current safe compartment
   40 #
   41 # # ^variable my $macrosPath
   42 # my ($macrosPath,
   43 #     # ^variable my $pwd
   44 #     $pwd,
   45 #     # ^variable my $appletPath
   46 #     $appletPath,
   47 #     # ^variable my $server_root_url
   48 #     $server_root_url,
   49 #   # ^variable my $templateDirectory
   50 #   $templateDirectory,
   51 #   # ^variable my $scriptDirectory
   52 #   $scriptDirectory,
   53 #   # ^variable my $externalTTHPath
   54 #   $externalTTHPath,
   55 #   );
   56 #
   57 # # ^function _dangerousMacros_init
   58 # # ^uses %envir
   59 # # ^uses $macrosPath
   60 # # ^uses $pwd
   61 # # ^uses $appletPath
   62 # # ^uses $server_root_url
   63 # # ^uses $templateDirectory
   64 # # ^uses $scriptDirectory
   65 # # ^uses $externalTTHPath
   66 # # ^uses $debugON
   67 # sub _dangerousMacros_init {   #use  envir instead of local variables?
   68 #     # will allow easy addition of new directories -- is this too liberal? do some pg directories need to be protected?
   69 #     $macrosPath               = eval('$main::envir{pgDirectories}{macrosPath}');
   70 #     # will allow easy addition of new directories -- is this too liberal? do some pg directories need to be protected?
   71 #     $pwd                      = eval('$main::envir{fileName}'); $pwd =~ s!/[^/]*$!!;
   72 #     $appletPath               = eval('$main::envir{pgDirectories}{appletPath}');
   73 #     $server_root_url          = eval('$main::envir{server_root_url}');
   74 #
   75 #     $templateDirectory        = eval('$main::envir{templateDirectory}');
   76 #     $scriptDirectory          = eval('$main::envir{scriptDirectory}');
   77 #     $externalTTHPath          = eval('$main::envir{externalTTHPath}');
   78 #     $pwd = $templateDirectory.$pwd unless substr($pwd,0,1) eq '/';
   79 #     $pwd =~ s!/tmpEdit/!/!;
   80 #     warn "dangerousmacros initialized" if $debugON;
   81 #     warn eval(q! "dangerousmacros.pl externalTTHPath is ".$main::externalTTHPath;!) if $debugON;
   82 #     warn eval(q! "dangerousmacros.pl:  The envir variable $main::{envir} is".join(" ",%main::envir)!) if $debugON;
   83 # }
   84 #
   85 # # ^function _dangerousMacros_export
   86 # sub _dangerousMacros_export {
   87 #   my @EXPORT= (
   88 #       '&_dangerousMacros_init',
   89 #     '&alias',
   90 #     '&compile_file',
   91 #     '&insertGraph',
   92 #     '&loadMacros',
   93 #     '&HEADER_TEXT',
   94 #     '&sourceAlias',
   95 #     '&tth',
   96 #   );
   97 #   @EXPORT;
   98 # }
   99 
  100 
  101 =head2 loadMacros
  102 
  103   loadMacros(@macroFiles)
  104 
  105 loadMacros takes a list of file names and evaluates the contents of each file.
  106 This is used to load macros which define and augment the PG language. The macro
  107 files are searched for in the directories specified by the array referenced by
  108 $macrosPath, which by default is the current course's macros directory followed
  109 by WeBWorK's pg/macros directory. The latter is where the default behaviour of
  110 the PG language is defined. The default path is set in the global.conf file.
  111 
  112 Macro files named PG.pl, IO.pl, or dangerousMacros.pl will be loaded with no
  113 opcode restrictions, hence any code in those files will be able to execute
  114 privileged operations. This is true no matter which macro directory the file is
  115 in. For example, if $macrosPath contains the path to a problem library macros
  116 directory which contains a PG.pl file, this file will be loaded and allowed to
  117 engage in privileged behavior.
  118 
  119 =head3 Overloading macro files
  120 
  121 An individual course can modify the PG language, for that course only, by
  122 duplicating one of the macro files in the system-wide macros directory and
  123 placing this file in the macros directory for the course. The new file in the
  124 course's macros directory will now be used instead of the file in the
  125 system-wide macros directory.
  126 
  127 The new file in the course macros directory can by modified by adding macros or
  128 modifying existing macros.
  129 
  130 =head3 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
  135 depend on the 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
  137 on the modified behavior of existing macros will not work in other courses
  138 unless the macros are also transferred to the new course.  It helps to document
  139 the  problems by indicating any special macros which the problems require.
  140 
  141 There is no facility for modifying or overloading a single macro. The entire
  142 file containing the macro 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 WeBWorK in other courses.
  146 
  147 =cut
  148 
  149 our $debugON =0;
  150 
  151 package PGloadfiles;
  152 use strict;
  153 use Exporter;
  154 use PGcore;
  155 use WeBWorK::PG::Translator;
  156 use WeBWorK::PG::IO;
  157 
  158 our @ISA = qw ( PGcore  ) ;  # look up features in PGcore -- in this case we want the environment.
  159 
  160 
  161 
  162 
  163 # Global variables used
  164 #   ${main::macrosPath}
  165 # Global macros used
  166 # None
  167 
  168 # Because of the need to use the directory variables it is tricky to define this
  169 # in translate.pl since, as currently written, the directories are not available
  170 # at that time.  Perhaps if I rewrite translate as an object that method will work.
  171 
  172 # The only difficulty with defining loadMacros inside the Safe compartment is that
  173 # the error reporting does not work with syntax errors.
  174 # A kludge using require works around this problem
  175 
  176 # our ($macrosPath,
  177 #     # ^variable my $pwd
  178 #     $pwd,
  179 #     # ^variable my $appletPath
  180 #     $appletPath,
  181 #     # ^variable my $server_root_url
  182 #     $server_root_url,
  183 #   # ^variable my $templateDirectory
  184 #   $templateDirectory,
  185 #   # ^variable my $scriptDirectory
  186 #   $scriptDirectory,
  187 #   # ^variable my $externalTTHPath
  188 #   $externalTTHPath,
  189 #   );
  190 # sub _dangerousMacros_init {   #use  envir instead of local variables?
  191 #     # will allow easy addition of new directories -- is this too liberal? do some pg directories need to be protected?
  192 #     $macrosPath               = eval('$main::envir{pgDirectories}{macrosPath}');
  193 #     # will allow easy addition of new directories -- is this too liberal? do some pg directories need to be protected?
  194 #     $pwd                      = eval('$main::envir{fileName}'); $pwd =~ s!/[^/]*$!!;
  195 #     $appletPath               = eval('$main::envir{pgDirectories}{appletPath}');
  196 #     $server_root_url          = eval('$main::envir{server_root_url}');
  197 #
  198 #     $templateDirectory        = eval('$main::envir{templateDirectory}');
  199 #     $scriptDirectory          = eval('$main::envir{scriptDirectory}');
  200 #     $externalTTHPath          = eval('$main::envir{externalTTHPath}');
  201 #     $pwd = $templateDirectory.$pwd unless substr($pwd,0,1) eq '/';
  202 #     $pwd =~ s!/tmpEdit/!/!;
  203 #     warn "dangerousmacros initialized" if $debugON;
  204 #     warn eval(q! "dangerousmacros.pl externalTTHPath is ".$main::externalTTHPath;!) if $debugON;
  205 #     warn eval(q! "dangerousmacros.pl:  The envir variable $main::{envir} is".join(" ",%main::envir)!) if $debugON;
  206 # }
  207 # new
  208 #   Create one loadfiles object per question (and per PGcore object)
  209 #   Process macro files
  210 #   Keep list of macro files processed.
  211 sub new {
  212   my $class = shift;
  213   my $envir = shift;  #pointer to environment hash
  214   warn "PGloadmacros must be called with an environment" unless ref($envir) eq 'HASH';
  215   my $self = {
  216     envir   =>  $envir,
  217     macroFileList    => {},    # records macros used in compilation
  218     pgFileName       => '',    # current pg file being processed
  219     server_root_url  => '',    # how do we find this?
  220     macrosPath       => '',
  221     pwd              => '',    # current directory -- defined in initialize
  222   };
  223   bless $self, $class;
  224   $self->initialize;
  225   #$self->check_parameters;
  226   return $self;
  227 }
  228 sub initialize {
  229   my $self = shift;
  230   my $templateDirectory = $self->{envir}->{templateDirectory};
  231   my $pwd = $self->{envir}->{fileName};
  232   $pwd =~ s!/[^/]*$!!;
  233     $pwd = $templateDirectory.$pwd unless substr($pwd,0,1) eq '/';
  234     $pwd =~ s!/tmpEdit/!/!;
  235   $self->{pwd} = $pwd;
  236   $self->{macrosPath} = $self->{envir}->{pgDirectories}->{macrosPath};
  237 
  238 }
  239 
  240 sub PG_restricted_eval {
  241   my $self = shift;
  242   WeBWorK::PG::Translator::PG_restricted_eval(@_);
  243 }
  244 sub PG_macro_file_eval {
  245   my $self = shift;
  246   WeBWorK::PG::Translator::PG_macro_file_eval(@_);
  247 }
  248 
  249 
  250 # ^function loadMacros
  251 # ^uses time_it
  252 # ^uses $debugON
  253 # ^uses $externalTTHPath
  254 # ^uses findMacroFile
  255 sub loadMacros {
  256   my $self = shift;
  257     my @files = @_;
  258     my $fileName;
  259     my $macrosPath = $self->{envir}->{macrosPath};
  260     eval {main::time_it("begin load macros");};
  261     ###############################################################################
  262   # At this point the directories have been defined from %envir and we can define
  263   # the directories for this file
  264   ###############################################################################
  265 
  266   # special case inits
  267 #   foreach my $file ('PG.pl','dangerousMacros.pl','IO.pl') {
  268 #       my $macro_file_name = $file;
  269 #     $macro_file_name =~s/\.pl//;  # trim off the extension
  270 #     $macro_file_name =~s/\.pg//;  # sometimes the extension is .pg (e.g. CAPA files)
  271 #     my $init_subroutine_name = "_${macro_file_name}_init";
  272 #       my $init_subroutine  = eval { \&{$init_subroutine_name} };
  273 #     use strict;
  274 #         my $macro_file_loaded = defined($init_subroutine);
  275 #         warn "dangerousMacros: macro init $init_subroutine_name defined |$init_subroutine| |$macro_file_loaded|" if $debugON;
  276 #     if ( defined($init_subroutine) && defined( &{$init_subroutine} ) ) {
  277 #
  278 #         warn "dangerousMacros:  initializing $macro_file_name"  if $debugON;
  279 #         &$init_subroutine();
  280 #     }
  281 #   }
  282   #FIXME -- how to check that things are defined properly
  283 #     unless (defined( &DOCUMENT)){
  284 #       warn "WARNING::Please make sure that the DOCUMENT() statement comes before<BR>\n" .
  285 #            " the loadMacros() statement in the problem template.<p>" .
  286 #            " The externalTTHPath variable |$externalTTHPath| was\n".
  287 #            " not defined which usually indicates the problem above.<br>\n";
  288 #
  289 #     }
  290     #warn "running load macros";
  291 
  292     while (@files) {
  293         $fileName = shift @files;
  294         next  if ($fileName =~ /^PG.pl$/) ;    # the PG.pl macro package is already loaded.
  295 
  296         my $macro_file_name = $fileName;
  297     $macro_file_name =~s/\.pl//;  # trim off the extension
  298     $macro_file_name =~s/\.pg//;  # sometimes the extension is .pg (e.g. CAPA files)
  299     my $init_subroutine_name = "_${macro_file_name}_init";
  300     $init_subroutine_name =~ s![^a-zA-Z0-9_]!_!g;  # remove dangerous chars
  301 
  302     ###############################################################################
  303     # For some reason the "no stict" which works on webwork-db doesn't work on
  304     # webwork.  For this reason the constuction &{$init_subroutine_name}
  305     # was abandoned and replaced by eval.  This is considerably more dangerous
  306     # since one could hide something nasty in a file name.
  307     #  Keep an eye on this ???
  308     # webwork-db used perl 5.6.1 and webwork used perl 5.6.0
  309     ###############################################################################
  310 
  311     # compile initialization subroutine. (5.6.0 version)
  312 
  313 
  314 #   eval( q{ \$init_subroutine = \\&main::}.$init_subroutine_name);
  315 #   warn "dangerousMacros: failed to compile $init_subroutine_name. $@" if $@;
  316 
  317 
  318     ###############################################################################
  319     #compile initialization subroutine. (5.6.1 version) also works with 5.6.0
  320 
  321 #     no strict;
  322     my $init_subroutine  = eval { \&{'main::'.$init_subroutine_name} };
  323 #     use strict;
  324 
  325     ###############################################################################
  326 
  327         # macros are searched for in the directories listed in the $macrosPath array reference.
  328 
  329         my $macro_file_loaded = defined($init_subroutine) && defined(&$init_subroutine);
  330         warn "dangerousMacros: macro init $init_subroutine_name defined |$init_subroutine| |$macro_file_loaded|"  if $debugON;
  331         unless ($macro_file_loaded) {
  332           warn "loadMacros: loading macro file $fileName\n" if $debugON;
  333     my $filePath = $self->findMacroFile($fileName);
  334     #### (check for renamed files here?) ####
  335     if ($filePath) {
  336       $self->compile_file($filePath);
  337       warn "loadMacros is compiling $filePath\n" if $debugON;
  338     }
  339     else {
  340       die "Can't locate macro file |$fileName| via path: |".join("|, |",@{$macrosPath})."|";
  341     }
  342     }
  343     ###############################################################################
  344     # Try again to define the initialization subroutine. (5.6.0 version)
  345 
  346 #   eval( q{ \$init_subroutine = \\&main::}.$init_subroutine_name );
  347 #   warn "dangerousMacros: failed to compile $init_subroutine_name. $@" if $@;
  348 #   $init_subroutine = $temp::rf_init_subroutine;
  349     ###############################################################################
  350     # Try again to define the initialization subroutine. (5.6.1 version) also works with 5.6.0
  351 
  352 #     no strict;
  353     $init_subroutine  = eval { \&{'main::'.$init_subroutine_name} };
  354 #     use strict;
  355     ###############################################################################
  356     #warn "loadMacros: defining \$temp::rf_init_subroutine ",$temp::rf_init_subroutine;
  357        $macro_file_loaded = defined($init_subroutine) && defined(&$init_subroutine);
  358        warn "dangerousMacros: macro init $init_subroutine_name defined |$init_subroutine| |$macro_file_loaded|" if $debugON;
  359 
  360     if ( defined($init_subroutine) && defined( &{$init_subroutine} ) ) {
  361         warn "dangerousMacros:  initializing $macro_file_name" if $debugON;
  362         &$init_subroutine();
  363     }
  364     #warn "main:: contains <br>\n $macro_file_name ".join("<br>\n $macro_file_name ", %main::);
  365   }
  366   #arn "files loaded:", join(" ", keys %{ $self->{macroFileList} });
  367   eval{main::time_it("end load macros");};
  368 }
  369 
  370 
  371 # ^function findMacroFile
  372 # ^uses $macrosPath
  373 # ^uses $pwd
  374 sub findMacroFile {
  375   my $self   = shift;
  376   my $macroFileName = shift;
  377   my $macroFilePath;
  378   my $pwd = $self->{pwd};
  379   foreach my $dir (@{$self->{macrosPath} } ) {
  380     $macroFilePath = "$dir/$macroFileName";
  381     $macroFilePath =~ s!^\.\.?/!$pwd/!;
  382     return $macroFilePath if (-r $macroFilePath);
  383   }
  384   return;  # no file found
  385 }
  386 # errors in compiling macros is not always being reported.
  387 # ^function compile_file
  388 # ^uses @__eval__
  389 # ^uses PG_restricted_eval
  390 # ^uses $__files__
  391 sub compile_file {
  392     my $self     = shift;
  393   my $filePath = shift;
  394   warn "loading $filePath" if $debugON;
  395   local(*MACROFILE);
  396   local($/);
  397   $/ = undef;   # allows us to treat the file as a single line
  398   open(MACROFILE, "<$filePath") || die "Cannot open file: $filePath";
  399   my $string = <MACROFILE>;
  400   #warn "compiling $string";
  401   my ($result,$error,$fullerror) = $self->PG_macro_file_eval($string);
  402   #eval ('$main::__files__->{pop @main::__eval__} = $filePath');
  403   if ($error) {    # the $fullerror report has formatting and is never empty
  404                 # this is now handled by PG_errorMessage() in the PG translator
  405     #$fullerror =~ s/\(eval \d+\)/ $filePath\n/;   # attempt to insert file name instead of eval number
  406     die "Error detected while loading $filePath:\n$fullerror";
  407 
  408   }
  409   $self->{macroFileList}->{$filePath} =1;
  410   close(MACROFILE);
  411 
  412 }
  413 
  414 
  415 
  416 
  417 
  418 
  419 =head2 sourceAlias
  420 
  421   sourceAlias($path_to_PG_file);
  422 
  423 Returns a relative URL to the F<source.pl> script, which may be installed in a
  424 course's F<html> directory to allow formatted viewing of the problem source.
  425 
  426 =cut
  427 
  428 # ^function sourceAlias
  429 # ^uses PG_restricted_eval
  430 # ^uses %envir
  431 # ^uses $envir{inputs_ref}
  432 # ^uses $envir{psvn}
  433 # ^uses $envir{probNum}
  434 # ^uses $envir{displayMode}
  435 # ^uses $envir{courseName}
  436 # ^uses $envir{sessionKey}
  437 sub sourceAlias {
  438   my $self         = shift;
  439   my $path_to_file = shift;
  440   my $envir        =  PG_restricted_eval(q!\%main::envir!);
  441   my $user         = $envir->{inputs_ref}->{user};
  442   $user            = " " unless defined($user);
  443     my $out = 'source.pl?probSetKey='  . $envir->{psvn}.
  444           '&amp;probNum='          . $envir->{probNum} .
  445           '&amp;Mode='             . $envir->{displayMode} .
  446           '&amp;course='           . $envir->{courseName} .
  447           '&amp;user='             . $user .
  448         '&amp;displayPath='      . $path_to_file .
  449           '&amp;key='              . $envir->{sessionKey};
  450 
  451    $out;
  452 }
  453 
  454 
  455 1;

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9