[comp.lang.c] Redirection question

roarment@faui09.informatik.uni-erlangen.de (Roberto Armenti) (11/12/90)

Hi net-people,

perhaps someone out there can help me.

Is there a _portable_ way to recognize whether input comes from
stdin or from another stream ?
To make the problem clearer : i'm working on a programm that takes
its input from stdin. If however someone chooses to redirect the input
to a file, so that data is read from that file, how can I figure that
out ( Prompting and so on should not occur in this case ) ???

The solution should at least work on UNIX _AND_ MS-DOS, so i'm looking for
a _portable_ implementation.
Help out there ?
	Thanks in advance
		Roberto




--
please contact ( no commercials please )
* Roberto Armenti    *   Voice   *  For E-Mail                  * On IRC
* Wielandstrasse 6   *   0841/   *  roarment@faui09.informatik. * madguitar
* 8070 Ingolstadt    *   52126   *  uni-erlangen.de             * or just mad

gwyn@smoke.brl.mil (Doug Gwyn) (11/13/90)

In article <roarment.658423394@faui09> roarment@faui09.informatik.uni-erlangen.de (Roberto Armenti) writes:
>Is there a _portable_ way to recognize whether input comes from
>stdin or from another stream ?

Wrong question.  It comes from stdin if you're reading it from the
stdin stream.

>To make the problem clearer : i'm working on a programm that takes
>its input from stdin. If however someone chooses to redirect the input
>to a file, so that data is read from that file, how can I figure that
>out ( Prompting and so on should not occur in this case ) ???

What you really want to determine is whether or not input is coming
from an interactive device.  This is in general impossible to
ascertain.  The usual UNIX kludge is to invoke isatty(fileno(stdin));
I don't know whether or not MS/DOS has something equivalent.  Anyway,
it is not a reliable test, since just because something is coming via
a terminal port does not necessarily mean that there is a human typing
the input.  You should probably use a command option to determine how
prompting should be done, if at all.  (One approach is to not prompt
initially, but support an input command that enables/disables
prompting; the UNIX System V "ed" uses this method.)

epames@eos.ericsson.se (Michael Salmon) (11/13/90)

In article <roarment.658423394@faui09> roarment@faui09.informatik.uni-erlangen.de
(Roberto Armenti) writes:
>Is there a _portable_ way to recognize whether input comes from
>stdin or from another stream ?
>
>The solution should at least work on UNIX _AND_ MS-DOS, so i'm looking for
>a _portable_ implementation.

isatty(fileno(stdin)) should do what you want. I have seen it implemented
on Unix, MS_DOS and CP/M systems but I can't say how portable it is.
I also find it very handy to determine when to give a usage message
when file names are omitted from the command line, I hate programmes
that do nothing when I make a mistake.

Michael Salmon
L.M.Ericsson
Stockholm

brianh@hpcvia.CV.HP.COM (brian_helterline) (11/14/90)

>Hi net-people,

>perhaps someone out there can help me.

>Is there a _portable_ way to recognize whether input comes from
>stdin or from another stream ?
>To make the problem clearer : i'm working on a programm that takes
>its input from stdin. If however someone chooses to redirect the input
>to a file, so that data is read from that file, how can I figure that
>out ( Prompting and so on should not occur in this case ) ???
	
	Check out isatty()

>The solution should at least work on UNIX _AND_ MS-DOS, so i'm looking for
>a _portable_ implementation.
>Help out there ?
>	Thanks in advance
>		Roberto




--
please contact ( no commercials please )
* Roberto Armenti    *   Voice   *  For E-Mail                  * On IRC
* Wielandstrasse 6   *   0841/   *  roarment@faui09.informatik. * madguitar
* 8070 Ingolstadt    *   52126   *  uni-erlangen.de             * or just mad
----------

