develooper Front page | perl.perl5.porters | Postings from March 2000

[ID 20000324.060] various glob() bugs

Thread Previous
From:
Tom Christiansen
Date:
March 24, 2000 17:13
Subject:
[ID 20000324.060] various glob() bugs
Message ID:
1385.953946808@chthon
Summary:

    1.  Prototype change breaks documented examples.
    2.  :globally problems
    3.  Incompatible breakage 
    4.  Missing docs

+--------------------------------------------------+
| 1.  Prototype change breaks documented examples. |
+--------------------------------------------------+

I seem to recall that this is my own fault:

[  5163] By: gsar                                  on 2000/02/20  16:34:33
        Log: glob() takes one or no user arguments and a non-user-visible second
             hidden argument, fix its prototype-checking accordingly
     Branch: perl

That made this:

    glob            glob                    ck_glob         t@      S? S?
become this
    glob            glob                    ck_glob         t@      S?

And that breaks this:

     use File::Glob ':glob';
     @list = glob('*.[ch]');
     $homedir = glob('~gnat', GLOB_TILDE | GLOB_ERR);
     if (GLOB_ERROR) {
         print "can't glob ~gnat: $!\n";
     } else {
	  print "Gnat lives in $homedir\n";
     } 

Which used to say

    Gnat lives in /home/gnat

But now says

    Too many arguments for glob at - line 3, near "GLOB_ERR)"

So even though you import it, and even though it goes into <*> fileglobs,
you have to say this:

     use File::Glob ':glob';
     @list = glob('*.[ch]');
     $homedir = &glob('~gnat', GLOB_TILDE | GLOB_ERR);
     if (GLOB_ERROR) {
         print "can't glob ~gnat: $!\n";
     } else {
	  print "Gnat lives in $homedir\n";
     } 

Yes, you have to use &glob to give another argument. 

I don't know a perfect solution here, but right now, there's
a problem.  Well, yes, I do know a perfect solution: if one
could (effectively) frob the opcode.pl output so that

    *CORE::GLOBAL::glob = \&File::Glob::csh_glob;

would make the parser tolerate 0 or 1 arguments, but with 

    *CORE::GLOBAL::glob = \&File::Glob::glob;

it would tolerate 0, 1, or 2 arguments.

+------------------------+
| 2.  :globally problems |
+------------------------+

There are other problems with this module.  The import

     use File::Glob ':globally';

is a silent no-op on systems compiled with -DPERL_EXTERNAL_GLOB.
That's because all it does is                 

    *CORE::GLOBAL::glob = \&File::Glob::csh_glob;

but that's what you have already.  If you want to have space-sensitive
globbing, then you use

    use File::Glob ':glob';

But that's just that package.  You can't use ':globally'
to do a 

    *CORE::GLOBAL::glob = \&File::Glob::glob;

So you have to do it yourself, which feels sleasy.  Here's the demo.
You can't get qw/:glob :globally/ or or qw/:globally :glob/ to do
what you need done.  (Yeah, I know, CORE::GLOBAL is "evil".)

    #!/bin/sh -x
    rm -rf /tmp/fred "/tmp/fred stuff"
    mkdir "/tmp/fred stuff"
    touch "/tmp/fred stuff/a"
    touch "/tmp/fred stuff/b"
    perl -We '
	use File::Glob qw/:glob :globally/;
	#use File::Glob qw/:globally :glob/;
	# BEGIN { *CORE::GLOBAL::glob = \&File::Glob::glob };
	package bad;
	@a = </tmp/fred stu*>;
	print "File Glob globbed @a\n"
    ';

I think I prefer ":everywhere"  to ":globally".  It's far far too
close to ":glob", and means something completely different.

It would also be nice to get at File::Glob::glob without overriding the
built-in.  But then you don't get the flags and such you need.  Too
bad it's not "POSIX::glob" -- less typing.

I think you should be able to say whether 

    This package uses POSIX glob for the Perl fileglob operator.
    This package uses csh   glob for the Perl fileglob operator.
    All packages use  POSIX glob for the Perl fileglob operator.
    All packages use  csh   glob for the Perl fileglob operator.

+----------------------------+
| 3.  Incompatible breakage  |
+----------------------------+

    % perl5.004 -le 'print glob("*.[^x]")'

That gets all the files that end in a dot followed by anything not
an x.  But it is silently broken now:

    % perl -le 'print glob("*.[^x]")'

Because of this *.[!x] thing.  And there's no way to get back
what it used to do.

+-----------------+
| 4. Missing docs |
+-----------------+

I notice in passing that csh_glob is not documented.  And when it is,
the space bug should be explained.  Also, this $^O oddity isn't
explained, either.  Iff you call glob with only one argument, then
iff you're on a case-screwed system (happy unicode, mate!), then 
you get the default weirdness.

All of these things need doc'ing, including the various breakages.
What you import to get what to happen is highly unclear.  It could
really use some work.

--tom

Thread Previous


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About