Xref: utzoo comp.lang.c:13634 comp.unix.questions:9960 Path: utzoo!yunexus!geac!syntron!jtsv16!uunet!ncrlnk!ncrcae!ece-csc!mcnc!rutgers!att!poseidon!psrc From: psrc@poseidon.ATT.COM (Paul S. R. Chisholm) Newsgroups: comp.lang.c,comp.unix.questions Subject: Re: input ready under UNIX ??!!?? Summary: non-blocked I/O, blocked I/O with timeout, VTIME, curses Keywords: input, unix, help Message-ID: <547@poseidon.ATT.COM> Date: 26 Oct 88 16:28:59 GMT Article-I.D.: poseidon.547 References: <771@necis.UUCP> Organization: AT&T Bell Laboratories Lines: 61 <"He seemed like such a nice man . . . and then he turned out to be a writer!"> In article <771@necis.UUCP>, rbono@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@necis.nec.com, (508) 635-6303 Paul S. R. Chisholm, psrc@poseidon.att.com (formerly psc@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