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.
7 # Documentation at the __END__
10 package File::DosGlob;
12 our $VERSION = '1.00';
19 #print "doglob: ", join('|', @_), "\n";
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) {
31 if ($cond eq 'd') { push(@retval, $pat) if -d $pat }
32 else { push(@retval, $pat) if -e $pat }
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 . "./";
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;
49 $head .= $sepchr if $head eq '' or $head =~ /^[A-Za-z]:\z/s;
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;
58 if ($cond eq 'd') { push(@retval,$head) if -d $head }
59 else { push(@retval,$head) if -e $head }
62 opendir(D, $head) or next OUTER;
63 my @leaves = readdir D;
65 $head = '' if $head eq '.';
66 $head .= $sepchr unless $head eq '' or substr($head,-1) eq $sepchr;
68 # escape regex metachars but not glob chars
69 $pat =~ s:([].+^\-\${}[|]):\\$1:g;
70 # and convert DOS-style wildcards to regex
74 #print "regex: '$pat', head: '$head'\n";
75 my $matchsub = sub { $_[0] =~ m|^$pat\z|is };
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);
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.
87 if (index($e,'.') == -1 and length($e) < 9
88 and index($pat,'\\.') != -1) {
89 push(@matched, "$head$e"), next INNER if &$matchsub("$e.");
92 push @retval, @matched if @matched;
99 # Do DOS-like globbing on Mac OS
105 #print "doglob_Mac: ", join('|', @_), "\n";
112 my $not_esc_head = $head;
114 next OUTER unless defined $_ and $_ ne '';
115 # if arg is within quotes strip em and do no globbing
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 }
126 if (m|^(.*?)(:+)([^:]*)\z|s) { # note: $1 is not greedy
128 ($head, $sepchr, $tail) = ($1,$2,$3);
129 #print "div: |$head|$sepchr|$tail|\n";
130 push (@retval, $_), next OUTER if $tail eq '';
132 # $head may contain escaped metachars '\*' and '\?'
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
138 $tmp_head =~ s/(\\*)([*?])/$2 x ((length($1) + 1) % 2)/eg;
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;
147 $not_esc_head = $head;
148 # unescape $head for file operations
149 $not_esc_head =~ s/\\([*?\\])/$1/g;
153 # If file component has no wildcards, we can avoid opendir
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
159 $tmp_tail =~ s/(\\*)([*?])/$2 x ((length($1) + 1) % 2)/eg;
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;
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 }
172 #print "opendir($not_esc_head)\n";
173 opendir(D, $not_esc_head) or next OUTER;
174 my @leaves = readdir D;
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;
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 $@;
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";
191 if (&$matchsub($e)) {
192 my $leave = (($not_esc_head eq ':') && (-f "$not_esc_head$e")) ?
193 "$e" : "$not_esc_head$e";
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);
203 push @retval, @matched if @matched;
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
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
217 # Note that the returned array of patterns may be empty.
221 require MacPerl; # to be verbose
225 my @FSSpec_Vols = MacPerl::Volumes();
226 my @mounted_volumes = ();
228 foreach my $spec_vol (@FSSpec_Vols) {
229 # push all mounted volumes into array
230 push @mounted_volumes, MacPerl::MakePath($spec_vol);
232 #print "mounted volumes: |@mounted_volumes|\n";
235 my $pat = shift @pat;
236 if ($pat =~ /^([^:]+:)(.*)\z/) { # match a volume name?
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";
247 foreach my $volume (@mounted_volumes) {
248 if ($volume =~ m|^$vol_pat\z|ios) {
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;
257 } else { # no volume name in pattern, push original pattern
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:"
270 sub _preprocess_pattern {
273 foreach my $p (@pat) {
275 # resolve any updirs, e.g. "*HD:t?p::a*" -> "*HD:a*"
277 $proceed = ($p =~ s/^(.*):[^:]+::(.*?)\z/$1:$2/);
279 # remove a single trailing colon, e.g. ":*:" -> ":*"
280 $p =~ s/:([^:]+):\z/:$1/;
287 # _un_escape() will only be used on Mac OS (Classic):
288 # Unescapes a list of arguments which may contain escaped
289 # metachars '*', '?' and '\'.
299 # this can be used to override CORE::glob in a specific
300 # package by saying C<use File::DosGlob 'glob';> in that
304 # context (keyed by second cxix arg provided by core)
312 # glob without args defaults to $_
313 $pat = $_ unless defined $pat;
317 require Text::ParseWords;
318 @pat = Text::ParseWords::parse_line('\s+',0,$pat);
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.
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.
341 push @appendpat, ("$tmp");
342 s/^\Q$start\E(?<!\\)\{\Q$match\E(?<!\\)\,/$start\{/;
343 if ( /^\Q$start\E(?<!\\)\{(?!.*?(?<!\\)\,.*?\Q$end\E$)(.*)(?<!\\)\}\Q$end\E$/ ) {
345 #print "GOT: \n\t$start\n\t$match\n\t$end\n\n";
346 $_ = "$start$match$end";
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.
353 if ( $#appendpat != -1
356 #FIXME: Max loop, no way! :")
368 #print join ("\n", @pat). "\n";
370 # assume global context if not provided one
371 $cxix = '_G_' unless defined $cxix;
372 $iter{$cxix} = 0 unless exists $iter{$cxix};
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) )] : [()];
383 $entries{$cxix} = [doglob(1,@pat)];
387 # chuck it all out, quick or slow
390 return @{delete $entries{$cxix}};
393 if ($iter{$cxix} = scalar @{$entries{$cxix}}) {
394 return shift @{$entries{$cxix}};
397 # return undef for EOL
399 delete $entries{$cxix};
412 my $callpkg = ($sym =~ s/^GLOBAL_//s ? 'CORE::GLOBAL' : caller(0));
413 *{$callpkg.'::'.$sym} = \&{$pkg.'::'.$sym} if $sym eq 'glob';
422 File::DosGlob - DOS like globbing and then some
428 # override CORE::glob in current package
429 use File::DosGlob 'glob';
431 # override CORE::glob in ALL packages (use with extreme caution!)
432 use File::DosGlob 'GLOBAL_glob';
434 @perlfiles = glob "..\\pe?l/*.p?";
435 print <..\\pe?l/*.p?>;
437 # from the command line (overrides only in main::)
438 > perl -MFile::DosGlob=glob -e "print <../pe*/*p?>"
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.
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.
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.
463 Extending it to csh patterns is left as an exercise to the reader.
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.
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).
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.
498 - Match '\*' literally
500 escape both '\' and '*' : '\\\*'
501 double the backslashes : '\\\\\\*'
503 (Internally, the glob routine sees a '\\\*', which means that both '\' and
507 - Match '\' literally, treat '*' as metachar
509 escape '\' but not '*' : '\\*'
510 double the backslashes : '\\\\*'
512 (Internally, the glob routine sees a '\\*', which means that '\' is escaped and
515 Note that you also have to quote literal spaces in the glob pattern, as described
520 =head1 EXPORTS (by request only)
526 Should probably be built into the core, and needs to stop
527 pandering to DOS habits. Needs a dose of optimizium too.
531 Gurusamy Sarathy <gsar@activestate.com>
539 Support for globally overriding glob() (GSAR 3-JUN-98)
543 Scalar context, independent iterator context fixes (GSAR 15-SEP-97)
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)
553 Several cleanups prompted by lack of compatible perlglob.exe
554 under Borland (GSAR 27-MAY-97)
558 Initial version (GSAR 20-FEB-97)