1/********************************************************************** 2 3 stringio.c - 4 5 $Author: glass $ 6 $RoughId: stringio.c,v 1.13 2002/03/14 03:24:18 nobu Exp $ 7 created at: Tue Feb 19 04:10:38 JST 2002 8 9 All the files in this distribution are covered under the Ruby's 10 license (see the file COPYING). 11 12**********************************************************************/ 13 14#include "ruby.h" 15#include "ruby/io.h" 16#include "ruby/encoding.h" 17#if defined(HAVE_FCNTL_H) || defined(_WIN32) 18#include <fcntl.h> 19#elif defined(HAVE_SYS_FCNTL_H) 20#include <sys/fcntl.h> 21#endif 22 23struct StringIO { 24 VALUE string; 25 long pos; 26 long lineno; 27 int flags; 28 int count; 29}; 30 31static void strio_init(int, VALUE *, struct StringIO *, VALUE); 32 33#define IS_STRIO(obj) (rb_typeddata_is_kind_of((obj), &strio_data_type)) 34#define error_inval(msg) (errno = EINVAL, rb_sys_fail(msg)) 35 36static struct StringIO * 37strio_alloc(void) 38{ 39 struct StringIO *ptr = ALLOC(struct StringIO); 40 ptr->string = Qnil; 41 ptr->pos = 0; 42 ptr->lineno = 0; 43 ptr->flags = 0; 44 ptr->count = 1; 45 return ptr; 46} 47 48static void 49strio_mark(void *p) 50{ 51 struct StringIO *ptr = p; 52 if (ptr) { 53 rb_gc_mark(ptr->string); 54 } 55} 56 57static void 58strio_free(void *p) 59{ 60 struct StringIO *ptr = p; 61 if (--ptr->count <= 0) { 62 xfree(ptr); 63 } 64} 65 66static size_t 67strio_memsize(const void *p) 68{ 69 const struct StringIO *ptr = p; 70 if (!ptr) return 0; 71 return sizeof(struct StringIO); 72} 73 74static const rb_data_type_t strio_data_type = { 75 "strio", 76 { 77 strio_mark, 78 strio_free, 79 strio_memsize, 80 }, 81}; 82 83#define check_strio(self) ((struct StringIO*)rb_check_typeddata((self), &strio_data_type)) 84 85static struct StringIO* 86get_strio(VALUE self) 87{ 88 struct StringIO *ptr = check_strio(rb_io_taint_check(self)); 89 90 if (!ptr) { 91 rb_raise(rb_eIOError, "uninitialized stream"); 92 } 93 return ptr; 94} 95 96static VALUE 97strio_substr(struct StringIO *ptr, long pos, long len) 98{ 99 VALUE str = ptr->string; 100 rb_encoding *enc = rb_enc_get(str); 101 long rlen = RSTRING_LEN(str) - pos; 102 103 if (len > rlen) len = rlen; 104 if (len < 0) len = 0; 105 return rb_enc_str_new(RSTRING_PTR(str)+pos, len, enc); 106} 107 108#define StringIO(obj) get_strio(obj) 109 110#define STRIO_READABLE FL_USER4 111#define STRIO_WRITABLE FL_USER5 112#define STRIO_READWRITE (STRIO_READABLE|STRIO_WRITABLE) 113typedef char strio_flags_check[(STRIO_READABLE/FMODE_READABLE == STRIO_WRITABLE/FMODE_WRITABLE) * 2 - 1]; 114#define STRIO_MODE_SET_P(strio, mode) \ 115 ((RBASIC(strio)->flags & STRIO_##mode) && \ 116 ((struct StringIO*)DATA_PTR(strio))->flags & FMODE_##mode) 117#define CLOSED(strio) (!STRIO_MODE_SET_P(strio, READWRITE)) 118#define READABLE(strio) STRIO_MODE_SET_P(strio, READABLE) 119#define WRITABLE(strio) STRIO_MODE_SET_P(strio, WRITABLE) 120 121static struct StringIO* 122readable(VALUE strio) 123{ 124 struct StringIO *ptr = StringIO(strio); 125 if (!READABLE(strio)) { 126 rb_raise(rb_eIOError, "not opened for reading"); 127 } 128 return ptr; 129} 130 131static struct StringIO* 132writable(VALUE strio) 133{ 134 struct StringIO *ptr = StringIO(strio); 135 if (!WRITABLE(strio)) { 136 rb_raise(rb_eIOError, "not opened for writing"); 137 } 138 if (!OBJ_TAINTED(ptr->string)) { 139 rb_secure(4); 140 } 141 return ptr; 142} 143 144static void 145check_modifiable(struct StringIO *ptr) 146{ 147 if (OBJ_FROZEN(ptr->string)) { 148 rb_raise(rb_eIOError, "not modifiable string"); 149 } 150} 151 152static VALUE 153strio_s_allocate(VALUE klass) 154{ 155 return TypedData_Wrap_Struct(klass, &strio_data_type, 0); 156} 157 158/* 159 * call-seq: StringIO.new(string=""[, mode]) 160 * 161 * Creates new StringIO instance from with _string_ and _mode_. 162 */ 163static VALUE 164strio_initialize(int argc, VALUE *argv, VALUE self) 165{ 166 struct StringIO *ptr = check_strio(self); 167 168 if (!ptr) { 169 DATA_PTR(self) = ptr = strio_alloc(); 170 } 171 rb_call_super(0, 0); 172 strio_init(argc, argv, ptr, self); 173 return self; 174} 175 176static void 177strio_init(int argc, VALUE *argv, struct StringIO *ptr, VALUE self) 178{ 179 VALUE string, mode; 180 int trunc = 0; 181 182 switch (rb_scan_args(argc, argv, "02", &string, &mode)) { 183 case 2: 184 if (FIXNUM_P(mode)) { 185 int flags = FIX2INT(mode); 186 ptr->flags = rb_io_modenum_flags(flags); 187 trunc = flags & O_TRUNC; 188 } 189 else { 190 const char *m = StringValueCStr(mode); 191 ptr->flags = rb_io_mode_flags(m); 192 trunc = *m == 'w'; 193 } 194 StringValue(string); 195 if ((ptr->flags & FMODE_WRITABLE) && OBJ_FROZEN(string)) { 196 errno = EACCES; 197 rb_sys_fail(0); 198 } 199 if (trunc) { 200 rb_str_resize(string, 0); 201 } 202 break; 203 case 1: 204 StringValue(string); 205 ptr->flags = OBJ_FROZEN(string) ? FMODE_READABLE : FMODE_READWRITE; 206 break; 207 case 0: 208 string = rb_enc_str_new("", 0, rb_default_external_encoding()); 209 ptr->flags = FMODE_READWRITE; 210 break; 211 } 212 ptr->string = string; 213 ptr->pos = 0; 214 ptr->lineno = 0; 215 RBASIC(self)->flags |= (ptr->flags & FMODE_READWRITE) * (STRIO_READABLE / FMODE_READABLE); 216} 217 218static VALUE 219strio_finalize(VALUE self) 220{ 221 struct StringIO *ptr = StringIO(self); 222 ptr->string = Qnil; 223 ptr->flags &= ~FMODE_READWRITE; 224 return self; 225} 226 227/* 228 * call-seq: StringIO.open(string=""[, mode]) {|strio| ...} 229 * 230 * Equivalent to StringIO.new except that when it is called with a block, it 231 * yields with the new instance and closes it, and returns the result which 232 * returned from the block. 233 */ 234static VALUE 235strio_s_open(int argc, VALUE *argv, VALUE klass) 236{ 237 VALUE obj = rb_class_new_instance(argc, argv, klass); 238 if (!rb_block_given_p()) return obj; 239 return rb_ensure(rb_yield, obj, strio_finalize, obj); 240} 241 242/* 243 * Returns +false+. Just for compatibility to IO. 244 */ 245static VALUE 246strio_false(VALUE self) 247{ 248 StringIO(self); 249 return Qfalse; 250} 251 252/* 253 * Returns +nil+. Just for compatibility to IO. 254 */ 255static VALUE 256strio_nil(VALUE self) 257{ 258 StringIO(self); 259 return Qnil; 260} 261 262/* 263 * Returns *strio* itself. Just for compatibility to IO. 264 */ 265static VALUE 266strio_self(VALUE self) 267{ 268 StringIO(self); 269 return self; 270} 271 272/* 273 * Returns 0. Just for compatibility to IO. 274 */ 275static VALUE 276strio_0(VALUE self) 277{ 278 StringIO(self); 279 return INT2FIX(0); 280} 281 282/* 283 * Returns the argument unchanged. Just for compatibility to IO. 284 */ 285static VALUE 286strio_first(VALUE self, VALUE arg) 287{ 288 StringIO(self); 289 return arg; 290} 291 292/* 293 * Raises NotImplementedError. 294 */ 295static VALUE 296strio_unimpl(int argc, VALUE *argv, VALUE self) 297{ 298 StringIO(self); 299 rb_notimplement(); 300 301 UNREACHABLE; 302} 303 304/* 305 * call-seq: strio.string -> string 306 * 307 * Returns underlying String object, the subject of IO. 308 */ 309static VALUE 310strio_get_string(VALUE self) 311{ 312 return StringIO(self)->string; 313} 314 315/* 316 * call-seq: 317 * strio.string = string -> string 318 * 319 * Changes underlying String object, the subject of IO. 320 */ 321static VALUE 322strio_set_string(VALUE self, VALUE string) 323{ 324 struct StringIO *ptr = StringIO(self); 325 326 rb_io_taint_check(self); 327 ptr->flags &= ~FMODE_READWRITE; 328 StringValue(string); 329 ptr->flags = OBJ_FROZEN(string) ? FMODE_READABLE : FMODE_READWRITE; 330 ptr->pos = 0; 331 ptr->lineno = 0; 332 return ptr->string = string; 333} 334 335/* 336 * call-seq: 337 * strio.close -> nil 338 * 339 * Closes strio. The *strio* is unavailable for any further data 340 * operations; an +IOError+ is raised if such an attempt is made. 341 */ 342static VALUE 343strio_close(VALUE self) 344{ 345 StringIO(self); 346 if (CLOSED(self)) { 347 rb_raise(rb_eIOError, "closed stream"); 348 } 349 RBASIC(self)->flags &= ~STRIO_READWRITE; 350 return Qnil; 351} 352 353/* 354 * call-seq: 355 * strio.close_read -> nil 356 * 357 * Closes the read end of a StringIO. Will raise an +IOError+ if the 358 * *strio* is not readable. 359 */ 360static VALUE 361strio_close_read(VALUE self) 362{ 363 StringIO(self); 364 if (!READABLE(self)) { 365 rb_raise(rb_eIOError, "closing non-duplex IO for reading"); 366 } 367 RBASIC(self)->flags &= ~STRIO_READABLE; 368 return Qnil; 369} 370 371/* 372 * call-seq: 373 * strio.close_write -> nil 374 * 375 * Closes the write end of a StringIO. Will raise an +IOError+ if the 376 * *strio* is not writeable. 377 */ 378static VALUE 379strio_close_write(VALUE self) 380{ 381 StringIO(self); 382 if (!WRITABLE(self)) { 383 rb_raise(rb_eIOError, "closing non-duplex IO for writing"); 384 } 385 RBASIC(self)->flags &= ~STRIO_WRITABLE; 386 return Qnil; 387} 388 389/* 390 * call-seq: 391 * strio.closed? -> true or false 392 * 393 * Returns +true+ if *strio* is completely closed, +false+ otherwise. 394 */ 395static VALUE 396strio_closed(VALUE self) 397{ 398 StringIO(self); 399 if (!CLOSED(self)) return Qfalse; 400 return Qtrue; 401} 402 403/* 404 * call-seq: 405 * strio.closed_read? -> true or false 406 * 407 * Returns +true+ if *strio* is not readable, +false+ otherwise. 408 */ 409static VALUE 410strio_closed_read(VALUE self) 411{ 412 StringIO(self); 413 if (READABLE(self)) return Qfalse; 414 return Qtrue; 415} 416 417/* 418 * call-seq: 419 * strio.closed_write? -> true or false 420 * 421 * Returns +true+ if *strio* is not writable, +false+ otherwise. 422 */ 423static VALUE 424strio_closed_write(VALUE self) 425{ 426 StringIO(self); 427 if (WRITABLE(self)) return Qfalse; 428 return Qtrue; 429} 430 431/* 432 * call-seq: 433 * strio.eof -> true or false 434 * strio.eof? -> true or false 435 * 436 * Returns true if *strio* is at end of file. The stringio must be 437 * opened for reading or an +IOError+ will be raised. 438 */ 439static VALUE 440strio_eof(VALUE self) 441{ 442 struct StringIO *ptr = readable(self); 443 if (ptr->pos < RSTRING_LEN(ptr->string)) return Qfalse; 444 return Qtrue; 445} 446 447/* :nodoc: */ 448static VALUE 449strio_copy(VALUE copy, VALUE orig) 450{ 451 struct StringIO *ptr; 452 453 orig = rb_convert_type(orig, T_DATA, "StringIO", "to_strio"); 454 if (copy == orig) return copy; 455 ptr = StringIO(orig); 456 if (check_strio(copy)) { 457 strio_free(DATA_PTR(copy)); 458 } 459 DATA_PTR(copy) = ptr; 460 OBJ_INFECT(copy, orig); 461 RBASIC(copy)->flags &= ~STRIO_READWRITE; 462 RBASIC(copy)->flags |= RBASIC(orig)->flags & STRIO_READWRITE; 463 ++ptr->count; 464 return copy; 465} 466 467/* 468 * call-seq: 469 * strio.lineno -> integer 470 * 471 * Returns the current line number in *strio*. The stringio must be 472 * opened for reading. +lineno+ counts the number of times +gets+ is 473 * called, rather than the number of newlines encountered. The two 474 * values will differ if +gets+ is called with a separator other than 475 * newline. See also the <code>$.</code> variable. 476 */ 477static VALUE 478strio_get_lineno(VALUE self) 479{ 480 return LONG2NUM(StringIO(self)->lineno); 481} 482 483/* 484 * call-seq: 485 * strio.lineno = integer -> integer 486 * 487 * Manually sets the current line number to the given value. 488 * <code>$.</code> is updated only on the next read. 489 */ 490static VALUE 491strio_set_lineno(VALUE self, VALUE lineno) 492{ 493 StringIO(self)->lineno = NUM2LONG(lineno); 494 return lineno; 495} 496 497/* call-seq: strio.binmode -> true */ 498#define strio_binmode strio_self 499 500/* call-seq: strio.fcntl */ 501#define strio_fcntl strio_unimpl 502 503/* call-seq: strio.flush -> strio */ 504#define strio_flush strio_self 505 506/* call-seq: strio.fsync -> 0 */ 507#define strio_fsync strio_0 508 509/* 510 * call-seq: 511 * strio.reopen(other_StrIO) -> strio 512 * strio.reopen(string, mode) -> strio 513 * 514 * Reinitializes *strio* with the given <i>other_StrIO</i> or _string_ 515 * and _mode_ (see StringIO#new). 516 */ 517static VALUE 518strio_reopen(int argc, VALUE *argv, VALUE self) 519{ 520 rb_io_taint_check(self); 521 if (argc == 1 && !RB_TYPE_P(*argv, T_STRING)) { 522 return strio_copy(self, *argv); 523 } 524 strio_init(argc, argv, StringIO(self), self); 525 return self; 526} 527 528/* 529 * call-seq: 530 * strio.pos -> integer 531 * strio.tell -> integer 532 * 533 * Returns the current offset (in bytes) of *strio*. 534 */ 535static VALUE 536strio_get_pos(VALUE self) 537{ 538 return LONG2NUM(StringIO(self)->pos); 539} 540 541/* 542 * call-seq: 543 * strio.pos = integer -> integer 544 * 545 * Seeks to the given position (in bytes) in *strio*. 546 */ 547static VALUE 548strio_set_pos(VALUE self, VALUE pos) 549{ 550 struct StringIO *ptr = StringIO(self); 551 long p = NUM2LONG(pos); 552 if (p < 0) { 553 error_inval(0); 554 } 555 ptr->pos = p; 556 return pos; 557} 558 559/* 560 * call-seq: 561 * strio.rewind -> 0 562 * 563 * Positions *strio* to the beginning of input, resetting 564 * +lineno+ to zero. 565 */ 566static VALUE 567strio_rewind(VALUE self) 568{ 569 struct StringIO *ptr = StringIO(self); 570 ptr->pos = 0; 571 ptr->lineno = 0; 572 return INT2FIX(0); 573} 574 575/* 576 * call-seq: 577 * strio.seek(amount, whence=SEEK_SET) -> 0 578 * 579 * Seeks to a given offset _amount_ in the stream according to 580 * the value of _whence_ (see IO#seek). 581 */ 582static VALUE 583strio_seek(int argc, VALUE *argv, VALUE self) 584{ 585 VALUE whence; 586 struct StringIO *ptr = StringIO(self); 587 long offset; 588 589 rb_scan_args(argc, argv, "11", NULL, &whence); 590 offset = NUM2LONG(argv[0]); 591 if (CLOSED(self)) { 592 rb_raise(rb_eIOError, "closed stream"); 593 } 594 switch (NIL_P(whence) ? 0 : NUM2LONG(whence)) { 595 case 0: 596 break; 597 case 1: 598 offset += ptr->pos; 599 break; 600 case 2: 601 offset += RSTRING_LEN(ptr->string); 602 break; 603 default: 604 error_inval("invalid whence"); 605 } 606 if (offset < 0) { 607 error_inval(0); 608 } 609 ptr->pos = offset; 610 return INT2FIX(0); 611} 612 613/* 614 * call-seq: 615 * strio.sync -> true 616 * 617 * Returns +true+ always. 618 */ 619static VALUE 620strio_get_sync(VALUE self) 621{ 622 StringIO(self); 623 return Qtrue; 624} 625 626/* call-seq: strio.sync = boolean -> boolean */ 627#define strio_set_sync strio_first 628 629#define strio_tell strio_get_pos 630 631/* 632 * call-seq: 633 * strio.each_byte {|byte| block } -> strio 634 * strio.each_byte -> anEnumerator 635 * 636 * See IO#each_byte. 637 */ 638static VALUE 639strio_each_byte(VALUE self) 640{ 641 struct StringIO *ptr = readable(self); 642 643 RETURN_ENUMERATOR(self, 0, 0); 644 645 while (ptr->pos < RSTRING_LEN(ptr->string)) { 646 char c = RSTRING_PTR(ptr->string)[ptr->pos++]; 647 rb_yield(CHR2FIX(c)); 648 } 649 return self; 650} 651 652/* 653 * This is a deprecated alias for <code>each_byte</code>. 654 */ 655static VALUE 656strio_bytes(VALUE self) 657{ 658 rb_warn("StringIO#bytes is deprecated; use #each_byte instead"); 659 if (!rb_block_given_p()) 660 return rb_enumeratorize(self, ID2SYM(rb_intern("each_byte")), 0, 0); 661 return strio_each_byte(self); 662} 663 664/* 665 * call-seq: 666 * strio.getc -> string or nil 667 * 668 * See IO#getc. 669 */ 670static VALUE 671strio_getc(VALUE self) 672{ 673 struct StringIO *ptr = readable(self); 674 rb_encoding *enc = rb_enc_get(ptr->string); 675 int len; 676 char *p; 677 678 if (ptr->pos >= RSTRING_LEN(ptr->string)) { 679 return Qnil; 680 } 681 p = RSTRING_PTR(ptr->string)+ptr->pos; 682 len = rb_enc_mbclen(p, RSTRING_END(ptr->string), enc); 683 ptr->pos += len; 684 return rb_enc_str_new(p, len, rb_enc_get(ptr->string)); 685} 686 687/* 688 * call-seq: 689 * strio.getbyte -> fixnum or nil 690 * 691 * See IO#getbyte. 692 */ 693static VALUE 694strio_getbyte(VALUE self) 695{ 696 struct StringIO *ptr = readable(self); 697 int c; 698 if (ptr->pos >= RSTRING_LEN(ptr->string)) { 699 return Qnil; 700 } 701 c = RSTRING_PTR(ptr->string)[ptr->pos++]; 702 return CHR2FIX(c); 703} 704 705static void 706strio_extend(struct StringIO *ptr, long pos, long len) 707{ 708 long olen; 709 710 check_modifiable(ptr); 711 olen = RSTRING_LEN(ptr->string); 712 if (pos + len > olen) { 713 rb_str_resize(ptr->string, pos + len); 714 if (pos > olen) 715 MEMZERO(RSTRING_PTR(ptr->string) + olen, char, pos - olen); 716 } 717 else { 718 rb_str_modify(ptr->string); 719 } 720} 721 722/* 723 * call-seq: 724 * strio.ungetc(string) -> nil 725 * 726 * Pushes back one character (passed as a parameter) onto *strio* 727 * such that a subsequent buffered read will return it. There is no 728 * limitation for multiple pushbacks including pushing back behind the 729 * beginning of the buffer string. 730 */ 731static VALUE 732strio_ungetc(VALUE self, VALUE c) 733{ 734 struct StringIO *ptr = readable(self); 735 long lpos, clen; 736 char *p, *pend; 737 rb_encoding *enc, *enc2; 738 739 if (NIL_P(c)) return Qnil; 740 check_modifiable(ptr); 741 if (FIXNUM_P(c)) { 742 int cc = FIX2INT(c); 743 char buf[16]; 744 745 enc = rb_enc_get(ptr->string); 746 rb_enc_mbcput(cc, buf, enc); 747 c = rb_enc_str_new(buf, rb_enc_codelen(cc, enc), enc); 748 } 749 else { 750 SafeStringValue(c); 751 enc = rb_enc_get(ptr->string); 752 enc2 = rb_enc_get(c); 753 if (enc != enc2 && enc != rb_ascii8bit_encoding()) { 754 c = rb_str_conv_enc(c, enc2, enc); 755 } 756 } 757 if (RSTRING_LEN(ptr->string) < ptr->pos) { 758 long len = RSTRING_LEN(ptr->string); 759 rb_str_resize(ptr->string, ptr->pos - 1); 760 memset(RSTRING_PTR(ptr->string) + len, 0, ptr->pos - len - 1); 761 rb_str_concat(ptr->string, c); 762 ptr->pos--; 763 } 764 else { 765 /* get logical position */ 766 lpos = 0; p = RSTRING_PTR(ptr->string); pend = p + ptr->pos; 767 for (;;) { 768 clen = rb_enc_mbclen(p, pend, enc); 769 if (p+clen >= pend) break; 770 p += clen; 771 lpos++; 772 } 773 clen = p - RSTRING_PTR(ptr->string); 774 rb_str_update(ptr->string, lpos, ptr->pos ? 1 : 0, c); 775 ptr->pos = clen; 776 } 777 778 return Qnil; 779} 780 781/* 782 * call-seq: 783 * strio.ungetbyte(fixnum) -> nil 784 * 785 * See IO#ungetbyte 786 */ 787static VALUE 788strio_ungetbyte(VALUE self, VALUE c) 789{ 790 struct StringIO *ptr = readable(self); 791 char buf[1], *cp = buf; 792 long pos = ptr->pos, cl = 1; 793 VALUE str = ptr->string; 794 795 if (NIL_P(c)) return Qnil; 796 if (FIXNUM_P(c)) { 797 buf[0] = (char)FIX2INT(c); 798 } 799 else { 800 SafeStringValue(c); 801 cp = RSTRING_PTR(c); 802 cl = RSTRING_LEN(c); 803 if (cl == 0) return Qnil; 804 } 805 check_modifiable(ptr); 806 rb_str_modify(str); 807 if (cl > pos) { 808 char *s; 809 long rest = RSTRING_LEN(str) - pos; 810 rb_str_resize(str, rest + cl); 811 s = RSTRING_PTR(str); 812 memmove(s + cl, s + pos, rest); 813 pos = 0; 814 } 815 else { 816 pos -= cl; 817 } 818 memcpy(RSTRING_PTR(str) + pos, cp, cl); 819 ptr->pos = pos; 820 RB_GC_GUARD(c); 821 return Qnil; 822} 823 824/* 825 * call-seq: 826 * strio.readchar -> string 827 * 828 * See IO#readchar. 829 */ 830static VALUE 831strio_readchar(VALUE self) 832{ 833 VALUE c = rb_funcall2(self, rb_intern("getc"), 0, 0); 834 if (NIL_P(c)) rb_eof_error(); 835 return c; 836} 837 838/* 839 * call-seq: 840 * strio.readbyte -> fixnum 841 * 842 * See IO#readbyte. 843 */ 844static VALUE 845strio_readbyte(VALUE self) 846{ 847 VALUE c = rb_funcall2(self, rb_intern("getbyte"), 0, 0); 848 if (NIL_P(c)) rb_eof_error(); 849 return c; 850} 851 852/* 853 * call-seq: 854 * strio.each_char {|char| block } -> strio 855 * strio.each_char -> anEnumerator 856 * 857 * See IO#each_char. 858 */ 859static VALUE 860strio_each_char(VALUE self) 861{ 862 VALUE c; 863 864 RETURN_ENUMERATOR(self, 0, 0); 865 866 while (!NIL_P(c = strio_getc(self))) { 867 rb_yield(c); 868 } 869 return self; 870} 871 872/* 873 * This is a deprecated alias for <code>each_char</code>. 874 */ 875static VALUE 876strio_chars(VALUE self) 877{ 878 rb_warn("StringIO#chars is deprecated; use #each_char instead"); 879 if (!rb_block_given_p()) 880 return rb_enumeratorize(self, ID2SYM(rb_intern("each_char")), 0, 0); 881 return strio_each_char(self); 882} 883 884/* 885 * call-seq: 886 * strio.each_codepoint {|c| block } -> strio 887 * strio.each_codepoint -> anEnumerator 888 * 889 * See IO#each_codepoint. 890 */ 891static VALUE 892strio_each_codepoint(VALUE self) 893{ 894 struct StringIO *ptr; 895 rb_encoding *enc; 896 unsigned int c; 897 int n; 898 899 RETURN_ENUMERATOR(self, 0, 0); 900 901 ptr = readable(self); 902 enc = rb_enc_get(ptr->string); 903 for (;;) { 904 if (ptr->pos >= RSTRING_LEN(ptr->string)) { 905 return self; 906 } 907 908 c = rb_enc_codepoint_len(RSTRING_PTR(ptr->string)+ptr->pos, 909 RSTRING_END(ptr->string), &n, enc); 910 rb_yield(UINT2NUM(c)); 911 ptr->pos += n; 912 } 913 return self; 914} 915 916/* 917 * This is a deprecated alias for <code>each_codepoint</code>. 918 */ 919static VALUE 920strio_codepoints(VALUE self) 921{ 922 rb_warn("StringIO#codepoints is deprecated; use #each_codepoint instead"); 923 if (!rb_block_given_p()) 924 return rb_enumeratorize(self, ID2SYM(rb_intern("each_codepoint")), 0, 0); 925 return strio_each_codepoint(self); 926} 927 928/* Boyer-Moore search: copied from regex.c */ 929static void 930bm_init_skip(long *skip, const char *pat, long m) 931{ 932 int c; 933 934 for (c = 0; c < (1 << CHAR_BIT); c++) { 935 skip[c] = m; 936 } 937 while (--m) { 938 skip[(unsigned char)*pat++] = m; 939 } 940} 941 942static long 943bm_search(const char *little, long llen, const char *big, long blen, const long *skip) 944{ 945 long i, j, k; 946 947 i = llen - 1; 948 while (i < blen) { 949 k = i; 950 j = llen - 1; 951 while (j >= 0 && big[k] == little[j]) { 952 k--; 953 j--; 954 } 955 if (j < 0) return k + 1; 956 i += skip[(unsigned char)big[i]]; 957 } 958 return -1; 959} 960 961static VALUE 962strio_getline(int argc, VALUE *argv, struct StringIO *ptr) 963{ 964 const char *s, *e, *p; 965 long n, limit = 0; 966 VALUE str, lim; 967 968 rb_scan_args(argc, argv, "02", &str, &lim); 969 switch (argc) { 970 case 0: 971 str = rb_rs; 972 break; 973 974 case 1: 975 if (!NIL_P(str) && !RB_TYPE_P(str, T_STRING)) { 976 VALUE tmp = rb_check_string_type(str); 977 if (NIL_P(tmp)) { 978 limit = NUM2LONG(str); 979 if (limit == 0) return rb_str_new(0,0); 980 str = rb_rs; 981 } 982 else { 983 str = tmp; 984 } 985 } 986 break; 987 988 case 2: 989 if (!NIL_P(str)) StringValue(str); 990 if (!NIL_P(lim)) limit = NUM2LONG(lim); 991 break; 992 } 993 994 if (ptr->pos >= (n = RSTRING_LEN(ptr->string))) { 995 return Qnil; 996 } 997 s = RSTRING_PTR(ptr->string); 998 e = s + RSTRING_LEN(ptr->string); 999 s += ptr->pos; 1000 if (limit > 0 && s + limit < e) { 1001 e = rb_enc_right_char_head(s, s + limit, e, rb_enc_get(ptr->string)); 1002 } 1003 if (NIL_P(str)) { 1004 str = strio_substr(ptr, ptr->pos, e - s); 1005 } 1006 else if ((n = RSTRING_LEN(str)) == 0) { 1007 p = s; 1008 while (*p == '\n') { 1009 if (++p == e) { 1010 return Qnil; 1011 } 1012 } 1013 s = p; 1014 while ((p = memchr(p, '\n', e - p)) && (p != e)) { 1015 if (*++p == '\n') { 1016 e = p + 1; 1017 break; 1018 } 1019 } 1020 str = strio_substr(ptr, s - RSTRING_PTR(ptr->string), e - s); 1021 } 1022 else if (n == 1) { 1023 if ((p = memchr(s, RSTRING_PTR(str)[0], e - s)) != 0) { 1024 e = p + 1; 1025 } 1026 str = strio_substr(ptr, ptr->pos, e - s); 1027 } 1028 else { 1029 if (n < e - s) { 1030 if (e - s < 1024) { 1031 for (p = s; p + n <= e; ++p) { 1032 if (MEMCMP(p, RSTRING_PTR(str), char, n) == 0) { 1033 e = p + n; 1034 break; 1035 } 1036 } 1037 } 1038 else { 1039 long skip[1 << CHAR_BIT], pos; 1040 p = RSTRING_PTR(str); 1041 bm_init_skip(skip, p, n); 1042 if ((pos = bm_search(p, n, s, e - s, skip)) >= 0) { 1043 e = s + pos + n; 1044 } 1045 } 1046 } 1047 str = strio_substr(ptr, ptr->pos, e - s); 1048 } 1049 ptr->pos = e - RSTRING_PTR(ptr->string); 1050 ptr->lineno++; 1051 return str; 1052} 1053 1054/* 1055 * call-seq: 1056 * strio.gets(sep=$/) -> string or nil 1057 * strio.gets(limit) -> string or nil 1058 * strio.gets(sep, limit) -> string or nil 1059 * 1060 * See IO#gets. 1061 */ 1062static VALUE 1063strio_gets(int argc, VALUE *argv, VALUE self) 1064{ 1065 VALUE str = strio_getline(argc, argv, readable(self)); 1066 1067 rb_lastline_set(str); 1068 return str; 1069} 1070 1071/* 1072 * call-seq: 1073 * strio.readline(sep=$/) -> string 1074 * strio.readline(limit) -> string or nil 1075 * strio.readline(sep, limit) -> string or nil 1076 * 1077 * See IO#readline. 1078 */ 1079static VALUE 1080strio_readline(int argc, VALUE *argv, VALUE self) 1081{ 1082 VALUE line = rb_funcall2(self, rb_intern("gets"), argc, argv); 1083 if (NIL_P(line)) rb_eof_error(); 1084 return line; 1085} 1086 1087/* 1088 * call-seq: 1089 * strio.each(sep=$/) {|line| block } -> strio 1090 * strio.each(limit) {|line| block } -> strio 1091 * strio.each(sep, limit) {|line| block } -> strio 1092 * strio.each(...) -> anEnumerator 1093 * 1094 * strio.each_line(sep=$/) {|line| block } -> strio 1095 * strio.each_line(limit) {|line| block } -> strio 1096 * strio.each_line(sep,limit) {|line| block } -> strio 1097 * strio.each_line(...) -> anEnumerator 1098 * 1099 * See IO#each. 1100 */ 1101static VALUE 1102strio_each(int argc, VALUE *argv, VALUE self) 1103{ 1104 VALUE line; 1105 1106 StringIO(self); 1107 RETURN_ENUMERATOR(self, argc, argv); 1108 1109 if (argc > 0 && !NIL_P(argv[argc-1]) && NIL_P(rb_check_string_type(argv[argc-1])) && 1110 NUM2LONG(argv[argc-1]) == 0) { 1111 rb_raise(rb_eArgError, "invalid limit: 0 for each_line"); 1112 } 1113 1114 while (!NIL_P(line = strio_getline(argc, argv, readable(self)))) { 1115 rb_yield(line); 1116 } 1117 return self; 1118} 1119 1120/* 1121 * This is a deprecated alias for <code>each_line</code>. 1122 */ 1123static VALUE 1124strio_lines(int argc, VALUE *argv, VALUE self) 1125{ 1126 rb_warn("StringIO#lines is deprecated; use #each_line instead"); 1127 if (!rb_block_given_p()) 1128 return rb_enumeratorize(self, ID2SYM(rb_intern("each_line")), argc, argv); 1129 return strio_each(argc, argv, self); 1130} 1131 1132/* 1133 * call-seq: 1134 * strio.readlines(sep=$/) -> array 1135 * strio.readlines(limit) -> array 1136 * strio.readlines(sep,limit) -> array 1137 * 1138 * See IO#readlines. 1139 */ 1140static VALUE 1141strio_readlines(int argc, VALUE *argv, VALUE self) 1142{ 1143 VALUE ary, line; 1144 1145 StringIO(self); 1146 ary = rb_ary_new(); 1147 if (argc > 0 && !NIL_P(argv[argc-1]) && NIL_P(rb_check_string_type(argv[argc-1])) && 1148 NUM2LONG(argv[argc-1]) == 0) { 1149 rb_raise(rb_eArgError, "invalid limit: 0 for readlines"); 1150 } 1151 1152 while (!NIL_P(line = strio_getline(argc, argv, readable(self)))) { 1153 rb_ary_push(ary, line); 1154 } 1155 return ary; 1156} 1157 1158/* 1159 * call-seq: 1160 * strio.write(string) -> integer 1161 * strio.syswrite(string) -> integer 1162 * 1163 * Appends the given string to the underlying buffer string of *strio*. 1164 * The stream must be opened for writing. If the argument is not a 1165 * string, it will be converted to a string using <code>to_s</code>. 1166 * Returns the number of bytes written. See IO#write. 1167 */ 1168static VALUE 1169strio_write(VALUE self, VALUE str) 1170{ 1171 struct StringIO *ptr = writable(self); 1172 long len, olen; 1173 rb_encoding *enc, *enc2; 1174 1175 RB_GC_GUARD(str); 1176 if (!RB_TYPE_P(str, T_STRING)) 1177 str = rb_obj_as_string(str); 1178 enc = rb_enc_get(ptr->string); 1179 enc2 = rb_enc_get(str); 1180 if (enc != enc2 && enc != rb_ascii8bit_encoding()) { 1181 str = rb_str_conv_enc(str, enc2, enc); 1182 } 1183 len = RSTRING_LEN(str); 1184 if (len == 0) return INT2FIX(0); 1185 check_modifiable(ptr); 1186 olen = RSTRING_LEN(ptr->string); 1187 if (ptr->flags & FMODE_APPEND) { 1188 ptr->pos = olen; 1189 } 1190 if (ptr->pos == olen) { 1191 rb_str_cat(ptr->string, RSTRING_PTR(str), len); 1192 } 1193 else { 1194 strio_extend(ptr, ptr->pos, len); 1195 memmove(RSTRING_PTR(ptr->string)+ptr->pos, RSTRING_PTR(str), len); 1196 OBJ_INFECT(ptr->string, str); 1197 } 1198 OBJ_INFECT(ptr->string, self); 1199 ptr->pos += len; 1200 return LONG2NUM(len); 1201} 1202 1203/* 1204 * call-seq: 1205 * strio << obj -> strio 1206 * 1207 * See IO#<<. 1208 */ 1209#define strio_addstr rb_io_addstr 1210 1211/* 1212 * call-seq: 1213 * strio.print() -> nil 1214 * strio.print(obj, ...) -> nil 1215 * 1216 * See IO#print. 1217 */ 1218#define strio_print rb_io_print 1219 1220/* 1221 * call-seq: 1222 * strio.printf(format_string [, obj, ...] ) -> nil 1223 * 1224 * See IO#printf. 1225 */ 1226#define strio_printf rb_io_printf 1227 1228/* 1229 * call-seq: 1230 * strio.putc(obj) -> obj 1231 * 1232 * See IO#putc. 1233 */ 1234static VALUE 1235strio_putc(VALUE self, VALUE ch) 1236{ 1237 struct StringIO *ptr = writable(self); 1238 int c = NUM2CHR(ch); 1239 long olen; 1240 1241 check_modifiable(ptr); 1242 olen = RSTRING_LEN(ptr->string); 1243 if (ptr->flags & FMODE_APPEND) { 1244 ptr->pos = olen; 1245 } 1246 strio_extend(ptr, ptr->pos, 1); 1247 RSTRING_PTR(ptr->string)[ptr->pos++] = c; 1248 OBJ_INFECT(ptr->string, self); 1249 return ch; 1250} 1251 1252/* 1253 * call-seq: 1254 * strio.puts(obj, ...) -> nil 1255 * 1256 * See IO#puts. 1257 */ 1258#define strio_puts rb_io_puts 1259 1260/* 1261 * call-seq: 1262 * strio.read([length [, outbuf]]) -> string, outbuf, or nil 1263 * 1264 * See IO#read. 1265 */ 1266static VALUE 1267strio_read(int argc, VALUE *argv, VALUE self) 1268{ 1269 struct StringIO *ptr = readable(self); 1270 VALUE str = Qnil; 1271 long len; 1272 int binary = 0; 1273 1274 switch (argc) { 1275 case 2: 1276 str = argv[1]; 1277 if (!NIL_P(str)) { 1278 StringValue(str); 1279 rb_str_modify(str); 1280 } 1281 case 1: 1282 if (!NIL_P(argv[0])) { 1283 len = NUM2LONG(argv[0]); 1284 if (len < 0) { 1285 rb_raise(rb_eArgError, "negative length %ld given", len); 1286 } 1287 if (len > 0 && ptr->pos >= RSTRING_LEN(ptr->string)) { 1288 if (!NIL_P(str)) rb_str_resize(str, 0); 1289 return Qnil; 1290 } 1291 binary = 1; 1292 break; 1293 } 1294 /* fall through */ 1295 case 0: 1296 len = RSTRING_LEN(ptr->string); 1297 if (len <= ptr->pos) { 1298 if (NIL_P(str)) { 1299 str = rb_str_new(0, 0); 1300 } 1301 else { 1302 rb_str_resize(str, 0); 1303 } 1304 return str; 1305 } 1306 else { 1307 len -= ptr->pos; 1308 } 1309 break; 1310 default: 1311 rb_raise(rb_eArgError, "wrong number of arguments (%d for 0)", argc); 1312 } 1313 if (NIL_P(str)) { 1314 str = strio_substr(ptr, ptr->pos, len); 1315 if (binary) rb_enc_associate(str, rb_ascii8bit_encoding()); 1316 } 1317 else { 1318 long rest = RSTRING_LEN(ptr->string) - ptr->pos; 1319 if (len > rest) len = rest; 1320 rb_str_resize(str, len); 1321 MEMCPY(RSTRING_PTR(str), RSTRING_PTR(ptr->string) + ptr->pos, char, len); 1322 if (binary) 1323 rb_enc_associate(str, rb_ascii8bit_encoding()); 1324 else 1325 rb_enc_copy(str, ptr->string); 1326 } 1327 ptr->pos += RSTRING_LEN(str); 1328 return str; 1329} 1330 1331/* 1332 * call-seq: 1333 * strio.sysread(integer[, outbuf]) -> string 1334 * 1335 * Similar to #read, but raises +EOFError+ at end of string instead of 1336 * returning +nil+, as well as IO#sysread does. 1337 */ 1338static VALUE 1339strio_sysread(int argc, VALUE *argv, VALUE self) 1340{ 1341 VALUE val = rb_funcall2(self, rb_intern("read"), argc, argv); 1342 if (NIL_P(val)) { 1343 rb_eof_error(); 1344 } 1345 return val; 1346} 1347 1348#define strio_syswrite rb_io_write 1349 1350/* 1351 * call-seq: 1352 * strio.isatty -> nil 1353 * strio.tty? -> nil 1354 * 1355 */ 1356#define strio_isatty strio_false 1357 1358/* call-seq: strio.pid -> nil */ 1359#define strio_pid strio_nil 1360 1361/* call-seq: strio.fileno -> nil */ 1362#define strio_fileno strio_nil 1363 1364/* 1365 * call-seq: 1366 * strio.size -> integer 1367 * 1368 * Returns the size of the buffer string. 1369 */ 1370static VALUE 1371strio_size(VALUE self) 1372{ 1373 VALUE string = StringIO(self)->string; 1374 if (NIL_P(string)) { 1375 rb_raise(rb_eIOError, "not opened"); 1376 } 1377 return ULONG2NUM(RSTRING_LEN(string)); 1378} 1379 1380/* 1381 * call-seq: 1382 * strio.truncate(integer) -> 0 1383 * 1384 * Truncates the buffer string to at most _integer_ bytes. The *strio* 1385 * must be opened for writing. 1386 */ 1387static VALUE 1388strio_truncate(VALUE self, VALUE len) 1389{ 1390 VALUE string = writable(self)->string; 1391 long l = NUM2LONG(len); 1392 long plen = RSTRING_LEN(string); 1393 if (l < 0) { 1394 error_inval("negative length"); 1395 } 1396 rb_str_resize(string, l); 1397 if (plen < l) { 1398 MEMZERO(RSTRING_PTR(string) + plen, char, l - plen); 1399 } 1400 return len; 1401} 1402 1403/* 1404 * call-seq: 1405 * strio.external_encoding => encoding 1406 * 1407 * Returns the Encoding object that represents the encoding of the file. 1408 * If strio is write mode and no encoding is specified, returns <code>nil</code>. 1409 */ 1410 1411static VALUE 1412strio_external_encoding(VALUE self) 1413{ 1414 return rb_enc_from_encoding(rb_enc_get(StringIO(self)->string)); 1415} 1416 1417/* 1418 * call-seq: 1419 * strio.internal_encoding => encoding 1420 * 1421 * Returns the Encoding of the internal string if conversion is 1422 * specified. Otherwise returns nil. 1423 */ 1424 1425static VALUE 1426strio_internal_encoding(VALUE self) 1427{ 1428 return Qnil; 1429} 1430 1431/* 1432 * call-seq: 1433 * strio.set_encoding(ext_enc, [int_enc[, opt]]) => strio 1434 * 1435 * Specify the encoding of the StringIO as <i>ext_enc</i>. 1436 * Use the default external encoding if <i>ext_enc</i> is nil. 1437 * 2nd argument <i>int_enc</i> and optional hash <i>opt</i> argument 1438 * are ignored; they are for API compatibility to IO. 1439 */ 1440 1441static VALUE 1442strio_set_encoding(int argc, VALUE *argv, VALUE self) 1443{ 1444 rb_encoding* enc; 1445 VALUE str = StringIO(self)->string; 1446 VALUE ext_enc, int_enc, opt; 1447 1448 argc = rb_scan_args(argc, argv, "11:", &ext_enc, &int_enc, &opt); 1449 1450 if (NIL_P(ext_enc)) { 1451 enc = rb_default_external_encoding(); 1452 } 1453 else { 1454 enc = rb_to_encoding(ext_enc); 1455 } 1456 rb_enc_associate(str, enc); 1457 return self; 1458} 1459 1460/* 1461 * Pseudo I/O on String object. 1462 */ 1463void 1464Init_stringio() 1465{ 1466 VALUE StringIO = rb_define_class("StringIO", rb_cData); 1467 1468 rb_include_module(StringIO, rb_mEnumerable); 1469 rb_define_alloc_func(StringIO, strio_s_allocate); 1470 rb_define_singleton_method(StringIO, "open", strio_s_open, -1); 1471 rb_define_method(StringIO, "initialize", strio_initialize, -1); 1472 rb_define_method(StringIO, "initialize_copy", strio_copy, 1); 1473 rb_define_method(StringIO, "reopen", strio_reopen, -1); 1474 1475 rb_define_method(StringIO, "string", strio_get_string, 0); 1476 rb_define_method(StringIO, "string=", strio_set_string, 1); 1477 rb_define_method(StringIO, "lineno", strio_get_lineno, 0); 1478 rb_define_method(StringIO, "lineno=", strio_set_lineno, 1); 1479 1480 rb_define_method(StringIO, "binmode", strio_binmode, 0); 1481 rb_define_method(StringIO, "close", strio_close, 0); 1482 rb_define_method(StringIO, "close_read", strio_close_read, 0); 1483 rb_define_method(StringIO, "close_write", strio_close_write, 0); 1484 rb_define_method(StringIO, "closed?", strio_closed, 0); 1485 rb_define_method(StringIO, "closed_read?", strio_closed_read, 0); 1486 rb_define_method(StringIO, "closed_write?", strio_closed_write, 0); 1487 rb_define_method(StringIO, "eof", strio_eof, 0); 1488 rb_define_method(StringIO, "eof?", strio_eof, 0); 1489 rb_define_method(StringIO, "fcntl", strio_fcntl, -1); 1490 rb_define_method(StringIO, "flush", strio_flush, 0); 1491 rb_define_method(StringIO, "fsync", strio_fsync, 0); 1492 rb_define_method(StringIO, "pos", strio_get_pos, 0); 1493 rb_define_method(StringIO, "pos=", strio_set_pos, 1); 1494 rb_define_method(StringIO, "rewind", strio_rewind, 0); 1495 rb_define_method(StringIO, "seek", strio_seek, -1); 1496 rb_define_method(StringIO, "sync", strio_get_sync, 0); 1497 rb_define_method(StringIO, "sync=", strio_set_sync, 1); 1498 rb_define_method(StringIO, "tell", strio_tell, 0); 1499 1500 rb_define_method(StringIO, "each", strio_each, -1); 1501 rb_define_method(StringIO, "each_line", strio_each, -1); 1502 rb_define_method(StringIO, "lines", strio_lines, -1); 1503 rb_define_method(StringIO, "each_byte", strio_each_byte, 0); 1504 rb_define_method(StringIO, "bytes", strio_bytes, 0); 1505 rb_define_method(StringIO, "each_char", strio_each_char, 0); 1506 rb_define_method(StringIO, "chars", strio_chars, 0); 1507 rb_define_method(StringIO, "each_codepoint", strio_each_codepoint, 0); 1508 rb_define_method(StringIO, "codepoints", strio_codepoints, 0); 1509 rb_define_method(StringIO, "getc", strio_getc, 0); 1510 rb_define_method(StringIO, "ungetc", strio_ungetc, 1); 1511 rb_define_method(StringIO, "ungetbyte", strio_ungetbyte, 1); 1512 rb_define_method(StringIO, "getbyte", strio_getbyte, 0); 1513 rb_define_method(StringIO, "gets", strio_gets, -1); 1514 rb_define_method(StringIO, "readlines", strio_readlines, -1); 1515 rb_define_method(StringIO, "read", strio_read, -1); 1516 1517 rb_define_method(StringIO, "write", strio_write, 1); 1518 rb_define_method(StringIO, "putc", strio_putc, 1); 1519 1520 rb_define_method(StringIO, "isatty", strio_isatty, 0); 1521 rb_define_method(StringIO, "tty?", strio_isatty, 0); 1522 rb_define_method(StringIO, "pid", strio_pid, 0); 1523 rb_define_method(StringIO, "fileno", strio_fileno, 0); 1524 rb_define_method(StringIO, "size", strio_size, 0); 1525 rb_define_method(StringIO, "length", strio_size, 0); 1526 rb_define_method(StringIO, "truncate", strio_truncate, 1); 1527 1528 rb_define_method(StringIO, "external_encoding", strio_external_encoding, 0); 1529 rb_define_method(StringIO, "internal_encoding", strio_internal_encoding, 0); 1530 rb_define_method(StringIO, "set_encoding", strio_set_encoding, -1); 1531 1532 { 1533 VALUE mReadable = rb_define_module_under(rb_cIO, "readable"); 1534 rb_define_method(mReadable, "readchar", strio_readchar, 0); 1535 rb_define_method(mReadable, "readbyte", strio_readbyte, 0); 1536 rb_define_method(mReadable, "readline", strio_readline, -1); 1537 rb_define_method(mReadable, "sysread", strio_sysread, -1); 1538 rb_define_method(mReadable, "readpartial", strio_sysread, -1); 1539 rb_define_method(mReadable, "read_nonblock", strio_sysread, -1); 1540 rb_include_module(StringIO, mReadable); 1541 } 1542 { 1543 VALUE mWritable = rb_define_module_under(rb_cIO, "writable"); 1544 rb_define_method(mWritable, "<<", strio_addstr, 1); 1545 rb_define_method(mWritable, "print", strio_print, -1); 1546 rb_define_method(mWritable, "printf", strio_printf, -1); 1547 rb_define_method(mWritable, "puts", strio_puts, -1); 1548 rb_define_method(mWritable, "syswrite", strio_syswrite, 1); 1549 rb_define_method(mWritable, "write_nonblock", strio_syswrite, 1); 1550 rb_include_module(StringIO, mWritable); 1551 } 1552} 1553