fix capture bugs for utf8 if output handles closed
David Golden
15 years ago
85 | 85 | _open $dup{stdin} = IO::Handle->new, "<&=STDIN"; |
86 | 86 | } |
87 | 87 | $proxies{stdin} = \*STDIN; |
88 | binmode(STDIN, ':utf8'); | |
88 | 89 | } |
89 | 90 | if ( ! defined fileno STDOUT ) { |
90 | 91 | $proxy_count{stdout}++; |
98 | 99 | _open $dup{stdout} = IO::Handle->new, ">&=STDOUT"; |
99 | 100 | } |
100 | 101 | $proxies{stdout} = \*STDOUT; |
102 | binmode(STDOUT, ':utf8'); | |
101 | 103 | } |
102 | 104 | if ( ! defined fileno STDERR ) { |
103 | 105 | $proxy_count{stderr}++; |
111 | 113 | _open $dup{stderr} = IO::Handle->new, ">&=STDERR"; |
112 | 114 | } |
113 | 115 | $proxies{stderr} = \*STDERR; |
116 | binmode(STDERR, ':utf8'); | |
114 | 117 | } |
115 | 118 | return %proxies; |
116 | 119 | } |
234 | 237 | local *CT_ORIG_STDIN = *STDIN ; |
235 | 238 | local *CT_ORIG_STDOUT = *STDOUT; |
236 | 239 | local *CT_ORIG_STDERR = *STDERR; |
240 | # find initial layers | |
237 | 241 | my %layers = ( |
238 | 242 | stdin => [PerlIO::get_layers(\*STDIN) ], |
239 | 243 | stdout => [PerlIO::get_layers(\*STDOUT)], |
251 | 255 | my %proxy_std = _proxy_std(); |
252 | 256 | _debug( "# proxy std is @{ [%proxy_std] }\n" ); |
253 | 257 | my $stash = { old => _copy_std() }; |
258 | # update layers after any proxying | |
259 | %layers = ( | |
260 | stdin => [PerlIO::get_layers(\*STDIN) ], | |
261 | stdout => [PerlIO::get_layers(\*STDOUT)], | |
262 | stderr => [PerlIO::get_layers(\*STDERR)], | |
263 | ); | |
254 | 264 | # get handles for capture and apply existing IO layers |
255 | 265 | $stash->{new}{$_} = $stash->{capture}{$_} = tempfile() for qw/stdout stderr/; |
256 | 266 | _debug("# will capture $_ on " .fileno($stash->{capture}{$_})."\n" ) for qw/stdout stderr/; |
264 | 274 | _debug( "# redirecting in parent ...\n" ); |
265 | 275 | _open_std( $stash->{new} ); |
266 | 276 | # execute user provided code |
277 | my $exit_code; | |
267 | 278 | { |
268 | 279 | local *STDIN = *CT_ORIG_STDIN if $localize{stdin}; # get original, not proxy STDIN |
269 | 280 | local *STDERR = *STDOUT if $merge; # minimize buffer mixups during $code |
272 | 283 | _relayer(\*STDERR, $layers{stderr}) unless $merge; |
273 | 284 | _debug( "# running code $code ...\n" ); |
274 | 285 | $code->(); |
275 | } | |
276 | my $exit_code = $?; # save this for later | |
286 | $exit_code = $?; # save this for later | |
287 | } | |
277 | 288 | # restore prior filehandles and shut down tees |
278 | 289 | _debug( "# restoring ...\n" ); |
279 | 290 | _open_std( $stash->{old} ); |
46 | 46 | # capture |
47 | 47 | #--------------------------------------------------------------------------# |
48 | 48 | |
49 | sub capture_count { 23 } | |
49 | sub capture_count { 25 } | |
50 | 50 | sub capture_tests { |
51 | 51 | my $sub = 'capture'; |
52 | 52 | |
113 | 113 | _reset; |
114 | 114 | my %seen; |
115 | 115 | my @orig_layers = grep {$_ ne 'unix' and $seen{$_}++} PerlIO::get_layers(STDOUT); |
116 | binmode(STDOUT, ":utf8"); binmode(STDERR, ":utf8"); | |
116 | binmode(STDOUT, ":utf8") if fileno(STDOUT); | |
117 | binmode(STDERR, ":utf8") if fileno(STDERR); | |
117 | 118 | ($out, $err) = capture { |
118 | 119 | print $unicode; print STDERR $unicode; |
119 | 120 | }; |
127 | 128 | is($out, $unicode, "$label captured stdout"); |
128 | 129 | is($err, $unicode, "$label captured stderr"); |
129 | 130 | } |
130 | binmode(STDOUT, join( ":", "", "raw", @orig_layers)); | |
131 | binmode(STDERR, join( ":", "", "raw", @orig_layers)); | |
131 | binmode(STDOUT, join( ":", "", "raw", @orig_layers)) if fileno(STDOUT); | |
132 | binmode(STDERR, join( ":", "", "raw", @orig_layers)) if fileno(STDERR); | |
132 | 133 | } |
133 | 134 | |
134 | 135 | |
196 | 197 | $label ="[$sub] s-STDOUT/STDERR:"; |
197 | 198 | is($out, "Foo", "$label captured stdout"); |
198 | 199 | is($err, "Bar", "$label captured stderr"); |
200 | ||
201 | # Capture STDOUT/STDERR from perl -- unicode line | |
202 | SKIP: { | |
203 | skip "unicode support requires perl 5.8", 2 unless $] >= 5.008; | |
204 | _reset; | |
205 | my %seen; | |
206 | my @orig_layers = grep {$_ ne 'unix' and $seen{$_}++} PerlIO::get_layers(STDOUT); | |
207 | binmode(STDOUT, ":utf8") if fileno(STDOUT); | |
208 | binmode(STDERR, ":utf8") if fileno(STDERR); | |
209 | ($out, $err) = capture { | |
210 | system ($^X, '-e', 'binmode(STDOUT,q{:utf8});binmode(STDERR,q{:utf8});print qq{Hi! \x{263a}\n}; print STDERR qq{Hi! \x{263a}\n}'); | |
211 | }; | |
212 | ||
213 | $label ="[$sub] s-unicode-STDOUT/STDERR:"; | |
214 | if ( $have_diff ) { | |
215 | eq_or_diff($out, $unicode, "$label captured stdout"); | |
216 | eq_or_diff($err, $unicode, "$label captured stderr"); | |
217 | } | |
218 | else { | |
219 | is($out, $unicode, "$label captured stdout"); | |
220 | is($err, $unicode, "$label captured stderr"); | |
221 | } | |
222 | binmode(STDOUT, join( ":", "", "raw", @orig_layers)) if fileno(STDOUT); | |
223 | binmode(STDERR, join( ":", "", "raw", @orig_layers)) if fileno(STDERR); | |
224 | } | |
199 | 225 | |
200 | 226 | } |
201 | 227 |