IO should provide #each_char and #chars

Yuguie$B$G$9!#e(B

IOe$B$K$O%P%$%H%9%H%j!<%$@$1$G$O$J$/J8;z%9%H%j!<%$H$7$F$N5!G=e(B
e$B$b4|BT$5$l$F$$$k$H;W$&$N$G$9$,!“e(B
IO#each_chare$B$de(BIO#charse$B$,$”$j$^$;$s!#e(B

e$B%P%C%U%!$KFO$$$F$$$J$$%P%$%H$N$;$$$GIT40A4$JJ8;z$,=P8=$9$k2De(B
e$BG=@-$r9M$($?$N$+$H$b;W$$$^$7$?$,!“e(Bgetce$B$,$”$k$J$ie(B
each_chare$B$b$"$k$Y$-$G$O$J$$$G$7$g$&$+!#e(B

e$B$H$j$"$($:!"e(Bgetce$B$r%Y!<%9$K=q$$$F$_$^$7$?!#e(B


Yugui
[email protected]

Index: io.c

— io.c (revision 15781)
+++ io.c (working copy)
@@ -2226,8 +2226,79 @@
return io;
}

+static VALUE
+io_getc(rb_io_t *fptr, rb_encoding *enc)
+{

  • int r, n;
  • VALUE str;
  • if (io_fillbuf(fptr) < 0) {
  • return Qnil;
  • }
  • r = rb_enc_precise_mbclen(fptr->rbuf+fptr->rbuf_off, fptr->rbuf
    +fptr->rbuf_off+fptr->rbuf_len, enc);
  • if (MBCLEN_CHARFOUND_P(r) &&
  •    (n = MBCLEN_CHARFOUND_LEN(r)) <= fptr->rbuf_len) {
    
  • str = rb_str_new(fptr->rbuf+fptr->rbuf_off, n);
  • fptr->rbuf_off += n;
  • fptr->rbuf_len -= n;
  • }
  • else if (MBCLEN_NEEDMORE_P(r)) {
  • str = rb_str_new(fptr->rbuf+fptr->rbuf_off, fptr->rbuf_len);
  •    fptr->rbuf_len = 0;
    
  •  getc_needmore:
    
  •    if (io_fillbuf(fptr) != -1) {
    
  •        rb_str_cat(str, fptr->rbuf+fptr->rbuf_off, 1);
    
  •        fptr->rbuf_off++;
    
  •        fptr->rbuf_len--;
    
  •        r = rb_enc_precise_mbclen(RSTRING_PTR(str),
    

RSTRING_PTR(str)+RSTRING_LEN(str), enc);

  •        if (MBCLEN_NEEDMORE_P(r)) {
    
  •            goto getc_needmore;
    
  •        }
    
  •    }
    
  • }
  • else {
  • str = rb_str_new(fptr->rbuf+fptr->rbuf_off, 1);
  • fptr->rbuf_off++;
  • fptr->rbuf_len–;
  • }
  • return io_enc_str(str, fptr);
    +}
  • /*
    • call-seq:
    • ios.each_char {|c| block }  => ios
      
    • Calls the given block once for each character in ios,
    • passing the character as an argument. The stream must be opened for
    • reading or an IOError will be raised.
    • f = File.new("testfile")
      
    • f.each_char {|c| print c, ' ' }   #=> #<File:testfile>
      
  • */

+static VALUE
+rb_io_each_char(VALUE io)
+{

  • rb_io_t *fptr;
  • rb_encoding *enc;
  • VALUE c;
  • RETURN_ENUMERATOR(io, 0, 0);
  • GetOpenFile(io, fptr);
  • rb_io_check_readable(fptr);
  • enc = io_input_encoding(fptr);
  • READ_CHECK(fptr);
  • while (!NIL_P(c = io_getc(fptr, enc))) {
  •    rb_yield(c);
    
  • }
  • return io;
    +}

+/*

    • call-seq:
    • str.lines(sep=$/)     => anEnumerator
      
    • str.lines(limit)      => anEnumerator
      
    • str.lines(sep, limit) => anEnumerator
      

@@ -2239,9 +2310,9 @@
*/

static VALUE
-rb_io_lines(int argc, VALUE *argv, VALUE str)
+rb_io_lines(int argc, VALUE *argv, VALUE io)
{

  • return rb_enumeratorize(str, ID2SYM(rb_intern(“each_line”)),
    argc, argv);
  • return rb_enumeratorize(io, ID2SYM(rb_intern(“each_line”)), argc,
    argv);
    }

/*
@@ -2254,13 +2325,31 @@
*/

static VALUE
-rb_io_bytes(VALUE str)
+rb_io_bytes(VALUE io)
{

  • return rb_enumeratorize(str, ID2SYM(rb_intern(“each_byte”)), 0, 0);
  • return rb_enumeratorize(io, ID2SYM(rb_intern(“each_byte”)), 0, 0);
    }

/*

  • call-seq:
    • ios.chars   => anEnumerator
      
    • Returns an enumerator that gives each character in ios.
    • The stream must be opened for reading or an IOError
    • will be raised.
    • f = File.new("testfile)
      
    • f.chars.each {|c| print c, ' ' }
      
  • */

+static VALUE
+rb_io_chars(VALUE io)
+{

  • return rb_enumeratorize(io, ID2SYM(rb_intern(“each_char”)), 0, 0);
    +}

+/*

    • call-seq:

    • ios.getc   => fixnum or nil
      
    • Reads a one-character string from ios. Returns
      @@ -2284,38 +2373,8 @@

      enc = io_input_encoding(fptr);
      READ_CHECK(fptr);

  • if (io_fillbuf(fptr) < 0) {
  • return Qnil;
  • }
  • r = rb_enc_precise_mbclen(fptr->rbuf+fptr->rbuf_off, fptr->rbuf
    +fptr->rbuf_off+fptr->rbuf_len, enc);
  • if (MBCLEN_CHARFOUND_P(r) &&
  •    (n = MBCLEN_CHARFOUND_LEN(r)) <= fptr->rbuf_len) {
    
  • str = rb_str_new(fptr->rbuf+fptr->rbuf_off, n);
  • fptr->rbuf_off += n;
  • fptr->rbuf_len -= n;
  • }
  • else if (MBCLEN_NEEDMORE_P(r)) {
  • str = rb_str_new(fptr->rbuf+fptr->rbuf_off, fptr->rbuf_len);
  •    fptr->rbuf_len = 0;
    
  •  getc_needmore:
    
  •    if (io_fillbuf(fptr) != -1) {
    
  •        rb_str_cat(str, fptr->rbuf+fptr->rbuf_off, 1);
    
  •        fptr->rbuf_off++;
    
  •        fptr->rbuf_len--;
    
  •        r = rb_enc_precise_mbclen(RSTRING_PTR(str),
    

RSTRING_PTR(str)+RSTRING_LEN(str), enc);

  •        if (MBCLEN_NEEDMORE_P(r)) {
    
  •            goto getc_needmore;
    
  •        }
    
  •    }
    
  • }
  • else {
  • str = rb_str_new(fptr->rbuf+fptr->rbuf_off, 1);
  • fptr->rbuf_off++;
  • fptr->rbuf_len–;
  • }
  • return io_enc_str(str, fptr);
  • return io_getc(fptr, enc);
    }
  • int
    rb_getc(FILE *f)
    {
    @@ -6477,6 +6536,17 @@
    }

    static VALUE
    +argf_each_char(VALUE argf)
    +{

  • RETURN_ENUMERATOR(argf, 0, 0);
  • for (;:wink: {
  • if (!next_argv()) return Qnil;
  • rb_block_call(current_file, rb_intern(“each_char”), 0, 0, rb_yield,
    0);
  • next_p = 1;
  • }
    +}

+static VALUE
argf_filename(VALUE argf)
{
next_argv();
@@ -6773,8 +6843,10 @@
rb_define_method(rb_cIO, “each”, rb_io_each_line, -1);
rb_define_method(rb_cIO, “each_line”, rb_io_each_line, -1);
rb_define_method(rb_cIO, “each_byte”, rb_io_each_byte, 0);

  • rb_define_method(rb_cIO, “each_char”, rb_io_each_char, 0);
    rb_define_method(rb_cIO, “lines”, rb_io_lines, -1);
    rb_define_method(rb_cIO, “bytes”, rb_io_bytes, 0);

  • rb_define_method(rb_cIO, “chars”, rb_io_chars, 0);

    rb_define_method(rb_cIO, “syswrite”, rb_io_syswrite, 1);
    rb_define_method(rb_cIO, “sysread”, rb_io_sysread, -1);
    @@ -6870,6 +6942,7 @@
    rb_define_method(rb_cARGF, “each”, argf_each_line, -1);
    rb_define_method(rb_cARGF, “each_line”, argf_each_line, -1);
    rb_define_method(rb_cARGF, “each_byte”, argf_each_byte, 0);

  • rb_define_method(rb_cARGF, “each_char”, argf_each_char, 0);

    rb_define_method(rb_cARGF, “read”, argf_read, -1);
    rb_define_method(rb_cARGF, “readpartial”, argf_readpartial, -1);

e$B$^$D$b$He(B e$B$f$-$R$m$G$9e(B

In message “Re: [ruby-dev:34052] IO should provide #each_char and
#chars
on Fri, 14 Mar 2008 19:00:39 +0900, Yugui [email protected]
writes:

|IOe$B$K$O%P%$%H%9%H%j!<%$@$1$G$O$J$/J8;z%9%H%j!<%$H$7$F$N5!G=e(B
|e$B$b4|BT$5$l$F$$$k$H;W$&$N$G$9$,!“e(B
|IO#each_chare$B$de(BIO#charse$B$,$”$j$^$;$s!#e(B
|
|e$B%P%C%U%!$KFO$$$F$$$J$$%P%$%H$N$;$$$GIT40A4$JJ8;z$,=P8=$9$k2De(B
|e$BG=@-$r9M$($?$N$+$H$b;W$$$^$7$?$,!“e(Bgetce$B$,$”$k$J$ie(B
|each_chare$B$b$“$k$Y$-$G$O$J$$$G$7$g$&$+!#e(B
|
|e$B$H$j$”$($:!"e(Bgetce$B$r%Y!<%9$K=q$$$F$_$^$7$?!#e(B

(e$B%3%%C%H8"$,Mh$?$ie(B)e$B%3%%C%H$7$F$/$@$5$$!#e(B