[comp.unix.wizards] How can I read keyboard without stopping

isns02@ms3.UUCP (Harris Reavin) (08/09/88)

	I would like to know if it is possible to get input data from the
keyboard while my program is constantly looping and displaying output to
the screen. The input comes from a call to "popen()".
I am using C, curses, and BSD4.2 on a VAX-780. I have only been
able to enter input if the display stops for "getch()". This is not acceptable
because I want the display to be continuous unless I am going to change one
of the parameters.  For my PC I have Aspen Curses which has a "nodelay()" 
function that indicates the presence of characters in the keyboard buffer. 
Is there an some way to do this under UNIX?
-- 
Harris Reavin
ISN, Crystal City, VA, 703-979-8900
umd5!vrdxhq!ms3!isns02

kevin%kalli@Sun.COM (Kevin Sheehan (Consulting Poster Child)) (08/09/88)

In article <813@ms3.UUCP> isns02@ms3.UUCP (Harris Reavin) writes:
>
>	I would like to know if it is possible to get input data from the
>keyboard while my program is constantly looping and displaying output to
>the screen. The input comes from a call to "popen()".
>I am using C, curses, and BSD4.2 on a VAX-780. I have only been
>able to enter input if the display stops for "getch()". This is not acceptable
>because I want the display to be continuous unless I am going to change one
>of the parameters.  For my PC I have Aspen Curses which has a "nodelay()" 
>function that indicates the presence of characters in the keyboard buffer. 
>Is there an some way to do this under UNIX?

ioctl(fd,FIONREAD, &count) will tell you the number of characters available
on a file descriptor.  A simple version of what I think you want:

/*
 *	returns -1 if no char, -2 for read error, otherwise char
 */

maygetchar(fd)
int fd;
{
	int	count;
	char	c;

	ioctl(fd, FIONREAD, &count);
	if (!count) {
	    return(-1);
	} else {
	    if(read(fd, &c, 1) != 1) return(-2);
	    return(c);
	}
}

		l & h,
		kev

mouse@mcgill-vision.UUCP (der Mouse) (08/15/88)

In article <813@ms3.UUCP>, isns02@ms3.UUCP (Harris Reavin) writes:
> I would like to know if it is possible to get input data from the
> keyboard while my program is constantly looping and displaying output
> to the screen.  The input comes from a call to "popen()".

Now wait a minute!  If you used popen(), your input is coming from
another program, and only indirectly (if at all) from the keyboard.

> I am using C, curses, and BSD4.2 on a VAX-780.  I have only been able
> to enter input if the display stops for "getch()".  This is not
> acceptable because I want the display to be continuous unless I am
> going to change one of the parameters.

It sounds as though you really want to read from the keyboard, so I'll
ignore the bit about popen().

I know of at least four ways to do this (read without jamming the whole
process), of varying degrees of portability and functionality.

1) Signals.  Set up an alarm signal (eg, with alarm()) before doing the
   read and disable it afterwards.  Have the signal handler either
   longjmp out or, depending on how signals interact with read on the
   system in question, simply do nothing.

   Good:	- works nearly everywhere.

   Bad:		- program blocks for a while.
		- if alarm() is used (as it must for portability), the
		  granularity of this timeout is one second.

2) Non-blocking I/O.  BSD systems, and I believe recent SV systems,
   support the notion of "non-blocking" reads.  What this amounts to is
   you make a call to turn this mode on, and then any read for which no
   characters are available will return an error indication instead of
   blocking.

   Good:	- no temporary blockage.
		- reasonably widely available (I think).

   Bad:		- may not interact well with curses.  Many programs
		  (and library packages) are not prepared to handle
		  "would block" errors.
		- specifics vary from system to system.
		- generally, non-blocking mode *must* be turned off or
		  the shell will die - so you must trap SIGBUS,
		  SIGSEGV, SIGINT, etc.
		- requires constant polling.

3) FIONREAD.  BSD systems have an ioctl you can apply to a terminal
   line to get the number of characters queued available for a read().
   SV may have something similar; I don't know.

   Good:	- no temporary blockage.
		- indicates not only *whether* input is available but
		  also *how much* input is available.

   Bad:		- BSD only (as far as I know).
		- requires constant polling.

4) select().  BSD systems, and some "SV with BSD extensions" systems (I
   know of at least one) have the select() syscall.  This allows you to
   block until something is available from any one of several sources
   you specify, or a timeout expires.  (It is possible to wait for
   other conditions as well, but I'm not trying to write a manpage for
   the thing.)  This is the most flexible method of the four.

   Good:	- full control over blockage, from a zero timeout
		  (polling) to infinite (blocking).

   Bad:		- BSD-specific, though your system may have it even if
		  it's primarily SV.

Pick the one you think best suits your needs.  Since you're on a BSD
system, all four are available.  If you aren't interested in porting to
non-BSD systems, I recommend select().  (Actually, I recommend that you
use select(), with preprocessor #if lines to select some other method
if you have to compile somewhere select() is unavailable.)

					der Mouse

			old: mcgill-vision!mouse
			new: mouse@larry.mcrcim.mcgill.edu

kpv@ulysses.homer.nj.att.com (Phong Vo[eww]) (08/15/88)

In article <1246@mcgill-vision.UUCP>, mouse@mcgill-vision.UUCP (der Mouse) writes:
> In article <813@ms3.UUCP>, isns02@ms3.UUCP (Harris Reavin) writes:
> > I would like to know if it is possible to get input data from the
> > keyboard while my program is constantly looping and displaying output
> > to the screen.  The input comes from a call to "popen()".
> 
> 
> I know of at least four ways to do this (read without jamming the whole
> process), of varying degrees of portability and functionality.
...four different ways described ... 

