xref: /netbsd-src/games/hack/hack.tty.c (revision 5f7096188587a2c7c95fa3c69b78e1ec9c7923d0)
1 /*-
2  * Copyright (c) 1988 The Regents of the University of California.
3  * 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 
34 #ifndef lint
35 /*static char sccsid[] = "from: @(#)hack.tty.c	5.3 (Berkeley) 5/13/91";*/
36 static char rcsid[] = "$Id: hack.tty.c,v 1.2 1993/08/01 18:54:35 mycroft Exp $";
37 #endif /* not lint */
38 
39 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
40 /* hack.tty.c - version 1.0.3 */
41 /* With thanks to the people who sent code for SYSV - hpscdi!jon,
42    arnold@ucsf-cgl, wcs@bo95b, cbcephus!pds and others. */
43 
44 #include	"hack.h"
45 #include	<stdio.h>
46 
47 /*
48  * The distinctions here are not BSD - rest but rather USG - rest, as
49  * BSD still has the old sgttyb structure, but SYSV has termio. Thus:
50  */
51 #ifdef BSD
52 #define	V7
53 #else
54 #define USG
55 #endif BSD
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 
66 #ifdef USG
67 
68 #include	<termio.h>
69 #define termstruct	termio
70 #define kill_sym	c_cc[VKILL]
71 #define erase_sym	c_cc[VERASE]
72 #define EXTABS		TAB3
73 #define tabflgs		c_oflag
74 #define echoflgs	c_lflag
75 #define cbrkflgs	c_lflag
76 #define CBRKMASK	ICANON
77 #define CBRKON		! /* reverse condition */
78 #define OSPEED(x)	((x).c_cflag & CBAUD)
79 #define GTTY(x)		(ioctl(0, TCGETA, x))
80 #define STTY(x)		(ioctl(0, TCSETA, x))	/* TCSETAF? TCSETAW? */
81 
82 #else	/* V7 */
83 
84 #include	<sgtty.h>
85 #define termstruct	sgttyb
86 #define	kill_sym	sg_kill
87 #define	erase_sym	sg_erase
88 #define EXTABS		XTABS
89 #define tabflgs		sg_flags
90 #define echoflgs	sg_flags
91 #define cbrkflgs	sg_flags
92 #define CBRKMASK	CBREAK
93 #define CBRKON		/* empty */
94 #define OSPEED(x)	(x).sg_ospeed
95 #define GTTY(x)		(gtty(0, x))
96 #define STTY(x)		(stty(0, x))
97 
98 #endif USG
99 
100 extern short ospeed;
101 static char erase_char, kill_char;
102 static boolean settty_needed = FALSE;
103 struct termstruct inittyb, curttyb;
104 
105 /*
106  * Get initial state of terminal, set ospeed (for termcap routines)
107  * and switch off tab expansion if necessary.
108  * Called by startup() in termcap.c and after returning from ! or ^Z
109  */
110 gettty(){
111 	if(GTTY(&inittyb) < 0)
112 		perror("Hack (gettty)");
113 	curttyb = inittyb;
114 	ospeed = OSPEED(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 settty(s) char *s; {
129 	clear_screen();
130 	end_screen();
131 	if(s) printf(s);
132 	(void) fflush(stdout);
133 	if(STTY(&inittyb) < 0)
134 		perror("Hack (settty)");
135 	flags.echo = (inittyb.echoflgs & ECHO) ? ON : OFF;
136 	flags.cbreak = (CBRKON(inittyb.cbrkflgs & CBRKMASK)) ? ON : OFF;
137 	setioctls();
138 }
139 
140 setctty(){
141 	if(STTY(&curttyb) < 0)
142 		perror("Hack (setctty)");
143 }
144 
145 
146 setftty(){
147 register int ef = 0;			/* desired value of flags & ECHO */
148 register int cf = CBRKON(CBRKMASK);	/* desired value of flags & CBREAK */
149 register int change = 0;
150 	flags.cbreak = ON;
151 	flags.echo = OFF;
152 	/* Should use (ECHO|CRMOD) here instead of ECHO */
153 	if((curttyb.echoflgs & ECHO) != ef){
154 		curttyb.echoflgs &= ~ECHO;
155 /*		curttyb.echoflgs |= ef;					*/
156 		change++;
157 	}
158 	if((curttyb.cbrkflgs & CBRKMASK) != cf){
159 		curttyb.cbrkflgs &= ~CBRKMASK;
160 		curttyb.cbrkflgs |= cf;
161 #ifdef USG
162 		/* be satisfied with one character; no timeout */
163 		curttyb.c_cc[VMIN] = 1;		/* was VEOF */
164 		curttyb.c_cc[VTIME] = 0;	/* was VEOL */
165 #endif USG
166 		change++;
167 	}
168 	if(change){
169 		setctty();
170 	}
171 	start_screen();
172 }
173 
174 
175 /* fatal error */
176 /*VARARGS1*/
177 error(s,x,y) char *s; {
178 	if(settty_needed)
179 		settty((char *) 0);
180 	printf(s,x,y);
181 	putchar('\n');
182 	exit(1);
183 }
184 
185 /*
186  * Read a line closed with '\n' into the array char bufp[BUFSZ].
187  * (The '\n' is not stored. The string is closed with a '\0'.)
188  * Reading can be interrupted by an escape ('\033') - now the
189  * resulting string is "\033".
190  */
191 getlin(bufp)
192 register char *bufp;
193 {
194 	register char *obufp = bufp;
195 	register int c;
196 
197 	flags.toplin = 2;		/* nonempty, no --More-- required */
198 	for(;;) {
199 		(void) fflush(stdout);
200 		if((c = getchar()) == EOF) {
201 			*bufp = 0;
202 			return;
203 		}
204 		if(c == '\033') {
205 			*obufp = c;
206 			obufp[1] = 0;
207 			return;
208 		}
209 		if(c == erase_char || c == '\b') {
210 			if(bufp != obufp) {
211 				bufp--;
212 				putstr("\b \b"); /* putsym converts \b */
213 			} else	bell();
214 		} else if(c == '\n') {
215 			*bufp = 0;
216 			return;
217 		} else if(' ' <= c && c < '\177') {
218 				/* avoid isprint() - some people don't have it
219 				   ' ' is not always a printing char */
220 			*bufp = c;
221 			bufp[1] = 0;
222 			putstr(bufp);
223 			if(bufp-obufp < BUFSZ-1 && bufp-obufp < COLNO)
224 				bufp++;
225 		} else if(c == kill_char || c == '\177') { /* Robert Viduya */
226 				/* this test last - @ might be the kill_char */
227 			while(bufp != obufp) {
228 				bufp--;
229 				putstr("\b \b");
230 			}
231 		} else
232 			bell();
233 	}
234 }
235 
236 getret() {
237 	cgetret("");
238 }
239 
240 cgetret(s)
241 register char *s;
242 {
243 	putsym('\n');
244 	if(flags.standout)
245 		standoutbeg();
246 	putstr("Hit ");
247 	putstr(flags.cbreak ? "space" : "return");
248 	putstr(" to continue: ");
249 	if(flags.standout)
250 		standoutend();
251 	xwaitforspace(s);
252 }
253 
254 char morc;	/* tell the outside world what char he used */
255 
256 xwaitforspace(s)
257 register char *s;	/* chars allowed besides space or return */
258 {
259 register int c;
260 
261 	morc = 0;
262 
263 	while((c = readchar()) != '\n') {
264 	    if(flags.cbreak) {
265 		if(c == ' ') break;
266 		if(s && index(s,c)) {
267 			morc = c;
268 			break;
269 		}
270 		bell();
271 	    }
272 	}
273 }
274 
275 char *
276 parse()
277 {
278 	static char inputline[COLNO];
279 	register foo;
280 
281 	flags.move = 1;
282 	if(!Invisible) curs_on_u(); else home();
283 	while((foo = readchar()) >= '0' && foo <= '9')
284 		multi = 10*multi+foo-'0';
285 	if(multi) {
286 		multi--;
287 		save_cm = inputline;
288 	}
289 	inputline[0] = foo;
290 	inputline[1] = 0;
291 	if(foo == 'f' || foo == 'F'){
292 		inputline[1] = getchar();
293 #ifdef QUEST
294 		if(inputline[1] == foo) inputline[2] = getchar(); else
295 #endif QUEST
296 		inputline[2] = 0;
297 	}
298 	if(foo == 'm' || foo == 'M'){
299 		inputline[1] = getchar();
300 		inputline[2] = 0;
301 	}
302 	clrlin();
303 	return(inputline);
304 }
305 
306 char
307 readchar() {
308 	register 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 		register int cnt = NR_OF_EOFS;
319 		while (cnt--) {
320 		    clearerr(stdin);	/* omit if clearerr is undefined */
321 		    if((sym = getchar()) != EOF) goto noteof;
322 		}
323 		end_of_input();
324 	     noteof:	;
325 	}
326 #else
327 		end_of_input();
328 #endif NR_OF_EOFS
329 	if(flags.toplin == 1)
330 		flags.toplin = 2;
331 	return((char) sym);
332 }
333 
334 end_of_input()
335 {
336 	settty("End of input?\n");
337 	clearlocks();
338 	exit(0);
339 }
340