Class: StringIO

Class | StringIO
In: | stringio/stringio.c
Parent: | Data

Pseudo I/O on String object.

### Methods

<< binmode close close_read close_write closed? closed_read? closed_write? each each_byte each_line eof eof? fcntl fileno flush fsync getc gets initialize_copy isatty length lineno lineno= new open path pid pos pos= print printf putc puts read readchar readline readlines reopen rewind seek size string string= sync sync= sysread syswrite tell truncate tty? ungetc write

### Included Modules

Enumerable

### Public Class methods

StringIO.new(string=""[, mode])

Creates new StringIO instance from with string and mode.

[Source]

    /*
     * call-seq: StringIO.new(string=""[, mode])
     *
     * Creates new StringIO instance from with _string_ and _mode_.
     */
    static VALUE
    strio_initialize(argc, argv, self)
        int argc;
        VALUE *argv;
        VALUE self;
    {
        struct StringIO *ptr = check_strio(self);
        VALUE string, mode;
        int trunc = Qfalse;

        if (!ptr) {
    	DATA_PTR(self) = ptr = strio_alloc();
        }
        rb_call_super(0, 0);
        switch (rb_scan_args(argc, argv, "02", &string, &mode)) {
          case 2:
    	if (FIXNUM_P(mode)) {
    	    int flags = FIX2INT(mode);
    	    ptr->flags = rb_io_modenum_flags(flags);
    	    trunc = flags & O_TRUNC;
    	}
    	else {
    	    const char *m = StringValueCStr(mode);
    	    ptr->flags = rb_io_mode_flags(m);
    	    trunc = *m == 'w';
    	}
    	StringValue(string);
    	if ((ptr->flags & FMODE_WRITABLE) && OBJ_FROZEN(string)) {
    	    errno = EACCES;
    	    rb_sys_fail(0);
    	}
    	if (trunc) {
    	    rb_str_resize(string, 0);
    	}
    	break;
          case 1:
    	StringValue(string);
    	ptr->flags = OBJ_FROZEN(string) ? FMODE_READABLE : FMODE_READWRITE;
    	break;
          case 0:
    	string = rb_str_new("", 0);
    	ptr->flags = FMODE_READWRITE;
    	break;
        }
        ptr->string = string;
        return self;
    }

StringIO.open(string=""[, mode]) {|strio| ...}

Equivalent to StringIO.new except that when it is called with a block, it yields with the new instance and closes it, and returns the result which returned from the block.

[Source]

    /*
     * call-seq: StringIO.open(string=""[, mode]) {|strio| ...}
     *
     * Equivalent to StringIO.new except that when it is called with a block, it
     * yields with the new instance and closes it, and returns the result which
     * returned from the block.
     */
    static VALUE
    strio_s_open(argc, argv, klass)
        int argc;
        VALUE *argv;
        VALUE klass;
    {
        VALUE obj = rb_class_new_instance(argc, argv, klass);
        if (!rb_block_given_p()) return obj;
        return rb_ensure(rb_yield, obj, strio_finalize, obj);
    }

### Public Instance methods

<<(p1)
binmode()
strio.close → nil

Closes strio. The strio is unavailable for any further data operations; an `IOError` is raised if such an attempt is made.

[Source]

    /*
     * call-seq:
     *   strio.close  -> nil
     *
     * Closes strio.  The *strio* is unavailable for any further data
     * operations; an +IOError+ is raised if such an attempt is made.
     */
    static VALUE
    strio_close(self)
        VALUE self;
    {
        struct StringIO *ptr = StringIO(self);
        if (CLOSED(ptr)) {
    	rb_raise(rb_eIOError, "closed stream");
        }
        ptr->flags &= ~FMODE_READWRITE;
        return Qnil;
    }

strio.close_read → nil

Closes the read end of a StringIO. Will raise an `IOError` if the strio is not readable.

[Source]

    /*
     * call-seq:
     *   strio.close_read    -> nil
     *
     * Closes the read end of a StringIO.  Will raise an +IOError+ if the
     * *strio* is not readable.
     */
    static VALUE
    strio_close_read(self)
        VALUE self;
    {
        struct StringIO *ptr = StringIO(self);
        if (!READABLE(ptr)) {
    	rb_raise(rb_eIOError, "closing non-duplex IO for reading");
        }
        ptr->flags &= ~FMODE_READABLE;
        return Qnil;
    }

