diff options
| author | Yukihiro "Matz" Matsumoto <[email protected]> | 2020-03-07 19:07:13 +0900 |
|---|---|---|
| committer | Yukihiro "Matz" Matsumoto <[email protected]> | 2020-03-07 19:07:13 +0900 |
| commit | 4398bae56a04a6ac1ac7f49935075bcbd8f50872 (patch) | |
| tree | 59ac85c717351487c77d4f7e81e5cfca2cf97be3 | |
| parent | f45549edbfd2131e40363af93ee14e73694f3d20 (diff) | |
| parent | 20f9128f732c3f4f51834fc0096abb0382cc4837 (diff) | |
| download | mruby-4398bae56a04a6ac1ac7f49935075bcbd8f50872.tar.gz mruby-4398bae56a04a6ac1ac7f49935075bcbd8f50872.zip | |
Merge branch 'dearblue-io-pread-pwrite'
| -rw-r--r-- | mrbgems/mruby-io/include/mruby/ext/io.h | 8 | ||||
| -rw-r--r-- | mrbgems/mruby-io/src/file.c | 2 | ||||
| -rw-r--r-- | mrbgems/mruby-io/src/io.c | 114 | ||||
| -rw-r--r-- | mrbgems/mruby-io/test/io.rb | 28 | ||||
| -rw-r--r-- | mrbgems/mruby-io/test/mruby_io_test.c | 9 |
5 files changed, 150 insertions, 11 deletions
diff --git a/mrbgems/mruby-io/include/mruby/ext/io.h b/mrbgems/mruby-io/include/mruby/ext/io.h index 4bcbbe914..c4eccb936 100644 --- a/mrbgems/mruby-io/include/mruby/ext/io.h +++ b/mrbgems/mruby-io/include/mruby/ext/io.h @@ -9,6 +9,14 @@ extern "C" { #endif +#if defined(MRB_WITHOUT_IO_PREAD_PWRITE) +# undef MRB_WITH_IO_PREAD_PWRITE +#elif !defined(MRB_WITH_IO_PREAD_PWRITE) +# if defined(__unix__) +# define MRB_WITH_IO_PREAD_PWRITE +# endif +#endif + struct mrb_io { int fd; /* file descriptor, or -1 */ int fd2; /* file descriptor to write if it's different from fd, or -1 */ diff --git a/mrbgems/mruby-io/src/file.c b/mrbgems/mruby-io/src/file.c index ffce0ddcb..3f3b6bb25 100644 --- a/mrbgems/mruby-io/src/file.c +++ b/mrbgems/mruby-io/src/file.c @@ -284,7 +284,7 @@ mrb_file_is_absolute_path(const char *path) { #ifdef _WIN32 #define IS_PATHSEP(x) (x == '/' || x == '\\') - if (isalpha(path[0])) + if (ISALPHA(path[0])) return (strlen(path) > 2 && path[1] == ':' && IS_PATHSEP(path[2])); else return (IS_PATHSEP(path[0]) && IS_PATHSEP(path[1])); diff --git a/mrbgems/mruby-io/src/io.c b/mrbgems/mruby-io/src/io.c index e28946597..41d6b6120 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 @@ -44,6 +45,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 @@ -846,15 +848,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"); } @@ -876,7 +898,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) { @@ -926,11 +948,12 @@ mrb_io_sysseek(mrb_state *mrb, mrb_value io) } } -mrb_value -mrb_io_syswrite(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) { struct mrb_io *fptr; - mrb_value str, buf; int fd, length; fptr = io_get_open_fptr(mrb, io); @@ -938,15 +961,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); } @@ -954,6 +974,22 @@ mrb_io_syswrite(mrb_state *mrb, mrb_value io) return mrb_fixnum_value(length); } +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); +} + mrb_value mrb_io_close(mrb_state *mrb, mrb_value self) { @@ -1329,6 +1365,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) { @@ -1384,6 +1476,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)); } diff --git a/mrbgems/mruby-io/test/io.rb b/mrbgems/mruby-io/test/io.rb index e3024cf9a..458d2cdc2 100644 --- a/mrbgems/mruby-io/test/io.rb +++ b/mrbgems/mruby-io/test/io.rb @@ -564,6 +564,34 @@ assert('IO#sysseek') do end end +assert('IO#pread') do + skip "IO#pread is not implemented on this configuration" unless MRubyIOTestUtil::MRB_WITH_IO_PREAD_PWRITE + + IO.open(IO.sysopen($mrbtest_io_rfname, 'r'), 'r') do |io| + assert_equal $mrbtest_io_msg.byteslice(5, 8), io.pread(8, 5) + assert_equal 0, io.pos + assert_equal $mrbtest_io_msg.byteslice(1, 5), io.pread(5, 1) + assert_equal 0, io.pos + assert_raise(RuntimeError) { io.pread(20, -9) } + end +end + +assert('IO#pwrite') do + skip "IO#pwrite is not implemented on this configuration" unless MRubyIOTestUtil::MRB_WITH_IO_PREAD_PWRITE + + IO.open(IO.sysopen($mrbtest_io_wfname, 'w+'), 'w+') do |io| + assert_equal 6, io.pwrite("Warld!", 7) + assert_equal 0, io.pos + assert_equal 7, io.pwrite("Hello, ", 0) + assert_equal 0, io.pos + assert_equal "Hello, Warld!", io.read + assert_equal 6, io.pwrite("world!", 7) + assert_equal 13, io.pos + io.pos = 0 + assert_equal "Hello, world!", io.read + end +end + assert('IO.pipe') do begin called = false diff --git a/mrbgems/mruby-io/test/mruby_io_test.c b/mrbgems/mruby-io/test/mruby_io_test.c index 7e272d45a..581472eaa 100644 --- a/mrbgems/mruby-io/test/mruby_io_test.c +++ b/mrbgems/mruby-io/test/mruby_io_test.c @@ -64,6 +64,7 @@ mkdtemp(char *temp) #include "mruby/error.h" #include "mruby/string.h" #include "mruby/variable.h" +#include <mruby/ext/io.h> static mrb_value mrb_io_test_io_setup(mrb_state *mrb, mrb_value self) @@ -219,6 +220,12 @@ mrb_io_win_p(mrb_state *mrb, mrb_value klass) #endif } +#ifdef MRB_WITH_IO_PREAD_PWRITE +# define MRB_WITH_IO_PREAD_PWRITE_ENABLED TRUE +#else +# define MRB_WITH_IO_PREAD_PWRITE_ENABLED FALSE +#endif + void mrb_mruby_io_gem_test(mrb_state* mrb) { @@ -229,4 +236,6 @@ mrb_mruby_io_gem_test(mrb_state* mrb) mrb_define_class_method(mrb, io_test, "mkdtemp", mrb_io_test_mkdtemp, MRB_ARGS_REQ(1)); mrb_define_class_method(mrb, io_test, "rmdir", mrb_io_test_rmdir, MRB_ARGS_REQ(1)); mrb_define_class_method(mrb, io_test, "win?", mrb_io_win_p, MRB_ARGS_NONE()); + + mrb_define_const(mrb, io_test, "MRB_WITH_IO_PREAD_PWRITE", mrb_bool_value(MRB_WITH_IO_PREAD_PWRITE_ENABLED)); } |
