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