strio.close_write → nil

Closes the write end of a StringIO. Will raise an `IOError` if the strio is not writeable.

[Source]

    /*
     * call-seq:
     *   strio.close_write    -> nil
     *
     * Closes the write end of a StringIO.  Will raise an  +IOError+ if the
     * *strio* is not writeable.
     */
    static VALUE
    strio_close_write(self)
        VALUE self;
    {
        struct StringIO *ptr = StringIO(self);
        if (!WRITABLE(ptr)) {
    	rb_raise(rb_eIOError, "closing non-duplex IO for writing");
        }
        ptr->flags &= ~FMODE_WRITABLE;
        return Qnil;
    }

strio.closed? → true or false

Returns `true` if strio is completely closed, `false` otherwise.

[Source]

    /*
     * call-seq:
     *   strio.closed?    -> true or false
     *
     * Returns +true+ if *strio* is completely closed, +false+ otherwise.
     */
    static VALUE
    strio_closed(self)
        VALUE self;
    {
        struct StringIO *ptr = StringIO(self);
        if (!CLOSED(ptr)) return Qfalse;
        return Qtrue;
    }

strio.closed_read? → true or false

Returns `true` if strio is not readable, `false` otherwise.

[Source]

    /*
     * call-seq:
     *   strio.closed_read?    -> true or false
     *
     * Returns +true+ if *strio* is not readable, +false+ otherwise.
     */
    static VALUE
    strio_closed_read(self)
        VALUE self;
    {
        struct StringIO *ptr = StringIO(self);
        if (READABLE(ptr)) return Qfalse;
        return Qtrue;
    }

strio.closed_write? → true or false

Returns `true` if strio is not writable, `false` otherwise.

[Source]

    /*
     * call-seq:
     *   strio.closed_write?    -> true or false
     *
     * Returns +true+ if *strio* is not writable, +false+ otherwise.
     */
    static VALUE
    strio_closed_write(self)
        VALUE self;
    {
        struct StringIO *ptr = StringIO(self);
        if (WRITABLE(ptr)) return Qfalse;
        return Qtrue;
    }

strio.each(sep_string=$/) {|line| block } → strio
strio.each_line(sep_string=$/) {|line| block } → strio

See IO#each.

[Source]

    /*
     * call-seq:
     *   strio.each(sep_string=$/)      {|line| block }  -> strio
     *   strio.each_line(sep_string=$/) {|line| block }  -> strio
     *
     * See IO#each.
     */
    static VALUE
    strio_each(argc, argv, self)
        int argc;
        VALUE *argv;
        VALUE self;
    {
        struct StringIO *ptr = StringIO(self);
        VALUE line;

        while (!NIL_P(line = strio_getline(argc, argv, readable(ptr)))) {
    	rb_yield(line);
        }
        return self;
    }

strio.each_byte {|byte| block } → strio

See IO#each_byte.

[Source]

    /*
     * call-seq:
     *   strio.each_byte {|byte| block }  -> strio
     *
     * See IO#each_byte.
     */
    static VALUE
    strio_each_byte(self)
        VALUE self;
    {
        struct StringIO *ptr = readable(StringIO(self));
        while (ptr->pos < RSTRING(ptr->string)->len) {
    	char c = RSTRING(ptr->string)->ptr[ptr->pos++];
    	rb_yield(CHR2FIX(c));
        }
        return Qnil;
    }

strio.each(sep_string=$/) {|line| block } → strio
strio.each_line(sep_string=$/) {|line| block } → strio

See IO#each.

[Source]

    /*
     * call-seq:
     *   strio.each(sep_string=$/)      {|line| block }  -> strio
     *   strio.each_line(sep_string=$/) {|line| block }  -> strio
     *
     * See IO#each.
     */
    static VALUE
    strio_each(argc, argv, self)
        int argc;
        VALUE *argv;
        VALUE self;
    {
        struct StringIO *ptr = StringIO(self);
        VALUE line;

        while (!NIL_P(line = strio_getline(argc, argv, readable(ptr)))) {
    	rb_yield(line);
        }
        return self;
    }

