switch between writing to file and stdout - c

I want to switch between writing to the file and to the stdout
I can't use fprintf, but only printf and freopen
something like this:
for(size_t i;i<100;++i)
{
if(i%2)
{
freopen("tmp","w",stdout);
printf("%d\n",i);
}
else
{
//return to write to stdout?
printf("%d\n",i);
}
}
How can I return to writing to the stdout?
Update
I write cross-platform application and dup can't be used.

Never use freopen. It cannot achieve what you want, and it's a very dangerous function. If it fails, the only safe thing you can do is immediately terminate the program or ensure that stdout is never accessed again.
There is a way to do what you want on POSIX systems with dup and dup2. It looks something like this:
fflush(stdout);
int old_stdout = dup(1);
int new_stdout = open("whatever", O_WRDONLY|O_CREAT, 0666);
dup2(new_stdout, 1);
close(new_stdout);
/* use new stdout here */
fflush(stdout);
dup2(old_stdout, 1);
close(old_stdout);

You need to dup the file descriptors, and reopen to the open descriptor. Why can't you use fprintf? (Is this homework?)

Related

How to change stdout via program

Program:
#include<stdio.h>
void main()
{
printf("Hello world\n");
}
The above program print the output as "Hello world" in stdout(Terminal). But, I need the output of the program in some other
file like "output.txt". So, is there any way to change the standard output of the process to some other file via programatically.
You don't need all this stdout changing business. Everything you have to do is to open a file and then write to it. Use fopen and fprintf to do it.
You might want to use freopen(3) on stdout but it would close stdout.
You could use dup2(2) like:
int newfd = open("/tmp/someoutput.txt", O_WRONLY|O_CREAT, 0640);
if (newfd<0) {
perror("/tmp/someoutput.txt"); exit(EXIT_FAILURE); };
if (dup2(STDOUT_FILENO, newfd)) {
perror("dup2"); exit(EXIT_FAILURE); }
But as commented by David Heffernan you really want to use redirections in your shell.
IMHO redirecting STDOUT_FILENO like above smells bad.
A possible way might be to declare a global
FILE* myout = stdout;
and use always fprintf(myout, instead of printf( and perhaps sometimes doing myout = fopen("/tmp/someoutput.txt"); with a test!
At least inform the user that you are redirecting his stdout (perhaps by some message to stderr etc...) !
You can make use of fprintf to write in a file .Open file in w or a mode and then use fprintf to write in it .

C restore stdout to terminal

I am working with a multi-thread program.
First I redirect my stdout to a certain file. No problem there (I used dup2(fd, 1) where fd is the file descriptor for the file).
Afterwards, I need to redirect my stdout to the terminal again.
My first approach:
/*Declaration*/
fpost_t stream_sdout;
/*code*/
if ( fgetpos( stdout, &stream_sdout) == -1 )
perror(Error:);
It says illegal seek.
No idea why this is happening.
But if I get this to work, then I only need to use fsetpos(stdout, &stream_stdout) and it should work.
My second idea, was to to copy the stdout using dup2(stdout, 4) to the file descriptor table, at position 4. But that ain't working either.
How can I switch the standard output back to its original destination (terminal, pipe, file, whatever)?
#include <unistd.h>
...
int saved_stdout;
...
/* Save current stdout for use later */
saved_stdout = dup(1);
dup2(my_temporary_stdout_fd, 1);
... do some work on your new stdout ...
/* Restore stdout */
dup2(saved_stdout, 1);
close(saved_stdout);
Before you do the dup2(fd, STDOUT_FILENO), you should save the current open file descriptor for standard output by doing int saved_stdout = dup(STDOUT_FILENO); (letting dup() choose an available file descriptor number for you). Then, after you've finished with the output redirected to a file, you can do dup2(saved_stdout, STDOUT_FILENO) to restore standard output to where it was before you started all this (and you should close saved_stdout too).
You do need to worry about flushing standard I/O streams (fflush(stdout)) at appropriate times as you mess around with this. That means 'before you switch stdout over'.
If the program runs on a Linux environment, you can freopen ("/dev/stdout", "a", stdout).
But if you know that stdout was the terminal, freopen ("/dev/tty", "a", stdout) or the equivalent for other OSs—even Windows.

How to restore standard output's file descriptor?

I need help to understand the file descriptors
So here is my code:
int main()
{
char ch;
close(1);
//now opening a file so that it gets the lowest possible fd i.e. 1
int fd=open("txt",O_RDWR);
//check..
printf("first printtf is executed\n");
scanf("%c",&ch);
printf("ur value is %c\n",ch);
printf("second printf is executed\n");
return 0;
}
in the above program, I tried to redirect the output of printf to the txt file rather than the standard output, i.e. the terminal.
But how to restore the standard output file descriptor so that the printf again works as normal for the second case, i.e the second printtf should give output to the terminal only..
The simplest way to do this would be to duplicate the output descriptor before closing it. You must look at dup.
Before you close it I think you want to dup() it.
When you need it back, you can dup() the dup.
dup will always use the lowest descriptor
int out = dup(1);
close(1);
int fd = open();
...
close(fd);
dup(out);
close(out);
Warning: this is from memory and untested ;-)

How could I temporary redirect stdout to a file in a C program?

Within my C program, I’d like to temporarly redirect stdout to /dev/null (for example). Then,
after writing to /dev/null, I’d like to restore stdout. How do I manage this?
On POSIX systems, you can do it as follows:
int bak, new;
fflush(stdout);
bak = dup(1);
new = open("/dev/null", O_WRONLY);
dup2(new, 1);
close(new);
/* your code here ... */
fflush(stdout);
dup2(bak, 1);
close(bak);
What you want is not possible in further generality.
Any solution using freopen is wrong, as it does not allow you to restore the original stdout. Any solution by assignment to stdout is wrong, as stdout is not an lvalue (it's a macro that expands to an expression of type FILE *).

How to redirect the output back to the screen after freopen("out.txt", "a", stdout)

#include <stdio.h>
int main() {
printf("This goes to screen\n");
freopen("out.txt", "a", stdout);
printf("This goes to out.txt");
freopen("/dev/stdout", "a", stdout);
printf("This should go to screen too, but doesn't\n");
return 0;
}
I call freopen to redirect the stdout to out.txt then I print something on the file, now I want to redirect it back to the screen, but freopen("/dev/stdout", "a", stdout); doesn't work. Is there any way to do that using ANSI C or POSIX system calls?
I can't think of a way to do this in a cross-platform manner, but on GNU/Linux systems (and maybe other POSIX-compliant ones, too) you can freopen ("/dev/tty", "a", stdout). Is this what you were trying to do?
Unfortunately, there doesn't seem to be a good way:
http://c-faq.com/stdio/undofreopen.html
The best recommendation is not to use freopen in this circumstance.
Generally speaking, you can't. You have closed the file, which could've been pipe or whatever. It's not reopenable. You might have saved stdout value, then assign some fopen to it and then close it and copy the old value back. Example:
FILE *o = stdout;
stdout=fopen("/tmp/crap.txt","a");
printf("Oh no!\n");
fclose(stdout);
stdout = o;
Mike Weller suggested below in comments that stdout might not always be writable. In this case something like that might help:
int o = dup(fileno(stdout));
freopen("/tmp/crap.txt","a",stdout);
printf("Oh no!\n");
dup2(o,fileno(stdout));
close(o);
Another edit: if you're using it to redirect output from the child process like your comment elsewhere suggest, you can redirect it after the fork.
Use fdopen() and dup() as well as freopen().
int old_stdout = dup(1); // Preserve original file descriptor for stdout.
FILE *fp1 = freopen("out.txt", "w", stdout); // Open new stdout
...write to stdout... // Use new stdout
FILE *fp2 = fdopen(old_stdout, "w"); // Open old stdout as a stream
...Now, how to get stdout to refer to fp2?
...Under glibc, I believe you can use:
fclose(stdout); // Equivalent to fclose(fp1);
stdout = fp2; // Assign fp2 to stdout
// *stdout = *fp2; // Works on Solaris and MacOS X, might work elsewhere.
close(old_stdout); // Close the file descriptor so pipes work sanely
I'm not sure whether you can do the assignment reliably elsewhere.
Dubious code that does actually work
The code below worked on Solaris 10 and MacOS X 10.6.2 - but I'm not confident that it is reliable. The structure assignment may or may not work with Linux glibc.
#include <stdio.h>
#include <unistd.h>
int main(void)
{
printf("This goes to screen\n");
int old_stdout = dup(1); // Consider dup(STDOUT_FILENO) or dup(fileno(stdout))
FILE *fp1 = freopen("out.txt", "a", stdout);
printf("This goes to out.txt\n");
fclose(stdout);
FILE *fp2 = fdopen(old_stdout, "w");
*stdout = *fp2; // Unreliable!
printf("This should go to screen too, but doesn't\n");
return 0;
}
You can't say you weren't warned — this is playing with fire!
If you're on a system with the /dev/fd file system, you could create the name of the file implied by the file descriptor returned from dup() with sprintf(buffer, "/dev/fd/%d", old_stdout) and then use freopen() with that name. This would be a lot more reliable than the assignment used in this code.
The better solutions either make the code use 'fprintf(fp, ...)' everywhere, or use a cover function that allows you set your own default file pointer:
mprintf.c
#include "mprintf.h"
#include <stdarg.h>
static FILE *default_fp = 0;
void set_default_stream(FILE *fp)
{
default_fp = fp;
}
int mprintf(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
if (default_fp == 0)
default_fp = stdout;
int rv = vfprintf(default_fp, fmt, args);
va_end(args);
return(rv);
}
mprintf.h
#ifndef MPRINTF_H_INCLUDED
#define MPRINTF_H_INCLUDED
#include <stdio.h>
extern void set_default_stream(FILE *fp);
extern int mprintf(const char *fmt, ...);
#endif
Clearly, you can create an mvprintf() and other functions as needed.
Example use of mprintf()
Then, in place of the original code, you can use:
#include "mprintf.h"
int main()
{
mprintf("This goes to screen\n");
FILE *fp1 = fopen("out.txt", "w");
set_default_stream(fp1);
mprintf("This goes to out.txt\n");
fclose(fp1);
set_default_stream(stdout);
mprintf("This should go to screen too, but doesn't\n");
return 0;
}
(Warning: untested code - confidence level too high. Also, all code written assuming you use a C99 compiler, primarily because I declare variables when I first need them, not at the beginning of the function.)
Caution:
Note that if the original program is invoked as ./original_program > file or ./original_program | grep something (with redirected output) or is run from a cron job, then opening /dev/tty is not usually appropriate as a way to reopen standard output because the original standard output was not the terminal.
Also, note that if the redirection of standard output is used prior to forking and execing a child program and the original standard output is reinstated in the parent, then the sequence of operations is wrong. You should fork and then adjust the I/O of the child (only), without modifying the parent's I/O at all.
On Windows, you can open "CONOUT$".
freopen("test.txt", "w", stdout);
printf("this goes to test.txt");
freopen("CONOUT$", "w", stdout);
printf("this goes to the console\n");
This probably doesn't work if stdout is redirected to start with.
The following code (SwapIOB) is used in Testbenches that want to store
the stdout stream for comparison to an expected results file.
Background: File streams are managed using an _IOB structure that is stored in an array of 20 _IOB entries. This includes stdout stream. The IOBs are stored in an array. When a file is created the application code gets a ptr to an element in that array. The application code then passes that ptr to the OS for processing I/O calls. Thus, the OS does NOT itself contain or rely on its own pointers to the application's IOB.
Requirement: When running a testbench the stdout messages issued by an application should be re-directed to a file. However, after the module under test has completed then stdout messages should be re-redirected to the console.
This routine was tested and is currently used on Windows XP/Pro system.
void SwapIOB(FILE *A, FILE *B) {
FILE temp;
// make a copy of IOB A (usually this is "stdout")
memcpy(&temp, A, sizeof(struct _iobuf));
// copy IOB B to A's location, now any output
// sent to A is redirected thru B's IOB.
memcpy(A, B, sizeof(struct _iobuf));
// copy A into B, the swap is complete
memcpy(B, &temp, sizeof(struct _iobuf));
} // end SwapIOB;
Application code uses SwapIOB() similar to:
FILE *fp;
fp = fopen("X", "w");
SwapIOB(stdout, fp);
printf("text to file X");
SwapIOB(stdout, fp);
fclose(fp);
printf("text to console works, again!");

Resources