--- loncom/xml/lonxml.pm 2001/06/08 17:52:03 1.87
+++ loncom/xml/lonxml.pm 2011/12/06 16:30:19 1.526
@@ -1,50 +1,129 @@
# The LearningOnline Network with CAPA
# XML Parser Module
#
-# last modified 06/26/00 by Alexander Sakharuk
-# 11/6 Gerd Kortemeyer
-# 6/1/1 Gerd Kortemeyer
-# 2/21,3/13 Guy
-# 3/29,5/4 Gerd Kortemeyer
-# 5/10 Scott Harrison
-# 5/26 Gerd Kortemeyer
-# 5/27 H. K. Ng
-# 6/2,6/3,6/8 Gerd Kortemeyer
+# $Id: lonxml.pm,v 1.526 2011/12/06 16:30:19 dseaton Exp $
+#
+# Copyright Michigan State University Board of Trustees
+#
+# This file is part of the LearningOnline Network with CAPA (LON-CAPA).
+#
+# LON-CAPA is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# LON-CAPA is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with LON-CAPA; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+# /home/httpd/html/adm/gpl.txt
+#
+# http://www.lon-capa.org/
+#
+# Copyright for TtHfunc and TtMfunc by Ian Hutchinson.
+# TtHfunc and TtMfunc (the "Code") may be compiled and linked into
+# binary executable programs or libraries distributed by the
+# Michigan State University (the "Licensee"), but any binaries so
+# distributed are hereby licensed only for use in the context
+# of a program or computational system for which the Licensee is the
+# primary author or distributor, and which performs substantial
+# additional tasks beyond the translation of (La)TeX into HTML.
+# The C source of the Code may not be distributed by the Licensee
+# to any other parties under any circumstances.
+#
+
+=pod
+
+=head1 NAME
+
+Apache::lonxml
+
+=head1 SYNOPSIS
+
+XML Parsing Module
+
+This is part of the LearningOnline Network with CAPA project
+described at http://www.lon-capa.org.
+
+
+=head1 SUBROUTINES
+
+=cut
+
+
package Apache::lonxml;
use vars
-qw(@pwd @outputstack $redirection $import @extlinks $metamode $evaluate %insertlist @namespace);
+qw(@pwd @outputstack $redirection $import @extlinks $metamode $evaluate %insertlist @namespace $errorcount $warningcount);
use strict;
-use HTML::TokeParser;
-use Safe;
-use Safe::Hole;
-use Math::Cephes qw(:trigs :hypers :bessels erf erfc);
-use Opcode;
+use LONCAPA;
+use HTML::LCParser();
+use HTML::TreeBuilder();
+use HTML::Entities();
+use Safe();
+use Safe::Hole();
+use Math::Cephes();
+use Math::Random();
+use Opcode();
+use POSIX qw(strftime);
+use Time::HiRes qw( gettimeofday tv_interval );
+use Symbol();
sub register {
- my $space;
- my @taglist;
- my $temptag;
- ($space,@taglist) = @_;
- foreach $temptag (@taglist) {
- $Apache::lonxml::alltags{$temptag}=$space;
+ my ($space,@taglist) = @_;
+ foreach my $temptag (@taglist) {
+ push(@{ $Apache::lonxml::alltags{$temptag} },$space);
}
}
+sub deregister {
+ my ($space,@taglist) = @_;
+ foreach my $temptag (@taglist) {
+ my $tempspace = $Apache::lonxml::alltags{$temptag}[-1];
+ if ($tempspace eq $space) {
+ pop(@{ $Apache::lonxml::alltags{$temptag} });
+ }
+ }
+ #&printalltags();
+}
+
use Apache::Constants qw(:common);
-use Apache::lontexconvert;
-use Apache::style;
-use Apache::run;
-use Apache::londefdef;
-use Apache::scripttag;
-use Apache::edit;
+use Apache::lontexconvert();
+use Apache::style();
+use Apache::run();
+use Apache::londefdef();
+use Apache::scripttag();
+use Apache::languagetags();
+use Apache::edit();
+use Apache::inputtags();
+use Apache::outputtags();
use Apache::lonnet;
-use Apache::File;
+use Apache::File();
+use Apache::loncommon();
+use Apache::lonfeedback();
+use Apache::lonmsg();
+use Apache::loncacc();
+use Apache::lonmaxima();
+use Apache::lonr();
+use Apache::lonlocal;
+use Apache::lonhtmlcommon();
+use Apache::functionplotresponse();
+
+#==================================== Main subroutine: xmlparse
-#================================================== Main subroutine: xmlparse
#debugging control, to turn on debugging modify the correct handler
+
$Apache::lonxml::debug=0;
+# keeps count of the number of warnings and errors generated in a parse
+$warningcount=0;
+$errorcount=0;
+
#path to the directory containing the file currently being processed
@pwd=();
@@ -67,183 +146,132 @@ $evaluate = 1;
# data structure for eidt mode, determines what tags can go into what other tags
%insertlist=();
-#stores the list of active tag namespaces
+# stores the list of active tag namespaces
@namespace=();
-sub xmlbegin {
- my $output='';
- if ($ENV{'browser.mathml'}) {
- $output=''
- .''
- .']>'
- .'';
- } else {
- $output='';
- }
- return $output;
-}
+# stores all Scrit Vars displays for later showing
+my @script_var_displays=();
-sub xmlend {
- return '';
-}
+# a pointer the the Apache request object
+$Apache::lonxml::request='';
-sub fontsettings() {
- my $headerstring='';
- if (($ENV{'browser.os'} eq 'mac') && (!$ENV{'browser.mathml'})) {
- $headerstring.=
- '';
- }
- return $headerstring;
-}
-
-sub registerurl {
- if ($ENV{'REQUEST_URI'}!~/^\/(res\/)*adm\//) {
- my $hwkadd='';
- if ($ENV{'REQUEST_URI'}=~/\.(problem|exam|quiz|assess|survey|form)$/) {
- if (&Apache::lonnet::allowed('vgr',$ENV{'request.course.id'})) {
- $hwkadd.=(<
\n");
- $sub1="$space\:\:$sub";
- $Apache::lonxml::curdepth=join('_',@Apache::lonxml::depthcounter);
- ($currentstring,$nodefault) = &$sub1($target,$token,$tagstack,
- $parstack,$parser,$safeeval,
- $style);
- } else {
- #&Apache::lonxml::debug("NOT Calling sub $sub in $space $metamode
\n");
- if ($metamode <1) {
- if (defined($token->[4]) && ($metamode < 1)) {
- $currentstring = $token->[4];
- } else {
- $currentstring = $token->[2];
- }
- }
+
+ my $deleted=0;
+ if (($token->[0] eq 'S') && ($target eq 'modified')) {
+ $deleted=&Apache::edit::handle_delete($space,$target,$token,$tagstack,
+ $parstack,$parser,$safeeval,
+ $style);
}
-# &Apache::lonxml::debug("nodefalt:$nodefault:");
- if ($currentstring eq '' && $nodefault eq '') {
- if ($target eq 'edit') {
- &Apache::lonxml::debug("doing default edit for $token->[1]");
- if ($token->[0] eq 'S') {
- $currentstring = &Apache::edit::tag_start($target,$token);
- } elsif ($token->[0] eq 'E') {
- $currentstring = &Apache::edit::tag_end($target,$token);
+ if (!$deleted) {
+ if ($space) {
+ #&Apache::lonxml::debug("Calling sub $sub in $space $metamode");
+ $sub1="$space\:\:$sub";
+ ($currentstring,$nodefault) = &$sub1($target,$token,$tagstack,
+ $parstack,$parser,$safeeval,
+ $style);
+ } else {
+ if ($target eq 'tex') {
+ # throw away tag name
+ return '';
+ }
+ #&Apache::lonxml::debug("NOT Calling sub $sub in $space $metamode");
+ if ($metamode <1) {
+ if (defined($token->[4]) && ($metamode < 1)) {
+ $currentstring = $token->[4];
+ } else {
+ $currentstring = $token->[2];
+ }
}
- } elsif ($target eq 'modified') {
- if ($token->[0] eq 'S') {
- $currentstring = $token->[4];
- $currentstring.=&Apache::edit::handle_insert();
- } else {
- $currentstring = $token->[2];
+ }
+ # &Apache::lonxml::debug("nodefalt:$nodefault:");
+ if ($currentstring eq '' && $nodefault eq '') {
+ if ($target eq 'edit') {
+ #&Apache::lonxml::debug("doing default edit for $token->[1]");
+ if ($token->[0] eq 'S') {
+ $currentstring = &Apache::edit::tag_start($target,$token);
+ } elsif ($token->[0] eq 'E') {
+ $currentstring = &Apache::edit::tag_end($target,$token);
+ }
}
}
+ if ($target eq 'modified' && $nodefault eq '') {
+ if ($currentstring eq '') {
+ if ($token->[0] eq 'S') {
+ $currentstring = $token->[4];
+ } elsif ($token->[0] eq 'E') {
+ $currentstring = $token->[2];
+ } else {
+ $currentstring = $token->[2];
+ }
+ }
+ if ($token->[0] eq 'S') {
+ $currentstring.=&Apache::edit::handle_insert();
+ } elsif ($token->[0] eq 'E') {
+ $currentstring.=&Apache::edit::handle_insertafter($token->[1]);
+ }
+ }
}
use strict 'refs';
}
return $currentstring;
}
+{
+ my %state;
+
+ sub init_state {
+ undef(%state);
+ }
+
+ sub set_state {
+ my ($key,$value) = @_;
+ $state{$key} = $value;
+ return $value;
+ }
+ sub get_state {
+ my ($key) = @_;
+ return $state{$key};
+ }
+}
+
+sub setup_globals {
+ my ($request,$target)=@_;
+ $Apache::lonxml::request=$request;
+ $errorcount=0;
+ $warningcount=0;
+ $Apache::lonxml::internal_error=0;
+ $Apache::lonxml::default_homework_loaded=0;
+ $Apache::lonxml::usestyle=1;
+ &init_counter();
+ &clear_bubble_lines_for_part();
+ &init_state();
+ &set_state('target',$target);
+ @Apache::lonxml::pwd=();
+ @Apache::lonxml::extlinks=();
+ @script_var_displays=();
+ @Apache::lonxml::ssi_info=();
+ $Apache::lonxml::post_evaluate=1;
+ $Apache::lonxml::warnings_error_header='';
+ $Apache::lonxml::substitute_LaTeX_symbols = 1;
+ if ($target eq 'meta') {
+ $Apache::lonxml::redirection = 0;
+ $Apache::lonxml::metamode = 1;
+ $Apache::lonxml::evaluate = 1;
+ $Apache::lonxml::import = 0;
+ } elsif ($target eq 'answer') {
+ $Apache::lonxml::redirection = 0;
+ $Apache::lonxml::metamode = 1;
+ $Apache::lonxml::evaluate = 1;
+ $Apache::lonxml::import = 1;
+ } elsif ($target eq 'grade') {
+ &startredirection(); #ended in inner_xmlparse on exit
+ $Apache::lonxml::metamode = 0;
+ $Apache::lonxml::evaluate = 1;
+ $Apache::lonxml::import = 1;
+ } elsif ($target eq 'modified') {
+ $Apache::lonxml::redirection = 0;
+ $Apache::lonxml::metamode = 0;
+ $Apache::lonxml::evaluate = 0;
+ $Apache::lonxml::import = 0;
+ } elsif ($target eq 'edit') {
+ $Apache::lonxml::redirection = 0;
+ $Apache::lonxml::metamode = 0;
+ $Apache::lonxml::evaluate = 0;
+ $Apache::lonxml::import = 0;
+ } elsif ($target eq 'analyze') {
+ $Apache::lonxml::redirection = 0;
+ $Apache::lonxml::metamode = 0;
+ $Apache::lonxml::evaluate = 1;
+ $Apache::lonxml::import = 1;
+ } else {
+ $Apache::lonxml::redirection = 0;
+ $Apache::lonxml::metamode = 0;
+ $Apache::lonxml::evaluate = 1;
+ $Apache::lonxml::import = 1;
+ }
+}
+
sub init_safespace {
my ($target,$safeeval,$safehole,$safeinit) = @_;
+ $safeeval->reval('use Math::Complex;');
+ $safeeval->reval('use LaTeX::Table;');
+ $safeeval->deny_only(':dangerous');
+ $safeeval->permit_only(":default");
$safeeval->permit("entereval");
$safeeval->permit(":base_math");
$safeeval->permit("sort");
+ $safeeval->permit("time");
+ $safeeval->permit("caller");
+ $safeeval->deny("rand");
+ $safeeval->deny("srand");
$safeeval->deny(":base_io");
+ $safehole->wrap(\&Apache::scripttag::xmlparse,$safeeval,'&xmlparse');
+ $safehole->wrap(\&Apache::outputtags::multipart,$safeeval,'&multipart');
$safehole->wrap(\&Apache::lonnet::EXT,$safeeval,'&EXT');
-
+ $safehole->wrap(\&Apache::chemresponse::chem_standard_order,$safeeval,
+ '&chem_standard_order');
+ $safehole->wrap(\&Apache::response::check_status,$safeeval,'&check_status');
+ $safehole->wrap(\&Apache::response::implicit_multiplication,$safeeval,'&implicit_multiplication');
+
+ $safehole->wrap(\&Apache::lonmaxima::maxima_eval,$safeeval,'&maxima_eval');
+ $safehole->wrap(\&Apache::lonmaxima::maxima_check,$safeeval,'&maxima_check');
+ $safehole->wrap(\&Apache::lonmaxima::maxima_cas_formula_fix,$safeeval,
+ '&maxima_cas_formula_fix');
+
+ $safehole->wrap(\&Apache::lonr::r_eval,$safeeval,'&r_eval');
+ $safehole->wrap(\&Apache::lonr::Rentry,$safeeval,'&Rentry');
+ $safehole->wrap(\&Apache::lonr::Rarray,$safeeval,'&Rarray');
+ $safehole->wrap(\&Apache::lonr::r_check,$safeeval,'&r_check');
+ $safehole->wrap(\&Apache::lonr::r_cas_formula_fix,$safeeval,
+ '&r_cas_formula_fix');
+
+ $safehole->wrap(\&Apache::caparesponse::capa_formula_fix,$safeeval,
+ '&capa_formula_fix');
+
+ $safehole->wrap(\&Apache::lonlocal::locallocaltime,$safeeval,
+ '&locallocaltime');
+
$safehole->wrap(\&Math::Cephes::asin,$safeeval,'&asin');
$safehole->wrap(\&Math::Cephes::acos,$safeeval,'&acos');
$safehole->wrap(\&Math::Cephes::atan,$safeeval,'&atan');
@@ -493,145 +701,659 @@ sub init_safespace {
$safehole->wrap(\&Math::Cephes::yn,$safeeval,'&yn');
$safehole->wrap(\&Math::Cephes::yv,$safeeval,'&yv');
+ $safehole->wrap(\&Math::Cephes::bdtr ,$safeeval,'&bdtr' );
+ $safehole->wrap(\&Math::Cephes::bdtrc ,$safeeval,'&bdtrc' );
+ $safehole->wrap(\&Math::Cephes::bdtri ,$safeeval,'&bdtri' );
+ $safehole->wrap(\&Math::Cephes::btdtr ,$safeeval,'&btdtr' );
+ $safehole->wrap(\&Math::Cephes::chdtr ,$safeeval,'&chdtr' );
+ $safehole->wrap(\&Math::Cephes::chdtrc,$safeeval,'&chdtrc');
+ $safehole->wrap(\&Math::Cephes::chdtri,$safeeval,'&chdtri');
+ $safehole->wrap(\&Math::Cephes::fdtr ,$safeeval,'&fdtr' );
+ $safehole->wrap(\&Math::Cephes::fdtrc ,$safeeval,'&fdtrc' );
+ $safehole->wrap(\&Math::Cephes::fdtri ,$safeeval,'&fdtri' );
+ $safehole->wrap(\&Math::Cephes::gdtr ,$safeeval,'&gdtr' );
+ $safehole->wrap(\&Math::Cephes::gdtrc ,$safeeval,'&gdtrc' );
+ $safehole->wrap(\&Math::Cephes::nbdtr ,$safeeval,'&nbdtr' );
+ $safehole->wrap(\&Math::Cephes::nbdtrc,$safeeval,'&nbdtrc');
+ $safehole->wrap(\&Math::Cephes::nbdtri,$safeeval,'&nbdtri');
+ $safehole->wrap(\&Math::Cephes::ndtr ,$safeeval,'&ndtr' );
+ $safehole->wrap(\&Math::Cephes::ndtri ,$safeeval,'&ndtri' );
+ $safehole->wrap(\&Math::Cephes::pdtr ,$safeeval,'&pdtr' );
+ $safehole->wrap(\&Math::Cephes::pdtrc ,$safeeval,'&pdtrc' );
+ $safehole->wrap(\&Math::Cephes::pdtri ,$safeeval,'&pdtri' );
+ $safehole->wrap(\&Math::Cephes::stdtr ,$safeeval,'&stdtr' );
+ $safehole->wrap(\&Math::Cephes::stdtri,$safeeval,'&stdtri');
+
+ $safehole->wrap(\&Math::Cephes::Matrix::mat,$safeeval,'&mat');
+ $safehole->wrap(\&Math::Cephes::Matrix::new,$safeeval,
+ '&Math::Cephes::Matrix::new');
+ $safehole->wrap(\&Math::Cephes::Matrix::coef,$safeeval,
+ '&Math::Cephes::Matrix::coef');
+ $safehole->wrap(\&Math::Cephes::Matrix::clr,$safeeval,
+ '&Math::Cephes::Matrix::clr');
+ $safehole->wrap(\&Math::Cephes::Matrix::add,$safeeval,
+ '&Math::Cephes::Matrix::add');
+ $safehole->wrap(\&Math::Cephes::Matrix::sub,$safeeval,
+ '&Math::Cephes::Matrix::sub');
+ $safehole->wrap(\&Math::Cephes::Matrix::mul,$safeeval,
+ '&Math::Cephes::Matrix::mul');
+ $safehole->wrap(\&Math::Cephes::Matrix::div,$safeeval,
+ '&Math::Cephes::Matrix::div');
+ $safehole->wrap(\&Math::Cephes::Matrix::inv,$safeeval,
+ '&Math::Cephes::Matrix::inv');
+ $safehole->wrap(\&Math::Cephes::Matrix::transp,$safeeval,
+ '&Math::Cephes::Matrix::transp');
+ $safehole->wrap(\&Math::Cephes::Matrix::simq,$safeeval,
+ '&Math::Cephes::Matrix::simq');
+ $safehole->wrap(\&Math::Cephes::Matrix::mat_to_vec,$safeeval,
+ '&Math::Cephes::Matrix::mat_to_vec');
+ $safehole->wrap(\&Math::Cephes::Matrix::vec_to_mat,$safeeval,
+ '&Math::Cephes::Matrix::vec_to_mat');
+ $safehole->wrap(\&Math::Cephes::Matrix::check,$safeeval,
+ '&Math::Cephes::Matrix::check');
+ $safehole->wrap(\&Math::Cephes::Matrix::check,$safeeval,
+ '&Math::Cephes::Matrix::check');
+
+# $safehole->wrap(\&Math::Cephes::new_fract,$safeeval,'&new_fract');
+# $safehole->wrap(\&Math::Cephes::radd,$safeeval,'&radd');
+# $safehole->wrap(\&Math::Cephes::rsub,$safeeval,'&rsub');
+# $safehole->wrap(\&Math::Cephes::rmul,$safeeval,'&rmul');
+# $safehole->wrap(\&Math::Cephes::rdiv,$safeeval,'&rdiv');
+# $safehole->wrap(\&Math::Cephes::euclid,$safeeval,'&euclid');
+
+ $safehole->wrap(\&Math::Random::random_beta,$safeeval,'&math_random_beta');
+ $safehole->wrap(\&Math::Random::random_chi_square,$safeeval,'&math_random_chi_square');
+ $safehole->wrap(\&Math::Random::random_exponential,$safeeval,'&math_random_exponential');
+ $safehole->wrap(\&Math::Random::random_f,$safeeval,'&math_random_f');
+ $safehole->wrap(\&Math::Random::random_gamma,$safeeval,'&math_random_gamma');
+ $safehole->wrap(\&Math::Random::random_multivariate_normal,$safeeval,'&math_random_multivariate_normal');
+ $safehole->wrap(\&Math::Random::random_multinomial,$safeeval,'&math_random_multinomial');
+ $safehole->wrap(\&Math::Random::random_noncentral_chi_square,$safeeval,'&math_random_noncentral_chi_square');
+ $safehole->wrap(\&Math::Random::random_noncentral_f,$safeeval,'&math_random_noncentral_f');
+ $safehole->wrap(\&Math::Random::random_normal,$safeeval,'&math_random_normal');
+ $safehole->wrap(\&Math::Random::random_permutation,$safeeval,'&math_random_permutation');
+ $safehole->wrap(\&Math::Random::random_permuted_index,$safeeval,'&math_random_permuted_index');
+ $safehole->wrap(\&Math::Random::random_uniform,$safeeval,'&math_random_uniform');
+ $safehole->wrap(\&Math::Random::random_poisson,$safeeval,'&math_random_poisson');
+ $safehole->wrap(\&Math::Random::random_uniform_integer,$safeeval,'&math_random_uniform_integer');
+ $safehole->wrap(\&Math::Random::random_negative_binomial,$safeeval,'&math_random_negative_binomial');
+ $safehole->wrap(\&Math::Random::random_binomial,$safeeval,'&math_random_binomial');
+ $safehole->wrap(\&Math::Random::random_seed_from_phrase,$safeeval,'&random_seed_from_phrase');
+ $safehole->wrap(\&Math::Random::random_set_seed_from_phrase,$safeeval,'&random_set_seed_from_phrase');
+ $safehole->wrap(\&Math::Random::random_get_seed,$safeeval,'&random_get_seed');
+ $safehole->wrap(\&Math::Random::random_set_seed,$safeeval,'&random_set_seed');
+ $safehole->wrap(\&Apache::loncommon::languages,$safeeval,'&languages');
+ $safehole->wrap(\&Apache::lonxml::error,$safeeval,'&LONCAPA_INTERNAL_ERROR');
+ $safehole->wrap(\&Apache::lonxml::debug,$safeeval,'&LONCAPA_INTERNAL_DEBUG');
+ $safehole->wrap(\&Apache::lonnet::logthis,$safeeval,'&LONCAPA_INTERNAL_LOGTHIS');
+ $safehole->wrap(\&Apache::inputtags::finalizeawards,$safeeval,'&LONCAPA_INTERNAL_FINALIZEAWARDS');
+ $safehole->wrap(\&Apache::caparesponse::get_sigrange,$safeeval,'&LONCAPA_INTERNAL_get_sigrange');
+ $safehole->wrap(\&Apache::functionplotresponse::fpr_val,$safeeval,'&fpr_val');
+ $safehole->wrap(\&Apache::functionplotresponse::fpr_f,$safeeval,'&fpr_f');
+ $safehole->wrap(\&Apache::functionplotresponse::fpr_dfdx,$safeeval,'&fpr_dfdx');
+ $safehole->wrap(\&Apache::functionplotresponse::fpr_d2fdx2,$safeeval,'&fpr_d2fdx2');
+ $safehole->wrap(\&Apache::functionplotresponse::fpr_vectorcoords,$safeeval,'&fpr_vectorcoords');
+ $safehole->wrap(\&Apache::functionplotresponse::fpr_objectcoords,$safeeval,'&fpr_objectcoords');
+ $safehole->wrap(\&Apache::functionplotresponse::fpr_vectorlength,$safeeval,'&fpr_vectorlength');
+ $safehole->wrap(\&Apache::functionplotresponse::fpr_vectorangle,$safeeval,'&fpr_vectorangle');
+
+# use Data::Dumper;
+# $safehole->wrap(\&Data::Dumper::Dumper,$safeeval,'&LONCAPA_INTERNAL_Dumper');
#need to inspect this class of ops
# $safeeval->deny(":base_orig");
- $safeinit .= ';$external::target='.$target.';';
- $safeinit .= ';$external::randomseed='.&Apache::lonnet::rndseed().';';
+ $safeeval->permit("require");
+ $safeinit .= ';$external::target="'.$target.'";';
&Apache::run::run($safeinit,$safeeval);
+ &initialize_rndseed($safeeval);
+}
+
+sub clean_safespace {
+ my ($safeeval) = @_;
+ delete_package_recurse($safeeval->{Root});
+}
+
+sub delete_package_recurse {
+ my ($package) = @_;
+ my @subp;
+ {
+ no strict 'refs';
+ while (my ($key,$val) = each(%{*{"$package\::"}})) {
+ if (!defined($val)) { next; }
+ local (*ENTRY) = $val;
+ if (defined *ENTRY{HASH} && $key =~ /::$/ &&
+ $key ne "main::" && $key ne "
s $Apache::lonxml::depth : $Apache::lonxml::olddepth : $curdepth : $token->[1]\n";
}
sub decreasedepth {
my ($token) = @_;
- $Apache::lonxml::depth--;
- if ($Apache::lonxml::depth<$Apache::lonxml::olddepth-1) {
- $#Apache::lonxml::depthcounter--;
- $Apache::lonxml::olddepth=$Apache::lonxml::depth+1;
- }
- if ( $Apache::lonxml::depth < -1) {
- &Apache::lonxml::warning("Unbalanced tags in resource");
- $Apache::lonxml::depth='-1';
+ if ( $#Apache::lonxml::depthcounter == -1) {
+ &Apache::lonxml::warning(&mt("Missing tags, unable to properly run file."));
+ }
+ $Apache::lonxml::last_depth_count = pop(@Apache::lonxml::depthcounter);
+
+ my ($timer,$time);
+ if ($Apache::lonxml::debug eq "1") {
+ $timer=pop(@timers);
+ $time=&tv_interval($lasttime);
+ $lasttime=[&gettimeofday()];
}
- my $curdepth=join('_',@Apache::lonxml::depthcounter);
- &Apache::lonxml::debug("e $Apache::lonxml::depth : $Apache::lonxml::olddepth : $token->[1] : $curdepth\n");
+ my $spacing=' 'x($#Apache::lonxml::depthcounter);
+ $Apache::lonxml::curdepth = join('_',@Apache::lonxml::depthcounter);
+# &Apache::lonxml::debug("e$spacing$Apache::lonxml::depth : $Apache::lonxml::olddepth : $Apache::lonxml::curdepth : $token->[1] : $time : ".&tv_interval($timer));
#print "
e $Apache::lonxml::depth : $Apache::lonxml::olddepth : $token->[1] : $curdepth\n";
}
-sub get_all_text {
+sub get_id {
+ my ($parstack,$safeeval)=@_;
+ my $id= &Apache::lonxml::get_param('id',$parstack,$safeeval);
+ if ($env{'request.state'} eq 'construct' && $id =~ /([._]|[^\w\d\s[:punct:]])/) {
+ &error(&mt('ID [_1] contains invalid characters. IDs are only allowed to contain letters, numbers, spaces and -','"'.$id.'"'));
+ }
+ if ($id =~ /^\s*$/) { $id = $Apache::lonxml::curdepth; }
+ return $id;
+}
+
+sub get_all_text_unbalanced {
+#there is a copy of this in lonpublisher.pm
+ my($tag,$pars)= @_;
+ my $token;
+ my $result='';
+ $tag='<'.$tag.'>';
+ while ($token = $$pars[-1]->get_token) {
+ if (($token->[0] eq 'T')||($token->[0] eq 'C')||($token->[0] eq 'D')) {
+ if ($token->[0] eq 'T' && $token->[2]) {
+ $result.='[1].']]>';
+ } else {
+ $result.=$token->[1];
+ }
+ } elsif ($token->[0] eq 'PI') {
+ $result.=$token->[2];
+ } elsif ($token->[0] eq 'S') {
+ $result.=$token->[4];
+ } elsif ($token->[0] eq 'E') {
+ $result.=$token->[2];
+ }
+ if ($result =~ /\Q$tag\E/is) {
+ ($result,my $redo)=$result =~ /(.*)\Q$tag\E(.*)/is;
+ #&Apache::lonxml::debug('Got a winner with leftovers ::'.$2);
+ #&Apache::lonxml::debug('Result is :'.$1);
+ $redo=$tag.$redo;
+ &Apache::lonxml::newparser($pars,\$redo);
+ last;
+ }
+ }
+ return $result
- my($tag,$pars)= @_;
- my $depth=0;
- my $token;
- my $result='';
- if ( $tag =~ m:^/: ) {
- my $tag=substr($tag,1);
-# &Apache::lonxml::debug("have:$tag:");
- while (($depth >=0) && ($token = $pars->get_token)) {
-# &Apache::lonxml::debug("e token:$token->[0]:$depth:$token->[1]");
- if (($token->[0] eq 'T')||($token->[0] eq 'C')||($token->[0] eq 'D')) {
- $result.=$token->[1];
- } elsif ($token->[0] eq 'PI') {
- $result.=$token->[2];
- } elsif ($token->[0] eq 'S') {
- if ($token->[1] eq $tag) { $depth++; }
- $result.=$token->[4];
- } elsif ($token->[0] eq 'E') {
- if ( $token->[1] eq $tag) { $depth--; }
- #skip sending back the last end tag
- if ($depth > -1) { $result.=$token->[2]; } else {
- $pars->unget_token($token);
- }
- }
- }
- } else {
- while ($token = $pars->get_token) {
-# &Apache::lonxml::debug("s token:$token->[0]:$depth:$token->[1]");
- if (($token->[0] eq 'T')||($token->[0] eq 'C')||($token->[0] eq 'D')) {
- $result.=$token->[1];
- } elsif ($token->[0] eq 'PI') {
- $result.=$token->[2];
- } elsif ($token->[0] eq 'S') {
- if ( $token->[1] eq $tag) {
- $pars->unget_token($token); last;
- } else {
- $result.=$token->[4];
- }
- } elsif ($token->[0] eq 'E') {
- $result.=$token->[2];
- }
- }
- }
-# &Apache::lonxml::debug("Exit:$result:");
- return $result
+}
+
+#########################################################################
+# #
+# bubble line counter management #
+# #
+#########################################################################
+
+=pod
+
+For bubble grading mode and exam bubble printing mode, the tracking of
+the current 'bubble line number' is stored in the %env element
+'form.counter', and is modifed and handled by the following routines.
+
+The value of it is stored in $Apache:lonxml::counter when live and
+stored back to env after done.
+
+=item &increment_counter($increment, $part_response);
+
+Increments the internal counter environment variable a specified amount
+
+Optional Arguments:
+ $increment - amount to increment by (defaults to 1)
+ Also 1 if the value is negative or zero.
+ $part_response - A concatenation of the part and response id
+ identifying exactly what is being 'answered'.
+
+
+=cut
+
+sub increment_counter {
+ my ($increment, $part_response) = @_;
+ if ($env{'form.grade_noincrement'}) { return; }
+ if (!defined($increment) || $increment le 0) {
+ $increment = 1;
+ }
+ $Apache::lonxml::counter += $increment;
+
+ # If the caller supplied the response_id parameter,
+ # Maintain its counter.. creating if necessary.
+
+ if (defined($part_response)) {
+ if (!defined($Apache::lonxml::counters_per_part{$part_response})) {
+ $Apache::lonxml::counters_per_part{$part_response} = 0;
+ }
+ $Apache::lonxml::counters_per_part{$part_response} += $increment;
+ my $new_value = $Apache::lonxml::counters_per_part{$part_response};
+ }
+
+ $Apache::lonxml::counter_changed=1;
+}
+
+=pod
+
+=item &init_counter($increment);
+
+Initialize the internal counter environment variable
+
+=cut
+
+sub init_counter {
+ if ($env{'request.state'} eq 'construct') {
+ $Apache::lonxml::counter=1;
+ $Apache::lonxml::counter_changed=1;
+ } elsif (defined($env{'form.counter'})) {
+ $Apache::lonxml::counter=$env{'form.counter'};
+ $Apache::lonxml::counter_changed=0;
+ } else {
+ $Apache::lonxml::counter=1;
+ $Apache::lonxml::counter_changed=1;
+ }
+}
+
+sub store_counter {
+ &Apache::lonnet::appenv({'form.counter' => $Apache::lonxml::counter});
+ $Apache::lonxml::counter_changed=0;
+ return '';
+}
+
+{
+ my $state;
+ sub clear_problem_counter {
+ undef($state);
+ &Apache::lonnet::delenv('form.counter');
+ &Apache::lonxml::init_counter();
+ &Apache::lonxml::store_counter();
+ }
+
+ sub remember_problem_counter {
+ &Apache::lonnet::transfer_profile_to_env(undef,undef,1);
+ $state = $env{'form.counter'};
+ }
+
+ sub restore_problem_counter {
+ if (defined($state)) {
+ &Apache::lonnet::appenv({'form.counter' => $state});
+ }
+ }
+ sub get_problem_counter {
+ if ($Apache::lonxml::counter_changed) { &store_counter() }
+ &Apache::lonnet::transfer_profile_to_env(undef,undef,1);
+ return $env{'form.counter'};
+ }
+}
+
+=pod
+
+=item bubble_lines_for_part(part_response)
+
+Returns the number of lines required to get a response for
+$part_response (this is just $Apache::lonxml::counters_per_part{$part_response}
+
+=cut
+
+sub bubble_lines_for_part {
+ my ($part_response) = @_;
+
+ if (!defined($Apache::lonxml::counters_per_part{$part_response})) {
+ return 0;
+ } else {
+ return $Apache::lonxml::counters_per_part{$part_response};
+ }
+}
+
+=pod
+
+=item clear_bubble_lines_for_part
+
+Clears the hash of bubble lines per part. If a caller
+needs to analyze several resources this should be called between
+resources to reset the hash for each problem being analyzed.
+
+=cut
+
+sub clear_bubble_lines_for_part {
+ undef(%Apache::lonxml::counters_per_part);
+}
+
+=pod
+
+=item set_bubble_lines(part_response, value)
+
+If there is a problem part, that for whatever reason
+requires bubble lines that are not
+the same as the counter increment, it can call this sub during
+analysis to set its hash value explicitly.
+
+=cut
+
+sub set_bubble_lines {
+ my ($part_response, $value) = @_;
+
+ $Apache::lonxml::counters_per_part{$part_response} = $value;
+}
+
+=pod
+
+=item get_bubble_line_hash
+
+Returns the current bubble line hash. This is assumed to
+be small so we return a copy
+
+
+=cut
+
+sub get_bubble_line_hash {
+ return %Apache::lonxml::counters_per_part;
+}
+
+
+#--------------------------------------------------
+
+sub get_all_text {
+ my($tag,$pars,$style)= @_;
+ my $gotfullstack=1;
+ if (ref($pars) ne 'ARRAY') {
+ $gotfullstack=0;
+ $pars=[$pars];
+ }
+ if (ref($style) ne 'HASH') {
+ $style={};
+ }
+ my $depth=0;
+ my $token;
+ my $result='';
+ if ( $tag =~ m:^/: ) {
+ my $tag=substr($tag,1);
+ #&Apache::lonxml::debug("have:$tag:");
+ my $top_empty=0;
+ while (($depth >=0) && ($#$pars > -1) && (!$top_empty)) {
+ while (($depth >=0) && ($token = $$pars[-1]->get_token)) {
+ #&Apache::lonxml::debug("e token:$token->[0]:$depth:$token->[1]:".$#$pars.":".$#Apache::lonxml::pwd);
+ if (($token->[0] eq 'T')||($token->[0] eq 'C')||($token->[0] eq 'D')) {
+ if ($token->[2]) {
+ $result.='[1].']]>';
+ } else {
+ $result.=$token->[1];
+ }
+ } elsif ($token->[0] eq 'PI') {
+ $result.=$token->[2];
+ } elsif ($token->[0] eq 'S') {
+ if ($token->[1] =~ /^\Q$tag\E$/i) { $depth++; }
+ if ($token->[1] =~ /^LONCAPA_INTERNAL_TURN_STYLE_ON$/) { $Apache::lonxml::usestyle=1; }
+ if ($token->[1] =~ /^LONCAPA_INTERNAL_TURN_STYLE_OFF$/) { $Apache::lonxml::usestyle=0; }
+ $result.=$token->[4];
+ } elsif ($token->[0] eq 'E') {
+ if ( $token->[1] =~ /^\Q$tag\E$/i) { $depth--; }
+ #skip sending back the last end tag
+ if ($depth == 0 && exists($$style{'/'.$token->[1]}) && $Apache::lonxml::usestyle) {
+ my $string=
+ ''.
+ &HTML::Entities::encode($result,'<>&"').
+ '
');
+ if ($gotfullstack) {
+ my $newstring=''.$tag.'>'.$result;
+ &Apache::lonxml::newparser($pars,\$newstring);
+ }
+ $result='';
+ }
+ } else {
+ while ($#$pars > -1) {
+ while ($token = $$pars[-1]->get_token) {
+ #&Apache::lonxml::debug("s token:$token->[0]:$depth:$token->[1]");
+ if (($token->[0] eq 'T')||($token->[0] eq 'C')||
+ ($token->[0] eq 'D')) {
+ if ($token->[2]) {
+ $result.='[1].']]>';
+ } else {
+ $result.=$token->[1];
+ }
+ } elsif ($token->[0] eq 'PI') {
+ $result.=$token->[2];
+ } elsif ($token->[0] eq 'S') {
+ if ( $token->[1] =~ /^\Q$tag\E$/i) {
+ $$pars[-1]->unget_token($token); last;
+ } else {
+ $result.=$token->[4];
+ }
+ if ($token->[1] =~ /^LONCAPA_INTERNAL_TURN_STYLE_ON$/) { $Apache::lonxml::usestyle=1; }
+ if ($token->[1] =~ /^LONCAPA_INTERNAL_TURN_STYLE_OFF$/) { $Apache::lonxml::usestyle=0; }
+ } elsif ($token->[0] eq 'E') {
+ $result.=$token->[2];
+ }
+ }
+ if (($#$pars > 0) ) {
+ pop(@$pars);
+ pop(@Apache::lonxml::pwd);
+ } else { last; }
+ }
+ }
+ #&Apache::lonxml::debug("Exit:$result:");
+ return $result
}
sub newparser {
my ($parser,$contentref,$dir) = @_;
- push (@$parser,HTML::TokeParser->new($contentref));
- $$parser['-1']->xml_mode('1');
+ push (@$parser,HTML::LCParser->new($contentref));
+ $$parser[-1]->xml_mode(1);
+ $$parser[-1]->marked_sections(1);
if ( $dir eq '' ) {
push (@Apache::lonxml::pwd, $Apache::lonxml::pwd[$#Apache::lonxml::pwd]);
} else {
push (@Apache::lonxml::pwd, $dir);
}
-# &Apache::lonxml::debug("pwd:$#Apache::lonxml::pwd");
-# &Apache::lonxml::debug("pwd:$Apache::lonxml::pwd[$#Apache::lonxml::pwd]");
}
sub parstring {
- my ($token) = @_;
- my $temp='';
- map {
- unless ($_=~/\W/) {
- my $val=$token->[2]->{$_};
- $val =~ s/([\%\@\\])/\\$1/g;
- #if ($val =~ m/^[\%\@]/) { $val="\\".$val; }
- $temp .= "my \$$_=\"$val\";"
+ my ($token) = @_;
+ my (@vars,@values);
+ foreach my $attr (@{$token->[3]}) {
+ if ($attr!~/\W/) {
+ my $val=$token->[2]->{$attr};
+ $val =~ s/([\%\@\\\"\'])/\\$1/g;
+ $val =~ s/(\$[^\{a-zA-Z_])/\\$1/g;
+ $val =~ s/(\$)$/\\$1/;
+ #if ($val =~ m/^[\%\@]/) { $val="\\".$val; }
+ push(@vars,"\$$attr");
+ push(@values,"\"$val\"");
+ }
+ }
+ my $var_init =
+ (@vars) ? 'my ('.join(',',@vars).') = ('.join(',',@values).');'
+ : '';
+ return $var_init;
+}
+
+sub extlink {
+ my ($res,$exact)=@_;
+ if (!$exact) {
+ $res=&Apache::lonnet::hreflocation($Apache::lonxml::pwd[-1],$res);
}
- } @{$token->[3]};
- return $temp;
+ push(@Apache::lonxml::extlinks,$res)
}
sub writeallows {
- my $thisurl='/res/'.&Apache::lonnet::declutter(shift);
+ unless ($#extlinks>=0) { return; }
+ my $thisurl = &Apache::lonnet::clutter(shift);
+ if ($env{'httpref.'.$thisurl}) {
+ $thisurl=$env{'httpref.'.$thisurl};
+ }
my $thisdir=$thisurl;
$thisdir=~s/\/[^\/]+$//;
my %httpref=();
- map {
+ foreach (@extlinks) {
$httpref{'httpref.'.
- &Apache::lonnet::hreflocation($thisdir,$_)}=$thisurl; } @extlinks;
- &Apache::lonnet::appenv(%httpref);
+ &Apache::lonnet::hreflocation($thisdir,&unescape($_))}=$thisurl;
+ }
+ @extlinks=();
+ &Apache::lonnet::appenv(\%httpref);
+}
+
+sub register_ssi {
+ my ($url,%form)=@_;
+ push (@Apache::lonxml::ssi_info,{'url'=>$url,'form'=>\%form});
+ return '';
+}
+
+sub do_registered_ssi {
+ foreach my $info (@Apache::lonxml::ssi_info) {
+ my %form=%{ $info->{'form'}};
+ my $url=$info->{'url'};
+ &Apache::lonnet::ssi($url,%form);
+ }
+}
+
+sub add_script_result {
+ my ($display) = @_;
+ push(@script_var_displays, $display);
}
#
@@ -639,39 +1361,31 @@ sub writeallows {
#
sub afterburn {
my $result=shift;
- map {
- my ($name, $value) = split(/=/,$_);
- $value =~ tr/+/ /;
- $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C",hex($1))/eg;
- if (($name eq 'highlight')||($name eq 'anchor')||($name eq 'link')) {
- unless ($ENV{'form.'.$name}) {
- $ENV{'form.'.$name}=$value;
- }
- }
- } (split(/&/,$ENV{'QUERY_STRING'}));
- if ($ENV{'form.highlight'}) {
- map {
+ &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},
+ ['highlight','anchor','link']);
+ if ($env{'form.highlight'}) {
+ foreach (split(/\,/,$env{'form.highlight'})) {
my $anchorname=$_;
my $matchthis=$anchorname;
$matchthis=~s/\_+/\\s\+/g;
- $result=~s/($matchthis)/\$1\<\/font\>/gs;
- } split(/\,/,$ENV{'form.highlight'});
+ $result=~s/(\Q$matchthis\E)/\$1\<\/font\>/gs;
+ }
}
- if ($ENV{'form.link'}) {
- map {
+ if ($env{'form.link'}) {
+ foreach (split(/\,/,$env{'form.link'})) {
my ($anchorname,$linkurl)=split(/\>/,$_);
my $matchthis=$anchorname;
$matchthis=~s/\_+/\\s\+/g;
- $result=~s/($matchthis)/\$1\<\/a\>/gs;
- } split(/\,/,$ENV{'form.link'});
+ $result=~s/(\Q$matchthis\E)/\$1\<\/a\>/gs;
+ }
}
- if ($ENV{'form.anchor'}) {
- my $anchorname=$ENV{'form.anchor'};
+ if ($env{'form.anchor'}) {
+ my $anchorname=$env{'form.anchor'};
my $matchthis=$anchorname;
$matchthis=~s/\_+/\\s\+/g;
- $result=~s/($matchthis)/\$1\<\/a\>/s;
+ $result=~s/(\Q$matchthis\E)/\$1\<\/a\>/s;
$result.=(<<"ENDSCRIPT");
-
ENDSCRIPT
@@ -681,179 +1395,893 @@ ENDSCRIPT
sub storefile {
my ($file,$contents)=@_;
+ &Apache::lonnet::correct_line_ends(\$contents);
if (my $fh=Apache::File->new('>'.$file)) {
print $fh $contents;
$fh->close();
+ return 1;
+ } else {
+ &warning(&mt('Unable to save file [_1]',''.$file.''));
+ return 0;
}
}
-sub inserteditinfo {
- my ($result,$filecontents)=@_;
- unless ($filecontents) {
- $filecontents=(<
';
my $editfooter=(<