>Johnathan Doe wrote:
I'm trying to find a way to reliably peek at stdin, and if anything's
waiting, flush stdin so that it clears the stream ready to wait for a
character.
In article <news:2g************@uni-berlin.de>
Thomas stegen <ts*****@cis.strath.ac.uk> suggests:char c;
scanf("%c%*[^\n]%*c", &c);
Should do the trick. It does not clear stdin if more than
one line was entered in some way.
Unfortunately, this technique does not work *unless* there is
at least one character other than newline following the one
desired input character. The reason is that the %[ directive
("%*[^\n]" => scan an unlimited length sequence of characters
other than newline, discarding each character scanned) fails
if the number of characters that match the scanset is zero.
In other words, scanning an input stream containing "y\n" puts the
'y' into c, then finds a newline and fails the %[ directive, and
then stops (and scanf() returns 1 -- one successful convert and
assign occurred). The newline remains in the stream. If the stream
contains "yes\n", on the other hand, the %c converts the 'y' as
desired, the %[ skips the 'e' and 's' as desired, than the %*c
discards the newline as desired. (Here scanf() again returns 1.)
The trick is to separate this into *two* scanf() calls:
r1 = scanf("%c%*[^\n]", &c);
r2 = scanf("%*c");
If it ever gets anything at all, the second scanf() just gets one
newline character, so it can be replaced with getchar(). The return
value from the first scanf() should be inspected first, to make
sure that the stream has not already hit end-of-file.
These all have a flaw: if the character stuck into "c" is a newline,
they read one more line, so you actually need *three* scanf() calls:
r1 = scanf("%c", &c);
... check for EOF and newline; if not ...
r2 = scanf("%*[^\n]"); /* read and discard all non-newlines */
if (r2 != EOF)
r3 = scanf("%*c"); /* then read and discard the newline */
A tiny function that calls getchar() in a loop may be more readable
to future programmers:
int get_one_letter_response_on_a_line(void) {
int c, first;
/* get and save the first character */
first = c = getchar();
/* if it was not newline, keep getting more (but stop on EOF) */
while (c != '\n' && c != EOF)
c = getchar();
/* in any case, return the first one, which may be '\n' or EOF */
return first;
}
Now you can just have:
int c;
...
c = get_one_letter_response_on_a_line();
switch (c) {
case 'y': case 'Y': /* handle "yes" */ break;
case 'n': case 'N': /* handle "no" */ break;
case EOF: /* handle EOF */ break;
default: puts("y(es) or n(o), please"); ...
}
for instance.
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
email: forget about it
http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.