xref: /netbsd-src/games/hack/hack.tty.c (revision 2c0ecb1ab63c4e87a4abcff12e0a9e999ff836d9)
1 /*	$NetBSD: hack.tty.c,v 1.16 2011/08/06 20:42:43 dholland 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.16 2011/08/06 20:42:43 dholland 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 static struct termios  inittyb, curttyb;
124 
125 static void setctty(void);
126 
127 /*
128  * Get initial state of terminal, set ospeed (for termcap routines)
129  * and switch off tab expansion if necessary.
130  * Called by startup() in termcap.c and after returning from ! or ^Z
131  */
132 void
gettty(void)133 gettty(void)
134 {
135 	if (tcgetattr(0, &inittyb) < 0)
136 		perror("Hack (gettty)");
137 	curttyb = inittyb;
138 	ospeed = cfgetospeed(&inittyb);
139 	erase_char = inittyb.c_cc[VERASE];
140 	kill_char = inittyb.c_cc[VKILL];
141 	getioctls();
142 
143 	/* do not expand tabs - they might be needed inside a cm sequence */
144 	if (curttyb.c_oflag & OXTABS) {
145 		curttyb.c_oflag &= ~OXTABS;
146 		setctty();
147 	}
148 	settty_needed = TRUE;
149 }
150 
151 /* reset terminal to original state */
152 void
settty(const char * s)153 settty(const char *s)
154 {
155 	clearscreen();
156 	endscreen();
157 	if (s)
158 		printf("%s", s);
159 	(void) fflush(stdout);
160 	if (tcsetattr(0, TCSADRAIN, &inittyb) < 0)
161 		perror("Hack (settty)");
162 	flags.echo = (inittyb.c_lflag & ECHO) ? ON : OFF;
163 	flags.cbreak = (inittyb.c_lflag & ICANON) ? OFF : ON;
164 	setioctls();
165 }
166 
167 static void
setctty(void)168 setctty(void)
169 {
170 	if (tcsetattr(0, TCSADRAIN, &curttyb) < 0)
171 		perror("Hack (setctty)");
172 }
173 
174 
175 void
setftty(void)176 setftty(void)
177 {
178 	int             change = 0;
179 	flags.cbreak = ON;
180 	flags.echo = OFF;
181 	/* Should use (ECHO|CRMOD) here instead of ECHO */
182 	if (curttyb.c_lflag & ECHO) {
183 		curttyb.c_lflag &= ~ECHO;
184 		change++;
185 	}
186 	if (curttyb.c_lflag & ICANON) {
187 		curttyb.c_lflag &= ~ICANON;
188 		/* be satisfied with one character; no timeout */
189 		curttyb.c_cc[VMIN] = 1;
190 		curttyb.c_cc[VTIME] = 0;
191 		change++;
192 	}
193 	if (change) {
194 		setctty();
195 	}
196 	startscreen();
197 }
198 
199 
200 /* fatal error */
201 /* VARARGS1 */
202 void
error(const char * fmt,...)203 error(const char *fmt, ...)
204 {
205 	va_list ap;
206 
207 	va_start(ap, fmt);
208 	if (settty_needed)
209 		settty(NULL);
210 	vprintf(fmt, ap);
211 	va_end(ap);
212 	putchar('\n');
213 	exit(1);
214 }
215 
216 /*
217  * Read a line closed with '\n' into the array char bufp[BUFSZ].
218  * (The '\n' is not stored. The string is closed with a '\0'.)
219  * Reading can be interrupted by an escape ('\033') - now the
220  * resulting string is "\033".
221  */
222 void
getlin(char * bufp)223 getlin(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 				sound_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 			sound_bell();
267 	}
268 }
269 
270 void
getret(void)271 getret(void)
272 {
273 	cgetret("");
274 }
275 
276 void
cgetret(const char * s)277 cgetret(const char *s)
278 {
279 	putsym('\n');
280 	if (flags.standout)
281 		standoutbeg();
282 	putstr("Hit ");
283 	putstr(flags.cbreak ? "space" : "return");
284 	putstr(" to continue: ");
285 	if (flags.standout)
286 		standoutend();
287 	xwaitforspace(s);
288 }
289 
290 char            morc;		/* tell the outside world what char he used */
291 
292 /* s = chars allowed besides space or return */
293 void
xwaitforspace(const char * s)294 xwaitforspace(const char *s)
295 {
296 	int             c;
297 
298 	morc = 0;
299 
300 	while ((c = readchar()) != '\n') {
301 		if (flags.cbreak) {
302 			if (c == ' ')
303 				break;
304 			if (s && strchr(s, c)) {
305 				morc = c;
306 				break;
307 			}
308 			sound_bell();
309 		}
310 	}
311 }
312 
313 char           *
parse(void)314 parse(void)
315 {
316 	static char     inputline[COLNO];
317 	int		foo;
318 
319 	flags.move = 1;
320 	if (!Invisible)
321 		curs_on_u();
322 	else
323 		home();
324 	while ((foo = readchar()) >= '0' && foo <= '9')
325 		multi = 10 * multi + foo - '0';
326 	if (multi) {
327 		multi--;
328 		save_cm = inputline;
329 	}
330 	inputline[0] = foo;
331 	inputline[1] = 0;
332 	if (foo == 'f' || foo == 'F') {
333 		inputline[1] = getchar();
334 #ifdef QUEST
335 		if (inputline[1] == foo)
336 			inputline[2] = getchar();
337 		else
338 #endif	/* QUEST */
339 			inputline[2] = 0;
340 	}
341 	if (foo == 'm' || foo == 'M') {
342 		inputline[1] = getchar();
343 		inputline[2] = 0;
344 	}
345 	clrlin();
346 	return (inputline);
347 }
348 
349 char
readchar(void)350 readchar(void)
351 {
352 	int             sym;
353 
354 	(void) fflush(stdout);
355 	if ((sym = getchar()) == EOF)
356 #ifdef NR_OF_EOFS
357 	{			/*
358 			         * Some SYSV systems seem to return EOFs for various reasons
359 			         * (?like when one hits break or for interrupted systemcalls?),
360 			         * and we must see several before we quit.
361 			         */
362 		int             cnt = NR_OF_EOFS;
363 		while (cnt--) {
364 			clearerr(stdin);	/* omit if clearerr is
365 						 * undefined */
366 			if ((sym = getchar()) != EOF)
367 				goto noteof;
368 		}
369 		end_of_input();
370 noteof:	;
371 	}
372 #else
373 		end_of_input();
374 #endif	/* NR_OF_EOFS */
375 	if (flags.toplin == 1)
376 		flags.toplin = 2;
377 	return ((char) sym);
378 }
379 
380 void
end_of_input(void)381 end_of_input(void)
382 {
383 	settty("End of input?\n");
384 	clearlocks();
385 	exit(0);
386 }
387