[net.unix-wizards] Scanning stdin with no pause

Gregg Wonderly <kermit%okstate.csnet@CSNET-RELAY.ARPA> (12/20/84)

[munch...munch...munch...]

    I am working with V7 UN*X.  I need a way to scan the standard input
stream for a character, but not wait.  If I set to cbreak mode, the
machine still waits for at least one character.  Looking at stdio.h
gave me no clues as it seems that the routine _filbuf() is called when
no characters are available, and this is where the system hangs.  I
am looking for a more or less portable solution if possible.  Also,
I almost forgot.  I need to put the character back on to stdin or 
only look at stdin and not take the character from the buffer.  This
appears more than trivial, so any help would be appreciated

Thanks in advance...

Gregg Wonderly
Department of Computing and Information Sciences
Oklahoma State University

          1                 ...!ihnp4!umn-cs!isucs1!\
         /|\         UUCP:     ...!ucbvax!mtxinu!ea! > okstate!kermit
         | |                ...!convex!ctvax!uokvax!/
   _____//|\\_____ 
  |_|_|_||_||_|_|_|
  |_|_|_|||||_|_|_|  ARPA:  kermit%okstate.csnet@csnet-relay.arpa  

gwyn@brl-tgr.ARPA (Doug Gwyn <gwyn>) (12/20/84)

>     I am working with V7 UN*X.  I need a way to scan the standard input
> stream for a character, but not wait.

This is not supported by 7th Edition UNIX.  You need to add something
to your kernel to do this directly; the Rand Corp. empty() call has
been distributed by USENIX a long time ago, and more recent approaches
include VTIME,VMIN in AT&T UNIX Systems III & V and select() in 4.2BSD.

A groady way to accomplish this on any UNIX is to use a second process
that communicates with the controlling process via a pipe.

> I need to put the character back on to stdin or 
> only look at stdin and not take the character from the buffer.

ungetc() does this (only one character of pushback).  If you need more
pushback, see the buffered input routines in Software Tools.

Barry Gold <lcc.barry@UCLA-LOCUS.ARPA> (12/20/84)

May I suggest:
	A. ioctl(fildes,FIONREAD, &count) which will tell you whether there are
any characters available from the file.
	B. If you're using stdio, look in the buffer--the format of the stdio
FILE construct is published.
	C. Run in cbreak mode and make the character you want to spot (I assume
it's one specific character you're interested in) into an interrupt character
(INT or QUIT) which you can then catch.

If you really want never to hang on that input stream, you'd better not use
stdio.

barry

geoff@desint.UUCP (Geoff Kuenning) (12/24/84)

>>     I am working with V7 UN*X.  I need a way to scan the standard input
>> stream for a character, but not wait.
>
>This is not supported by 7th Edition UNIX.  You need to add something
>to your kernel to do this directly; the Rand Corp. empty() call has
>been distributed by USENIX a long time ago, and more recent approaches
>include VTIME,VMIN in AT&T UNIX Systems III & V and select() in 4.2BSD.

Also the FIONREAD ioctl found in 4.1BSD and 4.2BSD.  If you have access
to BSD code, you may be able to copy that one, since it isn't complex code.
I prefer the idea of doing it with an ioctl anyway.

>A groady way to accomplish this on any UNIX is to use a second process
>that communicates with the controlling process via a pipe.

An even grodier way is to use a 1-second alarm to blast you off the read if
there is nothing coming.  This is obviously not much good unless it is the
unusual case (e.g., a missed packet in a packet protocol).

A final note.  If part of your concern is packet protocol efficiency, some
people have hacked V7 uucp to do the following:  if the last read returned
only 1 character, they sleep for some baud-rate-dependent time (calculated to
be approximately one packet time) before they issue another read.  This
markedly improved CPU availability on some V7 systems without affecting uucp
performance.
-- 

	Geoff Kuenning
	...!ihnp4!trwrb!desint!geoff

david@ukma.UUCP (David Herron, NPR Lover) (12/27/84)

We had to do this a couple of years ago to get running a multi-user
version of empire and some other games.  (We do important work
around here!!!!)  We did the following:

The system call fstat(2) is used to get info about a file... It is
located in sys3.c in the kernel.  Normally, the st_size field in
the stat structure is set to the size of the file.  This is always
zero if the file is a tty.  So, we put in a test to see if the
file was a tty, and if it was, we stored the sum of the char counts
of the character queues associated with that tty (simple huh).
If we had the code in front of us, we could be more specific, but
that's life in the big city.  Hint: I think we checked the major
device number -- you'll see where this gets assigned into the
stat structure.  I think the if(...) was a compound OR or AND so
there was more than one thing we needed to check...
		(wws, whuxlg!wws, on vacation)


--:--:--:--:--:--:--:--:--:--:--:--:--:--:--:--:--:--:--:--:--:--:--:--:-
David Herron;  ARPA-> "ukma!david"@ANL-MCS
(Try the arpa address w/ and w/o the quotes, I have had much trouble with both.)

UUCP          -:--:--:--:--:--:--:--:--:-          (follow one of these routes)

{ucbvax,unmvax,boulder,research} ! {anlams,anl-mcs} -----\  vvvvvvvvvvv
							  >-!ukma!david
   {cbosgd!hasmed,mcvax!qtlon,vax135,mddc} ! qusavx -----/  ^^^^^^^^^^^

jwg@galbp.UUCP (Joe Guthridge) (12/28/84)

>>     I am working with V7 UN*X.  I need a way to scan the standard input
>> stream for a character, but not wait.
>
>This is not supported by 7th Edition UNIX.  You need to add something
>to your kernel to do this directly; the Rand Corp. empty() call has
>been distributed by USENIX a long time ago, and more recent approaches
>include VTIME,VMIN in AT&T UNIX Systems III & V and select() in 4.2BSD.
>
Xenix has a system call rdchk() to do this.

-- 
					Joe Guthridge
					..!akgua!galbp!jwg
			NOTE NEW MACHINE NAME    ^^^^^

phil@qfdts.OZ (Phil Chadwick) (01/11/85)

    >>     I am working with V7 UN*X.  I need a way to scan the standard input
    >> stream for a character, but not wait.
    >
    >This is not supported by 7th Edition UNIX.  You need to add something
    >to your kernel to do this directly; the Rand Corp. empty() call has
    >been distributed by USENIX a long time ago, and more recent approaches
    >include VTIME,VMIN in AT&T UNIX Systems III & V and select() in 4.2BSD.
 
VTIME and VMIN index the control character array in the termio structure
of USG systems.  They appear to be potentially very usefull, but I have
been unable to locate any printed documentation on how to manipulate
c_cc[VTIME] and c_cc[VMIN] to achieve a non-blocking read.  Can anyone
enlighten me please?
----
Phil Chadwick			Australia:	(07) 2296500
Department of Forestry		International:	+61 7 2296500
PO Box 5
Brisbane, Roma Street		SUN:	phil:qfdts		
AUSTRALIA	4001		UUCP:	{decvax,vax135}!mulga!phil:qfdts

guy@rlgvax.UUCP (Guy Harris) (01/15/85)

> VTIME and VMIN index the control character array in the termio structure
> of USG systems.  They appear to be potentially very usefull, but I have
> been unable to locate any printed documentation on how to manipulate
> c_cc[VTIME] and c_cc[VMIN] to achieve a non-blocking read.  Can anyone
> enlighten me please?

The way to do non-blocking reads on terminals in USG systems is not to
fiddle with VMIN and VTIME, but to set the O_NDELAY flag for the terminal's
file descriptor using "fcntl".  A way to do it is:

	if ((oldflags = fcntl(tty_fd, F_GETFL, 0)) < 0)
		fprintf(stderr, "Oops! [THIS SHOULD NOT HAPPEN]\n");
	fcntl(tty_fd, F_SETFL, oldflags|O_NDELAY);
		...
	fcntl(tty_fd, F_SETFL, oldflags);
	exit(0);

Now, any reads on "tty_fd" will only return the number of characters immediately
available, and not wait for any to become available.  Note that if there are
no characters available, the read will return 0, which is indistinguishable
from end-of-file.  Because of this, make sure you set the flags back to their
old value before you exit; otherwise, the program that ran your program,
probably a shell, will try to read something and, if you haven't typed
anything, will get a return of 0, think it's an EOF, and dutifully exit.
(4.2BSD handles this differently; you set no-delay mode on the terminal
(i.e., *all* file descriptors referring to that terminal) with the FIONBIO
"ioctl" (you can do it with "fcntl" as well, but unlike the USG "fcntl" it
affects all file descriptors) and, if there is no data available, a read
returns -1 with the error code EWOULDBLOCK.  (In 4.2, this also affects writes;
the write will only write as much data as will go without blocking.)

The purpose of VMIN and VTIME is to act like the input silo on a DMF32.
The read doesn't complete unless c_cc[VMIN] characters have come in, or
c_cc[VTIME] 10ths of a second have elapsed *AND* at least one character has
come in.  (Completing the read if nothing came in is useless; the silos on
the DH11 and DZ11 have no builtin timeouts, so they have to be polled under
the control of the CPU clock even if they're empty, which sort of loses.
Admittedly, in System V (but NOT System III) if c_cc[VMIN] is zero, the
read completes after c_cc[VTIME] 10ths of a second even if no data is
available.  This sounds to me like rewriting to code to fit user's
misconceptions of what the code was supposed to do...)

	Guy Harris
	{seismo,ihnp4,allegra}!rlgvax!guy

henry@utzoo.UUCP (Henry Spencer) (01/16/85)

>     >>     I am working with V7 UN*X.  I need a way to scan the standard input
>     >> stream for a character, but not wait.
>     >
>     >This is not supported by 7th Edition UNIX.  You need to add something
>     >to your kernel to do this directly; the Rand Corp. empty() call has
>     >been distributed by USENIX a long time ago, and more recent approaches
>     >include VTIME,VMIN in AT&T UNIX Systems III & V and select() in 4.2BSD.
>  
> VTIME and VMIN index the control character array in the termio structure
> of USG systems.  They appear to be potentially very usefull, but I have
> been unable to locate any printed documentation on how to manipulate
> c_cc[VTIME] and c_cc[VMIN] to achieve a non-blocking read.  Can anyone
> enlighten me please?

As I understand them, VTIME and VMIN cannot be used to do non-blocking
reads, contrary to the second excerpt above.  What they can be used to
do is to make raw mode more efficient when you have some idea of what
to expect in the way of input -- you can make raw mode deliver more than
one character per system call, by having it wait for a specified time or
a specified number of characters (whichever comes first).  But if
absolutely nothing is received, you still hang waiting for something.
The VTIME setting is not a timeout when waiting for the first character,
it is a timeout when waiting for *more* characters.

Caveat:  I'm not an expert on the SysV terminal driver.
-- 
				Henry Spencer @ U of Toronto Zoology
				{allegra,ihnp4,linus,decvax}!utzoo!henry