-
-
Save sorah/69c544ec245f3a07aabd to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git io.c io.c | |
index 4e1945c..eeb9458 100644 | |
--- io.c | |
+++ io.c | |
@@ -805,6 +805,12 @@ struct binwrite_arg { | |
long length; | |
}; | |
+struct write_arg { | |
+ VALUE io; | |
+ VALUE str; | |
+ int nosync; | |
+}; | |
+ | |
static VALUE | |
io_binwrite_string(VALUE arg) | |
{ | |
@@ -8366,6 +8372,164 @@ rb_io_s_binread(int argc, VALUE *argv, VALUE io) | |
return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io); | |
} | |
+static VALUE | |
+io_s_write(struct write_arg *arg) | |
+{ | |
+ return io_write(arg->io,arg->str,arg->nosync); | |
+} | |
+ | |
+/* | |
+ * call-seq: | |
+ * IO.write(name, string, [offset] ) => fixnum | |
+ * IO.write(name, string, [offset], open_args ) => fixnum | |
+ * | |
+ * Opens the file, optionally seeks to the given <i>offset</i>, writes | |
+ * <i>string</i>, then returns the length written. | |
+ * <code>write</code> ensures the file is closed before returning. | |
+ * If <i>offset</i> is not given, the file is truncated. Otherwise, | |
+ * it is not truncated. | |
+ * | |
+ * If the last argument is a hash, it specifies option for internal | |
+ * open(). The key would be the following. open_args: is exclusive | |
+ * to others. | |
+ * | |
+ * encoding: string or encoding | |
+ * | |
+ * specifies encoding of the read string. encoding will be ignored | |
+ * if length is specified. | |
+ * | |
+ * mode: string | |
+ * | |
+ * specifies mode argument for open(). it should start with "w" or "a" or "r+" | |
+ * otherwise it would cause error. | |
+ * | |
+ * perm: fixnum | |
+ * | |
+ * specifies perm argument for open(). | |
+ * | |
+ * open_args: array of strings | |
+ * | |
+ * specifies arguments for open() as an array. | |
+ * | |
+ * IO.write("testfile", "0123456789") #=> "0123456789" | |
+ * IO.write("testfile", "0123456789", 20) #=> "This is line one\nThi0123456789two\nThis is line three\nAnd so on...\n" | |
+ */ | |
+ | |
+static VALUE | |
+rb_io_s_write(int argc, VALUE *argv, VALUE io) | |
+{ | |
+ VALUE opt, offset, string; | |
+ struct foreach_arg arg; | |
+ struct write_arg warg; | |
+ | |
+ rb_scan_args(argc, argv, "21:", NULL, &string, &offset, &opt); | |
+ | |
+ if (NIL_P(opt)) opt = rb_hash_new(); | |
+ else opt = rb_hash_dup(opt); | |
+ | |
+ if (NIL_P(rb_hash_aref(opt,sym_mode))) { | |
+ if (NIL_P(offset)) { | |
+ rb_hash_aset(opt,sym_mode,INT2NUM(O_WRONLY|O_TRUNC|O_CREAT)); | |
+ } | |
+ else{ | |
+ rb_hash_aset(opt,sym_mode,INT2NUM(O_WRONLY|O_CREAT)); | |
+ } | |
+ } | |
+ | |
+ open_key_args(argc,argv,opt,&arg); | |
+ | |
+ if (NIL_P(arg.io)) return Qnil; | |
+ if (!NIL_P(offset)) { | |
+ struct seek_arg sarg; | |
+ int state = 0; | |
+ sarg.io = arg.io; | |
+ sarg.offset = offset; | |
+ sarg.mode = SEEK_SET; | |
+ rb_protect(seek_before_access, (VALUE)&sarg, &state); | |
+ if (state) { | |
+ rb_io_close(arg.io); | |
+ rb_jump_tag(state); | |
+ } | |
+ } | |
+ | |
+ warg.io = arg.io; | |
+ warg.str = string; | |
+ warg.nosync = 0; | |
+ | |
+ return rb_ensure(io_s_write, (VALUE)&warg, rb_io_close, arg.io); | |
+} | |
+ | |
+/* | |
+ * call-seq: | |
+ * IO.binwrite(name, string, [offset] ) => fixnum | |
+ * | |
+ * Opens the file, optionally seeks to the given <i>offset</i>, write | |
+ * <i>string</i> then returns the length written. | |
+ * <code>binwrite</code> ensures the file is closed before returning. | |
+ * The open mode would be "wb:ASCII-8BIT". | |
+ * If <i>offset</i> is not given, the file is truncated. Otherwise, | |
+ * it is not truncated. | |
+ * | |
+ * IO.binwrite("testfile", "0123456789") #=> "0123456789" | |
+ * IO.binwrite("testfile", "0123456789", 20) #=> "This is line one\nThi0123456789two\nThis is line three\nAnd so on...\n" | |
+ */ | |
+ | |
+static VALUE | |
+rb_io_s_binwrite(int argc, VALUE *argv, VALUE io) | |
+{ | |
+ VALUE path, string, offset, opt; | |
+ struct foreach_arg arg; | |
+ struct write_arg warg; | |
+ | |
+ rb_scan_args(argc, argv, "21:", &path, &string, &offset, &opt); | |
+ | |
+ if (NIL_P(opt)) opt = rb_hash_new(); | |
+ else opt = rb_hash_dup(opt); | |
+ | |
+ if (NIL_P(rb_hash_aref(opt,sym_mode))) { | |
+ if (NIL_P(offset)) { | |
+#ifdef O_BINARY | |
+ rb_hash_aset(opt,sym_mode,INT2NUM(O_WRONLY|O_TRUNC|O_CREAT|O_BINARY)); | |
+#else | |
+ rb_hash_aset(opt,sym_mode,INT2NUM(O_WRONLY|O_TRUNC|O_CREAT)); | |
+#endif | |
+ } | |
+ else{ | |
+#ifdef O_BINARY | |
+ rb_hash_aset(opt,sym_mode,INT2NUM(O_WRONLY|O_CREAT|O_BINARY)); | |
+#else | |
+ rb_hash_aset(opt,sym_mode,INT2NUM(O_WRONLY|O_CREAT)); | |
+#endif | |
+ } | |
+ } | |
+ | |
+ open_key_args(argc,argv,opt,&arg); | |
+ if (NIL_P(arg.io)) return Qnil; | |
+ | |
+#ifndef O_BINARY | |
+ rb_io_binmode_m(arg.io); | |
+#endif | |
+ | |
+ if(!NIL_P(offset)) { | |
+ struct seek_arg sarg; | |
+ int state = 0; | |
+ sarg.io = arg.io; | |
+ sarg.offset = offset; | |
+ sarg.mode = SEEK_SET; | |
+ rb_protect(seek_before_access, (VALUE)&sarg, &state); | |
+ if (state) { | |
+ rb_io_close(arg.io); | |
+ rb_jump_tag(state); | |
+ } | |
+ } | |
+ | |
+ warg.io = arg.io; | |
+ warg.str = string; | |
+ warg.nosync = 0; | |
+ | |
+ return rb_ensure(io_s_write, (VALUE)&warg, rb_io_close, arg.io); | |
+} | |
+ | |
struct copy_stream_struct { | |
VALUE src; | |
VALUE dst; | |
@@ -10315,6 +10479,8 @@ Init_IO(void) | |
rb_define_singleton_method(rb_cIO, "readlines", rb_io_s_readlines, -1); | |
rb_define_singleton_method(rb_cIO, "read", rb_io_s_read, -1); | |
rb_define_singleton_method(rb_cIO, "binread", rb_io_s_binread, -1); | |
+ rb_define_singleton_method(rb_cIO, "write", rb_io_s_write, -1); | |
+ rb_define_singleton_method(rb_cIO, "binwrite", rb_io_s_binwrite, -1); | |
rb_define_singleton_method(rb_cIO, "select", rb_f_select, -1); | |
rb_define_singleton_method(rb_cIO, "pipe", rb_io_s_pipe, -1); | |
rb_define_singleton_method(rb_cIO, "try_convert", rb_io_s_try_convert, 1); | |
diff --git test/ruby/test_io.rb test/ruby/test_io.rb | |
index f919227..8aaecd1 100644 | |
--- test/ruby/test_io.rb | |
+++ test/ruby/test_io.rb | |
@@ -1861,4 +1861,61 @@ End | |
end | |
end | |
+ def test_s_write | |
+ t = Tempfile.new("foo") | |
+ path = t.path | |
+ t.close(false) | |
+ File.write(path, "foo\nbar\nbaz") | |
+ assert_equal("foo\nbar\nbaz", File.read(path)) | |
+ File.write(path, "FOO", 0) | |
+ assert_equal("FOO\nbar\nbaz", File.read(path)) | |
+ File.write(path, "BAR") | |
+ assert_equal("BAR", File.read(path)) | |
+ File.write(path, "\u{3042}", mode: "w", encoding: "EUC-JP") | |
+ assert_equal("\u{3042}".encode("EUC-JP"), File.read(path, encoding: "EUC-JP")) | |
+ File.delete t | |
+ assert_equal(6, File.write(path,'string',2)) | |
+ File.delete t | |
+ assert_raise(Errno::EINVAL) { File.write('/tmp/nonexisting','string',-2) } | |
+ assert_equal(6, File.write(path, 'string')) | |
+ assert_equal(3, File.write(path, 'sub', 1)) | |
+ assert_equal("ssubng", File.read(path)) | |
+ File.delete t | |
+ assert_equal(3, File.write(path, "foo", encoding: "UTF-8")) | |
+ File.delete t | |
+ assert_equal(3, File.write(path, "foo", 0, encoding: "UTF-8")) | |
+ assert_equal("foo", File.read(path)) | |
+ assert_equal(1, File.write(path, "f", 1, encoding: "UTF-8")) | |
+ assert_equal("ffo", File.read(path)) | |
+ File.delete t | |
+ assert_equal(1, File.write(path, "f", 1, encoding: "UTF-8")) | |
+ assert_equal("\00f", File.read(path)) | |
+ assert_equal(1, File.write(path, "f", 0, encoding: "UTF-8")) | |
+ assert_equal("ff", File.read(path)) | |
+ t.unlink | |
+ end | |
+ | |
+ def test_s_binwrite | |
+ t = Tempfile.new("foo") | |
+ path = t.path | |
+ t.close(false) | |
+ File.binwrite(path, "foo\nbar\nbaz") | |
+ assert_equal("foo\nbar\nbaz", File.read(path)) | |
+ File.binwrite(path, "FOO", 0) | |
+ assert_equal("FOO\nbar\nbaz", File.read(path)) | |
+ File.binwrite(path, "BAR") | |
+ assert_equal("BAR", File.read(path)) | |
+ File.binwrite(path, "\u{3042}") | |
+ assert_equal("\u{3042}".force_encoding("ASCII-8BIT"), File.binread(path)) | |
+ File.delete t | |
+ assert_equal(6, File.binwrite(path,'string',2)) | |
+ File.delete t | |
+ assert_equal(6, File.binwrite(path, 'string')) | |
+ assert_equal(3, File.binwrite(path, 'sub', 1)) | |
+ assert_equal("ssubng", File.binread(path)) | |
+ assert_equal(6, File.size(path)) | |
+ assert_raise(Errno::EINVAL) { File.binwrite('/tmp/nonexisting','string',-2) } | |
+ assert_nothing_raised(TypeError) { File.binwrite(path, "string", mode: "w", encoding: "EUC-JP") } | |
+ t.unlink | |
+ end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment