Hide Show 57 lines of Pod
BEGIN {
$VERSION
=
'20231003.0'
;
if
(Win32_MODE) {
eval
"use IPC::Run::Win32Helper; require IPC::Run::Win32IO; 1"
or ( $@ &&
die
)
or
die
"$!"
;
}
}
sub
_empty($);
*_empty
= \
&IPC::Run::_empty
;
Hide Show 12 lines of Pod
sub
new {
my
$class
=
shift
;
$class
=
ref
$class
||
$class
;
my
(
$external
,
$type
,
$internal
) = (
shift
,
shift
,
pop
);
croak
"$class: '$_' is not a valid I/O operator"
unless
$type
=~ /^(?:<<?|>>?)$/;
my
IPC::Run::IO
$self
=
$class
->_new_internal(
$type
,
undef
,
undef
,
$internal
,
undef
,
@_
);
if
( !
ref
$external
) {
$self
->{FILENAME} =
$external
;
}
elsif
(
ref
$external
eq
'GLOB'
|| UNIVERSAL::isa(
$external
,
'IO::Handle'
) ) {
$self
->{HANDLE} =
$external
;
$self
->{DONT_CLOSE} = 1;
}
else
{
croak
"$class: cannot accept "
.
ref
(
$external
) .
" to do I/O with"
;
}
return
$self
;
}
sub
_new_internal {
my
$class
=
shift
;
$class
=
ref
$class
||
$class
;
$class
=
"IPC::Run::Win32IO"
if
Win32_MODE &&
$class
eq
"IPC::Run::IO"
;
my
IPC::Run::IO
$self
;
$self
=
bless
{},
$class
;
my
(
$type
,
$kfd
,
$pty_id
,
$internal
,
$binmode
,
@filters
) =
@_
;
$self
->{TYPE} =
$type
;
$self
->{KFD} =
$kfd
;
$self
->{PTY_ID} =
$pty_id
;
$self
->
binmode
(
$binmode
);
$self
->{FILTERS} = [
@filters
];
if
(
$self
->op =~ />/ ) {
croak
"'$_' missing a destination"
if
_empty
$internal
;
$self
->{DEST} =
$internal
;
if
( UNIVERSAL::isa(
$self
->{DEST},
'CODE'
) ) {
unshift
(
@{
$self
->{FILTERS} },
sub
{
my
(
$in_ref
) =
@_
;
return
IPC::Run::input_avail() &&
do
{
$self
->{DEST}->(
$$in_ref
);
$$in_ref
=
''
;
1;
}
}
);
}
}
else
{
croak
"'$_' missing a source"
if
_empty
$internal
;
$self
->{SOURCE} =
$internal
;
if
( UNIVERSAL::isa(
$internal
,
'CODE'
) ) {
push
(
@{
$self
->{FILTERS} },
sub
{
my
(
$in_ref
,
$out_ref
) =
@_
;
return
0
if
length
$$out_ref
;
return
undef
if
$self
->{SOURCE_EMPTY};
my
$in
=
$internal
->();
unless
(
defined
$in
) {
$self
->{SOURCE_EMPTY} = 1;
return
undef
;
}
return
0
unless
length
$in
;
$$out_ref
=
$in
;
return
1;
}
);
}
elsif
( UNIVERSAL::isa(
$internal
,
'SCALAR'
) ) {
push
(
@{
$self
->{FILTERS} },
sub
{
my
(
$in_ref
,
$out_ref
) =
@_
;
return
0
if
length
$$out_ref
;
return
$self
->{HARNESS}->{auto_close_ins} ?
undef
: 0
if
IPC::Run::_empty ${
$self
->{SOURCE} }
||
$self
->{SOURCE_EMPTY};
$$out_ref
=
$$internal
;
eval
{
$$internal
=
''
}
if
$self
->{HARNESS}->{clear_ins};
$self
->{SOURCE_EMPTY} =
$self
->{HARNESS}->{auto_close_ins};
return
1;
}
);
}
}
return
$self
;
}
Hide Show 7 lines of Pod
sub
filename {
my
IPC::Run::IO
$self
=
shift
;
$self
->{FILENAME} =
shift
if
@_
;
return
$self
->{FILENAME};
}
Hide Show 7 lines of Pod
sub
init {
my
IPC::Run::IO
$self
=
shift
;
$self
->{SOURCE_EMPTY} = 0;
${
$self
->{DEST} } =
''
if
$self
->mode =~ /r/ &&
ref
$self
->{DEST} eq
'SCALAR'
;
$self
->
open
if
defined
$self
->filename;
$self
->{FD} =
$self
->
fileno
;
if
( !
$self
->{FILTERS} ) {
$self
->{FBUFS} =
undef
;
}
else
{
@{
$self
->{FBUFS} } =
map
{
my
$s
=
""
;
\
$s
;
} ( @{
$self
->{FILTERS} },
''
);
$self
->{FBUFS}->[0] =
$self
->{DEST}
if
$self
->{DEST} &&
ref
$self
->{DEST} eq
'SCALAR'
;
push
@{
$self
->{FBUFS} },
$self
->{SOURCE};
}
return
undef
;
}
Hide Show 7 lines of Pod
my
%open_flags
= (
'>'
=> O_RDONLY,
'>>'
=> O_RDONLY,
'<'
=> O_WRONLY | O_CREAT | O_TRUNC,
'<<'
=> O_WRONLY | O_CREAT | O_APPEND,
);
sub
open
{
my
IPC::Run::IO
$self
=
shift
;
croak
"IPC::Run::IO: Can't open() a file with no name"
unless
defined
$self
->{FILENAME};
$self
->{HANDLE} = gensym
unless
$self
->{HANDLE};
_debug
"opening '"
,
$self
->filename,
"' mode '"
,
$self
->mode,
"'"
if
_debugging_data;
sysopen
(
$self
->{HANDLE},
$self
->filename,
$open_flags
{
$self
->op },
) or croak
"IPC::Run::IO: $! opening '$self->{FILENAME}', mode '"
.
$self
->mode .
"'"
;
return
undef
;
}
Hide Show 7 lines of Pod
sub
_do_open {
my
$self
=
shift
;
my
(
$child_debug_fd
,
$parent_handle
) =
@_
;
if
(
$self
->dir eq
"<"
) {
(
$self
->{TFD},
$self
->{FD} ) = IPC::Run::_pipe_nb;
if
(
$parent_handle
) {
CORE::
open
$parent_handle
,
">&=$self->{FD}"
or croak
"$! duping write end of pipe for caller"
;
}
}
else
{
(
$self
->{FD},
$self
->{TFD} ) = IPC::Run::_pipe;
if
(
$parent_handle
) {
CORE::
open
$parent_handle
,
"<&=$self->{FD}"
or croak
"$! duping read end of pipe for caller"
;
}
}
}
sub
open_pipe {
my
IPC::Run::IO
$self
=
shift
;
croak
"IPC::Run::IO: Can't pipe() when a file name has been set"
if
defined
$self
->{FILENAME};
$self
->_do_open(
@_
);
return
$self
->dir eq
"<"
? (
$self
->{TFD},
$self
->{FD} )
: (
$self
->{FD},
$self
->{TFD} );
}
sub
_cleanup {
my
$self
=
shift
;
undef
$self
->{FAKE_PIPE};
}
Hide Show 7 lines of Pod
sub
close
{
my
IPC::Run::IO
$self
=
shift
;
if
(
defined
$self
->{HANDLE} ) {
close
$self
->{HANDLE}
or croak(
"IPC::Run::IO: $! closing "
. (
defined
$self
->{FILENAME}
?
"'$self->{FILENAME}'"
:
"handle"
)
);
}
else
{
IPC::Run::_close(
$self
->{FD} );
}
$self
->{FD} =
undef
;
return
undef
;
}
Hide Show 7 lines of Pod
sub
fileno
{
my
IPC::Run::IO
$self
=
shift
;
my
$fd
=
fileno
$self
->{HANDLE};
croak(
"IPC::Run::IO: $! "
. (
defined
$self
->{FILENAME}
?
"'$self->{FILENAME}'"
:
"handle"
)
)
unless
defined
$fd
;
return
$fd
;
}
Hide Show 20 lines of Pod
sub
mode {
my
IPC::Run::IO
$self
=
shift
;
croak
"IPC::Run::IO: unexpected arguments for mode(): @_"
if
@_
;
return
(
$self
->{TYPE} =~ /</ ?
'w'
:
'r'
) . (
$self
->{TYPE} =~ /<<|>>/ ?
'a'
:
''
);
}
Hide Show 7 lines of Pod
sub
op {
my
IPC::Run::IO
$self
=
shift
;
croak
"IPC::Run::IO: unexpected arguments for op(): @_"
if
@_
;
return
$self
->{TYPE};
}
Hide Show 7 lines of Pod
sub
binmode
{
my
IPC::Run::IO
$self
=
shift
;
$self
->{BINMODE} =
shift
if
@_
;
return
$self
->{BINMODE};
}
Hide Show 6 lines of Pod
sub
dir {
my
IPC::Run::IO
$self
=
shift
;
croak
"IPC::Run::IO: unexpected arguments for dir(): @_"
if
@_
;
return
substr
$self
->{TYPE}, 0, 1;
}
'$filter_op'
,
'$filter_num'
);
sub
_init_filters {
my
IPC::Run::IO
$self
=
shift
;
confess
"\$self not an IPC::Run::IO"
unless
UNIVERSAL::isa(
$self
,
"IPC::Run::IO"
);
$self
->{FBUFS} = [];
$self
->{FBUFS}->[0] =
$self
->{DEST}
if
$self
->{DEST} &&
ref
$self
->{DEST} eq
'SCALAR'
;
return
unless
$self
->{FILTERS} && @{
$self
->{FILTERS} };
push
@{
$self
->{FBUFS} },
map
{
my
$s
=
""
;
\
$s
;
} ( @{
$self
->{FILTERS} },
''
);
push
@{
$self
->{FBUFS} },
$self
->{SOURCE};
}
Hide Show 8 lines of Pod
sub
poll {
my
IPC::Run::IO
$self
=
shift
;
my
(
$harness
) =
@_
;
if
(
defined
$self
->{FD} ) {
my
$d
=
$self
->dir;
if
(
$d
eq
"<"
) {
if
(
vec
$harness
->{WOUT},
$self
->{FD}, 1 ) {
_debug_desc_fd(
"filtering data to"
,
$self
)
if
_debugging_details;
return
$self
->_do_filters(
$harness
);
}
}
elsif
(
$d
eq
">"
) {
if
(
vec
$harness
->{ROUT},
$self
->{FD}, 1 ) {
_debug_desc_fd(
"filtering data from"
,
$self
)
if
_debugging_details;
return
$self
->_do_filters(
$harness
);
}
}
}
return
0;
}
sub
_do_filters {
my
IPC::Run::IO
$self
=
shift
;
(
$self
->{HARNESS} ) =
@_
;
my
(
$saved_op
,
$saved_num
) = (
$IPC::Run::filter_op
,
$IPC::Run::filter_num
);
$IPC::Run::filter_op
=
$self
;
$IPC::Run::filter_num
= -1;
my
$redos
= 0;
my
$r
;
{
$@ =
''
;
$r
=
eval
{ IPC::Run::get_more_input(); };
if
( ( $@ ||
''
) =~
$IPC::Run::_EAGAIN
&&
$redos
++ < 200 ) {
select
(
undef
,
undef
,
undef
, 0.01 );
redo
;
}
}
(
$IPC::Run::filter_op
,
$IPC::Run::filter_num
) = (
$saved_op
,
$saved_num
);
$self
->{HARNESS} =
undef
;
die
"ack "
, $@
if
$@;
return
$r
;
}
Hide Show 12 lines of Pod
1;