chris@mimsy.umd.edu (Chris Torek) (05/02/90)
(First, an obligatory note to comp.lang.c readers: the notion of a `key' is found nowhere in the C language, therefore the notion of testing for `strokes of keys' is not C, and does not belong in comp.lang.c. Although the C language does provide the notion of a standard input, it does not provide any notion of testing whether there is input available `now' on this standard input, so it is pointless to ask how this is done `in C'. It is not done `in C' at all; rather, it is done `using C on Unix' or `using C on the Macintosh' or `using C on VMS', and it is done differently in each case. comp.lang.c is therefore not the best place to ask how it is done. Readers not interested in Unix details can skip the rest of this followup.) In article <1990Apr25.000456.25048@cunixf.cc.columbia.edu> gm@cunixd.cc.columbia.edu (Gary Mathews) quotes code from jeff@orca.WV.TEK.COM (Jeff Beadles). This code is specific to Unix C implementations, and in fact is further specific to 4.2BSD systems and derivatives and to systems that borrowed notions from such systems. > if (select(1,&mask,0,0,&waittime)) { > num_chars_read=read(0,&keypressed,1); > if (num_chars_read == 1) > return((int)keypressed); > } > return(-1); There are several problems with this code. The first is that the two `0' arguments to select have the wrong type. The three middle arguments should have type (fd_set *) or (int *) (the latter being 4.2BSD-specific; `fd_set's really only came into existence when the number of file descriptors per process was raised beyond the number of bits per `int'). Thus, one should use select(1, &mask, (fd_set *)0, (fd_set *)0, &waittime) A more important bug, however, lies in the fact that select does not test for `input available' or `output ready', but rather for `calls to read or write will not block'. Because end-of-file is not a blocking input condition, select for input is always true at end of file. Thus, this code will try the read() call, and will return 0. If a program using this routine is run with stdin set to a regular file, the routine will always return -1 once EOF is reached. Likewise, if the input is from a terminal that gets disconnected (e.g., due to a modem hanging up), the routine will return -1 forever. A program using this code may then get stuck waiting for more input, using machine resources without end. Note that select is not (or more precisely, `should not be') affected by non-blocking input or output modes. That is, select for input should be true exactly when a blocking input call would not block, and select for output should be true exactly when a blocking output call (of some sufficiently small but unspecified output size) would not block. The latter is often combined with non-blocking output modes to allow larger output sizes to be trimmed (the system returns the number of bytes queued, instead of waiting for sufficient space to queue everything). This is not normally necessary for input descriptors. -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163) Domain: chris@cs.umd.edu Path: uunet!mimsy!chris
wht@n4hgf.uucp (Warren Tucker) (05/04/90)
In article <24107@mimsy.umd.edu> chris@mimsy.umd.edu (Chris Torek) writes: >(First, an obligatory note to comp.lang.c readers: the notion of a `key' >is found nowhere in the C language, therefore the notion of testing for >... well said >Readers not interested in Unix details can skip the rest of >this followup. ditto BSD: ioctl(0,FIONREAD,&number_of_chars_waiting_to_be_read); XENIX V, SCO UNIX, UNIX Sys V Rel 4: if(rdchk(0)) /* if ICANON is on, rdchk will report nothing until * newline or whatever is typed */ { data is waiting ... } else { no data is waiting ... } Sys V Rel 2, standard Rel 3: (tricky; this is just a clue) ioctl(0,TCGETA,&termio_struct_at_beginning); ioctl(0,TCGETA,&termio_struct); termio_struct.c_lflags ~= ~(ICANON); termio_struct.c_cc[VMIN] = 0; termio_struct.c_cc[VTIME] = 0; ioctl(0,TCSETA,&termio_struct); if((i = read(0,&input_char,1) == 0) { no input } else if(i < 0) { read error } else { 'input_character' has a charcter } /* before program terminates */ ioctl(0,TCSETA,&termio_struct_at_beginning); V7: horrible /dev/kmem munging you dont want to hear about ------------------------------------------------------------------ Warren Tucker, TuckerWare gatech!n4hgf!wht or wht%n4hgf@gatech.edu McCarthyism did to cinema what ANSI did to C, cast a great number of characters into the void.
sofmac@porthos.rutgers.edu (Sofus Macskassy) (05/04/90)
So how would you go about
guy@auspex.auspex.com (Guy Harris) (05/06/90)
>XENIX V, SCO UNIX, UNIX Sys V Rel 4: > if(rdchk(0)) /* if ICANON is on, rdchk will report nothing until > * newline or whatever is typed */ The same, or equivalent, is true of FIONREAD as well; it reports how many characters are ready to be read, and the line you're typing in "cooked mode" isn't ready to be read until you type newline or whatever. (It does, however, include typeahead, of course.)
chip@tct.uucp (Chip Salzenberg) (05/07/90)
Followups to comp.unix.questions. According to wht@n4hgf.UUCP (Warren Tucker): >XENIX V, SCO UNIX, UNIX Sys V Rel 4: > if(rdchk(0)) /* if ICANON is on, rdchk will report nothing until > * newline or whatever is typed */ > { > data is waiting ... > } A nit: rdchk() returns -1 for error, zero if a read() will block, and a positive integer if a read() will not block. Check those errors! Note that if you opened with O_NDELAY, or if you turned on the NDELAY bit with fcntl(), then rdchk() will *always* return a positive integer. After all, with NDELAY on, read() never blocks. Sigh. -- Chip Salzenberg at ComDev/TCT <chip%tct@ateng.com>, <uunet!ateng!tct!chip>