xref: /netbsd-src/games/hack/hack.tty.c (revision 2c0ecb1ab63c4e87a4abcff12e0a9e999ff836d9)
1*2c0ecb1aSdholland /*	$NetBSD: hack.tty.c,v 1.16 2011/08/06 20:42:43 dholland Exp $	*/
23ea4a95cSchristos 
361f28255Scgd /*-
442fb1b9dScgd  * Copyright (c) 1988, 1993
542fb1b9dScgd  *	The Regents of the University of California.  All rights reserved.
661f28255Scgd  *
761f28255Scgd  * Redistribution and use in source and binary forms, with or without
861f28255Scgd  * modification, are permitted provided that the following conditions
961f28255Scgd  * are met:
1061f28255Scgd  * 1. Redistributions of source code must retain the above copyright
1161f28255Scgd  *    notice, this list of conditions and the following disclaimer.
1261f28255Scgd  * 2. Redistributions in binary form must reproduce the above copyright
1361f28255Scgd  *    notice, this list of conditions and the following disclaimer in the
1461f28255Scgd  *    documentation and/or other materials provided with the distribution.
15e5aeb4eaSagc  * 3. Neither the name of the University nor the names of its contributors
1661f28255Scgd  *    may be used to endorse or promote products derived from this software
1761f28255Scgd  *    without specific prior written permission.
1861f28255Scgd  *
1961f28255Scgd  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2061f28255Scgd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2161f28255Scgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2261f28255Scgd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2361f28255Scgd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2461f28255Scgd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2561f28255Scgd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2661f28255Scgd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2761f28255Scgd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2861f28255Scgd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2961f28255Scgd  * SUCH DAMAGE.
3061f28255Scgd  */
3161f28255Scgd 
323ea4a95cSchristos #include <sys/cdefs.h>
3361f28255Scgd #ifndef lint
3442fb1b9dScgd #if 0
3542fb1b9dScgd static char     sccsid[] = "@(#)hack.tty.c	8.1 (Berkeley) 5/31/93";
3642fb1b9dScgd #else
37*2c0ecb1aSdholland __RCSID("$NetBSD: hack.tty.c,v 1.16 2011/08/06 20:42:43 dholland Exp $");
3842fb1b9dScgd #endif
3961f28255Scgd #endif				/* not lint */
4061f28255Scgd 
411c7f94e5Sjsm /*
421c7f94e5Sjsm  * Copyright (c) 1985, Stichting Centrum voor Wiskunde en Informatica,
431c7f94e5Sjsm  * Amsterdam
441c7f94e5Sjsm  * All rights reserved.
451c7f94e5Sjsm  *
461c7f94e5Sjsm  * Redistribution and use in source and binary forms, with or without
471c7f94e5Sjsm  * modification, are permitted provided that the following conditions are
481c7f94e5Sjsm  * met:
491c7f94e5Sjsm  *
501c7f94e5Sjsm  * - Redistributions of source code must retain the above copyright notice,
511c7f94e5Sjsm  * this list of conditions and the following disclaimer.
521c7f94e5Sjsm  *
531c7f94e5Sjsm  * - Redistributions in binary form must reproduce the above copyright
541c7f94e5Sjsm  * notice, this list of conditions and the following disclaimer in the
551c7f94e5Sjsm  * documentation and/or other materials provided with the distribution.
561c7f94e5Sjsm  *
571c7f94e5Sjsm  * - Neither the name of the Stichting Centrum voor Wiskunde en
581c7f94e5Sjsm  * Informatica, nor the names of its contributors may be used to endorse or
591c7f94e5Sjsm  * promote products derived from this software without specific prior
601c7f94e5Sjsm  * written permission.
611c7f94e5Sjsm  *
621c7f94e5Sjsm  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
631c7f94e5Sjsm  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
641c7f94e5Sjsm  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
651c7f94e5Sjsm  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
661c7f94e5Sjsm  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
671c7f94e5Sjsm  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
681c7f94e5Sjsm  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
691c7f94e5Sjsm  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
701c7f94e5Sjsm  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
711c7f94e5Sjsm  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
721c7f94e5Sjsm  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
731c7f94e5Sjsm  */
741c7f94e5Sjsm 
751c7f94e5Sjsm /*
761c7f94e5Sjsm  * Copyright (c) 1982 Jay Fenlason <hack@gnu.org>
771c7f94e5Sjsm  * All rights reserved.
781c7f94e5Sjsm  *
791c7f94e5Sjsm  * Redistribution and use in source and binary forms, with or without
801c7f94e5Sjsm  * modification, are permitted provided that the following conditions
811c7f94e5Sjsm  * are met:
821c7f94e5Sjsm  * 1. Redistributions of source code must retain the above copyright
831c7f94e5Sjsm  *    notice, this list of conditions and the following disclaimer.
841c7f94e5Sjsm  * 2. Redistributions in binary form must reproduce the above copyright
851c7f94e5Sjsm  *    notice, this list of conditions and the following disclaimer in the
861c7f94e5Sjsm  *    documentation and/or other materials provided with the distribution.
871c7f94e5Sjsm  * 3. The name of the author may not be used to endorse or promote products
881c7f94e5Sjsm  *    derived from this software without specific prior written permission.
891c7f94e5Sjsm  *
901c7f94e5Sjsm  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
911c7f94e5Sjsm  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
921c7f94e5Sjsm  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
931c7f94e5Sjsm  * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
941c7f94e5Sjsm  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
951c7f94e5Sjsm  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
961c7f94e5Sjsm  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
971c7f94e5Sjsm  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
981c7f94e5Sjsm  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
991c7f94e5Sjsm  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1001c7f94e5Sjsm  */
1011c7f94e5Sjsm 
10261f28255Scgd /* hack.tty.c - version 1.0.3 */
1033ea4a95cSchristos /*
1043ea4a95cSchristos  * With thanks to the people who sent code for SYSV - hpscdi!jon,
1053ea4a95cSchristos  * arnold@ucsf-cgl, wcs@bo95b, cbcephus!pds and others.
1063ea4a95cSchristos  */
10761f28255Scgd 
10853eb389bSmycroft #include <termios.h>
109bc32159dSchristos #include <termcap.h>
1103ea4a95cSchristos #include "hack.h"
1113ea4a95cSchristos #include "extern.h"
11261f28255Scgd 
11361f28255Scgd /*
11461f28255Scgd  * Some systems may have getchar() return EOF for various reasons, and
11561f28255Scgd  * we should not quit before seeing at least NR_OF_EOFS consecutive EOFs.
11661f28255Scgd  */
11761f28255Scgd #ifndef BSD
11861f28255Scgd #define	NR_OF_EOFS	20
1193ea4a95cSchristos #endif	/* BSD */
12061f28255Scgd 
12161f28255Scgd static char     erase_char, kill_char;
12261f28255Scgd static boolean  settty_needed = FALSE;
1239b92b189Sdholland static struct termios  inittyb, curttyb;
1249b92b189Sdholland 
1259b92b189Sdholland static void setctty(void);
12661f28255Scgd 
12761f28255Scgd /*
12861f28255Scgd  * Get initial state of terminal, set ospeed (for termcap routines)
12961f28255Scgd  * and switch off tab expansion if necessary.
13061f28255Scgd  * Called by startup() in termcap.c and after returning from ! or ^Z
13161f28255Scgd  */
1323ea4a95cSchristos void
gettty(void)1331fa8a9a6Sdholland gettty(void)
1343ea4a95cSchristos {
13553eb389bSmycroft 	if (tcgetattr(0, &inittyb) < 0)
13661f28255Scgd 		perror("Hack (gettty)");
13761f28255Scgd 	curttyb = inittyb;
13853eb389bSmycroft 	ospeed = cfgetospeed(&inittyb);
13953eb389bSmycroft 	erase_char = inittyb.c_cc[VERASE];
14053eb389bSmycroft 	kill_char = inittyb.c_cc[VKILL];
14161f28255Scgd 	getioctls();
14261f28255Scgd 
14361f28255Scgd 	/* do not expand tabs - they might be needed inside a cm sequence */
14453eb389bSmycroft 	if (curttyb.c_oflag & OXTABS) {
14553eb389bSmycroft 		curttyb.c_oflag &= ~OXTABS;
14661f28255Scgd 		setctty();
14761f28255Scgd 	}
14861f28255Scgd 	settty_needed = TRUE;
14961f28255Scgd }
15061f28255Scgd 
15161f28255Scgd /* reset terminal to original state */
1523ea4a95cSchristos void
settty(const char * s)1531fa8a9a6Sdholland settty(const char *s)
1543ea4a95cSchristos {
15598eb8895Sroy 	clearscreen();
15698eb8895Sroy 	endscreen();
1573ea4a95cSchristos 	if (s)
158d3039275Sitojun 		printf("%s", s);
15961f28255Scgd 	(void) fflush(stdout);
16053eb389bSmycroft 	if (tcsetattr(0, TCSADRAIN, &inittyb) < 0)
16161f28255Scgd 		perror("Hack (settty)");
16253eb389bSmycroft 	flags.echo = (inittyb.c_lflag & ECHO) ? ON : OFF;
16353eb389bSmycroft 	flags.cbreak = (inittyb.c_lflag & ICANON) ? OFF : ON;
16461f28255Scgd 	setioctls();
16561f28255Scgd }
16661f28255Scgd 
1679b92b189Sdholland static void
setctty(void)1681fa8a9a6Sdholland setctty(void)
1693ea4a95cSchristos {
17053eb389bSmycroft 	if (tcsetattr(0, TCSADRAIN, &curttyb) < 0)
17161f28255Scgd 		perror("Hack (setctty)");
17261f28255Scgd }
17361f28255Scgd 
17461f28255Scgd 
1753ea4a95cSchristos void
setftty(void)1761fa8a9a6Sdholland setftty(void)
1773ea4a95cSchristos {
1783ea4a95cSchristos 	int             change = 0;
17961f28255Scgd 	flags.cbreak = ON;
18061f28255Scgd 	flags.echo = OFF;
18161f28255Scgd 	/* Should use (ECHO|CRMOD) here instead of ECHO */
18253eb389bSmycroft 	if (curttyb.c_lflag & ECHO) {
18353eb389bSmycroft 		curttyb.c_lflag &= ~ECHO;
18461f28255Scgd 		change++;
18561f28255Scgd 	}
18653eb389bSmycroft 	if (curttyb.c_lflag & ICANON) {
18753eb389bSmycroft 		curttyb.c_lflag &= ~ICANON;
18861f28255Scgd 		/* be satisfied with one character; no timeout */
18953eb389bSmycroft 		curttyb.c_cc[VMIN] = 1;
19053eb389bSmycroft 		curttyb.c_cc[VTIME] = 0;
19161f28255Scgd 		change++;
19261f28255Scgd 	}
19361f28255Scgd 	if (change) {
19461f28255Scgd 		setctty();
19561f28255Scgd 	}
19698eb8895Sroy 	startscreen();
19761f28255Scgd }
19861f28255Scgd 
19961f28255Scgd 
20061f28255Scgd /* fatal error */
20161f28255Scgd /* VARARGS1 */
2023ea4a95cSchristos void
error(const char * fmt,...)2033ea4a95cSchristos error(const char *fmt, ...)
2043ea4a95cSchristos {
2053ea4a95cSchristos 	va_list ap;
2063ea4a95cSchristos 
2073ea4a95cSchristos 	va_start(ap, fmt);
20861f28255Scgd 	if (settty_needed)
209*2c0ecb1aSdholland 		settty(NULL);
2103ea4a95cSchristos 	vprintf(fmt, ap);
2113ea4a95cSchristos 	va_end(ap);
21261f28255Scgd 	putchar('\n');
21361f28255Scgd 	exit(1);
21461f28255Scgd }
21561f28255Scgd 
21661f28255Scgd /*
21761f28255Scgd  * Read a line closed with '\n' into the array char bufp[BUFSZ].
21861f28255Scgd  * (The '\n' is not stored. The string is closed with a '\0'.)
21961f28255Scgd  * Reading can be interrupted by an escape ('\033') - now the
22061f28255Scgd  * resulting string is "\033".
22161f28255Scgd  */
2223ea4a95cSchristos void
getlin(char * bufp)2231fa8a9a6Sdholland getlin(char *bufp)
22461f28255Scgd {
2253ea4a95cSchristos 	char           *obufp = bufp;
2263ea4a95cSchristos 	int             c;
22761f28255Scgd 
22861f28255Scgd 	flags.toplin = 2;	/* nonempty, no --More-- required */
22961f28255Scgd 	for (;;) {
23061f28255Scgd 		(void) fflush(stdout);
23161f28255Scgd 		if ((c = getchar()) == EOF) {
23261f28255Scgd 			*bufp = 0;
23361f28255Scgd 			return;
23461f28255Scgd 		}
23561f28255Scgd 		if (c == '\033') {
23661f28255Scgd 			*obufp = c;
23761f28255Scgd 			obufp[1] = 0;
23861f28255Scgd 			return;
23961f28255Scgd 		}
24061f28255Scgd 		if (c == erase_char || c == '\b') {
24161f28255Scgd 			if (bufp != obufp) {
24261f28255Scgd 				bufp--;
24361f28255Scgd 				putstr("\b \b");	/* putsym converts \b */
2443ea4a95cSchristos 			} else
24598eb8895Sroy 				sound_bell();
24661f28255Scgd 		} else if (c == '\n') {
24761f28255Scgd 			*bufp = 0;
24861f28255Scgd 			return;
24961f28255Scgd 		} else if (' ' <= c && c < '\177') {
2503ea4a95cSchristos 			/*
2513ea4a95cSchristos 			 * avoid isprint() - some people don't have it ' ' is
2523ea4a95cSchristos 			 * not always a printing char
2533ea4a95cSchristos 			 */
25461f28255Scgd 			*bufp = c;
25561f28255Scgd 			bufp[1] = 0;
25661f28255Scgd 			putstr(bufp);
25761f28255Scgd 			if (bufp - obufp < BUFSZ - 1 && bufp - obufp < COLNO)
25861f28255Scgd 				bufp++;
25961f28255Scgd 		} else if (c == kill_char || c == '\177') {	/* Robert Viduya */
26061f28255Scgd 			/* this test last - @ might be the kill_char */
26161f28255Scgd 			while (bufp != obufp) {
26261f28255Scgd 				bufp--;
26361f28255Scgd 				putstr("\b \b");
26461f28255Scgd 			}
26561f28255Scgd 		} else
26698eb8895Sroy 			sound_bell();
26761f28255Scgd 	}
26861f28255Scgd }
26961f28255Scgd 
2703ea4a95cSchristos void
getret(void)2711fa8a9a6Sdholland getret(void)
2723ea4a95cSchristos {
27361f28255Scgd 	cgetret("");
27461f28255Scgd }
27561f28255Scgd 
2763ea4a95cSchristos void
cgetret(const char * s)2771fa8a9a6Sdholland cgetret(const char *s)
27861f28255Scgd {
27961f28255Scgd 	putsym('\n');
28061f28255Scgd 	if (flags.standout)
28161f28255Scgd 		standoutbeg();
28261f28255Scgd 	putstr("Hit ");
28361f28255Scgd 	putstr(flags.cbreak ? "space" : "return");
28461f28255Scgd 	putstr(" to continue: ");
28561f28255Scgd 	if (flags.standout)
28661f28255Scgd 		standoutend();
28761f28255Scgd 	xwaitforspace(s);
28861f28255Scgd }
28961f28255Scgd 
29061f28255Scgd char            morc;		/* tell the outside world what char he used */
29161f28255Scgd 
2921fa8a9a6Sdholland /* s = chars allowed besides space or return */
2933ea4a95cSchristos void
xwaitforspace(const char * s)2941fa8a9a6Sdholland xwaitforspace(const char *s)
29561f28255Scgd {
2963ea4a95cSchristos 	int             c;
29761f28255Scgd 
29861f28255Scgd 	morc = 0;
29961f28255Scgd 
30061f28255Scgd 	while ((c = readchar()) != '\n') {
30161f28255Scgd 		if (flags.cbreak) {
3023ea4a95cSchristos 			if (c == ' ')
3033ea4a95cSchristos 				break;
3043ea4a95cSchristos 			if (s && strchr(s, c)) {
30561f28255Scgd 				morc = c;
30661f28255Scgd 				break;
30761f28255Scgd 			}
30898eb8895Sroy 			sound_bell();
30961f28255Scgd 		}
31061f28255Scgd 	}
31161f28255Scgd }
31261f28255Scgd 
31361f28255Scgd char           *
parse(void)3141fa8a9a6Sdholland parse(void)
31561f28255Scgd {
31661f28255Scgd 	static char     inputline[COLNO];
3173ea4a95cSchristos 	int		foo;
31861f28255Scgd 
31961f28255Scgd 	flags.move = 1;
3203ea4a95cSchristos 	if (!Invisible)
3213ea4a95cSchristos 		curs_on_u();
3223ea4a95cSchristos 	else
3233ea4a95cSchristos 		home();
32461f28255Scgd 	while ((foo = readchar()) >= '0' && foo <= '9')
32561f28255Scgd 		multi = 10 * multi + foo - '0';
32661f28255Scgd 	if (multi) {
32761f28255Scgd 		multi--;
32861f28255Scgd 		save_cm = inputline;
32961f28255Scgd 	}
33061f28255Scgd 	inputline[0] = foo;
33161f28255Scgd 	inputline[1] = 0;
33261f28255Scgd 	if (foo == 'f' || foo == 'F') {
33361f28255Scgd 		inputline[1] = getchar();
33461f28255Scgd #ifdef QUEST
3353ea4a95cSchristos 		if (inputline[1] == foo)
3363ea4a95cSchristos 			inputline[2] = getchar();
3373ea4a95cSchristos 		else
3383ea4a95cSchristos #endif	/* QUEST */
33961f28255Scgd 			inputline[2] = 0;
34061f28255Scgd 	}
34161f28255Scgd 	if (foo == 'm' || foo == 'M') {
34261f28255Scgd 		inputline[1] = getchar();
34361f28255Scgd 		inputline[2] = 0;
34461f28255Scgd 	}
34561f28255Scgd 	clrlin();
34661f28255Scgd 	return (inputline);
34761f28255Scgd }
34861f28255Scgd 
34961f28255Scgd char
readchar(void)3501fa8a9a6Sdholland readchar(void)
3513ea4a95cSchristos {
3523ea4a95cSchristos 	int             sym;
35361f28255Scgd 
35461f28255Scgd 	(void) fflush(stdout);
35561f28255Scgd 	if ((sym = getchar()) == EOF)
35661f28255Scgd #ifdef NR_OF_EOFS
35761f28255Scgd 	{			/*
35861f28255Scgd 			         * Some SYSV systems seem to return EOFs for various reasons
35961f28255Scgd 			         * (?like when one hits break or for interrupted systemcalls?),
36061f28255Scgd 			         * and we must see several before we quit.
36161f28255Scgd 			         */
3623ea4a95cSchristos 		int             cnt = NR_OF_EOFS;
36361f28255Scgd 		while (cnt--) {
3643ea4a95cSchristos 			clearerr(stdin);	/* omit if clearerr is
3653ea4a95cSchristos 						 * undefined */
3663ea4a95cSchristos 			if ((sym = getchar()) != EOF)
3673ea4a95cSchristos 				goto noteof;
36861f28255Scgd 		}
36961f28255Scgd 		end_of_input();
37061f28255Scgd noteof:	;
37161f28255Scgd 	}
37261f28255Scgd #else
37361f28255Scgd 		end_of_input();
3743ea4a95cSchristos #endif	/* NR_OF_EOFS */
37561f28255Scgd 	if (flags.toplin == 1)
37661f28255Scgd 		flags.toplin = 2;
37761f28255Scgd 	return ((char) sym);
37861f28255Scgd }
37961f28255Scgd 
3803ea4a95cSchristos void
end_of_input(void)3811fa8a9a6Sdholland end_of_input(void)
38261f28255Scgd {
38361f28255Scgd 	settty("End of input?\n");
38461f28255Scgd 	clearlocks();
38561f28255Scgd 	exit(0);
38661f28255Scgd }
387