update from From: Sven Verdoolaege <skimo@breughel.ufsia.ac.be>
[nvi.git] / ip / ip_read.c
blobf0acd0d8f76ac4b6855b547fa4f91f6dc26266d5
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.16 1996/12/18 10:28:03 bostic Exp $ (Berkeley) $Date: 1996/12/18 10:28:03 $";
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 /* Set timer. */
70 if (ms == 0)
71 tp = NULL;
72 else {
73 t.tv_sec = ms / 1000;
74 t.tv_usec = (ms % 1000) * 1000;
75 tp = &t;
78 /* Read input events. */
79 for (;;) {
80 switch (ip_read(sp, ipp, tp)) {
81 case INP_OK:
82 if (!ip_trans(sp, ipp, evp))
83 continue;
84 break;
85 case INP_EOF:
86 evp->e_event = E_EOF;
87 break;
88 case INP_ERR:
89 evp->e_event = E_ERR;
90 break;
91 case INP_TIMEOUT:
92 evp->e_event = E_TIMEOUT;
93 break;
94 default:
95 abort();
97 break;
99 return (0);
103 * ip_read --
104 * Read characters from the input.
106 static input_t
107 ip_read(sp, ipp, tp)
108 SCR *sp;
109 IP_PRIVATE *ipp;
110 struct timeval *tp;
112 struct timeval poll;
113 GS *gp;
114 SCR *tsp;
115 fd_set rdfd;
116 input_t rval;
117 size_t blen;
118 int maxfd, nr;
119 char *bp;
121 gp = sp == NULL ? __global_list : sp->gp;
122 bp = ipp->ibuf + ipp->iblen;
123 blen = sizeof(ipp->ibuf) - ipp->iblen;
126 * 1: A read with an associated timeout, e.g., trying to complete
127 * a map sequence. If input exists, we fall into #2.
129 FD_ZERO(&rdfd);
130 poll.tv_sec = 0;
131 poll.tv_usec = 0;
132 if (tp != NULL) {
133 FD_SET(ipp->i_fd, &rdfd);
134 switch (select(ipp->i_fd + 1,
135 &rdfd, NULL, NULL, tp == NULL ? &poll : tp)) {
136 case 0:
137 return (INP_TIMEOUT);
138 case -1:
139 goto err;
140 default:
141 break;
146 * 2: Wait for input.
148 * Select on the command input and scripting window file descriptors.
149 * It's ugly that we wait on scripting file descriptors here, but it's
150 * the only way to keep from locking out scripting windows.
152 if (sp != NULL && F_ISSET(gp, G_SCRWIN)) {
153 loop: FD_ZERO(&rdfd);
154 FD_SET(ipp->i_fd, &rdfd);
155 maxfd = ipp->i_fd;
156 for (tsp = gp->dq.cqh_first;
157 tsp != (void *)&gp->dq; tsp = tsp->q.cqe_next)
158 if (F_ISSET(sp, SC_SCRIPT)) {
159 FD_SET(sp->script->sh_master, &rdfd);
160 if (sp->script->sh_master > maxfd)
161 maxfd = sp->script->sh_master;
163 switch (select(maxfd + 1, &rdfd, NULL, NULL, NULL)) {
164 case 0:
165 abort();
166 case -1:
167 goto err;
168 default:
169 break;
171 if (!FD_ISSET(ipp->i_fd, &rdfd)) {
172 if (sscr_input(sp))
173 return (INP_ERR);
174 goto loop;
179 * 3: Read the input.
181 switch (nr = read(ipp->i_fd, bp, blen)) {
182 case 0: /* EOF. */
183 rval = INP_EOF;
184 break;
185 case -1: /* Error or interrupt. */
186 err: rval = INP_ERR;
187 msgq(sp, M_SYSERR, "input");
188 break;
189 default: /* Input characters. */
190 ipp->iblen += nr;
191 rval = INP_OK;
192 break;
194 return (rval);
198 * ip_trans --
199 * Translate messages into events.
201 static int
202 ip_trans(sp, ipp, evp)
203 SCR *sp;
204 IP_PRIVATE *ipp;
205 EVENT *evp;
207 u_int32_t skip, val;
208 char *fmt;
210 switch (ipp->ibuf[0]) {
211 case VI_C_BOL:
212 case VI_C_BOTTOM:
213 case VI_C_DEL:
214 case VI_C_EOL:
215 case VI_C_INSERT:
216 case VI_C_LEFT:
217 case VI_C_RIGHT:
218 case VI_C_TOP:
219 case VI_QUIT:
220 case VI_TAG:
221 case VI_TAGSPLIT:
222 case VI_UNDO:
223 case VI_WQ:
224 case VI_WRITE:
225 evp->e_event = E_IPCOMMAND;
226 evp->e_ipcom = ipp->ibuf[0];
227 ipp->iskip = IPO_CODE_LEN;
228 return (1);
229 case VI_C_DOWN:
230 case VI_C_PGDOWN:
231 case VI_C_PGUP:
232 case VI_C_UP:
233 case VI_C_SETTOP:
234 evp->e_event = E_IPCOMMAND;
235 evp->e_ipcom = ipp->ibuf[0];
236 fmt = "1";
237 break;
238 case VI_C_SEARCH:
239 evp->e_event = E_IPCOMMAND;
240 evp->e_ipcom = ipp->ibuf[0];
241 fmt = "a1";
242 break;
243 case VI_EDIT:
244 case VI_EDITSPLIT:
245 case VI_TAGAS:
246 case VI_WRITEAS:
247 evp->e_event = E_IPCOMMAND;
248 evp->e_ipcom = ipp->ibuf[0];
249 fmt = "a";
250 break;
251 case VI_EDITOPT:
252 evp->e_event = E_IPCOMMAND;
253 evp->e_ipcom = ipp->ibuf[0];
254 fmt = "ab1";
255 break;
256 case VI_EOF:
257 evp->e_event = E_EOF;
258 ipp->iskip = IPO_CODE_LEN;
259 return (1);
260 case VI_ERR:
261 evp->e_event = E_ERR;
262 ipp->iskip = IPO_CODE_LEN;
263 return (1);
264 case VI_INTERRUPT:
265 evp->e_event = E_INTERRUPT;
266 ipp->iskip = IPO_CODE_LEN;
267 return (1);
268 case VI_MOUSE_MOVE:
269 case VI_SEL_END:
270 case VI_SEL_START:
271 evp->e_event = E_IPCOMMAND;
272 evp->e_ipcom = ipp->ibuf[0];
273 fmt = "12";
274 break;
275 case VI_RESIZE:
276 evp->e_event = E_WRESIZE;
277 fmt = "12";
278 break;
279 case VI_SIGHUP:
280 evp->e_event = E_SIGHUP;
281 ipp->iskip = IPO_CODE_LEN;
282 return (1);
283 case VI_SIGTERM:
284 evp->e_event = E_SIGTERM;
285 ipp->iskip = IPO_CODE_LEN;
286 return (1);
287 case VI_STRING:
288 evp->e_event = E_STRING;
289 fmt = "a";
290 break;
291 default:
293 * XXX: Protocol is out of sync?
295 abort();
298 for (skip = IPO_CODE_LEN; *fmt != '\0'; ++fmt)
299 switch (*fmt) {
300 case '1':
301 case '2':
302 if (ipp->iblen < skip + IPO_INT_LEN)
303 return (0);
304 memcpy(&val, ipp->ibuf + skip, IPO_INT_LEN);
305 val = ntohl(val);
306 if (*fmt == '1')
307 evp->e_val1 = val;
308 else
309 evp->e_val2 = val;
310 skip += IPO_INT_LEN;
311 break;
312 case 'a':
313 case 'b':
314 if (ipp->iblen < skip + IPO_INT_LEN)
315 return (0);
316 memcpy(&val, ipp->ibuf + skip, IPO_INT_LEN);
317 val = ntohl(val);
318 skip += IPO_INT_LEN;
319 if (ipp->iblen < skip + val)
320 return (0);
321 if (*fmt == 'a') {
322 evp->e_str1 = ipp->ibuf + skip;
323 evp->e_len1 = val;
324 } else {
325 evp->e_str2 = ipp->ibuf + skip;
326 evp->e_len2 = val;
328 skip += val;
329 break;
332 ipp->iskip = skip;
334 if (evp->e_event == E_WRESIZE)
335 (void)ip_resize(sp, evp->e_val1, evp->e_val2);
337 return (1);
341 * ip_resize --
342 * Reset the options for a resize event.
344 static int
345 ip_resize(sp, lines, columns)
346 SCR *sp;
347 u_int32_t lines, columns;
349 GS *gp;
350 int rval;
353 * XXX
354 * The IP screen has to know the lines and columns before anything
355 * else happens. So, we may not have a valid SCR pointer, and we
356 * have to deal with that.
358 if (sp == NULL) {
359 gp = __global_list;
360 OG_VAL(gp, GO_LINES) = OG_D_VAL(gp, GO_LINES) = lines;
361 OG_VAL(gp, GO_COLUMNS) = OG_D_VAL(gp, GO_COLUMNS) = columns;
362 return (0);
365 rval = api_opts_set(sp, "lines", NULL, lines, 0);
366 if (api_opts_set(sp, "columns", NULL, columns, 0))
367 rval = 1;
368 return (rval);