#include <sys/types.h>
#if !defined(OLD_TTY) && !defined(TIOCPKT_DATA)
#include <sys/ioctl.h>
#endif
#include <sys/time.h>
#include <poll.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <err.h>
#include "ww.h"
void
wwiomux(void)
{
struct ww *w;
nfds_t nfd;
int i;
int volatile dostdin;
char volatile c;
char *p;
int millis;
char noblock = 0;
static struct pollfd *pfd = NULL;
static nfds_t maxfds = 0;
c = 0;
for (;;) {
if (wwinterrupt()) {
wwclrintr();
return;
}
nfd = 0;
for (w = wwhead.ww_forw; w != &wwhead; w = w->ww_forw) {
if (w->ww_pty < 0 || w->ww_obq >= w->ww_obe)
continue;
nfd++;
}
if (maxfds <= ++nfd) {
struct pollfd *npfd = pfd == NULL ?
malloc(sizeof(*pfd) * nfd) :
realloc(pfd, sizeof(*pfd) * nfd);
if (npfd == NULL) {
warn("will retry");
if (pfd)
free(pfd);
pfd = NULL;
maxfds = 0;
return;
}
pfd = npfd;
maxfds = nfd;
}
nfd = 0;
for (w = wwhead.ww_forw; w != &wwhead; w = w->ww_forw) {
if (w->ww_pty < 0)
continue;
if (w->ww_obq < w->ww_obe) {
pfd[nfd].fd = w->ww_pty;
pfd[nfd++].events = POLLIN;
}
if (w->ww_obq > w->ww_obp &&
!ISSET(w->ww_pflags, WWP_STOPPED))
noblock = 1;
}
if (wwibq < wwibe) {
dostdin = nfd;
pfd[nfd].fd = 0;
pfd[nfd++].events = POLLIN;
} else {
dostdin = -1;
}
if (!noblock) {
if (wwcurwin != 0)
wwcurtowin(wwcurwin);
wwupdate();
wwflush();
(void) setjmp(wwjmpbuf);
wwsetjmp = 1;
if (wwinterrupt()) {
wwsetjmp = 0;
wwclrintr();
return;
}
millis = 30000;
} else {
millis = 10;
}
wwnselect++;
i = poll(pfd, nfd, millis);
wwsetjmp = 0;
noblock = 0;
if (i < 0)
wwnselecte++;
else if (i == 0)
wwnselectz++;
else {
if (dostdin != -1 && (pfd[dostdin].revents & POLLIN) != 0)
wwrint();
nfd = 0;
for (w = wwhead.ww_forw; w != &wwhead; w = w->ww_forw) {
int n;
if (w->ww_pty < 0)
continue;
if (w->ww_pty != pfd[nfd].fd)
continue;
if ((pfd[nfd++].revents & POLLIN) == 0)
continue;
wwnwread++;
p = w->ww_obq;
if (w->ww_type == WWT_PTY) {
if (p == w->ww_ob) {
w->ww_obp++;
w->ww_obq++;
} else
p--;
c = *p;
}
n = read(w->ww_pty, p, w->ww_obe - p);
if (n < 0) {
wwnwreade++;
(void) close(w->ww_pty);
w->ww_pty = -1;
} else if (n == 0) {
wwnwreadz++;
(void) close(w->ww_pty);
w->ww_pty = -1;
} else if (w->ww_type != WWT_PTY) {
wwnwreadd++;
wwnwreadc += n;
w->ww_obq += n;
} else if (*p == TIOCPKT_DATA) {
n--;
wwnwreadd++;
wwnwreadc += n;
w->ww_obq += n;
} else {
wwnwreadp++;
if (*p & TIOCPKT_STOP)
SET(w->ww_pflags, WWP_STOPPED);
if (*p & TIOCPKT_START)
CLR(w->ww_pflags, WWP_STOPPED);
if (*p & TIOCPKT_FLUSHWRITE) {
CLR(w->ww_pflags, WWP_STOPPED);
w->ww_obq = w->ww_obp =
w->ww_ob;
}
}
if (w->ww_type == WWT_PTY)
*p = c;
}
}
if ((w = wwcurwin) != NULL && w->ww_pty >= 0 &&
w->ww_obq > w->ww_obp &&
!ISSET(w->ww_pflags, WWP_STOPPED)) {
int n = wwwrite(w, w->ww_obp, w->ww_obq - w->ww_obp);
if ((w->ww_obp += n) == w->ww_obq)
w->ww_obq = w->ww_obp = w->ww_ob;
noblock = 1;
continue;
}
for (w = wwhead.ww_forw; w != &wwhead; w = w->ww_forw)
if (w->ww_pty >= 0 && w->ww_obq > w->ww_obp &&
!ISSET(w->ww_pflags, WWP_STOPPED)) {
int n = wwwrite(w, w->ww_obp,
w->ww_obq - w->ww_obp);
if ((w->ww_obp += n) == w->ww_obq)
w->ww_obq = w->ww_obp = w->ww_ob;
if (wwinterrupt())
break;
}
}
}