diff options
-rw-r--r-- | ChangeLog | 8 | ||||
-rw-r--r-- | Doc/Zsh/expn.yo | 12 | ||||
-rw-r--r-- | README | 11 | ||||
-rw-r--r-- | Src/exec.c | 18 | ||||
-rw-r--r-- | Src/lex.c | 17 | ||||
-rw-r--r-- | Src/subst.c | 90 | ||||
-rw-r--r-- | Test/D03procsubst.ztst | 48 |
7 files changed, 143 insertions, 61 deletions
diff --git a/ChangeLog b/ChangeLog index 3912efe29..94f89b120 100644 --- a/ChangeLog +++ b/ChangeLog @@ -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 diff --git a/Doc/Zsh/expn.yo b/Doc/Zsh/expn.yo index 5526ff3ea..2ab0d417e 100644 --- a/Doc/Zsh/expn.yo +++ b/Doc/Zsh/expn.yo @@ -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 diff --git a/README b/README index b64000c26..3a8597033 100644 --- a/README +++ b/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 diff --git a/Src/exec.c b/Src/exec.c index 47c0184aa..a398211d3 100644 --- a/Src/exec.c +++ b/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))) { diff --git a/Src/lex.c b/Src/lex.c index 025387ca1..f5999d798 100644 --- a/Src/lex.c +++ b/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; diff --git a/Src/subst.c b/Src/subst.c index d76215838..5cc4748b8 100644 --- a/Src/subst.c +++ b/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; diff --git a/Test/D03procsubst.ztst b/Test/D03procsubst.ztst index e176d8934..37a67630f 100644 --- a/Test/D03procsubst.ztst +++ b/Test/D03procsubst.ztst @@ -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 |