stringio 3.1.0 → 3.1.7

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 67351f85af240c4189d6d1eaf805bfade85b9aae65d930326ec1c6930c5ba9c9
4
- data.tar.gz: 51016af4762d130788a7f80798fafd346225f67c86096f95e7f3f2f5244d8b17
3
+ metadata.gz: d32a3b9eb5ecb12a5c78c7a79418ed351272fe49a2fc1bbde837880a8e6a2a53
4
+ data.tar.gz: 8f965cb4f731147e7d6da44db5acbeda3a08ac51df419445d8001f35b17a1dc9
5
5
  SHA512:
6
- metadata.gz: 6e15df64d01a1592cf7ca5f0024cdd693494c5db5c5cfcf9e7d4662c3f8a8c8cdadf2032e72c80d1baa2110c6310f4e6e0fdc96926eee53095ddf443caab9b5c
7
- data.tar.gz: 50dafc1b4c0de2e659860b00b6d6e6ef43eedba1cf059956d86acc9f9bb6c28c3924ef5ff3e5b7ba8719afc5366bf1cebf9a0e67b1e1a918a1347aa28f18ea0c
6
+ metadata.gz: 6c3f11fa1dee2b8e00269cad5e99db7014ecdc7b1b7d99f5086d15fb3f04d17105dabd838887e5f87af817851e2a8a59260c7c7af26a5ea40f2ce103ad830775
7
+ data.tar.gz: c9e2afe1c8104c27591454cfeefdc71926c76196d3afc343f76052b9e465566f62df19ae25baaa1217839684910b0c94e4d05b7b08723f1960065f0c2d0844df
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ COPYING
2
+ *.md
3
+ *.txt
4
+ docs/
5
+ ext/stringio/
data/.rdoc_options ADDED
@@ -0,0 +1,2 @@
1
+ ---
2
+ main_page: README.md
data/COPYING ADDED
@@ -0,0 +1,56 @@
1
+ Ruby is copyrighted free software by Yukihiro Matsumoto <matz@netlab.jp>.
2
+ You can redistribute it and/or modify it under either the terms of the
3
+ 2-clause BSDL (see the file BSDL), or the conditions below:
4
+
5
+ 1. You may make and give away verbatim copies of the source form of the
6
+ software without restriction, provided that you duplicate all of the
7
+ original copyright notices and associated disclaimers.
8
+
9
+ 2. You may modify your copy of the software in any way, provided that
10
+ you do at least ONE of the following:
11
+
12
+ a. place your modifications in the Public Domain or otherwise
13
+ make them Freely Available, such as by posting said
14
+ modifications to Usenet or an equivalent medium, or by allowing
15
+ the author to include your modifications in the software.
16
+
17
+ b. use the modified software only within your corporation or
18
+ organization.
19
+
20
+ c. give non-standard binaries non-standard names, with
21
+ instructions on where to get the original software distribution.
22
+
23
+ d. make other distribution arrangements with the author.
24
+
25
+ 3. You may distribute the software in object code or binary form,
26
+ provided that you do at least ONE of the following:
27
+
28
+ a. distribute the binaries and library files of the software,
29
+ together with instructions (in the manual page or equivalent)
30
+ on where to get the original distribution.
31
+
32
+ b. accompany the distribution with the machine-readable source of
33
+ the software.
34
+
35
+ c. give non-standard binaries non-standard names, with
36
+ instructions on where to get the original software distribution.
37
+
38
+ d. make other distribution arrangements with the author.
39
+
40
+ 4. You may modify and include the part of the software into any other
41
+ software (possibly commercial). But some files in the distribution
42
+ are not written by the author, so that they are not under these terms.
43
+
44
+ For the list of those files and their copying conditions, see the
45
+ file LEGAL.
46
+
47
+ 5. The scripts and library files supplied as input to or produced as
48
+ output from the software do not automatically fall under the
49
+ copyright of the software, but belong to whomever generated them,
50
+ and may be sold commercially, and may be aggregated with this
51
+ software.
52
+
53
+ 6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
54
+ IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
55
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
56
+ PURPOSE.
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (C) 1993-2013 Yukihiro Matsumoto. All rights reserved.
2
+
3
+ Redistribution and use in source and binary forms, with or without
4
+ modification, are permitted provided that the following conditions
5
+ are met:
6
+ 1. Redistributions of source code must retain the above copyright
7
+ notice, this list of conditions and the following disclaimer.
8
+ 2. Redistributions in binary form must reproduce the above copyright
9
+ notice, this list of conditions and the following disclaimer in the
10
+ documentation and/or other materials provided with the distribution.
11
+
12
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
13
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
14
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
15
+ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
16
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
17
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
18
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
19
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
20
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
21
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
22
+ SUCH DAMAGE.
data/NEWS.md ADDED
@@ -0,0 +1,243 @@
1
+ # News
2
+
3
+ ## 3.1.7 - 2025-04-21
4
+
5
+ ### Improvements
6
+
7
+ * CRuby: Added support for `rb_io_mode_t` that will be introduced in
8
+ Ruby 3.5 or later.
9
+ * GH-129
10
+ * Patch by Samuel Williams
11
+
12
+ ### Thanks
13
+
14
+ * Samuel Williams
15
+
16
+ ## 3.1.6 - 2025-03-25
17
+
18
+ ### Fixes
19
+
20
+ * CRuby: Fix SEGV at unget to a null device StringIO
21
+ * JRuby:
22
+ * Fix NullPointerException at unget to a null device StringIO
23
+ * Use proper checkEncoding signature
24
+ * Update strioWrite logic to match CRuby
25
+ * GH-124
26
+
27
+ ## 3.1.5 - 2025-02-21
28
+
29
+ ### Improvements
30
+
31
+ * JRuby: Improved compatibility with CRuby for `StringIO#seek` with
32
+ frozen string.
33
+ * GH-119
34
+ * GH-121
35
+
36
+ ## 3.1.4 - 2025-02-20
37
+
38
+ ### Improvements
39
+
40
+ * JRuby: Improved compatibility with CRuby.
41
+ * GH-116
42
+
43
+ ### Fixes
44
+
45
+ * CRuby: Fixed a bug that `StringIO` may mutate a shared string.
46
+ * GH-117
47
+
48
+ ## 3.1.3 - 2025-02-14
49
+
50
+ ### Fixes
51
+
52
+ * JRuby: Fixed a bug that JRuby may not be able to be started
53
+ * GH-112
54
+ * GH-113
55
+ * Reported by Karol Bucek
56
+
57
+ ### Thanks
58
+
59
+ * Karol Bucek
60
+
61
+ ## 3.1.2 - 2024-11-07
62
+
63
+ ### Improvements
64
+
65
+ * JRuby: Added support for detecting encoding by BOM.
66
+ * GH-100
67
+ * GH-101
68
+
69
+ ### Fixes
70
+
71
+ * CRuby: Fixed a bug that unknown memory may be used by
72
+ `StringIO#ungetc`/`StringIO#ungetbyte`.
73
+ * https://hackerone.com/reports/2805165
74
+ * Reported by manun.
75
+
76
+ ### Thanks
77
+
78
+ * manun
79
+
80
+ ## 3.1.1 - 2024-06-13
81
+
82
+ ### Improvements
83
+
84
+ * JRuby: Improved.
85
+ * GH-83
86
+ * GH-84
87
+ * GH-85
88
+
89
+ * Added `StringIO::MAX_LENGTH`.
90
+
91
+ * Added support for NULL `StringIO` by `StringIO.new(nil)`.
92
+
93
+ * Improved IO compatibility for partial read.
94
+ * GH-95
95
+ * https://bugs.ruby-lang.org/issues/20418
96
+
97
+ ### Fixes
98
+
99
+ * Fixed a bug that coderange isn't updated after overwrite.
100
+ * Reported by Tiago Cardoso.
101
+ * https://bugs.ruby-lang.org/issues/20185
102
+ * GH-77
103
+ * GH-79
104
+
105
+ ### Thanks
106
+
107
+ * Tiago Cardoso
108
+
109
+ ## 3.1.0 - 2023-11-28
110
+
111
+ ### Fixes
112
+
113
+ * TruffleRuby: Do not compile the C extension
114
+
115
+ GH-71
116
+
117
+ ## 3.0.9 - 2023-11-08
118
+
119
+ ### Improvements
120
+
121
+ * JRuby: Aligned `StringIO#gets` behavior with the C implementation.
122
+
123
+ GH-61
124
+
125
+ ### Fixes
126
+
127
+ * CRuby: Fixed `StringIO#pread` with the length 0.
128
+
129
+ Patch by Jean byroot Boussier.
130
+
131
+ GH-67
132
+
133
+ * CRuby: Fixed a bug that `StringIO#gets` with non ASCII compatible
134
+ encoding such as UTF-16 doesn't detect correct new line characters.
135
+
136
+ Reported by IWAMOTO Kouichi.
137
+
138
+ GH-68
139
+
140
+ ### Thanks
141
+
142
+ * Jean byroot Boussier
143
+
144
+ * IWAMOTO Kouichi
145
+
146
+ ## 3.0.8 - 2023-08-10
147
+
148
+ ### Improvements
149
+
150
+ * Added `StringIO#pread`.
151
+
152
+ Patch by Jean byroot Boussier.
153
+
154
+ GH-56
155
+
156
+ * JRuby: Added `StringIO::VERSION`.
157
+
158
+ GH-57 GH-59
159
+
160
+ ### Thanks
161
+
162
+ * Jean byroot Boussier
163
+
164
+ ## 3.0.7 - 2023-06-02
165
+
166
+ * CRuby: Avoid direct struct usage. This change is for supporting
167
+ Ruby 3.3.
168
+
169
+ GH-54
170
+
171
+ ## 3.0.6 - 2023-04-14
172
+
173
+ ### Improvements
174
+
175
+ * CRuby: Added support for write barrier.
176
+
177
+ * JRuby: Added missing arty-checking.
178
+
179
+ GH-48
180
+
181
+ * JRuby: Added support for `StringIO.new(encoding:)`.
182
+
183
+ GH-45
184
+
185
+ ## 3.0.5 - 2023-02-02
186
+
187
+ ### Improvements
188
+
189
+ ### Fixes
190
+
191
+ * Fixed a bug that `StringIO#gets("2+ character", chomp: true)` did not
192
+ remove the separator at the end.
193
+ [[Bug #19389](https://bugs.ruby-lang.org/issues/19389)]
194
+
195
+ ## 3.0.4 - 2022-12-09
196
+
197
+ ### Improvements
198
+
199
+ * JRuby: Changed to use flag registry.
200
+ [[GitHub#33](https://github.com/ruby/stringio/pull/26)]
201
+
202
+ ## 3.0.3 - 2022-12-08
203
+
204
+ ### Improvements
205
+
206
+ * Improved documents.
207
+ [[GitHub#33](https://github.com/ruby/stringio/pull/33)]
208
+ [[GitHub#34](https://github.com/ruby/stringio/pull/34)]
209
+ [[GitHub#35](https://github.com/ruby/stringio/pull/35)]
210
+ [[GitHub#36](https://github.com/ruby/stringio/pull/36)]
211
+ [[GitHub#37](https://github.com/ruby/stringio/pull/37)]
212
+ [Patch by Burdette Lamar]
213
+
214
+ ### Fixes
215
+
216
+ * Fixed a bug that large `StringIO#ungetc`/`StringIO#ungetbyte`
217
+ break internal buffer.
218
+
219
+ * Fixed a bug that `StringIO#each("2+ character", chomp: true)` cause
220
+ infinite loop.
221
+ [[Bug #18769](https://bugs.ruby-lang.org/issues/18769)]
222
+
223
+ * Fixed a bug that `StringIO#each(nil, chomp: true)` chomps.
224
+ [[Bug #18770](https://bugs.ruby-lang.org/issues/18770)]
225
+
226
+ * Fixed a bug that `StringIO#each("", chomp: true)` isn't compatible
227
+ with `IO#each("", chomp: true)`.
228
+ [[Bug #18768](https://bugs.ruby-lang.org/issues/18768)]
229
+
230
+ * Fixed a bug that `StringIO#set_encoding` doesn't accept external
231
+ and internal encodings pairo.
232
+ [[GitHub#16](https://github.com/ruby/stringio/issues/16)]
233
+ [Reported by Kenta Murata]
234
+
235
+ * Fixed a bug that `StringIO#truncate` isn't compatible with
236
+ `File#truncate`.
237
+
238
+ ### Thanks
239
+
240
+ * Kenta Murata
241
+
242
+ * Burdette Lamar
243
+
data/README.md CHANGED
@@ -12,7 +12,7 @@ This library is based on MoonWolf version written in Ruby. Thanks a lot.
12
12
 
13
13
  * `fileno` raises `NotImplementedError`.
14
14
  * encoding conversion is not implemented, and ignored silently.
15
- * there is no `#to_io` method because this is not an `IO.
15
+ * there is no `#to_io` method because this is not an `IO`.
16
16
 
17
17
  ## Installation
18
18
 
data/docs/io.rb ADDED
@@ -0,0 +1,8 @@
1
+ # :stopdoc:
2
+ class IO
3
+ module generic_readable
4
+ end
5
+ module generic_writable
6
+ end
7
+ end
8
+ # :startdoc:
@@ -0,0 +1 @@
1
+ *.[ch]
@@ -1,6 +1,8 @@
1
1
  # frozen_string_literal: false
2
2
  require 'mkmf'
3
3
  if RUBY_ENGINE == 'ruby'
4
+ have_type("rb_io_mode_t", "ruby/io.h")
5
+
4
6
  create_makefile('stringio')
5
7
  else
6
8
  File.write('Makefile', dummy_makefile("").join)
@@ -13,7 +13,9 @@
13
13
  **********************************************************************/
14
14
 
15
15
  static const char *const
16
- STRINGIO_VERSION = "3.1.0";
16
+ STRINGIO_VERSION = "3.1.7";
17
+
18
+ #include <stdbool.h>
17
19
 
18
20
  #include "ruby.h"
19
21
  #include "ruby/io.h"
@@ -33,12 +35,16 @@ STRINGIO_VERSION = "3.1.0";
33
35
  # define rb_class_new_instance_kw(argc, argv, klass, kw_splat) rb_class_new_instance(argc, argv, klass)
34
36
  #endif
35
37
 
38
+ #ifndef HAVE_TYPE_RB_IO_MODE_T
39
+ typedef int rb_io_mode_t;
40
+ #endif
41
+
36
42
  struct StringIO {
37
43
  VALUE string;
38
44
  rb_encoding *enc;
39
45
  long pos;
40
46
  long lineno;
41
- int flags;
47
+ rb_io_mode_t flags;
42
48
  int count;
43
49
  };
44
50
 
@@ -48,7 +54,13 @@ static long strio_write(VALUE self, VALUE str);
48
54
 
49
55
  #define IS_STRIO(obj) (rb_typeddata_is_kind_of((obj), &strio_data_type))
50
56
  #define error_inval(msg) (rb_syserr_fail(EINVAL, msg))
51
- #define get_enc(ptr) ((ptr)->enc ? (ptr)->enc : rb_enc_get((ptr)->string))
57
+ #define get_enc(ptr) ((ptr)->enc ? (ptr)->enc : !NIL_P((ptr)->string) ? rb_enc_get((ptr)->string) : NULL)
58
+
59
+ static bool
60
+ readonly_string_p(VALUE string)
61
+ {
62
+ return OBJ_FROZEN_RAW(string);
63
+ }
52
64
 
53
65
  static struct StringIO *
54
66
  strio_alloc(void)
@@ -166,9 +178,15 @@ writable(VALUE strio)
166
178
  static void
167
179
  check_modifiable(struct StringIO *ptr)
168
180
  {
169
- if (OBJ_FROZEN(ptr->string)) {
181
+ if (NIL_P(ptr->string)) {
182
+ /* Null device StringIO */
183
+ }
184
+ else if (OBJ_FROZEN_RAW(ptr->string)) {
170
185
  rb_raise(rb_eIOError, "not modifiable string");
171
186
  }
187
+ else {
188
+ rb_str_modify(ptr->string);
189
+ }
172
190
  }
173
191
 
174
192
  static VALUE
@@ -281,13 +299,14 @@ strio_init(int argc, VALUE *argv, struct StringIO *ptr, VALUE self)
281
299
 
282
300
  argc = rb_scan_args(argc, argv, "02:", &string, &vmode, &opt);
283
301
  rb_io_extract_modeenc(&vmode, 0, opt, &oflags, &ptr->flags, &convconfig);
284
- if (argc) {
302
+ if (!NIL_P(string)) {
285
303
  StringValue(string);
286
304
  }
287
- else {
305
+ else if (!argc) {
288
306
  string = rb_enc_str_new("", 0, rb_default_external_encoding());
289
307
  }
290
- if (OBJ_FROZEN_RAW(string)) {
308
+
309
+ if (!NIL_P(string) && readonly_string_p(string)) {
291
310
  if (ptr->flags & FMODE_WRITABLE) {
292
311
  rb_syserr_fail(EACCES, 0);
293
312
  }
@@ -297,11 +316,11 @@ strio_init(int argc, VALUE *argv, struct StringIO *ptr, VALUE self)
297
316
  ptr->flags |= FMODE_WRITABLE;
298
317
  }
299
318
  }
300
- if (ptr->flags & FMODE_TRUNC) {
319
+ if (!NIL_P(string) && (ptr->flags & FMODE_TRUNC)) {
301
320
  rb_str_resize(string, 0);
302
321
  }
303
322
  RB_OBJ_WRITE(self, &ptr->string, string);
304
- if (argc == 1) {
323
+ if (argc == 1 && !NIL_P(string)) {
305
324
  ptr->enc = rb_enc_get(string);
306
325
  }
307
326
  else {
@@ -481,7 +500,7 @@ strio_set_string(VALUE self, VALUE string)
481
500
  rb_io_taint_check(self);
482
501
  ptr->flags &= ~FMODE_READWRITE;
483
502
  StringValue(string);
484
- ptr->flags = OBJ_FROZEN(string) ? FMODE_READABLE : FMODE_READWRITE;
503
+ ptr->flags = readonly_string_p(string) ? FMODE_READABLE : FMODE_READWRITE;
485
504
  ptr->pos = 0;
486
505
  ptr->lineno = 0;
487
506
  RB_OBJ_WRITE(self, &ptr->string, string);
@@ -595,6 +614,7 @@ static struct StringIO *
595
614
  strio_to_read(VALUE self)
596
615
  {
597
616
  struct StringIO *ptr = readable(self);
617
+ if (NIL_P(ptr->string)) return NULL;
598
618
  if (ptr->pos < RSTRING_LEN(ptr->string)) return ptr;
599
619
  return NULL;
600
620
  }
@@ -872,7 +892,7 @@ strio_getc(VALUE self)
872
892
  int len;
873
893
  char *p;
874
894
 
875
- if (pos >= RSTRING_LEN(str)) {
895
+ if (NIL_P(str) || pos >= RSTRING_LEN(str)) {
876
896
  return Qnil;
877
897
  }
878
898
  p = RSTRING_PTR(str)+pos;
@@ -893,7 +913,7 @@ strio_getbyte(VALUE self)
893
913
  {
894
914
  struct StringIO *ptr = readable(self);
895
915
  int c;
896
- if (ptr->pos >= RSTRING_LEN(ptr->string)) {
916
+ if (NIL_P(ptr->string) || ptr->pos >= RSTRING_LEN(ptr->string)) {
897
917
  return Qnil;
898
918
  }
899
919
  c = RSTRING_PTR(ptr->string)[ptr->pos++];
@@ -915,8 +935,17 @@ strio_extend(struct StringIO *ptr, long pos, long len)
915
935
  if (pos > olen)
916
936
  MEMZERO(RSTRING_PTR(ptr->string) + olen, char, pos - olen);
917
937
  }
918
- else {
919
- rb_str_modify(ptr->string);
938
+ }
939
+
940
+ static void
941
+ strio_unget_string(struct StringIO *ptr, VALUE c)
942
+ {
943
+ const char *cp = NULL;
944
+ long cl = RSTRING_LEN(c);
945
+ if (cl > 0) {
946
+ if (c != ptr->string) cp = RSTRING_PTR(c);
947
+ strio_unget_bytes(ptr, cp, cl);
948
+ RB_GC_GUARD(c);
920
949
  }
921
950
  }
922
951
 
@@ -934,6 +963,7 @@ strio_ungetc(VALUE self, VALUE c)
934
963
  rb_encoding *enc, *enc2;
935
964
 
936
965
  check_modifiable(ptr);
966
+ if (NIL_P(ptr->string)) return Qnil;
937
967
  if (NIL_P(c)) return Qnil;
938
968
  if (RB_INTEGER_TYPE_P(c)) {
939
969
  int len, cc = NUM2INT(c);
@@ -941,19 +971,22 @@ strio_ungetc(VALUE self, VALUE c)
941
971
 
942
972
  enc = rb_enc_get(ptr->string);
943
973
  len = rb_enc_codelen(cc, enc);
944
- if (len <= 0) rb_enc_uint_chr(cc, enc);
974
+ if (len <= 0) {
975
+ rb_enc_uint_chr(cc, enc); /* to raise an exception */
976
+ UNREACHABLE;
977
+ }
945
978
  rb_enc_mbcput(cc, buf, enc);
946
979
  return strio_unget_bytes(ptr, buf, len);
947
980
  }
948
981
  else {
949
- SafeStringValue(c);
982
+ StringValue(c);
983
+ if (RSTRING_LEN(c) == 0) return Qnil;
950
984
  enc = rb_enc_get(ptr->string);
951
985
  enc2 = rb_enc_get(c);
952
986
  if (enc != enc2 && enc != rb_ascii8bit_encoding()) {
953
987
  c = rb_str_conv_enc(c, enc2, enc);
954
988
  }
955
- strio_unget_bytes(ptr, RSTRING_PTR(c), RSTRING_LEN(c));
956
- RB_GC_GUARD(c);
989
+ strio_unget_string(ptr, c);
957
990
  return Qnil;
958
991
  }
959
992
  }
@@ -971,21 +1004,17 @@ strio_ungetbyte(VALUE self, VALUE c)
971
1004
  struct StringIO *ptr = readable(self);
972
1005
 
973
1006
  check_modifiable(ptr);
1007
+ if (NIL_P(ptr->string)) return Qnil;
974
1008
  if (NIL_P(c)) return Qnil;
975
1009
  if (RB_INTEGER_TYPE_P(c)) {
976
- /* rb_int_and() not visible from exts */
977
- VALUE v = rb_funcall(c, '&', 1, INT2FIX(0xff));
978
- const char cc = NUM2INT(v) & 0xFF;
979
- strio_unget_bytes(ptr, &cc, 1);
1010
+ /* rb_int_and() not visible from exts */
1011
+ VALUE v = rb_funcall(c, '&', 1, INT2FIX(0xff));
1012
+ const char cc = NUM2INT(v) & 0xFF;
1013
+ strio_unget_bytes(ptr, &cc, 1);
980
1014
  }
981
1015
  else {
982
- long cl;
983
- SafeStringValue(c);
984
- cl = RSTRING_LEN(c);
985
- if (cl > 0) {
986
- strio_unget_bytes(ptr, RSTRING_PTR(c), cl);
987
- RB_GC_GUARD(c);
988
- }
1016
+ StringValue(c);
1017
+ strio_unget_string(ptr, c);
989
1018
  }
990
1019
  return Qnil;
991
1020
  }
@@ -1016,7 +1045,7 @@ strio_unget_bytes(struct StringIO *ptr, const char *cp, long cl)
1016
1045
  if (rest > cl) memset(s + len, 0, rest - cl);
1017
1046
  pos -= cl;
1018
1047
  }
1019
- memcpy(s + pos, cp, cl);
1048
+ memcpy(s + pos, (cp ? cp : s), cl);
1020
1049
  ptr->pos = pos;
1021
1050
  return Qnil;
1022
1051
  }
@@ -1157,41 +1186,41 @@ prepare_getline_args(struct StringIO *ptr, struct getline_arg *arg, int argc, VA
1157
1186
  break;
1158
1187
 
1159
1188
  case 1:
1160
- if (!NIL_P(rs) && !RB_TYPE_P(rs, T_STRING)) {
1161
- VALUE tmp = rb_check_string_type(rs);
1189
+ if (!NIL_P(rs) && !RB_TYPE_P(rs, T_STRING)) {
1190
+ VALUE tmp = rb_check_string_type(rs);
1162
1191
  if (NIL_P(tmp)) {
1163
- limit = NUM2LONG(rs);
1164
- rs = rb_rs;
1192
+ limit = NUM2LONG(rs);
1193
+ rs = rb_rs;
1165
1194
  }
1166
1195
  else {
1167
- rs = tmp;
1196
+ rs = tmp;
1168
1197
  }
1169
1198
  }
1170
1199
  break;
1171
1200
 
1172
1201
  case 2:
1173
- if (!NIL_P(rs)) StringValue(rs);
1202
+ if (!NIL_P(rs)) StringValue(rs);
1174
1203
  if (!NIL_P(lim)) limit = NUM2LONG(lim);
1175
1204
  break;
1176
1205
  }
1177
- if (!NIL_P(rs)) {
1178
- rb_encoding *enc_rs, *enc_io;
1179
- enc_rs = rb_enc_get(rs);
1180
- enc_io = get_enc(ptr);
1181
- if (enc_rs != enc_io &&
1182
- (rb_enc_str_coderange(rs) != ENC_CODERANGE_7BIT ||
1183
- (RSTRING_LEN(rs) > 0 && !rb_enc_asciicompat(enc_io)))) {
1184
- if (rs == rb_rs) {
1185
- rs = rb_enc_str_new(0, 0, enc_io);
1186
- rb_str_buf_cat_ascii(rs, "\n");
1187
- rs = rs;
1188
- }
1189
- else {
1190
- rb_raise(rb_eArgError, "encoding mismatch: %s IO with %s RS",
1191
- rb_enc_name(enc_io),
1192
- rb_enc_name(enc_rs));
1193
- }
1194
- }
1206
+ if (!NIL_P(ptr->string) && !NIL_P(rs)) {
1207
+ rb_encoding *enc_rs, *enc_io;
1208
+ enc_rs = rb_enc_get(rs);
1209
+ enc_io = get_enc(ptr);
1210
+ if (enc_rs != enc_io &&
1211
+ (rb_enc_str_coderange(rs) != ENC_CODERANGE_7BIT ||
1212
+ (RSTRING_LEN(rs) > 0 && !rb_enc_asciicompat(enc_io)))) {
1213
+ if (rs == rb_rs) {
1214
+ rs = rb_enc_str_new(0, 0, enc_io);
1215
+ rb_str_buf_cat_ascii(rs, "\n");
1216
+ rs = rs;
1217
+ }
1218
+ else {
1219
+ rb_raise(rb_eArgError, "encoding mismatch: %s IO with %s RS",
1220
+ rb_enc_name(enc_io),
1221
+ rb_enc_name(enc_rs));
1222
+ }
1223
+ }
1195
1224
  }
1196
1225
  arg->rs = rs;
1197
1226
  arg->limit = limit;
@@ -1203,9 +1232,9 @@ prepare_getline_args(struct StringIO *ptr, struct getline_arg *arg, int argc, VA
1203
1232
  keywords[0] = rb_intern_const("chomp");
1204
1233
  }
1205
1234
  rb_get_kwargs(opts, keywords, 0, 1, &vchomp);
1206
- if (respect_chomp) {
1235
+ if (respect_chomp) {
1207
1236
  arg->chomp = (vchomp != Qundef) && RTEST(vchomp);
1208
- }
1237
+ }
1209
1238
  }
1210
1239
  return arg;
1211
1240
  }
@@ -1229,7 +1258,7 @@ strio_getline(struct getline_arg *arg, struct StringIO *ptr)
1229
1258
  long w = 0;
1230
1259
  rb_encoding *enc = get_enc(ptr);
1231
1260
 
1232
- if (ptr->pos >= (n = RSTRING_LEN(ptr->string))) {
1261
+ if (NIL_P(ptr->string) || ptr->pos >= (n = RSTRING_LEN(ptr->string))) {
1233
1262
  return Qnil;
1234
1263
  }
1235
1264
  s = RSTRING_PTR(ptr->string);
@@ -1245,7 +1274,7 @@ strio_getline(struct getline_arg *arg, struct StringIO *ptr)
1245
1274
  str = strio_substr(ptr, ptr->pos, e - s - w, enc);
1246
1275
  }
1247
1276
  else if ((n = RSTRING_LEN(str)) == 0) {
1248
- const char *paragraph_end = NULL;
1277
+ const char *paragraph_end = NULL;
1249
1278
  p = s;
1250
1279
  while (p[(p + 1 < e) && (*p == '\r') && 0] == '\n') {
1251
1280
  p += *p == '\r';
@@ -1255,18 +1284,18 @@ strio_getline(struct getline_arg *arg, struct StringIO *ptr)
1255
1284
  }
1256
1285
  s = p;
1257
1286
  while ((p = memchr(p, '\n', e - p)) && (p != e)) {
1258
- p++;
1259
- if (!((p < e && *p == '\n') ||
1260
- (p + 1 < e && *p == '\r' && *(p+1) == '\n'))) {
1261
- continue;
1262
- }
1263
- paragraph_end = p - ((*(p-2) == '\r') ? 2 : 1);
1264
- while ((p < e && *p == '\n') ||
1265
- (p + 1 < e && *p == '\r' && *(p+1) == '\n')) {
1266
- p += (*p == '\r') ? 2 : 1;
1267
- }
1268
- e = p;
1269
- break;
1287
+ p++;
1288
+ if (!((p < e && *p == '\n') ||
1289
+ (p + 1 < e && *p == '\r' && *(p+1) == '\n'))) {
1290
+ continue;
1291
+ }
1292
+ paragraph_end = p - ((*(p-2) == '\r') ? 2 : 1);
1293
+ while ((p < e && *p == '\n') ||
1294
+ (p + 1 < e && *p == '\r' && *(p+1) == '\n')) {
1295
+ p += (*p == '\r') ? 2 : 1;
1296
+ }
1297
+ e = p;
1298
+ break;
1270
1299
  }
1271
1300
  if (arg->chomp && paragraph_end) {
1272
1301
  w = e - paragraph_end;
@@ -1326,6 +1355,7 @@ strio_gets(int argc, VALUE *argv, VALUE self)
1326
1355
  VALUE str;
1327
1356
 
1328
1357
  if (prepare_getline_args(ptr, &arg, argc, argv)->limit == 0) {
1358
+ if (NIL_P(ptr->string)) return Qnil;
1329
1359
  return rb_enc_str_new(0, 0, get_enc(ptr));
1330
1360
  }
1331
1361
 
@@ -1440,6 +1470,7 @@ strio_write(VALUE self, VALUE str)
1440
1470
  if (!RB_TYPE_P(str, T_STRING))
1441
1471
  str = rb_obj_as_string(str);
1442
1472
  enc = get_enc(ptr);
1473
+ if (!enc) return 0;
1443
1474
  enc2 = rb_enc_get(str);
1444
1475
  if (enc != enc2 && enc != ascii8bit && enc != (usascii = rb_usascii_encoding())) {
1445
1476
  VALUE converted = rb_str_conv_enc(str, enc2, enc);
@@ -1465,6 +1496,7 @@ strio_write(VALUE self, VALUE str)
1465
1496
  }
1466
1497
  else {
1467
1498
  strio_extend(ptr, ptr->pos, len);
1499
+ rb_str_modify(ptr->string);
1468
1500
  memmove(RSTRING_PTR(ptr->string)+ptr->pos, RSTRING_PTR(str), len);
1469
1501
  }
1470
1502
  RB_GC_GUARD(str);
@@ -1511,10 +1543,12 @@ strio_putc(VALUE self, VALUE ch)
1511
1543
 
1512
1544
  check_modifiable(ptr);
1513
1545
  if (RB_TYPE_P(ch, T_STRING)) {
1546
+ if (NIL_P(ptr->string)) return ch;
1514
1547
  str = rb_str_substr(ch, 0, 1);
1515
1548
  }
1516
1549
  else {
1517
1550
  char c = NUM2CHR(ch);
1551
+ if (NIL_P(ptr->string)) return ch;
1518
1552
  str = rb_str_new(&c, 1);
1519
1553
  }
1520
1554
  strio_write(self, str);
@@ -1557,7 +1591,8 @@ strio_read(int argc, VALUE *argv, VALUE self)
1557
1591
  if (len < 0) {
1558
1592
  rb_raise(rb_eArgError, "negative length %ld given", len);
1559
1593
  }
1560
- if (len > 0 && ptr->pos >= RSTRING_LEN(ptr->string)) {
1594
+ if (len > 0 &&
1595
+ (NIL_P(ptr->string) || ptr->pos >= RSTRING_LEN(ptr->string))) {
1561
1596
  if (!NIL_P(str)) rb_str_resize(str, 0);
1562
1597
  return Qnil;
1563
1598
  }
@@ -1566,6 +1601,7 @@ strio_read(int argc, VALUE *argv, VALUE self)
1566
1601
  }
1567
1602
  /* fall through */
1568
1603
  case 0:
1604
+ if (NIL_P(ptr->string)) return Qnil;
1569
1605
  len = RSTRING_LEN(ptr->string);
1570
1606
  if (len <= ptr->pos) {
1571
1607
  rb_encoding *enc = get_enc(ptr);
@@ -1583,7 +1619,7 @@ strio_read(int argc, VALUE *argv, VALUE self)
1583
1619
  }
1584
1620
  break;
1585
1621
  default:
1586
- rb_error_arity(argc, 0, 2);
1622
+ rb_error_arity(argc, 0, 2);
1587
1623
  }
1588
1624
  if (NIL_P(str)) {
1589
1625
  rb_encoding *enc = binary ? rb_ascii8bit_encoding() : get_enc(ptr);
@@ -1594,10 +1630,9 @@ strio_read(int argc, VALUE *argv, VALUE self)
1594
1630
  if (len > rest) len = rest;
1595
1631
  rb_str_resize(str, len);
1596
1632
  MEMCPY(RSTRING_PTR(str), RSTRING_PTR(ptr->string) + ptr->pos, char, len);
1597
- if (binary)
1598
- rb_enc_associate(str, rb_ascii8bit_encoding());
1599
- else
1633
+ if (!binary) {
1600
1634
  rb_enc_copy(str, ptr->string);
1635
+ }
1601
1636
  }
1602
1637
  ptr->pos += RSTRING_LEN(str);
1603
1638
  return str;
@@ -1619,28 +1654,28 @@ strio_pread(int argc, VALUE *argv, VALUE self)
1619
1654
  long offset = NUM2LONG(rb_offset);
1620
1655
 
1621
1656
  if (len < 0) {
1622
- rb_raise(rb_eArgError, "negative string size (or size too big): %" PRIsVALUE, rb_len);
1657
+ rb_raise(rb_eArgError, "negative string size (or size too big): %" PRIsVALUE, rb_len);
1623
1658
  }
1624
1659
 
1625
1660
  if (len == 0) {
1626
- if (NIL_P(rb_buf)) {
1627
- return rb_str_new("", 0);
1628
- }
1629
- return rb_buf;
1661
+ if (NIL_P(rb_buf)) {
1662
+ return rb_str_new("", 0);
1663
+ }
1664
+ return rb_buf;
1630
1665
  }
1631
1666
 
1632
1667
  if (offset < 0) {
1633
- rb_syserr_fail_str(EINVAL, rb_sprintf("pread: Invalid offset argument: %" PRIsVALUE, rb_offset));
1668
+ rb_syserr_fail_str(EINVAL, rb_sprintf("pread: Invalid offset argument: %" PRIsVALUE, rb_offset));
1634
1669
  }
1635
1670
 
1636
1671
  struct StringIO *ptr = readable(self);
1637
1672
 
1638
1673
  if (offset >= RSTRING_LEN(ptr->string)) {
1639
- rb_eof_error();
1674
+ rb_eof_error();
1640
1675
  }
1641
1676
 
1642
1677
  if (NIL_P(rb_buf)) {
1643
- return strio_substr(ptr, offset, len, rb_ascii8bit_encoding());
1678
+ return strio_substr(ptr, offset, len, rb_ascii8bit_encoding());
1644
1679
  }
1645
1680
 
1646
1681
  long rest = RSTRING_LEN(ptr->string) - offset;
@@ -1700,8 +1735,14 @@ strio_read_nonblock(int argc, VALUE *argv, VALUE self)
1700
1735
  return val;
1701
1736
  }
1702
1737
 
1738
+ /*
1739
+ * See IO#write
1740
+ */
1703
1741
  #define strio_syswrite rb_io_write
1704
1742
 
1743
+ /*
1744
+ * See IO#write_nonblock
1745
+ */
1705
1746
  static VALUE
1706
1747
  strio_syswrite_nonblock(int argc, VALUE *argv, VALUE self)
1707
1748
  {
@@ -1729,7 +1770,7 @@ strio_size(VALUE self)
1729
1770
  {
1730
1771
  VALUE string = StringIO(self)->string;
1731
1772
  if (NIL_P(string)) {
1732
- rb_raise(rb_eIOError, "not opened");
1773
+ return INT2FIX(0);
1733
1774
  }
1734
1775
  return ULONG2NUM(RSTRING_LEN(string));
1735
1776
  }
@@ -1746,10 +1787,12 @@ strio_truncate(VALUE self, VALUE len)
1746
1787
  {
1747
1788
  VALUE string = writable(self)->string;
1748
1789
  long l = NUM2LONG(len);
1749
- long plen = RSTRING_LEN(string);
1790
+ long plen;
1750
1791
  if (l < 0) {
1751
1792
  error_inval("negative length");
1752
1793
  }
1794
+ if (NIL_P(string)) return 0;
1795
+ plen = RSTRING_LEN(string);
1753
1796
  rb_str_resize(string, l);
1754
1797
  if (plen < l) {
1755
1798
  MEMZERO(RSTRING_PTR(string) + plen, char, l - plen);
@@ -1813,20 +1856,30 @@ strio_set_encoding(int argc, VALUE *argv, VALUE self)
1813
1856
  enc = rb_find_encoding(ext_enc);
1814
1857
  if (!enc) {
1815
1858
  rb_io_enc_t convconfig;
1816
- int oflags, fmode;
1859
+ int oflags;
1860
+ rb_io_mode_t fmode;
1817
1861
  VALUE vmode = rb_str_append(rb_str_new_cstr("r:"), ext_enc);
1818
1862
  rb_io_extract_modeenc(&vmode, 0, Qnil, &oflags, &fmode, &convconfig);
1819
1863
  enc = convconfig.enc2;
1820
1864
  }
1821
1865
  }
1822
1866
  ptr->enc = enc;
1823
- if (WRITABLE(self)) {
1867
+ if (!NIL_P(ptr->string) && WRITABLE(self)) {
1824
1868
  rb_enc_associate(ptr->string, enc);
1825
1869
  }
1826
1870
 
1827
1871
  return self;
1828
1872
  }
1829
1873
 
1874
+ /*
1875
+ * call-seq:
1876
+ * strio.set_encoding_by_bom => strio or nil
1877
+ *
1878
+ * Sets the encoding according to the BOM (Byte Order Mark) in the
1879
+ * string.
1880
+ *
1881
+ * Returns +self+ if the BOM is found, otherwise +nil.
1882
+ */
1830
1883
  static VALUE
1831
1884
  strio_set_encoding_by_bom(VALUE self)
1832
1885
  {
@@ -1859,10 +1912,15 @@ Init_stringio(void)
1859
1912
 
1860
1913
  VALUE StringIO = rb_define_class("StringIO", rb_cObject);
1861
1914
 
1915
+ /* The version string */
1862
1916
  rb_define_const(StringIO, "VERSION", rb_str_new_cstr(STRINGIO_VERSION));
1863
1917
 
1864
1918
  rb_include_module(StringIO, rb_mEnumerable);
1865
1919
  rb_define_alloc_func(StringIO, strio_s_allocate);
1920
+
1921
+ /* Maximum length that a StringIO instance can hold */
1922
+ rb_define_const(StringIO, "MAX_LENGTH", LONG2NUM(LONG_MAX));
1923
+
1866
1924
  rb_define_singleton_method(StringIO, "new", strio_s_new, -1);
1867
1925
  rb_define_singleton_method(StringIO, "open", strio_s_open, -1);
1868
1926
  rb_define_method(StringIO, "initialize", strio_initialize, -1);
metadata CHANGED
@@ -1,15 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: stringio
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.1.0
4
+ version: 3.1.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nobu Nakada
8
8
  - Charles Oliver Nutter
9
- autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2023-11-28 00:00:00.000000000 Z
11
+ date: 2025-04-21 00:00:00.000000000 Z
13
12
  dependencies: []
14
13
  description: Pseudo `IO` class from/to `String`.
15
14
  email:
@@ -18,17 +17,32 @@ email:
18
17
  executables: []
19
18
  extensions:
20
19
  - ext/stringio/extconf.rb
21
- extra_rdoc_files: []
20
+ extra_rdoc_files:
21
+ - ".document"
22
+ - ".rdoc_options"
23
+ - COPYING
24
+ - LICENSE.txt
25
+ - NEWS.md
26
+ - README.md
27
+ - docs/io.rb
28
+ - ext/stringio/.document
22
29
  files:
30
+ - ".document"
31
+ - ".rdoc_options"
32
+ - COPYING
33
+ - LICENSE.txt
34
+ - NEWS.md
23
35
  - README.md
36
+ - docs/io.rb
37
+ - ext/stringio/.document
24
38
  - ext/stringio/extconf.rb
25
39
  - ext/stringio/stringio.c
26
40
  homepage: https://github.com/ruby/stringio
27
41
  licenses:
28
42
  - Ruby
29
43
  - BSD-2-Clause
30
- metadata: {}
31
- post_install_message:
44
+ metadata:
45
+ changelog_uri: https://github.com/ruby/stringio/releases/tag/v3.1.7
32
46
  rdoc_options: []
33
47
  require_paths:
34
48
  - lib
@@ -43,8 +57,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
43
57
  - !ruby/object:Gem::Version
44
58
  version: '0'
45
59
  requirements: []
46
- rubygems_version: 3.4.10
47
- signing_key:
60
+ rubygems_version: 3.6.7
48
61
  specification_version: 4
49
62
  summary: Pseudo IO on String
50
63
  test_files: []