From 0b0e6d70fad47cd67e69fd39ca89beb755332502 Mon Sep 17 00:00:00 2001 From: Father Chrysostomos Date: Mon, 24 Oct 2011 16:03:55 -0700 Subject: [PATCH] Make File::Glob::csh_glob consisent wrt '"\ MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit File::Glob::csh_glob, which is the routine implementing Perl’s own glob function, is not consistent in its treatment of quotation marks and backslashes. It differs depending on whether there are white- space characters in the pattern both preceded and followed by non- whitespace. Without whitespace, quotation marks are treated literally and back- slashes are treated as escapes that cause metacharacters to be treated literally. So <"foo*"> looks for files with literal quotation marks in their name. With whitespace, quotation marks are treated as word delimiters, so <"foo copy*"> will find file names matching /^foo copy/. Backslash escapes are pro- cessed twice, so one has to write glob '\\\** .\\\**' to find files beginning with a literal ‘*’ or ‘.*’. But simply glob '\**' to find files beginning with ‘*’. (Note that <> is a double-quotish operator, so in <> those would have to be quadruple and double back- slashes, respectively.) There are two problems with the code: 1) Text::Parsewords is only used when there is whitespace present. It should be used also for quotation marks, too, if they exist. 2) Text::Parsewords should not be removing backslash escapes. 3) Actually, there’s a third. A final escaped space should also go through Text::ParseWords, instead of being stripped. This commit fixes both things. --- ext/File-Glob/Glob.pm | 15 ++++++++++----- ext/File-Glob/t/basic.t | 11 ++++++++++- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/ext/File-Glob/Glob.pm b/ext/File-Glob/Glob.pm index af17cff..30263d9 100644 --- a/ext/File-Glob/Glob.pm +++ b/ext/File-Glob/Glob.pm @@ -36,7 +36,7 @@ use feature 'switch'; @EXPORT_OK = (@{$EXPORT_TAGS{'glob'}}, 'csh_glob'); -$VERSION = '1.13'; +$VERSION = '1.14'; sub import { require Exporter; @@ -84,14 +84,19 @@ sub csh_glob { # extract patterns $pat =~ s/^\s+//; # Protect against empty elements in - $pat =~ s/\s+$//; # things like < *.c> and <*.c >. - # These alone shouldn't trigger ParseWords. - if ($pat =~ /\s/) { + # things like < *.c>, which alone + # shouldn't trigger ParseWords. Patterns + # with a trailing space must be passed + # to ParseWords, in case it is escaped, + # as in <\ >. + if ($pat =~ /[\s"']/) { # XXX this is needed for compatibility with the csh # implementation in Perl. Need to support a flag # to disable this behavior. require Text::ParseWords; - @pat = Text::ParseWords::parse_line('\s+',0,$pat); + for (@pat = Text::ParseWords::parse_line('\s+',1,$pat)) { + s/^['"]// and chop; + } } # assume global context if not provided one diff --git a/ext/File-Glob/t/basic.t b/ext/File-Glob/t/basic.t index c40b1d5..bdf0d94 100644 --- a/ext/File-Glob/t/basic.t +++ b/ext/File-Glob/t/basic.t @@ -10,7 +10,7 @@ BEGIN { } } use strict; -use Test::More tests => 18; +use Test::More tests => 23; BEGIN {use_ok('File::Glob', ':glob')}; use Cwd (); @@ -233,3 +233,12 @@ pass("Don't panic"); # This used to segfault. my $i = bsd_glob('*', GLOB_ALTDIRFUNC); is(&File::Glob::GLOB_ERROR, 0, "Successfuly ignored unsupported flag"); + +package frimpy; # get away from the glob override, so we can test csh_glob, +use Test::More; # which is perl's default + +is +(glob "a'b'")[0], ()[0], "a'b' with and without spaces"; +is +()[0], ()[0], 'a"b" with and without spaces'; +is <\\*>, '*', 'backslashes without spaces'; +is_deeply [sort <\\* .\\*>], [sort qw<* .*>], 'backslashes with spaces'; +is <\\ >, ' ', 'final escaped space'; -- 2.7.4