[comp.bugs.sys5] empty

dan@rna.UUCP (Dan Ts'o) (11/02/88)

	Sorry for being so lazy, but can someone send me a C routine for
the USG System V termio equivalent of the old Rand empty(fd) call.
The empty(fd) call took a file descriptor argument, usually a tty, and returned
1 if there were no characters in the queue to read (would block if read(fd)
were issued) and 0 if there were bytes to read. It also worked on pipes, but
I don't care about that feature at this point. I have the 4BSD equivalent,
which just uses ioctl(FIONREAD) to return how many characters are in the
queue. So what is the System V equivalent ? Thanks.
	Please email responses.

				Cheers,
				Dan Ts'o		212-570-7671
				Dept. Neurobiology	dan@rna.rockefeller.edu
				Rockefeller Univ.	...cmcl2!rna!dan
				1230 York Ave.		rna!dan@nyu.arpa
				NY, NY 10021		tso@rockefeller.arpa
							tso@rockvax.bitnet

ka@june.cs.washington.edu (Kenneth Almquist) (11/09/88)

Dan Ts'o <dan@rna.rockefeller.edu> asks for a  System V routine to test
whether data is available to be read on a file descriptor referring to a
slow device (such as a tty).  I doubt that such a routine can be written.
Depending on what you are doing, you may be able to use FNDELAY mode to
get the same effect.  Code like:

	ioctl(fd, FIONREAD, (char *)&nchars);
	if (nchars) {
		count = read(fd, buf, sizeof(buf));
		Code to process input.
	} else {
		Do something else.
	}

becomes:

	fcntl(fd, F_SETFL, FNDELAY);
	if ((count = read(fd, buf, sizeof(buf))) != 0) {
		Code to process input.
	} else {
		Do something else.
	}

These two pieces of code are approximately equivalent, but the former
contains a race condition.  (The fact that characters are available to
be read when the FIONREAD ioctl is performed doesn't mean that these
characters will still be around by the time the code gets around to
performing the read.)  So the latter version of the code is preferable
on systems that support both.
				Kenneth Almquist

jbayer@ispi.UUCP (id for use with uunet/usenet) (11/09/88)

In article <6373@june.cs.washington.edu>, ka@june.cs.washington.edu (Kenneth Almquist) writes:
> Dan Ts'o <dan@rna.rockefeller.edu> asks for a  System V routine to test
> whether data is available to be read on a file descriptor referring to a
> slow device (such as a tty).  I doubt that such a routine can be written.
> Depending on what you are doing, you may be able to use FNDELAY mode to
> get the same effect.  Code like:
> 
> 	ioctl(fd, FIONREAD, (char *)&nchars);
> 	if (nchars) {
> 		count = read(fd, buf, sizeof(buf));
> 		Code to process input.
> 	} else {
> 		Do something else.
> 	}
> 
> becomes:
> 
> 	fcntl(fd, F_SETFL, FNDELAY);
> 	if ((count = read(fd, buf, sizeof(buf))) != 0) {
> 		Code to process input.
> 	} else {
> 		Do something else.
> 	}
> 
> These two pieces of code are approximately equivalent, but the former
> contains a race condition.  (The fact that characters are available to
> be read when the FIONREAD ioctl is performed doesn't mean that these
> characters will still be around by the time the code gets around to
> performing the read.)  So the latter version of the code is preferable
> on systems that support both.
> 				Kenneth Almquist


I have also had the same problem (of needing to know whether a character
is ready at a terminal).  I was able to solve it by using the following
routines, which were taking from the book called "Advanced Unix Programaming"
written by Marc J. Rochkind, pages 79-81

void setblock(fd, on)	/* turn blocking on or off */
int	fd;
BOOLEAN	on;
{
	static int	blockf, nonblockf;
	static BOOLEAN	first = TRUE;
	int		flags;

	if (first) {
		first = FALSE;
		if ((flags = fcntl(fd, F_GETFL, 0)) == -1)
			syserr("fcntl");
		blockf = flags & ~O_NDELAY;		/* make sure O_NDELAY is off */
		nonblockf = flags & O_NDELAY;		/* make sure O_NDELAY is on */
	}
	if (fcntl(fd, F_SETFL, on ? blockf : nonblockf) == -1)
		syserr("fcntl2");
} /* setblock */



#define	EMPTY	'\0'
static char	cbuf = EMPTY;

BOOLEAN	cready()	/* is a character ready */
{
	if (cbuf != EMPTY)
		return (TRUE);
	setblock(0,FALSE);
	switch (read(0, &cbuf, 1)) {
		case -1:
			syserr("read");
		case 0:
			return (FALSE);	/* could be EOF too */
		default:
			return (TRUE);
	}
} /* cready */


int	cget()	/* get a character */
{
	char	c;

	if (cbuf != EMPTYY) {
		c = cbuf;
		cbuf = EMPTY;
		return (c & 0377);	/* prevent sign extension */
	}
	setblock(0,TRUE);
	switch (read(0, &c, 1)) {
		case -1:
			syserr("read");
		case 0:
			return (-1);	/* must be eof */
		default:
			return (c & 0377);
	}
} /* cget */