home *** CD-ROM | disk | FTP | other *** search
/ PC Welt 2006 November (DVD) / PCWELT_11_2006.ISO / casper / filesystem.squashfs / usr / share / perl / 5.8.8 / IPC / Open3.pm < prev   
Encoding:
Perl POD Document  |  2006-07-07  |  7.5 KB  |  272 lines

  1. package IPC::Open3;
  2.  
  3. use strict;
  4. no strict 'refs'; # because users pass me bareword filehandles
  5. our ($VERSION, @ISA, @EXPORT);
  6.  
  7. require Exporter;
  8.  
  9. use Carp;
  10. use Symbol qw(gensym qualify);
  11.  
  12. $VERSION    = 1.02;
  13. @ISA        = qw(Exporter);
  14. @EXPORT        = qw(open3);
  15.  
  16. # &open3: Marc Horowitz <marc@mit.edu>
  17. # derived mostly from &open2 by tom christiansen, <tchrist@convex.com>
  18. # fixed for 5.001 by Ulrich Kunitz <kunitz@mai-koeln.com>
  19. # ported to Win32 by Ron Schmidt, Merrill Lynch almost ended my career
  20. # fixed for autovivving FHs, tchrist again
  21. # allow fd numbers to be used, by Frank Tobin
  22. # allow '-' as command (c.f. open "-|"), by Adam Spiers <perl@adamspiers.org>
  23. #
  24. # $Id: open3.pl,v 1.1 1993/11/23 06:26:15 marc Exp $
  25. #
  26. # usage: $pid = open3('wtr', 'rdr', 'err' 'some cmd and args', 'optarg', ...);
  27. #
  28. # spawn the given $cmd and connect rdr for
  29. # reading, wtr for writing, and err for errors.
  30. # if err is '', or the same as rdr, then stdout and
  31. # stderr of the child are on the same fh.  returns pid
  32. # of child (or dies on failure).
  33.  
  34. # if wtr begins with '<&', then wtr will be closed in the parent, and
  35. # the child will read from it directly.  if rdr or err begins with
  36. # '>&', then the child will send output directly to that fd.  In both
  37. # cases, there will be a dup() instead of a pipe() made.
  38.  
  39. # WARNING: this is dangerous, as you may block forever
  40. # unless you are very careful.
  41. #
  42. # $wtr is left unbuffered.
  43. #
  44. # abort program if
  45. #   rdr or wtr are null
  46. #   a system call fails
  47.  
  48. our $Me = 'open3 (bug)';    # you should never see this, it's always localized
  49.  
  50. # Fatal.pm needs to be fixed WRT prototypes.
  51.  
  52. sub xfork {
  53.     my $pid = fork;
  54.     defined $pid or croak "$Me: fork failed: $!";
  55.     return $pid;
  56. }
  57.  
  58. sub xpipe {
  59.     pipe $_[0], $_[1] or croak "$Me: pipe($_[0], $_[1]) failed: $!";
  60. }
  61.  
  62. # I tried using a * prototype character for the filehandle but it still
  63. # disallows a bearword while compiling under strict subs.
  64.  
  65. sub xopen {
  66.     open $_[0], $_[1] or croak "$Me: open($_[0], $_[1]) failed: $!";
  67. }
  68.  
  69. sub xclose {
  70.     close $_[0] or croak "$Me: close($_[0]) failed: $!";
  71. }
  72.  
  73. sub fh_is_fd {
  74.     return $_[0] =~ /\A=?(\d+)\z/;
  75. }
  76.  
  77. sub xfileno {
  78.     return $1 if $_[0] =~ /\A=?(\d+)\z/;  # deal with fh just being an fd
  79.     return fileno $_[0];
  80. }
  81.  
  82. my $do_spawn = $^O eq 'os2' || $^O eq 'MSWin32';
  83.  
  84. sub _open3 {
  85.     local $Me = shift;
  86.     my($package, $dad_wtr, $dad_rdr, $dad_err, @cmd) = @_;
  87.     my($dup_wtr, $dup_rdr, $dup_err, $kidpid);
  88.  
  89.     # simulate autovivification of filehandles because
  90.     # it's too ugly to use @_ throughout to make perl do it for us
  91.     # tchrist 5-Mar-00
  92.  
  93.     unless (eval  {
  94.     $dad_wtr = $_[1] = gensym unless defined $dad_wtr && length $dad_wtr;
  95.     $dad_rdr = $_[2] = gensym unless defined $dad_rdr && length $dad_rdr;
  96.     1; }) 
  97.     {
  98.     # must strip crud for croak to add back, or looks ugly
  99.     $@ =~ s/(?<=value attempted) at .*//s;
  100.     croak "$Me: $@";
  101.     } 
  102.  
  103.     $dad_err ||= $dad_rdr;
  104.  
  105.     $dup_wtr = ($dad_wtr =~ s/^[<>]&//);
  106.     $dup_rdr = ($dad_rdr =~ s/^[<>]&//);
  107.     $dup_err = ($dad_err =~ s/^[<>]&//);
  108.  
  109.     # force unqualified filehandles into caller's package
  110.     $dad_wtr = qualify $dad_wtr, $package unless fh_is_fd($dad_wtr);
  111.     $dad_rdr = qualify $dad_rdr, $package unless fh_is_fd($dad_rdr);
  112.     $dad_err = qualify $dad_err, $package unless fh_is_fd($dad_err);
  113.  
  114.     my $kid_rdr = gensym;
  115.     my $kid_wtr = gensym;
  116.     my $kid_err = gensym;
  117.  
  118.     xpipe $kid_rdr, $dad_wtr if !$dup_wtr;
  119.     xpipe $dad_rdr, $kid_wtr if !$dup_rdr;
  120.     xpipe $dad_err, $kid_err if !$dup_err && $dad_err ne $dad_rdr;
  121.  
  122.     $kidpid = $do_spawn ? -1 : xfork;
  123.     if ($kidpid == 0) {        # Kid
  124.     # A tie in the parent should not be allowed to cause problems.
  125.     untie *STDIN;
  126.     untie *STDOUT;
  127.     # If she wants to dup the kid's stderr onto her stdout I need to
  128.     # save a copy of her stdout before I put something else there.
  129.     if ($dad_rdr ne $dad_err && $dup_err
  130.         && xfileno($dad_err) == fileno(STDOUT)) {
  131.         my $tmp = gensym;
  132.         xopen($tmp, ">&$dad_err");
  133.         $dad_err = $tmp;
  134.     }
  135.  
  136.     if ($dup_wtr) {
  137.         xopen \*STDIN,  "<&$dad_wtr" if fileno(STDIN) != xfileno($dad_wtr);
  138.     } else {
  139.         xclose $dad_wtr;
  140.         xopen \*STDIN,  "<&=" . fileno $kid_rdr;
  141.     }
  142.     if ($dup_rdr) {
  143.         xopen \*STDOUT, ">&$dad_rdr" if fileno(STDOUT) != xfileno($dad_rdr);
  144.     } else {
  145.         xclose $dad_rdr;
  146.         xopen \*STDOUT, ">&=" . fileno $kid_wtr;
  147.     }
  148.     if ($dad_rdr ne $dad_err) {
  149.         if ($dup_err) {
  150.         # I have to use a fileno here because in this one case
  151.         # I'm doing a dup but the filehandle might be a reference
  152.         # (from the special case above).
  153.         xopen \*STDERR, ">&" . xfileno($dad_err)
  154.             if fileno(STDERR) != xfileno($dad_err);
  155.         } else {
  156.         xclose $dad_err;
  157.         xopen \*STDERR, ">&=" . fileno $kid_err;
  158.         }
  159.     } else {
  160.         xopen \*STDERR, ">&STDOUT" if fileno(STDERR) != fileno(STDOUT);
  161.     }
  162.     if ($cmd[0] eq '-') {
  163.         croak "Arguments don't make sense when the command is '-'"
  164.           if @cmd > 1;
  165.         return 0;
  166.     }
  167.     local($")=(" ");
  168.     exec @cmd # XXX: wrong process to croak from
  169.         or croak "$Me: exec of @cmd failed";
  170.     } elsif ($do_spawn) {
  171.     # All the bookkeeping of coincidence between handles is
  172.     # handled in spawn_with_handles.
  173.  
  174.     my @close;
  175.     if ($dup_wtr) {
  176.       $kid_rdr = \*{$dad_wtr};
  177.       push @close, $kid_rdr;
  178.     } else {
  179.       push @close, \*{$dad_wtr}, $kid_rdr;
  180.     }
  181.     if ($dup_rdr) {
  182.       $kid_wtr = \*{$dad_rdr};
  183.       push @close, $kid_wtr;
  184.     } else {
  185.       push @close, \*{$dad_rdr}, $kid_wtr;
  186.     }
  187.     if ($dad_rdr ne $dad_err) {
  188.         if ($dup_err) {
  189.           $kid_err = \*{$dad_err};
  190.           push @close, $kid_err;
  191.         } else {
  192.           push @close, \*{$dad_err}, $kid_err;
  193.         }
  194.     } else {
  195.       $kid_err = $kid_wtr;
  196.     }
  197.     require IO::Pipe;
  198.     $kidpid = eval {
  199.         spawn_with_handles( [ { mode => 'r',
  200.                     open_as => $kid_rdr,
  201.                     handle => \*STDIN },
  202.                   { mode => 'w',
  203.                     open_as => $kid_wtr,
  204.                     handle => \*STDOUT },
  205.                   { mode => 'w',
  206.                     open_as => $kid_err,
  207.                     handle => \*STDERR },
  208.                 ], \@close, @cmd);
  209.     };
  210.     die "$Me: $@" if $@;
  211.     }
  212.  
  213.     xclose $kid_rdr if !$dup_wtr;
  214.     xclose $kid_wtr if !$dup_rdr;
  215.     xclose $kid_err if !$dup_err && $dad_rdr ne $dad_err;
  216.     # If the write handle is a dup give it away entirely, close my copy
  217.     # of it.
  218.     xclose $dad_wtr if $dup_wtr;
  219.  
  220.     select((select($dad_wtr), $| = 1)[0]); # unbuffer pipe
  221.     $kidpid;
  222. }
  223.  
  224. sub open3 {
  225.     if (@_ < 4) {
  226.     local $" = ', ';
  227.     croak "open3(@_): not enough arguments";
  228.     }
  229.     return _open3 'open3', scalar caller, @_
  230. }
  231.  
  232. sub spawn_with_handles {
  233.     my $fds = shift;        # Fields: handle, mode, open_as
  234.     my $close_in_child = shift;
  235.     my ($fd, $pid, @saved_fh, $saved, %saved, @errs);
  236.     require Fcntl;
  237.  
  238.     foreach $fd (@$fds) {
  239.     $fd->{tmp_copy} = IO::Handle->new_from_fd($fd->{handle}, $fd->{mode});
  240.     $saved{fileno $fd->{handle}} = $fd->{tmp_copy};
  241.     }
  242.     foreach $fd (@$fds) {
  243.     bless $fd->{handle}, 'IO::Handle'
  244.         unless eval { $fd->{handle}->isa('IO::Handle') } ;
  245.     # If some of handles to redirect-to coincide with handles to
  246.     # redirect, we need to use saved variants:
  247.     $fd->{handle}->fdopen($saved{fileno $fd->{open_as}} || $fd->{open_as},
  248.                   $fd->{mode});
  249.     }
  250.     unless ($^O eq 'MSWin32') {
  251.     # Stderr may be redirected below, so we save the err text:
  252.     foreach $fd (@$close_in_child) {
  253.         fcntl($fd, Fcntl::F_SETFD(), 1) or push @errs, "fcntl $fd: $!"
  254.         unless $saved{fileno $fd}; # Do not close what we redirect!
  255.     }
  256.     }
  257.  
  258.     unless (@errs) {
  259.     $pid = eval { system 1, @_ }; # 1 == P_NOWAIT
  260.     push @errs, "IO::Pipe: Can't spawn-NOWAIT: $!" if !$pid || $pid < 0;
  261.     }
  262.  
  263.     foreach $fd (@$fds) {
  264.     $fd->{handle}->fdopen($fd->{tmp_copy}, $fd->{mode});
  265.     $fd->{tmp_copy}->close or croak "Can't close: $!";
  266.     }
  267.     croak join "\n", @errs if @errs;
  268.     return $pid;
  269. }
  270.  
  271. 1; # so require is happy
  272.