stringio 0.0.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of stringio might be problematic. Click here for more details.

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