From: Poster Matt on
Ben Bacarisse wrote:
> Poster Matt <postermatt(a)no_spam_for_me.org> writes:
>
>> 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.

Yes, I had got that. What I should have said is that on my system when printing
EOF cast as a char, 'ÿ' is displayed.

Cheers.
From: Eric Sosman on
On 3/1/2010 9:16 AM, Poster Matt wrote:
> [... getchar() for user input when stdin comes from a 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.

The important point is that stdin is *one* stream, reading
from *one* source of data. If you've got two different data
sources -- a file plus a keyboard (or whatever), you can't use
the same stream for both of them.

Well, actually, you can -- but not at the same time, or in
the same "incarnation." There's freopen(), which allows you to
reassign stdin (or another stream) at will, so you could use
stdin to read your file, then reassign it and re-use it to read
from /dev/tty. Or you could open an independent stream on
/dev/tty and read from that. This is, however, quite often a
Bad Idea: It means your program cannot be used non-interactively,
as in `echo y | program' or even `yes | program' -- and the
inability to do such things raises barriers to use by scripts
or in daemons and so on.

I think you need to take a step backward and ponder why you
need interactive confirmation. Is your program about to start
a potentially dangerous or expensive operation? If not, you
might be better off just letting it run. Or you might skip the
confirmation step if you can tell you're running non-interactively
(isatty() is a reasonable starting point, but "The device is some
kind of tty" is not exactly the same thing as "A user is watching
over me"). Solidify your requirements; decide what you really
need/want to do.

--
Eric Sosman
esosman(a)ieee-dot-org.invalid
From: Poster Matt on
Eric Sosman wrote:
> On 3/1/2010 9:16 AM, Poster Matt wrote:
>> [... getchar() for user input when stdin comes from a 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.
>
> The important point is that stdin is *one* stream, reading
> from *one* source of data. If you've got two different data
> sources -- a file plus a keyboard (or whatever), you can't use
> the same stream for both of them.
>
> Well, actually, you can -- but not at the same time, or in
> the same "incarnation." There's freopen(), which allows you to
> reassign stdin (or another stream) at will, so you could use
> stdin to read your file, then reassign it and re-use it to read
> from /dev/tty. Or you could open an independent stream on
> /dev/tty and read from that. This is, however, quite often a
> Bad Idea: It means your program cannot be used non-interactively,
> as in `echo y | program' or even `yes | program' -- and the
> inability to do such things raises barriers to use by scripts
> or in daemons and so on.
>
> I think you need to take a step backward and ponder why you
> need interactive confirmation. Is your program about to start
> a potentially dangerous or expensive operation? If not, you
> might be better off just letting it run. Or you might skip the
> confirmation step if you can tell you're running non-interactively
> (isatty() is a reasonable starting point, but "The device is some
> kind of tty" is not exactly the same thing as "A user is watching
> over me"). Solidify your requirements; decide what you really
> need/want to do.

Thanks for the further explanation, appreciated.

I require user confirmation for two reasons. Firstly the command line switches
are extensive, 25 at the moment, so easy for a user to omit one by accident. So
the program outputs a message stating exactly what will take place. Secondly the
operations performed are potentially time consuming, possibly as much as 15-20
minutes on my system. So the user will waste time if the command line is wrong,
or be forced to use a dirty exit.

For script use or for a seasoned user, there's already a 'bypass confirmation'
switch.

Here's what I'm now doing to be able to (possibly) read a file from stdin that's
been redirected on the command line, and to get user confirmation:

if (isatty(fileno(stdin)) == 0)
stdin is not a terminal device - search stdin for the expected data.

then later when getting the user confirmation:

int c;

// stdin is a terminal device, read a character from stdin.
if (isatty(fileno(stdin)) == 1)
c = getchar();

// stdin is not a terminal device, open '/dev/tty'.
else
{
FILE* fp = fopen("/dev/tty", "r");
if (fp == NULL)
{
strcpy(errMsg, ErrOpeningDevTty);
return false;
}

c = fgetc(fp);
fclose(fp);
}

How does that look?

By the way is reading '/dev/tty' as keyboard input guaranteed on all Unix/Linux
systems?

Many thanks again, regards,

Matt
From: Eric Sosman on
On 3/1/2010 11:49 AM, Poster Matt wrote:
> [...]
> By the way is reading '/dev/tty' as keyboard input guaranteed on all
> Unix/Linux systems?

Yes, sort of. /dev/tty is (an alias for) the process'
"controlling terminal." That device might be a tty with a
keyboard, or a pty, or a serial line with unknown gadgetry
at the far end, or ... It's Unix' notion of a device that
someone/something can use to "control" the process.

However, a process might have no "controlling terminal"
at all; this is quite commonly the case for daemons, and can
also be true for other processes. So in that sense, No: the
existence of /dev/tty is not guaranteed. (Off-hand, I don't
recall whether an attempt to open /dev/tty when there's no
controlling terminal simply fails, or opens /dev/null instead;
look it up for yourself.) In any event, there do exist Unix
processes that are not associated with any interactive devices
at all -- which would make "user confirmation" difficult ...


--
Eric Sosman
esosman(a)ieee-dot-org.invalid
From: Barry Margolin on
In article <d%Pin.46118$Ym4.7352(a)text.news.virginmedia.com>,
Poster Matt <postermatt(a)no_spam_for_me.org> wrote:

> 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?

If you want stdin to revert to its previous value when the end of the
file is reached, you can invoke your program as follows:

cat filename - | program

Supplying a filename of "-" to cat refers to cat's stdin.

However, if your program reads to EOF, and then expects to read the
answer to a question from the user, the above won't work, because your
program won't see EOF when the end of the file is reached.

--
Barry Margolin, barmar(a)alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***
*** PLEASE don't copy me on replies, I'll read them in the group ***