Testing if keystrokes are waiting in the buffer (solution)

Chris Torek chris at mimsy.umd.edu
Wed May 2 17:04:26 AEST 1990


(First, an obligatory note to comp.lang.c readers: the notion of a `key'
is found nowhere in the C language, therefore the notion of testing for
`strokes of keys' is not C, and does not belong in comp.lang.c.  Although
the C language does provide the notion of a standard input, it does not
provide any notion of testing whether there is input available `now' on
this standard input, so it is pointless to ask how this is done `in C'.
It is not done `in C' at all; rather, it is done `using C on Unix' or
`using C on the Macintosh' or `using C on VMS', and it is done differently
in each case.  comp.lang.c is therefore not the best place to ask how
it is done.  Readers not interested in Unix details can skip the rest of
this followup.)

In article <1990Apr25.000456.25048 at cunixf.cc.columbia.edu>
gm at cunixd.cc.columbia.edu (Gary Mathews) quotes code from
jeff at orca.WV.TEK.COM (Jeff Beadles).  This code is specific to Unix
C implementations, and in fact is further specific to 4.2BSD systems
and derivatives and to systems that borrowed notions from such systems.

>	if (select(1,&mask,0,0,&waittime)) {
>		num_chars_read=read(0,&keypressed,1);
>		if (num_chars_read == 1)
>			return((int)keypressed);
>	}
>	return(-1);

There are several problems with this code.  The first is that the two
`0' arguments to select have the wrong type.  The three middle arguments
should have type (fd_set *) or (int *) (the latter being 4.2BSD-specific;
`fd_set's really only came into existence when the number of file
descriptors per process was raised beyond the number of bits per `int').
Thus, one should use

	select(1, &mask, (fd_set *)0, (fd_set *)0, &waittime)

A more important bug, however, lies in the fact that select does not
test for `input available' or `output ready', but rather for `calls
to read or write will not block'.  Because end-of-file is not a blocking
input condition, select for input is always true at end of file.  Thus,
this code will try the read() call, and will return 0.  If a program
using this routine is run with stdin set to a regular file, the routine
will always return -1 once EOF is reached.  Likewise, if the input is
from a terminal that gets disconnected (e.g., due to a modem hanging up),
the routine will return -1 forever.  A program using this code may then
get stuck waiting for more input, using machine resources without end.

Note that select is not (or more precisely, `should not be') affected
by non-blocking input or output modes.  That is, select for input should
be true exactly when a blocking input call would not block, and select
for output should be true exactly when a blocking output call (of some
sufficiently small but unspecified output size) would not block.  The
latter is often combined with non-blocking output modes to allow larger
output sizes to be trimmed (the system returns the number of bytes
queued, instead of waiting for sufficient space to queue everything).
This is not normally necessary for input descriptors.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris at cs.umd.edu	Path:	uunet!mimsy!chris



More information about the Comp.unix.questions mailing list