[comp.lang.c] redirecting output

emf@eleazar.dartmouth.edu (Eric Friets) (06/28/90)

I need to redirect output in the middle of a program
from the standard output to a file.  The use of
fprintf is ruled out because I do not have the
source of the functions whose output I want.

Options that are not acceptable:
1. redirect output of the entire program, as in
	prog > file
2. have the rest of the program write to stderr, and 
then redirect the entire program, as above
3. write the necessary data to a file, and have a
smaller program that redirects to a file

What is really needed is a way to change the pointer
to stdout to a file pointer returned by fopen().  Any
suggestions would be appreciated.  I will summarize and
post responses that are mailed to me.

Eric Friets
emf@eleazar.dartmouth.edu
.

jason@cs.odu.edu (Jason C Austin) (06/29/90)

In article <22931@dartvax.Dartmouth.EDU> emf@eleazar.dartmouth.edu (Eric Friets) writes:
-> 
-> I need to redirect output in the middle of a program
-> from the standard output to a file.  The use of
-> fprintf is ruled out because I do not have the
-> source of the functions whose output I want.
-> 
-> Options that are not acceptable:
-> 1. redirect output of the entire program, as in
-> 	prog > file
-> 2. have the rest of the program write to stderr, and 
-> then redirect the entire program, as above
-> 3. write the necessary data to a file, and have a
-> smaller program that redirects to a file
-> 
-> What is really needed is a way to change the pointer
-> to stdout to a file pointer returned by fopen().  Any
-> suggestions would be appreciated.  I will summarize and
-> post responses that are mailed to me.
-> 
-> Eric Friets
-> emf@eleazar.dartmouth.edu
-> .

	freopen will do the job for you.  In fact the unix manual page
says that this command is mostly used for this purpose.

	freopen( "filename", "w", stdout );

	Anything sent to stdout after this command is executed will go
to filename.  The function returns the previous value of stdout, so
you'll probably want to keep it and restore the value, if you want to
start sending things back to the screen.

	

	
--
Jason C. Austin
jason@cs.odu.edu

scjones@thor (Larry Jones) (06/29/90)

In article <JASON.90Jun28152010@oswine.cs.odu.edu>, jason@cs.odu.edu (Jason C Austin) writes:
> 	freopen( "filename", "w", stdout );
> 
> 	Anything sent to stdout after this command is executed will go
> to filename.  The function returns the previous value of stdout, so
> you'll probably want to keep it and restore the value, if you want to
> start sending things back to the screen.

No, freopen does NOT return the previous value of stdout, it returns
the current value of stdout (which should, I think, be the same).
The old file has been CLOSED, so there is no way to continue sending
data to it without reopening it, which you probably can't do since
you probably don't know its name.

freopen is portable and works fine for a permanent diversion.  For a
temporary diversion, you have to do something system dependent.  On
most unix systems you need to use fileno, dup, and fdopen to make it
all work.
----
Larry Jones                         UUCP: uunet!sdrc!scjones
SDRC                                      scjones@SDRC.UU.NET
2000 Eastman Dr.                    BIX:  ltl
Milford, OH  45150-2789             AT&T: (513) 576-2070
"This probably just goes to show something, but I sure don't know what."
-Calvin

henry@zoo.toronto.edu (Henry Spencer) (06/30/90)

In article <JASON.90Jun28152010@oswine.cs.odu.edu> jason@cs.odu.edu (Jason C Austin) writes:
>	freopen will do the job for you.  In fact the unix manual page
>says that this command is mostly used for this purpose.
>
>	freopen( "filename", "w", stdout );

You have the right idea, but you left something out.  Try this instead:

	#define	FILENAME	"filename"
	if (freopen(FILENAME, "w", stdout) == NULL) {
		fprintf(stderr, "freopen on `%s' failed", FILENAME)
		exit(1);
	}

God is not on your side; such a call *will* fail eventually.  Life is
much more pleasant if your code copes properly.
-- 
"Either NFS must be scrapped or NFS    | Henry Spencer at U of Toronto Zoology
must be changed."  -John K. Ousterhout |  henry@zoo.toronto.edu   utzoo!henry

peter@ficc.ferranti.com (Peter da Silva) (07/02/90)

In article <1990Jun29.172429.2818@zoo.toronto.edu> henry@zoo.toronto.edu (Henry Spencer) writes:
> You have the right idea, but you left something out.  Try this instead:

While picking nits, how about doing it right. There's really no excuse for
not calling perror:

> 	#define	FILENAME	"filename"
> 	if (freopen(FILENAME, "w", stdout) == NULL) {
+		perror(FILENAME);
! 		fprintf(stderr, "Can't re-open standard output -- exiting\n");
> 		exit(1);
> 	}

> God is not on your side; such a call *will* fail eventually.  Life is
> much more pleasant if your code copes properly.

And life is even better if it tells you *why* it fails. If your C runtime
doesn't implement perror, make it. I don't know of any operating system where
you can't at least differentiate between missing files and other errors.

