📄 dosglob.pm
字号:
# _un_escape() will only be used on Mac OS (Classic):# Unescapes a list of arguments which may contain escaped # metachars '*', '?' and '\'.#sub _un_escape { foreach (@_) { s/\\([*?\\])/$1/g; } return @_;}## this can be used to override CORE::glob in a specific# package by saying C<use File::DosGlob 'glob';> in that# namespace.## context (keyed by second cxix arg provided by core)my %iter;my %entries;sub glob { my($pat,$cxix) = @_; my @pat; # glob without args defaults to $_ $pat = $_ unless defined $pat; # extract patterns if ($pat =~ /\s/) { require Text::ParseWords; @pat = Text::ParseWords::parse_line('\s+',0,$pat); } else { push @pat, $pat; } # Mike Mestnik: made to do abc{1,2,3} == abc1 abc2 abc3. # abc3 will be the original {3} (and drop the {}). # abc1 abc2 will be put in @appendpat. # This was just the esiest way, not nearly the best. REHASH: { my @appendpat = (); for (@pat) { # There must be a "," I.E. abc{efg} is not what we want. while ( /^(.*)(?<!\\)\{(.*?)(?<!\\)\,.*?(?<!\\)\}(.*)$/ ) { my ($start, $match, $end) = ($1, $2, $3); #print "Got: \n\t$start\n\t$match\n\t$end\n"; my $tmp = "$start$match$end"; while ( $tmp =~ s/^(.*?)(?<!\\)\{(?:.*(?<!\\)\,)?(.*\Q$match\E.*?)(?:(?<!\\)\,.*)?(?<!\\)\}(.*)$/$1$2$3/ ) { #print "Striped: $tmp\n"; # these expanshions will be preformed by the original, # when we call REHASH. } push @appendpat, ("$tmp"); s/^\Q$start\E(?<!\\)\{\Q$match\E(?<!\\)\,/$start\{/; if ( /^\Q$start\E(?<!\\)\{(?!.*?(?<!\\)\,.*?\Q$end\E$)(.*)(?<!\\)\}\Q$end\E$/ ) { $match = $1; #print "GOT: \n\t$start\n\t$match\n\t$end\n\n"; $_ = "$start$match$end"; } } #print "Sould have "GOT" vs "Got"!\n"; #FIXME: There should be checking for this. # How or what should be done about failure is beond me. } if ( $#appendpat != -1 ) { #print "LOOP\n"; #FIXME: Max loop, no way! :") for ( @appendpat ) { push @pat, $_; } goto REHASH; } } for ( @pat ) { s/\\{/{/g; s/\\}/}/g; s/\\,/,/g; } #print join ("\n", @pat). "\n"; # 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) { if ($^O eq 'MacOS') { # first, take care of updirs and trailing colons @pat = _preprocess_pattern(@pat); # expand volume names @pat = _expand_volume(@pat); $entries{$cxix} = (@pat) ? [_un_escape( doglob_Mac(1,@pat) )] : [()]; } else { $entries{$cxix} = [doglob(1,@pat)]; } } # chuck it all out, quick or slow if (wantarray) { delete $iter{$cxix}; return @{delete $entries{$cxix}}; } else { if ($iter{$cxix} = scalar @{$entries{$cxix}}) { return shift @{$entries{$cxix}}; } else { # return undef for EOL delete $iter{$cxix}; delete $entries{$cxix}; return undef; } }}{ no strict 'refs'; sub import { my $pkg = shift; return unless @_; my $sym = shift; my $callpkg = ($sym =~ s/^GLOBAL_//s ? 'CORE::GLOBAL' : caller(0)); *{$callpkg.'::'.$sym} = \&{$pkg.'::'.$sym} if $sym eq 'glob'; }}1;__END__=head1 NAMEFile::DosGlob - DOS like globbing and then some=head1 SYNOPSIS require 5.004; # override CORE::glob in current package use File::DosGlob 'glob'; # override CORE::glob in ALL packages (use with extreme caution!) use File::DosGlob 'GLOBAL_glob'; @perlfiles = glob "..\\pe?l/*.p?"; print <..\\pe?l/*.p?>; # from the command line (overrides only in main::) > perl -MFile::DosGlob=glob -e "print <../pe*/*p?>"=head1 DESCRIPTIONA module that implements DOS-like globbing with a few enhancements.It is largely compatible with perlglob.exe (the M$ setargv.objversion) in all but one respect--it understands wildcards indirectory components.For example, C<<..\\l*b\\file/*glob.p?>> will work as expected (inthat it will find something like '..\lib\File/DosGlob.pm' alright).Note that all path components are case-insensitive, and thatbackslashes and forward slashes are both accepted, and preserved.You may have to double the backslashes if you are putting them inliterally, due to double-quotish parsing of the pattern by perl.Spaces in the argument delimit distinct patterns, soC<glob('*.exe *.dll')> globs all filenames that end in C<.exe>or C<.dll>. If you want to put in literal spaces in the globpattern, you can escape them with either double quotes, or backslashes.e.g. C<glob('c:/"Program Files"/*/*.dll')>, orC<glob('c:/Program\ Files/*/*.dll')>. The argument is tokenized usingC<Text::ParseWords::parse_line()>, so see L<Text::ParseWords> for detailsof the quoting rules used.Extending it to csh patterns is left as an exercise to the reader.=head1 NOTES=over 4=item *Mac OS (Classic) users should note a few differences. The specification of pathnames in glob patterns adheres to the usual Mac OS conventions: The path separator is a colon ':', not a slash '/' or backslash '\'. A full path always begins with a volume name. A relative pathname on Mac OS must always begin with a ':', except when specifying a file or directory name in the current working directory, where the leading colon is optional. If specifying a volume name only, a trailing ':' is required. Due to these rules, a glob like E<lt>*:E<gt> will find all mounted volumes, while a glob like E<lt>*E<gt> or E<lt>:*E<gt> will find all files and directories in the current directory.Note that updirs in the glob pattern are resolved before the matching begins,i.e. a pattern like "*HD:t?p::a*" will be matched as "*HD:a*". Note also,that a single trailing ':' in the pattern is ignored (unless it's a volumename pattern like "*HD:"), i.e. a glob like <:*:> will find both directories I<and> files (and not, as one might expect, only directories). The metachars '*', '?' and the escape char '\' are valid characters in volume, directory and file names on Mac OS. Hence, if you want to matcha '*', '?' or '\' literally, you have to escape these characters. Due to perl's quoting rules, things may get a bit complicated, when you want to match a string like '\*' literally, or when you want to match '\' literally, but treat the immediately following character '*' as metachar. So, here's a rule of thumb (applies to both single- and double-quoted strings): escape each '*' or '?' or '\' with a backslash, if you want to treat them literally, and then double each backslash and your are done. E.g. - Match '\*' literally escape both '\' and '*' : '\\\*' double the backslashes : '\\\\\\*'(Internally, the glob routine sees a '\\\*', which means that both '\' and '*' are escaped.)- Match '\' literally, treat '*' as metachar escape '\' but not '*' : '\\*' double the backslashes : '\\\\*'(Internally, the glob routine sees a '\\*', which means that '\' is escaped and '*' is not.)Note that you also have to quote literal spaces in the glob pattern, as describedabove.=back=head1 EXPORTS (by request only)glob()=head1 BUGSShould probably be built into the core, and needs to stoppandering to DOS habits. Needs a dose of optimizium too.=head1 AUTHORGurusamy Sarathy <gsar@activestate.com>=head1 HISTORY=over 4=item *Support for globally overriding glob() (GSAR 3-JUN-98)=item *Scalar context, independent iterator context fixes (GSAR 15-SEP-97)=item *A few dir-vs-file optimizations result in glob importation being10 times faster than using perlglob.exe, and using perlglob.bat isonly twice as slow as perlglob.exe (GSAR 28-MAY-97)=item *Several cleanups prompted by lack of compatible perlglob.exeunder Borland (GSAR 27-MAY-97)=item *Initial version (GSAR 20-FEB-97)=back=head1 SEE ALSOperlperlglob.batText::ParseWords=cut
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -