Ruby 1.9.3p327(2012-11-10revision37606)
ext/stringio/stringio.c
Go to the documentation of this file.
00001 /**********************************************************************
00002 
00003   stringio.c -
00004 
00005   $Author: nobu $
00006   $RoughId: stringio.c,v 1.13 2002/03/14 03:24:18 nobu Exp $
00007   created at: Tue Feb 19 04:10:38 JST 2002
00008 
00009   All the files in this distribution are covered under the Ruby's
00010   license (see the file COPYING).
00011 
00012 **********************************************************************/
00013 
00014 #include "ruby.h"
00015 #include "ruby/io.h"
00016 #include "ruby/encoding.h"
00017 #if defined(HAVE_FCNTL_H) || defined(_WIN32)
00018 #include <fcntl.h>
00019 #elif defined(HAVE_SYS_FCNTL_H)
00020 #include <sys/fcntl.h>
00021 #endif
00022 
00023 struct StringIO {
00024     VALUE string;
00025     long pos;
00026     long lineno;
00027     int flags;
00028     int count;
00029 };
00030 
00031 static void strio_init(int, VALUE *, struct StringIO *);
00032 
00033 #define IS_STRIO(obj) (rb_typeddata_is_kind_of((obj), &strio_data_type))
00034 #define error_inval(msg) (errno = EINVAL, rb_sys_fail(msg))
00035 
00036 static struct StringIO *
00037 strio_alloc(void)
00038 {
00039     struct StringIO *ptr = ALLOC(struct StringIO);
00040     ptr->string = Qnil;
00041     ptr->pos = 0;
00042     ptr->lineno = 0;
00043     ptr->flags = 0;
00044     ptr->count = 1;
00045     return ptr;
00046 }
00047 
00048 static void
00049 strio_mark(void *p)
00050 {
00051     struct StringIO *ptr = p;
00052     if (ptr) {
00053         rb_gc_mark(ptr->string);
00054     }
00055 }
00056 
00057 static void
00058 strio_free(void *p)
00059 {
00060     struct StringIO *ptr = p;
00061     if (--ptr->count <= 0) {
00062         xfree(ptr);
00063     }
00064 }
00065 
00066 static size_t
00067 strio_memsize(const void *p)
00068 {
00069     const struct StringIO *ptr = p;
00070     if (!ptr) return 0;
00071     return sizeof(struct StringIO);
00072 }
00073 
00074 static const rb_data_type_t strio_data_type = {
00075     "strio",
00076     {
00077         strio_mark,
00078         strio_free,
00079         strio_memsize,
00080     },
00081 };
00082 
00083 #define check_strio(self) ((struct StringIO*)rb_check_typeddata((self), &strio_data_type))
00084 
00085 static struct StringIO*
00086 get_strio(VALUE self)
00087 {
00088     struct StringIO *ptr = check_strio(rb_io_taint_check(self));
00089 
00090     if (!ptr) {
00091         rb_raise(rb_eIOError, "uninitialized stream");
00092     }
00093     return ptr;
00094 }
00095 
00096 static VALUE
00097 strio_substr(struct StringIO *ptr, long pos, long len)
00098 {
00099     VALUE str = ptr->string;
00100     rb_encoding *enc = rb_enc_get(str);
00101     long rlen = RSTRING_LEN(str) - pos;
00102 
00103     if (len > rlen) len = rlen;
00104     if (len < 0) len = 0;
00105     return rb_enc_str_new(RSTRING_PTR(str)+pos, len, enc);
00106 }
00107 
00108 #define StringIO(obj) get_strio(obj)
00109 
00110 #define CLOSED(ptr) (!((ptr)->flags & FMODE_READWRITE))
00111 #define READABLE(ptr) ((ptr)->flags & FMODE_READABLE)
00112 #define WRITABLE(ptr) ((ptr)->flags & FMODE_WRITABLE)
00113 
00114 static struct StringIO*
00115 readable(struct StringIO *ptr)
00116 {
00117     if (!READABLE(ptr)) {
00118         rb_raise(rb_eIOError, "not opened for reading");
00119     }
00120     return ptr;
00121 }
00122 
00123 static struct StringIO*
00124 writable(struct StringIO *ptr)
00125 {
00126     if (!WRITABLE(ptr)) {
00127         rb_raise(rb_eIOError, "not opened for writing");
00128     }
00129     if (!OBJ_TAINTED(ptr->string)) {
00130         rb_secure(4);
00131     }
00132     return ptr;
00133 }
00134 
00135 static void
00136 check_modifiable(struct StringIO *ptr)
00137 {
00138     if (OBJ_FROZEN(ptr->string)) {
00139         rb_raise(rb_eIOError, "not modifiable string");
00140     }
00141 }
00142 
00143 static VALUE
00144 strio_s_allocate(VALUE klass)
00145 {
00146     return TypedData_Wrap_Struct(klass, &strio_data_type, 0);
00147 }
00148 
00149 /*
00150  * call-seq: StringIO.new(string=""[, mode])
00151  *
00152  * Creates new StringIO instance from with _string_ and _mode_.
00153  */
00154 static VALUE
00155 strio_initialize(int argc, VALUE *argv, VALUE self)
00156 {
00157     struct StringIO *ptr = check_strio(self);
00158 
00159     if (!ptr) {
00160         DATA_PTR(self) = ptr = strio_alloc();
00161     }
00162     rb_call_super(0, 0);
00163     strio_init(argc, argv, ptr);
00164     return self;
00165 }
00166 
00167 static void
00168 strio_init(int argc, VALUE *argv, struct StringIO *ptr)
00169 {
00170     VALUE string, mode;
00171     int trunc = 0;
00172 
00173     switch (rb_scan_args(argc, argv, "02", &string, &mode)) {
00174       case 2:
00175         if (FIXNUM_P(mode)) {
00176             int flags = FIX2INT(mode);
00177             ptr->flags = rb_io_modenum_flags(flags);
00178             trunc = flags & O_TRUNC;
00179         }
00180         else {
00181             const char *m = StringValueCStr(mode);
00182             ptr->flags = rb_io_mode_flags(m);
00183             trunc = *m == 'w';
00184         }
00185         StringValue(string);
00186         if ((ptr->flags & FMODE_WRITABLE) && OBJ_FROZEN(string)) {
00187             errno = EACCES;
00188             rb_sys_fail(0);
00189         }
00190         if (trunc) {
00191             rb_str_resize(string, 0);
00192         }
00193         break;
00194       case 1:
00195         StringValue(string);
00196         ptr->flags = OBJ_FROZEN(string) ? FMODE_READABLE : FMODE_READWRITE;
00197         break;
00198       case 0:
00199         string = rb_enc_str_new("", 0, rb_default_external_encoding());
00200         ptr->flags = FMODE_READWRITE;
00201         break;
00202     }
00203     ptr->string = string;
00204     ptr->pos = 0;
00205     ptr->lineno = 0;
00206 }
00207 
00208 static VALUE
00209 strio_finalize(VALUE self)
00210 {
00211     struct StringIO *ptr = StringIO(self);
00212     ptr->string = Qnil;
00213     ptr->flags &= ~FMODE_READWRITE;
00214     return self;
00215 }
00216 
00217 /*
00218  * call-seq: StringIO.open(string=""[, mode]) {|strio| ...}
00219  *
00220  * Equivalent to StringIO.new except that when it is called with a block, it
00221  * yields with the new instance and closes it, and returns the result which
00222  * returned from the block.
00223  */
00224 static VALUE
00225 strio_s_open(int argc, VALUE *argv, VALUE klass)
00226 {
00227     VALUE obj = rb_class_new_instance(argc, argv, klass);
00228     if (!rb_block_given_p()) return obj;
00229     return rb_ensure(rb_yield, obj, strio_finalize, obj);
00230 }
00231 
00232 /*
00233  * Returns +false+.  Just for compatibility to IO.
00234  */
00235 static VALUE
00236 strio_false(VALUE self)
00237 {
00238     StringIO(self);
00239     return Qfalse;
00240 }
00241 
00242 /*
00243  * Returns +nil+.  Just for compatibility to IO.
00244  */
00245 static VALUE
00246 strio_nil(VALUE self)
00247 {
00248     StringIO(self);
00249     return Qnil;
00250 }
00251 
00252 /*
00253  * Returns *strio* itself.  Just for compatibility to IO.
00254  */
00255 static VALUE
00256 strio_self(VALUE self)
00257 {
00258     StringIO(self);
00259     return self;
00260 }
00261 
00262 /*
00263  * Returns 0.  Just for compatibility to IO.
00264  */
00265 static VALUE
00266 strio_0(VALUE self)
00267 {
00268     StringIO(self);
00269     return INT2FIX(0);
00270 }
00271 
00272 /*
00273  * Returns the argument unchanged.  Just for compatibility to IO.
00274  */
00275 static VALUE
00276 strio_first(VALUE self, VALUE arg)
00277 {
00278     StringIO(self);
00279     return arg;
00280 }
00281 
00282 /*
00283  * Raises NotImplementedError.
00284  */
00285 static VALUE
00286 strio_unimpl(int argc, VALUE *argv, VALUE self)
00287 {
00288     StringIO(self);
00289     rb_notimplement();
00290     return Qnil;                /* not reached */
00291 }
00292 
00293 /*
00294  * call-seq: strio.string     -> string
00295  *
00296  * Returns underlying String object, the subject of IO.
00297  */
00298 static VALUE
00299 strio_get_string(VALUE self)
00300 {
00301     return StringIO(self)->string;
00302 }
00303 
00304 /*
00305  * call-seq:
00306  *   strio.string = string  -> string
00307  *
00308  * Changes underlying String object, the subject of IO.
00309  */
00310 static VALUE
00311 strio_set_string(VALUE self, VALUE string)
00312 {
00313     struct StringIO *ptr = StringIO(self);
00314 
00315     rb_io_taint_check(self);
00316     ptr->flags &= ~FMODE_READWRITE;
00317     StringValue(string);
00318     ptr->flags = OBJ_FROZEN(string) ? FMODE_READABLE : FMODE_READWRITE;
00319     ptr->pos = 0;
00320     ptr->lineno = 0;
00321     return ptr->string = string;
00322 }
00323 
00324 /*
00325  * call-seq:
00326  *   strio.close  -> nil
00327  *
00328  * Closes strio.  The *strio* is unavailable for any further data
00329  * operations; an +IOError+ is raised if such an attempt is made.
00330  */
00331 static VALUE
00332 strio_close(VALUE self)
00333 {
00334     struct StringIO *ptr = StringIO(self);
00335     if (CLOSED(ptr)) {
00336         rb_raise(rb_eIOError, "closed stream");
00337     }
00338     ptr->flags &= ~FMODE_READWRITE;
00339     return Qnil;
00340 }
00341 
00342 /*
00343  * call-seq:
00344  *   strio.close_read    -> nil
00345  *
00346  * Closes the read end of a StringIO.  Will raise an +IOError+ if the
00347  * *strio* is not readable.
00348  */
00349 static VALUE
00350 strio_close_read(VALUE self)
00351 {
00352     struct StringIO *ptr = StringIO(self);
00353     if (!READABLE(ptr)) {
00354         rb_raise(rb_eIOError, "closing non-duplex IO for reading");
00355     }
00356     ptr->flags &= ~FMODE_READABLE;
00357     return Qnil;
00358 }
00359 
00360 /*
00361  * call-seq:
00362  *   strio.close_write    -> nil
00363  *
00364  * Closes the write end of a StringIO.  Will raise an  +IOError+ if the
00365  * *strio* is not writeable.
00366  */
00367 static VALUE
00368 strio_close_write(VALUE self)
00369 {
00370     struct StringIO *ptr = StringIO(self);
00371     if (!WRITABLE(ptr)) {
00372         rb_raise(rb_eIOError, "closing non-duplex IO for writing");
00373     }
00374     ptr->flags &= ~FMODE_WRITABLE;
00375     return Qnil;
00376 }
00377 
00378 /*
00379  * call-seq:
00380  *   strio.closed?    -> true or false
00381  *
00382  * Returns +true+ if *strio* is completely closed, +false+ otherwise.
00383  */
00384 static VALUE
00385 strio_closed(VALUE self)
00386 {
00387     struct StringIO *ptr = StringIO(self);
00388     if (!CLOSED(ptr)) return Qfalse;
00389     return Qtrue;
00390 }
00391 
00392 /*
00393  * call-seq:
00394  *   strio.closed_read?    -> true or false
00395  *
00396  * Returns +true+ if *strio* is not readable, +false+ otherwise.
00397  */
00398 static VALUE
00399 strio_closed_read(VALUE self)
00400 {
00401     struct StringIO *ptr = StringIO(self);
00402     if (READABLE(ptr)) return Qfalse;
00403     return Qtrue;
00404 }
00405 
00406 /*
00407  * call-seq:
00408  *   strio.closed_write?    -> true or false
00409  *
00410  * Returns +true+ if *strio* is not writable, +false+ otherwise.
00411  */
00412 static VALUE
00413 strio_closed_write(VALUE self)
00414 {
00415     struct StringIO *ptr = StringIO(self);
00416     if (WRITABLE(ptr)) return Qfalse;
00417     return Qtrue;
00418 }
00419 
00420 /*
00421  * call-seq:
00422  *   strio.eof     -> true or false
00423  *   strio.eof?    -> true or false
00424  *
00425  * Returns true if *strio* is at end of file. The stringio must be
00426  * opened for reading or an +IOError+ will be raised.
00427  */
00428 static VALUE
00429 strio_eof(VALUE self)
00430 {
00431     struct StringIO *ptr = readable(StringIO(self));
00432     if (ptr->pos < RSTRING_LEN(ptr->string)) return Qfalse;
00433     return Qtrue;
00434 }
00435 
00436 /* :nodoc: */
00437 static VALUE
00438 strio_copy(VALUE copy, VALUE orig)
00439 {
00440     struct StringIO *ptr;
00441 
00442     orig = rb_convert_type(orig, T_DATA, "StringIO", "to_strio");
00443     if (copy == orig) return copy;
00444     ptr = StringIO(orig);
00445     if (check_strio(copy)) {
00446         strio_free(DATA_PTR(copy));
00447     }
00448     DATA_PTR(copy) = ptr;
00449     OBJ_INFECT(copy, orig);
00450     ++ptr->count;
00451     return copy;
00452 }
00453 
00454 /*
00455  * call-seq:
00456  *   strio.lineno    -> integer
00457  *
00458  * Returns the current line number in *strio*. The stringio must be
00459  * opened for reading. +lineno+ counts the number of times  +gets+ is
00460  * called, rather than the number of newlines  encountered. The two
00461  * values will differ if +gets+ is  called with a separator other than
00462  * newline.  See also the  <code>$.</code> variable.
00463  */
00464 static VALUE
00465 strio_get_lineno(VALUE self)
00466 {
00467     return LONG2NUM(StringIO(self)->lineno);
00468 }
00469 
00470 /*
00471  * call-seq:
00472  *   strio.lineno = integer    -> integer
00473  *
00474  * Manually sets the current line number to the given value.
00475  * <code>$.</code> is updated only on the next read.
00476  */
00477 static VALUE
00478 strio_set_lineno(VALUE self, VALUE lineno)
00479 {
00480     StringIO(self)->lineno = NUM2LONG(lineno);
00481     return lineno;
00482 }
00483 
00484 /* call-seq: strio.binmode -> true */
00485 #define strio_binmode strio_self
00486 
00487 /* call-seq: strio.fcntl */
00488 #define strio_fcntl strio_unimpl
00489 
00490 /* call-seq: strio.flush -> strio */
00491 #define strio_flush strio_self
00492 
00493 /* call-seq: strio.fsync -> 0 */
00494 #define strio_fsync strio_0
00495 
00496 /*
00497  * call-seq:
00498  *   strio.reopen(other_StrIO)     -> strio
00499  *   strio.reopen(string, mode)    -> strio
00500  *
00501  * Reinitializes *strio* with the given <i>other_StrIO</i> or _string_
00502  * and _mode_ (see StringIO#new).
00503  */
00504 static VALUE
00505 strio_reopen(int argc, VALUE *argv, VALUE self)
00506 {
00507     rb_io_taint_check(self);
00508     if (argc == 1 && TYPE(*argv) != T_STRING) {
00509         return strio_copy(self, *argv);
00510     }
00511     strio_init(argc, argv, StringIO(self));
00512     return self;
00513 }
00514 
00515 /*
00516  * call-seq:
00517  *   strio.pos     -> integer
00518  *   strio.tell    -> integer
00519  *
00520  * Returns the current offset (in bytes) of *strio*.
00521  */
00522 static VALUE
00523 strio_get_pos(VALUE self)
00524 {
00525     return LONG2NUM(StringIO(self)->pos);
00526 }
00527 
00528 /*
00529  * call-seq:
00530  *   strio.pos = integer    -> integer
00531  *
00532  * Seeks to the given position (in bytes) in *strio*.
00533  */
00534 static VALUE
00535 strio_set_pos(VALUE self, VALUE pos)
00536 {
00537     struct StringIO *ptr = StringIO(self);
00538     long p = NUM2LONG(pos);
00539     if (p < 0) {
00540         error_inval(0);
00541     }
00542     ptr->pos = p;
00543     return pos;
00544 }
00545 
00546 /*
00547  * call-seq:
00548  *   strio.rewind    -> 0
00549  *
00550  * Positions *strio* to the beginning of input, resetting
00551  * +lineno+ to zero.
00552  */
00553 static VALUE
00554 strio_rewind(VALUE self)
00555 {
00556     struct StringIO *ptr = StringIO(self);
00557     ptr->pos = 0;
00558     ptr->lineno = 0;
00559     return INT2FIX(0);
00560 }
00561 
00562 /*
00563  * call-seq:
00564  *   strio.seek(amount, whence=SEEK_SET) -> 0
00565  *
00566  * Seeks to a given offset _amount_ in the stream according to
00567  * the value of _whence_ (see IO#seek).
00568  */
00569 static VALUE
00570 strio_seek(int argc, VALUE *argv, VALUE self)
00571 {
00572     VALUE whence;
00573     struct StringIO *ptr = StringIO(self);
00574     long offset;
00575 
00576     rb_scan_args(argc, argv, "11", NULL, &whence);
00577     offset = NUM2LONG(argv[0]);
00578     if (CLOSED(ptr)) {
00579         rb_raise(rb_eIOError, "closed stream");
00580     }
00581     switch (NIL_P(whence) ? 0 : NUM2LONG(whence)) {
00582       case 0:
00583         break;
00584       case 1:
00585         offset += ptr->pos;
00586         break;
00587       case 2:
00588         offset += RSTRING_LEN(ptr->string);
00589         break;
00590       default:
00591         error_inval("invalid whence");
00592     }
00593     if (offset < 0) {
00594         error_inval(0);
00595     }
00596     ptr->pos = offset;
00597     return INT2FIX(0);
00598 }
00599 
00600 /*
00601  * call-seq:
00602  *   strio.sync    -> true
00603  *
00604  * Returns +true+ always.
00605  */
00606 static VALUE
00607 strio_get_sync(VALUE self)
00608 {
00609     StringIO(self);
00610     return Qtrue;
00611 }
00612 
00613 /* call-seq: strio.sync = boolean -> boolean */
00614 #define strio_set_sync strio_first
00615 
00616 #define strio_tell strio_get_pos
00617 
00618 /*
00619  * call-seq:
00620  *   strio.bytes {|byte| block }      -> strio
00621  *   strio.bytes                      -> anEnumerator
00622  *
00623  *   strio.each_byte {|byte| block }  -> strio
00624  *   strio.each_byte                  -> anEnumerator
00625  *
00626  * See IO#each_byte.
00627  */
00628 static VALUE
00629 strio_each_byte(VALUE self)
00630 {
00631     struct StringIO *ptr = readable(StringIO(self));
00632 
00633     RETURN_ENUMERATOR(self, 0, 0);
00634 
00635     while (ptr->pos < RSTRING_LEN(ptr->string)) {
00636         char c = RSTRING_PTR(ptr->string)[ptr->pos++];
00637         rb_yield(CHR2FIX(c));
00638     }
00639     return self;
00640 }
00641 
00642 /*
00643  * call-seq:
00644  *   strio.getc   -> string or nil
00645  *
00646  * See IO#getc.
00647  */
00648 static VALUE
00649 strio_getc(VALUE self)
00650 {
00651     struct StringIO *ptr = readable(StringIO(self));
00652     rb_encoding *enc = rb_enc_get(ptr->string);
00653     int len;
00654     char *p;
00655 
00656     if (ptr->pos >= RSTRING_LEN(ptr->string)) {
00657         return Qnil;
00658     }
00659     p = RSTRING_PTR(ptr->string)+ptr->pos;
00660     len = rb_enc_mbclen(p, RSTRING_END(ptr->string), enc);
00661     ptr->pos += len;
00662     return rb_enc_str_new(p, len, rb_enc_get(ptr->string));
00663 }
00664 
00665 /*
00666  * call-seq:
00667  *   strio.getbyte   -> fixnum or nil
00668  *
00669  * See IO#getbyte.
00670  */
00671 static VALUE
00672 strio_getbyte(VALUE self)
00673 {
00674     struct StringIO *ptr = readable(StringIO(self));
00675     int c;
00676     if (ptr->pos >= RSTRING_LEN(ptr->string)) {
00677         return Qnil;
00678     }
00679     c = RSTRING_PTR(ptr->string)[ptr->pos++];
00680     return CHR2FIX(c);
00681 }
00682 
00683 static void
00684 strio_extend(struct StringIO *ptr, long pos, long len)
00685 {
00686     long olen;
00687 
00688     check_modifiable(ptr);
00689     olen = RSTRING_LEN(ptr->string);
00690     if (pos + len > olen) {
00691         rb_str_resize(ptr->string, pos + len);
00692         if (pos > olen)
00693             MEMZERO(RSTRING_PTR(ptr->string) + olen, char, pos - olen);
00694     }
00695     else {
00696         rb_str_modify(ptr->string);
00697     }
00698 }
00699 
00700 /*
00701  * call-seq:
00702  *   strio.ungetc(string)   -> nil
00703  *
00704  * Pushes back one character (passed as a parameter) onto *strio*
00705  * such that a subsequent buffered read will return it.  There is no
00706  * limitation for multiple pushbacks including pushing back behind the
00707  * beginning of the buffer string.
00708  */
00709 static VALUE
00710 strio_ungetc(VALUE self, VALUE c)
00711 {
00712     struct StringIO *ptr = readable(StringIO(self));
00713     long lpos, clen;
00714     char *p, *pend;
00715     rb_encoding *enc, *enc2;
00716 
00717     if (NIL_P(c)) return Qnil;
00718     if (FIXNUM_P(c)) {
00719         int cc = FIX2INT(c);
00720         char buf[16];
00721 
00722         enc = rb_enc_get(ptr->string);
00723         rb_enc_mbcput(cc, buf, enc);
00724         c = rb_enc_str_new(buf, rb_enc_codelen(cc, enc), enc);
00725     }
00726     else {
00727         SafeStringValue(c);
00728         enc = rb_enc_get(ptr->string);
00729         enc2 = rb_enc_get(c);
00730         if (enc != enc2 && enc != rb_ascii8bit_encoding()) {
00731             c = rb_str_conv_enc(c, enc2, enc);
00732         }
00733     }
00734     if (RSTRING_LEN(ptr->string) < ptr->pos) {
00735         long len = RSTRING_LEN(ptr->string);
00736         rb_str_resize(ptr->string, ptr->pos - 1);
00737         memset(RSTRING_PTR(ptr->string) + len, 0, ptr->pos - len - 1);
00738         rb_str_concat(ptr->string, c);
00739         ptr->pos--;
00740     }
00741     else {
00742         /* get logical position */
00743         lpos = 0; p = RSTRING_PTR(ptr->string); pend = p + ptr->pos;
00744         for (;;) {
00745             clen = rb_enc_mbclen(p, pend, enc);
00746             if (p+clen >= pend) break;
00747             p += clen;
00748             lpos++;
00749         }
00750         clen = p - RSTRING_PTR(ptr->string);
00751         rb_str_update(ptr->string, lpos, ptr->pos ? 1 : 0, c);
00752         ptr->pos = clen;
00753     }
00754 
00755     return Qnil;
00756 }
00757 
00758 /*
00759  * call-seq:
00760  *   strio.ungetbyte(fixnum)   -> nil
00761  *
00762  * See IO#ungetbyte
00763  */
00764 static VALUE
00765 strio_ungetbyte(VALUE self, VALUE c)
00766 {
00767     struct StringIO *ptr = readable(StringIO(self));
00768     char buf[1], *cp = buf;
00769     long pos = ptr->pos, cl = 1;
00770     VALUE str = ptr->string;
00771 
00772     if (NIL_P(c)) return Qnil;
00773     if (FIXNUM_P(c)) {
00774         buf[0] = (char)FIX2INT(c);
00775     }
00776     else {
00777         SafeStringValue(c);
00778         cp = RSTRING_PTR(c);
00779         cl = RSTRING_LEN(c);
00780         if (cl == 0) return Qnil;
00781     }
00782     rb_str_modify(str);
00783     if (cl > pos) {
00784         char *s;
00785         long rest = RSTRING_LEN(str) - pos;
00786         rb_str_resize(str, rest + cl);
00787         s = RSTRING_PTR(str);
00788         memmove(s + cl, s + pos, rest);
00789         pos = 0;
00790     }
00791     else {
00792         pos -= cl;
00793     }
00794     memcpy(RSTRING_PTR(str) + pos, cp, cl);
00795     ptr->pos = pos;
00796     RB_GC_GUARD(c);
00797     return Qnil;
00798 }
00799 
00800 /*
00801  * call-seq:
00802  *   strio.readchar   -> string
00803  *
00804  * See IO#readchar.
00805  */
00806 static VALUE
00807 strio_readchar(VALUE self)
00808 {
00809     VALUE c = rb_funcall2(self, rb_intern("getc"), 0, 0);
00810     if (NIL_P(c)) rb_eof_error();
00811     return c;
00812 }
00813 
00814 /*
00815  * call-seq:
00816  *   strio.readbyte   -> fixnum
00817  *
00818  * See IO#readbyte.
00819  */
00820 static VALUE
00821 strio_readbyte(VALUE self)
00822 {
00823     VALUE c = rb_funcall2(self, rb_intern("getbyte"), 0, 0);
00824     if (NIL_P(c)) rb_eof_error();
00825     return c;
00826 }
00827 
00828 /*
00829  * call-seq:
00830  *   strio.chars {|char| block }      -> strio
00831  *   strio.chars                      -> anEnumerator
00832  *
00833  *   strio.each_char {|char| block }  -> strio
00834  *   strio.each_char                  -> anEnumerator
00835  *
00836  * See IO#each_char.
00837  */
00838 static VALUE
00839 strio_each_char(VALUE self)
00840 {
00841     VALUE c;
00842 
00843     RETURN_ENUMERATOR(self, 0, 0);
00844 
00845     while (!NIL_P(c = strio_getc(self))) {
00846         rb_yield(c);
00847     }
00848     return self;
00849 }
00850 
00851 /*
00852  * call-seq:
00853  *   strio.codepoints {|c| block }      -> strio
00854  *   strio.codepoints                   -> anEnumerator
00855  *
00856  *   strio.each_codepoint {|c| block }  -> strio
00857  *   strio.each_codepoint               -> anEnumerator
00858  *
00859  * See IO#each_codepoint.
00860  */
00861 static VALUE
00862 strio_each_codepoint(VALUE self)
00863 {
00864     struct StringIO *ptr;
00865     rb_encoding *enc;
00866     unsigned int c;
00867     int n;
00868 
00869     RETURN_ENUMERATOR(self, 0, 0);
00870 
00871     ptr = readable(StringIO(self));
00872     enc = rb_enc_get(ptr->string);
00873     for (;;) {
00874         if (ptr->pos >= RSTRING_LEN(ptr->string)) {
00875             return self;
00876         }
00877 
00878         c = rb_enc_codepoint_len(RSTRING_PTR(ptr->string)+ptr->pos,
00879                                  RSTRING_END(ptr->string), &n, enc);
00880         rb_yield(UINT2NUM(c));
00881         ptr->pos += n;
00882     }
00883     return self;
00884 }
00885 
00886 /* Boyer-Moore search: copied from regex.c */
00887 static void
00888 bm_init_skip(long *skip, const char *pat, long m)
00889 {
00890     int c;
00891 
00892     for (c = 0; c < (1 << CHAR_BIT); c++) {
00893         skip[c] = m;
00894     }
00895     while (--m) {
00896         skip[(unsigned char)*pat++] = m;
00897     }
00898 }
00899 
00900 static long
00901 bm_search(const char *little, long llen, const char *big, long blen, const long *skip)
00902 {
00903     long i, j, k;
00904 
00905     i = llen - 1;
00906     while (i < blen) {
00907         k = i;
00908         j = llen - 1;
00909         while (j >= 0 && big[k] == little[j]) {
00910             k--;
00911             j--;
00912         }
00913         if (j < 0) return k + 1;
00914         i += skip[(unsigned char)big[i]];
00915     }
00916     return -1;
00917 }
00918 
00919 static VALUE
00920 strio_getline(int argc, VALUE *argv, struct StringIO *ptr)
00921 {
00922     const char *s, *e, *p;
00923     long n, limit = 0;
00924     VALUE str, lim;
00925 
00926     rb_scan_args(argc, argv, "02", &str, &lim);
00927     switch (argc) {
00928       case 0:
00929         str = rb_rs;
00930         break;
00931 
00932       case 1:
00933         if (!NIL_P(str) && TYPE(str) != T_STRING) {
00934             VALUE tmp = rb_check_string_type(str);
00935             if (NIL_P(tmp)) {
00936                 limit = NUM2LONG(str);
00937                 if (limit == 0) return rb_str_new(0,0);
00938                 str = rb_rs;
00939             }
00940             else {
00941                 str = tmp;
00942             }
00943         }
00944         break;
00945 
00946       case 2:
00947         if (!NIL_P(str)) StringValue(str);
00948         limit = NUM2LONG(lim);
00949         break;
00950     }
00951 
00952     if (ptr->pos >= (n = RSTRING_LEN(ptr->string))) {
00953         return Qnil;
00954     }
00955     s = RSTRING_PTR(ptr->string);
00956     e = s + RSTRING_LEN(ptr->string);
00957     s += ptr->pos;
00958     if (limit > 0 && s + limit < e) {
00959         e = rb_enc_right_char_head(s, s + limit, e, rb_enc_get(ptr->string));
00960     }
00961     if (NIL_P(str)) {
00962         str = strio_substr(ptr, ptr->pos, e - s);
00963     }
00964     else if ((n = RSTRING_LEN(str)) == 0) {
00965         p = s;
00966         while (*p == '\n') {
00967             if (++p == e) {
00968                 return Qnil;
00969             }
00970         }
00971         s = p;
00972         while ((p = memchr(p, '\n', e - p)) && (p != e)) {
00973             if (*++p == '\n') {
00974                 e = p + 1;
00975                 break;
00976             }
00977         }
00978         str = strio_substr(ptr, s - RSTRING_PTR(ptr->string), e - s);
00979     }
00980     else if (n == 1) {
00981         if ((p = memchr(s, RSTRING_PTR(str)[0], e - s)) != 0) {
00982             e = p + 1;
00983         }
00984         str = strio_substr(ptr, ptr->pos, e - s);
00985     }
00986     else {
00987         if (n < e - s) {
00988             if (e - s < 1024) {
00989                 for (p = s; p + n <= e; ++p) {
00990                     if (MEMCMP(p, RSTRING_PTR(str), char, n) == 0) {
00991                         e = p + n;
00992                         break;
00993                     }
00994                 }
00995             }
00996             else {
00997                 long skip[1 << CHAR_BIT], pos;
00998                 p = RSTRING_PTR(str);
00999                 bm_init_skip(skip, p, n);
01000                 if ((pos = bm_search(p, n, s, e - s, skip)) >= 0) {
01001                     e = s + pos + n;
01002                 }
01003             }
01004         }
01005         str = strio_substr(ptr, ptr->pos, e - s);
01006     }
01007     ptr->pos = e - RSTRING_PTR(ptr->string);
01008     ptr->lineno++;
01009     return str;
01010 }
01011 
01012 /*
01013  * call-seq:
01014  *   strio.gets(sep=$/)     -> string or nil
01015  *   strio.gets(limit)      -> string or nil
01016  *   strio.gets(sep, limit) -> string or nil
01017  *
01018  * See IO#gets.
01019  */
01020 static VALUE
01021 strio_gets(int argc, VALUE *argv, VALUE self)
01022 {
01023     VALUE str = strio_getline(argc, argv, readable(StringIO(self)));
01024 
01025     rb_lastline_set(str);
01026     return str;
01027 }
01028 
01029 /*
01030  * call-seq:
01031  *   strio.readline(sep=$/)     -> string
01032  *   strio.readline(limit)      -> string or nil
01033  *   strio.readline(sep, limit) -> string or nil
01034  *
01035  * See IO#readline.
01036  */
01037 static VALUE
01038 strio_readline(int argc, VALUE *argv, VALUE self)
01039 {
01040     VALUE line = rb_funcall2(self, rb_intern("gets"), argc, argv);
01041     if (NIL_P(line)) rb_eof_error();
01042     return line;
01043 }
01044 
01045 /*
01046  * call-seq:
01047  *   strio.each(sep=$/) {|line| block }         -> strio
01048  *   strio.each(limit) {|line| block }          -> strio
01049  *   strio.each(sep, limit) {|line| block }     -> strio
01050  *   strio.each(...)                            -> anEnumerator
01051  *
01052  *   strio.each_line(sep=$/) {|line| block }    -> strio
01053  *   strio.each_line(limit) {|line| block }     -> strio
01054  *   strio.each_line(sep,limit) {|line| block } -> strio
01055  *   strio.each_line(...)                       -> anEnumerator
01056  *
01057  *   strio.lines(sep=$/) {|line| block }        -> strio
01058  *   strio.lines(limit) {|line| block }         -> strio
01059  *   strio.lines(sep,limit) {|line| block }     -> strio
01060  *   strio.lines(...)                           -> anEnumerator
01061  *
01062  * See IO#each.
01063  */
01064 static VALUE
01065 strio_each(int argc, VALUE *argv, VALUE self)
01066 {
01067     struct StringIO *ptr = StringIO(self);
01068     VALUE line;
01069 
01070     RETURN_ENUMERATOR(self, argc, argv);
01071 
01072     if (argc > 0 && !NIL_P(argv[argc-1]) && NIL_P(rb_check_string_type(argv[argc-1])) &&
01073         NUM2LONG(argv[argc-1]) == 0) {
01074         rb_raise(rb_eArgError, "invalid limit: 0 for each_line");
01075     }
01076 
01077     while (!NIL_P(line = strio_getline(argc, argv, readable(ptr)))) {
01078         rb_yield(line);
01079     }
01080     return self;
01081 }
01082 
01083 /*
01084  * call-seq:
01085  *   strio.readlines(sep=$/)    ->   array
01086  *   strio.readlines(limit)     ->   array
01087  *   strio.readlines(sep,limit) ->   array
01088  *
01089  * See IO#readlines.
01090  */
01091 static VALUE
01092 strio_readlines(int argc, VALUE *argv, VALUE self)
01093 {
01094     struct StringIO *ptr = StringIO(self);
01095     VALUE ary = rb_ary_new(), line;
01096 
01097     if (argc > 0 && !NIL_P(argv[argc-1]) && NIL_P(rb_check_string_type(argv[argc-1])) &&
01098         NUM2LONG(argv[argc-1]) == 0) {
01099         rb_raise(rb_eArgError, "invalid limit: 0 for readlines");
01100     }
01101 
01102     while (!NIL_P(line = strio_getline(argc, argv, readable(ptr)))) {
01103         rb_ary_push(ary, line);
01104     }
01105     return ary;
01106 }
01107 
01108 /*
01109  * call-seq:
01110  *   strio.write(string)    -> integer
01111  *   strio.syswrite(string) -> integer
01112  *
01113  * Appends the given string to the underlying buffer string of *strio*.
01114  * The stream must be opened for writing.  If the argument is not a
01115  * string, it will be converted to a string using <code>to_s</code>.
01116  * Returns the number of bytes written.  See IO#write.
01117  */
01118 static VALUE
01119 strio_write(VALUE self, VALUE str)
01120 {
01121     struct StringIO *ptr = writable(StringIO(self));
01122     long len, olen;
01123     rb_encoding *enc, *enc2;
01124 
01125     RB_GC_GUARD(str);
01126     if (TYPE(str) != T_STRING)
01127         str = rb_obj_as_string(str);
01128     enc = rb_enc_get(ptr->string);
01129     enc2 = rb_enc_get(str);
01130     if (enc != enc2 && enc != rb_ascii8bit_encoding()) {
01131         str = rb_str_conv_enc(str, enc2, enc);
01132     }
01133     len = RSTRING_LEN(str);
01134     if (len == 0) return INT2FIX(0);
01135     check_modifiable(ptr);
01136     olen = RSTRING_LEN(ptr->string);
01137     if (ptr->flags & FMODE_APPEND) {
01138         ptr->pos = olen;
01139     }
01140     if (ptr->pos == olen) {
01141         rb_str_cat(ptr->string, RSTRING_PTR(str), len);
01142     }
01143     else {
01144         strio_extend(ptr, ptr->pos, len);
01145         memmove(RSTRING_PTR(ptr->string)+ptr->pos, RSTRING_PTR(str), len);
01146         OBJ_INFECT(ptr->string, str);
01147     }
01148     OBJ_INFECT(ptr->string, self);
01149     ptr->pos += len;
01150     return LONG2NUM(len);
01151 }
01152 
01153 /*
01154  * call-seq:
01155  *   strio << obj     -> strio
01156  *
01157  * See IO#<<.
01158  */
01159 #define strio_addstr rb_io_addstr
01160 
01161 /*
01162  * call-seq:
01163  *   strio.print()             -> nil
01164  *   strio.print(obj, ...)     -> nil
01165  *
01166  * See IO#print.
01167  */
01168 #define strio_print rb_io_print
01169 
01170 /*
01171  * call-seq:
01172  *   strio.printf(format_string [, obj, ...] )   -> nil
01173  *
01174  * See IO#printf.
01175  */
01176 #define strio_printf rb_io_printf
01177 
01178 /*
01179  * call-seq:
01180  *   strio.putc(obj)    -> obj
01181  *
01182  * See IO#putc.
01183  */
01184 static VALUE
01185 strio_putc(VALUE self, VALUE ch)
01186 {
01187     struct StringIO *ptr = writable(StringIO(self));
01188     int c = NUM2CHR(ch);
01189     long olen;
01190 
01191     check_modifiable(ptr);
01192     olen = RSTRING_LEN(ptr->string);
01193     if (ptr->flags & FMODE_APPEND) {
01194         ptr->pos = olen;
01195     }
01196     strio_extend(ptr, ptr->pos, 1);
01197     RSTRING_PTR(ptr->string)[ptr->pos++] = c;
01198     OBJ_INFECT(ptr->string, self);
01199     return ch;
01200 }
01201 
01202 /*
01203  * call-seq:
01204  *   strio.puts(obj, ...)    -> nil
01205  *
01206  * See IO#puts.
01207  */
01208 #define strio_puts rb_io_puts
01209 
01210 /*
01211  * call-seq:
01212  *   strio.read([length [, buffer]])    -> string, buffer, or nil
01213  *
01214  * See IO#read.
01215  */
01216 static VALUE
01217 strio_read(int argc, VALUE *argv, VALUE self)
01218 {
01219     struct StringIO *ptr = readable(StringIO(self));
01220     VALUE str = Qnil;
01221     long len;
01222     int binary = 0;
01223 
01224     switch (argc) {
01225       case 2:
01226         str = argv[1];
01227         if (!NIL_P(str)) {
01228             StringValue(str);
01229             rb_str_modify(str);
01230         }
01231       case 1:
01232         if (!NIL_P(argv[0])) {
01233             len = NUM2LONG(argv[0]);
01234             if (len < 0) {
01235                 rb_raise(rb_eArgError, "negative length %ld given", len);
01236             }
01237             if (len > 0 && ptr->pos >= RSTRING_LEN(ptr->string)) {
01238                 if (!NIL_P(str)) rb_str_resize(str, 0);
01239                 return Qnil;
01240             }
01241             binary = 1;
01242             break;
01243         }
01244         /* fall through */
01245       case 0:
01246         len = RSTRING_LEN(ptr->string);
01247         if (len <= ptr->pos) {
01248             if (NIL_P(str)) {
01249                 str = rb_str_new(0, 0);
01250             }
01251             else {
01252                 rb_str_resize(str, 0);
01253             }
01254             return str;
01255         }
01256         else {
01257             len -= ptr->pos;
01258         }
01259         break;
01260       default:
01261         rb_raise(rb_eArgError, "wrong number of arguments (%d for 0)", argc);
01262     }
01263     if (NIL_P(str)) {
01264         str = strio_substr(ptr, ptr->pos, len);
01265         if (binary) rb_enc_associate(str, rb_ascii8bit_encoding());
01266     }
01267     else {
01268         long rest = RSTRING_LEN(ptr->string) - ptr->pos;
01269         if (len > rest) len = rest;
01270         rb_str_resize(str, len);
01271         MEMCPY(RSTRING_PTR(str), RSTRING_PTR(ptr->string) + ptr->pos, char, len);
01272         if (binary)
01273             rb_enc_associate(str, rb_ascii8bit_encoding());
01274         else
01275             rb_enc_copy(str, ptr->string);
01276     }
01277     ptr->pos += RSTRING_LEN(str);
01278     return str;
01279 }
01280 
01281 /*
01282  * call-seq:
01283  *   strio.sysread(integer[, outbuf])    -> string
01284  *
01285  * Similar to #read, but raises +EOFError+ at end of string instead of
01286  * returning +nil+, as well as IO#sysread does.
01287  */
01288 static VALUE
01289 strio_sysread(int argc, VALUE *argv, VALUE self)
01290 {
01291     VALUE val = rb_funcall2(self, rb_intern("read"), argc, argv);
01292     if (NIL_P(val)) {
01293         rb_eof_error();
01294     }
01295     return val;
01296 }
01297 
01298 #define strio_syswrite rb_io_write
01299 
01300 /*
01301  * call-seq:
01302  *   strio.isatty -> nil
01303  *   strio.tty? -> nil
01304  *
01305  */
01306 #define strio_isatty strio_false
01307 
01308 /* call-seq: strio.pid -> nil */
01309 #define strio_pid strio_nil
01310 
01311 /* call-seq: strio.fileno -> nil */
01312 #define strio_fileno strio_nil
01313 
01314 /*
01315  * call-seq:
01316  *   strio.size   -> integer
01317  *
01318  * Returns the size of the buffer string.
01319  */
01320 static VALUE
01321 strio_size(VALUE self)
01322 {
01323     VALUE string = StringIO(self)->string;
01324     if (NIL_P(string)) {
01325         rb_raise(rb_eIOError, "not opened");
01326     }
01327     return ULONG2NUM(RSTRING_LEN(string));
01328 }
01329 
01330 /*
01331  * call-seq:
01332  *   strio.truncate(integer)    -> 0
01333  *
01334  * Truncates the buffer string to at most _integer_ bytes. The *strio*
01335  * must be opened for writing.
01336  */
01337 static VALUE
01338 strio_truncate(VALUE self, VALUE len)
01339 {
01340     VALUE string = writable(StringIO(self))->string;
01341     long l = NUM2LONG(len);
01342     long plen = RSTRING_LEN(string);
01343     if (l < 0) {
01344         error_inval("negative legnth");
01345     }
01346     rb_str_resize(string, l);
01347     if (plen < l) {
01348         MEMZERO(RSTRING_PTR(string) + plen, char, l - plen);
01349     }
01350     return len;
01351 }
01352 
01353 /*
01354  *  call-seq:
01355  *     strio.external_encoding   => encoding
01356  *
01357  *  Returns the Encoding object that represents the encoding of the file.
01358  *  If strio is write mode and no encoding is specified, returns <code>nil</code>.
01359  */
01360 
01361 static VALUE
01362 strio_external_encoding(VALUE self)
01363 {
01364     return rb_enc_from_encoding(rb_enc_get(StringIO(self)->string));
01365 }
01366 
01367 /*
01368  *  call-seq:
01369  *     strio.internal_encoding   => encoding
01370  *
01371  *  Returns the Encoding of the internal string if conversion is
01372  *  specified.  Otherwise returns nil.
01373  */
01374 
01375 static VALUE
01376 strio_internal_encoding(VALUE self)
01377 {
01378      return Qnil;
01379 }
01380 
01381 /*
01382  *  call-seq:
01383  *     strio.set_encoding(ext_enc, [int_enc[, opt]])  => strio
01384  *
01385  *  Specify the encoding of the StringIO as <i>ext_enc</i>.
01386  *  Use the default external encoding if <i>ext_enc</i> is nil.
01387  *  2nd argument <i>int_enc</i> and optional hash <i>opt</i> argument
01388  *  are ignored; they are for API compatibility to IO.
01389  */
01390 
01391 static VALUE
01392 strio_set_encoding(int argc, VALUE *argv, VALUE self)
01393 {
01394     rb_encoding* enc;
01395     VALUE str = StringIO(self)->string;
01396     VALUE ext_enc, int_enc, opt;
01397 
01398     argc = rb_scan_args(argc, argv, "11:", &ext_enc, &int_enc, &opt);
01399 
01400     if (NIL_P(ext_enc)) {
01401         enc = rb_default_external_encoding();
01402     }
01403     else {
01404         enc = rb_to_encoding(ext_enc);
01405     }
01406     rb_enc_associate(str, enc);
01407     return self;
01408 }
01409 
01410 /*
01411  * Pseudo I/O on String object.
01412  */
01413 void
01414 Init_stringio()
01415 {
01416     VALUE StringIO = rb_define_class("StringIO", rb_cData);
01417 
01418     rb_include_module(StringIO, rb_mEnumerable);
01419     rb_define_alloc_func(StringIO, strio_s_allocate);
01420     rb_define_singleton_method(StringIO, "open", strio_s_open, -1);
01421     rb_define_method(StringIO, "initialize", strio_initialize, -1);
01422     rb_define_method(StringIO, "initialize_copy", strio_copy, 1);
01423     rb_define_method(StringIO, "reopen", strio_reopen, -1);
01424 
01425     rb_define_method(StringIO, "string", strio_get_string, 0);
01426     rb_define_method(StringIO, "string=", strio_set_string, 1);
01427     rb_define_method(StringIO, "lineno", strio_get_lineno, 0);
01428     rb_define_method(StringIO, "lineno=", strio_set_lineno, 1);
01429 
01430     rb_define_method(StringIO, "binmode", strio_binmode, 0);
01431     rb_define_method(StringIO, "close", strio_close, 0);
01432     rb_define_method(StringIO, "close_read", strio_close_read, 0);
01433     rb_define_method(StringIO, "close_write", strio_close_write, 0);
01434     rb_define_method(StringIO, "closed?", strio_closed, 0);
01435     rb_define_method(StringIO, "closed_read?", strio_closed_read, 0);
01436     rb_define_method(StringIO, "closed_write?", strio_closed_write, 0);
01437     rb_define_method(StringIO, "eof", strio_eof, 0);
01438     rb_define_method(StringIO, "eof?", strio_eof, 0);
01439     rb_define_method(StringIO, "fcntl", strio_fcntl, -1);
01440     rb_define_method(StringIO, "flush", strio_flush, 0);
01441     rb_define_method(StringIO, "fsync", strio_fsync, 0);
01442     rb_define_method(StringIO, "pos", strio_get_pos, 0);
01443     rb_define_method(StringIO, "pos=", strio_set_pos, 1);
01444     rb_define_method(StringIO, "rewind", strio_rewind, 0);
01445     rb_define_method(StringIO, "seek", strio_seek, -1);
01446     rb_define_method(StringIO, "sync", strio_get_sync, 0);
01447     rb_define_method(StringIO, "sync=", strio_set_sync, 1);
01448     rb_define_method(StringIO, "tell", strio_tell, 0);
01449 
01450     rb_define_method(StringIO, "each", strio_each, -1);
01451     rb_define_method(StringIO, "each_line", strio_each, -1);
01452     rb_define_method(StringIO, "lines", strio_each, -1);
01453     rb_define_method(StringIO, "each_byte", strio_each_byte, 0);
01454     rb_define_method(StringIO, "bytes", strio_each_byte, 0);
01455     rb_define_method(StringIO, "each_char", strio_each_char, 0);
01456     rb_define_method(StringIO, "chars", strio_each_char, 0);
01457     rb_define_method(StringIO, "each_codepoint", strio_each_codepoint, 0);
01458     rb_define_method(StringIO, "codepoints", strio_each_codepoint, 0);
01459     rb_define_method(StringIO, "getc", strio_getc, 0);
01460     rb_define_method(StringIO, "ungetc", strio_ungetc, 1);
01461     rb_define_method(StringIO, "ungetbyte", strio_ungetbyte, 1);
01462     rb_define_method(StringIO, "getbyte", strio_getbyte, 0);
01463     rb_define_method(StringIO, "gets", strio_gets, -1);
01464     rb_define_method(StringIO, "readlines", strio_readlines, -1);
01465     rb_define_method(StringIO, "read", strio_read, -1);
01466 
01467     rb_define_method(StringIO, "write", strio_write, 1);
01468     rb_define_method(StringIO, "putc", strio_putc, 1);
01469 
01470     rb_define_method(StringIO, "isatty", strio_isatty, 0);
01471     rb_define_method(StringIO, "tty?", strio_isatty, 0);
01472     rb_define_method(StringIO, "pid", strio_pid, 0);
01473     rb_define_method(StringIO, "fileno", strio_fileno, 0);
01474     rb_define_method(StringIO, "size", strio_size, 0);
01475     rb_define_method(StringIO, "length", strio_size, 0);
01476     rb_define_method(StringIO, "truncate", strio_truncate, 1);
01477 
01478     rb_define_method(StringIO, "external_encoding", strio_external_encoding, 0);
01479     rb_define_method(StringIO, "internal_encoding", strio_internal_encoding, 0);
01480     rb_define_method(StringIO, "set_encoding", strio_set_encoding, -1);
01481 
01482     {
01483         VALUE mReadable = rb_define_module_under(rb_cIO, "readable");
01484         rb_define_method(mReadable, "readchar", strio_readchar, 0);
01485         rb_define_method(mReadable, "readbyte", strio_readbyte, 0);
01486         rb_define_method(mReadable, "readline", strio_readline, -1);
01487         rb_define_method(mReadable, "sysread", strio_sysread, -1);
01488         rb_define_method(mReadable, "readpartial", strio_sysread, -1);
01489         rb_define_method(mReadable, "read_nonblock", strio_sysread, -1);
01490         rb_include_module(StringIO, mReadable);
01491     }
01492     {
01493         VALUE mWritable = rb_define_module_under(rb_cIO, "writable");
01494         rb_define_method(mWritable, "<<", strio_addstr, 1);
01495         rb_define_method(mWritable, "print", strio_print, -1);
01496         rb_define_method(mWritable, "printf", strio_printf, -1);
01497         rb_define_method(mWritable, "puts", strio_puts, -1);
01498         rb_define_method(mWritable, "syswrite", strio_syswrite, 1);
01499         rb_define_method(mWritable, "write_nonblock", strio_syswrite, 1);
01500         rb_include_module(StringIO, mWritable);
01501     }
01502 }
01503