ed-precompiled_stringio 3.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,2051 @@
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
+ static const char *const
16
+ STRINGIO_VERSION = "3.1.8";
17
+
18
+ #include <stdbool.h>
19
+
20
+ #include "ruby.h"
21
+ #include "ruby/io.h"
22
+ #include "ruby/encoding.h"
23
+ #include "ruby/version.h"
24
+ #if defined(HAVE_FCNTL_H) || defined(_WIN32)
25
+ #include <fcntl.h>
26
+ #elif defined(HAVE_SYS_FCNTL_H)
27
+ #include <sys/fcntl.h>
28
+ #endif
29
+
30
+ #ifndef RB_INTEGER_TYPE_P
31
+ # define RB_INTEGER_TYPE_P(c) (FIXNUM_P(c) || RB_TYPE_P(c, T_BIGNUM))
32
+ #endif
33
+
34
+ #ifndef RB_PASS_CALLED_KEYWORDS
35
+ # define rb_funcallv_kw(recv, mid, arg, argv, kw_splat) rb_funcallv(recv, mid, arg, argv)
36
+ # define rb_class_new_instance_kw(argc, argv, klass, kw_splat) rb_class_new_instance(argc, argv, klass)
37
+ #endif
38
+
39
+ static inline bool
40
+ str_chilled_p(VALUE str)
41
+ {
42
+ #if (RUBY_API_VERSION_MAJOR == 3 && RUBY_API_VERSION_MINOR >= 4) || RUBY_API_VERSION_MAJOR >= 4
43
+ // Do not attempt to modify chilled strings on Ruby 3.4+
44
+ // RUBY_FL_USER2 == STR_CHILLED_LITERAL
45
+ // RUBY_FL_USER3 == STR_CHILLED_SYMBOL_TO_S
46
+ return FL_TEST_RAW(str, RUBY_FL_USER2 | RUBY_FL_USER3);
47
+ #else
48
+ return false;
49
+ #endif
50
+ }
51
+
52
+ #ifndef HAVE_TYPE_RB_IO_MODE_T
53
+ typedef int rb_io_mode_t;
54
+ #endif
55
+
56
+ struct StringIO {
57
+ VALUE string;
58
+ rb_encoding *enc;
59
+ long pos;
60
+ long lineno;
61
+ rb_io_mode_t flags;
62
+ int count;
63
+ };
64
+
65
+ static VALUE strio_init(int, VALUE *, struct StringIO *, VALUE);
66
+ static VALUE strio_unget_bytes(struct StringIO *, const char *, long);
67
+ static long strio_write(VALUE self, VALUE str);
68
+
69
+ #define IS_STRIO(obj) (rb_typeddata_is_kind_of((obj), &strio_data_type))
70
+ #define error_inval(msg) (rb_syserr_fail(EINVAL, msg))
71
+ #define get_enc(ptr) ((ptr)->enc ? (ptr)->enc : !NIL_P((ptr)->string) ? rb_enc_get((ptr)->string) : NULL)
72
+
73
+ static bool
74
+ readonly_string_p(VALUE string)
75
+ {
76
+ return OBJ_FROZEN_RAW(string);
77
+ }
78
+
79
+ static struct StringIO *
80
+ strio_alloc(void)
81
+ {
82
+ struct StringIO *ptr = ALLOC(struct StringIO);
83
+ ptr->string = Qnil;
84
+ ptr->pos = 0;
85
+ ptr->lineno = 0;
86
+ ptr->flags = 0;
87
+ ptr->count = 1;
88
+ return ptr;
89
+ }
90
+
91
+ static void
92
+ strio_mark(void *p)
93
+ {
94
+ struct StringIO *ptr = p;
95
+
96
+ rb_gc_mark(ptr->string);
97
+ }
98
+
99
+ static void
100
+ strio_free(void *p)
101
+ {
102
+ struct StringIO *ptr = p;
103
+ if (--ptr->count <= 0) {
104
+ xfree(ptr);
105
+ }
106
+ }
107
+
108
+ static size_t
109
+ strio_memsize(const void *p)
110
+ {
111
+ return sizeof(struct StringIO);
112
+ }
113
+
114
+ static const rb_data_type_t strio_data_type = {
115
+ "strio",
116
+ {
117
+ strio_mark,
118
+ strio_free,
119
+ strio_memsize,
120
+ },
121
+ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED
122
+ };
123
+
124
+ #define check_strio(self) ((struct StringIO*)rb_check_typeddata((self), &strio_data_type))
125
+
126
+ static struct StringIO*
127
+ get_strio(VALUE self)
128
+ {
129
+ struct StringIO *ptr = check_strio(rb_io_taint_check(self));
130
+
131
+ if (!ptr) {
132
+ rb_raise(rb_eIOError, "uninitialized stream");
133
+ }
134
+ return ptr;
135
+ }
136
+
137
+ static VALUE
138
+ enc_subseq(VALUE str, long pos, long len, rb_encoding *enc)
139
+ {
140
+ str = rb_str_subseq(str, pos, len);
141
+ rb_enc_associate(str, enc);
142
+ return str;
143
+ }
144
+
145
+ static VALUE
146
+ strio_substr(struct StringIO *ptr, long pos, long len, rb_encoding *enc)
147
+ {
148
+ VALUE str = ptr->string;
149
+ long rlen = RSTRING_LEN(str) - pos;
150
+
151
+ if (len > rlen) len = rlen;
152
+ if (len < 0) len = 0;
153
+ if (len == 0) return rb_enc_str_new(0, 0, enc);
154
+ return enc_subseq(str, pos, len, enc);
155
+ }
156
+
157
+ #define StringIO(obj) get_strio(obj)
158
+
159
+ #define STRIO_READABLE FL_USER4
160
+ #define STRIO_WRITABLE FL_USER5
161
+ #define STRIO_READWRITE (STRIO_READABLE|STRIO_WRITABLE)
162
+ typedef char strio_flags_check[(STRIO_READABLE/FMODE_READABLE == STRIO_WRITABLE/FMODE_WRITABLE) * 2 - 1];
163
+ #define STRIO_MODE_SET_P(strio, mode) \
164
+ ((RBASIC(strio)->flags & STRIO_##mode) && \
165
+ ((struct StringIO*)DATA_PTR(strio))->flags & FMODE_##mode)
166
+ #define CLOSED(strio) (!STRIO_MODE_SET_P(strio, READWRITE))
167
+ #define READABLE(strio) STRIO_MODE_SET_P(strio, READABLE)
168
+ #define WRITABLE(strio) STRIO_MODE_SET_P(strio, WRITABLE)
169
+
170
+ static VALUE sym_exception;
171
+
172
+ static struct StringIO*
173
+ readable(VALUE strio)
174
+ {
175
+ struct StringIO *ptr = StringIO(strio);
176
+ if (!READABLE(strio)) {
177
+ rb_raise(rb_eIOError, "not opened for reading");
178
+ }
179
+ return ptr;
180
+ }
181
+
182
+ static struct StringIO*
183
+ writable(VALUE strio)
184
+ {
185
+ struct StringIO *ptr = StringIO(strio);
186
+ if (!WRITABLE(strio)) {
187
+ rb_raise(rb_eIOError, "not opened for writing");
188
+ }
189
+ return ptr;
190
+ }
191
+
192
+ static void
193
+ check_modifiable(struct StringIO *ptr)
194
+ {
195
+ if (NIL_P(ptr->string)) {
196
+ /* Null device StringIO */
197
+ }
198
+ else if (OBJ_FROZEN_RAW(ptr->string)) {
199
+ rb_raise(rb_eIOError, "not modifiable string");
200
+ }
201
+ else {
202
+ rb_str_modify(ptr->string);
203
+ }
204
+ }
205
+
206
+ static inline bool
207
+ outside_p(struct StringIO *ptr, long pos)
208
+ {
209
+ return NIL_P(ptr->string) || pos >= RSTRING_LEN(ptr->string);
210
+ }
211
+
212
+ static inline bool
213
+ eos_p(struct StringIO *ptr)
214
+ {
215
+ return outside_p(ptr, ptr->pos);
216
+ }
217
+
218
+ static VALUE
219
+ strio_s_allocate(VALUE klass)
220
+ {
221
+ return TypedData_Wrap_Struct(klass, &strio_data_type, 0);
222
+ }
223
+
224
+ /*
225
+ * call-seq:
226
+ * StringIO.new(string = '', mode = 'r+') -> new_stringio
227
+ *
228
+ * Note that +mode+ defaults to <tt>'r'</tt> if +string+ is frozen.
229
+ *
230
+ * Returns a new \StringIO instance formed from +string+ and +mode+;
231
+ * see {Access Modes}[rdoc-ref:File@Access+Modes]:
232
+ *
233
+ * strio = StringIO.new # => #<StringIO>
234
+ * strio.close
235
+ *
236
+ * The instance should be closed when no longer needed.
237
+ *
238
+ * Related: StringIO.open (accepts block; closes automatically).
239
+ */
240
+ static VALUE
241
+ strio_initialize(int argc, VALUE *argv, VALUE self)
242
+ {
243
+ struct StringIO *ptr = check_strio(self);
244
+
245
+ if (!ptr) {
246
+ DATA_PTR(self) = ptr = strio_alloc();
247
+ }
248
+ rb_call_super(0, 0);
249
+ return strio_init(argc, argv, ptr, self);
250
+ }
251
+
252
+ static int
253
+ detect_bom(VALUE str, int *bomlen)
254
+ {
255
+ const char *p;
256
+ long len;
257
+
258
+ RSTRING_GETMEM(str, p, len);
259
+ if (len < 1) return 0;
260
+ switch ((unsigned char)p[0]) {
261
+ case 0xEF:
262
+ if (len < 2) break;
263
+ if ((unsigned char)p[1] == 0xBB && len > 2) {
264
+ if ((unsigned char)p[2] == 0xBF) {
265
+ *bomlen = 3;
266
+ return rb_utf8_encindex();
267
+ }
268
+ }
269
+ break;
270
+
271
+ case 0xFE:
272
+ if (len < 2) break;
273
+ if ((unsigned char)p[1] == 0xFF) {
274
+ *bomlen = 2;
275
+ return rb_enc_find_index("UTF-16BE");
276
+ }
277
+ break;
278
+
279
+ case 0xFF:
280
+ if (len < 2) break;
281
+ if ((unsigned char)p[1] == 0xFE) {
282
+ if (len >= 4 && (unsigned char)p[2] == 0 && (unsigned char)p[3] == 0) {
283
+ *bomlen = 4;
284
+ return rb_enc_find_index("UTF-32LE");
285
+ }
286
+ *bomlen = 2;
287
+ return rb_enc_find_index("UTF-16LE");
288
+ }
289
+ break;
290
+
291
+ case 0:
292
+ if (len < 4) break;
293
+ if ((unsigned char)p[1] == 0 && (unsigned char)p[2] == 0xFE && (unsigned char)p[3] == 0xFF) {
294
+ *bomlen = 4;
295
+ return rb_enc_find_index("UTF-32BE");
296
+ }
297
+ break;
298
+ }
299
+ return 0;
300
+ }
301
+
302
+ static rb_encoding *
303
+ set_encoding_by_bom(struct StringIO *ptr)
304
+ {
305
+ int bomlen, idx = detect_bom(ptr->string, &bomlen);
306
+ rb_encoding *extenc = NULL;
307
+
308
+ if (idx) {
309
+ extenc = rb_enc_from_index(idx);
310
+ ptr->pos = bomlen;
311
+ if (ptr->flags & FMODE_WRITABLE) {
312
+ rb_enc_associate_index(ptr->string, idx);
313
+ }
314
+ }
315
+ ptr->enc = extenc;
316
+ return extenc;
317
+ }
318
+
319
+ static VALUE
320
+ strio_init(int argc, VALUE *argv, struct StringIO *ptr, VALUE self)
321
+ {
322
+ VALUE string, vmode, opt;
323
+ int oflags;
324
+ rb_io_enc_t convconfig;
325
+
326
+ argc = rb_scan_args(argc, argv, "02:", &string, &vmode, &opt);
327
+ rb_io_extract_modeenc(&vmode, 0, opt, &oflags, &ptr->flags, &convconfig);
328
+ if (!NIL_P(string)) {
329
+ StringValue(string);
330
+ }
331
+ else if (!argc) {
332
+ string = rb_enc_str_new("", 0, rb_default_external_encoding());
333
+ }
334
+
335
+ if (!NIL_P(string) && readonly_string_p(string)) {
336
+ if (ptr->flags & FMODE_WRITABLE) {
337
+ rb_syserr_fail(EACCES, 0);
338
+ }
339
+ }
340
+ else {
341
+ if (NIL_P(vmode)) {
342
+ ptr->flags |= FMODE_WRITABLE;
343
+ }
344
+ }
345
+ if (!NIL_P(string) && (ptr->flags & FMODE_TRUNC)) {
346
+ rb_str_resize(string, 0);
347
+ }
348
+ RB_OBJ_WRITE(self, &ptr->string, string);
349
+ if (argc == 1 && !NIL_P(string)) {
350
+ ptr->enc = rb_enc_get(string);
351
+ }
352
+ else {
353
+ ptr->enc = convconfig.enc;
354
+ }
355
+ ptr->pos = 0;
356
+ ptr->lineno = 0;
357
+ if (ptr->flags & FMODE_SETENC_BY_BOM) set_encoding_by_bom(ptr);
358
+ RBASIC(self)->flags |= (ptr->flags & FMODE_READWRITE) * (STRIO_READABLE / FMODE_READABLE);
359
+ return self;
360
+ }
361
+
362
+ static VALUE
363
+ strio_finalize(VALUE self)
364
+ {
365
+ struct StringIO *ptr = StringIO(self);
366
+ RB_OBJ_WRITE(self, &ptr->string, Qnil);
367
+ ptr->flags &= ~FMODE_READWRITE;
368
+ return self;
369
+ }
370
+
371
+ /*
372
+ * call-seq:
373
+ * StringIO.open(string = '', mode = 'r+') {|strio| ... }
374
+ *
375
+ * Note that +mode+ defaults to <tt>'r'</tt> if +string+ is frozen.
376
+ *
377
+ * Creates a new \StringIO instance formed from +string+ and +mode+;
378
+ * see {Access Modes}[rdoc-ref:File@Access+Modes].
379
+ *
380
+ * With no block, returns the new instance:
381
+ *
382
+ * strio = StringIO.open # => #<StringIO>
383
+ *
384
+ * With a block, calls the block with the new instance
385
+ * and returns the block's value;
386
+ * closes the instance on block exit.
387
+ *
388
+ * StringIO.open {|strio| p strio }
389
+ * # => #<StringIO>
390
+ *
391
+ * Related: StringIO.new.
392
+ */
393
+ static VALUE
394
+ strio_s_open(int argc, VALUE *argv, VALUE klass)
395
+ {
396
+ VALUE obj = rb_class_new_instance_kw(argc, argv, klass, RB_PASS_CALLED_KEYWORDS);
397
+ if (!rb_block_given_p()) return obj;
398
+ return rb_ensure(rb_yield, obj, strio_finalize, obj);
399
+ }
400
+
401
+ /* :nodoc: */
402
+ static VALUE
403
+ strio_s_new(int argc, VALUE *argv, VALUE klass)
404
+ {
405
+ if (rb_block_given_p()) {
406
+ VALUE cname = rb_obj_as_string(klass);
407
+
408
+ rb_warn("%"PRIsVALUE"::new() does not take block; use %"PRIsVALUE"::open() instead",
409
+ cname, cname);
410
+ }
411
+ return rb_class_new_instance_kw(argc, argv, klass, RB_PASS_CALLED_KEYWORDS);
412
+ }
413
+
414
+ /*
415
+ * Returns +false+. Just for compatibility to IO.
416
+ */
417
+ static VALUE
418
+ strio_false(VALUE self)
419
+ {
420
+ StringIO(self);
421
+ return Qfalse;
422
+ }
423
+
424
+ /*
425
+ * Returns +nil+. Just for compatibility to IO.
426
+ */
427
+ static VALUE
428
+ strio_nil(VALUE self)
429
+ {
430
+ StringIO(self);
431
+ return Qnil;
432
+ }
433
+
434
+ /*
435
+ * Returns an object itself. Just for compatibility to IO.
436
+ */
437
+ static VALUE
438
+ strio_self(VALUE self)
439
+ {
440
+ StringIO(self);
441
+ return self;
442
+ }
443
+
444
+ /*
445
+ * Returns 0. Just for compatibility to IO.
446
+ */
447
+ static VALUE
448
+ strio_0(VALUE self)
449
+ {
450
+ StringIO(self);
451
+ return INT2FIX(0);
452
+ }
453
+
454
+ /*
455
+ * Returns the argument unchanged. Just for compatibility to IO.
456
+ */
457
+ static VALUE
458
+ strio_first(VALUE self, VALUE arg)
459
+ {
460
+ StringIO(self);
461
+ return arg;
462
+ }
463
+
464
+ /*
465
+ * Raises NotImplementedError.
466
+ */
467
+ static VALUE
468
+ strio_unimpl(int argc, VALUE *argv, VALUE self)
469
+ {
470
+ StringIO(self);
471
+ rb_notimplement();
472
+
473
+ UNREACHABLE;
474
+ }
475
+
476
+ /*
477
+ * call-seq:
478
+ * string -> string
479
+ *
480
+ * Returns underlying string:
481
+ *
482
+ * StringIO.open('foo') do |strio|
483
+ * p strio.string
484
+ * strio.string = 'bar'
485
+ * p strio.string
486
+ * end
487
+ *
488
+ * Output:
489
+ *
490
+ * "foo"
491
+ * "bar"
492
+ *
493
+ * Related: StringIO#string= (assigns the underlying string).
494
+ */
495
+ static VALUE
496
+ strio_get_string(VALUE self)
497
+ {
498
+ return StringIO(self)->string;
499
+ }
500
+
501
+ /*
502
+ * call-seq:
503
+ * string = other_string -> other_string
504
+ *
505
+ * Assigns the underlying string as +other_string+, and sets position to zero;
506
+ * returns +other_string+:
507
+ *
508
+ * StringIO.open('foo') do |strio|
509
+ * p strio.string
510
+ * strio.string = 'bar'
511
+ * p strio.string
512
+ * end
513
+ *
514
+ * Output:
515
+ *
516
+ * "foo"
517
+ * "bar"
518
+ *
519
+ * Related: StringIO#string (returns the underlying string).
520
+ */
521
+ static VALUE
522
+ strio_set_string(VALUE self, VALUE string)
523
+ {
524
+ struct StringIO *ptr = StringIO(self);
525
+
526
+ rb_io_taint_check(self);
527
+ ptr->flags &= ~FMODE_READWRITE;
528
+ StringValue(string);
529
+ ptr->flags = readonly_string_p(string) ? FMODE_READABLE : FMODE_READWRITE;
530
+ ptr->pos = 0;
531
+ ptr->lineno = 0;
532
+ RB_OBJ_WRITE(self, &ptr->string, string);
533
+ return string;
534
+ }
535
+
536
+ /*
537
+ * call-seq:
538
+ * close -> nil
539
+ *
540
+ * Closes +self+ for both reading and writing.
541
+ *
542
+ * Raises IOError if reading or writing is attempted.
543
+ *
544
+ * Related: StringIO#close_read, StringIO#close_write.
545
+ */
546
+ static VALUE
547
+ strio_close(VALUE self)
548
+ {
549
+ StringIO(self);
550
+ RBASIC(self)->flags &= ~STRIO_READWRITE;
551
+ return Qnil;
552
+ }
553
+
554
+ /*
555
+ * call-seq:
556
+ * close_read -> nil
557
+ *
558
+ * Closes +self+ for reading; closed-write setting remains unchanged.
559
+ *
560
+ * Raises IOError if reading is attempted.
561
+ *
562
+ * Related: StringIO#close, StringIO#close_write.
563
+ */
564
+ static VALUE
565
+ strio_close_read(VALUE self)
566
+ {
567
+ struct StringIO *ptr = StringIO(self);
568
+ if (!(ptr->flags & FMODE_READABLE)) {
569
+ rb_raise(rb_eIOError, "closing non-duplex IO for reading");
570
+ }
571
+ RBASIC(self)->flags &= ~STRIO_READABLE;
572
+ return Qnil;
573
+ }
574
+
575
+ /*
576
+ * call-seq:
577
+ * close_write -> nil
578
+ *
579
+ * Closes +self+ for writing; closed-read setting remains unchanged.
580
+ *
581
+ * Raises IOError if writing is attempted.
582
+ *
583
+ * Related: StringIO#close, StringIO#close_read.
584
+ */
585
+ static VALUE
586
+ strio_close_write(VALUE self)
587
+ {
588
+ struct StringIO *ptr = StringIO(self);
589
+ if (!(ptr->flags & FMODE_WRITABLE)) {
590
+ rb_raise(rb_eIOError, "closing non-duplex IO for writing");
591
+ }
592
+ RBASIC(self)->flags &= ~STRIO_WRITABLE;
593
+ return Qnil;
594
+ }
595
+
596
+ /*
597
+ * call-seq:
598
+ * closed? -> true or false
599
+ *
600
+ * Returns +true+ if +self+ is closed for both reading and writing,
601
+ * +false+ otherwise.
602
+ */
603
+ static VALUE
604
+ strio_closed(VALUE self)
605
+ {
606
+ StringIO(self);
607
+ if (!CLOSED(self)) return Qfalse;
608
+ return Qtrue;
609
+ }
610
+
611
+ /*
612
+ * call-seq:
613
+ * closed_read? -> true or false
614
+ *
615
+ * Returns +true+ if +self+ is closed for reading, +false+ otherwise.
616
+ */
617
+ static VALUE
618
+ strio_closed_read(VALUE self)
619
+ {
620
+ StringIO(self);
621
+ if (READABLE(self)) return Qfalse;
622
+ return Qtrue;
623
+ }
624
+
625
+ /*
626
+ * call-seq:
627
+ * closed_write? -> true or false
628
+ *
629
+ * Returns +true+ if +self+ is closed for writing, +false+ otherwise.
630
+ */
631
+ static VALUE
632
+ strio_closed_write(VALUE self)
633
+ {
634
+ StringIO(self);
635
+ if (WRITABLE(self)) return Qfalse;
636
+ return Qtrue;
637
+ }
638
+
639
+ static struct StringIO *
640
+ strio_to_read(VALUE self)
641
+ {
642
+ struct StringIO *ptr = readable(self);
643
+ if (eos_p(ptr)) return NULL;
644
+ return ptr;
645
+ }
646
+
647
+ /*
648
+ * call-seq:
649
+ * eof? -> true or false
650
+ *
651
+ * Returns +true+ if positioned at end-of-stream, +false+ otherwise;
652
+ * see {Position}[rdoc-ref:IO@Position].
653
+ *
654
+ * Raises IOError if the stream is not opened for reading.
655
+ */
656
+ static VALUE
657
+ strio_eof(VALUE self)
658
+ {
659
+ if (strio_to_read(self)) return Qfalse;
660
+ return Qtrue;
661
+ }
662
+
663
+ /* :nodoc: */
664
+ static VALUE
665
+ strio_copy(VALUE copy, VALUE orig)
666
+ {
667
+ struct StringIO *ptr, *old_ptr;
668
+ VALUE old_string = Qundef;
669
+
670
+ orig = rb_convert_type(orig, T_DATA, "StringIO", "to_strio");
671
+ if (copy == orig) return copy;
672
+ ptr = StringIO(orig);
673
+ old_ptr = check_strio(copy);
674
+ if (old_ptr) {
675
+ old_string = old_ptr->string;
676
+ strio_free(old_ptr);
677
+ }
678
+ DATA_PTR(copy) = ptr;
679
+ RB_OBJ_WRITTEN(copy, old_string, ptr->string);
680
+ RBASIC(copy)->flags &= ~STRIO_READWRITE;
681
+ RBASIC(copy)->flags |= RBASIC(orig)->flags & STRIO_READWRITE;
682
+ ++ptr->count;
683
+ return copy;
684
+ }
685
+
686
+ /*
687
+ * call-seq:
688
+ * lineno -> current_line_number
689
+ *
690
+ * Returns the current line number in +self+;
691
+ * see {Line Number}[rdoc-ref:IO@Line+Number].
692
+ */
693
+ static VALUE
694
+ strio_get_lineno(VALUE self)
695
+ {
696
+ return LONG2NUM(StringIO(self)->lineno);
697
+ }
698
+
699
+ /*
700
+ * call-seq:
701
+ * lineno = new_line_number -> new_line_number
702
+ *
703
+ * Sets the current line number in +self+ to the given +new_line_number+;
704
+ * see {Line Number}[rdoc-ref:IO@Line+Number].
705
+ */
706
+ static VALUE
707
+ strio_set_lineno(VALUE self, VALUE lineno)
708
+ {
709
+ StringIO(self)->lineno = NUM2LONG(lineno);
710
+ return lineno;
711
+ }
712
+
713
+ /*
714
+ * call-seq:
715
+ * binmode -> self
716
+ *
717
+ * Sets the data mode in +self+ to binary mode;
718
+ * see {Data Mode}[rdoc-ref:File@Data+Mode].
719
+ *
720
+ */
721
+ static VALUE
722
+ strio_binmode(VALUE self)
723
+ {
724
+ struct StringIO *ptr = StringIO(self);
725
+ rb_encoding *enc = rb_ascii8bit_encoding();
726
+
727
+ ptr->enc = enc;
728
+ if (WRITABLE(self)) {
729
+ rb_enc_associate(ptr->string, enc);
730
+ }
731
+ return self;
732
+ }
733
+
734
+ #define strio_fcntl strio_unimpl
735
+
736
+ #define strio_flush strio_self
737
+
738
+ #define strio_fsync strio_0
739
+
740
+ /*
741
+ * call-seq:
742
+ * reopen(other, mode = 'r+') -> self
743
+ *
744
+ * Reinitializes the stream with the given +other+ (string or StringIO) and +mode+;
745
+ * see IO.new:
746
+ *
747
+ * StringIO.open('foo') do |strio|
748
+ * p strio.string
749
+ * strio.reopen('bar')
750
+ * p strio.string
751
+ * other_strio = StringIO.new('baz')
752
+ * strio.reopen(other_strio)
753
+ * p strio.string
754
+ * other_strio.close
755
+ * end
756
+ *
757
+ * Output:
758
+ *
759
+ * "foo"
760
+ * "bar"
761
+ * "baz"
762
+ *
763
+ */
764
+ static VALUE
765
+ strio_reopen(int argc, VALUE *argv, VALUE self)
766
+ {
767
+ rb_io_taint_check(self);
768
+ if (argc == 1 && !RB_TYPE_P(*argv, T_STRING)) {
769
+ return strio_copy(self, *argv);
770
+ }
771
+ return strio_init(argc, argv, StringIO(self), self);
772
+ }
773
+
774
+ /*
775
+ * call-seq:
776
+ * pos -> stream_position
777
+ *
778
+ * Returns the current position (in bytes);
779
+ * see {Position}[rdoc-ref:IO@Position].
780
+ */
781
+ static VALUE
782
+ strio_get_pos(VALUE self)
783
+ {
784
+ return LONG2NUM(StringIO(self)->pos);
785
+ }
786
+
787
+ /*
788
+ * call-seq:
789
+ * pos = new_position -> new_position
790
+ *
791
+ * Sets the current position (in bytes);
792
+ * see {Position}[rdoc-ref:IO@Position].
793
+ */
794
+ static VALUE
795
+ strio_set_pos(VALUE self, VALUE pos)
796
+ {
797
+ struct StringIO *ptr = StringIO(self);
798
+ long p = NUM2LONG(pos);
799
+ if (p < 0) {
800
+ error_inval(0);
801
+ }
802
+ ptr->pos = p;
803
+ return pos;
804
+ }
805
+
806
+ /*
807
+ * call-seq:
808
+ * rewind -> 0
809
+ *
810
+ * Sets the current position and line number to zero;
811
+ * see {Position}[rdoc-ref:IO@Position]
812
+ * and {Line Number}[rdoc-ref:IO@Line+Number].
813
+ */
814
+ static VALUE
815
+ strio_rewind(VALUE self)
816
+ {
817
+ struct StringIO *ptr = StringIO(self);
818
+ ptr->pos = 0;
819
+ ptr->lineno = 0;
820
+ return INT2FIX(0);
821
+ }
822
+
823
+ /*
824
+ * call-seq:
825
+ * seek(offset, whence = SEEK_SET) -> 0
826
+ *
827
+ * Sets the current position to the given integer +offset+ (in bytes),
828
+ * with respect to a given constant +whence+;
829
+ * see {Position}[rdoc-ref:IO@Position].
830
+ */
831
+ static VALUE
832
+ strio_seek(int argc, VALUE *argv, VALUE self)
833
+ {
834
+ VALUE whence;
835
+ struct StringIO *ptr = StringIO(self);
836
+ long amount, offset;
837
+
838
+ rb_scan_args(argc, argv, "11", NULL, &whence);
839
+ amount = NUM2LONG(argv[0]);
840
+ if (CLOSED(self)) {
841
+ rb_raise(rb_eIOError, "closed stream");
842
+ }
843
+ switch (NIL_P(whence) ? 0 : NUM2LONG(whence)) {
844
+ case 0:
845
+ offset = 0;
846
+ break;
847
+ case 1:
848
+ offset = ptr->pos;
849
+ break;
850
+ case 2:
851
+ if (NIL_P(ptr->string)) {
852
+ offset = 0;
853
+ } else {
854
+ offset = RSTRING_LEN(ptr->string);
855
+ }
856
+ break;
857
+ default:
858
+ error_inval("invalid whence");
859
+ }
860
+ if (amount > LONG_MAX - offset || amount + offset < 0) {
861
+ error_inval(0);
862
+ }
863
+ ptr->pos = amount + offset;
864
+ return INT2FIX(0);
865
+ }
866
+
867
+ /*
868
+ * call-seq:
869
+ * sync -> true
870
+ *
871
+ * Returns +true+; implemented only for compatibility with other stream classes.
872
+ */
873
+ static VALUE
874
+ strio_get_sync(VALUE self)
875
+ {
876
+ StringIO(self);
877
+ return Qtrue;
878
+ }
879
+
880
+ #define strio_set_sync strio_first
881
+
882
+ #define strio_tell strio_get_pos
883
+
884
+ /*
885
+ * call-seq:
886
+ * each_byte {|byte| ... } -> self
887
+ *
888
+ * With a block given, calls the block with each remaining byte in the stream;
889
+ * see {Byte IO}[rdoc-ref:IO@Byte+IO].
890
+ *
891
+ * With no block given, returns an enumerator.
892
+ */
893
+ static VALUE
894
+ strio_each_byte(VALUE self)
895
+ {
896
+ struct StringIO *ptr;
897
+
898
+ RETURN_ENUMERATOR(self, 0, 0);
899
+
900
+ while ((ptr = strio_to_read(self)) != NULL) {
901
+ char c = RSTRING_PTR(ptr->string)[ptr->pos++];
902
+ rb_yield(CHR2FIX(c));
903
+ }
904
+ return self;
905
+ }
906
+
907
+ /*
908
+ * call-seq:
909
+ * getc -> character or nil
910
+ *
911
+ * Reads and returns the next character from the stream;
912
+ * see {Character IO}[rdoc-ref:IO@Character+IO].
913
+ */
914
+ static VALUE
915
+ strio_getc(VALUE self)
916
+ {
917
+ struct StringIO *ptr = readable(self);
918
+ rb_encoding *enc = get_enc(ptr);
919
+ VALUE str = ptr->string;
920
+ long pos = ptr->pos;
921
+ int len;
922
+ char *p;
923
+
924
+ if (eos_p(ptr)) {
925
+ return Qnil;
926
+ }
927
+ p = RSTRING_PTR(str)+pos;
928
+ len = rb_enc_mbclen(p, RSTRING_END(str), enc);
929
+ ptr->pos += len;
930
+ return enc_subseq(str, pos, len, enc);
931
+ }
932
+
933
+ /*
934
+ * call-seq:
935
+ * getbyte -> byte or nil
936
+ *
937
+ * Reads and returns the next 8-bit byte from the stream;
938
+ * see {Byte IO}[rdoc-ref:IO@Byte+IO].
939
+ */
940
+ static VALUE
941
+ strio_getbyte(VALUE self)
942
+ {
943
+ struct StringIO *ptr = readable(self);
944
+ int c;
945
+ if (eos_p(ptr)) {
946
+ return Qnil;
947
+ }
948
+ c = RSTRING_PTR(ptr->string)[ptr->pos++];
949
+ return CHR2FIX(c);
950
+ }
951
+
952
+ static void
953
+ strio_extend(struct StringIO *ptr, long pos, long len)
954
+ {
955
+ long olen;
956
+
957
+ if (len > LONG_MAX - pos)
958
+ rb_raise(rb_eArgError, "string size too big");
959
+
960
+ check_modifiable(ptr);
961
+ olen = RSTRING_LEN(ptr->string);
962
+ if (pos + len > olen) {
963
+ rb_str_resize(ptr->string, pos + len);
964
+ if (pos > olen)
965
+ MEMZERO(RSTRING_PTR(ptr->string) + olen, char, pos - olen);
966
+ }
967
+ }
968
+
969
+ static void
970
+ strio_unget_string(struct StringIO *ptr, VALUE c)
971
+ {
972
+ const char *cp = NULL;
973
+ long cl = RSTRING_LEN(c);
974
+ if (cl > 0) {
975
+ if (c != ptr->string) cp = RSTRING_PTR(c);
976
+ strio_unget_bytes(ptr, cp, cl);
977
+ RB_GC_GUARD(c);
978
+ }
979
+ }
980
+
981
+ /*
982
+ * call-seq:
983
+ * ungetc(character) -> nil
984
+ *
985
+ * Pushes back ("unshifts") a character or integer onto the stream;
986
+ * see {Character IO}[rdoc-ref:IO@Character+IO].
987
+ */
988
+ static VALUE
989
+ strio_ungetc(VALUE self, VALUE c)
990
+ {
991
+ struct StringIO *ptr = readable(self);
992
+ rb_encoding *enc, *enc2;
993
+
994
+ check_modifiable(ptr);
995
+ if (NIL_P(ptr->string)) return Qnil;
996
+ if (NIL_P(c)) return Qnil;
997
+ if (RB_INTEGER_TYPE_P(c)) {
998
+ int len, cc = NUM2INT(c);
999
+ char buf[16];
1000
+
1001
+ enc = rb_enc_get(ptr->string);
1002
+ len = rb_enc_codelen(cc, enc);
1003
+ if (len <= 0) {
1004
+ rb_enc_uint_chr(cc, enc); /* to raise an exception */
1005
+ UNREACHABLE;
1006
+ }
1007
+ rb_enc_mbcput(cc, buf, enc);
1008
+ return strio_unget_bytes(ptr, buf, len);
1009
+ }
1010
+ else {
1011
+ StringValue(c);
1012
+ if (RSTRING_LEN(c) == 0) return Qnil;
1013
+ enc = rb_enc_get(ptr->string);
1014
+ enc2 = rb_enc_get(c);
1015
+ if (enc != enc2 && enc != rb_ascii8bit_encoding()) {
1016
+ c = rb_str_conv_enc(c, enc2, enc);
1017
+ }
1018
+ strio_unget_string(ptr, c);
1019
+ return Qnil;
1020
+ }
1021
+ }
1022
+
1023
+ /*
1024
+ * call-seq:
1025
+ * ungetbyte(byte) -> nil
1026
+ *
1027
+ * Pushes back ("unshifts") an 8-bit byte onto the stream;
1028
+ * see {Byte IO}[rdoc-ref:IO@Byte+IO].
1029
+ */
1030
+ static VALUE
1031
+ strio_ungetbyte(VALUE self, VALUE c)
1032
+ {
1033
+ struct StringIO *ptr = readable(self);
1034
+
1035
+ check_modifiable(ptr);
1036
+ if (NIL_P(ptr->string)) return Qnil;
1037
+ if (NIL_P(c)) return Qnil;
1038
+ if (RB_INTEGER_TYPE_P(c)) {
1039
+ /* rb_int_and() not visible from exts */
1040
+ VALUE v = rb_funcall(c, '&', 1, INT2FIX(0xff));
1041
+ const char cc = NUM2INT(v) & 0xFF;
1042
+ strio_unget_bytes(ptr, &cc, 1);
1043
+ }
1044
+ else {
1045
+ StringValue(c);
1046
+ strio_unget_string(ptr, c);
1047
+ }
1048
+ return Qnil;
1049
+ }
1050
+
1051
+ static VALUE
1052
+ strio_unget_bytes(struct StringIO *ptr, const char *cp, long cl)
1053
+ {
1054
+ long pos = ptr->pos, len, rest;
1055
+ VALUE str = ptr->string;
1056
+ char *s;
1057
+
1058
+ len = RSTRING_LEN(str);
1059
+ rest = pos - len;
1060
+ if (cl > pos) {
1061
+ long ex = cl - (rest < 0 ? pos : len);
1062
+ rb_str_modify_expand(str, ex);
1063
+ rb_str_set_len(str, len + ex);
1064
+ s = RSTRING_PTR(str);
1065
+ if (rest < 0) memmove(s + cl, s + pos, -rest);
1066
+ pos = 0;
1067
+ }
1068
+ else {
1069
+ if (rest > 0) {
1070
+ rb_str_modify_expand(str, rest);
1071
+ rb_str_set_len(str, len + rest);
1072
+ }
1073
+ s = RSTRING_PTR(str);
1074
+ if (rest > cl) memset(s + len, 0, rest - cl);
1075
+ pos -= cl;
1076
+ }
1077
+ memcpy(s + pos, (cp ? cp : s), cl);
1078
+ ptr->pos = pos;
1079
+ return Qnil;
1080
+ }
1081
+
1082
+ /*
1083
+ * call-seq:
1084
+ * readchar -> string
1085
+ *
1086
+ * Like +getc+, but raises an exception if already at end-of-stream;
1087
+ * see {Character IO}[rdoc-ref:IO@Character+IO].
1088
+ */
1089
+ static VALUE
1090
+ strio_readchar(VALUE self)
1091
+ {
1092
+ VALUE c = rb_funcallv(self, rb_intern("getc"), 0, 0);
1093
+ if (NIL_P(c)) rb_eof_error();
1094
+ return c;
1095
+ }
1096
+
1097
+ /*
1098
+ * call-seq:
1099
+ * readbyte -> byte
1100
+ *
1101
+ * Like +getbyte+, but raises an exception if already at end-of-stream;
1102
+ * see {Byte IO}[rdoc-ref:IO@Byte+IO].
1103
+ */
1104
+ static VALUE
1105
+ strio_readbyte(VALUE self)
1106
+ {
1107
+ VALUE c = rb_funcallv(self, rb_intern("getbyte"), 0, 0);
1108
+ if (NIL_P(c)) rb_eof_error();
1109
+ return c;
1110
+ }
1111
+
1112
+ /*
1113
+ * call-seq:
1114
+ * each_char {|c| ... } -> self
1115
+ *
1116
+ * With a block given, calls the block with each remaining character in the stream;
1117
+ * see {Character IO}[rdoc-ref:IO@Character+IO].
1118
+ *
1119
+ * With no block given, returns an enumerator.
1120
+ */
1121
+ static VALUE
1122
+ strio_each_char(VALUE self)
1123
+ {
1124
+ VALUE c;
1125
+
1126
+ RETURN_ENUMERATOR(self, 0, 0);
1127
+
1128
+ while (!NIL_P(c = strio_getc(self))) {
1129
+ rb_yield(c);
1130
+ }
1131
+ return self;
1132
+ }
1133
+
1134
+ /*
1135
+ * call-seq:
1136
+ * each_codepoint {|codepoint| ... } -> self
1137
+ *
1138
+ * With a block given, calls the block with each remaining codepoint in the stream;
1139
+ * see {Codepoint IO}[rdoc-ref:IO@Codepoint+IO].
1140
+ *
1141
+ * With no block given, returns an enumerator.
1142
+ */
1143
+ static VALUE
1144
+ strio_each_codepoint(VALUE self)
1145
+ {
1146
+ struct StringIO *ptr;
1147
+ rb_encoding *enc;
1148
+ unsigned int c;
1149
+ int n;
1150
+
1151
+ RETURN_ENUMERATOR(self, 0, 0);
1152
+
1153
+ ptr = readable(self);
1154
+ enc = get_enc(ptr);
1155
+ while ((ptr = strio_to_read(self)) != NULL) {
1156
+ c = rb_enc_codepoint_len(RSTRING_PTR(ptr->string)+ptr->pos,
1157
+ RSTRING_END(ptr->string), &n, enc);
1158
+ ptr->pos += n;
1159
+ rb_yield(UINT2NUM(c));
1160
+ }
1161
+ return self;
1162
+ }
1163
+
1164
+ /* Boyer-Moore search: copied from regex.c */
1165
+ static void
1166
+ bm_init_skip(long *skip, const char *pat, long m)
1167
+ {
1168
+ int c;
1169
+
1170
+ for (c = 0; c < (1 << CHAR_BIT); c++) {
1171
+ skip[c] = m;
1172
+ }
1173
+ while (--m) {
1174
+ skip[(unsigned char)*pat++] = m;
1175
+ }
1176
+ }
1177
+
1178
+ static long
1179
+ bm_search(const char *little, long llen, const char *big, long blen, const long *skip)
1180
+ {
1181
+ long i, j, k;
1182
+
1183
+ i = llen - 1;
1184
+ while (i < blen) {
1185
+ k = i;
1186
+ j = llen - 1;
1187
+ while (j >= 0 && big[k] == little[j]) {
1188
+ k--;
1189
+ j--;
1190
+ }
1191
+ if (j < 0) return k + 1;
1192
+ i += skip[(unsigned char)big[i]];
1193
+ }
1194
+ return -1;
1195
+ }
1196
+
1197
+ struct getline_arg {
1198
+ VALUE rs;
1199
+ long limit;
1200
+ unsigned int chomp: 1;
1201
+ };
1202
+
1203
+ static struct getline_arg *
1204
+ prepare_getline_args(struct StringIO *ptr, struct getline_arg *arg, int argc, VALUE *argv)
1205
+ {
1206
+ VALUE rs, lim, opts;
1207
+ long limit = -1;
1208
+ int respect_chomp;
1209
+
1210
+ argc = rb_scan_args(argc, argv, "02:", &rs, &lim, &opts);
1211
+ respect_chomp = argc == 0 || !NIL_P(rs);
1212
+ switch (argc) {
1213
+ case 0:
1214
+ rs = rb_rs;
1215
+ break;
1216
+
1217
+ case 1:
1218
+ if (!NIL_P(rs) && !RB_TYPE_P(rs, T_STRING)) {
1219
+ VALUE tmp = rb_check_string_type(rs);
1220
+ if (NIL_P(tmp)) {
1221
+ limit = NUM2LONG(rs);
1222
+ rs = rb_rs;
1223
+ }
1224
+ else {
1225
+ rs = tmp;
1226
+ }
1227
+ }
1228
+ break;
1229
+
1230
+ case 2:
1231
+ if (!NIL_P(rs)) StringValue(rs);
1232
+ if (!NIL_P(lim)) limit = NUM2LONG(lim);
1233
+ break;
1234
+ }
1235
+ if (!NIL_P(ptr->string) && !NIL_P(rs)) {
1236
+ rb_encoding *enc_rs, *enc_io;
1237
+ enc_rs = rb_enc_get(rs);
1238
+ enc_io = get_enc(ptr);
1239
+ if (enc_rs != enc_io &&
1240
+ (rb_enc_str_coderange(rs) != ENC_CODERANGE_7BIT ||
1241
+ (RSTRING_LEN(rs) > 0 && !rb_enc_asciicompat(enc_io)))) {
1242
+ if (rs == rb_rs) {
1243
+ rs = rb_enc_str_new(0, 0, enc_io);
1244
+ rb_str_buf_cat_ascii(rs, "\n");
1245
+ rs = rs;
1246
+ }
1247
+ else {
1248
+ rb_raise(rb_eArgError, "encoding mismatch: %s IO with %s RS",
1249
+ rb_enc_name(enc_io),
1250
+ rb_enc_name(enc_rs));
1251
+ }
1252
+ }
1253
+ }
1254
+ arg->rs = rs;
1255
+ arg->limit = limit;
1256
+ arg->chomp = 0;
1257
+ if (!NIL_P(opts)) {
1258
+ static ID keywords[1];
1259
+ VALUE vchomp;
1260
+ if (!keywords[0]) {
1261
+ keywords[0] = rb_intern_const("chomp");
1262
+ }
1263
+ rb_get_kwargs(opts, keywords, 0, 1, &vchomp);
1264
+ if (respect_chomp) {
1265
+ arg->chomp = (vchomp != Qundef) && RTEST(vchomp);
1266
+ }
1267
+ }
1268
+ return arg;
1269
+ }
1270
+
1271
+ static inline int
1272
+ chomp_newline_width(const char *s, const char *e)
1273
+ {
1274
+ if (e > s && *--e == '\n') {
1275
+ if (e > s && *--e == '\r') return 2;
1276
+ return 1;
1277
+ }
1278
+ return 0;
1279
+ }
1280
+
1281
+ static VALUE
1282
+ strio_getline(struct getline_arg *arg, struct StringIO *ptr)
1283
+ {
1284
+ const char *s, *e, *p;
1285
+ long n, limit = arg->limit;
1286
+ VALUE str = arg->rs;
1287
+ long w = 0;
1288
+ rb_encoding *enc = get_enc(ptr);
1289
+
1290
+ if (NIL_P(ptr->string) || ptr->pos >= (n = RSTRING_LEN(ptr->string))) {
1291
+ return Qnil;
1292
+ }
1293
+ s = RSTRING_PTR(ptr->string);
1294
+ e = s + RSTRING_LEN(ptr->string);
1295
+ s += ptr->pos;
1296
+ if (limit > 0 && (size_t)limit < (size_t)(e - s)) {
1297
+ e = rb_enc_right_char_head(s, s + limit, e, get_enc(ptr));
1298
+ }
1299
+ if (NIL_P(str)) {
1300
+ if (arg->chomp) {
1301
+ w = chomp_newline_width(s, e);
1302
+ }
1303
+ str = strio_substr(ptr, ptr->pos, e - s - w, enc);
1304
+ }
1305
+ else if ((n = RSTRING_LEN(str)) == 0) {
1306
+ const char *paragraph_end = NULL;
1307
+ p = s;
1308
+ while (p[(p + 1 < e) && (*p == '\r') && 0] == '\n') {
1309
+ p += *p == '\r';
1310
+ if (++p == e) {
1311
+ return Qnil;
1312
+ }
1313
+ }
1314
+ s = p;
1315
+ while ((p = memchr(p, '\n', e - p)) && (p != e)) {
1316
+ p++;
1317
+ if (!((p < e && *p == '\n') ||
1318
+ (p + 1 < e && *p == '\r' && *(p+1) == '\n'))) {
1319
+ continue;
1320
+ }
1321
+ paragraph_end = p - ((*(p-2) == '\r') ? 2 : 1);
1322
+ while ((p < e && *p == '\n') ||
1323
+ (p + 1 < e && *p == '\r' && *(p+1) == '\n')) {
1324
+ p += (*p == '\r') ? 2 : 1;
1325
+ }
1326
+ e = p;
1327
+ break;
1328
+ }
1329
+ if (arg->chomp && paragraph_end) {
1330
+ w = e - paragraph_end;
1331
+ }
1332
+ str = strio_substr(ptr, s - RSTRING_PTR(ptr->string), e - s - w, enc);
1333
+ }
1334
+ else if (n == 1) {
1335
+ if ((p = memchr(s, RSTRING_PTR(str)[0], e - s)) != 0) {
1336
+ e = p + 1;
1337
+ w = (arg->chomp ? (p > s && *(p-1) == '\r') + 1 : 0);
1338
+ }
1339
+ str = strio_substr(ptr, ptr->pos, e - s - w, enc);
1340
+ }
1341
+ else {
1342
+ if (n < e - s + arg->chomp) {
1343
+ /* unless chomping, RS at the end does not matter */
1344
+ if (e - s < 1024 || n == e - s) {
1345
+ for (p = s; p + n <= e; ++p) {
1346
+ if (MEMCMP(p, RSTRING_PTR(str), char, n) == 0) {
1347
+ e = p + n;
1348
+ w = (arg->chomp ? n : 0);
1349
+ break;
1350
+ }
1351
+ }
1352
+ }
1353
+ else {
1354
+ long skip[1 << CHAR_BIT], pos;
1355
+ p = RSTRING_PTR(str);
1356
+ bm_init_skip(skip, p, n);
1357
+ if ((pos = bm_search(p, n, s, e - s, skip)) >= 0) {
1358
+ e = s + pos + (arg->chomp ? 0 : n);
1359
+ }
1360
+ }
1361
+ }
1362
+ str = strio_substr(ptr, ptr->pos, e - s - w, enc);
1363
+ }
1364
+ ptr->pos = e - RSTRING_PTR(ptr->string);
1365
+ ptr->lineno++;
1366
+ return str;
1367
+ }
1368
+
1369
+ /*
1370
+ * call-seq:
1371
+ * gets(sep = $/, chomp: false) -> string or nil
1372
+ * gets(limit, chomp: false) -> string or nil
1373
+ * gets(sep, limit, chomp: false) -> string or nil
1374
+ *
1375
+ * Reads and returns a line from the stream;
1376
+ * assigns the return value to <tt>$_</tt>;
1377
+ * see {Line IO}[rdoc-ref:IO@Line+IO].
1378
+ */
1379
+ static VALUE
1380
+ strio_gets(int argc, VALUE *argv, VALUE self)
1381
+ {
1382
+ struct StringIO *ptr = readable(self);
1383
+ struct getline_arg arg;
1384
+ VALUE str;
1385
+
1386
+ if (prepare_getline_args(ptr, &arg, argc, argv)->limit == 0) {
1387
+ if (NIL_P(ptr->string)) return Qnil;
1388
+ return rb_enc_str_new(0, 0, get_enc(ptr));
1389
+ }
1390
+
1391
+ str = strio_getline(&arg, ptr);
1392
+ rb_lastline_set(str);
1393
+ return str;
1394
+ }
1395
+
1396
+ /*
1397
+ * call-seq:
1398
+ * readline(sep = $/, chomp: false) -> string
1399
+ * readline(limit, chomp: false) -> string
1400
+ * readline(sep, limit, chomp: false) -> string
1401
+ *
1402
+ * Reads a line as with IO#gets, but raises EOFError if already at end-of-file;
1403
+ * see {Line IO}[rdoc-ref:IO@Line+IO].
1404
+ */
1405
+ static VALUE
1406
+ strio_readline(int argc, VALUE *argv, VALUE self)
1407
+ {
1408
+ VALUE line = rb_funcallv_kw(self, rb_intern("gets"), argc, argv, RB_PASS_CALLED_KEYWORDS);
1409
+ if (NIL_P(line)) rb_eof_error();
1410
+ return line;
1411
+ }
1412
+
1413
+ /*
1414
+ * call-seq:
1415
+ * each_line(sep = $/, chomp: false) {|line| ... } -> self
1416
+ * each_line(limit, chomp: false) {|line| ... } -> self
1417
+ * each_line(sep, limit, chomp: false) {|line| ... } -> self
1418
+ *
1419
+ * Calls the block with each remaining line read from the stream;
1420
+ * does nothing if already at end-of-file;
1421
+ * returns +self+.
1422
+ * See {Line IO}[rdoc-ref:IO@Line+IO].
1423
+ */
1424
+ static VALUE
1425
+ strio_each(int argc, VALUE *argv, VALUE self)
1426
+ {
1427
+ VALUE line;
1428
+ struct StringIO *ptr = readable(self);
1429
+ struct getline_arg arg;
1430
+
1431
+ RETURN_ENUMERATOR(self, argc, argv);
1432
+
1433
+ if (prepare_getline_args(ptr, &arg, argc, argv)->limit == 0) {
1434
+ rb_raise(rb_eArgError, "invalid limit: 0 for each_line");
1435
+ }
1436
+
1437
+ while (!NIL_P(line = strio_getline(&arg, ptr))) {
1438
+ rb_yield(line);
1439
+ }
1440
+ return self;
1441
+ }
1442
+
1443
+ /*
1444
+ * call-seq:
1445
+ * strio.readlines(sep=$/, chomp: false) -> array
1446
+ * strio.readlines(limit, chomp: false) -> array
1447
+ * strio.readlines(sep, limit, chomp: false) -> array
1448
+ *
1449
+ * See IO#readlines.
1450
+ */
1451
+ static VALUE
1452
+ strio_readlines(int argc, VALUE *argv, VALUE self)
1453
+ {
1454
+ VALUE ary, line;
1455
+ struct StringIO *ptr = readable(self);
1456
+ struct getline_arg arg;
1457
+
1458
+ if (prepare_getline_args(ptr, &arg, argc, argv)->limit == 0) {
1459
+ rb_raise(rb_eArgError, "invalid limit: 0 for readlines");
1460
+ }
1461
+
1462
+ ary = rb_ary_new();
1463
+ while (!NIL_P(line = strio_getline(&arg, ptr))) {
1464
+ rb_ary_push(ary, line);
1465
+ }
1466
+ return ary;
1467
+ }
1468
+
1469
+ /*
1470
+ * call-seq:
1471
+ * strio.write(string, ...) -> integer
1472
+ * strio.syswrite(string) -> integer
1473
+ *
1474
+ * Appends the given string to the underlying buffer string.
1475
+ * The stream must be opened for writing. If the argument is not a
1476
+ * string, it will be converted to a string using <code>to_s</code>.
1477
+ * Returns the number of bytes written. See IO#write.
1478
+ */
1479
+ static VALUE
1480
+ strio_write_m(int argc, VALUE *argv, VALUE self)
1481
+ {
1482
+ long len = 0;
1483
+ while (argc-- > 0) {
1484
+ /* StringIO can't exceed long limit */
1485
+ len += strio_write(self, *argv++);
1486
+ }
1487
+ return LONG2NUM(len);
1488
+ }
1489
+
1490
+ static long
1491
+ strio_write(VALUE self, VALUE str)
1492
+ {
1493
+ struct StringIO *ptr = writable(self);
1494
+ long len, olen;
1495
+ rb_encoding *enc, *enc2;
1496
+ rb_encoding *const ascii8bit = rb_ascii8bit_encoding();
1497
+ rb_encoding *usascii = 0;
1498
+
1499
+ if (!RB_TYPE_P(str, T_STRING))
1500
+ str = rb_obj_as_string(str);
1501
+ enc = get_enc(ptr);
1502
+ if (!enc) return 0;
1503
+ enc2 = rb_enc_get(str);
1504
+ if (enc != enc2 && enc != ascii8bit && enc != (usascii = rb_usascii_encoding())) {
1505
+ VALUE converted = rb_str_conv_enc(str, enc2, enc);
1506
+ if (converted == str && enc2 != ascii8bit && enc2 != usascii) { /* conversion failed */
1507
+ rb_enc_check(rb_enc_from_encoding(enc), str);
1508
+ }
1509
+ str = converted;
1510
+ }
1511
+ len = RSTRING_LEN(str);
1512
+ if (len == 0) return 0;
1513
+ check_modifiable(ptr);
1514
+ olen = RSTRING_LEN(ptr->string);
1515
+ if (ptr->flags & FMODE_APPEND) {
1516
+ ptr->pos = olen;
1517
+ }
1518
+ if (ptr->pos == olen) {
1519
+ if (enc == ascii8bit || enc2 == ascii8bit) {
1520
+ rb_enc_str_buf_cat(ptr->string, RSTRING_PTR(str), len, enc);
1521
+ }
1522
+ else {
1523
+ rb_str_buf_append(ptr->string, str);
1524
+ }
1525
+ }
1526
+ else {
1527
+ strio_extend(ptr, ptr->pos, len);
1528
+ rb_str_modify(ptr->string);
1529
+ memmove(RSTRING_PTR(ptr->string)+ptr->pos, RSTRING_PTR(str), len);
1530
+ }
1531
+ RB_GC_GUARD(str);
1532
+ ptr->pos += len;
1533
+ return len;
1534
+ }
1535
+
1536
+ /*
1537
+ * call-seq:
1538
+ * strio << obj -> strio
1539
+ *
1540
+ * See IO#<<.
1541
+ */
1542
+ #define strio_addstr rb_io_addstr
1543
+
1544
+ /*
1545
+ * call-seq:
1546
+ * strio.print() -> nil
1547
+ * strio.print(obj, ...) -> nil
1548
+ *
1549
+ * See IO#print.
1550
+ */
1551
+ #define strio_print rb_io_print
1552
+
1553
+ /*
1554
+ * call-seq:
1555
+ * strio.printf(format_string [, obj, ...] ) -> nil
1556
+ *
1557
+ * See IO#printf.
1558
+ */
1559
+ #define strio_printf rb_io_printf
1560
+
1561
+ /*
1562
+ * call-seq:
1563
+ * strio.putc(obj) -> obj
1564
+ *
1565
+ * See IO#putc.
1566
+ */
1567
+ static VALUE
1568
+ strio_putc(VALUE self, VALUE ch)
1569
+ {
1570
+ struct StringIO *ptr = writable(self);
1571
+ VALUE str;
1572
+
1573
+ check_modifiable(ptr);
1574
+ if (RB_TYPE_P(ch, T_STRING)) {
1575
+ if (NIL_P(ptr->string)) return ch;
1576
+ str = rb_str_substr(ch, 0, 1);
1577
+ }
1578
+ else {
1579
+ char c = NUM2CHR(ch);
1580
+ if (NIL_P(ptr->string)) return ch;
1581
+ str = rb_str_new(&c, 1);
1582
+ }
1583
+ strio_write(self, str);
1584
+ return ch;
1585
+ }
1586
+
1587
+ /*
1588
+ * call-seq:
1589
+ * strio.puts(obj, ...) -> nil
1590
+ *
1591
+ * See IO#puts.
1592
+ */
1593
+ #define strio_puts rb_io_puts
1594
+
1595
+ /*
1596
+ * call-seq:
1597
+ * strio.read([length [, outbuf]]) -> string, outbuf, or nil
1598
+ *
1599
+ * See IO#read.
1600
+ */
1601
+ static VALUE
1602
+ strio_read(int argc, VALUE *argv, VALUE self)
1603
+ {
1604
+ struct StringIO *ptr = readable(self);
1605
+ VALUE str = Qnil;
1606
+ long len;
1607
+ int binary = 0;
1608
+
1609
+ switch (argc) {
1610
+ case 2:
1611
+ str = argv[1];
1612
+ if (!NIL_P(str)) {
1613
+ StringValue(str);
1614
+ rb_str_modify(str);
1615
+ }
1616
+ /* fall through */
1617
+ case 1:
1618
+ if (!NIL_P(argv[0])) {
1619
+ len = NUM2LONG(argv[0]);
1620
+ if (len < 0) {
1621
+ rb_raise(rb_eArgError, "negative length %ld given", len);
1622
+ }
1623
+ if (eos_p(ptr)) {
1624
+ if (!NIL_P(str)) rb_str_resize(str, 0);
1625
+ return len > 0 ? Qnil : rb_str_new(0, 0);
1626
+ }
1627
+ binary = 1;
1628
+ break;
1629
+ }
1630
+ /* fall through */
1631
+ case 0:
1632
+ if (NIL_P(ptr->string)) return Qnil;
1633
+ len = RSTRING_LEN(ptr->string);
1634
+ if (len <= ptr->pos) {
1635
+ rb_encoding *enc = get_enc(ptr);
1636
+ if (NIL_P(str)) {
1637
+ str = rb_str_new(0, 0);
1638
+ }
1639
+ else {
1640
+ rb_str_resize(str, 0);
1641
+ }
1642
+ rb_enc_associate(str, enc);
1643
+ return str;
1644
+ }
1645
+ else {
1646
+ len -= ptr->pos;
1647
+ }
1648
+ break;
1649
+ default:
1650
+ rb_error_arity(argc, 0, 2);
1651
+ }
1652
+ if (NIL_P(str)) {
1653
+ rb_encoding *enc = binary ? rb_ascii8bit_encoding() : get_enc(ptr);
1654
+ str = strio_substr(ptr, ptr->pos, len, enc);
1655
+ }
1656
+ else {
1657
+ long rest = RSTRING_LEN(ptr->string) - ptr->pos;
1658
+ if (len > rest) len = rest;
1659
+ rb_str_resize(str, len);
1660
+ MEMCPY(RSTRING_PTR(str), RSTRING_PTR(ptr->string) + ptr->pos, char, len);
1661
+ if (!binary) {
1662
+ rb_enc_copy(str, ptr->string);
1663
+ }
1664
+ }
1665
+ ptr->pos += RSTRING_LEN(str);
1666
+ return str;
1667
+ }
1668
+
1669
+ /*
1670
+ * call-seq:
1671
+ * pread(maxlen, offset) -> string
1672
+ * pread(maxlen, offset, out_string) -> string
1673
+ *
1674
+ * See IO#pread.
1675
+ */
1676
+ static VALUE
1677
+ strio_pread(int argc, VALUE *argv, VALUE self)
1678
+ {
1679
+ VALUE rb_len, rb_offset, rb_buf;
1680
+ rb_scan_args(argc, argv, "21", &rb_len, &rb_offset, &rb_buf);
1681
+ long len = NUM2LONG(rb_len);
1682
+ long offset = NUM2LONG(rb_offset);
1683
+
1684
+ if (len < 0) {
1685
+ rb_raise(rb_eArgError, "negative string size (or size too big): %" PRIsVALUE, rb_len);
1686
+ }
1687
+
1688
+ if (len == 0) {
1689
+ if (NIL_P(rb_buf)) {
1690
+ return rb_str_new("", 0);
1691
+ }
1692
+ return rb_buf;
1693
+ }
1694
+
1695
+ if (offset < 0) {
1696
+ rb_syserr_fail_str(EINVAL, rb_sprintf("pread: Invalid offset argument: %" PRIsVALUE, rb_offset));
1697
+ }
1698
+
1699
+ struct StringIO *ptr = readable(self);
1700
+
1701
+ if (outside_p(ptr, offset)) {
1702
+ rb_eof_error();
1703
+ }
1704
+
1705
+ if (NIL_P(rb_buf)) {
1706
+ return strio_substr(ptr, offset, len, rb_ascii8bit_encoding());
1707
+ }
1708
+
1709
+ long rest = RSTRING_LEN(ptr->string) - offset;
1710
+ if (len > rest) len = rest;
1711
+ rb_str_resize(rb_buf, len);
1712
+ rb_enc_associate(rb_buf, rb_ascii8bit_encoding());
1713
+ MEMCPY(RSTRING_PTR(rb_buf), RSTRING_PTR(ptr->string) + offset, char, len);
1714
+ return rb_buf;
1715
+ }
1716
+
1717
+
1718
+ /*
1719
+ * call-seq:
1720
+ * strio.sysread(integer[, outbuf]) -> string
1721
+ * strio.readpartial(integer[, outbuf]) -> string
1722
+ *
1723
+ * Similar to #read, but raises +EOFError+ at end of string instead of
1724
+ * returning +nil+, as well as IO#sysread does.
1725
+ */
1726
+ static VALUE
1727
+ strio_sysread(int argc, VALUE *argv, VALUE self)
1728
+ {
1729
+ VALUE val = rb_funcallv_kw(self, rb_intern("read"), argc, argv, RB_PASS_CALLED_KEYWORDS);
1730
+ if (NIL_P(val)) {
1731
+ rb_eof_error();
1732
+ }
1733
+ return val;
1734
+ }
1735
+
1736
+ /*
1737
+ * call-seq:
1738
+ * strio.read_nonblock(integer[, outbuf [, opts]]) -> string
1739
+ *
1740
+ * Similar to #read, but raises +EOFError+ at end of string unless the
1741
+ * +exception: false+ option is passed in.
1742
+ */
1743
+ static VALUE
1744
+ strio_read_nonblock(int argc, VALUE *argv, VALUE self)
1745
+ {
1746
+ VALUE opts = Qnil, val;
1747
+
1748
+ rb_scan_args(argc, argv, "11:", NULL, NULL, &opts);
1749
+
1750
+ if (!NIL_P(opts)) {
1751
+ argc--;
1752
+ }
1753
+
1754
+ val = strio_read(argc, argv, self);
1755
+ if (NIL_P(val)) {
1756
+ if (!NIL_P(opts) &&
1757
+ rb_hash_lookup2(opts, sym_exception, Qundef) == Qfalse)
1758
+ return Qnil;
1759
+ else
1760
+ rb_eof_error();
1761
+ }
1762
+
1763
+ return val;
1764
+ }
1765
+
1766
+ /*
1767
+ * See IO#write
1768
+ */
1769
+ #define strio_syswrite rb_io_write
1770
+
1771
+ /*
1772
+ * See IO#write_nonblock
1773
+ */
1774
+ static VALUE
1775
+ strio_syswrite_nonblock(int argc, VALUE *argv, VALUE self)
1776
+ {
1777
+ VALUE str;
1778
+
1779
+ rb_scan_args(argc, argv, "10:", &str, NULL);
1780
+ return strio_syswrite(self, str);
1781
+ }
1782
+
1783
+ #define strio_isatty strio_false
1784
+
1785
+ #define strio_pid strio_nil
1786
+
1787
+ #define strio_fileno strio_nil
1788
+
1789
+ /*
1790
+ * call-seq:
1791
+ * strio.length -> integer
1792
+ * strio.size -> integer
1793
+ *
1794
+ * Returns the size of the buffer string.
1795
+ */
1796
+ static VALUE
1797
+ strio_size(VALUE self)
1798
+ {
1799
+ VALUE string = StringIO(self)->string;
1800
+ if (NIL_P(string)) {
1801
+ return INT2FIX(0);
1802
+ }
1803
+ return ULONG2NUM(RSTRING_LEN(string));
1804
+ }
1805
+
1806
+ /*
1807
+ * call-seq:
1808
+ * strio.truncate(integer) -> 0
1809
+ *
1810
+ * Truncates the buffer string to at most _integer_ bytes. The stream
1811
+ * must be opened for writing.
1812
+ */
1813
+ static VALUE
1814
+ strio_truncate(VALUE self, VALUE len)
1815
+ {
1816
+ VALUE string = writable(self)->string;
1817
+ long l = NUM2LONG(len);
1818
+ long plen;
1819
+ if (l < 0) {
1820
+ error_inval("negative length");
1821
+ }
1822
+ if (NIL_P(string)) return 0;
1823
+ plen = RSTRING_LEN(string);
1824
+ rb_str_resize(string, l);
1825
+ if (plen < l) {
1826
+ MEMZERO(RSTRING_PTR(string) + plen, char, l - plen);
1827
+ }
1828
+ return INT2FIX(0);
1829
+ }
1830
+
1831
+ /*
1832
+ * call-seq:
1833
+ * strio.external_encoding => encoding
1834
+ *
1835
+ * Returns the Encoding object that represents the encoding of the file.
1836
+ * If the stream is write mode and no encoding is specified, returns
1837
+ * +nil+.
1838
+ */
1839
+
1840
+ static VALUE
1841
+ strio_external_encoding(VALUE self)
1842
+ {
1843
+ struct StringIO *ptr = StringIO(self);
1844
+ return rb_enc_from_encoding(get_enc(ptr));
1845
+ }
1846
+
1847
+ /*
1848
+ * call-seq:
1849
+ * strio.internal_encoding => encoding
1850
+ *
1851
+ * Returns the Encoding of the internal string if conversion is
1852
+ * specified. Otherwise returns +nil+.
1853
+ */
1854
+
1855
+ static VALUE
1856
+ strio_internal_encoding(VALUE self)
1857
+ {
1858
+ return Qnil;
1859
+ }
1860
+
1861
+ /*
1862
+ * call-seq:
1863
+ * strio.set_encoding(ext_enc, [int_enc[, opt]]) => strio
1864
+ *
1865
+ * Specify the encoding of the StringIO as <i>ext_enc</i>.
1866
+ * Use the default external encoding if <i>ext_enc</i> is nil.
1867
+ * 2nd argument <i>int_enc</i> and optional hash <i>opt</i> argument
1868
+ * are ignored; they are for API compatibility to IO.
1869
+ */
1870
+
1871
+ static VALUE
1872
+ strio_set_encoding(int argc, VALUE *argv, VALUE self)
1873
+ {
1874
+ rb_encoding* enc;
1875
+ struct StringIO *ptr = StringIO(self);
1876
+ VALUE ext_enc, int_enc, opt;
1877
+
1878
+ argc = rb_scan_args(argc, argv, "11:", &ext_enc, &int_enc, &opt);
1879
+
1880
+ if (NIL_P(ext_enc)) {
1881
+ enc = rb_default_external_encoding();
1882
+ }
1883
+ else {
1884
+ enc = rb_find_encoding(ext_enc);
1885
+ if (!enc) {
1886
+ rb_io_enc_t convconfig;
1887
+ int oflags;
1888
+ rb_io_mode_t fmode;
1889
+ VALUE vmode = rb_str_append(rb_str_new_cstr("r:"), ext_enc);
1890
+ rb_io_extract_modeenc(&vmode, 0, Qnil, &oflags, &fmode, &convconfig);
1891
+ enc = convconfig.enc2;
1892
+ }
1893
+ }
1894
+ ptr->enc = enc;
1895
+ if (!NIL_P(ptr->string) && WRITABLE(self) && !str_chilled_p(ptr->string)) {
1896
+ rb_enc_associate(ptr->string, enc);
1897
+ }
1898
+
1899
+ return self;
1900
+ }
1901
+
1902
+ /*
1903
+ * call-seq:
1904
+ * strio.set_encoding_by_bom => strio or nil
1905
+ *
1906
+ * Sets the encoding according to the BOM (Byte Order Mark) in the
1907
+ * string.
1908
+ *
1909
+ * Returns +self+ if the BOM is found, otherwise +nil.
1910
+ */
1911
+ static VALUE
1912
+ strio_set_encoding_by_bom(VALUE self)
1913
+ {
1914
+ struct StringIO *ptr = StringIO(self);
1915
+
1916
+ if (!set_encoding_by_bom(ptr)) return Qnil;
1917
+ return rb_enc_from_encoding(ptr->enc);
1918
+ }
1919
+
1920
+ /*
1921
+ * \IO streams for strings, with access similar to
1922
+ * {IO}[rdoc-ref:IO];
1923
+ * see {IO}[rdoc-ref:IO].
1924
+ *
1925
+ * === About the Examples
1926
+ *
1927
+ * Examples on this page assume that \StringIO has been required:
1928
+ *
1929
+ * require 'stringio'
1930
+ *
1931
+ */
1932
+ void
1933
+ Init_stringio(void)
1934
+ {
1935
+ #undef rb_intern
1936
+
1937
+ #ifdef HAVE_RB_EXT_RACTOR_SAFE
1938
+ rb_ext_ractor_safe(true);
1939
+ #endif
1940
+
1941
+ VALUE StringIO = rb_define_class("StringIO", rb_cObject);
1942
+
1943
+ /* The version string */
1944
+ rb_define_const(StringIO, "VERSION", rb_str_new_cstr(STRINGIO_VERSION));
1945
+
1946
+ rb_include_module(StringIO, rb_mEnumerable);
1947
+ rb_define_alloc_func(StringIO, strio_s_allocate);
1948
+
1949
+ /* Maximum length that a StringIO instance can hold */
1950
+ rb_define_const(StringIO, "MAX_LENGTH", LONG2NUM(LONG_MAX));
1951
+
1952
+ rb_define_singleton_method(StringIO, "new", strio_s_new, -1);
1953
+ rb_define_singleton_method(StringIO, "open", strio_s_open, -1);
1954
+ rb_define_method(StringIO, "initialize", strio_initialize, -1);
1955
+ rb_define_method(StringIO, "initialize_copy", strio_copy, 1);
1956
+ rb_define_method(StringIO, "reopen", strio_reopen, -1);
1957
+
1958
+ rb_define_method(StringIO, "string", strio_get_string, 0);
1959
+ rb_define_method(StringIO, "string=", strio_set_string, 1);
1960
+ rb_define_method(StringIO, "lineno", strio_get_lineno, 0);
1961
+ rb_define_method(StringIO, "lineno=", strio_set_lineno, 1);
1962
+
1963
+
1964
+ /* call-seq: strio.binmode -> true */
1965
+ rb_define_method(StringIO, "binmode", strio_binmode, 0);
1966
+ rb_define_method(StringIO, "close", strio_close, 0);
1967
+ rb_define_method(StringIO, "close_read", strio_close_read, 0);
1968
+ rb_define_method(StringIO, "close_write", strio_close_write, 0);
1969
+ rb_define_method(StringIO, "closed?", strio_closed, 0);
1970
+ rb_define_method(StringIO, "closed_read?", strio_closed_read, 0);
1971
+ rb_define_method(StringIO, "closed_write?", strio_closed_write, 0);
1972
+ rb_define_method(StringIO, "eof", strio_eof, 0);
1973
+ rb_define_method(StringIO, "eof?", strio_eof, 0);
1974
+ /* call-seq: strio.fcntl */
1975
+ rb_define_method(StringIO, "fcntl", strio_fcntl, -1);
1976
+ /* call-seq: strio.flush -> strio */
1977
+ rb_define_method(StringIO, "flush", strio_flush, 0);
1978
+ /* call-seq: strio.fsync -> 0 */
1979
+ rb_define_method(StringIO, "fsync", strio_fsync, 0);
1980
+ rb_define_method(StringIO, "pos", strio_get_pos, 0);
1981
+ rb_define_method(StringIO, "pos=", strio_set_pos, 1);
1982
+ rb_define_method(StringIO, "rewind", strio_rewind, 0);
1983
+ rb_define_method(StringIO, "seek", strio_seek, -1);
1984
+ rb_define_method(StringIO, "sync", strio_get_sync, 0);
1985
+ /* call-seq: strio.sync = boolean -> boolean */
1986
+ rb_define_method(StringIO, "sync=", strio_set_sync, 1);
1987
+ rb_define_method(StringIO, "tell", strio_tell, 0);
1988
+
1989
+ rb_define_method(StringIO, "each", strio_each, -1);
1990
+ rb_define_method(StringIO, "each_line", strio_each, -1);
1991
+ rb_define_method(StringIO, "each_byte", strio_each_byte, 0);
1992
+ rb_define_method(StringIO, "each_char", strio_each_char, 0);
1993
+ rb_define_method(StringIO, "each_codepoint", strio_each_codepoint, 0);
1994
+ rb_define_method(StringIO, "getc", strio_getc, 0);
1995
+ rb_define_method(StringIO, "ungetc", strio_ungetc, 1);
1996
+ rb_define_method(StringIO, "ungetbyte", strio_ungetbyte, 1);
1997
+ rb_define_method(StringIO, "getbyte", strio_getbyte, 0);
1998
+ rb_define_method(StringIO, "gets", strio_gets, -1);
1999
+ rb_define_method(StringIO, "readlines", strio_readlines, -1);
2000
+ rb_define_method(StringIO, "read", strio_read, -1);
2001
+ rb_define_method(StringIO, "pread", strio_pread, -1);
2002
+
2003
+ rb_define_method(StringIO, "write", strio_write_m, -1);
2004
+ rb_define_method(StringIO, "putc", strio_putc, 1);
2005
+
2006
+ /*
2007
+ * call-seq:
2008
+ * strio.isatty -> nil
2009
+ * strio.tty? -> nil
2010
+ *
2011
+ */
2012
+ rb_define_method(StringIO, "isatty", strio_isatty, 0);
2013
+ rb_define_method(StringIO, "tty?", strio_isatty, 0);
2014
+
2015
+ /* call-seq: strio.pid -> nil */
2016
+ rb_define_method(StringIO, "pid", strio_pid, 0);
2017
+
2018
+ /* call-seq: strio.fileno -> nil */
2019
+ rb_define_method(StringIO, "fileno", strio_fileno, 0);
2020
+ rb_define_method(StringIO, "size", strio_size, 0);
2021
+ rb_define_method(StringIO, "length", strio_size, 0);
2022
+ rb_define_method(StringIO, "truncate", strio_truncate, 1);
2023
+
2024
+ rb_define_method(StringIO, "external_encoding", strio_external_encoding, 0);
2025
+ rb_define_method(StringIO, "internal_encoding", strio_internal_encoding, 0);
2026
+ rb_define_method(StringIO, "set_encoding", strio_set_encoding, -1);
2027
+ rb_define_method(StringIO, "set_encoding_by_bom", strio_set_encoding_by_bom, 0);
2028
+
2029
+ {
2030
+ VALUE mReadable = rb_define_module_under(rb_cIO, "generic_readable");
2031
+ rb_define_method(mReadable, "readchar", strio_readchar, 0);
2032
+ rb_define_method(mReadable, "readbyte", strio_readbyte, 0);
2033
+ rb_define_method(mReadable, "readline", strio_readline, -1);
2034
+ rb_define_method(mReadable, "sysread", strio_sysread, -1);
2035
+ rb_define_method(mReadable, "readpartial", strio_sysread, -1);
2036
+ rb_define_method(mReadable, "read_nonblock", strio_read_nonblock, -1);
2037
+ rb_include_module(StringIO, mReadable);
2038
+ }
2039
+ {
2040
+ VALUE mWritable = rb_define_module_under(rb_cIO, "generic_writable");
2041
+ rb_define_method(mWritable, "<<", strio_addstr, 1);
2042
+ rb_define_method(mWritable, "print", strio_print, -1);
2043
+ rb_define_method(mWritable, "printf", strio_printf, -1);
2044
+ rb_define_method(mWritable, "puts", strio_puts, -1);
2045
+ rb_define_method(mWritable, "syswrite", strio_syswrite, 1);
2046
+ rb_define_method(mWritable, "write_nonblock", strio_syswrite_nonblock, -1);
2047
+ rb_include_module(StringIO, mWritable);
2048
+ }
2049
+
2050
+ sym_exception = ID2SYM(rb_intern("exception"));
2051
+ }