strio.eof → true or false
strio.eof? → true or false

Returns true if strio is at end of file. The stringio must be opened for reading or an `IOError` will be raised.

[Source]

    /*
     * call-seq:
     *   strio.eof     -> true or false
     *   strio.eof?    -> true or false
     *
     * Returns true if *strio* is at end of file. The stringio must be
     * opened for reading or an +IOError+ will be raised.
     */
    static VALUE
    strio_eof(self)
        VALUE self;
    {
        struct StringIO *ptr = readable(StringIO(self));
        if (ptr->pos < RSTRING(ptr->string)->len) return Qfalse;
        return Qtrue;
    }

strio.eof → true or false
strio.eof? → true or false

Returns true if strio is at end of file. The stringio must be opened for reading or an `IOError` will be raised.

[Source]

    /*
     * call-seq:
     *   strio.eof     -> true or false
     *   strio.eof?    -> true or false
     *
     * Returns true if *strio* is at end of file. The stringio must be
     * opened for reading or an +IOError+ will be raised.
     */
    static VALUE
    strio_eof(self)
        VALUE self;
    {
        struct StringIO *ptr = readable(StringIO(self));
        if (ptr->pos < RSTRING(ptr->string)->len) return Qfalse;
        return Qtrue;
    }

fcntl(...)
fileno()
flush()
fsync()
strio.getc → fixnum or nil

See IO#getc.

[Source]

    /*
     * call-seq:
     *   strio.getc   -> fixnum or nil
     *
     * See IO#getc.
     */
    static VALUE
    strio_getc(self)
        VALUE self;
    {
        struct StringIO *ptr = readable(StringIO(self));
        int c;
        if (ptr->pos >= RSTRING(ptr->string)->len) {
    	ptr->flags |= STRIO_EOF;
    	return Qnil;
        }
        c = RSTRING(ptr->string)->ptr[ptr->pos++];
        return CHR2FIX(c);
    }

strio.gets(sep_string=$/) → string or nil

See IO#gets.

[Source]

    /*
     * call-seq:
     *   strio.gets(sep_string=$/)   -> string or nil
     *
     * See IO#gets.
     */
    static VALUE
    strio_gets(argc, argv, self)
        int argc;
        VALUE *argv;
        VALUE self;
    {
        VALUE str = strio_getline(argc, argv, readable(StringIO(self)));

        rb_lastline_set(str);
        return str;
    }

initialize_copy(p1)

:nodoc:

[Source]

    /* :nodoc: */
    static VALUE
    strio_copy(copy, orig)
        VALUE copy, orig;
    {
        struct StringIO *ptr;

        orig = rb_convert_type(orig, T_DATA, "StringIO", "to_strio");
        if (copy == orig) return copy;
        ptr = StringIO(orig);
        if (check_strio(copy)) {
    	strio_free(DATA_PTR(copy));
        }
        DATA_PTR(copy) = ptr;
        OBJ_INFECT(copy, orig);
        ++ptr->count;
        return copy;
    }

isatty()
strio.size → integer

Returns the size of the buffer string.

[Source]

    /*
     * call-seq:
     *   strio.size   -> integer
     *
     * Returns the size of the buffer string.
     */
    static VALUE
    strio_size(self)
        VALUE self;
    {
        VALUE string = StringIO(self)->string;
        if (NIL_P(string)) {
    	rb_raise(rb_eIOError, "not opened");
        }
        return ULONG2NUM(RSTRING(string)->len);
    }

strio.lineno → integer

Returns the current line number in strio. The stringio must be opened for reading. `lineno` counts the number of times `gets` is called, rather than the number of newlines encountered. The two values will differ if `gets` is called with a separator other than newline. See also the `$.` variable.

[Source]

    /*
     * call-seq:
     *   strio.lineno    -> integer
     *
     * Returns the current line number in *strio*. The stringio must be
     * opened for reading. +lineno+ counts the number of times  +gets+ is
     * called, rather than the number of newlines  encountered. The two
     * values will differ if +gets+ is  called with a separator other than
     * newline.  See also the  <code>$.</code> variable.
     */
    static VALUE
    strio_get_lineno(self)
        VALUE self;
    {
        return LONG2NUM(StringIO(self)->lineno);
    }

strio.lineno = integer → integer

