Skip to content

Instantly share code, notes, and snippets.

@seki
Created October 2, 2016 09:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save seki/641cabb835005c32c140096918db8d5a to your computer and use it in GitHub Desktop.
Save seki/641cabb835005c32c140096918db8d5a to your computer and use it in GitHub Desktop.
これをプルリクするには!
diff --git a/src/io.c b/src/io.c
index c9b1a8e..f0f8ff2 100644
--- a/src/io.c
+++ b/src/io.c
@@ -1042,6 +1042,113 @@ mrb_io_sync(mrb_state *mrb, mrb_value self)
}
void
+mrb_fd_set_nonblock(mrb_state *mrb, int fd)
+{
+#if defined(F_GETFL) && defined(F_SETFL) && defined(O_NONBLOCK)
+ int oflags;
+
+ oflags = fcntl(fd, F_GETFL);
+ if (oflags == -1) {
+ mrb_sys_fail(mrb, "fcntl");
+ }
+
+ if ((oflags & O_NONBLOCK) == 0) {
+ oflags |= O_NONBLOCK;
+ if (fcntl(fd, F_SETFL, oflags) == -1) {
+ mrb_sys_fail(mrb, "fcntl");
+ }
+ }
+#endif
+}
+
+mrb_value
+mrb_io_read_nonblock(mrb_state *mrb, mrb_value io)
+{
+ struct mrb_io *fptr;
+ mrb_value buf = mrb_nil_value();
+ mrb_int maxlen;
+ int ret;
+
+ mrb_get_args(mrb, "i|S", &maxlen, &buf);
+ if (maxlen < 0) {
+ return mrb_nil_value();
+ }
+
+ if (mrb_nil_p(buf)) {
+ buf = mrb_str_new(mrb, NULL, maxlen);
+ }
+ if (RSTRING_LEN(buf) != maxlen) {
+ buf = mrb_str_resize(mrb, buf, maxlen);
+ }
+
+ fptr = (struct mrb_io *)mrb_get_datatype(mrb, io, &mrb_io_type);
+ mrb_fd_set_nonblock(mrb, fptr->fd);
+ ret = read(fptr->fd, RSTRING_PTR(buf), maxlen);
+ switch (ret) {
+ case 0: /* EOF */
+ if (maxlen == 0) {
+ buf = mrb_str_new_cstr(mrb, "");
+ } else {
+ mrb_raise(mrb, E_EOF_ERROR, "read_nonblock failed: End of File");
+ }
+ break;
+ case -1: /* Error */
+ {
+ int e = errno;
+ if ((e == EWOULDBLOCK || e == EAGAIN)) {
+ return mrb_symbol_value(mrb_intern_cstr(mrb, "wait_readable"));
+ }
+ }
+ mrb_sys_fail(mrb, "read_nonblock failed");
+ break;
+ default:
+ if (RSTRING_LEN(buf) != ret) {
+ buf = mrb_str_resize(mrb, buf, ret);
+ }
+ break;
+ }
+
+ return buf;
+}
+
+mrb_value
+mrb_io_write_nonblock(mrb_state *mrb, mrb_value io)
+{
+ struct mrb_io *fptr;
+ mrb_value str, buf;
+ int fd, length;
+
+ fptr = (struct mrb_io *)mrb_get_datatype(mrb, io, &mrb_io_type);
+ if (! fptr->writable) {
+ mrb_raise(mrb, E_IO_ERROR, "not opened for writing");
+ }
+
+ mrb_get_args(mrb, "S", &str);
+ if (mrb_type(str) != MRB_TT_STRING) {
+ buf = mrb_funcall(mrb, str, "to_s", 0);
+ } else {
+ buf = str;
+ }
+
+ if (fptr->fd2 == -1) {
+ fd = fptr->fd;
+ } else {
+ fd = fptr->fd2;
+ }
+ mrb_fd_set_nonblock(mrb, fd);
+ length = write(fd, RSTRING_PTR(buf), RSTRING_LEN(buf));
+
+ if (length == -1) {
+ int e = errno;
+ if ((e == EWOULDBLOCK || e == EAGAIN)) {
+ return mrb_symbol_value(mrb_intern_cstr(mrb, "wait_writable"));
+ }
+ }
+
+ return mrb_fixnum_value(length);
+}
+
+void
mrb_init_io(mrb_state *mrb)
{
struct RClass *io;
@@ -1075,6 +1182,8 @@ mrb_init_io(mrb_state *mrb)
mrb_define_method(mrb, io, "pid", mrb_io_pid, MRB_ARGS_NONE()); /* 15.2.20.5.2 */
mrb_define_method(mrb, io, "fileno", mrb_io_fileno, MRB_ARGS_NONE());
+ mrb_define_method(mrb, io, "read_nonblock", mrb_io_read_nonblock, MRB_ARGS_ANY());
+ mrb_define_method(mrb, io, "write_nonblock", mrb_io_write_nonblock, MRB_ARGS_REQ(1));
mrb_gv_set(mrb, mrb_intern_cstr(mrb, "$/"), mrb_str_new_cstr(mrb, "\n"));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment