diff options
author | Peter Stephenson <pws@users.sourceforge.net> | 2005-09-23 17:03:16 +0000 |
---|---|---|
committer | Peter Stephenson <pws@users.sourceforge.net> | 2005-09-23 17:03:16 +0000 |
commit | ad2bd42c858aa7236e7b7404806d16b5b0efb6ac (patch) | |
tree | 3c7fd50ab1014769c6d59d15145aefca37ed02be | |
parent | ced5aab522df2754c2fa4581c3538c2cb6d4c1e1 (diff) | |
download | zsh-ad2bd42c858aa7236e7b7404806d16b5b0efb6ac.tar.gz zsh-ad2bd42c858aa7236e7b7404806d16b5b0efb6ac.tar.xz zsh-ad2bd42c858aa7236e7b7404806d16b5b0efb6ac.zip |
21758: optimise =(<<<...) to run within the shell.
-rw-r--r-- | ChangeLog | 6 | ||||
-rw-r--r-- | Doc/Zsh/expn.yo | 9 | ||||
-rw-r--r-- | Src/exec.c | 67 | ||||
-rw-r--r-- | Test/A04redirect.ztst | 8 |
4 files changed, 77 insertions, 13 deletions
diff --git a/ChangeLog b/ChangeLog index c2894399f..d4ce2f9d2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2005-09-23 Peter Stephenson <pws@csr.com> + + * 21758: Doc/Zsh/expn.yo, Src/exec.c: optimise =(<<<...) to + replace an argument by a filename containing it within the + shell. + 2005-09-22 Peter Stephenson <pws@pwstephenson.fsnet.co.uk> * unposted, c.f. 21752: Doc/Zsh/contrib.yo, diff --git a/Doc/Zsh/expn.yo b/Doc/Zsh/expn.yo index a75513b25..60c74cab1 100644 --- a/Doc/Zsh/expn.yo +++ b/Doc/Zsh/expn.yo @@ -340,6 +340,15 @@ process. This may be used instead of the tt(<) form for a program that expects to lseek (see manref(lseek)(2)) on the input file. +There is an optimisation for substitutions of the form +tt(=LPAR()<<<)var(arg)tt(RPAR()), where var(arg) is a single-word argument +to the here-string redirection tt(<<<). This form produces a file name +containing the value of var(arg) after any substitutions have been +performed. This is handled entirely within the current shell. This is +effectively the reverse of the special form tt($LPAR()<)var(arg)tt(RPAR()) +which treats var(arg) as a file name and replaces it with the file's +contents. + The tt(=) form is useful as both the tt(/dev/fd) and the named pipe implementation of tt(<LPAR())var(...)tt(RPAR()) have drawbacks. In the former case, some programmes may automatically close the file diff --git a/Src/exec.c b/Src/exec.c index 95583d4e7..e77a04a53 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -2941,33 +2941,50 @@ getherestr(struct redir *fn) return fd; } -/* $(...) */ +/* + * Test if some wordcode starts with a simple redirection of type + * redir_type. If it does, return the name of the file, copied onto + * the heap. If it doesn't, return NULL. + */ -/**/ -LinkList -getoutput(char *cmd, int qt) +static char * +simple_redir_name(Eprog prog, int redir_type) { - Eprog prog; - int pipes[2]; - pid_t pid; Wordcode pc; - if (!(prog = parse_string(cmd))) - return NULL; - pc = prog->prog; if (prog != &dummy_eprog && wc_code(pc[0]) == WC_LIST && (WC_LIST_TYPE(pc[0]) & Z_END) && wc_code(pc[1]) == WC_SUBLIST && !WC_SUBLIST_FLAGS(pc[1]) && WC_SUBLIST_TYPE(pc[1]) == WC_SUBLIST_END && wc_code(pc[2]) == WC_PIPE && WC_PIPE_TYPE(pc[2]) == WC_PIPE_END && - wc_code(pc[3]) == WC_REDIR && WC_REDIR_TYPE(pc[3]) == REDIR_READ && + wc_code(pc[3]) == WC_REDIR && WC_REDIR_TYPE(pc[3]) == redir_type && !WC_REDIR_VARID(pc[3]) && !pc[4] && wc_code(pc[6]) == WC_SIMPLE && !WC_SIMPLE_ARGC(pc[6])) { + return dupstring(ecrawstr(prog, pc + 5, NULL)); + } + + return NULL; +} + +/* $(...) */ + +/**/ +LinkList +getoutput(char *cmd, int qt) +{ + Eprog prog; + int pipes[2]; + pid_t pid; + char *s; + + if (!(prog = parse_string(cmd))) + return NULL; + + if ((s = simple_redir_name(prog, REDIR_READ))) { /* $(< word) */ int stream; - char *s = dupstring(ecrawstr(prog, pc + 5, NULL)); singsub(&s); if (errflag) @@ -3101,6 +3118,7 @@ getoutputfile(char *cmd) char *nam; Eprog prog; int fd; + char *s; if (thisjob == -1) return NULL; @@ -3109,13 +3127,36 @@ getoutputfile(char *cmd) if (!(nam = gettempname(NULL, 0))) return NULL; + if ((s = simple_redir_name(prog, REDIR_HERESTR))) { + /* + * =(<<<stuff). Optimise a la $(<file). It's + * effectively the reverse, converting a string into a file name + * rather than vice versa. + */ + singsub(&s); + if (errflag) + s = NULL; + else + untokenize(s); + } + if (!jobtab[thisjob].filelist) jobtab[thisjob].filelist = znewlinklist(); zaddlinknode(jobtab[thisjob].filelist, nam); - child_block(); + if (!s) + child_block(); fd = open(nam, O_WRONLY | O_CREAT | O_EXCL | O_NOCTTY, 0600); + if (s) { + /* optimised here-string */ + int len; + unmetafy(s, &len); + write(fd, s, len); + close(fd); + return nam; + } + if (fd < 0 || (cmdoutpid = pid = zfork(NULL)) == -1) { /* fork or open error */ child_unblock(); diff --git a/Test/A04redirect.ztst b/Test/A04redirect.ztst index b80556797..06c380bdb 100644 --- a/Test/A04redirect.ztst +++ b/Test/A04redirect.ztst @@ -269,3 +269,11 @@ exec {myfd}>&- 1:Error closing file descriptor using readonly variable ?(eval):4: can't close file descriptor from readonly parameter myfd + +# This tests the here-string to filename optimisation; we can't +# test that it's actually being optimised, but we can test that it +# still works. + cat =(<<<$'This string has been replaced\nby a file containing it.\n') +0:Optimised here-string to filename +>This string has been replaced +>by a file containing it. |