On Sun, May 11, 2003 at 09:29:43AM +0900, Simon Strandgaard wrote:
>         stdout = fdopen(new_stdout, "a"); // BOOM!
>         stderr = fdopen(new_stderr, "a"); // BOOM!

The particular BOOM I get is:

main.cpp:40: non-lvalue in assignment
main.cpp:41: non-lvalue in assignment

That's because stdout is not a variable: on my FreeBSD box it is defined as

  extern FILE __sF[];
  ...
  #define stdout  (&__sF[1])

(so it's not a pointer variable which can be reassigned, it is a pointer to
a static piece of storage)

To reopen stdout you need either 'freopen' (at the stdio.h layer) or 'dup2'
(at the Unix API layer). I don't know if there's also a C++ way of doing
this by making a method call on 'cout'.

> Well, there is no thread to flush the pipe.. but this is not important
> here!  What is important is that system('ls a.c xx')'s output goes to
> stdout/stderr,  is mixed up with C's output.

Yes, of course it is.

If you want the child to have a different stdout/stderr than yours, then
what you need to do is:
    - fork
      - (in child) reopen stdout/stderr
      - (in child) exec
    - (in parent) wait for child to finish

This is all that 'system' does, except it omits the 'reopen stdout/stderr'
step.

Your logic is wrong: you are trying to reopen stdout/stderr before the fork,
which means you are affecting your main program (the parent) as well as the
child.

If you want to use a pipe, the logic is:
   - open the pipe(s)
   - fork
      (in child)
      - dup the writer end of each pipe to stdout/stderr
      - close the reader end
      - exec
    (in parent)
    - close the writer end of each pipe
    - read from the reader end of the pipes until they are closed
    - wait for the child to finish

This is a sufficiently common operation that most Unixes have a function
"popen" which does it (try "man popen" on your system). But if you want
pipes for both stdout and stderr then usually you'll have to do it the
longhand way.

See pages 223 and 435 of the Stevens book I referred you to. It sounds to me
like this would be a good investment! For example, after showing
step-by-step how to set up communication between parent and child using
pipes, the section about popen begins:

  "Since a common operation is to create a pipe to another process, to
   either read its output or send it input, the standard I/O library
   has historically provided the popen and pclose functions. These two
   functions handle all the dirty work that we've been doing ourselves:
   the creation of a pipe, the fork of a child, closing the unused ends
   of the pipe, execing a shell to execute the command, and waiting for
   the command to terminate"

He then goes on to show not just how to use popen, but gives an
implementation of it.

> Making this possible would require changes to ruby.. this is what my RCR
> proposal is about.  

It sounds to me like you are actually asking for changes to Unix, but I
can't see exactly what.

The Unix API has stood the test of time (30 years?!) so, no disrespect,
maybe you just need to learn a bit more about how to use it...

Regards,

Brian.