darcy@druid.uucp (D'Arcy J.M. Cain) (11/14/90)

In article <14447@smoke.brl.mil> gwyn@smoke.brl.mil (Doug Gwyn) writes:
>What you really want to determine is whether or not input is coming
>from an interactive device.  This is in general impossible to
>ascertain.  The usual UNIX kludge is to invoke isatty(fileno(stdin));
>I don't know whether or not MS/DOS has something equivalent.  Anyway,
>it is not a reliable test, since just because something is coming via
>a terminal port does not necessarily mean that there is a human typing
>the input.  You should probably use a command option to determine how
>prompting should be done, if at all.  (One approach is to not prompt
>initially, but support an input command that enables/disables
>prompting; the UNIX System V "ed" uses this method.)

How about this for a kludge?  Have an input routine that takes a prompt
and a buffer argument and checks to see if there are characters waiting.
If not then issue the prompt.  as long as there are characters then you
just read.  If there is a human waiting for a prompt then you issue one.
If necessary you can add timing stuff so that slow terminals with stuff
in the pipe don't trigger the prompt.  Maybe I'll write this and post it
if I get a little time.

-- 
D'Arcy J.M. Cain (darcy@druid)     |
D'Arcy Cain Consulting             |   I support gun control.
West Hill, Ontario, Canada         |   Let's start with the government!
+ 416 281 6094                     |

aquesada@mtecv2.mty.itesm.mx (11/15/90)

From: roarment@faui09.informatik.uni-erlangen.de (Roberto Armenti)
Message-ID: <roarment.658423394@faui09>

>Hi net-people,
> 
> perhaps someone out there can help me.
> 
> Is there a _portable_ way to recognize whether input comes from
> stdin or from another stream ?
> To make the problem clearer : i'm working on a programm that takes
> its input from stdin. If however someone chooses to redirect the input
> to a file, so that data is read from that file, how can I figure that
> out ( Prompting and so on should not occur in this case ) ???
> 
> The solution should at least work on UNIX _AND_ MS-DOS, so i'm looking for
> a _portable_ implementation.
> Help out there ?
> 	Thanks in advance
> 		Roberto
> 
> 
> 
> 
>    
      Try this, it ran under both MSDOS and Ultrix. Sorry i don't give
 a longer explanation but i'm in a rush.

                 ************************************
#include <stdio.h>

FILE *entrada={stdin};
char linea[255];

main(argc,argv)
char *argv[];
{
    if(argc>1)
         {
           if((entrada=fopen(argv[1],"r"))==NULL)
                 puts("file not found"),exit(1);
           printf("Reading from file: %s\n",argv[1]);
/* In here goes any other code you need to execute when reading from a file */
         }
     while(!feof(entrada))
           {
          fgets(linea,255,entrada);
          puts(linea);
           }
}


  *************************************
From Monterrey, Mexico:
Antonio Quesada Duarte
aquesada@mtecv2.mty.itesm.mx
 

weimer@ssd.kodak.com (Gary Weimer) (11/15/90)

In article <1990Nov14.150228.4038@druid.uucp> darcy@druid.uucp (D'Arcy J.M. Cain) writes:
>
>How about this for a kludge?  Have an input routine that takes a prompt
>and a buffer argument and checks to see if there are characters waiting.
>If not then issue the prompt.  as long as there are characters then you
>just read.  If there is a human waiting for a prompt then you issue one.
>If necessary you can add timing stuff so that slow terminals with stuff
>in the pipe don't trigger the prompt.  Maybe I'll write this and post it
>if I get a little time.

This won't work if the program you are piping from runs slower than the
program you are piping to (i.e. a spell checker piped through cat). The
second program will always be waiting for the first.

dhesi%cirrusl@oliveb.ATC.olivetti.com (Rahul Dhesi) (11/16/90)

>>Is there a _portable_ way to recognize whether input comes from
>>stdin or from another stream ?

Absolutely none!

But isatty(fd) works reasonably well on many systems.  Beware of just
doing a single test, however (which you may have been thinking of doing
after seeing some other postings).  You might want to do it like this:

    if (isatty(fileno(stdin)) && isatty(fileno(stdout))) {
       ... interactive code ...
    } else {
       ... noninteractive code ...
    }

This way you don't print a prompt to the output stream unless it's
connected to a tty, and you don't print a prompt unless the input is
coming from a tty.  You can also explicitly open /dev/tty to print the
prompt, but that's much less portable than isatty() alone.
--
Rahul Dhesi <dhesi%cirrusl@oliveb.ATC.olivetti.com>
UUCP:  oliveb!cirrusl!dhesi

scs@adam.mit.edu (Steve Summit) (11/16/90)

[I've included comp.unix.programmer since this is a bit of a
tutorial which gets fairly Unix-specific...]

In article <roarment.658423394@faui09> roarment@faui09.informatik.uni-erlangen.de (Roberto Armenti) writes:
>i'm working on a programm that takes
>its input from stdin. If however someone chooses to redirect the input
>to a file, so that data is read from that file, how can I figure that
>out ( Prompting and so on should not occur in this case ) ???

In article <1990Nov13.073315.2831@ericsson.se> epames@eos.ericsson.se writes:
>isatty(fileno(stdin)) should do what you want. I have seen it implemented
>on Unix, MS_DOS and CP/M systems but I can't say how portable it is.

Correct (but see below for one addition).  (Notwithstanding my
crosspost to comp.unix, isatty does indeed exist on non-Unix
systems.)

>I also find it very handy to determine when to give a usage message
>when file names are omitted from the command line, I hate programmes
>that do nothing when I make a mistake.

Excellent!  I hit upon this maneuver myself just last week.  The
implication may not be obvious, so it deserves some explication.

Many, many utilities which follow the "everything's a text
stream" model usefully read from their standard input if they are
invoked without explicit input filenames on their invocation
command line.  That is, the code looks something like this:

	#include <stdio.h>

	main(argc, argv)
	int argc;
	char *argv[];
	{
	if(argc <= 1)
		process(stdin, "standard input");
	else	{
		int argi;
		for(argi = 1; argi < argc; argi++)
			{
			FILE *ifd = fopen(argv[argi], "r");
			if(ifd == NULL)
				perror(argv[argi]);
			else	{
				process(ifd, argv[argi]);
				(void)fclose(ifd);
				}
			}
		}

	exit(0);
	}

The problem is that when you've forgotten what the thing is or
how it works or what option flags it takes, you can't just invoke
it with no arguments and get a usage message.  Therefore, a
useful wrinkle is

	if(argc <= 1)
		{
		if(isatty(fileno(stdin)))
			{
			fprintf(stderr, "usage: ...\n");
			exit(1);
			}

		process(stdin);
		}

The one drawback here is that the "expert" user now can't type
in raw input directly.  (Does the Unix beginner/novice/expert
hierarchy include "creates programs with `/lib/ccom | as'"?)
If easily-accessible usage messages are more important to you
than coddling gurus, just tell the gurus to use

	cat | yourprogram

which will let them type away.  (Note that one program which
therefore _can't_ receive this treatment is cat itself, which is
fine, since you also want to leave cat > file working as expected,
although it could again be argued that this is guru-coddling :-) .)

In article <14447@smoke.brl.mil> gwyn@smoke.brl.mil (Doug Gwyn) writes:
>What you really want to determine is whether or not input is coming
>from an interactive device.
>The usual UNIX kludge is to invoke isatty(fileno(stdin));
>it is not a reliable test, since just because something is coming via
>a terminal port does not necessarily mean that there is a human typing
>the input.

Kludge?  I doubt this is much of a problem in practice;
presumably non-humans (i.e. programs) which have gone to the
trouble to talk to another program through a tty or pty are
clever enough (and, I should think, rare enough) that they can
figure out how to deal with prompts.%%

A somewhat bigger problem than noninteractive tty's is the case
when stdin is not a tty, but is interactive.  Have you (not Doug;
I'm just being didactic) ever wondered why /bin/sh has a -i flag?
This tells it to be interactive and issue prompts, even when
isatty(0) fails.  You need this when you're typing at a shell
through a pipe or something, which is admittedly rare, but it
does happen.  (One example, from BSD Unix, is

	rsh machine sh -i

which is a quick-and-dirty rlogin, without .profile/.login
overhead, but which uses sockets rather than pty's, so you need
-i if you want prompts.  A contrived but perhaps more appreciable
example would be something like

	dd conv=lcase | sh -i

when your caps lock key is stuck and you don't know about stty
lcase, although how you'd type it is another question :-) ...)

%% I do not mean to imply that ignoring prompts is easy for a
program to do; in fact, it's surprisingly hard.  But I'd rather
that programs attempt to be useful to large numbers of users, by
using isatty if necessary even if it's imperfect, than that they
worry about the occasional non-human-but-on-a-tty "user."  And,
before someone gives me a lecture on the importance, in the
toolkit model, of programs' being invokable by other programs,
remember that the vast majority of them do so through pipes or
files.  (In fact, I could give quite a lecture on the importance
of programs' being invokable by other programs, and the way it's
being forgotten in the rush towards highly interactive,
graphical, mouse-based applications, but that's another article.)

                                            Steve Summit
                                            scs@adam.mit.edu