[comp.lang.perl] Operations on filehandles

pem@frankland-river.aaii.oz.au (Paul E. Maisano) (02/05/90)

I was wondering what sort of object a filehandle was and what can be done
with one besides printing to them etc.

Specifically, can you save them in a local context in some way, similar to
what the local() function does with variables.

For example, if I open a file in a subroutine and use a file handle called
FILE which I open and then close, how do I know I'm not stomping on
another filehandle called FILE which has already been opened somewhere else
in my program.

I could create a package to avoid the possibility of a naming conflict but
this does not really solve the problem.

What if I want to write a recursive subroutine which opens a file ? How do
I keep separate filehandles for each recursive call ?

Is there a simple way to do this or must I generate a unique filehandle name
on each invocation ?

Any ideas appreciated.

------------------
Paul E. Maisano (email: pem@aaii.oz.au)
Australian Artificial Intelligence Institute
1 Grattan St. Carlton, Vic. 3053, Australia
Ph: +613 663-7922  Fax: +613 663-7937

rae%alias@csri.toronto.edu (Reid Ellis) (02/07/90)

pem@frankland-river.aaii.oz.au (Paul E. Maisano) writes:
|... if I open a file in a subroutine and use a file handle called
|FILE which I open and then close, how do I know I'm not stomping on
|another filehandle called FILE which has already been opened somewhere else
|in my program.
|
| ...
|
|Is there a simple way to do this or must I generate a unique filehandle name
|on each invocation ?

Don't forget that you can use variables for filehandles.  I ran into
the recusion problem myself and found that you couldn't have "local"
filehandles, so the way I got around this was as follows:

$input = "recursion00";

sub recur
	{
	$input++;
	open($input, "filename");
	if(condition) { &recur(); }
	close($input);
	$input--;
	}

Or something along those lines..  This will give you filehandles with
names like recursion01, recursion02, recursion03 etc.  Note that I
wrote the above off the top of my head, but you get the idea.

					Reid
---
"I don't even know what street Canada is on"  -- Al Capone
Reid Ellis  264 Broadway Avenue, Toronto ON, Canada M4P 1V9
rae%alias@csri.toronto.edu || +1 416 487 1383
"I don't even know what street Canada is on"  -- Al Capone
Reid Ellis  264 Broadway Avenue, Toronto ON, Canada M4P 1V9
rae%alias@csri.toronto.edu || +1 416 487 1383

lwall@jpl-devvax.JPL.NASA.GOV (Larry Wall) (02/08/90)

In article <1004@frankland-river.aaii.oz.au> pem@frankland-river.aaii.oz.au (Paul E. Maisano) writes:
: I was wondering what sort of object a filehandle was and what can be done
: with one besides printing to them etc.
: 
: Specifically, can you save them in a local context in some way, similar to
: what the local() function does with variables.
:
: For example, if I open a file in a subroutine and use a file handle called
: FILE which I open and then close, how do I know I'm not stomping on
: another filehandle called FILE which has already been opened somewhere else
: in my program.
: 
: I could create a package to avoid the possibility of a naming conflict but
: this does not really solve the problem.

