Merge from vendor branch LIBPCAP:
[dragonfly.git] / contrib / nvi / ip / ip_read.c
1 /*-
2  * Copyright (c) 1996
3  *      Keith Bostic.  All rights reserved.
4  *
5  * See the LICENSE file for redistribution information.
6  */
7
8 #include "config.h"
9
10 #ifndef lint
11 static const char sccsid[] = "@(#)ip_read.c     8.3 (Berkeley) 9/24/96";
12 #endif /* not lint */
13
14 #include <sys/types.h>
15 #include <sys/queue.h>
16
17 #include <bitstring.h>
18 #include <stdio.h>
19 #include <termios.h>
20 #include <time.h>
21  
22 #include "../common/common.h"
23 #include "../ex/script.h"
24 #include "ip.h"
25
26 extern GS *__global_list;
27
28 typedef enum { INP_OK=0, INP_EOF, INP_ERR, INP_TIMEOUT } input_t;
29
30 static input_t  ip_read __P((SCR *, IP_PRIVATE *, struct timeval *));
31 static int      ip_resize __P((SCR *, size_t, size_t));
32 static int      ip_trans __P((SCR *, IP_PRIVATE *, EVENT *));
33
34 /*
35  * ip_event --
36  *      Return a single event.
37  *
38  * PUBLIC: int ip_event __P((SCR *, EVENT *, u_int32_t, int));
39  */
40 int
41 ip_event(sp, evp, flags, ms)
42         SCR *sp;
43         EVENT *evp;
44         u_int32_t flags;
45         int ms;
46 {
47         IP_PRIVATE *ipp;
48         struct timeval t, *tp;
49
50         if (LF_ISSET(EC_INTERRUPT)) {           /* XXX */
51                 evp->e_event = E_TIMEOUT;
52                 return (0);
53         }
54
55         ipp = sp == NULL ? GIPP(__global_list) : IPP(sp);
56
57         /* Discard the last command. */
58         if (ipp->iskip != 0) {
59                 ipp->iblen -= ipp->iskip;
60                 memmove(ipp->ibuf, ipp->ibuf + ipp->iskip, ipp->iblen);
61                 ipp->iskip = 0;
62         }
63
64         /* Set timer. */
65         if (ms == 0)
66                 tp = NULL;
67         else {
68                 t.tv_sec = ms / 1000;
69                 t.tv_usec = (ms % 1000) * 1000;
70                 tp = &t;
71         }
72
73         /* Read input events. */
74         for (;;) {
75                 switch (ip_read(sp, ipp, tp)) {
76                 case INP_OK:
77                         if (!ip_trans(sp, ipp, evp))
78                                 continue;
79                         break;
80                 case INP_EOF:
81                         evp->e_event = E_EOF;
82                         break;
83                 case INP_ERR:
84                         evp->e_event = E_ERR;
85                         break;
86                 case INP_TIMEOUT:
87                         evp->e_event = E_TIMEOUT;
88                         break;
89                 default:
90                         abort();
91                 }
92                 break;
93         }
94         return (0);
95 }
96
97 /*
98  * ip_read --
99  *      Read characters from the input.
100  */
101 static input_t
102 ip_read(sp, ipp, tp)
103         SCR *sp;
104         IP_PRIVATE *ipp;
105         struct timeval *tp;
106 {
107         struct timeval poll;
108         GS *gp;
109         SCR *tsp;
110         fd_set rdfd;
111         input_t rval;
112         size_t blen;
113         int maxfd, nr;
114         char *bp;
115
116         gp = sp == NULL ? __global_list : sp->gp;
117         bp = ipp->ibuf + ipp->iblen;
118         blen = sizeof(ipp->ibuf) - ipp->iblen;
119
120         /*
121          * 1: A read with an associated timeout, e.g., trying to complete
122          *    a map sequence.  If input exists, we fall into #2.
123          */
124         FD_ZERO(&rdfd);
125         poll.tv_sec = 0;
126         poll.tv_usec = 0;
127         if (tp != NULL) {
128                 FD_SET(ipp->i_fd, &rdfd);
129                 switch (select(ipp->i_fd + 1,
130                     &rdfd, NULL, NULL, tp == NULL ? &poll : tp)) {
131                 case 0:
132                         return (INP_TIMEOUT);
133                 case -1:
134                         goto err;
135                 default:
136                         break;
137                 }
138         }
139         
140         /*
141          * 2: Wait for input.
142          *
143          * Select on the command input and scripting window file descriptors.
144          * It's ugly that we wait on scripting file descriptors here, but it's
145          * the only way to keep from locking out scripting windows.
146          */
147         if (sp != NULL && F_ISSET(gp, G_SCRWIN)) {
148 loop:           FD_ZERO(&rdfd);
149                 FD_SET(ipp->i_fd, &rdfd);
150                 maxfd = ipp->i_fd;
151                 for (tsp = gp->dq.cqh_first;
152                     tsp != (void *)&gp->dq; tsp = tsp->q.cqe_next)
153                         if (F_ISSET(sp, SC_SCRIPT)) {
154                                 FD_SET(sp->script->sh_master, &rdfd);
155                                 if (sp->script->sh_master > maxfd)
156                                         maxfd = sp->script->sh_master;
157                         }
158                 switch (select(maxfd + 1, &rdfd, NULL, NULL, NULL)) {
159                 case 0:
160                         abort();
161                 case -1:
162                         goto err;
163                 default:
164                         break;
165                 }
166                 if (!FD_ISSET(ipp->i_fd, &rdfd)) {
167                         if (sscr_input(sp))
168                                 return (INP_ERR);
169                         goto loop;
170                 }
171         }
172
173         /*
174          * 3: Read the input.
175          */
176         switch (nr = read(ipp->i_fd, bp, blen)) {
177         case  0:                                /* EOF. */
178                 rval = INP_EOF;
179                 break;
180         case -1:                                /* Error or interrupt. */
181 err:            rval = INP_ERR;
182                 msgq(sp, M_SYSERR, "input");
183                 break;
184         default:                                /* Input characters. */
185                 ipp->iblen += nr;
186                 rval = INP_OK;
187                 break;
188         }
189         return (rval);
190 }
191
192 /*
193  * ip_trans --
194  *      Translate messages into events.
195  */
196 static int
197 ip_trans(sp, ipp, evp)
198         SCR *sp;
199         IP_PRIVATE *ipp;
200         EVENT *evp;
201 {
202         u_int32_t val1, val2;
203
204         switch (ipp->ibuf[0]) {
205         case IPO_EOF:
206                 evp->e_event = E_EOF;
207                 ipp->iskip = IPO_CODE_LEN;
208                 return (1);
209         case IPO_ERR:
210                 evp->e_event = E_ERR;
211                 ipp->iskip = IPO_CODE_LEN;
212                 return (1);
213         case IPO_INTERRUPT:
214                 evp->e_event = E_INTERRUPT;
215                 ipp->iskip = IPO_CODE_LEN;
216                 return (1);
217         case IPO_QUIT:
218                 evp->e_event = E_QUIT;
219                 ipp->iskip = IPO_CODE_LEN;
220                 return (1);
221         case IPO_RESIZE:
222                 if (ipp->iblen < IPO_CODE_LEN + IPO_INT_LEN * 2)
223                         return (0);
224                 evp->e_event = E_WRESIZE;
225                 memcpy(&val1, ipp->ibuf + IPO_CODE_LEN, IPO_INT_LEN);
226                 val1 = ntohl(val1);
227                 memcpy(&val2,
228                     ipp->ibuf + IPO_CODE_LEN + IPO_INT_LEN, IPO_INT_LEN);
229                 val2 = ntohl(val2);
230                 ip_resize(sp, val1, val2);
231                 ipp->iskip = IPO_CODE_LEN + IPO_INT_LEN * 2;
232                 return (1);
233         case IPO_SIGHUP:
234                 evp->e_event = E_SIGHUP;
235                 ipp->iskip = IPO_CODE_LEN;
236                 return (1);
237         case IPO_SIGTERM:
238                 evp->e_event = E_SIGTERM;
239                 ipp->iskip = IPO_CODE_LEN;
240                 return (1);
241         case IPO_STRING:
242                 evp->e_event = E_STRING;
243 string:         if (ipp->iblen < IPO_CODE_LEN + IPO_INT_LEN)
244                         return (0);
245                 memcpy(&val1, ipp->ibuf + IPO_CODE_LEN, IPO_INT_LEN);
246                 val1 = ntohl(val1);
247                 if (ipp->iblen < IPO_CODE_LEN + IPO_INT_LEN + val1)
248                         return (0);
249                 ipp->iskip = IPO_CODE_LEN + IPO_INT_LEN + val1;
250                 evp->e_csp = ipp->ibuf + IPO_CODE_LEN + IPO_INT_LEN;
251                 evp->e_len = val1;
252                 return (1);
253         case IPO_WRITE:
254                 evp->e_event = E_WRITE;
255                 ipp->iskip = IPO_CODE_LEN;
256                 return (1);
257         default:
258                 /*
259                  * XXX: Protocol is out of sync?
260                  */
261                 abort();
262         }
263         /* NOTREACHED */
264 }
265
266 /* 
267  * ip_resize --
268  *      Reset the options for a resize event.
269  */
270 static int
271 ip_resize(sp, lines, columns)
272         SCR *sp;
273         size_t lines, columns;
274 {
275         GS *gp;
276         ARGS *argv[2], a, b;
277         char b1[1024];
278
279         /*
280          * XXX
281          * The IP screen has to know the lines and columns before anything
282          * else happens.  So, we may not have a valid SCR pointer, and we
283          * have to deal with that.
284          */
285         if (sp == NULL) {
286                 gp = __global_list;
287                 OG_VAL(gp, GO_LINES) = OG_D_VAL(gp, GO_LINES) = lines;
288                 OG_VAL(gp, GO_COLUMNS) = OG_D_VAL(gp, GO_COLUMNS) = columns;
289                 return (0);
290         }
291
292         a.bp = b1;
293         b.bp = NULL;
294         a.len = b.len = 0;
295         argv[0] = &a;
296         argv[1] = &b;
297
298         (void)snprintf(b1, sizeof(b1), "lines=%lu", (u_long)lines);
299         a.len = strlen(b1);
300         if (opts_set(sp, argv, NULL))
301                 return (1);
302         (void)snprintf(b1, sizeof(b1), "columns=%lu", (u_long)columns);
303         a.len = strlen(b1);
304         if (opts_set(sp, argv, NULL))
305                 return (1);
306         return (0);
307 }