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