window(1): Remove __RCSID & friends.
[dragonfly.git] / usr.bin / window / wwiomux.c
1 /*      @(#)wwiomux.c   8.1 (Berkeley) 6/6/93   */
2 /*      $NetBSD: wwiomux.c,v 1.14 2009/04/14 08:50:06 lukem Exp $       */
3
4 /*
5  * Copyright (c) 1983, 1993
6  *      The Regents of the University of California.  All rights reserved.
7  *
8  * This code is derived from software contributed to Berkeley by
9  * Edward Wang at The University of California, Berkeley.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. Neither the name of the University nor the names of its contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  */
35
36 #include <sys/types.h>
37 #if !defined(OLD_TTY) && !defined(TIOCPKT_DATA)
38 #include <sys/ioctl.h>
39 #endif
40 #include <sys/time.h>
41 #include <poll.h>
42 #include <stdlib.h>
43 #include <fcntl.h>
44 #include <string.h>
45 #include <unistd.h>
46 #include <err.h>
47 #include "ww.h"
48
49 /*
50  * Multiple window output handler.
51  * The idea is to copy window outputs to the terminal, via the
52  * display package.  We try to give wwcurwin highest priority.
53  * The only return conditions are when there is keyboard input
54  * and when a child process dies.
55  * When there's nothing to do, we sleep in a select().
56  * The history of this routine is interesting.
57  */
58 void
59 wwiomux(void)
60 {
61         struct ww *w;
62         nfds_t nfd;
63         int i;
64         int volatile dostdin;   /* avoid longjmp clobbering */
65         char volatile c;        /* avoid longjmp clobbering */
66         char *p;
67         int millis;
68         char noblock = 0;
69         static struct pollfd *pfd = NULL;
70         static nfds_t maxfds = 0;
71
72         c = 0;  /* XXXGCC -Wuninitialized */
73
74         for (;;) {
75                 if (wwinterrupt()) {
76                         wwclrintr();
77                         return;
78                 }
79
80                 nfd = 0;
81                 for (w = wwhead.ww_forw; w != &wwhead; w = w->ww_forw) {
82                         if (w->ww_pty < 0 || w->ww_obq >= w->ww_obe)
83                                 continue;
84                         nfd++;
85                 }
86
87                 if (maxfds <= ++nfd) {  /* One more for the fd=0 case below */
88                         struct pollfd *npfd = pfd == NULL ?
89                             malloc(sizeof(*pfd) * nfd) :
90                            realloc(pfd, sizeof(*pfd) * nfd);
91                         if (npfd == NULL) {
92                                 warn("will retry");
93                                 if (pfd)
94                                         free(pfd);
95                                 pfd = NULL;
96                                 maxfds = 0;
97                                 return;
98                         }
99                         pfd = npfd;
100                         maxfds = nfd;
101                 }
102
103                 nfd = 0;
104                 for (w = wwhead.ww_forw; w != &wwhead; w = w->ww_forw) {
105                         if (w->ww_pty < 0)
106                                 continue;
107                         if (w->ww_obq < w->ww_obe) {
108                                 pfd[nfd].fd = w->ww_pty;
109                                 pfd[nfd++].events = POLLIN;
110                         }
111                         if (w->ww_obq > w->ww_obp &&
112                             !ISSET(w->ww_pflags, WWP_STOPPED))
113                                 noblock = 1;
114                 }
115                 if (wwibq < wwibe) {
116                         dostdin = nfd;
117                         pfd[nfd].fd = 0;
118                         pfd[nfd++].events = POLLIN;
119                 } else {
120                         dostdin = -1;
121                 }
122
123                 if (!noblock) {
124                         if (wwcurwin != 0)
125                                 wwcurtowin(wwcurwin);
126                         wwupdate();
127                         wwflush();
128                         (void) setjmp(wwjmpbuf);
129                         wwsetjmp = 1;
130                         if (wwinterrupt()) {
131                                 wwsetjmp = 0;
132                                 wwclrintr();
133                                 return;
134                         }
135                         /* XXXX */
136                         millis = 30000;
137                 } else {
138                         millis = 10;
139                 }
140                 wwnselect++;
141                 i = poll(pfd, nfd, millis);
142                 wwsetjmp = 0;
143                 noblock = 0;
144
145                 if (i < 0)
146                         wwnselecte++;
147                 else if (i == 0)
148                         wwnselectz++;
149                 else {
150                         if (dostdin != -1 && (pfd[dostdin].revents & POLLIN) != 0)
151                                 wwrint();
152
153                         nfd = 0;
154                         for (w = wwhead.ww_forw; w != &wwhead; w = w->ww_forw) {
155                                 int n;
156
157                                 if (w->ww_pty < 0)
158                                         continue;
159                                 if (w->ww_pty != pfd[nfd].fd)
160                                         continue;
161                                 if ((pfd[nfd++].revents & POLLIN) == 0)
162                                         continue;
163                                 wwnwread++;
164                                 p = w->ww_obq;
165                                 if (w->ww_type == WWT_PTY) {
166                                         if (p == w->ww_ob) {
167                                                 w->ww_obp++;
168                                                 w->ww_obq++;
169                                         } else
170                                                 p--;
171                                         c = *p;
172                                 }
173                                 n = read(w->ww_pty, p, w->ww_obe - p);
174                                 if (n < 0) {
175                                         wwnwreade++;
176                                         (void) close(w->ww_pty);
177                                         w->ww_pty = -1;
178                                 } else if (n == 0) {
179                                         wwnwreadz++;
180                                         (void) close(w->ww_pty);
181                                         w->ww_pty = -1;
182                                 } else if (w->ww_type != WWT_PTY) {
183                                         wwnwreadd++;
184                                         wwnwreadc += n;
185                                         w->ww_obq += n;
186                                 } else if (*p == TIOCPKT_DATA) {
187                                         n--;
188                                         wwnwreadd++;
189                                         wwnwreadc += n;
190                                         w->ww_obq += n;
191                                 } else {
192                                         wwnwreadp++;
193                                         if (*p & TIOCPKT_STOP)
194                                                 SET(w->ww_pflags, WWP_STOPPED);
195                                         if (*p & TIOCPKT_START)
196                                                 CLR(w->ww_pflags, WWP_STOPPED);
197                                         if (*p & TIOCPKT_FLUSHWRITE) {
198                                                 CLR(w->ww_pflags, WWP_STOPPED);
199                                                 w->ww_obq = w->ww_obp =
200                                                         w->ww_ob;
201                                         }
202                                 }
203                                 if (w->ww_type == WWT_PTY)
204                                         *p = c;
205                         }
206                 }
207                 /*
208                  * Try the current window first, if there is output
209                  * then process it and go back to the top to try again.
210                  * This can lead to starvation of the other windows,
211                  * but presumably that what we want.
212                  * Update will eventually happen when output from wwcurwin
213                  * dies down.
214                  */
215                 if ((w = wwcurwin) != 0 && w->ww_pty >= 0 &&
216                     w->ww_obq > w->ww_obp &&
217                     !ISSET(w->ww_pflags, WWP_STOPPED)) {
218                         int n = wwwrite(w, w->ww_obp, w->ww_obq - w->ww_obp);
219                         if ((w->ww_obp += n) == w->ww_obq)
220                                 w->ww_obq = w->ww_obp = w->ww_ob;
221                         noblock = 1;
222                         continue;
223                 }
224                 for (w = wwhead.ww_forw; w != &wwhead; w = w->ww_forw)
225                         if (w->ww_pty >= 0 && w->ww_obq > w->ww_obp &&
226                             !ISSET(w->ww_pflags, WWP_STOPPED)) {
227                                 int n = wwwrite(w, w->ww_obp,
228                                         w->ww_obq - w->ww_obp);
229                                 if ((w->ww_obp += n) == w->ww_obq)
230                                         w->ww_obq = w->ww_obp = w->ww_ob;
231                                 if (wwinterrupt())
232                                         break;
233                         }
234         }
235 }