diff options
author | akr <akr@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2004-08-11 16:57:14 +0000 |
---|---|---|
committer | akr <akr@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2004-08-11 16:57:14 +0000 |
commit | 8f8de7782e93aab8e09c0727140fd1ff02d8ca6f (patch) | |
tree | 242a1a265a0ae94447562e3109c1031a741bbf00 | |
parent | 9492165db232bb3bee4c13ac03bf96eb0e76d6ad (diff) | |
download | ruby-8f8de7782e93aab8e09c0727140fd1ff02d8ca6f.tar.gz |
* io.c (read_buffered_data): extracted from rb_io_fread.
(io_readpartial): new method IO#readpartial.
[ruby-dev:24055]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@6756 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r-- | ChangeLog | 6 | ||||
-rw-r--r-- | io.c | 157 |
2 files changed, 142 insertions, 21 deletions
@@ -1,3 +1,9 @@ +Thu Aug 12 01:53:10 2004 Tanaka Akira <akr@m17n.org> + + * io.c (read_buffered_data): extracted from rb_io_fread. + (io_readpartial): new method IO#readpartial. + [ruby-dev:24055] + Wed Aug 11 17:17:50 2004 WATANABE Hirofumi <eban@ruby-lang.org> * configure.in (RPATHFLAG): stop setting RPATHFLAG on Interix. @@ -907,6 +907,27 @@ rb_io_to_io(io) } /* reading functions */ +static long +read_buffered_data(ptr, len, f) + char *ptr; + long len; + FILE *f; +{ + long n; + +#ifdef READ_DATA_PENDING_COUNT + n = READ_DATA_PENDING_COUNT(f); + if (n <= 0) return 0; + if (n > len) n = len; + return fread(ptr, 1, n, f); +#else + for (n = 0; n < len && READ_DATA_PENDING(f); ++n) { + *ptr++ = getc(f); + } + return n; +#endif +} + long rb_io_fread(ptr, len, f) char *ptr; @@ -917,28 +938,12 @@ rb_io_fread(ptr, len, f) int c; while (n > 0) { -#ifdef READ_DATA_PENDING_COUNT - long i = READ_DATA_PENDING_COUNT(f); - if (i <= 0) { - rb_thread_wait_fd(fileno(f)); - i = READ_DATA_PENDING_COUNT(f); - } - if (i > 0) { - if (i > n) i = n; - TRAP_BEG; - c = fread(ptr, 1, i, f); - TRAP_END; - if (c < 0) goto eof; + c = read_buffered_data(ptr, n, f); + if (c < 0) goto eof; + if (c > 0) { ptr += c; - n -= c; - if (c < i) goto eof; - continue; + if ((n -= c) <= 0) break; } -#else - if (!READ_DATA_PENDING(f)) { - rb_thread_wait_fd(fileno(f)); - } -#endif TRAP_BEG; c = getc(f); TRAP_END; @@ -1042,6 +1047,113 @@ read_all(fptr, siz, str) /* * call-seq: + * ios.readpartial(integer[, outbuf]) => string, outbuf + * + * Reads at most <i>integer</i> bytes from the I/O stream but + * it blocks only if <em>ios</em> has no data immediately available. + * If the optional <i>outbuf</i> argument is present, + * it must reference a String, which will receive the data. + * It raises <code>EOFError</code> on end of file. + * + * readpartial is designed for streams such as pipe, socket, etc. + * It blocks only when no data immediately available. + * This means that it blocks only when following all conditions hold. + * * the stdio buffer in the IO object is empty. + * * the content of the stream is empty. + * * the stream is not reached to EOF. + * + * When readpartial blocks, it waits data or EOF on the stream. + * If some data is reached, readpartial returns with the data. + * If EOF is reached, readpartial raises EOFError. + * + * When readpartial doesn't blocks, it returns or raises immediately. + * If the stdio buffer is not empty, it returns the data in the buffer. + * Otherwise if the stream has some content, + * it returns the data in the stream. + * Otherwise if the stream is reached to EOF, it raises EOFError. + * + * r, w = IO.pipe # stdio buffer pipe content + * w << "abc" # "" "abc". + * r.readpartial(4096) #=> "abc" "" "" + * r.readpartial(4096) # blocks because buffer and pipe is empty. + * + * r, w = IO.pipe # stdio buffer pipe content + * w << "abc" # "" "abc" + * w.close # "" "abc" EOF + * r.readpartial(4096) #=> "abc" "" EOF + * r.readpartial(4096) # raises EOFError + * + * r, w = IO.pipe # stdio buffer pipe content + * w << "abc\ndef\n" # "" "abc\ndef\n" + * r.gets #=> "abc\n" "def\n" "" + * w << "ghi\n" # "def\n" "ghi\n" + * r.readpartial(4096) #=> "def\n" "" "ghi\n" + * r.readpartial(4096) #=> "ghi\n" "" "" + * + * Note that readpartial is nonblocking-flag insensitive. + * It blocks even if the nonblocking-flag is set. + * + * Also note that readpartial behaves similar to sysread in blocking mode. + * The behavior is identical when the stdio buffer is empty. + * + */ + +static VALUE +io_readpartial(argc, argv, io) + int argc; + VALUE *argv; + VALUE io; +{ + OpenFile *fptr; + VALUE length, str; + long n, len; + + rb_scan_args(argc, argv, "11", &length, &str); + + GetOpenFile(io, fptr); + rb_io_check_readable(fptr); + + if ((len = NUM2LONG(length)) < 0) { + rb_raise(rb_eArgError, "negative length %ld given", len); + } + + if (NIL_P(str)) { + str = rb_str_new(0, len); + } + else { + StringValue(str); + rb_str_modify(str); + rb_str_resize(str, len); + } + OBJ_TAINT(str); + + if (len == 0) + return str; + + READ_CHECK(fptr->f); + n = read_buffered_data(RSTRING(str)->ptr, len, fptr->f); + if (n <= 0) { + again: + TRAP_BEG; + n = read(fileno(fptr->f), RSTRING(str)->ptr, len); + TRAP_END; + if (n < 0) { + if (rb_io_wait_readable(fileno(fptr->f))) + goto again; + rb_str_resize(str, 0); + rb_sys_fail(fptr->path); + } + } + rb_str_resize(str, n); + + if (n == 0) + rb_eof_error(); + else + return str; +} + +/* + * call-seq: * ios.read([integer [, buffer]]) => string, buffer, or nil * * Reads at most <i>integer</i> bytes from the I/O stream, or to the @@ -2072,11 +2184,13 @@ rb_io_syswrite(io, str) /* * call-seq: - * ios.sysread(integer ) => string + * ios.sysread(integer[, outbuf]) => string * * Reads <i>integer</i> bytes from <em>ios</em> using a low-level * read and returns them as a string. Do not mix with other methods * that read from <em>ios</em> or you may get unpredictable results. + * If the optional <i>outbuf</i> argument is present, it must reference + * a String, which will receive the data. * Raises <code>SystemCallError</code> on error and * <code>EOFError</code> at end of file. * @@ -5439,6 +5553,7 @@ Init_IO() rb_define_method(rb_cIO, "readlines", rb_io_readlines, -1); + rb_define_method(rb_cIO, "readpartial", io_readpartial, -1); rb_define_method(rb_cIO, "read", io_read, -1); rb_define_method(rb_cIO, "write", io_write, 1); rb_define_method(rb_cIO, "gets", rb_io_gets_m, -1); |