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