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