summaryrefslogtreecommitdiff
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
}