Diff for /loncom/xml/lonxml.pm between versions 1.298 and 1.318

version 1.298, 2004/01/28 16:10:26 version 1.318, 2004/05/21 21:07:54
Line 36 Line 36
 # The C source of the Code may not be distributed by the Licensee  # The C source of the Code may not be distributed by the Licensee
 # to any other parties under any circumstances.  # to any other parties under any circumstances.
 #  #
 # 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/26 Gerd Kortemeyer  
 # 5/27 H. K. Ng  
 # 6/2,6/3,6/8,6/9 Gerd Kortemeyer  
 # 6/12,6/13 H. K. Ng  
 # 6/16 Gerd Kortemeyer  
 # 7/27 H. K. Ng  
 # 8/7,8/9,8/10,8/11,8/15,8/16,8/17,8/18,8/20,8/23,8/24 Gerd Kortemeyer  
 # Guy Albertelli  
 # 9/26 Gerd Kortemeyer  
 # Dec Guy Albertelli  
 # YEAR=2002  
 # 1/1 Gerd Kortemeyer  
 # 1/2 Matthew Hall  
 # 1/3 Gerd Kortemeyer  
 #  
   
 package Apache::lonxml;   package Apache::lonxml; 
 use vars   use vars 
 qw(@pwd @outputstack $redirection $import @extlinks $metamode $evaluate %insertlist @namespace $prevent_entity_encode $errorcount $warningcount);  qw(@pwd @outputstack $redirection $import @extlinks $metamode $evaluate %insertlist @namespace $errorcount $warningcount);
 use strict;  use strict;
 use HTML::LCParser();  use HTML::LCParser();
 use HTML::TreeBuilder();  use HTML::TreeBuilder();
Line 141  $evaluate = 1; Line 122  $evaluate = 1;
 # stores the list of active tag namespaces  # stores the list of active tag namespaces
 @namespace=();  @namespace=();
   
 # if 0 all high ASCII characters will be encoded into HTML Entities  
 $prevent_entity_encode=0;  
   
 # has the dynamic menu been updated to know about this resource  # has the dynamic menu been updated to know about this resource
 $Apache::lonxml::registered=0;  $Apache::lonxml::registered=0;
   
