00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
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 *, VALUE);
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 NULL, NULL, RUBY_TYPED_FREE_IMMEDIATELY
00082 };
00083
00084 #define check_strio(self) ((struct StringIO*)rb_check_typeddata((self), &strio_data_type))
00085
00086 static struct StringIO*
00087 get_strio(VALUE self)
00088 {
00089 struct StringIO *ptr = check_strio(rb_io_taint_check(self));
00090
00091 if (!ptr) {
00092 rb_raise(rb_eIOError, "uninitialized stream");
00093 }
00094 return ptr;
00095 }
00096
00097 static VALUE
00098 strio_substr(struct StringIO *ptr, long pos, long len)
00099 {
00100 VALUE str = ptr->string;
00101 rb_encoding *enc = rb_enc_get(str);
00102 long rlen = RSTRING_LEN(str) - pos;
00103
00104 if (len > rlen) len = rlen;
00105 if (len < 0) len = 0;
00106 if (len == 0) return rb_str_new(0,0);
00107 return rb_enc_str_new(RSTRING_PTR(str)+pos, len, enc);
00108 }
00109
00110 #define StringIO(obj) get_strio(obj)
00111
00112 #define STRIO_READABLE FL_USER4
00113 #define STRIO_WRITABLE FL_USER5
00114 #define STRIO_READWRITE (STRIO_READABLE|STRIO_WRITABLE)
00115 typedef char strio_flags_check[(STRIO_READABLE/FMODE_READABLE == STRIO_WRITABLE/FMODE_WRITABLE) * 2 - 1];
00116 #define STRIO_MODE_SET_P(strio, mode) \
00117 ((RBASIC(strio)->flags & STRIO_##mode) && \
00118 ((struct StringIO*)DATA_PTR(strio))->flags & FMODE_##mode)
00119 #define CLOSED(strio) (!STRIO_MODE_SET_P(strio, READWRITE))
00120 #define READABLE(strio) STRIO_MODE_SET_P(strio, READABLE)
00121 #define WRITABLE(strio) STRIO_MODE_SET_P(strio, WRITABLE)
00122
00123 static VALUE sym_exception;
00124
00125 static struct StringIO*
00126 readable(VALUE strio)
00127 {
00128 struct StringIO *ptr = StringIO(strio);
00129 if (!READABLE(strio)) {
00130 rb_raise(rb_eIOError, "not opened for reading");
00131 }
00132 return ptr;
00133 }
00134
00135 static struct StringIO*
00136 writable(VALUE strio)
00137 {
00138 struct StringIO *ptr = StringIO(strio);
00139 if (!WRITABLE(strio)) {
00140 rb_raise(rb_eIOError, "not opened for writing");
00141 }
00142 if (!OBJ_TAINTED(ptr->string)) {
00143 }
00144 return ptr;
00145 }
00146
00147 static void
00148 check_modifiable(struct StringIO *ptr)
00149 {
00150 if (OBJ_FROZEN(ptr->string)) {
00151 rb_raise(rb_eIOError, "not modifiable string");
00152 }
00153 }
00154
00155 static VALUE
00156 strio_s_allocate(VALUE klass)
00157 {
00158 return TypedData_Wrap_Struct(klass, &strio_data_type, 0);
00159 }
00160
00161
00162
00163
00164
00165
00166 static VALUE
00167 strio_initialize(int argc, VALUE *argv, VALUE self)
00168 {
00169 struct StringIO *ptr = check_strio(self);
00170
00171 if (!ptr) {
00172 DATA_PTR(self) = ptr = strio_alloc();
00173 }
00174 rb_call_super(0, 0);
00175 strio_init(argc, argv, ptr, self);
00176 return self;
00177 }
00178
00179 static void
00180 strio_init(int argc, VALUE *argv, struct StringIO *ptr, VALUE self)
00181 {
00182 VALUE string, mode;
00183 int trunc = 0;
00184
00185 switch (rb_scan_args(argc, argv, "02", &string, &mode)) {
00186 case 2:
00187 if (FIXNUM_P(mode)) {
00188 int flags = FIX2INT(mode);
00189 ptr->flags = rb_io_modenum_flags(flags);
00190 trunc = flags & O_TRUNC;
00191 }
00192 else {
00193 const char *m = StringValueCStr(mode);
00194 ptr->flags = rb_io_mode_flags(m);
00195 trunc = *m == 'w';
00196 }
00197 StringValue(string);
00198 if ((ptr->flags & FMODE_WRITABLE) && OBJ_FROZEN(string)) {
00199 errno = EACCES;
00200 rb_sys_fail(0);
00201 }
00202 if (trunc) {
00203 rb_str_resize(string, 0);
00204 }
00205 break;
00206 case 1:
00207 StringValue(string);
00208 ptr->flags = OBJ_FROZEN(string) ? FMODE_READABLE : FMODE_READWRITE;
00209 break;
00210 case 0:
00211 string = rb_enc_str_new("", 0, rb_default_external_encoding());
00212 ptr->flags = FMODE_READWRITE;
00213 break;
00214 }
00215 ptr->string = string;
00216 ptr->pos = 0;
00217 ptr->lineno = 0;
00218 RBASIC(self)->flags |= (ptr->flags & FMODE_READWRITE) * (STRIO_READABLE / FMODE_READABLE);
00219 }
00220
00221 static VALUE
00222 strio_finalize(VALUE self)
00223 {
00224 struct StringIO *ptr = StringIO(self);
00225 ptr->string = Qnil;
00226 ptr->flags &= ~FMODE_READWRITE;
00227 return self;
00228 }
00229
00230
00231
00232
00233
00234
00235
00236
00237 static VALUE
00238 strio_s_open(int argc, VALUE *argv, VALUE klass)
00239 {
00240 VALUE obj = rb_class_new_instance(argc, argv, klass);
00241 if (!rb_block_given_p()) return obj;
00242 return rb_ensure(rb_yield, obj, strio_finalize, obj);
00243 }
00244
00245
00246
00247
00248 static VALUE
00249 strio_false(VALUE self)
00250 {
00251 StringIO(self);
00252 return Qfalse;
00253 }
00254
00255
00256
00257
00258 static VALUE
00259 strio_nil(VALUE self)
00260 {
00261 StringIO(self);
00262 return Qnil;
00263 }
00264
00265
00266
00267
00268 static VALUE
00269 strio_self(VALUE self)
00270 {
00271 StringIO(self);
00272 return self;
00273 }
00274
00275
00276
00277
00278 static VALUE
00279 strio_0(VALUE self)
00280 {
00281 StringIO(self);
00282 return INT2FIX(0);
00283 }
00284
00285
00286
00287
00288 static VALUE
00289 strio_first(VALUE self, VALUE arg)
00290 {
00291 StringIO(self);
00292 return arg;
00293 }
00294
00295
00296
00297
00298 static VALUE
00299 strio_unimpl(int argc, VALUE *argv, VALUE self)
00300 {
00301 StringIO(self);
00302 rb_notimplement();
00303
00304 UNREACHABLE;
00305 }
00306
00307
00308
00309
00310
00311
00312 static VALUE
00313 strio_get_string(VALUE self)
00314 {
00315 return StringIO(self)->string;
00316 }
00317
00318
00319
00320
00321
00322
00323
00324 static VALUE
00325 strio_set_string(VALUE self, VALUE string)
00326 {
00327 struct StringIO *ptr = StringIO(self);
00328
00329 rb_io_taint_check(self);
00330 ptr->flags &= ~FMODE_READWRITE;
00331 StringValue(string);
00332 ptr->flags = OBJ_FROZEN(string) ? FMODE_READABLE : FMODE_READWRITE;
00333 ptr->pos = 0;
00334 ptr->lineno = 0;
00335 return ptr->string = string;
00336 }
00337
00338
00339
00340
00341
00342
00343
00344
00345 static VALUE
00346 strio_close(VALUE self)
00347 {
00348 StringIO(self);
00349 if (CLOSED(self)) {
00350 rb_raise(rb_eIOError, "closed stream");
00351 }
00352 RBASIC(self)->flags &= ~STRIO_READWRITE;
00353 return Qnil;
00354 }
00355
00356
00357
00358
00359
00360
00361
00362
00363 static VALUE
00364 strio_close_read(VALUE self)
00365 {
00366 StringIO(self);
00367 if (!READABLE(self)) {
00368 rb_raise(rb_eIOError, "closing non-duplex IO for reading");
00369 }
00370 RBASIC(self)->flags &= ~STRIO_READABLE;
00371 return Qnil;
00372 }
00373
00374
00375
00376
00377
00378
00379
00380
00381 static VALUE
00382 strio_close_write(VALUE self)
00383 {
00384 StringIO(self);
00385 if (!WRITABLE(self)) {
00386 rb_raise(rb_eIOError, "closing non-duplex IO for writing");
00387 }
00388 RBASIC(self)->flags &= ~STRIO_WRITABLE;
00389 return Qnil;
00390 }
00391
00392
00393
00394
00395
00396
00397
00398 static VALUE
00399 strio_closed(VALUE self)
00400 {
00401 StringIO(self);
00402 if (!CLOSED(self)) return Qfalse;
00403 return Qtrue;
00404 }
00405
00406
00407
00408
00409
00410
00411
00412 static VALUE
00413 strio_closed_read(VALUE self)
00414 {
00415 StringIO(self);
00416 if (READABLE(self)) return Qfalse;
00417 return Qtrue;
00418 }
00419
00420
00421
00422
00423
00424
00425
00426 static VALUE
00427 strio_closed_write(VALUE self)
00428 {
00429 StringIO(self);
00430 if (WRITABLE(self)) return Qfalse;
00431 return Qtrue;
00432 }
00433
00434
00435
00436
00437
00438
00439
00440
00441
00442 static VALUE
00443 strio_eof(VALUE self)
00444 {
00445 struct StringIO *ptr = readable(self);
00446 if (ptr->pos < RSTRING_LEN(ptr->string)) return Qfalse;
00447 return Qtrue;
00448 }
00449
00450
00451 static VALUE
00452 strio_copy(VALUE copy, VALUE orig)
00453 {
00454 struct StringIO *ptr;
00455
00456 orig = rb_convert_type(orig, T_DATA, "StringIO", "to_strio");
00457 if (copy == orig) return copy;
00458 ptr = StringIO(orig);
00459 if (check_strio(copy)) {
00460 strio_free(DATA_PTR(copy));
00461 }
00462 DATA_PTR(copy) = ptr;
00463 OBJ_INFECT(copy, orig);
00464 RBASIC(copy)->flags &= ~STRIO_READWRITE;
00465 RBASIC(copy)->flags |= RBASIC(orig)->flags & STRIO_READWRITE;
00466 ++ptr->count;
00467 return copy;
00468 }
00469
00470
00471
00472
00473
00474
00475
00476
00477
00478
00479
00480 static VALUE
00481 strio_get_lineno(VALUE self)
00482 {
00483 return LONG2NUM(StringIO(self)->lineno);
00484 }
00485
00486
00487
00488
00489
00490
00491
00492
00493 static VALUE
00494 strio_set_lineno(VALUE self, VALUE lineno)
00495 {
00496 StringIO(self)->lineno = NUM2LONG(lineno);
00497 return lineno;
00498 }
00499
00500 static VALUE
00501 strio_binmode(VALUE self)
00502 {
00503 struct StringIO *ptr = StringIO(self);
00504 rb_encoding *enc = rb_ascii8bit_encoding();
00505
00506 if (WRITABLE(self)) {
00507 rb_enc_associate(ptr->string, enc);
00508 }
00509 return self;
00510 }
00511
00512 #define strio_fcntl strio_unimpl
00513
00514 #define strio_flush strio_self
00515
00516 #define strio_fsync strio_0
00517
00518
00519
00520
00521
00522
00523
00524
00525
00526 static VALUE
00527 strio_reopen(int argc, VALUE *argv, VALUE self)
00528 {
00529 rb_io_taint_check(self);
00530 if (argc == 1 && !RB_TYPE_P(*argv, T_STRING)) {
00531 return strio_copy(self, *argv);
00532 }
00533 strio_init(argc, argv, StringIO(self), self);
00534 return self;
00535 }
00536
00537
00538
00539
00540
00541
00542
00543
00544 static VALUE
00545 strio_get_pos(VALUE self)
00546 {
00547 return LONG2NUM(StringIO(self)->pos);
00548 }
00549
00550
00551
00552
00553
00554
00555
00556 static VALUE
00557 strio_set_pos(VALUE self, VALUE pos)
00558 {
00559 struct StringIO *ptr = StringIO(self);
00560 long p = NUM2LONG(pos);
00561 if (p < 0) {
00562 error_inval(0);
00563 }
00564 ptr->pos = p;
00565 return pos;
00566 }
00567
00568
00569
00570
00571
00572
00573
00574
00575 static VALUE
00576 strio_rewind(VALUE self)
00577 {
00578 struct StringIO *ptr = StringIO(self);
00579 ptr->pos = 0;
00580 ptr->lineno = 0;
00581 return INT2FIX(0);
00582 }
00583
00584
00585
00586
00587
00588
00589
00590
00591 static VALUE
00592 strio_seek(int argc, VALUE *argv, VALUE self)
00593 {
00594 VALUE whence;
00595 struct StringIO *ptr = StringIO(self);
00596 long offset;
00597
00598 rb_scan_args(argc, argv, "11", NULL, &whence);
00599 offset = NUM2LONG(argv[0]);
00600 if (CLOSED(self)) {
00601 rb_raise(rb_eIOError, "closed stream");
00602 }
00603 switch (NIL_P(whence) ? 0 : NUM2LONG(whence)) {
00604 case 0:
00605 break;
00606 case 1:
00607 offset += ptr->pos;
00608 break;
00609 case 2:
00610 offset += RSTRING_LEN(ptr->string);
00611 break;
00612 default:
00613 error_inval("invalid whence");
00614 }
00615 if (offset < 0) {
00616 error_inval(0);
00617 }
00618 ptr->pos = offset;
00619 return INT2FIX(0);
00620 }
00621
00622
00623
00624
00625
00626
00627
00628 static VALUE
00629 strio_get_sync(VALUE self)
00630 {
00631 StringIO(self);
00632 return Qtrue;
00633 }
00634
00635 #define strio_set_sync strio_first
00636
00637 #define strio_tell strio_get_pos
00638
00639
00640
00641
00642
00643
00644
00645
00646 static VALUE
00647 strio_each_byte(VALUE self)
00648 {
00649 struct StringIO *ptr = readable(self);
00650
00651 RETURN_ENUMERATOR(self, 0, 0);
00652
00653 while (ptr->pos < RSTRING_LEN(ptr->string)) {
00654 char c = RSTRING_PTR(ptr->string)[ptr->pos++];
00655 rb_yield(CHR2FIX(c));
00656 }
00657 return self;
00658 }
00659
00660
00661
00662
00663 static VALUE
00664 strio_bytes(VALUE self)
00665 {
00666 rb_warn("StringIO#bytes is deprecated; use #each_byte instead");
00667 if (!rb_block_given_p())
00668 return rb_enumeratorize(self, ID2SYM(rb_intern("each_byte")), 0, 0);
00669 return strio_each_byte(self);
00670 }
00671
00672
00673
00674
00675
00676
00677
00678 static VALUE
00679 strio_getc(VALUE self)
00680 {
00681 struct StringIO *ptr = readable(self);
00682 rb_encoding *enc = rb_enc_get(ptr->string);
00683 int len;
00684 char *p;
00685
00686 if (ptr->pos >= RSTRING_LEN(ptr->string)) {
00687 return Qnil;
00688 }
00689 p = RSTRING_PTR(ptr->string)+ptr->pos;
00690 len = rb_enc_mbclen(p, RSTRING_END(ptr->string), enc);
00691 ptr->pos += len;
00692 return rb_enc_str_new(p, len, rb_enc_get(ptr->string));
00693 }
00694
00695
00696
00697
00698
00699
00700
00701 static VALUE
00702 strio_getbyte(VALUE self)
00703 {
00704 struct StringIO *ptr = readable(self);
00705 int c;
00706 if (ptr->pos >= RSTRING_LEN(ptr->string)) {
00707 return Qnil;
00708 }
00709 c = RSTRING_PTR(ptr->string)[ptr->pos++];
00710 return CHR2FIX(c);
00711 }
00712
00713 static void
00714 strio_extend(struct StringIO *ptr, long pos, long len)
00715 {
00716 long olen;
00717
00718 check_modifiable(ptr);
00719 olen = RSTRING_LEN(ptr->string);
00720 if (pos + len > olen) {
00721 rb_str_resize(ptr->string, pos + len);
00722 if (pos > olen)
00723 MEMZERO(RSTRING_PTR(ptr->string) + olen, char, pos - olen);
00724 }
00725 else {
00726 rb_str_modify(ptr->string);
00727 }
00728 }
00729
00730
00731
00732
00733
00734
00735
00736
00737
00738
00739 static VALUE
00740 strio_ungetc(VALUE self, VALUE c)
00741 {
00742 struct StringIO *ptr = readable(self);
00743 long lpos, clen;
00744 char *p, *pend;
00745 rb_encoding *enc, *enc2;
00746
00747 if (NIL_P(c)) return Qnil;
00748 check_modifiable(ptr);
00749 if (FIXNUM_P(c)) {
00750 int cc = FIX2INT(c);
00751 char buf[16];
00752
00753 enc = rb_enc_get(ptr->string);
00754 rb_enc_mbcput(cc, buf, enc);
00755 c = rb_enc_str_new(buf, rb_enc_codelen(cc, enc), enc);
00756 }
00757 else {
00758 SafeStringValue(c);
00759 enc = rb_enc_get(ptr->string);
00760 enc2 = rb_enc_get(c);
00761 if (enc != enc2 && enc != rb_ascii8bit_encoding()) {
00762 c = rb_str_conv_enc(c, enc2, enc);
00763 }
00764 }
00765 if (RSTRING_LEN(ptr->string) < ptr->pos) {
00766 long len = RSTRING_LEN(ptr->string);
00767 rb_str_resize(ptr->string, ptr->pos - 1);
00768 memset(RSTRING_PTR(ptr->string) + len, 0, ptr->pos - len - 1);
00769 rb_str_concat(ptr->string, c);
00770 ptr->pos--;
00771 }
00772 else {
00773
00774 lpos = 0; p = RSTRING_PTR(ptr->string); pend = p + ptr->pos;
00775 for (;;) {
00776 clen = rb_enc_mbclen(p, pend, enc);
00777 if (p+clen >= pend) break;
00778 p += clen;
00779 lpos++;
00780 }
00781 clen = p - RSTRING_PTR(ptr->string);
00782 rb_str_update(ptr->string, lpos, ptr->pos ? 1 : 0, c);
00783 ptr->pos = clen;
00784 }
00785
00786 return Qnil;
00787 }
00788
00789
00790
00791
00792
00793
00794
00795 static VALUE
00796 strio_ungetbyte(VALUE self, VALUE c)
00797 {
00798 struct StringIO *ptr = readable(self);
00799 char buf[1], *cp = buf;
00800 long pos = ptr->pos, cl = 1;
00801 VALUE str = ptr->string;
00802
00803 if (NIL_P(c)) return Qnil;
00804 if (FIXNUM_P(c)) {
00805 buf[0] = (char)FIX2INT(c);
00806 }
00807 else {
00808 SafeStringValue(c);
00809 cp = RSTRING_PTR(c);
00810 cl = RSTRING_LEN(c);
00811 if (cl == 0) return Qnil;
00812 }
00813 check_modifiable(ptr);
00814 rb_str_modify(str);
00815 if (cl > pos) {
00816 char *s;
00817 long rest = RSTRING_LEN(str) - pos;
00818 rb_str_resize(str, rest + cl);
00819 s = RSTRING_PTR(str);
00820 memmove(s + cl, s + pos, rest);
00821 pos = 0;
00822 }
00823 else {
00824 pos -= cl;
00825 }
00826 memcpy(RSTRING_PTR(str) + pos, cp, cl);
00827 ptr->pos = pos;
00828 RB_GC_GUARD(c);
00829 return Qnil;
00830 }
00831
00832
00833
00834
00835
00836
00837
00838 static VALUE
00839 strio_readchar(VALUE self)
00840 {
00841 VALUE c = rb_funcall2(self, rb_intern("getc"), 0, 0);
00842 if (NIL_P(c)) rb_eof_error();
00843 return c;
00844 }
00845
00846
00847
00848
00849
00850
00851
00852 static VALUE
00853 strio_readbyte(VALUE self)
00854 {
00855 VALUE c = rb_funcall2(self, rb_intern("getbyte"), 0, 0);
00856 if (NIL_P(c)) rb_eof_error();
00857 return c;
00858 }
00859
00860
00861
00862
00863
00864
00865
00866
00867 static VALUE
00868 strio_each_char(VALUE self)
00869 {
00870 VALUE c;
00871
00872 RETURN_ENUMERATOR(self, 0, 0);
00873
00874 while (!NIL_P(c = strio_getc(self))) {
00875 rb_yield(c);
00876 }
00877 return self;
00878 }
00879
00880
00881
00882
00883 static VALUE
00884 strio_chars(VALUE self)
00885 {
00886 rb_warn("StringIO#chars is deprecated; use #each_char instead");
00887 if (!rb_block_given_p())
00888 return rb_enumeratorize(self, ID2SYM(rb_intern("each_char")), 0, 0);
00889 return strio_each_char(self);
00890 }
00891
00892
00893
00894
00895
00896
00897
00898
00899 static VALUE
00900 strio_each_codepoint(VALUE self)
00901 {
00902 struct StringIO *ptr;
00903 rb_encoding *enc;
00904 unsigned int c;
00905 int n;
00906
00907 RETURN_ENUMERATOR(self, 0, 0);
00908
00909 ptr = readable(self);
00910 enc = rb_enc_get(ptr->string);
00911 for (;;) {
00912 if (ptr->pos >= RSTRING_LEN(ptr->string)) {
00913 return self;
00914 }
00915
00916 c = rb_enc_codepoint_len(RSTRING_PTR(ptr->string)+ptr->pos,
00917 RSTRING_END(ptr->string), &n, enc);
00918 rb_yield(UINT2NUM(c));
00919 ptr->pos += n;
00920 }
00921 return self;
00922 }
00923
00924
00925
00926
00927 static VALUE
00928 strio_codepoints(VALUE self)
00929 {
00930 rb_warn("StringIO#codepoints is deprecated; use #each_codepoint instead");
00931 if (!rb_block_given_p())
00932 return rb_enumeratorize(self, ID2SYM(rb_intern("each_codepoint")), 0, 0);
00933 return strio_each_codepoint(self);
00934 }
00935
00936
00937 static void
00938 bm_init_skip(long *skip, const char *pat, long m)
00939 {
00940 int c;
00941
00942 for (c = 0; c < (1 << CHAR_BIT); c++) {
00943 skip[c] = m;
00944 }
00945 while (--m) {
00946 skip[(unsigned char)*pat++] = m;
00947 }
00948 }
00949
00950 static long
00951 bm_search(const char *little, long llen, const char *big, long blen, const long *skip)
00952 {
00953 long i, j, k;
00954
00955 i = llen - 1;
00956 while (i < blen) {
00957 k = i;
00958 j = llen - 1;
00959 while (j >= 0 && big[k] == little[j]) {
00960 k--;
00961 j--;
00962 }
00963 if (j < 0) return k + 1;
00964 i += skip[(unsigned char)big[i]];
00965 }
00966 return -1;
00967 }
00968
00969 static VALUE
00970 strio_getline(int argc, VALUE *argv, struct StringIO *ptr)
00971 {
00972 const char *s, *e, *p;
00973 long n, limit = 0;
00974 VALUE str, lim;
00975
00976 rb_scan_args(argc, argv, "02", &str, &lim);
00977 switch (argc) {
00978 case 0:
00979 str = rb_rs;
00980 break;
00981
00982 case 1:
00983 if (!NIL_P(str) && !RB_TYPE_P(str, T_STRING)) {
00984 VALUE tmp = rb_check_string_type(str);
00985 if (NIL_P(tmp)) {
00986 limit = NUM2LONG(str);
00987 if (limit == 0) return rb_str_new(0,0);
00988 str = rb_rs;
00989 }
00990 else {
00991 str = tmp;
00992 }
00993 }
00994 break;
00995
00996 case 2:
00997 if (!NIL_P(str)) StringValue(str);
00998 if (!NIL_P(lim)) limit = NUM2LONG(lim);
00999 break;
01000 }
01001
01002 if (ptr->pos >= (n = RSTRING_LEN(ptr->string))) {
01003 return Qnil;
01004 }
01005 s = RSTRING_PTR(ptr->string);
01006 e = s + RSTRING_LEN(ptr->string);
01007 s += ptr->pos;
01008 if (limit > 0 && s + limit < e) {
01009 e = rb_enc_right_char_head(s, s + limit, e, rb_enc_get(ptr->string));
01010 }
01011 if (NIL_P(str)) {
01012 str = strio_substr(ptr, ptr->pos, e - s);
01013 }
01014 else if ((n = RSTRING_LEN(str)) == 0) {
01015 p = s;
01016 while (*p == '\n') {
01017 if (++p == e) {
01018 return Qnil;
01019 }
01020 }
01021 s = p;
01022 while ((p = memchr(p, '\n', e - p)) && (p != e)) {
01023 if (*++p == '\n') {
01024 e = p + 1;
01025 break;
01026 }
01027 }
01028 str = strio_substr(ptr, s - RSTRING_PTR(ptr->string), e - s);
01029 }
01030 else if (n == 1) {
01031 if ((p = memchr(s, RSTRING_PTR(str)[0], e - s)) != 0) {
01032 e = p + 1;
01033 }
01034 str = strio_substr(ptr, ptr->pos, e - s);
01035 }
01036 else {
01037 if (n < e - s) {
01038 if (e - s < 1024) {
01039 for (p = s; p + n <= e; ++p) {
01040 if (MEMCMP(p, RSTRING_PTR(str), char, n) == 0) {
01041 e = p + n;
01042 break;
01043 }
01044 }
01045 }
01046 else {
01047 long skip[1 << CHAR_BIT], pos;
01048 p = RSTRING_PTR(str);
01049 bm_init_skip(skip, p, n);
01050 if ((pos = bm_search(p, n, s, e - s, skip)) >= 0) {
01051 e = s + pos + n;
01052 }
01053 }
01054 }
01055 str = strio_substr(ptr, ptr->pos, e - s);
01056 }
01057 ptr->pos = e - RSTRING_PTR(ptr->string);
01058 ptr->lineno++;
01059 return str;
01060 }
01061
01062
01063
01064
01065
01066
01067
01068
01069
01070 static VALUE
01071 strio_gets(int argc, VALUE *argv, VALUE self)
01072 {
01073 VALUE str = strio_getline(argc, argv, readable(self));
01074
01075 rb_lastline_set(str);
01076 return str;
01077 }
01078
01079
01080
01081
01082
01083
01084
01085
01086
01087 static VALUE
01088 strio_readline(int argc, VALUE *argv, VALUE self)
01089 {
01090 VALUE line = rb_funcall2(self, rb_intern("gets"), argc, argv);
01091 if (NIL_P(line)) rb_eof_error();
01092 return line;
01093 }
01094
01095
01096
01097
01098
01099
01100
01101
01102
01103
01104
01105
01106
01107
01108
01109 static VALUE
01110 strio_each(int argc, VALUE *argv, VALUE self)
01111 {
01112 VALUE line;
01113
01114 StringIO(self);
01115 RETURN_ENUMERATOR(self, argc, argv);
01116
01117 if (argc > 0 && !NIL_P(argv[argc-1]) && NIL_P(rb_check_string_type(argv[argc-1])) &&
01118 NUM2LONG(argv[argc-1]) == 0) {
01119 rb_raise(rb_eArgError, "invalid limit: 0 for each_line");
01120 }
01121
01122 while (!NIL_P(line = strio_getline(argc, argv, readable(self)))) {
01123 rb_yield(line);
01124 }
01125 return self;
01126 }
01127
01128
01129
01130
01131 static VALUE
01132 strio_lines(int argc, VALUE *argv, VALUE self)
01133 {
01134 rb_warn("StringIO#lines is deprecated; use #each_line instead");
01135 if (!rb_block_given_p())
01136 return rb_enumeratorize(self, ID2SYM(rb_intern("each_line")), argc, argv);
01137 return strio_each(argc, argv, self);
01138 }
01139
01140
01141
01142
01143
01144
01145
01146
01147
01148 static VALUE
01149 strio_readlines(int argc, VALUE *argv, VALUE self)
01150 {
01151 VALUE ary, line;
01152
01153 StringIO(self);
01154 ary = rb_ary_new();
01155 if (argc > 0 && !NIL_P(argv[argc-1]) && NIL_P(rb_check_string_type(argv[argc-1])) &&
01156 NUM2LONG(argv[argc-1]) == 0) {
01157 rb_raise(rb_eArgError, "invalid limit: 0 for readlines");
01158 }
01159
01160 while (!NIL_P(line = strio_getline(argc, argv, readable(self)))) {
01161 rb_ary_push(ary, line);
01162 }
01163 return ary;
01164 }
01165
01166
01167
01168
01169
01170
01171
01172
01173
01174
01175
01176 static VALUE
01177 strio_write(VALUE self, VALUE str)
01178 {
01179 struct StringIO *ptr = writable(self);
01180 long len, olen;
01181 rb_encoding *enc, *enc2;
01182 rb_encoding *const ascii8bit = rb_ascii8bit_encoding();
01183
01184 if (!RB_TYPE_P(str, T_STRING))
01185 str = rb_obj_as_string(str);
01186 enc = rb_enc_get(ptr->string);
01187 enc2 = rb_enc_get(str);
01188 if (enc != enc2 && enc != ascii8bit) {
01189 str = rb_str_conv_enc(str, enc2, enc);
01190 }
01191 len = RSTRING_LEN(str);
01192 if (len == 0) return INT2FIX(0);
01193 check_modifiable(ptr);
01194 olen = RSTRING_LEN(ptr->string);
01195 if (ptr->flags & FMODE_APPEND) {
01196 ptr->pos = olen;
01197 }
01198 if (ptr->pos == olen) {
01199 if (enc == ascii8bit || enc2 == ascii8bit) {
01200 rb_enc_str_buf_cat(ptr->string, RSTRING_PTR(str), len, enc);
01201 OBJ_INFECT(ptr->string, str);
01202 }
01203 else {
01204 rb_str_buf_append(ptr->string, str);
01205 }
01206 }
01207 else {
01208 strio_extend(ptr, ptr->pos, len);
01209 memmove(RSTRING_PTR(ptr->string)+ptr->pos, RSTRING_PTR(str), len);
01210 OBJ_INFECT(ptr->string, str);
01211 }
01212 OBJ_INFECT(ptr->string, self);
01213 RB_GC_GUARD(str);
01214 ptr->pos += len;
01215 return LONG2NUM(len);
01216 }
01217
01218
01219
01220
01221
01222
01223
01224 #define strio_addstr rb_io_addstr
01225
01226
01227
01228
01229
01230
01231
01232
01233 #define strio_print rb_io_print
01234
01235
01236
01237
01238
01239
01240
01241 #define strio_printf rb_io_printf
01242
01243
01244
01245
01246
01247
01248
01249 static VALUE
01250 strio_putc(VALUE self, VALUE ch)
01251 {
01252 struct StringIO *ptr = writable(self);
01253 VALUE str;
01254
01255 check_modifiable(ptr);
01256 if (RB_TYPE_P(ch, T_STRING)) {
01257 str = rb_str_substr(ch, 0, 1);
01258 }
01259 else {
01260 char c = NUM2CHR(ch);
01261 str = rb_str_new(&c, 1);
01262 }
01263 strio_write(self, str);
01264 return ch;
01265 }
01266
01267
01268
01269
01270
01271
01272
01273 #define strio_puts rb_io_puts
01274
01275
01276
01277
01278
01279
01280
01281 static VALUE
01282 strio_read(int argc, VALUE *argv, VALUE self)
01283 {
01284 struct StringIO *ptr = readable(self);
01285 VALUE str = Qnil;
01286 long len;
01287 int binary = 0;
01288
01289 switch (argc) {
01290 case 2:
01291 str = argv[1];
01292 if (!NIL_P(str)) {
01293 StringValue(str);
01294 rb_str_modify(str);
01295 }
01296 case 1:
01297 if (!NIL_P(argv[0])) {
01298 len = NUM2LONG(argv[0]);
01299 if (len < 0) {
01300 rb_raise(rb_eArgError, "negative length %ld given", len);
01301 }
01302 if (len > 0 && ptr->pos >= RSTRING_LEN(ptr->string)) {
01303 if (!NIL_P(str)) rb_str_resize(str, 0);
01304 return Qnil;
01305 }
01306 binary = 1;
01307 break;
01308 }
01309
01310 case 0:
01311 len = RSTRING_LEN(ptr->string);
01312 if (len <= ptr->pos) {
01313 if (NIL_P(str)) {
01314 str = rb_str_new(0, 0);
01315 }
01316 else {
01317 rb_str_resize(str, 0);
01318 }
01319 return str;
01320 }
01321 else {
01322 len -= ptr->pos;
01323 }
01324 break;
01325 default:
01326 rb_raise(rb_eArgError, "wrong number of arguments (%d for 0)", argc);
01327 }
01328 if (NIL_P(str)) {
01329 str = strio_substr(ptr, ptr->pos, len);
01330 if (binary) rb_enc_associate(str, rb_ascii8bit_encoding());
01331 }
01332 else {
01333 long rest = RSTRING_LEN(ptr->string) - ptr->pos;
01334 if (len > rest) len = rest;
01335 rb_str_resize(str, len);
01336 MEMCPY(RSTRING_PTR(str), RSTRING_PTR(ptr->string) + ptr->pos, char, len);
01337 if (binary)
01338 rb_enc_associate(str, rb_ascii8bit_encoding());
01339 else
01340 rb_enc_copy(str, ptr->string);
01341 }
01342 ptr->pos += RSTRING_LEN(str);
01343 return str;
01344 }
01345
01346
01347
01348
01349
01350
01351
01352
01353
01354 static VALUE
01355 strio_sysread(int argc, VALUE *argv, VALUE self)
01356 {
01357 VALUE val = rb_funcall2(self, rb_intern("read"), argc, argv);
01358 if (NIL_P(val)) {
01359 rb_eof_error();
01360 }
01361 return val;
01362 }
01363
01364
01365
01366
01367
01368
01369
01370
01371 static VALUE
01372 strio_read_nonblock(int argc, VALUE *argv, VALUE self)
01373 {
01374 VALUE opts = Qnil, val;
01375 int no_exception = 0;
01376
01377 rb_scan_args(argc, argv, "11:", NULL, NULL, &opts);
01378
01379 if (!NIL_P(opts)) {
01380 argc--;
01381
01382 if (Qfalse == rb_hash_aref(opts, sym_exception))
01383 no_exception = 1;
01384 }
01385
01386 val = strio_read(argc, argv, self);
01387 if (NIL_P(val)) {
01388 if (no_exception)
01389 return Qnil;
01390 else
01391 rb_eof_error();
01392 }
01393
01394 return val;
01395 }
01396
01397 #define strio_syswrite rb_io_write
01398
01399 static VALUE
01400 strio_syswrite_nonblock(int argc, VALUE *argv, VALUE self)
01401 {
01402 VALUE str;
01403
01404 rb_scan_args(argc, argv, "10:", &str, NULL);
01405 return strio_syswrite(self, str);
01406 }
01407
01408 #define strio_isatty strio_false
01409
01410 #define strio_pid strio_nil
01411
01412 #define strio_fileno strio_nil
01413
01414
01415
01416
01417
01418
01419
01420
01421 static VALUE
01422 strio_size(VALUE self)
01423 {
01424 VALUE string = StringIO(self)->string;
01425 if (NIL_P(string)) {
01426 rb_raise(rb_eIOError, "not opened");
01427 }
01428 return ULONG2NUM(RSTRING_LEN(string));
01429 }
01430
01431
01432
01433
01434
01435
01436
01437
01438 static VALUE
01439 strio_truncate(VALUE self, VALUE len)
01440 {
01441 VALUE string = writable(self)->string;
01442 long l = NUM2LONG(len);
01443 long plen = RSTRING_LEN(string);
01444 if (l < 0) {
01445 error_inval("negative length");
01446 }
01447 rb_str_resize(string, l);
01448 if (plen < l) {
01449 MEMZERO(RSTRING_PTR(string) + plen, char, l - plen);
01450 }
01451 return len;
01452 }
01453
01454
01455
01456
01457
01458
01459
01460
01461
01462 static VALUE
01463 strio_external_encoding(VALUE self)
01464 {
01465 return rb_enc_from_encoding(rb_enc_get(StringIO(self)->string));
01466 }
01467
01468
01469
01470
01471
01472
01473
01474
01475
01476 static VALUE
01477 strio_internal_encoding(VALUE self)
01478 {
01479 return Qnil;
01480 }
01481
01482
01483
01484
01485
01486
01487
01488
01489
01490
01491
01492 static VALUE
01493 strio_set_encoding(int argc, VALUE *argv, VALUE self)
01494 {
01495 rb_encoding* enc;
01496 VALUE str = StringIO(self)->string;
01497 VALUE ext_enc, int_enc, opt;
01498
01499 argc = rb_scan_args(argc, argv, "11:", &ext_enc, &int_enc, &opt);
01500
01501 if (NIL_P(ext_enc)) {
01502 enc = rb_default_external_encoding();
01503 }
01504 else {
01505 enc = rb_to_encoding(ext_enc);
01506 }
01507 rb_enc_associate(str, enc);
01508 return self;
01509 }
01510
01511
01512
01513
01514 void
01515 Init_stringio()
01516 {
01517 VALUE StringIO = rb_define_class("StringIO", rb_cData);
01518
01519 rb_include_module(StringIO, rb_mEnumerable);
01520 rb_define_alloc_func(StringIO, strio_s_allocate);
01521 rb_define_singleton_method(StringIO, "open", strio_s_open, -1);
01522 rb_define_method(StringIO, "initialize", strio_initialize, -1);
01523 rb_define_method(StringIO, "initialize_copy", strio_copy, 1);
01524 rb_define_method(StringIO, "reopen", strio_reopen, -1);
01525
01526 rb_define_method(StringIO, "string", strio_get_string, 0);
01527 rb_define_method(StringIO, "string=", strio_set_string, 1);
01528 rb_define_method(StringIO, "lineno", strio_get_lineno, 0);
01529 rb_define_method(StringIO, "lineno=", strio_set_lineno, 1);
01530
01531
01532
01533 rb_define_method(StringIO, "binmode", strio_binmode, 0);
01534 rb_define_method(StringIO, "close", strio_close, 0);
01535 rb_define_method(StringIO, "close_read", strio_close_read, 0);
01536 rb_define_method(StringIO, "close_write", strio_close_write, 0);
01537 rb_define_method(StringIO, "closed?", strio_closed, 0);
01538 rb_define_method(StringIO, "closed_read?", strio_closed_read, 0);
01539 rb_define_method(StringIO, "closed_write?", strio_closed_write, 0);
01540 rb_define_method(StringIO, "eof", strio_eof, 0);
01541 rb_define_method(StringIO, "eof?", strio_eof, 0);
01542
01543 rb_define_method(StringIO, "fcntl", strio_fcntl, -1);
01544
01545 rb_define_method(StringIO, "flush", strio_flush, 0);
01546
01547 rb_define_method(StringIO, "fsync", strio_fsync, 0);
01548 rb_define_method(StringIO, "pos", strio_get_pos, 0);
01549 rb_define_method(StringIO, "pos=", strio_set_pos, 1);
01550 rb_define_method(StringIO, "rewind", strio_rewind, 0);
01551 rb_define_method(StringIO, "seek", strio_seek, -1);
01552 rb_define_method(StringIO, "sync", strio_get_sync, 0);
01553
01554 rb_define_method(StringIO, "sync=", strio_set_sync, 1);
01555 rb_define_method(StringIO, "tell", strio_tell, 0);
01556
01557 rb_define_method(StringIO, "each", strio_each, -1);
01558 rb_define_method(StringIO, "each_line", strio_each, -1);
01559 rb_define_method(StringIO, "lines", strio_lines, -1);
01560 rb_define_method(StringIO, "each_byte", strio_each_byte, 0);
01561 rb_define_method(StringIO, "bytes", strio_bytes, 0);
01562 rb_define_method(StringIO, "each_char", strio_each_char, 0);
01563 rb_define_method(StringIO, "chars", strio_chars, 0);
01564 rb_define_method(StringIO, "each_codepoint", strio_each_codepoint, 0);
01565 rb_define_method(StringIO, "codepoints", strio_codepoints, 0);
01566 rb_define_method(StringIO, "getc", strio_getc, 0);
01567 rb_define_method(StringIO, "ungetc", strio_ungetc, 1);
01568 rb_define_method(StringIO, "ungetbyte", strio_ungetbyte, 1);
01569 rb_define_method(StringIO, "getbyte", strio_getbyte, 0);
01570 rb_define_method(StringIO, "gets", strio_gets, -1);
01571 rb_define_method(StringIO, "readlines", strio_readlines, -1);
01572 rb_define_method(StringIO, "read", strio_read, -1);
01573
01574 rb_define_method(StringIO, "write", strio_write, 1);
01575 rb_define_method(StringIO, "putc", strio_putc, 1);
01576
01577
01578
01579
01580
01581
01582
01583 rb_define_method(StringIO, "isatty", strio_isatty, 0);
01584 rb_define_method(StringIO, "tty?", strio_isatty, 0);
01585
01586
01587 rb_define_method(StringIO, "pid", strio_pid, 0);
01588
01589
01590 rb_define_method(StringIO, "fileno", strio_fileno, 0);
01591 rb_define_method(StringIO, "size", strio_size, 0);
01592 rb_define_method(StringIO, "length", strio_size, 0);
01593 rb_define_method(StringIO, "truncate", strio_truncate, 1);
01594
01595 rb_define_method(StringIO, "external_encoding", strio_external_encoding, 0);
01596 rb_define_method(StringIO, "internal_encoding", strio_internal_encoding, 0);
01597 rb_define_method(StringIO, "set_encoding", strio_set_encoding, -1);
01598
01599 {
01600 VALUE mReadable = rb_define_module_under(rb_cIO, "generic_readable");
01601 rb_define_method(mReadable, "readchar", strio_readchar, 0);
01602 rb_define_method(mReadable, "readbyte", strio_readbyte, 0);
01603 rb_define_method(mReadable, "readline", strio_readline, -1);
01604 rb_define_method(mReadable, "sysread", strio_sysread, -1);
01605 rb_define_method(mReadable, "readpartial", strio_sysread, -1);
01606 rb_define_method(mReadable, "read_nonblock", strio_read_nonblock, -1);
01607 rb_include_module(StringIO, mReadable);
01608 }
01609 {
01610 VALUE mWritable = rb_define_module_under(rb_cIO, "generic_writable");
01611 rb_define_method(mWritable, "<<", strio_addstr, 1);
01612 rb_define_method(mWritable, "print", strio_print, -1);
01613 rb_define_method(mWritable, "printf", strio_printf, -1);
01614 rb_define_method(mWritable, "puts", strio_puts, -1);
01615 rb_define_method(mWritable, "syswrite", strio_syswrite, 1);
01616 rb_define_method(mWritable, "write_nonblock", strio_syswrite_nonblock, -1);
01617 rb_include_module(StringIO, mWritable);
01618 }
01619
01620 sym_exception = ID2SYM(rb_intern("exception"));
01621 }
01622