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