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!wcsguy@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