[net.sources.games] hack.tty.c for SysVR2

wcs@ho95b.UUCP (Bill Stewart) (05/03/85)

/*
 *	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			 */

#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;
extern 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)) {
			*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)
		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;

	flags.move = 1;
	if(!Invis) curs_on_u(); else home();
	(void) fflush(stdout);
	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)
		end_of_input();
	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)
		end_of_input();
	if(flags.toplin == 1) flags.toplin = 2;
	return((char) sym);
}

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

-- 
			Bill Stewart	1-201-949-0705
			AT&T Bell Labs, Room 4K-435, Holmdel NJ
			{ihnp4,allegra,cbosgd,vax135}!ho95c!wcs

guy@sun.uucp (Guy Harris) (05/04/85)

> #ifdef BSD

This should be "#ifdef V7"; it's not the BSD driver that's being used, it's
the V7 driver (the BSD driver is a V7 superset).

> #define	CBREAK		ICANON

Nope.  Turning CBREAK *on* is equivalent to turning ICANON off.  However,
the later code doesn't use CBREAK for the USDL driver, and does recognize
that the sense of the bit is reversed, so this may not be a problem.

> #ifdef BSD
> register int cf = (flags.cbreak == ON) ? CBREAK : 0;
> #else
> register int cf = (flags.cbreak == ON) ? 0 : ICANON;
> #endif
> ...
> #ifdef BSD
> 	if((curttyb.sg_flags & CBREAK) != cf){
> 		curttyb.sg_flags &= ~CBREAK;
> #else
> 	if((curttyb.sg_flags & ICANON || curttyb.c_cc[VMIN] > 1 ) != cf){

I'd remove the test of c_cc[VMIN] if I were you - the appearance of the
"||" means that the LHS of the comparison will be 1 or 0, but the RHS is
"cf" which is either ICANON or 0 - ICANON is, if I remember correctly, 2 not
1.

Other than that, it looks sane.

	Guy Harris