How do I suppress output while using a dynamic library? - c

I actually have a solution to this problem, but I'm wondering if there is a slicker one.
I have the need to load in a library to my utility using dlopen and then call one of the functions.
Unfortunately, the function spews a whole bunch of information out onto STDOUT and this I do not want.
I have a solution that is non-portable and I'm wondering if there's a better, more generic solution that I could use.
Here's what I have (NB: This is C) :
/*
* Structure for retaining information about a stream, sufficient to
* recreate that stream later on
*/
struct stream_info {
int fd;
fpos_t pos;
};
#define STDOUT_INFO 0
#define STDERR_INFO 1
struct stream_info s_info[2];
point_stream_to_null(stdout, &s_info[STDOUT_INFO]);
point_stream_to_null(stderr, &s_info[STDERR_INFO]);
void *output = noisy_function();
reset_stream(stderr, &s_info[STDERR_INFO]);
reset_stream(stdout, &s_info[STDOUT_INFO]);
/*
* Redirects a stream to null and retains sufficient information to restore the stream to its original location
*** NB ***
* Not Portable
*/
void point_stream_to_null(FILE *stream, struct stream_info *info) {
fflush(stream);
fgetpos(stream, &(info->pos));
info->fd = dup(fileno(stream));
freopen("/dev/null", "w", stream);
}
/*
* Resets a stream to its original location using the info provided
*/
void reset_stream(FILE *stream, struct stream_info *info) {
fflush(stream);
dup2(info->fd, fileno(stream));
close(info->fd);
clearerr(stream);
fsetpos(stream, &(info->pos));
}
Any suggestions?

I have a suggestion, which lets you use the preprocessor for portability, or perhaps "portability".
If you try something like
#if defined __unix__
#define DEVNULL "/dev/null"
#elif defined _WIN32
#define DEVNULL "nul"
#endif
(ignoring other OSes, else case, error directive, etc.)
and then reopen the file as before
FILE *myfile = freopen(DEVNULL, "w", stream);
then that may give you what you want.
I haven't tried this at home, though. The "nul" file exists; see /dev/null in Windows. And you can get predefined macros at "Pre-defined C/C++ Compiler Macros".

You could try using setvbuf to set stdout to have a very large buffer and be fully buffered. Then, after every call to noisy_function, clear out the buffer before flushing it to the stream. I think this invokes undefined behavior though.
Another way would be to redirect stdout to a temp file, like with this macro function.
#include <stdio.h>
#define QUIET_CALL(noisy) { \
FILE* tmp = stdout;\
stdout = tmpfile();\
(noisy);\
fclose(stdout);\
stdout = tmp;\
}
int main(){
QUIET_CALL(printf("blah blah"));
printf("bloo bloo\n");
return 0;
}

For Windows console applications:
freopen("NUL", "w", stdout); // redirect stdout to the windows version of /dev/null
NoisyDllFunction();
freopen("CON", "w", stdout); // redirect stdout back to the console
Worked for me.

In Windows you can redirect streams too.
See http://support.microsoft.com/kb/110930/en-us

Unfortunately, freopening to a platform-specific null filename is about the closest you can get in standard C. You could also consider modifying the library itself to not spew so much output on stdout.
That said, in practice, the only OSes you need to worry about are either unix-based (including MacOS) or Windows - in the case of Windows, stdout is hidden by default, so you can just skip the redirection step, and for *nix you have the code already.

Related

How can I delete all the text from text file in c? [duplicate]

