Catching a process' own stdout

  • Thread starter Philip Hölzenspies
  • Start date
P

Philip Hölzenspies

Hi All,

I have been crunching my brains on this one all day. I use this library that
creates output I want, but it can only write it to a file or the stdout. The
problem is that I don't want to use the filesystem (permissions, latency
through NFS, etc, etc), but a memory buffer. I've been looking for a way to
redirect stdout to a buffer that I manage myself. Obviously I considered
setbuf (from stdio.h), but then I'ld still have to redirect output to
/dev/null on posix systems and to something I'm not too sure about on
non-posix systems.

I'ld really prefer an ANSI C solution to this problem. Basically what I want
is the following:

int main(void)
{
char buf[BUFFER_SIZE];
FILE *stdout_bkp, *stdout_rep;

some_function_to_backup_a_stream(stdout, stdout_bkp);
stdout_rep = some_function_to_create_a_FILEPTR_to_a_memptr(&buf);
some_function_to_redirect_a_stream(stdout_rep, stdout);

my_library_function();

some_function_to_redirect_a_stream(stdout_bkp, stdout)
fclose(stdout_rep);

my_function_to_do_something_with_the_output(&buf);

return 0;
}

I tried stuff like (open_memstream is part of the GNU C lib, which I'ld
rather not use, if ANSI has alternatives):

int main(void)
{
char *buf;
size_t size;
int stdout_bkp, stdout_rep = open_memstream(&buf, &size);

stdout_bkp = dup(1);
dup2(fileno(stdout_rep), 1);

printf("This should end up in the buffer\n");
libfunc();
fprintf(stdout_rep, "Just to make sure that SOMETHING ends up in the
buffer");
fclose(stdout_rep);

fprintf(stderr, "Result in buffer:\n%s\n", buf);
return 0;
}

This results in the output:
Result in buffer:
Just to make sure that SOMETHING ends up in the buffer

Does anyone have any clue as to what I want and wether it is possible?

Regards,
Philip
 
E

Eric Sosman

Philip said:
Hi All,

I have been crunching my brains on this one all day. I use this library that
creates output I want, but it can only write it to a file or the stdout. The
problem is that I don't want to use the filesystem (permissions, latency
through NFS, etc, etc), but a memory buffer. I've been looking for a way to
redirect stdout to a buffer that I manage myself. Obviously I considered
setbuf (from stdio.h), but then I'ld still have to redirect output to
/dev/null on posix systems and to something I'm not too sure about on
non-posix systems.

I'ld really prefer an ANSI C solution to this problem. [...]

There isn't one. See Questions 19.30 in the comp.lang.c
Frequently Asked Questions (FAQ) list

http://www.eskimo.com/~scs/C-faq/top.html

By the way, setbuf() and setvbuf() do not do what you
seem to think they do. What goes into the buffer you
provide, if anything at all does, is not specified. You
have no way of knowing which parts of the buffer contain
what, or whether the contents might vanish while you're
attempting to use them. Don't Do That.
 
P

Philip Hölzenspies

Thanks for your warning on setbuf, I had indeed misread the docs on that.
However, I had already seen 19.30 of the FAQ, but figured it to be
irrelevant, since I don't mean to fork a new process. The point is that I
want to reroute stdout to a buffer before I hand it over to a function I
don't have any control over.

Essentially, the dup-method should work, but doesn't and I simply don't get
why not.

Still open for suggestions.

Philip
 
E

Eric Sosman

Philip said:
Thanks for your warning on setbuf, I had indeed misread the docs on that.
However, I had already seen 19.30 of the FAQ, but figured it to be
irrelevant, since I don't mean to fork a new process.

Sorry; my mistake. I read too hastily. The answer
remains the same, though: there's no Standard-provided
way to do what you're attempting.
The point is that I
want to reroute stdout to a buffer before I hand it over to a function I
don't have any control over.

Essentially, the dup-method should work, but doesn't and I simply don't get
why not.

Well, you *did* say you were looking for "an ANSI C
solution." Since Standard C doesn't have open_memstream()
or dup() or dup2() or fileno() -- Standard C doesn't even
have any concept of "file descriptor" in the POSIX sense --
I think you're out of luck. You're going to need platform-
specific facilities to fill your need.
 
K

Keith Thompson

Eric Sosman said:
I'ld really prefer an ANSI C solution to this problem. [...]

There isn't one. See Questions 19.30 in the comp.lang.c
Frequently Asked Questions (FAQ) list

http://www.eskimo.com/~scs/C-faq/top.html

Actually, 19.30 doesn't address the OP's question. It's about
invoking another program and capturing its output; the OP wants to
capture the output of the current program.

You're right that there's no portable way to do this without using an
external file. You might be able to do something with tmpnam() and
freopen() (I'm too lazy to work out the details). <OT>On Unix-like
systems, tmpnam() is likely to give you the name of a file on /tmp,
which is unlikely to be NFS-mounted.</OT>
 
C

Chris Torek

... The point is that I want to reroute stdout to a buffer before
I hand it over to a function I don't have any control over.

Unfortunately, this cannot be done in Standard C. Even the
GNU extension you are using is insufficient, because (begin
off-topicness...):
Essentially, the dup-method should work, but doesn't and I simply don't get
why not.

The "FILE *" entity you obtain when you open a "memory stream"
has no underlying file descriptor associated with it. The same
is true for the "function oriented stdio" I put into 4.xBSD.
Since there *is* no file descriptor, no amount of dup()ing will
make the file descriptor become the right one. (End off-topic-ness.)

What you need is to modify the apparently-unmodifiable function
so that instead of writing to stdout, it writes to a user-specified
"FILE *" value. While Standard C will still be unable to solve
the problem, the GNU extension will then do the trick.

One can lump this under the general claim that "global variables
are bad": stdout is in effect a global variable, and the library-writer
used it.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,048
Latest member
verona

Latest Threads

Top