add VI_SEL_END, VI_SEL_START
[nvi.git] / ip / ip_read.c
blobecf29ac8aa472a716d984175590f881b4ebdd865
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.15 1996/12/17 20:15:22 bostic Exp $ (Berkeley) $Date: 1996/12/17 20:15:22 $";
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 "ip.h"
30 extern GS *__global_list;
32 typedef enum { INP_OK=0, INP_EOF, INP_ERR, INP_TIMEOUT } input_t;
34 static input_t ip_read __P((SCR *, IP_PRIVATE *, struct timeval *));
35 static int ip_resize __P((SCR *, u_int32_t, u_int32_t));
36 static int ip_trans __P((SCR *, IP_PRIVATE *, EVENT *));
39 * ip_event --
40 * Return a single event.
42 * PUBLIC: int ip_event __P((SCR *, EVENT *, u_int32_t, int));
44 int
45 ip_event(sp, evp, flags, ms)
46 SCR *sp;
47 EVENT *evp;
48 u_int32_t flags;
49 int ms;
51 IP_PRIVATE *ipp;
52 struct timeval t, *tp;
54 if (LF_ISSET(EC_INTERRUPT)) { /* XXX */
55 evp->e_event = E_TIMEOUT;
56 return (0);
59 ipp = sp == NULL ? GIPP(__global_list) : IPP(sp);
61 /* Discard the last command. */
62 if (ipp->iskip != 0) {
63 ipp->iblen -= ipp->iskip;
64 memmove(ipp->ibuf, ipp->ibuf + ipp->iskip, ipp->iblen);
65 ipp->iskip = 0;
68 /* Set timer. */
69 if (ms == 0)
70 tp = NULL;
71 else {
72 t.tv_sec = ms / 1000;
73 t.tv_usec = (ms % 1000) * 1000;
74 tp = &t;
77 /* Read input events. */
78 for (;;) {
79 switch (ip_read(sp, ipp, tp)) {
80 case INP_OK:
81 if (!ip_trans(sp, ipp, evp))
82 continue;
83 break;
84 case INP_EOF:
85 evp->e_event = E_EOF;
86 break;
87 case INP_ERR:
88 evp->e_event = E_ERR;
89 break;
90 case INP_TIMEOUT:
91 evp->e_event = E_TIMEOUT;
92 break;
93 default:
94 abort();
96 break;
98 return (0);
102 * ip_read --
103 * Read characters from the input.
105 static input_t
106 ip_read(sp, ipp, tp)
107 SCR *sp;
108 IP_PRIVATE *ipp;
109 struct timeval *tp;
111 struct timeval poll;
112 GS *gp;
113 SCR *tsp;
114 fd_set rdfd;
115 input_t rval;
116 size_t blen;
117 int maxfd, nr;
118 char *bp;
120 gp = sp == NULL ? __global_list : sp->gp;
121 bp = ipp->ibuf + ipp->iblen;
122 blen = sizeof(ipp->ibuf) - ipp->iblen;
125 * 1: A read with an associated timeout, e.g., trying to complete
126 * a map sequence. If input exists, we fall into #2.
128 FD_ZERO(&rdfd);
129 poll.tv_sec = 0;
130 poll.tv_usec = 0;
131 if (tp != NULL) {
132 FD_SET(ipp->i_fd, &rdfd);
133 switch (select(ipp->i_fd + 1,
134 &rdfd, NULL, NULL, tp == NULL ? &poll : tp)) {
135 case 0:
136 return (INP_TIMEOUT);
137 case -1:
138 goto err;
139 default:
140 break;
145 * 2: Wait for input.
147 * Select on the command input and scripting window file descriptors.
148 * It's ugly that we wait on scripting file descriptors here, but it's
149 * the only way to keep from locking out scripting windows.
151 if (sp != NULL && F_ISSET(gp, G_SCRWIN)) {
152 loop: FD_ZERO(&rdfd);
153 FD_SET(ipp->i_fd, &rdfd);
154 maxfd = ipp->i_fd;
155 for (tsp = gp->dq.cqh_first;
156 tsp != (void *)&gp->dq; tsp = tsp->q.cqe_next)
157 if (F_ISSET(sp, SC_SCRIPT)) {
158 FD_SET(sp->script->sh_master, &rdfd);
159 if (sp->script->sh_master > maxfd)
160 maxfd = sp->script->sh_master;
162 switch (select(maxfd + 1, &rdfd, NULL, NULL, NULL)) {
163 case 0:
164 abort();
165 case -1:
166 goto err;
167 default:
168 break;
170 if (!FD_ISSET(ipp->i_fd, &rdfd)) {
171 if (sscr_input(sp))
172 return (INP_ERR);
173 goto loop;
178 * 3: Read the input.
180 switch (nr = read(ipp->i_fd, bp, blen)) {
181 case 0: /* EOF. */
182 rval = INP_EOF;
183 break;
184 case -1: /* Error or interrupt. */
185 err: rval = INP_ERR;
186 msgq(sp, M_SYSERR, "input");
187 break;
188 default: /* Input characters. */
189 ipp->iblen += nr;
190 rval = INP_OK;
191 break;
193 return (rval);
197 * ip_trans --
198 * Translate messages into events.
200 static int
201 ip_trans(sp, ipp, evp)
202 SCR *sp;
203 IP_PRIVATE *ipp;
204 EVENT *evp;
206 u_int32_t skip, val;
207 char *fmt;
209 switch (ipp->ibuf[0]) {
210 case VI_C_BOL:
211 case VI_C_BOTTOM:
212 case VI_C_DEL:
213 case VI_C_EOL:
214 case VI_C_INSERT:
215 case VI_C_LEFT:
216 case VI_C_RIGHT:
217 case VI_C_TOP:
218 case VI_QUIT:
219 case VI_TAG:
220 case VI_TAGSPLIT:
221 case VI_UNDO:
222 case VI_WQ:
223 case VI_WRITE:
224 evp->e_event = E_IPCOMMAND;
225 evp->e_ipcom = ipp->ibuf[0];
226 ipp->iskip = IPO_CODE_LEN;
227 return (1);
228 case VI_C_DOWN:
229 case VI_C_PGDOWN:
230 case VI_C_PGUP:
231 case VI_C_UP:
232 case VI_C_SETTOP:
233 evp->e_event = E_IPCOMMAND;
234 evp->e_ipcom = ipp->ibuf[0];
235 fmt = "1";
236 break;
237 case VI_C_SEARCH:
238 evp->e_event = E_IPCOMMAND;
239 evp->e_ipcom = ipp->ibuf[0];
240 fmt = "a1";
241 break;
242 case VI_EDIT:
243 case VI_EDITSPLIT:
244 case VI_TAGAS:
245 case VI_WRITEAS:
246 evp->e_event = E_IPCOMMAND;
247 evp->e_ipcom = ipp->ibuf[0];
248 fmt = "a";
249 break;
250 case VI_EDITOPT:
251 evp->e_event = E_IPCOMMAND;
252 evp->e_ipcom = ipp->ibuf[0];
253 fmt = "ab1";
254 break;
255 case VI_EOF:
256 evp->e_event = E_EOF;
257 ipp->iskip = IPO_CODE_LEN;
258 return (1);
259 case VI_ERR:
260 evp->e_event = E_ERR;
261 ipp->iskip = IPO_CODE_LEN;
262 return (1);
263 case VI_INTERRUPT:
264 evp->e_event = E_INTERRUPT;
265 ipp->iskip = IPO_CODE_LEN;
266 return (1);
267 case VI_MOUSE_MOVE:
268 case VI_SEL_END:
269 case VI_SEL_START:
270 evp->e_event = E_IPCOMMAND;
271 evp->e_ipcom = ipp->ibuf[0];
272 fmt = "12";
273 break;
274 case VI_RESIZE:
275 evp->e_event = E_WRESIZE;
276 fmt = "12";
277 break;
278 case VI_SIGHUP:
279 evp->e_event = E_SIGHUP;
280 ipp->iskip = IPO_CODE_LEN;
281 return (1);
282 case VI_SIGTERM:
283 evp->e_event = E_SIGTERM;
284 ipp->iskip = IPO_CODE_LEN;
285 return (1);
286 case VI_STRING:
287 evp->e_event = E_STRING;
288 fmt = "a";
289 break;
290 default:
292 * XXX: Protocol is out of sync?
294 abort();
297 for (skip = IPO_CODE_LEN; *fmt != '\0'; ++fmt)
298 switch (*fmt) {
299 case '1':
300 case '2':
301 if (ipp->iblen < skip + IPO_INT_LEN)
302 return (0);
303 memcpy(&val, ipp->ibuf + skip, IPO_INT_LEN);
304 val = ntohl(val);
305 if (*fmt == '1')
306 evp->e_val1 = val;
307 else
308 evp->e_val2 = val;
309 skip += IPO_INT_LEN;
310 break;
311 case 'a':
312 case 'b':
313 if (ipp->iblen < skip + IPO_INT_LEN)
314 return (0);
315 memcpy(&val, ipp->ibuf + skip, IPO_INT_LEN);
316 val = ntohl(val);
317 skip += IPO_INT_LEN;
318 if (ipp->iblen < skip + val)
319 return (0);
320 if (*fmt == 'a') {
321 evp->e_str1 = ipp->ibuf + skip;
322 evp->e_len1 = val;
323 } else {
324 evp->e_str2 = ipp->ibuf + skip;
325 evp->e_len2 = val;
327 skip += val;
328 break;
331 ipp->iskip = skip;
333 if (evp->e_event == E_WRESIZE)
334 (void)ip_resize(sp, evp->e_val1, evp->e_val2);
336 return (1);
340 * ip_resize --
341 * Reset the options for a resize event.
343 static int
344 ip_resize(sp, lines, columns)
345 SCR *sp;
346 u_int32_t lines, columns;
348 GS *gp;
349 int rval;
352 * XXX
353 * The IP screen has to know the lines and columns before anything
354 * else happens. So, we may not have a valid SCR pointer, and we
355 * have to deal with that.
357 if (sp == NULL) {
358 gp = __global_list;
359 OG_VAL(gp, GO_LINES) = OG_D_VAL(gp, GO_LINES) = lines;
360 OG_VAL(gp, GO_COLUMNS) = OG_D_VAL(gp, GO_COLUMNS) = columns;
361 return (0);
364 rval = api_opts_set(sp, "lines", NULL, lines, 0);
365 if (api_opts_set(sp, "columns", NULL, columns, 0))
366 rval = 1;
367 return (rval);