[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/se3-unattended/var/se3/unattended/install/linuxaux/opt/perl/lib/5.10.0/File/ -> DosGlob.pm (source)

   1  #!perl -w
   2  
   3  # use strict fails
   4  #Can't use string ("main::glob") as a symbol ref while "strict refs" in use at /usr/lib/perl5/5.005/File/DosGlob.pm line 191.
   5  
   6  #
   7  # Documentation at the __END__
   8  #
   9  
  10  package File::DosGlob;
  11  
  12  our $VERSION = '1.00';
  13  use strict;
  14  use warnings;
  15  
  16  sub doglob {
  17      my $cond = shift;
  18      my @retval = ();
  19      #print "doglob: ", join('|', @_), "\n";
  20    OUTER:
  21      for my $pat (@_) {
  22      my @matched = ();
  23      my @globdirs = ();
  24      my $head = '.';
  25      my $sepchr = '/';
  26          my $tail;
  27      next OUTER unless defined $pat and $pat ne '';
  28      # if arg is within quotes strip em and do no globbing
  29      if ($pat =~ /^"(.*)"\z/s) {
  30          $pat = $1;
  31          if ($cond eq 'd') { push(@retval, $pat) if -d $pat }
  32          else              { push(@retval, $pat) if -e $pat }
  33          next OUTER;
  34      }
  35      # wildcards with a drive prefix such as h:*.pm must be changed
  36      # to h:./*.pm to expand correctly
  37      if ($pat =~ m|^([A-Za-z]:)[^/\\]|s) {
  38          substr($_,0,2) = $1 . "./";
  39      }
  40      if ($pat =~ m|^(.*)([\\/])([^\\/]*)\z|s) {
  41          ($head, $sepchr, $tail) = ($1,$2,$3);
  42          #print "div: |$head|$sepchr|$tail|\n";
  43          push (@retval, $pat), next OUTER if $tail eq '';
  44          if ($head =~ /[*?]/) {
  45          @globdirs = doglob('d', $head);
  46          push(@retval, doglob($cond, map {"$_$sepchr$tail"} @globdirs)),
  47              next OUTER if @globdirs;
  48          }
  49          $head .= $sepchr if $head eq '' or $head =~ /^[A-Za-z]:\z/s;
  50          $pat = $tail;
  51      }
  52      #
  53      # If file component has no wildcards, we can avoid opendir
  54      unless ($pat =~ /[*?]/) {
  55          $head = '' if $head eq '.';
  56          $head .= $sepchr unless $head eq '' or substr($head,-1) eq $sepchr;
  57          $head .= $pat;
  58          if ($cond eq 'd') { push(@retval,$head) if -d $head }
  59          else              { push(@retval,$head) if -e $head }
  60          next OUTER;
  61      }
  62      opendir(D, $head) or next OUTER;
  63      my @leaves = readdir D;
  64      closedir D;
  65      $head = '' if $head eq '.';
  66      $head .= $sepchr unless $head eq '' or substr($head,-1) eq $sepchr;
  67  
  68      # escape regex metachars but not glob chars
  69          $pat =~ s:([].+^\-\${}[|]):\\$1:g;
  70      # and convert DOS-style wildcards to regex
  71      $pat =~ s/\*/.*/g;
  72      $pat =~ s/\?/.?/g;
  73  
  74      #print "regex: '$pat', head: '$head'\n";
  75      my $matchsub = sub { $_[0] =~ m|^$pat\z|is };
  76        INNER:
  77      for my $e (@leaves) {
  78          next INNER if $e eq '.' or $e eq '..';
  79          next INNER if $cond eq 'd' and ! -d "$head$e";
  80          push(@matched, "$head$e"), next INNER if &$matchsub($e);
  81          #
  82          # [DOS compatibility special case]
  83          # Failed, add a trailing dot and try again, but only
  84          # if name does not have a dot in it *and* pattern
  85          # has a dot *and* name is shorter than 9 chars.
  86          #
  87          if (index($e,'.') == -1 and length($e) < 9
  88              and index($pat,'\\.') != -1) {
  89          push(@matched, "$head$e"), next INNER if &$matchsub("$e.");
  90          }
  91      }
  92      push @retval, @matched if @matched;
  93      }
  94      return @retval;
  95  }
  96  
  97  
  98  #
  99  # Do DOS-like globbing on Mac OS 
 100  #
 101  sub doglob_Mac {
 102      my $cond = shift;
 103      my @retval = ();
 104  
 105      #print "doglob_Mac: ", join('|', @_), "\n";
 106    OUTER:
 107      for my $arg (@_) {
 108          local $_ = $arg;
 109      my @matched = ();
 110      my @globdirs = ();
 111      my $head = ':';
 112      my $not_esc_head = $head;
 113      my $sepchr = ':';    
 114      next OUTER unless defined $_ and $_ ne '';
 115      # if arg is within quotes strip em and do no globbing
 116      if (/^"(.*)"\z/s) {
 117          $_ = $1;
 118          # $_ may contain escaped metachars '\*', '\?' and '\'
 119              my $not_esc_arg = $_;
 120          $not_esc_arg =~ s/\\([*?\\])/$1/g;
 121          if ($cond eq 'd') { push(@retval, $not_esc_arg) if -d $not_esc_arg }
 122          else              { push(@retval, $not_esc_arg) if -e $not_esc_arg }
 123          next OUTER;
 124      }
 125  
 126      if (m|^(.*?)(:+)([^:]*)\z|s) { # note: $1 is not greedy
 127          my $tail;
 128          ($head, $sepchr, $tail) = ($1,$2,$3);
 129          #print "div: |$head|$sepchr|$tail|\n";
 130          push (@retval, $_), next OUTER if $tail eq '';        
 131          #
 132          # $head may contain escaped metachars '\*' and '\?'
 133          
 134          my $tmp_head = $head;
 135          # if a '*' or '?' is preceded by an odd count of '\', temporary delete 
 136          # it (and its preceding backslashes), i.e. don't treat '\*' and '\?' as 
 137          # wildcards
 138          $tmp_head =~ s/(\\*)([*?])/$2 x ((length($1) + 1) % 2)/eg;
 139      
 140          if ($tmp_head =~ /[*?]/) { # if there are wildcards ...    
 141          @globdirs = doglob_Mac('d', $head);
 142          push(@retval, doglob_Mac($cond, map {"$_$sepchr$tail"} @globdirs)),
 143              next OUTER if @globdirs;
 144          }
 145          
 146          $head .= $sepchr; 
 147          $not_esc_head = $head;
 148          # unescape $head for file operations
 149          $not_esc_head =~ s/\\([*?\\])/$1/g;
 150          $_ = $tail;
 151      }
 152      #
 153      # If file component has no wildcards, we can avoid opendir
 154      
 155      my $tmp_tail = $_;
 156      # if a '*' or '?' is preceded by an odd count of '\', temporary delete 
 157      # it (and its preceding backslashes), i.e. don't treat '\*' and '\?' as 
 158      # wildcards
 159      $tmp_tail =~ s/(\\*)([*?])/$2 x ((length($1) + 1) % 2)/eg;
 160      
 161      unless ($tmp_tail =~ /[*?]/) { # if there are wildcards ...
 162          $not_esc_head = $head = '' if $head eq ':';
 163          my $not_esc_tail = $_;
 164          # unescape $head and $tail for file operations
 165          $not_esc_tail =~ s/\\([*?\\])/$1/g;
 166          $head .= $_;
 167          $not_esc_head .= $not_esc_tail;
 168          if ($cond eq 'd') { push(@retval,$head) if -d $not_esc_head }
 169          else              { push(@retval,$head) if -e $not_esc_head }
 170          next OUTER;
 171      }
 172      #print "opendir($not_esc_head)\n";
 173      opendir(D, $not_esc_head) or next OUTER;
 174      my @leaves = readdir D;
 175      closedir D;
 176  
 177      # escape regex metachars but not '\' and glob chars '*', '?'
 178      $_ =~ s:([].+^\-\${}[|]):\\$1:g;
 179      # and convert DOS-style wildcards to regex,
 180      # but only if they are not escaped
 181      $_ =~ s/(\\*)([*?])/$1 . ('.' x ((length($1) + 1) % 2)) . $2/eg;
 182  
 183      #print "regex: '$_', head: '$head', unescaped head: '$not_esc_head'\n";
 184      my $matchsub = eval 'sub { $_[0] =~ m|^' . $_ . '\\z|ios }';
 185      warn($@), next OUTER if $@;
 186        INNER:
 187      for my $e (@leaves) {
 188          next INNER if $e eq '.' or $e eq '..';
 189          next INNER if $cond eq 'd' and ! -d "$not_esc_head$e";
 190          
 191          if (&$matchsub($e)) {
 192              my $leave = (($not_esc_head eq ':') && (-f "$not_esc_head$e")) ? 
 193                          "$e" : "$not_esc_head$e";
 194              #
 195              # On Mac OS, the two glob metachars '*' and '?' and the escape 
 196              # char '\' are valid characters for file and directory names. 
 197              # We have to escape and treat them specially.
 198              $leave =~ s|([*?\\])|\\$1|g;        
 199              push(@matched, $leave);
 200              next INNER;
 201          }
 202      }
 203      push @retval, @matched if @matched;
 204      }
 205      return @retval;
 206  }
 207  
 208  #
 209  # _expand_volume() will only be used on Mac OS (Classic): 
 210  # Takes an array of original patterns as argument and returns an array of  
 211  # possibly modified patterns. Each original pattern is processed like 
 212  # that:
 213  # + If there's a volume name in the pattern, we push a separate pattern 
 214  #   for each mounted volume that matches (with '*', '?' and '\' escaped).  
 215  # + If there's no volume name in the original pattern, it is pushed 
 216  #   unchanged. 
 217  # Note that the returned array of patterns may be empty.
 218  #  
 219  sub _expand_volume {
 220      
 221      require MacPerl; # to be verbose
 222      
 223      my @pat = @_;
 224      my @new_pat = ();
 225      my @FSSpec_Vols = MacPerl::Volumes();
 226      my @mounted_volumes = ();
 227  
 228      foreach my $spec_vol (@FSSpec_Vols) {        
 229          # push all mounted volumes into array
 230           push @mounted_volumes, MacPerl::MakePath($spec_vol);
 231      }
 232      #print "mounted volumes: |@mounted_volumes|\n";
 233      
 234      while (@pat) {
 235          my $pat = shift @pat;    
 236          if ($pat =~ /^([^:]+:)(.*)\z/) { # match a volume name?
 237              my $vol_pat = $1;
 238              my $tail = $2;
 239              #
 240              # escape regex metachars but not '\' and glob chars '*', '?'
 241              $vol_pat =~ s:([].+^\-\${}[|]):\\$1:g;
 242              # and convert DOS-style wildcards to regex,
 243              # but only if they are not escaped
 244              $vol_pat =~ s/(\\*)([*?])/$1 . ('.' x ((length($1) + 1) % 2)) . $2/eg;
 245              #print "volume regex: '$vol_pat' \n";
 246                  
 247              foreach my $volume (@mounted_volumes) {
 248                  if ($volume =~ m|^$vol_pat\z|ios) {
 249                      #
 250                      # On Mac OS, the two glob metachars '*' and '?' and the  
 251                      # escape char '\' are valid characters for volume names. 
 252                      # We have to escape and treat them specially.
 253                      $volume =~ s|([*?\\])|\\$1|g;
 254                      push @new_pat, $volume . $tail;
 255                  }
 256              }            
 257          } else { # no volume name in pattern, push original pattern
 258              push @new_pat, $pat;
 259          }
 260      }
 261      return @new_pat;
 262  }
 263  
 264  
 265  #
 266  # _preprocess_pattern() will only be used on Mac OS (Classic): 
 267  # Resolves any updirs in the pattern. Removes a single trailing colon 
 268  # from the pattern, unless it's a volume name pattern like "*HD:"
 269  #
 270  sub _preprocess_pattern {
 271      my @pat = @_;
 272      
 273      foreach my $p (@pat) {
 274          my $proceed;
 275          # resolve any updirs, e.g. "*HD:t?p::a*" -> "*HD:a*"
 276          do {
 277              $proceed = ($p =~ s/^(.*):[^:]+::(.*?)\z/$1:$2/);  
 278          } while ($proceed);
 279          # remove a single trailing colon, e.g. ":*:" -> ":*"
 280          $p =~ s/:([^:]+):\z/:$1/;
 281      }
 282      return @pat;
 283  }
 284          
 285          
 286  #
 287  # _un_escape() will only be used on Mac OS (Classic):
 288  # Unescapes a list of arguments which may contain escaped 
 289  # metachars '*', '?' and '\'.
 290  #
 291  sub _un_escape {
 292      foreach (@_) {
 293          s/\\([*?\\])/$1/g;
 294      }
 295      return @_;
 296  }
 297  
 298  #
 299  # this can be used to override CORE::glob in a specific
 300  # package by saying C<use File::DosGlob 'glob';> in that
 301  # namespace.
 302  #
 303  
 304  # context (keyed by second cxix arg provided by core)
 305  my %iter;
 306  my %entries;
 307  
 308  sub glob {
 309      my($pat,$cxix) = @_;
 310      my @pat;
 311  
 312      # glob without args defaults to $_
 313      $pat = $_ unless defined $pat;
 314  
 315      # extract patterns
 316      if ($pat =~ /\s/) {
 317      require Text::ParseWords;
 318      @pat = Text::ParseWords::parse_line('\s+',0,$pat);
 319      }
 320      else {
 321      push @pat, $pat;
 322      }
 323  
 324      # Mike Mestnik: made to do abc{1,2,3} == abc1 abc2 abc3.
 325      #   abc3 will be the original {3} (and drop the {}).
 326      #   abc1 abc2 will be put in @appendpat.
 327      # This was just the esiest way, not nearly the best.
 328      REHASH: {
 329      my @appendpat = ();
 330      for (@pat) {
 331          # There must be a "," I.E. abc{efg} is not what we want.
 332          while ( /^(.*)(?<!\\)\{(.*?)(?<!\\)\,.*?(?<!\\)\}(.*)$/ ) {
 333          my ($start, $match, $end) = ($1, $2, $3);
 334          #print "Got: \n\t$start\n\t$match\n\t$end\n";
 335          my $tmp = "$start$match$end";
 336          while ( $tmp =~ s/^(.*?)(?<!\\)\{(?:.*(?<!\\)\,)?(.*\Q$match\E.*?)(?:(?<!\\)\,.*)?(?<!\\)\}(.*)$/$1$2$3/ ) {
 337              #print "Striped: $tmp\n";
 338              #  these expanshions will be preformed by the original,
 339              #  when we call REHASH.
 340          }
 341          push @appendpat, ("$tmp");
 342          s/^\Q$start\E(?<!\\)\{\Q$match\E(?<!\\)\,/$start\{/;
 343          if ( /^\Q$start\E(?<!\\)\{(?!.*?(?<!\\)\,.*?\Q$end\E$)(.*)(?<!\\)\}\Q$end\E$/ ) {
 344              $match = $1;
 345              #print "GOT: \n\t$start\n\t$match\n\t$end\n\n";
 346              $_ = "$start$match$end";
 347          }
 348          }
 349          #print "Sould have "GOT" vs "Got"!\n";
 350          #FIXME: There should be checking for this.
 351          #  How or what should be done about failure is beond me.
 352      }
 353      if ( $#appendpat != -1
 354          ) {
 355          #print "LOOP\n";
 356          #FIXME: Max loop, no way! :")
 357          for ( @appendpat ) {
 358              push @pat, $_;
 359          }
 360          goto REHASH;
 361      }
 362      }
 363      for ( @pat ) {
 364      s/\\{/{/g;
 365      s/\\}/}/g;
 366      s/\\,/,/g;
 367      }
 368      #print join ("\n", @pat). "\n";
 369   
 370      # assume global context if not provided one
 371      $cxix = '_G_' unless defined $cxix;
 372      $iter{$cxix} = 0 unless exists $iter{$cxix};
 373  
 374      # if we're just beginning, do it all first
 375      if ($iter{$cxix} == 0) {
 376      if ($^O eq 'MacOS') {
 377          # first, take care of updirs and trailing colons
 378          @pat = _preprocess_pattern(@pat);
 379          # expand volume names
 380          @pat = _expand_volume(@pat);
 381          $entries{$cxix} = (@pat) ? [_un_escape( doglob_Mac(1,@pat) )] : [()];
 382      } else {
 383          $entries{$cxix} = [doglob(1,@pat)];
 384      }
 385      }
 386  
 387      # chuck it all out, quick or slow
 388      if (wantarray) {
 389      delete $iter{$cxix};
 390      return @{delete $entries{$cxix}};
 391      }
 392      else {
 393      if ($iter{$cxix} = scalar @{$entries{$cxix}}) {
 394          return shift @{$entries{$cxix}};
 395      }
 396      else {
 397          # return undef for EOL
 398          delete $iter{$cxix};
 399          delete $entries{$cxix};
 400          return undef;
 401      }
 402      }
 403  }
 404  
 405  {
 406      no strict 'refs';
 407  
 408      sub import {
 409      my $pkg = shift;
 410      return unless @_;
 411      my $sym = shift;
 412      my $callpkg = ($sym =~ s/^GLOBAL_//s ? 'CORE::GLOBAL' : caller(0));
 413      *{$callpkg.'::'.$sym} = \&{$pkg.'::'.$sym} if $sym eq 'glob';
 414      }
 415  }
 416  1;
 417  
 418  __END__
 419  
 420  =head1 NAME
 421  
 422  File::DosGlob - DOS like globbing and then some
 423  
 424  =head1 SYNOPSIS
 425  
 426      require 5.004;
 427  
 428      # override CORE::glob in current package
 429      use File::DosGlob 'glob';
 430  
 431      # override CORE::glob in ALL packages (use with extreme caution!)
 432      use File::DosGlob 'GLOBAL_glob';
 433  
 434      @perlfiles = glob  "..\\pe?l/*.p?";
 435      print <..\\pe?l/*.p?>;
 436  
 437      # from the command line (overrides only in main::)
 438      > perl -MFile::DosGlob=glob -e "print <../pe*/*p?>"
 439  
 440  =head1 DESCRIPTION
 441  
 442  A module that implements DOS-like globbing with a few enhancements.
 443  It is largely compatible with perlglob.exe (the M$ setargv.obj
 444  version) in all but one respect--it understands wildcards in
 445  directory components.
 446  
 447  For example, C<<..\\l*b\\file/*glob.p?>> will work as expected (in
 448  that it will find something like '..\lib\File/DosGlob.pm' alright).
 449  Note that all path components are case-insensitive, and that
 450  backslashes and forward slashes are both accepted, and preserved.
 451  You may have to double the backslashes if you are putting them in
 452  literally, due to double-quotish parsing of the pattern by perl.
 453  
 454  Spaces in the argument delimit distinct patterns, so
 455  C<glob('*.exe *.dll')> globs all filenames that end in C<.exe>
 456  or C<.dll>.  If you want to put in literal spaces in the glob
 457  pattern, you can escape them with either double quotes, or backslashes.
 458  e.g. C<glob('c:/"Program Files"/*/*.dll')>, or
 459  C<glob('c:/Program\ Files/*/*.dll')>.  The argument is tokenized using
 460  C<Text::ParseWords::parse_line()>, so see L<Text::ParseWords> for details
 461  of the quoting rules used.
 462  
 463  Extending it to csh patterns is left as an exercise to the reader.
 464  
 465  =head1 NOTES
 466  
 467  =over 4
 468  
 469  =item *
 470  
 471  Mac OS (Classic) users should note a few differences. The specification 
 472  of pathnames in glob patterns adheres to the usual Mac OS conventions: 
 473  The path separator is a colon ':', not a slash '/' or backslash '\'. A 
 474  full path always begins with a volume name. A relative pathname on Mac 
 475  OS must always begin with a ':', except when specifying a file or 
 476  directory name in the current working directory, where the leading colon 
 477  is optional. If specifying a volume name only, a trailing ':' is 
 478  required. Due to these rules, a glob like E<lt>*:E<gt> will find all 
 479  mounted volumes, while a glob like E<lt>*E<gt> or E<lt>:*E<gt> will find 
 480  all files and directories in the current directory.
 481  
 482  Note that updirs in the glob pattern are resolved before the matching begins,
 483  i.e. a pattern like "*HD:t?p::a*" will be matched as "*HD:a*". Note also,
 484  that a single trailing ':' in the pattern is ignored (unless it's a volume
 485  name pattern like "*HD:"), i.e. a glob like <:*:> will find both directories 
 486  I<and> files (and not, as one might expect, only directories). 
 487  
 488  The metachars '*', '?' and the escape char '\' are valid characters in 
 489  volume, directory and file names on Mac OS. Hence, if you want to match
 490  a '*', '?' or '\' literally, you have to escape these characters. Due to 
 491  perl's quoting rules, things may get a bit complicated, when you want to 
 492  match a string like '\*' literally, or when you want to match '\' literally, 
 493  but treat the immediately following character '*' as metachar. So, here's a 
 494  rule of thumb (applies to both single- and double-quoted strings): escape 
 495  each '*' or '?' or '\' with a backslash, if you want to treat them literally, 
 496  and then double each backslash and your are done. E.g. 
 497  
 498  - Match '\*' literally
 499  
 500     escape both '\' and '*'  : '\\\*'
 501     double the backslashes   : '\\\\\\*'
 502  
 503  (Internally, the glob routine sees a '\\\*', which means that both '\' and 
 504  '*' are escaped.)
 505  
 506  
 507  - Match '\' literally, treat '*' as metachar
 508  
 509     escape '\' but not '*'   : '\\*'
 510     double the backslashes   : '\\\\*'
 511  
 512  (Internally, the glob routine sees a '\\*', which means that '\' is escaped and 
 513  '*' is not.)
 514  
 515  Note that you also have to quote literal spaces in the glob pattern, as described
 516  above.
 517  
 518  =back
 519  
 520  =head1 EXPORTS (by request only)
 521  
 522  glob()
 523  
 524  =head1 BUGS
 525  
 526  Should probably be built into the core, and needs to stop
 527  pandering to DOS habits.  Needs a dose of optimizium too.
 528  
 529  =head1 AUTHOR
 530  
 531  Gurusamy Sarathy <gsar@activestate.com>
 532  
 533  =head1 HISTORY
 534  
 535  =over 4
 536  
 537  =item *
 538  
 539  Support for globally overriding glob() (GSAR 3-JUN-98)
 540  
 541  =item *
 542  
 543  Scalar context, independent iterator context fixes (GSAR 15-SEP-97)
 544  
 545  =item *
 546  
 547  A few dir-vs-file optimizations result in glob importation being
 548  10 times faster than using perlglob.exe, and using perlglob.bat is
 549  only twice as slow as perlglob.exe (GSAR 28-MAY-97)
 550  
 551  =item *
 552  
 553  Several cleanups prompted by lack of compatible perlglob.exe
 554  under Borland (GSAR 27-MAY-97)
 555  
 556  =item *
 557  
 558  Initial version (GSAR 20-FEB-97)
 559  
 560  =back
 561  
 562  =head1 SEE ALSO
 563  
 564  perl
 565  
 566  perlglob.bat
 567  
 568  Text::ParseWords
 569  
 570  =cut
 571  


Generated: Tue Mar 17 22:47:18 2015 Cross-referenced by PHPXref 0.7.1