/* * call-seq: * ios.read([length [, buffer]]) => string, buffer, or nil * * Reads at most <i>length</i> bytes from the I/O stream, or to the * end of file if <i>length</i> is omitted or is <code>nil</code>. * <i>length</i> must be a non-negative integer or nil. * If the optional <i>buffer</i> argument is present, it must reference * a String, which will receive the data. * * At end of file, it returns <code>nil</code> or <code>""</code> * depend on <i>length</i>. * <code><i>ios</i>.read()</code> and * <code><i>ios</i>.read(nil)</code> returns <code>""</code>. * <code><i>ios</i>.read(<i>positive-integer</i>)</code> returns nil. * * f = File.new("testfile") * f.read(16) #=> "This is line one" */ static VALUE io_read(argc, argv, io) int argc; VALUE *argv; VALUE io; { OpenFile *fptr; long n, len; VALUE length, str; rb_scan_args(argc, argv, "02", &length, &str); if (NIL_P(length)) { if (!NIL_P(str)) StringValue(str); GetOpenFile(io, fptr); rb_io_check_readable(fptr); return read_all(fptr, remain_size(fptr), str); } len = NUM2LONG(length); if (len < 0) { rb_raise(rb_eArgError, "negative length %ld given", len); } if (NIL_P(str)) { str = rb_tainted_str_new(0, len); } else { StringValue(str); rb_str_modify(str); rb_str_resize(str,len); } GetOpenFile(io, fptr); rb_io_check_readable(fptr); if (feof(fptr->f)) return Qnil; if (len == 0) return str; rb_str_locktmp(str); READ_CHECK(fptr->f); if (RSTRING(str)->len != len) { rb_raise(rb_eRuntimeError, "buffer string modified"); } n = io_fread(RSTRING(str)->ptr, len, fptr); rb_str_unlocktmp(str); if (n == 0) { if (!fptr->f) return Qnil; if (feof(fptr->f)) { rb_str_resize(str, 0); return Qnil; } if (len > 0) rb_sys_fail(fptr->path); } rb_str_resize(str, n); RSTRING(str)->len = n; RSTRING(str)->ptr[n] = '\0'; OBJ_TAINT(str); return str; }