xref: /openbsd/games/hack/hack.tty.c (revision d0b779f3)
1 /*	$OpenBSD: hack.tty.c,v 1.4 2001/01/28 23:41:46 niklas 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. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *	This product includes software developed by the University of
18  *	California, Berkeley and its contributors.
19  * 4. Neither the name of the University nor the names of its contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  */
35 
36 #ifndef lint
37 #if 0
38 static char sccsid[] = "@(#)hack.tty.c	8.1 (Berkeley) 5/31/93";
39 #else
40 static char rcsid[] = "$OpenBSD: hack.tty.c,v 1.4 2001/01/28 23:41:46 niklas Exp $";
41 #endif
42 #endif /* not lint */
43 
44 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
45 /* hack.tty.c - version 1.0.3 */
46 /* With thanks to the people who sent code for SYSV - hpscdi!jon,
47    arnold@ucsf-cgl, wcs@bo95b, cbcephus!pds and others. */
48 
49 #include	"hack.h"
50 #include	<stdio.h>
51 #include	<termios.h>
52 
53 /*
54  * Some systems may have getchar() return EOF for various reasons, and
55  * we should not quit before seeing at least NR_OF_EOFS consecutive EOFs.
56  */
57 #ifndef BSD
58 #define	NR_OF_EOFS	20
59 #endif BSD
60 
61 extern speed_t ospeed;
62 static char erase_char, kill_char;
63 static boolean settty_needed = FALSE;
64 struct termios inittyb, curttyb;
65 
66 /*
67  * Get initial state of terminal, set ospeed (for termcap routines)
68  * and switch off tab expansion if necessary.
69  * Called by startup() in termcap.c and after returning from ! or ^Z
70  */
71 gettty(){
72 	if(tcgetattr(0, &inittyb) < 0)
73 		perror("Hack (gettty)");
74 	curttyb = inittyb;
75 	ospeed = cfgetospeed(&inittyb);
76 	erase_char = inittyb.c_cc[VERASE];
77 	kill_char = inittyb.c_cc[VKILL];
78 	getioctls();
79 
80 	/* do not expand tabs - they might be needed inside a cm sequence */
81 	if(curttyb.c_oflag & OXTABS) {
82 		curttyb.c_oflag &= ~OXTABS;
83 		setctty();
84 	}
85 	settty_needed = TRUE;
86 }
87 
88 /* reset terminal to original state */
89 settty(s) char *s; {
90 	clear_screen();
91 	end_screen();
92 	if(s) printf("%s", s);
93 	(void) fflush(stdout);
94 	if(tcsetattr(0, TCSADRAIN, &inittyb) < 0)
95 		perror("Hack (settty)");
96 	flags.echo = (inittyb.c_lflag & ECHO) ? ON : OFF;
97 	flags.cbreak = (inittyb.c_lflag & ICANON) ? OFF : ON;
98 	setioctls();
99 }
100 
101 setctty(){
102 	if(tcsetattr(0, TCSADRAIN, &curttyb) < 0)
103 		perror("Hack (setctty)");
104 }
105 
106 
107 setftty(){
108 register int change = 0;
109 	flags.cbreak = ON;
110 	flags.echo = OFF;
111 	/* Should use (ECHO|CRMOD) here instead of ECHO */
112 	if(curttyb.c_lflag & ECHO){
113 		curttyb.c_lflag &= ~ECHO;
114 		change++;
115 	}
116 	if(curttyb.c_lflag & ICANON){
117 		curttyb.c_lflag &= ~ICANON;
118 		/* be satisfied with one character; no timeout */
119 		curttyb.c_cc[VMIN] = 1;
120 		curttyb.c_cc[VTIME] = 0;
121 		change++;
122 	}
123 	if(change){
124 		setctty();
125 	}
126 	start_screen();
127 }
128 
129 
130 /* fatal error */
131 /*VARARGS1*/
132 error(s,x,y) char *s; {
133 	if(settty_needed)
134 		settty((char *) 0);
135 	printf(s,x,y);
136 	putchar('\n');
137 	exit(1);
138 }
139 
140 /*
141  * Read a line closed with '\n' into the array char bufp[BUFSZ].
142  * (The '\n' is not stored. The string is closed with a '\0'.)
143  * Reading can be interrupted by an escape ('\033') - now the
144  * resulting string is "\033".
145  */
146 getlin(bufp)
147 register char *bufp;
148 {
149 	register char *obufp = bufp;
150 	register int c;
151 
152 	flags.toplin = 2;		/* nonempty, no --More-- required */
153 	for(;;) {
154 		(void) fflush(stdout);
155 		if((c = getchar()) == EOF) {
156 			*bufp = 0;
157 			return;
158 		}
159 		if(c == '\033') {
160 			*obufp = c;
161 			obufp[1] = 0;
162 			return;
163 		}
164 		if(c == erase_char || c == '\b') {
165 			if(bufp != obufp) {
166 				bufp--;
167 				putstr("\b \b"); /* putsym converts \b */
168 			} else	bell();
169 		} else if(c == '\n') {
170 			*bufp = 0;
171 			return;
172 		} else if(' ' <= c && c < '\177') {
173 				/* avoid isprint() - some people don't have it
174 				   ' ' is not always a printing char */
175 			*bufp = c;
176 			bufp[1] = 0;
177 			putstr(bufp);
178 			if(bufp-obufp < BUFSZ-1 && bufp-obufp < COLNO)
179 				bufp++;
180 		} else if(c == kill_char || c == '\177') { /* Robert Viduya */
181 				/* this test last - @ might be the kill_char */
182 			while(bufp != obufp) {
183 				bufp--;
184 				putstr("\b \b");
185 			}
186 		} else
187 			bell();
188 	}
189 }
190 
191 getret() {
192 	cgetret("");
193 }
194 
195 cgetret(s)
196 register char *s;
197 {
198 	putsym('\n');
199 	if(flags.standout)
200 		standoutbeg();
201 	putstr("Hit ");
202 	putstr(flags.cbreak ? "space" : "return");
203 	putstr(" to continue: ");
204 	if(flags.standout)
205 		standoutend();
206 	xwaitforspace(s);
207 }
208 
209 char morc;	/* tell the outside world what char he used */
210 
211 xwaitforspace(s)
212 register char *s;	/* chars allowed besides space or return */
213 {
214 register int c;
215 
216 	morc = 0;
217 
218 	while((c = readchar()) != '\n') {
219 	    if(flags.cbreak) {
220 		if(c == ' ') break;
221 		if(s && strchr(s,c)) {
222 			morc = c;
223 			break;
224 		}
225 		bell();
226 	    }
227 	}
228 }
229 
230 char *
231 parse()
232 {
233 	static char inputline[COLNO];
234 	register foo;
235 
236 	flags.move = 1;
237 	if(!Invisible) curs_on_u(); else home();
238 	while((foo = readchar()) >= '0' && foo <= '9')
239 		multi = 10*multi+foo-'0';
240 	if(multi) {
241 		multi--;
242 		save_cm = inputline;
243 	}
244 	inputline[0] = foo;
245 	inputline[1] = 0;
246 	if(foo == 'f' || foo == 'F'){
247 		inputline[1] = getchar();
248 #ifdef QUEST
249 		if(inputline[1] == foo) inputline[2] = getchar(); else
250 #endif QUEST
251 		inputline[2] = 0;
252 	}
253 	if(foo == 'm' || foo == 'M'){
254 		inputline[1] = getchar();
255 		inputline[2] = 0;
256 	}
257 	clrlin();
258 	return(inputline);
259 }
260 
261 char
262 readchar() {
263 	register int sym;
264 
265 	(void) fflush(stdout);
266 	if((sym = getchar()) == EOF)
267 #ifdef NR_OF_EOFS
268 	{ /*
269 	   * Some SYSV systems seem to return EOFs for various reasons
270 	   * (?like when one hits break or for interrupted systemcalls?),
271 	   * and we must see several before we quit.
272 	   */
273 		register int cnt = NR_OF_EOFS;
274 		while (cnt--) {
275 		    clearerr(stdin);	/* omit if clearerr is undefined */
276 		    if((sym = getchar()) != EOF) goto noteof;
277 		}
278 		end_of_input();
279 	     noteof:	;
280 	}
281 #else
282 		end_of_input();
283 #endif NR_OF_EOFS
284 	if(flags.toplin == 1)
285 		flags.toplin = 2;
286 	return((char) sym);
287 }
288 
289 end_of_input()
290 {
291 	settty("End of input?\n");
292 	clearlocks();
293 	exit(0);
294 }
295