/*
 *  call-seq:
 *     IO.new(fd, mode)   => io
 *
 *  Returns a new <code>IO</code> object (a stream) for the given
 *  <code>IO</code> object or integer file descriptor and mode
 *  string. See also <code>IO#fileno</code> and
 *  <code>IO::for_fd</code>.
 *
 *     puts IO.new($stdout).fileno # => 1
 *
 *     a = IO.new(2,"w")      # '2' is standard error
 *     $stderr.puts "Hello"
 *     a.puts "World"
 *
 *  <em>produces:</em>
 *
 *     Hello
 *     World
 */

static VALUE
rb_io_initialize(int argc, VALUE *argv, VALUE io)
{
    VALUE fnum, mode, orig;
    rb_io_t *fp, *ofp = NULL;
    int fd, fmode, flags = O_RDONLY;

    rb_secure(4);
    rb_scan_args(argc, argv, "11", &fnum, &mode);
    if (argc == 2) {
        if (FIXNUM_P(mode)) {
            flags = FIX2LONG(mode);
        }
        else {
            SafeStringValue(mode);
            flags = rb_io_mode_modenum(StringValueCStr(mode));
        }
    }
    orig = rb_io_check_io(fnum);
    if (NIL_P(orig)) {
        fd = NUM2INT(fnum);
        UPDATE_MAXFD(fd);
        if (argc != 2) {
#if defined(HAVE_FCNTL) && defined(F_GETFL)
            flags = fcntl(fd, F_GETFL);
            if (flags == -1) rb_sys_fail(0);
#endif
        }
        MakeOpenFile(io, fp);
        fp->fd = fd;
        fp->mode = rb_io_modenum_flags(flags);
        io_check_tty(fp);
    }
    else if (RFILE(io)->fptr) {
        rb_raise(rb_eRuntimeError, "reinitializing IO");
    }
    else {
        GetOpenFile(orig, ofp);
        if (ofp->refcnt == LONG_MAX) {
            VALUE s = rb_inspect(orig);
            rb_raise(rb_eIOError, "too many shared IO for %s", StringValueCStr(s));
        }
        if (argc == 2) {
            fmode = rb_io_modenum_flags(flags);
            if ((ofp->mode ^ fmode) & (FMODE_READWRITE|FMODE_BINMODE)) {
                if (FIXNUM_P(mode)) {
                    rb_raise(rb_eArgError, "incompatible mode 0%o", flags);
                }
                else {
                    rb_raise(rb_eArgError, "incompatible mode \"%s\"", RSTRING_PTR(mode));
                }
            }
        }
        ofp->refcnt++;
        RFILE(io)->fptr = ofp;
    }

    return io;
}