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[] = "@(#)tk_read.c	8.12 (Berkeley) 9/24/96";
14 #endif /* not lint */
15 
16 #include <sys/types.h>
17 #include <sys/queue.h>
18 
19 #include <bitstring.h>
20 #include <errno.h>
21 #include <fcntl.h>
22 #include <signal.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <termios.h>
27 #include <unistd.h>
28 
29 #include "../common/common.h"
30 #include "../ex/script.h"
31 #include "tki.h"
32 
33 static input_t	tk_read __P((SCR *, int));
34 static int	tk_resize __P((SCR *, size_t, size_t));
35 
36 
37 /*
38  * tk_event --
39  *	Return a single event.
40  *
41  * PUBLIC: int tk_event __P((SCR *, EVENT *, u_int32_t, int));
42  */
43 int
tk_event(sp,evp,flags,timeout)44 tk_event(sp, evp, flags, timeout)
45 	SCR *sp;
46 	EVENT *evp;
47 	u_int32_t flags;
48 	int timeout;
49 {
50 	EVENT *tevp;
51 	TK_PRIVATE *tkp;
52 	size_t lines, columns;
53 	int changed;
54 
55 	/*
56 	 * Queue signal based events.  We never clear SIGHUP or SIGTERM events,
57 	 * so that we just keep returning them until the editor dies.
58 	 */
59 	tkp = TKP(sp);
60 sig:	if (LF_ISSET(EC_INTERRUPT) || F_ISSET(tkp, TK_SIGINT)) {
61 		if (F_ISSET(tkp, TK_SIGINT)) {
62 			F_CLR(tkp, TK_SIGINT);
63 			evp->e_event = E_INTERRUPT;
64 		} else
65 			evp->e_event = E_TIMEOUT;
66 		return (0);
67 	}
68 	if (F_ISSET(tkp, TK_SIGHUP | TK_SIGTERM | TK_SIGWINCH)) {
69 		if (F_ISSET(tkp, TK_SIGHUP)) {
70 			evp->e_event = E_SIGHUP;
71 			return (0);
72 		}
73 		if (F_ISSET(tkp, TK_SIGTERM)) {
74 			evp->e_event = E_SIGTERM;
75 			return (0);
76 		}
77 		if (F_ISSET(tkp, TK_SIGWINCH)) {
78 			F_CLR(tkp, TK_SIGWINCH);
79 			(void)tk_ssize(sp, 1, &lines, &columns, &changed);
80 			if (changed) {
81 				(void)tk_resize(sp, lines, columns);
82 				evp->e_event = E_WRESIZE;
83 				return (0);
84 			}
85 			/* No change, so ignore the signal. */
86 		}
87 	}
88 
89 	/* Queue special ops. */
90 ops:	if ((tevp = tkp->evq.tqh_first) != NULL) {
91 		*evp = *tevp;
92 		TAILQ_REMOVE(&tkp->evq, tevp, q);
93 		free(tevp);
94 		return (0);
95 	}
96 
97 	/* Read input characters. */
98 	switch (tk_read(sp, timeout)) {
99 	case INP_OK:
100 		evp->e_csp = tkp->ibuf;
101 		evp->e_len = tkp->ibuf_cnt;
102 		evp->e_event = E_STRING;
103 		tkp->ibuf_cnt = 0;
104 		break;
105 	case INP_EOF:
106 		evp->e_event = E_EOF;
107 		break;
108 	case INP_ERR:
109 		evp->e_event = E_ERR;
110 		break;
111 	case INP_INTR:
112 		goto sig;
113 		break;
114 	case INP_TIMEOUT:
115 		/* May have returned because queued a special op. */
116 		if (tkp->evq.tqh_first != NULL)
117 			goto ops;
118 
119 		/* Otherwise, we timed out. */
120 		evp->e_event = E_TIMEOUT;
121 		break;
122 	default:
123 		abort();
124 	}
125 	return (0);
126 }
127 
128 /*
129  * tk_read --
130  *	Read characters from the input.
131  */
132 static input_t
tk_read(sp,timeout)133 tk_read(sp, timeout)
134 	SCR *sp;
135 	int timeout;
136 {
137 	TK_PRIVATE *tkp;
138 	char buf[20];
139 
140 	/*
141 	 * Check scripting window file descriptors.  It's ugly that we wait
142 	 * on scripting file descriptors here, but it's the only way to keep
143 	 * from locking out scripting windows.
144 	 */
145 	if (F_ISSET(sp->gp, G_SCRWIN) && sscr_input(sp))
146 		return (INP_ERR);
147 
148 	/* Read characters. */
149 	tkp = TKP(sp);
150 	(void)snprintf(buf, sizeof(buf), "%d", timeout);
151 	(void)Tcl_VarEval(tkp->interp, "tk_key_wait ", buf, NULL);
152 
153 	return (tkp->ibuf_cnt == 0 ? INP_TIMEOUT : INP_OK);
154 }
155 
156 /*
157  * tk_key --
158  *	Receive an input key.
159  *
160  * PUBLIC: int tk_key __P((ClientData, Tcl_Interp *, int, char *[]));
161  */
162 int
tk_key(clientData,interp,argc,argv)163 tk_key(clientData, interp, argc, argv)
164 	ClientData clientData;
165 	Tcl_Interp *interp;
166 	int argc;
167 	char *argv[];
168 {
169 	TK_PRIVATE *tkp;
170 	u_int8_t *p, *t;
171 
172 	tkp = (TK_PRIVATE *)clientData;
173 	for (p =
174 	    tkp->ibuf + tkp->ibuf_cnt, t = argv[1]; (*p++ = *t++) != '\0';
175 	    ++tkp->ibuf_cnt);
176 	return (TCL_OK);
177 }
178 
179 /*
180  * tk_resize --
181  *	Reset the options for a resize event.
182  */
183 static int
tk_resize(sp,lines,columns)184 tk_resize(sp, lines, columns)
185 	SCR *sp;
186 	size_t lines, columns;
187 {
188 	ARGS *argv[2], a, b;
189 	int rval;
190 	char b1[1024];
191 
192 	a.bp = b1;
193 	b.bp = NULL;
194 	a.len = b.len = 0;
195 	argv[0] = &a;
196 	argv[1] = &b;
197 
198 	(void)snprintf(b1, sizeof(b1), "lines=%lu", (u_long)lines);
199 	a.len = strlen(b1);
200 	if (opts_set(sp, argv, NULL))
201 		return (1);
202 	(void)snprintf(b1, sizeof(b1), "columns=%lu", (u_long)columns);
203 	a.len = strlen(b1);
204 	if (opts_set(sp, argv, NULL))
205 		return (1);
206 	return (0);
207 }
208