[net.sources.games] new version of hack.tty.c

local@ihopb.UUCP (Steven Spearman) (07/18/85)

Here is yet another rendition of hack.tty.c for System V unix.
This attempts a fix of the 'End of Input?' error caused by hitting
the old BREAK at the wrong time.  The problem appears to be
casued by the interrupt normally occuring while waiting for input
in getchar() which in system V causes a return of -1 which looks
like an EOF.  The solution is to do a clearerr(stdin) and try again.

I don't have any idea if this is now still compatible with BSD.

Steve Spearman  ihnp4!ihopb!spear

-----cut here-------

/*
 *	Here is hack.tty.c, modified to work on System V Release 2.
 *	I haven't checked to see if it will still work on BSD, but it should.
 *				Bill
 */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* hack.tty.c - version 1.0.2 */

/* hacked by bill stewart at att-bl because the CBREAK flag doesn't work */
/* on System V - so I hacked it to use termio instead			 */
/*
 * re-hacked to eliminate 'End of Input?' error upon signal
 *    -Steve Spearman ihnp4!ihopb!spear
 */

#include	"hack.h"
#include	<stdio.h>
#include	<ctype.h>	/* for isprint() */
#ifdef BSD
#include	<sgtty.h>
#else
#include	<termio.h>
#define	sgttyb		termio
#define	sg_flags	c_lflag
			/* Well, most of the time it's used for c_lflag */
			/*	Yes, I admit it's crude			*/
#define	CBREAK		ICANON
			/* Usually you just care about the bitmask */
#endif BSD

struct sgttyb inittyb, curttyb;
short ospeed;
char erase_char, kill_char;
static boolean settty_needed = FALSE;
#ifndef	BSD
unsigned char	c_cc_VMIN, c_cc_VTIME;	/* = c_cc[EOF] and c_cc[EOL] */
#endif

/*
 * Get initial state of terminal, set ospeed (for termcap routines)
 * and switch off tab expansion if necessary.
 * Called by startup() in termcap.c and after returning from ! or ^Z
 */
