Redirection question

Steve Summit scs at adam.mit.edu
Fri Nov 16 13:22:51 AEST 1990


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

In article <roarment.658423394 at faui09> roarment at 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 at ericsson.se> epames at 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 at smoke.brl.mil> gwyn at 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 at adam.mit.edu



More information about the Comp.lang.c mailing list