#include "config.h"
#include <sys/types.h>
#include <sys/queue.h>
#include <sys/time.h>
#include <bitstring.h>
#include <curses.h>
#include <errno.h>
#include <fcntl.h>
#include <poll.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
#include "../common/common.h"
#include "../ex/script.h"
#include "cl.h"
static input_t cl_read(SCR *,
u_int32_t, CHAR_T *, size_t, int *, struct timeval *);
static int cl_resize(SCR *, size_t, size_t);
int
cl_event(SCR *sp, EVENT *evp, u_int32_t flags, int ms)
{
struct timeval t, *tp;
CL_PRIVATE *clp;
size_t lines, columns;
int changed, nr;
clp = CLP(sp);
retest: if (LF_ISSET(EC_INTERRUPT) || cl_sigint) {
if (cl_sigint) {
cl_sigint = 0;
evp->e_event = E_INTERRUPT;
} else
evp->e_event = E_TIMEOUT;
return (0);
}
switch (cl_sigterm) {
case SIGHUP:
evp->e_event = E_SIGHUP;
return (0);
case SIGTERM:
evp->e_event = E_SIGTERM;
return (0);
default:
break;
}
if (cl_sigwinch) {
cl_sigwinch = 0;
if (cl_ssize(sp, 1, &lines, &columns, &changed))
return (1);
if (changed) {
(void)cl_resize(sp, lines, columns);
evp->e_event = E_WRESIZE;
return (0);
}
}
if (ms == 0)
tp = NULL;
else {
t.tv_sec = ms / 1000;
t.tv_usec = (ms % 1000) * 1000;
tp = &t;
}
switch (cl_read(sp, LF_ISSET(EC_QUOTED | EC_RAW),
clp->ibuf, sizeof(clp->ibuf), &nr, tp)) {
case INP_OK:
evp->e_csp = clp->ibuf;
evp->e_len = nr;
evp->e_event = E_STRING;
break;
case INP_EOF:
evp->e_event = E_EOF;
break;
case INP_ERR:
evp->e_event = E_ERR;
break;
case INP_INTR:
goto retest;
case INP_TIMEOUT:
evp->e_event = E_TIMEOUT;
break;
default:
abort();
}
return (0);
}
static input_t
cl_read(SCR *sp, u_int32_t flags, CHAR_T *bp, size_t blen, int *nrp,
struct timeval *tp)
{
struct termios term1, term2;
CL_PRIVATE *clp;
GS *gp;
struct pollfd pfd[1];
input_t rval;
int nr, term_reset, timeout;
gp = sp->gp;
clp = CLP(sp);
term_reset = 0;
if (!F_ISSET(clp, CL_STDIN_TTY)) {
switch (nr = read(STDIN_FILENO, bp, blen)) {
case 0:
return (INP_EOF);
case -1:
goto err;
default:
*nrp = nr;
return (INP_OK);
}
}
tty_retry:
if (tp != NULL) {
pfd[0].fd = STDIN_FILENO;
pfd[0].events = POLLIN;
timeout = tp ? (tp->tv_sec * 1000) + (tp->tv_usec / 1000) : 0;
switch (poll(pfd, 1, timeout)) {
case 0:
return (INP_TIMEOUT);
case -1:
goto err;
default:
break;
}
}
if (LF_ISSET(EC_QUOTED | EC_RAW) && !tcgetattr(STDIN_FILENO, &term1)) {
term_reset = 1;
if (LF_ISSET(EC_QUOTED)) {
term2 = term1;
term2.c_lflag &= ~ISIG;
term2.c_iflag &= ~(IXON | IXOFF);
(void)tcsetattr(STDIN_FILENO,
TCSASOFT | TCSADRAIN, &term2);
} else
(void)tcsetattr(STDIN_FILENO,
TCSASOFT | TCSADRAIN, &clp->vi_enter);
}
if (F_ISSET(gp, G_SCRWIN)) {
if (sscr_check_input(sp))
goto err;
}
#define ONE_FOR_EOF 1
switch (nr = read(STDIN_FILENO, bp, blen - ONE_FOR_EOF)) {
case 0:
if (++clp->eof_count < 50) {
bp[0] = clp->orig.c_cc[VEOF];
*nrp = 1;
rval = INP_OK;
} else
rval = INP_EOF;
break;
case -1:
err: if (errno == EINTR)
rval = INP_INTR;
else if (errno == EAGAIN)
goto tty_retry;
else {
rval = INP_ERR;
msgq(sp, M_SYSERR, "input");
}
break;
default:
if (F_ISSET(sp, SC_EX) && bp[nr - 1] != '\n')
bp[nr++] = clp->orig.c_cc[VEOF];
*nrp = nr;
clp->eof_count = 0;
rval = INP_OK;
break;
}
if (term_reset)
(void)tcsetattr(STDIN_FILENO, TCSASOFT | TCSADRAIN, &term1);
return (rval);
}
static int
cl_resize(SCR *sp, size_t lines, size_t columns)
{
ARGS *argv[2], a, b;
char b1[1024];
a.bp = b1;
b.bp = NULL;
a.len = b.len = 0;
argv[0] = &a;
argv[1] = &b;
(void)snprintf(b1, sizeof(b1), "lines=%lu", (u_long)lines);
a.len = strlen(b1);
if (opts_set(sp, argv, NULL))
return (1);
(void)snprintf(b1, sizeof(b1), "columns=%lu", (u_long)columns);
a.len = strlen(b1);
if (opts_set(sp, argv, NULL))
return (1);
return (0);
}