Manually sets the current line number to the given value. `$.` is updated only on the next read.

[Source]

    /*
     * call-seq:
     *   strio.lineno = integer    -> integer
     *
     * Manually sets the current line number to the given value.
     * <code>$.</code> is updated only on the next read.
     */
    static VALUE
    strio_set_lineno(self, lineno)
        VALUE self, lineno;
    {
        StringIO(self)->lineno = NUM2LONG(lineno);
        return lineno;
    }

path()
pid()
strio.pos → integer
strio.tell → integer

Returns the current offset (in bytes) of strio.

[Source]

    /*
     * call-seq:
     *   strio.pos     -> integer
     *   strio.tell    -> integer
     *
     * Returns the current offset (in bytes) of *strio*.
     */
    static VALUE
    strio_get_pos(self)
        VALUE self;
    {
        return LONG2NUM(StringIO(self)->pos);
    }

strio.pos = integer → integer

Seeks to the given position (in bytes) in strio.

[Source]

    /*
     * call-seq:
     *   strio.pos = integer    -> integer
     *
     * Seeks to the given position (in bytes) in *strio*.
     */
    static VALUE
    strio_set_pos(self, pos)
        VALUE self;
        VALUE pos;
    {
        struct StringIO *ptr = StringIO(self);
        long p = NUM2LONG(pos);
        if (p < 0) {
    	error_inval(0);
        }
        ptr->pos = p;
        ptr->flags &= ~STRIO_EOF;
        return pos;
    }

print(...)
printf(...)
strio.putc(obj) → obj

See IO#putc.

[Source]

    /*
     * call-seq:
     *   strio.putc(obj)    -> obj
     *
     * See IO#putc.
     */
    static VALUE
    strio_putc(self, ch)
        VALUE self, ch;
    {
        struct StringIO *ptr = writable(StringIO(self));
        int c = NUM2CHR(ch);
        long olen;

        check_modifiable(ptr);
        olen = RSTRING(ptr->string)->len;
        if (ptr->flags & FMODE_APPEND) {
    	ptr->pos = olen;
        }
        strio_extend(ptr, ptr->pos, 1);
        RSTRING(ptr->string)->ptr[ptr->pos++] = c;
        OBJ_INFECT(ptr->string, self);
        return ch;
    }

puts(...)
strio.read([length [, buffer]]) → string, buffer, or nil

See IO#read.

[Source]

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

strio.readchar → fixnum

See IO#readchar.

[Source]

    /*
     * call-seq:
     *   strio.readchar   -> fixnum
     *
     * See IO#readchar.
     */
    static VALUE
    strio_readchar(self)
        VALUE self;
    {
        VALUE c = strio_getc(self);
        if (NIL_P(c)) rb_eof_error();
        return c;
    }

strio.readline(sep_string=$/) → string

See IO#readline.

[Source]

    /*
     * call-seq:
     *   strio.readline(sep_string=$/)   -> string
     *
     * See IO#readline.
     */
    static VALUE
    strio_readline(argc, argv, self)
        int argc;
        VALUE *argv;
        VALUE self;
    {
        VALUE line = strio_getline(argc, argv, readable(StringIO(self)));
        if (NIL_P(line)) rb_eof_error();
        return line;
    }

strio.readlines(sep_string=$/) → array

See IO#readlines.

[Source]

    /*
     * call-seq:
     *   strio.readlines(sep_string=$/)  ->   array
     *
     * See IO#readlines.
     */
    static VALUE
    strio_readlines(argc, argv, self)
        int argc;
        VALUE *argv;
        VALUE self;
    {
        struct StringIO *ptr = StringIO(self);
        VALUE ary = rb_ary_new(), line;
        while (!NIL_P(line = strio_getline(argc, argv, readable(ptr)))) {
    	rb_ary_push(ary, line);
        }
        return ary;
    }

strio.reopen(other_StrIO) → strio
strio.reopen(string, mode) → strio

