home *** CD-ROM | disk | FTP | other *** search
- @rem = '--*-Perl-*--
- @echo off
- perl -x -S %0 %1 %2 %3 %4 %5 %6 %7 %8 %9
- goto endofperl
- @rem ';
- #!perl -w
- #line 8
-
- #
- # Documentation at the __END__
- #
-
- package File::DosGlob;
-
- unless (caller) {
- $| = 1;
- while (@ARGV) {
- #
- # We have to do this one by one for compatibility reasons.
- # If an arg doesn't match anything, we are supposed to return
- # the original arg. I know, it stinks, eh?
- #
- my $arg = shift;
- my @m = doglob(1,$arg);
- print (@m ? join("\0", sort @m) : $arg);
- print "\0" if @ARGV;
- }
- }
-
- sub doglob {
- my $cond = shift;
- my @retval = ();
- #print "doglob: ", join('|', @_), "\n";
- OUTER:
- for my $arg (@_) {
- local $_ = $arg;
- my @matched = ();
- my @globdirs = ();
- my $head = '.';
- my $sepchr = '/';
- next OUTER unless defined $_ and $_ ne '';
- # if arg is within quotes strip em and do no globbing
- if (/^"(.*)"$/) {
- $_ = $1;
- if ($cond eq 'd') { push(@retval, $_) if -d $_ }
- else { push(@retval, $_) if -e $_ }
- next OUTER;
- }
- if (m|^(.*)([\\/])([^\\/]*)$|) {
- my $tail;
- ($head, $sepchr, $tail) = ($1,$2,$3);
- #print "div: |$head|$sepchr|$tail|\n";
- push (@retval, $_), next OUTER if $tail eq '';
- if ($head =~ /[*?]/) {
- @globdirs = doglob('d', $head);
- push(@retval, doglob($cond, map {"$_$sepchr$tail"} @globdirs)),
- next OUTER if @globdirs;
- }
- $head .= $sepchr if $head eq '' or $head =~ /^[A-Za-z]:$/;
- $_ = $tail;
- }
- #
- # If file component has no wildcards, we can avoid opendir
- unless (/[*?]/) {
- $head = '' if $head eq '.';
- $head .= $sepchr unless $head eq '' or substr($head,-1) eq $sepchr;
- $head .= $_;
- if ($cond eq 'd') { push(@retval,$head) if -d $head }
- else { push(@retval,$head) if -e $head }
- next OUTER;
- }
- opendir(D, $head) or next OUTER;
- my @leaves = readdir D;
- closedir D;
- $head = '' if $head eq '.';
- $head .= $sepchr unless $head eq '' or substr($head,-1) eq $sepchr;
-
- # escape regex metachars but not glob chars
- s:([].+^\-\${}[|]):\\$1:g;
- # and convert DOS-style wildcards to regex
- s/\*/.*/g;
- s/\?/.?/g;
-
- #print "regex: '$_', head: '$head'\n";
- my $matchsub = eval 'sub { $_[0] =~ m|^' . $_ . '$|io }';
- warn($@), next OUTER if $@;
- INNER:
- for my $e (@leaves) {
- next INNER if $e eq '.' or $e eq '..';
- next INNER if $cond eq 'd' and ! -d "$head$e";
- push(@matched, "$head$e"), next INNER if &$matchsub($e);
- #
- # [DOS compatibility special case]
- # Failed, add a trailing dot and try again, but only
- # if name does not have a dot in it *and* pattern
- # has a dot *and* name is shorter than 9 chars.
- #
- if (index($e,'.') == -1 and length($e) < 9
- and index($_,'\\.') != -1) {
- push(@matched, "$head$e"), next INNER if &$matchsub("$e.");
- }
- }
- push @retval, @matched if @matched;
- }
- return @retval;
- }
-
- #
- # this can be used to override CORE::glob
- # by saying C<use File::DosGlob 'glob';>.
- #
- sub glob { doglob(1,@_) }
-
- sub import {
- my $pkg = shift;
- my $callpkg = caller(0);
- my $sym = shift;
- *{$callpkg.'::'.$sym} = \&{$pkg.'::'.$sym} if $sym eq 'glob';
- }
-
- 1;
-
- __END__
-
- =head1 NAME
-
- File::DosGlob - DOS like globbing and then some
-
- perlglob.bat - a more capable perlglob.exe replacement
-
- =head1 SYNOPSIS
-
- require 5.004;
- use File::DosGlob 'glob'; # override CORE::glob
- @perlfiles = glob "..\\pe?l/*.p?";
- print <..\\pe?l/*.p?>;
-
- # from the command line
- > perl -MFile::DosGlob=glob -e "print <../pe*/*p?>"
-
- > perlglob ../pe*/*p?
-
- =head1 DESCRIPTION
-
- A module that implements DOS-like globbing with a few enhancements.
- This file is also a portable replacement for perlglob.exe. It
- is largely compatible with perlglob.exe (the M$ setargv.obj
- version) in all but one respect--it understands wildcards in
- directory components.
-
- For example, C<<..\\l*b\\file/*glob.p?>> will work as expected (in
- that it will find something like '..\lib\File/DosGlob.pm' alright).
- Note that all path components are case-insensitive, and that
- backslashes and forward slashes are both accepted, and preserved.
- You may have to double the backslashes if you are putting them in
- literally, due to double-quotish parsing of the pattern by perl.
-
- When invoked as a program, it will print null-separated filenames
- to standard output.
-
- While one may replace perlglob.exe with this, usage by overriding
- CORE::glob via importation should be much more efficient, because
- it avoids launching a separate process, and is therefore strongly
- recommended.
-
- Extending it to csh patterns is left as an exercise to the reader.
-
- =head1 EXPORTS (by request only)
-
- glob()
-
- =head1 BUGS
-
- Should probably be built into the core, and needs to stop
- pandering to DOS habits. Needs a dose of optimizium too.
-
- =head1 AUTHOR
-
- Gurusamy Sarathy <gsar@umich.edu>
-
- =head1 HISTORY
-
- =over 4
-
- =item *
-
- A few dir-vs-file optimizations result in glob importation being
- 10 times faster than using perlglob.exe, and using perlglob.bat is
- only twice as slow as perlglob.exe (GSAR 28-MAY-97)
-
- =item *
-
- Several cleanups prompted by lack of compatible perlglob.exe
- under Borland (GSAR 27-MAY-97)
-
- =item *
-
- Initial version (GSAR 20-FEB-97)
-
- =back
-
- =head1 SEE ALSO
-
- perl
-
- =cut
-
- __END__
- :endofperl
-