Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I suppress output while using a dynamic library?

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?

like image 215
Dancrumb Avatar asked Jan 21 '11 14:01

Dancrumb


2 Answers

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".

like image 74
JXG Avatar answered Oct 17 '22 05:10

JXG


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;
}
like image 29
Null Set Avatar answered Oct 17 '22 05:10

Null Set