summaryrefslogtreecommitdiff
path: root/spec/ruby/optional/capi/ext/io_spec.c
diff options
context:
space:
mode:
Diffstat (limited to 'spec/ruby/optional/capi/ext/io_spec.c')
-rw-r--r--spec/ruby/optional/capi/ext/io_spec.c319
1 files changed, 216 insertions, 103 deletions
diff --git a/spec/ruby/optional/capi/ext/io_spec.c b/spec/ruby/optional/capi/ext/io_spec.c
index 40069bd54b..fe31cffb49 100644
--- a/spec/ruby/optional/capi/ext/io_spec.c
+++ b/spec/ruby/optional/capi/ext/io_spec.c
@@ -21,33 +21,27 @@ static int set_non_blocking(int fd) {
int flags = 1;
return ioctl(fd, FIOBIO, &flags);
#else
+#define SET_NON_BLOCKING_FAILS_ALWAYS 1
errno = ENOSYS;
return -1;
#endif
}
-#ifdef HAVE_GET_OPEN_FILE
static int io_spec_get_fd(VALUE io) {
- rb_io_t* fp;
- GetOpenFile(io, fp);
- return fp->fd;
+ return rb_io_descriptor(io);
}
VALUE io_spec_GetOpenFile_fd(VALUE self, VALUE io) {
return INT2NUM(io_spec_get_fd(io));
}
-#endif
-#ifdef HAVE_RB_IO_ADDSTR
VALUE io_spec_rb_io_addstr(VALUE self, VALUE io, VALUE str) {
return rb_io_addstr(io, str);
}
-#endif
-#ifdef HAVE_RB_IO_PRINTF
VALUE io_spec_rb_io_printf(VALUE self, VALUE io, VALUE ary) {
long argc = RARRAY_LEN(ary);
- VALUE *argv = alloca(sizeof(VALUE) * argc);
+ VALUE *argv = (VALUE*) alloca(sizeof(VALUE) * argc);
int i;
for (i = 0; i < argc; i++) {
@@ -56,12 +50,10 @@ VALUE io_spec_rb_io_printf(VALUE self, VALUE io, VALUE ary) {
return rb_io_printf((int)argc, argv, io);
}
-#endif
-#ifdef HAVE_RB_IO_PRINT
VALUE io_spec_rb_io_print(VALUE self, VALUE io, VALUE ary) {
long argc = RARRAY_LEN(ary);
- VALUE *argv = alloca(sizeof(VALUE) * argc);
+ VALUE *argv = (VALUE*) alloca(sizeof(VALUE) * argc);
int i;
for (i = 0; i < argc; i++) {
@@ -70,12 +62,10 @@ VALUE io_spec_rb_io_print(VALUE self, VALUE io, VALUE ary) {
return rb_io_print((int)argc, argv, io);
}
-#endif
-#ifdef HAVE_RB_IO_PUTS
VALUE io_spec_rb_io_puts(VALUE self, VALUE io, VALUE ary) {
long argc = RARRAY_LEN(ary);
- VALUE *argv = alloca(sizeof(VALUE) * argc);
+ VALUE *argv = (VALUE*) alloca(sizeof(VALUE) * argc);
int i;
for (i = 0; i < argc; i++) {
@@ -84,68 +74,61 @@ VALUE io_spec_rb_io_puts(VALUE self, VALUE io, VALUE ary) {
return rb_io_puts((int)argc, argv, io);
}
-#endif
-#ifdef HAVE_RB_IO_WRITE
VALUE io_spec_rb_io_write(VALUE self, VALUE io, VALUE str) {
return rb_io_write(io, str);
}
-#endif
-#ifdef HAVE_RB_IO_CHECK_IO
VALUE io_spec_rb_io_check_io(VALUE self, VALUE io) {
return rb_io_check_io(io);
}
-#endif
-#ifdef HAVE_RB_IO_CHECK_READABLE
VALUE io_spec_rb_io_check_readable(VALUE self, VALUE io) {
rb_io_t* fp;
GetOpenFile(io, fp);
rb_io_check_readable(fp);
return Qnil;
}
-#endif
-#ifdef HAVE_RB_IO_CHECK_WRITABLE
VALUE io_spec_rb_io_check_writable(VALUE self, VALUE io) {
rb_io_t* fp;
GetOpenFile(io, fp);
rb_io_check_writable(fp);
return Qnil;
}
-#endif
-#ifdef HAVE_RB_IO_CHECK_CLOSED
VALUE io_spec_rb_io_check_closed(VALUE self, VALUE io) {
rb_io_t* fp;
GetOpenFile(io, fp);
rb_io_check_closed(fp);
return Qnil;
}
-#endif
-#ifdef HAVE_RB_IO_TAINT_CHECK
VALUE io_spec_rb_io_taint_check(VALUE self, VALUE io) {
/*rb_io_t* fp;
GetOpenFile(io, fp);*/
rb_io_taint_check(io);
return io;
}
-#endif
-#ifdef HAVE_RB_IO_WAIT_READABLE
#define RB_IO_WAIT_READABLE_BUF 13
+#ifdef SET_NON_BLOCKING_FAILS_ALWAYS
+NORETURN(VALUE io_spec_rb_io_wait_readable(VALUE self, VALUE io, VALUE read_p));
+#endif
+
VALUE io_spec_rb_io_wait_readable(VALUE self, VALUE io, VALUE read_p) {
int fd = io_spec_get_fd(io);
+#ifndef SET_NON_BLOCKING_FAILS_ALWAYS
char buf[RB_IO_WAIT_READABLE_BUF];
int ret, saved_errno;
+#endif
if (set_non_blocking(fd) == -1)
rb_sys_fail("set_non_blocking failed");
- if(RTEST(read_p)) {
+#ifndef SET_NON_BLOCKING_FAILS_ALWAYS
+ if (RTEST(read_p)) {
if (read(fd, buf, RB_IO_WAIT_READABLE_BUF) != -1) {
return Qnil;
}
@@ -154,9 +137,9 @@ VALUE io_spec_rb_io_wait_readable(VALUE self, VALUE io, VALUE read_p) {
errno = saved_errno;
}
- ret = rb_io_wait_readable(fd);
+ ret = rb_io_maybe_wait_readable(errno, io, Qnil);
- if(RTEST(read_p)) {
+ if (RTEST(read_p)) {
ssize_t r = read(fd, buf, RB_IO_WAIT_READABLE_BUF);
if (r != RB_IO_WAIT_READABLE_BUF) {
perror("read");
@@ -167,135 +150,265 @@ VALUE io_spec_rb_io_wait_readable(VALUE self, VALUE io, VALUE read_p) {
}
return ret ? Qtrue : Qfalse;
-}
+#else
+ UNREACHABLE_RETURN(Qnil);
#endif
+}
-#ifdef HAVE_RB_IO_WAIT_WRITABLE
VALUE io_spec_rb_io_wait_writable(VALUE self, VALUE io) {
- int ret = rb_io_wait_writable(io_spec_get_fd(io));
+ int ret = rb_io_maybe_wait_writable(errno, io, Qnil);
return ret ? Qtrue : Qfalse;
}
+
+VALUE io_spec_rb_io_maybe_wait_writable(VALUE self, VALUE error, VALUE io, VALUE timeout) {
+ int ret = rb_io_maybe_wait_writable(NUM2INT(error), io, timeout);
+ return INT2NUM(ret);
+}
+
+#ifdef SET_NON_BLOCKING_FAILS_ALWAYS
+NORETURN(VALUE io_spec_rb_io_maybe_wait_readable(VALUE self, VALUE error, VALUE io, VALUE timeout, VALUE read_p));
#endif
-#ifdef HAVE_RB_THREAD_WAIT_FD
+VALUE io_spec_rb_io_maybe_wait_readable(VALUE self, VALUE error, VALUE io, VALUE timeout, VALUE read_p) {
+ int fd = io_spec_get_fd(io);
+#ifndef SET_NON_BLOCKING_FAILS_ALWAYS
+ char buf[RB_IO_WAIT_READABLE_BUF];
+ int ret, saved_errno;
+#endif
+
+ if (set_non_blocking(fd) == -1)
+ rb_sys_fail("set_non_blocking failed");
+
+#ifndef SET_NON_BLOCKING_FAILS_ALWAYS
+ if (RTEST(read_p)) {
+ if (read(fd, buf, RB_IO_WAIT_READABLE_BUF) != -1) {
+ return Qnil;
+ }
+ saved_errno = errno;
+ rb_ivar_set(self, rb_intern("@write_data"), Qtrue);
+ errno = saved_errno;
+ }
+
+ // main part
+ ret = rb_io_maybe_wait_readable(NUM2INT(error), io, timeout);
+
+ if (RTEST(read_p)) {
+ ssize_t r = read(fd, buf, RB_IO_WAIT_READABLE_BUF);
+ if (r != RB_IO_WAIT_READABLE_BUF) {
+ perror("read");
+ return SSIZET2NUM(r);
+ }
+ rb_ivar_set(self, rb_intern("@read_data"),
+ rb_str_new(buf, RB_IO_WAIT_READABLE_BUF));
+ }
+
+ return INT2NUM(ret);
+#else
+ UNREACHABLE_RETURN(Qnil);
+#endif
+}
+
+VALUE io_spec_rb_io_maybe_wait(VALUE self, VALUE error, VALUE io, VALUE events, VALUE timeout) {
+ return rb_io_maybe_wait(NUM2INT(error), io, events, timeout);
+}
+
VALUE io_spec_rb_thread_wait_fd(VALUE self, VALUE io) {
rb_thread_wait_fd(io_spec_get_fd(io));
return Qnil;
}
-#endif
-#ifdef HAVE_RB_THREAD_FD_WRITABLE
+VALUE io_spec_rb_wait_for_single_fd(VALUE self, VALUE io, VALUE events, VALUE secs, VALUE usecs) {
+ VALUE timeout = Qnil;
+ if (!NIL_P(secs)) {
+ timeout = rb_float_new((double)FIX2INT(secs) + (0.000001 * FIX2INT(usecs)));
+ }
+ VALUE result = rb_io_wait(io, events, timeout);
+ if (result == Qfalse) return INT2FIX(0);
+ else return result;
+}
+
VALUE io_spec_rb_thread_fd_writable(VALUE self, VALUE io) {
rb_thread_fd_writable(io_spec_get_fd(io));
return Qnil;
}
-#endif
-#ifdef HAVE_RB_IO_BINMODE
+VALUE io_spec_rb_thread_fd_select_read(VALUE self, VALUE io) {
+ int fd = io_spec_get_fd(io);
+
+ rb_fdset_t fds;
+ rb_fd_init(&fds);
+ rb_fd_set(fd, &fds);
+
+ int r = rb_thread_fd_select(fd + 1, &fds, NULL, NULL, NULL);
+ rb_fd_term(&fds);
+ return INT2FIX(r);
+}
+
+VALUE io_spec_rb_thread_fd_select_write(VALUE self, VALUE io) {
+ int fd = io_spec_get_fd(io);
+
+ rb_fdset_t fds;
+ rb_fd_init(&fds);
+ rb_fd_set(fd, &fds);
+
+ int r = rb_thread_fd_select(fd + 1, NULL, &fds, NULL, NULL);
+ rb_fd_term(&fds);
+ return INT2FIX(r);
+}
+
+VALUE io_spec_rb_thread_fd_select_timeout(VALUE self, VALUE io) {
+ int fd = io_spec_get_fd(io);
+
+ struct timeval timeout;
+ timeout.tv_sec = 10;
+ timeout.tv_usec = 20;
+
+ rb_fdset_t fds;
+ rb_fd_init(&fds);
+ rb_fd_set(fd, &fds);
+
+ int r = rb_thread_fd_select(fd + 1, NULL, &fds, NULL, &timeout);
+ rb_fd_term(&fds);
+ return INT2FIX(r);
+}
+
VALUE io_spec_rb_io_binmode(VALUE self, VALUE io) {
return rb_io_binmode(io);
}
-#endif
-#ifdef HAVE_RB_FD_FIX_CLOEXEC
VALUE io_spec_rb_fd_fix_cloexec(VALUE self, VALUE io) {
rb_fd_fix_cloexec(io_spec_get_fd(io));
return Qnil;
}
-#endif
-#ifdef HAVE_RB_CLOEXEC_OPEN
VALUE io_spec_rb_cloexec_open(VALUE self, VALUE path, VALUE flags, VALUE mode) {
const char *pathname = StringValuePtr(path);
int fd = rb_cloexec_open(pathname, FIX2INT(flags), FIX2INT(mode));
return rb_funcall(rb_cIO, rb_intern("for_fd"), 1, INT2FIX(fd));
}
-#endif
-#ifdef HAVE_RB_IO_CLOSE
+VALUE io_spec_rb_cloexec_dup(VALUE self, VALUE io) {
+ int fd = io_spec_get_fd(io);
+ int new_fd = rb_cloexec_dup(fd);
+ return rb_funcall(rb_cIO, rb_intern("for_fd"), 1, INT2FIX(new_fd));
+}
+
+VALUE io_spec_rb_cloexec_fcntl_dupfd(VALUE self, VALUE io, VALUE minfd) {
+ int fd = io_spec_get_fd(io);
+ int new_fd = rb_cloexec_fcntl_dupfd(fd, FIX2INT(minfd));
+ return rb_funcall(rb_cIO, rb_intern("for_fd"), 1, INT2FIX(new_fd));
+}
+
VALUE io_spec_rb_io_close(VALUE self, VALUE io) {
return rb_io_close(io);
}
+
+VALUE io_spec_rb_io_set_nonblock(VALUE self, VALUE io) {
+ rb_io_t* fp;
+#ifdef F_GETFL
+ int flags;
#endif
+ GetOpenFile(io, fp);
+ rb_io_set_nonblock(fp);
+#ifdef F_GETFL
+ flags = fcntl(io_spec_get_fd(io), F_GETFL, 0);
+ return flags & O_NONBLOCK ? Qtrue : Qfalse;
+#else
+ return Qfalse;
+#endif
+}
+
+/*
+ * this is needed to ensure rb_io_wait_*able functions behave
+ * predictably because errno may be set to unexpected values
+ * otherwise.
+ */
+static VALUE io_spec_errno_set(VALUE self, VALUE val) {
+ int e = NUM2INT(val);
+ errno = e;
+ return val;
+}
+
+VALUE io_spec_mode_sync_flag(VALUE self, VALUE io) {
+ int mode;
+ mode = rb_io_mode(io);
+ if (mode & FMODE_SYNC) {
+ return Qtrue;
+ } else {
+ return Qfalse;
+ }
+}
+
+static VALUE io_spec_rb_io_mode(VALUE self, VALUE io) {
+ return INT2FIX(rb_io_mode(io));
+}
+
+static VALUE io_spec_rb_io_path(VALUE self, VALUE io) {
+ return rb_io_path(io);
+}
+
+static VALUE io_spec_rb_io_closed_p(VALUE self, VALUE io) {
+ return rb_io_closed_p(io);
+}
+
+static VALUE io_spec_rb_io_open_descriptor(VALUE self, VALUE klass, VALUE descriptor, VALUE mode, VALUE path, VALUE timeout, VALUE internal_encoding, VALUE external_encoding, VALUE ecflags, VALUE ecopts) {
+ struct rb_io_encoding io_encoding;
+
+ io_encoding.enc = rb_to_encoding(internal_encoding);
+ io_encoding.enc2 = rb_to_encoding(external_encoding);
+ io_encoding.ecflags = FIX2INT(ecflags);
+ io_encoding.ecopts = ecopts;
+
+ return rb_io_open_descriptor(klass, FIX2INT(descriptor), FIX2INT(mode), path, timeout, &io_encoding);
+}
+
+static VALUE io_spec_rb_io_open_descriptor_without_encoding(VALUE self, VALUE klass, VALUE descriptor, VALUE mode, VALUE path, VALUE timeout) {
+ return rb_io_open_descriptor(klass, FIX2INT(descriptor), FIX2INT(mode), path, timeout, NULL);
+}
void Init_io_spec(void) {
VALUE cls = rb_define_class("CApiIOSpecs", rb_cObject);
-
-#ifdef HAVE_GET_OPEN_FILE
rb_define_method(cls, "GetOpenFile_fd", io_spec_GetOpenFile_fd, 1);
-#endif
-
-#ifdef HAVE_RB_IO_ADDSTR
rb_define_method(cls, "rb_io_addstr", io_spec_rb_io_addstr, 2);
-#endif
-
-#ifdef HAVE_RB_IO_PRINTF
rb_define_method(cls, "rb_io_printf", io_spec_rb_io_printf, 2);
-#endif
-
-#ifdef HAVE_RB_IO_PRINT
rb_define_method(cls, "rb_io_print", io_spec_rb_io_print, 2);
-#endif
-
-#ifdef HAVE_RB_IO_PUTS
rb_define_method(cls, "rb_io_puts", io_spec_rb_io_puts, 2);
-#endif
-
-#ifdef HAVE_RB_IO_WRITE
rb_define_method(cls, "rb_io_write", io_spec_rb_io_write, 2);
-#endif
-
-#ifdef HAVE_RB_IO_CLOSE
rb_define_method(cls, "rb_io_close", io_spec_rb_io_close, 1);
-#endif
-
-#ifdef HAVE_RB_IO_CHECK_IO
rb_define_method(cls, "rb_io_check_io", io_spec_rb_io_check_io, 1);
-#endif
-
-#ifdef HAVE_RB_IO_CHECK_READABLE
rb_define_method(cls, "rb_io_check_readable", io_spec_rb_io_check_readable, 1);
-#endif
-
-#ifdef HAVE_RB_IO_CHECK_WRITABLE
rb_define_method(cls, "rb_io_check_writable", io_spec_rb_io_check_writable, 1);
-#endif
-
-#ifdef HAVE_RB_IO_CHECK_CLOSED
rb_define_method(cls, "rb_io_check_closed", io_spec_rb_io_check_closed, 1);
-#endif
-
-#ifdef HAVE_RB_IO_TAINT_CHECK
+ rb_define_method(cls, "rb_io_set_nonblock", io_spec_rb_io_set_nonblock, 1);
rb_define_method(cls, "rb_io_taint_check", io_spec_rb_io_taint_check, 1);
-#endif
-
-#ifdef HAVE_RB_IO_WAIT_READABLE
rb_define_method(cls, "rb_io_wait_readable", io_spec_rb_io_wait_readable, 2);
-#endif
-
-#ifdef HAVE_RB_IO_WAIT_WRITABLE
rb_define_method(cls, "rb_io_wait_writable", io_spec_rb_io_wait_writable, 1);
-#endif
-
-#ifdef HAVE_RB_THREAD_WAIT_FD
+ rb_define_method(cls, "rb_io_maybe_wait_writable", io_spec_rb_io_maybe_wait_writable, 3);
+ rb_define_method(cls, "rb_io_maybe_wait_readable", io_spec_rb_io_maybe_wait_readable, 4);
+ rb_define_method(cls, "rb_io_maybe_wait", io_spec_rb_io_maybe_wait, 4);
rb_define_method(cls, "rb_thread_wait_fd", io_spec_rb_thread_wait_fd, 1);
-#endif
-
-#ifdef HAVE_RB_THREAD_FD_WRITABLE
rb_define_method(cls, "rb_thread_fd_writable", io_spec_rb_thread_fd_writable, 1);
-#endif
-
-#ifdef HAVE_RB_IO_BINMODE
+ rb_define_method(cls, "rb_thread_fd_select_read", io_spec_rb_thread_fd_select_read, 1);
+ rb_define_method(cls, "rb_thread_fd_select_write", io_spec_rb_thread_fd_select_write, 1);
+ rb_define_method(cls, "rb_thread_fd_select_timeout", io_spec_rb_thread_fd_select_timeout, 1);
+ rb_define_method(cls, "rb_wait_for_single_fd", io_spec_rb_wait_for_single_fd, 4);
rb_define_method(cls, "rb_io_binmode", io_spec_rb_io_binmode, 1);
-#endif
-
-#ifdef HAVE_RB_FD_FIX_CLOEXEC
rb_define_method(cls, "rb_fd_fix_cloexec", io_spec_rb_fd_fix_cloexec, 1);
-#endif
-
-#ifdef HAVE_RB_CLOEXEC_OPEN
rb_define_method(cls, "rb_cloexec_open", io_spec_rb_cloexec_open, 3);
-#endif
+ rb_define_method(cls, "rb_cloexec_dup", io_spec_rb_cloexec_dup, 1);
+ rb_define_method(cls, "rb_cloexec_fcntl_dupfd", io_spec_rb_cloexec_fcntl_dupfd, 2);
+ rb_define_method(cls, "errno=", io_spec_errno_set, 1);
+ rb_define_method(cls, "rb_io_mode_sync_flag", io_spec_mode_sync_flag, 1);
+ rb_define_method(cls, "rb_io_mode", io_spec_rb_io_mode, 1);
+ rb_define_method(cls, "rb_io_path", io_spec_rb_io_path, 1);
+ rb_define_method(cls, "rb_io_closed_p", io_spec_rb_io_closed_p, 1);
+ rb_define_method(cls, "rb_io_open_descriptor", io_spec_rb_io_open_descriptor, 9);
+ rb_define_method(cls, "rb_io_open_descriptor_without_encoding", io_spec_rb_io_open_descriptor_without_encoding, 5);
+ rb_define_const(cls, "FMODE_READABLE", INT2FIX(FMODE_READABLE));
+ rb_define_const(cls, "FMODE_WRITABLE", INT2FIX(FMODE_WRITABLE));
+ rb_define_const(cls, "FMODE_BINMODE", INT2FIX(FMODE_BINMODE));
+ rb_define_const(cls, "FMODE_TEXTMODE", INT2FIX(FMODE_TEXTMODE));
+ rb_define_const(cls, "ECONV_UNIVERSAL_NEWLINE_DECORATOR", INT2FIX(ECONV_UNIVERSAL_NEWLINE_DECORATOR));
}
#ifdef __cplusplus