about summary refs log tree commit diff
diff options
context:
space:
mode:
authorPeter Stephenson <pws@users.sourceforge.net>2008-01-25 16:48:22 +0000
committerPeter Stephenson <pws@users.sourceforge.net>2008-01-25 16:48:22 +0000
commitb5570971efc9cd3f41f2f89bdd287a72866edaf7 (patch)
tree573478a9cbd3205abf4cf152735f25aa0a541c44
parentcf416b753e9a123519b63f3e9ce6478a1996bb60 (diff)
downloadzsh-b5570971efc9cd3f41f2f89bdd287a72866edaf7.tar.gz
zsh-b5570971efc9cd3f41f2f89bdd287a72866edaf7.tar.xz
zsh-b5570971efc9cd3f41f2f89bdd287a72866edaf7.zip
24460: make zpty -rt more consistent by polling before every byte
-rw-r--r--ChangeLog6
-rw-r--r--Doc/Zsh/mod_zpty.yo5
-rw-r--r--Src/Modules/zpty.c46
-rw-r--r--Src/utils.c2
4 files changed, 52 insertions, 7 deletions
diff --git a/ChangeLog b/ChangeLog
index d3035a1a4..47f5f51ba 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2008-01-25  Peter Stephenson  <pws@csr.com>
+
+	* 24460: Doc/Zsh/mod_zpty.yo, Src/utils.c, Src/Modules/zpty.c:
+	make "zpty -rt" more consistent by polling before every byte,
+	not just the first.
+
 2008-01-25  Clint Adams  <clint@zsh.org>
 
 	* 24464: Completion/Unix/Command/_git: remove trailing whitespace.
diff --git a/Doc/Zsh/mod_zpty.yo b/Doc/Zsh/mod_zpty.yo
index 39347c116..5a5459179 100644
--- a/Doc/Zsh/mod_zpty.yo
+++ b/Doc/Zsh/mod_zpty.yo
@@ -64,7 +64,10 @@ is tt(2) if this is because the command has finished.
 
 If the tt(-r) option is combined with the tt(-t) option, tt(zpty) tests
 whether output is available before trying to read.  If no output is
-available, tt(zpty) immediately returns the status tt(1).
+available, tt(zpty) immediately returns the status tt(1).  When used
+with a var(pattern), the behaviour on a failed poll is similar to
+when the command has exited:  the return value is zero if at least
+one character could still be read even if the pattern failed to match.
 )
 item(tt(zpty) tt(-t) var(name))(
 The tt(-t) option without the tt(-r) option can be used to test
diff --git a/Src/Modules/zpty.c b/Src/Modules/zpty.c
index 7e140102e..9bd14985e 100644
--- a/Src/Modules/zpty.c
+++ b/Src/Modules/zpty.c
@@ -468,7 +468,7 @@ checkptycmd(Ptycmd cmd)
 }
 
 static int
-ptyread(char *nam, Ptycmd cmd, char **args)
+ptyread(char *nam, Ptycmd cmd, char **args, int noblock)
 {
     int blen, used, seen = 0, ret = 0;
     char *buf;
@@ -509,6 +509,45 @@ ptyread(char *nam, Ptycmd cmd, char **args)
 	cmd->read = -1;
     }
     do {
+	if (noblock && cmd->read == -1) {
+	    int pollret;
+	    /*
+	     * Check there is data available.  Borrowed from
+	     * poll_read() in utils.c and simplified.
+	     */
+#ifdef HAVE_SELECT
+	    fd_set foofd;
+	    struct timeval expire_tv;
+	    expire_tv.tv_sec = 0;
+	    expire_tv.tv_usec = 0;
+	    FD_ZERO(&foofd);
+	    FD_SET(cmd->fd, &foofd);
+	    pollret = select(cmd->fd+1,
+			 (SELECT_ARG_2_T) &foofd, NULL, NULL, &expire_tv);
+#else
+#ifdef FIONREAD
+	    if (ioctl(cmd->fd, FIONREAD, (char *) &val) == 0)
+		pollret = (val > 0);
+#endif
+#endif
+
+	    if (pollret < 0) {
+		/*
+		 * See read_poll() for this.
+		 * Last despairing effort to poll: attempt to
+		 * set nonblocking I/O and actually read the
+		 * character.  cmd->read stores the character read.
+		 */
+		long mode;
+
+		if (setblock_fd(0, cmd->fd, &mode))
+		    pollret = read(cmd->fd, &cmd->read, 1);
+		if (mode != -1)
+		    fcntl(cmd->fd, F_SETFL, mode);
+	    }
+	    if (pollret == 0)
+		break;
+	}
 	if (!ret) {
 	    checkptycmd(cmd);
 	    if (cmd->fin)
@@ -648,12 +687,9 @@ bin_zpty(char *nam, char **args, Options ops, UNUSED(int func))
 	}
 	if (p->fin)
 	    return 2;
-	if (OPT_ISSET(ops,'t') && p->read == -1 &&
-	    !read_poll(p->fd, &p->read, 0, 0))
-	    return 1;
 
 	return (OPT_ISSET(ops,'r') ?
-		ptyread(nam, p, args + 1) :
+		ptyread(nam, p, args + 1, OPT_ISSET(ops,'t')) :
 		ptywrite(p, args + 1, OPT_ISSET(ops,'n')));
     } else if (OPT_ISSET(ops,'d')) {
 	Ptycmd p;
diff --git a/Src/utils.c b/Src/utils.c
index 85646d827..edf1ea288 100644
--- a/Src/utils.c
+++ b/Src/utils.c
@@ -1886,7 +1886,7 @@ zstrtol(const char *s, char **t, int base)
 }
 
 /**/
-int
+mod_export int
 setblock_fd(int turnonblocking, int fd, long *modep)
 {
 #ifdef O_NDELAY