/* * 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; }