Well, outside the top levels of the orange book, anyway.
-- 
Peter da Silva.   `-_-'
+1 713 274 5180.
<peter@ficc.ferranti.com>

peter@ficc.ferranti.com (Peter da Silva) (07/03/90)

In article <17008@haddock.ima.isc.com> karl@haddock.ima.isc.com (Karl Heuer) writes:
> Technically, there is.

OK, but it's not a *good* excuse.

> The polite action is to set errno iff an error
> occurs, but most non-syscall functions are not guaranteed to be polite.  In
> particular, many implementations of fopen() can fail without setting errno (by
> running out of buffers);

Didn't know about that...

> conversely, an internal call to isatty() may have set
> errno when no error has really occurred.

I knew about this one, but it's not relevant to the problem at hand. It does
mean you can't use perror to tell if an error occurred... just what it was.
-- 
Peter da Silva.   `-_-'
+1 713 274 5180.
<peter@ficc.ferranti.com>: Inappropriate ioctl for device
-- 

henry@zoo.toronto.edu (Henry Spencer) (07/04/90)

In article <JID4B=4@ficc.ferranti.com> peter@ficc.ferranti.com (Peter da Silva) writes:
>While picking nits, how about doing it right. There's really no excuse for
>not calling perror...

Yes there is:  it doesn't do what I want, which is a more informative
message about the high-level nature of the problem.  A major reason why
perror() doesn't get used is that it is simply too inflexible:  it takes
too much extra work to put together a useful message, since that generally
requires assembling an argument string out of pieces.  One often wants
more information than just the filename and the error code.  Something
like the Kernighan&Pike error() function is vastly more useful, but alas,
not everyone has it.  If you're willing to rely on ANSI C facilities (or
imitations of same, e.g. my old strings package), then strerror() can
be used to get much the same effect.
-- 
"Either NFS must be scrapped or NFS    | Henry Spencer at U of Toronto Zoology
must be changed."  -John K. Ousterhout |  henry@zoo.toronto.edu   utzoo!henry

karl@haddock.ima.isc.com (Karl Heuer) (07/04/90)

In article <JID4B=4@ficc.ferranti.com> peter@ficc.ferranti.com (Peter da Silva) writes:
>While picking nits, how about doing it right. There's really no excuse for
>not calling perror:

Technically, there is.  The polite action is to set errno iff an error
occurs, but most non-syscall functions are not guaranteed to be polite.  In
particular, many implementations of fopen() can fail without setting errno (by
running out of buffers); conversely, an internal call to isatty() may have set
errno when no error has really occurred.

Some people maintain that, for this reason, one should not use perror() under
the circumstances we're talking about.  I disagree; even though errno is badly
botched, it's reasonable to use it until something better comes along.  (And I
use a version of isatty() that leaves errno alone.)

Karl W. Z. Heuer (karl@kelp.ima.isc.com or ima!kelp!karl), The Walking Lint

peter@ficc.ferranti.com (Peter da Silva) (07/05/90)

In article <1990Jul3.171151.6137@zoo.toronto.edu> henry@zoo.toronto.edu (Henry Spencer) writes:
> In article <JID4B=4@ficc.ferranti.com> peter@ficc.ferranti.com (Peter da Silva) writes:
> >While picking nits, how about doing it right. There's really no excuse for
> >not calling perror...

> Yes there is:  it doesn't do what I want, which is a more informative
> message about the high-level nature of the problem.

"Can't open %s for reading" does?

> A major reason why
> perror() doesn't get used is that it is simply too inflexible:  it takes
> too much extra work to put together a useful message, since that generally
> requires assembling an argument string out of pieces.

Or simply calling perror and following it with a text description, which is
what I have done in the past in the fow cases a simple perror hasn't been
enough.

Let's face it. Perror isn't perfect, but it's a LOT better than what people
actually use. Strerror will be better, when it becomes widely available, but
a simple call to perror covers most cases.

In any case, there isn't any excuse for using something *worse* than perror.
And there's no excuse for cat(1) still not using perror in System V.3.2.
-- 
Peter da Silva.   `-_-'
+1 713 274 5180.
<peter@ficc.ferranti.com>

emf@eleazar.dartmouth.edu (Eric Friets) (07/27/90)

A while ago I posted a request concerning redirecting
output in midprogram.  Thanks for the many responses;
the only workable one (received from a few netters) 
looks something like this: (the key is the dup2...)

int fdstdout,fdplot;

fflush(stdout);
fdplot=fopen("plot.out",O_WRONLY|O_CREAT,0644);
fdstdout=dup(1);
dup2(fdplot,1);
...
...
...
fflush(&_iob[fdplot]);
dup2(fdstdout,1);
close(fdplot);
close(fdstdout);

This works, but has a small glitch.  When unredirecting the
output (ie, sending to stdout instead of the file), a few
characters at the end of the file are corrupted.  Running
the program without this redirection results in the correct
output.  I tried pausing the program for a few seconds before
unredirecting, but this had no effect.

The computer is a SUN 3/160, running under the UNIX operating system.

Thanks,
Eric Friets
emf@eleazar.dartmouth.edu
.