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 11static 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 26extern GS *__global_list; 27 28typedef enum { INP_OK=0, INP_EOF, INP_ERR, INP_TIMEOUT } input_t; 29 30static input_t ip_read __P((SCR *, IP_PRIVATE *, struct timeval *)); 31static int ip_resize __P((SCR *, size_t, size_t)); 32static 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 */ 40int 41ip_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 */ 101static input_t 102ip_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)) { 148loop: 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. */ 181err: 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 */ 196static int 197ip_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; 243string: 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 */ 270static int 271ip_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} 308