--- loncom/xml/lonxml.pm 2002/01/09 09:50:59 1.148 +++ loncom/xml/lonxml.pm 2007/02/18 02:10:04 1.439 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # XML Parser Module # -# $Id: lonxml.pm,v 1.148 2002/01/09 09:50:59 albertel Exp $ +# $Id: lonxml.pm,v 1.439 2007/02/18 02:10:04 albertel Exp $ # # Copyright Michigan State University Board of Trustees # @@ -36,39 +36,23 @@ # The C source of the Code may not be distributed by the Licensee # 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/10 Scott Harrison -# 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; 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 HTML::TreeBuilder; -use Safe; -use Safe::Hole; -use Math::Cephes qw(:trigs :hypers :bessels erf erfc); -use Math::Random qw(:all); -use Opcode; +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,@taglist) = @_; @@ -89,20 +73,32 @@ sub deregister { } 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::loncommon; +use Apache::File(); +use Apache::loncommon(); +use Apache::lonfeedback(); +use Apache::lonmsg(); +use Apache::loncacc(); +use Apache::lonmaxima(); +use Apache::lonlocal; #================================================== 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=(); @@ -128,87 +124,72 @@ $evaluate = 1; # stores the list of active tag namespaces @namespace=(); -# has the dynamic menu been updated to know about this resource -$Apache::lonxml::registered=0; +# a pointer the the Apache request object +$Apache::lonxml::request=''; -sub xmlbegin { - my $output=''; - if ($ENV{'browser.mathml'}) { - $output='' - .'' - .']>' - .''; - } else { - $output=''; - } - return $output; +# a problem number counter, and check on ether it is used +$Apache::lonxml::counter=1; +$Apache::lonxml::counter_changed=0; + +#internal check on whether to look at style defs +$Apache::lonxml::usestyle=1; + +#locations used to store the parameter string for style substitutions +$Apache::lonxml::style_values=''; +$Apache::lonxml::style_end_values=''; + +#array of ssi calls that need to occur after we are done parsing +@Apache::lonxml::ssi_info=(); + +#should we do the postag variable interpolation +$Apache::lonxml::post_evaluate=1; + +#a header message to emit in the case of any generated warning or errors +$Apache::lonxml::warnings_error_header=''; + +# Control whether or not LaTeX symbols should be substituted for their +# \ style equivalents...this may be turned off e.g. in an verbatim +# environment. + +$Apache::lonxml::substitute_LaTeX_symbols = 1; # Starts out on. + +sub enable_LaTeX_substitutions { + $Apache::lonxml::substitute_LaTeX_symbols = 1; +} +sub disable_LaTeX_substitutions { + $Apache::lonxml::substitute_LaTeX_symbols = 0; } sub xmlend { - my $discussion=''; - if ($ENV{'request.course.id'}) { - my $crs='/'.$ENV{'request.course.id'}; - if ($ENV{'request.course.sec'}) { - $crs.='_'.$ENV{'request.course.sec'}; - } - $crs=~s/\_/\//g; - my $seeid=&Apache::lonnet::allowed('rin',$crs); - my $symb=&Apache::lonnet::symbread(); - if ($symb) { - my %contrib=&Apache::lonnet::restore($symb,$ENV{'request.course.id'}, - $ENV{'course.'.$ENV{'request.course.id'}.'.domain'}, - $ENV{'course.'.$ENV{'request.course.id'}.'.num'}); - if ($contrib{'version'}) { - $discussion.= - '

Course Discussion of Resource

'; - my $idx; - for ($idx=1;$idx<=$contrib{'version'};$idx++) { - my $hidden=($contrib{'hidden'}=~/\.$idx\./); - unless (($hidden) && (!$seeid)) { - my $message=$contrib{$idx.':message'}; - $message=~s/\n/\
/g; - if ($message) { - if ($hidden) { - $message=''.$message.''; - } - my $sender='Anonymous'; - if ((!$contrib{$idx.':anonymous'}) || ($seeid)) { - $sender=$contrib{$idx.':sendername'}.' at '. - $contrib{$idx.':senderdomain'}; - if ($contrib{$idx.':anonymous'}) { - $sender.=' (anonymous)'; - } - if ($seeid) { - if ($hidden) { - $sender.=' Make Visible'; - } else { - $sender.=' Hide'; - } - } - } - $discussion.='

'.$sender.' ('. - localtime($contrib{$idx.':timestamp'}). - '):

'.$message. - '

