Determine read/write status of filehandles connected to memory objects.

S

Sisyphus

Hi,

On unix, with filehandles connected to normal files, we can query the
read/write status of the filehandle by examining the return value of the
fcntl() function:

use Fcntl;
# some code that creates the open $filehandle.
my $fmode = fcntl($filehandle, F_GETFL, my $slush = 0);

The value of $fmode will allow us to determine whether the filehandle is
readonly, writeonly, or readable/writable.

But with perl 5.8, it's possible to create filehandles connected to memory
objects:

use warnings;
use strict;

my ($fh1, $fh2, $var1, $var2);
open $fh1, '>', \$var1 or die $!;
print $fh1 "hello"; # $var1 contains "hello"

open $fh2, '<', \$var1 or die $!;
$var2 = <$fh2>; # $var2 contains "hello";

close $fh1 or die $!;
close $fh2 or die $!;

print $var1, " ", $var2, "\n"; # prints "hello hello"
__END__

But now the fcntl() function is unable to provide information that I can use
to determine the read/write status of $fh1and $fh2.
For both $fh1 and $fh2 the fcntl() function will return undef - and fileno()
will return -1.

The question:
How can I determine the read/write status of an open filehandle that's
connected to a memory object ?

Cheers,
Rob
 
A

Anno Siegel

Sisyphus said:
Hi,

On unix, with filehandles connected to normal files, we can query the
read/write status of the filehandle by examining the return value of the
fcntl() function:

use Fcntl;
# some code that creates the open $filehandle.
my $fmode = fcntl($filehandle, F_GETFL, my $slush = 0);

The value of $fmode will allow us to determine whether the filehandle is
readonly, writeonly, or readable/writable.

But with perl 5.8, it's possible to create filehandles connected to memory
objects:

use warnings;
use strict;

my ($fh1, $fh2, $var1, $var2);
open $fh1, '>', \$var1 or die $!;
print $fh1 "hello"; # $var1 contains "hello"

open $fh2, '<', \$var1 or die $!;
$var2 = <$fh2>; # $var2 contains "hello";

close $fh1 or die $!;
close $fh2 or die $!;

print $var1, " ", $var2, "\n"; # prints "hello hello"
__END__

But now the fcntl() function is unable to provide information that I can use
to determine the read/write status of $fh1and $fh2.
For both $fh1 and $fh2 the fcntl() function will return undef - and fileno()
will return -1.

The question:
How can I determine the read/write status of an open filehandle that's
connected to a memory object ?

I don't know of a built-in method. You can attempt to write an empty
string to the filehandle and catch the warning if it fails:

sub can_write {
my $fh = shift;
eval {
use warnings FATAL => 'io';
print $fh '';
};
not $@;
}

Alternatively one could try to use 4-arg select().

Anno
 
S

Sisyphus

..
..
I don't know of a built-in method. You can attempt to write an empty
string to the filehandle and catch the warning if it fails:

sub can_write {
my $fh = shift;
eval {
use warnings FATAL => 'io';
print $fh '';
};
not $@;
}

Any script containing that subroutine that was run on pre-5.6 perl would, I
believe, fail to compile - even if can_write() was never going to be called
unless $] >= 5.008. (I know this shouldn't be a consideration, but I was
hoping to do it in a way that wouldn't break pre-5.6 perls, if possible.) Is
there perhaps a workaround to "use warnings FATAL => 'io';" involving
'require warnings;' (and perhaps also 'import') ? I couldn't produce an
incantation that worked.
Alternatively one could try to use 4-arg select().

Yes - otherwise this looks a possibility. Unfortunately, I find the 1-arg
select() confusing enough. I'm not going to specifically request any help
with potential code, as I haven't yet made a serious attempt to come to
terms with the 4-arg version - but if someone likes to provide further
hints/suggestions along those lines, then that's fine by me :)

Thanks for your insight, Anno.

Now ... back to 'perldoc -f select' ....

Cheers,
Rob
 
A

Anno Siegel

Sisyphus said:
.
.
I don't know of a built-in method. You can attempt to write an empty
string to the filehandle and catch the warning if it fails:

sub can_write {
my $fh = shift;
eval {
use warnings FATAL => 'io';
print $fh '';
};
not $@;
}

Any script containing that subroutine that was run on pre-5.6 perl would, I
believe, fail to compile - even if can_write() was never going to be called
unless $] >= 5.008. (I know this shouldn't be a consideration, but I was
hoping to do it in a way that wouldn't break pre-5.6 perls, if possible.) Is
there perhaps a workaround to "use warnings FATAL => 'io';" involving
'require warnings;' (and perhaps also 'import') ? I couldn't produce an
incantation that worked.

Use $SIG{ __WARN__} instead, that's been around forever.

sub can_write {
my $fh = shift;
my $warned;
local $SIG{ __WARN__} = sub { $warned ++ };
print $fh '';
return ! $warned;
}

A more specific test if the warning was indeed the text "Filehandle
%s opened only for input" would be wise in both variants.
Yes - otherwise this looks a possibility. Unfortunately, I find the 1-arg
select() confusing enough. I'm not going to specifically request any help
with potential code, as I haven't yet made a serious attempt to come to
terms with the 4-arg version - but if someone likes to provide further
hints/suggestions along those lines, then that's fine by me :)

Can't be done with select(). You'd need a file number for the handle
you want to test, but fileno( $f) is -1 (invalid) if $f is a "stringy"
filehandle.

Anno

Anno
 
S

Sisyphus

Anno Siegel said:
Use $SIG{ __WARN__} instead, that's been around forever.

sub can_write {
my $fh = shift;
my $warned;
local $SIG{ __WARN__} = sub { $warned ++ };
print $fh '';
return ! $warned;
}

A more specific test if the warning was indeed the text "Filehandle
%s opened only for input" would be wise in both variants.
..
..

Can't be done with select(). You'd need a file number for the handle
you want to test, but fileno( $f) is -1 (invalid) if $f is a "stringy"
filehandle.

Ok ... thanks again, Anno.

Cheers,
Rob
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Staff online

Members online

Forum statistics

Threads
473,734
Messages
2,569,441
Members
44,832
Latest member
GlennSmall

Latest Threads

Top