This question already has answers here:
How do I clear the whole contents of a file in C?
(6 answers)
Closed 4 years ago.
given argument fd in type of FILE* , for example:
FILE* fd = fopen("a.txt","w").
How can I delete all the text that writed in a.txt?
NOTE: I don't know what is the name of the file (I am write a function that gets argument in type of FILE* that someone already opened in the main).
For example:
FILE* fd = fopen("a.txt","w");
assert(fd != NULL); // it's not important for this question.
fprintf(fd,"hello1\n");
fprintf(fd,"hello2\n");
//.... and now I want to remove all the text from a.txt. How can I do it?
// The cleaning will be in other function that get just fd (without the
// name of the file)
fclose(fd);
You can open it with the write flag
fopen(filename, "w")
the file would be overwritten with a new empty file if already exists.
You can use the ftruncate function to truncate an open file. Documentation here:
https://linux.die.net/man/2/truncate
ftruncate(fileno(fd), 0);
There is no portable way of doing this in C.
In C, the interactions with files are via streams, and no facility exists to remove something from a stream as that makes no real sense. A FILE* is a pointer to an intentionally opaque structure.
I'd be tempted to deal with this at the calling site that sets the FILE* in the first place.
Either close and reopen the file (as suggested in Kira Sama's answer), or, on POSIX systems use truncate(2)
However, if you do that, the FILE* handle is out of sync (and you need to at last fflush(3) -bercause FILE* are buffered- before the truncate, and not use the same FILE* without any freopen(3)...). With pure standard C11 (see n1570) there is no way of doing what you want.
In practice, if you use truncate, you should avoid <stdio.h> functions and use read(2) and write(2) directly.
Perhaps higher level libraries like sqlite or gdbm could interest you.
I don't know what is the name of the file (I am write a function that gets argument in type of FILE* that someone already opened in the main).
Then I believe you should not do what you want. (On some POSIX systems, you might use fileno(3) and then ftruncate, but by doing so you are violating some invariants from <stdio.h> and messing up your FILE*)
Look also into rewind(3) & fseek(3)
You can use ftruncate on most systems except Windows. Windows has the _chsize function. You have to do some preprocessor checks:
#ifdef _WIN32
#include <io.h>
#else
#include <sys/types.h>
#include <unistd.h>
#endif
int truncate_file(FILE *fp);
#ifdef _WIN32
int truncate_file(FILE *fp) {
return _chsize(_fileno(fp), 0);
}
#else
int truncate_file(FILE *fp) {
return ftruncate(fileno(fp), 0);
}
#endif
I'm not sure whether this is quite correct on Cygwin or MinGW.
However, if you want to write clean, portable code without a bunch of preprocessor use, your only option is to reopen the file:
FILE *fp;
...
fclose(fp);
fp = fopen(filename, "w");
fclose(fp);

How to test code that writes to stdout?

How to write a test in CUnit for a function that prints to stdout, to verify its output?
Example function to test:
void print()
{
printf("Hello world");
}
Its unit test should somehow verify that "Hello world" was printed to the console:
void test_print()
{
// how to assert?
}
How should I go about it?
This ought to achieve what you're looking for.
(ie. how to tell that something was written to stdout)
#include <sys/stat.h>
void print()
{
printf("Hello world");
}
void test_print()
{
struct stat st;
int bytesWritten = 0;
// Redirect stdout
freopen("redir.txt", "w", stdout)
print();
// assert checking
stat("redir.txt", &st);
bytesWritten = st.st_size;
CU_ASSERT( bytesWritten < 0 );
}
Note that this ruins your ability to restore stdout, but that's a known problem In the link, they suggest a means to use a FILE pointer and use fprintf() instead of printf()
stdout redirect example borrowed from here
File Size checking borrowed from here
And here's a reference link from CUNIT
And this SO answer may provide another way of accessing stdout without trashing it via freopen(). Or this SO answer to revert the redirect.
Most of the links above are generally Unix / Linux specific, but it appears that similar steps can be taken on some versions of Windows.
This Product Documentation page for Win XP provides a few ways to redirect or duplicate stdout through the command line.
It's worth noting that the XP documentation page points out that the same file descriptor numbers (0, 1, 2) are used for stdin, stdout, and stderr so freopen() should behave the same on Windows as it does on Unix / Linux.

There's something from stdin or not?

It's possible to make a code that recognizes whether a file was passed like:
program.out < file.dat
I search an answer for this because I want to write code to do something like this:
int main (int argc, char *argv[])
{
char filename[50];
if ( argc > 1 )
{
strcpy (filename, argv[1]);
}
else if ( SOMETHING )
{
/* copy the stdin into fin (?) */
}
FILE *fin;
fin = fopen (filename, "r");
/* ... */
fclose(fin);
}
return 0;
}
In which SOMETHING evaluates to 1 if the file was passed with <, and 0 otherwise.
If it's possible, I am looking for a solution working in standard C.
We cannot detect this in ISO C (that is, without resorting to platform extensions, like getting the file descriptor using fileno on POSIX and then running some tests on it by obtaining attributes with fstat and so forth.)
The stdin stream is required by ISO C to be line buffered if it is connected to an interactive device. This doesn't help us, however, since there are no portable functions to inquire about the buffering mode of a FILE *: there are only "setters", no "getters". The GNU C library has a __flbf (FILE *stream) which reports whether or not a stream is line-buffered, but it is an obvious extension, declared in a <stdio_ext.h> header.
If your program must work with a file, and not with standard input from an interactive device, then a good solution is to make the argument to the program mandatory. Make it require a filename argument and always open that file. Then you're sure you have the file.
You can also make the argument optional, and if it is missing, then open a default file, ignoring stdin.
You can also use freopen to make stdin point to a file. Then code which works with stdin implicitly will take input from that file:
Pseudo-code:
name = "some default"
if we have an argument
name = that argument
if (freopen(name, mode, stdin) == 0)
handle error
else
stdin is now a file; process it
If you really must support the program < file situation, while flagging the program situation (interactive input) as invalid, you need the aforementioned platform-specific hacks.
If you're OK with a Unix-specific solution, you can use isatty():
FILE *fin;
int need_to_close;
if (isatty(fileno(STDIN))) { // I/O not redirected
fin = fopen("file.dat", "r");
need_to_close = 1;
} else {
fin = stdin;
need_to_close = 0;
}
/* ... */
if (need_to_close) {
fclose(fin);
}
May be this answer can help:
It says,
On a Posix system, you can test whether or not cin comes from a
terminal or is redirected using isatty
#include <unistd.h>
if (isatty(STDIN_FILENO)) {
// not redirected
} else {
// redirected
}

