xref: /openbsd/games/hack/hack.tty.c (revision df69c215)
1 /*	$OpenBSD: hack.tty.c,v 1.16 2019/06/28 13:32:52 deraadt Exp $	*/
2 
3 /*-
4  * Copyright (c) 1988, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the University nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 /*
33  * Copyright (c) 1985, Stichting Centrum voor Wiskunde en Informatica,
34  * Amsterdam
35  * All rights reserved.
36  *
37  * Redistribution and use in source and binary forms, with or without
38  * modification, are permitted provided that the following conditions are
39  * met:
40  *
41  * - Redistributions of source code must retain the above copyright notice,
42  * this list of conditions and the following disclaimer.
43  *
44  * - Redistributions in binary form must reproduce the above copyright
45  * notice, this list of conditions and the following disclaimer in the
46  * documentation and/or other materials provided with the distribution.
47  *
48  * - Neither the name of the Stichting Centrum voor Wiskunde en
49  * Informatica, nor the names of its contributors may be used to endorse or
50  * promote products derived from this software without specific prior
51  * written permission.
52  *
53  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
54  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
55  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
56  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
57  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
58  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
59  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
60  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
61  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
62  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
63  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
64  */
65 
66 /*
67  * Copyright (c) 1982 Jay Fenlason <hack@gnu.org>
68  * All rights reserved.
69  *
70  * Redistribution and use in source and binary forms, with or without
71  * modification, are permitted provided that the following conditions
72  * are met:
73  * 1. Redistributions of source code must retain the above copyright
74  *    notice, this list of conditions and the following disclaimer.
75  * 2. Redistributions in binary form must reproduce the above copyright
76  *    notice, this list of conditions and the following disclaimer in the
77  *    documentation and/or other materials provided with the distribution.
78  * 3. The name of the author may not be used to endorse or promote products
79  *    derived from this software without specific prior written permission.
80  *
81  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
82  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
83  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
84  * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
85  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
86  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
87  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
88  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
89  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
90  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
91  */
92 
93 /* hack.tty.c - version 1.0.3 */
94 /* With thanks to the people who sent code for SYSV - hpscdi!jon,
95    arnold@ucsf-cgl, wcs@bo95b, cbcephus!pds and others. */
96 
97 #include <stdio.h>
98 #include <stdlib.h>
99 #include <termios.h>
100 
101 #include "hack.h"
102 
103 static char erase_char, kill_char;
104 static boolean settty_needed = FALSE;
105 struct termios inittyb, curttyb;
106 
107 static void setctty(void);
108 
109 /*
110  * Get initial state of terminal,
111  * and switch off tab expansion if necessary.
112  * Called by startup() in termcap.c and after returning from ! or ^Z
113  */
114 void
gettty(void)115 gettty(void)
116 {
117 	if(tcgetattr(0, &inittyb) == -1)
118 		perror("Hack (gettty)");
119 	curttyb = inittyb;
120 	erase_char = inittyb.c_cc[VERASE];
121 	kill_char = inittyb.c_cc[VKILL];
122 	getioctls();
123 
124 	/* do not expand tabs - they might be needed inside a cm sequence */
125 	if(curttyb.c_oflag & OXTABS) {
126 		curttyb.c_oflag &= ~OXTABS;
127 		setctty();
128 	}
129 	settty_needed = TRUE;
130 }
131 
132 /* reset terminal to original state */
133 void
settty(char * s)134 settty(char *s)
135 {
136 	clr_screen();
137 	end_screen();
138 	if(s) printf("%s", s);
139 	(void) fflush(stdout);
140 	if(tcsetattr(0, TCSADRAIN, &inittyb) == -1)
141 		perror("Hack (settty)");
142 	flags.echo = (inittyb.c_lflag & ECHO) ? ON : OFF;
143 	flags.cbreak = (inittyb.c_lflag & ICANON) ? OFF : ON;
144 	setioctls();
145 }
146 
147 static void
setctty(void)148 setctty(void)
149 {
150 	if(tcsetattr(0, TCSADRAIN, &curttyb) == -1)
151 		perror("Hack (setctty)");
152 }
153 
154 void
setftty(void)155 setftty(void)
156 {
157 	int change = 0;
158 	flags.cbreak = ON;
159 	flags.echo = OFF;
160 	/* Should use (ECHO|CRMOD) here instead of ECHO */
161 	if(curttyb.c_lflag & ECHO){
162 		curttyb.c_lflag &= ~ECHO;
163 		change++;
164 	}
165 	if(curttyb.c_lflag & ICANON){
166 		curttyb.c_lflag &= ~ICANON;
167 		/* be satisfied with one character; no timeout */
168 		curttyb.c_cc[VMIN] = 1;
169 		curttyb.c_cc[VTIME] = 0;
170 		/* we need to be able to read ^Z */
171 		curttyb.c_cc[VSUSP] = _POSIX_VDISABLE;
172 		change++;
173 	}
174 	if(change){
175 		setctty();
176 	}
177 	start_screen();
178 }
179 
180 
181 /* fatal error */
182 void
error(const char * s,...)183 error(const char *s, ...)
184 {
185 	va_list ap;
186 
187 	if(settty_needed)
188 		settty(NULL);
189 	va_start(ap, s);
190 	vprintf(s, ap);
191 	va_end(ap);
192 	putchar('\n');
193 	exit(1);
194 }
195 
196 /*
197  * Read a line closed with '\n' into the array char bufp[BUFSZ].
198  * (The '\n' is not stored. The string is closed with a '\0'.)
199  * Reading can be interrupted by an escape ('\033') - now the
200  * resulting string is "\033".
201  */
202 void
getlin(char * bufp)203 getlin(char *bufp)
204 {
205 	char *obufp = bufp;
206 	int c;
207 
208 	flags.toplin = 2;		/* nonempty, no --More-- required */
209 	for(;;) {
210 		(void) fflush(stdout);
211 		if((c = getchar()) == EOF) {
212 			*bufp = 0;
213 			return;
214 		}
215 		if(c == '\033') {
216 			*obufp = c;
217 			obufp[1] = 0;
218 			return;
219 		}
220 		if(c == erase_char || c == '\b') {
221 			if(bufp != obufp) {
222 				bufp--;
223 				putstr("\b \b"); /* putsym converts \b */
224 			} else	hackbell();
225 		} else if(c == '\n') {
226 			*bufp = 0;
227 			return;
228 		} else if(' ' <= c && c < '\177') {
229 				/* avoid isprint() - some people don't have it
230 				   ' ' is not always a printing char */
231 			*bufp = c;
232 			bufp[1] = 0;
233 			putstr(bufp);
234 			if(bufp-obufp < BUFSZ-1 && bufp-obufp < COLNO)
235 				bufp++;
236 		} else if(c == kill_char || c == '\177') { /* Robert Viduya */
237 				/* this test last - @ might be the kill_char */
238 			while(bufp != obufp) {
239 				bufp--;
240 				putstr("\b \b");
241 			}
242 		} else
243 			hackbell();
244 	}
245 }
246 
247 void
getret(void)248 getret(void)
249 {
250 	cgetret("");
251 }
252 
253 void
cgetret(char * s)254 cgetret(char *s)
255 {
256 	putsym('\n');
257 	if(flags.standout)
258 		standoutbeg();
259 	putstr("Hit ");
260 	putstr(flags.cbreak ? "space" : "return");
261 	putstr(" to continue: ");
262 	if(flags.standout)
263 		standoutend();
264 	xwaitforspace(s);
265 }
266 
267 char morc;	/* tell the outside world what char he used */
268 
269 /* s: chars allowed besides space or return */
270 void
xwaitforspace(char * s)271 xwaitforspace(char *s)
272 {
273 	int c;
274 
275 	morc = 0;
276 
277 	while((c = readchar()) != '\n') {
278 	    if(flags.cbreak) {
279 		if(c == ' ') break;
280 		if(s && strchr(s,c)) {
281 			morc = c;
282 			break;
283 		}
284 		hackbell();
285 	    }
286 	}
287 }
288 
289 char *
parse(void)290 parse(void)
291 {
292 	static char inputline[COLNO];
293 	int foo;
294 
295 	flags.move = 1;
296 	if(!Invisible) curs_on_u(); else home();
297 	while((foo = readchar()) >= '0' && foo <= '9')
298 		multi = 10*multi+foo-'0';
299 	if(multi) {
300 		multi--;
301 		save_cm = inputline;
302 	}
303 	inputline[0] = foo;
304 	inputline[1] = 0;
305 	if(foo == 'f' || foo == 'F'){
306 		inputline[1] = getchar();
307 #ifdef QUEST
308 		if(inputline[1] == foo) inputline[2] = getchar(); else
309 #endif /* QUEST */
310 		inputline[2] = 0;
311 	}
312 	if(foo == 'm' || foo == 'M'){
313 		inputline[1] = getchar();
314 		inputline[2] = 0;
315 	}
316 	clrlin();
317 	return(inputline);
318 }
319 
320 char
readchar(void)321 readchar(void)
322 {
323 	int sym;
324 
325 	(void) fflush(stdout);
326 	if((sym = getchar()) == EOF)
327 		end_of_input();
328 	if(flags.toplin == 1)
329 		flags.toplin = 2;
330 	return((char) sym);
331 }
332 
333 void
end_of_input(void)334 end_of_input(void)
335 {
336 	settty("End of input?\n");
337 	clearlocks();
338 	exit(0);
339 }
340