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

PATCH: new parameter expansion type?



This is from `_arguments':

  if [[ "$def" = :* ]]; then
    opt=yes
  else
    opt=''
  fi

... the completion functions are full of these -- always making me
wish that we had some kind of ternary operator in parameter
expansions. The patch below implements this:

  ${name^pattern^then^else}

Gives you the (substituted) `then' string if the expansion of `name'
matches the `pattern' and otherwise it gives you the `else'
string. The first `^' may be doubled to negate the test. `^'s in the
`pattern' and the `then' may be quoted with two bacslashes (as in
`${../..}'). The `^else' may be omitted in which case it expands to
nothing (not even the empty string if you are using this on an array)
if the `pattern' doesn't match. Finally, the `then' and the `else' may 
be only a `.' to make them expand to the original string (needed if
used on arrays).
Ok, the `.' thingy is just because I couldn't think of a better
character/syntax (suggestions?) and this isn't as powerful as I would
like it because `then' and `else' can't expand to arrays. Maybe we
could make `${(A)foo^?^$arr1^$arr2}' do that (and maybe we could do
the same for `${(A)foo:-$arr}'.

But then, maybe you don't like this at all...

Bye
 Sven

--- os/subst.c	Sun Aug 29 20:02:43 1999
+++ Src/subst.c	Sun Aug 29 21:38:14 1999
@@ -725,6 +725,8 @@
     char *sep = NULL, *spsep = NULL;
     char *premul = NULL, *postmul = NULL, *preone = NULL, *postone = NULL;
     char *replstr = NULL;	/* replacement string for /orig/repl */
+    char *thenstr, *elsestr;    /* then and else for ${..^..^..^..} */
+    int negpat = 0;
     zlong prenum = 0, postnum = 0;
     int copied = 0;
     int arrasg = 0;
@@ -1227,7 +1229,8 @@
 		    *s == '%' ||
 		    *s == '#' || *s == Pound ||
 		    *s == '?' || *s == Quest ||
-		    *s == '/')) {
+		    *s == '/' ||
+		    *s == '^' || *s == Hat)) {
 
 	if (!flnum)
 	    flnum++;
@@ -1282,7 +1285,47 @@
 	    untokenize(replstr);
 	    *ptr = '\0';
 	}