Functionality such as this is required frequently enough and its implementation
is reasonably hard for ensuring portability across different UNIX flavors that
I think it ought to be a part of a standard package such as curses.
In a version of curses that I wrote a number of years back, there is a function
wtimeout(WINDOW *win,int delay) which let users define a delay in miniseconds
for getting keyboard inputs. Delay < 0 means blocking on reads, delay == 0 means
no blocking, and so on. This can be implemented nicely with select().
On systems without select() or an equivalent function,
it can be simulated with a hack using fcntl() and times().
This curses is now distributed with a version of system V.
	Phong Vo, AT&T Bell Labs, ulysses!kpv

chip@ateng.uucp (Chip Salzenberg) (08/16/88)

According to mouse@mcgill-vision.UUCP (der Mouse):
>3) FIONREAD.  BSD systems have an ioctl you can apply to a terminal
>   line to get the number of characters queued available for a read().
>   SV may have something similar; I don't know.
>
>   Bad:        - BSD only (as far as I know).

Xenix has the exact equivalent to FIONREAD, but it's not an ioctl() call.
Instead, it's a system call all its own: rdchk(fildes).  Return values are
-1 (not a tty fildes) or >= 0 (number of bytes available).
-- 
Chip Salzenberg                <chip@ateng.uu.net> or <uunet!ateng!chip>
A T Engineering                My employer may or may not agree with me.
        You make me wanna break the laws of time and space
                    You make me wanna eat pork

jsilva@cogsci.berkeley.edu (John Silva) (08/16/88)

Here's a little demo program which should work fine on System V or Xenix 
systems.  (doesn't work under BSD, due to the use of the termio structure).

---------------------------- CUT HERE -------------------------------

#include<stdio.h>
#include<termio.h>
#include<signal.h>


void Finish();

static struct termio term, saveterm;
static long chars = 0;
static long counter = 0;

main(argc, argv)
int argc;
char *argv[];
{
int old, i, timeout;
char ch;

timeout = 1;

ioctl(fileno(stdin), TCGETA, &saveterm);

for (i = 0; i < NSIG; i++)
	signal(i, Finish);

if (--argc) {
	if (i = (0xFF & atoi(*(++argv)))) timeout = i;
	}
printf("Using timeout of %.2fs\n", (float)timeout/10);
printf("You may begin typing....\n");

ioctl(fileno(stdin), TCGETA, &term);
term.c_lflag &= ~ICANON;
term.c_cc[VMIN]='\0';
term.c_cc[VTIME]=(char)timeout;
ioctl(fileno(stdin), TCSETA, &term);

while(1) {
	if((ch = getchar()) != (char)EOF) chars++;
	counter++;
	}

ioctl(fileno(stdin), TCSETA, &saveterm);
exit(0);
}

void
Finish(sig)
int sig;
{
ioctl(fileno(stdin), TCSETA, &saveterm);
printf("\nExiting, signal #%d\n", sig);
printf("chars: %ld\ncounter: %ld\n",chars,counter);
exit(0);
}

------------------------------ CUT HERE -----------------------------

John Silva
---
UUCP:	ucbvax!cogsci!jsilva
DOMAIN:	jsilva@cogsci.berkeley.edu

jfh@rpp386.UUCP (The Beach Bum) (08/16/88)

In article <1988Aug15.130550.8571@ateng.uucp> chip@ateng.UUCP (Chip Salzenberg) writes:
|According to mouse@mcgill-vision.UUCP (der Mouse):
|>3) FIONREAD.  BSD systems have an ioctl you can apply to a terminal
|>   line to get the number of characters queued available for a read().
|>   SV may have something similar; I don't know.
|>
|>   Bad:        - BSD only (as far as I know).
|
|Xenix has the exact equivalent to FIONREAD, but it's not an ioctl() call.
|Instead, it's a system call all its own: rdchk(fildes).

xenix has both methods.  the rdchk() and an ioctl() request.  it is
spelt differently, FIORDCHK.

this does not improve the situation.  real unix still doesn't have a
parallel method.
-- 
John F. Haugh II                 +--------- Cute Chocolate Quote ---------
HASA, "S" Division               | "USENET should not be confused with
UUCP:   killer!rpp386!jfh        |  something that matters, like CHOCOLATE"
DOMAIN: jfh@rpp386.uucp          |         -- apologizes to Dennis O'Connor

peter@ficc.UUCP (Peter da Silva) (08/17/88)

In article ... chip@ateng.uucp (Chip Salzenberg) writes:
> According to mouse@mcgill-vision.UUCP (der Mouse):
> >3) FIONREAD.  BSD systems have an ioctl you can apply to a terminal
> >   line to get the number of characters queued available for a read().

> [Xenix] it's a system call all its own: rdchk(fildes).

I believe that once upon a time on some system a stat() on a pipe would
return the number of characters in a pipe. Wouldn't it make sense to
have stat() on a terminal device return the number of characters available?
(and a stat() on /dev/mem return memory size, and...)
-- 
Peter da Silva, Ferranti International Controls Corporation, sugar!ficc!peter.
"You made a TIME MACHINE out of a VOLKSWAGEN BEETLE?"
"Well, I couldn't afford another deLorean."
"But how do you ever get it up to 88 miles per hour????"

bgg@yarra.oz.au (Benjamin G. Golding) (08/17/88)

