1
0
Fork 0
mirror of git://git.code.sf.net/p/zsh/code synced 2025-10-01 07:31:20 +02:00

21758: optimise =(<<<...) to run within the shell.

This commit is contained in:
Peter Stephenson 2005-09-23 17:03:16 +00:00
parent ced5aab522
commit ad2bd42c85
4 changed files with 77 additions and 13 deletions

View file

@ -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,

View file

@ -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

View file

@ -2941,6 +2941,33 @@ 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.
*/
static char *
simple_redir_name(Eprog prog, int redir_type)
{
Wordcode pc;
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_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;
}
/* $(...) */
/**/
@ -2950,24 +2977,14 @@ getoutput(char *cmd, int qt)
Eprog prog;
int pipes[2];
pid_t pid;
Wordcode pc;
char *s;
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_REDIR_VARID(pc[3]) &&
!pc[4] &&
wc_code(pc[6]) == WC_SIMPLE && !WC_SIMPLE_ARGC(pc[6])) {
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();

View file

@ -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.