From 6269db883ad6989a578bac299deab9c4285bb1df Mon Sep 17 00:00:00 2001
From: Peter Stephenson
Date: Sun, 10 May 2015 19:19:34 +0100
Subject: [PATCH] 35067: Add (b) parameter flag for pattern char backslashing.
Doc tweak from Daniel in 35071.
Includes test.
---
ChangeLog | 7 +++++++
Doc/Zsh/expn.yo | 19 +++++++++++++++++++
Src/subst.c | 13 +++++++++++--
Src/utils.c | 23 +++++++++++++++++++----
Src/zsh.h | 10 ++++++++++
Src/ztype.h | 2 ++
Test/D04parameter.ztst | 4 ++++
7 files changed, 72 insertions(+), 6 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 7c2b62990..5563797ba 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2015-05-10 Peter Stephenson
+
+ * 35067 (doc tweak from Daniel, 35071): Doc/Zsh/expn.yo,
+ Src/subst.c, Src/utils.c, Src/zsh.h, Src/ztype.h,
+ Test/D04parameter.ztst: add ${(b)foo} for backslash
+ quoting of patterns.
+
2015-05-10 Mikael Magnusson
* 35065: Src/zsh.h: Don't treat NUL as a combining character
diff --git a/Doc/Zsh/expn.yo b/Doc/Zsh/expn.yo
index 85191edeb..8e5ab4bfd 100644
--- a/Doc/Zsh/expn.yo
+++ b/Doc/Zsh/expn.yo
@@ -1014,6 +1014,25 @@ form of single quoting is used that only quotes the string if needed to
protect special characters. Typically this form gives the most readable
output.
)
+item(tt(b))(
+Quote with backslashes only characters that are special to pattern
+matching. This is useful when the contents of the variable are to be
+tested using tt(GLOB_SUBST), including the tt(${~)var(...)tt(}) switch.
+
+Quoting using one of the tt(q) family of flags does not work
+for this purpose since quotes are not stripped from non-pattern
+characters by tt(GLOB_SUBST). In other words,
+
+example(pattern=${(q)str}
+[[ $str = ${~pattern} ]])
+
+works if tt($str) is tt('a*b') but not if it is tt('a b'), whereas
+
+example(pattern=${(b)str}
+[[ $str = ${~pattern} ]])
+
+is always true for any possible value of tt($str).
+)
item(tt(Q))(
Remove one level of quotes from the resulting words.
)
diff --git a/Src/subst.c b/Src/subst.c
index f52bcdfc8..bf80495bd 100644
--- a/Src/subst.c
+++ b/Src/subst.c
@@ -1592,7 +1592,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags)
/* combination of (L), (U) and (C) flags. */
int casmod = CASMOD_NONE;
/*
- * quotemod says we are doing either (q) (positive), (Q) (negative)
+ * quotemod says we are doing either (q/b) (positive), (Q) (negative)
* or not (0). quotetype counts the q's for the first case.
* quoterr is simply (X) but gets passed around a lot because the
* combination (eX) needs it.
@@ -1861,6 +1861,12 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags)
quotemod++, quotetype++;
}
break;
+ case 'b':
+ if (quotemod || quotetype != QT_NONE)
+ goto flagerr;
+ quotemod = 1;
+ quotetype = QT_BACKSLASH_PATTERN;
+ break;
case 'Q':
quotemod--;
break;
@@ -3460,7 +3466,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags)
if (quotemod) {
int pre = 0, post = 0;
- if (quotemod > 0 && quotetype > QT_BACKSLASH) {
+ if (quotemod > 0) {
switch (quotetype)
{
case QT_DOLLARS:
@@ -3471,6 +3477,9 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags)
case QT_SINGLE_OPTIONAL:
/* quotes will be added for us */
+ case QT_BACKSLASH:
+ case QT_BACKSLASH_PATTERN:
+ /* no quotes */
break;
default:
diff --git a/Src/utils.c b/Src/utils.c
index 13d4b83d4..271c800fd 100644
--- a/Src/utils.c
+++ b/Src/utils.c
@@ -3694,6 +3694,8 @@ inittyptab(void)
typtab[bangchar] |= ISPECIAL;
} else
typtab_flags &= ~ZTF_BANGCHAR;
+ for (s = PATCHARS; *s; s++)
+ typtab[STOUC(*s)] |= IPATTERN;
unqueue_signals();
}
@@ -5075,6 +5077,10 @@ quotestring(const char *s, char **e, int instring)
alloclen = slen * 7 + 1;
break;
+ case QT_BACKSLASH_PATTERN:
+ alloclen = slen * 2 + 1;
+ break;
+
case QT_SINGLE_OPTIONAL:
/*
* Here, we may need to add single quotes.
@@ -5094,7 +5100,7 @@ quotestring(const char *s, char **e, int instring)
quotestart = v = buf = zshcalloc(alloclen);
DPUTS(instring < QT_BACKSLASH || instring == QT_BACKTICK ||
- instring > QT_SINGLE_OPTIONAL,
+ instring > QT_BACKSLASH_PATTERN,
"BUG: bad quote type in quotestring");
u = s;
if (instring == QT_DOLLARS) {
@@ -5134,9 +5140,18 @@ quotestring(const char *s, char **e, int instring)
u = uend;
}
}
- }
- else
- {
+ } else if (instring == QT_BACKSLASH_PATTERN) {
+ while (*u) {
+ if (e && !sf && *e == u) {
+ *e = v;
+ sf = 1;
+ }
+
+ if (ipattern(*u))
+ *v++ = '\\';
+ *v++ = *u++;
+ }
+ } else {
if (shownull) {
/* We can't show an empty string with just backslash quoting. */
if (!*u) {
diff --git a/Src/zsh.h b/Src/zsh.h
index bb52e106d..b2ab1dfae 100644
--- a/Src/zsh.h
+++ b/Src/zsh.h
@@ -215,6 +215,10 @@ struct mathfunc {
#define SPECCHARS "#$^*()=|{}[]`<>?~;&\n\t \\\'\""
+/* chars that need to be quoted for pattern matching */
+
+#define PATCHARS "#^*()|[]<>?~"
+
/*
* Types of quote. This is used in various places, so care needs
* to be taken when changing them. (Oooh, don't you look surprised.)
@@ -248,6 +252,12 @@ enum {
* This is only useful as an argument to quotestring().
*/
QT_SINGLE_OPTIONAL,
+ /*
+ * Only quote pattern characters.
+ * ${(b)foo} guarantees that ${~foo} matches the string
+ * contained in foo.
+ */
+ QT_BACKSLASH_PATTERN,
/*
* As QT_BACKSLASH, but a NULL string is shown as ''.
*/
diff --git a/Src/ztype.h b/Src/ztype.h
index b73e3f840..76589b152 100644
--- a/Src/ztype.h
+++ b/Src/ztype.h
@@ -42,6 +42,7 @@
#define IMETA (1 << 12)
#define IWSEP (1 << 13)
#define INULL (1 << 14)
+#define IPATTERN (1 << 15)
#define zistype(X,Y) (typtab[STOUC(X)] & Y)
#define idigit(X) zistype(X,IDIGIT)
#define ialnum(X) zistype(X,IALNUM)
@@ -58,6 +59,7 @@
#define imeta(X) zistype(X,IMETA)
#define iwsep(X) zistype(X,IWSEP)
#define inull(X) zistype(X,INULL)
+#define ipattern(X) zistype(X,IPATTERN)
/*
* Bit flags for typtab_flags --- preserved after
diff --git a/Test/D04parameter.ztst b/Test/D04parameter.ztst
index 42c7b4ec6..17a59cb2c 100644
--- a/Test/D04parameter.ztst
+++ b/Test/D04parameter.ztst
@@ -1699,3 +1699,7 @@
>
>
>Four
+
+ funnychars='The qu*nk br!wan f@x j/mps o[]r the la~# ^"&;'
+ [[ $funnychars = ${~${(b)funnychars}} ]]
+0:${(b)...} quoting protects from GLOB_SUBST