about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog6
-rw-r--r--Doc/Zsh/mod_zpty.yo11
-rw-r--r--Src/Modules/zpty.c46
-rw-r--r--Test/comptest4
4 files changed, 46 insertions, 21 deletions
diff --git a/ChangeLog b/ChangeLog
index 50e9bdc09..2ee34773b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,9 @@
 2009-01-13  Peter Stephenson  <pws@csr.com>
 
+	* Doc/Zsh/mod_zpty.yo, Src/Modules/zpty.c, Test/comptest:
+	make "zpty -r" exit more cleanly on read failures and add and
+	use option to ensure a pattern has been matched.
+
 	* 26300: Src/zsh.mdd: don't use "echo -n" for $ZSH_PATCHLEVEL.
 
 2009-01-09  Peter Stephenson  <p.w.stephenson@ntlworld.com>
@@ -10893,5 +10897,5 @@
 
 *****************************************************
 * This is used by the shell to define $ZSH_PATCHLEVEL
-* $Revision: 1.4504 $                         
+* $Revision: 1.4505 $                         
 *****************************************************
diff --git a/Doc/Zsh/mod_zpty.yo b/Doc/Zsh/mod_zpty.yo
index 5a5459179..de471153e 100644
--- a/Doc/Zsh/mod_zpty.yo
+++ b/Doc/Zsh/mod_zpty.yo
@@ -38,7 +38,7 @@ Note that the command under the pseudo-terminal sees this input as if it
 were typed, so beware when sending special tty driver characters such as
 word-erase, line-kill, and end-of-file.
 )
-item(tt(zpty) tt(-r) [ tt(-t) ] var(name) [ var(param) [ var(pattern) ] ])(
+item(tt(zpty) tt(-r) [ tt(-mt) ] var(name) [ var(param) [ var(pattern) ] ])(
 The tt(-r) option can be used to read the output of the command var(name).
 With only a var(name) argument, the output read is copied to the standard
 output.  Unless the pseudo-terminal is non-blocking, copying continues
@@ -54,10 +54,11 @@ one character is stored in var(param).
 If a var(pattern) is given as well, output is read until the whole string
 read matches the var(pattern), even in the non-blocking case.  The return
 status is zero if the string read matches the pattern, or if the command
-has exited but at least one character could still be read.  As of this
-writing, a maximum of one megabyte of output can be consumed this way; if
-a full megabyte is read without matching the pattern, the return status is
-non-zero.
+has exited but at least one character could still be read.  If the option
+tt(-m) is present, the return status is zero only if the pattern matches.
+As of this writing, a maximum of one megabyte of output can be consumed
+this way; if a full megabyte is read without matching the pattern, the
+return status is non-zero.
 
 In all cases, the return status is non-zero if nothing could be read, and
 is tt(2) if this is because the command has finished.
diff --git a/Src/Modules/zpty.c b/Src/Modules/zpty.c
index d115afcef..4899f8e2e 100644
--- a/Src/Modules/zpty.c
+++ b/Src/Modules/zpty.c
@@ -485,9 +485,9 @@ checkptycmd(Ptycmd cmd)
 }
 
 static int
-ptyread(char *nam, Ptycmd cmd, char **args, int noblock)
+ptyread(char *nam, Ptycmd cmd, char **args, int noblock, int mustmatch)
 {
-    int blen, used, seen = 0, ret = 0;
+    int blen, used, seen = 0, ret = 0, matchok = 0;
     char *buf;
     Patprog prog = NULL;
 
@@ -589,10 +589,24 @@ ptyread(char *nam, Ptycmd cmd, char **args, int noblock)
 	}
 	buf[used] = '\0';
 
-	if (!prog && (ret <= 0 || (*args && buf[used - 1] == '\n')))
-	    break;
+	if (!prog) {
+	    if (ret <= 0 || (*args && buf[used - 1] == '\n'))
+		break;
+	} else {
+	    if (ret < 0
+#ifdef EWOULDBLOCK
+		&& errno != EWOULDBLOCK
+#else
+#ifdef EAGAIN
+		&& errno != EAGAIN
+#endif
+#endif
+		)
+		break;
+	}
     } while (!(errflag || breaks || retflag || contflag) &&
-	     used < READ_MAX && !(prog && ret && pattry(prog, buf)));
+	     used < READ_MAX &&
+	     !(prog && ret && (matchok = pattry(prog, buf))));
 
     if (prog && ret < 0 &&
 #ifdef EWOULDBLOCK
@@ -613,7 +627,9 @@ ptyread(char *nam, Ptycmd cmd, char **args, int noblock)
     else if (used)
 	write(1, buf, used);
 
-    return (seen ? 0 : cmd->fin + 1);
+    if (seen && (!prog || matchok || !mustmatch))
+	return 0;
+    return cmd->fin + 1;
 }
 
 static int
