perl5.001 patch.1f
[p5sagit/p5-mst-13.2.git] / lib / IPC / Open3.pm
CommitLineData
a0d0e21e 1package IPC::Open3;
2require 5.000;
3require Exporter;
4use Carp;
5
6@ISA = qw(Exporter);
7@EXPORT = qw(open3);
8
9# &open3: Marc Horowitz <marc@mit.edu>
10# derived mostly from &open2 by tom christiansen, <tchrist@convex.com>
11#
12# $Id: open3.pl,v 1.1 1993/11/23 06:26:15 marc Exp $
13#
14# usage: $pid = open3('wtr', 'rdr', 'err' 'some cmd and args', 'optarg', ...);
15#
16# spawn the given $cmd and connect rdr for
17# reading, wtr for writing, and err for errors.
18# if err is '', or the same as rdr, then stdout and
19# stderr of the child are on the same fh. returns pid
20# of child, or 0 on failure.
21
22
23# if wtr begins with '>&', then wtr will be closed in the parent, and
24# the child will read from it directly. if rdr or err begins with
25# '>&', then the child will send output directly to that fd. In both
26# cases, there will be a dup() instead of a pipe() made.
27
28
29# WARNING: this is dangerous, as you may block forever
30# unless you are very careful.
31#
32# $wtr is left unbuffered.
33#
34# abort program if
35# rdr or wtr are null
36# pipe or fork or exec fails
37
38$fh = 'FHOPEN000'; # package static in case called more than once
39
40sub open3 {
41 local($kidpid);
42 local($dad_wtr, $dad_rdr, $dad_err, @cmd) = @_;
43 local($dup_wtr, $dup_rdr, $dup_err);
44
45 $dad_wtr || croak "open3: wtr should not be null";
46 $dad_rdr || croak "open3: rdr should not be null";
47 $dad_err = $dad_rdr if ($dad_err eq '');
48
49 $dup_wtr = ($dad_wtr =~ s/^\>\&//);
50 $dup_rdr = ($dad_rdr =~ s/^\>\&//);
51 $dup_err = ($dad_err =~ s/^\>\&//);
52
53 # force unqualified filehandles into callers' package
54 local($package) = caller;
55 $dad_wtr =~ s/^[^']+$/$package'$&/;
56 $dad_rdr =~ s/^[^']+$/$package'$&/;
57 $dad_err =~ s/^[^']+$/$package'$&/;
58
59 local($kid_rdr) = ++$fh;
60 local($kid_wtr) = ++$fh;
61 local($kid_err) = ++$fh;
62
63 if (!$dup_wtr) {
64 pipe($kid_rdr, $dad_wtr) || croak "open3: pipe 1 (stdin) failed: $!";
65 }
66 if (!$dup_rdr) {
67 pipe($dad_rdr, $kid_wtr) || croak "open3: pipe 2 (stdout) failed: $!";
68 }
69 if ($dad_err ne $dad_rdr && !$dup_err) {
70 pipe($dad_err, $kid_err) || croak "open3: pipe 3 (stderr) failed: $!";
71 }
72
73 if (($kidpid = fork) < 0) {
74 croak "open2: fork failed: $!";
75 } elsif ($kidpid == 0) {
76 if ($dup_wtr) {
77 open(STDIN, ">&$dad_wtr") if (fileno(STDIN) != fileno($dad_wtr));
78 } else {
79 close($dad_wtr);
80 open(STDIN, ">&$kid_rdr");
81 }
82 if ($dup_rdr) {
83 open(STDOUT, ">&$dad_rdr") if (fileno(STDOUT) != fileno($dad_rdr));
84 } else {
85 close($dad_rdr);
86 open(STDOUT, ">&$kid_wtr");
87 }
88 if ($dad_rdr ne $dad_err) {
89 if ($dup_err) {
90 open(STDERR, ">&$dad_err")
91 if (fileno(STDERR) != fileno($dad_err));
92 } else {
93 close($dad_err);
94 open(STDERR, ">&$kid_err");
95 }
96 } else {
97 open(STDERR, ">&STDOUT") if (fileno(STDERR) != fileno(STDOUT));
98 }
99 local($")=(" ");
100 exec @cmd;
101 croak "open2: exec of @cmd failed";
102 }
103
104 close $kid_rdr; close $kid_wtr; close $kid_err;
105 if ($dup_wtr) {
106 close($dad_wtr);
107 }
108
109 select((select($dad_wtr), $| = 1)[0]); # unbuffer pipe
110 $kidpid;
111}
1121; # so require is happy
113