In article <1246@mcgill-vision.UUCP>, mouse@mcgill-vision.UUCP (der Mouse) writes:
> In article <813@ms3.UUCP>, isns02@ms3.UUCP (Harris Reavin) writes:
> > I would like to know if it is possible to get input data from the
> > keyboard while my program is constantly looping and displaying output
> > to the screen.  The input comes from a call to "popen()".
>
> [der mouse lists four techniques to do this]

 5) A pair of processes and a pipe.  Have the main process create a
    pipe and spawn a subprocess to do all the work; it can then block
    reading from the keyboard.  When keyboard input arrives, the main
    process copies it to the pipe for the other process and sends a
    signal to notify it that data is waiting there.

    Good: It will work almost anywhere, even V6!  It is simple and
    natural: there are two tasks to be done, so we have two processes.

    Bad: If we lose a signal we may not get all input as it arrives.
    This may be acceptable because people can't type very fast at the
    keyboard.  The sensible thing to do would be to check the amount of
    data in the pipe using stat() before reading it.  This doesn't work
    under Berkeley unix because it sets st_size to 0 on a pipe - a
    peculiar thing to do.

	Ben.

allbery@ncoast.UUCP (Brandon S. Allbery) (08/18/88)

As quoted from <1246@mcgill-vision.UUCP> by mouse@mcgill-vision.UUCP (der Mouse):
+---------------
| In article <813@ms3.UUCP>, isns02@ms3.UUCP (Harris Reavin) writes:
| > I would like to know if it is possible to get input data from the
| > keyboard while my program is constantly looping and displaying output
| > to the screen.  The input comes from a call to "popen()".
| 
| Now wait a minute!  If you used popen(), your input is coming from
| another program, and only indirectly (if at all) from the keyboard.
+---------------

I think he meant the program is copying from a popen()'ed stream to the
screen but *also* wants to catch keypresses.

+---------------
| 2) Non-blocking I/O.  BSD systems, and I believe recent SV systems,
|    support the notion of "non-blocking" reads.  What this amounts to is
|    you make a call to turn this mode on, and then any read for which no
|    characters are available will return an error indication instead of
|    blocking.
+---------------

*All* System III and System V systems have it.  You're only out of luck if
you want to port to V6/V7 or Minix (and you probably have bigger problems
than non-blocking reads in that case!).

+---------------
|    Bad:	- may not interact well with curses.  Many programs
| 		  (and library packages) are not prepared to handle
| 		  "would block" errors.
+---------------

Note that System III/V returns 0 and leaves errno unchanged; BSD returns -1
and sets errno to EWOULDBLOCK.

+---------------
| 3) FIONREAD.  BSD systems have an ioctl you can apply to a terminal
|    line to get the number of characters queued available for a read().
|    SV may have something similar; I don't know.
+---------------

System V does not.  Xenix has rdchk(fd).  (I wish AT&T would pick it up!)

+---------------
| 4) select().  BSD systems, and some "SV with BSD extensions" systems (I
|    know of at least one) have the select() syscall.  This allows you to
+---------------

