119304Speter/*- 219304Speter * Copyright (c) 1993, 1994 319304Speter * The Regents of the University of California. All rights reserved. 419304Speter * Copyright (c) 1993, 1994, 1995, 1996 519304Speter * Keith Bostic. All rights reserved. 619304Speter * 719304Speter * See the LICENSE file for redistribution information. 819304Speter */ 919304Speter 1019304Speter#include "config.h" 1119304Speter 1219304Speter#ifndef lint 13254225Speterstatic const char sccsid[] = "$Id: cl_read.c,v 10.30 2012/07/12 18:28:58 zy Exp $"; 1419304Speter#endif /* not lint */ 1519304Speter 1619304Speter#include <sys/types.h> 1719304Speter#include <sys/queue.h> 1819304Speter#include <sys/select.h> 1919304Speter 2019304Speter#include <bitstring.h> 2119304Speter#include <errno.h> 2219304Speter#include <fcntl.h> 2319304Speter#include <signal.h> 2419304Speter#include <stdio.h> 2519304Speter#include <stdlib.h> 2619304Speter#include <string.h> 2719304Speter#include <termios.h> 2819304Speter#include <unistd.h> 2919304Speter 3019304Speter#include "../common/common.h" 3119304Speter#include "../ex/script.h" 3219304Speter#include "cl.h" 3319304Speter 34254225Speter/* Pollution by Solaris curses. */ 35254225Speter#undef columns 36254225Speter#undef lines 37254225Speter 3819304Speterstatic input_t cl_read __P((SCR *, 39254225Speter u_int32_t, char *, size_t, int *, struct timeval *)); 4019304Speterstatic int cl_resize __P((SCR *, size_t, size_t)); 4119304Speter 4219304Speter/* 4319304Speter * cl_event -- 4419304Speter * Return a single event. 4519304Speter * 4619304Speter * PUBLIC: int cl_event __P((SCR *, EVENT *, u_int32_t, int)); 4719304Speter */ 4819304Speterint 49254225Spetercl_event(SCR *sp, EVENT *evp, u_int32_t flags, int ms) 5019304Speter{ 5119304Speter struct timeval t, *tp; 5219304Speter CL_PRIVATE *clp; 5319304Speter size_t lines, columns; 54254225Speter int changed, nr = 0; 55254225Speter CHAR_T *wp; 56254225Speter size_t wlen; 57254225Speter int rc; 5819304Speter 5919304Speter /* 6019304Speter * Queue signal based events. We never clear SIGHUP or SIGTERM events, 6119304Speter * so that we just keep returning them until the editor dies. 6219304Speter */ 6319304Speter clp = CLP(sp); 6419304Speterretest: if (LF_ISSET(EC_INTERRUPT) || F_ISSET(clp, CL_SIGINT)) { 6519304Speter if (F_ISSET(clp, CL_SIGINT)) { 6619304Speter F_CLR(clp, CL_SIGINT); 6719304Speter evp->e_event = E_INTERRUPT; 6819304Speter } else 6919304Speter evp->e_event = E_TIMEOUT; 7019304Speter return (0); 7119304Speter } 7219304Speter if (F_ISSET(clp, CL_SIGHUP | CL_SIGTERM | CL_SIGWINCH)) { 7319304Speter if (F_ISSET(clp, CL_SIGHUP)) { 7419304Speter evp->e_event = E_SIGHUP; 7519304Speter return (0); 7619304Speter } 7719304Speter if (F_ISSET(clp, CL_SIGTERM)) { 7819304Speter evp->e_event = E_SIGTERM; 7919304Speter return (0); 8019304Speter } 8119304Speter if (F_ISSET(clp, CL_SIGWINCH)) { 8219304Speter F_CLR(clp, CL_SIGWINCH); 8319304Speter if (cl_ssize(sp, 1, &lines, &columns, &changed)) 8419304Speter return (1); 8519304Speter if (changed) { 8619304Speter (void)cl_resize(sp, lines, columns); 8719304Speter evp->e_event = E_WRESIZE; 8819304Speter return (0); 8919304Speter } 9019304Speter /* No real change, ignore the signal. */ 9119304Speter } 9219304Speter } 9319304Speter 9419304Speter /* Set timer. */ 9519304Speter if (ms == 0) 9619304Speter tp = NULL; 9719304Speter else { 9819304Speter t.tv_sec = ms / 1000; 9919304Speter t.tv_usec = (ms % 1000) * 1000; 10019304Speter tp = &t; 10119304Speter } 10219304Speter 10319304Speter /* Read input characters. */ 104254225Speterread: 10519304Speter switch (cl_read(sp, LF_ISSET(EC_QUOTED | EC_RAW), 106254225Speter clp->ibuf + clp->skip, SIZE(clp->ibuf) - clp->skip, &nr, tp)) { 10719304Speter case INP_OK: 108254225Speter rc = INPUT2INT5(sp, clp->cw, clp->ibuf, nr + clp->skip, 109254225Speter wp, wlen); 110254225Speter evp->e_csp = wp; 111254225Speter evp->e_len = wlen; 11219304Speter evp->e_event = E_STRING; 113254225Speter if (rc < 0) { 114254225Speter int n = -rc; 115254225Speter memmove(clp->ibuf, clp->ibuf + nr + clp->skip - n, n); 116254225Speter clp->skip = n; 117254225Speter if (wlen == 0) 118254225Speter goto read; 119254225Speter } else if (rc == 0) 120254225Speter clp->skip = 0; 121254225Speter else 122254225Speter msgq(sp, M_ERR, "323|Invalid input. Truncated."); 12319304Speter break; 12419304Speter case INP_EOF: 12519304Speter evp->e_event = E_EOF; 12619304Speter break; 12719304Speter case INP_ERR: 12819304Speter evp->e_event = E_ERR; 12919304Speter break; 13019304Speter case INP_INTR: 13119304Speter goto retest; 13219304Speter case INP_TIMEOUT: 13319304Speter evp->e_event = E_TIMEOUT; 13419304Speter break; 13519304Speter default: 13619304Speter abort(); 13719304Speter } 13819304Speter return (0); 13919304Speter} 14019304Speter 14119304Speter/* 14219304Speter * cl_read -- 14319304Speter * Read characters from the input. 14419304Speter */ 14519304Speterstatic input_t 146254225Spetercl_read(SCR *sp, u_int32_t flags, char *bp, size_t blen, int *nrp, struct timeval *tp) 14719304Speter{ 14819304Speter struct termios term1, term2; 14919304Speter CL_PRIVATE *clp; 15019304Speter GS *gp; 15119304Speter fd_set rdfd; 15219304Speter input_t rval; 15319304Speter int maxfd, nr, term_reset; 15419304Speter 15519304Speter gp = sp->gp; 15619304Speter clp = CLP(sp); 15719304Speter term_reset = 0; 15819304Speter 15919304Speter /* 16019304Speter * 1: A read from a file or a pipe. In this case, the reads 16119304Speter * never timeout regardless. This means that we can hang 16219304Speter * when trying to complete a map, but we're going to hang 16319304Speter * on the next read anyway. 16419304Speter */ 16519304Speter if (!F_ISSET(clp, CL_STDIN_TTY)) { 16619304Speter switch (nr = read(STDIN_FILENO, bp, blen)) { 16719304Speter case 0: 16819304Speter return (INP_EOF); 16919304Speter case -1: 17019304Speter goto err; 17119304Speter default: 17219304Speter *nrp = nr; 17319304Speter return (INP_OK); 17419304Speter } 17519304Speter /* NOTREACHED */ 17619304Speter } 17719304Speter 17819304Speter /* 17919304Speter * 2: A read with an associated timeout, e.g., trying to complete 18019304Speter * a map sequence. If input exists, we fall into #3. 18119304Speter */ 18219304Speter if (tp != NULL) { 183254225Speter FD_ZERO(&rdfd); 18419304Speter FD_SET(STDIN_FILENO, &rdfd); 185254225Speter switch (select(STDIN_FILENO + 1, &rdfd, NULL, NULL, tp)) { 18619304Speter case 0: 18719304Speter return (INP_TIMEOUT); 18819304Speter case -1: 18919304Speter goto err; 19019304Speter default: 19119304Speter break; 19219304Speter } 19319304Speter } 19419304Speter 19519304Speter /* 19619304Speter * The user can enter a key in the editor to quote a character. If we 19719304Speter * get here and the next key is supposed to be quoted, do what we can. 19819304Speter * Reset the tty so that the user can enter a ^C, ^Q, ^S. There's an 19919304Speter * obvious race here, when the key has already been entered, but there's 20019304Speter * nothing that we can do to fix that problem. 20119304Speter * 20219304Speter * The editor can ask for the next literal character even thought it's 20319304Speter * generally running in line-at-a-time mode. Do what we can. 20419304Speter */ 20519304Speter if (LF_ISSET(EC_QUOTED | EC_RAW) && !tcgetattr(STDIN_FILENO, &term1)) { 20619304Speter term_reset = 1; 20719304Speter if (LF_ISSET(EC_QUOTED)) { 20819304Speter term2 = term1; 20919304Speter term2.c_lflag &= ~ISIG; 21019304Speter term2.c_iflag &= ~(IXON | IXOFF); 21119304Speter (void)tcsetattr(STDIN_FILENO, 21219304Speter TCSASOFT | TCSADRAIN, &term2); 21319304Speter } else 21419304Speter (void)tcsetattr(STDIN_FILENO, 21519304Speter TCSASOFT | TCSADRAIN, &clp->vi_enter); 21619304Speter } 21719304Speter 21819304Speter /* 21919304Speter * 3: Wait for input. 22019304Speter * 22119304Speter * Select on the command input and scripting window file descriptors. 22219304Speter * It's ugly that we wait on scripting file descriptors here, but it's 22319304Speter * the only way to keep from locking out scripting windows. 22419304Speter */ 22519304Speter if (F_ISSET(gp, G_SCRWIN)) { 22619304Speterloop: FD_ZERO(&rdfd); 22719304Speter FD_SET(STDIN_FILENO, &rdfd); 22819304Speter maxfd = STDIN_FILENO; 229254225Speter if (F_ISSET(sp, SC_SCRIPT)) { 230254225Speter FD_SET(sp->script->sh_master, &rdfd); 231254225Speter if (sp->script->sh_master > maxfd) 232254225Speter maxfd = sp->script->sh_master; 233254225Speter } 23419304Speter switch (select(maxfd + 1, &rdfd, NULL, NULL, NULL)) { 23519304Speter case 0: 23619304Speter abort(); 23719304Speter case -1: 23819304Speter goto err; 23919304Speter default: 24019304Speter break; 24119304Speter } 24219304Speter if (!FD_ISSET(STDIN_FILENO, &rdfd)) { 24319304Speter if (sscr_input(sp)) 24419304Speter return (INP_ERR); 24519304Speter goto loop; 24619304Speter } 24719304Speter } 24819304Speter 24919304Speter /* 25019304Speter * 4: Read the input. 25119304Speter * 25219304Speter * !!! 25319304Speter * What's going on here is some scary stuff. Ex runs the terminal in 25419304Speter * canonical mode. So, the <newline> character terminating a line of 25519304Speter * input is returned in the buffer, but a trailing <EOF> character is 25619304Speter * not similarly included. As ex uses 0<EOF> and ^<EOF> as autoindent 25719304Speter * commands, it has to see the trailing <EOF> characters to determine 25819304Speter * the difference between the user entering "0ab" and "0<EOF>ab". We 25919304Speter * leave an extra slot in the buffer, so that we can add a trailing 26019304Speter * <EOF> character if the buffer isn't terminated by a <newline>. We 26119304Speter * lose if the buffer is too small for the line and exactly N characters 26219304Speter * are entered followed by an <EOF> character. 26319304Speter */ 26419304Speter#define ONE_FOR_EOF 1 26519304Speter switch (nr = read(STDIN_FILENO, bp, blen - ONE_FOR_EOF)) { 26619304Speter case 0: /* EOF. */ 26719304Speter /* 26819304Speter * ^D in canonical mode returns a read of 0, i.e. EOF. EOF is 26919304Speter * a valid command, but we don't want to loop forever because 27019304Speter * the terminal driver is returning EOF because the user has 27119304Speter * disconnected. The editor will almost certainly try to write 27219304Speter * something before this fires, which should kill us, but You 27319304Speter * Never Know. 27419304Speter */ 27519304Speter if (++clp->eof_count < 50) { 27619304Speter bp[0] = clp->orig.c_cc[VEOF]; 27719304Speter *nrp = 1; 27819304Speter rval = INP_OK; 27919304Speter 28019304Speter } else 28119304Speter rval = INP_EOF; 28219304Speter break; 28319304Speter case -1: /* Error or interrupt. */ 28419304Spetererr: if (errno == EINTR) 28519304Speter rval = INP_INTR; 28619304Speter else { 28719304Speter rval = INP_ERR; 28819304Speter msgq(sp, M_SYSERR, "input"); 28919304Speter } 29019304Speter break; 29119304Speter default: /* Input characters. */ 29219304Speter if (F_ISSET(sp, SC_EX) && bp[nr - 1] != '\n') 29319304Speter bp[nr++] = clp->orig.c_cc[VEOF]; 29419304Speter *nrp = nr; 29519304Speter clp->eof_count = 0; 29619304Speter rval = INP_OK; 29719304Speter break; 29819304Speter } 29919304Speter 30019304Speter /* Restore the terminal state if it was modified. */ 30119304Speter if (term_reset) 30219304Speter (void)tcsetattr(STDIN_FILENO, TCSASOFT | TCSADRAIN, &term1); 30319304Speter return (rval); 30419304Speter} 30519304Speter 30619304Speter/* 30719304Speter * cl_resize -- 30819304Speter * Reset the options for a resize event. 30919304Speter */ 31019304Speterstatic int 311254225Spetercl_resize(SCR *sp, size_t lines, size_t columns) 31219304Speter{ 31319304Speter ARGS *argv[2], a, b; 314254225Speter CHAR_T b1[1024]; 31519304Speter 31619304Speter a.bp = b1; 31719304Speter b.bp = NULL; 31819304Speter a.len = b.len = 0; 31919304Speter argv[0] = &a; 32019304Speter argv[1] = &b; 32119304Speter 322254225Speter a.len = SPRINTF(b1, sizeof(b1), L("lines=%lu"), (u_long)lines); 32319304Speter if (opts_set(sp, argv, NULL)) 32419304Speter return (1); 325254225Speter a.len = SPRINTF(b1, sizeof(b1), L("columns=%lu"), (u_long)columns); 32619304Speter if (opts_set(sp, argv, NULL)) 32719304Speter return (1); 32819304Speter return (0); 32919304Speter} 330