/io.c
C | 10125 lines | 6664 code | 926 blank | 2535 comment | 1551 complexity | 2b17d4671a383515e7a3d8139f578390 MD5 | raw file
Possible License(s): GPL-2.0, BSD-3-Clause
Large files files are truncated, but you can click here to view the full file
- /**********************************************************************
- io.c -
- $Author$
- created at: Fri Oct 15 18:08:59 JST 1993
- Copyright (C) 1993-2007 Yukihiro Matsumoto
- Copyright (C) 2000 Network Applied Communication Laboratory, Inc.
- Copyright (C) 2000 Information-technology Promotion Agency, Japan
- **********************************************************************/
- #include "ruby/ruby.h"
- #include "ruby/io.h"
- #include "dln.h"
- #include <ctype.h>
- #include <errno.h>
- #define free(x) xfree(x)
- #if defined(DOSISH) || defined(__CYGWIN__)
- #include <io.h>
- #endif
- #include <sys/types.h>
- #if defined HAVE_NET_SOCKET_H
- # include <net/socket.h>
- #elif defined HAVE_SYS_SOCKET_H
- # include <sys/socket.h>
- #endif
- #if defined(__BOW__) || defined(__CYGWIN__) || defined(_WIN32) || defined(__EMX__) || defined(__BEOS__) || defined(__HAIKU__)
- # define NO_SAFE_RENAME
- #endif
- #if defined(__CYGWIN__) || defined(_WIN32)
- # define NO_LONG_FNAME
- #endif
- #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(sun) || defined(_nec_ews)
- # define USE_SETVBUF
- #endif
- #ifdef __QNXNTO__
- #include "unix.h"
- #endif
- #include <sys/types.h>
- #if defined(HAVE_SYS_IOCTL_H) && !defined(_WIN32)
- #include <sys/ioctl.h>
- #endif
- #if defined(HAVE_FCNTL_H) || defined(_WIN32)
- #include <fcntl.h>
- #elif defined(HAVE_SYS_FCNTL_H)
- #include <sys/fcntl.h>
- #endif
- #if !HAVE_OFF_T && !defined(off_t)
- # define off_t long
- #endif
- #include <sys/stat.h>
- /* EMX has sys/param.h, but.. */
- #if defined(HAVE_SYS_PARAM_H) && !(defined(__EMX__) || defined(__HIUX_MPP__))
- # include <sys/param.h>
- #endif
- #if !defined NOFILE
- # define NOFILE 64
- #endif
- #ifdef HAVE_UNISTD_H
- #include <unistd.h>
- #endif
- #ifdef HAVE_SYSCALL_H
- #include <syscall.h>
- #elif defined HAVE_SYS_SYSCALL_H
- #include <sys/syscall.h>
- #endif
- extern void Init_File(void);
- #if defined(__BEOS__) || defined(__HAIKU__)
- # ifndef NOFILE
- # define NOFILE (OPEN_MAX)
- # endif
- #endif
- #include "ruby/util.h"
- #ifndef O_ACCMODE
- #define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR)
- #endif
- #if SIZEOF_OFF_T > SIZEOF_LONG && !defined(HAVE_LONG_LONG)
- # error off_t is bigger than long, but you have no long long...
- #endif
- #ifndef PIPE_BUF
- # ifdef _POSIX_PIPE_BUF
- # define PIPE_BUF _POSIX_PIPE_BUF
- # else
- # define PIPE_BUF 512 /* is this ok? */
- # endif
- #endif
- #define numberof(array) (int)(sizeof(array) / sizeof((array)[0]))
- #define IO_RBUF_CAPA_MIN 8192
- #define IO_CBUF_CAPA_MIN (128*1024)
- #define IO_RBUF_CAPA_FOR(fptr) (NEED_READCONV(fptr) ? IO_CBUF_CAPA_MIN : IO_RBUF_CAPA_MIN)
- #define IO_WBUF_CAPA_MIN 8192
- /* define system APIs */
- #ifdef _WIN32
- #undef open
- #define open rb_w32_uopen
- #endif
- VALUE rb_cIO;
- VALUE rb_eEOFError;
- VALUE rb_eIOError;
- VALUE rb_mWaitReadable;
- VALUE rb_mWaitWritable;
- VALUE rb_stdin, rb_stdout, rb_stderr;
- VALUE rb_deferr; /* rescue VIM plugin */
- static VALUE orig_stdout, orig_stderr;
- VALUE rb_output_fs;
- VALUE rb_rs;
- VALUE rb_output_rs;
- VALUE rb_default_rs;
- static VALUE argf;
- static ID id_write, id_read, id_getc, id_flush, id_readpartial;
- static VALUE sym_mode, sym_perm, sym_extenc, sym_intenc, sym_encoding, sym_open_args;
- static VALUE sym_textmode, sym_binmode, sym_autoclose;
- struct timeval rb_time_interval(VALUE);
- struct argf {
- VALUE filename, current_file;
- int last_lineno; /* $. */
- int lineno;
- int init_p, next_p;
- VALUE argv;
- char *inplace;
- int binmode;
- struct rb_io_enc_t encs;
- };
- static int max_file_descriptor = NOFILE;
- #define UPDATE_MAXFD(fd) \
- do { \
- if (max_file_descriptor < (fd)) max_file_descriptor = (fd); \
- } while (0)
- #define argf_of(obj) (*(struct argf *)DATA_PTR(obj))
- #define ARGF argf_of(argf)
- #ifdef _STDIO_USES_IOSTREAM /* GNU libc */
- # ifdef _IO_fpos_t
- # define STDIO_READ_DATA_PENDING(fp) ((fp)->_IO_read_ptr != (fp)->_IO_read_end)
- # else
- # define STDIO_READ_DATA_PENDING(fp) ((fp)->_gptr < (fp)->_egptr)
- # endif
- #elif defined(FILE_COUNT)
- # define STDIO_READ_DATA_PENDING(fp) ((fp)->FILE_COUNT > 0)
- #elif defined(FILE_READEND)
- # define STDIO_READ_DATA_PENDING(fp) ((fp)->FILE_READPTR < (fp)->FILE_READEND)
- #elif defined(__BEOS__) || defined(__HAIKU__)
- # define STDIO_READ_DATA_PENDING(fp) (fp->_state._eof == 0)
- #else
- # define STDIO_READ_DATA_PENDING(fp) (!feof(fp))
- #endif
- #define GetWriteIO(io) rb_io_get_write_io(io)
- #define READ_DATA_PENDING(fptr) ((fptr)->rbuf_len)
- #define READ_DATA_PENDING_COUNT(fptr) ((fptr)->rbuf_len)
- #define READ_DATA_PENDING_PTR(fptr) ((fptr)->rbuf+(fptr)->rbuf_off)
- #define READ_DATA_BUFFERED(fptr) READ_DATA_PENDING(fptr)
- #define READ_CHAR_PENDING(fptr) ((fptr)->cbuf_len)
- #define READ_CHAR_PENDING_COUNT(fptr) ((fptr)->cbuf_len)
- #define READ_CHAR_PENDING_PTR(fptr) ((fptr)->cbuf+(fptr)->cbuf_off)
- #if defined(_WIN32)
- #define WAIT_FD_IN_WIN32(fptr) \
- (rb_w32_has_cancel_io() ? 0 : rb_thread_wait_fd((fptr)->fd))
- #else
- #define WAIT_FD_IN_WIN32(fptr)
- #endif
- #define READ_CHECK(fptr) do {\
- if (!READ_DATA_PENDING(fptr)) {\
- WAIT_FD_IN_WIN32(fptr);\
- rb_io_check_closed(fptr);\
- }\
- } while(0)
- #ifndef S_ISSOCK
- # ifdef _S_ISSOCK
- # define S_ISSOCK(m) _S_ISSOCK(m)
- # else
- # ifdef _S_IFSOCK
- # define S_ISSOCK(m) ((m & S_IFMT) == _S_IFSOCK)
- # else
- # ifdef S_IFSOCK
- # define S_ISSOCK(m) ((m & S_IFMT) == S_IFSOCK)
- # endif
- # endif
- # endif
- #endif
- #if defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32)
- /* Windows */
- # define NEED_NEWLINE_DECORATOR_ON_READ(fptr) (!(fptr->mode & FMODE_BINMODE))
- # define NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) (!(fptr->mode & FMODE_BINMODE))
- # define TEXTMODE_NEWLINE_DECORATOR_ON_WRITE ECONV_CRLF_NEWLINE_DECORATOR
- #else
- /* Unix */
- # define NEED_NEWLINE_DECORATOR_ON_READ(fptr) (fptr->mode & FMODE_TEXTMODE)
- # define NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) 0
- #endif
- #define NEED_READCONV(fptr) (fptr->encs.enc2 != NULL || NEED_NEWLINE_DECORATOR_ON_READ(fptr))
- #define NEED_WRITECONV(fptr) ((fptr->encs.enc != NULL && fptr->encs.enc != rb_ascii8bit_encoding()) || NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) || (fptr->encs.ecflags & (ECONV_DECORATOR_MASK|ECONV_STATEFUL_DECORATOR_MASK)))
- #if !defined HAVE_SHUTDOWN && !defined shutdown
- #define shutdown(a,b) 0
- #endif
- #define rb_sys_fail_path(path) rb_sys_fail(NIL_P(path) ? 0 : RSTRING_PTR(path))
- #if defined(_WIN32)
- #define is_socket(fd, path) rb_w32_is_socket(fd)
- #elif !defined(S_ISSOCK)
- #define is_socket(fd, path) 0
- #else
- static int
- is_socket(int fd, VALUE path)
- {
- struct stat sbuf;
- if (fstat(fd, &sbuf) < 0)
- rb_sys_fail_path(path);
- return S_ISSOCK(sbuf.st_mode);
- }
- #endif
- void
- rb_eof_error(void)
- {
- rb_raise(rb_eEOFError, "end of file reached");
- }
- VALUE
- rb_io_taint_check(VALUE io)
- {
- if (!OBJ_UNTRUSTED(io) && rb_safe_level() >= 4)
- rb_raise(rb_eSecurityError, "Insecure: operation on trusted IO");
- rb_check_frozen(io);
- return io;
- }
- void
- rb_io_check_initialized(rb_io_t *fptr)
- {
- if (!fptr) {
- rb_raise(rb_eIOError, "uninitialized stream");
- }
- }
- void
- rb_io_check_closed(rb_io_t *fptr)
- {
- rb_io_check_initialized(fptr);
- if (fptr->fd < 0) {
- rb_raise(rb_eIOError, "closed stream");
- }
- }
- static int io_fflush(rb_io_t *);
- VALUE
- rb_io_get_io(VALUE io)
- {
- return rb_convert_type(io, T_FILE, "IO", "to_io");
- }
- static VALUE
- rb_io_check_io(VALUE io)
- {
- return rb_check_convert_type(io, T_FILE, "IO", "to_io");
- }
- VALUE
- rb_io_get_write_io(VALUE io)
- {
- VALUE write_io;
- rb_io_check_initialized(RFILE(io)->fptr);
- write_io = RFILE(io)->fptr->tied_io_for_writing;
- if (write_io) {
- return write_io;
- }
- return io;
- }
- /*
- * call-seq:
- * IO.try_convert(obj) -> io or nil
- *
- * Try to convert <i>obj</i> into an IO, using to_io method.
- * Returns converted IO or nil if <i>obj</i> cannot be converted
- * for any reason.
- *
- * IO.try_convert(STDOUT) #=> STDOUT
- * IO.try_convert("STDOUT") #=> nil
- *
- * require 'zlib'
- * f = open("/tmp/zz.gz") #=> #<File:/tmp/zz.gz>
- * z = Zlib::GzipReader.open(f) #=> #<Zlib::GzipReader:0x81d8744>
- * IO.try_convert(z) #=> #<File:/tmp/zz.gz>
- *
- */
- static VALUE
- rb_io_s_try_convert(VALUE dummy, VALUE io)
- {
- return rb_io_check_io(io);
- }
- static void
- io_unread(rb_io_t *fptr)
- {
- off_t r;
- rb_io_check_closed(fptr);
- if (fptr->rbuf_len == 0 || fptr->mode & FMODE_DUPLEX)
- return;
- /* xxx: target position may be negative if buffer is filled by ungetc */
- errno = 0;
- r = lseek(fptr->fd, -fptr->rbuf_len, SEEK_CUR);
- if (r < 0 && errno) {
- if (errno == ESPIPE)
- fptr->mode |= FMODE_DUPLEX;
- return;
- }
- fptr->rbuf_off = 0;
- fptr->rbuf_len = 0;
- return;
- }
- static rb_encoding *io_input_encoding(rb_io_t *fptr);
- static void
- io_ungetbyte(VALUE str, rb_io_t *fptr)
- {
- long len = RSTRING_LEN(str);
- if (fptr->rbuf == NULL) {
- const int min_capa = IO_RBUF_CAPA_FOR(fptr);
- fptr->rbuf_off = 0;
- fptr->rbuf_len = 0;
- #if SIZEOF_LONG > SIZEOF_INT
- if (len > INT_MAX)
- rb_raise(rb_eIOError, "ungetbyte failed");
- #endif
- if (len > min_capa)
- fptr->rbuf_capa = (int)len;
- else
- fptr->rbuf_capa = min_capa;
- fptr->rbuf = ALLOC_N(char, fptr->rbuf_capa);
- }
- if (fptr->rbuf_capa < len + fptr->rbuf_len) {
- rb_raise(rb_eIOError, "ungetbyte failed");
- }
- if (fptr->rbuf_off < len) {
- MEMMOVE(fptr->rbuf+fptr->rbuf_capa-fptr->rbuf_len,
- fptr->rbuf+fptr->rbuf_off,
- char, fptr->rbuf_len);
- fptr->rbuf_off = fptr->rbuf_capa-fptr->rbuf_len;
- }
- fptr->rbuf_off-=(int)len;
- fptr->rbuf_len+=(int)len;
- MEMMOVE(fptr->rbuf+fptr->rbuf_off, RSTRING_PTR(str), char, len);
- }
- static rb_io_t *
- flush_before_seek(rb_io_t *fptr)
- {
- if (io_fflush(fptr) < 0)
- rb_sys_fail(0);
- io_unread(fptr);
- errno = 0;
- return fptr;
- }
- #define io_seek(fptr, ofs, whence) (errno = 0, lseek(flush_before_seek(fptr)->fd, ofs, whence))
- #define io_tell(fptr) lseek(flush_before_seek(fptr)->fd, 0, SEEK_CUR)
- #ifndef SEEK_CUR
- # define SEEK_SET 0
- # define SEEK_CUR 1
- # define SEEK_END 2
- #endif
- #define FMODE_SYNCWRITE (FMODE_SYNC|FMODE_WRITABLE)
- void
- rb_io_check_char_readable(rb_io_t *fptr)
- {
- rb_io_check_closed(fptr);
- if (!(fptr->mode & FMODE_READABLE)) {
- rb_raise(rb_eIOError, "not opened for reading");
- }
- if (fptr->wbuf_len) {
- if (io_fflush(fptr) < 0)
- rb_sys_fail(0);
- }
- if (fptr->tied_io_for_writing) {
- rb_io_t *wfptr;
- GetOpenFile(fptr->tied_io_for_writing, wfptr);
- if (io_fflush(wfptr) < 0)
- rb_sys_fail(0);
- }
- }
- void
- rb_io_check_byte_readable(rb_io_t *fptr)
- {
- rb_io_check_char_readable(fptr);
- if (READ_CHAR_PENDING(fptr)) {
- rb_raise(rb_eIOError, "byte oriented read for character buffered IO");
- }
- }
- void
- rb_io_check_readable(rb_io_t *fptr)
- {
- rb_io_check_byte_readable(fptr);
- }
- static rb_encoding*
- io_read_encoding(rb_io_t *fptr)
- {
- if (fptr->encs.enc) {
- return fptr->encs.enc;
- }
- return rb_default_external_encoding();
- }
- static rb_encoding*
- io_input_encoding(rb_io_t *fptr)
- {
- if (fptr->encs.enc2) {
- return fptr->encs.enc2;
- }
- return io_read_encoding(fptr);
- }
- void
- rb_io_check_writable(rb_io_t *fptr)
- {
- rb_io_check_closed(fptr);
- if (!(fptr->mode & FMODE_WRITABLE)) {
- rb_raise(rb_eIOError, "not opened for writing");
- }
- if (fptr->rbuf_len) {
- io_unread(fptr);
- }
- }
- int
- rb_io_read_pending(rb_io_t *fptr)
- {
- /* This function is used for bytes and chars. Confusing. */
- if (READ_CHAR_PENDING(fptr))
- return 1; /* should raise? */
- return READ_DATA_PENDING(fptr);
- }
- void
- rb_read_check(FILE *fp)
- {
- if (!STDIO_READ_DATA_PENDING(fp)) {
- rb_thread_wait_fd(fileno(fp));
- }
- }
- void
- rb_io_read_check(rb_io_t *fptr)
- {
- if (!READ_DATA_PENDING(fptr)) {
- rb_thread_wait_fd(fptr->fd);
- }
- return;
- }
- static int
- ruby_dup(int orig)
- {
- int fd;
- fd = dup(orig);
- if (fd < 0) {
- if (errno == EMFILE || errno == ENFILE || errno == ENOMEM) {
- rb_gc();
- fd = dup(orig);
- }
- if (fd < 0) {
- rb_sys_fail(0);
- }
- }
- UPDATE_MAXFD(fd);
- return fd;
- }
- static VALUE
- io_alloc(VALUE klass)
- {
- NEWOBJ(io, struct RFile);
- OBJSETUP(io, klass, T_FILE);
- io->fptr = 0;
- return (VALUE)io;
- }
- #ifndef S_ISREG
- # define S_ISREG(m) ((m & S_IFMT) == S_IFREG)
- #endif
- static int
- wsplit_p(rb_io_t *fptr)
- {
- #if defined(HAVE_FCNTL) && defined(F_GETFL) && defined(O_NONBLOCK)
- int r;
- #endif
- if (!(fptr->mode & FMODE_WSPLIT_INITIALIZED)) {
- struct stat buf;
- if (fstat(fptr->fd, &buf) == 0 &&
- !S_ISREG(buf.st_mode)
- #if defined(HAVE_FCNTL) && defined(F_GETFL) && defined(O_NONBLOCK)
- && (r = fcntl(fptr->fd, F_GETFL)) != -1 &&
- !(r & O_NONBLOCK)
- #endif
- ) {
- fptr->mode |= FMODE_WSPLIT;
- }
- fptr->mode |= FMODE_WSPLIT_INITIALIZED;
- }
- return fptr->mode & FMODE_WSPLIT;
- }
- struct io_internal_struct {
- int fd;
- void *buf;
- size_t capa;
- };
- static VALUE
- internal_read_func(void *ptr)
- {
- struct io_internal_struct *iis = (struct io_internal_struct*)ptr;
- return read(iis->fd, iis->buf, iis->capa);
- }
- static VALUE
- internal_write_func(void *ptr)
- {
- struct io_internal_struct *iis = (struct io_internal_struct*)ptr;
- return write(iis->fd, iis->buf, iis->capa);
- }
- static ssize_t
- rb_read_internal(int fd, void *buf, size_t count)
- {
- struct io_internal_struct iis;
- iis.fd = fd;
- iis.buf = buf;
- iis.capa = count;
- return (ssize_t)rb_thread_blocking_region(internal_read_func, &iis, RUBY_UBF_IO, 0);
- }
- static ssize_t
- rb_write_internal(int fd, void *buf, size_t count)
- {
- struct io_internal_struct iis;
- iis.fd = fd;
- iis.buf = buf;
- iis.capa = count;
- return (ssize_t)rb_thread_blocking_region(internal_write_func, &iis, RUBY_UBF_IO, 0);
- }
- static long
- io_writable_length(rb_io_t *fptr, long l)
- {
- if (PIPE_BUF < l &&
- !rb_thread_alone() &&
- wsplit_p(fptr)) {
- l = PIPE_BUF;
- }
- return l;
- }
- static VALUE
- io_flush_buffer(VALUE arg)
- {
- rb_io_t *fptr = (rb_io_t *)arg;
- long l = io_writable_length(fptr, fptr->wbuf_len);
- return rb_write_internal(fptr->fd, fptr->wbuf+fptr->wbuf_off, l);
- }
- static int
- io_fflush(rb_io_t *fptr)
- {
- long r;
- rb_io_check_closed(fptr);
- if (fptr->wbuf_len == 0)
- return 0;
- if (!rb_thread_fd_writable(fptr->fd)) {
- rb_io_check_closed(fptr);
- }
- retry:
- if (fptr->wbuf_len == 0)
- return 0;
- if (fptr->write_lock) {
- r = rb_mutex_synchronize(fptr->write_lock, io_flush_buffer, (VALUE)fptr);
- }
- else {
- long l = io_writable_length(fptr, fptr->wbuf_len);
- r = rb_write_internal(fptr->fd, fptr->wbuf+fptr->wbuf_off, l);
- }
- /* xxx: Other threads may modify wbuf.
- * A lock is required, definitely. */
- rb_io_check_closed(fptr);
- if (fptr->wbuf_len <= r) {
- fptr->wbuf_off = 0;
- fptr->wbuf_len = 0;
- return 0;
- }
- if (0 <= r) {
- fptr->wbuf_off += (int)r;
- fptr->wbuf_len -= (int)r;
- errno = EAGAIN;
- }
- if (rb_io_wait_writable(fptr->fd)) {
- rb_io_check_closed(fptr);
- goto retry;
- }
- return -1;
- }
- #ifdef HAVE_RB_FD_INIT
- static VALUE
- wait_readable(VALUE p)
- {
- rb_fdset_t *rfds = (rb_fdset_t *)p;
- return rb_thread_select(rb_fd_max(rfds), rb_fd_ptr(rfds), NULL, NULL, NULL);
- }
- #endif
- int
- rb_io_wait_readable(int f)
- {
- rb_fdset_t rfds;
- if (f < 0) {
- rb_raise(rb_eIOError, "closed stream");
- }
- switch (errno) {
- case EINTR:
- #if defined(ERESTART)
- case ERESTART:
- #endif
- rb_thread_wait_fd(f);
- return TRUE;
- case EAGAIN:
- #if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
- case EWOULDBLOCK:
- #endif
- rb_fd_init(&rfds);
- rb_fd_set(f, &rfds);
- #ifdef HAVE_RB_FD_INIT
- rb_ensure(wait_readable, (VALUE)&rfds,
- (VALUE (*)(VALUE))rb_fd_term, (VALUE)&rfds);
- #else
- rb_thread_select(f + 1, rb_fd_ptr(&rfds), NULL, NULL, NULL);
- #endif
- return TRUE;
- default:
- return FALSE;
- }
- }
- #ifdef HAVE_RB_FD_INIT
- static VALUE
- wait_writable(VALUE p)
- {
- rb_fdset_t *wfds = (rb_fdset_t *)p;
- return rb_thread_select(rb_fd_max(wfds), NULL, rb_fd_ptr(wfds), NULL, NULL);
- }
- #endif
- int
- rb_io_wait_writable(int f)
- {
- rb_fdset_t wfds;
- if (f < 0) {
- rb_raise(rb_eIOError, "closed stream");
- }
- switch (errno) {
- case EINTR:
- #if defined(ERESTART)
- case ERESTART:
- #endif
- rb_thread_fd_writable(f);
- return TRUE;
- case EAGAIN:
- #if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
- case EWOULDBLOCK:
- #endif
- rb_fd_init(&wfds);
- rb_fd_set(f, &wfds);
- #ifdef HAVE_RB_FD_INIT
- rb_ensure(wait_writable, (VALUE)&wfds,
- (VALUE (*)(VALUE))rb_fd_term, (VALUE)&wfds);
- #else
- rb_thread_select(f + 1, NULL, rb_fd_ptr(&wfds), NULL, NULL);
- #endif
- return TRUE;
- default:
- return FALSE;
- }
- }
- static void
- make_writeconv(rb_io_t *fptr)
- {
- if (!fptr->writeconv_initialized) {
- const char *senc, *denc;
- rb_encoding *enc;
- int ecflags;
- VALUE ecopts;
- fptr->writeconv_initialized = 1;
- ecflags = fptr->encs.ecflags;
- ecopts = fptr->encs.ecopts;
- #ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
- if (NEED_NEWLINE_DECORATOR_ON_WRITE(fptr))
- ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
- #endif
- if (!fptr->encs.enc || (fptr->encs.enc == rb_ascii8bit_encoding() && !fptr->encs.enc2)) {
- /* no encoding conversion */
- fptr->writeconv_pre_ecflags = 0;
- fptr->writeconv_pre_ecopts = Qnil;
- fptr->writeconv = rb_econv_open_opts("", "", ecflags, ecopts);
- if (!fptr->writeconv)
- rb_exc_raise(rb_econv_open_exc("", "", ecflags));
- fptr->writeconv_asciicompat = Qnil;
- }
- else {
- enc = fptr->encs.enc2 ? fptr->encs.enc2 : fptr->encs.enc;
- senc = rb_econv_asciicompat_encoding(rb_enc_name(enc));
- if (!senc && !(fptr->encs.ecflags & ECONV_STATEFUL_DECORATOR_MASK)) {
- /* single conversion */
- fptr->writeconv_pre_ecflags = ecflags;
- fptr->writeconv_pre_ecopts = ecopts;
- fptr->writeconv = NULL;
- fptr->writeconv_asciicompat = Qnil;
- }
- else {
- /* double conversion */
- fptr->writeconv_pre_ecflags = ecflags & ~ECONV_STATEFUL_DECORATOR_MASK;
- fptr->writeconv_pre_ecopts = ecopts;
- if (senc) {
- denc = rb_enc_name(enc);
- fptr->writeconv_asciicompat = rb_str_new2(senc);
- }
- else {
- senc = denc = "";
- fptr->writeconv_asciicompat = rb_str_new2(rb_enc_name(enc));
- }
- ecflags = fptr->encs.ecflags & (ECONV_ERROR_HANDLER_MASK|ECONV_STATEFUL_DECORATOR_MASK);
- ecopts = fptr->encs.ecopts;
- fptr->writeconv = rb_econv_open_opts(senc, denc, ecflags, ecopts);
- if (!fptr->writeconv)
- rb_exc_raise(rb_econv_open_exc(senc, denc, ecflags));
- }
- }
- }
- }
- /* writing functions */
- struct binwrite_arg {
- rb_io_t *fptr;
- VALUE str;
- long offset;
- long length;
- };
- static VALUE
- io_binwrite_string(VALUE arg)
- {
- struct binwrite_arg *p = (struct binwrite_arg *)arg;
- long l = io_writable_length(p->fptr, p->length);
- return rb_write_internal(p->fptr->fd, RSTRING_PTR(p->str)+p->offset, l);
- }
- static long
- io_binwrite(VALUE str, rb_io_t *fptr, int nosync)
- {
- long len, n, r, offset = 0;
- len = RSTRING_LEN(str);
- if ((n = len) <= 0) return n;
- if (fptr->wbuf == NULL && !(!nosync && (fptr->mode & FMODE_SYNC))) {
- fptr->wbuf_off = 0;
- fptr->wbuf_len = 0;
- fptr->wbuf_capa = IO_WBUF_CAPA_MIN;
- fptr->wbuf = ALLOC_N(char, fptr->wbuf_capa);
- fptr->write_lock = rb_mutex_new();
- }
- if ((!nosync && (fptr->mode & (FMODE_SYNC|FMODE_TTY))) ||
- (fptr->wbuf && fptr->wbuf_capa <= fptr->wbuf_len + len)) {
- struct binwrite_arg arg;
- /* xxx: use writev to avoid double write if available */
- if (fptr->wbuf_len && fptr->wbuf_len+len <= fptr->wbuf_capa) {
- if (fptr->wbuf_capa < fptr->wbuf_off+fptr->wbuf_len+len) {
- MEMMOVE(fptr->wbuf, fptr->wbuf+fptr->wbuf_off, char, fptr->wbuf_len);
- fptr->wbuf_off = 0;
- }
- MEMMOVE(fptr->wbuf+fptr->wbuf_off+fptr->wbuf_len, RSTRING_PTR(str)+offset, char, len);
- fptr->wbuf_len += (int)len;
- n = 0;
- }
- if (io_fflush(fptr) < 0)
- return -1L;
- if (n == 0)
- return len;
- /* avoid context switch between "a" and "\n" in STDERR.puts "a".
- [ruby-dev:25080] */
- if (fptr->stdio_file != stderr && !rb_thread_fd_writable(fptr->fd)) {
- rb_io_check_closed(fptr);
- }
- arg.fptr = fptr;
- arg.str = str;
- retry:
- arg.offset = offset;
- arg.length = n;
- if (fptr->write_lock) {
- r = rb_mutex_synchronize(fptr->write_lock, io_binwrite_string, (VALUE)&arg);
- }
- else {
- long l = io_writable_length(fptr, n);
- r = rb_write_internal(fptr->fd, RSTRING_PTR(str)+offset, l);
- }
- /* xxx: other threads may modify given string. */
- if (r == n) return len;
- if (0 <= r) {
- offset += r;
- n -= r;
- errno = EAGAIN;
- }
- if (rb_io_wait_writable(fptr->fd)) {
- rb_io_check_closed(fptr);
- if (offset < RSTRING_LEN(str))
- goto retry;
- }
- return -1L;
- }
- if (fptr->wbuf_off) {
- if (fptr->wbuf_len)
- MEMMOVE(fptr->wbuf, fptr->wbuf+fptr->wbuf_off, char, fptr->wbuf_len);
- fptr->wbuf_off = 0;
- }
- MEMMOVE(fptr->wbuf+fptr->wbuf_off+fptr->wbuf_len, RSTRING_PTR(str)+offset, char, len);
- fptr->wbuf_len += (int)len;
- return len;
- }
- static VALUE
- do_writeconv(VALUE str, rb_io_t *fptr)
- {
- if (NEED_WRITECONV(fptr)) {
- VALUE common_encoding = Qnil;
- make_writeconv(fptr);
- if (fptr->writeconv) {
- if (!NIL_P(fptr->writeconv_asciicompat))
- common_encoding = fptr->writeconv_asciicompat;
- else if (!rb_enc_asciicompat(rb_enc_get(str))) {
- rb_raise(rb_eArgError, "ASCII incompatible string written for text mode IO without encoding conversion: %s",
- rb_enc_name(rb_enc_get(str)));
- }
- }
- else {
- if (fptr->encs.enc2)
- common_encoding = rb_enc_from_encoding(fptr->encs.enc2);
- else if (fptr->encs.enc != rb_ascii8bit_encoding())
- common_encoding = rb_enc_from_encoding(fptr->encs.enc);
- }
- if (!NIL_P(common_encoding)) {
- str = rb_str_encode(str, common_encoding,
- fptr->writeconv_pre_ecflags, fptr->writeconv_pre_ecopts);
- }
- if (fptr->writeconv) {
- str = rb_econv_str_convert(fptr->writeconv, str, ECONV_PARTIAL_INPUT);
- }
- }
- return str;
- }
- static long
- io_fwrite(VALUE str, rb_io_t *fptr, int nosync)
- {
- str = do_writeconv(str, fptr);
- return io_binwrite(str, fptr, nosync);
- }
- static VALUE
- io_write(VALUE io, VALUE str, int nosync)
- {
- rb_io_t *fptr;
- long n;
- VALUE tmp;
- rb_secure(4);
- io = GetWriteIO(io);
- str = rb_obj_as_string(str);
- tmp = rb_io_check_io(io);
- if (NIL_P(tmp)) {
- /* port is not IO, call write method for it. */
- return rb_funcall(io, id_write, 1, str);
- }
- io = tmp;
- if (RSTRING_LEN(str) == 0) return INT2FIX(0);
- GetOpenFile(io, fptr);
- rb_io_check_writable(fptr);
- n = io_fwrite(str, fptr, nosync);
- if (n == -1L) rb_sys_fail_path(fptr->pathv);
- return LONG2FIX(n);
- }
- /*
- * call-seq:
- * ios.write(string) -> integer
- *
- * Writes the given string to <em>ios</em>. The stream must be opened
- * for writing. If the argument is not a string, it will be converted
- * to a string using <code>to_s</code>. Returns the number of bytes
- * written.
- *
- * count = $stdout.write( "This is a test\n" )
- * puts "That was #{count} bytes of data"
- *
- * <em>produces:</em>
- *
- * This is a test
- * That was 15 bytes of data
- */
- static VALUE
- io_write_m(VALUE io, VALUE str)
- {
- return io_write(io, str, 0);
- }
- VALUE
- rb_io_write(VALUE io, VALUE str)
- {
- return rb_funcall(io, id_write, 1, str);
- }
- /*
- * call-seq:
- * ios << obj -> ios
- *
- * String Output---Writes <i>obj</i> to <em>ios</em>.
- * <i>obj</i> will be converted to a string using
- * <code>to_s</code>.
- *
- * $stdout << "Hello " << "world!\n"
- *
- * <em>produces:</em>
- *
- * Hello world!
- */
- VALUE
- rb_io_addstr(VALUE io, VALUE str)
- {
- rb_io_write(io, str);
- return io;
- }
- /*
- * call-seq:
- * ios.flush -> ios
- *
- * Flushes any buffered data within <em>ios</em> to the underlying
- * operating system (note that this is Ruby internal buffering only;
- * the OS may buffer the data as well).
- *
- * $stdout.print "no newline"
- * $stdout.flush
- *
- * <em>produces:</em>
- *
- * no newline
- */
- VALUE
- rb_io_flush(VALUE io)
- {
- rb_io_t *fptr;
- if (TYPE(io) != T_FILE) {
- return rb_funcall(io, id_flush, 0);
- }
- io = GetWriteIO(io);
- GetOpenFile(io, fptr);
- if (fptr->mode & FMODE_WRITABLE) {
- if (io_fflush(fptr) < 0)
- rb_sys_fail(0);
- #ifdef _WIN32
- fsync(fptr->fd);
- #endif
- }
- if (fptr->mode & FMODE_READABLE) {
- io_unread(fptr);
- }
- return io;
- }
- /*
- * call-seq:
- * ios.pos -> integer
- * ios.tell -> integer
- *
- * Returns the current offset (in bytes) of <em>ios</em>.
- *
- * f = File.new("testfile")
- * f.pos #=> 0
- * f.gets #=> "This is line one\n"
- * f.pos #=> 17
- */
- static VALUE
- rb_io_tell(VALUE io)
- {
- rb_io_t *fptr;
- off_t pos;
- GetOpenFile(io, fptr);
- pos = io_tell(fptr);
- if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
- pos -= fptr->rbuf_len;
- return OFFT2NUM(pos);
- }
- static VALUE
- rb_io_seek(VALUE io, VALUE offset, int whence)
- {
- rb_io_t *fptr;
- off_t pos;
- pos = NUM2OFFT(offset);
- GetOpenFile(io, fptr);
- pos = io_seek(fptr, pos, whence);
- if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
- return INT2FIX(0);
- }
- /*
- * call-seq:
- * ios.seek(amount, whence=IO::SEEK_SET) -> 0
- *
- * Seeks to a given offset <i>anInteger</i> in the stream according to
- * the value of <i>whence</i>:
- *
- * IO::SEEK_CUR | Seeks to _amount_ plus current position
- * --------------+----------------------------------------------------
- * IO::SEEK_END | Seeks to _amount_ plus end of stream (you probably
- * | want a negative value for _amount_)
- * --------------+----------------------------------------------------
- * IO::SEEK_SET | Seeks to the absolute location given by _amount_
- *
- * Example:
- *
- * f = File.new("testfile")
- * f.seek(-13, IO::SEEK_END) #=> 0
- * f.readline #=> "And so on...\n"
- */
- static VALUE
- rb_io_seek_m(int argc, VALUE *argv, VALUE io)
- {
- VALUE offset, ptrname;
- int whence = SEEK_SET;
- if (rb_scan_args(argc, argv, "11", &offset, &ptrname) == 2) {
- whence = NUM2INT(ptrname);
- }
- return rb_io_seek(io, offset, whence);
- }
- /*
- * call-seq:
- * ios.pos = integer -> integer
- *
- * Seeks to the given position (in bytes) in <em>ios</em>.
- *
- * f = File.new("testfile")
- * f.pos = 17
- * f.gets #=> "This is line two\n"
- */
- static VALUE
- rb_io_set_pos(VALUE io, VALUE offset)
- {
- rb_io_t *fptr;
- off_t pos;
- pos = NUM2OFFT(offset);
- GetOpenFile(io, fptr);
- pos = io_seek(fptr, pos, SEEK_SET);
- if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
- return OFFT2NUM(pos);
- }
- static void clear_readconv(rb_io_t *fptr);
- /*
- * call-seq:
- * ios.rewind -> 0
- *
- * Positions <em>ios</em> to the beginning of input, resetting
- * <code>lineno</code> to zero.
- *
- * f = File.new("testfile")
- * f.readline #=> "This is line one\n"
- * f.rewind #=> 0
- * f.lineno #=> 0
- * f.readline #=> "This is line one\n"
- *
- * Note that it cannot be used with streams such as pipes, ttys, and sockets.
- */
- static VALUE
- rb_io_rewind(VALUE io)
- {
- rb_io_t *fptr;
- GetOpenFile(io, fptr);
- if (io_seek(fptr, 0L, 0) < 0 && errno) rb_sys_fail_path(fptr->pathv);
- if (io == ARGF.current_file) {
- ARGF.lineno -= fptr->lineno;
- }
- fptr->lineno = 0;
- if (fptr->readconv) {
- clear_readconv(fptr);
- }
- return INT2FIX(0);
- }
- static int
- io_fillbuf(rb_io_t *fptr)
- {
- ssize_t r;
- if (fptr->rbuf == NULL) {
- fptr->rbuf_off = 0;
- fptr->rbuf_len = 0;
- fptr->rbuf_capa = IO_RBUF_CAPA_FOR(fptr);
- fptr->rbuf = ALLOC_N(char, fptr->rbuf_capa);
- }
- if (fptr->rbuf_len == 0) {
- retry:
- {
- r = rb_read_internal(fptr->fd, fptr->rbuf, fptr->rbuf_capa);
- }
- if (r < 0) {
- if (rb_io_wait_readable(fptr->fd))
- goto retry;
- rb_sys_fail_path(fptr->pathv);
- }
- fptr->rbuf_off = 0;
- fptr->rbuf_len = (int)r; /* r should be <= rbuf_capa */
- if (r == 0)
- return -1; /* EOF */
- }
- return 0;
- }
- /*
- * call-seq:
- * ios.eof -> true or false
- * ios.eof? -> true or false
- *
- * Returns true if <em>ios</em> is at end of file that means
- * there are no more data to read.
- * The stream must be opened for reading or an <code>IOError</code> will be
- * raised.
- *
- * f = File.new("testfile")
- * dummy = f.readlines
- * f.eof #=> true
- *
- * If <em>ios</em> is a stream such as pipe or socket, <code>IO#eof?</code>
- * blocks until the other end sends some data or closes it.
- *
- * r, w = IO.pipe
- * Thread.new { sleep 1; w.close }
- * r.eof? #=> true after 1 second blocking
- *
- * r, w = IO.pipe
- * Thread.new { sleep 1; w.puts "a" }
- * r.eof? #=> false after 1 second blocking
- *
- * r, w = IO.pipe
- * r.eof? # blocks forever
- *
- * Note that <code>IO#eof?</code> reads data to the input byte buffer.
- * So <code>IO#sysread</code> may not behave as you intend with
- * <code>IO#eof?</code>, unless you call <code>IO#rewind</code>
- * first (which is not available for some streams).
- */
- VALUE
- rb_io_eof(VALUE io)
- {
- rb_io_t *fptr;
- GetOpenFile(io, fptr);
- rb_io_check_char_readable(fptr);
- if (READ_CHAR_PENDING(fptr)) return Qfalse;
- if (READ_DATA_PENDING(fptr)) return Qfalse;
- READ_CHECK(fptr);
- if (io_fillbuf(fptr) < 0) {
- return Qtrue;
- }
- return Qfalse;
- }
- /*
- * call-seq:
- * ios.sync -> true or false
- *
- * Returns the current ``sync mode'' of <em>ios</em>. When sync mode is
- * true, all output is immediately flushed to the underlying operating
- * system and is not buffered by Ruby internally. See also
- * <code>IO#fsync</code>.
- *
- * f = File.new("testfile")
- * f.sync #=> false
- */
- static VALUE
- rb_io_sync(VALUE io)
- {
- rb_io_t *fptr;
- io = GetWriteIO(io);
- GetOpenFile(io, fptr);
- return (fptr->mode & FMODE_SYNC) ? Qtrue : Qfalse;
- }
- /*
- * call-seq:
- * ios.sync = boolean -> boolean
- *
- * Sets the ``sync mode'' to <code>true</code> or <code>false</code>.
- * When sync mode is true, all output is immediately flushed to the
- * underlying operating system and is not buffered internally. Returns
- * the new state. See also <code>IO#fsync</code>.
- *
- * f = File.new("testfile")
- * f.sync = true
- *
- * <em>(produces no output)</em>
- */
- static VALUE
- rb_io_set_sync(VALUE io, VALUE sync)
- {
- rb_io_t *fptr;
- io = GetWriteIO(io);
- GetOpenFile(io, fptr);
- if (RTEST(sync)) {
- fptr->mode |= FMODE_SYNC;
- }
- else {
- fptr->mode &= ~FMODE_SYNC;
- }
- return sync;
- }
- #ifdef HAVE_FSYNC
- /*
- * call-seq:
- * ios.fsync -> 0 or nil
- *
- * Immediately writes all buffered data in <em>ios</em> to disk.
- * Note that <code>fsync</code> differs from
- * using <code>IO#sync=</code>. The latter ensures that data is flushed
- * from Ruby's buffers, but doesn't not guarantee that the underlying
- * operating system actually writes it to disk.
- *
- * <code>NotImplementedError</code> is raised
- * if the underlying operating system does not support <em>fsync(2)</em>.
- */
- static VALUE
- rb_io_fsync(VALUE io)
- {
- rb_io_t *fptr;
- io = GetWriteIO(io);
- GetOpenFile(io, fptr);
- if (io_fflush(fptr) < 0)
- rb_sys_fail(0);
- if (fsync(fptr->fd) < 0)
- rb_sys_fail_path(fptr->pathv);
- return INT2FIX(0);
- }
- #else
- #define rb_io_fsync rb_f_notimplement
- #endif
- #ifdef HAVE_FDATASYNC
- /*
- * call-seq:
- * ios.fdatasync -> 0 or nil
- *
- * Immediately writes all buffered data in <em>ios</em> to disk.
- *
- * <code>NotImplementedError</code> is raised
- * if the underlying operating system does not support <em>fdatasync(2)</em>.
- */
- static VALUE
- rb_io_fdatasync(VALUE io)
- {
- rb_io_t *fptr;
- io = GetWriteIO(io);
- GetOpenFile(io, fptr);
- if (io_fflush(fptr) < 0)
- rb_sys_fail(0);
- if (fdatasync(fptr->fd) < 0)
- rb_sys_fail_path(fptr->pathv);
- return INT2FIX(0);
- }
- #else
- #define rb_io_fdatasync rb_f_notimplement
- #endif
- /*
- * call-seq:
- * ios.fileno -> fixnum
- * ios.to_i -> fixnum
- *
- * Returns an integer representing the numeric file descriptor for
- * <em>ios</em>.
- *
- * $stdin.fileno #=> 0
- * $stdout.fileno #=> 1
- */
- static VALUE
- rb_io_fileno(VALUE io)
- {
- rb_io_t *fptr;
- int fd;
- GetOpenFile(io, fptr);
- fd = fptr->fd;
- return INT2FIX(fd);
- }
- /*
- * call-seq:
- * ios.pid -> fixnum
- *
- * Returns the process ID of a child process associated with
- * <em>ios</em>. This will be set by <code>IO.popen</code>.
- *
- * pipe = IO.popen("-")
- * if pipe
- * $stderr.puts "In parent, child pid is #{pipe.pid}"
- * else
- * $stderr.puts "In child, pid is #{$$}"
- * end
- *
- * <em>produces:</em>
- *
- * In child, pid is 26209
- * In parent, child pid is 26209
- */
- static VALUE
- rb_io_pid(VALUE io)
- {
- rb_io_t *fptr;
- GetOpenFile(io, fptr);
- if (!fptr->pid)
- return Qnil;
- return PIDT2NUM(fptr->pid);
- }
- /*
- * call-seq:
- * ios.inspect -> string
- *
- * Return a string describing this IO object.
- */
- static VALUE
- rb_io_inspect(VALUE obj)
- {
- rb_io_t *fptr;
- const char *cname;
- char fd_desc[4+sizeof(int)*3];
- const char *path;
- const char *st = "";
- fptr = RFILE(rb_io_taint_check(obj))->fptr;
- if (!fptr) return rb_any_to_s(obj);
- cname = rb_obj_classname(obj);
- if (NIL_P(fptr->pathv)) {
- if (fptr->fd < 0) {
- path = "";
- st = "(closed)";
- }
- else {
- snprintf(fd_desc, sizeof(fd_desc), "fd %d", fptr->fd);
- path = fd_desc;
- }
- }
- else {
- path = RSTRING_PTR(fptr->pathv);
- if (fptr->fd < 0) {
- st = " (closed)";
- }
- }
- return rb_sprintf("#<%s:%s%s>", cname, path, st);
- }
- /*
- * call-seq:
- * ios.to_io -> ios
- *
- * Returns <em>ios</em>.
- */
- static VALUE
- rb_io_to_io(VALUE io)
- {
- return io;
- }
- /* reading functions */
- static long
- read_buffered_data(char *ptr, long len, rb_io_t *fptr)
- {
- int n;
- n = READ_DATA_PENDING_COUNT(fptr);
- if (n <= 0) return 0;
- if (n > len) n = (int)len;
- MEMMOVE(ptr, fptr->rbuf+fptr->rbuf_off, char, n);
- fptr->rbuf_off += n;
- fptr->rbuf_len -= n;
- return n;
- }
- static long
- io_fread(VALUE str, long offset, rb_io_t *fptr)
- {
- long len = RSTRING_LEN(str) - offset;
- long n = len;
- long c;
- rb_str_locktmp(str);
- if (READ_DATA_PENDING(fptr) == 0) {
- while (n > 0) {
- again:
- c = rb_read_internal(fptr->fd, RSTRING_PTR(str)+offset, n);
- if (c == 0) break;
- if (c < 0) {
- if (rb_io_wait_readable(fptr->fd))
- goto again;
- rb_sys_fail_path(fptr->pathv);
- }
- offset += c;
- if ((n -= c) <= 0) break;
- rb_thread_wait_fd(fptr->fd);
- }
- rb_str_unlocktmp(str);
- return len - n;
- }
- while (n > 0) {
- c = read_buffered_data(RSTRING_PTR(str)+offset, n, fptr);
- if (c > 0) {
- offset += c;
- if ((n -= c) <= 0) break;
- }
- rb_thread_wait_fd(fptr->fd);
- rb_io_check_closed(fptr);
- if (io_fillbuf(fptr) < 0) {
- break;
- }
- }
- rb_str_unlocktmp(str);
- return len - n;
- }
- #define SMALLBUF 100
- static long
- remain_size(rb_io_t *fptr)
- {
- struct stat st;
- off_t siz = READ_DATA_PENDING_COUNT(fptr);
- off_t pos;
- if (fstat(fptr->fd, &st) == 0 && S_ISREG(st.st_mode)
- #if defined(__BEOS__) || defined(__HAIKU__)
- && (st.st_dev > 3)
- #endif
- )
- {
- if (io_fflush(fptr) < 0)
- rb_sys_fail(0);
- pos = lseek(fptr->fd, 0, SEEK_CUR);
- if (st.st_size >= pos && pos >= 0) {
- siz += st.st_size - pos;
- if (siz > LONG_MAX) {
- rb_raise(rb_eIOError, "file too big for single read");
- }
- }
- }
- else {
- siz += BUFSIZ;
- }
- return (long)siz;
- }
- static VALUE
- io_enc_str(VALUE str, rb_io_t *fptr)
- {
- OBJ_TAINT(str);
- rb_enc_associate(str, io_read_encoding(fptr));
- return str;
- }
- static void
- make_readconv(rb_io_t *fptr, int size)
- {
- if (!fptr->readconv) {
- int ecflags;
- VALUE ecopts;
- const char *sname, *dname;
- ecflags = fptr->encs.ecflags;
- ecopts = fptr->encs.ecopts;
- if (NEED_NEWLINE_DECORATOR_ON_READ(fptr))
- ecflags |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;
- if (fptr->encs.enc2) {
- sname = rb_enc_name(fptr->encs.enc2);
- dname = rb_enc_name(fptr->encs.enc);
- }
- else {
- sname = dname = "";
- }
- fptr->readconv = rb_econv_open_opts(sname, dname, ecflags, ecopts);
- if (!fptr->readconv)
- rb_exc_raise(rb_econv_open_exc(sname, dname, ecflags));
- fptr->cbuf_off = 0;
- fptr->cbuf_len = 0;
- if (size < IO_CBUF_CAPA_MIN) size = IO_CBUF_CAPA_MIN;
- fptr->cbuf_capa = size;
- fptr->cbuf = ALLOC_N(char, fptr->cbuf_capa);
- }
- }
- #define MORE_CHAR_SUSPENDED Qtrue
- #define MORE_CHAR_FINISHED Qnil
- static VALUE
- fill_cbuf(rb_io_t *fptr, int ec_flags)
- {
- const unsigned char *ss, *sp, *se;
- unsigned char *ds, *dp, *de;
- rb_econv_result_t res;
- int putbackable;
- int cbuf_len0;
- VALUE exc;
- ec_flags |= ECONV_PARTIAL_INPUT;
- if (fptr->cbuf_len == fptr->cbuf_capa)
- return MORE_CHAR_SUSPENDED; /* cbuf full */
- if (fptr->cbuf_len == 0)
- fptr->cbuf_off = 0;
- else if (fptr->cbuf_off + fptr->cbuf_len == fptr->cbuf_capa) {
- memmove(fptr->cbuf, fptr->cbuf+fptr->cbuf_off, fptr->cbuf_len);
- fptr->cbuf_off = 0;
- }
- cbuf_len0 = fptr->cbuf_len;
- while (1) {
- ss = sp = (const unsigned char *)fptr->rbuf + fptr->rbuf_off;
- se = sp + fptr->rbuf_len;
- ds = dp = (unsigned char *)fptr->cbuf + fptr->cbuf_off + fptr->cbuf_len;
- de = (unsigned char *)fptr->cbuf + fptr->cbuf_capa;
- res = rb_econv_convert(fptr->readconv, &sp, se, &dp, de, ec_flags);
- fptr->rbuf_off += (int)(sp - ss);
- fptr->rbuf_len -= (int)(sp - ss);
- fptr->cbuf_len += (int)(dp - ds);
- putbackable = rb_econv_putbackable(fptr->readconv);
- if (putbackable) {
- rb_econv_putback(fptr->readconv, (unsigned char *)fptr->rbuf + fptr->rbuf_off - putbackable, putbackable);
- fptr->rbuf_off -= putbackable;
- fptr->rbuf_len += putbackable;
- }
- exc = rb_econv_make_exception(fptr->readconv);
- if (!NIL_P(exc))
- return exc;
- if (cbuf_len0 != fptr->cbuf_len)
- return MORE_CHAR_SUSPENDED;
- if (res == econv_finished) {
- return MORE_CHAR_FINISHED;
- }
- if (res == econv_source_buffer_empty) {
- if (fptr->rbuf_len == 0) {
- READ_CHECK(fptr);
- if (io_fillbuf(fptr) == -1) {
- ds = dp = (unsigned char *)fptr->cbuf + fptr->cbuf_off + fptr->cbuf_len;
- de = (unsigned char *)fptr->cbuf + fptr->cbuf_capa;
- res = rb_econv_convert(fptr->readconv, NULL, NULL, &dp, de, 0);
- fptr->cbuf_len += (int)(dp - ds);
- rb_econv_check_error(fptr->readconv);
- }
- }
- }
- }
- }
- static VALUE
- more_char(rb_io_t *fptr)
- {
- VALUE v;
- v = fill_cbuf(fptr, ECONV_AFTER_OUTPUT);
- if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED)
- rb_exc_raise(v);
- return v;
- }
- static VALUE
- io_shift_cbuf(rb_io_t *fptr, int len, VALUE *strp)
- {
- VALUE str = Qnil;
- if (strp) {
- str = *strp;
- if (NIL_P(str)) {
- *strp = str = rb_str_new(fptr->cbuf+fptr->cbuf_off, len);
- }
- else {
- rb_str_cat(str, fptr->cbuf+fptr->cbuf_off, len);
- }
- OBJ_TAINT(str);
- rb_enc_associate(str, fptr->encs.enc);
- }
- fptr->cbuf_off += len;
- fptr->cbuf_len -= len;
- /* xxx: set coderange */
- if (fptr->cbuf_len == 0)
- fptr->cbuf_off = 0;
- else if (fptr->cbuf_capa/2 < fptr->cbuf_off) {
- memmove(fptr->cbuf, fptr->cbuf+fptr->cbuf_off, fptr->cbuf_len);
- fptr->cbuf_off = 0;
- }
- return str;
- }
- static VALUE
- read_all(rb_io_t *fptr, long siz, VALUE str)
- {
- long bytes;
- long n;
- long pos;
- rb_encoding *enc;
- int cr;
- if (NEED_READCONV(fptr)) {
- if (NIL_P(str)) str = rb_str_new(NULL, 0);
- else rb_str_set_len(str, 0);
- make_readconv(fptr, 0);
- while (1) {
- VALUE v;
- if (fptr->cbuf_len) {
- io_shift_cbuf(fptr, fptr->cbuf_len, &str);
- }
- v = fill_cbuf(fptr, 0);
- if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED) {
- if (fptr->cbuf_len) {
- io_shift_cbuf(fptr, fptr->cbuf_len, &str);
- }
- rb_exc_raise(v);
- }
- if (v == MORE_CHAR_FINISHED) {
- clear_readconv(fptr);
- return io_enc_str(str, fptr);
- }
- }
- }
- bytes = 0;
- pos = 0;
- enc = io_read_encoding(fptr);
- cr = 0;
- if (siz == 0) siz = BUFSIZ;
- if (NIL_P(str)) {
- str = rb_str_new(0, siz);
- }
- else {
- rb_str_resize(str, siz);
- }
- for (;;) {
- READ_CHECK(fptr);
- n = io_fread(str, bytes, fptr);
- if (n == 0 && bytes == 0) {
- break;
- }
- bytes += n;
- if (cr != ENC_CODERANGE_BROKEN)
- pos += rb_str_coderange_scan_restartable(RSTRING_PTR(str) + pos, RSTRING_PTR(str) + bytes, enc, &cr);
- if (bytes < siz) break;
- siz += BUFSIZ;
- rb_str_resize(str, siz);
- }
- if (bytes != siz) rb_str_resize(str, bytes);
- str = io_enc_str(str, fptr);
- ENC_CODERANGE_SET(str, cr);
- return str;
- }
- void
- rb_io_set_nonblock(rb_io_t *fptr)
- {
- int oflags;
- #ifdef F_GETFL
- oflags = fcntl(fptr->fd, F_GETFL);
- if (oflags == -1) {
- rb_sys_fail_path(fptr->pathv);
- }
- #else
- oflags = 0;
- #endif
- if ((oflags & O_NONBLOCK) == 0) {
- oflags |= O_NONBLOCK;
- if (fcntl(fptr->fd, F_SETFL, oflags) == -1) {
- rb_sys_fail_path(fptr->pathv);
- }
- }
- }
- static VALUE
- io_getpartial(int argc, VALUE *argv, VALUE io, int nonblock)
- {
- rb_io_t *fptr;
- VALUE length, str;
- long n, len;
- rb_scan_args(argc, argv, "11", &length, &str);
- 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);
- GetOpenFile(io, fptr);
- rb_io_check_byte_readable(fptr);
- if (len == 0)
- return str;
- if (!nonblock)
- READ_CHECK(fptr);
- n = read_buffered_data(RSTRING_PTR(str), len, fptr);
- if (n <= 0) {
- again:
- if (nonblock) {
- rb_io_set_nonblock(fptr);
- }
- rb_str_locktmp(str);
- n = rb_read_internal(fptr->fd, RSTRING_PTR(str), len);
- rb_str_unlocktmp(str);
- if (n < 0) {
- if (!nonblock && rb_io_wait_readable(fptr->fd))
- goto again;
- if (nonblock && (errno == EWOULDBLOCK || errno == EAGAIN))
- rb_mod_sys_fail(rb_mWaitReadable, "read would block");
- rb_sys_fail_path(fptr->pathv);
- }
- }
- rb_str_resize(str, n);
- if (n == 0)
- return Qnil;
- else
- return str;
- }
- /*
- * call-seq:
- * ios.readpartial(maxlen) -> string
- * ios.readpartial(maxlen, outbuf) -> outbuf
- *
- * Reads at most <i>maxlen</i> bytes from the I/O stream.
- * It blocks only if <em>ios</em> has no data immediately available.
- * It doesn't block if some data 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, tty, etc.
- * It blocks only when no data immediately available.
- * This means that it blocks only when following all conditions hold.
- * * the byte 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 byte 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 # buffer pipe content
- * w << "abc" # "" "abc".
- * r.readpartial(4096) #=> "abc" "" ""
- * r.readpartial(4096) # blocks because buffer and pipe is empty.
- *
- * r, w = IO.pipe # buffer pipe content
- * w << "abc" # "" "abc"
- * w.close # "" "abc" EOF
- * r.readpartial(4096) #=> "abc" "" EOF
- * r.readpartial(4096) # raises EOFError
- *
- * r, w = IO.pipe # 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 behaves similar to sysread.
- * The differences are:
- * * If the byte buffer is not empty, read from the byte buffer instead of "sysread for buffered IO (IOError)".
- * * It doesn't cause Errno::EWOULDBLOCK and Errno::EINTR. When readpartial meets EWOULDBLOCK and EINTR by read system call, readpartial retry the system call.
- *
- * The later means that readpartial is nonblocking-flag insensitive.
- * It blocks on the situation IO#sysread causes Errno::EWOULDBLOCK as if the fd is blocking mode.
- *
- */
- static VALUE
- io_readpartial(int argc, VALUE *argv, VALUE io)
- {
- VALUE ret;
- ret = io_getpartial(argc, argv, io, 0);
- if (NIL_P(ret))
- rb_eof_error();
- else
- return ret;
- }
- /*
- * call-seq:
- * ios.read_nonblock(maxlen) -> string
- * ios.read_nonblock(maxlen, outbuf) -> outbuf
- *
- * Reads at most <i>maxlen</i> bytes from <em>ios</em> using
- * the read(2) system call after O_NONBLOCK is set for
- * the underlying file descriptor.
- *
- * If the optional <i>outbuf</i> argument is present,
- * it must reference a String, which will receive the data.
- *
- * read_nonblock just calls the read(2) system call.
- * It causes all errors the read(2) system call causes: Errno::EWOULDBLOCK, Errno::EINTR, etc.
- * The caller should care such errors.
- *
- * If the exception is Errno::EWOULDBLOCK or Errno::AGAIN,
- * it is extended by IO::WaitReadable.
- * So IO::WaitReadable can be used to rescue the exceptions for retrying read_nonblock.
- *
- * read_nonblock causes EOFError on EOF.
- *
- * If the read byte buffer is not empty,
- * read_nonblock reads from the buffer like readpartial.
- * In this case, the read(2) system call is not called.
- *
- * When read_nonblock raises an exception kind of IO::WaitReadable,
- * read_nonblock should not be called
- * until io is readable for avoiding busy loop.
- * This can be done as follows.
- *
- * # emulates blocking read (readpartial).
- * begin
- * result = io.read_nonblock(maxlen)
- * rescue IO::WaitReadable
- * IO.select([io])
- * retry
- * end
- *
- * Although IO#read_nonblock doesn't raise IO::WaitWritable.
- * OpenSSL::Buffering#read_nonblock can raise IO::WaitWritable.
- * If IO and SSL should be used polymorphically,
- * IO::WaitWritable should be rescued too.
- * See the document of OpenSSL::Buffering#read_nonblock for sample code.
- *
- * Note that this method is identical to readpartial
- * except the non-blocking flag is set.
- */
- static VALUE
- io_read_nonblock(int argc, VALUE *argv, VALUE io)
- {
- VALUE ret;
- ret = io_getpartial(argc, argv, io, 1);
- if (NIL_P(ret))
- rb_eof_error();
- else
- return ret;
- }
- /*
- * call-seq:
- * ios.write_nonblock(string) -> integer
- *
- * Writes the given string to <em>ios</em> using
- * the write(2) system call after O_NONBLOCK is set for
- * the underlying file descriptor.
- *
- * It returns the number of bytes written.
- *
- * write_nonblock just calls the write(2) system call.
- * It causes all errors the write(2) system call causes: Errno::EWOULDBLOCK, Errno::EINTR, etc.
- * The result may also be smaller than string.length (partial write).
- * The caller should care such errors and partial write.
- *
- * If the exception is Err…
Large files files are truncated, but you can click here to view the full file