+	if (s[-1] == '^' || s[-1] == Hat) {
+	    char *ptr = s;
 
+	    if (*s == s[-1]) {
+		s++;
+		negpat = 1;
+	    }
+	    for (ptr = s; *ptr && *ptr != '^' && *ptr != Hat; ptr++)
+		if (*ptr == '\\' && (ptr[1] == '^' || ptr[1] == Hat))
+		    chuck(ptr);
+	    if (!*ptr || !ptr[1]) {
+		zerr("missing `then' string", NULL, 0);
+		return NULL;
+	    }
+	    *ptr++ = '\0';
+	    thenstr = ptr;
+	    for (; *ptr && *ptr != '^' && *ptr != Hat; ptr++)
+		if (*ptr == '\\' && (ptr[1] == '^' || ptr[1] == Hat))
+		    chuck(ptr);
+	    if (*ptr) {
+		elsestr = ptr + 1;
+		if (elsestr[0] == '\\' && elsestr[1] == '.')
+		    elsestr++;
+		if (elsestr[0] == '.' && !elsestr[1])
+		    elsestr = (char *) 1;
+		else {
+		    singsub(&elsestr);
+		    untokenize(elsestr);
+		}
+		*ptr = '\0';
+	    } else
+		elsestr = NULL;
+	    if (thenstr[0] == '\\' && thenstr[1] == '.')
+		thenstr++;
+	    if (thenstr[0] == '.' && !thenstr[1])
+		thenstr = (char *) 1;
+	    else {
+		singsub(&thenstr);
+		untokenize(thenstr);
+	    }
+	}
 	if (colf)
 	    flags |= SUB_ALL;
 	/*
@@ -1396,6 +1439,8 @@
 	case '#':
 	case Pound:
 	case '/':
+	case '^':
+	case Hat:
 	    if (qt) {
 		int one = noerrs, oef = errflag, haserr;
 
@@ -1417,26 +1462,65 @@
 		char t = s[-1];
 
 		singsub(&s);
-		if (t == '/' && (flags & SUB_SUBSTR)) {
-		    if (*s == '#' || *s == '%') {
-			flags &= ~SUB_SUBSTR;
-			if (*s == '%')
-			    flags |= SUB_END;
-			s++;
-		    } else if (*s == '\\') {
-			s++;
+		if (t == '^' || t == Hat) {
+		    if (!vunset && isarr) {
+			char **ap, **pp;
+			Patprog pprg;
+
+			if (!(pprg = patcompile(s, PAT_STATIC, NULL))) {
+			    zerr("bad pattern: %s", s, 0);
+			    return NULL;
+			}
+			if (!copied)
+			    aval = arrdup(aval), copied = 1;
+			for (ap = pp = aval; *ap; ap++) {
+			    if ((!!pattry(pprg, *ap)) ^ negpat)
+				*pp++ = dupstring(thenstr == ((char *) 1) ?
+						  *ap : thenstr);
+			    else if (elsestr)
+				*pp++ = dupstring(elsestr == ((char *) 1) ?
+						  *ap : elsestr);
+			}
+			*pp = NULL;
+		    } else {
+			Patprog pprg;
+
+			if (vunset)
+			    val = dupstring("");
+			if ((pprg = patcompile(s, PAT_STATIC, NULL)) &&
+			    ((!!pattry(pprg, val)) ^ negpat))
+			    val = dupstring(thenstr == ((char *) 1) ?
+					    val : thenstr);
+			else if (elsestr)
+			    val = dupstring(elsestr == ((char *) 1) ?
+					    val : elsestr);
+			else {
+			    vunset = 1;
+			    val = dupstring("");
+			}
+			copied = 1;
+		    }
+		} else {
+		    if (t == '/' && (flags & SUB_SUBSTR)) {
+			if (*s == '#' || *s == '%') {
+			    flags &= ~SUB_SUBSTR;
+			    if (*s == '%')
+				flags |= SUB_END;
+			    s++;
+			} else if (*s == '\\') {
+			    s++;
+			}
+		    }
+		    if (!vunset && isarr) {
+			getmatcharr(&aval, s, flags, flnum, replstr);
+			copied = 1;
+		    } else {
+			if (vunset)
+			    val = dupstring("");
+			getmatch(&val, s, flags, flnum, replstr);
+			copied = 1;
 		    }
 		}
-	    }
-
-	    if (!vunset && isarr) {
-		getmatcharr(&aval, s, flags, flnum, replstr);
-		copied = 1;
-	    } else {
-		if (vunset)
-		    val = dupstring("");
-		getmatch(&val, s, flags, flnum, replstr);
-		copied = 1;
 	    }
 	    break;
 	}
--- od/Zsh/expn.yo	Sun Aug 29 20:02:39 1999
+++ Doc/Zsh/expn.yo	Sun Aug 29 22:00:54 1999
@@ -447,6 +447,21 @@
 while in the second case, the shortest matches are taken and the
 result is `tt(spy spy lispy star)'.
 )
+xitem(tt(${)var(name)tt(^)var(pattern)tt(^)var(then)tt(^)var(else)tt(}))
+item(tt(${)var(name)tt(^^)var(pattern)tt(^)var(then)tt(^)var(else)tt(}))(
+If the expansion of var(name) matches the var(pattern), the var(then)
+string is substituted, otherwise the var(else) string is
+substituted. In the second form the var(pattern) is taken to be
+negated (even if the tt(EXTENDED_GLOB) option is not set. The
+var(else) string with the preceding `tt(^)' may be omitted in which
+case the expansion behaves as if var(name) were unset (or, if
+var(name) is an array, as if the element compared did not exist). In
+the var(pattern) and the var(then) string a `tt(^)' may be included by 
+preceding it with two backslashes. Finally, the var(then) and
+var(else) string may consist of only a dot to make it expand to the
+original string. To make them expand to only a dot, the string
+`tt(\.)' has to be used.
+)
 item(tt(${#)var(spec)tt(}))(
 If var(spec) is one of the above substitutions, substitute
 the length in characters of the result instead of

--
Sven Wischnowsky                         wischnow@xxxxxxxxxxxxxxxxxxxxxxx



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