177943Sdfr/*-
277943Sdfr * Copyright (c) 1996
377943Sdfr *	Keith Bostic.  All rights reserved.
477943Sdfr *
577943Sdfr * See the LICENSE file for redistribution information.
677943Sdfr */
777943Sdfr
877943Sdfr#include "config.h"
977943Sdfr
1077943Sdfr#ifndef lint
1177943Sdfrstatic const char sccsid[] = "@(#)ip_read.c	8.3 (Berkeley) 9/24/96";
1277943Sdfr#endif /* not lint */
1377943Sdfr
1477943Sdfr#include <sys/types.h>
1577943Sdfr#include <sys/queue.h>
1677943Sdfr
1777943Sdfr#include <bitstring.h>
1877943Sdfr#include <stdio.h>
1977943Sdfr#include <termios.h>
2077943Sdfr#include <time.h>
2177943Sdfr
2277943Sdfr#include "../common/common.h"
2377943Sdfr#include "../ex/script.h"
2477943Sdfr#include "ip.h"
2577943Sdfr
2677943Sdfrextern GS *__global_list;
2777943Sdfr
2877943Sdfrtypedef enum { INP_OK=0, INP_EOF, INP_ERR, INP_TIMEOUT } input_t;
2977943Sdfr
3077943Sdfrstatic input_t	ip_read __P((SCR *, IP_PRIVATE *, struct timeval *));
3177943Sdfrstatic int	ip_resize __P((SCR *, size_t, size_t));
3277943Sdfrstatic int	ip_trans __P((SCR *, IP_PRIVATE *, EVENT *));
3377943Sdfr
3477943Sdfr/*
3577943Sdfr * ip_event --
3677943Sdfr *	Return a single event.
3777943Sdfr *
3877943Sdfr * PUBLIC: int ip_event __P((SCR *, EVENT *, u_int32_t, int));
3977943Sdfr */
4077943Sdfrint
4177943Sdfrip_event(sp, evp, flags, ms)
4277943Sdfr	SCR *sp;
4377943Sdfr	EVENT *evp;
4477943Sdfr	u_int32_t flags;
4577943Sdfr	int ms;
4677943Sdfr{
4777943Sdfr	IP_PRIVATE *ipp;
4877943Sdfr	struct timeval t, *tp;
4977943Sdfr
5077943Sdfr	if (LF_ISSET(EC_INTERRUPT)) {		/* XXX */
5177943Sdfr		evp->e_event = E_TIMEOUT;
5277943Sdfr		return (0);
5377943Sdfr	}
5477943Sdfr
5577943Sdfr	ipp = sp == NULL ? GIPP(__global_list) : IPP(sp);
5677943Sdfr
5777943Sdfr	/* Discard the last command. */
5877943Sdfr	if (ipp->iskip != 0) {
5977943Sdfr		ipp->iblen -= ipp->iskip;
6077943Sdfr		memmove(ipp->ibuf, ipp->ibuf + ipp->iskip, ipp->iblen);
6177943Sdfr		ipp->iskip = 0;
6277943Sdfr	}
6377943Sdfr
6477943Sdfr	/* Set timer. */
65154491Smarcel	if (ms == 0)
66154491Smarcel		tp = NULL;
67154491Smarcel	else {
68154491Smarcel		t.tv_sec = ms / 1000;
69154491Smarcel		t.tv_usec = (ms % 1000) * 1000;
70154491Smarcel		tp = &t;
7177943Sdfr	}
7277943Sdfr
7377943Sdfr	/* Read input events. */
7477943Sdfr	for (;;) {
7577943Sdfr		switch (ip_read(sp, ipp, tp)) {
7677943Sdfr		case INP_OK:
7777943Sdfr			if (!ip_trans(sp, ipp, evp))
7877943Sdfr				continue;
7977943Sdfr			break;
8077943Sdfr		case INP_EOF:
8195190Smarcel			evp->e_event = E_EOF;
8277943Sdfr			break;
8377943Sdfr		case INP_ERR:
8477943Sdfr			evp->e_event = E_ERR;
8577943Sdfr			break;
8677943Sdfr		case INP_TIMEOUT:
8777943Sdfr			evp->e_event = E_TIMEOUT;
8877943Sdfr			break;
8977943Sdfr		default:
9077943Sdfr			abort();
9177943Sdfr		}
9277943Sdfr		break;
9377943Sdfr	}
9477943Sdfr	return (0);
9577943Sdfr}
9677943Sdfr
9777943Sdfr/*
9877943Sdfr * ip_read --
9977943Sdfr *	Read characters from the input.
100132437Smarcel */
101132437Smarcelstatic input_t
102132437Smarcelip_read(sp, ipp, tp)
10377943Sdfr	SCR *sp;
10477943Sdfr	IP_PRIVATE *ipp;
10577943Sdfr	struct timeval *tp;
10677943Sdfr{
107132437Smarcel	struct timeval poll;
108132437Smarcel	GS *gp;
109132437Smarcel	SCR *tsp;
110132437Smarcel	fd_set rdfd;
11177943Sdfr	input_t rval;
11277943Sdfr	size_t blen;
11395190Smarcel	int maxfd, nr;
11495190Smarcel	char *bp;
11595190Smarcel
11695190Smarcel	gp = sp == NULL ? __global_list : sp->gp;
11795190Smarcel	bp = ipp->ibuf + ipp->iblen;
11895190Smarcel	blen = sizeof(ipp->ibuf) - ipp->iblen;
11995190Smarcel
12095190Smarcel	/*
12195190Smarcel	 * 1: A read with an associated timeout, e.g., trying to complete
12295190Smarcel	 *    a map sequence.  If input exists, we fall into #2.
12395190Smarcel	 */
12495190Smarcel	FD_ZERO(&rdfd);
12595190Smarcel	poll.tv_sec = 0;
12695190Smarcel	poll.tv_usec = 0;
12795190Smarcel	if (tp != NULL) {
12895190Smarcel		FD_SET(ipp->i_fd, &rdfd);
12995190Smarcel		switch (select(ipp->i_fd + 1,
13095190Smarcel		    &rdfd, NULL, NULL, tp == NULL ? &poll : tp)) {
13195190Smarcel		case 0:
132154491Smarcel			return (INP_TIMEOUT);
13395190Smarcel		case -1:
13495190Smarcel			goto err;
13595190Smarcel		default:
13677943Sdfr			break;
13795190Smarcel		}
13895190Smarcel	}
13977943Sdfr
14095190Smarcel	/*
14177943Sdfr	 * 2: Wait for input.
14295190Smarcel	 *
14395190Smarcel	 * Select on the command input and scripting window file descriptors.
14495190Smarcel	 * It's ugly that we wait on scripting file descriptors here, but it's
14595190Smarcel	 * the only way to keep from locking out scripting windows.
14695190Smarcel	 */
14795190Smarcel	if (sp != NULL && F_ISSET(gp, G_SCRWIN)) {
14895190Smarcelloop:		FD_ZERO(&rdfd);
14995190Smarcel		FD_SET(ipp->i_fd, &rdfd);
15085436Sdfr		maxfd = ipp->i_fd;
15195190Smarcel		for (tsp = gp->dq.cqh_first;
15295190Smarcel		    tsp != (void *)&gp->dq; tsp = tsp->q.cqe_next)
153154491Smarcel			if (F_ISSET(sp, SC_SCRIPT)) {
15477943Sdfr				FD_SET(sp->script->sh_master, &rdfd);
15595190Smarcel				if (sp->script->sh_master > maxfd)
15695190Smarcel					maxfd = sp->script->sh_master;
15777943Sdfr			}
15877943Sdfr		switch (select(maxfd + 1, &rdfd, NULL, NULL, NULL)) {
15977943Sdfr		case 0:
16077943Sdfr			abort();
16177943Sdfr		case -1:
16277943Sdfr			goto err;
16395190Smarcel		default:
16495190Smarcel			break;
16595190Smarcel		}
16695190Smarcel		if (!FD_ISSET(ipp->i_fd, &rdfd)) {
16795190Smarcel			if (sscr_input(sp))
16895190Smarcel				return (INP_ERR);
16995190Smarcel			goto loop;
17095190Smarcel		}
17195190Smarcel	}
17295190Smarcel
17395190Smarcel	/*
17495190Smarcel	 * 3: Read the input.
17595190Smarcel	 */
17695190Smarcel	switch (nr = read(ipp->i_fd, bp, blen)) {
17795190Smarcel	case  0:				/* EOF. */
17895190Smarcel		rval = INP_EOF;
17995190Smarcel		break;
18095190Smarcel	case -1:				/* Error or interrupt. */
18195190Smarcelerr:		rval = INP_ERR;
18295190Smarcel		msgq(sp, M_SYSERR, "input");
18395190Smarcel		break;
18495190Smarcel	default:				/* Input characters. */
18595190Smarcel		ipp->iblen += nr;
18695190Smarcel		rval = INP_OK;
18795190Smarcel		break;
18895190Smarcel	}
18995190Smarcel	return (rval);
19095190Smarcel}
19195190Smarcel
19295190Smarcel/*
19395190Smarcel * ip_trans --
19495190Smarcel *	Translate messages into events.
19595190Smarcel */
19695190Smarcelstatic int
19795190Smarcelip_trans(sp, ipp, evp)
19895190Smarcel	SCR *sp;
19995190Smarcel	IP_PRIVATE *ipp;
20095190Smarcel	EVENT *evp;
20195190Smarcel{
20295190Smarcel	u_int32_t val1, val2;
20395190Smarcel
20495190Smarcel	switch (ipp->ibuf[0]) {
20577943Sdfr	case IPO_EOF:
20695190Smarcel		evp->e_event = E_EOF;
20777943Sdfr		ipp->iskip = IPO_CODE_LEN;
20877943Sdfr		return (1);
20995190Smarcel	case IPO_ERR:
21077943Sdfr		evp->e_event = E_ERR;
21177943Sdfr		ipp->iskip = IPO_CODE_LEN;
212154491Smarcel		return (1);
21395190Smarcel	case IPO_INTERRUPT:
21477943Sdfr		evp->e_event = E_INTERRUPT;
215154491Smarcel		ipp->iskip = IPO_CODE_LEN;
216132437Smarcel		return (1);
217132437Smarcel	case IPO_QUIT:
218154491Smarcel		evp->e_event = E_QUIT;
21977943Sdfr		ipp->iskip = IPO_CODE_LEN;
22077943Sdfr		return (1);
22195190Smarcel	case IPO_RESIZE:
22277943Sdfr		if (ipp->iblen < IPO_CODE_LEN + IPO_INT_LEN * 2)
22395190Smarcel			return (0);
22477943Sdfr		evp->e_event = E_WRESIZE;
22595190Smarcel		memcpy(&val1, ipp->ibuf + IPO_CODE_LEN, IPO_INT_LEN);
22677943Sdfr		val1 = ntohl(val1);
22795190Smarcel		memcpy(&val2,
22877943Sdfr		    ipp->ibuf + IPO_CODE_LEN + IPO_INT_LEN, IPO_INT_LEN);
22995190Smarcel		val2 = ntohl(val2);
23085436Sdfr		ip_resize(sp, val1, val2);
23195190Smarcel		ipp->iskip = IPO_CODE_LEN + IPO_INT_LEN * 2;
23295190Smarcel		return (1);
23395190Smarcel	case IPO_SIGHUP:
23495190Smarcel		evp->e_event = E_SIGHUP;
235154491Smarcel		ipp->iskip = IPO_CODE_LEN;
23685436Sdfr		return (1);
23785436Sdfr	case IPO_SIGTERM:
238154491Smarcel		evp->e_event = E_SIGTERM;
23995190Smarcel		ipp->iskip = IPO_CODE_LEN;
24077943Sdfr		return (1);
24195190Smarcel	case IPO_STRING:
24295190Smarcel		evp->e_event = E_STRING;
24377943Sdfrstring:		if (ipp->iblen < IPO_CODE_LEN + IPO_INT_LEN)
24495190Smarcel			return (0);
24595190Smarcel		memcpy(&val1, ipp->ibuf + IPO_CODE_LEN, IPO_INT_LEN);
24677943Sdfr		val1 = ntohl(val1);
24795190Smarcel		if (ipp->iblen < IPO_CODE_LEN + IPO_INT_LEN + val1)
24877943Sdfr			return (0);
24995190Smarcel		ipp->iskip = IPO_CODE_LEN + IPO_INT_LEN + val1;
25095190Smarcel		evp->e_csp = ipp->ibuf + IPO_CODE_LEN + IPO_INT_LEN;
25177943Sdfr		evp->e_len = val1;
252132437Smarcel		return (1);
253132437Smarcel	case IPO_WRITE:
254132437Smarcel		evp->e_event = E_WRITE;
255132437Smarcel		ipp->iskip = IPO_CODE_LEN;
256132437Smarcel		return (1);
257132437Smarcel	default:
258132437Smarcel		/*
25995190Smarcel		 * XXX: Protocol is out of sync?
26095190Smarcel		 */
26195190Smarcel		abort();
26277943Sdfr	}
26395190Smarcel	/* NOTREACHED */
26495190Smarcel}
26595190Smarcel
26695190Smarcel/*
26795190Smarcel * ip_resize --
26895190Smarcel *	Reset the options for a resize event.
26977943Sdfr */
27095190Smarcelstatic int
27195190Smarcelip_resize(sp, lines, columns)
27295190Smarcel	SCR *sp;
27395190Smarcel	size_t lines, columns;
27495190Smarcel{
27585436Sdfr	GS *gp;
27695190Smarcel	ARGS *argv[2], a, b;
27795190Smarcel	char b1[1024];
27895190Smarcel
27995190Smarcel	/*
28085436Sdfr	 * XXX
28195190Smarcel	 * The IP screen has to know the lines and columns before anything
28285436Sdfr	 * else happens.  So, we may not have a valid SCR pointer, and we
28395190Smarcel	 * have to deal with that.
28495190Smarcel	 */
28595190Smarcel	if (sp == NULL) {
28695190Smarcel		gp = __global_list;
28795190Smarcel		OG_VAL(gp, GO_LINES) = OG_D_VAL(gp, GO_LINES) = lines;
28877943Sdfr		OG_VAL(gp, GO_COLUMNS) = OG_D_VAL(gp, GO_COLUMNS) = columns;
28995190Smarcel		return (0);
29077943Sdfr	}
29195190Smarcel
29277943Sdfr	a.bp = b1;
29395190Smarcel	b.bp = NULL;
29477943Sdfr	a.len = b.len = 0;
29595190Smarcel	argv[0] = &a;
29695190Smarcel	argv[1] = &b;
29777943Sdfr
29877943Sdfr	(void)snprintf(b1, sizeof(b1), "lines=%lu", (u_long)lines);
29977943Sdfr	a.len = strlen(b1);
30077943Sdfr	if (opts_set(sp, argv, NULL))
30177943Sdfr		return (1);
30277943Sdfr	(void)snprintf(b1, sizeof(b1), "columns=%lu", (u_long)columns);
30377943Sdfr	a.len = strlen(b1);
30477943Sdfr	if (opts_set(sp, argv, NULL))
30577943Sdfr		return (1);
30677943Sdfr	return (0);
307107720Smarcel}
30877943Sdfr