/*
 *  call-seq:
 *     IO.popen(cmd_string, mode="r" )               => io
 *     IO.popen(cmd_string, mode="r" ) {|io| block } => obj
 *  
 *  Runs the specified command string as a subprocess; the subprocess's
 *  standard input and output will be connected to the returned
 *  <code>IO</code> object. If <i>cmd_string</i> starts with a
 *  ``<code>-</code>'', then a new instance of Ruby is started as the
 *  subprocess. The default mode for the new file object is ``r'', but
 *  <i>mode</i> may be set to any of the modes listed in the description
 *  for class IO.
 *     
 *  If a block is given, Ruby will run the command as a child connected
 *  to Ruby with a pipe. Ruby's end of the pipe will be passed as a
 *  parameter to the block.
 *  At the end of block, Ruby close the pipe and sets <code>$?</code>.
 *  In this case <code>IO::popen</code> returns
 *  the value of the block.
 *     
 *  If a block is given with a <i>cmd_string</i> of ``<code>-</code>'',
 *  the block will be run in two separate processes: once in the parent,
 *  and once in a child. The parent process will be passed the pipe
 *  object as a parameter to the block, the child version of the block
 *  will be passed <code>nil</code>, and the child's standard in and
 *  standard out will be connected to the parent through the pipe. Not
 *  available on all platforms.
 *     
 *     f = IO.popen("uname")
 *     p f.readlines
 *     puts "Parent is #{Process.pid}"
 *     IO.popen ("date") { |f| puts f.gets }
 *     IO.popen("-") {|f| $stderr.puts "#{Process.pid} is here, f is #{f}"}
 *     p $?
 *     
 *  <em>produces:</em>
 *     
 *     ["Linux\n"]
 *     Parent is 26166
 *     Wed Apr  9 08:53:52 CDT 2003
 *     26169 is here, f is
 *     26166 is here, f is #<IO:0x401b3d44>
 *     #<Process::Status: pid=26166,exited(0)>
 */

static VALUE
rb_io_s_popen(argc, argv, klass)
    int argc;
    VALUE *argv;
    VALUE klass;
{
    char *mode;
    VALUE pname, pmode, port;

    if (rb_scan_args(argc, argv, "11", &pname, &pmode) == 1) {
        mode = "r";
    }
    else if (FIXNUM_P(pmode)) {
        mode = rb_io_modenum_mode(FIX2INT(pmode));
    }
    else {
        mode = rb_io_flags_mode(rb_io_mode_flags(StringValueCStr(pmode)));
    }
    SafeStringValue(pname);
    port = pipe_open(pname, 0, mode);
    if (NIL_P(port)) {
        /* child */
        if (rb_block_given_p()) {
            rb_yield(Qnil);
            fflush(stdout);
            fflush(stderr);
            _exit(0);
        }
        return Qnil;
    }
    RBASIC(port)->klass = klass;
    if (rb_block_given_p()) {
        return rb_ensure(rb_yield, port, io_close, port);
    }
    return port;
}