/*
 * $Id: io_ruby18.c,v 1.1 2002/09/11 11:25:49 knu Exp $
 */

#include "ruby.h"
#include "rubyio.h"
#include "rubysig.h"
#include "config.h"

#ifdef _STDIO_USES_IOSTREAM  /* GNU libc */
#  ifdef _IO_fpos_t
#    define READ_DATA_PENDING(fp) ((fp)->_IO_read_ptr != (fp)->_IO_read_end)
#  else
#    define READ_DATA_PENDING(fp) ((fp)->_gptr < (fp)->_egptr)
#  endif
#elif defined(FILE_COUNT)
#  define READ_DATA_PENDING(fp) ((fp)->FILE_COUNT > 0)
#elif defined(__BEOS__)
#  define READ_DATA_PENDING(fp) (fp->_state._eof == 0)
#elif defined(__UCLIBC__) && !defined(_UC_IOFBF)
#  define READ_DATA_PENDING(fp) ((fp)->bufpos < (fp)->bufread)
#else
#  define READ_DATA_PENDING(fp) (!feof(fp))
#endif

static void
io_fflush(f, path)
    FILE *f;
    const char *path;
{
    int n;

    rb_thread_fd_writable(fileno(f));
    TRAP_BEG;
    n = fflush(f);
    TRAP_END;
    if (n == EOF) rb_sys_fail(path);
}

static VALUE
rb_io_fsync(io)
    VALUE io;
{
#ifdef HAVE_FSYNC
    OpenFile *fptr;
    FILE *f;

    GetOpenFile(io, fptr);
    rb_io_check_writable(fptr);
    f = GetWriteFile(fptr);

    io_fflush(f, fptr);
    if (fsync(fileno(f)) < 0)
	rb_sys_fail(fptr->path);
    return INT2FIX(0);
#else
    rb_notimplement();
    return Qnil;		/* not reached */
#endif
}

static VALUE
rb_io_sysseek(argc, argv, io)
    int argc;
    VALUE *argv;
    VALUE io;
{
    VALUE offset, ptrname;
    int whence;
    OpenFile *fptr;
    long pos;

    rb_scan_args(argc, argv, "11", &offset, &ptrname);
    if (argc == 1) whence = SEEK_SET;
    else whence = NUM2INT(ptrname);

    GetOpenFile(io, fptr);
    if ((fptr->mode & FMODE_READABLE) && READ_DATA_PENDING(fptr->f)) {
	rb_raise(rb_eIOError, "sysseek for buffered IO");
    }
    pos = lseek(fileno(fptr->f), NUM2INT(offset), whence);
    if (pos == -1) rb_sys_fail(fptr->path);
    clearerr(fptr->f);

    return INT2FIX(pos);
}

void
Init_io_ruby18()
{
    rb_define_method(rb_cIO, "fsync", rb_io_fsync, 0);
    rb_define_method(rb_cIO, "sysseek", rb_io_sysseek, -1);
}
