/* unix.c */ /* Author: * Steve Kirkendall * 14407 SW Teal Blvd. #C * Beaverton, OR 97005 * kirkenda@cs.pdx.edu */ /* This file contains the unix-specific versions the ttyread() functions. * There are actually three versions of ttyread() defined here, because * BSD, SysV, and V7 all need quite different implementations. */ #include "config.h" #if ANY_UNIX # include "vi.h" # if BSD /* For BSD, we use select() to wait for characters to become available, * and then do a read() to actually get the characters. We also try to * handle SIGWINCH -- if the signal arrives during the select() call, then * we adjust the o_columns and o_lines variables, and fake a control-L. */ # include # include int ttyread(buf, len, time) char *buf; /* where to store the gotten characters */ int len; /* maximum number of characters to read */ int time; /* maximum time to allow for reading */ { fd_set rd; /* the file descriptors that we want to read from */ static tty; /* 'y' if reading from tty, or 'n' if not a tty */ int i; struct timeval t; struct timeval *tp; /* do we know whether this is a tty or not? */ if (!tty) { tty = (isatty(0) ? 'y' : 'n'); } /* compute the timeout value */ if (time) { t.tv_sec = time / 10; t.tv_usec = (time % 10) * 100000L; tp = &t; } else { tp = (struct timeval *)0; } /* loop until we get characters or a definite EOF */ for (;;) { if (tty == 'y') { /* wait until timeout or characters are available */ FD_ZERO(&rd); FD_SET(0, &rd); i = select(1, &rd, (fd_set *)0, (fd_set *)0, tp); } else { /* if reading from a file or pipe, never timeout! * (This also affects the way that EOF is detected) */ i = 1; } /* react accordingly... */ switch (i) { case -1: /* assume we got an EINTR because of SIGWINCH */ if (*o_lines != LINES || *o_columns != COLS) { *o_lines = LINES; *o_columns = COLS; #ifndef CRUNCH if (!wset) { *o_window = LINES - 1; } #endif if (mode != MODE_EX) { /* pretend the user hit ^L */ *buf = ctrl('L'); return 1; } } break; case 0: /* timeout */ return 0; default: /* characters available */ return read(0, buf, len); } } } # else # if M_SYSV /* For System-V or Coherent, we use VMIN/VTIME to implement the timeout. * For no timeout, VMIN should be 1 and VTIME should be 0; for timeout, * VMIN should be 0 and VTIME should be the timeout value. */ # include int ttyread(buf, len, time) char *buf; /* where to store the gotten characters */ int len; /* maximum number of characters to read */ int time; /* maximum time to allow for reading */ { struct termio tio; int bytes; /* number of bytes actually read */ /* arrange for timeout */ ioctl(0, TCGETA, &tio); if (time) { tio.c_cc[VMIN] = 0; tio.c_cc[VTIME] = time; } else { tio.c_cc[VMIN] = 1; tio.c_cc[VTIME] = 0; } ioctl(0, TCSETA, &tio); /* Perform the read. Loop if EINTR error happens */ while ((bytes = read(0, buf, len)) < 0) { /* probably EINTR error because a SIGWINCH was received */ if (*o_lines != LINES || *o_columns != COLS) { *o_lines = LINES; *o_columns = COLS; #ifndef CRUNCH if (!wset) { *o_window = LINES - 1; } #endif if (mode != MODE_EX) { /* pretend the user hit ^L */ *buf = ctrl('L'); return 1; } } } /* return the number of bytes read */ return bytes; /* NOTE: The terminal may be left in a timeout-mode after this function * returns. This shouldn't be a problem since Elvis *NEVER* tries to * read from the keyboard except through this function. */ } # else /* any other version of UNIX, assume it is V7 compatible */ /* For V7 UNIX (including Minix) we set an alarm() before doing a blocking * read(), and assume that the SIGALRM signal will cause the read() function * to give up. */ #include static jmp_buf env; /*ARGSUSED*/ int dummy(signo) int signo; { longjmp(env, 1); } int ttyread(buf, len, time) char *buf; /* where to store the gotten characters */ int len; /* maximum number of characters to read */ int time; /* maximum time to allow for reading */ { /* arrange for timeout */ #if __GNUC__ || _ANSI signal(SIGALRM, (void (*)()) dummy); #else signal(SIGALRM, dummy); #endif alarm(time); /* perform the blocking read */ if (setjmp(env) == 0) { len = read(0, buf, len); } else /* I guess we timed out */ { len = 0; } /* cancel the alarm */ #if _ANSI signal(SIGALRM, (void (*)())dummy); /* work around a bug in Minix */ #else signal(SIGALRM, dummy); /* work around a bug in Minix */ #endif alarm(0); /* return the number of bytes read */ if (len < 0) len = 0; return len; } # endif /* !(M_SYSV || COHERENT) */ # endif /* !BSD */ #endif /* ANY_UNIX */