I believe you can do a local on a name using the type globbing syntax:

    sub foo {
	local(*FILE);

	open(FILE,'foo');
	etc.

I haven't exercised it heavily, but the code is supposedly there to create
a new name if you aren't assigning another name to *FILE.  Just as normal
variables created with a null value when you don't assign something to them.

: What if I want to write a recursive subroutine which opens a file ? How do
: I keep separate filehandles for each recursive call ?

Same way.

: Is there a simple way to do this or must I generate a unique filehandle name
: on each invocation ?

That's pretty simple, though it's easy to generate unique filehandles too:

	$genhandle = 'AAAAAA';			# increments to AAAAAB

	sub foo {
	    local($FILE) = $genhandle++;	# magical autoincrement

	    open($FILE,'foo');
	    ...
		&foo();
	    ...
	    close $FILE;
	}

But I THINK the other way is more efficient, if you reference the filehandle
much, since it has to do a symbol table lookup every time you say $FILE,
but references to FILE already point to the symbol table entry upon compilation.
But it probably takes a little longer to local(*FILE) than local($FILE).

It's 6 1/2 of one, and uh, uh, half a baker's dozen of the other.

Larry

lwall@jpl-devvax.JPL.NASA.GOV (Larry Wall) (02/09/90)

In article <738@alias.UUCP> Reid Ellis <rae%alias@csri.toronto.edu> writes:
: Don't forget that you can use variables for filehandles.  I ran into
: the recusion problem myself and found that you couldn't have "local"
: filehandles, so the way I got around this was as follows:
: 
: $input = "recursion00";
: 
: sub recur
: 	{
: 	$input++;
: 	open($input, "filename");
: 	if(condition) { &recur(); }
: 	close($input);
: 	$input--;
: 	}
: 
: Or something along those lines..  This will give you filehandles with
: names like recursion01, recursion02, recursion03 etc.  Note that I
: wrote the above off the top of my head, but you get the idea.

That's the idea, but $input-- isn't magical, so it'll wipe out the value
of $input, turning it into a -1.  The when you return from the recursion
you'll try to close filehandle '-1'.

Larry

pem@frankland-river.aaii.oz.au (Paul E. Maisano) (02/09/90)

In article <7020@jpl-devvax.JPL.NASA.GOV>, lwall@jpl-devvax.JPL.NASA.GOV (Larry Wall) writes:
> 
> I believe you can do a local on a name using the type globbing syntax:
> 
>     sub foo {
> 	local(*FILE);
> 
> 	open(FILE,'foo');
> 	etc.
> 
> I haven't exercised it heavily, but the code is supposedly there to create
> a new name if you aren't assigning another name to *FILE.  Just as normal
> variables created with a null value when you don't assign something to them.

This pretty much what I was looking for. It's neater than generating unique
filehandle names by hand, but I can't seem to get it to work in a test program.
I end up getting a segmentation fault. 

#!/usr/bin/perl
# This is just an otherwise useless program to test recursive opens.

sub read_lines {
    local($name, $n) = @_;
    local($i);
    local(*F);

    open(F, $name) || die "$name: $!\n";
    for ($i = 0; $i < $n; $i++) {
	$_ = <F>;
	print("$i ($n): ", $_) || warn("print failed: $!\n");
	if ($i == 2 && $n <= 10) { &read_lines($name, $n+5); }
    }
    close(F);
    print "finished $n\n";
}

&read_lines("/etc/passwd", 5);
exit 0;

Generating unique names for filehandles does work, though (as I expected).

------------------
Paul E. Maisano
Australian Artificial Intelligence Institute
1 Grattan St. Carlton, Vic. 3053, Australia
Ph: +613 663-7922  Fax: +613 663-7937
Email: pem@aaii.oz.au

lwall@jpl-devvax.JPL.NASA.GOV (Larry Wall) (02/14/90)

In article <1041@frankland-river.aaii.oz.au> pem@frankland-river.aaii.oz.au (Paul E. Maisano) writes:
: In article <7020@jpl-devvax.JPL.NASA.GOV>, lwall@jpl-devvax.JPL.NASA.GOV (Larry Wall) writes:
: > 
: > I believe you can do a local on a name using the type globbing syntax:
: > 
: >     sub foo {
: > 	local(*FILE);
: > 
: > 	open(FILE,'foo');
: > 	etc.
: > 
: > I haven't exercised it heavily, but the code is supposedly there to create
: > a new name if you aren't assigning another name to *FILE.  Just as normal
: > variables created with a null value when you don't assign something to them.
: 
: This pretty much what I was looking for. It's neater than generating unique
: filehandle names by hand, but I can't seem to get it to work in a test program.
: I end up getting a segmentation fault. 

I think this will work after the infamous patch #9.

Larry