FAQ 5.9 How can I use a filehandle indirectly?



This is an excerpt from the latest version perlfaq5.pod, which
comes with the standard Perl distribution. These postings aim to
reduce the number of repeated questions as well as allow the community
to review and update the answers. The latest version of the complete
perlfaq is at http://faq.perl.org .

--------------------------------------------------------------------

5.9: How can I use a filehandle indirectly?

An indirect filehandle is using something other than a symbol in a place
that a filehandle is expected. Here are ways to get indirect
filehandles:

$fh = SOME_FH; # bareword is strict-subs hostile
$fh = "SOME_FH"; # strict-refs hostile; same package only
$fh = *SOME_FH; # typeglob
$fh = \*SOME_FH; # ref to typeglob (bless-able)
$fh = *SOME_FH{IO}; # blessed IO::Handle from *SOME_FH typeglob

Or, you can use the "new" method from one of the IO::* modules to create
an anonymous filehandle, store that in a scalar variable, and use it as
though it were a normal filehandle.

use IO::Handle; # 5.004 or higher
$fh = IO::Handle->new();

Then use any of those as you would a normal filehandle. Anywhere that
Perl is expecting a filehandle, an indirect filehandle may be used
instead. An indirect filehandle is just a scalar variable that contains
a filehandle. Functions like "print", "open", "seek", or the "<FH>"
diamond operator will accept either a named filehandle or a scalar
variable containing one:

($ifh, $ofh, $efh) = (*STDIN, *STDOUT, *STDERR);
print $ofh "Type it: ";
$got = <$ifh>
print $efh "What was that: $got";

If you're passing a filehandle to a function, you can write the function
in two ways:

sub accept_fh {
my $fh = shift;
print $fh "Sending to indirect filehandle\n";
}

Or it can localize a typeglob and use the filehandle directly:

sub accept_fh {
local *FH = shift;
print FH "Sending to localized filehandle\n";
}

Both styles work with either objects or typeglobs of real filehandles.
(They might also work with strings under some circumstances, but this is
risky.)

accept_fh(*STDOUT);
accept_fh($handle);

In the examples above, we assigned the filehandle to a scalar variable
before using it. That is because only simple scalar variables, not
expressions or subscripts of hashes or arrays, can be used with
built-ins like "print", "printf", or the diamond operator. Using
something other than a simple scalar variable as a filehandle is illegal
and won't even compile:

@fd = (*STDIN, *STDOUT, *STDERR);
print $fd[1] "Type it: "; # WRONG
$got = <$fd[0]> # WRONG
print $fd[2] "What was that: $got"; # WRONG

With "print" and "printf", you get around this by using a block and an
expression where you would place the filehandle:

print { $fd[1] } "funny stuff\n";
printf { $fd[1] } "Pity the poor %x.\n", 3_735_928_559;
# Pity the poor deadbeef.

That block is a proper block like any other, so you can put more
complicated code there. This sends the message out to one of two places:

$ok = -x "/bin/cat";
print { $ok ? $fd[1] : $fd[2] } "cat stat $ok\n";
print { $fd[ 1+ ($ok || 0) ] } "cat stat $ok\n";

This approach of treating "print" and "printf" like object methods calls
doesn't work for the diamond operator. That's because it's a real
operator, not just a function with a comma-less argument. Assuming
you've been storing typeglobs in your structure as we did above, you can
use the built-in function named "readline" to read a record just as "<>"
does. Given the initialization shown above for @fd, this would work, but
only because readline() requires a typeglob. It doesn't work with
objects or strings, which might be a bug we haven't fixed yet.

$got = readline($fd[0]);

Let it be noted that the flakiness of indirect filehandles is not
related to whether they're strings, typeglobs, objects, or anything
else. It's the syntax of the fundamental operators. Playing the object
game doesn't help you at all here.



--------------------------------------------------------------------

The perlfaq-workers, a group of volunteers, maintain the perlfaq. They
are not necessarily experts in every domain where Perl might show up,
so please include as much information as possible and relevant in any
corrections. The perlfaq-workers also don't have access to every
operating system or platform, so please include relevant details for
corrections to examples that do not work on particular platforms.
Working code is greatly appreciated.

If you'd like to help maintain the perlfaq, see the details in
perlfaq.pod.

--
Posted via a free Usenet account from http://www.teranews.com

.