@@ -679,16 +695,19 @@ static int
 bin_zpty(char *nam, char **args, Options ops, UNUSED(int func))
 {
     if ((OPT_ISSET(ops,'r') && OPT_ISSET(ops,'w')) ||
-	((OPT_ISSET(ops,'r') || OPT_ISSET(ops,'w')) && 
+	((OPT_ISSET(ops,'r') || OPT_ISSET(ops,'w')) &&
 	 (OPT_ISSET(ops,'d') || OPT_ISSET(ops,'e') ||
 	  OPT_ISSET(ops,'b') || OPT_ISSET(ops,'L'))) ||
-	(OPT_ISSET(ops,'w') && OPT_ISSET(ops,'t')) ||
+	(OPT_ISSET(ops,'w') && (OPT_ISSET(ops,'t') || OPT_ISSET(ops,'m'))) ||
 	(OPT_ISSET(ops,'n') && (OPT_ISSET(ops,'b') || OPT_ISSET(ops,'e') ||
 				OPT_ISSET(ops,'r') || OPT_ISSET(ops,'t') ||
-				OPT_ISSET(ops,'d') || OPT_ISSET(ops,'L'))) ||
+				OPT_ISSET(ops,'d') || OPT_ISSET(ops,'L') ||
+				OPT_ISSET(ops,'m'))) ||
 	(OPT_ISSET(ops,'d') && (OPT_ISSET(ops,'b') || OPT_ISSET(ops,'e') ||
-				OPT_ISSET(ops,'L') || OPT_ISSET(ops,'t'))) ||
-	(OPT_ISSET(ops,'L') && (OPT_ISSET(ops,'b') || OPT_ISSET(ops,'e')))) {
+				OPT_ISSET(ops,'L') || OPT_ISSET(ops,'t') ||
+				OPT_ISSET(ops,'m'))) ||
+	(OPT_ISSET(ops,'L') && (OPT_ISSET(ops,'b') || OPT_ISSET(ops,'e') ||
+				OPT_ISSET(ops,'m')))) {
 	zwarnnam(nam, "illegal option combination");
 	return 1;
     }
@@ -706,7 +725,8 @@ bin_zpty(char *nam, char **args, Options ops, UNUSED(int func))
 	    return 2;
 
 	return (OPT_ISSET(ops,'r') ?
-		ptyread(nam, p, args + 1, OPT_ISSET(ops,'t')) :
+		ptyread(nam, p, args + 1, OPT_ISSET(ops,'t'),
+			OPT_ISSET(ops, 'm')) :
 		ptywrite(p, args + 1, OPT_ISSET(ops,'n')));
     } else if (OPT_ISSET(ops,'d')) {
 	Ptycmd p;
@@ -780,7 +800,7 @@ ptyhook(UNUSED(Hookdef d), UNUSED(void *dummy))
 
 
 static struct builtin bintab[] = {
-    BUILTIN("zpty", 0, bin_zpty, 0, -1, 0, "ebdrwLnt", NULL),
+    BUILTIN("zpty", 0, bin_zpty, 0, -1, 0, "ebdmrwLnt", NULL),
 };
 
 static struct features module_features = {
diff --git a/Test/comptest b/Test/comptest
index 8a3900f5e..14938a7cd 100644
--- a/Test/comptest
+++ b/Test/comptest
@@ -80,7 +80,7 @@ comptesteval () {
 
   print -lr - "$@" > $tmp
   zpty -w zsh ". $tmp"
-  zpty -r zsh log_eval "*<PROMPT>*" || {
+  zpty -r -m zsh log_eval "*<PROMPT>*" || {
     print "prompt hasn't appeared."
     return 1
   }
@@ -90,7 +90,7 @@ comptesteval () {
 comptest () {
   input="$*"
   zpty -n -w zsh "$input"$'\C-Z'
-  zpty -r zsh log "*<WIDGET><finish>*<PROMPT>*" || {
+  zpty -r -m zsh log "*<WIDGET><finish>*<PROMPT>*" || {
     print "failed to invoke finish widget."
     return 1
   }