summaryrefslogtreecommitdiff
path: root/ext/stringio
diff options
context:
space:
mode:
Diffstat (limited to 'ext/stringio')
-rw-r--r--ext/stringio/.cvsignore1
-rw-r--r--ext/stringio/README3
-rw-r--r--ext/stringio/depend5
-rw-r--r--ext/stringio/stringio.c808
4 files changed, 488 insertions, 329 deletions
diff --git a/ext/stringio/.cvsignore b/ext/stringio/.cvsignore
index 4088712231..814345ece8 100644
--- a/ext/stringio/.cvsignore
+++ b/ext/stringio/.cvsignore
@@ -1,3 +1,4 @@
Makefile
mkmf.log
*.def
+extconf.h
diff --git a/ext/stringio/README b/ext/stringio/README
index 190052309c..10dd237de8 100644
--- a/ext/stringio/README
+++ b/ext/stringio/README
@@ -1,6 +1,5 @@
-*- rd -*-
-$Author: nobu $
-$Date: 2002/02/19 13:16:24 $
+$Author$
=begin
diff --git a/ext/stringio/depend b/ext/stringio/depend
index cc9eae3f55..338ebde529 100644
--- a/ext/stringio/depend
+++ b/ext/stringio/depend
@@ -1,2 +1,3 @@
-stringio.o: stringio.c $(hdrdir)/ruby.h $(topdir)/config.h \
- $(hdrdir)/defines.h $(hdrdir)/intern.h $(hdrdir)/rubyio.h
+stringio.o: stringio.c $(hdrdir)/ruby/ruby.h $(arch_hdrdir)/ruby/config.h \
+ $(hdrdir)/ruby/defines.h $(hdrdir)/ruby/intern.h $(hdrdir)/ruby/io.h \
+ $(hdrdir)/ruby/encoding.h
diff --git a/ext/stringio/stringio.c b/ext/stringio/stringio.c
index 09867009b5..3ca5001fe0 100644
--- a/ext/stringio/stringio.c
+++ b/ext/stringio/stringio.c
@@ -2,8 +2,7 @@
stringio.c -
- $Author: nobu $
- $Date: 2005/08/13 09:36:12 $
+ $Author$
$RoughId: stringio.c,v 1.13 2002/03/14 03:24:18 nobu Exp $
created at: Tue Feb 19 04:10:38 JST 2002
@@ -13,15 +12,14 @@
**********************************************************************/
#include "ruby.h"
-#include "rubyio.h"
+#include "ruby/io.h"
+#include "ruby/encoding.h"
#if defined(HAVE_FCNTL_H) || defined(_WIN32)
#include <fcntl.h>
#elif defined(HAVE_SYS_FCNTL_H)
#include <sys/fcntl.h>
#endif
-#define STRIO_EOF FMODE_SYNC
-
struct StringIO {
VALUE string;
long pos;
@@ -30,20 +28,13 @@ struct StringIO {
int count;
};
-static struct StringIO* strio_alloc _((void));
-static void strio_mark _((struct StringIO *));
-static void strio_free _((struct StringIO *));
-static struct StringIO* check_strio _((VALUE));
-static struct StringIO* get_strio _((VALUE));
-static struct StringIO* readable _((struct StringIO *));
-static struct StringIO* writable _((struct StringIO *));
-static void check_modifiable _((struct StringIO *));
+static void strio_init(int, VALUE *, struct StringIO *);
-#define IS_STRIO(obj) (RDATA(obj)->dmark == (RUBY_DATA_FUNC)strio_mark)
+#define IS_STRIO(obj) (rb_typeddata_is_kind_of(obj, &strio_data_type))
#define error_inval(msg) (errno = EINVAL, rb_sys_fail(msg))
static struct StringIO *
-strio_alloc()
+strio_alloc(void)
{
struct StringIO *ptr = ALLOC(struct StringIO);
ptr->string = Qnil;
@@ -55,40 +46,44 @@ strio_alloc()
}
static void
-strio_mark(ptr)
- struct StringIO *ptr;
+strio_mark(void *p)
{
+ struct StringIO *ptr = p;
if (ptr) {
rb_gc_mark(ptr->string);
}
}
static void
-strio_free(ptr)
- struct StringIO *ptr;
+strio_free(void *p)
{
+ struct StringIO *ptr = p;
if (--ptr->count <= 0) {
xfree(ptr);
}
}
-static struct StringIO*
-check_strio(self)
- VALUE self;
+static size_t
+strio_memsize(const void *p)
{
- Check_Type(self, T_DATA);
- if (!IS_STRIO(self)) {
- rb_raise(rb_eTypeError, "wrong argument type %s (expected StringIO)",
- rb_class2name(CLASS_OF(self)));
- }
- return DATA_PTR(self);
+ const struct StringIO *ptr = p;
+ if (!ptr) return 0;
+ return sizeof(struct StringIO);
}
+static const rb_data_type_t strio_data_type = {
+ "strio",
+ strio_mark,
+ strio_free,
+ strio_memsize,
+};
+
+#define check_strio(self) ((struct StringIO*)rb_check_typeddata(self, &strio_data_type))
+
static struct StringIO*
-get_strio(self)
- VALUE self;
+get_strio(VALUE self)
{
- struct StringIO *ptr = check_strio(self);
+ struct StringIO *ptr = check_strio(rb_io_taint_check(self));
if (!ptr) {
rb_raise(rb_eIOError, "uninitialized stream");
@@ -96,6 +91,18 @@ get_strio(self)
return ptr;
}
+static VALUE
+strio_substr(struct StringIO *ptr, long pos, long len)
+{
+ VALUE str = ptr->string;
+ rb_encoding *enc = rb_enc_get(str);
+ long rlen = RSTRING_LEN(str) - pos;
+
+ if (len > rlen) len = rlen;
+ if (len < 0) len = 0;
+ return rb_enc_str_new(RSTRING_PTR(str)+pos, len, enc);
+}
+
#define StringIO(obj) get_strio(obj)
#define CLOSED(ptr) (!((ptr)->flags & FMODE_READWRITE))
@@ -103,8 +110,7 @@ get_strio(self)
#define WRITABLE(ptr) ((ptr)->flags & FMODE_WRITABLE)
static struct StringIO*
-readable(ptr)
- struct StringIO *ptr;
+readable(struct StringIO *ptr)
{
if (!READABLE(ptr)) {
rb_raise(rb_eIOError, "not opened for reading");
@@ -113,8 +119,7 @@ readable(ptr)
}
static struct StringIO*
-writable(ptr)
- struct StringIO *ptr;
+writable(struct StringIO *ptr)
{
if (!WRITABLE(ptr)) {
rb_raise(rb_eIOError, "not opened for writing");
@@ -126,83 +131,17 @@ writable(ptr)
}
static void
-check_modifiable(ptr)
- struct StringIO *ptr;
+check_modifiable(struct StringIO *ptr)
{
if (OBJ_FROZEN(ptr->string)) {
rb_raise(rb_eIOError, "not modifiable string");
}
}
-static VALUE strio_s_allocate _((VALUE));
-static VALUE strio_s_open _((int, VALUE *, VALUE));
-static VALUE strio_initialize _((int, VALUE *, VALUE));
-static VALUE strio_finalize _((VALUE));
-static VALUE strio_self _((VALUE));
-static VALUE strio_false _((VALUE));
-static VALUE strio_nil _((VALUE));
-static VALUE strio_0 _((VALUE));
-static VALUE strio_first _((VALUE, VALUE));
-static VALUE strio_unimpl _((int, VALUE *, VALUE));
-static VALUE strio_get_string _((VALUE));
-static VALUE strio_set_string _((VALUE, VALUE));
-static VALUE strio_close _((VALUE));
-static VALUE strio_close_read _((VALUE));
-static VALUE strio_close_write _((VALUE));
-static VALUE strio_closed _((VALUE));
-static VALUE strio_closed_read _((VALUE));
-static VALUE strio_closed_write _((VALUE));
-static VALUE strio_eof _((VALUE));
-static VALUE strio_get_lineno _((VALUE));
-static VALUE strio_set_lineno _((VALUE, VALUE));
-static VALUE strio_get_pos _((VALUE));
-static VALUE strio_set_pos _((VALUE, VALUE));
-static VALUE strio_rewind _((VALUE));
-static VALUE strio_seek _((int, VALUE *, VALUE));
-static VALUE strio_get_sync _((VALUE));
-static VALUE strio_each_byte _((VALUE));
-static VALUE strio_getc _((VALUE));
-static VALUE strio_ungetc _((VALUE, VALUE));
-static VALUE strio_readchar _((VALUE));
-static VALUE strio_getline _((int, VALUE *, struct StringIO *));
-static VALUE strio_gets _((int, VALUE *, VALUE));
-static VALUE strio_readline _((int, VALUE *, VALUE));
-static VALUE strio_each _((int, VALUE *, VALUE));
-static VALUE strio_readlines _((int, VALUE *, VALUE));
-static VALUE strio_write _((VALUE, VALUE));
-static VALUE strio_putc _((VALUE, VALUE));
-static VALUE strio_read _((int, VALUE *, VALUE));
-static VALUE strio_size _((VALUE));
-static VALUE strio_truncate _((VALUE, VALUE));
-void Init_stringio _((void));
-
-/* Boyer-Moore search: copied from regex.c */
-static void bm_init_skip _((long *, const char *, long));
-static long bm_search _((const char *, long, const char *, long, const long *));
-
-static VALUE
-strio_s_allocate(klass)
- VALUE klass;
-{
- return Data_Wrap_Struct(klass, strio_mark, strio_free, 0);
-}
-
-/*
- * call-seq: StringIO.open(string=""[, mode]) {|strio| ...}
- *
- * Equivalent to StringIO.new except that when it is called with a block, it
- * yields with the new instance and closes it, and returns the result which
- * returned from the block.
- */
static VALUE
-strio_s_open(argc, argv, klass)
- int argc;
- VALUE *argv;
- VALUE klass;
+strio_s_allocate(VALUE klass)
{
- VALUE obj = rb_class_new_instance(argc, argv, klass);
- if (!rb_block_given_p()) return obj;
- return rb_ensure(rb_yield, obj, strio_finalize, obj);
+ return TypedData_Wrap_Struct(klass, &strio_data_type, 0);
}
/*
@@ -211,19 +150,24 @@ strio_s_open(argc, argv, klass)
* Creates new StringIO instance from with _string_ and _mode_.
*/
static VALUE
-strio_initialize(argc, argv, self)
- int argc;
- VALUE *argv;
- VALUE self;
+strio_initialize(int argc, VALUE *argv, VALUE self)
{
struct StringIO *ptr = check_strio(self);
- VALUE string, mode;
- int trunc = Qfalse;
if (!ptr) {
DATA_PTR(self) = ptr = strio_alloc();
}
rb_call_super(0, 0);
+ strio_init(argc, argv, ptr);
+ return self;
+}
+
+static void
+strio_init(int argc, VALUE *argv, struct StringIO *ptr)
+{
+ VALUE string, mode;
+ int trunc = 0;
+
switch (rb_scan_args(argc, argv, "02", &string, &mode)) {
case 2:
if (FIXNUM_P(mode)) {
@@ -250,17 +194,17 @@ strio_initialize(argc, argv, self)
ptr->flags = OBJ_FROZEN(string) ? FMODE_READABLE : FMODE_READWRITE;
break;
case 0:
- string = rb_str_new("", 0);
+ string = rb_enc_str_new("", 0, rb_default_external_encoding());
ptr->flags = FMODE_READWRITE;
break;
}
ptr->string = string;
- return self;
+ ptr->pos = 0;
+ ptr->lineno = 0;
}
static VALUE
-strio_finalize(self)
- VALUE self;
+strio_finalize(VALUE self)
{
struct StringIO *ptr = StringIO(self);
ptr->string = Qnil;
@@ -269,11 +213,25 @@ strio_finalize(self)
}
/*
+ * call-seq: StringIO.open(string=""[, mode]) {|strio| ...}
+ *
+ * Equivalent to StringIO.new except that when it is called with a block, it
+ * yields with the new instance and closes it, and returns the result which
+ * returned from the block.
+ */
+static VALUE
+strio_s_open(int argc, VALUE *argv, VALUE klass)
+{
+ VALUE obj = rb_class_new_instance(argc, argv, klass);
+ if (!rb_block_given_p()) return obj;
+ return rb_ensure(rb_yield, obj, strio_finalize, obj);
+}
+
+/*
* Returns +false+. Just for compatibility to IO.
*/
static VALUE
-strio_false(self)
- VALUE self;
+strio_false(VALUE self)
{
StringIO(self);
return Qfalse;
@@ -283,8 +241,7 @@ strio_false(self)
* Returns +nil+. Just for compatibility to IO.
*/
static VALUE
-strio_nil(self)
- VALUE self;
+strio_nil(VALUE self)
{
StringIO(self);
return Qnil;
@@ -294,8 +251,7 @@ strio_nil(self)
* Returns *strio* itself. Just for compatibility to IO.
*/
static VALUE
-strio_self(self)
- VALUE self;
+strio_self(VALUE self)
{
StringIO(self);
return self;
@@ -305,8 +261,7 @@ strio_self(self)
* Returns 0. Just for compatibility to IO.
*/
static VALUE
-strio_0(self)
- VALUE self;
+strio_0(VALUE self)
{
StringIO(self);
return INT2FIX(0);
@@ -316,8 +271,7 @@ strio_0(self)
* Returns the argument unchanged. Just for compatibility to IO.
*/
static VALUE
-strio_first(self, arg)
- VALUE self, arg;
+strio_first(VALUE self, VALUE arg)
{
StringIO(self);
return arg;
@@ -327,10 +281,7 @@ strio_first(self, arg)
* Raises NotImplementedError.
*/
static VALUE
-strio_unimpl(argc, argv, self)
- int argc;
- VALUE *argv;
- VALUE self;
+strio_unimpl(int argc, VALUE *argv, VALUE self)
{
StringIO(self);
rb_notimplement();
@@ -343,8 +294,7 @@ strio_unimpl(argc, argv, self)
* Returns underlying String object, the subject of IO.
*/
static VALUE
-strio_get_string(self)
- VALUE self;
+strio_get_string(VALUE self)
{
return StringIO(self)->string;
}
@@ -356,12 +306,11 @@ strio_get_string(self)
* Changes underlying String object, the subject of IO.
*/
static VALUE
-strio_set_string(self, string)
- VALUE self, string;
+strio_set_string(VALUE self, VALUE string)
{
struct StringIO *ptr = StringIO(self);
- if (!OBJ_TAINTED(self)) rb_secure(4);
+ rb_io_taint_check(self);
ptr->flags &= ~FMODE_READWRITE;
StringValue(string);
ptr->flags = OBJ_FROZEN(string) ? FMODE_READABLE : FMODE_READWRITE;
@@ -374,12 +323,11 @@ strio_set_string(self, string)
* call-seq:
* strio.close -> nil
*
- * Closes strio. The *strio* is unavailable for any further data
+ * Closes strio. The *strio* is unavailable for any further data
* operations; an +IOError+ is raised if such an attempt is made.
*/
static VALUE
-strio_close(self)
- VALUE self;
+strio_close(VALUE self)
{
struct StringIO *ptr = StringIO(self);
if (CLOSED(ptr)) {
@@ -397,8 +345,7 @@ strio_close(self)
* *strio* is not readable.
*/
static VALUE
-strio_close_read(self)
- VALUE self;
+strio_close_read(VALUE self)
{
struct StringIO *ptr = StringIO(self);
if (!READABLE(ptr)) {
@@ -416,8 +363,7 @@ strio_close_read(self)
* *strio* is not writeable.
*/
static VALUE
-strio_close_write(self)
- VALUE self;
+strio_close_write(VALUE self)
{
struct StringIO *ptr = StringIO(self);
if (!WRITABLE(ptr)) {
@@ -434,8 +380,7 @@ strio_close_write(self)
* Returns +true+ if *strio* is completely closed, +false+ otherwise.
*/
static VALUE
-strio_closed(self)
- VALUE self;
+strio_closed(VALUE self)
{
struct StringIO *ptr = StringIO(self);
if (!CLOSED(ptr)) return Qfalse;
@@ -449,8 +394,7 @@ strio_closed(self)
* Returns +true+ if *strio* is not readable, +false+ otherwise.
*/
static VALUE
-strio_closed_read(self)
- VALUE self;
+strio_closed_read(VALUE self)
{
struct StringIO *ptr = StringIO(self);
if (READABLE(ptr)) return Qfalse;
@@ -464,8 +408,7 @@ strio_closed_read(self)
* Returns +true+ if *strio* is not writable, +false+ otherwise.
*/
static VALUE
-strio_closed_write(self)
- VALUE self;
+strio_closed_write(VALUE self)
{
struct StringIO *ptr = StringIO(self);
if (WRITABLE(ptr)) return Qfalse;
@@ -477,22 +420,20 @@ strio_closed_write(self)
* strio.eof -> true or false
* strio.eof? -> true or false
*
- * Returns true if *strio* is at end of file. The stringio must be
+ * Returns true if *strio* is at end of file. The stringio must be
* opened for reading or an +IOError+ will be raised.
*/
static VALUE
-strio_eof(self)
- VALUE self;
+strio_eof(VALUE self)
{
struct StringIO *ptr = readable(StringIO(self));
- if (ptr->pos < RSTRING(ptr->string)->len) return Qfalse;
+ if (ptr->pos < RSTRING_LEN(ptr->string)) return Qfalse;
return Qtrue;
}
/* :nodoc: */
static VALUE
-strio_copy(copy, orig)
- VALUE copy, orig;
+strio_copy(VALUE copy, VALUE orig)
{
struct StringIO *ptr;
@@ -519,8 +460,7 @@ strio_copy(copy, orig)
* newline. See also the <code>$.</code> variable.
*/
static VALUE
-strio_get_lineno(self)
- VALUE self;
+strio_get_lineno(VALUE self)
{
return LONG2NUM(StringIO(self)->lineno);
}
@@ -533,8 +473,7 @@ strio_get_lineno(self)
* <code>$.</code> is updated only on the next read.
*/
static VALUE
-strio_set_lineno(self, lineno)
- VALUE self, lineno;
+strio_set_lineno(VALUE self, VALUE lineno)
{
StringIO(self)->lineno = NUM2LONG(lineno);
return lineno;
@@ -557,20 +496,18 @@ strio_set_lineno(self, lineno)
* strio.reopen(other_StrIO) -> strio
* strio.reopen(string, mode) -> strio
*
- * Reinitializes *strio* with the given <i>other_StrIO</i> or _string_
+ * Reinitializes *strio* with the given <i>other_StrIO</i> or _string_
* and _mode_ (see StringIO#new).
*/
static VALUE
-strio_reopen(argc, argv, self)
- int argc;
- VALUE *argv;
- VALUE self;
+strio_reopen(int argc, VALUE *argv, VALUE self)
{
- if (!OBJ_TAINTED(self)) rb_secure(4);
+ rb_io_taint_check(self);
if (argc == 1 && TYPE(*argv) != T_STRING) {
return strio_copy(self, *argv);
}
- return strio_initialize(argc, argv, self);
+ strio_init(argc, argv, StringIO(self));
+ return self;
}
/*
@@ -581,8 +518,7 @@ strio_reopen(argc, argv, self)
* Returns the current offset (in bytes) of *strio*.
*/
static VALUE
-strio_get_pos(self)
- VALUE self;
+strio_get_pos(VALUE self)
{
return LONG2NUM(StringIO(self)->pos);
}
@@ -594,9 +530,7 @@ strio_get_pos(self)
* Seeks to the given position (in bytes) in *strio*.
*/
static VALUE
-strio_set_pos(self, pos)
- VALUE self;
- VALUE pos;
+strio_set_pos(VALUE self, VALUE pos)
{
struct StringIO *ptr = StringIO(self);
long p = NUM2LONG(pos);
@@ -604,7 +538,6 @@ strio_set_pos(self, pos)
error_inval(0);
}
ptr->pos = p;
- ptr->flags &= ~STRIO_EOF;
return pos;
}
@@ -616,13 +549,11 @@ strio_set_pos(self, pos)
* +lineno+ to zero.
*/
static VALUE
-strio_rewind(self)
- VALUE self;
+strio_rewind(VALUE self)
{
struct StringIO *ptr = StringIO(self);
ptr->pos = 0;
ptr->lineno = 0;
- ptr->flags &= ~STRIO_EOF;
return INT2FIX(0);
}
@@ -634,10 +565,7 @@ strio_rewind(self)
* the value of _whence_ (see IO#seek).
*/
static VALUE
-strio_seek(argc, argv, self)
- int argc;
- VALUE *argv;
- VALUE self;
+strio_seek(int argc, VALUE *argv, VALUE self)
{
VALUE whence;
struct StringIO *ptr = StringIO(self);
@@ -645,6 +573,9 @@ strio_seek(argc, argv, self)
rb_scan_args(argc, argv, "11", NULL, &whence);
offset = NUM2LONG(argv[0]);
+ if (CLOSED(ptr)) {
+ rb_raise(rb_eIOError, "closed stream");
+ }
switch (NIL_P(whence) ? 0 : NUM2LONG(whence)) {
case 0:
break;
@@ -652,16 +583,15 @@ strio_seek(argc, argv, self)
offset += ptr->pos;
break;
case 2:
- offset += RSTRING(ptr->string)->len;
+ offset += RSTRING_LEN(ptr->string);
break;
default:
- rb_raise(rb_eArgError, "invalid whence %ld", NUM2LONG(whence));
+ error_inval("invalid whence");
}
if (offset < 0) {
error_inval(0);
}
ptr->pos = offset;
- ptr->flags &= ~STRIO_EOF;
return INT2FIX(0);
}
@@ -672,8 +602,7 @@ strio_seek(argc, argv, self)
* Returns +true+ always.
*/
static VALUE
-strio_get_sync(self)
- VALUE self;
+strio_get_sync(VALUE self)
{
StringIO(self);
return Qtrue;
@@ -686,55 +615,80 @@ strio_get_sync(self)
/*
* call-seq:
+ * strio.bytes {|byte| block } -> strio
+ * strio.bytes -> anEnumerator
+ *
* strio.each_byte {|byte| block } -> strio
+ * strio.each_byte -> anEnumerator
*
* See IO#each_byte.
*/
static VALUE
-strio_each_byte(self)
- VALUE self;
+strio_each_byte(VALUE self)
{
struct StringIO *ptr = readable(StringIO(self));
- while (ptr->pos < RSTRING(ptr->string)->len) {
- char c = RSTRING(ptr->string)->ptr[ptr->pos++];
+
+ RETURN_ENUMERATOR(self, 0, 0);
+
+ while (ptr->pos < RSTRING_LEN(ptr->string)) {
+ char c = RSTRING_PTR(ptr->string)[ptr->pos++];
rb_yield(CHR2FIX(c));
}
- return Qnil;
+ return self;
}
/*
* call-seq:
- * strio.getc -> fixnum or nil
+ * strio.getc -> string or nil
*
* See IO#getc.
*/
static VALUE
-strio_getc(self)
- VALUE self;
+strio_getc(VALUE self)
+{
+ struct StringIO *ptr = readable(StringIO(self));
+ rb_encoding *enc = rb_enc_get(ptr->string);
+ int len;
+ char *p;
+
+ if (ptr->pos >= RSTRING_LEN(ptr->string)) {
+ return Qnil;
+ }
+ p = RSTRING_PTR(ptr->string)+ptr->pos;
+ len = rb_enc_mbclen(p, RSTRING_END(ptr->string), enc);
+ ptr->pos += len;
+ return rb_enc_str_new(p, len, rb_enc_get(ptr->string));
+}
+
+/*
+ * call-seq:
+ * strio.getbyte -> fixnum or nil
+ *
+ * See IO#getbyte.
+ */
+static VALUE
+strio_getbyte(VALUE self)
{
struct StringIO *ptr = readable(StringIO(self));
int c;
- if (ptr->pos >= RSTRING(ptr->string)->len) {
- ptr->flags |= STRIO_EOF;
+ if (ptr->pos >= RSTRING_LEN(ptr->string)) {
return Qnil;
}
- c = RSTRING(ptr->string)->ptr[ptr->pos++];
+ c = RSTRING_PTR(ptr->string)[ptr->pos++];
return CHR2FIX(c);
}
static void
-strio_extend(ptr, pos, len)
- struct StringIO *ptr;
- long pos, len;
+strio_extend(struct StringIO *ptr, long pos, long len)
{
long olen;
check_modifiable(ptr);
- olen = RSTRING(ptr->string)->len;
+ olen = RSTRING_LEN(ptr->string);
if (pos + len > olen) {
rb_str_resize(ptr->string, pos + len);
if (pos > olen)
- MEMZERO(RSTRING(ptr->string)->ptr + olen, char, pos - olen);
+ MEMZERO(RSTRING_PTR(ptr->string) + olen, char, pos - olen);
}
else {
rb_str_modify(ptr->string);
@@ -743,56 +697,193 @@ strio_extend(ptr, pos, len)
/*
* call-seq:
- * strio.ungetc(integer) -> nil
+ * strio.ungetc(string) -> nil
*
* Pushes back one character (passed as a parameter) onto *strio*
- * such that a subsequent buffered read will return it. Pushing back
- * behind the beginning of the buffer string is not possible. Nothing
- * will be done if such an attempt is made.
- * In other case, there is no limitation for multiple pushbacks.
+ * such that a subsequent buffered read will return it. There is no
+ * limitation for multiple pushbacks including pushing back behind the
+ * beginning of the buffer string.
*/
static VALUE
-strio_ungetc(self, ch)
- VALUE self, ch;
+strio_ungetc(VALUE self, VALUE c)
{
struct StringIO *ptr = readable(StringIO(self));
- int cc = NUM2INT(ch);
- long len, pos = ptr->pos;
-
- if (cc != EOF && pos > 0) {
- if ((len = RSTRING(ptr->string)->len) < pos-- ||
- (unsigned char)RSTRING(ptr->string)->ptr[pos] !=
- (unsigned char)cc) {
- strio_extend(ptr, pos, 1);
- RSTRING(ptr->string)->ptr[pos] = cc;
- OBJ_INFECT(ptr->string, self);
+ long lpos, clen;
+ char *p, *pend;
+ rb_encoding *enc, *enc2;
+
+ if (NIL_P(c)) return Qnil;
+ if (FIXNUM_P(c)) {
+ int cc = FIX2INT(c);
+ char buf[16];
+
+ enc = rb_enc_get(ptr->string);
+ rb_enc_mbcput(cc, buf, enc);
+ c = rb_enc_str_new(buf, rb_enc_codelen(cc, enc), enc);
+ }
+ else {
+ SafeStringValue(c);
+ enc = rb_enc_get(ptr->string);
+ enc2 = rb_enc_get(c);
+ if (enc != enc2 && enc != rb_ascii8bit_encoding()) {
+ c = rb_str_conv_enc(c, enc2, enc);
+ }
+ }
+ if (RSTRING_LEN(ptr->string) < ptr->pos) {
+ long len = RSTRING_LEN(ptr->string);
+ rb_str_resize(ptr->string, ptr->pos - 1);
+ memset(RSTRING_PTR(ptr->string) + len, 0, ptr->pos - len - 1);
+ rb_str_concat(ptr->string, c);
+ ptr->pos--;
+ }
+ else {
+ /* get logical position */
+ lpos = 0; p = RSTRING_PTR(ptr->string); pend = p + ptr->pos;
+ for (;;) {
+ clen = rb_enc_mbclen(p, pend, enc);
+ if (p+clen >= pend) break;
+ p += clen;
+ lpos++;
}
- --ptr->pos;
- ptr->flags &= ~STRIO_EOF;
+ clen = p - RSTRING_PTR(ptr->string);
+ rb_str_update(ptr->string, lpos, ptr->pos ? 1 : 0, c);
+ ptr->pos = clen;
+ }
+
+ return Qnil;
+}
+
+/*
+ * call-seq:
+ * strio.ungetbyte(fixnum) -> nil
+ *
+ * See IO#ungetbyte
+ */
+static VALUE
+strio_ungetbyte(VALUE self, VALUE c)
+{
+ struct StringIO *ptr = readable(StringIO(self));
+ char buf[1], *cp = buf;
+ long pos = ptr->pos, cl = 1;
+ VALUE str = ptr->string;
+
+ if (NIL_P(c)) return Qnil;
+ if (FIXNUM_P(c)) {
+ buf[0] = (char)FIX2INT(c);
+ }
+ else {
+ SafeStringValue(c);
+ cp = RSTRING_PTR(c);
+ cl = RSTRING_LEN(c);
+ if (cl == 0) return Qnil;
+ }
+ rb_str_modify(str);
+ if (cl > pos) {
+ char *s;
+ long rest = RSTRING_LEN(str) - pos;
+ rb_str_resize(str, rest + cl);
+ s = RSTRING_PTR(str);
+ memmove(s + cl, s + pos, rest);
+ pos = 0;
}
+ else {
+ pos -= cl;
+ }
+ memcpy(RSTRING_PTR(str) + pos, cp, cl);
+ ptr->pos = pos;
+ RB_GC_GUARD(c);
return Qnil;
}
/*
* call-seq:
- * strio.readchar -> fixnum
+ * strio.readchar -> string
*
* See IO#readchar.
*/
static VALUE
-strio_readchar(self)
- VALUE self;
+strio_readchar(VALUE self)
{
VALUE c = strio_getc(self);
if (NIL_P(c)) rb_eof_error();
return c;
}
+/*
+ * call-seq:
+ * strio.readbyte -> fixnum
+ *
+ * See IO#readbyte.
+ */
+static VALUE
+strio_readbyte(VALUE self)
+{
+ VALUE c = strio_getbyte(self);
+ if (NIL_P(c)) rb_eof_error();
+ return c;
+}
+
+/*
+ * call-seq:
+ * strio.chars {|char| block } -> strio
+ * strio.chars -> anEnumerator
+ *
+ * strio.each_char {|char| block } -> strio
+ * strio.each_char -> anEnumerator
+ *
+ * See IO#each_char.
+ */
+static VALUE
+strio_each_char(VALUE self)
+{
+ VALUE c;
+
+ RETURN_ENUMERATOR(self, 0, 0);
+
+ while (!NIL_P(c = strio_getc(self))) {
+ rb_yield(c);
+ }
+ return self;
+}
+
+/*
+ * call-seq:
+ * strio.codepoints {|c| block } -> strio
+ * strio.codepoints -> anEnumerator
+ *
+ * strio.each_codepoint {|c| block } -> strio
+ * strio.each_codepoint -> anEnumerator
+ *
+ * See IO#each_codepoint.
+ */
+static VALUE
+strio_each_codepoint(VALUE self)
+{
+ struct StringIO *ptr;
+ rb_encoding *enc;
+ unsigned int c;
+ int n;
+
+ RETURN_ENUMERATOR(self, 0, 0);
+
+ ptr = readable(StringIO(self));
+ enc = rb_enc_get(ptr->string);
+ for (;;) {
+ if (ptr->pos >= RSTRING_LEN(ptr->string)) {
+ return self;
+ }
+
+ c = rb_enc_codepoint_len(RSTRING_PTR(ptr->string)+ptr->pos,
+ RSTRING_END(ptr->string), &n, enc);
+ rb_yield(UINT2NUM(c));
+ ptr->pos += n;
+ }
+ return self;
+}
+
+/* Boyer-Moore search: copied from regex.c */
static void
-bm_init_skip(skip, pat, m)
- long *skip;
- const char *pat;
- long m;
+bm_init_skip(long *skip, const char *pat, long m)
{
int c;
@@ -805,12 +896,7 @@ bm_init_skip(skip, pat, m)
}
static long
-bm_search(little, llen, big, blen, skip)
- const char *little;
- long llen;
- const char *big;
- long blen;
- const long *skip;
+bm_search(const char *little, long llen, const char *big, long blen, const long *skip)
{
long i, j, k;
@@ -829,61 +915,77 @@ bm_search(little, llen, big, blen, skip)
}
static VALUE
-strio_getline(argc, argv, ptr)
- int argc;
- VALUE *argv;
- struct StringIO *ptr;
+strio_getline(int argc, VALUE *argv, struct StringIO *ptr)
{
const char *s, *e, *p;
- long n;
- VALUE str;
+ long n, limit = 0;
+ VALUE str, lim;
- if (argc == 0) {
+ rb_scan_args(argc, argv, "02", &str, &lim);
+ switch (argc) {
+ case 0:
str = rb_rs;
- }
- else {
- rb_scan_args(argc, argv, "1", &str);
+ break;
+
+ case 1:
+ if (!NIL_P(str) && TYPE(str) != T_STRING) {
+ VALUE tmp = rb_check_string_type(str);
+ if (NIL_P(tmp)) {
+ limit = NUM2LONG(str);
+ if (limit == 0) return rb_str_new(0,0);
+ str = rb_rs;
+ }
+ else {
+ str = tmp;
+ }
+ }
+ break;
+
+ case 2:
if (!NIL_P(str)) StringValue(str);
+ limit = NUM2LONG(lim);
+ break;
}
- if (ptr->pos >= (n = RSTRING(ptr->string)->len)) {
- ptr->flags |= STRIO_EOF;
+ if (ptr->pos >= (n = RSTRING_LEN(ptr->string))) {
return Qnil;
}
- s = RSTRING(ptr->string)->ptr;
- e = s + RSTRING(ptr->string)->len;
+ s = RSTRING_PTR(ptr->string);
+ e = s + RSTRING_LEN(ptr->string);
s += ptr->pos;
+ if (limit > 0 && s + limit < e) {
+ e = rb_enc_right_char_head(s, s + limit, e, rb_enc_get(ptr->string));
+ }
if (NIL_P(str)) {
- str = rb_str_substr(ptr->string, ptr->pos, e - s);
+ str = strio_substr(ptr, ptr->pos, e - s);
}
- else if ((n = RSTRING(str)->len) == 0) {
+ else if ((n = RSTRING_LEN(str)) == 0) {
p = s;
while (*p == '\n') {
if (++p == e) {
- ptr->flags |= STRIO_EOF;
return Qnil;
}
}
s = p;
while ((p = memchr(p, '\n', e - p)) && (p != e)) {
if (*++p == '\n') {
- e = p;
+ e = p + 1;
break;
}
}
- str = rb_str_substr(ptr->string, s - RSTRING(ptr->string)->ptr, e - s);
+ str = strio_substr(ptr, s - RSTRING_PTR(ptr->string), e - s);
}
else if (n == 1) {
- if ((p = memchr(s, RSTRING(str)->ptr[0], e - s)) != 0) {
+ if ((p = memchr(s, RSTRING_PTR(str)[0], e - s)) != 0) {
e = p + 1;
}
- str = rb_str_substr(ptr->string, ptr->pos, e - s);
+ str = strio_substr(ptr, ptr->pos, e - s);
}
else {
if (n < e - s) {
if (e - s < 1024) {
for (p = s; p + n <= e; ++p) {
- if (MEMCMP(p, RSTRING(str)->ptr, char, n) == 0) {
+ if (MEMCMP(p, RSTRING_PTR(str), char, n) == 0) {
e = p + n;
break;
}
@@ -891,31 +993,30 @@ strio_getline(argc, argv, ptr)
}
else {
long skip[1 << CHAR_BIT], pos;
- p = RSTRING(str)->ptr;
+ p = RSTRING_PTR(str);
bm_init_skip(skip, p, n);
if ((pos = bm_search(p, n, s, e - s, skip)) >= 0) {
e = s + pos + n;
}
}
}
- str = rb_str_substr(ptr->string, ptr->pos, e - s);
+ str = strio_substr(ptr, ptr->pos, e - s);
}
- ptr->pos = e - RSTRING(ptr->string)->ptr;
+ ptr->pos = e - RSTRING_PTR(ptr->string);
ptr->lineno++;
return str;
}
/*
* call-seq:
- * strio.gets(sep_string=$/) -> string or nil
+ * strio.gets(sep=$/) -> string or nil
+ * strio.gets(limit) -> string or nil
+ * strio.gets(sep, limit) -> string or nil
*
* See IO#gets.
*/
static VALUE
-strio_gets(argc, argv, self)
- int argc;
- VALUE *argv;
- VALUE self;
+strio_gets(int argc, VALUE *argv, VALUE self)
{
VALUE str = strio_getline(argc, argv, readable(StringIO(self)));
@@ -925,37 +1026,47 @@ strio_gets(argc, argv, self)
/*
* call-seq:
- * strio.readline(sep_string=$/) -> string
+ * strio.readline(sep=$/) -> string
+ * strio.readline(limit) -> string or nil
+ * strio.readline(sep, limit) -> string or nil
*
* See IO#readline.
*/
static VALUE
-strio_readline(argc, argv, self)
- int argc;
- VALUE *argv;
- VALUE self;
+strio_readline(int argc, VALUE *argv, VALUE self)
{
- VALUE line = strio_getline(argc, argv, readable(StringIO(self)));
+ VALUE line = strio_gets(argc, argv, self);
if (NIL_P(line)) rb_eof_error();
return line;
}
/*
* call-seq:
- * strio.each(sep_string=$/) {|line| block } -> strio
- * strio.each_line(sep_string=$/) {|line| block } -> strio
+ * strio.each(sep=$/) {|line| block } -> strio
+ * strio.each(limit) {|line| block } -> strio
+ * strio.each(sep, limit) {|line| block } -> strio
+ * strio.each(...) -> anEnumerator
+ *
+ * strio.each_line(sep=$/) {|line| block } -> strio
+ * strio.each_line(limit) {|line| block } -> strio
+ * strio.each_line(sep,limit) {|line| block } -> strio
+ * strio.each_line(...) -> anEnumerator
+ *
+ * strio.lines(sep=$/) {|line| block } -> strio
+ * strio.lines(limit) {|line| block } -> strio
+ * strio.lines(sep,limit) {|line| block } -> strio
+ * strio.lines(...) -> anEnumerator
*
* See IO#each.
*/
static VALUE
-strio_each(argc, argv, self)
- int argc;
- VALUE *argv;
- VALUE self;
+strio_each(int argc, VALUE *argv, VALUE self)
{
struct StringIO *ptr = StringIO(self);
VALUE line;
+ RETURN_ENUMERATOR(self, argc, argv);
+
while (!NIL_P(line = strio_getline(argc, argv, readable(ptr)))) {
rb_yield(line);
}
@@ -964,15 +1075,14 @@ strio_each(argc, argv, self)
/*
* call-seq:
- * strio.readlines(sep_string=$/) -> array
+ * strio.readlines(sep=$/) -> array
+ * strio.readlines(limit) -> array
+ * strio.readlines(sep,limit) -> array
*
* See IO#readlines.
*/
static VALUE
-strio_readlines(argc, argv, self)
- int argc;
- VALUE *argv;
- VALUE self;
+strio_readlines(int argc, VALUE *argv, VALUE self)
{
struct StringIO *ptr = StringIO(self);
VALUE ary = rb_ary_new(), line;
@@ -993,27 +1103,34 @@ strio_readlines(argc, argv, self)
* Returns the number of bytes written. See IO#write.
*/
static VALUE
-strio_write(self, str)
- VALUE self, str;
+strio_write(VALUE self, VALUE str)
{
struct StringIO *ptr = writable(StringIO(self));
long len, olen;
+ rb_encoding *enc, *enc2;
+ RB_GC_GUARD(str);
if (TYPE(str) != T_STRING)
str = rb_obj_as_string(str);
- len = RSTRING(str)->len;
- if (!len) return INT2FIX(0);
+ enc = rb_enc_get(ptr->string);
+ enc2 = rb_enc_get(str);
+ if (enc != enc2 && enc != rb_ascii8bit_encoding()) {
+ str = rb_str_conv_enc(str, enc2, enc);
+ }
+ len = RSTRING_LEN(str);
+ if (len == 0) return INT2FIX(0);
check_modifiable(ptr);
- olen = RSTRING(ptr->string)->len;
+ olen = RSTRING_LEN(ptr->string);
if (ptr->flags & FMODE_APPEND) {
ptr->pos = olen;
}
if (ptr->pos == olen) {
- rb_str_cat(ptr->string, RSTRING(str)->ptr, len);
+ rb_str_cat(ptr->string, RSTRING_PTR(str), len);
}
else {
strio_extend(ptr, ptr->pos, len);
- rb_str_update(ptr->string, ptr->pos, len, str);
+ memmove(RSTRING_PTR(ptr->string)+ptr->pos, RSTRING_PTR(str), len);
+ OBJ_INFECT(ptr->string, str);
}
OBJ_INFECT(ptr->string, self);
ptr->pos += len;
@@ -1052,20 +1169,19 @@ strio_write(self, str)
* See IO#putc.
*/
static VALUE
-strio_putc(self, ch)
- VALUE self, ch;
+strio_putc(VALUE self, VALUE ch)
{
struct StringIO *ptr = writable(StringIO(self));
int c = NUM2CHR(ch);
long olen;
check_modifiable(ptr);
- olen = RSTRING(ptr->string)->len;
+ olen = RSTRING_LEN(ptr->string);
if (ptr->flags & FMODE_APPEND) {
ptr->pos = olen;
}
strio_extend(ptr, ptr->pos, 1);
- RSTRING(ptr->string)->ptr[ptr->pos++] = c;
+ RSTRING_PTR(ptr->string)[ptr->pos++] = c;
OBJ_INFECT(ptr->string, self);
return ch;
}
@@ -1085,14 +1201,11 @@ strio_putc(self, ch)
* See IO#read.
*/
static VALUE
-strio_read(argc, argv, self)
- int argc;
- VALUE *argv;
- VALUE self;
+strio_read(int argc, VALUE *argv, VALUE self)
{
struct StringIO *ptr = readable(StringIO(self));
VALUE str = Qnil;
- long len, olen;
+ long len;
switch (argc) {
case 2:
@@ -1101,16 +1214,11 @@ strio_read(argc, argv, self)
rb_str_modify(str);
case 1:
if (!NIL_P(argv[0])) {
- len = olen = NUM2LONG(argv[0]);
+ len = NUM2LONG(argv[0]);
if (len < 0) {
rb_raise(rb_eArgError, "negative length %ld given", len);
}
- if (len > 0 && ptr->pos >= RSTRING(ptr->string)->len) {
- ptr->flags |= STRIO_EOF;
- if (!NIL_P(str)) rb_str_resize(str, 0);
- return Qnil;
- }
- else if (ptr->flags & STRIO_EOF) {
+ if (len > 0 && ptr->pos >= RSTRING_LEN(ptr->string)) {
if (!NIL_P(str)) rb_str_resize(str, 0);
return Qnil;
}
@@ -1118,10 +1226,8 @@ strio_read(argc, argv, self)
}
/* fall through */
case 0:
- olen = -1;
- len = RSTRING(ptr->string)->len;
+ len = RSTRING_LEN(ptr->string);
if (len <= ptr->pos) {
- ptr->flags |= STRIO_EOF;
if (NIL_P(str)) {
str = rb_str_new(0, 0);
}
@@ -1138,22 +1244,22 @@ strio_read(argc, argv, self)
rb_raise(rb_eArgError, "wrong number of arguments (%d for 0)", argc);
}
if (NIL_P(str)) {
- str = rb_str_substr(ptr->string, ptr->pos, len);
+ str = strio_substr(ptr, ptr->pos, len);
+ if (argc > 0) rb_enc_associate(str, rb_ascii8bit_encoding());
}
else {
- long rest = RSTRING(ptr->string)->len - ptr->pos;
+ long rest = RSTRING_LEN(ptr->string) - ptr->pos;
if (len > rest) len = rest;
rb_str_resize(str, len);
- MEMCPY(RSTRING(str)->ptr, RSTRING(ptr->string)->ptr + ptr->pos, char, len);
+ MEMCPY(RSTRING_PTR(str), RSTRING_PTR(ptr->string) + ptr->pos, char, len);
}
if (NIL_P(str)) {
- if (!(ptr->flags & STRIO_EOF)) str = rb_str_new(0, 0);
+ str = rb_str_new(0, 0);
len = 0;
}
else {
- ptr->pos += len = RSTRING(str)->len;
+ ptr->pos += len = RSTRING_LEN(str);
}
- if (olen < 0 || olen > len) ptr->flags |= STRIO_EOF;
return str;
}
@@ -1165,13 +1271,10 @@ strio_read(argc, argv, self)
* returning +nil+, as well as IO#sysread does.
*/
static VALUE
-strio_sysread(argc, argv, self)
- int argc;
- VALUE *argv;
- VALUE self;
+strio_sysread(int argc, VALUE *argv, VALUE self)
{
VALUE val = strio_read(argc, argv, self);
- if (NIL_P(val) || RSTRING(val)->len == 0) {
+ if (NIL_P(val)) {
rb_eof_error();
}
return val;
@@ -1179,9 +1282,6 @@ strio_sysread(argc, argv, self)
#define strio_syswrite strio_write
-/* call-seq: strio.path -> nil */
-#define strio_path strio_nil
-
/*
* call-seq:
* strio.isatty -> nil
@@ -1203,14 +1303,13 @@ strio_sysread(argc, argv, self)
* Returns the size of the buffer string.
*/
static VALUE
-strio_size(self)
- VALUE self;
+strio_size(VALUE self)
{
VALUE string = StringIO(self)->string;
if (NIL_P(string)) {
rb_raise(rb_eIOError, "not opened");
}
- return ULONG2NUM(RSTRING(string)->len);
+ return ULONG2NUM(RSTRING_LEN(string));
}
/*
@@ -1221,23 +1320,67 @@ strio_size(self)
* must be opened for writing.
*/
static VALUE
-strio_truncate(self, len)
- VALUE self, len;
+strio_truncate(VALUE self, VALUE len)
{
VALUE string = writable(StringIO(self))->string;
long l = NUM2LONG(len);
- long plen = RSTRING(string)->len;
+ long plen = RSTRING_LEN(string);
if (l < 0) {
error_inval("negative legnth");
}
rb_str_resize(string, l);
if (plen < l) {
- MEMZERO(RSTRING(string)->ptr + plen, char, l - plen);
+ MEMZERO(RSTRING_PTR(string) + plen, char, l - plen);
}
return len;
}
/*
+ * call-seq:
+ * strio.external_encoding => encoding
+ *
+ * Returns the Encoding object that represents the encoding of the file.
+ * If strio is write mode and no encoding is specified, returns <code>nil</code>.
+ */
+
+static VALUE
+strio_external_encoding(VALUE self)
+{
+ return rb_enc_from_encoding(rb_enc_get(StringIO(self)->string));
+}
+
+/*
+ * call-seq:
+ * strio.internal_encoding => encoding
+ *
+ * Returns the Encoding of the internal string if conversion is
+ * specified. Otherwise returns nil.
+ */
+
+static VALUE
+strio_internal_encoding(VALUE self)
+{
+ return Qnil;
+}
+
+/*
+ * call-seq:
+ * strio.set_encoding(ext_enc) => strio
+ *
+ * Tagged with the encoding specified.
+ */
+
+static VALUE
+strio_set_encoding(VALUE self, VALUE ext_enc)
+{
+ rb_encoding* enc;
+ VALUE str = StringIO(self)->string;
+ enc = rb_to_encoding(ext_enc);
+ rb_enc_associate(str, enc);
+ return self;
+}
+
+/*
* Pseudo I/O on String object.
*/
void
@@ -1276,19 +1419,29 @@ Init_stringio()
rb_define_method(StringIO, "sync", strio_get_sync, 0);
rb_define_method(StringIO, "sync=", strio_set_sync, 1);
rb_define_method(StringIO, "tell", strio_tell, 0);
- rb_define_method(StringIO, "path", strio_path, 0);
rb_define_method(StringIO, "each", strio_each, -1);
- rb_define_method(StringIO, "each_byte", strio_each_byte, 0);
rb_define_method(StringIO, "each_line", strio_each, -1);
+ rb_define_method(StringIO, "lines", strio_each, -1);
+ rb_define_method(StringIO, "each_byte", strio_each_byte, 0);
+ rb_define_method(StringIO, "bytes", strio_each_byte, 0);
+ rb_define_method(StringIO, "each_char", strio_each_char, 0);
+ rb_define_method(StringIO, "chars", strio_each_char, 0);
+ rb_define_method(StringIO, "each_codepoint", strio_each_codepoint, 0);
+ rb_define_method(StringIO, "codepoints", strio_each_codepoint, 0);
rb_define_method(StringIO, "getc", strio_getc, 0);
rb_define_method(StringIO, "ungetc", strio_ungetc, 1);
+ rb_define_method(StringIO, "ungetbyte", strio_ungetbyte, 1);
rb_define_method(StringIO, "readchar", strio_readchar, 0);
+ rb_define_method(StringIO, "getbyte", strio_getbyte, 0);
+ rb_define_method(StringIO, "readbyte", strio_readbyte, 0);
rb_define_method(StringIO, "gets", strio_gets, -1);
rb_define_method(StringIO, "readline", strio_readline, -1);
rb_define_method(StringIO, "readlines", strio_readlines, -1);
rb_define_method(StringIO, "read", strio_read, -1);
rb_define_method(StringIO, "sysread", strio_sysread, -1);
+ rb_define_method(StringIO, "readpartial", strio_sysread, -1);
+ rb_define_method(StringIO, "read_nonblock", strio_sysread, -1);
rb_define_method(StringIO, "write", strio_write, 1);
rb_define_method(StringIO, "<<", strio_addstr, 1);
@@ -1297,6 +1450,7 @@ Init_stringio()
rb_define_method(StringIO, "putc", strio_putc, 1);
rb_define_method(StringIO, "puts", strio_puts, -1);
rb_define_method(StringIO, "syswrite", strio_syswrite, 1);
+ rb_define_method(StringIO, "write_nonblock", strio_syswrite, 1);
rb_define_method(StringIO, "isatty", strio_isatty, 0);
rb_define_method(StringIO, "tty?", strio_isatty, 0);
@@ -1305,4 +1459,8 @@ Init_stringio()
rb_define_method(StringIO, "size", strio_size, 0);
rb_define_method(StringIO, "length", strio_size, 0);
rb_define_method(StringIO, "truncate", strio_truncate, 1);
+
+ rb_define_method(StringIO, "external_encoding", strio_external_encoding, 0);
+ rb_define_method(StringIO, "internal_encoding", strio_internal_encoding, 0);
+ rb_define_method(StringIO, "set_encoding", strio_set_encoding, 1);
}