Line 401  sub latex_special_symbols { Line 379  sub latex_special_symbols {
     my ($string,$where)=@_;      my ($string,$where)=@_;
     if ($where eq 'header') {      if ($where eq 'header') {
  $string =~ s/(\\|_|\^)/ /g;   $string =~ s/(\\|_|\^)/ /g;
  $string =~ s/(\$|%|\#|&|\{|\})/\\$1/g;   $string =~ s/(\$|%|\{|\})/\\$1/g;
  $string =~ s/_/ /g;   $string =~ s/_/ /g;
    $string=&Apache::lonprintout::character_chart($string);
    # any & or # leftover should be safe to just escape
           $string=~s/([^\\])\&/$1\\\&/g;
           $string=~s/([^\\])\#/$1\\\#/g;
     } else {      } else {
  $string=~s/\\ /\\char92 /g;   $string=~s/\\/\\ensuremath{\\backslash}/g;
  $string=~s/\^/\\\^ /g;   $string=~s/([^\\]|^)\%/$1\\\%/g;
  $string=~s/\~/\\char126 /g;   $string=~s/([^\\]|^)(\$|_)/$1\\$2/g;
  #fixup & if it doesn't look like   $string=~s/\$\$/\$\\\$/g;
         # { or α   $string=~s/\#\#/\#\\\#/g;
  $string=~s/(&(?!((\#[0-9]+)|([a-z]+));))/\\$1/gi;          $string=~s/([^\\]|^)(\~|\^)/$1\\$2\\strut /g;
  $string=~s/([^&])\#/$1\\#/g;   $string=~s/(>|<)/\\ensuremath\{$1\}/g; #more or less
  $string=~s/(\$|_|{|})/\\$1/g;   $string=&Apache::lonprintout::character_chart($string);
  $string=~s/\\char92 /\\texttt{\\char92}/g;   # any & or # leftover should be safe to just escape
  $string=~s/(>|<)/\$$1\$/g; #more or less          $string=~s/([^\\]|^)\&/$1\\\&/g;
  if ($string=~m/\d%/) {$string =~ s/(\d)%/$1\\%/g;} #percent after digit          $string=~s/([^\\]|^)\#/$1\\\#/g;
  if ($string=~m/\s%/) {$string =~ s/(\s)%/$1\\%/g;} #percent after space  #single { or } How to escape?
  if ($string eq '%.') {$string = '\%.';} #percent at the end of statement  
     }      }
     return $string;      return $string;
 }  }
Line 479  sub inner_xmlparse { Line 460  sub inner_xmlparse {
     #clear out any tags that didn't end      #clear out any tags that didn't end
     while ($token->[1] ne $$stack['-1'] && ($#$stack > -1)) {      while ($token->[1] ne $$stack['-1'] && ($#$stack > -1)) {
  my $lasttag=$$stack[-1];   my $lasttag=$$stack[-1];
  if ($token->[1] =~ /^$lasttag$/i) {   if ($token->[1] =~ /^\Q$lasttag\E$/i) {
     &Apache::lonxml::warning('Using tag &lt;/'.$token->[1].'&gt; on line '.$token->[3].' as end tag to &lt;'.$$stack[-1].'&gt;');      &Apache::lonxml::warning('Using tag &lt;/'.$token->[1].'&gt; on line '.$token->[3].' as end tag to &lt;'.$$stack[-1].'&gt;');
     last;      last;
  } else {   } else {
Line 514  sub inner_xmlparse { Line 495  sub inner_xmlparse {
   }    }
       }        }
   
       # Encode any high ASCII characters  
 #      if (!$Apache::lonxml::prevent_entity_encode) {  
 # $result=&HTML::Entities::encode($result,"\200-\377");  
 #      }  
       if ($Apache::lonxml::redirection) {        if ($Apache::lonxml::redirection) {
  $Apache::lonxml::outputstack['-1'] .= $result;   $Apache::lonxml::outputstack['-1'] .= $result;
       } else {        } else {
Line 547  sub inner_xmlparse { Line 524  sub inner_xmlparse {
   return $finaloutput;    return $finaloutput;
 }  }
   
   ## 
   ## Looks to see if there is a subroutine defined for this tag.  If so, call it,
   ## otherwise do not call it as we do not know what it is.
   ##
 sub callsub {  sub callsub {
   my ($sub,$target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;    my ($sub,$target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_;
   my $currentstring='';    my $currentstring='';
Line 579  sub callsub { Line 560  sub callsub {
      $parstack,$parser,$safeeval,       $parstack,$parser,$safeeval,
      $style);       $style);
       } else {        } else {
             if ($target eq 'tex') {
                 # throw away tag name
                 return '';
             }
  #&Apache::lonxml::debug("NOT Calling sub $sub in $space $metamode");   #&Apache::lonxml::debug("NOT Calling sub $sub in $space $metamode");
  if ($metamode <1) {   if ($metamode <1) {
   if (defined($token->[4]) && ($metamode < 1)) {    if (defined($token->[4]) && ($metamode < 1)) {
Line 749  sub init_safespace { Line 734  sub init_safespace {
   $safehole->wrap(\&Math::Random::random_set_seed_from_phrase,$safeeval,'&random_set_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_get_seed,$safeeval,'&random_get_seed');
   $safehole->wrap(\&Math::Random::random_set_seed,$safeeval,'&random_set_seed');    $safehole->wrap(\&Math::Random::random_set_seed,$safeeval,'&random_set_seed');
     $safehole->wrap(\&Apache::lonxml::error,$safeeval,'&LONCAPA_INTERNAL_ERROR');
     $safehole->wrap(\&Apache::lonxml::debug,$safeeval,'&LONCAPA_INTERNAL_DEBUG');
   
 #need to inspect this class of ops  #need to inspect this class of ops
 # $safeeval->deny(":base_orig");  # $safeeval->deny(":base_orig");
Line 759  sub init_safespace { Line 746  sub init_safespace {
   $safeinit .= ';$external::randomseed='.$rndseed.';';    $safeinit .= ';$external::randomseed='.$rndseed.';';
   &Apache::lonxml::debug("Setting rndseed to $rndseed");    &Apache::lonxml::debug("Setting rndseed to $rndseed");
   &Apache::run::run($safeinit,$safeeval);    &Apache::run::run($safeinit,$safeeval);
   
     my $subroutine=<<'EVALUATESUB';
   sub __LC_INTERNAL_EVALUATE__ {
       my ($__LC__a,$__LC__b,$__LC__c)=@_;
       my $__LC__prefix;
       while(1){
    { 
       use strict;
       no strict "vars";
       if (eval(defined(eval($__LC__a.$__LC__b)))) {
    return $__LC__prefix.eval($__LC__a.$__LC__b.$__LC__c);
       }
    }
    $__LC__prefix.=substr($__LC__a,0,1,"");
    if ($__LC__a!~/^(\$|&|\#)/) { last; }
       }
       return $__LC__prefix.$__LC__a.$__LC__b.$__LC__c;
   }
   EVALUATESUB
       $safeeval->permit("require");
       $safeeval->reval($subroutine);
       $safeeval->deny("require");
 }  }
   
 sub default_homework_load {  sub default_homework_load {
Line 844  sub get_all_text_unbalanced { Line 853  sub get_all_text_unbalanced {
    } elsif ($token->[0] eq 'E')  {     } elsif ($token->[0] eq 'E')  {
      $result.=$token->[2];       $result.=$token->[2];
    }     }
    if ($result =~ /(.*)\Q$tag\E(.*)/s) {     if ($result =~ /(.*)\Q$tag\E(.*)/is) {
      &Apache::lonxml::debug('Got a winner with leftovers ::'.$2);       &Apache::lonxml::debug('Got a winner with leftovers ::'.$2);
      &Apache::lonxml::debug('Result is :'.$1);       &Apache::lonxml::debug('Result is :'.$1);
      $result=$1;       $result=$1;
Line 906  sub get_all_text { Line 915  sub get_all_text {
  } elsif ($token->[0] eq 'PI') {   } elsif ($token->[0] eq 'PI') {
     $result.=$token->[2];      $result.=$token->[2];
  } elsif ($token->[0] eq 'S') {   } elsif ($token->[0] eq 'S') {
     if ($token->[1] =~ /^$tag$/i) { $depth++; }      if ($token->[1] =~ /^\Q$tag\E$/i) { $depth++; }
     if ($token->[1] =~ /^LONCAPA_INTERNAL_TURN_STYLE_ON$/i) { $Apache::lonxml::usestyle=1; }      if ($token->[1] =~ /^LONCAPA_INTERNAL_TURN_STYLE_ON$/) { $Apache::lonxml::usestyle=1; }
     if ($token->[1] =~ /^LONCAPA_INTERNAL_TURN_STYLE_OFF$/i) { $Apache::lonxml::usestyle=0; }      if ($token->[1] =~ /^LONCAPA_INTERNAL_TURN_STYLE_OFF$/) { $Apache::lonxml::usestyle=0; }
     $result.=$token->[4];      $result.=$token->[4];
  } elsif ($token->[0] eq 'E')  {   } elsif ($token->[0] eq 'E')  {
     if ( $token->[1] =~ /^$tag$/i) { $depth--; }      if ( $token->[1] =~ /^\Q$tag\E$/i) { $depth--; }
     #skip sending back the last end tag      #skip sending back the last end tag
     if ($depth == 0 && exists($$style{'/'.$token->[1]}) && $Apache::lonxml::usestyle) {      if ($depth == 0 && exists($$style{'/'.$token->[1]}) && $Apache::lonxml::usestyle) {
  my $string=   my $string=
Line 940  sub get_all_text { Line 949  sub get_all_text {
     #never found the end tag ran out of text, throw error send back blank      #never found the end tag ran out of text, throw error send back blank
     &error('Never found end tag for &lt;'.$tag.      &error('Never found end tag for &lt;'.$tag.
    '&gt; current string <pre>'.     '&gt; current string <pre>'.
    &HTML::Entities::encode($result).     &HTML::Entities::encode($result,'<>&"').
    '</pre>');     '</pre>');
     if ($gotfullstack) {      if ($gotfullstack) {
  my $newstring='</'.$tag.'>'.$result;   my $newstring='</'.$tag.'>'.$result;
Line 958  sub get_all_text { Line 967  sub get_all_text {
  } elsif ($token->[0] eq 'PI') {   } elsif ($token->[0] eq 'PI') {
     $result.=$token->[2];      $result.=$token->[2];
  } elsif ($token->[0] eq 'S') {   } elsif ($token->[0] eq 'S') {
     if ( $token->[1] =~ /^$tag$/i) {      if ( $token->[1] =~ /^\Q$tag\E$/i) {
  $$pars[-1]->unget_token($token); last;   $$pars[-1]->unget_token($token); last;
     } else {      } else {
  $result.=$token->[4];   $result.=$token->[4];
     }      }
     if ($token->[1] =~ /^LONCAPA_INTERNAL_TURN_STYLE_ON$/i) { $Apache::lonxml::usestyle=1; }      if ($token->[1] =~ /^LONCAPA_INTERNAL_TURN_STYLE_ON$/) { $Apache::lonxml::usestyle=1; }
     if ($token->[1] =~ /^LONCAPA_INTERNAL_TURN_STYLE_OFF$/i) { $Apache::lonxml::usestyle=0; }      if ($token->[1] =~ /^LONCAPA_INTERNAL_TURN_STYLE_OFF$/) { $Apache::lonxml::usestyle=0; }
  } elsif ($token->[0] eq 'E')  {   } elsif ($token->[0] eq 'E')  {
     $result.=$token->[2];      $result.=$token->[2];
  }   }
Line 1046  sub afterburn { Line 1055  sub afterburn {
            my $anchorname=$_;             my $anchorname=$_;
    my $matchthis=$anchorname;     my $matchthis=$anchorname;
            $matchthis=~s/\_+/\\s\+/g;             $matchthis=~s/\_+/\\s\+/g;
            $result=~s/($matchthis)/\<font color=\"red\"\>$1\<\/font\>/gs;             $result=~s/(\Q$matchthis\E)/\<font color=\"red\"\>$1\<\/font\>/gs;
        }         }
     }      }
     if ($ENV{'form.link'}) {      if ($ENV{'form.link'}) {
Line 1054  sub afterburn { Line 1063  sub afterburn {
            my ($anchorname,$linkurl)=split(/\>/,$_);             my ($anchorname,$linkurl)=split(/\>/,$_);
    my $matchthis=$anchorname;     my $matchthis=$anchorname;
            $matchthis=~s/\_+/\\s\+/g;             $matchthis=~s/\_+/\\s\+/g;
            $result=~s/($matchthis)/\<a href=\"$linkurl\"\>$1\<\/a\>/gs;             $result=~s/(\Q$matchthis\E)/\<a href=\"$linkurl\"\>$1\<\/a\>/gs;
        }         }
     }      }
     if ($ENV{'form.anchor'}) {      if ($ENV{'form.anchor'}) {
         my $anchorname=$ENV{'form.anchor'};          my $anchorname=$ENV{'form.anchor'};
  my $matchthis=$anchorname;   my $matchthis=$anchorname;
         $matchthis=~s/\_+/\\s\+/g;          $matchthis=~s/\_+/\\s\+/g;
         $result=~s/($matchthis)/\<a name=\"$anchorname\"\>$1\<\/a\>/s;          $result=~s/(\Q$matchthis\E)/\<a name=\"$anchorname\"\>$1\<\/a\>/s;
         $result.=(<<"ENDSCRIPT");          $result.=(<<"ENDSCRIPT");
 <script type="text/javascript">  <script type="text/javascript">
     document.location.hash='$anchorname';      document.location.hash='$anchorname';
Line 1117  SIMPLECONTENT Line 1126  SIMPLECONTENT
   
 sub inserteditinfo {  sub inserteditinfo {
       my ($result,$filecontents,$filetype)=@_;        my ($result,$filecontents,$filetype)=@_;
       $filecontents = &HTML::Entities::encode($filecontents);        $filecontents = &HTML::Entities::encode($filecontents,'<>&"');
 #      my $editheader='<a href="#editsection">Edit below</a><hr />';  #      my $editheader='<a href="#editsection">Edit below</a><hr />';
       my $xml_help = '';        my $xml_help = '';
       if ($filetype eq 'html') {        if ($filetype eq 'html') {
Line 1134  sub inserteditinfo { Line 1143  sub inserteditinfo {
  'ed' => 'Edit');   'ed' => 'Edit');
       my $buttons=(<<BUTTONS);        my $buttons=(<<BUTTONS);
 $cleanbut  $cleanbut
 <input type="submit" name="savethisfile" value="$lt{'st'}" />  <input type="submit" name="savethisfile" accesskey="s"  value="$lt{'st'}" />
 <input type="submit" name="viewmode" value="$lt{'vi'}" />  <input type="submit" name="viewmode" accesskey="v" value="$lt{'vi'}" />
 BUTTONS  BUTTONS
       my $editfooter=(<<ENDFOOTER);        my $editfooter=(<<ENDFOOTER);
 <hr />  <hr />
Line 1213  sub handler { Line 1222  sub handler {
     unless ($ENV{'request.state'} eq 'published') {      unless ($ENV{'request.state'} eq 'published') {
  if (($ENV{'form.savethisfile'}) || ($ENV{'form.attemptclean'})) {   if (($ENV{'form.savethisfile'}) || ($ENV{'form.attemptclean'})) {
     if (&storefile($file,$ENV{'form.filecont'})) {      if (&storefile($file,$ENV{'form.filecont'})) {
  $request->print("<font COLOR=\"#0000FF\">".&mt('Updated').": ".   &Apache::lonxml::info("<font COLOR=\"#0000FF\">".
 &Apache::lonlocal::locallocaltime(time)." </font>");        &mt('Updated').": ".
         &Apache::lonlocal::locallocaltime(time).
         " </font>");
     }       } 
  }   }
     }      }
Line 1266  ENDNOTFOUND Line 1277  ENDNOTFOUND
  if ($ENV{'form.editmode'} && (!($ENV{'form.viewmode'}))) {   if ($ENV{'form.editmode'} && (!($ENV{'form.viewmode'}))) {
     my $displayfile=$request->uri;      my $displayfile=$request->uri;
     $displayfile=~s/^\/[^\/]*//;      $displayfile=~s/^\/[^\/]*//;
     $result='<html><body bgcolor="#FFFFFF"><h3>'.$displayfile.      $result='<html><body bgcolor="#FFFFFF">'.
    &Apache::lonxml::message_location().'<h3>'.
    $displayfile.
  '</h3></body></html>';   '</h3></body></html>';
     $result=&inserteditinfo($result,$filecontents,$filetype);      $result=&inserteditinfo($result,$filecontents,$filetype);
  }   }
Line 1274  ENDNOTFOUND Line 1287  ENDNOTFOUND
     if ($filetype eq 'html') { writeallows($request->uri); }      if ($filetype eq 'html') { writeallows($request->uri); }
   
           
       &Apache::lonxml::add_messages(\$result);
     $request->print($result);      $request->print($result);
           
     return OK;      return OK;
Line 1296  sub display_title { Line 1309  sub display_title {
 sub debug {  sub debug {
     if ($Apache::lonxml::debug eq "1") {      if ($Apache::lonxml::debug eq "1") {
  $|=1;   $|=1;
  Apache->request->print('<font size="-2"<pre>DEBUG:'.&HTML::Entities::encode($_[0])."</pre></font>\n");   my $request=$Apache::lonxml::request;
    if (!$request) { $request=Apache->request; }
    $request->print('<font size="-2"><pre>DEBUG:'.&HTML::Entities::encode($_[0],'<>&"')."</pre></font>\n");
     }      }
 }  }
   
 sub error {  sub error {
   $errorcount++;    $errorcount++;
     my $request=$Apache::lonxml::request;
     if (!$request) { $request=Apache->request; }
   if (($Apache::lonxml::debug eq 1) || ($ENV{'request.state'} eq 'construct') ) {    if (($Apache::lonxml::debug eq 1) || ($ENV{'request.state'} eq 'construct') ) {
     # If printing in construction space, put the error inside <pre></pre>      # If printing in construction space, put the error inside <pre></pre>
       print $Apache::lonxml::warnings_error_header.        push(@Apache::lonxml::error_messages,
   "<b>ERROR:</b>".join("\n",@_)."\n";     $Apache::lonxml::warnings_error_header.
      "<b>ERROR:</b>".join("<br />\n",@_)."<br />\n");
       $Apache::lonxml::warnings_error_header='';        $Apache::lonxml::warnings_error_header='';
   } else {    } else {
     print "<b>An Error occured while processing this resource. The instructor has been notified.</b> <br />";        push(@Apache::lonxml::error_messages,
      "<b>An Error occured while processing this resource. The instructor has been notified.</b> <br />");
     #notify author      #notify author
     &Apache::lonmsg::author_res_msg($ENV{'request.filename'},join('<br />',@_));      &Apache::lonmsg::author_res_msg($ENV{'request.filename'},join('<br />',@_));
     #notify course      #notify course
Line 1321  sub error { Line 1340  sub error {
         "Error [$declutter]",join('<br />',@_));          "Error [$declutter]",join('<br />',@_));
       }        }
     }      }
   
     #FIXME probably shouldn't have me get everything forever.  
     &Apache::lonmsg::user_normal_msg('albertel','msu',"Error in $ENV{'request.filename'}",join('<br />',@_));  
     #&Apache::lonmsg::user_normal_msg('albertel','103',"Error in $ENV{'request.filename'}",$_[0]);  
   }    }
 }  }
   
Line 1333  sub warning { Line 1348  sub warning {
       
     if ($ENV{'form.grade_target'} ne 'tex') {      if ($ENV{'form.grade_target'} ne 'tex') {
  if ($ENV{'request.state'} eq 'construct' || $Apache::lonxml::debug) {   if ($ENV{'request.state'} eq 'construct' || $Apache::lonxml::debug) {
     print $Apache::lonxml::warnings_error_header.      my $request=$Apache::lonxml::request;
  "<b>W</b>ARNING<b>:</b>".join('<br />',@_)."<br />\n";      if (!$request) { $request=Apache->request; }
       push(@Apache::lonxml::warning_messages,
    $Apache::lonxml::warnings_error_header.
    "<b>W</b>ARNING<b>:</b>".join('<br />',@_)."<br />\n");
     $Apache::lonxml::warnings_error_header='';      $Apache::lonxml::warnings_error_header='';
  }   }
     }      }
 }  }
   
   sub info {
       if ($ENV{'form.grade_target'} ne 'tex' 
    && $ENV{'request.state'} eq 'construct') {
    push(@Apache::lonxml::info_messages,join('<br />',@_)."<br />\n");
       }
   }
   
   sub message_location {
       return '__LONCAPA_INTERNAL_MESSAGE_LOCATION__';
   }
   
   sub add_messages {
       my ($msg)=@_;
       my $result=join(' ',
       @Apache::lonxml::info_messages,
       @Apache::lonxml::error_messages,
       @Apache::lonxml::warning_messages);
       undef(@Apache::lonxml::info_messages);
       undef(@Apache::lonxml::error_messages);
       undef(@Apache::lonxml::warning_messages);
       $$msg=~s/__LONCAPA_INTERNAL_MESSAGE_LOCATION__/$result/;
       $$msg=~s/__LONCAPA_INTERNAL_MESSAGE_LOCATION__//g;
   }
   
 sub get_param {  sub get_param {
     my ($param,$parstack,$safeeval,$context,$case_insensitive) = @_;      my ($param,$parstack,$safeeval,$context,$case_insensitive) = @_;
     if ( ! $context ) { $context = -1; }      if ( ! $context ) { $context = -1; }

Removed from v.1.298  
changed lines
  Added in v.1.318


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>