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