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