/*
 *  call-seq:
 *     ios.reopen(other_IO)         => ios 
 *     ios.reopen(path, mode_str)   => ios
 *  
 *  Reassociates <em>ios</em> with the I/O stream given in
 *  <i>other_IO</i> or to a new stream opened on <i>path</i>. This may
 *  dynamically change the actual class of this stream.
 *     
 *     f1 = File.new("testfile")
 *     f2 = File.new("testfile")
 *     f2.readlines[0]   #=> "This is line one\n"
 *     f2.reopen(f1)     #=> #<File:testfile>
 *     f2.readlines[0]   #=> "This is line one\n"
 */

static VALUE
rb_io_reopen(argc, argv, file)
    int argc;
    VALUE *argv;
    VALUE file;
{
    VALUE fname, nmode;
    char *mode;
    OpenFile *fptr;

    rb_secure(4);
    if (rb_scan_args(argc, argv, "11", &fname, &nmode) == 1) {
        VALUE tmp = rb_io_check_io(fname);
        if (!NIL_P(tmp)) {
            return io_reopen(file, tmp);
        }
    }

    SafeStringValue(fname);
    rb_io_taint_check(file);
    fptr = RFILE(file)->fptr;
    if (!fptr) {
        fptr = RFILE(file)->fptr = ALLOC(OpenFile);
        MEMZERO(fptr, OpenFile, 1);
    }

    if (!NIL_P(nmode)) {
        fptr->mode = rb_io_mode_flags(StringValueCStr(nmode));
    }

    if (fptr->path) {
        free(fptr->path);
        fptr->path = 0;
    }

    fptr->path = strdup(StringValueCStr(fname));
    mode = rb_io_flags_mode(fptr->mode);
    if (!fptr->f) {
        fptr->f = rb_fopen(fptr->path, mode);
        if (fptr->f2) {
            fclose(fptr->f2);
            fptr->f2 = 0;
        }
        return file;
    }

    if (freopen(fptr->path, mode, fptr->f) == 0) {
        rb_sys_fail(fptr->path);
    }
#ifdef USE_SETVBUF
    if (setvbuf(fptr->f, NULL, _IOFBF, 0) != 0)
        rb_warn("setvbuf() can't be honoured for %s", fptr->path);
#endif

    if (fptr->f2) {
        if (freopen(fptr->path, "w", fptr->f2) == 0) {
            rb_sys_fail(fptr->path);
        }
    }

    return file;
}