summaryrefslogtreecommitdiff
path: root/Src/exec.c
diff options
context:
space:
mode:
Diffstat (limited to 'Src/exec.c')
-rw-r--r--Src/exec.c67
1 files changed, 54 insertions, 13 deletions
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();