[comp.lang.c] I/O redirection

wkaufman@oracle.oracle.com (William P. Kaufman) (04/06/90)

In article <1990Apr2.144841.12905@mentor.com> swhitchurch@mentor.com (Steve Whitchurch) writes:
>Hi;
>
>I have a question: I need to change or redirect "stdout" from inside
>a C function. What I want to do is capture the output of a printf and
>put the results into a file. so it would go something like this:
>
> redirect_stdout ();
> call_function_that_prints_to_stdout ();
> reset_stdout ();
>

Oooo, ugly.  There is a way, but it's thouroughly machine-depedent.  What you
can do is:
	freopen(file, "w", stdout);
	function..();
	freopen("/dev/ttyXX", "w", stdout);
for a UNIX machine, assuming you know what terminal you're on,...or,...

Much easier is:
	FILE *out_fp = stdout;

	out_fp = fopen(new_file, "w");
	call_function_that_prints_to_out_fp();
	out_fp = stdout;
and change all your code from
	printf(...);
ro
	fprintf(out_fp, ...);
and put in some error checking.  _That's_ portable (modulo file-naming
conventions), you don't need to know your terminal, etc., etc.  Granted, it
won't work on procedures you can't control (say, perror()), but I hope it's
good enough for you.

Happy hunting,....
				-- Bill Kaufman

darcy@druid.uucp (D'Arcy J.M. Cain) (04/07/90)

In article <1990Apr2.144841.12905@mentor.com> swhitchurch@mentor.com (Steve Whitchurch) writes:
>Hi;
>
>I have a question: I need to change or redirect "stdout" from inside
>a C function. What I want to do is capture the output of a printf and
>put the results into a file. so it would go something like this:
>
> redirect_stdout ();
> call_function_that_prints_to_stdout ();
> reset_stdout ();
>
> Is there a way in C that I can do this ?????????? Change where stdout
> goes ???????

It's even easier than you think.  Use fprintf (see printf(3S))

-- 
D'Arcy J.M. Cain (darcy@druid)     |   Government:
D'Arcy Cain Consulting             |   Organized crime with an attitude
West Hill, Ontario, Canada         |
(416) 281-6094                     |

levy@cbnewsc.ATT.COM (Daniel R. Levy) (04/11/90)

In article <1418@quando.UUCP>, cmueller@quando.UUCP (Christoph Mueller) writes:
< In article <1990Apr2.144841.12905@mentor.com> swhitchurch@mentor.com (Steve Whitchurch) writes:
< >I have a question: I need to change or redirect "stdout" from inside
< >a C function. What I want to do is capture the output of a printf and
< >put the results into a file. so it would go something like this:
< > redirect_stdout ();
< > call_function_that_prints_to_stdout ();
< > reset_stdout ();

< #include <stdio.h>
< static int filedescr;
< int redirect_stdout (filename)
< char *filename;
< {
< 	filedescr = dup (1);
< 	if (freopen (filename, "w", stdout) == (FILE *) 0)
< 	{
< 		return (-1); /* redirection failed */
< 	}
< 	else
< 	{
< 		return (0);  /* OK! */
< 	}
< }
< void reset_stdout ()
< {
	/*
< 	fclose (stdout);
	^^^^^^^^^^^^^^^^

	It is unsafe to use stdout after fclose()'ing it.  Better to
	*/

	fflush(stdout);
	close(1);

	/*
	You may want to be sure fd 0 is open first.  Maybe the program
	closed it somewhere along the line; you're OK if it was closed when
	the program started, because "filedescr" will be fd 0 in that event.
	Otherwise, the dup() will return fd 0, and stdio writes to "stdout"
	will go to a still-closed fd 1.
	*/

	{
#include <sys/types.h>	/* O.K., this should be at the top of the file, but */
#include <sys/stat.h>	/* it is more self-explanatory here <yes it works> */
	struct stat s;
	int fd0_open;
	if (!(fd0_open=(fstat(0,&s)==0))) open("/dev/null",0);
< 	dup (filedescr);
	if (fd0_open) close(0);
	}
< }
< main ()
< {
< 	char file [80];
< 	strcpy (file, "/tmp/out");
	/*
< 	redirect (file);

	Presumably redirect_stdout() was intended
	*/

	redirect_stdout(file);

< 	printf ("This will be written into a file.\n");
< 	reset_stdout ();
< 	printf ("This will be written to stdout.\n");
< }
-- 
Daniel R. Levy                     >>> God: just say "yes" <<<
AT&T Bell Laboratories     UNIX(R) mail:  att!ttbcad!levy, att!cbnewsc!levy
5555 West Touhy Avenue     Any opinions expressed in the message above are
Skokie, Illinois  60077    mine, and not necessarily AT&T's.