/************************************************************************ * This program is Copyright (C) 1986 by Jonathan Payne. JOVE is * * provided to you without charge, and with no warranty. You may give * * away copies of JOVE, including sources, provided that this notice is * * included in all the files. * ************************************************************************/ /* Contains some system dependent type things, e.g. putting terminal in CBREAK mode, etc. [TRH] this was originally in "jove.c" [May 89 TRH] facilitate port to non-unix systems, You have to supply the following routines: - getchar() {or rawchar(time_out) if you still want to use fkeys.c} - charp() - input character available? - do_sgtty() - get current tty state - ttyset(on) - set / restore tty state - ttsize() - (re)size screen; should also set ILI to LI - 1 - ttinit() - get additional tty state info (see do-sgtty) - ttexit() - last-minute tty cleanup actions - DoSit(delay) - wait for delay * 100 ms unix version now uses ANSI clock() if possible */ #define NO_PROCDECL /* kludge for teensy pdp11 compiler */ #include "jove.h" RCS("$Id: tty.c,v 14.32.0.12 1994/06/24 00:10:20 tom Exp tom $") #include "io.h" #ifdef TINY # undef putch /* to un-hide the function */ #endif #ifndef NO_PROCDECL # include "screen.h" #endif #include "termcap.h" #define Extern public /* to force definition of variables */ #include "tty.h" int done_ttinit ZERO; DEF_INT( "cps", CharsPerSec, V_BASE10|V_CONST ) = CSPEED; DEF_STR( "ttyname", tt_name, 20, V_STRING|V_CONST ) _IF(def PRIVATE) = DevTty; DEF_INT( "erase-char", EraseChar, V_CHAR|V_CONST ) _IF(def PRIVATE) = /* On UNIX, this is set to the actual erase character. */ #ifdef STDBINDINGS RUBOUT; #else CTL('H'); #endif #if unix || vms DEF_INT( "allow-^S-and-^Q", OKXonXoff, V_BOOL|V_TTY_RESET ) _IF( unix||vms) ZERO; /* ^S and ^Q initially DON'T work */ DEF_INT( "interrupt-character", IntChar, V_CHAR|V_TTY_RESET ) _IF( unix||vms) = CTL(']'); #endif #if unix/*================= START OF UNIX-SPECIFIC STUFF =====================*/ #include "process.h" #ifdef BSD4_2 # include #else # include #endif #ifdef _POSIX_SOURCE # define O_NDELAY O_NONBLOCK #endif #ifdef BSD4_2 /* on hybrid systems, make sure we use `select' with timeout 0 instead of non-blocking I/O in charp(). */ # if !aiws /* for AIX this does not work on console. */ # undef O_NDELAY # endif #endif #ifdef TERMIOS # define KEY_VMIN 2 /* max "sizeof smbuf" gets jerky */ # define KEY_VTIME 1 #endif #ifdef O_NDELAY void setblock(fd, on) /* turn blocking on or off */ register int fd; int on; { static int saveflags; static int beenhere = -1; register int flags = saveflags; if (beenhere != fd) { beenhere = fd; if ((flags = fcntl(fd, F_GETFL, 0)) < 0) finish(-99); /* shouldn't fail */ saveflags = flags; } if (on) flags &= ~O_NDELAY; else flags |= O_NDELAY; if (flags != saveflags) { saveflags = flags; if (fcntl(fd, F_SETFL, flags) < 0) finish(-98); /* shouldn't fail */ } } #endif /* O_NDELAY */ private char smbuf[20], *bp = smbuf; private int nchars ZERO; #ifdef IPROCS # ifndef PIPEPROCS # ifndef MSEC_TIMEOUT /* allow definition from command line */ /*- # define MSEC_TIMEOUT 200 -*/ /* NO -- too short in networking env. */ # define MSEC_TIMEOUT 350 # endif # endif #endif #ifndef MSEC_TIMEOUT # ifdef ITIMER_REAL # define MSEC_TIMEOUT 350 # else # define MSEC_TIMEOUT (ALARM_1_SEC * 1000) # endif #endif #define MIN_TIMEOUT 250 #ifndef TINY DEF_INT( "keyseq-timeout-in-ms", msec_timeout, V_BASE10 ) _IF( unix)_IF(ndef TINY) = MSEC_TIMEOUT; #else # define msec_timeout MSEC_TIMEOUT #endif #ifdef FUNCKEYS rawchar(time_out) #else getchar() # define time_out NO #endif /* FUNCKEYS */ { register int c, n; extern void (*timeout_proc)__(( void )); #define handle_timeout() { \ if (timeout_proc) \ (*timeout_proc)(); \ } #ifdef time_out # define timed_out NO #else /* handle "real" time-outs left over from last time, but only if we had to wait long for the timeout to happen */ static int interrupted ZERO; if (interrupted) { interrupted = NO; if (msec_timeout >= 500) { handle_timeout(); } } # undef handle_timeout /* ...and redefine this to handle time_out requests */ # define handle_timeout() { \ if (timeout_proc) \ (*timeout_proc)(); \ interrupted++; \ if (time_out) \ return -1; \ } #endif if (nchars <= 0) { #ifdef IPROCS # ifdef PIPEPROCS retry: if (NumProcs != 0) { /* * Get input from the Process pipe. Output from the * keyboard and portsrv processes is multiplexed there and * presented to JOVE in data packets. Its source is * identified by the header. * When we detect that all sub-processes have died, we * suspend the kbd process and revert to direct keyboard * input. However we cannot switch immediately since the * kbd process may have "read ahead" and deposited the * readahead characters in the pipe. So after suspending * the kbd process we keep draining the pipe until we see * the acknowledgment packet sent by the kbd process. */ static int draining ZERO; # define DRAINING (-10000) if (NumProcs < 0) { if (!draining) { /* some sub-processes have been closed since our last "emergency stop" */ NumProcs = 0; goto retry; } if (NumProcs > draining) { /* some processes have been started while we were still draining */ NumProcs += draining; draining = OFF; } } if (time_out || timeout_proc) kbd_timeout(); n = 0; do { struct header header; /* get header */ if (proc_read(&header, sizeof header) != sizeof header) { proc_error("[iproc: bad header]"); } if (header.pid != kbd_pid) { /* handle data from sub-process */ read_proc(header.pid, header.nbytes); if (NumProcs <= 0) { /* all sub-processes have died; suspend kbd process and setup for draining */ kbd(OFF); NumProcs -= draining = DRAINING; } continue; } /* handle data from the kbd process */ if ((n = header.nbytes) < 0) { if (n == -EINTR) { /* timeout */ handle_timeout(); continue; /* ignore spurious */ } if (n == KBD_SUSPENDED) { NumProcs += draining; draining = OFF; goto retry; } s_mess("[kbd error (%s)]", n); proc_error((char *) 0); /* shouldn't happen. */ } if (proc_read(smbuf, n) != n) { proc_error("[kbd: bad data]"); } } while (n <= 0); } else /* (NumProcs == 0) */ # else /* ! PIPEPROCS */ # define BITS_INT (sizeof(long) * 8) register int tmp, nfds; long reads; /* * Get a character from the keyboard, first checking for * any pty input from a process. Deal with terminal input * first, and then handle any pty input. */ if (time_out || timeout_proc || NumProcs > 0) { n = 0; do { struct timeval tv; register struct timeval *t = NULL; if (time_out) { if ((tmp = msec_timeout) < MIN_TIMEOUT) msec_timeout = tmp = MIN_TIMEOUT; t = &tv; t->tv_sec = tmp / 1000; t->tv_usec = (tmp % 1000) * 1000L; } if (timeout_proc) { t = &tv; t->tv_sec = 1; t->tv_usec = 0; } reads = global_fd; if ((nfds = select(BITS_INT, (int *)&reads, (int *)0, (int *)0, t)) <= 0) { if (nfds == 0) { handle_timeout(); } else if (errno != EINTR) { f_mess("[select(0x%X) error. (%s)]", global_fd, syserr()); global_fd = Bit(0); } continue; } if (reads & Bit(0)) { /* ie. JOVEs stdin */ /* Keyboard input has the highest priority. So bail out if keyboard input present, even if process output is pending; it'll be there next time around... */ if ((n = read(0, smbuf, sizeof(smbuf))) > 0) break; if (--nfds == 0) continue; } for (tmp = 0; ++tmp < BITS_INT; ) { if (reads & (1L << tmp)) { read_proc(tmp); if (--nfds == 0) break; } } } while (n <= 0); # undef t # define DONT_TIME_OUT /* to suppress generation of time-out handling code further on. */ } else /* (!time_out && !timeout_proc && NumProcs <= 0) */ # endif /* !PIPEPROCS */ #endif /* IPROCS */ { #ifndef DONT_TIME_OUT /* * If requested, setup to generate a timeout after a short * time when no input is available. This works fine on SYSV * and BSD systems, and not so good on others (due to the * lack of timer resolution). {{The following code assumes * that there is always a SIGALRM handler installed. For JOVE * this is indeed the case. (cf. update)}} */ # ifdef ITIMER_REAL /* use fancy high-precision alarm timer */ static struct itimerval timout = {{0}, {MSEC_TIMEOUT/1000, MSEC_TIMEOUT%1000*1000L}}, one_second = {{0}, {1, 0}}; struct itimerval old_it; register struct itimerval *t = NULL; if (time_out) t = &timout; if (timeout_proc) t = &one_second; if (t) setitimer(ITIMER_REAL, t, &old_it); # define clean_timeout() { \ if (t && !interrupted && timerisset(&old_it.it_value)) \ setitimer(ITIMER_REAL, &old_it, \ (struct itimerval *)0); \ } # else /* !ITIMER_REAL */ /* use alarm() to setup crude time-out */ register unsigned old_alarm = 0; if (time_out || timeout_proc) old_alarm = alarm(MSEC_TIMEOUT/1000); # define clean_timeout() { \ if (old_alarm && !interrupted) \ alarm(old_alarm); \ } # endif /* ITIMER_REAL */ #else # define clean_timeout() # undef handle_timeout # define handle_timeout() #endif /* DONT_TIME_OUT */ #ifdef DEBUG c = NO; #endif while ((n = read(0, smbuf, sizeof smbuf)) <= 0) { if (n == 0) continue; if (errno == EINTR) { handle_timeout(); continue; } /* This shouldn't happen! */ #ifdef DEBUG f_mess("[tty read error. (%s) %s] ", syserr(), c ? "I give up" : "I'll try to reopen"); /* ...but try to recover if it does. */ if (c == NO) { ++c; if (close(0) != 0) printf("close failed! (%s)", syserr()); else if ((n = open(DevTty, O_RDONLY)) != 0) if (n < 0) printf("open failed! (%s)", syserr()); else printf("wrong handle (%d)", n); else continue; } #endif /* DEBUG */ finish(-errno); } clean_timeout(); } nchars = n; bp = smbuf; InputPending = n; } c = *bp++; #ifndef FUNCKEYS if (c & 0200) { if (MetaKey) { *--bp = (c &= 0177); return MetaKey; } else { static SendQuote ZERO; if (SendQuote ^= 1) { --bp; return QuoteChar; /* [TRH] my 8-bit kludge. */ } } } #endif /* FUNCKEYS */ nchars--; return _UC_(c); #undef clean_timeout #undef handle_timeout #undef time_out #undef interrupted } /* Returns non-zero if a character waiting */ int charp() { if (inIOread) /* force update of non-interactive processes */ return 0; if (InJoverc || nchars > 0) return 1; #ifdef BRLUNIX { SGTTY gttyBuf; gtty(0, (char *) >tyBuf); return (gttyBuf.sg_xflags & INWAIT) != 0; } #endif /* BRLUNIX */ #ifdef O_NDELAY # ifdef PIPEPROCS if (NumProcs != 0) /* DON'T readahead if kbd process is active! */ return 0; # endif setblock(0, NO); /* turn blocking off */ nchars = read(0, smbuf, sizeof smbuf); /* Is anything there? */ setblock(0, YES); /* turn blocking on */ if (nchars > 0) { /* something was there */ bp = smbuf; /* make sure bp points to it */ return 1; /* just say we found something */ } return 0; #endif /* O_NDELAY */ #ifdef BSD4_2 { static struct timeval nulltime ZERO; int readfds = 1; return select(1, &readfds, (int *)0, (int *)0, &nulltime) == 1; } #endif #ifdef FIONREAD { long c; return (ioctl(0, FIONREAD, (SGTTYB *) &c) == 0 && c > 0); } #endif /* FIONREAD */ #ifdef TIOCNRD /* (some versions of??) V7 */ { int c; return (ioctl(0, TIOCNRD, (SGTTYB *) &c) == 0 && c > 0); } #endif /* TIOCNRD */ #ifdef c70 return !empty(0); #endif return 0; /* if none of the above compiles... */ } void ttsize() { #ifdef TIOCGWINSZ struct winsize win; if (ioctl(0, TIOCGWINSZ, &win) == 0) { if (win.ws_col) CO = win.ws_col; if (win.ws_row) LI = win.ws_row; } # define ADJUST_SIZE #endif /* TIOCGWINSZ */ #ifdef VARTERM { extern short newdim[2]; /* from term.c */ register int c, l; if (c = newdim[0]) { newdim[0] = 0; CO = c; } if (l = newdim[1]) { newdim[1] = 0; LI = l; } } # define ADJUST_SIZE #endif /* VARTERM */ #ifdef ADJUST_SIZE if (LI < 2 + 1) /* window (1 line + modeline) + minibuf */ LI = 2 + 1; if (CO < 2) CO = 2; if (CO > MAXCOLS) CO = MAXCOLS; # undef ADJUST_SIZE #endif #ifdef TIOCGWINSZ # ifdef TIOCSWINSZ if (win.ws_col != CO || win.ws_row != LI) { /* let the kernel know. */ win.ws_col = CO; win.ws_row = LI; ioctl(0, TIOCSWINSZ, &win); } # endif #endif /* TIOCGWINSZ */ ILI = LI - 1; } extern char *ttyname __(( int _(fd) )); #ifdef BIFF DEF_INT( "disable-biff", BiffChk, V_BOOL|V_TTY_RESET ) _IF(def BIFF)_IF( unix)_IF(def PRIVATE) ZERO; /* whether or not to turn off biff while in JOVE */ private int tt_mode ZERO; /* mode flags of tty, for biff */ private void biff_init __(( void )); private void biff_init() { struct stat tt_stat; tt_mode = 0; if (fstat(0, &tt_stat) == 0) tt_mode = tt_stat.st_mode; } private void biff __(( int _(off) )); private void biff(off) { /* Only change state if "disable-biff" is on, and we're using biff. */ if (True(BiffChk)) { register int mode = tt_mode; if (mode & S_IXUSR) { /* using biff... */ if (off) mode &= ~S_IXUSR; # ifndef BSD4_2 chmod(tt_name, mode); # else fchmod(0, mode); # endif } } } #endif /* BIFF */ /* Determine tty speed in characters per second from `ospeed' */ #define CPS(baud) (((baud) + 5) / 10) #if (B9600 == 96 && B2400 == 24) /* Minix (1.5) encoding (baud/100). */ # define SPEED(ospeed) ((ospeed) ? CPS(ospeed * 100) : CSPEED) #endif #ifndef SPEED private const int speeds[] = { CSPEED, CPS(50), CPS(75), CPS(110), CPS(134), CPS(150), #if (B200) CPS(200), #endif CPS(300), CPS(600), #if (B900) CPS(900), #endif CPS(1200), CPS(1800), #if (B2000 || vms) CPS(2000), #endif CPS(2400), #if (B3600 || vms) CPS(3600), #endif CPS(4800), #if (B7200 || vms) CPS(7200), #endif CPS(9600), CPS(19200), CPS(38400) }; # undef CPS # define SPEED(ospeed) speeds[(ospeed) - (B50 - 1)] #endif /* SPEED */ void do_sgtty() { register char None = -1; #ifdef TERMIOS CHECK( tcgetattr(0, &sg[OFF]), finish(-97) ); sg[ON] = sg[OFF]; /* determine VDISABLE character. */ # ifdef _POSIX_VDISABLE None = _POSIX_VDISABLE; /* actually incorrect if _POSIX_VDISABLE == -1 (cannot be disabled) */ # else # ifdef _PC_VDISABLE None = fpathconf(0, _PC_VDISABLE); # else # ifdef VDISABLE # if (0 <= VDISABLE && VDISABLE < NCCS) None = sg[OFF].c_cc[VDISABLE]; # endif # endif # endif # endif # ifdef CURSOPT # ifdef OXTABS TABS = ((sg[OFF].c_oflag & OXTABS) != OXTABS); # endif # endif ospeed = cfgetospeed(&sg[OFF]); sg[ON].c_iflag &= ~(INLCR|ICRNL|IGNCR); if (MetaKey) { /* [TRH] turn off input stripping (and parity check?) */ sg[ON].c_iflag &= ~(ISTRIP); sg[ON].c_cflag = (sg[ON].c_cflag & ~(CSIZE|PARENB)) | CS8; } if (True(OKXonXoff)) { /* [TRH] turn off output flow control */ sg[ON].c_iflag &= ~(IXON); # ifdef VSTART # ifdef VSTOP sg[ON].c_cc[VSTART] = sg[ON].c_cc[VSTOP] = None; # endif # endif } # ifdef ASCEDIT /* * AIX: disable enhanced edit since it loses NULs. * Also disable break signaling since pty cannot distinguish between * NUL and BREAK. This is useful only if you are running JOVE over * a network connection or in a window, but does not seem to harm * anything in other cases. */ sg[ON].c_iflag &= ~(ASCEDIT|IGNBRK|BRKINT); # endif # ifdef IEXTEN sg[ON].c_lflag &= ~(IEXTEN); /* Department of silly bugs: this is needed for SunOS 4.1.1b since otherwise ^O (or more accurately c_cc[VDISCARD]) is gobbled up even though canonical mode is turned off. */ # endif sg[ON].c_lflag &= ~(ICANON|ECHO); sg[ON].c_oflag &= ~(OCRNL|ONLCR); sg[ON].c_cc[VMIN] = KEY_VMIN; sg[ON].c_cc[VTIME] = KEY_VTIME; sg[ON].c_cc[VINTR] = IntChar; /* on HP-UX (and maybe some other SYSV unices) the quit character cannot be turned off; setting it to -1 will bind it to Meta-DEL, which is not what we want. So set it to IntChar (and make sure SIGINT and SIGQUIT are treated alike in the interrupt handler so we don't care which one is received.) */ sg[ON].c_cc[VQUIT] = IntChar; # ifdef VSWTCH sg[ON].c_cc[VSWTCH] = None; # endif # ifdef VSUSP sg[ON].c_cc[VSUSP] = None; # endif # ifdef VDSUSP sg[ON].c_cc[VDSUSP] = None; # endif EraseChar = sg[OFF].c_cc[VERASE]; #else /* !TERMIOS */ # ifdef TIOCGETA CHECK( ioctl(0, TIOCGETA, &sg[OFF]), finish(-97) ); # else CHECK( gtty(0, &sg[OFF]), finish(-97) ); # endif sg[ON] = sg[OFF]; # ifdef CURSOPT TABS = !(sg[OFF].sg_flags & XTABS); # endif ospeed = sg[OFF].sg_ospeed; sg[ON].sg_flags &= ~(ECHO | CRMOD); # ifdef BRLUNIX sg[ON].sg_flags |= CBREAK; /* VT100 Kludge: leave STALL on for flow control if DC3DC1 (Yuck.) */ sg[ON].sg_xflags &= ~((sg[ON].sg_xflags&DC3DC1 ? 0 : STALL) | PAGE); # endif /* BRLUNIX */ # ifdef EUNICE sg[ON].sg_flags |= RAW; /* Eunice needs RAW mode last I heard. */ # else # ifdef PURDUE_EE # ifdef pdp11 sg[ON].sg_flags |= RAW; # else sg[ON].sg_flags |= (MetaKey ? RAW : CBREAK); # endif # else # ifdef TIOCGETA /* extended 7th Ed. sgtty */ sg[ON].sg_length = 0; /* so page mode is off even in CBREAK */ # endif # ifdef TIOCLGET /* local mode; the "new" BSD tty driver */ CHECK( ioctl(0, TIOCLGET, (SGTTYB *) &lm[OFF]), finish(-96) ); lm[ON] = lm[OFF]; # if (BPC == 8) if ((sg[ON].sg_flags & ANYP) == ANYP) /* if not inhibited by parity */ lm[ON] |= LLITOUT; /* allow 8-bit char output */ # endif # ifdef LPASS8 if (MetaKey) lm[ON] |= LPASS8; # endif # ifdef TANDEM if (True(OKXonXoff)) sg[ON].sg_flags &= ~TANDEM; # ifdef LPASS8 sg[ON].sg_flags |= CBREAK; # else sg[ON].sg_flags |= (MetaKey) ? RAW : CBREAK; # endif # else /* !TANDEM */ # ifdef LPASS8 sg[ON].sg_flags |= True(OKXonXoff) ? RAW : CBREAK; # else sg[ON].sg_flags |= (MetaKey && True(OKXonXoff)) ? RAW : CBREAK; # endif # endif # else /* !TIOCLGET */ /* Assume we can't do Xon-Xoff flow control in raw mode */ sg[ON].sg_flags |= (MetaKey && True(OKXonXoff)) ? RAW : CBREAK; # endif /* TIOCLGET */ # endif /* PURDUE_EE */ # endif /* EUNICE */ # ifdef TIOCGETC /* Change interrupt and quit characters. */ CHECK( ioctl(0, TIOCGETC, (SGTTYB *) &tc[OFF]), finish(-94) ); tc[ON] = tc[OFF]; tc[ON].t_intrc = IntChar; tc[ON].t_quitc = None; if (True(OKXonXoff)) { tc[ON].t_stopc = None; tc[ON].t_startc = None; } # endif /* TIOCGETC */ EraseChar = sg[OFF].sg_erase; #endif /* TERMIOS */ #ifdef TIOCGLTC /* !! outside !TERMIOS to accommodate HP-UX braindamage. */ CHECK( ioctl(0, TIOCGLTC, (SGTTYB *) &ls[OFF]), finish(-95) ); ls[ON] = ls[OFF]; ls[ON].t_suspc = None; ls[ON].t_dsuspc = None; ls[ON].t_flushc = None; ls[ON].t_lnextc = None; #endif CharsPerSec = SPEED(ospeed); /* this is to disable padding when we're using Xon/Xoff flow control. */ if (False(OKXonXoff)) ospeed = 0; } void ttinit() { #ifndef TINY tt_name = ttyname(0); #endif do_sgtty(); done_ttinit = YES; } /* If n is OFF reset to original modes */ void ttyset(on) register int on; { if (!done_ttinit) /* Try to reset before we've set! */ return; #ifdef TERMIOS CHECK( tcsetattr(0, TCSADRAIN, &sg[on]), finish(-93) ); #else # ifdef TIOCSETA CHECK( ioctl(0, TIOCSETA, &sg[on]), finish(-93) ); # else # ifdef TIOCSETN CHECK( ioctl(0, TIOCSETN, &sg[on]), finish(-93) ); # else CHECK( stty(0, &sg[on]), finish(-93) ); # endif # endif # ifdef TIOCSETC CHECK( ioctl(0, TIOCSETC, (SGTTYB *) &tc[on]), finish(-92) ); # endif # ifdef TIOCLSET CHECK( ioctl(0, TIOCLSET, (SGTTYB *) &lm[on]), finish(-90) ); # endif #endif /* TERMIOS */ #ifdef TIOCSLTC /* !! outside !TERMIOS to accommodate HP-UX braindamage. */ CHECK( ioctl(0, TIOCSLTC, (SGTTYB *) &ls[on]), finish(-91) ); #endif #ifdef BIFF biff(on); #endif } /* * [TRH] handle signal entry/exit for non-interactive processes: * old_state = ttsigset(OFF); * ... * fork/exec process * * ... * wait for completion * * ttsigset(old_state); * {{to alleviate catch-22 on 7th Ed.: * CBREAK strips parity bit (so MetaKey would be useless) * and RAW disables Interrupts... * so now at least we are able to interrupt sub-processes. * }} */ ttsigset(state) int state; { #ifndef TERMIOS # ifdef RAW /* hope this is specific enough */ # ifdef CBREAK register int prev = sg[ON].sg_flags, new; if ((new = state) == OFF) new = (prev & ~RAW) | CBREAK; if (new != prev) { /* something changes */ sg[ON].sg_flags = new; ttyset(ON); } return prev; # endif /* CBREAK */ # endif /* RAW */ #endif /* TERMIOS */ } /* * Tries to pause for delay/10 seconds OR until a character is typed * at the keyboard. This works well on BSD4_2 and on systems with a * clock() with sufficiently high resolution and not so well on the * rest. Returns 1 if it returned because of keyboard input, or 0 * otherwise. * This does the actual pause, without redisplay. */ DoSit(delay) { #ifdef BSD4_2 struct timeval timer; int readfds = 1; timer.tv_sec = (delay / 10); timer.tv_usec = (delay % 10) * 100 * 1000L; return select(1, &readfds, (int *)0, (int *)0, &timer); #else register int input_pending = NO; # if (CLK_TCK - 0 >= 10) && 0 /* busy-waiting is A Bad Thing(tm) */ register clock_t goal = clock() + delay * (CLK_TCK / 10); while (clock() < goal) { if (InputPending = charp()) { input_pending++; break; } } # else while (--delay >= 0) { register int i = CharsPerSec / 10; do putch(PC); while (--i > 0); flusho(); if (InputPending = charp()) { input_pending++; break; } } # endif /* CLK_TCK */ return input_pending; #endif /* BSD4_2 */ } #endif /*================== END OF UNIX-SPECIFIC STUFF ======================*/ void ResetTerm() { putp(TI); putp(VS); if (MetaKey) putp(MM); #ifdef FUNCKEYS if (True(UseKeyPad)) #endif putp(KS); #ifdef ID_CHAR putp(EI); /* just to be sure */ #endif #ifdef COLOR set_color(DefColor); #endif #ifdef MOUSE mouseinit(); #endif #ifdef BIFF biff_init(); #endif #ifdef MAIL chkmail(YES); /* force it to check to we can be accurate */ #endif ttinit(); /* this is so if you change baudrate or stuff like that, JOVE will notice. */ ttyset(ON); } void UnsetTerm(mesg) const char *mesg; { putp(KE); putp(VE); putp(TE); putp(MO); ttyset(OFF); #ifdef ID_CHAR INSmode(0); #endif #ifdef COLOR if (COorig) putp(COorig); else set_color(ExitColor); #endif #ifdef MOUSE mousefinish(); #endif curstoLL(); putp(CE); if (mesg) printf("%s\n", mesg); flusho(); } void tty_reset() { if (!done_ttinit) return; ttyset(OFF); /* go back to original modes */ ttinit(); ttyset(ON); /* so these are updated when variables are changed */ putp((const char *)(MetaKey ? MM : MO)); #ifdef FUNCKEYS putp((const char *)(True(UseKeyPad) ? KS : KE)); #endif /* {the casts are necessary for Borland C--BOOH!!!} */ } SitFor(delay) { if (charp() || Inputp) return YES; /* gross that I had to snarf this from getch() */ if (mesgbuf[0] && !UpdMesg && !Asking && !errormsg) message(NullStr); #ifdef AUTOSCROLL curwind->w_flags |= W_NOAUTOSCROLL; #endif redisplay(); #ifdef AUTOSCROLL curwind->w_flags |= W_NOAUTOSCROLL; #endif return DoSit(delay); } #ifdef LOAD_AV # if unix /* [TRH] get_la() now returns (int) load-average times 100 */ /* {{This needs revision (maybe we should start to use GNU getloadavg)?}} */ int get_la() { # ifdef BSD4_2 # ifdef PURDUE_EE extern double load_av(); return (int) (load_av(0) + .5); # else /* PURDUE_EE */ # include # ifndef KERNEL_IMAGE /* so we can define it elsewhere. */ # if hpux # define KERNEL_IMAGE "/hp-ux" # else # if NeXT # define KERNEL_IMAGE "/mach" # define NLIST_UNION # else # define KERNEL_IMAGE "/vmunix" # endif # endif # endif /* {Note the double braces to accommodate systems (NeXT!) that declare the `n_name' field as part of a union; other systems don't seem to mind. (the pdp11 K&R compiler groks this construct -- and how much dumber can you get :-)} Unfortunately it _doesn't_ work on systems that matter, like suns. Sigh... */ static struct nlist nl[] = { # ifdef NLIST_UNION {{ "_avenrun" }}, {{ "" }} # else { "_avenrun" }, { "" } # endif }; # define X_AVENRUN 0 static int kmem ZERO; # if NeXT long avenrun[3]; # else double avenrun[3]; # endif if (kmem == 0) { if ((kmem = open("/dev/kmem", O_RDONLY)) < 0) { message("Can't open kmem for load average."); } else { nlist(KERNEL_IMAGE, nl); if (nl[X_AVENRUN].n_value == 0) { message("Can't get address of load average."); close(kmem); kmem = -1; } } } if (kmem > 0) { lseek(kmem, (long) nl[X_AVENRUN].n_value, SEEK_SET); read(kmem, (void_*) avenrun, sizeof(avenrun)); # if NeXT /* NeXT stores load averages, in milli-units, as longs. */ return (int) ((avenrun[0] + 5) / 10); # else return (int) (avenrun[0] * 100.0 + .5); # endif } # endif /* PURDUE_EE */ # else /* !BSD4_2 */ /* [TRH] I don't know what system is meant by this (BSD 2.9 perhaps?) */ short avg[3]; if (gldav(avg) >= 0) return /* (avg[0] * 100 + 128) / 256 */ (avg[0] * 25 + 32) / 64; # endif /* BSD4_2 */ /* if none of the above compiles, or fails */ return 4 * 100; /* So shell commands will say "Chugging" */ } # endif /* unix */ #endif /* LOAD_AV */ /*====================================================================== * $Log: tty.c,v $ * Revision 14.32.0.12 1994/06/24 00:10:20 tom * (rawchar): return immediately if keyboard input read, even if process * output is pending. * * Revision 14.32.0.10 1994/04/08 19:21:38 tom * ("keyseq-timeout-in-ms"): new variable, replaces fixed MSEC_TIMEOUT; * (rawchar): use it, fix bug in select() timeout handling. * * Revision 14.32.0.9 1994/01/31 17:56:16 tom * reorganize TERMIOS/ltchars handling to accommodate HP-UX braindamage. * * Revision 14.32.0.5 1993/08/29 23:36:41 tom * (DoSit): disable busy-waiting; comment fixes. * * Revision 14.32 1993/07/05 17:49:40 tom * (ttsize): check LI, CO against minimum values. * * Revision 14.31.0.1 1993/03/22 10:34:52 tom * (some?) SysV systems do not define VSTART and VSTOP: made conditional. * * Revision 14.31 1993/02/18 02:27:11 tom * fix BIFF code to take effect immediately if user changes "disable-biff"; * remove (void) casts; lotsa random optimizations. * * Revision 14.30 1993/01/26 18:43:14 tom * cleanup whitespace. * * Revision 14.29 1992/12/30 10:19:47 tom * workaround bug in SunOS 4.1.1; fix NLIST portability. * * Revision 14.28 1992/10/24 01:24:23 tom * convert to "port{ansi,defs}.h" conventions; make VARTERM notify changes to * tty driver. * convert to "port{ansi,defs}.h" conventions. * * Revision 14.27 1992/09/22 00:15:28 tom * replace CTL('Q') with `QuoteChar'; cleanup empty `#' directives. * * Revision 14.26 1992/08/27 00:06:54 tom * add "erase-char" support; use Posix' VDISABLE to disable special characters * (when available); PRIVATE-ized some Variable defs; add RCS directives. * */