odd problem with open()

C

Colin Howarth

Hi, I'm running perl 5.6.0 on Mac OS X (darwin) and have a program with
the following code:

sub do_dir {
my $dir = shift;
....
opendir(DIR, $dir) or die "Can't open directory '$dir' $!";

while ($file = readdir(DIR)) {
next if $file =~ /^\.\.?$/;
next if -l "$dir/$file";

if (-d "$dir/$file") {
do_dir("$dir/$file");
} elsif (-f "$dir/$file") {
open(FILE, "$dir/$file") or die "Can't open
'$dir/$file': $!";

...
}

i.e. it's recursing through the filesystem, skipping symbolic links
(because there are entries linked back to a parent directory (!)) and
skipping '.' and '..' of course.

This works fine except when it comes across a filename like

/Library//CFMSupport/StuffItEngineShell.cfm/Icon^M

i.e. where the last character is a CR, when the program dies.

Now, I don't know why the odd file has a CR in it's name, but why
doesn't open() work anyway?

At present I've resorted to

# chop $file if $file =~/\r$/;
chop $file if substr($file, -1, 1) eq "\r";

(substr seems to be slightly quicker here)

Thanks,

colin
 
T

Tad McClellan

Colin Howarth said:
open(FILE, "$dir/$file") or die "Can't open
'$dir/$file': $!";

This works fine except when it comes across a filename like

/Library//CFMSupport/StuffItEngineShell.cfm/Icon^M

i.e. where the last character is a CR, when the program dies.

Now, I don't know why the odd file has a CR in it's name, but why
doesn't open() work anyway?


The documentation for open() says why it is not working.

You must have missed it.

perldoc -f open

The filename passed to 2-argument (or 1-argument) form of open() will
have leading and trailing whitespace deleted,
...
Use 3-argument form to open a file with arbitrary weird characters in it,

At present I've resorted to

# chop $file if $file =~/\r$/;
chop $file if substr($file, -1, 1) eq "\r";


And that makes it work?

If so, then the file does NOT have a CR in its name.

I thought you said above that it did have a CR in its name.

Which is it?

Anyway:

open(FILE, '<', "$dir/$file") or die...

will open() it even if CR is part of the filename.
 
J

Joe Smith

Colin said:
sub do_dir {
while ($file = readdir(DIR)) {
if (-d "$dir/$file") {
do_dir("$dir/$file");

It is not a good idea to call readdir() in scalar context when doing
recursion. An older version of perl would lose its place in the
parent readir() when the subdirectory readdir() started.

If you're going to re-invent the wheel that has already been solved
via File::Find, be sure to use lexical file handles and dir handles,
not global ones.
-Joe
 
1

187

Joe said:
It is not a good idea to call readdir() in scalar context when doing
recursion. An older version of perl would lose its place in the
parent readir() when the subdirectory readdir() started.

This is a work arond I once imployed in a some what similar situation
(as far as using a file handle of the same name multiple time from the
result of recursion) :

sub do_dir {
# makes sure DIR from resursive calls to do_dir() don't clash.
local *DIR; # localize file handle.
#-------------------------------------------------------------

while ($file = readdir(DIR)) {
if (-d "$dir/$file") {
do_dir("$dir/$file");
[...]
If you're going to re-invent the wheel that has already been solved
via File::Find, be sure to use lexical file handles and dir handles,
not global ones.

Good mudule. Just FYI, for the last part of the sentance, my addition to
the OP's code applies as well :)
 
C

Colin Howarth

The documentation for open() says why it is not working.

You must have missed it.

Yup, missed it. The description for open() has about 300 lines. I
stopped reading somewhere around when the tutorial on Bourne shell
filehandle redirection. That was unfortunate since just after that came
the 2/3 argument bit. :)

perldoc -f open

The filename passed to 2-argument (or 1-argument) form of open() will
have leading and trailing whitespace deleted,
...
Use 3-argument form to open a file with arbitrary weird characters in it,

Thanks, that does the trick.
And that makes it work?

Ah. Depends what you meen by work ;-)

It stopped the error in the open, but if you look at the original code,

if (-d "$dir/$file") {
do_dir("$dir/$file");
} elsif (-f "$dir/$file") {
open(FILE, "$dir/$file") or die "Can't open
'$dir/$file': $!";


and "$dir/$file" (with the last character chopped) is no longer a plain
file. In fact it isn't any sort of file...
If so, then the file does NOT have a CR in its name.

I thought you said above that it did have a CR in its name.

Which is it?

It did have a CR.


So, thanks - problem solved (and something learned).

colin
 

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

Members online

No members online now.

Forum statistics

Threads
474,161
Messages
2,570,892
Members
47,427
Latest member
HildredDic

Latest Threads

Top