'; - } - } - } - $discussion.='
'; - } - } + my ($target,$parser)=@_; + my $mode='xml'; + my $status='OPEN'; + if ($Apache::lonhomework::parsing_a_problem || + $Apache::lonhomework::parsing_a_task ) { + $mode='problem'; + $status=$Apache::inputtags::status[-1]; + } + my $discussion; + &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'}, + ['LONCAPA_INTERNAL_no_discussion']); + if (! exists($env{'form.LONCAPA_INTERNAL_no_discussion'}) || + $env{'form.LONCAPA_INTERNAL_no_discussion'} ne 'true') { + $discussion=&Apache::lonfeedback::list_discussion($mode,$status); + } + if ($target eq 'tex') { + $discussion.='\keephidden{ENDOFPROBLEM}\vskip 0.5mm\noindent\makebox[\textwidth/$number_of_columns][b]{\hrulefill}\end{document}'; + &Apache::lonxml::newparser($parser,\$discussion,''); + return ''; } - return $discussion.''; + + return $discussion; } sub tokeninputfield { my $defhost=$Apache::lonnet::perlvar{'lonHostID'}; $defhost=~tr/a-z/A-Z/; return (< +'; - } - if ($Apache::lonxml::registered && !$forcereg) { return ''; } - $Apache::lonxml::registered=1; - if (($ENV{'REQUEST_URI'}!~/^\/(res\/)*adm\//) || ($forcereg)) { - my $hwkadd=''; - if ($ENV{'REQUEST_URI'}=~/\.(problem|exam|quiz|assess|survey|form)$/) { - if (&Apache::lonnet::allowed('vgr',$ENV{'request.course.id'})) { - $hwkadd.=(< -// BEGIN LON-CAPA Internal - - function LONCAPAreg() { - menu=window.open("","LONCAPAmenu"); - menu.clearTimeout(menu.menucltim); - menu.currentURL=window.location.pathname; - menu.currentStale=0; - menu.clearbut(3,1); - menu.switchbutton - (6,3,'catalog.gif','catalog','info','catalog_info()'); - menu.switchbutton - (8,1,'eval.gif','evaluate','this','gopost("/adm/evaluate",currentURL)'); - menu.switchbutton - (8,2,'fdbk.gif','feedback','on this','gopost("/adm/feedback",currentURL)'); - menu.switchbutton - (8,3,'prt.gif','prepare','printout','gopost("/adm/printout",currentURL)'); - menu.switchbutton - (2,1,'back.gif','backward','','gopost("/adm/flip","back:"+currentURL)'); - menu.switchbutton - (2,3,'forw.gif','forward','','gopost("/adm/flip","forward:"+currentURL)'); - menu.switchbutton - (9,1,'sbkm.gif','set','bookmark','set_bookmark()'); - menu.switchbutton - (9,2,'vbkm.gif','view','bookmark','edit_bookmarks()'); - menu.switchbutton - (9,3,'anot.gif','anno-','tations','annotate()'); - $hwkadd - } - - function LONCAPAstale() { - menu=window.open("","LONCAPAmenu"); - menu.currentStale=1; - menu.switchbutton - (3,1,'reload.gif','return','location','go(currentURL)'); - menu.clearbut(7,1); - menu.clearbut(7,2); - menu.clearbut(7,3); - menu.menucltim=menu.setTimeout( - 'clearbut(2,1);clearbut(2,3);clearbut(8,1);clearbut(8,2);clearbut(8,3);'+ - 'clearbut(9,1);clearbut(9,2);clearbut(9,3);clearbut(6,3)', - 2000); - - } - -// END LON-CAPA Internal - -ENDREGTHIS - - } else { - return (< -// BEGIN LON-CAPA Internal - - function LONCAPAreg() { - menu=window.open("","LONCAPAmenu"); - menu.currentStale=1; - menu.clearbut(2,1); - menu.clearbut(2,3); - menu.clearbut(8,1); - menu.clearbut(8,2); - menu.clearbut(8,3); - if (menu.currentURL) { - menu.switchbutton - (3,1,'reload.gif','return','location','go(currentURL)'); - } else { - menu.clearbut(3,1); - } - } - - function LONCAPAstale() { - } - -// END LON-CAPA Internal - -ENDDONOTREGTHIS - - } -} - -sub loadevents() { - return 'LONCAPAreg();'; -} - -sub unloadevents() { - return 'LONCAPAstale();'; -} - sub printalltags { my $temp; foreach $temp (sort keys %Apache::lonxml::alltags) { @@ -447,12 +289,43 @@ sub printalltags { } sub xmlparse { - my ($target,$content_file_string,$safeinit,%style_for_target) = @_; + my ($request,$target,$content_file_string,$safeinit,%style_for_target) = @_; + + &setup_globals($request,$target); + &Apache::inputtags::initialize_inputtags(); + &Apache::bridgetask::initialize_bridgetask(); + &Apache::outputtags::initialize_outputtags(); + &Apache::edit::initialize_edit(); + &Apache::londefdef::initialize_londefdef(); - &setup_globals($target); - #&printalltags(); +# +# do we have a course style file? +# + + if ($env{'request.course.id'} && $env{'request.state'} ne 'construct') { + my $bodytext= + $env{'course.'.$env{'request.course.id'}.'.default_xml_style'}; + if ($bodytext) { + foreach my $file (split(',',$bodytext)) { + my $location=&Apache::lonnet::filelocation('',$file); + my $styletext=&Apache::lonnet::getfile($location); + if ($styletext ne '-1') { + %style_for_target = (%style_for_target, + &Apache::style::styleparser($target,$styletext)); + } + } + } + } elsif ($env{'construct.style'} && ($env{'request.state'} eq 'construct')) { + my $location=&Apache::lonnet::filelocation('',$env{'construct.style'}); + my $styletext=&Apache::lonnet::getfile($location); + if ($styletext ne '-1') { + %style_for_target = (%style_for_target, + &Apache::style::styleparser($target,$styletext)); + } + } +#&printalltags(); my @pars = (); - my $pwd=$ENV{'request.filename'}; + my $pwd=$env{'request.filename'}; $pwd =~ s:/[^/]*$::; &newparser(\@pars,\$content_file_string,$pwd); @@ -463,52 +336,95 @@ sub xmlparse { ($target, my @tenta) = split('&&',$target); - my @stack = (); + my @stack = (); my @parstack = (); - &initdepth; - + &initdepth(); + &init_alarm(); my $finaloutput = &inner_xmlparse($target,\@stack,\@parstack,\@pars, - $safeeval,\%style_for_target); - if ($ENV{'request.uri'}) { - &writeallows($ENV{'request.uri'}); - } - return $finaloutput; -} + $safeeval,\%style_for_target,1); -sub htmlclean { - my ($raw,$full)=@_; - - my $tree = HTML::TreeBuilder->new; - $tree->ignore_unknown(0); + if (@stack) { + &warning("At end of file some tags were still left unclosed, ". + '<'.join('>, <',reverse(@stack)). + '>'); + } + if ($env{'request.uri'}) { + &writeallows($env{'request.uri'}); + } + &do_registered_ssi(); + if ($Apache::lonxml::counter_changed) { &store_counter() } - $tree->parse($raw); + &clean_safespace($safeeval); - my $output= $tree->as_HTML(undef,' '); + if ($env{'form.return_only_error_and_warning_counts'}) { + return "$errorcount:$warningcount"; + } + return $finaloutput; +} - $output=~s/\<(br|hr|img|meta|allow)([^\>\/]*)\>/\<$1$2 \/\>/gis; - $output=~s/\<\/(br|hr|img|meta|allow)\>//gis; - unless ($full) { - $output=~s/\<[\/]*(body|head|html)\>//gis; +sub latex_special_symbols { + my ($string,$where)=@_; + # + # If e.g. in verbatim mode, then don't substitute. + # but return original string. + # + if (!($Apache::lonxml::substitute_LaTeX_symbols)) { + return $string; + } + if ($where eq 'header') { + $string =~ s/\\/\$\\backslash\$/g; # \ -> $\backslash$ per LaTex line by line pg 10. + $string =~ s/(\$|%|\{|\})/\\$1/g; + $string=&Apache::lonprintout::character_chart($string); + # any & or # leftover should be safe to just escape + $string=~s/([^\\])\&/$1\\\&/g; + $string=~s/([^\\])\#/$1\\\#/g; + $string =~ s/_/\\_/g; # _ -> \_ + $string =~ s/\^/\\\^{}/g; # ^ -> \^{} + } else { + $string=~s/\\/\\ensuremath{\\backslash}/g; + $string=~s/\\\%|\%/\\\%/g; + $string=~s/\\{|{/\\{/g; + $string=~s/\\}|}/\\}/g; + $string=~s/\\ensuremath\\{\\backslash\\}/\\ensuremath{\\backslash}/g; + $string=~s/\\\$|\$/\\\$/g; + $string=~s/\\\_|\_/\\\_/g; + $string=~s/([^\\]|^)(\~|\^)/$1\\$2\\strut /g; + $string=~s/(>|<)/\\ensuremath\{$1\}/g; #more or less + $string=&Apache::lonprintout::character_chart($string); + # any & or # leftover should be safe to just escape + $string=~s/\\\&|\&/\\\&/g; + $string=~s/\\\#|\#/\\\#/g; + $string=~s/\|/\$\\mid\$/g; +#single { or } How to escape? } - - $tree = $tree->delete; - - return $output; + return $string; } sub inner_xmlparse { - my ($target,$stack,$parstack,$pars,$safeeval,$style_for_target)=@_; + my ($target,$stack,$parstack,$pars,$safeeval,$style_for_target,$start)=@_; my $finaloutput = ''; my $result; my $token; + my $dontpop=0; + my $startredirection = $Apache::lonxml::redirection; while ( $#$pars > -1 ) { 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->[0] eq 'C') ) { if ($metamode<1) { - $result=$token->[1]; + my $text=$token->[1]; + if ($token->[0] eq 'C' && $target eq 'tex') { + $text = ''; +# $text = '%'.$text."\n"; + } + $result.=$text; + } + } elsif (($token->[0] eq 'D')) { + if ($metamode<1 && $target eq 'web') { + my $text=$token->[1]; + $result.=$text; } } elsif ($token->[0] eq 'PI') { - if ($metamode<1) { + if ($metamode<1 && $target eq 'web') { $result=$token->[2]; } } elsif ($token->[0] eq 'S') { @@ -517,142 +433,105 @@ sub inner_xmlparse { # add parameters list to another stack push (@$parstack,&parstring($token)); &increasedepth($token); - if (exists $$style_for_target{$token->[1]}) { - if ($Apache::lonxml::redirection) { - $Apache::lonxml::outputstack['-1'] .= - &recurse($$style_for_target{$token->[1]},$target,$safeeval, - $style_for_target,@$parstack); - } else { - $finaloutput .= &recurse($$style_for_target{$token->[1]},$target, - $safeeval,$style_for_target,@$parstack); - } + if ($Apache::lonxml::usestyle && + exists($$style_for_target{$token->[1]})) { + $Apache::lonxml::usestyle=0; + my $string=$$style_for_target{$token->[1]}. + ''; + &Apache::lonxml::newparser($pars,\$string); + $Apache::lonxml::style_values=$$parstack[-1]; + $Apache::lonxml::style_end_values=$$parstack[-1]; } else { $result = &callsub("start_$token->[1]", $target, $token, $stack, $parstack, $pars, $safeeval, $style_for_target); } } elsif ($token->[0] eq 'E') { - #clear out any tags that didn't end - while ($token->[1] ne $$stack['-1'] && ($#$stack > -1)) { - &Apache::lonxml::warning('Missing tag </'.$$stack['-1'].'> in file'); - &end_tag($stack,$parstack,$token); - } - - if (exists($$style_for_target{'/'."$token->[1]"})) { - if ($Apache::lonxml::redirection) { - $Apache::lonxml::outputstack['-1'] .= - &recurse($$style_for_target{'/'."$token->[1]"}, - $target,$safeeval,$style_for_target,@$parstack); - } else { - $finaloutput .= &recurse($$style_for_target{'/'."$token->[1]"}, - $target,$safeeval,$style_for_target, - @$parstack); - } + if ($Apache::lonxml::usestyle && + exists($$style_for_target{'/'."$token->[1]"})) { + $Apache::lonxml::usestyle=0; + my $string=$$style_for_target{'/'.$token->[1]}. + ''; + &Apache::lonxml::newparser($pars,\$string); + $Apache::lonxml::style_values=$Apache::lonxml::style_end_values; + $Apache::lonxml::style_end_values=''; + $dontpop=1; } else { - $result = &callsub("end_$token->[1]", $target, $token, $stack, - $parstack, $pars,$safeeval, $style_for_target); + #clear out any tags that didn't end + while ($token->[1] ne $$stack['-1'] && ($#$stack > -1)) { + my $lasttag=$$stack[-1]; + if ($token->[1] =~ /^\Q$lasttag\E$/i) { + &Apache::lonxml::warning('Using tag </'.$token->[1].'> on line '.$token->[3].' as end tag to <'.$$stack[-1].'>'); + last; + } else { + &Apache::lonxml::warning('Found tag </'.$token->[1].'> on line '.$token->[3].' when looking for </'.$$stack[-1].'> in file'); + &end_tag($stack,$parstack,$token); + } + } + $result = &callsub("end_$token->[1]", $target, $token, $stack, + $parstack, $pars,$safeeval, $style_for_target); } } else { &Apache::lonxml::error("Unknown token event :$token->[0]:$token->[1]:"); } #evaluate variable refs in result - if ($result ne "") { - if ( $#$parstack > -1 ) { - if ($Apache::lonxml::redirection) { - $Apache::lonxml::outputstack['-1'] .= - &Apache::run::evaluate($result,$safeeval,$$parstack['-1']); - } else { - $finaloutput .= &Apache::run::evaluate($result,$safeeval, - $$parstack['-1']); + if ($Apache::lonxml::post_evaluate &&$result ne "") { + my $extras; + if (!$Apache::lonxml::usestyle) { + $extras=$Apache::lonxml::style_values; } + if ( $#$parstack > -1 ) { + $result=&Apache::run::evaluate($result,$safeeval,$extras.$$parstack[-1]); } else { - $finaloutput .= &Apache::run::evaluate($result,$safeeval,''); + $result= &Apache::run::evaluate($result,$safeeval,$extras); } - $result = ''; - } - if ($token->[0] eq 'E') { + } + $Apache::lonxml::post_evaluate=1; + + if (($token->[0] eq 'T') || ($token->[0] eq 'C') || ($token->[0] eq 'D') ) { + #Style file definitions should be correct + if ($target eq 'tex' && ($Apache::lonxml::usestyle)) { + $result=&latex_special_symbols($result); + } + } + + if ($Apache::lonxml::redirection) { + $Apache::lonxml::outputstack['-1'] .= $result; + } else { + $finaloutput.=$result; + } + $result = ''; + + if ($token->[0] eq 'E' && !$dontpop) { &end_tag($stack,$parstack,$token); } + $dontpop=0; + } + if ($#$pars > -1) { + pop @$pars; + pop @Apache::lonxml::pwd; } - pop @$pars; - pop @Apache::lonxml::pwd; } # if ($target eq 'meta') { # $finaloutput.=&endredirection; # } + if ( $start && $target eq 'grade') { &endredirection(); } + if ( $Apache::lonxml::redirection > $startredirection) { + while ($Apache::lonxml::redirection > $startredirection) { + $finaloutput .= &endredirection(); + } + } if (($ENV{'QUERY_STRING'}) && ($target eq 'web')) { $finaloutput=&afterburn($finaloutput); - } + } return $finaloutput; } -sub recurse { - my @innerstack = (); - my @innerparstack = (); - my ($newarg,$target,$safeeval,$style_for_target,@parstack) = @_; - my @pat = (); - &newparser(\@pat,\$newarg); - my $tokenpat; - my $partstring = ''; - my $output=''; - my $decls=''; - &Apache::lonxml::debug("Recursing"); - while ( $#pat > -1 ) { - while ($tokenpat = $pat[$#pat]->get_token) { - if (($tokenpat->[0] eq 'T') || ($tokenpat->[0] eq 'C') || ($tokenpat->[0] eq 'D') ) { - if ($metamode<1) { $partstring=$tokenpat->[1]; } - } elsif ($tokenpat->[0] eq 'PI') { - if ($metamode<1) { $partstring=$tokenpat->[2]; } - } elsif ($tokenpat->[0] eq 'S') { - push (@innerstack,$tokenpat->[1]); - push (@innerparstack,&parstring($tokenpat)); - &increasedepth($tokenpat); - $partstring = &callsub("start_$tokenpat->[1]", $target, $tokenpat, - \@innerstack, \@innerparstack, \@pat, - $safeeval, $style_for_target); - } elsif ($tokenpat->[0] eq 'E') { - #clear out any tags that didn't end - while ($tokenpat->[1] ne $innerstack[$#innerstack] - && ($#innerstack > -1)) { - &Apache::lonxml::warning('Missing tag </'.$innerstack['-1'].'> in style'); - &end_tag(\@innerstack,\@innerparstack,$tokenpat); - } - $partstring = &callsub("end_$tokenpat->[1]", $target, $tokenpat, - \@innerstack, \@innerparstack, \@pat, - $safeeval, $style_for_target); - } else { - &Apache::lonxml::error("Unknown token event :$tokenpat->[0]:$tokenpat->[1]:"); - } - #pass both the variable to the style tag, and the tag we - #are processing inside the - if ( $partstring ne "" ) { - if ( $#parstack > -1 ) { - if ( $#innerparstack > -1 ) { - $decls= $parstack[$#parstack].$innerparstack[$#innerparstack]; - } else { - $decls= $parstack[$#parstack]; - } - } else { - if ( $#innerparstack > -1 ) { - $decls=$innerparstack[$#innerparstack]; - } else { - $decls=''; - } - } - $output .= &Apache::run::evaluate($partstring,$safeeval,$decls); - $partstring = ''; - } - if ($tokenpat->[0] eq 'E') { pop @innerstack;pop @innerparstack; - &decreasedepth($tokenpat);} - } - pop @pat; - pop @Apache::lonxml::pwd; - } - &Apache::lonxml::debug("Exiting Recursing"); - return $output; -} - +## +## 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 { my ($sub,$target,$token,$tagstack,$parstack,$parser,$safeeval,$style)=@_; my $currentstring=''; @@ -661,6 +540,8 @@ sub callsub { my $sub1; no strict 'refs'; my $tag=$token->[1]; +# get utterly rid of extended html tags + if ($tag=~/^x\-/i) { return ''; } my $space=$Apache::lonxml::alltags{$tag}[-1]; if (!$space) { $tag=~tr/A-Z/a-z/; @@ -669,7 +550,6 @@ sub callsub { } my $deleted=0; - $Apache::lonxml::curdepth=join('_',@Apache::lonxml::depthcounter); if (($token->[0] eq 'S') && ($target eq 'modified')) { $deleted=&Apache::edit::handle_delete($space,$target,$token,$tagstack, $parstack,$parser,$safeeval, @@ -677,13 +557,17 @@ sub callsub { } if (!$deleted) { if ($space) { - #&Apache::lonxml::debug("Calling sub $sub in $space $metamode
\n"); + #&Apache::lonxml::debug("Calling sub $sub in $space $metamode"); $sub1="$space\:\:$sub"; ($currentstring,$nodefault) = &$sub1($target,$token,$tagstack, $parstack,$parser,$safeeval, $style); } else { - #&Apache::lonxml::debug("NOT Calling sub $sub in $space $metamode
\n"); + 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]; @@ -695,7 +579,7 @@ sub callsub { # &Apache::lonxml::debug("nodefalt:$nodefault:"); if ($currentstring eq '' && $nodefault eq '') { if ($target eq 'edit') { - &Apache::lonxml::debug("doing default edit for $token->[1]"); + #&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') { @@ -705,6 +589,9 @@ sub callsub { if ($token->[0] eq 'S') { $currentstring = $token->[4]; $currentstring.=&Apache::edit::handle_insert(); + } elsif ($token->[0] eq 'E') { + $currentstring = $token->[2]; + $currentstring.=&Apache::edit::handle_insertafter($token->[1]); } else { $currentstring = $token->[2]; } @@ -717,10 +604,19 @@ sub callsub { } sub setup_globals { - my ($target)=@_; - $Apache::lonxml::registered = 0; + my ($request,$target)=@_; + $Apache::lonxml::request=$request; + $errorcount=0; + $warningcount=0; + $Apache::lonxml::default_homework_loaded=0; + $Apache::lonxml::usestyle=1; + &init_counter(); @Apache::lonxml::pwd=(); @Apache::lonxml::extlinks=(); + @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; @@ -732,7 +628,7 @@ sub setup_globals { $Apache::lonxml::evaluate = 1; $Apache::lonxml::import = 1; } elsif ($target eq 'grade') { - &startredirection; + &startredirection(); #ended in inner_xmlparse on exit $Apache::lonxml::metamode = 0; $Apache::lonxml::evaluate = 1; $Apache::lonxml::import = 1; @@ -746,6 +642,11 @@ sub setup_globals { $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; @@ -756,13 +657,31 @@ sub setup_globals { sub init_safespace { my ($target,$safeeval,$safehole,$safeinit) = @_; + $safeeval->deny_only(':dangerous'); + $safeeval->reval('use Math::Complex;'); + $safeeval->permit_only(":default"); $safeeval->permit("entereval"); $safeeval->permit(":base_math"); $safeeval->permit("sort"); + $safeeval->permit("time"); + $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::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::caparesponse::capa_formula_fix,$safeeval, + '&capa_formula_fix'); + $safehole->wrap(\&Math::Cephes::asin,$safeeval,'&asin'); $safehole->wrap(\&Math::Cephes::acos,$safeeval,'&acos'); $safehole->wrap(\&Math::Cephes::atan,$safeeval,'&atan'); @@ -782,6 +701,67 @@ sub init_safespace { $safehole->wrap(\&Math::Cephes::y1,$safeeval,'&y1'); $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'); @@ -803,29 +783,113 @@ sub init_safespace { $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::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'); +# use Data::Dumper; +# $safehole->wrap(\&Data::Dumper::Dumper,$safeeval,'&LONCAPA_INTERNAL_Dumper'); #need to inspect this class of ops # $safeeval->deny(":base_orig"); + $safeeval->permit("require"); $safeinit .= ';$external::target="'.$target.'";'; - my $rndseed; - my ($symb,$courseid,$domain,$name) = &Apache::lonxml::whichuser(); - $rndseed=&Apache::lonnet::rndseed($symb,$courseid,$domain,$name); - $safeinit .= ';$external::randomseed='.$rndseed.';'; &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 "::") + { + my ($p) = $package ne "main" ? "$package\::" : ""; + ($p .= $key) =~ s/::$//; + push(@subp,$p); + } + } + } + foreach my $p (@subp) { + delete_package_recurse($p); + } + Symbol::delete_package($package); +} + +sub initialize_rndseed { + my ($safeeval)=@_; + my $rndseed; + my ($symb,$courseid,$domain,$name) = &Apache::lonnet::whichuser(); + $rndseed=&Apache::lonnet::rndseed($symb,$courseid,$domain,$name); + my $safeinit = '$external::randomseed="'.$rndseed.'";'; + &Apache::lonxml::debug("Setting rndseed to $rndseed"); + &Apache::run::run($safeinit,$safeeval); +} + +sub default_homework_load { + my ($safeeval)=@_; + &Apache::lonxml::debug('Loading default_homework'); + my $default=&Apache::lonnet::getfile('/home/httpd/html/res/adm/includes/default_homework.lcpm'); + if ($default eq -1) { + &Apache::lonxml::error("Unable to find default_homework.lcpm"); + } else { + &Apache::run::run($default,$safeeval); + $Apache::lonxml::default_homework_loaded=1; + } +} + +{ + my $alarm_depth; + sub init_alarm { + alarm(0); + $alarm_depth=0; + } + + sub start_alarm { + if ($alarm_depth<1) { + my $old=alarm($Apache::lonnet::perlvar{'lonScriptTimeout'}); + if ($old) { + &Apache::lonxml::error("Cancelled an alarm of $old, this shouldn't occur."); + } + } + $alarm_depth++; + } + + sub end_alarm { + $alarm_depth--; + if ($alarm_depth<1) { alarm(0); } + } +} +my $metamode_was; sub startredirection { - $Apache::lonxml::redirection++; - push (@Apache::lonxml::outputstack, ''); + if (!$Apache::lonxml::redirection) { + $metamode_was=$Apache::lonxml::metamode; + } + $Apache::lonxml::metamode=0; + $Apache::lonxml::redirection++; + push (@Apache::lonxml::outputstack, ''); } sub endredirection { - if (!$Apache::lonxml::redirection) { - &Apache::lonxml::error("Endredirection was called, before a startredirection, perhaps you have unbalanced tags. Some debuging information:".join ":",caller); - return ''; - } - $Apache::lonxml::redirection--; - pop @Apache::lonxml::outputstack; + if (!$Apache::lonxml::redirection) { + &Apache::lonxml::error("Endredirection was called before a startredirection, perhaps you have unbalanced tags. Some debugging information:".join ":",caller); + return ''; + } + $Apache::lonxml::redirection--; + if (!$Apache::lonxml::redirection) { + $Apache::lonxml::metamode=$metamode_was; + } + pop @Apache::lonxml::outputstack; } sub end_tag { @@ -837,118 +901,301 @@ sub end_tag { sub initdepth { @Apache::lonxml::depthcounter=(); - $Apache::lonxml::depth=-1; - $Apache::lonxml::olddepth=-1; + undef($Apache::lonxml::last_depth_count); } + +my @timers; +my $lasttime; +# @Apache::lonxml::depthcounter -> count of tags that exist so +# far at each level +# $Apache::lonxml::last_depth_count -> when ascending, need to +# remember the count for the level below the current level (for +# example going from 1_2 -> 1 -> 1_3 need to remember the 2 ) + sub increasedepth { my ($token) = @_; - $Apache::lonxml::depth++; - $Apache::lonxml::depthcounter[$Apache::lonxml::depth]++; - if ($Apache::lonxml::depthcounter[$Apache::lonxml::depth]==1) { - $Apache::lonxml::olddepth=$Apache::lonxml::depth; - } - my $curdepth=join('_',@Apache::lonxml::depthcounter); - &Apache::lonxml::debug("s $Apache::lonxml::depth : $Apache::lonxml::olddepth : $curdepth : $token->[1]\n"); + push(@Apache::lonxml::depthcounter,$Apache::lonxml::last_depth_count+1); + undef($Apache::lonxml::last_depth_count); + my $time; + if ($Apache::lonxml::debug eq "1") { + push(@timers,[&gettimeofday()]); + $time=&tv_interval($lasttime); + $lasttime=[&gettimeofday()]; + } + my $spacing=' 'x($#Apache::lonxml::depthcounter); + $Apache::lonxml::curdepth=join('_',@Apache::lonxml::depthcounter); +# &Apache::lonxml::debug("s$spacing$Apache::lonxml::depth : $Apache::lonxml::olddepth : $Apache::lonxml::curdepth : $token->[1] : $time"); #print "
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::depthcounter == -1) { + &Apache::lonxml::warning(&mt("Missing tags, unable to properly run file.")); } - if ( $Apache::lonxml::depth < -1) { - &Apache::lonxml::warning("Missing tags, unable to properly run file."); - $Apache::lonxml::depth='-1'; - } - my $curdepth=join('_',@Apache::lonxml::depthcounter); - &Apache::lonxml::debug("e $Apache::lonxml::depth : $Apache::lonxml::olddepth : $token->[1] : $curdepth\n"); + $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 $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 =~ /(\.|_)/) { + &error(&mt("IDs are not allowed to contain "_" or "."")); + } + 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 +sub increment_counter { + my ($increment) = @_; + if (defined($increment) && $increment gt 0) { + $Apache::lonxml::counter+=$increment; + } else { + $Apache::lonxml::counter++; + } + $Apache::lonxml::counter_changed=1; +} + +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'}; + } +} + +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= + ''. + $$style{'/'.$token->[1]}. + $token->[2]. + ''; + &Apache::lonxml::newparser($pars,\$string); + #&Apache::lonxml::debug("reParsing $string"); + next; + } + if ($depth > -1) { + $result.=$token->[2]; + } else { + $$pars[-1]->unget_token($token); + } + } + } + if (($depth >=0) && ($#$pars == 0) ) { $top_empty=1; } + if (($depth >=0) && ($#$pars > 0) ) { + pop(@$pars); + pop(@Apache::lonxml::pwd); + } + } + if ($top_empty && $depth >= 0) { + #never found the end tag ran out of text, throw error send back blank + &error('Never found end tag for <'.$tag. + '> current string
'.
+		   &HTML::Entities::encode($result,'<>&"').
+		   '
'); + if ($gotfullstack) { + my $newstring=''.$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=''; - foreach (@{$token->[3]}) { - 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\""); + } } - } - return $temp; + 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); + } + push(@Apache::lonxml::extlinks,$res) } sub writeallows { unless ($#extlinks>=0) { return; } - my $thisurl='/res/'.&Apache::lonnet::declutter(shift); - if ($ENV{'httpref.'.$thisurl}) { - $thisurl=$ENV{'httpref.'.$thisurl}; + my $thisurl = &Apache::lonnet::clutter(shift); + if ($env{'httpref.'.$thisurl}) { + $thisurl=$env{'httpref.'.$thisurl}; } my $thisdir=$thisurl; $thisdir=~s/\/[^\/]+$//; @@ -961,44 +1208,49 @@ sub writeallows { &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); + } +} # # Afterburner handles anchors, highlights and links # sub afterburn { my $result=shift; - foreach (split(/&/,$ENV{'QUERY_STRING'})) { - 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; - } - } - } - if ($ENV{'form.highlight'}) { - foreach (split(/\,/,$ENV{'form.highlight'})) { + &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; + $result=~s/(\Q$matchthis\E)/\$1\<\/font\>/gs; } } - if ($ENV{'form.link'}) { - foreach (split(/\,/,$ENV{'form.link'})) { + 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; + $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 @@ -1008,200 +1260,439 @@ 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("Unable to save file $file"); + &warning("Unable to save file $file"); + return 0; } } -sub inserteditinfo { - my ($result,$filecontents)=@_; - unless ($filecontents) { - $filecontents=(< - - Title of Document Goes Here - +$title - - Body of Document Goes Here - +$body SIMPLECONTENT - } + return $filecontents; +} - $filecontents =~ s::</textarea>:ig; +sub createnewsty { + my $filecontents=(< + + + + + +SIMPLECONTENT + return $filecontents; +} + + +sub inserteditinfo { + my ($result,$filecontents,$filetype)=@_; + $filecontents = &HTML::Entities::encode($filecontents,'<>&"'); # my $editheader='Edit below
'; + my $xml_help = ''; + my $initialize=''; + if ($filetype eq 'html') { + my $addbuttons=&Apache::lonhtmlcommon::htmlareaaddbuttons(); + $initialize=&Apache::lonhtmlcommon::spellheader(); + if (!&Apache::lonhtmlcommon::htmlareablocked() && + &Apache::lonhtmlcommon::htmlareabrowser()) { + $initialize.=(< +$addbuttons + + HTMLArea.loadPlugin("FullPage"); + + function initDocument() { + var editor=new HTMLArea("filecont",config); + editor.registerPlugin(FullPage); + editor.generate(); + } + +FULLPAGE + } else { + $initialize.=(< +$addbuttons + function initDocument() { + } + +FULLPAGE + } + $result=~s/\]*)\>/\/i; + $xml_help=&Apache::loncommon::helpLatexCheatsheet(); + } + my $cleanbut = ''; + + my $titledisplay=&display_title(); + my %lt=&Apache::lonlocal::texthash('st' => 'Save and Edit', + 'vi' => 'Save and View', + 'dv' => 'Discard Edits and View', + 'un' => 'undo', + 'ed' => 'Edit'); + my $buttons=(< +
+ + +BUTTONS + $buttons.=&Apache::lonhtmlcommon::spelllink('xmledit','filecont'); my $editfooter=(< -
- + +$xml_help + +$buttons
+ +
$buttons
- - - -
+$titledisplay + ENDFOOTER # $result=~s/(\]*\>)/$1$editheader/is; $result=~s/(\<\/body\>)/$editfooter/is; return $result; } -sub editbutton { - my ($result) = @_; - my $button=(< - - -EDITBUTTON - $result=~s/(\<\/body\>)/$button/is; - return $result; -} - -sub handler { - my $request=shift; - - my $target='web'; - - $Apache::lonxml::debug=0; - - if ($ENV{'browser.mathml'}) { - $request->content_type('text/xml'); +sub get_target { + my $viewgrades=&Apache::lonnet::allowed('vgr',$env{'request.course.id'}); + if ( $env{'request.state'} eq 'published') { + if ( defined($env{'form.grade_target'}) + && ($viewgrades == 'F' )) { + return ($env{'form.grade_target'}); + } elsif (defined($env{'form.grade_target'})) { + if (($env{'form.grade_target'} eq 'web') || + ($env{'form.grade_target'} eq 'tex') ) { + return $env{'form.grade_target'} + } else { + return 'web'; + } + } else { + return 'web'; + } + } elsif ($env{'request.state'} eq 'construct') { + if ( defined($env{'form.grade_target'})) { + return ($env{'form.grade_target'}); + } else { + return 'web'; + } } else { - $request->content_type('text/html'); + return 'web'; } - &Apache::loncommon::no_cache($request); - $request->send_http_header; - - return OK if $request->header_only; - +} - my $file=&Apache::lonnet::filelocation("",$request->uri); +sub handler { + my $request=shift; + + my $target=&get_target(); + + $Apache::lonxml::debug=$env{'user.debug'}; + + &Apache::loncommon::content_type($request,'text/html'); + &Apache::loncommon::no_cache($request); + if ($env{'request.state'} eq 'published') { + $request->set_last_modified(&Apache::lonnet::metadata($request->uri, + 'lastrevisiondate')); + } + $request->send_http_header; + + return OK if $request->header_only; + + + my $file=&Apache::lonnet::filelocation("",$request->uri); + my $filetype; + if ($file =~ /\.sty$/) { + $filetype='sty'; + } else { + $filetype='html'; + } # # Edit action? Save file. # - unless ($ENV{'request.state'} eq 'published') { - if (($ENV{'form.savethisfile'}) || ($ENV{'form.attemptclean'})) { - &storefile($file,$ENV{'form.filecont'}); - } - } - my %mystyle; - my $result = ''; - my $filecontents=&Apache::lonnet::getfile($file); - if ($filecontents == -1) { - $result=(< - -File not found - - -File not found: $file - - -ENDNOTFOUND - $filecontents=''; - } else { - unless ($ENV{'request.state'} eq 'published') { - if ($ENV{'form.attemptclean'}) { - $filecontents=&htmlclean($filecontents,1); - } + if (!($env{'request.state'} eq 'published')) { + if ($env{'form.savethisfile'} || $env{'form.viewmode'} || $env{'form.Undo'}) { + my $html_file=&Apache::lonnet::getfile($file); + my $error = &Apache::lonhomework::handle_save_or_undo($request, \$html_file, \$env{'form.filecont'}); + } } - if ($ENV{'form.showmode'} ne 'Edit') { - $result = &Apache::lonxml::xmlparse($target,$filecontents,'',%mystyle); + my %mystyle; + my $result = ''; + my $filecontents=&Apache::lonnet::getfile($file); + if ($filecontents eq -1) { + my $start_page=&Apache::loncommon::start_page('File Error'); + my $end_page=&Apache::loncommon::end_page(); + my $fnf=&mt('File not found'); + $result=(<$fnf: $file +$end_page +ENDNOTFOUND + $filecontents=''; + if ($env{'request.state'} ne 'published') { + if ($filetype eq 'sty') { + $filecontents=&createnewsty(); + } else { + $filecontents=&createnewhtml(); + } + $env{'form.editmode'}='Edit'; #force edit mode + } + } else { + unless ($env{'request.state'} eq 'published') { + if ($filecontents=~/BEGIN LON-CAPA Internal/) { + &Apache::lonxml::error(&mt('This file appears to be a rendering of a LON-CAPA resource. If this is correct, this resource will act very oddly and incorrectly.')); + } +# +# we are in construction space, see if edit mode forced + &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'}, + ['editmode']); + } + if (!$env{'form.editmode'} || $env{'form.viewmode'} || $env{'form.discardview'}) { + $result = &Apache::lonxml::xmlparse($request,$target,$filecontents, + '',%mystyle); + undef($Apache::lonhomework::parsing_a_task); + &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'}, + ['rawmode']); + if ($env{'form.rawmode'}) { $result = $filecontents; } + } } - } - + # # Edit action? Insert editing commands # - unless ($ENV{'request.state'} eq 'published') { - if ($ENV{'form.showmode'} eq 'Edit') { - $result=''; - $result=&inserteditinfo($result,$filecontents); - } else { - $result = &editbutton($result); + unless ($env{'request.state'} eq 'published') { + if ($env{'form.editmode'} && (!($env{'form.viewmode'})) && (!($env{'form.discardview'}))) + { + my $displayfile=$request->uri; + $displayfile=~s/^\/[^\/]*//; + my %options = (); + if ($env{'environment.remote'} ne 'off') { + $options{'bgcolor'} = '#FFFFFF'; + } + my $start_page = &Apache::loncommon::start_page(undef,undef, + \%options); + $result=$start_page. + &Apache::lonxml::message_location().'

'. + $displayfile. + '

'.&Apache::loncommon::end_page(); + $result=&inserteditinfo($result,$filecontents,$filetype); + } } - } - - writeallows($request->uri); - - $request->print($result); - - return OK; + if ($filetype eq 'html') { &writeallows($request->uri); } + + + &Apache::lonxml::add_messages(\$result); + $request->print($result); + + return OK; +} + +sub display_title { + my $result; + if ($env{'request.state'} eq 'construct') { + my $title=&Apache::lonnet::gettitle(); + if (!defined($title) || $title eq '') { + $title = $env{'request.filename'}; + $title = substr($title, rindex($title, '/') + 1); + } + $result = ""; + } + return $result; } sub debug { - if ($Apache::lonxml::debug eq 1) { - $|=1; - print("DEBUG:".join('
',@_)."
\n"); - } + if ($Apache::lonxml::debug eq "1") { + $|=1; + my $request=$Apache::lonxml::request; + if (!$request) { + eval { $request=Apache->request; }; + } + if (!$request) { + eval { $request=Apache2::RequestUtil->request; }; + } + $request->print('
DEBUG:'.&HTML::Entities::encode($_[0],'<>&"')."
\n"); + #&Apache::lonnet::logthis($_[0]); + } } -sub error { - if (($Apache::lonxml::debug eq 1) || ($ENV{'request.state'} eq 'construct') ) { - print "ERROR:".join('
',@_)."
\n"; - } else { - print "An Error occured while processing this resource. The instructor has been notified.
"; - #notify author - &Apache::lonmsg::author_res_msg($ENV{'request.filename'},join('
',@_)); - #notify course - if ( $ENV{'request.course.id'} ) { - my $users=$ENV{'course.'.$ENV{'request.course.id'}.'.comment.email'}; - my $declutter=&Apache::lonnet::declutter($ENV{'request.filename'}); - foreach my $user (split /\,/, $users) { - ($user,my $domain) = split /:/, $user; - &Apache::lonmsg::user_normal_msg($user,$domain, - "Error [$declutter]",join('
',@_)); - } +sub show_error_warn_msg { + if ($env{'request.filename'} eq '/home/httpd/html/res/lib/templates/simpleproblem.problem' && + &Apache::lonnet::allowed('mdc',$env{'request.course.id'})) { + return 1; } + return (($Apache::lonxml::debug eq 1) || + ($env{'request.state'} eq 'construct') || + ($Apache::lonhomework::browse eq 'F' + && + $env{'form.show_errors'} eq 'on')); +} - #FIXME probably shouldn't have me get everything forever. - &Apache::lonmsg::user_normal_msg('albertel','msu',"Error in $ENV{'request.filename'}",join('
',@_)); - #&Apache::lonmsg::user_normal_msg('albertel','103',"Error in $ENV{'request.filename'}",$_[0]); - } +sub error { + $errorcount++; + if ( &show_error_warn_msg() ) { + # If printing in construction space, put the error inside

+	push(@Apache::lonxml::error_messages,
+	     $Apache::lonxml::warnings_error_header.
+	     "ERROR:".join("
\n",@_)."
\n"); + $Apache::lonxml::warnings_error_header=''; + } else { + my $errormsg; + my ($symb)=&Apache::lonnet::symbread(); + if ( !$symb ) { + #public or browsers + $errormsg=&mt("An error occured while processing this resource. The author has been notified."); + } + my $host=$Apache::lonnet::perlvar{'lonHostID'}; + my $msg = join('
',(@_,"The error occurred on host $host")); + #notify author + &Apache::lonmsg::author_res_msg($env{'request.filename'},$msg); + #notify course + if ( $symb && $env{'request.course.id'} ) { + my $cnum=$env{'course.'.$env{'request.course.id'}.'.num'}; + my $cdom=$env{'course.'.$env{'request.course.id'}.'.domain'}; + my (undef,%users)=&Apache::lonfeedback::decide_receiver(undef,0,1,1,1); + my $declutter=&Apache::lonnet::declutter($env{'request.filename'}); + my $baseurl = &Apache::lonnet::clutter($declutter); + my @userlist; + foreach (keys %users) { + my ($user,$domain) = split(/:/, $_); + push(@userlist,"$user\@$domain"); + my $key=$declutter.'_'.$user.'_'.$domain; + my %lastnotified=&Apache::lonnet::get('nohist_xmlerrornotifications', + [$key], + $cdom,$cnum); + my $now=time; + if ($now-$lastnotified{$key}>86400) { + my $title = &Apache::lonnet::gettitle($symb); + my $sentmessage; + &Apache::lonmsg::user_normal_msg($user,$domain, + "Error [$title]",$msg,'',$baseurl,'','', + \$sentmessage,$symb,$title,1); + &Apache::lonnet::put('nohist_xmlerrornotifications', + {$key => $now}, + $cdom,$cnum); + } + } + if ($env{'request.role.adv'}) { + $errormsg=&mt("An error occured while processing this resource. The course personnel ([_1]) and the author have been notified.",join(', ',@userlist)); + } else { + $errormsg=&mt("An error occured while processing this resource. The instructor has been notified."); + } + } + push(@Apache::lonxml::error_messages,"$errormsg
"); + } } sub warning { - if ($ENV{'request.state'} eq 'construct') { - print "WARNING:".join('
',@_)."
\n"; - } + $warningcount++; + + if ($env{'form.grade_target'} ne 'tex') { + if ( &show_error_warn_msg() ) { + push(@Apache::lonxml::warning_messages, + $Apache::lonxml::warnings_error_header. + "WARNING:".join('
',@_)."
\n"); + $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('
',@_)."
\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 { - my ($param,$parstack,$safeeval,$context) = @_; - if ( ! $context ) { $context = -1; } - my $args =''; - if ( $#$parstack > (-2-$context) ) { $args=$$parstack[$context]; } - if ( $args =~ /my \$$param=\"/ ) { - return &Apache::run::run("{$args;".'return $'.$param.'}',$safeeval); #' - } else { - return undef; - } + my ($param,$parstack,$safeeval,$context,$case_insensitive) = @_; + if ( ! $context ) { $context = -1; } + my $args =''; + if ( $#$parstack > (-2-$context) ) { $args=$$parstack[$context]; } + if ( ! $Apache::lonxml::usestyle ) { + $args=$Apache::lonxml::style_values.$args; + } + if ( ! $args ) { return undef; } + if ( $case_insensitive ) { + if ($args =~ s/(my (?:.*))(\$\Q$param\E[,\)])/$1.lc($2)/ei) { + return &Apache::run::run("{$args;".'return $'.$param.'}', + $safeeval); #' + } else { + return undef; + } + } else { + if ( $args =~ /my .*\$\Q$param\E[,\)]/ ) { + return &Apache::run::run("{$args;".'return $'.$param.'}', + $safeeval); #' + } else { + return undef; + } + } } sub get_param_var { - my ($param,$parstack,$safeeval,$context) = @_; + my ($param,$parstack,$safeeval,$context,$case_insensitive) = @_; if ( ! $context ) { $context = -1; } my $args =''; if ( $#$parstack > (-2-$context) ) { $args=$$parstack[$context]; } - if ( $args !~ /my \$$param=\"/ ) { return undef; } + if ( ! $Apache::lonxml::usestyle ) { + $args=$Apache::lonxml::style_values.$args; + } + &Apache::lonxml::debug("Args are $args param is $param"); + if ($case_insensitive) { + if (! ($args=~s/(my (?:.*))(\$\Q$param\E[,\)])/$1.lc($2)/ei)) { + return undef; + } + } elsif ( $args !~ /my .*\$\Q$param\E[,\)]/ ) { return undef; } my $value=&Apache::run::run("{$args;".'return $'.$param.'}',$safeeval); #' - if ($value =~ /^[\$\@\%]/) { - return &Apache::run::run("return $value",$safeeval,1); + &Apache::lonxml::debug("first run is $value"); + if ($value =~ /^[\$\@\%][a-zA-Z_]\w*$/) { + &Apache::lonxml::debug("doing second"); + my @result=&Apache::run::run("return $value",$safeeval,1); + if (!defined($result[0])) { + return $value + } else { + if (wantarray) { return @result; } else { return $result[0]; } + } } else { return $value; } } -sub register_insert { +sub register_insert_tab { my @data = split /\n/, &Apache::lonnet::getfile('/home/httpd/lonTabs/insertlist.tab'); my $i; my $tagnum=0; @@ -1210,14 +1701,16 @@ sub register_insert { my $line = $data[$i]; if ( $line =~ /^\#/ || $line =~ /^\s*\n/) { next; } if ( $line =~ /TABLE/ ) { last; } - my ($tag,$descrip,$color,$function,$show) = split(/,/, $line); + my ($tag,$descrip,$color,$function,$show,$helpfile,$helpdesc) = split(/,/, $line); if ($tag) { $insertlist{"$tagnum.tag"} = $tag; - $insertlist{"$tagnum.description"} = $descrip; - $insertlist{"$tagnum.color"} = $color; - $insertlist{"$tagnum.function"} = $function; + $insertlist{"$tag.description"} = $descrip; + $insertlist{"$tag.color"} = $color; + $insertlist{"$tag.function"} = $function; if (!defined($show)) { $show='yes'; } - $insertlist{"$tagnum.show"}= $show; + $insertlist{"$tag.show"}= $show; + $insertlist{"$tag.helpfile"} = $helpfile; + $insertlist{"$tag.helpdesc"} = $helpdesc; $insertlist{"$tag.num"}=$tagnum; $tagnum++; } @@ -1231,7 +1724,7 @@ sub register_insert { for (my $j=0;$j <=$#which;$j++) { if ( $which[$j] eq 'Y' ) { if ($insertlist{"$j.show"} ne 'no') { - push(@{ $insertlist{"$tag.which"} },$j); + push(@{ $insertlist{"$tag.which"} },$insertlist{"$j.tag"}); } } } @@ -1239,41 +1732,136 @@ sub register_insert { } } +sub register_insert_xml { + my $parser = HTML::LCParser->new($Apache::lonnet::perlvar{'lonTabDir'} + .'/insertlist.xml'); + my ($tagnum,$in_help)=(0,0); + my $tag; + while (my $token = $parser->get_token()) { + if ($token->[0] eq 'S') { + my $key; + if ($token->[1] eq 'tag') { + $tag = $token->[2]{'name'}; + $insertlist{"$tagnum.tag"} = $tag; + $insertlist{"$tag.num"} = $tagnum; + } elsif ($in_help && $token->[1] eq 'file') { + $key = $tag.'.helpfile'; + } elsif ($in_help && $token->[1] eq 'description') { + $key = $tag.'.helpdesc'; + } elsif ($token->[1] eq 'description' || + $token->[1] eq 'color' || + $token->[1] eq 'show' ) { + $key = $tag.'.'.$token->[1]; + } elsif ($token->[1] eq 'insert_sub') { + $key = $tag.'.function'; + } elsif ($token->[1] eq 'help') { + $in_help=1; + } elsif ($token->[1] eq 'allow') { + my $allow = $parser->get_text(); + foreach my $element (split(',',$allow)) { + $element =~ s/(^\s*|\s*$ )//gx; + push(@{ $insertlist{$tag.'.which'} },$element); + } + } + if (defined($key)) { + $insertlist{$key} = $parser->get_text(); + $insertlist{$key} =~ s/(^\s*|\s*$ )//gx; + } + } elsif ($token->[0] eq 'E') { + if ($token->[1] eq 'tag') { + undef($tag); + $tagnum++; + } elsif ($token->[1] eq 'help') { + undef($in_help); + } + } + } +} + +sub register_insert { +# ®ister_insert_tab(@_); +# &dump_insertlist('1'); +# undef(%insertlist); + return ®ister_insert_xml(@_); +# &dump_insertlist('2'); +} + +sub dump_insertlist { + my ($ext) = @_; + open(XML,">/tmp/insertlist.xml.$ext"); + print XML (""); + my $i=0; + + while (exists($insertlist{"$i.tag"})) { + my $tag = $insertlist{"$i.tag"}; + print XML (" +\t"); + if (defined($insertlist{"$tag.description"})) { + print XML (" +\t\t".$insertlist{"$tag.description"}.""); + } + if (defined($insertlist{"$tag.color"})) { + print XML (" +\t\t".$insertlist{"$tag.color"}.""); + } + if (defined($insertlist{"$tag.function"})) { + print XML (" +\t\t".$insertlist{"$tag.function"}.""); + } + if (defined($insertlist{"$tag.show"}) + && $insertlist{"$tag.show"} ne 'yes') { + print XML (" +\t\t".$insertlist{"$tag.show"}.""); + } + if (defined($insertlist{"$tag.helpfile"})) { + print XML (" +\t\t +\t\t\t".$insertlist{"$tag.helpfile"}.""); + if ($insertlist{"$tag.helpdesc"} ne '') { + print XML (" +\t\t\t".$insertlist{"$tag.helpdesc"}.""); + } + print XML (" +\t\t"); + } + if (defined($insertlist{"$tag.which"})) { + print XML (" +\t\t".join(',',sort(@{ $insertlist{"$tag.which"} })).""); + } + print XML (" +\t"); + $i++; + } + print XML ("\n\n"); + close(XML); +} + sub description { - my ($token)=@_; - my $tagnum; - my $tag=$token->[1]; - foreach my $namespace (reverse @Apache::lonxml::namespace) { - my $testtag=$namespace.'::'.$tag; - $tagnum=$insertlist{"$testtag.num"}; - if (defined($tagnum)) { last; } - } - if (!defined ($tagnum)) { $tagnum=$Apache::lonxml::insertlist{"$tag.num"}; } - return $insertlist{$tagnum.'.description'}; + my ($token)=@_; + my $tag = &get_tag($token); + return $insertlist{$tag.'.description'}; +} + +# Returns a list containing the help file, and the description +sub helpinfo { + my ($token)=@_; + my $tag = &get_tag($token); + return ($insertlist{$tag.'.helpfile'}, $insertlist{$tag.'.helpdesc'}); } -# ----------------------------------------------------------------- whichuser -# returns a list of $symb, $courseid, $domain, $name that is correct for -# calls to lonnet functions for this setup. -# - looks for form.grade_ parameters -sub whichuser { - my ($symb,$courseid,$domain,$name); - if (defined($ENV{'form.grade_symb'})) { - my $tmp_courseid=$ENV{'form.grade_courseid'}; - my $allowed=&Apache::lonnet::allowed('mgr',$tmp_courseid); - if ($allowed) { - $symb=$ENV{'form.grade_symb'}; - $courseid=$ENV{'form.grade_courseid'}; - $domain=$ENV{'form.grade_domain'}; - $name=$ENV{'form.grade_username'}; +sub get_tag { + my ($token)=@_; + my $tagnum; + my $tag=$token->[1]; + foreach my $namespace (reverse(@Apache::lonxml::namespace)) { + my $testtag = $namespace.'::'.$tag; + $tagnum = $insertlist{"$testtag.num"}; + last if (defined($tagnum)); } - } else { - $symb=&Apache::lonnet::symbread(); - $courseid=$ENV{'request.course.id'}; - $domain=$ENV{'user.domain'}; - $name=$ENV{'user.name'}; - } - return ($symb,$courseid,$domain,$name); + if (!defined($tagnum)) { + $tagnum = $Apache::lonxml::insertlist{"$tag.num"}; + } + return $insertlist{"$tagnum.tag"}; } 1; 500 Internal Server Error

Internal Server Error

The server encountered an internal error or misconfiguration and was unable to complete your request.

Please contact the server administrator at root@localhost to inform them of the time this error occurred, and the actions you performed just before this error.

More information about this error may be available in the server error log.