diff --git a/ChangeLog b/ChangeLog
index 885777e37..0040c2367 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,9 @@
2016-11-15 Peter Stephenson
+ * 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;
+ wint_t wc;
+ len = mb_metacharlenconv(ptr, &wc);
+
+ if (!len)
break;
- case ISEP:
- if (!wmemchr(ifs_wide.chars, wc, ifs_wide.len))
- return (char *)ptr;
- 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 */
+ 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;
- default:
- if (!iswalnum(wc))
- return (char *)ptr;
+ 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