zsh-workers
 help / color / mirror / code / Atom feed
From: Peter Stephenson <pws@csr.com>
To: zsh-workers@sunsite.dk
Subject: Re: input redirect from a variable
Date: Fri, 23 Sep 2005 17:45:24 +0100	[thread overview]
Message-ID: <200509231645.j8NGjPHn017379@news01.csr.com> (raw)
In-Reply-To: <1050923144315.ZM13059@candle.brasslantern.com>

Bart Schaefer wrote:
> A nice optimization (which has not yet been done) would be to have this
> special case avoid forking a new process, much as $(<file) reads a file.

This isn't too difficult since most of the hairy test for a simple
enough redirection already exists (and presumably works, though I
certainly can't tell by looking at it).

> Right now =(<<<...) is equivalent to =($NULLCMD <<<...).  Which actually
> seems like a bug to me; shouldn't it use $READNULLCMD instead?  (Not that
> one really wants "more" rather than "cat" inside a substitution, but even
> outside of substitutions, here-documents are fed to $NULLCMD rather than
> to $READNULLCMD.)

It's a bit curious, but maybe the thinking was that you aren't likely to
want to look at a here-doc or here-string via a pager, which is the
typical use of $READNULLCMD.

Index: Doc/Zsh/expn.yo
===================================================================
RCS file: /cvsroot/zsh/zsh/Doc/Zsh/expn.yo,v
retrieving revision 1.55
diff -u -r1.55 expn.yo
--- Doc/Zsh/expn.yo	2 Sep 2005 11:38:42 -0000	1.55
+++ Doc/Zsh/expn.yo	23 Sep 2005 16:40:08 -0000
@@ -340,6 +340,15 @@
 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
Index: Src/exec.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/exec.c,v
retrieving revision 1.92
diff -u -r1.92 exec.c
--- Src/exec.c	8 Aug 2005 17:01:37 -0000	1.92
+++ Src/exec.c	23 Sep 2005 16:40:23 -0000
@@ -2941,33 +2941,50 @@
     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 @@
     char *nam;
     Eprog prog;
     int fd;
+    char *s;
 
     if (thisjob == -1)
 	return NULL;
@@ -3109,13 +3127,36 @@
     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();
Index: Test/A04redirect.ztst
===================================================================
RCS file: /cvsroot/zsh/zsh/Test/A04redirect.ztst,v
retrieving revision 1.9
diff -u -r1.9 A04redirect.ztst
--- Test/A04redirect.ztst	16 Apr 2005 23:24:57 -0000	1.9
+++ Test/A04redirect.ztst	23 Sep 2005 16:40:24 -0000
@@ -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.

-- 
Peter Stephenson <pws@csr.com>                  Software Engineer
CSR PLC, Churchill House, Cambridge Business Park, Cowley Road
Cambridge, CB4 0WZ, UK                          Tel: +44 (0)1223 692070


**********************************************************************
This email and any files transmitted with it are confidential and
intended solely for the use of the individual or entity to whom they
are addressed. If you have received this email in error please notify
the system manager.

**********************************************************************


      reply	other threads:[~2005-09-23 16:45 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2005-09-23  8:49 Fwd: " Peter Stephenson
2005-09-23 10:15 ` Mikael Magnusson
2005-09-23 13:14   ` Dave Yost
2005-09-23 14:21     ` Bart Schaefer
2005-09-23 16:38       ` Dave Yost
2005-09-23 14:43   ` Bart Schaefer
2005-09-23 16:45     ` Peter Stephenson [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=200509231645.j8NGjPHn017379@news01.csr.com \
    --to=pws@csr.com \
    --cc=zsh-workers@sunsite.dk \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/zsh/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).