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