summaryrefslogtreecommitdiffhomepage
path: root/mrbgems/mruby-io/src
diff options
context:
space:
mode:
authordearblue <[email protected]>2020-02-01 16:25:39 +0900
committerdearblue <[email protected]>2020-02-02 21:20:25 +0900
commit4c6d524c473ebb9174d0183dc1d1ac0530337314 (patch)
tree1aec9457c2862557440a3d718f459020334e0383 /mrbgems/mruby-io/src
parent3c67d9b1c0e4970db1d88fccdf7f26c781aa2c5f (diff)
downloadmruby-4c6d524c473ebb9174d0183dc1d1ac0530337314.tar.gz
mruby-4c6d524c473ebb9174d0183dc1d1ac0530337314.zip
Implement `IO#pread` and `IO#pwrite`
It is available by default in environments where `__unix__` is defined. Other environments are enabled by defining `MRB_WITH_IO_PREAD_PWRITE` (requires an implementation of `pread()` and `pwrite()` functions). In any case, you can disable it by defining `MRB_WITHOUT_IO_PREAD_PWRITE`.
Diffstat (limited to 'mrbgems/mruby-io/src')
-rw-r--r--mrbgems/mruby-io/src/io.c113
1 files changed, 105 insertions, 8 deletions
diff --git a/mrbgems/mruby-io/src/io.c b/mrbgems/mruby-io/src/io.c
index 4be41ef31..b7f70a5f8 100644
--- a/mrbgems/mruby-io/src/io.c
+++ b/mrbgems/mruby-io/src/io.c
@@ -31,6 +31,7 @@
typedef long ftime_t;
typedef long fsuseconds_t;
typedef int fmode_t;
+ typedef int mrb_io_read_write_size;
#ifndef O_TMPFILE
#define O_TMPFILE O_TEMPORARY
@@ -43,6 +44,7 @@
typedef time_t ftime_t;
typedef suseconds_t fsuseconds_t;
typedef mode_t fmode_t;
+ typedef ssize_t mrb_io_read_write_size;
#endif
#ifdef _MSC_VER
@@ -845,15 +847,35 @@ mrb_io_s_sysopen(mrb_state *mrb, mrb_value klass)
return mrb_fixnum_value(fd);
}
+static mrb_value mrb_io_sysread_common(mrb_state *mrb,
+ mrb_io_read_write_size (*readfunc)(int, void *, fsize_t, off_t),
+ mrb_value io, mrb_value buf, mrb_int maxlen, off_t offset);
+
+static mrb_io_read_write_size
+mrb_sysread_dummy(int fd, void *buf, fsize_t nbytes, off_t offset)
+{
+ return (mrb_io_read_write_size)read(fd, buf, nbytes);
+}
+
mrb_value
mrb_io_sysread(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);
+
+ return mrb_io_sysread_common(mrb, mrb_sysread_dummy, io, buf, maxlen, 0);
+}
+
+static mrb_value
+mrb_io_sysread_common(mrb_state *mrb,
+ mrb_io_read_write_size (*readfunc)(int, void *, fsize_t, off_t),
+ mrb_value io, mrb_value buf, mrb_int maxlen, off_t offset)
+{
+ struct mrb_io *fptr;
+ int ret;
+
if (maxlen < 0) {
mrb_raise(mrb, E_ARGUMENT_ERROR, "negative expanding string size");
}
@@ -875,7 +897,7 @@ mrb_io_sysread(mrb_state *mrb, mrb_value io)
if (!fptr->readable) {
mrb_raise(mrb, E_IO_ERROR, "not opened for reading");
}
- ret = read(fptr->fd, RSTRING_PTR(buf), (fsize_t)maxlen);
+ ret = readfunc(fptr->fd, RSTRING_PTR(buf), (fsize_t)maxlen, offset);
switch (ret) {
case 0: /* EOF */
if (maxlen == 0) {
@@ -925,11 +947,31 @@ mrb_io_sysseek(mrb_state *mrb, mrb_value io)
}
}
+static mrb_value mrb_io_syswrite_common(mrb_state *mrb,
+ mrb_io_read_write_size (*writefunc)(int, const void *, fsize_t, off_t),
+ mrb_value io, mrb_value buf, off_t offset);
+
+static mrb_io_read_write_size
+mrb_syswrite_dummy(int fd, const void *buf, fsize_t nbytes, off_t offset)
+{
+ return (mrb_io_read_write_size)write(fd, buf, nbytes);
+}
+
mrb_value
mrb_io_syswrite(mrb_state *mrb, mrb_value io)
{
+ mrb_value buf;
+
+ mrb_get_args(mrb, "S", &buf);
+
+ return mrb_io_syswrite_common(mrb, mrb_syswrite_dummy, io, buf, 0);
+}
+
+static mrb_value mrb_io_syswrite_common(mrb_state *mrb,
+ mrb_io_read_write_size (*writefunc)(int, const void *, fsize_t, off_t),
+ mrb_value io, mrb_value buf, off_t offset)
+{
struct mrb_io *fptr;
- mrb_value str, buf;
int fd, length;
fptr = io_get_open_fptr(mrb, io);
@@ -937,15 +979,12 @@ mrb_io_syswrite(mrb_state *mrb, mrb_value io)
mrb_raise(mrb, E_IO_ERROR, "not opened for writing");
}
- mrb_get_args(mrb, "S", &str);
- buf = str;
-
if (fptr->fd2 == -1) {
fd = fptr->fd;
} else {
fd = fptr->fd2;
}
- length = write(fd, RSTRING_PTR(buf), (fsize_t)RSTRING_LEN(buf));
+ length = writefunc(fd, RSTRING_PTR(buf), (fsize_t)RSTRING_LEN(buf), offset);
if (length == -1) {
mrb_sys_fail(mrb, 0);
}
@@ -1328,6 +1367,62 @@ mrb_io_sync(mrb_state *mrb, mrb_value self)
return mrb_bool_value(fptr->sync);
}
+#ifndef MRB_WITH_IO_PREAD_PWRITE
+# define mrb_io_pread mrb_notimplement_m
+# define mrb_io_pwrite mrb_notimplement_m
+#else
+static off_t
+value2off(mrb_state *mrb, mrb_value offv)
+{
+ switch (mrb_type(offv)) {
+#ifndef MRB_WITHOUT_FLOAT
+ case MRB_TT_FLOAT:
+ {
+ mrb_float tmp = mrb_float(offv);
+ if (tmp < INT64_MIN || tmp > INT64_MAX) {
+ /* fall through to use convert by `mrb_int()` (and raise error if out of range) */
+ } else {
+ return (off_t)tmp;
+ }
+ }
+ /* fall through */
+#endif /* MRB_WITHOUT_FLOAT */
+ default:
+ return (off_t)mrb_int(mrb, offv);
+ }
+}
+
+/*
+ * call-seq:
+ * pread(maxlen, offset, outbuf = "") -> outbuf
+ */
+static mrb_value
+mrb_io_pread(mrb_state *mrb, mrb_value io)
+{
+ mrb_value buf = mrb_nil_value();
+ mrb_value off;
+ mrb_int maxlen;
+
+ mrb_get_args(mrb, "io|S!", &maxlen, &off, &buf);
+
+ return mrb_io_sysread_common(mrb, pread, io, buf, maxlen, value2off(mrb, off));
+}
+
+/*
+ * call-seq:
+ * pwrite(buffer, offset) -> wrote_bytes
+ */
+static mrb_value
+mrb_io_pwrite(mrb_state *mrb, mrb_value io)
+{
+ mrb_value buf, off;
+
+ mrb_get_args(mrb, "So", &buf, &off);
+
+ return mrb_io_syswrite_common(mrb, pwrite, io, buf, value2off(mrb, off));
+}
+#endif /* MRB_WITH_IO_PREAD_PWRITE */
+
static mrb_value
io_bufread(mrb_state *mrb, mrb_value self)
{
@@ -1383,6 +1478,8 @@ mrb_init_io(mrb_state *mrb)
mrb_define_method(mrb, io, "closed?", mrb_io_closed, MRB_ARGS_NONE()); /* 15.2.20.5.2 */
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_m, MRB_ARGS_NONE());
+ mrb_define_method(mrb, io, "pread", mrb_io_pread, MRB_ARGS_ANY()); /* ruby 2.5 feature */
+ mrb_define_method(mrb, io, "pwrite", mrb_io_pwrite, MRB_ARGS_ANY()); /* ruby 2.5 feature */
mrb_define_class_method(mrb, io, "_bufread", io_bufread, MRB_ARGS_REQ(2));
}