xref: /dragonfly/games/hack/hack.tty.c (revision 2cd2d2b5)
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.2 2003/06/17 04:25:24 dillon 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 #include	<stdio.h>
45 
46 /*
47  * The distinctions here are not BSD - rest but rather USG - rest, as
48  * BSD still has the old sgttyb structure, but SYSV has termio. Thus:
49  */
50 #ifdef BSD
51 #define	V7
52 #else
53 #define USG
54 #endif BSD
55 
56 /*
57  * Some systems may have getchar() return EOF for various reasons, and
58  * we should not quit before seeing at least NR_OF_EOFS consecutive EOFs.
59  */
60 #ifndef BSD
61 #define	NR_OF_EOFS	20
62 #endif BSD
63 
64 
65 #ifdef USG
66 
67 #include	<termio.h>
68 #define termstruct	termio
69 #define kill_sym	c_cc[VKILL]
70 #define erase_sym	c_cc[VERASE]
71 #define EXTABS		TAB3
72 #define tabflgs		c_oflag
73 #define echoflgs	c_lflag
74 #define cbrkflgs	c_lflag
75 #define CBRKMASK	ICANON
76 #define CBRKON		! /* reverse condition */
77 #define OSPEED(x)	((x).c_cflag & CBAUD)
78 #define GTTY(x)		(ioctl(0, TCGETA, x))
79 #define STTY(x)		(ioctl(0, TCSETA, x))	/* TCSETAF? TCSETAW? */
80 
81 #else	/* V7 */
82 
83 #include	<sgtty.h>
84 #define termstruct	sgttyb
85 #define	kill_sym	sg_kill
86 #define	erase_sym	sg_erase
87 #define EXTABS		XTABS
88 #define tabflgs		sg_flags
89 #define echoflgs	sg_flags
90 #define cbrkflgs	sg_flags
91 #define CBRKMASK	CBREAK
92 #define CBRKON		/* empty */
93 #define OSPEED(x)	(x).sg_ospeed
94 #define GTTY(x)		(gtty(0, x))
95 #define STTY(x)		(stty(0, x))
96 
97 #endif USG
98 
99 #if 0
100 extern short ospeed;
101 #endif
102 static char erase_char, kill_char;
103 static boolean settty_needed = FALSE;
104 struct termstruct inittyb, curttyb;
105 
106 /*
107  * Get initial state of terminal, set ospeed (for termcap routines)
108  * and switch off tab expansion if necessary.
109  * Called by startup() in termcap.c and after returning from ! or ^Z
110  */
111 gettty(){
112 	if(GTTY(&inittyb) < 0)
113 		perror("Hack (gettty)");
114 	curttyb = inittyb;
115 #if 0
116 	ospeed = OSPEED(inittyb);
117 #endif
118 	erase_char = inittyb.erase_sym;
119 	kill_char = inittyb.kill_sym;
120 	getioctls();
121 
122 	/* do not expand tabs - they might be needed inside a cm sequence */
123 	if(curttyb.tabflgs & EXTABS) {
124 		curttyb.tabflgs &= ~EXTABS;
125 		setctty();
126 	}
127 	settty_needed = TRUE;
128 }
129 
130 /* reset terminal to original state */
131 settty(s) char *s; {
132 	clear_screen();
133 	end_screen();
134 	if(s) printf("%s", s);
135 	(void) fflush(stdout);
136 	if(STTY(&inittyb) < 0)
137 		perror("Hack (settty)");
138 	flags.echo = (inittyb.echoflgs & ECHO) ? ON : OFF;
139 	flags.cbreak = (CBRKON(inittyb.cbrkflgs & CBRKMASK)) ? ON : OFF;
140 	setioctls();
141 }
142 
143 setctty(){
144 	if(STTY(&curttyb) < 0)
145 		perror("Hack (setctty)");
146 }
147 
148 
149 setftty(){
150 int ef = 0;			/* desired value of flags & ECHO */
151 int cf = CBRKON(CBRKMASK);	/* desired value of flags & CBREAK */
152 int change = 0;
153 	flags.cbreak = ON;
154 	flags.echo = OFF;
155 	/* Should use (ECHO|CRMOD) here instead of ECHO */
156 	if((curttyb.echoflgs & ECHO) != ef){
157 		curttyb.echoflgs &= ~ECHO;
158 /*		curttyb.echoflgs |= ef;					*/
159 		change++;
160 	}
161 	if((curttyb.cbrkflgs & CBRKMASK) != cf){
162 		curttyb.cbrkflgs &= ~CBRKMASK;
163 		curttyb.cbrkflgs |= cf;
164 #ifdef USG
165 		/* be satisfied with one character; no timeout */
166 		curttyb.c_cc[VMIN] = 1;		/* was VEOF */
167 		curttyb.c_cc[VTIME] = 0;	/* was VEOL */
168 #endif USG
169 		change++;
170 	}
171 	if(change){
172 		setctty();
173 	}
174 	start_screen();
175 }
176 
177 
178 /* fatal error */
179 /*VARARGS1*/
180 error(s,x,y) char *s; {
181 	if(settty_needed)
182 		settty((char *) 0);
183 	printf(s,x,y);
184 	putchar('\n');
185 	exit(1);
186 }
187 
188 /*
189  * Read a line closed with '\n' into the array char bufp[BUFSZ].
190  * (The '\n' is not stored. The string is closed with a '\0'.)
191  * Reading can be interrupted by an escape ('\033') - now the
192  * resulting string is "\033".
193  */
194 getlin(bufp)
195 char *bufp;
196 {
197 	char *obufp = bufp;
198 	int c;
199 
200 	flags.toplin = 2;		/* nonempty, no --More-- required */
201 	for(;;) {
202 		(void) fflush(stdout);
203 		if((c = getchar()) == EOF) {
204 			*bufp = 0;
205 			return;
206 		}
207 		if(c == '\033') {
208 			*obufp = c;
209 			obufp[1] = 0;
210 			return;
211 		}
212 		if(c == erase_char || c == '\b') {
213 			if(bufp != obufp) {
214 				bufp--;
215 				putstr("\b \b"); /* putsym converts \b */
216 			} else	bell();
217 		} else if(c == '\n') {
218 			*bufp = 0;
219 			return;
220 		} else if(' ' <= c && c < '\177') {
221 				/* avoid isprint() - some people don't have it
222 				   ' ' is not always a printing char */
223 			*bufp = c;
224 			bufp[1] = 0;
225 			putstr(bufp);
226 			if(bufp-obufp < BUFSZ-1 && bufp-obufp < COLNO)
227 				bufp++;
228 		} else if(c == kill_char || c == '\177') { /* Robert Viduya */
229 				/* this test last - @ might be the kill_char */
230 			while(bufp != obufp) {
231 				bufp--;
232 				putstr("\b \b");
233 			}
234 		} else
235 			bell();
236 	}
237 }
238 
239 getret() {
240 	cgetret("");
241 }
242 
243 cgetret(s)
244 char *s;
245 {
246 	putsym('\n');
247 	if(flags.standout)
248 		standoutbeg();
249 	putstr("Hit ");
250 	putstr(flags.cbreak ? "space" : "return");
251 	putstr(" to continue: ");
252 	if(flags.standout)
253 		standoutend();
254 	xwaitforspace(s);
255 }
256 
257 char morc;	/* tell the outside world what char he used */
258 
259 xwaitforspace(s)
260 char *s;	/* chars allowed besides space or return */
261 {
262 int c;
263 
264 	morc = 0;
265 
266 	while((c = readchar()) != '\n') {
267 	    if(flags.cbreak) {
268 		if(c == ' ') break;
269 		if(s && index(s,c)) {
270 			morc = c;
271 			break;
272 		}
273 		bell();
274 	    }
275 	}
276 }
277 
278 char *
279 parse()
280 {
281 	static char inputline[COLNO];
282 	int foo;
283 
284 	flags.move = 1;
285 	if(!Invisible) curs_on_u(); else home();
286 	while((foo = readchar()) >= '0' && foo <= '9')
287 		multi = 10*multi+foo-'0';
288 	if(multi) {
289 		multi--;
290 		save_cm = inputline;
291 	}
292 	inputline[0] = foo;
293 	inputline[1] = 0;
294 	if(foo == 'f' || foo == 'F'){
295 		inputline[1] = getchar();
296 #ifdef QUEST
297 		if(inputline[1] == foo) inputline[2] = getchar(); else
298 #endif QUEST
299 		inputline[2] = 0;
300 	}
301 	if(foo == 'm' || foo == 'M'){
302 		inputline[1] = getchar();
303 		inputline[2] = 0;
304 	}
305 	clrlin();
306 	return(inputline);
307 }
308 
309 char
310 readchar() {
311 	int sym;
312 
313 	(void) fflush(stdout);
314 	if((sym = getchar()) == EOF)
315 #ifdef NR_OF_EOFS
316 	{ /*
317 	   * Some SYSV systems seem to return EOFs for various reasons
318 	   * (?like when one hits break or for interrupted systemcalls?),
319 	   * and we must see several before we quit.
320 	   */
321 		int cnt = NR_OF_EOFS;
322 		while (cnt--) {
323 		    clearerr(stdin);	/* omit if clearerr is undefined */
324 		    if((sym = getchar()) != EOF) goto noteof;
325 		}
326 		end_of_input();
327 	     noteof:	;
328 	}
329 #else
330 		end_of_input();
331 #endif NR_OF_EOFS
332 	if(flags.toplin == 1)
333 		flags.toplin = 2;
334 	return((char) sym);
335 }
336 
337 end_of_input()
338 {
339 	settty("End of input?\n");
340 	clearlocks();
341 	exit(0);
342 }
343