ip synchronisation problem
[nvi.git] / ip / ip_read.c
bloba706e14d8b466140af35e2b2565929decba4dad1
1 /*-
2 * Copyright (c) 1996
3 * Keith Bostic. All rights reserved.
5 * See the LICENSE file for redistribution information.
6 */
8 #include "config.h"
10 #ifndef lint
11 static const char sccsid[] = "$Id: ip_read.c,v 8.17 2000/04/30 17:15:55 skimo Exp $ (Berkeley) $Date: 2000/04/30 17:15:55 $";
12 #endif /* not lint */
14 #include <sys/types.h>
15 #include <sys/queue.h>
16 #include <sys/time.h>
18 #include <bitstring.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <termios.h>
23 #include <time.h>
24 #include <unistd.h>
26 #include "../common/common.h"
27 #include "../ex/script.h"
28 #include "../ipc/ip.h"
29 #include "extern.h"
31 extern GS *__global_list;
33 typedef enum { INP_OK=0, INP_EOF, INP_ERR, INP_TIMEOUT } input_t;
35 static input_t ip_read __P((SCR *, IP_PRIVATE *, struct timeval *));
36 static int ip_resize __P((SCR *, u_int32_t, u_int32_t));
37 static int ip_trans __P((SCR *, IP_PRIVATE *, EVENT *));
40 * ip_event --
41 * Return a single event.
43 * PUBLIC: int ip_event __P((SCR *, EVENT *, u_int32_t, int));
45 int
46 ip_event(sp, evp, flags, ms)
47 SCR *sp;
48 EVENT *evp;
49 u_int32_t flags;
50 int ms;
52 IP_PRIVATE *ipp;
53 struct timeval t, *tp;
55 if (LF_ISSET(EC_INTERRUPT)) { /* XXX */
56 evp->e_event = E_TIMEOUT;
57 return (0);
60 ipp = sp == NULL ? GIPP(__global_list) : IPP(sp);
62 /* Discard the last command. */
63 if (ipp->iskip != 0) {
64 ipp->iblen -= ipp->iskip;
65 memmove(ipp->ibuf, ipp->ibuf + ipp->iskip, ipp->iblen);
66 ipp->iskip = 0;
69 /* Process possible remaining commands */
70 if (ipp->iblen >= IPO_CODE_LEN && ip_trans(sp, ipp, evp))
71 return 0;
73 /* Set timer. */
74 if (ms == 0)
75 tp = NULL;
76 else {
77 t.tv_sec = ms / 1000;
78 t.tv_usec = (ms % 1000) * 1000;
79 tp = &t;
82 /* Read input events. */
83 for (;;) {
84 switch (ip_read(sp, ipp, tp)) {
85 case INP_OK:
86 if (!ip_trans(sp, ipp, evp))
87 continue;
88 break;
89 case INP_EOF:
90 evp->e_event = E_EOF;
91 break;
92 case INP_ERR:
93 evp->e_event = E_ERR;
94 break;
95 case INP_TIMEOUT:
96 evp->e_event = E_TIMEOUT;
97 break;
98 default:
99 abort();
101 break;
103 return (0);
107 * ip_read --
108 * Read characters from the input.
110 static input_t
111 ip_read(sp, ipp, tp)
112 SCR *sp;
113 IP_PRIVATE *ipp;
114 struct timeval *tp;
116 struct timeval poll;
117 GS *gp;
118 SCR *tsp;
119 fd_set rdfd;
120 input_t rval;
121 size_t blen;
122 int maxfd, nr;
123 char *bp;
125 gp = sp == NULL ? __global_list : sp->gp;
126 bp = ipp->ibuf + ipp->iblen;
127 blen = sizeof(ipp->ibuf) - ipp->iblen;
130 * 1: A read with an associated timeout, e.g., trying to complete
131 * a map sequence. If input exists, we fall into #2.
133 FD_ZERO(&rdfd);
134 poll.tv_sec = 0;
135 poll.tv_usec = 0;
136 if (tp != NULL) {
137 FD_SET(ipp->i_fd, &rdfd);
138 switch (select(ipp->i_fd + 1,
139 &rdfd, NULL, NULL, tp == NULL ? &poll : tp)) {
140 case 0:
141 return (INP_TIMEOUT);
142 case -1:
143 goto err;
144 default:
145 break;
150 * 2: Wait for input.
152 * Select on the command input and scripting window file descriptors.
153 * It's ugly that we wait on scripting file descriptors here, but it's
154 * the only way to keep from locking out scripting windows.
156 if (sp != NULL && F_ISSET(gp, G_SCRWIN)) {
157 loop: FD_ZERO(&rdfd);
158 FD_SET(ipp->i_fd, &rdfd);
159 maxfd = ipp->i_fd;
160 for (tsp = gp->dq.cqh_first;
161 tsp != (void *)&gp->dq; tsp = tsp->q.cqe_next)
162 if (F_ISSET(sp, SC_SCRIPT)) {
163 FD_SET(sp->script->sh_master, &rdfd);
164 if (sp->script->sh_master > maxfd)
165 maxfd = sp->script->sh_master;
167 switch (select(maxfd + 1, &rdfd, NULL, NULL, NULL)) {
168 case 0:
169 abort();
170 case -1:
171 goto err;
172 default:
173 break;
175 if (!FD_ISSET(ipp->i_fd, &rdfd)) {
176 if (sscr_input(sp))
177 return (INP_ERR);
178 goto loop;
183 * 3: Read the input.
185 switch (nr = read(ipp->i_fd, bp, blen)) {
186 case 0: /* EOF. */
187 rval = INP_EOF;
188 break;
189 case -1: /* Error or interrupt. */
190 err: rval = INP_ERR;
191 msgq(sp, M_SYSERR, "input");
192 break;
193 default: /* Input characters. */
194 ipp->iblen += nr;
195 rval = INP_OK;
196 break;
198 return (rval);
202 * ip_trans --
203 * Translate messages into events.
205 static int
206 ip_trans(sp, ipp, evp)
207 SCR *sp;
208 IP_PRIVATE *ipp;
209 EVENT *evp;
211 u_int32_t skip, val;
212 char *fmt;
214 switch (ipp->ibuf[0]) {
215 case VI_C_BOL:
216 case VI_C_BOTTOM:
217 case VI_C_DEL:
218 case VI_C_EOL:
219 case VI_C_INSERT:
220 case VI_C_LEFT:
221 case VI_C_RIGHT:
222 case VI_C_TOP:
223 case VI_QUIT:
224 case VI_TAG:
225 case VI_TAGSPLIT:
226 case VI_UNDO:
227 case VI_WQ:
228 case VI_WRITE:
229 evp->e_event = E_IPCOMMAND;
230 evp->e_ipcom = ipp->ibuf[0];
231 ipp->iskip = IPO_CODE_LEN;
232 return (1);
233 case VI_C_DOWN:
234 case VI_C_PGDOWN:
235 case VI_C_PGUP:
236 case VI_C_UP:
237 case VI_C_SETTOP:
238 evp->e_event = E_IPCOMMAND;
239 evp->e_ipcom = ipp->ibuf[0];
240 fmt = "1";
241 break;
242 case VI_C_SEARCH:
243 evp->e_event = E_IPCOMMAND;
244 evp->e_ipcom = ipp->ibuf[0];
245 fmt = "a1";
246 break;
247 case VI_EDIT:
248 case VI_EDITSPLIT:
249 case VI_TAGAS:
250 case VI_WRITEAS:
251 evp->e_event = E_IPCOMMAND;
252 evp->e_ipcom = ipp->ibuf[0];
253 fmt = "a";
254 break;
255 case VI_EDITOPT:
256 evp->e_event = E_IPCOMMAND;
257 evp->e_ipcom = ipp->ibuf[0];
258 fmt = "ab1";
259 break;
260 case VI_EOF:
261 evp->e_event = E_EOF;
262 ipp->iskip = IPO_CODE_LEN;
263 return (1);
264 case VI_ERR:
265 evp->e_event = E_ERR;
266 ipp->iskip = IPO_CODE_LEN;
267 return (1);
268 case VI_INTERRUPT:
269 evp->e_event = E_INTERRUPT;
270 ipp->iskip = IPO_CODE_LEN;
271 return (1);
272 case VI_MOUSE_MOVE:
273 case VI_SEL_END:
274 case VI_SEL_START:
275 evp->e_event = E_IPCOMMAND;
276 evp->e_ipcom = ipp->ibuf[0];
277 fmt = "12";
278 break;
279 case VI_RESIZE:
280 evp->e_event = E_WRESIZE;
281 fmt = "12";
282 break;
283 case VI_SIGHUP:
284 evp->e_event = E_SIGHUP;
285 ipp->iskip = IPO_CODE_LEN;
286 return (1);
287 case VI_SIGTERM:
288 evp->e_event = E_SIGTERM;
289 ipp->iskip = IPO_CODE_LEN;
290 return (1);
291 case VI_STRING:
292 evp->e_event = E_STRING;
293 fmt = "a";
294 break;
295 default:
297 * XXX: Protocol is out of sync?
299 abort();
302 for (skip = IPO_CODE_LEN; *fmt != '\0'; ++fmt)
303 switch (*fmt) {
304 case '1':
305 case '2':
306 if (ipp->iblen < skip + IPO_INT_LEN)
307 return (0);
308 memcpy(&val, ipp->ibuf + skip, IPO_INT_LEN);
309 val = ntohl(val);
310 if (*fmt == '1')
311 evp->e_val1 = val;
312 else
313 evp->e_val2 = val;
314 skip += IPO_INT_LEN;
315 break;
316 case 'a':
317 case 'b':
318 if (ipp->iblen < skip + IPO_INT_LEN)
319 return (0);
320 memcpy(&val, ipp->ibuf + skip, IPO_INT_LEN);
321 val = ntohl(val);
322 skip += IPO_INT_LEN;
323 if (ipp->iblen < skip + val)
324 return (0);
325 if (*fmt == 'a') {
326 evp->e_str1 = ipp->ibuf + skip;
327 evp->e_len1 = val;
328 } else {
329 evp->e_str2 = ipp->ibuf + skip;
330 evp->e_len2 = val;
332 skip += val;
333 break;
336 ipp->iskip = skip;
338 if (evp->e_event == E_WRESIZE)
339 (void)ip_resize(sp, evp->e_val1, evp->e_val2);
341 return (1);
345 * ip_resize --
346 * Reset the options for a resize event.
348 static int
349 ip_resize(sp, lines, columns)
350 SCR *sp;
351 u_int32_t lines, columns;
353 GS *gp;
354 int rval;
357 * XXX
358 * The IP screen has to know the lines and columns before anything
359 * else happens. So, we may not have a valid SCR pointer, and we
360 * have to deal with that.
362 if (sp == NULL) {
363 gp = __global_list;
364 OG_VAL(gp, GO_LINES) = OG_D_VAL(gp, GO_LINES) = lines;
365 OG_VAL(gp, GO_COLUMNS) = OG_D_VAL(gp, GO_COLUMNS) = columns;
366 return (0);
369 rval = api_opts_set(sp, "lines", NULL, lines, 0);
370 if (api_opts_set(sp, "columns", NULL, columns, 0))
371 rval = 1;
372 return (rval);