If you are one of the elite with a System V whose terminal drivers are
STREAMS modules (not many are as yet, although it's supposed to be in SVR4)
you can use poll() the same way that BSD uses select().  Another wish of mine
is for poll() to work on non-STREAMS fd's -- how would BSD be if select()
only worked on sockets?

++Brandon
-- 
Brandon S. Allbery, uunet!marque!ncoast!allbery			DELPHI: ALLBERY
	    For comp.sources.misc send mail to ncoast!sources-misc

jfh@rpp386.UUCP (The Beach Bum) (08/18/88)

In article <1267@ficc.UUCP> peter@ficc.UUCP (Peter da Silva) writes:
>I believe that once upon a time on some system a stat() on a pipe would
>return the number of characters in a pipe. Wouldn't it make sense to
>have stat() on a terminal device return the number of characters available?
>(and a stat() on /dev/mem return memory size, and...)

stat() is implemented by taking chunks of the inode table enty and stuffing
that into a "struct stat" thingy.  i believe the number of characters
queued in a pipe was a side effect (read `feature') of the implementation
of pipes, and probably not intentional.

one must remember that under system v, pipes are really just unnamed
files which never grow past a certain size, and who blocks get
juggled as they are written.
-- 
John F. Haugh II                 +--------- Cute Chocolate Quote ---------
HASA, "S" Division               | "USENET should not be confused with
UUCP:   killer!rpp386!jfh        |  something that matters, like CHOCOLATE"
DOMAIN: jfh@rpp386.uucp          |         -- apologizes to Dennis O'Connor

maart@cs.vu.nl (Maarten Litmaath) (08/19/88)

In article <1246@mcgill-vision.UUCP> mouse@mcgill-vision.UUCP (der Mouse) writes:
\		- generally, non-blocking mode *must* be turned off or
\		  the shell will die - so you must trap SIGBUS,
\		  SIGSEGV, SIGINT, etc.

Are you saying that the shell will die if a CHILD sets the non-blocking mode?
I guess your operating system isn't Unix.
-- 
If you enjoyed the recent heat wave,  |Maarten Litmaath @ Free U Amsterdam:
you'll certainly like the ozone gap...|maart@cs.vu.nl, mcvax!botter!maart

bph@buengc.BU.EDU (Blair P. Houghton) (08/19/88)

In article <51@yarra.oz.au> bgg@yarra.oz.au (Benjamin G. Golding) writes:
> In article <813@ms3.UUCP>, isns02@ms3.UUCP (Harris Reavin) writes:
> > I would like to know if it is possible to get input data from the
> > keyboard while my program is constantly looping and displaying output
>
> 5) A pair of processes and a pipe.  Have the main process create a
>    pipe and spawn a subprocess to do all the work; it can then block
>    reading from the keyboard.  When keyboard input arrives, the main
>    process copies it to the pipe for the other process and sends a
>    signal to notify it that data is waiting there.
>
>    Good: It will work almost anywhere, even V6!  It is simple and
>    natural: there are two tasks to be done, so we have two processes.
>
>    Bad: If we lose a signal we may not get all input as it arrives.

I think I know of an example of this, and a fun one at that!

If you can find it (I don't believe I have a noncorrupted copy), look
at the vrogue extension to the game rogue.  It allows switching two
character sets when sending graphics-characters and ascii to the terminal
under the X window system.

Lemme look...

Aha! I do have it; just not on this computer.  No ftping problem...

Yes, it is neat as all-get-out.  It does some Rube Goldberg plumbing,
(no doubt brilliant to another eye) and handles almost all of the
signals itself.  I don't know of its portability, but I'm certain for
Ultrix 2.2.

I would appreciate someone's telling me what my liability is if I start
passing it around.  I pulled it off the net, myself, but I don't know
whether it should have been there; seems it was part of a systems-software
release once, then not.

Jim Gettys would know.

				--Blair
				  "So would his lawyer, I fear..."

robert@pvab.UUCP (Robert Claeson) (08/20/88)

In article <12251@ncoast.UUCP>, allbery@ncoast.UUCP (Brandon S. Allbery) writes:

> Xenix has rdchk(fd).  (I wish AT&T would pick it up!)

Check out the new S5R3.2, which is supposed to be a merger of UNIX System V
and Xenix.

henry@utzoo.uucp (Henry Spencer) (08/21/88)

In article <5558@rpp386.UUCP> jfh@rpp386.UUCP (The Beach Bum) writes:
>stat() is implemented by taking chunks of the inode table enty and stuffing
>that into a "struct stat" thingy.  i believe the number of characters
>queued in a pipe was a side effect (read `feature') of the implementation
>of pipes, and probably not intentional.

Possibly so in the beginning, but it *was* documented in V7.
-- 
Intel CPUs are not defective,  |     Henry Spencer at U of Toronto Zoology
they just act that way.        | uunet!attcan!utzoo!henry henry@zoo.toronto.edu

daveh@marob.MASA.COM (Dave Hammond) (08/22/88)

In article <1202@tjalk.cs.vu.nl> maart@cs.vu.nl () writes:
>In article <1246@mcgill-vision.UUCP> mouse@mcgill-vision.UUCP (der Mouse) writes:
>\		- generally, non-blocking mode *must* be turned off or
>\		  the shell will die - so you must trap SIGBUS,
>\		  SIGSEGV, SIGINT, etc.
>Are you saying that the shell will die if a CHILD sets the non-blocking mode?
>I guess your operating system isn't Unix.

Mine is (Unix), and yes, the shell dies if a child dies with the terminal in
non-blocking mode -- every time.  At least sh and ksh do; I don't know 'bout csh
but I suspect the same is true.

Dave Hammond
  UUCP: {uunet|...}!masa.com!{dsix2|marob}!daveh
DOMAIN: dsix2!daveh@masa.com
------------------------------------------------------------------------------

alvitar@madhat.UUCP (Phil Harbison) (08/23/88)

In article <813@ms3.UUCP>, isns02@ms3.UUCP (Harris Reavin) writes:
> I would like to know if it is possible to get input data from the
> keyboard while my program is constantly looping and displaying output
> to the screen.  The input comes from a call to "popen()".

The  best  way  I've  found to do this is to spawn a separate process to
handle  the keyboard and communicate using pipes.  I have a program that
performs  an  I/O multiplexing function.  It must simultaneously monitor
the keyboard and the output of a pipe, sending data from the pipe to the
display,  and  data  from  the  keyboard to a subprocess.  I have fork a
couple  of  "handler"  processes,  one  for the keyboard and one for the
subprocess.   The handlers collect their data using blocking reads, then
send  the  data through a pipe to the main process using a simple packet
protocol.  The main process does a blocking read on the pipe waiting for
the  next packet, and can tell by the packet ID whether it came from the
keyboard or the subprocess.  The packets look like this:

	+-----------+------------+------+
	| source-id | byte count | data |
	+-----------+------------+------+

There  are  two nice side effects of this implementation.  The same code
runs  on  v7,  BSD, and USG flavors of UNIX, and probably any version of
UNIX or UNIX-derivatives which support atomic writes to pipes and fstat.
Previous  versions  of this code used select for BSD, non-blocking reads
for  USG,  and punted on v7.  Checking for type-ahead is now easy, since
the  main  process  can perform an fstat to find out if there is data in
the pipe. 

In article <12251@ncoast.UUCP>, Brandon S. Allbery writes:
> +---------------
> | 3) FIONREAD.  BSD systems have an ioctl you can apply to a terminal
> |    line to get the number of characters queued ...
> 
> System V does not.  Xenix has rdchk(fd).  (I wish AT&T would pick it up!)

Unisoft's  version  of  System V has FIONREAD, but unfortunately it only
works when the tty is in cooked mode!  In most cases where I want to use
FIONREAD, the tty is in raw mode. 

daveb@laidbak.UUCP (Dave Burton) (08/23/88)

In article <1202@tjalk.cs.vu.nl> maart@cs.vu.nl () writes:
|In article <1246@mcgill-vision.UUCP> mouse@mcgill-vision.UUCP (der Mouse) writes:
|\		- generally, non-blocking mode *must* be turned off or
|\		  the shell will die - so you must trap SIGBUS,
|\		  SIGSEGV, SIGINT, etc.
|Are you saying that the shell will die if a CHILD sets the non-blocking mode?
|I guess your operating system isn't Unix.

Consider what read(2) returns in non-blocking mode. I'd bet that the
input routine for the shell says something to the effect of:

	if ((cc = read(0, buf, sizeof buf)) == 0) {	/* EOF seen */
		cleanup();
		exit(0);
	}
-- 
Dave Burton		| ``/* You are not expected to understand this. */''
{att,sun}!laidbak!daveb	|
(312) 505-9100 x325	| Disclaimer: I channel only for myself.

allbery@ncoast.UUCP (Brandon S. Allbery) (08/29/88)

As quoted from <373@marob.MASA.COM> by daveh@marob.MASA.COM (Dave Hammond):
+---------------
| In article <1202@tjalk.cs.vu.nl> maart@cs.vu.nl () writes:
| >In article <1246@mcgill-vision.UUCP> mouse@mcgill-vision.UUCP (der Mouse) writes:
| >\		- generally, non-blocking mode *must* be turned off or
| >\		  the shell will die - so you must trap SIGBUS,
| >\		  SIGSEGV, SIGINT, etc.
| >Are you saying that the shell will die if a CHILD sets the non-blocking mode?
| >I guess your operating system isn't Unix.
| 
| Mine is (Unix), and yes, the shell dies if a child dies with the terminal in
| non-blocking mode -- every time.  At least sh and ksh do; I don't know 'bout csh
| but I suspect the same is true.
+---------------

Keep in mind that dup()'ed file descriptors and file descriptors inherited
across a fork() share a file table entry -- and it is the file table entry
that holds the O_NDELAY (FNDELAY on BSD) flag.  So yes, if a child changes
the no-delay status the parent sees it also.

++Brandon
-- 
Brandon S. Allbery, uunet!marque!ncoast!allbery			DELPHI: ALLBERY
	    For comp.sources.misc send mail to ncoast!sources-misc

rminnich@super.ORG (Ronald G Minnich) (08/30/88)

In article <1267@ficc.UUCP> peter@ficc.UUCP (Peter da Silva) writes:
>I believe that once upon a time on some system a stat() on a pipe would
>return the number of characters in a pipe. Wouldn't it make sense to
>have stat() on a terminal device return the number of characters available?
You would think so, wouldn't you. 
On most of the systems i have tried it on it 
always returns 0 on ttys. 
That seems quite wrong to me, but there you are. 
Also, on most unix's you can't tell whether there are 0 bytes
to read because of an eof or 0 bytes cause nothing is there yet. 
I haven't looked lately to see if such a thing has been added; on 4.2-like
systems you had to to shenanigans with select() and FIONREAD to determine
that you were at EOF. And then you had to try to read 1 byte
to get the rest of the kernel to realize you really WERE
at EOF. Annoying. So many other OSs have a way of just TELLING you 
you are at EOF with a simple function call.
There are funny little holes in the Unix filesystem even now ...
ron

chris@mimsy.UUCP (Chris Torek) (08/31/88)

>In article <1267@ficc.UUCP> peter@ficc.UUCP (Peter da Silva) writes:
>>... Wouldn't it make sense to have stat() on a terminal device return
>>the number of characters available?

In article <669@super.ORG> rminnich@super.ORG (Ronald G Minnich) writes:
>You would think so, wouldn't you.

Perhaps.  I doubt one could make much use of it, since it would change
from moment to moment, as the user types.

>Also, on most unix's you can't tell whether there are 0 bytes
>to read because of an eof or 0 bytes cause nothing is there yet. 

False (except perhaps on SysV, where read on a non-blocking descriptor
returns 0 instead of -1).

>I haven't looked lately to see if such a thing has been added; on 4.2-like
>systems you had to to shenanigans with select() and FIONREAD to determine
>that you were at EOF.

Again, false.  The only odd thing about EOF on a terminal is that it is
not `sticky', since it is (usually) caused by a human agent and not
something reliable :-) .
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris

rminnich@super.ORG (Ronald G Minnich) (08/31/88)

In article <13307@mimsy.UUCP> chris@mimsy.UUCP (Chris Torek) writes:
>>(... my comment on stat() returning bytes-to-read for a terminal)
>Perhaps.  I doubt one could make much use of it, since it would change
>from moment to moment, as the user types.
Well, for one thing, it pretty much eliminates the need for FIONREAD.
Seems to me a good thing. It bugs me that there are two 
different ways to do the same thing for different types of files.
Seems to bug Peter too, so that makes two of us :-)
FIONREAD changes from moment to moment as the user types too.
>>Also, on most unix's you can't tell whether there are 0 bytes
>>to read because of an eof or 0 bytes cause nothing is there yet. 
>False.
Well, last time i tried a few years ago that was true. 
I.e. for some arbitrary file descriptor, you do a stat, 
and that stat indicates 0 bytes to read. OK, are you
at EOF, or are you at a lull in the data? Last time i looked
you couldn't tell the difference, except by doing a read. 
This was especially a pain if the file was a pipe.
Now i know about the EWOULDBLOCK business but that is non-portable.
So if you actually go to read the file to close it up you risk
being put to sleep if you are not at EOF.
   Anyway, if things have changed and there is a way to find 
you are at EOF, i would be happy to know.
So how do you (on an arbitrary file, not just terminals, now):
1) tell the difference
2) tell you are at EOF? And i mean for both blocking and non-blocking.
   I know about non-blocking.
I think you are assuming my question is differentiating EOF from 0 bytes after 
a return from a read(). My question is determining that you are
at EOF WITHOUT doing a read(). That is possible on many systems. 
I didn't think it was easily done on Unix.
inquiring minds want to know.
ron

chris@mimsy.UUCP (Chris Torek) (09/01/88)

>>>(... comment on stat() returning bytes-to-read for a terminal)

>In article <13307@mimsy.UUCP> chris@mimsy.UUCP (Chris Torek) writes:
>>Perhaps.  I doubt one could make much use of it, since it would change
>>from moment to moment, as the user types.

In article <679@super.ORG> rminnich@super.ORG (Ronald G Minnich) writes:
>Well, for one thing, it pretty much eliminates the need for FIONREAD.
>Seems to me a good thing. It bugs me that there are two 
>different ways to do the same thing for different types of files.
>Seems to bug Peter too, so that makes two of us :-)
>FIONREAD changes from moment to moment as the user types too.

The difference (or so it seems to me) is that FIONREAD is implicitly
defined as st.st_size - current_seek_offset, so that it makes sense for
it to change as you read data.  But seek offsets are peculiar on ttys.
Hence `perhaps'....

At any rate, no one ever seems to use the value from FIONREAD as anything
other than a ready/not-ready flag, and here select does the job.

>>>Also, on most unix's you can't tell whether there are 0 bytes
>>>to read because of an eof or 0 bytes cause nothing is there yet. 

>>False.

>Well, last time i tried a few years ago that was true. 
>I.e. for some arbitrary file descriptor, you do a stat, 
>and that stat indicates 0 bytes to read. OK, are you
>at EOF, or are you at a lull in the data? Last time i looked
>you couldn't tell the difference, except by doing a read. 
>This was especially a pain if the file was a pipe.

This paragraph seems hopelessly confused.  stat says how big the file
is, and is completely orthogonal to your current seek offset.  And I
thought we were talking about tty devices, not pipes.

>Now i know about the EWOULDBLOCK business but that is non-portable.
>So if you actually go to read the file to close it up you risk
>being put to sleep if you are not at EOF.

Use select (or, in SysV, poll, except that it only works on STREAMS).
Select says that you can read or write exactly when that read or write
would not block (not that it would necessarily succeed).

>   Anyway, if things have changed and there is a way to find 
>you are at EOF, i would be happy to know.
>So how do you (on an arbitrary file, not just terminals, now):

(Changing the rules again, but okay:)

>1) tell the difference
>2) tell you are at EOF? And i mean for both blocking and non-blocking.
>   I know about non-blocking.
>I think you are assuming my question is differentiating EOF from 0 bytes after 
>a return from a read(). My question is determining that you are
>at EOF WITHOUT doing a read(). That is possible on many systems. 
>I didn't think it was easily done on Unix.

