zsh-workers
 help / color / mirror / code / Atom feed
From: Bart Schaefer <schaefer@brasslantern.com>
To: Zsh hackers list <zsh-workers@zsh.org>
Subject: Re: [BUG] var=$* and var=$@ create array with SHWORDSPLIT and null or unset IFS
Date: Mon, 20 Feb 2017 10:58:37 -0800	[thread overview]
Message-ID: <170220105837.ZM12210@torch.brasslantern.com> (raw)
In-Reply-To: <170216211431.ZM25042@torch.brasslantern.com>

On Feb 16,  9:14pm, Bart Schaefer wrote:
}
} } In SHWORDSPLIT mode, if IFS is null (no field splitting) or unset
} } (default fieldsplitting), both var=$* and var=$@ act like var=("$@"), so
} } turn 'var' into an array.
} 
} Undoing 30299 fixes the bug Martijn is reporting here, but re-introduces
} the incorrect splitting behavior.

I have a question about one of your test cases.

>--- null IFS, native splitting ---
>> var=$@
>[one two three four]
>> var=$*
>[onetwo threefour]
>> var="$@"
>[one two three four]
>> var="$*"
>[onetwo threefour]

Joining the array for assignment is forced by prefork() passing
PREFORK_SINGLE down to paramsubst().  Joining is supposed to be done on
the first character of $IFS in this case.  When IFS is null (as opposed
to unset), this causes both $@ and $* to join on empty string.

Where is the space supposed to come from when joining $@ here?

As for the reported bug -- in certain circumstances paramsubst() skips
doing joins/splits to avoid other problems with the semantics, which
results in an array being returned to prefork() even though it asked
for a scalar.  Instead of choking on this, prefork() converts to an
array assignment.

So the following fixes this, but still joins on empty string rather
than on space in the case of $@.  There's probably a better way to turn
the LinkList back into an array?  But if this join is done any sooner,
then sorting, rcexpandparam, etc. don't happen properly.  If we can
figure out what to pass to sepjoin() in place of NULL as the second
argument, to answer my question above, all Martijn's tests can pass.

The first bit with ms_flags may be meaningless, I was never sure whether
that needed resetting in any case.  Meat is the last hunk.

diff --git a/Src/subst.c b/Src/subst.c
index 1c2397c..4df53bd 100644
--- a/Src/subst.c
+++ b/Src/subst.c
@@ -3475,7 +3475,6 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags,
 	    if (nojoin == 0 || sep) {
 		val = sepjoin(aval, sep, 1);
 		isarr = 0;
-		ms_flags = 0;
 	    } else if (force_split &&
 		       (spsep || nojoin == 2 || (!ifs && isarr < 0))) {
 		/* Hack to simulate splitting individual elements:
@@ -3485,6 +3484,8 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags,
 		val = sepjoin(aval, (nojoin == 1 ? NULL : spsep), 1);
 		isarr = 0;
 	    }
+	    if (!isarr)
+		ms_flags = 0;
 	}
 	if (force_split && !isarr) {
 	    aval = sepsplit(val, spsep, 0, 1);
@@ -4007,6 +4008,18 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags,
 	    y = dupstring(nulstring);
 	setdata(n, (void *) y);
     }
+    if (isarr && ssub) {
+	/* prefork() wants a scalar, so join no matter what else */
+	LinkNode tn;
+
+	aval = hlinklist2array(l, 0);
+	val = sepjoin(aval, NULL, 1);
+	n = firstnode(l);
+	for (tn = lastnode(l); tn && tn != n; tn = lastnode(l))
+	    uremnode(l, tn);
+	setdata(n, (void *) val);
+	l->list.flags &= ~LF_ARRAY;
+    }
     if (eval)
 	*str = (char *) getdata(n);
 


  reply	other threads:[~2017-02-20 18:59 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-02-16 23:05 Martijn Dekker
2017-02-17  0:07 ` Martijn Dekker
2017-02-17  5:14 ` Bart Schaefer
2017-02-20 18:58   ` Bart Schaefer [this message]
2017-02-20 21:20     ` Bart Schaefer
2017-02-20 22:13       ` Martijn Dekker

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=170220105837.ZM12210@torch.brasslantern.com \
    --to=schaefer@brasslantern.com \
    --cc=zsh-workers@zsh.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/zsh/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).