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

Re: globbing in conditional expressions



On Fri, 30 May 2014 08:55:42 -0700
Bart Schaefer <schaefer@xxxxxxxxxxxxxxxx> wrote:
> On May 30,  9:47am, Peter Stephenson wrote:
> } But this is specific to zsh --- why are we using [ rather than [[ anyway?
> 
> Because [[ ]] doesn't do globbing on its arguments, and this is a
> filename generation rather than a pattern.  We messed around a few weeks
> ago with trying to make [[ ]] do globbing and ran into tokenization
> conflicts.

(Moved this to workers.  No user serviceable parts here.)

Oh, er, right... you make it sound as if knowing what's going on is
somehow a positive thing.

One thing we could do is make [[ ... = ... ]] expand its right hand
argument the same way as normal command arguments when told to do so, so
there's no retokenization.  (There's no point for [ ] since the globbing
has already happened.)  Then we could simply join the arguments
resulting from the glob --- there may just be one, but we shouldn't
simply ignore multuple results.

We wouldn't want this always to happen, since that's confusing, but we
could signal it, for example, using the extended glob syntax (#q), which
explicitly indicates a glob pattern --- it has no meaning at all in
non-glob pattern matching.  This would limit it's use to when extended
globbing is on, but I think that's an entirely sensible limitation
anyway.

I think this patch does roughly the right thing.

So, for example, in the zsh Src directory

[[ "glob.c glob.o" = g*.?(#q) ]]

is true.  Of course you can have other qualifiers such as NY after the
#q.

Piecing together the various sorts of expansion from execmd() isn't
trivial --- it's quite likely I've missed some subtlety, possibly not
even very subtle, in the first hunk below.

diff --git a/Functions/Zle/expand-absolute-path b/Functions/Zle/expand-absolute-path
index b857576..a420d41 100644
--- a/Src/cond.c
+++ b/Src/cond.c
@@ -282,9 +282,20 @@ evalcond(Estate state, char *fromtest)
 
 		right = dupstring(opat = ecrawstr(state->prog, state->pc,
 						  &htok));
-		if (htok)
-		    singsub(&right);
+		if (htok) { 
+		    if (!fromtest &&
+			checkglobqual(right, strlen(right), 1, NULL)) {
+			LinkList args = newlinklist();
+			addlinknode(args, right);
+			prefork(args, 0);
+			while (!errflag && args && nonempty(args) &&
+			       has_token((char *)peekfirst(args)))
+			    zglob(args, firstnode(args), 0);
+			right = sepjoin(hlinklist2array(args, 0), NULL, 1);
+		    } else
+			singsub(&right);
+		}
 		save = (!(state->prog->flags & EF_HEAP) &&
    
    char *s = *sp; 			!strcmp(opat, right) && pprog != dummy_patprog2);
 
diff --git a/Src/glob.c b/Src/glob.c
index 07dd7c2..01f8a6e 100644
--- a/Src/glob.c
+++ b/Src/glob.c
@@ -1061,6 +1061,65 @@ insert_glob_match(LinkList list, LinkNode next, char *data)
     insertlinknode(list, next, data);
 }
 
+/*
+ * Return
+ *   1 if str ends in bare glob qualifiers
+ *   2 if str ends in non-bare glob qualifiers (#q)
+ *   0 otherwise.
+ *
+ * str is the string to check.
+ * sl is it's length (to avoid recalculation).
+ * nobareglob is 1 if bare glob qualifiers are not allowed.
+ * *sp, if sp is not null, wil be a pointer to the start parentheses.
+ */
+
+/**/
+int
+checkglobqual(char *str, int sl, int nobareglob, char **sp)
+{
+    char *s;
+    int paren, ret = 1;
+
+    if (str[sl - 1] != Outpar)
+	return 0;
+
+    /* Check these are really qualifiers, not a set of *
+     * alternatives or exclusions.  We can be more     *
+     * lenient with an explicit (#q) than with a bare  *
+     * set of qualifiers.                              */
+    paren = 0;
+    for (s = str + sl - 2; *s && (*s != Inpar || paren); s--) {
+	switch (*s) {
+	case Outpar:
+	    paren++; /*FALLTHROUGH*/
+	case Bar:
+	    if (!zpc_disables[ZPC_BAR])
+		nobareglob = 1;
+	    break;
+	case Tilde:
+	    if (isset(EXTENDEDGLOB) && !zpc_disables[ZPC_TILDE])
+		nobareglob = 1;
+	    break;
+	case Inpar:
+	    paren--;
+	    break;
+	}
+    }
+    if (*s != Inpar)
+	return 0;
+    if (isset(EXTENDEDGLOB) && !zpc_disables[ZPC_HASH] && s[1] == Pound) {
+	if (s[2] != 'q')
+	    return 0;
+	ret = 2;
+    } else if (nobareglob)
+	return 0;
+
+    if (sp)
+	*sp = s;
+
+    return ret;
+}
+
 /* Main entry point to the globbing code for filename globbing. *
  * np points to a node in the list list which will be expanded  *
  * into a series of nodes.                                      */
@@ -1118,7 +1177,7 @@ zglob(LinkList list, LinkNode np, int nountok)
 	   (isset(EXTENDEDGLOB) && !zpc_disables[ZPC_HASH])) {
 	struct qual *newquals;
 	char *s;
-	int sense, paren;
+	int sense, qualsfound;
 	off_t data;
 	char *sdata, *newcolonmod;
 	int (*func) _((char *, Statptr, off_t, char *));
@@ -1148,40 +1207,7 @@ zglob(LinkList list, LinkNode np, int nountok)
 	newquals = qo = qn = ql = NULL;
 
 	sl = strlen(str);
-	if (str[sl - 1] != Outpar)
-	    break;
-
-	/* Check these are really qualifiers, not a set of *
-	 * alternatives or exclusions.  We can be more     *
-	 * lenient with an explicit (#q) than with a bare  *
-	 * set of qualifiers.                              */
-	paren = 0;
-	for (s = str + sl - 2; *s && (*s != Inpar || paren); s--) {
-	    switch (*s) {
-	    case Outpar:
-		paren++; /*FALLTHROUGH*/
-	    case Bar:
-		if (!zpc_disables[ZPC_BAR])
-		    nobareglob = 1;
-		break;
-	    case Tilde:
-		if (isset(EXTENDEDGLOB) && !zpc_disables[ZPC_TILDE])
-		    nobareglob = 1;
-		break;
-	    case Inpar:
-		paren--;
-		break;
-	    }
-	}
-	if (*s != Inpar)
-	    break;
-	if (isset(EXTENDEDGLOB) && !zpc_disables[ZPC_HASH] && s[1] == Pound) {
-	    if (s[2] == 'q') {
-		*s = 0;
-		s += 2;
-	    } else
-		break;
-	} else if (nobareglob)
+	if (!(qualsfound = checkglobqual(str, sl, nobareglob, &s)))
 	    break;
 
 	/* Real qualifiers found. */
@@ -1194,6 +1220,8 @@ zglob(LinkList list, LinkNode np, int nountok)
 
 	str[sl-1] = 0;
 	*s++ = 0;
+	if (qualsfound == 2)
+	    s += 2;
 	while (*s && !newcolonmod) {
 	    func = (int (*) _((char *, Statptr, off_t, char *)))0;
 	    if (idigit(*s)) {

-- 
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