Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Re: Set operations



On Sat, 27 Sep 2008 02:02:25 -0700
Phil Pennock <zsh-workers+phil.pennock@xxxxxxxxxxxx> wrote:
> So given 'b' naming the set variable with the elements to remove, I do a
> first pass approximation like this:
> 
> safesub=("${(@)${(@)${(@)${(P@)b//\\/\\\\}//\|/\\|}//\?/\\?}//\*/\\*}")
> 
> instead of just, for set subtraction of b from a:
> 
>   "${(P@)a:#${(Pj,|,)~b}}"

I appreciate there's a problem here, but I'm a little bit lost as to
what exactly you're after.  Do you mean you'd like the "|" in the (j,|,)
to be treated as a pattern character, but the characters substituted
from the paramater named by b not to be expanded?

I *think*, in that case, the right thing to do might be a flag to cause
the argument to j to be tokenized, rather than forcing the substitution
of b to be quoted, since this is much simpler.  Currently, I don't think
we have any code that will quote a string so that future token expansion
will leave it as it was at the start.  (We do do this with quoting, but
it's not the same thing---we're in too deep here for quoting and
unquoting to be useful.)

An obvious way to do this would be to allow '~' in the parentheses to
have that meaning.  It's easier to do this if that '~' only applies to
arguments to its right, which I think is natural (and is true of the
current (p) flag, although this doesn't seem to be documented).  So, if
I'm following, you want

   "${(P@)a:#${(P~j,|,)b}"

If I'm not following, you may want white chococlate mousse followed by a
cappuccino.

Anyway, I'm not sure why I didn't do this ages ago, it makes testing
lists of alternatives vastly easier.

I've also achieved a long-standing ambition of editing out a pointless
and ugly macro.

Index: Doc/Zsh/expn.yo
===================================================================
RCS file: /cvsroot/zsh/zsh/Doc/Zsh/expn.yo,v
retrieving revision 1.93
diff -u -r1.93 expn.yo
--- Doc/Zsh/expn.yo	27 Sep 2008 19:57:33 -0000	1.93
+++ Doc/Zsh/expn.yo	27 Sep 2008 20:46:18 -0000
@@ -910,7 +910,19 @@
 startitem()
 item(tt(p))(
 Recognize the same escape sequences as the tt(print) builtin
-in string arguments to any of the flags described below.
+in string arguments to any of the flags described below that
+follow this argument.
+)
+item(tt(~))(
+Force string arguments to any of the flags below that follow within
+the parentheses to be treated as patterns.  Compare with a tt(~)
+outside parentheses, which forces the entire substituted string to
+be treated as a pattern.  Hence, for example,
+example([[ "?" = ${(~j.|.)array} ]])
+with the tt(EXTENDED_GLOB) option set succeeds if and only if tt($array)
+contains the string `tt(?)' as an element.  The argument may be
+repeated to toggle the behaviour; its effect only lasts to the
+end of the parenthesised group.
 )
 item(tt(j:)var(string)tt(:))(
 Join the words of arrays together using var(string) as a separator.
Index: Src/subst.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/subst.c,v
retrieving revision 1.88
diff -u -r1.88 subst.c
--- Src/subst.c	27 Sep 2008 19:57:33 -0000	1.88
+++ Src/subst.c	27 Sep 2008 20:46:20 -0000
@@ -1232,6 +1232,22 @@
     return metafy(ptr, len, META_USEHEAP);
 }
 
+static char *
+untok_and_escape(char *s, int escapes, int tok_arg)
+{
+    int klen;
+    char *dst;
+
+    untokenize(dst = dupstring(s));
+    if (escapes) {
+	dst = getkeystring(dst, &klen, GETKEYS_SEP, NULL);
+	dst = metafy(dst, klen, META_HREALLOC);
+    }
+    if (tok_arg)
+	shtokenize(dst);
+    return dst;
+}
+
 /* parameter substitution */
 
 #define	isstring(c) ((c) == '$' || (char)(c) == String || (char)(c) == Qstring)
@@ -1501,23 +1517,16 @@
 	    int tt = 0;
 	    zlong num;
 	    /*
-	     * The (p) flag is (uniquely) only remembered within
+	     * The (p) flag is only remembered within
 	     * this block.  It says we do print-style handling
 	     * on the values for flags, but only on those.
-	     * This explains the ghastly macro, but why can't it
-	     * be a function?  UNTOK_AND_ESCAPE is defined
-	     * so that the argument must be an lvalue.
 	     */
 	    int escapes = 0;
-	    int klen;
-#define UNTOK(C)  (itok(C) ? ztokens[(C) - Pound] : (C))
-#define UNTOK_AND_ESCAPE(X, S) {\
-		untokenize(X = dupstring(S));\
-		if (escapes) {\
-		    X = getkeystring(X, &klen, GETKEYS_SEP, NULL);\
-		    X = metafy(X, klen, META_HREALLOC);\
-		}\
-	    }
+	    /*
+	     * '~' in parentheses caused tokenization of string arg:
+	     * similar to (p).
+	     */
+	    int tok_arg = 0;
 
 	    for (s++; (c = *s) != ')' && c != Outpar; s++, tt = 0) {
 		int arglen;	/* length of modifier argument */
@@ -1528,6 +1537,10 @@
 		case ')':
 		case Outpar:
 		    break;
+		case '~':
+		case Tilde:
+		    tok_arg = !tok_arg;
+		    break;
 		case 'A':
 		    ++arrasg;
 		    break;
@@ -1642,9 +1655,11 @@
 			sav = *t;
 			*t = '\0';
 			if (tt)
-			    UNTOK_AND_ESCAPE(spsep, s + arglen)
+			    spsep = untok_and_escape(s + arglen,
+						     escapes, tok_arg);
 			else
-			    UNTOK_AND_ESCAPE(sep, s + arglen)
+			    sep = untok_and_escape(s + arglen,
+						   escapes, tok_arg);
 			*t = sav;
 			s = t + arglen - 1;
 		    } else
@@ -1677,9 +1692,11 @@
 		    sav = *t;
 		    *t = '\0';
 		    if (tt)
-			UNTOK_AND_ESCAPE(premul, s + arglen)
+			premul = untok_and_escape(s + arglen, escapes,
+						  tok_arg);
 		    else
-			UNTOK_AND_ESCAPE(postmul, s + arglen)
+			postmul = untok_and_escape(s + arglen, escapes,
+						   tok_arg);
 		    *t = sav;
 		    sav = *s;
 		    s = t + arglen;
@@ -1695,9 +1712,11 @@
 		    sav = *t;
 		    *t = '\0';
 		    if (tt)
-			UNTOK_AND_ESCAPE(preone, s + arglen)
+			preone = untok_and_escape(s + arglen,
+						  escapes, tok_arg);
 		    else
-			UNTOK_AND_ESCAPE(postone, s + arglen)
+			postone = untok_and_escape(s + arglen,
+						   escapes, tok_arg);
 		    *t = sav;
 		    /* -1 since loop will increment */
 		    s = t + arglen - 1;
Index: Test/D04parameter.ztst
===================================================================
RCS file: /cvsroot/zsh/zsh/Test/D04parameter.ztst,v
retrieving revision 1.34
diff -u -r1.34 D04parameter.ztst
--- Test/D04parameter.ztst	5 Sep 2008 21:02:16 -0000	1.34
+++ Test/D04parameter.ztst	27 Sep 2008 20:46:20 -0000
@@ -1,4 +1,5 @@
 # Test parameter expansion.  Phew.
+# (By the way, did I say "phew"?)
 
 %prep
 
@@ -1062,3 +1063,26 @@
 >1
 >1
 >1
+
+  foo=("|" "?")
+  [[ "|" = ${(j.|.)foo} ]] && print yes || print no
+  [[ "|" = ${(j.|.)~foo} ]] && print yes || print no
+  [[ "|" = ${(~j.|.)foo} ]] && print yes || print no
+  [[ "|" = ${(~~j.|.)foo} ]] && print yes || print no
+  [[ "|" = ${(j.|.~)foo} ]] && print yes || print no
+  [[ "x" = ${(j.|.)foo} ]] && print yes || print no
+  [[ "x" = ${(j.|.)~foo} ]] && print yes || print no
+  [[ "x" = ${(~j.|.)foo} ]] && print yes || print no
+  [[ "x" = ${(~~j.|.)foo} ]] && print yes || print no
+  [[ "x" = ${(j.|.~)foo} ]] && print yes || print no
+0:GLOBSUBST only on parameter substitution arguments
+>no
+>yes
+>yes
+>no
+>no
+>no
+>yes
+>no
+>no
+>no


-- 
Peter Stephenson <p.w.stephenson@xxxxxxxxxxxx>
Web page now at http://homepage.ntlworld.com/p.w.stephenson/



Messages sorted by: Reverse Date, Date, Thread, Author