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

Oldie but goodie: glob in scalar context

Thread Next
From:
Peter Scott
Date:
March 27, 2008 11:28
Subject:
Oldie but goodie: glob in scalar context
Message ID:
pan.2008.03.27.18.28.14.457199@PSDT.com
I just found the discussion at
http://groups.google.com/group/perl.perl5.porters/browse_thread/thread/5401ccdcbd6d4fa1/
the hard way.  It appears to have petered out and I would like to reopen
it.

Posit that you are on a large networked filesystem where many user home
directories are segmented by first letter, e.g., /home/a/alfred,
/home/x/xavier, etc.  And a user wishes to vet a list of putative
usernames to see if they have home directories.  A natural solution is:

    print "$_ not found\n" unless glob "/home/?/$_" for @putative_users;
    
Elegant, yes.  Correct, no.  Because when glob() matches the first username,
on the next call, it will ignore its argument and return undef to indicate
that it has no more matches for the previous username.

Imagine that user is then trying to use the debugger that you have taught
them to use, on an expanded version of this so they can inspect $_ before
the glob call, and they find that when they type

  DBG> x glob "/home/?/$_"

it produces a different result from what the program itself does when they
take the next step.  It's somewhat embarrassing and not a little
convoluted to explain to them that this is their fault.

I think that scalar glob iteration should be reset when the value of its
expression changes.  This is what Schwern and chromatic espoused in the
thread I cite above. 

I append a patch that seems to do the job in my humble environment.

*** /usr/local/lib/perl5/5.10.0/i686-linux/File/Glob.pm.orig    2008-03-27 11:04:10.000000000 -0700
--- /usr/local/lib/perl5/5.10.0/i686-linux/File/Glob.pm 2008-03-27 11:20:39.000000000 -0700
***************
*** 132,142 ****
--- 132,147 ----
  ## borrowed heavily from gsar's File::DosGlob
  my %iter;
  my %entries;
+ my %prev_pat;
  
  sub csh_glob {
      my $pat = shift;
      my $cxix = shift;
      my @pat;
+     my $pat_changed;
+ 
+     $pat_changed = 1 if defined $prev_pat{$cxix} && $pat ne $prev_pat{$cxix};
+     $prev_pat{$cxix} = $pat;
  
      # glob without args defaults to $_
      $pat = $_ unless defined $pat;
***************
*** 155,161 ****
  
      # assume global context if not provided one
      $cxix = '_G_' unless defined $cxix;
!     $iter{$cxix} = 0 unless exists $iter{$cxix};
  
      # if we're just beginning, do it all first
      if ($iter{$cxix} == 0) {
--- 160,166 ----
  
      # assume global context if not provided one
      $cxix = '_G_' unless defined $cxix;
!     $iter{$cxix} = 0 if ! exists $iter{$cxix} || $pat_changed;
  
      # if we're just beginning, do it all first
      if ($iter{$cxix} == 0) {
***************
*** 170,175 ****
--- 175,181 ----
      # chuck it all out, quick or slow
      if (wantarray) {
          delete $iter{$cxix};
+       delete $prev_pat{$cxix};
          return @{delete $entries{$cxix}};
      }
      else {
***************
*** 180,185 ****
--- 186,192 ----
              # return undef for EOL
              delete $iter{$cxix};
              delete $entries{$cxix};
+           delete $prev_pat{$cxix};
              return undef;
          }
      }


-- 
Peter Scott

Thread Next


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