1
0
mirror of git://git.code.sf.net/p/zsh/code synced 2024-11-18 21:14:11 +01:00

Assorted read_poll() and zpty cleanup.

This commit is contained in:
Bart Schaefer 2000-11-05 09:27:08 +00:00
parent ab99c6d8b6
commit dbc0aebcd4
5 changed files with 146 additions and 73 deletions

@ -1,3 +1,12 @@
2000-11-05 Bart Schaefer <schaefer@zsh.org>
* 13120: Doc/Zsh/mod_zpty.yo, Functions/Misc/nslookup,
Src/utils.c, Src/Modules/zpty.c: Merge Sven's uncommitted patch
from 13061 with 13116. WARNING: This reverses the meaning of
`zpty -b'; the default is now blocking, -b selects non-blocking.
Fix nslookup accordingly. Clean up read_poll() somewhat.
Document that `zpty -w' and `zpty -r' can stream to/from the pty.
2000-11-04 Bart Schaefer <schaefer@zsh.org>
* 13118: Completion/Core/compinit: Add `bareglobqual' to the

@ -5,42 +5,73 @@ The tt(zsh/zpty) module offers one builtin:
startitem()
findex(zpty)
xitem(tt(zpty) [ tt(-e) ] [ tt(-b) ] var(name) var(command) [ var(args ...) ])
xitem(tt(zpty) tt(-d) [ var(names) ... ])
xitem(tt(zpty) tt(-w) [ tt(-n) ] var(name) var(strings ...))
xitem(tt(zpty) tt(-r) var(name) [ var(param) [ var(pattern) ] ])
xitem(tt(zpty) tt(-t) var(name))
item(tt(zpty) [ tt(-L) ])(
item(tt(zpty) [ tt(-e) ] [ tt(-b) ] var(name) var(command) [ var(args ...) ])(
In the first form, the var(command) is started with the var(args) as
arguments. The command runs under a newly assigned pseudo-terminal; this
is useful for running commands non-interactively which expect an
interactive environment. The var(name) given is used to refer to this
command in later calls to tt(pty). With the tt(-e) option given, the
pseudo-terminal will be set up so that input characters are echoed and
with the tt(-b) option given, input and output from and to the
pseudo-terminal will be blocking.
interactive environment. The var(name) is used to refer to this command
in later calls to tt(zpty).
The second form with the tt(-d) option is used to delete commands
previously started by supplying a list of their var(name)s. If no
With the tt(-e) option, the pseudo-terminal is set up so that input
characters are echoed.
With the tt(-b) option, input to and output from the pseudo-terminal are
made non-blocking.
)
item(tt(zpty) tt(-d) [ var(names) ... ])(
The second form, with the tt(-d) option, is used to delete commands
previously started, by supplying a list of their var(name)s. If no
var(names) are given, all commands are deleted. Deleting a command causes
the HUP signal to be sent to the corresponding process.
The tt(-w) option can be used to send the command var(name) the given
)
item(tt(zpty) tt(-w) [ tt(-n) ] var(name) [ var(strings ...) ])(
The tt(-w) option can be used to send the to command var(name) the given
var(strings) as input (separated by spaces). If the tt(-n) option is
not given, a newline will be added at the end.
em(not) given, a newline is added at the end.
The tt(-r) option can be used to read the output of the command
var(name). Without a var(param) argument, the string read will be
printed to standard output. With a var(param) argument, the string
read will be put in the parameter named var(param). If the
var(pattern) is also given, output will be read until the whole string
read matches the var(pattern).
If no var(strings) are provided, the standard input is copied to the
pseudo-terminal; this may stop before copying the full input if the
pseudo-terminal is non-blocking.
The tt(-t) option can be used to test whether the command var(name) is
still running. It returns a zero value if the command is running and
a non-zero value otherwise.
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) ] ])(
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
until the command under the pseudo-terminal exits; when non-blocking, only
as much output as is immediately available is copied. The return value is
zero if any output is copied.
The last form without any arguments is used to list the commands
When also given a var(param) argument, at most one line is read and stored
in the parameter named var(param). Less than a full line may be read if
the pseudo-terminal is non-blocking. The return value is zero if at least
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
value 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 value is
non-zero.
In all cases, the return value is non-zero if nothing could be read, and
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 value tt(1).
)
item(tt(zpty) tt(-t) var(name))(
The tt(-t) option without the tt(-r) option can be used to test
whether the command var(name) is still running. It returns a zero
value if the command is running and a non-zero value otherwise.
)
item(tt(zpty) [ tt(-L) ])(
The last form, without any arguments, is used to list the commands
currently defined. If the tt(-L) option is given, this is done in the
form of calls to the tt(zpty) builtin.
)

@ -24,7 +24,7 @@ zstyle -s ':nslookup' pager tmp &&
[[ -z "$pager" ]] && pager="${opager:-more}"
(( $#pmpt )) || pmpt=(-p '> ')
zpty -b nslookup nslookup "$@"
zpty nslookup nslookup "$@"
zpty -r nslookup line '*
> '

@ -34,7 +34,6 @@
* upper bound on the number of bytes we read (even if we are give a
* pattern). */
#define READ_LEN 1024
#define READ_MAX (1024 * 1024)
typedef struct ptycmd *Ptycmd;
@ -46,9 +45,10 @@ struct ptycmd {
int fd;
int pid;
int echo;
int block;
int nblock;
int fin;
int read;
char *old;
};
static Ptycmd ptycmds;
@ -264,7 +264,7 @@ get_pty(int master, int *retfd)
#endif /* __SVR4 */
static int
newptycmd(char *nam, char *pname, char **args, int echo, int block)
newptycmd(char *nam, char *pname, char **args, int echo, int nblock)
{
Ptycmd p;
int master, slave, pid;
@ -380,14 +380,15 @@ newptycmd(char *nam, char *pname, char **args, int echo, int block)
p->fd = master;
p->pid = pid;
p->echo = echo;
p->block = block;
p->nblock = nblock;
p->fin = 0;
p->read = -1;
p->old = NULL;
p->next = ptycmds;
ptycmds = p;
if (!block)
if (nblock)
ptynonblock(master);
return 0;
@ -411,12 +412,12 @@ deleteptycmd(Ptycmd cmd)
zsfree(p->name);
freearray(p->args);
zclose(cmd->fd);
/* We kill the process group the command put itself in. */
kill(-(p->pid), SIGHUP);
zclose(cmd->fd);
zfree(p, sizeof(*p));
}
@ -438,7 +439,7 @@ checkptycmd(Ptycmd cmd)
{
if (cmd->read != -1)
return;
if (!read_poll(cmd->fd, &cmd->read, !cmd->block) &&
if (!read_poll(cmd->fd, &cmd->read, 0) &&
kill(cmd->pid, 0) < 0) {
cmd->fin = 1;
zclose(cmd->fd);
@ -448,8 +449,8 @@ checkptycmd(Ptycmd cmd)
static int
ptyread(char *nam, Ptycmd cmd, char **args)
{
int blen = 256, used = 0, seen = 0, ret = 1;
char *buf = (char *) zhalloc((blen = 256) + 1);
int blen, used, seen = 0, ret = 0;
char *buf;
Patprog prog = NULL;
if (*args && args[1]) {
@ -469,10 +470,20 @@ ptyread(char *nam, Ptycmd cmd, char **args)
} else
fflush(stdout);
if (cmd->old) {
used = strlen(cmd->old);
buf = (char *) zhalloc((blen = 256 + used) + 1);
strcpy(buf, cmd->old);
zsfree(cmd->old);
cmd->old = NULL;
} else {
used = 0;
buf = (char *) zhalloc((blen = 256) + 1);
}
if (cmd->read != -1) {
buf[0] = (char) cmd->read;
buf[1] = '\0';
used = 1;
buf[used] = (char) cmd->read;
buf[used + 1] = '\0';
seen = used = 1;
cmd->read = -1;
}
do {
@ -495,36 +506,60 @@ ptyread(char *nam, Ptycmd cmd, char **args)
}
buf[used] = '\0';
if (!prog && ret <= 0)
if (!prog && (ret <= 0 || (*args && buf[used - 1] == '\n')))
break;
} while (!errflag && !breaks && !retflag && !contflag &&
(prog ? (used < READ_MAX && (!ret || !pattry(prog, buf))) :
(used < READ_LEN)));
} while (!(errflag || breaks || retflag || contflag) &&
used < READ_MAX && !(prog && ret && pattry(prog, buf)));
if (prog && ret < 0 &&
#ifdef EWOULDBLOCK
errno == EWOULDBLOCK
#else
#ifdef EAGAIN
errno == EAGAIN
#endif
#endif
) {
cmd->old = ztrdup(buf);
used = 0;
return 1;
}
if (*args)
setsparam(*args, ztrdup(metafy(buf, used, META_HREALLOC)));
else
else if (used)
write(1, buf, used);
return !seen;
return (seen ? 0 : cmd->fin + 1);
}
static int
ptywritestr(Ptycmd cmd, char *s, int len)
{
int written;
int written, all = 0;
for (; len; len -= written, s += written) {
if ((written = write(cmd->fd, s, len)) < 0)
return 1;
for (; !errflag && !breaks && !retflag && !contflag && len;
len -= written, s += written) {
if ((written = write(cmd->fd, s, len)) < 0 && cmd->nblock &&
#ifdef EWOULDBLOCK
errno == EWOULDBLOCK
#else
#ifdef EAGAIN
errno == EAGAIN
#endif
#endif
)
return !all;
if (written < 0) {
checkptycmd(cmd);
if (cmd->fin)
break;
written = 0;
}
if (written > 0)
all += written;
}
return 0;
return (all ? 0 : cmd->fin + 1);
}
static int
@ -559,8 +594,9 @@ static int
bin_zpty(char *nam, char **args, char *ops, int func)
{
if ((ops['r'] && ops['w']) ||
((ops['r'] || ops['w']) && (ops['d'] || ops['e'] || ops['t'] ||
((ops['r'] || ops['w']) && (ops['d'] || ops['e'] ||
ops['b'] || ops['L'])) ||
(ops['w'] && ops['t']) ||
(ops['n'] && (ops['b'] || ops['e'] || ops['r'] || ops['t'] ||
ops['d'] || ops['L'])) ||
(ops['d'] && (ops['b'] || ops['e'] || ops['L'] || ops['t'])) ||
@ -579,7 +615,10 @@ bin_zpty(char *nam, char **args, char *ops, int func)
return 1;
}
if (p->fin)
return 2;
if (ops['t'] && p->read == -1 && !read_poll(p->fd, &p->read, 0))
return 1;
return (ops['r'] ?
ptyread(nam, p, args + 1) :
ptywrite(p, args + 1, ops['n']));
@ -629,7 +668,7 @@ bin_zpty(char *nam, char **args, char *ops, int func)
checkptycmd(p);
if (ops['L'])
printf("%s %s%s%s ", nam, (p->echo ? "-e " : ""),
(p->block ? "-b " : ""), p->name);
(p->nblock ? "-b " : ""), p->name);
else if (p->fin)
printf("(finished) %s: ", p->name);
else

@ -1315,7 +1315,7 @@ setblock_stdin(void)
mod_export int
read_poll(int fd, int *readchar, int polltty)
{
int ret = 0;
int ret = -1;
long mode = -1;
char c;
#ifdef HAVE_SELECT
@ -1353,38 +1353,32 @@ read_poll(int fd, int *readchar, int polltty)
*/
if (polltty) {
gettyinfo(&ti);
ti.tio.c_cc[VMIN] = 0;
settyinfo(&ti);
if ((polltty = ti.tio.c_cc[VMIN])) {
ti.tio.c_cc[VMIN] = 0;
settyinfo(&ti);
}
}
#else
polltty = 0;
#endif
#ifdef HAVE_SELECT
if (!ret) {
expire_tv.tv_sec = expire_tv.tv_usec = 0;
FD_ZERO(&foofd);
FD_SET(fd, &foofd);
if (select(fd+1, (SELECT_ARG_2_T) &foofd, NULL, NULL, &expire_tv)
> 1)
ret = 1;
}
expire_tv.tv_sec = expire_tv.tv_usec = 0;
FD_ZERO(&foofd);
FD_SET(fd, &foofd);
ret = select(fd+1, (SELECT_ARG_2_T) &foofd, NULL, NULL, &expire_tv);
#else
#ifdef FIONREAD
if (!ret) {
ioctl(fd, FIONREAD, (char *)&val);
if (val)
ret = 1;
}
if (ioctl(fd, FIONREAD, (char *) &val) == 0)
ret = (val > 0);
#endif
#endif
if (!ret) {
if (ret <= 0) {
/*
* Final attempt: set non-blocking read and try to read a character.
* Praise Bill, this works under Cygwin (nothing else seems to).
*/
if ((polltty || setblock_fd(0, fd, &mode))
&& read(fd, &c, 1) > 0) {
if ((polltty || setblock_fd(0, fd, &mode)) && read(fd, &c, 1) > 0) {
*readchar = STOUC(c);
ret = 1;
}
@ -1397,7 +1391,7 @@ read_poll(int fd, int *readchar, int polltty)
settyinfo(&ti);
}
#endif
return ret;
return (ret > 0);
}
/**/