Ruby 3.0.5p211 (2022-11-24 revision ba5cf0f7c52d4d35cc6a173c89eda98ceffa2dcf)
stringio.c
Go to the documentation of this file.
1/* -*- mode: c; indent-tabs-mode: t -*- */
2/**********************************************************************
3
4 stringio.c -
5
6 $Author$
7 $RoughId: stringio.c,v 1.13 2002/03/14 03:24:18 nobu Exp $
8 created at: Tue Feb 19 04:10:38 JST 2002
9
10 All the files in this distribution are covered under the Ruby's
11 license (see the file COPYING).
12
13**********************************************************************/
14
15#define STRINGIO_VERSION "3.0.1"
16
17#include "ruby.h"
18#include "ruby/io.h"
19#include "ruby/encoding.h"
20#if defined(HAVE_FCNTL_H) || defined(_WIN32)
21#include <fcntl.h>
22#elif defined(HAVE_SYS_FCNTL_H)
23#include <sys/fcntl.h>
24#endif
25
26#ifndef RB_INTEGER_TYPE_P
27# define RB_INTEGER_TYPE_P(c) (FIXNUM_P(c) || RB_TYPE_P(c, T_BIGNUM))
28#endif
29
30#ifndef RB_PASS_CALLED_KEYWORDS
31# define rb_funcallv_kw(recv, mid, arg, argv, kw_splat) rb_funcallv(recv, mid, arg, argv)
32# define rb_class_new_instance_kw(argc, argv, klass, kw_splat) rb_class_new_instance(argc, argv, klass)
33#endif
34
35#ifndef HAVE_RB_IO_EXTRACT_MODEENC
36#define rb_io_extract_modeenc strio_extract_modeenc
37static void
38strio_extract_modeenc(VALUE *vmode_p, VALUE *vperm_p, VALUE opthash,
39 int *oflags_p, int *fmode_p, struct rb_io_enc_t *convconfig_p)
40{
41 VALUE mode = *vmode_p;
42 VALUE intmode;
43 int fmode;
44 int has_enc = 0, has_vmode = 0;
45
46 convconfig_p->enc = convconfig_p->enc2 = 0;
47
48 vmode_handle:
49 if (NIL_P(mode)) {
51 }
52 else if (!NIL_P(intmode = rb_check_to_integer(mode, "to_int"))) {
53 int flags = NUM2INT(intmode);
55 }
56 else {
57 const char *m = StringValueCStr(mode), *n, *e;
59 n = strchr(m, ':');
60 if (n) {
61 long len;
62 char encname[ENCODING_MAXNAMELEN+1];
63 has_enc = 1;
65 n = strchr(n, '|');
66 }
67 e = strchr(++n, ':');
68 len = e ? e - n : (long)strlen(n);
69 if (len > 0 && len <= ENCODING_MAXNAMELEN) {
70 if (e) {
71 memcpy(encname, n, len);
72 encname[len] = '\0';
73 n = encname;
74 }
75 convconfig_p->enc = rb_enc_find(n);
76 }
77 if (e && (len = strlen(++e)) > 0 && len <= ENCODING_MAXNAMELEN) {
78 convconfig_p->enc2 = rb_enc_find(e);
79 }
80 }
81 }
82
83 if (!NIL_P(opthash)) {
84 rb_encoding *extenc = 0, *intenc = 0;
85 VALUE v;
86 if (!has_vmode) {
87 ID id_mode;
88 CONST_ID(id_mode, "mode");
89 v = rb_hash_aref(opthash, ID2SYM(id_mode));
90 if (!NIL_P(v)) {
91 if (!NIL_P(mode)) {
92 rb_raise(rb_eArgError, "mode specified twice");
93 }
94 has_vmode = 1;
95 mode = v;
96 goto vmode_handle;
97 }
98 }
99
100 if (rb_io_extract_encoding_option(opthash, &extenc, &intenc, &fmode)) {
101 if (has_enc) {
102 rb_raise(rb_eArgError, "encoding specified twice");
103 }
104 }
105 }
106 *fmode_p = fmode;
107}
108#endif
109
110struct StringIO {
113 long pos;
114 long lineno;
115 int flags;
116 int count;
117};
118
119static VALUE strio_init(int, VALUE *, struct StringIO *, VALUE);
120static VALUE strio_unget_bytes(struct StringIO *, const char *, long);
121static long strio_write(VALUE self, VALUE str);
122
123#define IS_STRIO(obj) (rb_typeddata_is_kind_of((obj), &strio_data_type))
124#define error_inval(msg) (rb_syserr_fail(EINVAL, msg))
125#define get_enc(ptr) ((ptr)->enc ? (ptr)->enc : rb_enc_get((ptr)->string))
126
127static struct StringIO *
128strio_alloc(void)
129{
130 struct StringIO *ptr = ALLOC(struct StringIO);
131 ptr->string = Qnil;
132 ptr->pos = 0;
133 ptr->lineno = 0;
134 ptr->flags = 0;
135 ptr->count = 1;
136 return ptr;
137}
138
139static void
140strio_mark(void *p)
141{
142 struct StringIO *ptr = p;
143
144 rb_gc_mark(ptr->string);
145}
146
147static void
148strio_free(void *p)
149{
150 struct StringIO *ptr = p;
151 if (--ptr->count <= 0) {
152 xfree(ptr);
153 }
154}
155
156static size_t
157strio_memsize(const void *p)
158{
159 return sizeof(struct StringIO);
160}
161
162static const rb_data_type_t strio_data_type = {
163 "strio",
164 {
165 strio_mark,
166 strio_free,
167 strio_memsize,
168 },
170};
171
172#define check_strio(self) ((struct StringIO*)rb_check_typeddata((self), &strio_data_type))
173
174static struct StringIO*
175get_strio(VALUE self)
176{
177 struct StringIO *ptr = check_strio(rb_io_taint_check(self));
178
179 if (!ptr) {
180 rb_raise(rb_eIOError, "uninitialized stream");
181 }
182 return ptr;
183}
184
185static VALUE
186enc_subseq(VALUE str, long pos, long len, rb_encoding *enc)
187{
188 str = rb_str_subseq(str, pos, len);
189 rb_enc_associate(str, enc);
190 return str;
191}
192
193static VALUE
194strio_substr(struct StringIO *ptr, long pos, long len, rb_encoding *enc)
195{
196 VALUE str = ptr->string;
197 long rlen = RSTRING_LEN(str) - pos;
198
199 if (len > rlen) len = rlen;
200 if (len < 0) len = 0;
201 if (len == 0) return rb_enc_str_new(0, 0, enc);
202 return enc_subseq(str, pos, len, enc);
203}
204
205#define StringIO(obj) get_strio(obj)
206
207#define STRIO_READABLE FL_USER4
208#define STRIO_WRITABLE FL_USER5
209#define STRIO_READWRITE (STRIO_READABLE|STRIO_WRITABLE)
211#define STRIO_MODE_SET_P(strio, mode) \
212 ((RBASIC(strio)->flags & STRIO_##mode) && \
213 ((struct StringIO*)DATA_PTR(strio))->flags & FMODE_##mode)
214#define CLOSED(strio) (!STRIO_MODE_SET_P(strio, READWRITE))
215#define READABLE(strio) STRIO_MODE_SET_P(strio, READABLE)
216#define WRITABLE(strio) STRIO_MODE_SET_P(strio, WRITABLE)
217
218static VALUE sym_exception;
219
220static struct StringIO*
221readable(VALUE strio)
222{
223 struct StringIO *ptr = StringIO(strio);
224 if (!READABLE(strio)) {
225 rb_raise(rb_eIOError, "not opened for reading");
226 }
227 return ptr;
228}
229
230static struct StringIO*
231writable(VALUE strio)
232{
233 struct StringIO *ptr = StringIO(strio);
234 if (!WRITABLE(strio)) {
235 rb_raise(rb_eIOError, "not opened for writing");
236 }
237 return ptr;
238}
239
240static void
241check_modifiable(struct StringIO *ptr)
242{
243 if (OBJ_FROZEN(ptr->string)) {
244 rb_raise(rb_eIOError, "not modifiable string");
245 }
246}
247
248static VALUE
249strio_s_allocate(VALUE klass)
250{
251 return TypedData_Wrap_Struct(klass, &strio_data_type, 0);
252}
253
254/*
255 * call-seq: StringIO.new(string=""[, mode])
256 *
257 * Creates new StringIO instance from with _string_ and _mode_.
258 */
259static VALUE
260strio_initialize(int argc, VALUE *argv, VALUE self)
261{
262 struct StringIO *ptr = check_strio(self);
263
264 if (!ptr) {
265 DATA_PTR(self) = ptr = strio_alloc();
266 }
267 rb_call_super(0, 0);
268 return strio_init(argc, argv, ptr, self);
269}
270
271static int
272detect_bom(VALUE str, int *bomlen)
273{
274 const char *p;
275 long len;
276
278 if (len < 1) return 0;
279 switch ((unsigned char)p[0]) {
280 case 0xEF:
281 if (len < 2) break;
282 if ((unsigned char)p[1] == 0xBB && len > 2) {
283 if ((unsigned char)p[2] == 0xBF) {
284 *bomlen = 3;
285 return rb_utf8_encindex();
286 }
287 }
288 break;
289
290 case 0xFE:
291 if (len < 2) break;
292 if ((unsigned char)p[1] == 0xFF) {
293 *bomlen = 2;
294 return rb_enc_find_index("UTF-16BE");
295 }
296 break;
297
298 case 0xFF:
299 if (len < 2) break;
300 if ((unsigned char)p[1] == 0xFE) {
301 if (len >= 4 && (unsigned char)p[2] == 0 && (unsigned char)p[3] == 0) {
302 *bomlen = 4;
303 return rb_enc_find_index("UTF-32LE");
304 }
305 *bomlen = 2;
306 return rb_enc_find_index("UTF-16LE");
307 }
308 break;
309
310 case 0:
311 if (len < 4) break;
312 if ((unsigned char)p[1] == 0 && (unsigned char)p[2] == 0xFE && (unsigned char)p[3] == 0xFF) {
313 *bomlen = 4;
314 return rb_enc_find_index("UTF-32BE");
315 }
316 break;
317 }
318 return 0;
319}
320
321static rb_encoding *
322set_encoding_by_bom(struct StringIO *ptr)
323{
324 int bomlen, idx = detect_bom(ptr->string, &bomlen);
325 rb_encoding *extenc = NULL;
326
327 if (idx) {
328 extenc = rb_enc_from_index(idx);
329 ptr->pos = bomlen;
330 if (ptr->flags & FMODE_WRITABLE) {
331 rb_enc_associate_index(ptr->string, idx);
332 }
333 }
334 ptr->enc = extenc;
335 return extenc;
336}
337
338static VALUE
339strio_init(int argc, VALUE *argv, struct StringIO *ptr, VALUE self)
340{
341 VALUE string, vmode, opt;
342 int oflags;
343 struct rb_io_enc_t convconfig;
344
345 argc = rb_scan_args(argc, argv, "02:", &string, &vmode, &opt);
346 rb_io_extract_modeenc(&vmode, 0, opt, &oflags, &ptr->flags, &convconfig);
347 if (argc) {
348 StringValue(string);
349 }
350 else {
352 }
353 if (OBJ_FROZEN_RAW(string)) {
354 if (ptr->flags & FMODE_WRITABLE) {
355 rb_syserr_fail(EACCES, 0);
356 }
357 }
358 else {
359 if (NIL_P(vmode)) {
361 }
362 }
363 if (ptr->flags & FMODE_TRUNC) {
364 rb_str_resize(string, 0);
365 }
366 ptr->string = string;
367 if (argc == 1) {
368 ptr->enc = rb_enc_get(string);
369 }
370 else {
371 ptr->enc = convconfig.enc;
372 }
373 ptr->pos = 0;
374 ptr->lineno = 0;
375 if (ptr->flags & FMODE_SETENC_BY_BOM) set_encoding_by_bom(ptr);
376 RBASIC(self)->flags |= (ptr->flags & FMODE_READWRITE) * (STRIO_READABLE / FMODE_READABLE);
377 return self;
378}
379
380static VALUE
381strio_finalize(VALUE self)
382{
383 struct StringIO *ptr = StringIO(self);
384 ptr->string = Qnil;
385 ptr->flags &= ~FMODE_READWRITE;
386 return self;
387}
388
389/*
390 * call-seq: StringIO.open(string=""[, mode]) {|strio| ...}
391 *
392 * Equivalent to StringIO.new except that when it is called with a block, it
393 * yields with the new instance and closes it, and returns the result which
394 * returned from the block.
395 */
396static VALUE
397strio_s_open(int argc, VALUE *argv, VALUE klass)
398{
400 if (!rb_block_given_p()) return obj;
401 return rb_ensure(rb_yield, obj, strio_finalize, obj);
402}
403
404/* :nodoc: */
405static VALUE
406strio_s_new(int argc, VALUE *argv, VALUE klass)
407{
408 if (rb_block_given_p()) {
409 VALUE cname = rb_obj_as_string(klass);
410
411 rb_warn("%"PRIsVALUE"::new() does not take block; use %"PRIsVALUE"::open() instead",
412 cname, cname);
413 }
415}
416
417/*
418 * Returns +false+. Just for compatibility to IO.
419 */
420static VALUE
421strio_false(VALUE self)
422{
423 StringIO(self);
424 return Qfalse;
425}
426
427/*
428 * Returns +nil+. Just for compatibility to IO.
429 */
430static VALUE
431strio_nil(VALUE self)
432{
433 StringIO(self);
434 return Qnil;
435}
436
437/*
438 * Returns an object itself. Just for compatibility to IO.
439 */
440static VALUE
441strio_self(VALUE self)
442{
443 StringIO(self);
444 return self;
445}
446
447/*
448 * Returns 0. Just for compatibility to IO.
449 */
450static VALUE
451strio_0(VALUE self)
452{
453 StringIO(self);
454 return INT2FIX(0);
455}
456
457/*
458 * Returns the argument unchanged. Just for compatibility to IO.
459 */
460static VALUE
461strio_first(VALUE self, VALUE arg)
462{
463 StringIO(self);
464 return arg;
465}
466
467/*
468 * Raises NotImplementedError.
469 */
470static VALUE
471strio_unimpl(int argc, VALUE *argv, VALUE self)
472{
473 StringIO(self);
475
477}
478
479/*
480 * call-seq: strio.string -> string
481 *
482 * Returns underlying String object, the subject of IO.
483 */
484static VALUE
485strio_get_string(VALUE self)
486{
487 return StringIO(self)->string;
488}
489
490/*
491 * call-seq:
492 * strio.string = string -> string
493 *
494 * Changes underlying String object, the subject of IO.
495 */
496static VALUE
497strio_set_string(VALUE self, VALUE string)
498{
499 struct StringIO *ptr = StringIO(self);
500
501 rb_io_taint_check(self);
502 ptr->flags &= ~FMODE_READWRITE;
503 StringValue(string);
505 ptr->pos = 0;
506 ptr->lineno = 0;
507 return ptr->string = string;
508}
509
510/*
511 * call-seq:
512 * strio.close -> nil
513 *
514 * Closes a StringIO. The stream is unavailable for any further data
515 * operations; an +IOError+ is raised if such an attempt is made.
516 */
517static VALUE
518strio_close(VALUE self)
519{
520 StringIO(self);
521 RBASIC(self)->flags &= ~STRIO_READWRITE;
522 return Qnil;
523}
524
525/*
526 * call-seq:
527 * strio.close_read -> nil
528 *
529 * Closes the read end of a StringIO. Will raise an +IOError+ if the
530 * receiver is not readable.
531 */
532static VALUE
533strio_close_read(VALUE self)
534{
535 struct StringIO *ptr = StringIO(self);
536 if (!(ptr->flags & FMODE_READABLE)) {
537 rb_raise(rb_eIOError, "closing non-duplex IO for reading");
538 }
539 RBASIC(self)->flags &= ~STRIO_READABLE;
540 return Qnil;
541}
542
543/*
544 * call-seq:
545 * strio.close_write -> nil
546 *
547 * Closes the write end of a StringIO. Will raise an +IOError+ if the
548 * receiver is not writeable.
549 */
550static VALUE
551strio_close_write(VALUE self)
552{
553 struct StringIO *ptr = StringIO(self);
554 if (!(ptr->flags & FMODE_WRITABLE)) {
555 rb_raise(rb_eIOError, "closing non-duplex IO for writing");
556 }
557 RBASIC(self)->flags &= ~STRIO_WRITABLE;
558 return Qnil;
559}
560
561/*
562 * call-seq:
563 * strio.closed? -> true or false
564 *
565 * Returns +true+ if the stream is completely closed, +false+ otherwise.
566 */
567static VALUE
568strio_closed(VALUE self)
569{
570 StringIO(self);
571 if (!CLOSED(self)) return Qfalse;
572 return Qtrue;
573}
574
575/*
576 * call-seq:
577 * strio.closed_read? -> true or false
578 *
579 * Returns +true+ if the stream is not readable, +false+ otherwise.
580 */
581static VALUE
582strio_closed_read(VALUE self)
583{
584 StringIO(self);
585 if (READABLE(self)) return Qfalse;
586 return Qtrue;
587}
588
589/*
590 * call-seq:
591 * strio.closed_write? -> true or false
592 *
593 * Returns +true+ if the stream is not writable, +false+ otherwise.
594 */
595static VALUE
596strio_closed_write(VALUE self)
597{
598 StringIO(self);
599 if (WRITABLE(self)) return Qfalse;
600 return Qtrue;
601}
602
603static struct StringIO *
604strio_to_read(VALUE self)
605{
606 struct StringIO *ptr = readable(self);
607 if (ptr->pos < RSTRING_LEN(ptr->string)) return ptr;
608 return NULL;
609}
610
611/*
612 * call-seq:
613 * strio.eof -> true or false
614 * strio.eof? -> true or false
615 *
616 * Returns true if the stream is at the end of the data (underlying string).
617 * The stream must be opened for reading or an +IOError+ will be raised.
618 */
619static VALUE
620strio_eof(VALUE self)
621{
622 if (strio_to_read(self)) return Qfalse;
623 return Qtrue;
624}
625
626/* :nodoc: */
627static VALUE
628strio_copy(VALUE copy, VALUE orig)
629{
630 struct StringIO *ptr;
631
632 orig = rb_convert_type(orig, T_DATA, "StringIO", "to_strio");
633 if (copy == orig) return copy;
634 ptr = StringIO(orig);
635 if (check_strio(copy)) {
636 strio_free(DATA_PTR(copy));
637 }
638 DATA_PTR(copy) = ptr;
639 RBASIC(copy)->flags &= ~STRIO_READWRITE;
640 RBASIC(copy)->flags |= RBASIC(orig)->flags & STRIO_READWRITE;
641 ++ptr->count;
642 return copy;
643}
644
645/*
646 * call-seq:
647 * strio.lineno -> integer
648 *
649 * Returns the current line number. The stream must be
650 * opened for reading. +lineno+ counts the number of times +gets+ is
651 * called, rather than the number of newlines encountered. The two
652 * values will differ if +gets+ is called with a separator other than
653 * newline. See also the <code>$.</code> variable.
654 */
655static VALUE
656strio_get_lineno(VALUE self)
657{
658 return LONG2NUM(StringIO(self)->lineno);
659}
660
661/*
662 * call-seq:
663 * strio.lineno = integer -> integer
664 *
665 * Manually sets the current line number to the given value.
666 * <code>$.</code> is updated only on the next read.
667 */
668static VALUE
669strio_set_lineno(VALUE self, VALUE lineno)
670{
671 StringIO(self)->lineno = NUM2LONG(lineno);
672 return lineno;
673}
674
675/*
676 * call-seq:
677 * strio.binmode -> stringio
678 *
679 * Puts stream into binary mode. See IO#binmode.
680 *
681 */
682static VALUE
683strio_binmode(VALUE self)
684{
685 struct StringIO *ptr = StringIO(self);
687
688 ptr->enc = enc;
689 if (WRITABLE(self)) {
690 rb_enc_associate(ptr->string, enc);
691 }
692 return self;
693}
694
695#define strio_fcntl strio_unimpl
696
697#define strio_flush strio_self
698
699#define strio_fsync strio_0
700
701/*
702 * call-seq:
703 * strio.reopen(other_StrIO) -> strio
704 * strio.reopen(string, mode) -> strio
705 *
706 * Reinitializes the stream with the given <i>other_StrIO</i> or _string_
707 * and _mode_ (see StringIO#new).
708 */
709static VALUE
710strio_reopen(int argc, VALUE *argv, VALUE self)
711{
712 rb_io_taint_check(self);
713 if (argc == 1 && !RB_TYPE_P(*argv, T_STRING)) {
714 return strio_copy(self, *argv);
715 }
716 return strio_init(argc, argv, StringIO(self), self);
717}
718
719/*
720 * call-seq:
721 * strio.pos -> integer
722 * strio.tell -> integer
723 *
724 * Returns the current offset (in bytes).
725 */
726static VALUE
727strio_get_pos(VALUE self)
728{
729 return LONG2NUM(StringIO(self)->pos);
730}
731
732/*
733 * call-seq:
734 * strio.pos = integer -> integer
735 *
736 * Seeks to the given position (in bytes).
737 */
738static VALUE
739strio_set_pos(VALUE self, VALUE pos)
740{
741 struct StringIO *ptr = StringIO(self);
742 long p = NUM2LONG(pos);
743 if (p < 0) {
744 error_inval(0);
745 }
746 ptr->pos = p;
747 return pos;
748}
749
750/*
751 * call-seq:
752 * strio.rewind -> 0
753 *
754 * Positions the stream to the beginning of input, resetting
755 * +lineno+ to zero.
756 */
757static VALUE
758strio_rewind(VALUE self)
759{
760 struct StringIO *ptr = StringIO(self);
761 ptr->pos = 0;
762 ptr->lineno = 0;
763 return INT2FIX(0);
764}
765
766/*
767 * call-seq:
768 * strio.seek(amount, whence=SEEK_SET) -> 0
769 *
770 * Seeks to a given offset _amount_ in the stream according to
771 * the value of _whence_ (see IO#seek).
772 */
773static VALUE
774strio_seek(int argc, VALUE *argv, VALUE self)
775{
776 VALUE whence;
777 struct StringIO *ptr = StringIO(self);
778 long amount, offset;
779
780 rb_scan_args(argc, argv, "11", NULL, &whence);
781 amount = NUM2LONG(argv[0]);
782 if (CLOSED(self)) {
783 rb_raise(rb_eIOError, "closed stream");
784 }
785 switch (NIL_P(whence) ? 0 : NUM2LONG(whence)) {
786 case 0:
787 offset = 0;
788 break;
789 case 1:
790 offset = ptr->pos;
791 break;
792 case 2:
793 offset = RSTRING_LEN(ptr->string);
794 break;
795 default:
796 error_inval("invalid whence");
797 }
798 if (amount > LONG_MAX - offset || amount + offset < 0) {
799 error_inval(0);
800 }
801 ptr->pos = amount + offset;
802 return INT2FIX(0);
803}
804
805/*
806 * call-seq:
807 * strio.sync -> true
808 *
809 * Returns +true+ always.
810 */
811static VALUE
812strio_get_sync(VALUE self)
813{
814 StringIO(self);
815 return Qtrue;
816}
817
818#define strio_set_sync strio_first
819
820#define strio_tell strio_get_pos
821
822/*
823 * call-seq:
824 * strio.each_byte {|byte| block } -> strio
825 * strio.each_byte -> anEnumerator
826 *
827 * See IO#each_byte.
828 */
829static VALUE
830strio_each_byte(VALUE self)
831{
832 struct StringIO *ptr;
833
834 RETURN_ENUMERATOR(self, 0, 0);
835
836 while ((ptr = strio_to_read(self)) != NULL) {
837 char c = RSTRING_PTR(ptr->string)[ptr->pos++];
838 rb_yield(CHR2FIX(c));
839 }
840 return self;
841}
842
843/*
844 * call-seq:
845 * strio.getc -> string or nil
846 *
847 * See IO#getc.
848 */
849static VALUE
850strio_getc(VALUE self)
851{
852 struct StringIO *ptr = readable(self);
853 rb_encoding *enc = get_enc(ptr);
854 VALUE str = ptr->string;
855 long pos = ptr->pos;
856 int len;
857 char *p;
858
859 if (pos >= RSTRING_LEN(str)) {
860 return Qnil;
861 }
862 p = RSTRING_PTR(str)+pos;
863 len = rb_enc_mbclen(p, RSTRING_END(str), enc);
864 ptr->pos += len;
865 return enc_subseq(str, pos, len, enc);
866}
867
868/*
869 * call-seq:
870 * strio.getbyte -> fixnum or nil
871 *
872 * See IO#getbyte.
873 */
874static VALUE
875strio_getbyte(VALUE self)
876{
877 struct StringIO *ptr = readable(self);
878 int c;
879 if (ptr->pos >= RSTRING_LEN(ptr->string)) {
880 return Qnil;
881 }
882 c = RSTRING_PTR(ptr->string)[ptr->pos++];
883 return CHR2FIX(c);
884}
885
886static void
887strio_extend(struct StringIO *ptr, long pos, long len)
888{
889 long olen;
890
891 if (len > LONG_MAX - pos)
892 rb_raise(rb_eArgError, "string size too big");
893
894 check_modifiable(ptr);
895 olen = RSTRING_LEN(ptr->string);
896 if (pos + len > olen) {
897 rb_str_resize(ptr->string, pos + len);
898 if (pos > olen)
899 MEMZERO(RSTRING_PTR(ptr->string) + olen, char, pos - olen);
900 }
901 else {
902 rb_str_modify(ptr->string);
903 }
904}
905
906/*
907 * call-seq:
908 * strio.ungetc(string) -> nil
909 *
910 * Pushes back one character (passed as a parameter)
911 * such that a subsequent buffered read will return it. There is no
912 * limitation for multiple pushbacks including pushing back behind the
913 * beginning of the buffer string.
914 */
915static VALUE
916strio_ungetc(VALUE self, VALUE c)
917{
918 struct StringIO *ptr = readable(self);
919 rb_encoding *enc, *enc2;
920
921 check_modifiable(ptr);
922 if (NIL_P(c)) return Qnil;
923 if (RB_INTEGER_TYPE_P(c)) {
924 int len, cc = NUM2INT(c);
925 char buf[16];
926
927 enc = rb_enc_get(ptr->string);
928 len = rb_enc_codelen(cc, enc);
929 if (len <= 0) rb_enc_uint_chr(cc, enc);
930 rb_enc_mbcput(cc, buf, enc);
931 return strio_unget_bytes(ptr, buf, len);
932 }
933 else {
935 enc = rb_enc_get(ptr->string);
936 enc2 = rb_enc_get(c);
937 if (enc != enc2 && enc != rb_ascii8bit_encoding()) {
938 c = rb_str_conv_enc(c, enc2, enc);
939 }
940 strio_unget_bytes(ptr, RSTRING_PTR(c), RSTRING_LEN(c));
941 RB_GC_GUARD(c);
942 return Qnil;
943 }
944}
945
946/*
947 * call-seq:
948 * strio.ungetbyte(fixnum) -> nil
949 *
950 * See IO#ungetbyte
951 */
952static VALUE
953strio_ungetbyte(VALUE self, VALUE c)
954{
955 struct StringIO *ptr = readable(self);
956
957 check_modifiable(ptr);
958 if (NIL_P(c)) return Qnil;
959 if (RB_INTEGER_TYPE_P(c)) {
960 /* rb_int_and() not visible from exts */
961 VALUE v = rb_funcall(c, '&', 1, INT2FIX(0xff));
962 const char cc = NUM2INT(v) & 0xFF;
963 strio_unget_bytes(ptr, &cc, 1);
964 }
965 else {
966 long cl;
968 cl = RSTRING_LEN(c);
969 if (cl > 0) {
970 strio_unget_bytes(ptr, RSTRING_PTR(c), cl);
971 RB_GC_GUARD(c);
972 }
973 }
974 return Qnil;
975}
976
977static VALUE
978strio_unget_bytes(struct StringIO *ptr, const char *cp, long cl)
979{
980 long pos = ptr->pos, len, rest;
981 VALUE str = ptr->string;
982 char *s;
983
985 rest = pos - len;
986 if (cl > pos) {
987 long ex = (rest < 0 ? cl-pos : cl+rest);
989 rb_str_set_len(str, len + ex);
990 s = RSTRING_PTR(str);
991 if (rest < 0) memmove(s + cl, s + pos, -rest);
992 pos = 0;
993 }
994 else {
995 if (rest > 0) {
997 rb_str_set_len(str, len + rest);
998 }
999 s = RSTRING_PTR(str);
1000 if (rest > cl) memset(s + len, 0, rest - cl);
1001 pos -= cl;
1002 }
1003 memcpy(s + pos, cp, cl);
1004 ptr->pos = pos;
1005 return Qnil;
1006}
1007
1008/*
1009 * call-seq:
1010 * strio.readchar -> string
1011 *
1012 * See IO#readchar.
1013 */
1014static VALUE
1015strio_readchar(VALUE self)
1016{
1017 VALUE c = rb_funcallv(self, rb_intern("getc"), 0, 0);
1018 if (NIL_P(c)) rb_eof_error();
1019 return c;
1020}
1021
1022/*
1023 * call-seq:
1024 * strio.readbyte -> fixnum
1025 *
1026 * See IO#readbyte.
1027 */
1028static VALUE
1029strio_readbyte(VALUE self)
1030{
1031 VALUE c = rb_funcallv(self, rb_intern("getbyte"), 0, 0);
1032 if (NIL_P(c)) rb_eof_error();
1033 return c;
1034}
1035
1036/*
1037 * call-seq:
1038 * strio.each_char {|char| block } -> strio
1039 * strio.each_char -> anEnumerator
1040 *
1041 * See IO#each_char.
1042 */
1043static VALUE
1044strio_each_char(VALUE self)
1045{
1046 VALUE c;
1047
1048 RETURN_ENUMERATOR(self, 0, 0);
1049
1050 while (!NIL_P(c = strio_getc(self))) {
1051 rb_yield(c);
1052 }
1053 return self;
1054}
1055
1056/*
1057 * call-seq:
1058 * strio.each_codepoint {|c| block } -> strio
1059 * strio.each_codepoint -> anEnumerator
1060 *
1061 * See IO#each_codepoint.
1062 */
1063static VALUE
1064strio_each_codepoint(VALUE self)
1065{
1066 struct StringIO *ptr;
1067 rb_encoding *enc;
1068 unsigned int c;
1069 int n;
1070
1071 RETURN_ENUMERATOR(self, 0, 0);
1072
1073 ptr = readable(self);
1074 enc = get_enc(ptr);
1075 while ((ptr = strio_to_read(self)) != NULL) {
1076 c = rb_enc_codepoint_len(RSTRING_PTR(ptr->string)+ptr->pos,
1077 RSTRING_END(ptr->string), &n, enc);
1078 ptr->pos += n;
1079 rb_yield(UINT2NUM(c));
1080 }
1081 return self;
1082}
1083
1084/* Boyer-Moore search: copied from regex.c */
1085static void
1086bm_init_skip(long *skip, const char *pat, long m)
1087{
1088 int c;
1089
1090 for (c = 0; c < (1 << CHAR_BIT); c++) {
1091 skip[c] = m;
1092 }
1093 while (--m) {
1094 skip[(unsigned char)*pat++] = m;
1095 }
1096}
1097
1098static long
1099bm_search(const char *little, long llen, const char *big, long blen, const long *skip)
1100{
1101 long i, j, k;
1102
1103 i = llen - 1;
1104 while (i < blen) {
1105 k = i;
1106 j = llen - 1;
1107 while (j >= 0 && big[k] == little[j]) {
1108 k--;
1109 j--;
1110 }
1111 if (j < 0) return k + 1;
1112 i += skip[(unsigned char)big[i]];
1113 }
1114 return -1;
1115}
1116
1119 long limit;
1120 unsigned int chomp: 1;
1121};
1122
1123static struct getline_arg *
1124prepare_getline_args(struct getline_arg *arg, int argc, VALUE *argv)
1125{
1126 VALUE str, lim, opts;
1127 long limit = -1;
1128
1129 argc = rb_scan_args(argc, argv, "02:", &str, &lim, &opts);
1130 switch (argc) {
1131 case 0:
1132 str = rb_rs;
1133 break;
1134
1135 case 1:
1136 if (!NIL_P(str) && !RB_TYPE_P(str, T_STRING)) {
1138 if (NIL_P(tmp)) {
1139 limit = NUM2LONG(str);
1140 str = rb_rs;
1141 }
1142 else {
1143 str = tmp;
1144 }
1145 }
1146 break;
1147
1148 case 2:
1149 if (!NIL_P(str)) StringValue(str);
1150 if (!NIL_P(lim)) limit = NUM2LONG(lim);
1151 break;
1152 }
1153 arg->rs = str;
1154 arg->limit = limit;
1155 arg->chomp = 0;
1156 if (!NIL_P(opts)) {
1157 static ID keywords[1];
1158 VALUE vchomp;
1159 if (!keywords[0]) {
1160 keywords[0] = rb_intern_const("chomp");
1161 }
1162 rb_get_kwargs(opts, keywords, 0, 1, &vchomp);
1163 arg->chomp = (vchomp != Qundef) && RTEST(vchomp);
1164 }
1165 return arg;
1166}
1167
1168static inline int
1169chomp_newline_width(const char *s, const char *e)
1170{
1171 if (e > s && *--e == '\n') {
1172 if (e > s && *--e == '\r') return 2;
1173 return 1;
1174 }
1175 return 0;
1176}
1177
1178static VALUE
1179strio_getline(struct getline_arg *arg, struct StringIO *ptr)
1180{
1181 const char *s, *e, *p;
1182 long n, limit = arg->limit;
1183 VALUE str = arg->rs;
1184 int w = 0;
1185 rb_encoding *enc = get_enc(ptr);
1186
1187 if (ptr->pos >= (n = RSTRING_LEN(ptr->string))) {
1188 return Qnil;
1189 }
1190 s = RSTRING_PTR(ptr->string);
1191 e = s + RSTRING_LEN(ptr->string);
1192 s += ptr->pos;
1193 if (limit > 0 && (size_t)limit < (size_t)(e - s)) {
1194 e = rb_enc_right_char_head(s, s + limit, e, get_enc(ptr));
1195 }
1196 if (NIL_P(str)) {
1197 if (arg->chomp) {
1198 w = chomp_newline_width(s, e);
1199 }
1200 str = strio_substr(ptr, ptr->pos, e - s - w, enc);
1201 }
1202 else if ((n = RSTRING_LEN(str)) == 0) {
1203 p = s;
1204 while (p[(p + 1 < e) && (*p == '\r') && 0] == '\n') {
1205 p += *p == '\r';
1206 if (++p == e) {
1207 return Qnil;
1208 }
1209 }
1210 s = p;
1211 while ((p = memchr(p, '\n', e - p)) && (p != e)) {
1212 if (*++p == '\n') {
1213 e = p + 1;
1214 w = (arg->chomp ? 1 : 0);
1215 break;
1216 }
1217 else if (*p == '\r' && p < e && p[1] == '\n') {
1218 e = p + 2;
1219 w = (arg->chomp ? 2 : 0);
1220 break;
1221 }
1222 }
1223 if (!w && arg->chomp) {
1224 w = chomp_newline_width(s, e);
1225 }
1226 str = strio_substr(ptr, s - RSTRING_PTR(ptr->string), e - s - w, enc);
1227 }
1228 else if (n == 1) {
1229 if ((p = memchr(s, RSTRING_PTR(str)[0], e - s)) != 0) {
1230 e = p + 1;
1231 w = (arg->chomp ? (p > s && *(p-1) == '\r') + 1 : 0);
1232 }
1233 str = strio_substr(ptr, ptr->pos, e - s - w, enc);
1234 }
1235 else {
1236 if (n < e - s) {
1237 if (e - s < 1024) {
1238 for (p = s; p + n <= e; ++p) {
1239 if (MEMCMP(p, RSTRING_PTR(str), char, n) == 0) {
1240 e = p + (arg->chomp ? 0 : n);
1241 break;
1242 }
1243 }
1244 }
1245 else {
1246 long skip[1 << CHAR_BIT], pos;
1247 p = RSTRING_PTR(str);
1248 bm_init_skip(skip, p, n);
1249 if ((pos = bm_search(p, n, s, e - s, skip)) >= 0) {
1250 e = s + pos + (arg->chomp ? 0 : n);
1251 }
1252 }
1253 }
1254 str = strio_substr(ptr, ptr->pos, e - s - w, enc);
1255 }
1256 ptr->pos = e - RSTRING_PTR(ptr->string);
1257 ptr->lineno++;
1258 return str;
1259}
1260
1261/*
1262 * call-seq:
1263 * strio.gets(sep=$/, chomp: false) -> string or nil
1264 * strio.gets(limit, chomp: false) -> string or nil
1265 * strio.gets(sep, limit, chomp: false) -> string or nil
1266 *
1267 * See IO#gets.
1268 */
1269static VALUE
1270strio_gets(int argc, VALUE *argv, VALUE self)
1271{
1272 struct getline_arg arg;
1273 VALUE str;
1274
1275 if (prepare_getline_args(&arg, argc, argv)->limit == 0) {
1276 struct StringIO *ptr = readable(self);
1277 return rb_enc_str_new(0, 0, get_enc(ptr));
1278 }
1279
1280 str = strio_getline(&arg, readable(self));
1282 return str;
1283}
1284
1285/*
1286 * call-seq:
1287 * strio.readline(sep=$/, chomp: false) -> string
1288 * strio.readline(limit, chomp: false) -> string or nil
1289 * strio.readline(sep, limit, chomp: false) -> string or nil
1290 *
1291 * See IO#readline.
1292 */
1293static VALUE
1294strio_readline(int argc, VALUE *argv, VALUE self)
1295{
1297 if (NIL_P(line)) rb_eof_error();
1298 return line;
1299}
1300
1301/*
1302 * call-seq:
1303 * strio.each(sep=$/, chomp: false) {|line| block } -> strio
1304 * strio.each(limit, chomp: false) {|line| block } -> strio
1305 * strio.each(sep, limit, chomp: false) {|line| block } -> strio
1306 * strio.each(...) -> anEnumerator
1307 *
1308 * strio.each_line(sep=$/, chomp: false) {|line| block } -> strio
1309 * strio.each_line(limit, chomp: false) {|line| block } -> strio
1310 * strio.each_line(sep, limit, chomp: false) {|line| block } -> strio
1311 * strio.each_line(...) -> anEnumerator
1312 *
1313 * See IO#each.
1314 */
1315static VALUE
1316strio_each(int argc, VALUE *argv, VALUE self)
1317{
1318 VALUE line;
1319 struct getline_arg arg;
1320
1321 StringIO(self);
1322 RETURN_ENUMERATOR(self, argc, argv);
1323
1324 if (prepare_getline_args(&arg, argc, argv)->limit == 0) {
1325 rb_raise(rb_eArgError, "invalid limit: 0 for each_line");
1326 }
1327
1328 while (!NIL_P(line = strio_getline(&arg, readable(self)))) {
1329 rb_yield(line);
1330 }
1331 return self;
1332}
1333
1334/*
1335 * call-seq:
1336 * strio.readlines(sep=$/, chomp: false) -> array
1337 * strio.readlines(limit, chomp: false) -> array
1338 * strio.readlines(sep, limit, chomp: false) -> array
1339 *
1340 * See IO#readlines.
1341 */
1342static VALUE
1343strio_readlines(int argc, VALUE *argv, VALUE self)
1344{
1345 VALUE ary, line;
1346 struct getline_arg arg;
1347
1348 StringIO(self);
1349 ary = rb_ary_new();
1350 if (prepare_getline_args(&arg, argc, argv)->limit == 0) {
1351 rb_raise(rb_eArgError, "invalid limit: 0 for readlines");
1352 }
1353
1354 while (!NIL_P(line = strio_getline(&arg, readable(self)))) {
1355 rb_ary_push(ary, line);
1356 }
1357 return ary;
1358}
1359
1360/*
1361 * call-seq:
1362 * strio.write(string, ...) -> integer
1363 * strio.syswrite(string) -> integer
1364 *
1365 * Appends the given string to the underlying buffer string.
1366 * The stream must be opened for writing. If the argument is not a
1367 * string, it will be converted to a string using <code>to_s</code>.
1368 * Returns the number of bytes written. See IO#write.
1369 */
1370static VALUE
1371strio_write_m(int argc, VALUE *argv, VALUE self)
1372{
1373 long len = 0;
1374 while (argc-- > 0) {
1375 /* StringIO can't exceed long limit */
1376 len += strio_write(self, *argv++);
1377 }
1378 return LONG2NUM(len);
1379}
1380
1381static long
1382strio_write(VALUE self, VALUE str)
1383{
1384 struct StringIO *ptr = writable(self);
1385 long len, olen;
1386 rb_encoding *enc, *enc2;
1387 rb_encoding *const ascii8bit = rb_ascii8bit_encoding();
1388 rb_encoding *usascii = 0;
1389
1390 if (!RB_TYPE_P(str, T_STRING))
1392 enc = get_enc(ptr);
1393 enc2 = rb_enc_get(str);
1394 if (enc != enc2 && enc != ascii8bit && enc != (usascii = rb_usascii_encoding())) {
1395 VALUE converted = rb_str_conv_enc(str, enc2, enc);
1396 if (converted == str && enc2 != ascii8bit && enc2 != usascii) { /* conversion failed */
1398 }
1399 str = converted;
1400 }
1401 len = RSTRING_LEN(str);
1402 if (len == 0) return 0;
1403 check_modifiable(ptr);
1404 olen = RSTRING_LEN(ptr->string);
1405 if (ptr->flags & FMODE_APPEND) {
1406 ptr->pos = olen;
1407 }
1408 if (ptr->pos == olen) {
1409 if (enc == ascii8bit || enc2 == ascii8bit) {
1410 rb_enc_str_buf_cat(ptr->string, RSTRING_PTR(str), len, enc);
1411 }
1412 else {
1413 rb_str_buf_append(ptr->string, str);
1414 }
1415 }
1416 else {
1417 strio_extend(ptr, ptr->pos, len);
1418 memmove(RSTRING_PTR(ptr->string)+ptr->pos, RSTRING_PTR(str), len);
1419 }
1421 ptr->pos += len;
1422 return len;
1423}
1424
1425/*
1426 * call-seq:
1427 * strio << obj -> strio
1428 *
1429 * See IO#<<.
1430 */
1431#define strio_addstr rb_io_addstr
1432
1433/*
1434 * call-seq:
1435 * strio.print() -> nil
1436 * strio.print(obj, ...) -> nil
1437 *
1438 * See IO#print.
1439 */
1440#define strio_print rb_io_print
1441
1442/*
1443 * call-seq:
1444 * strio.printf(format_string [, obj, ...] ) -> nil
1445 *
1446 * See IO#printf.
1447 */
1448#define strio_printf rb_io_printf
1449
1450/*
1451 * call-seq:
1452 * strio.putc(obj) -> obj
1453 *
1454 * See IO#putc.
1455 */
1456static VALUE
1457strio_putc(VALUE self, VALUE ch)
1458{
1459 struct StringIO *ptr = writable(self);
1460 VALUE str;
1461
1462 check_modifiable(ptr);
1463 if (RB_TYPE_P(ch, T_STRING)) {
1464 str = rb_str_substr(ch, 0, 1);
1465 }
1466 else {
1467 char c = NUM2CHR(ch);
1468 str = rb_str_new(&c, 1);
1469 }
1470 strio_write(self, str);
1471 return ch;
1472}
1473
1474/*
1475 * call-seq:
1476 * strio.puts(obj, ...) -> nil
1477 *
1478 * See IO#puts.
1479 */
1480#define strio_puts rb_io_puts
1481
1482/*
1483 * call-seq:
1484 * strio.read([length [, outbuf]]) -> string, outbuf, or nil
1485 *
1486 * See IO#read.
1487 */
1488static VALUE
1489strio_read(int argc, VALUE *argv, VALUE self)
1490{
1491 struct StringIO *ptr = readable(self);
1492 VALUE str = Qnil;
1493 long len;
1494 int binary = 0;
1495
1496 switch (argc) {
1497 case 2:
1498 str = argv[1];
1499 if (!NIL_P(str)) {
1502 }
1503 /* fall through */
1504 case 1:
1505 if (!NIL_P(argv[0])) {
1506 len = NUM2LONG(argv[0]);
1507 if (len < 0) {
1508 rb_raise(rb_eArgError, "negative length %ld given", len);
1509 }
1510 if (len > 0 && ptr->pos >= RSTRING_LEN(ptr->string)) {
1511 if (!NIL_P(str)) rb_str_resize(str, 0);
1512 return Qnil;
1513 }
1514 binary = 1;
1515 break;
1516 }
1517 /* fall through */
1518 case 0:
1519 len = RSTRING_LEN(ptr->string);
1520 if (len <= ptr->pos) {
1521 rb_encoding *enc = get_enc(ptr);
1522 if (NIL_P(str)) {
1523 str = rb_str_new(0, 0);
1524 }
1525 else {
1526 rb_str_resize(str, 0);
1527 }
1528 rb_enc_associate(str, enc);
1529 return str;
1530 }
1531 else {
1532 len -= ptr->pos;
1533 }
1534 break;
1535 default:
1536 rb_error_arity(argc, 0, 2);
1537 }
1538 if (NIL_P(str)) {
1539 rb_encoding *enc = binary ? rb_ascii8bit_encoding() : get_enc(ptr);
1540 str = strio_substr(ptr, ptr->pos, len, enc);
1541 }
1542 else {
1543 long rest = RSTRING_LEN(ptr->string) - ptr->pos;
1544 if (len > rest) len = rest;
1546 MEMCPY(RSTRING_PTR(str), RSTRING_PTR(ptr->string) + ptr->pos, char, len);
1547 if (binary)
1549 else
1550 rb_enc_copy(str, ptr->string);
1551 }
1552 ptr->pos += RSTRING_LEN(str);
1553 return str;
1554}
1555
1556/*
1557 * call-seq:
1558 * strio.sysread(integer[, outbuf]) -> string
1559 * strio.readpartial(integer[, outbuf]) -> string
1560 *
1561 * Similar to #read, but raises +EOFError+ at end of string instead of
1562 * returning +nil+, as well as IO#sysread does.
1563 */
1564static VALUE
1565strio_sysread(int argc, VALUE *argv, VALUE self)
1566{
1568 if (NIL_P(val)) {
1569 rb_eof_error();
1570 }
1571 return val;
1572}
1573
1574/*
1575 * call-seq:
1576 * strio.read_nonblock(integer[, outbuf [, opts]]) -> string
1577 *
1578 * Similar to #read, but raises +EOFError+ at end of string unless the
1579 * +exception: false+ option is passed in.
1580 */
1581static VALUE
1582strio_read_nonblock(int argc, VALUE *argv, VALUE self)
1583{
1584 VALUE opts = Qnil, val;
1585
1586 rb_scan_args(argc, argv, "11:", NULL, NULL, &opts);
1587
1588 if (!NIL_P(opts)) {
1589 argc--;
1590 }
1591
1592 val = strio_read(argc, argv, self);
1593 if (NIL_P(val)) {
1594 if (!NIL_P(opts) &&
1595 rb_hash_lookup2(opts, sym_exception, Qundef) == Qfalse)
1596 return Qnil;
1597 else
1598 rb_eof_error();
1599 }
1600
1601 return val;
1602}
1603
1604#define strio_syswrite rb_io_write
1605
1606static VALUE
1607strio_syswrite_nonblock(int argc, VALUE *argv, VALUE self)
1608{
1609 VALUE str;
1610
1611 rb_scan_args(argc, argv, "10:", &str, NULL);
1612 return strio_syswrite(self, str);
1613}
1614
1615#define strio_isatty strio_false
1616
1617#define strio_pid strio_nil
1618
1619#define strio_fileno strio_nil
1620
1621/*
1622 * call-seq:
1623 * strio.length -> integer
1624 * strio.size -> integer
1625 *
1626 * Returns the size of the buffer string.
1627 */
1628static VALUE
1629strio_size(VALUE self)
1630{
1631 VALUE string = StringIO(self)->string;
1632 if (NIL_P(string)) {
1633 rb_raise(rb_eIOError, "not opened");
1634 }
1635 return ULONG2NUM(RSTRING_LEN(string));
1636}
1637
1638/*
1639 * call-seq:
1640 * strio.truncate(integer) -> 0
1641 *
1642 * Truncates the buffer string to at most _integer_ bytes. The stream
1643 * must be opened for writing.
1644 */
1645static VALUE
1646strio_truncate(VALUE self, VALUE len)
1647{
1648 VALUE string = writable(self)->string;
1649 long l = NUM2LONG(len);
1650 long plen = RSTRING_LEN(string);
1651 if (l < 0) {
1652 error_inval("negative length");
1653 }
1654 rb_str_resize(string, l);
1655 if (plen < l) {
1656 MEMZERO(RSTRING_PTR(string) + plen, char, l - plen);
1657 }
1658 return len;
1659}
1660
1661/*
1662 * call-seq:
1663 * strio.external_encoding => encoding
1664 *
1665 * Returns the Encoding object that represents the encoding of the file.
1666 * If the stream is write mode and no encoding is specified, returns
1667 * +nil+.
1668 */
1669
1670static VALUE
1671strio_external_encoding(VALUE self)
1672{
1673 struct StringIO *ptr = StringIO(self);
1675}
1676
1677/*
1678 * call-seq:
1679 * strio.internal_encoding => encoding
1680 *
1681 * Returns the Encoding of the internal string if conversion is
1682 * specified. Otherwise returns +nil+.
1683 */
1684
1685static VALUE
1686strio_internal_encoding(VALUE self)
1687{
1688 return Qnil;
1689}
1690
1691/*
1692 * call-seq:
1693 * strio.set_encoding(ext_enc, [int_enc[, opt]]) => strio
1694 *
1695 * Specify the encoding of the StringIO as <i>ext_enc</i>.
1696 * Use the default external encoding if <i>ext_enc</i> is nil.
1697 * 2nd argument <i>int_enc</i> and optional hash <i>opt</i> argument
1698 * are ignored; they are for API compatibility to IO.
1699 */
1700
1701static VALUE
1702strio_set_encoding(int argc, VALUE *argv, VALUE self)
1703{
1704 rb_encoding* enc;
1705 struct StringIO *ptr = StringIO(self);
1706 VALUE ext_enc, int_enc, opt;
1707
1708 argc = rb_scan_args(argc, argv, "11:", &ext_enc, &int_enc, &opt);
1709
1710 if (NIL_P(ext_enc)) {
1712 }
1713 else {
1714 enc = rb_to_encoding(ext_enc);
1715 }
1716 ptr->enc = enc;
1717 if (WRITABLE(self)) {
1718 rb_enc_associate(ptr->string, enc);
1719 }
1720
1721 return self;
1722}
1723
1724static VALUE
1725strio_set_encoding_by_bom(VALUE self)
1726{
1727 struct StringIO *ptr = StringIO(self);
1728
1729 if (!set_encoding_by_bom(ptr)) return Qnil;
1730 return rb_enc_from_encoding(ptr->enc);
1731}
1732
1733/*
1734 * Pseudo I/O on String object, with interface corresponding to IO.
1735 *
1736 * Commonly used to simulate <code>$stdio</code> or <code>$stderr</code>
1737 *
1738 * === Examples
1739 *
1740 * require 'stringio'
1741 *
1742 * # Writing stream emulation
1743 * io = StringIO.new
1744 * io.puts "Hello World"
1745 * io.string #=> "Hello World\n"
1746 *
1747 * # Reading stream emulation
1748 * io = StringIO.new "first\nsecond\nlast\n"
1749 * io.getc #=> "f"
1750 * io.gets #=> "irst\n"
1751 * io.read #=> "second\nlast\n"
1752 */
1753void
1755{
1756#undef rb_intern
1757
1758#ifdef HAVE_RB_EXT_RACTOR_SAFE
1759 rb_ext_ractor_safe(true);
1760#endif
1761
1763
1765
1767 rb_define_alloc_func(StringIO, strio_s_allocate);
1768 rb_define_singleton_method(StringIO, "new", strio_s_new, -1);
1769 rb_define_singleton_method(StringIO, "open", strio_s_open, -1);
1770 rb_define_method(StringIO, "initialize", strio_initialize, -1);
1771 rb_define_method(StringIO, "initialize_copy", strio_copy, 1);
1772 rb_define_method(StringIO, "reopen", strio_reopen, -1);
1773
1774 rb_define_method(StringIO, "string", strio_get_string, 0);
1775 rb_define_method(StringIO, "string=", strio_set_string, 1);
1776 rb_define_method(StringIO, "lineno", strio_get_lineno, 0);
1777 rb_define_method(StringIO, "lineno=", strio_set_lineno, 1);
1778
1779
1780 /* call-seq: strio.binmode -> true */
1781 rb_define_method(StringIO, "binmode", strio_binmode, 0);
1782 rb_define_method(StringIO, "close", strio_close, 0);
1783 rb_define_method(StringIO, "close_read", strio_close_read, 0);
1784 rb_define_method(StringIO, "close_write", strio_close_write, 0);
1785 rb_define_method(StringIO, "closed?", strio_closed, 0);
1786 rb_define_method(StringIO, "closed_read?", strio_closed_read, 0);
1787 rb_define_method(StringIO, "closed_write?", strio_closed_write, 0);
1788 rb_define_method(StringIO, "eof", strio_eof, 0);
1789 rb_define_method(StringIO, "eof?", strio_eof, 0);
1790 /* call-seq: strio.fcntl */
1791 rb_define_method(StringIO, "fcntl", strio_fcntl, -1);
1792 /* call-seq: strio.flush -> strio */
1794 /* call-seq: strio.fsync -> 0 */
1796 rb_define_method(StringIO, "pos", strio_get_pos, 0);
1797 rb_define_method(StringIO, "pos=", strio_set_pos, 1);
1798 rb_define_method(StringIO, "rewind", strio_rewind, 0);
1799 rb_define_method(StringIO, "seek", strio_seek, -1);
1800 rb_define_method(StringIO, "sync", strio_get_sync, 0);
1801 /* call-seq: strio.sync = boolean -> boolean */
1804
1805 rb_define_method(StringIO, "each", strio_each, -1);
1806 rb_define_method(StringIO, "each_line", strio_each, -1);
1807 rb_define_method(StringIO, "each_byte", strio_each_byte, 0);
1808 rb_define_method(StringIO, "each_char", strio_each_char, 0);
1809 rb_define_method(StringIO, "each_codepoint", strio_each_codepoint, 0);
1810 rb_define_method(StringIO, "getc", strio_getc, 0);
1811 rb_define_method(StringIO, "ungetc", strio_ungetc, 1);
1812 rb_define_method(StringIO, "ungetbyte", strio_ungetbyte, 1);
1813 rb_define_method(StringIO, "getbyte", strio_getbyte, 0);
1814 rb_define_method(StringIO, "gets", strio_gets, -1);
1815 rb_define_method(StringIO, "readlines", strio_readlines, -1);
1816 rb_define_method(StringIO, "read", strio_read, -1);
1817
1818 rb_define_method(StringIO, "write", strio_write_m, -1);
1819 rb_define_method(StringIO, "putc", strio_putc, 1);
1820
1821 /*
1822 * call-seq:
1823 * strio.isatty -> nil
1824 * strio.tty? -> nil
1825 *
1826 */
1827 rb_define_method(StringIO, "isatty", strio_isatty, 0);
1829
1830 /* call-seq: strio.pid -> nil */
1832
1833 /* call-seq: strio.fileno -> nil */
1834 rb_define_method(StringIO, "fileno", strio_fileno, 0);
1835 rb_define_method(StringIO, "size", strio_size, 0);
1836 rb_define_method(StringIO, "length", strio_size, 0);
1837 rb_define_method(StringIO, "truncate", strio_truncate, 1);
1838
1839 rb_define_method(StringIO, "external_encoding", strio_external_encoding, 0);
1840 rb_define_method(StringIO, "internal_encoding", strio_internal_encoding, 0);
1841 rb_define_method(StringIO, "set_encoding", strio_set_encoding, -1);
1842 rb_define_method(StringIO, "set_encoding_by_bom", strio_set_encoding_by_bom, 0);
1843
1844 {
1845 VALUE mReadable = rb_define_module_under(rb_cIO, "generic_readable");
1846 rb_define_method(mReadable, "readchar", strio_readchar, 0);
1847 rb_define_method(mReadable, "readbyte", strio_readbyte, 0);
1848 rb_define_method(mReadable, "readline", strio_readline, -1);
1849 rb_define_method(mReadable, "sysread", strio_sysread, -1);
1850 rb_define_method(mReadable, "readpartial", strio_sysread, -1);
1851 rb_define_method(mReadable, "read_nonblock", strio_read_nonblock, -1);
1852 rb_include_module(StringIO, mReadable);
1853 }
1854 {
1855 VALUE mWritable = rb_define_module_under(rb_cIO, "generic_writable");
1856 rb_define_method(mWritable, "<<", strio_addstr, 1);
1857 rb_define_method(mWritable, "print", strio_print, -1);
1858 rb_define_method(mWritable, "printf", strio_printf, -1);
1859 rb_define_method(mWritable, "puts", strio_puts, -1);
1860 rb_define_method(mWritable, "syswrite", strio_syswrite, 1);
1861 rb_define_method(mWritable, "write_nonblock", strio_syswrite_nonblock, -1);
1862 rb_include_module(StringIO, mWritable);
1863 }
1864
1865 sym_exception = ID2SYM(rb_intern("exception"));
1866}
VALUE rb_ary_push(VALUE ary, VALUE item)
Definition: array.c:1301
VALUE rb_ary_new(void)
Definition: array.c:749
#define UNREACHABLE
Definition: assume.h:30
#define NUM2CHR
Definition: char.h:33
#define CHR2FIX
Definition: char.h:34
#define rb_define_method(klass, mid, func, arity)
Defines klass#mid.
Definition: cxxanyargs.hpp:653
#define rb_define_singleton_method(klass, mid, func, arity)
Defines klass.mid.
Definition: cxxanyargs.hpp:668
struct RIMemo * ptr
Definition: debug.c:88
char * strchr(char *, char)
#define rb_utf8_encindex()
Definition: encindex.h:58
VALUE rb_enc_associate(VALUE obj, rb_encoding *enc)
Definition: encoding.c:1064
rb_encoding * rb_ascii8bit_encoding(void)
Definition: encoding.c:1525
unsigned int rb_enc_codepoint_len(const char *p, const char *e, int *len_p, rb_encoding *enc)
Definition: encoding.c:1266
rb_encoding * rb_enc_from_index(int index)
Definition: encoding.c:414
rb_encoding * rb_enc_get(VALUE obj)
Definition: encoding.c:1070
void rb_enc_copy(VALUE obj1, VALUE obj2)
Definition: encoding.c:1188
rb_encoding * rb_enc_find(const char *name)
Definition: encoding.c:916
rb_encoding * rb_default_external_encoding(void)
Definition: encoding.c:1647
rb_encoding * rb_enc_check(VALUE str1, VALUE str2)
Definition: encoding.c:1089
int rb_enc_mbclen(const char *p, const char *e, rb_encoding *enc)
Definition: encoding.c:1218
rb_encoding * rb_to_encoding(VALUE enc)
Definition: encoding.c:329
rb_encoding * rb_usascii_encoding(void)
Definition: encoding.c:1549
VALUE rb_enc_from_encoding(rb_encoding *encoding)
Definition: encoding.c:188
VALUE rb_enc_associate_index(VALUE obj, int idx)
Definition: encoding.c:1036
int rb_enc_find_index(const char *name)
Definition: encoding.c:879
int rb_enc_codelen(int c, rb_encoding *enc)
Definition: encoding.c:1287
VALUE rb_mEnumerable
Definition: enum.c:27
uint8_t len
Definition: escape.c:17
char str[HTML_ESCAPE_MAX_LEN+1]
Definition: escape.c:18
#define RSTRING_LEN(string)
Definition: fbuffer.h:22
#define RSTRING_PTR(string)
Definition: fbuffer.h:19
#define memcpy(d, s, n)
Definition: ffi_common.h:55
#define PRIsVALUE
Definition: function.c:10
void rb_gc_mark(VALUE ptr)
Definition: gc.c:6112
VALUE rb_eIOError
Definition: io.c:185
VALUE rb_cIO
Definition: io.c:183
void rb_include_module(VALUE klass, VALUE module)
Definition: class.c:962
VALUE rb_define_class(const char *name, VALUE super)
Defines a top-level class.
Definition: class.c:748
VALUE rb_define_module_under(VALUE outer, const char *name)
Definition: class.c:895
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Definition: class.c:2296
int rb_block_given_p(void)
Determines if the current method is given a block.
Definition: eval.c:935
int rb_get_kwargs(VALUE keyword_hash, const ID *table, int required, int optional, VALUE *values)
Definition: class.c:2085
#define OBJ_FROZEN
Definition: fl_type.h:136
#define OBJ_FROZEN_RAW
Definition: fl_type.h:137
void rb_notimplement(void)
Definition: error.c:2960
void rb_syserr_fail(int e, const char *mesg)
Definition: error.c:3029
void rb_raise(VALUE exc, const char *fmt,...)
Definition: error.c:2917
void rb_warn(const char *fmt,...)
Definition: error.c:408
VALUE rb_eArgError
Definition: error.c:1058
VALUE rb_ensure(VALUE(*b_proc)(VALUE), VALUE data1, VALUE(*e_proc)(VALUE), VALUE data2)
An equivalent to ensure clause.
Definition: eval.c:1148
VALUE rb_convert_type(VALUE, int, const char *, const char *)
Converts an object into another type.
Definition: object.c:2930
VALUE rb_cObject
Object class.
Definition: object.c:49
VALUE rb_class_new_instance_kw(int, const VALUE *, VALUE, int)
Definition: object.c:1929
VALUE rb_check_to_integer(VALUE, const char *)
Tries to convert val into Integer.
Definition: object.c:3029
void skip(file *in, unsigned n)
Definition: gzappend.c:202
VALUE rb_hash_lookup2(VALUE hash, VALUE key, VALUE def)
Definition: hash.c:2059
VALUE rb_hash_aref(VALUE hash, VALUE key)
Definition: hash.c:2046
VALUE rb_str_conv_enc(VALUE str, rb_encoding *from, rb_encoding *to)
Definition: string.c:1100
#define rb_enc_mbcput(c, buf, enc)
Definition: encoding.h:208
VALUE rb_enc_uint_chr(unsigned int code, rb_encoding *enc)
Definition: numeric.c:3391
VALUE rb_enc_str_new(const char *, long, rb_encoding *)
Definition: string.c:857
#define ENCODING_MAXNAMELEN
Definition: encoding.h:53
VALUE rb_enc_str_buf_cat(VALUE str, const char *ptr, long len, rb_encoding *enc)
Definition: string.c:3072
#define rb_enc_right_char_head(s, p, e, enc)
Definition: encoding.h:214
VALUE rb_funcallv_kw(VALUE, ID, int, const VALUE *, int)
Definition: vm_eval.c:1030
VALUE rb_funcall(VALUE, ID, int,...)
Calls a method.
Definition: vm_eval.c:1077
VALUE rb_call_super(int, const VALUE *)
Definition: vm_eval.c:298
#define RETURN_ENUMERATOR(obj, argc, argv)
Definition: enumerator.h:74
void rb_error_arity(int, int, int)
void rb_ext_ractor_safe(bool flag)
Definition: load.c:1058
void rb_lastline_set(VALUE)
Definition: vm.c:1562
VALUE rb_str_resize(VALUE, long)
Definition: string.c:2859
#define rb_str_new(str, len)
Definition: string.h:213
void rb_str_set_len(VALUE, long)
Definition: string.c:2842
VALUE rb_str_substr(VALUE, long, long)
Definition: string.c:2734
void rb_str_modify(VALUE)
Definition: string.c:2262
VALUE rb_check_string_type(VALUE)
Definition: string.c:2462
VALUE rb_str_subseq(VALUE, long, long)
Definition: string.c:2624
void rb_str_modify_expand(VALUE, long)
Definition: string.c:2270
VALUE rb_str_buf_append(VALUE, VALUE)
Definition: string.c:3103
VALUE rb_obj_as_string(VALUE)
Definition: string.c:1529
#define rb_str_new_cstr(str)
Definition: string.h:219
void rb_define_alloc_func(VALUE, rb_alloc_func_t)
#define ID2SYM
Definition: symbol.h:44
ID rb_intern(const char *)
Definition: symbol.c:785
#define CONST_ID
Definition: symbol.h:47
void rb_define_const(VALUE, const char *, VALUE)
Definition: variable.c:3150
#define FMODE_READABLE
Definition: io.h:105
int rb_io_modestr_fmode(const char *modestr)
Definition: io.c:5580
#define FMODE_SETENC_BY_BOM
Definition: io.h:119
#define FMODE_READWRITE
Definition: io.h:107
int rb_io_extract_encoding_option(VALUE opt, rb_encoding **enc_p, rb_encoding **enc2_p, int *fmode_p)
Definition: io.c:5862
int rb_io_oflags_fmode(int oflags)
Definition: io.c:5637
struct rb_io_enc_t rb_io_enc_t
Definition: io.h:101
VALUE rb_io_taint_check(VALUE)
Definition: io.c:760
#define FMODE_WRITABLE
Definition: io.h:106
#define FMODE_APPEND
Definition: io.h:112
#define FMODE_TRUNC
Definition: io.h:116
void rb_eof_error(void)
Definition: io.c:754
void * memmove(void *, const void *, size_t)
Definition: memmove.c:7
#define NUM2INT
Definition: int.h:44
#define UINT2NUM
Definition: int.h:46
#define rb_funcallv(...)
Definition: internal.h:77
#define fmode
typedef long(ZCALLBACK *tell_file_func) OF((voidpf opaque
voidpf uLong offset
Definition: ioapi.h:144
const char int mode
Definition: ioapi.h:137
voidpf void * buf
Definition: ioapi.h:138
VALUE rb_yield(VALUE)
Definition: vm_eval.c:1341
#define CHAR_BIT
Definition: limits.h:44
#define LONG_MAX
Definition: limits.h:36
#define INT2FIX
Definition: long.h:48
#define ULONG2NUM
Definition: long.h:60
#define LONG2NUM
Definition: long.h:50
#define NUM2LONG
Definition: long.h:51
#define MEMCPY(p1, p2, type, n)
Definition: memory.h:129
#define MEMCMP(p1, p2, type, n)
Definition: memory.h:131
#define MEMZERO(p, type, n)
Definition: memory.h:128
#define RB_GC_GUARD(v)
Definition: memory.h:91
#define RBASIC(obj)
Definition: rbasic.h:34
#define DATA_PTR(obj)
Definition: rdata.h:56
#define NULL
Definition: regenc.h:69
#define SafeStringValue(v)
Definition: rstring.h:53
#define StringValue(v)
Definition: rstring.h:50
#define RSTRING_GETMEM(str, ptrvar, lenvar)
Definition: rstring.h:211
#define StringValueCStr(v)
Definition: rstring.h:52
#define TypedData_Wrap_Struct(klass, data_type, sval)
Definition: rtypeddata.h:101
@ RUBY_TYPED_FREE_IMMEDIATELY
Definition: rtypeddata.h:62
int argc
Definition: ruby.c:240
char ** argv
Definition: ruby.c:241
#define RB_INTEGER_TYPE_P(obj)
Definition: ruby_missing.h:15
#define RB_PASS_CALLED_KEYWORDS
Definition: scan_args.h:48
#define Qundef
#define Qtrue
#define RTEST
#define Qnil
#define Qfalse
#define NIL_P
size_t strlen(const char *)
#define rb_rs
Definition: string.c:8464
#define CLOSED(strio)
Definition: stringio.c:214
#define STRIO_WRITABLE
Definition: stringio.c:208
void Init_stringio(void)
Definition: stringio.c:1754
#define error_inval(msg)
Definition: stringio.c:124
#define strio_isatty
Definition: stringio.c:1615
#define strio_puts
Definition: stringio.c:1480
#define strio_print
Definition: stringio.c:1440
#define rb_io_extract_modeenc
Definition: stringio.c:36
#define strio_set_sync
Definition: stringio.c:818
#define STRIO_READWRITE
Definition: stringio.c:209
char strio_flags_check[(STRIO_READABLE/FMODE_READABLE==STRIO_WRITABLE/FMODE_WRITABLE) *2 - 1]
Definition: stringio.c:210
#define check_strio(self)
Definition: stringio.c:172
#define strio_fsync
Definition: stringio.c:699
#define STRINGIO_VERSION
Definition: stringio.c:15
#define STRIO_READABLE
Definition: stringio.c:207
#define strio_flush
Definition: stringio.c:697
#define READABLE(strio)
Definition: stringio.c:215
#define strio_addstr
Definition: stringio.c:1431
#define strio_syswrite
Definition: stringio.c:1604
#define strio_pid
Definition: stringio.c:1617
#define StringIO(obj)
Definition: stringio.c:205
#define strio_printf
Definition: stringio.c:1448
#define strio_tell
Definition: stringio.c:820
#define strio_fcntl
Definition: stringio.c:695
#define WRITABLE(strio)
Definition: stringio.c:216
#define strio_fileno
Definition: stringio.c:1619
#define get_enc(ptr)
Definition: stringio.c:125
VALUE flags
Definition: debug.c:33
long lineno
Definition: stringio.c:114
int flags
Definition: stringio.c:115
VALUE string
Definition: stringio.c:111
rb_encoding * enc
Definition: stringio.c:112
int count
Definition: stringio.c:116
long pos
Definition: stringio.c:113
unsigned int chomp
Definition: stringio.c:1120
VALUE rs
Definition: stringio.c:1118
long limit
Definition: stringio.c:1119
#define ALLOC(size)
Definition: unzip.c:112
unsigned long VALUE
Definition: value.h:38
unsigned long ID
Definition: value.h:39
#define T_STRING
Definition: value_type.h:77
#define T_DATA
Definition: value_type.h:59
#define xfree
Definition: xmalloc.h:49