Martijn Dekker said:
> So this patch makes quoted "$@" act according to the standard even when
> IFS is empty. Quoted "$*" is unchanged. For the unspecified (not
> standardised) cases of unquoted $@ and $*, this patch makes ksh act like
> AT&T ksh93, bash, zsh and (d)ash, which seems safest from a
> compatibility point of view.
This makes sense to me, and changes seem reasonable. I've re-generated
diff against -current. Anyone willing to OK it?
--
Dmitrij D. Czarkoff
Index: bin/ksh/eval.c
===================================================================
RCS file: /cvs/src/bin/ksh/eval.c,v
retrieving revision 1.49
diff -u -p -r1.49 eval.c
--- bin/ksh/eval.c 30 Dec 2015 09:07:00 -0000 1.49
+++ bin/ksh/eval.c 4 Mar 2016 09:39:07 -0000
@@ -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 *);
@@ -215,7 +217,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;
@@ -295,6 +307,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;
@@ -356,6 +370,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;
@@ -385,10 +404,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 if (quote) {
+ word = IFS_WORD;
type = XSUB;
- else
+ } else {
+ if (dp == Xstring(ds, dp))
+ word = IFS_IWS;
type = XNULLSUB;
+ }
if (f&DOBLANK)
doblank++;
st = st->prev;
@@ -420,6 +446,7 @@ expand(char *cp, /* input word */
if (f&DOBLANK)
doblank++;
st = st->prev;
+ word = quote || (!*x.str) ? IFS_WORD :
IFS_IWS;
continue;
case '?':
{
@@ -461,12 +488,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;
@@ -501,7 +524,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 "$@" */
@@ -552,15 +580,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);
#ifdef BRACE_EXPAND
Index: regress/bin/ksh/ifs.t
===================================================================
RCS file: /cvs/src/regress/bin/ksh/ifs.t,v
retrieving revision 1.1
diff -u -p -r1.1 ifs.t
--- regress/bin/ksh/ifs.t 2 Dec 2013 20:39:44 -0000 1.1
+++ regress/bin/ksh/ifs.t 4 Mar 2016 09:39:07 -0000
@@ -45,10 +45,10 @@ stdin:
showargs 3 $@
showargs 4 "$@"
expected-stdout:
- <1> <A B C>
+ <1> <A> <B> <C>
<2> <ABC>
- <3> <A B C>
- <4> <A B C>
+ <3> <A> <B> <C>
+ <4> <A> <B> <C>
---
name: IFS-space-colon-1