input ready under UNIX ??!!??

Paul S. R. Chisholm psrc at poseidon.ATT.COM
Thu Oct 27 02:28:59 AEST 1988


<"He seemed like such a nice man . . . and then he turned out to be a writer!">

In article <771 at necis.UUCP>, rbono at necis.UUCP (Rich Bono) writes:
> HELP!!  how can one (if at all) find out (non-destructivly) if there is
> any input waiting to be read from stdin???   With the Microsoft-C libraries
> I can use the kbhit() function which returns TRUE if there are any characters
> waiting to be input.  Clearing ICANON with a ioctl() for stdin does NOT do
> what I want.....
>(follows, an example that uses kbhit() and gets(); odd combination)

First of all, it sounds like a good idea to package this in a single
routine with a portable interface.  You may have to entirely rewrite
the routine to get it to run under the UNIX(R) operating system, but
it would be called the same as under MS-DOS.

Now, there are at least four ways of doing this that I can think of.
For any of the four, I'd use read(2) before I'd use gets(3), though
neither might be the best (see solution 4).  When reading from a tty,
read waits for a newline (or return if icrnl is set, which it usually
is), then returns the line (or as much of it as the read() call asked
for, saving the rest for the next call) if canonical processing is set.
If canonical processing is not set (and VMIN is set to 1), read()
returns a single character at a time.  See termio(7) for details on
both modes.

(1)  Using fcntl(2), set file descriptor 0 to be non-blocking (what
fcntl(5) calls O_NDELAY).  If you want line-at-a-time input, keep
canonical processing on.  read() will return a positive value if a
line has been entered.  If a line hasn't been entered yet, read() will
either return 0 (SVR2?), or -1 with errno set to EAGAIN (SVR3?).  Check
for both conditions.  WARNING:  make sure you fcntl() standard input
back before your program exit(2)s!  The parent (usually shell) process'
file descriptor zero is inherited, and *this* file descriptor is
modified by the child process' fcntl()!  So, the child arranges for
read() to return zero if no input is pending, the child dies, the
parent does a read() and sees zero bytes; gee, that's end of file,
right?  Goodbye!  (If you're paranoid that the child might die, dup(2)
file descriptor zero, close(2) file descriptor zero, dup() the copy
(which will become file descriptor zero), and close() the copy.  The
child process now has its own file descriptor for standard input.)

(2)  Do a blocking (normal) read(), but set an alarm(2) to go off after
a while.  The read() will return -1, with errno set to EINTR.

(3)  Use ioctl(2) to set VMIN and VTIME (see termio(7)).  This is
probably the closest to what you had in mind.  You'll need to turn
canonical processing off, and build up your own input lines (with your
own canonical processing, if any).  Read the termio(7) manual page
*carefully* for details.

(4)  Use curses(3X).  Call nodelay() to turn nodelay input mode on.
Read from the terminal with getch().  This is essentially the same as
solution three, but with an interface to your program that won't change
from System V to BSD-based variants.

>Rich Bono, rbono at necis.nec.com, (508) 635-6303

Paul S. R. Chisholm, psrc at poseidon.att.com (formerly psc at lznv.att.com)
AT&T Bell Laboratories, att!poseidon!psrc, AT&T Mail !psrchisholm
I'm not speaking for the company, I'm just speaking my mind.
UNIX(R) is a registered trademark of AT&T



More information about the Comp.unix.questions mailing list