4
0

p1.pl 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. package Embed::Persistent;
  2. #
  3. # Hacked version of the sample code from the perlembedded doco.
  4. #
  5. # Only major changes are to separate the compiling and caching from
  6. # the execution so that the cache can be kept in "non-volatile" parent
  7. # process while the execution is done from "volatile" child processes
  8. # and that STDOUT is redirected to a file by means of a tied filehandle
  9. # so that it can be returned to NetSaint in the same way as for
  10. # commands executed via the normal popen method.
  11. #
  12. use strict;
  13. use vars '%Cache';
  14. use Symbol qw(delete_package);
  15. package OutputTrap;
  16. #
  17. # Methods for use by tied STDOUT in embedded PERL module.
  18. #
  19. # Simply redirects STDOUT to a temporary file associated with the
  20. # current child/grandchild process.
  21. #
  22. use strict;
  23. # Perl before 5.6 does not seem to have warnings.pm ???
  24. #use warnings;
  25. use IO::File;
  26. sub TIEHANDLE {
  27. my ($class, $fn) = @_;
  28. my $handle = new IO::File "> $fn" or die "Cannot open embedded work filei $!\n";
  29. bless { FH => $handle, Value => 0}, $class;
  30. }
  31. sub PRINT {
  32. my $self = shift;
  33. my $handle = $self -> {FH};
  34. print $handle join("",@_);
  35. }
  36. sub PRINTF {
  37. my $self = shift;
  38. my $fmt = shift;
  39. my $handle = $self -> {FH};
  40. printf $handle ($fmt,@_);
  41. }
  42. sub CLOSE {
  43. my $self = shift;
  44. my $handle = $self -> {FH};
  45. close $handle;
  46. }
  47. package Embed::Persistent;
  48. sub valid_package_name {
  49. my($string) = @_;
  50. $string =~ s/([^A-Za-z0-9\/])/sprintf("_%2x",unpack("C",$1))/eg;
  51. # second pass only for words starting with a digit
  52. $string =~ s|/(\d)|sprintf("/_%2x",unpack("C",$1))|eg;
  53. # Dress it up as a real package name
  54. $string =~ s|/|::|g;
  55. return "Embed::" . $string;
  56. }
  57. sub eval_file {
  58. my $filename = shift;
  59. my $delete = shift;
  60. my $pn = substr($filename, rindex($filename,"/")+1);
  61. my $package = valid_package_name($pn);
  62. my $mtime = -M $filename;
  63. if(defined $Cache{$package}{mtime}
  64. &&
  65. $Cache{$package}{mtime} <= $mtime)
  66. {
  67. # we have compiled this subroutine already,
  68. # it has not been updated on disk, nothing left to do
  69. #print STDERR "already compiled $package->hndlr\n";
  70. }
  71. else {
  72. local *FH;
  73. open FH, $filename or die "open '$filename' $!";
  74. local($/) = undef;
  75. my $sub = <FH>;
  76. close FH;
  77. # cater for routines that expect to get args without prgname
  78. # and for those using @ARGV
  79. $sub = "shift(\@_);\n\@ARGV=\@_;\n" . $sub;
  80. # cater for scripts that have embedded EOF symbols (__END__)
  81. $sub =~ s/__END__/\;}\n__END__/;
  82. #wrap the code into a subroutine inside our unique package
  83. my $eval = qq{
  84. package main;
  85. use subs 'CORE::GLOBAL::exit';
  86. sub CORE::GLOBAL::exit { die "ExitTrap: \$_[0] ($package)"; }
  87. package $package; sub hndlr { $sub; }
  88. };
  89. {
  90. # hide our variables within this block
  91. my($filename,$mtime,$package,$sub);
  92. eval $eval;
  93. }
  94. if ($@){
  95. print STDERR $@."\n";
  96. die;
  97. }
  98. #cache it unless we're cleaning out each time
  99. $Cache{$package}{mtime} = $mtime unless $delete;
  100. }
  101. }
  102. sub run_package {
  103. my $filename = shift;
  104. my $delete = shift;
  105. my $tmpfname = shift;
  106. my $ar = shift;
  107. my $pn = substr($filename, rindex($filename,"/")+1);
  108. my $package = valid_package_name($pn);
  109. my $res = 0;
  110. tie (*STDOUT, 'OutputTrap', $tmpfname);
  111. my @a = split(/ /,$ar);
  112. eval {$res = $package->hndlr(@a);};
  113. if ($@){
  114. if ($@ =~ /^ExitTrap: /) {
  115. $res = 0;
  116. } else {
  117. # get return code (which may be negative)
  118. if ($@ =~ /^ExitTrap: (-?\d+)/) {
  119. $res = $1;
  120. } else {
  121. $res = 2;
  122. print STDERR "<".$@.">\n";
  123. }
  124. }
  125. }
  126. untie *STDOUT;
  127. return $res;
  128. }
  129. 1;