void wwvprintf(struct ww *w, const char *fmt, va_list ap) { char buf[1024]; (void) wwwrite(w, buf, vsnprintf(buf, sizeof(buf), fmt, ap)); }
void wwputs(const char *s, struct ww *w) { const char *p = s; while (*p++) ; (void) wwwrite(w, s, p - s - 1); }
/* * Multiple window output handler. * The idea is to copy window outputs to the terminal, via the * display package. We try to give wwcurwin highest priority. * The only return conditions are when there is keyboard input * and when a child process dies. * When there's nothing to do, we sleep in a select(). * The history of this routine is interesting. */ void wwiomux(void) { struct ww *w; nfds_t nfd; int i; int volatile dostdin; /* avoid longjmp clobbering */ char volatile c; /* avoid longjmp clobbering */ char *p; int millis; char noblock = 0; static struct pollfd *pfd = NULL; static nfds_t maxfds = 0; c = 0; /* XXXGCC -Wuninitialized */ 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) { /* One more for the fd=0 case below */ 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; } /* XXXX */ 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; } } /* * Try the current window first, if there is output * then process it and go back to the top to try again. * This can lead to starvation of the other windows, * but presumably that what we want. * Update will eventually happen when output from wwcurwin * dies down. */ 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; } } }
void docmd(void) { int c; struct ww *w; char out = 0; while (!out && !quit) { if ((c = wwgetc()) < 0) { if (terse) wwsetcursor(0, 0); else { wwputs("Command: ", cmdwin); wwcurtowin(cmdwin); } do wwiomux(); while ((c = wwgetc()) < 0); } if (!terse) wwputc('\n', cmdwin); switch (c) { default: if (c != escapec) break; case 'h': case 'j': case 'k': case 'l': case 'y': case 'p': case ctrl('y'): case ctrl('e'): case ctrl('u'): case ctrl('d'): case ctrl('b'): case ctrl('f'): case ctrl('s'): case ctrl('q'): case ctrl('['): if (selwin == 0) { error("No window."); continue; } } switch (c) { case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if ((w = window[c - '1']) == 0) { error("%c: No such window.", c); break; } setselwin(w); if (checkproc(selwin) >= 0) out = 1; break; case '%': if ((w = getwin()) != 0) setselwin(w); break; case ctrl('^'): if (lastselwin != 0) { setselwin(lastselwin); if (checkproc(selwin) >= 0) out = 1; } else error("No previous window."); break; case 'c': if ((w = getwin()) != 0) closewin(w); break; case 'w': c_window(); break; case 'm': if ((w = getwin()) != 0) c_move(w); break; case 'M': if ((w = getwin()) != 0) movewin(w, w->ww_alt.t, w->ww_alt.l); break; case 's': if ((w = getwin()) != 0) c_size(w); break; case 'S': if ((w = getwin()) != 0) sizewin(w, w->ww_alt.nr, w->ww_alt.nc); break; case 'y': c_yank(); break; case 'p': c_put(); break; case ':': c_colon(); break; case 'h': (void) wwwrite(selwin, "\b", 1); break; case 'j': (void) wwwrite(selwin, "\n", 1); break; case 'k': (void) wwwrite(selwin, "\033A", 2); break; case 'l': (void) wwwrite(selwin, "\033C", 2); break; case ctrl('e'): wwscroll(selwin, 1); break; case ctrl('y'): wwscroll(selwin, -1); break; case ctrl('d'): wwscroll(selwin, selwin->ww_w.nr / 2); break; case ctrl('u'): wwscroll(selwin, - selwin->ww_w.nr / 2); break; case ctrl('f'): wwscroll(selwin, selwin->ww_w.nr); break; case ctrl('b'): wwscroll(selwin, - selwin->ww_w.nr); break; case ctrl('s'): stopwin(selwin); break; case ctrl('q'): startwin(selwin); break; case ctrl('l'): wwredraw(); break; case '?': c_help(); break; case ctrl('['): if (checkproc(selwin) >= 0) out = 1; break; case ctrl('z'): wwsuspend(); break; case 'q': c_quit(); break; /* debugging stuff */ case '&': if (debug) { c_debug(); break; } default: if (c == escapec) { if (checkproc(selwin) >= 0) { (void) write(selwin->ww_pty, &escapec, 1); out = 1; } } else { if (!terse) wwbell(); error("Type ? for help."); } } } if (!quit) setcmd(0); }
void wwputc(char c, struct ww *w) { (void) wwwrite(w, &c, sizeof c); }
/* * Multiple window output handler. * The idea is to copy window outputs to the terminal, via the * display package. We try to give the top most window highest * priority. The only return condition is when there is keyboard * input, which is serviced asynchronously by wwrint(). * When there's nothing to do, we sleep in a select(). * This can be done better with interrupt driven io. But that's * not supported on ptys, yet. * The history of this routine is interesting. */ wwiomux() { register struct ww *w; fd_set imask; register n; register char *p; char c; static struct timeval tv = { 0, 0 }; char noblock; loop: if (wwinterrupt()) return; FD_ZERO(&imask); noblock = 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) FD_SET(w->ww_pty, &imask); if (w->ww_obq > w->ww_obp && !w->ww_stopped) noblock = 1; } if (!noblock) { if (wwcurwin != 0) wwcurtowin(wwcurwin); wwupdate(); wwflush(); if (setjmp(wwjmpbuf)) return; wwsetjmp = 1; if (wwinterrupt()) { wwsetjmp = 0; return; } } wwnselect++; n = select(wwdtablesize, &imask, (fd_set *)0, (fd_set *)0, noblock ? &tv : (struct timeval *)0); wwsetjmp = 0; if (n < 0) wwnselecte++; else if (n == 0) wwnselectz++; else for (w = wwhead.ww_forw; w != &wwhead; w = w->ww_forw) { if (w->ww_pty < 0 || !FD_ISSET(w->ww_pty, &imask)) continue; wwnwread++; p = w->ww_obq; if (w->ww_ispty) { 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_ispty) { 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) w->ww_stopped = 1; if (*p & TIOCPKT_START) w->ww_stopped = 0; if (*p & TIOCPKT_FLUSHWRITE) { w->ww_stopped = 0; w->ww_obq = w->ww_obp = w->ww_ob; } } if (w->ww_ispty) *p = c; } for (w = wwhead.ww_forw; w != &wwhead; w = w->ww_forw) if (w->ww_pty >= 0 && w->ww_obq > w->ww_obp && !w->ww_stopped) { 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()) return; break; } goto loop; }