Reinitializes strio with the given other_StrIO or string and mode (see StringIO#new).

[Source]

    /*
     * call-seq:
     *   strio.reopen(other_StrIO)     -> strio
     *   strio.reopen(string, mode)    -> strio
     *
     * Reinitializes *strio* with the given <i>other_StrIO</i> or _string_
     * and _mode_ (see StringIO#new).
     */
    static VALUE
    strio_reopen(argc, argv, self)
        int argc;
        VALUE *argv;
        VALUE self;
    {
        if (!OBJ_TAINTED(self)) rb_secure(4);
        if (argc == 1 && TYPE(*argv) != T_STRING) {
    	return strio_copy(self, *argv);
        }
        return strio_initialize(argc, argv, self);
    }

strio.rewind → 0

Positions strio to the beginning of input, resetting `lineno` to zero.

[Source]

    /*
     * call-seq:
     *   strio.rewind    -> 0
     *
     * Positions *strio* to the beginning of input, resetting
     * +lineno+ to zero.
     */
    static VALUE
    strio_rewind(self)
        VALUE self;
    {
        struct StringIO *ptr = StringIO(self);
        ptr->pos = 0;
        ptr->lineno = 0;
        ptr->flags &= ~STRIO_EOF;
        return INT2FIX(0);
    }

strio.seek(amount, whence=SEEK_SET) → 0

Seeks to a given offset amount in the stream according to the value of whence (see IO#seek).

[Source]

    /*
     * call-seq:
     *   strio.seek(amount, whence=SEEK_SET) -> 0
     *
     * Seeks to a given offset _amount_ in the stream according to
     * the value of _whence_ (see IO#seek).
     */
    static VALUE
    strio_seek(argc, argv, self)
        int argc;
        VALUE *argv;
        VALUE self;
    {
        VALUE whence;
        struct StringIO *ptr = StringIO(self);
        long offset;

        rb_scan_args(argc, argv, "11", NULL, &whence);
        offset = NUM2LONG(argv[0]);
        switch (NIL_P(whence) ? 0 : NUM2LONG(whence)) {
          case 0:
    	break;
          case 1:
    	offset += ptr->pos;
    	break;
          case 2:
    	offset += RSTRING(ptr->string)->len;
    	break;
          default:
    	rb_raise(rb_eArgError, "invalid whence %ld", NUM2LONG(whence));
        }
        if (offset < 0) {
    	error_inval(0);
        }
        ptr->pos = offset;
        ptr->flags &= ~STRIO_EOF;
        return INT2FIX(0);
    }

strio.size → integer

Returns the size of the buffer string.

[Source]

    /*
     * call-seq:
     *   strio.size   -> integer
     *
     * Returns the size of the buffer string.
     */
    static VALUE
    strio_size(self)
        VALUE self;
    {
        VALUE string = StringIO(self)->string;
        if (NIL_P(string)) {
    	rb_raise(rb_eIOError, "not opened");
        }
        return ULONG2NUM(RSTRING(string)->len);
    }

strio.string → string

Returns underlying String object, the subject of IO.

[Source]

    /*
     * call-seq: strio.string     -> string
     *
     * Returns underlying String object, the subject of IO.
     */
    static VALUE
    strio_get_string(self)
        VALUE self;
    {
        return StringIO(self)->string;
    }

strio.string = string → string

Changes underlying String object, the subject of IO.

[Source]

    /*
     * call-seq:
     *   strio.string = string  -> string
     *
     * Changes underlying String object, the subject of IO.
     */
    static VALUE
    strio_set_string(self, string)
        VALUE self, string;
    {
        struct StringIO *ptr = StringIO(self);

        if (!OBJ_TAINTED(self)) rb_secure(4);
        ptr->flags &= ~FMODE_READWRITE;
        StringValue(string);
        ptr->flags = OBJ_FROZEN(string) ? FMODE_READABLE : FMODE_READWRITE;
        ptr->pos = 0;
        ptr->lineno = 0;
        return ptr->string = string;
    }

strio.sync → true

Returns `true` always.

[Source]

    /*
     * call-seq:
     *   strio.sync    -> true
     *
     * Returns +true+ always.
     */
    static VALUE
    strio_get_sync(self)
        VALUE self;
    {
        StringIO(self);
        return Qtrue;
    }

sync=(p1)
strio.sysread(integer[, outbuf]) → string

Similar to read, but raises `EOFError` at end of string instead of returning `nil`, as well as IO#sysread does.

[Source]

    /*
     * call-seq:
     *   strio.sysread(integer[, outbuf])    -> string
     *
     * Similar to #read, but raises +EOFError+ at end of string instead of
     * returning +nil+, as well as IO#sysread does.
     */
    static VALUE
    strio_sysread(argc, argv, self)
        int argc;
        VALUE *argv;
        VALUE self;
    {
        VALUE val = strio_read(argc, argv, self);
        if (NIL_P(val) || RSTRING(val)->len == 0) {
    	rb_eof_error();
        }
        return val;
    }

syswrite(p1)
tell()
strio.truncate(integer) → 0

Truncates the buffer string to at most integer bytes. The strio must be opened for writing.

[Source]

    /*
     * call-seq:
     *   strio.truncate(integer)    -> 0
     *
     * Truncates the buffer string to at most _integer_ bytes. The *strio*
     * must be opened for writing.
     */
    static VALUE
    strio_truncate(self, len)
        VALUE self, len;
    {
        VALUE string = writable(StringIO(self))->string;
        long l = NUM2LONG(len);
        long plen = RSTRING(string)->len;
        if (l < 0) {
    	error_inval("negative legnth");
        }
        rb_str_resize(string, l);
        if (plen < l) {
    	MEMZERO(RSTRING(string)->ptr + plen, char, l - plen);
        }
        return len;
    }

tty?()
strio.ungetc(integer) → nil

Pushes back one character (passed as a parameter) onto strio such that a subsequent buffered read will return it. Pushing back behind the beginning of the buffer string is not possible. Nothing will be done if such an attempt is made. In other case, there is no limitation for multiple pushbacks.

[Source]

    /*
     * call-seq:
     *   strio.ungetc(integer)   -> nil
     *
     * Pushes back one character (passed as a parameter) onto *strio*
     * such that a subsequent buffered read will return it.  Pushing back
     * behind the beginning of the buffer string is not possible.  Nothing
     * will be done if such an attempt is made.
     * In other case, there is no limitation for multiple pushbacks.
     */
    static VALUE
    strio_ungetc(self, ch)
        VALUE self, ch;
    {
        struct StringIO *ptr = readable(StringIO(self));
        int cc = NUM2INT(ch);
        long len, pos = ptr->pos;

        if (cc != EOF && pos > 0) {
    	if ((len = RSTRING(ptr->string)->len) < pos-- ||
    	    (unsigned char)RSTRING(ptr->string)->ptr[pos] !=
    	    (unsigned char)cc) {
    	    strio_extend(ptr, pos, 1);
    	    RSTRING(ptr->string)->ptr[pos] = cc;
    	    OBJ_INFECT(ptr->string, self);
    	}
    	--ptr->pos;
    	ptr->flags &= ~STRIO_EOF;
        }
        return Qnil;
    }

strio.write(string) → integer
strio.syswrite(string) → integer

Appends the given string to the underlying buffer string of strio. The stream must be opened for writing. If the argument is not a string, it will be converted to a string using `to_s`. Returns the number of bytes written. See IO#write.

[Source]

    /*
     * call-seq:
     *   strio.write(string)    -> integer
     *   strio.syswrite(string) -> integer
     *
     * Appends the given string to the underlying buffer string of *strio*.
     * The stream must be opened for writing.  If the argument is not a
     * string, it will be converted to a string using <code>to_s</code>.
     * Returns the number of bytes written.  See IO#write.
     */
    static VALUE
    strio_write(self, str)
        VALUE self, str;
    {
        struct StringIO *ptr = writable(StringIO(self));
        long len, olen;

        if (TYPE(str) != T_STRING)
    	str = rb_obj_as_string(str);
        len = RSTRING(str)->len;
        if (!len) return INT2FIX(0);
        check_modifiable(ptr);
        olen = RSTRING(ptr->string)->len;
        if (ptr->flags & FMODE_APPEND) {
    	ptr->pos = olen;
        }
        if (ptr->pos == olen) {
    	rb_str_cat(ptr->string, RSTRING(str)->ptr, len);
        }
        else {
    	strio_extend(ptr, ptr->pos, len);
    	rb_str_update(ptr->string, ptr->pos, len, str);
        }
        OBJ_INFECT(ptr->string, self);
        ptr->pos += len;
        return LONG2NUM(len);
    }

[Validate]