summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bin/ksh/eval.c65
1 files changed, 48 insertions, 17 deletions
diff --git a/bin/ksh/eval.c b/bin/ksh/eval.c
index ba4b73f404e..2f22c2ee2eb 100644
--- a/bin/ksh/eval.c
+++ b/bin/ksh/eval.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: eval.c,v 1.65 2019/06/28 13:34:59 deraadt Exp $ */
+/* $OpenBSD: eval.c,v 1.66 2020/09/13 15:39:09 tb Exp $ */
/*
* Expansion - quoting, separation, substitution, globbing
@@ -47,6 +47,8 @@ typedef struct Expand {
#define IFS_WORD 0 /* word has chars (or quotes) */
#define IFS_WS 1 /* have seen IFS white-space */
#define IFS_NWS 2 /* have seen IFS non-white-space */
+#define IFS_IWS 3 /* beginning of word, ignore IFS white-space */
+#define IFS_QUOTE 4 /* beg.w/quote, becomes IFS_WORD unless "$@" */
static int varsub(Expand *, char *, char *, int *, int *);
static int comsub(Expand *, char *);
@@ -217,7 +219,17 @@ expand(char *cp, /* input word */
c = *sp++;
break;
case OQUOTE:
- word = IFS_WORD;
+ switch (word) {
+ case IFS_QUOTE:
+ /* """something */
+ word = IFS_WORD;
+ break;
+ case IFS_WORD:
+ break;
+ default:
+ word = IFS_QUOTE;
+ break;
+ }
tilde_ok = 0;
quote = 1;
continue;
@@ -297,6 +309,8 @@ expand(char *cp, /* input word */
if (f&DOBLANK)
doblank++;
tilde_ok = 0;
+ if (word == IFS_QUOTE && type != XNULLSUB)
+ word = IFS_WORD;
if (type == XBASE) { /* expand? */
if (!st->next) {
SubType *newst;
@@ -358,6 +372,11 @@ expand(char *cp, /* input word */
f |= DOTEMP_;
/* FALLTHROUGH */
default:
+ /* '-' '+' '?' */
+ if (quote)
+ word = IFS_WORD;
+ else if (dp == Xstring(ds, dp))
+ word = IFS_IWS;
/* Enable tilde expansion */
tilde_ok = 1;
f |= DOTILDE;
@@ -387,10 +406,17 @@ expand(char *cp, /* input word */
*/
x.str = trimsub(str_val(st->var),
dp, st->stype);
- if (x.str[0] != '\0' || st->quote)
+ if (x.str[0] != '\0') {
+ word = IFS_IWS;
type = XSUB;
- else
+ } else if (quote) {
+ word = IFS_WORD;
+ type = XSUB;
+ } else {
+ if (dp == Xstring(ds, dp))
+ word = IFS_IWS;
type = XNULLSUB;
+ }
if (f&DOBLANK)
doblank++;
st = st->prev;
@@ -422,6 +448,10 @@ expand(char *cp, /* input word */
if (f&DOBLANK)
doblank++;
st = st->prev;
+ if (quote || !*x.str)
+ word = IFS_WORD;
+ else
+ word = IFS_IWS;
continue;
case '?':
{
@@ -463,12 +493,8 @@ expand(char *cp, /* input word */
type = XBASE;
if (f&DOBLANK) {
doblank--;
- /* not really correct: x=; "$x$@" should
- * generate a null argument and
- * set A; "${@:+}" shouldn't.
- */
- if (dp == Xstring(ds, dp))
- word = IFS_WS;
+ if (dp == Xstring(ds, dp) && word != IFS_WORD)
+ word = IFS_IWS;
}
continue;
@@ -503,7 +529,12 @@ expand(char *cp, /* input word */
if (c == 0) {
if (quote && !x.split)
continue;
+ if (!quote && word == IFS_WS)
+ continue;
+ /* this is so we don't terminate */
c = ' ';
+ /* now force-emit a word */
+ goto emit_word;
}
if (quote && x.split) {
/* terminate word for "$@" */
@@ -554,15 +585,15 @@ expand(char *cp, /* input word */
* -----------------------------------
* IFS_WORD w/WS w/NWS w
* IFS_WS -/WS w/NWS -
- * IFS_NWS -/NWS w/NWS w
+ * IFS_NWS -/NWS w/NWS -
+ * IFS_IWS -/WS w/NWS -
* (w means generate a word)
- * Note that IFS_NWS/0 generates a word (at&t ksh
- * doesn't do this, but POSIX does).
*/
- if (word == IFS_WORD ||
- (!ctype(c, C_IFSWS) && c && word == IFS_NWS)) {
- char *p;
-
+ if ((word == IFS_WORD) || (word == IFS_QUOTE) || (c &&
+ (word == IFS_IWS || word == IFS_NWS) &&
+ !ctype(c, C_IFSWS))) {
+ char *p;
+ emit_word:
*dp++ = '\0';
p = Xclose(ds, dp);
if (fdo & DOBRACE_)