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