From: Eric Sosman on
On 2/28/2010 6:16 PM, Poster Matt wrote:
> [...]
> int GetUserConfirmation(void)
> {
> printf("\nAre all the settings and options correct?\n" \
> "Do you want to proceed? (Y = Yes, N = No): ");
>
> // Was using:
> //char c = (char) getchar();
>
> // Now using - has the same effect.
> int c = getchar();

Elsewhere you've ensured that stdin takes data from
something that is not a tty (you're assuming it's reading
from a file, but it might be a socket or a pipe or some
such -- but in any case, it is *not* reading the keyboard).

For ten points: From what stream does getchar() read
its character?

For ten more points: If getchar()'s input stream is not
reading from a keyboard, can getchar() read from a keyboard?

For yet another ten points (and and a share of the lead):
What does getchar() return if it cannot obtain a character
from its input stream?

For still another ten points (and sole possession of
first place!): Does getchar() *always* return an input
character?

For ONE HUNDRED POINTS (and an Olympic gold medal): Is
the comp.lang.c Frequently Asked Questions (FAQ) list at
<http://www.c-faq.com/> in your bookmarks list?

--
Eric Sosman
esosman(a)ieee-dot-org.invalid
From: yooooooooooooo on
On Mar 1, 5:56 am, Poster Matt <postermatt(a)no_spam_for_me.org> wrote:
> Hi,
>
> My code allows a user to redirect a file to stdin so that some text data can be
> read, no problem.
>
> Later a user confirmation to proceed is requested, using getchar(). This is not
> working because of what's left in stdin.
>
> Initially I was actually stopping reading stdin when some specific data being
> searched for was located, ignoring what was left in stdin. When I realized what
> was happening, I made sure I continued reading stdin all the way through.
>
> The problem seems to be that my user confirmation call to getchar() receives the
> following char: 'ÿ'. I looked in the ASCII table and it is the final char, 255
> or FF. But I have no idea what this is or why it's there.
>
> I've tried reading stdin through to the end with fgets...
>
> while (fgets(buffer, maxLineLen, stdin) != NULL)
>      check line for what I want;
>
> ...and also with scanf (just reading %s):
>
> while (scanf("%s", buffer) != EOF)
>      check line for what I want;
>
> but I always the get the 'ÿ' char when it comes to my user confirmation..
>
> The faq suggests trying the following code:
>
> while((c = getchar()) != '\n' && c != EOF)
>      /* discard */ ;
>
> No luck, I still get 'ÿ'.
>
> I even tried calling fgets and scanf immediately before calling getchar and
> printfing what was got - but there is nothing to printf - and yet 'ÿ' is still
> there to sabotage the call to getchar().
>
> Even though the faq warns against it, I even tried fflush(stdin). Nope. :(
>
> What is this little fellow, 'ÿ'. Why's it there? How can I get rid of it?
>
> I should mention that if I do not redirect a file to stdin on the command line,
> the user confirmation works fine, no sign at all of 'ÿ'.
>
> Many thanks.

I assume that EOF is usually implemented as -1 of int type. This may
be the key point. Hope this can help you.
From: Poster Matt on
Thanks for replying Eric and forcing me to follow a logical problem resolution
process.

Eric Sosman wrote:
>
> For ten points: From what stream does getchar() read
> its character?

stdin - Score: 10.

> For ten more points: If getchar()'s input stream is not
> reading from a keyboard, can getchar() read from a keyboard?

No - Score: 20.

> For yet another ten points (and and a share of the lead):
> What does getchar() return if it cannot obtain a character
> from its input stream?

EOF, on my system that equates to char 'ÿ' (BINGO!). Score 30.

> For still another ten points (and sole possession of
> first place!): Does getchar() *always* return an input
> character?

No - Score: 40.

> For ONE HUNDRED POINTS (and an Olympic gold medal): Is
> the comp.lang.c Frequently Asked Questions (FAQ) list at
> <http://www.c-faq.com/> in your bookmarks list?

Yes - Score 140 + Olympic Gold, in an event with no other competitors. :)

> Elsewhere you've ensured that stdin takes data from
> something that is not a tty (you're assuming it's reading
> from a file, but it might be a socket or a pipe or some
> such -- but in any case, it is *not* reading the keyboard).

Agreed, but I have not done that explicitly in my code. I've investigated what's
happening with ttyname.

"The ttyname() function returns a pointer to a string containing a
null-terminated pathname of the terminal associated with file descriptor fildes."

If I make this call in the program:

ttyname((fileno(stdin)));

having run my program with a file redirected to stdin on the command line IE.
'program < file.txt' then NULL is returned by ttyname - stdin is not a terminal
device.

If there's no file redirected on the command line then /dev/pts/6 is returned by
ttyname - that must be the terminal through which a user's key input can be read.

I didn't fully understand how stdin worked, assuming, without understanding,
that stdin would be fed a file redirected from the command line and then revert
to a terminal device once there's no more input from the redirected file.

The problem is now how do I achieve that behaviour? When the program starts,
check if there's been a file redirected from the command line, if so read that
file storing relevant data, then -either way- make sure I can read a character
entered by the user from the terminal/keyboard to give confirmation that
proceeding is ok?

I've got a much better understanding of stdin now, but for the life of me can't
work out how to do this.

Thanks and regards, and apologies for my amateurishness.
From: Ben Bacarisse on
Poster Matt <postermatt(a)no_spam_for_me.org> writes:

> Eric Sosman wrote:
<snip>
>> For yet another ten points (and and a share of the lead):
>> What does getchar() return if it cannot obtain a character
>> from its input stream?
>
> EOF, on my system that equates to char 'ÿ' (BINGO!).

This "equates to" hides too many details to leave it like that. It
may be true that EOF == 'ÿ' but when getchar returns a character from
its stream, the character has been converted to an unsigned char and
it is that value that forms the int returned by getchar. As a result

getchar() == EOF

can not be made to be true by reading a 'ÿ' from the input. This is
why the result of getchar should be stored in an int rather than a
char variable. Using a char variable throws away this extra
information -- the distinction between a valid input character (always
positive) and EOF (some negative int).

I sounds like you've "got" this. I add it simply in case someone
reading this concludes that, on some systems, 'ÿ' can't be
distinguished from EOF on input.

<snip>
--
Ben.
From: Poster Matt on
Poster Matt wrote:
> Thanks for replying Eric and forcing me to follow a logical problem
> resolution process.
>
> Eric Sosman wrote:
>>
>> For ten points: From what stream does getchar() read
>> its character?
>
> stdin - Score: 10.
>
>> For ten more points: If getchar()'s input stream is not
>> reading from a keyboard, can getchar() read from a keyboard?
>
> No - Score: 20.
>
>> For yet another ten points (and and a share of the lead):
>> What does getchar() return if it cannot obtain a character
>> from its input stream?
>
> EOF, on my system that equates to char 'ÿ' (BINGO!). Score 30.
>
>> For still another ten points (and sole possession of
>> first place!): Does getchar() *always* return an input
>> character?
>
> No - Score: 40.
>
>> For ONE HUNDRED POINTS (and an Olympic gold medal): Is
>> the comp.lang.c Frequently Asked Questions (FAQ) list at
>> <http://www.c-faq.com/> in your bookmarks list?
>
> Yes - Score 140 + Olympic Gold, in an event with no other competitors. :)
>
> > Elsewhere you've ensured that stdin takes data from
> > something that is not a tty (you're assuming it's reading
> > from a file, but it might be a socket or a pipe or some
> > such -- but in any case, it is *not* reading the keyboard).
>
> Agreed, but I have not done that explicitly in my code. I've
> investigated what's happening with ttyname.
>
> "The ttyname() function returns a pointer to a string containing a
> null-terminated pathname of the terminal associated with file descriptor
> fildes."
>
> If I make this call in the program:
>
> ttyname((fileno(stdin)));
>
> having run my program with a file redirected to stdin on the command
> line IE. 'program < file.txt' then NULL is returned by ttyname - stdin
> is not a terminal device.
>
> If there's no file redirected on the command line then /dev/pts/6 is
> returned by ttyname - that must be the terminal through which a user's
> key input can be read.
>
> I didn't fully understand how stdin worked, assuming, without
> understanding, that stdin would be fed a file redirected from the
> command line and then revert to a terminal device once there's no more
> input from the redirected file.
>
> The problem is now how do I achieve that behaviour? When the program
> starts, check if there's been a file redirected from the command line,
> if so read that file storing relevant data, then -either way- make sure
> I can read a character entered by the user from the terminal/keyboard to
> give confirmation that proceeding is ok?
>
> I've got a much better understanding of stdin now, but for the life of
> me can't work out how to do this.
>
> Thanks and regards, and apologies for my amateurishness.

Ok sorry, it is in the faq:

http://www.c-faq.com/stdio/devtty.html

Is reading the file '/dev/tty' as keyboard input guaranteed on all Unix/Linux
systems?

Thanks again everyone. It's working. Pheww! :)