new.diff

Roger Pack, 04/29/2010 03:42 AM

Download (9.02 KB)

View differences:

io.c (working copy)
7779 7779
};
7780 7780

  
7781 7781
static void
7782
open_key_args(int argc, VALUE *argv, struct foreach_arg *arg)
7782
open_key_args_with_opt(int argc, VALUE *argv, struct foreach_arg *arg, int mandatory_argc, int default_mode, int default_perm)
7783 7783
{
7784 7784
    VALUE opt, v;
7785 7785

  
......
7787 7787
    arg->io = 0;
7788 7788
    arg->argc = argc - 1;
7789 7789
    arg->argv = argv + 1;
7790
    if (argc == 1) {
7790
    if (argc == mandatory_argc) {
7791 7791
      no_key:
7792
	arg->io = rb_io_open(argv[0], INT2NUM(O_RDONLY), INT2FIX(0666), Qnil);
7792
	arg->io = rb_io_open(argv[0], INT2NUM(default_mode), INT2FIX(default_perm), Qnil);
7793 7793
	return;
7794 7794
    }
7795 7795
    opt = pop_last_hash(&arg->argc, arg->argv);
......
7814 7814
	rb_ary_clear(args);	/* prevent from GC */
7815 7815
	return;
7816 7816
    }
7817
    if (default_mode != O_RDONLY && NIL_P(rb_hash_aref(opt, sym_mode))) {
7818
	opt = rb_hash_dup(opt);
7819
	rb_hash_aset(opt, sym_mode, INT2NUM(default_mode));
7820
    }
7821
    if (default_perm != 0666 && NIL_P(rb_hash_aref(opt, sym_perm))) {
7822
	opt = rb_hash_dup(opt);
7823
	rb_hash_aset(opt, sym_perm, INT2FIX(default_perm));
7824
    }
7817 7825
    arg->io = rb_io_open(argv[0], Qnil, Qnil, opt);
7818 7826
}
7819 7827

  
7828
static void
7829
open_key_args(int argc, VALUE *argv, struct foreach_arg *arg)
7830
{
7831
    open_key_args_with_opt(argc, argv, arg, 1, O_RDONLY, 0666);
7832
}
7833

  
7820 7834
static VALUE
7821 7835
io_s_foreach(struct foreach_arg *arg)
7822 7836
{
......
7904 7918
    return io_read(arg->argc, arg->argv, arg->io);
7905 7919
}
7906 7920

  
7921
struct write_arg {
7922
    VALUE io, str;
7923
};
7924

  
7925
static VALUE
7926
io_s_write(struct write_arg *arg)
7927
{
7928
    return io_write(arg->io, arg->str, 0);
7929
}
7930

  
7907 7931
struct seek_arg {
7908 7932
    VALUE io;
7909 7933
    VALUE offset;
......
7911 7935
};
7912 7936

  
7913 7937
static VALUE
7914
seek_before_read(struct seek_arg *arg)
7938
seek_before_access(struct seek_arg *arg)
7915 7939
{
7916 7940
    rb_io_binmode(arg->io);
7917 7941
    return rb_io_seek(arg->io, arg->offset, arg->mode);
......
7922 7946
 *     IO.read(name, [length [, offset]] )   => string
7923 7947
 *     IO.read(name, [length [, offset]], open_args)   => string
7924 7948
 *
7925
 *  Opens the file, optionally seeks to the given offset, then returns
7949
 *  Opens the file, optionally seeks to the given <i>offset</i>, then returns
7926 7950
 *  <i>length</i> bytes (defaulting to the rest of the file).
7927 7951
 *  <code>read</code> ensures the file is closed before returning.
7928 7952
 *
......
7964 7988
	sarg.io = arg.io;
7965 7989
	sarg.offset = offset;
7966 7990
	sarg.mode = SEEK_SET;
7967
	rb_protect((VALUE (*)(VALUE))seek_before_read, (VALUE)&sarg, &state);
7991
	rb_protect((VALUE (*)(VALUE))seek_before_access, (VALUE)&sarg, &state);
7968 7992
	if (state) {
7969 7993
	    rb_io_close(arg.io);
7970 7994
	    rb_jump_tag(state);
......
7978 8002
 *  call-seq:
7979 8003
 *     IO.binread(name, [length [, offset]] )   => string
7980 8004
 *
7981
 *  Opens the file, optionally seeks to the given offset, then returns
8005
 *  Opens the file, optionally seeks to the given <i>offset</i>, then returns
7982 8006
 *  <i>length</i> bytes (defaulting to the rest of the file).
7983
 *  <code>read</code> ensures the file is closed before returning.
8007
 *  <code>binread</code> ensures the file is closed before returning.
7984 8008
 *  The open mode would be "rb:ASCII-8BIT".
7985 8009
 *
7986 8010
 *     IO.binread("testfile")           #=> "This is line one\nThis is line two\nThis is line three\nAnd so on...\n"
......
8006 8030
    return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
8007 8031
}
8008 8032

  
8033
/*
8034
 *  call-seq:
8035
 *     IO.write(name, string, [offset] )   => fixnum
8036
 *     IO.write(name, string, [offset], open_args )   => fixnum
8037
 *
8038
 *  Opens the file, optionally seeks to the given <i>offset</i>, writes
8039
 *  <i>string</i>, then returns the length written.
8040
 *  <code>write</code> ensures the file is closed before returning.
8041
 *  If <i>offset</i> is not given, the file is truncated.  Otherwise,
8042
 *  it is not truncated.
8043
 *
8044
 *  If the last argument is a hash, it specifies option for internal
8045
 *  open().  The key would be the following.  open_args: is exclusive
8046
 *  to others.
8047
 *
8048
 *   encoding: string or encoding
8049
 *
8050
 *    specifies encoding of the read string.  encoding will be ignored
8051
 *    if length is specified.
8052
 *
8053
 *   mode: string
8054
 *
8055
 *    specifies mode argument for open().  it should start with "w" or "a" or "r+"
8056
 *    otherwise it would cause error.
8057
 *
8058
 *   perm: fixnum
8059
 *
8060
 *    specifies perm argument for open().
8061
 *
8062
 *   open_args: array of strings
8063
 *
8064
 *    specifies arguments for open() as an array.
8065
 *
8066
 *     IO.write("testfile", "0123456789")      #=> "0123456789"
8067
 *     IO.write("testfile", "0123456789", 20)  #=> "This is line one\nThi0123456789two\nThis is line three\nAnd so on...\n"
8068
 */
8069

  
8070
static VALUE
8071
rb_io_s_write(int argc, VALUE *argv, VALUE io)
8072
{
8073
    VALUE offset;
8074
    struct foreach_arg arg;
8075
    struct write_arg warg;
8076
    int mode = O_WRONLY | O_CREAT, mandatory_argc;
8077

  
8078
    rb_scan_args(argc, argv, "22", NULL, &warg.str, &offset, NULL);
8079
    if (!NIL_P(offset) && FIXNUM_P(offset)) {
8080
	mandatory_argc = 3;
8081
    }
8082
    else {
8083
	mode |= O_TRUNC;
8084
	mandatory_argc = 2;
8085
    }
8086
    open_key_args_with_opt(argc, argv, &arg, mandatory_argc, mode, 0666);
8087
    if (NIL_P(arg.io)) return Qnil;
8088
    if (!NIL_P(offset) && FIXNUM_P(offset)) {
8089
	struct seek_arg sarg;
8090
	int state = 0;
8091
	sarg.io = arg.io;
8092
	sarg.offset = offset;
8093
	sarg.mode = SEEK_SET;
8094
	rb_protect((VALUE (*)(VALUE))seek_before_access, (VALUE)&sarg, &state);
8095
	if (state) {
8096
	    rb_io_close(arg.io);
8097
	    rb_jump_tag(state);
8098
	}
8099
	if (arg.argc == 2) arg.argc = 1;
8100
    }
8101
    warg.io = arg.io;
8102
    return rb_ensure(io_s_write, (VALUE)&warg, rb_io_close, arg.io);
8103
}
8104

  
8105
/*
8106
 *  call-seq:
8107
 *     IO.binwrite(name, string, [offset] )   => fixnum
8108
 *
8109
 *  Opens the file, optionally seeks to the given <i>offset</i>, write
8110
 *  <i>string</i> then returns the length written.
8111
 *  <code>binwrite</code> ensures the file is closed before returning.
8112
 *  The open mode would be "wb:ASCII-8BIT".
8113
 *  If <i>offset</i> is not given, the file is truncated.  Otherwise,
8114
 *  it is not truncated.
8115
 *
8116
 *     IO.binwrite("testfile", "0123456789")      #=> "0123456789"
8117
 *     IO.binwrite("testfile", "0123456789", 20)  #=> "This is line one\nThi0123456789two\nThis is line three\nAnd so on...\n"
8118
 */
8119

  
8120
static VALUE
8121
rb_io_s_binwrite(int argc, VALUE *argv, VALUE io)
8122
{
8123
    VALUE offset;
8124
    const char *mode;
8125
    struct write_arg warg;
8126

  
8127
    rb_scan_args(argc, argv, "21", NULL, &warg.str, &offset);
8128
    if (!NIL_P(offset)) {
8129
	NUM2OFFT(offset);
8130
	mode = "ab:ASCII-8BIT";
8131
    }
8132
    else {
8133
	mode = "wb:ASCII-8BIT";
8134
    }
8135
    FilePathValue(argv[0]);
8136
    warg.io = rb_io_open(argv[0], rb_str_new_cstr(mode), Qnil, Qnil);
8137
    if (NIL_P(warg.io)) return Qnil;
8138
    if (!NIL_P(offset)) {
8139
	rb_io_seek(warg.io, offset, SEEK_SET);
8140
    }
8141
    return rb_ensure(io_s_write, (VALUE)&warg, rb_io_close, warg.io);
8142
}
8143

  
8009 8144
struct copy_stream_struct {
8010 8145
    VALUE src;
8011 8146
    VALUE dst;
......
9809 9944
    rb_define_singleton_method(rb_cIO, "readlines", rb_io_s_readlines, -1);
9810 9945
    rb_define_singleton_method(rb_cIO, "read", rb_io_s_read, -1);
9811 9946
    rb_define_singleton_method(rb_cIO, "binread", rb_io_s_binread, -1);
9947
    rb_define_singleton_method(rb_cIO, "write", rb_io_s_write, -1);
9948
    rb_define_singleton_method(rb_cIO, "binwrite", rb_io_s_binwrite, -1);
9812 9949
    rb_define_singleton_method(rb_cIO, "select", rb_f_select, -1);
9813 9950
    rb_define_singleton_method(rb_cIO, "pipe", rb_io_s_pipe, -1);
9814 9951
    rb_define_singleton_method(rb_cIO, "try_convert", rb_io_s_try_convert, 1);
test/ruby/test_io.rb (working copy)
1582 1582
    t.close
1583 1583
    assert_raise(IOError) {t.binmode}
1584 1584
  end
1585

  
1586
  def test_s_write
1587
    t = Tempfile.new("foo")
1588
    path = t.path
1589
    t.close(false)
1590
    File.write(path, "foo\nbar\nbaz")
1591
    assert("foo\nbar\nbaz", File.read(path))
1592
    File.write(path, "FOO", 0)
1593
    assert("FOO\nbar\nbaz", File.read(path))
1594
    File.write(path, "BAR")
1595
    assert("BAR", File.read(path))
1596
    File.write(path, "\u{3042}", mode: "w", encoding: "EUC-JP")
1597
    assert("\u{3042}".encode("EUC-JP"), File.read(path, encoding: "EUC-JP"))
1598
    File.delete t
1599
    assert(6, File.write(path,'string',2))
1600
    File.delete t
1601
    assert_raise(Errno::EINVAL) { File.write('/tmp/offset','string',-2) }
1602
    File.write(path, 'string')
1603
    File.write(path, 'string', 1)
1604
    assert("sstring", File.read(path))
1605
    t.unlink
1606
  end
1607

  
1608
  def test_s_binwrite
1609
    t = Tempfile.new("foo")
1610
    path = t.path
1611
    t.close(false)
1612
    File.binwrite(path, "foo\nbar\nbaz")
1613
    assert("foo\nbar\nbaz", File.read(path))
1614
    File.binwrite(path, "FOO", 0)
1615
    assert("FOO\nbar\nbaz", File.read(path))
1616
    File.binwrite(path, "BAR")
1617
    assert("BAR", File.read(path))
1618
    File.binwrite(path, "\u{3042}")
1619
    assert("\u{3042}", File.read(path, encoding: "EUC-JP"))
1620
    File.delete t
1621
    assert(6, File.binwrite(path,'string',2))
1622
    File.delete t
1623
    File.write(path, 'string')
1624
    File.write(path, 'string', 1)
1625
    assert("sstring", File.binread(path))
1626
    assert_raise(Errno::EINVAL) { File.binwrite('/tmp/offset','string',-2) }
1627
    t.unlink
1628
  end
1585 1629
end