On regular files, you are at EOF if your current seek offset (available
via lseek()) matches the size returned via fstat().  Tty devices do not
have ends-of-files; instead, some peculiar creature types some special
character to pretend an end of file, and naturally this is
unpredictable.  `On many systems' there are no special files (ttys,
pipes, etc) and the question never even comes up.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris

ditto@cbmvax.UUCP (Michael "Ford" Ditto) (09/01/88)

In article <669@super.ORG> rminnich@metropolis.UUCP (Ronald G Minnich) writes:
[ about reading from ttys, possibly in O_NDELAY mode ]
>Also, on most unix's you can't tell whether there are 0 bytes
>to read because of an eof or 0 bytes cause nothing is there yet. 

But these are exactly the same condition.  Typing EOF on a tty in
cooked mode, by definition, causes a blocked read to "unblock", even if
it otherwise would have waited for some other contidion (like a line
terminator).  In other words, typing ^D causes exactly one read() to
magically be in NDELAY mode, causing it to return with whatever is in
the buffer, without blocking.  That's why typing ^D at the beginning of
a line looks to a program as if it has hit the end of a file -- the read
returns 0 bytes.

One might argue, however that O_NDELAY is a special case of an "early
return", and that an EWOULDBLOCK error is justified.  This could be
made consistant across all devices that support NDELAY reads.

The "unblocking" behavior of EOF can be useful sometimes... most
people think that the write(1) program only sends messages one-
line-at-a-time.  Actually, it sends them one-read()-at-a-time; if
you type ^D in the middle of your line, write's read() will unblock,
and what you have typed so far will appear on the destination terminal
(without a newline).  Then you can continue with the rest of the line.
-- 
					-=] Ford [=-

	.		.		(In Real Life: Mike Ditto)
.	    :	       ,		ford@kenobi.cts.com
This space under construction,		...!ucsd!elgar!ford
pardon our dust.			ditto@cbmvax.commodore.com

rminnich@super.ORG (Ronald G Minnich) (09/02/88)

In article <13333@mimsy.UUCP> chris@mimsy.UUCP (Chris Torek) writes:
>The difference (or so it seems to me) is that FIONREAD is implicitly
>defined as st.st_size - current_seek_offset, so that it makes sense for
>it to change as you read data.  But seek offsets are peculiar on ttys.
Well, ok, looking at stat i see:
               off_t  st_size;/* total size of file, in bytes */
So what can i say? Looks like the size to me. First time i saw this
i thought 'well, terminals aren't regular files, so i guess
they stuff the amount of characters in the queue in here'. 
And it still seems reasonable to me.
>At any rate, no one ever seems to use the value from FIONREAD as anything
>other than a ready/not-ready flag, and here select does the job.
I often use it as a way of determining how many bytes to 
read from the tty. I have gotten very good performance this way.
I.E. I can suck up a lot of 9600 baud input even on a VAX.
I have fixed a lot of people's programs just by changing
single-character reads to FIONREAD-driven reads.
> ... more stuff.
   I think Peter and I were both bothered by having two different
mechanisms for the same function for two different file types.
I was also thinking of the number of OSs that solve all this 
more intelligently than Unix. E.G. Burroughs MCP and the Amiga OS.
   I notice through your reply a pattern: 
'oh, we were talking about ttys, not pipes'
'oh, on 4bsd do this, on Sys V do this, except for STREAMS only'
'on regular files, do this, on ttys, no eof ...'
For example:
>Use select (or, in SysV, poll, except that it only works on STREAMS).
>Select says that you can read or write exactly when that read or write
>would not block (not that it would necessarily succeed).
>On regular files, you are at EOF if your current seek offset (available
but not on pipes or ttys. OK, no problem, I knew all that stuff 
already. What's wrong with a simple predicate: eof(fildes)?
Then you don't HAVE to know all this crap. Especially nice if you
are working from an inherited file descriptor. Failing that, wouldn't
it be nice if stat() were a little more informative?
   For what it is worth, you can use the st_size from stat()
to figure out how much to read from a pipe. That's the most
portable way i have found. That is why i was referring to 
st_size as the amount available to read- i was not clear on that, sorry.
   Now at some point st_size on a pipe will go to zero. 
Question is, what does that mean? That the pipe has closed? 
Or that there is nothing to read, come back later? I have a way
of determing that using select() and FIONREAD, but it is not real pretty.
   And i don't think Peter's main point was about tty's. I think it was
questioning the need for FIONREAD, given that the functionality
is just about there in stat().
   ron

rminnich@super.ORG (Ronald G Minnich) (09/02/88)

In article <4617@cbmvax.UUCP> ditto@cbmvax.UUCP (Michael "Ford" Ditto) writes:
>In article <669@super.ORG> rminnich@metropolis.UUCP (Ronald G Minnich) writes:
>>Also, on most unix's you can't tell whether there are 0 bytes
>>to read because of an eof or 0 bytes cause nothing is there yet. 
>But these are exactly the same condition.  Typing EOF on a tty in
> ... good explanation of how the read() tells you what's going on.

Sure, you can tell lots of things from the return of a read(). 
As i understood the original question it was what you 
could determine WITHOUT doing the read(). There are cases where 
you don't want to read without knowing whether you will block. 
That's why people use FIONREAD (which not everyone supports), or 
select (ditto), or in this case stat(). Or all the other 
not-quite-universal mechanisms.

There is a way to tell you are at eof, btw. ON 4.2-style systems, 
do a select on the file descriptor, and see if it returns indicating
'something there'. Then do an ioctl(fildes, FIONREAD, &length) and 
see if length is zero. If it is, the system is telling you:
there is something you can read, but you won't get anything, i.e. eof.
It is also telling you that you will return immediately if you do read.
SO, do a read(fildes, buf, 1), get the EOF indication back, fildes is
now closed. 
   This works on pipes (i.e. sockets) and ttys. I never got
around to trying it on files.
ron

rminnich@super.ORG (Ronald G Minnich) (09/02/88)

In article <13333@mimsy.UUCP> chris@mimsy.UUCP (Chris Torek) writes:
>>I.e. for some arbitrary file descriptor, you do a stat, 
>>and that stat indicates 0 bytes to read. OK, are you
>>at EOF, or are you at a lull in the data? Last time i looked
>This paragraph seems hopelessly confused.  stat says how big the file
>is, and is completely orthogonal to your current seek offset.  And I
>thought we were talking about tty devices, not pipes.
Well, it is confused. Sorry. Let me try again...
   It turns out that a portable way to 
do the equivalent of FIONREAD on a pipe is to use stat. 
The size field will tell you how much data is in the pipe. 
You then read that much data, and you don't get blocked. Handy, 
esp. for the many systems that didn't support FIONREAD (this was five
years ago). The fact that that worked is what led me to expect some similar
operation on tty lines. No such luck.
   I was not talking about tty devices, rather peter da silva's original
comment questioning stat's not supporting the size field for ttys. 
That comment got me to thinking about stat()s lack of generality, 
since i had been burned by it once. I think that he was making the same point.
>On regular files, you are at EOF if your current seek offset (available
>via lseek()) matches the size returned via fstat().  Tty devices do not
Only if someone else is not writing? If you are reading a regular file, 
and someone else is writing, then there are times when 
your current seek offset will match the returned size. You are still 
not at eof, as someone else has the file open. More data can
come along. This is 'nothing available to read, but you are not at eof'.
I.e. tail -f, tail never really does know when it hits eof- you, 
peculiar creature that you are, decide for it via ^C :-).
ron
P.S. Does it strike anyone as strange that stdio and level 2 have such
different ideas about eof? Level 2 you can just read right through ^D; 
As was pointed out, it is more like an enforced one-read FNDELAY than 
anything else. for standard IO, one is enough; you lose it all right there. 
The FILE * gets closed for you. 

gwyn@smoke.ARPA (Doug Gwyn ) (09/03/88)

In article <690@super.ORG> rminnich@metropolis.UUCP (Ronald G Minnich) writes:
>P.S. Does it strike anyone as strange that stdio and level 2 have such
>different ideas about eof? Level 2 you can just read right through ^D; 
>As was pointed out, it is more like an enforced one-read FNDELAY than 
>anything else. for standard IO, one is enough; you lose it all right there. 
>The FILE * gets closed for you. 

If that's true, it's a bug.  EOF on a stream is not supposed to
close the stream, merely set the EOF indicator.  In fact EOF
should not be "sticky"; if more data becomes available, as on a
terminal, it should be available for subsequent reading.  The
4.2BSD implementation broke this but it might be okay on 4.3BSD.

rminnich@super.ORG (Ronald G Minnich) (09/08/88)

In article <8422@smoke.ARPA> gwyn@brl.arpa (Doug Gwyn (VLD/VMB) <gwyn>) writes:
>If that's true, it's a bug.  EOF on a stream is not supposed to
>close the stream, merely set the EOF indicator.  In fact EOF
oh, great, another portability. Well, after you pointed this out
i realized it does vary a lot from machine to machine. I wrote 
a quicky to test it on SunOS 4.0 and it appears that the stream
gets closed for you. 
   I don't have the intestinal fortitude to test this out on our varied
machines. I *really* don't want to know ...
   So, Rule Number One: the definition and side-effects of eof 
are about as well-defined in stdio as they are in Pascal. arg.
ron

mouse@mcgill-vision.UUCP (der Mouse) (09/11/88)

In article <690@super.ORG>, rminnich@super.ORG (Ronald G Minnich) writes:
> If you are reading a regular file, and someone else is writing, then
> there are times when your current seek offset will match the returned
> size.  You are still not at eof, as someone else has the file open.

Sure you are.  Just because it might not be EOF a minute from now
doesn't make it any less truly EOF right now.  (Just because someone
else has the file open makes no difference.  Someone could open it and
append something else even if nobody has it open just now.)

> tail -f, tail never really does know when it hits eof- you, peculiar
> creature that you are, decide for it via ^C :-).

Tail hits EOF just fine.  The -f option tells it that when it does hit
EOF, it's to sleep a little and check again to see whether EOF is still
in the same place it used to be - and if not, to read the new data and
print it out.

> P.S. Does it strike anyone as strange that stdio and level 2 have
> such different ideas about eof? Level 2 you can just read right
> through ^D;

Tty EOF-character semantics are a muddy point: is it really EOF or is
it just a "push", which looks like EOF when typed alone on a line?  Or
is it something else?  The push interpretation seems to be common.

> for standard IO, one is enough; you lose it all right there.  The
> FILE * gets closed for you.

Not in any stdio I've ever heard of!  You must fclose() the stream if
you want it closed.  What if it's a read/write stream and the program
wants to rewind() and rewrite the file?

					der Mouse

			old: mcgill-vision!mouse
			new: mouse@larry.mcrcim.mcgill.edu

rminnich@super.ORG (Ronald G Minnich) (09/12/88)

In article <1305@mcgill-vision.UUCP> mouse@mcgill-vision.UUCP (der Mouse) writes:
>Tty EOF-character semantics are a muddy point: is it really EOF or is
>it just a "push", which looks like EOF when typed alone on a line?  Or
>is it something else?  The push interpretation seems to be common.
Yeah, this was a good point, as was chris's that EOF is a transient
thing. And it is, in many cases. And in many other cases, it is not
(e.g. you hit the end of a pipe and the proc on the other end just died.
You ain't goin' no where). So, it seems to me there are two types
of EOF- the real thing and the wanna be's. The ^D and such on a tty
are wanna be's; reading from a pipe the other end of which is closed
are the real thing. On some systems the equivalent of 'tty ^D' is very much
the real thing, to say the least ... the HP3000 had no less than 
3 ways to deliver 'pseudo-eof' from a terminal, and the 'hardest' one
not even their CLI's knew how to interpret!
   So, does it yet make sense to have the kernel tell you in a simple way?
"You just hit eof. and it's for good this time" vs. "You just hit 
eof. You can try again later, though".
   Gee, its these simple details that have always confused me the most ...
ron

allbery@ncoast.UUCP (Brandon S. Allbery) (09/19/88)

As quoted from <717@super.ORG> by rminnich@super.ORG (Ronald G Minnich):
+---------------
| In article <1305@mcgill-vision.UUCP> mouse@mcgill-vision.UUCP (der Mouse) writes:
| >Tty EOF-character semantics are a muddy point: is it really EOF or is
| >it just a "push", which looks like EOF when typed alone on a line?  Or
| >is it something else?  The push interpretation seems to be common.
| 
| Yeah, this was a good point, as was chris's that EOF is a transient
| thing. And it is, in many cases. And in many other cases, it is not
| (e.g. you hit the end of a pipe and the proc on the other end just died.
| You ain't goin' no where). So, it seems to me there are two types
+---------------

...unless the pipe is really a FIFO, in which case the EOF is (again)
temporary.  (That's how it seemed to work under SVR2, at least.  I would
have preferred that the call block until someone else opened the other end
of the FIFO and wrote to it, though, for the application I was trying to
write with FIFOs.  It made the program work like it was in NDELAY mode.  I
finally ended up using message queues.)

++Brandon
-- 
Brandon S. Allbery, uunet!marque!ncoast!allbery			DELPHI: ALLBERY
	    For comp.sources.misc send mail to ncoast!sources-misc
"Don't discount flying pigs before you have good air defense." -- jvh@clinet.FI

les@chinet.UUCP (Leslie Mikesell) (09/20/88)

In article <12587@ncoast.UUCP> allbery@ncoast.UUCP (Brandon S. Allbery) writes:

>...unless the pipe is really a FIFO, in which case the EOF is (again)
>temporary.  (That's how it seemed to work under SVR2, at least.  I would
>have preferred that the call block until someone else opened the other end
>of the FIFO and wrote to it, though, for the application I was trying to
>write with FIFOs.  It made the program work like it was in NDELAY mode.  I
>finally ended up using message queues.)

If you do not set NDELAY on a FIFO, the first read will block until something
is available, and the last close will make subsequent reads return EOF until
another process opens the FIFO for output.  If you want the reading process
to always block when no data is available, just have it open the FIFO for
write access (but don't write anything).  I use this trick to connect shell
scripts to FIFOs so I can periodically echo commands at them.  If I want
the script to be able to continue with something else when no command is
present, I don't open it for writing.  This is handy since you can't fcntl()
from a shell script but it would be nice if there were better documentation
about FIFOs.

Les Mikesell