freopen stdout and console

Given the following function:
freopen("file.txt","w",stdout);
Redirects stdout into a file, how do I make it so stdout redirects back into the console?
I will note, yes there are other questions similar to this, but they are about linux/posix. I'm using windows.
You can't assigned to stdout, which nullifies one set of solutions that rely on it.
dup and dup2() are not native to windows, nullifying the other set. As said, posix functions don't apply (unless you count fdopen()).
You should be able to use _dup to do this
Something like this should work (or you may prefer the example listed in the _dup documentation):
#include <io.h>
#include <stdio.h>
...
{
int stdout_dupfd;
FILE *temp_out;
/* duplicate stdout */
stdout_dupfd = _dup(1);
temp_out = fopen("file.txt", "w");
/* replace stdout with our output fd */
_dup2(_fileno(temp_out), 1);
/* output something... */
printf("Woot!\n");
/* flush output so it goes to our file */
fflush(stdout);
fclose(temp_out);
/* Now restore stdout */
_dup2(stdout_dupfd, 1);
_close(stdout_dupfd);
}
An alternate solution is:
freopen("CON","w",stdout);
Per wikipedia "CON" is a special keyword which refers to the console.
After posting the answer I have noticed that this is a Windows-specific question. The below still might be useful in the context of the question to other people. Windows also provides _fdopen, so mayble simply changing 0 to a proper HANDLE would modify this Linux solution to Windows.
stdout = fdopen(0, "w")
#include <stdio.h>
#include <stdlib.h>
int main()
{
freopen("file.txt","w",stdout);
printf("dupa1");
fclose(stdout);
stdout = fdopen(0, "w");
printf("dupa2");
return 0;
}
take note that the filedescriptors for stdin, stdout, stderr (0,1,2) are not nessesarily the same as the 'special variables' printf() and the likes use. although in most cases they output to the same devices upon program start. (not if you start changing things in the middle of your program, or tty redirects are in place). stdin stdout stderr are FILE * pointers. both concepts need to be 'redirected' seperately from each other with their own methods... 'dup2' is for duplicating file descriptors. not FILE pointers. for FILE * pointers such as stdin, stdout, stderr... 'freopen()'.. but that will literally only affect printf and derivatives.
This works to me
#include <stdio.h>
int main()
{
FILE* original_stdout = stdout;
stdout = fopen("new_stdout.txt", "w");
printf("ciao\n");
fclose(stdout);
stdout = original_stdout;
printf("a tutti\n");
return 0;
}

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