minix/commands/elvis/unix.c
2009-11-09 10:26:00 +00:00

226 lines
4.7 KiB
C

/* 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 <sys/types.h>
# include <sys/time.h>
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 <termio.h>
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 <setjmp.h>
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 */