package Apache::ESSI;
 
use strict;
use Apache::Constants qw(:common);
use Apache::File ();
use Text::ParseWords qw(quotewords);
my (%MODIFIED, %SUBSTITUTION);
 
sub handler {
    my $r = shift;
    $r->content_type() eq 'text/html' || return DECLINED;
    my $fh = Apache::File->new($r->filename) || return DECLINED;
    my $sub = read_definitions($r)    || return SERVER_ERROR;
    $r->send_http_header;
    $r->print($sub->($r, $fh));
    return OK;
}
 
sub read_definitions {
    my $r = shift;
    my $def = $r->dir_config('ESSIDefs');
    return unless $def;
    return unless -e ($def = $r->server_root_relative($def));
    return $SUBSTITUTION{$def} if $MODIFIED{$def} && $MODIFIED{$def} <= -M _;
 
    my $package = join "::", __PACKAGE__, $def;
    $package =~ tr/a-zA-Z0-9_/_/c;
     
    eval "package $package; do '$def'";
 
    if($@) {
 	$r->log_error("Eval of $def did not return true: $@");
 	return;
    }
 
    $SUBSTITUTION{$def} = sub { 
	do_substitutions($package, @_);
    };
 
    $MODIFIED{$def} = -M $def;  # store modification date
    return $SUBSTITUTION{$def};
}

sub do_substitutions {
    my $package = shift;
    my($r, $fh) = @_;
    # Make sure that eval() errors aren't trapped.
    local $SIG{__WARN__};
    local $SIG{__DIE__};
    local $/; #slurp $fh
    my $data = <$fh>;
    $data =~ s/<!--\s*\#(\w+) # start of a function name
	       \s*(.*?)         # optional parameters
	       \s*-->           # end of comment
	      /call_sub($package, $1, $r, $2)/xseg;
    $data;
}
 
sub call_sub {
    my($package, $name, $r, $args) = @_; 
    my $sub = \&{join '::', $package, $name};
    $r->chdir_file;
    my $res = eval { $sub->($r, quotewords('[ ,]',0,$args)) };
    return "<em>[$@]</em>" if $@;
    return $res;
}
 
1;
__END__
