File Coverage

blib/lib/IO/Pipe/Producer.pm
Criterion Covered Total %
statement 78 106 73.5
branch 30 38 78.9
condition 12 17 70.5
subroutine 10 11 90.9
pod 1 3 33.3
total 131 175 74.8


line stmt bran cond sub pod time code
1             package IO::Pipe::Producer;
2              
3 10     10   668440 use 5.010001;
  10         30  
4 10     10   40 use strict;
  10         20  
  10         160  
5 10     10   40 use warnings;
  10         20  
  10         300  
6 10     10   50 use Carp;
  10         20  
  10         1080  
7              
8             our @ISA = qw(IO::Pipe);
9 10     10   70 use base qw(IO::Pipe);
  10         10  
  10         4660  
10              
11             our $VERSION = '2.02';
12              
13             #NOTICE
14             #
15             #This software and ancillary information (herein called "SOFTWARE") called
16             #Producer.pm is made available under the terms described here. The
17             #SOFTWARE has been approved for release with associated LA-CC number
18             #LA-CC-05-060.
19             #
20             #Unless otherwise indicated, this software has been authored by an employee or
21             #employees of the University of California, operator of the Los Alamos National
22             #Laboratory under Contract No. W-7405-ENG-36 with the U.S. Department of
23             #Energy. The U.S. government has rights to use, reproduce, and distribute this
24             #SOFTWARE. The public may copy, distribute, prepare derivative works and
25             #publicly display this SOFTWARE without charge, provided that this notice and
26             #any statement of authorship are reproduced on all copies. Neither the
27             #government nor the university makes any warranty, express or implied, or
28             #assumes any liability or responsibility for the use of this SOFTWARE.
29             #
30             #If SOFTWARE is modified to produce derivative works, such modified SOFTWARE
31             #should be clearly marked, so as not to confuse it with the version available
32             #from LANL.
33              
34              
35             #Constructor
36              
37             sub new
38             {
39             #Get the class name
40 54     54 1 8622014 my $class = shift(@_);
41             #Instantiate an instance of the super class and bless into this class
42 54         709 my $self = bless($class->SUPER::new(),$class);
43             # Constructing a IO::Pipe results in an "Illegal seek" - clear that out
44 54         8971 $! = undef;
45             #If a subroutine call was supplied
46 54 100       240 if(scalar(@_))
47             {
48             #Declare file handles for STDOUT and STDERR
49 15         62 my($fh,$eh);
50             #If new was called in list context
51 15 100       188 if(wantarray)
52             {
53             #Fill the handles with the outputs from the subroutine
54 7         84 ($fh,$eh) = $self->getSubroutineProducer(@_);
55             #Bless referents to the file handles
56 6         90 my($bfh,$beh) = (bless($fh,$class),bless($eh,$class));
57             # Constructing a IO::Pipe results in an "Illegal seek" - clear it
58 6         60 $! = undef;
59 6         342 return($bfh,$beh);
60             }
61             #Fill the STDOUT handle with the output from the subroutine
62 8         72 $fh = $self->getSubroutineProducer(@_);
63             #Return blessed referent to the STDOUT handle
64 7         140 my $bfh = bless($fh,$class);
65             # Constructing a IO::Pipe results in an "Illegal seek" - clear it
66 7         693 $! = undef;
67 7         427 return($bfh);
68             }
69             #Return a blessed referent of the object hash
70 39 50       106 if(wantarray)
71             {
72             #Return a second blessed referent
73 0         0 my $self2 = bless($class->SUPER::new(),$class);
74             # Constructing a IO::Pipe results in an "Illegal seek" - clear it
75 0         0 $! = undef;
76 0         0 return($self,$self2);
77             }
78 39         908 return($self);
79             }
80              
81              
82              
83             #This method is also a constructor
84             sub getSubroutineProducer
85             {
86             #Read in subroutine reference
87 54     54 0 268 my $self = shift;
88 54         115 my $producer_sub = shift;
89 54         191 my @params = @_;
90 54         155 my($pid,$error);
91              
92 54 50 33     543 if(!defined($producer_sub) || ref($producer_sub) ne 'CODE')
93             {
94 0         0 $error = "ERROR:Producer.pm:getSubroutineProducer:A referenced " .
95             "subroutine is required as the first argument to " .
96             "getSubroutineProducer.";
97 0         0 $Producer::errstr = $error;
98 0         0 carp($error);
99 0         0 return(undef);
100             }
101              
102             #Create a pipe
103 54         312 my $stdout_pipe = $self->SUPER::new();
104 54         4010 my($stderr_pipe);
105 54 100       328 $stderr_pipe = $self->SUPER::new() if(wantarray);
106              
107 54   100     2679 my $caller_sub = (caller(1))[3] || "none";
108 54         280 my $issys = $caller_sub eq "IO::Pipe::Producer::getSystemProducer";
109              
110             #Fork off the Producer
111 54 50       50705 if(defined($pid = fork()))
112             {
113 54 100       596 if($pid)
114             {
115             ##
116             ## Parent
117             ##
118              
119 45         702 $! = undef;
120             #Create a read file handle
121 45         2894 $stdout_pipe->reader();
122 45 100       9366 $stderr_pipe->reader() if(wantarray);
123              
124             #Return the read file handle to the consumer
125 45 100       1172 if(wantarray)
126 23         1093 {return(bless($stdout_pipe,ref($self)),
127             bless($stderr_pipe,ref($self)),
128             $pid)}
129 22         899 return(bless($stdout_pipe,ref($self)));
130             }
131             else
132             {
133             ##
134             ## Child
135             ##
136              
137             #Create a write file handle for the Producer
138 9         1512 $stdout_pipe->writer();
139 9         1682 $stdout_pipe->autoflush;
140 9 100       1969 $stderr_pipe->writer() if(defined($stderr_pipe));
141 9 100       609 $stderr_pipe->autoflush if(defined($stderr_pipe));
142              
143             # $! = undef;
144             #Redirect standard outputs to the pipes or kill the child
145 9 50 66     187 if(!open(STDOUT,">&",\${$stdout_pipe}))
  9 50       973  
146             {
147 0         0 $error = "ERROR:Producer.pm:getSubroutineProducer:Can't " .
148             "redirect stdout to pipe: [" .
149             select($stdout_pipe) .
150             "]. $!";
151 0         0 $Producer::errstr = $error;
152 0         0 croak($error);
153             }
154 5         118 elsif(defined($stderr_pipe) && !open(STDERR,">&",\${$stderr_pipe}))
155             {
156 0         0 $error = "ERROR:Producer.pm:getSubroutineProducer:Can't " .
157             "redirect stderr to pipe: [" .
158             select($stderr_pipe) .
159             "]. $!";
160 0         0 $Producer::errstr = $error;
161 0         0 croak($error);
162             }
163              
164             #Track runtime errors/warnings (compile/system/etc) for inclusion
165             #in error stream
166             $SIG{__WARN__} =
167             sub
168             {
169 1     1   136 my $errin = join('',@_);
170 1         3 chomp($errin);
171 1         4 my $err = "WARNING:IO::Pipe::Producer: [$errin].";
172 1 50       14 if(defined($stderr_pipe))
173 1         29 {print STDERR ($err)}
174             else
175             {
176 0         0 chop($err);
177 0         0 carp($err);
178             }
179 9         424 };
180              
181             $SIG{__DIE__} =
182             sub
183             {
184 0     0   0 my $errin = join('',@_);
185 0         0 chomp($errin);
186 0         0 my $err = "ERROR:IO::Pipe::Producer: [$errin].";
187 0         0 $@ = '';
188 0 0       0 if(defined($stderr_pipe))
189 0         0 {print STDERR ($err)}
190             else
191             {
192 0         0 chop($err);
193 0         0 carp($err);
194             }
195             #Calling die() suppresses output of unwrapped fatal errors.
196 0         0 die();
197 9         288 };
198              
199 9         68 my $exit_code = 0;
200              
201             #Call the subroutine passed in & get it's return value
202 9         158 my $raw_exit_code = int($producer_sub->(@params));
203              
204 9 100 66     692 if($issys && defined($raw_exit_code) && $raw_exit_code != -1)
      100        
205 3         21 {$exit_code = $raw_exit_code >> 8}
206              
207 9 100 66     262 if(!defined($raw_exit_code) || $raw_exit_code == -1)
208             {
209 2 100       32 if(defined($stderr_pipe))
210             {
211 1         20 $error = "Unable to determine system call exit status";
212 1         13 $Producer::errstr = $error;
213 1         607 carp($error);
214             }
215 2         26 $exit_code = 255;
216             }
217              
218             #Close the writer pipes
219 9         125 close($stdout_pipe);
220 9 100       88 close($stderr_pipe) if(defined($stderr_pipe));
221              
222             #Exit with the exit status
223 9         3573 exit($exit_code);
224             }
225             }
226             else
227             {
228 0         0 $error = "ERROR:Producer.pm:getSubroutineProducer:fork() didn't work!";
229 0         0 $Producer::errstr = $error;
230 0         0 carp($error);
231 0         0 return(undef);
232             }
233             }
234              
235              
236             sub getSystemProducer
237             {
238 20     20 0 287 my $self = shift;
239 20     5   238 return($self->getSubroutineProducer(sub {system(@_)},@_));
  5         18807  
240             }
241              
242              
243             1;
244             __END__