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:
parent
ced5aab522
commit
ad2bd42c85
4 changed files with 77 additions and 13 deletions
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
67
Src/exec.c
67
Src/exec.c
|
@ -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();
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Reference in a new issue