1 /*- 2 * Copyright (c) 1993, 1994 3 * The Regents of the University of California. All rights reserved. 4 * Copyright (c) 1993, 1994, 1995, 1996 5 * Keith Bostic. All rights reserved. 6 * 7 * See the LICENSE file for redistribution information. 8 */ 9 10 #include "config.h" 11 12 #ifndef lint 13 static const char sccsid[] = "$Id: cl_read.c,v 10.30 2012/07/12 18:28:58 zy Exp $"; 14 #endif /* not lint */ 15 16 #include <sys/types.h> 17 #include <sys/queue.h> 18 #include <sys/select.h> 19 20 #include <bitstring.h> 21 #include <errno.h> 22 #include <fcntl.h> 23 #include <signal.h> 24 #include <stdio.h> 25 #include <stdlib.h> 26 #include <string.h> 27 #include <termios.h> 28 #include <unistd.h> 29 30 #include "../common/common.h" 31 #include "../ex/script.h" 32 #include "cl.h" 33 34 /* Pollution by Solaris curses. */ 35 #undef columns 36 #undef lines 37 38 static input_t cl_read __P((SCR *, 39 u_int32_t, char *, size_t, int *, struct timeval *)); 40 static int cl_resize __P((SCR *, size_t, size_t)); 41 42 /* 43 * cl_event -- 44 * Return a single event. 45 * 46 * PUBLIC: int cl_event __P((SCR *, EVENT *, u_int32_t, int)); 47 */ 48 int 49 cl_event(SCR *sp, EVENT *evp, u_int32_t flags, int ms) 50 { 51 struct timeval t, *tp; 52 CL_PRIVATE *clp; 53 size_t lines, columns; 54 int changed, nr = 0; 55 CHAR_T *wp; 56 size_t wlen; 57 int rc; 58 59 /* 60 * Queue signal based events. We never clear SIGHUP or SIGTERM events, 61 * so that we just keep returning them until the editor dies. 62 */ 63 clp = CLP(sp); 64 retest: if (LF_ISSET(EC_INTERRUPT) || F_ISSET(clp, CL_SIGINT)) { 65 if (F_ISSET(clp, CL_SIGINT)) { 66 F_CLR(clp, CL_SIGINT); 67 evp->e_event = E_INTERRUPT; 68 } else 69 evp->e_event = E_TIMEOUT; 70 return (0); 71 } 72 if (F_ISSET(clp, CL_SIGHUP | CL_SIGTERM | CL_SIGWINCH)) { 73 if (F_ISSET(clp, CL_SIGHUP)) { 74 evp->e_event = E_SIGHUP; 75 return (0); 76 } 77 if (F_ISSET(clp, CL_SIGTERM)) { 78 evp->e_event = E_SIGTERM; 79 return (0); 80 } 81 if (F_ISSET(clp, CL_SIGWINCH)) { 82 F_CLR(clp, CL_SIGWINCH); 83 if (cl_ssize(sp, 1, &lines, &columns, &changed)) 84 return (1); 85 if (changed) { 86 (void)cl_resize(sp, lines, columns); 87 evp->e_event = E_WRESIZE; 88 return (0); 89 } 90 /* No real change, ignore the signal. */ 91 } 92 } 93 94 /* Set timer. */ 95 if (ms == 0) 96 tp = NULL; 97 else { 98 t.tv_sec = ms / 1000; 99 t.tv_usec = (ms % 1000) * 1000; 100 tp = &t; 101 } 102 103 /* Read input characters. */ 104 read: 105 switch (cl_read(sp, LF_ISSET(EC_QUOTED | EC_RAW), 106 clp->ibuf + clp->skip, SIZE(clp->ibuf) - clp->skip, &nr, tp)) { 107 case INP_OK: 108 rc = INPUT2INT5(sp, clp->cw, clp->ibuf, nr + clp->skip, 109 wp, wlen); 110 evp->e_csp = wp; 111 evp->e_len = wlen; 112 evp->e_event = E_STRING; 113 if (rc < 0) { 114 int n = -rc; 115 memmove(clp->ibuf, clp->ibuf + nr + clp->skip - n, n); 116 clp->skip = n; 117 if (wlen == 0) 118 goto read; 119 } else if (rc == 0) 120 clp->skip = 0; 121 else 122 msgq(sp, M_ERR, "323|Invalid input. Truncated."); 123 break; 124 case INP_EOF: 125 evp->e_event = E_EOF; 126 break; 127 case INP_ERR: 128 evp->e_event = E_ERR; 129 break; 130 case INP_INTR: 131 goto retest; 132 case INP_TIMEOUT: 133 evp->e_event = E_TIMEOUT; 134 break; 135 default: 136 abort(); 137 } 138 return (0); 139 } 140 141 /* 142 * cl_read -- 143 * Read characters from the input. 144 */ 145 static input_t 146 cl_read(SCR *sp, u_int32_t flags, char *bp, size_t blen, int *nrp, struct timeval *tp) 147 { 148 struct termios term1, term2; 149 CL_PRIVATE *clp; 150 GS *gp; 151 fd_set rdfd; 152 input_t rval; 153 int maxfd, nr, term_reset; 154 155 gp = sp->gp; 156 clp = CLP(sp); 157 term_reset = 0; 158 159 /* 160 * 1: A read from a file or a pipe. In this case, the reads 161 * never timeout regardless. This means that we can hang 162 * when trying to complete a map, but we're going to hang 163 * on the next read anyway. 164 */ 165 if (!F_ISSET(clp, CL_STDIN_TTY)) { 166 switch (nr = read(STDIN_FILENO, bp, blen)) { 167 case 0: 168 return (INP_EOF); 169 case -1: 170 goto err; 171 default: 172 *nrp = nr; 173 return (INP_OK); 174 } 175 /* NOTREACHED */ 176 } 177 178 /* 179 * 2: A read with an associated timeout, e.g., trying to complete 180 * a map sequence. If input exists, we fall into #3. 181 */ 182 if (tp != NULL) { 183 FD_ZERO(&rdfd); 184 FD_SET(STDIN_FILENO, &rdfd); 185 switch (select(STDIN_FILENO + 1, &rdfd, NULL, NULL, tp)) { 186 case 0: 187 return (INP_TIMEOUT); 188 case -1: 189 goto err; 190 default: 191 break; 192 } 193 } 194 195 /* 196 * The user can enter a key in the editor to quote a character. If we 197 * get here and the next key is supposed to be quoted, do what we can. 198 * Reset the tty so that the user can enter a ^C, ^Q, ^S. There's an 199 * obvious race here, when the key has already been entered, but there's 200 * nothing that we can do to fix that problem. 201 * 202 * The editor can ask for the next literal character even thought it's 203 * generally running in line-at-a-time mode. Do what we can. 204 */ 205 if (LF_ISSET(EC_QUOTED | EC_RAW) && !tcgetattr(STDIN_FILENO, &term1)) { 206 term_reset = 1; 207 if (LF_ISSET(EC_QUOTED)) { 208 term2 = term1; 209 term2.c_lflag &= ~ISIG; 210 term2.c_iflag &= ~(IXON | IXOFF); 211 (void)tcsetattr(STDIN_FILENO, 212 TCSASOFT | TCSADRAIN, &term2); 213 } else 214 (void)tcsetattr(STDIN_FILENO, 215 TCSASOFT | TCSADRAIN, &clp->vi_enter); 216 } 217 218 /* 219 * 3: Wait for input. 220 * 221 * Select on the command input and scripting window file descriptors. 222 * It's ugly that we wait on scripting file descriptors here, but it's 223 * the only way to keep from locking out scripting windows. 224 */ 225 if (F_ISSET(gp, G_SCRWIN)) { 226 loop: FD_ZERO(&rdfd); 227 FD_SET(STDIN_FILENO, &rdfd); 228 maxfd = STDIN_FILENO; 229 if (F_ISSET(sp, SC_SCRIPT)) { 230 FD_SET(sp->script->sh_master, &rdfd); 231 if (sp->script->sh_master > maxfd) 232 maxfd = sp->script->sh_master; 233 } 234 switch (select(maxfd + 1, &rdfd, NULL, NULL, NULL)) { 235 case 0: 236 abort(); 237 case -1: 238 goto err; 239 default: 240 break; 241 } 242 if (!FD_ISSET(STDIN_FILENO, &rdfd)) { 243 if (sscr_input(sp)) 244 return (INP_ERR); 245 goto loop; 246 } 247 } 248 249 /* 250 * 4: Read the input. 251 * 252 * !!! 253 * What's going on here is some scary stuff. Ex runs the terminal in 254 * canonical mode. So, the <newline> character terminating a line of 255 * input is returned in the buffer, but a trailing <EOF> character is 256 * not similarly included. As ex uses 0<EOF> and ^<EOF> as autoindent 257 * commands, it has to see the trailing <EOF> characters to determine 258 * the difference between the user entering "0ab" and "0<EOF>ab". We 259 * leave an extra slot in the buffer, so that we can add a trailing 260 * <EOF> character if the buffer isn't terminated by a <newline>. We 261 * lose if the buffer is too small for the line and exactly N characters 262 * are entered followed by an <EOF> character. 263 */ 264 #define ONE_FOR_EOF 1 265 switch (nr = read(STDIN_FILENO, bp, blen - ONE_FOR_EOF)) { 266 case 0: /* EOF. */ 267 /* 268 * ^D in canonical mode returns a read of 0, i.e. EOF. EOF is 269 * a valid command, but we don't want to loop forever because 270 * the terminal driver is returning EOF because the user has 271 * disconnected. The editor will almost certainly try to write 272 * something before this fires, which should kill us, but You 273 * Never Know. 274 */ 275 if (++clp->eof_count < 50) { 276 bp[0] = clp->orig.c_cc[VEOF]; 277 *nrp = 1; 278 rval = INP_OK; 279 280 } else 281 rval = INP_EOF; 282 break; 283 case -1: /* Error or interrupt. */ 284 err: if (errno == EINTR) 285 rval = INP_INTR; 286 else { 287 rval = INP_ERR; 288 msgq(sp, M_SYSERR, "input"); 289 } 290 break; 291 default: /* Input characters. */ 292 if (F_ISSET(sp, SC_EX) && bp[nr - 1] != '\n') 293 bp[nr++] = clp->orig.c_cc[VEOF]; 294 *nrp = nr; 295 clp->eof_count = 0; 296 rval = INP_OK; 297 break; 298 } 299 300 /* Restore the terminal state if it was modified. */ 301 if (term_reset) 302 (void)tcsetattr(STDIN_FILENO, TCSASOFT | TCSADRAIN, &term1); 303 return (rval); 304 } 305 306 /* 307 * cl_resize -- 308 * Reset the options for a resize event. 309 */ 310 static int 311 cl_resize(SCR *sp, size_t lines, size_t columns) 312 { 313 ARGS *argv[2], a, b; 314 CHAR_T b1[1024]; 315 316 a.bp = b1; 317 b.bp = NULL; 318 a.len = b.len = 0; 319 argv[0] = &a; 320 argv[1] = &b; 321 322 a.len = SPRINTF(b1, sizeof(b1), L("lines=%lu"), (u_long)lines); 323 if (opts_set(sp, argv, NULL)) 324 return (1); 325 a.len = SPRINTF(b1, sizeof(b1), L("columns=%lu"), (u_long)columns); 326 if (opts_set(sp, argv, NULL)) 327 return (1); 328 return (0); 329 } 330