| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151 |
- package Embed::Persistent;
- #
- # Hacked version of the sample code from the perlembedded doco.
- #
- # Only major changes are to separate the compiling and caching from
- # the execution so that the cache can be kept in "non-volatile" parent
- # process while the execution is done from "volatile" child processes
- # and that STDOUT is redirected to a file by means of a tied filehandle
- # so that it can be returned to NetSaint in the same way as for
- # commands executed via the normal popen method.
- #
- use strict;
- use vars '%Cache';
- use Symbol qw(delete_package);
- package OutputTrap;
- #
- # Methods for use by tied STDOUT in embedded PERL module.
- #
- # Simply redirects STDOUT to a temporary file associated with the
- # current child/grandchild process.
- #
-
- use strict;
- # Perl before 5.6 does not seem to have warnings.pm ???
- #use warnings;
- use IO::File;
- sub TIEHANDLE {
- my ($class, $fn) = @_;
- my $handle = new IO::File "> $fn" or die "Cannot open embedded work filei $!\n";
- bless { FH => $handle, Value => 0}, $class;
- }
- sub PRINT {
- my $self = shift;
- my $handle = $self -> {FH};
- print $handle join("",@_);
- }
- sub PRINTF {
- my $self = shift;
- my $fmt = shift;
- my $handle = $self -> {FH};
- printf $handle ($fmt,@_);
- }
- sub CLOSE {
- my $self = shift;
- my $handle = $self -> {FH};
- close $handle;
- }
- package Embed::Persistent;
- sub valid_package_name {
- my($string) = @_;
- $string =~ s/([^A-Za-z0-9\/])/sprintf("_%2x",unpack("C",$1))/eg;
- # second pass only for words starting with a digit
- $string =~ s|/(\d)|sprintf("/_%2x",unpack("C",$1))|eg;
- # Dress it up as a real package name
- $string =~ s|/|::|g;
- return "Embed::" . $string;
- }
- sub eval_file {
- my $filename = shift;
- my $delete = shift;
- my $pn = substr($filename, rindex($filename,"/")+1);
- my $package = valid_package_name($pn);
- my $mtime = -M $filename;
- if(defined $Cache{$package}{mtime}
- &&
- $Cache{$package}{mtime} <= $mtime)
- {
- # we have compiled this subroutine already,
- # it has not been updated on disk, nothing left to do
- #print STDERR "already compiled $package->hndlr\n";
- }
- else {
- local *FH;
- open FH, $filename or die "open '$filename' $!";
- local($/) = undef;
- my $sub = <FH>;
- close FH;
- # cater for routines that expect to get args without prgname
- # and for those using @ARGV
- $sub = "shift(\@_);\n\@ARGV=\@_;\n" . $sub;
- # cater for scripts that have embedded EOF symbols (__END__)
- $sub =~ s/__END__/\;}\n__END__/;
-
- #wrap the code into a subroutine inside our unique package
- my $eval = qq{
- package main;
- use subs 'CORE::GLOBAL::exit';
- sub CORE::GLOBAL::exit { die "ExitTrap: \$_[0] ($package)"; }
- package $package; sub hndlr { $sub; }
- };
- {
- # hide our variables within this block
- my($filename,$mtime,$package,$sub);
- eval $eval;
- }
- if ($@){
- print STDERR $@."\n";
- die;
- }
- #cache it unless we're cleaning out each time
- $Cache{$package}{mtime} = $mtime unless $delete;
- }
- }
- sub run_package {
- my $filename = shift;
- my $delete = shift;
- my $tmpfname = shift;
- my $ar = shift;
- my $pn = substr($filename, rindex($filename,"/")+1);
- my $package = valid_package_name($pn);
- my $res = 0;
- tie (*STDOUT, 'OutputTrap', $tmpfname);
- my @a = split(/ /,$ar);
-
- eval {$res = $package->hndlr(@a);};
- if ($@){
- if ($@ =~ /^ExitTrap: /) {
- $res = 0;
- } else {
- # get return code (which may be negative)
- if ($@ =~ /^ExitTrap: (-?\d+)/) {
- $res = $1;
- } else {
- $res = 2;
- print STDERR "<".$@.">\n";
- }
- }
- }
- untie *STDOUT;
- return $res;
- }
- 1;
|