xref: /netbsd-src/games/hack/hack.tty.c (revision 10ad5ffa714ce1a679dcc9dd8159648df2d67b5a)
1 /*	$NetBSD: hack.tty.c,v 1.13 2009/06/07 18:30:39 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.13 2009/06/07 18:30:39 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 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(void)
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(const char *s)
152 {
153 	clear_screen();
154 	end_screen();
155 	if (s)
156 		printf("%s", s);
157 	(void) fflush(stdout);
158 	if (tcsetattr(0, TCSADRAIN, &inittyb) < 0)
159 		perror("Hack (settty)");
160 	flags.echo = (inittyb.c_lflag & ECHO) ? ON : OFF;
161 	flags.cbreak = (inittyb.c_lflag & ICANON) ? OFF : ON;
162 	setioctls();
163 }
164 
165 void
166 setctty(void)
167 {
168 	if (tcsetattr(0, TCSADRAIN, &curttyb) < 0)
169 		perror("Hack (setctty)");
170 }
171 
172 
173 void
174 setftty(void)
175 {
176 	int             change = 0;
177 	flags.cbreak = ON;
178 	flags.echo = OFF;
179 	/* Should use (ECHO|CRMOD) here instead of ECHO */
180 	if (curttyb.c_lflag & ECHO) {
181 		curttyb.c_lflag &= ~ECHO;
182 		change++;
183 	}
184 	if (curttyb.c_lflag & ICANON) {
185 		curttyb.c_lflag &= ~ICANON;
186 		/* be satisfied with one character; no timeout */
187 		curttyb.c_cc[VMIN] = 1;
188 		curttyb.c_cc[VTIME] = 0;
189 		change++;
190 	}
191 	if (change) {
192 		setctty();
193 	}
194 	start_screen();
195 }
196 
197 
198 /* fatal error */
199 /* VARARGS1 */
200 void
201 error(const char *fmt, ...)
202 {
203 	va_list ap;
204 
205 	va_start(ap, fmt);
206 	if (settty_needed)
207 		settty((char *) 0);
208 	vprintf(fmt, ap);
209 	va_end(ap);
210 	putchar('\n');
211 	exit(1);
212 }
213 
214 /*
215  * Read a line closed with '\n' into the array char bufp[BUFSZ].
216  * (The '\n' is not stored. The string is closed with a '\0'.)
217  * Reading can be interrupted by an escape ('\033') - now the
218  * resulting string is "\033".
219  */
220 void
221 getlin(char *bufp)
222 {
223 	char           *obufp = bufp;
224 	int             c;
225 
226 	flags.toplin = 2;	/* nonempty, no --More-- required */
227 	for (;;) {
228 		(void) fflush(stdout);
229 		if ((c = getchar()) == EOF) {
230 			*bufp = 0;
231 			return;
232 		}
233 		if (c == '\033') {
234 			*obufp = c;
235 			obufp[1] = 0;
236 			return;
237 		}
238 		if (c == erase_char || c == '\b') {
239 			if (bufp != obufp) {
240 				bufp--;
241 				putstr("\b \b");	/* putsym converts \b */
242 			} else
243 				bell();
244 		} else if (c == '\n') {
245 			*bufp = 0;
246 			return;
247 		} else if (' ' <= c && c < '\177') {
248 			/*
249 			 * avoid isprint() - some people don't have it ' ' is
250 			 * not always a printing char
251 			 */
252 			*bufp = c;
253 			bufp[1] = 0;
254 			putstr(bufp);
255 			if (bufp - obufp < BUFSZ - 1 && bufp - obufp < COLNO)
256 				bufp++;
257 		} else if (c == kill_char || c == '\177') {	/* Robert Viduya */
258 			/* this test last - @ might be the kill_char */
259 			while (bufp != obufp) {
260 				bufp--;
261 				putstr("\b \b");
262 			}
263 		} else
264 			bell();
265 	}
266 }
267 
268 void
269 getret(void)
270 {
271 	cgetret("");
272 }
273 
274 void
275 cgetret(const char *s)
276 {
277 	putsym('\n');
278 	if (flags.standout)
279 		standoutbeg();
280 	putstr("Hit ");
281 	putstr(flags.cbreak ? "space" : "return");
282 	putstr(" to continue: ");
283 	if (flags.standout)
284 		standoutend();
285 	xwaitforspace(s);
286 }
287 
288 char            morc;		/* tell the outside world what char he used */
289 
290 /* s = chars allowed besides space or return */
291 void
292 xwaitforspace(const char *s)
293 {
294 	int             c;
295 
296 	morc = 0;
297 
298 	while ((c = readchar()) != '\n') {
299 		if (flags.cbreak) {
300 			if (c == ' ')
301 				break;
302 			if (s && strchr(s, c)) {
303 				morc = c;
304 				break;
305 			}
306 			bell();
307 		}
308 	}
309 }
310 
311 char           *
312 parse(void)
313 {
314 	static char     inputline[COLNO];
315 	int		foo;
316 
317 	flags.move = 1;
318 	if (!Invisible)
319 		curs_on_u();
320 	else
321 		home();
322 	while ((foo = readchar()) >= '0' && foo <= '9')
323 		multi = 10 * multi + foo - '0';
324 	if (multi) {
325 		multi--;
326 		save_cm = inputline;
327 	}
328 	inputline[0] = foo;
329 	inputline[1] = 0;
330 	if (foo == 'f' || foo == 'F') {
331 		inputline[1] = getchar();
332 #ifdef QUEST
333 		if (inputline[1] == foo)
334 			inputline[2] = getchar();
335 		else
336 #endif	/* QUEST */
337 			inputline[2] = 0;
338 	}
339 	if (foo == 'm' || foo == 'M') {
340 		inputline[1] = getchar();
341 		inputline[2] = 0;
342 	}
343 	clrlin();
344 	return (inputline);
345 }
346 
347 char
348 readchar(void)
349 {
350 	int             sym;
351 
352 	(void) fflush(stdout);
353 	if ((sym = getchar()) == EOF)
354 #ifdef NR_OF_EOFS
355 	{			/*
356 			         * Some SYSV systems seem to return EOFs for various reasons
357 			         * (?like when one hits break or for interrupted systemcalls?),
358 			         * and we must see several before we quit.
359 			         */
360 		int             cnt = NR_OF_EOFS;
361 		while (cnt--) {
362 			clearerr(stdin);	/* omit if clearerr is
363 						 * undefined */
364 			if ((sym = getchar()) != EOF)
365 				goto noteof;
366 		}
367 		end_of_input();
368 noteof:	;
369 	}
370 #else
371 		end_of_input();
372 #endif	/* NR_OF_EOFS */
373 	if (flags.toplin == 1)
374 		flags.toplin = 2;
375 	return ((char) sym);
376 }
377 
378 void
379 end_of_input(void)
380 {
381 	settty("End of input?\n");
382 	clearlocks();
383 	exit(0);
384 }
385