diff options
Diffstat (limited to 'io.c')
-rw-r--r-- | io.c | 157 |
1 files changed, 136 insertions, 21 deletions
@@ -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); |