1
0
Fork 0
mirror of git://git.code.sf.net/p/zsh/code synced 2025-09-18 15:21:16 +02:00

26301: make zpty -r exit more cleanly on bad reads

add option -m to make zpty -r return status 1 if pattern failed to match
use this option in comptest
This commit is contained in:
Peter Stephenson 2009-01-13 12:09:26 +00:00
parent e763f79b3f
commit e7c9e03c58
4 changed files with 46 additions and 21 deletions

View file

@ -1,5 +1,9 @@
2009-01-13 Peter Stephenson <pws@csr.com> 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. * 26300: Src/zsh.mdd: don't use "echo -n" for $ZSH_PATCHLEVEL.
2009-01-09 Peter Stephenson <p.w.stephenson@ntlworld.com> 2009-01-09 Peter Stephenson <p.w.stephenson@ntlworld.com>
@ -10893,5 +10897,5 @@
***************************************************** *****************************************************
* This is used by the shell to define $ZSH_PATCHLEVEL * This is used by the shell to define $ZSH_PATCHLEVEL
* $Revision: 1.4504 $ * $Revision: 1.4505 $
***************************************************** *****************************************************

View file

@ -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 were typed, so beware when sending special tty driver characters such as
word-erase, line-kill, and end-of-file. 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). 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 With only a var(name) argument, the output read is copied to the standard
output. Unless the pseudo-terminal is non-blocking, copying continues 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 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 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 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 has exited but at least one character could still be read. If the option
writing, a maximum of one megabyte of output can be consumed this way; if tt(-m) is present, the return status is zero only if the pattern matches.
a full megabyte is read without matching the pattern, the return status is As of this writing, a maximum of one megabyte of output can be consumed
non-zero. 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 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. is tt(2) if this is because the command has finished.

View file

@ -485,9 +485,9 @@ checkptycmd(Ptycmd cmd)
} }
static int 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; char *buf;
Patprog prog = NULL; Patprog prog = NULL;
@ -589,10 +589,24 @@ ptyread(char *nam, Ptycmd cmd, char **args, int noblock)
} }
buf[used] = '\0'; buf[used] = '\0';
if (!prog && (ret <= 0 || (*args && buf[used - 1] == '\n'))) if (!prog) {
break; 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) && } 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 && if (prog && ret < 0 &&
#ifdef EWOULDBLOCK #ifdef EWOULDBLOCK
@ -613,7 +627,9 @@ ptyread(char *nam, Ptycmd cmd, char **args, int noblock)
else if (used) else if (used)
write(1, buf, used); write(1, buf, used);
return (seen ? 0 : cmd->fin + 1); if (seen && (!prog || matchok || !mustmatch))
return 0;
return cmd->fin + 1;
} }
static int static int
@ -679,16 +695,19 @@ static int
bin_zpty(char *nam, char **args, Options ops, UNUSED(int func)) bin_zpty(char *nam, char **args, Options ops, UNUSED(int func))
{ {
if ((OPT_ISSET(ops,'r') && OPT_ISSET(ops,'w')) || 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,'d') || OPT_ISSET(ops,'e') ||
OPT_ISSET(ops,'b') || OPT_ISSET(ops,'L'))) || 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,'n') && (OPT_ISSET(ops,'b') || OPT_ISSET(ops,'e') ||
OPT_ISSET(ops,'r') || OPT_ISSET(ops,'t') || 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,'d') && (OPT_ISSET(ops,'b') || OPT_ISSET(ops,'e') ||
OPT_ISSET(ops,'L') || OPT_ISSET(ops,'t'))) || OPT_ISSET(ops,'L') || OPT_ISSET(ops,'t') ||
(OPT_ISSET(ops,'L') && (OPT_ISSET(ops,'b') || OPT_ISSET(ops,'e')))) { 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"); zwarnnam(nam, "illegal option combination");
return 1; return 1;
} }
@ -706,7 +725,8 @@ bin_zpty(char *nam, char **args, Options ops, UNUSED(int func))
return 2; return 2;
return (OPT_ISSET(ops,'r') ? 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'))); ptywrite(p, args + 1, OPT_ISSET(ops,'n')));
} else if (OPT_ISSET(ops,'d')) { } else if (OPT_ISSET(ops,'d')) {
Ptycmd p; Ptycmd p;
@ -780,7 +800,7 @@ ptyhook(UNUSED(Hookdef d), UNUSED(void *dummy))
static struct builtin bintab[] = { 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 = { static struct features module_features = {

View file

@ -80,7 +80,7 @@ comptesteval () {
print -lr - "$@" > $tmp print -lr - "$@" > $tmp
zpty -w zsh ". $tmp" zpty -w zsh ". $tmp"
zpty -r zsh log_eval "*<PROMPT>*" || { zpty -r -m zsh log_eval "*<PROMPT>*" || {
print "prompt hasn't appeared." print "prompt hasn't appeared."
return 1 return 1
} }
@ -90,7 +90,7 @@ comptesteval () {
comptest () { comptest () {
input="$*" input="$*"
zpty -n -w zsh "$input"$'\C-Z' 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." print "failed to invoke finish widget."
return 1 return 1
} }