gettty(){
#ifdef BSD
	(void) gtty(0, &inittyb);
	(void) gtty(0, &curttyb);
	ospeed = inittyb.sg_ospeed;
	erase_char = inittyb.sg_erase;
	kill_char = inittyb.sg_kill;
	getioctls();
#else
	(void) ioctl(0, TCGETA, &inittyb);
	(void) ioctl(0, TCGETA, &curttyb);
	ospeed = inittyb.c_cflag & CBAUD;
	erase_char = inittyb.c_cc[VERASE];
	kill_char = inittyb.c_cc[VKILL];
	getioctls();
#endif

	/* do not expand tabs - they might be needed inside a cm sequence */
#ifdef BSD
	if(curttyb.sg_flags & XTABS) {
		curttyb.sg_flags &= ~XTABS;
#else
	if(curttyb.c_oflag & TAB3) {
		curttyb.c_oflag &= ~TAB3;
#endif BSD
		setctty();
	}
	settty_needed = TRUE;
}

/* fatal error */
/*VARARGS1*/
error(s,x,y) char *s; {
	if(settty_needed)
		settty((char *) 0);
	printf(s,x,y);
	putchar('\n');
	exit(1);
}

/* reset terminal to original state */
settty(s) char *s; {
	clear_screen();
	end_screen();
	if(s) printf(s);
	(void) fflush(stdout);
#ifdef BSD
	if(stty(0, &inittyb) == -1)
#else
	if(ioctl(0, TCSETA, &inittyb) == -1)
#endif BSD
		puts("Cannot change tty");
	flags.echo = (inittyb.sg_flags & ECHO) ? ON : OFF;
#ifdef	BSD
	flags.cbreak = (inittyb.sg_flags & CBREAK) ? ON : OFF;
#else
	flags.cbreak = (inittyb.c_lflag & ICANON) ? OFF : ON;
#endif
	setioctls();
}

setctty(){
#ifdef BSD
	if(stty(0, &curttyb) == -1) puts("Cannot change tty");
#else
	if(ioctl(0, TCSETA,  &curttyb) == -1) puts("Cannot change tty");
#endif BSD
}


setftty(){
	flags.cbreak = ON;
	flags.echo = OFF;
	setxtty();
}

setxtty(){
register int ef = (flags.echo == ON) ? ECHO : 0;
#ifdef BSD
register int cf = (flags.cbreak == ON) ? CBREAK : 0;
#else
register int cf = (flags.cbreak == ON) ? 0 : ICANON;
#endif
register int change = 0;
	/* Should use (ECHO|CRMOD) here instead of ECHO */
	if((curttyb.sg_flags & ECHO) != ef){
		curttyb.sg_flags &= ~ECHO;
		curttyb.sg_flags |= ef;
		change++;
	}
#ifdef BSD
	if((curttyb.sg_flags & CBREAK) != cf){
		curttyb.sg_flags &= ~CBREAK;
#else
	if((curttyb.sg_flags & ICANON || curttyb.c_cc[VMIN] > 1 ) != cf){
		curttyb.sg_flags   &= ~ICANON;
		curttyb.c_cc[VMIN]  = (char) 1;	/* Characters in a read() */
		curttyb.c_cc[VTIME] = (char) 0;	/* No timeout on a read() */
#endif BSD
		curttyb.sg_flags |= cf;
		change++;
	}
	if(change){
		setctty();
	}
	start_screen();
}

/*
 * Read a line closed with '\n' into the array char bufp[BUFSZ].
 * (The '\n' is not stored. The string is closed with a '\0'.)
 * Reading can be interrupted by an escape ('\033') - now the
 * resulting string is "\033".
 */
getlin(bufp)
register char *bufp;
{
	register char *obufp = bufp;
	register int c;

	flags.toplin = 2;		/* nonempty, no --More-- required */
	for(;;) {
		(void) fflush(stdout);
		if((c = getchar()) == EOF) {
			*bufp = 0;
			return;
		}
		if(c == '\033') {
			*obufp = c;
			obufp[1] = 0;
			return;
		}
		if(c == erase_char || c == '\b') {
			if(bufp != obufp) {
				bufp--;
				putstr("\b \b"); /* putsym converts \b */
			} else	bell();
		} else if(c == '\n') {
			*bufp = 0;
			return;
		} else if(c == kill_char || c == '\177') { /* Robert Viduya */
			while(bufp != obufp) {
				bufp--;
				putstr("\b \b");
			}
		} else if(isprint(c) || c == ' ') {
			*bufp = c;
			bufp[1] = 0;
			putstr(bufp);
			if(bufp-obufp < BUFSZ-1 && bufp-obufp < COLNO)
				bufp++;
		} else
			bell();
	}
}

getret() {
	xgetret("");
}

cgetret(s)
register char *s;
{
	xgetret(s);
}

xgetret(s)
register char *s;
{
	putsym('\n');
	if(flags.standout)
		standoutbeg();
	putstr("Hit ");
	putstr(flags.cbreak ? "space" : "return");
	putstr(" to continue: ");
	if(flags.standout)
		standoutend();
	xwaitforspace(s);
}

char morc;	/* tell the outside world what char he used */

xwaitforspace(s)
register char *s;	/* chars allowed besides space or return */
{
register int c;

	(void) fflush(stdout);
	morc = 0;

	while((c = getchar()) != '\n') {
	    if(c == EOF) {
		clearerr(stdin);
		if((c = getchar()) == EOF)
			end_of_input();
	    }
	    if(flags.cbreak) {
		if(c == ' ') break;
		if(s && index(s,c)) {
			morc = c;
			break;
		}
		bell();		/* useless if !cbreak */
	    }
	}
}

char *
parse()
{
	static char inline[COLNO];
	register foo;
	int footry;

	flags.move = 1;
	if(!Invis) curs_on_u(); else home();
	(void) fflush(stdout);
	footry= 0;
retry:
	while((foo = getchar()) >= '0' && foo <= '9')
		multi += 10*multi+foo-'0';
	if(multi) {
		multi--;
		save_cm = inline;
	}
	inline[0] = foo;
	inline[1] = 0;
	if(foo == EOF) {
		clearerr(stdin);
		if (footry++ > 0)
			end_of_input();
		goto retry;
	}
	if(foo == 'f' || foo == 'F'){
		inline[1] = getchar();
#ifdef QUEST
		if(inline[1] == foo) inline[2] = getchar(); else
#endif QUEST
		inline[2] = 0;
	}
	if(foo == 'm' || foo == 'M'){
		inline[1] = getchar();
		inline[2] = 0;
	}
	clrlin();
	return(inline);
}

char
readchar() {
	register int sym;
	(void) fflush(stdout);
	if((sym = getchar()) == EOF) { 	/* try to fix error */
		clearerr(stdin);
		if((sym = getchar()) == EOF)
			end_of_input();
	}
	if(flags.toplin == 1) flags.toplin = 2;
	return((char) sym);
}

end_of_input()
{
	settty("End of input?\n");
	clearlocks();
	exit(0);
}