diff options
author | Father Chrysostomos <sprout@cpan.org> | 2011-10-27 14:26:15 -0700 |
---|---|---|
committer | Father Chrysostomos <sprout@cpan.org> | 2011-10-27 14:26:15 -0700 |
commit | e1621fc96189270d9aa78c1f2dbc2200bd15cb59 (patch) | |
tree | c5666a57d92aac8fc7c438919f7cfdaf99e35524 /ext | |
parent | 040ac26489d0fa56b9bc1e898067e86d17ad5255 (diff) | |
download | perl-e1621fc96189270d9aa78c1f2dbc2200bd15cb59.tar.gz |
Make csh_glob remove quote-escaping backslashes
This commit does not change the output on Unix. On Windows, where the
globbing engine does not usually treat backslashes as escapes, this
restores the behaviour to what it was before commit 0b0e6d70, for
cases like glob('a\"b c\"d').
Before 0b0e6d70, the preprocessing done by csh_glob (which it out-
sourced to Text::ParseWords) would remove backslash escapes, so the
globbing engine got to see a"b and c"d.
Since 0b0e6d70, the backslash escapes were no longer removed (because
in most cases they needed to remain, to avoid backslashitis), so the
globbing engine got to see a\"b and c\"d. On Unix that made no dif-
ference, as the globbing engine treats \ as an escape character. But
on Windows it doesn’t usually, so the output changed and produced a
literal a\"b.
This commit strips out quote-escaping backslashes in the prepro-
cessing code.
Diffstat (limited to 'ext')
-rw-r--r-- | ext/File-Glob/Glob.xs | 26 | ||||
-rw-r--r-- | ext/File-Glob/t/basic.t | 6 |
2 files changed, 28 insertions, 4 deletions
diff --git a/ext/File-Glob/Glob.xs b/ext/File-Glob/Glob.xs index 9d35ac215c..c055d1ba2f 100644 --- a/ext/File-Glob/Glob.xs +++ b/ext/File-Glob/Glob.xs @@ -125,6 +125,7 @@ csh_glob(pTHX) case '"' : { bool found = FALSE; + const char quote = *s; if (!word) { word = newSVpvs(""); if (is_utf8) SvUTF8_on(word); @@ -132,8 +133,14 @@ csh_glob(pTHX) if (piece) sv_catpvn(word, piece, s-piece); piece = s+1; while (++s <= patend) - if (*s == '\\') s++; - else if (*s == *(piece-1)) { + if (*s == '\\') { + s++; + /* If the backslash is here to escape a quote, + obliterate it. */ + if (s < patend && *s == quote) + sv_catpvn(word, piece, s-piece-1), piece = s; + } + else if (*s == quote) { sv_catpvn(word, piece, s-piece); piece = NULL; found = TRUE; @@ -164,7 +171,20 @@ csh_glob(pTHX) } break; } - case '\\': if (!piece) piece = s; s++; break; + case '\\': + if (!piece) piece = s; + s++; + /* If the backslash is here to escape a quote, + obliterate it. */ + if (s < patend && (*s == '"' || *s == '\'')) { + if (!word) { + word = newSVpvn(piece,s-piece-1); + if (is_utf8) SvUTF8_on(word); + } + else sv_catpvn(word, piece, s-piece-1); + piece = s; + } + break; default: if (isSPACE(*s)) { if (piece) { diff --git a/ext/File-Glob/t/basic.t b/ext/File-Glob/t/basic.t index 309e2bb456..df2b958e65 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 => 25; +use Test::More tests => 29; BEGIN {use_ok('File::Glob', ':glob')}; use Cwd (); @@ -248,3 +248,7 @@ is_deeply [<\\* .\\*>], [<\\*>,<.\\*>], 'backslashes with(out) spaces'; like <\\ >, qr/^\\? \z/, 'final escaped space'; is <a"b>, 'a"b', 'unmatched quote'; is < a"b >, 'a"b', 'unmatched quote with surrounding spaces'; +is glob('a\"b'), 'a"b', '\ before quote *only* escapes quote'; +is glob(q"a\'b"), "a'b", '\ before single quote *only* escapes quote'; +is glob('"a\"b c\"d"'), 'a"b c"d', 'before \" within "..."'; +is glob(q"'a\'b c\'d'"), "a'b c'd", q"before \' within '...'"; |