1use strict; 2use warnings; 3 4package IO::CaptureOutput; 5# ABSTRACT: (DEPRECATED) capture STDOUT and STDERR from Perl code, subprocesses or XS 6 7our $VERSION = '1.1105'; 8 9use vars qw/@ISA @EXPORT_OK %EXPORT_TAGS $CarpLevel/; 10use Exporter; 11use Carp qw/croak/; 12@ISA = 'Exporter'; 13@EXPORT_OK = qw/capture capture_exec qxx capture_exec_combined qxy/; 14%EXPORT_TAGS = (all => \@EXPORT_OK); 15$CarpLevel = 0; # help capture report errors at the right level 16 17sub _capture (&@) { ## no critic 18 my ($code, $output, $error, $output_file, $error_file) = @_; 19 20 # check for valid combinations of input 21 { 22 local $Carp::CarpLevel = 1; 23 my $error = _validate($output, $error, $output_file, $error_file); 24 croak $error if $error; 25 } 26 27 # if either $output or $error are defined, then we need a variable for 28 # results; otherwise we only capture to files and don't waste memory 29 if ( defined $output || defined $error ) { 30 for ($output, $error) { 31 $_ = \do { my $s; $s = ''} unless ref $_; 32 $$_ = '' if $_ != \undef && !defined($$_); 33 } 34 } 35 36 # merge if same refs for $output and $error or if both are undef -- 37 # i.e. capture \&foo, undef, undef, $merged_file 38 # this means capturing into separate files *requires* at least one 39 # capture variable 40 my $should_merge = 41 (defined $error && defined $output && $output == $error) || 42 ( !defined $output && !defined $error ) || 43 0; 44 45 my ($capture_out, $capture_err); 46 47 # undef means capture anonymously; anything other than \undef means 48 # capture to that ref; \undef means skip capture 49 if ( !defined $output || $output != \undef ) { 50 $capture_out = IO::CaptureOutput::_proxy->new( 51 'STDOUT', $output, undef, $output_file 52 ); 53 } 54 if ( !defined $error || $error != \undef ) { 55 $capture_err = IO::CaptureOutput::_proxy->new( 56 'STDERR', $error, ($should_merge ? 'STDOUT' : undef), $error_file 57 ); 58 } 59 60 # now that output capture is setup, call the subroutine 61 # results get read when IO::CaptureOutput::_proxy objects go out of scope 62 &$code(); 63} 64 65# Extra indirection for symmetry with capture_exec, etc. Gets error reporting 66# to the right level 67sub capture (&@) { ## no critic 68 return &_capture; 69} 70 71sub capture_exec { 72 my @args = @_; 73 my ($output, $error); 74 my $exit = _capture sub { system _shell_quote(@args) }, \$output, \$error; 75 my $success = ($exit == 0 ) ? 1 : 0 ; 76 $? = $exit; 77 return wantarray ? ($output, $error, $success, $exit) : $output; 78} 79 80*qxx = \&capture_exec; 81 82sub capture_exec_combined { 83 my @args = @_; 84 my $output; 85 my $exit = _capture sub { system _shell_quote(@args) }, \$output, \$output; 86 my $success = ($exit == 0 ) ? 1 : 0 ; 87 $? = $exit; 88 return wantarray ? ($output, $success, $exit) : $output; 89} 90 91*qxy = \&capture_exec_combined; 92 93# extra quoting required on Win32 systems 94*_shell_quote = ($^O =~ /MSWin32/) ? \&_shell_quote_win32 : sub {@_}; 95sub _shell_quote_win32 { 96 my @args; 97 for (@_) { 98 if (/[ \"]/) { # TODO: check if ^ requires escaping 99 (my $escaped = $_) =~ s/([\"])/\\$1/g; 100 push @args, '"' . $escaped . '"'; 101 next; 102 } 103 push @args, $_ 104 } 105 return @args; 106} 107 108# detect errors and return an error message or empty string; 109sub _validate { 110 my ($output, $error, $output_file, $error_file) = @_; 111 112 # default to "ok" 113 my $msg = q{}; 114 115 # \$out, \$out, $outfile, $errfile 116 if ( defined $output && defined $error 117 && defined $output_file && defined $error_file 118 && $output == $error 119 && $output != \undef 120 && $output_file ne $error_file 121 ) { 122 $msg = "Merged STDOUT and STDERR, but specified different output and error files"; 123 } 124 # undef, undef, $outfile, $errfile 125 elsif ( !defined $output && !defined $error 126 && defined $output_file && defined $error_file 127 && $output_file ne $error_file 128 ) { 129 $msg = "Merged STDOUT and STDERR, but specified different output and error files"; 130 } 131 132 return $msg; 133} 134 135# Captures everything printed to a filehandle for the lifetime of the object 136# and then transfers it to a scalar reference 137package IO::CaptureOutput::_proxy; 138use File::Temp 0.16 'tempfile'; 139use File::Basename qw/basename/; 140use Symbol qw/gensym qualify qualify_to_ref/; 141use Carp; 142 143sub _is_wperl { $^O eq 'MSWin32' && basename($^X) eq 'wperl.exe' } 144 145sub new { 146 my $class = shift; 147 my ($orig_fh, $capture_var, $merge_fh, $capture_file) = @_; 148 $orig_fh = qualify($orig_fh); # e.g. main::STDOUT 149 my $fhref = qualify_to_ref($orig_fh); # e.g. \*STDOUT 150 151 # Duplicate the filehandle 152 my $saved_fh; 153 { 154 no strict 'refs'; ## no critic - needed for 5.005 155 if ( defined fileno($orig_fh) && ! _is_wperl() ) { 156 $saved_fh = gensym; 157 open $saved_fh, ">&$orig_fh" or croak "Can't redirect <$orig_fh> - $!"; 158 } 159 } 160 161 # Create replacement filehandle if not merging 162 my ($newio_fh, $newio_file); 163 if ( ! $merge_fh ) { 164 $newio_fh = gensym; 165 if ($capture_file) { 166 $newio_file = $capture_file; 167 } else { 168 (undef, $newio_file) = tempfile; 169 } 170 open $newio_fh, "+>$newio_file" or croak "Can't write temp file for $orig_fh - $!"; 171 } 172 else { 173 $newio_fh = qualify($merge_fh); 174 } 175 176 # Redirect (or merge) 177 { 178 no strict 'refs'; ## no critic -- needed for 5.005 179 open $fhref, ">&".fileno($newio_fh) or croak "Can't redirect $orig_fh - $!"; 180 } 181 182 bless [$$, $orig_fh, $saved_fh, $capture_var, $newio_fh, $newio_file, $capture_file], $class; 183} 184 185sub DESTROY { 186 my $self = shift; 187 188 my ($pid, $orig_fh, $saved_fh, $capture_var, $newio_fh, 189 $newio_file, $capture_file) = @$self; 190 return unless $pid eq $$; # only cleanup in the process that is capturing 191 192 # restore the original filehandle 193 my $fh_ref = Symbol::qualify_to_ref($orig_fh); 194 select((select ($fh_ref), $|=1)[0]); 195 if (defined $saved_fh) { 196 open $fh_ref, ">&". fileno($saved_fh) or croak "Can't restore $orig_fh - $!"; 197 } 198 else { 199 close $fh_ref; 200 } 201 202 # transfer captured data to the scalar reference if we didn't merge 203 # $newio_file is undef if this file handle is merged to another 204 if (ref $capture_var && $newio_file) { 205 # some versions of perl complain about reading from fd 1 or 2 206 # which could happen if STDOUT and STDERR were closed when $newio 207 # was opened, so we just squelch warnings here and continue 208 local $^W; 209 seek $newio_fh, 0, 0; 210 $$capture_var = do {local $/; <$newio_fh>}; 211 } 212 close $newio_fh if $newio_file; 213 214 # Cleanup 215 return unless defined $newio_file && -e $newio_file; 216 return if $capture_file; # the "temp" file was explicitly named 217 unlink $newio_file or carp "Couldn't remove temp file '$newio_file' - $!"; 218} 219 2201; 221 222__END__ 223 224=pod 225 226=encoding UTF-8 227 228=head1 NAME 229 230IO::CaptureOutput - (DEPRECATED) capture STDOUT and STDERR from Perl code, subprocesses or XS 231 232=head1 VERSION 233 234version 1.1105 235 236=head1 SYNOPSIS 237 238 use IO::CaptureOutput qw(capture qxx qxy); 239 240 # STDOUT and STDERR separately 241 capture { noisy_sub(@args) } \$stdout, \$stderr; 242 243 # STDOUT and STDERR together 244 capture { noisy_sub(@args) } \$combined, \$combined; 245 246 # STDOUT and STDERR from external command 247 ($stdout, $stderr, $success) = qxx( @cmd ); 248 249 # STDOUT and STDERR together from external command 250 ($combined, $success) = qxy( @cmd ); 251 252=head1 DESCRIPTION 253 254B<This module is no longer recommended by the maintainer> - see 255L<Capture::Tiny> instead. 256 257This module provides routines for capturing STDOUT and STDERR from perl 258subroutines, forked system calls (e.g. C<system()>, C<fork()>) and from XS 259or C modules. 260 261=head1 NAME 262 263=head1 FUNCTIONS 264 265The following functions will be exported on demand. 266 267=head2 capture() 268 269 capture \&subroutine, \$stdout, \$stderr; 270 271Captures everything printed to C<STDOUT> and C<STDERR> for the duration of 272C<&subroutine>. C<$stdout> and C<$stderr> are optional scalars that will 273contain C<STDOUT> and C<STDERR> respectively. 274 275C<capture()> uses a code prototype so the first argument can be specified 276directly within brackets if desired. 277 278 # shorthand with prototype 279 capture C< print __PACKAGE__ > \$stdout, \$stderr; 280 281Returns the return value(s) of C<&subroutine>. The sub is called in the 282same context as C<capture()> was called e.g.: 283 284 @rv = capture C< wantarray > ; # returns true 285 $rv = capture C< wantarray > ; # returns defined, but not true 286 capture C< wantarray >; # void, returns undef 287 288C<capture()> is able to capture output from subprocesses and C code, which 289traditional C<tie()> methods of output capture are unable to do. 290 291B<Note:> C<capture()> will only capture output that has been written or 292flushed to the filehandle. 293 294If the two scalar references refer to the same scalar, then C<STDERR> will 295be merged to C<STDOUT> before capturing and the scalar will hold the 296combined output of both. 297 298 capture \&subroutine, \$combined, \$combined; 299 300Normally, C<capture()> uses anonymous, temporary files for capturing 301output. If desired, specific file names may be provided instead as 302additional options. 303 304 capture \&subroutine, \$stdout, \$stderr, $out_file, $err_file; 305 306Files provided will be clobbered, overwriting any previous data, but will 307persist after the call to C<capture()> for inspection or other 308manipulation. 309 310By default, when no references are provided to hold STDOUT or STDERR, 311output is captured and silently discarded. 312 313 # Capture STDOUT, discard STDERR 314 capture \&subroutine, \$stdout; 315 316 # Discard STDOUT, capture STDERR 317 capture \&subroutine, undef, \$stderr; 318 319However, even when using C<undef>, output can be captured to specific 320files. 321 322 # Capture STDOUT to a specific file, discard STDERR 323 capture \&subroutine, \$stdout, undef, $outfile; 324 325 # Discard STDOUT, capture STDERR to a specific file 326 capture \&subroutine, undef, \$stderr, undef, $err_file; 327 328 # Discard both, capture merged output to a specific file 329 capture \&subroutine, undef, undef, $mergedfile; 330 331It is a fatal error to merge STDOUT and STDERR and request separate, 332specific files for capture. 333 334 # ERROR: 335 capture \&subroutine, \$stdout, \$stdout, $out_file, $err_file; 336 capture \&subroutine, undef, undef, $out_file, $err_file; 337 338If either STDOUT or STDERR should be passed through to the terminal instead 339of captured, provide a reference to undef -- C<\undef> -- instead of a 340capture variable. 341 342 # Capture STDOUT, display STDERR 343 capture \&subroutine, \$stdout, \undef; 344 345 # Display STDOUT, capture STDERR 346 capture \&subroutine, \undef, \$stderr; 347 348=head2 capture_exec() 349 350 ($stdout, $stderr, $success, $exit_code) = capture_exec(@args); 351 352Captures and returns the output from C<system(@args)>. In scalar context, 353C<capture_exec()> will return what was printed to C<STDOUT>. In list 354context, it returns what was printed to C<STDOUT> and C<STDERR> as well as 355a success flag and the exit value. 356 357 $stdout = capture_exec('perl', '-e', 'print "hello world"'); 358 359 ($stdout, $stderr, $success, $exit_code) = 360 capture_exec('perl', '-e', 'warn "Test"'); 361 362C<capture_exec> passes its arguments to C<system()> and on MSWin32 will 363protect arguments with shell quotes if necessary. This makes it a handy 364and slightly more portable alternative to backticks, piped C<open()> and 365C<IPC::Open3>. 366 367The C<$success> flag returned will be true if the command ran successfully 368and false if it did not (if the command could not be run or if it ran and 369returned a non-zero exit value). On failure, the raw exit value of the 370C<system()> call is available both in the C<$exit_code> returned and in the 371C<$?> variable. 372 373 ($stdout, $stderr, $success, $exit_code) = 374 capture_exec('perl', '-e', 'warn "Test" and exit 1'); 375 376 if ( ! $success ) { 377 print "The exit code was " . ($exit_code >> 8) . "\n"; 378 } 379 380See L<perlvar> for more information on interpreting a child process exit 381code. 382 383=head2 capture_exec_combined() 384 385 ($combined, $success, $exit_code) = capture_exec_combined( 386 'perl', '-e', 'print "hello\n"', 'warn "Test\n" 387 ); 388 389This is just like C<capture_exec()>, except that it merges C<STDERR> with 390C<STDOUT> before capturing output. 391 392B<Note:> there is no guarantee that text printed to C<STDOUT> and C<STDERR> 393in the subprocess will be appear in order. The actual order will depend on 394how IO buffering is handled in the subprocess. 395 396=head2 qxx() 397 398This is an alias for C<capture_exec()>. 399 400=head2 qxy() 401 402This is an alias for C<capture_exec_combined()>. 403 404=head1 SEE ALSO 405 406=over 4 407 408=item * 409 410L<Capture::Tiny> 411 412=item * 413 414L<IPC::Open3> 415 416=item * 417 418L<IO::Capture> 419 420=item * 421 422L<IO::Utils> 423 424=item * 425 426L<IPC::System::Simple> 427 428=back 429 430=for :stopwords cpan testmatrix url annocpan anno bugtracker rt cpants kwalitee diff irc mailto metadata placeholders metacpan 431 432=head1 SUPPORT 433 434=head2 Bugs / Feature Requests 435 436Please report any bugs or feature requests through the issue tracker 437at L<https://github.com/dagolden/IO-CaptureOutput/issues>. 438You will be notified automatically of any progress on your issue. 439 440=head2 Source Code 441 442This is open source software. The code repository is available for 443public review and contribution under the terms of the license. 444 445L<https://github.com/dagolden/IO-CaptureOutput> 446 447 git clone https://github.com/dagolden/IO-CaptureOutput.git 448 449=head1 AUTHORS 450 451=over 4 452 453=item * 454 455Simon Flack <simonflk@cpan.org> 456 457=item * 458 459David Golden <dagolden@cpan.org> 460 461=back 462 463=head1 CONTRIBUTORS 464 465=for stopwords David Golden José Joaquín Atria Mike Latimer Olivier Mengué Tony Cook 466 467=over 4 468 469=item * 470 471David Golden <xdg@xdg.me> 472 473=item * 474 475José Joaquín Atria <jjatria@gmail.com> 476 477=item * 478 479Mike Latimer <mlatimer@suse.com> 480 481=item * 482 483Olivier Mengué <dolmen@cpan.org> 484 485=item * 486 487Tony Cook <tony@develop-help.com> 488 489=back 490 491=head1 COPYRIGHT AND LICENSE 492 493This software is copyright (c) 2019 by Simon Flack and David Golden. 494 495This is free software; you can redistribute it and/or modify it under 496the same terms as the Perl 5 programming language system itself. 497 498=cut 499