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 | } |
---|