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