about summary refs log tree commit diff
path: root/Src/utils.c
diff options
context:
space:
mode:
Diffstat (limited to 'Src/utils.c')
-rw-r--r--Src/utils.c321
1 files changed, 233 insertions, 88 deletions
diff --git a/Src/utils.c b/Src/utils.c
index 28e78c149..579ab3be8 100644
--- a/Src/utils.c
+++ b/Src/utils.c
@@ -84,7 +84,15 @@ set_widearray(char *mb_array, Widechar_array wca)
 
 	mb_charinit();
 	while (*mb_array) {
-	    int mblen = mb_metacharlenconv(mb_array, &wci);
+	    int mblen;
+
+	    if (STOUC(*mb_array) <= 0x7f) {
+		mb_array++;
+		*wcptr++ = (wchar_t)*mb_array;
+		continue;
+	    }
+
+	    mblen = mb_metacharlenconv(mb_array, &wci);
 
 	    if (!mblen)
 		break;
@@ -621,7 +629,7 @@ wcs_nicechar_sel(wchar_t c, size_t *widthp, char **swidep, int quotable)
     }
 
     s = buf;
-    if (!iswprint(c) && (c < 0x80 || !isset(PRINTEIGHTBIT))) {
+    if (!WC_ISPRINT(c) && (c < 0x80 || !isset(PRINTEIGHTBIT))) {
 	if (c == 0x7f) {
 	    if (quotable) {
 		*s++ = '\\';
@@ -726,7 +734,7 @@ wcs_nicechar(wchar_t c, size_t *widthp, char **swidep)
 /**/
 mod_export int is_wcs_nicechar(wchar_t c)
 {
-    if (!iswprint(c) && (c < 0x80 || !isset(PRINTEIGHTBIT))) {
+    if (!WC_ISPRINT(c) && (c < 0x80 || !isset(PRINTEIGHTBIT))) {
 	if (c == 0x7f || c == L'\n' || c == L'\t' || c < 0x20)
 	    return 1;
 	if (c >= 0x80) {
@@ -801,9 +809,9 @@ findpwd(char *s)
     char *t;
 
     if (*s == '/')
-	return xsymlink(s);
+	return xsymlink(s, 0);
     s = tricat((pwd[1]) ? pwd : "", "/", s);
-    t = xsymlink(s);
+    t = xsymlink(s, 0);
     zsfree(s);
     return t;
 }
@@ -837,7 +845,7 @@ ispwd(char *s)
     return 0;
 }
 
-static char xbuf[PATH_MAX*2];
+static char xbuf[PATH_MAX*2+1];
 
 /**/
 static char **
@@ -876,9 +884,9 @@ static int
 xsymlinks(char *s, int full)
 {
     char **pp, **opp;
-    char xbuf2[PATH_MAX*3], xbuf3[PATH_MAX*2];
+    char xbuf2[PATH_MAX*3+1], xbuf3[PATH_MAX*2+1];
     int t0, ret = 0;
-    zulong xbuflen = strlen(xbuf);
+    zulong xbuflen = strlen(xbuf), pplen;
 
     opp = pp = slashsplit(s);
     for (; xbuflen < sizeof(xbuf) && *pp && ret >= 0; pp++) {
@@ -899,10 +907,18 @@ xsymlinks(char *s, int full)
 	    xbuflen--;
 	    continue;
 	}
-	sprintf(xbuf2, "%s/%s", xbuf, *pp);
+	/* Includes null byte. */
+	pplen = strlen(*pp) + 1;
+	if (xbuflen + pplen + 1 > sizeof(xbuf2)) {
+	    *xbuf = 0;
+	    ret = -1;
+	    break;
+	}
+	memcpy(xbuf2, xbuf, xbuflen);
+	xbuf2[xbuflen] = '/';
+	memcpy(xbuf2 + xbuflen + 1, *pp, pplen);
 	t0 = readlink(unmeta(xbuf2), xbuf3, PATH_MAX);
 	if (t0 == -1) {
-	    zulong pplen = strlen(*pp) + 1;
 	    if ((xbuflen += pplen) < sizeof(xbuf)) {
 		strcat(xbuf, "/");
 		strcat(xbuf, *pp);
@@ -969,11 +985,13 @@ xsymlinks(char *s, int full)
 /*
  * expand symlinks in s, and remove other weird things:
  * note that this always expands symlinks.
+ *
+ * 'heap' indicates whether to malloc() or allocate on the heap.
  */
 
 /**/
 char *
-xsymlink(char *s)
+xsymlink(char *s, int heap)
 {
     if (*s != '/')
 	return NULL;
@@ -981,8 +999,8 @@ xsymlink(char *s)
     if (xsymlinks(s + 1, 1) < 0)
 	zwarn("path expansion failed, using root directory");
     if (!*xbuf)
-	return ztrdup("/");
-    return ztrdup(xbuf);
+	return heap ? dupstring("/") : ztrdup("/");
+    return heap ? dupstring(xbuf) : ztrdup(xbuf);
 }
 
 /**/
@@ -993,7 +1011,7 @@ print_if_link(char *s, int all)
 	*xbuf = '\0';
 	if (all) {
 	    char *start = s + 1;
-	    char xbuflink[PATH_MAX];
+	    char xbuflink[PATH_MAX+1];
 	    for (;;) {
 		if (xsymlinks(start, 0) > 0) {
 		    printf(" -> ");
@@ -1045,9 +1063,9 @@ substnamedir(char *s)
     Nameddir d = finddir(s);
 
     if (!d)
-	return quotestring(s, NULL, QT_BACKSLASH);
+	return quotestring(s, QT_BACKSLASH);
     return zhtricat("~", d->node.nam, quotestring(s + strlen(d->dir),
-						  NULL, QT_BACKSLASH));
+						  QT_BACKSLASH));
 }
 
 
@@ -1130,7 +1148,7 @@ finddir(char *s)
 	if(homenode.diff==1)
 	    homenode.diff = 0;
 	if(!finddir_full)
-	    finddir_full = zalloc(ffsz = PATH_MAX);
+	    finddir_full = zalloc(ffsz = PATH_MAX+1);
 	finddir_full[0] = 0;
 	return finddir_last = NULL;
     }
@@ -1157,7 +1175,7 @@ finddir(char *s)
     scanhashtable(nameddirtab, 0, 0, 0, finddir_scan, 0);
 
     ares = subst_string_by_hook("zsh_directory_name", "d", finddir_full);
-    if (ares && arrlen(ares) >= 2 &&
+    if (ares && arrlen_ge(ares, 2) &&
 	(len = (int)zstrtol(ares[1], NULL, 10)) > finddir_best) {
 	/* better duplicate this string since it's come from REPLY */
 	finddir_last = (Nameddir)hcalloc(sizeof(struct nameddir));
@@ -1220,13 +1238,13 @@ adduserdir(char *s, char *t, int flags, int always)
 	 * named directory, since these are sometimes used for
 	 * special purposes.
 	 */
-	nd->dir = ztrdup(t);
+	nd->dir = metafy(t, -1, META_DUP);
     } else
-	nd->dir = ztrduppfx(t, eptr - t);
+	nd->dir = metafy(t, eptr - t, META_DUP);
     /* The variables PWD and OLDPWD are not to be displayed as ~PWD etc. */
     if (!strcmp(s, "PWD") || !strcmp(s, "OLDPWD"))
 	nd->node.flags |= ND_NOABBREV;
-    nameddirtab->addnode(nameddirtab, ztrdup(s), nd);
+    nameddirtab->addnode(nameddirtab, metafy(s, -1, META_DUP), nd);
 }
 
 /* Get a named directory: this function can cause a directory name *
@@ -1260,7 +1278,7 @@ getnameddir(char *name)
 	/* Retrieve an entry from the password table/database for this user. */
 	struct passwd *pw;
 	if ((pw = getpwnam(name))) {
-	    char *dir = isset(CHASELINKS) ? xsymlink(pw->pw_dir)
+	    char *dir = isset(CHASELINKS) ? xsymlink(pw->pw_dir, 0)
 		: ztrdup(pw->pw_dir);
 	    if (dir) {
 		adduserdir(name, dir, ND_USERNAME, 1);
@@ -1634,7 +1652,7 @@ checkmailpath(char **s)
 	} else if (S_ISDIR(st.st_mode)) {
 	    LinkList l;
 	    DIR *lock = opendir(unmeta(*s));
-	    char buf[PATH_MAX * 2], **arr, **ap;
+	    char buf[PATH_MAX * 2 + 1], **arr, **ap;
 	    int ct = 1;
 
 	    if (lock) {
@@ -2162,6 +2180,7 @@ gettempfile(const char *prefix, int use_heap, char **tempname)
 #if HAVE_MKSTEMP
     char *suffix = prefix ? ".XXXXXX" : "XXXXXX";
 
+    queue_signals();
     if (!prefix && !(prefix = getsparam("TMPPREFIX")))
 	prefix = DEFAULT_TMPPREFIX;
     if (use_heap)
@@ -2178,6 +2197,7 @@ gettempfile(const char *prefix, int use_heap, char **tempname)
 #else
     int failures = 0;
 
+    queue_signals();
     do {
 	if (!(fn = gettempname(prefix, use_heap))) {
 	    fd = -1;
@@ -2191,6 +2211,8 @@ gettempfile(const char *prefix, int use_heap, char **tempname)
     } while (errno == EEXIST && ++failures < 16);
 #endif
     *tempname = fn;
+
+    unqueue_signals();
     return fd;
 }
 
@@ -2280,6 +2302,46 @@ arrlen(char **s)
     return count;
 }
 
+/* Return TRUE iff arrlen(s) >= lower_bound, but more efficiently. */
+
+/**/
+mod_export char
+arrlen_ge(char **s, unsigned lower_bound)
+{
+    while (lower_bound--)
+	if (!*s++)
+	    return 0 /* FALSE */;
+
+    return 1 /* TRUE */;
+}
+
+/* Return TRUE iff arrlen(s) > lower_bound, but more efficiently. */
+
+/**/
+mod_export char
+arrlen_gt(char **s, unsigned lower_bound)
+{
+    return arrlen_ge(s, 1+lower_bound);
+}
+
+/* Return TRUE iff arrlen(s) <= upper_bound, but more efficiently. */
+
+/**/
+mod_export char
+arrlen_le(char **s, unsigned upper_bound)
+{
+    return arrlen_lt(s, 1+upper_bound);
+}
+
+/* Return TRUE iff arrlen(s) < upper_bound, but more efficiently. */
+
+/**/
+mod_export char
+arrlen_lt(char **s, unsigned upper_bound)
+{
+    return !arrlen_ge(s, upper_bound);
+}
+
 /* Skip over a balanced pair of parenthesis. */
 
 /**/
@@ -2322,7 +2384,7 @@ zstrtol_underscore(const char *s, char **t, int base, int underscore)
     while (inblank(*s))
 	s++;
 
-    if ((neg = (*s == '-')))
+    if ((neg = IS_DASH(*s)))
 	s++;
     else if (*s == '+')
 	s++;
@@ -2534,7 +2596,7 @@ read_poll(int fd, int *readchar, int polltty, zlong microseconds)
 #endif
 #endif
 
-    if (fd >= 0 && ret < 0) {
+    if (fd >= 0 && ret < 0 && !errflag) {
 	/*
 	 * Final attempt: set non-blocking read and try to read a character.
 	 * Praise Bill, this works under Cygwin (nothing else seems to).
@@ -2890,9 +2952,7 @@ mod_export void
 spckword(char **s, int hist, int cmd, int ask)
 {
     char *t, *correct_ignore;
-    int x;
     char ic = '\0';
-    int ne;
     int preflen = 0;
     int autocd = cmd && isset(AUTOCD) && strcmp(*s, ".") && strcmp(*s, "..");
 
@@ -2961,6 +3021,7 @@ spckword(char **s, int hist, int cmd, int ask)
     } else {
 	guess = *s;
 	if (*guess == Tilde || *guess == String) {
+	    int ne;
 	    ic = *guess;
 	    if (!*++t)
 		return;
@@ -3005,6 +3066,7 @@ spckword(char **s, int hist, int cmd, int ask)
     if (errflag)
 	return;
     if (best && (int)strlen(best) > 1 && strcmp(best, guess)) {
+	int x;
 	if (ic) {
 	    char *u;
 	    if (preflen) {
@@ -3034,14 +3096,14 @@ spckword(char **s, int hist, int cmd, int ask)
 		free(pptbuf);
 		fflush(shout);
 		zbeep();
-		x = getquery("nyae \t", 0);
+		x = getquery("nyae", 0);
 		if (cmd && x == 'n')
 		    pathchecked = path;
 	    } else
 		x = 'n';
 	} else
 	    x = 'y';
-	if (x == 'y' || x == ' ' || x == '\t') {
+	if (x == 'y') {
 	    *s = dupstring(best);
 	    if (hist)
 		hwrep(best);
@@ -3905,7 +3967,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;
@@ -4103,42 +4165,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;
@@ -4183,6 +4253,32 @@ arrdup(char **s)
     return y;
 }
 
+/* Duplicate at most max elements of the array s with heap memory */
+
+/**/
+mod_export char **
+arrdup_max(char **s, unsigned max)
+{
+    char **x, **y, **send;
+    int len = 0;
+
+    if (max)
+	len = arrlen(s);
+
+    /* Limit has sense only if not equal to len */
+    if (max > len)
+        max = len;
+
+    y = x = (char **) zhalloc(sizeof(char *) * (max + 1));
+
+    send = s + max;
+    while (s < send)
+	*x++ = dupstring(*s++);
+    *x = NULL;
+
+    return y;
+}
+
 /**/
 mod_export char **
 zarrdup(char **s)
@@ -4700,6 +4796,41 @@ unmeta(const char *file_name)
 }
 
 /*
+ * Unmetafy just one character and store the number of bytes it occupied.
+ */
+/**/
+mod_export convchar_t
+unmeta_one(const char *in, int *sz)
+{
+    convchar_t wc;
+    int newsz;
+#ifdef MULTIBYTE_SUPPORT
+    mbstate_t wstate;
+#endif
+
+    if (!sz)
+	sz = &newsz;
+    *sz = 0;
+
+    if (!in || !*in)
+	return 0;
+
+#ifdef MULTIBYTE_SUPPORT
+    memset(&wstate, 0, sizeof(wstate));
+    *sz = mb_metacharlenconv_r(in, &wc, &wstate);
+#else
+    if (in[0] == Meta) {
+      *sz = 2;
+      wc = STOUC(in[1] ^ 32);
+    } else {
+      *sz = 1;
+      wc = STOUC(in[0]);
+    }
+#endif
+    return wc;
+}
+
+/*
  * Unmetafy and compare two strings, comparing unsigned character values.
  * "a\0" sorts after "a".
  *
@@ -5040,8 +5171,10 @@ mb_niceformat(const char *s, FILE *stream, char **outstrp, int flags)
 	    cnt = 1;
 	    /* FALL THROUGH */
 	default:
-	    if (c == L'\'' && (flags & NICEFLAG_QUOTE))
+	    if (c == L'\'' && (flags & NICEFLAG_QUOTE)) {
 		fmt = "\\'";
+		newl = 2;
+	    }
 	    else
 		fmt = wcs_nicechar_sel(c, &newl, NULL, flags & NICEFLAG_QUOTE);
 	    break;
@@ -5176,6 +5309,12 @@ mb_metacharlenconv_r(const char *s, wint_t *wcp, mbstate_t *mbsp)
     const char *ptr;
     wchar_t wc;
 
+    if (STOUC(*s) <= 0x7f) {
+	if (wcp)
+	    *wcp = (wint_t)*s;
+	return 1;
+    }
+
     for (ptr = s; *ptr; ) {
 	if (*ptr == Meta) {
 	    inchar = *++ptr ^ 32;
@@ -5228,7 +5367,7 @@ mb_metacharlenconv_r(const char *s, wint_t *wcp, mbstate_t *mbsp)
 mod_export int
 mb_metacharlenconv(const char *s, wint_t *wcp)
 {
-    if (!isset(MULTIBYTE)) {
+    if (!isset(MULTIBYTE) || STOUC(*s) <= 0x7f) {
 	/* treat as single byte, possibly metafied */
 	if (wcp)
 	    *wcp = (wint_t)(*s == Meta ? s[1] ^ 32 : *s);
@@ -5275,7 +5414,7 @@ mb_metastrlenend(char *ptr, int width, char *eptr)
     char inchar, *laststart;
     size_t ret;
     wchar_t wc;
-    int num, num_in_char;
+    int num, num_in_char, complete;
 
     if (!isset(MULTIBYTE))
 	return ztrlen(ptr);
@@ -5283,6 +5422,7 @@ mb_metastrlenend(char *ptr, int width, char *eptr)
     laststart = ptr;
     ret = MB_INVALID;
     num = num_in_char = 0;
+    complete = 1;
 
     memset(&mb_shiftstate, 0, sizeof(mb_shiftstate));
     while (*ptr && !(eptr && ptr >= eptr)) {
@@ -5291,6 +5431,18 @@ mb_metastrlenend(char *ptr, int width, char *eptr)
 	else
 	    inchar = *ptr;
 	ptr++;
+
+	if (complete && STOUC(inchar) <= STOUC(0x7f)) {
+	    /*
+	     * We rely on 7-bit US-ASCII as a subset, so skip
+	     * multibyte handling if we have such a character.
+	     */
+	    num++;
+	    laststart = ptr;
+	    num_in_char = 0;
+	    continue;
+	}
+
 	ret = mbrtowc(&wc, &inchar, 1, &mb_shiftstate);
 
 	if (ret == MB_INCOMPLETE) {
@@ -5310,6 +5462,7 @@ mb_metastrlenend(char *ptr, int width, char *eptr)
 	     * so we don't count characters twice.
 	     */
 	    num_in_char++;
+	    complete = 0;
 	} else {
 	    if (ret == MB_INVALID) {
 		/* Reset, treat as single character */
@@ -5332,6 +5485,7 @@ mb_metastrlenend(char *ptr, int width, char *eptr)
 		num++;
 	    laststart = ptr;
 	    num_in_char = 0;
+	    complete = 1;
 	}
     }
 
@@ -5354,6 +5508,12 @@ mb_charlenconv_r(const char *s, int slen, wint_t *wcp, mbstate_t *mbsp)
     const char *ptr;
     wchar_t wc;
 
+    if (slen && STOUC(*s) <= 0x7f) {
+	if (wcp)
+	    *wcp = (wint_t)*s;
+	return 1;
+    }
+
     for (ptr = s; slen;  ) {
 	inchar = *ptr;
 	ptr++;
@@ -5389,7 +5549,7 @@ mb_charlenconv_r(const char *s, int slen, wint_t *wcp, mbstate_t *mbsp)
 mod_export int
 mb_charlenconv(const char *s, int slen, wint_t *wcp)
 {
-    if (!isset(MULTIBYTE)) {
+    if (!isset(MULTIBYTE) || STOUC(*s) <= 0x7f) {
 	if (wcp)
 	    *wcp = (wint_t)*s;
 	return 1;
@@ -5605,10 +5765,6 @@ addunprintable(char *v, const char *u, const char *uend)
 /*
  * Quote the string s and return the result as a string from the heap.
  *
- * If e is non-zero, the
- * pointer it points to may point to a position in s and in e the position
- * of the corresponding character in the quoted string is returned.
- * 
  * The last argument is a QT_ value defined in zsh.h other than QT_NONE.
  *
  * Most quote styles other than backslash assume the quotes are to
@@ -5621,13 +5777,13 @@ addunprintable(char *v, const char *u, const char *uend)
 
 /**/
 mod_export char *
-quotestring(const char *s, char **e, int instring)
+quotestring(const char *s, int instring)
 {
     const char *u;
     char *v;
     int alloclen;
     char *buf;
-    int sf = 0, shownull = 0;
+    int shownull = 0;
     /*
      * quotesub is used with QT_SINGLE_OPTIONAL.
      * quotesub = 0:  mechanism not active
@@ -5698,10 +5854,6 @@ quotestring(const char *s, char **e, int instring)
 	while (*u) {
 	    uend = u + MB_METACHARLENCONV(u, &cc);
 
-	    if (e && !sf && *e <= u) {
-		*e = v;
-		sf = 1;
-	    }
 	    if (
 #ifdef MULTIBYTE_SUPPORT
 		cc != WEOF &&
@@ -5728,11 +5880,6 @@ quotestring(const char *s, char **e, int instring)
 	}
     } else if (instring == QT_BACKSLASH_PATTERN) {
 	while (*u) {
-	    if (e && !sf && *e == u) {
-		*e = v;
-		sf = 1;
-	    }
-
 	    if (ipattern(*u))
 		*v++ = '\\';
 	    *v++ = *u++;
@@ -5751,8 +5898,6 @@ quotestring(const char *s, char **e, int instring)
 	 */
 	while (*u) {
 	    int dobackslash = 0;
-	    if (e && *e == u)
-		*e = v, sf = 1;
 	    if (*u == Tick || *u == Qtick) {
 		char c = *u++;
 
@@ -5940,10 +6085,6 @@ quotestring(const char *s, char **e, int instring)
 	*v++ = '\'';
     *v = '\0';
 
-    if (e && *e == u)
-	*e = v, sf = 1;
-    DPUTS(e && !sf, "BUG: Wild pointer *e in quotestring()");
-
     v = dupstring(buf);
     zfree(buf, alloclen);
     return v;
@@ -6020,7 +6161,9 @@ quotedzputs(char const *s, FILE *stream)
 	} else
 	    *ptr++ = '\'';
 	while(*s) {
-	    if (*s == Meta)
+	    if (*s == Dash)
+		c = '-';
+	    else if (*s == Meta)
 		c = *++s ^ 32;
 	    else
 		c = *s;
@@ -6057,7 +6200,9 @@ quotedzputs(char const *s, FILE *stream)
     } else {
 	/* use Bourne-style quoting, avoiding empty quoted strings */
 	while (*s) {
-	    if (*s == Meta)
+	    if (*s == Dash)
+		c = '-';
+	    else if (*s == Meta)
 		c = *++s ^ 32;
 	    else
 		c = *s;
@@ -6818,7 +6963,7 @@ strsfx(char *s, char *t)
 static int
 upchdir(int n)
 {
-    char buf[PATH_MAX];
+    char buf[PATH_MAX+1];
     char *s;
     int err = -1;