summary refs log tree commit diff
diff options
context:
space:
mode:
authorPeter Stephenson <pws@zsh.org>2016-11-15 18:01:32 +0000
committerPeter Stephenson <pws@zsh.org>2016-11-15 18:01:32 +0000
commit921b39ac6b25dbfcc477fc7db4ed1c5c3ffb778c (patch)
tree47a0b6481316082d3899ad190e444db0d89e698d
parente9dbfa8046e0da6dbb37340df9d3c95f410a713b (diff)
downloadzsh-921b39ac6b25dbfcc477fc7db4ed1c5c3ffb778c.tar.gz
zsh-921b39ac6b25dbfcc477fc7db4ed1c5c3ffb778c.tar.xz
zsh-921b39ac6b25dbfcc477fc7db4ed1c5c3ffb778c.zip
39949: Special case for "-" in directory names.
It can be sh-tokenized to Dash to allow for appearing in ranges
after substitution, so needs to be turned back to "-" in that case.
-rw-r--r--ChangeLog4
-rw-r--r--Src/subst.c16
-rw-r--r--Src/utils.c70
-rw-r--r--Test/B09hash.ztst8
4 files changed, 59 insertions, 39 deletions
diff --git a/ChangeLog b/ChangeLog
index 885777e37..0040c2367 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,9 @@
 2016-11-15  Peter Stephenson  <p.stephenson@samsung.com>
 
+	* 39949: Src/subst.c, Src/utils.c, Test/B09hash.ztst: "-" is
+	allowed in named directories, so needs a special case when
+	sh-tokenized for possible ranges.
+
 	* 39947: Test/D04parameter.ztst: Test out-of-rantge multiple
 	array subscripts with and without (@).
 
diff --git a/Src/subst.c b/Src/subst.c
index 447177409..c7c552257 100644
--- a/Src/subst.c
+++ b/Src/subst.c
@@ -684,19 +684,19 @@ filesubstr(char **namptr, int assign)
 	    *namptr = dyncat(ds, ptr);
 	    return 1;
 	} else if ((ptr = itype_end(str+1, IUSER, 0)) != str+1) {   /* ~foo */
-	    char *hom, save;
+	    char *untok, *hom;
 
-	    save = *ptr;
-	    if (!isend(save))
+	    if (!isend(*ptr))
 		return 0;
-	    *ptr = 0;
-	    if (!(hom = getnameddir(++str))) {
+	    untok = dupstring(++str);
+	    untok[ptr-str] = 0;
+	    untokenize(untok);
+
+	    if (!(hom = getnameddir(untok))) {
 		if (isset(NOMATCH) && isset(EXECOPT))
-		    zerr("no such user or named directory: %s", str);
-		*ptr = save;
+		    zerr("no such user or named directory: %s", untok);
 		return 0;
 	    }
-	    *ptr = save;
 	    *namptr = dyncat(hom, ptr);
 	    return 1;
 	}
diff --git a/Src/utils.c b/Src/utils.c
index cceaf4c57..92d831172 100644
--- a/Src/utils.c
+++ b/Src/utils.c
@@ -3959,7 +3959,7 @@ inittyptab(void)
 #endif
     /* typtab['.'] |= IIDENT; */ /* Allow '.' in variable names - broken */
     typtab['_'] = IIDENT | IUSER;
-    typtab['-'] = typtab['.'] = IUSER;
+    typtab['-'] = typtab['.'] = typtab[STOUC(Dash)] = IUSER;
     typtab[' '] |= IBLANK | INBLANK;
     typtab['\t'] |= IBLANK | INBLANK;
     typtab['\n'] |= INBLANK;
@@ -4157,42 +4157,50 @@ itype_end(const char *ptr, int itype, int once)
 	(itype != IIDENT || !isset(POSIXIDENTIFIERS))) {
 	mb_charinit();
 	while (*ptr) {
-	    wint_t wc;
-	    int len = mb_metacharlenconv(ptr, &wc);
-
-	    if (!len)
-		break;
-
-	    if (wc == WEOF) {
-		/* invalid, treat as single character */
-		int chr = STOUC(*ptr == Meta ? ptr[1] ^ 32 : *ptr);
-		/* in this case non-ASCII characters can't match */
-		if (chr > 127 || !zistype(chr,itype))
-		    break;
-	    } else if (len == 1 && isascii(*ptr)) {
-		/* ASCII: can't be metafied, use standard test */
+	    int len;
+	    if (itok(*ptr)) {
+		/* Not untokenised yet --- can happen in raw command line */
+		len = 1;
 		if (!zistype(*ptr,itype))
 		    break;
 	    } else {
-		/*
-		 * Valid non-ASCII character.
-		 */
-		switch (itype) {
-		case IWORD:
-		    if (!iswalnum(wc) &&
-			!wmemchr(wordchars_wide.chars, wc,
-				 wordchars_wide.len))
-			return (char *)ptr;
-		    break;
+		wint_t wc;
+		len = mb_metacharlenconv(ptr, &wc);
 
-		case ISEP:
-		    if (!wmemchr(ifs_wide.chars, wc, ifs_wide.len))
-			return (char *)ptr;
+		if (!len)
 		    break;
 
-		default:
-		    if (!iswalnum(wc))
-			return (char *)ptr;
+		if (wc == WEOF) {
+		    /* invalid, treat as single character */
+		    int chr = STOUC(*ptr == Meta ? ptr[1] ^ 32 : *ptr);
+		    /* in this case non-ASCII characters can't match */
+		    if (chr > 127 || !zistype(chr,itype))
+			break;
+		} else if (len == 1 && isascii(*ptr)) {
+		    /* ASCII: can't be metafied, use standard test */
+		    if (!zistype(*ptr,itype))
+			break;
+		} else {
+		    /*
+		     * Valid non-ASCII character.
+		     */
+		    switch (itype) {
+		    case IWORD:
+			if (!iswalnum(wc) &&
+			    !wmemchr(wordchars_wide.chars, wc,
+				     wordchars_wide.len))
+			    return (char *)ptr;
+			break;
+
+		    case ISEP:
+			if (!wmemchr(ifs_wide.chars, wc, ifs_wide.len))
+			    return (char *)ptr;
+			break;
+
+		    default:
+			if (!iswalnum(wc))
+			    return (char *)ptr;
+		    }
 		}
 	    }
 	    ptr += len;
diff --git a/Test/B09hash.ztst b/Test/B09hash.ztst
index 49f304838..7b5dfb43e 100644
--- a/Test/B09hash.ztst
+++ b/Test/B09hash.ztst
@@ -69,3 +69,11 @@
 >one=/first/directory
 >two=/directory/the/second
 >three=/noch/ein/verzeichnis
+
+  hash -d t-t=/foo
+  i="~t-t"
+  print ~t-t/bar
+  print ${~i}/rab
+0:Dashes are untokenized in directory hash names
+>/foo/bar
+>/foo/rab