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