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