/*
* call-seq:
* strio.read([length [, buffer]]) -> string, buffer, or nil
*
* See IO#read.
*/
static VALUE
strio_read(argc, argv, self)
int argc;
VALUE *argv;
VALUE self;
{
struct StringIO *ptr = readable(StringIO(self));
VALUE str = Qnil;
long len, olen;
switch (argc) {
case 2:
str = argv[1];
StringValue(str);
rb_str_modify(str);
case 1:
if (!NIL_P(argv[0])) {
len = olen = NUM2LONG(argv[0]);
if (len < 0) {
rb_raise(rb_eArgError, "negative length %ld given", len);
}
if (len > 0 && ptr->pos >= RSTRING(ptr->string)->len) {
ptr->flags |= STRIO_EOF;
if (!NIL_P(str)) rb_str_resize(str, 0);
return Qnil;
}
else if (ptr->flags & STRIO_EOF) {
if (!NIL_P(str)) rb_str_resize(str, 0);
return Qnil;
}
break;
}
/* fall through */
case 0:
olen = -1;
len = RSTRING(ptr->string)->len;
if (len <= ptr->pos) {
ptr->flags |= STRIO_EOF;
if (NIL_P(str)) {
str = rb_str_new(0, 0);
}
else {
rb_str_resize(str, 0);
}
return str;
}
else {
len -= ptr->pos;
}
break;
default:
rb_raise(rb_eArgError, "wrong number of arguments (%d for 0)", argc);
}
if (NIL_P(str)) {
str = rb_str_substr(ptr->string, ptr->pos, len);
}
else {
long rest = RSTRING(ptr->string)->len - ptr->pos;
if (len > rest) len = rest;
rb_str_resize(str, len);
MEMCPY(RSTRING(str)->ptr, RSTRING(ptr->string)->ptr + ptr->pos, char, len);
}
if (NIL_P(str)) {
if (!(ptr->flags & STRIO_EOF)) str = rb_str_new(0, 0);
len = 0;
}
else {
ptr->pos += len = RSTRING(str)->len;
}
if (olen < 0 || olen > len) ptr->flags |= STRIO_EOF;
return str;
}