mirror of
git://git.code.sf.net/p/zsh/code
synced 2025-01-01 05:16:05 +01:00
26042 with some fixes from 26043 (Mikael):
allow <(...) and >(...) to occur in the middle of strings and =(...) to have extra text following
This commit is contained in:
parent
dcd26714bb
commit
35a8612f21
7 changed files with 143 additions and 61 deletions
|
@ -1,3 +1,11 @@
|
|||
2008-11-13 Peter Stephenson <p.w.stephenson@ntlworld.com>
|
||||
|
||||
* 26042 with some fixes from 26043 (Mikael): README,
|
||||
Doc/Zsh/expn.yo, Src/exec.c, Src/lex.c, Src/subst.c,
|
||||
Test/D03procsubst.zst: allow <(...) and >(...) to occur
|
||||
in the middle of command arguments and =(...) to have
|
||||
other strings following.
|
||||
|
||||
2008-11-12 Oliver Kiddle <opk@zsh.org>
|
||||
|
||||
* 26030: Src/Zle/zle_main.c: fix memory leak in vared
|
||||
|
|
|
@ -353,12 +353,18 @@ texinode(Process Substitution)(Parameter Expansion)(History Expansion)(Expansion
|
|||
sect(Process Substitution)
|
||||
cindex(process substitution)
|
||||
cindex(substitution, process)
|
||||
Each command argument of the form
|
||||
Each part of a command argument that takes the form
|
||||
`tt(<LPAR())var(list)tt(RPAR())',
|
||||
`tt(>LPAR())var(list)tt(RPAR())' or
|
||||
`tt(=LPAR())var(list)tt(RPAR())'
|
||||
is subject to process substitution.
|
||||
In the case of the tt(<) or tt(>) forms, the shell runs process
|
||||
is subject to process substitution. The expression may be preceeded
|
||||
or followed by other strings except that, to prevent clashes with
|
||||
commonly occurring strings and patterns, the last
|
||||
form must occur at the start of a command argument, and none of
|
||||
the forms may occur inside parentheses used for grouping of patterns or
|
||||
inside parameter substitutions.
|
||||
|
||||
In the case of the tt(<) or tt(>) forms, the shell runs the commands in
|
||||
var(list) asynchronously. If the system supports the tt(/dev/fd)
|
||||
mechanism, the command argument is the name of the device file
|
||||
corresponding to a file descriptor; otherwise, if the system supports named
|
||||
|
|
11
README
11
README
|
@ -69,6 +69,17 @@ always the right behaviour for the intended purpose of debugging and is
|
|||
consistent with recent versions of other shells. The option
|
||||
DEBUG_BEFORE_CMD can be unset to revert to the previous behaviour.
|
||||
|
||||
Previously, process substitutions of the form =(...), <(...) and >(...)
|
||||
were only handled if they appeared as separate command arguments.
|
||||
(However, the latter two forms caused the current argument to be
|
||||
terminated and a new one started even if they occurred in the middle of
|
||||
a string.) Now all three may be followed by other strings, and the
|
||||
latter two may also be preceeded by other strings. None may occur inside
|
||||
parameter substitutions, or inside parentheses used for grouping of
|
||||
patterns, in order to avoid clashes with cases where
|
||||
tt(<) or tt(>) where not treated specially in previous versions of the
|
||||
shell.
|
||||
|
||||
In previous versions of the shell it was possible to use index 0 in an
|
||||
array or string subscript to refer to the same element as index 1 if the
|
||||
option KSH_ARRAYS was not in effect. This was a limited approximation to
|
||||
|
|
18
Src/exec.c
18
Src/exec.c
|
@ -3560,7 +3560,7 @@ readoutput(int in, int qt)
|
|||
|
||||
/**/
|
||||
static Eprog
|
||||
parsecmd(char *cmd)
|
||||
parsecmd(char *cmd, char **eptr)
|
||||
{
|
||||
char *str;
|
||||
Eprog prog;
|
||||
|
@ -3571,7 +3571,9 @@ parsecmd(char *cmd)
|
|||
return NULL;
|
||||
}
|
||||
*str = '\0';
|
||||
if (str[1] || !(prog = parse_string(cmd + 2, 0))) {
|
||||
if (eptr)
|
||||
*eptr = str+1;
|
||||
if (!(prog = parse_string(cmd + 2, 0))) {
|
||||
zerr("parse error in process substitution");
|
||||
return NULL;
|
||||
}
|
||||
|
@ -3582,7 +3584,7 @@ parsecmd(char *cmd)
|
|||
|
||||
/**/
|
||||
char *
|
||||
getoutputfile(char *cmd)
|
||||
getoutputfile(char *cmd, char **eptr)
|
||||
{
|
||||
pid_t pid;
|
||||
char *nam;
|
||||
|
@ -3592,7 +3594,7 @@ getoutputfile(char *cmd)
|
|||
|
||||
if (thisjob == -1)
|
||||
return NULL;
|
||||
if (!(prog = parsecmd(cmd)))
|
||||
if (!(prog = parsecmd(cmd, eptr)))
|
||||
return NULL;
|
||||
if (!(nam = gettempname(NULL, 0)))
|
||||
return NULL;
|
||||
|
@ -3677,7 +3679,7 @@ namedpipe(void)
|
|||
|
||||
/**/
|
||||
char *
|
||||
getproc(char *cmd)
|
||||
getproc(char *cmd, char **eptr)
|
||||
{
|
||||
#if !defined(HAVE_FIFOS) && !defined(PATH_DEV_FD)
|
||||
zerr("doesn't look like your system supports FIFOs.");
|
||||
|
@ -3696,7 +3698,7 @@ getproc(char *cmd)
|
|||
return NULL;
|
||||
if (!(pnam = namedpipe()))
|
||||
return NULL;
|
||||
if (!(prog = parsecmd(cmd)))
|
||||
if (!(prog = parsecmd(cmd, eptr)))
|
||||
return NULL;
|
||||
if (!jobtab[thisjob].filelist)
|
||||
jobtab[thisjob].filelist = znewlinklist();
|
||||
|
@ -3723,7 +3725,7 @@ getproc(char *cmd)
|
|||
if (thisjob == -1)
|
||||
return NULL;
|
||||
pnam = hcalloc(strlen(PATH_DEV_FD) + 6);
|
||||
if (!(prog = parsecmd(cmd)))
|
||||
if (!(prog = parsecmd(cmd, eptr)))
|
||||
return NULL;
|
||||
mpipe(pipes);
|
||||
if ((pid = zfork(&bgtime))) {
|
||||
|
@ -3772,7 +3774,7 @@ getpipe(char *cmd, int nullexec)
|
|||
pid_t pid;
|
||||
struct timeval bgtime;
|
||||
|
||||
if (!(prog = parsecmd(cmd)))
|
||||
if (!(prog = parsecmd(cmd, NULL)))
|
||||
return -1;
|
||||
mpipe(pipes);
|
||||
if ((pid = zfork(&bgtime))) {
|
||||
|
|
17
Src/lex.c
17
Src/lex.c
|
@ -835,7 +835,7 @@ gettok(void)
|
|||
return OUTPAR;
|
||||
case LX1_INANG:
|
||||
d = hgetc();
|
||||
if (!incmdpos && d == '(') {
|
||||
if (d == '(') {
|
||||
hungetc(d);
|
||||
lexstop = 0;
|
||||
unpeekfd:
|
||||
|
@ -1152,20 +1152,13 @@ gettokstr(int c, int sub)
|
|||
c = Comma;
|
||||
break;
|
||||
case LX2_OUTANG:
|
||||
if (!intpos) {
|
||||
if (in_brace_param || sub)
|
||||
break;
|
||||
else
|
||||
goto brk;
|
||||
}
|
||||
if (in_brace_param || sub)
|
||||
break;
|
||||
e = hgetc();
|
||||
if (e != '(') {
|
||||
hungetc(e);
|
||||
lexstop = 0;
|
||||
if (in_brace_param || sub)
|
||||
break;
|
||||
else
|
||||
goto brk;
|
||||
goto brk;
|
||||
}
|
||||
add(Outang);
|
||||
if (skipcomm()) {
|
||||
|
@ -1178,7 +1171,7 @@ gettokstr(int c, int sub)
|
|||
if (isset(SHGLOB) && sub)
|
||||
break;
|
||||
e = hgetc();
|
||||
if(e == '(' && intpos) {
|
||||
if (!(in_brace_param || sub) && e == '(') {
|
||||
add(Inang);
|
||||
if (skipcomm()) {
|
||||
peek = LEXERR;
|
||||
|
|
90
Src/subst.c
90
Src/subst.c
|
@ -56,43 +56,27 @@ prefork(LinkList list, int flags)
|
|||
|
||||
queue_signals();
|
||||
for (node = firstnode(list); node; incnode(node)) {
|
||||
char *str, c;
|
||||
|
||||
str = (char *)getdata(node);
|
||||
if (((c = *str) == Inang || c == Outang || c == Equals) &&
|
||||
str[1] == Inpar) {
|
||||
if (c == Inang || c == Outang)
|
||||
setdata(node, (void *) getproc(str)); /* <(...) or >(...) */
|
||||
else
|
||||
setdata(node, (void *) getoutputfile(str)); /* =(...) */
|
||||
if (!getdata(node)) {
|
||||
setdata(node, dupstring(""));
|
||||
unqueue_signals();
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (isset(SHFILEEXPANSION)) {
|
||||
/*
|
||||
* Here and below we avoid taking the address
|
||||
* of a void * and then pretending it's a char **
|
||||
* instead of a void ** by a little inefficiency.
|
||||
* This could be avoided with some extra linked list
|
||||
* machinery, but that would need quite a lot of work
|
||||
* to ensure consistency. What we really need is
|
||||
* templates...
|
||||
*/
|
||||
char *cptr = (char *)getdata(node);
|
||||
filesub(&cptr, flags & (PF_TYPESET|PF_ASSIGN));
|
||||
/*
|
||||
* The assignment is so simple it's not worth
|
||||
* testing if cptr changed...
|
||||
*/
|
||||
setdata(node, cptr);
|
||||
}
|
||||
if (!(node = stringsubst(list, node, flags & PF_SINGLE, asssub))) {
|
||||
unqueue_signals();
|
||||
return;
|
||||
}
|
||||
if (isset(SHFILEEXPANSION)) {
|
||||
/*
|
||||
* Here and below we avoid taking the address
|
||||
* of a void * and then pretending it's a char **
|
||||
* instead of a void ** by a little inefficiency.
|
||||
* This could be avoided with some extra linked list
|
||||
* machinery, but that would need quite a lot of work
|
||||
* to ensure consistency. What we really need is
|
||||
* templates...
|
||||
*/
|
||||
char *cptr = (char *)getdata(node);
|
||||
filesub(&cptr, flags & (PF_TYPESET|PF_ASSIGN));
|
||||
/*
|
||||
* The assignment is so simple it's not worth
|
||||
* testing if cptr changed...
|
||||
*/
|
||||
setdata(node, cptr);
|
||||
}
|
||||
if (!(node = stringsubst(list, node, flags & PF_SINGLE, asssub))) {
|
||||
unqueue_signals();
|
||||
return;
|
||||
}
|
||||
}
|
||||
for (node = firstnode(list); node; incnode(node)) {
|
||||
|
@ -168,7 +152,37 @@ stringsubst(LinkList list, LinkNode node, int ssub, int asssub)
|
|||
char *str = str3, c;
|
||||
|
||||
while (!errflag && (c = *str)) {
|
||||
if ((qt = c == Qstring) || c == String) {
|
||||
if ((c == Inang || c == Outang || (str == str3 && c == Equals)) &&
|
||||
str[1] == Inpar) {
|
||||
char *subst, *rest, *snew, *sptr;
|
||||
int str3len = str - str3, sublen, restlen;
|
||||
|
||||
if (c == Inang || c == Outang)
|
||||
subst = getproc(str, &rest); /* <(...) or >(...) */
|
||||
else
|
||||
subst = getoutputfile(str, &rest); /* =(...) */
|
||||
if (!subst)
|
||||
subst = "";
|
||||
|
||||
sublen = strlen(subst);
|
||||
restlen = strlen(rest);
|
||||
sptr = snew = hcalloc(str3len + sublen + restlen + 1);
|
||||
if (str3len) {
|
||||
memcpy(sptr, str3, str3len);
|
||||
sptr += str3len;
|
||||
}
|
||||
if (sublen) {
|
||||
memcpy(sptr, subst, sublen);
|
||||
sptr += sublen;
|
||||
}
|
||||
if (restlen)
|
||||
memcpy(sptr, rest, restlen);
|
||||
sptr[restlen] = '\0';
|
||||
str3 = snew;
|
||||
str = snew + str3len + sublen;
|
||||
setdata(node, str3);
|
||||
continue;
|
||||
} else if ((qt = c == Qstring) || c == String) {
|
||||
if ((c = str[1]) == Inpar) {
|
||||
if (!qt)
|
||||
list->list.flags |= LF_ARRAY;
|
||||
|
|
|
@ -36,3 +36,51 @@
|
|||
0:FDs remain open for external commands called from functions
|
||||
>First
|
||||
>Zweite
|
||||
|
||||
catfield2() {
|
||||
local -a args
|
||||
args=(${(s.,.)1})
|
||||
print $args[1]
|
||||
cat $args[2]
|
||||
print $args[3]
|
||||
}
|
||||
catfield2 up,<(print $'\x64'own),sideways
|
||||
0:<(...) when embedded within an argument
|
||||
>up
|
||||
>down
|
||||
>sideways
|
||||
|
||||
outputfield2() {
|
||||
local -a args
|
||||
args=(${(s.,.)1})
|
||||
print $args[1]
|
||||
echo 'How sweet the moonlight sits upon the bank' >$args[2]
|
||||
print $args[3]
|
||||
}
|
||||
outputfield2 muddy,>(sed -e s/s/th/g >outputfield2.txt),vesture
|
||||
# yuk
|
||||
while [[ ! -e outputfield2.txt || ! -s outputfield2.txt ]]; do :; done
|
||||
cat outputfield2.txt
|
||||
0:>(...) when embedded within an argument
|
||||
>muddy
|
||||
>vesture
|
||||
>How thweet the moonlight thitth upon the bank
|
||||
|
||||
catfield1() {
|
||||
local -a args
|
||||
args=(${(s.,.)1})
|
||||
cat $args[1]
|
||||
print $args[2]
|
||||
}
|
||||
catfield1 =(echo s$'\x69't),jessica
|
||||
0:=(...) followed by something else without a break
|
||||
>sit
|
||||
>jessica
|
||||
|
||||
(
|
||||
setopt nonomatch
|
||||
# er... why is this treated as a glob?
|
||||
print everything,=(here is left),alone
|
||||
)
|
||||
0:=(...) preceded by other stuff has no special effect
|
||||
>everything,=(here is left),alone
|
||||
|
|
Loading…
Reference in a new issue