io.c

Go to the documentation of this file.
00001 /**********************************************************************
00002 
00003   io.c -
00004 
00005   $Author: nagachika $
00006   created at: Fri Oct 15 18:08:59 JST 1993
00007 
00008   Copyright (C) 1993-2007 Yukihiro Matsumoto
00009   Copyright (C) 2000  Network Applied Communication Laboratory, Inc.
00010   Copyright (C) 2000  Information-technology Promotion Agency, Japan
00011 
00012 **********************************************************************/
00013 
00014 #include "ruby/ruby.h"
00015 #include "ruby/io.h"
00016 #include "ruby/thread.h"
00017 #include "dln.h"
00018 #include "internal.h"
00019 #include "id.h"
00020 #include <ctype.h>
00021 #include <errno.h>
00022 #include "ruby_atomic.h"
00023 
00024 #define free(x) xfree(x)
00025 
00026 #if defined(DOSISH) || defined(__CYGWIN__)
00027 #include <io.h>
00028 #endif
00029 
00030 #include <sys/types.h>
00031 #if defined HAVE_NET_SOCKET_H
00032 # include <net/socket.h>
00033 #elif defined HAVE_SYS_SOCKET_H
00034 # ifndef __native_client__
00035 #  include <sys/socket.h>
00036 # endif
00037 #endif
00038 
00039 #if defined(__BOW__) || defined(__CYGWIN__) || defined(_WIN32) || defined(__EMX__) || defined(__BEOS__) || defined(__HAIKU__)
00040 # define NO_SAFE_RENAME
00041 #endif
00042 
00043 #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__sun) || defined(_nec_ews)
00044 # define USE_SETVBUF
00045 #endif
00046 
00047 #ifdef __QNXNTO__
00048 #include "unix.h"
00049 #endif
00050 
00051 #include <sys/types.h>
00052 #if defined(HAVE_SYS_IOCTL_H) && !defined(_WIN32)
00053 #include <sys/ioctl.h>
00054 #endif
00055 #if defined(__native_client__) && defined(NACL_NEWLIB)
00056 # include "nacl/ioctl.h"
00057 #endif
00058 #if defined(HAVE_FCNTL_H) || defined(_WIN32)
00059 #include <fcntl.h>
00060 #elif defined(HAVE_SYS_FCNTL_H)
00061 #include <sys/fcntl.h>
00062 #endif
00063 
00064 #if !HAVE_OFF_T && !defined(off_t)
00065 # define off_t  long
00066 #endif
00067 
00068 #include <sys/stat.h>
00069 
00070 /* EMX has sys/param.h, but.. */
00071 #if defined(HAVE_SYS_PARAM_H) && !(defined(__EMX__) || defined(__HIUX_MPP__))
00072 # include <sys/param.h>
00073 #endif
00074 
00075 #if !defined NOFILE
00076 # define NOFILE 64
00077 #endif
00078 
00079 #ifdef HAVE_UNISTD_H
00080 #include <unistd.h>
00081 #endif
00082 
00083 #ifdef HAVE_SYSCALL_H
00084 #include <syscall.h>
00085 #elif defined HAVE_SYS_SYSCALL_H
00086 #include <sys/syscall.h>
00087 #endif
00088 
00089 #if defined(__BEOS__) || defined(__HAIKU__)
00090 # ifndef NOFILE
00091 #  define NOFILE (OPEN_MAX)
00092 # endif
00093 #endif
00094 
00095 #include "ruby/util.h"
00096 
00097 #ifndef O_ACCMODE
00098 #define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR)
00099 #endif
00100 
00101 #if SIZEOF_OFF_T > SIZEOF_LONG && !defined(HAVE_LONG_LONG)
00102 # error off_t is bigger than long, but you have no long long...
00103 #endif
00104 
00105 #ifndef PIPE_BUF
00106 # ifdef _POSIX_PIPE_BUF
00107 #  define PIPE_BUF _POSIX_PIPE_BUF
00108 # else
00109 #  define PIPE_BUF 512 /* is this ok? */
00110 # endif
00111 #endif
00112 
00113 #ifndef EWOULDBLOCK
00114 # define EWOULDBLOCK EAGAIN
00115 #endif
00116 
00117 #if defined(HAVE___SYSCALL) && (defined(__APPLE__) || defined(__OpenBSD__))
00118 /* Mac OS X and OpenBSD have __syscall but don't define it in headers */
00119 off_t __syscall(quad_t number, ...);
00120 #endif
00121 
00122 #define IO_RBUF_CAPA_MIN  8192
00123 #define IO_CBUF_CAPA_MIN  (128*1024)
00124 #define IO_RBUF_CAPA_FOR(fptr) (NEED_READCONV(fptr) ? IO_CBUF_CAPA_MIN : IO_RBUF_CAPA_MIN)
00125 #define IO_WBUF_CAPA_MIN  8192
00126 
00127 /* define system APIs */
00128 #ifdef _WIN32
00129 #undef open
00130 #define open    rb_w32_uopen
00131 #endif
00132 
00133 VALUE rb_cIO;
00134 VALUE rb_eEOFError;
00135 VALUE rb_eIOError;
00136 VALUE rb_mWaitReadable;
00137 VALUE rb_mWaitWritable;
00138 extern VALUE rb_eEAGAIN;
00139 extern VALUE rb_eEWOULDBLOCK;
00140 extern VALUE rb_eEINPROGRESS;
00141 
00142 static VALUE rb_eEAGAINWaitReadable;
00143 static VALUE rb_eEAGAINWaitWritable;
00144 static VALUE rb_eEWOULDBLOCKWaitReadable;
00145 static VALUE rb_eEWOULDBLOCKWaitWritable;
00146 static VALUE rb_eEINPROGRESSWaitWritable;
00147 static VALUE rb_eEINPROGRESSWaitReadable;
00148 
00149 VALUE rb_stdin, rb_stdout, rb_stderr;
00150 VALUE rb_deferr;                /* rescue VIM plugin */
00151 static VALUE orig_stdout, orig_stderr;
00152 
00153 VALUE rb_output_fs;
00154 VALUE rb_rs;
00155 VALUE rb_output_rs;
00156 VALUE rb_default_rs;
00157 
00158 static VALUE argf;
00159 
00160 static ID id_write, id_read, id_getc, id_flush, id_readpartial, id_set_encoding;
00161 static VALUE sym_mode, sym_perm, sym_extenc, sym_intenc, sym_encoding, sym_open_args;
00162 static VALUE sym_textmode, sym_binmode, sym_autoclose, sym_exception;
00163 static VALUE sym_SET, sym_CUR, sym_END;
00164 #ifdef SEEK_DATA
00165 static VALUE sym_DATA;
00166 #endif
00167 #ifdef SEEK_HOLE
00168 static VALUE sym_HOLE;
00169 #endif
00170 
00171 struct argf {
00172     VALUE filename, current_file;
00173     long last_lineno;           /* $. */
00174     long lineno;
00175     VALUE argv;
00176     char *inplace;
00177     struct rb_io_enc_t encs;
00178     int8_t init_p, next_p, binmode;
00179 };
00180 
00181 static rb_atomic_t max_file_descriptor = NOFILE;
00182 void
00183 rb_update_max_fd(int fd)
00184 {
00185     struct stat buf;
00186     rb_atomic_t afd = (rb_atomic_t)fd;
00187 
00188     if (fstat(fd, &buf) != 0 && errno == EBADF) {
00189         rb_bug("rb_update_max_fd: invalid fd (%d) given.", fd);
00190     }
00191 
00192     while (max_file_descriptor < afd) {
00193         ATOMIC_CAS(max_file_descriptor, max_file_descriptor, afd);
00194     }
00195 }
00196 
00197 void
00198 rb_maygvl_fd_fix_cloexec(int fd)
00199 {
00200   /* MinGW don't have F_GETFD and FD_CLOEXEC.  [ruby-core:40281] */
00201 #if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
00202     int flags, flags2, ret;
00203     flags = fcntl(fd, F_GETFD); /* should not fail except EBADF. */
00204     if (flags == -1) {
00205         rb_bug("rb_maygvl_fd_fix_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(errno));
00206     }
00207     if (fd <= 2)
00208         flags2 = flags & ~FD_CLOEXEC; /* Clear CLOEXEC for standard file descriptors: 0, 1, 2. */
00209     else
00210         flags2 = flags | FD_CLOEXEC; /* Set CLOEXEC for non-standard file descriptors: 3, 4, 5, ... */
00211     if (flags != flags2) {
00212         ret = fcntl(fd, F_SETFD, flags2);
00213         if (ret == -1) {
00214             rb_bug("rb_maygvl_fd_fix_cloexec: fcntl(%d, F_SETFD, %d) failed: %s", fd, flags2, strerror(errno));
00215         }
00216     }
00217 #endif
00218 }
00219 
00220 void
00221 rb_fd_fix_cloexec(int fd)
00222 {
00223     rb_maygvl_fd_fix_cloexec(fd);
00224     rb_update_max_fd(fd);
00225 }
00226 
00227 int
00228 rb_cloexec_open(const char *pathname, int flags, mode_t mode)
00229 {
00230     int ret;
00231 #ifdef O_CLOEXEC
00232     /* O_CLOEXEC is available since Linux 2.6.23.  Linux 2.6.18 silently ignore it. */
00233     flags |= O_CLOEXEC;
00234 #elif defined O_NOINHERIT
00235     flags |= O_NOINHERIT;
00236 #endif
00237     ret = open(pathname, flags, mode);
00238     if (ret == -1) return -1;
00239     rb_maygvl_fd_fix_cloexec(ret);
00240     return ret;
00241 }
00242 
00243 int
00244 rb_cloexec_dup(int oldfd)
00245 {
00246     /* Don't allocate standard file descriptors: 0, 1, 2 */
00247     return rb_cloexec_fcntl_dupfd(oldfd, 3);
00248 }
00249 
00250 int
00251 rb_cloexec_dup2(int oldfd, int newfd)
00252 {
00253     int ret;
00254 
00255     /* When oldfd == newfd, dup2 succeeds but dup3 fails with EINVAL.
00256      * rb_cloexec_dup2 succeeds as dup2.  */
00257     if (oldfd == newfd) {
00258         ret = newfd;
00259     }
00260     else {
00261 #if defined(HAVE_DUP3) && defined(O_CLOEXEC)
00262         static int try_dup3 = 1;
00263         if (2 < newfd && try_dup3) {
00264             ret = dup3(oldfd, newfd, O_CLOEXEC);
00265             if (ret != -1)
00266                 return ret;
00267             /* dup3 is available since Linux 2.6.27, glibc 2.9. */
00268             if (errno == ENOSYS) {
00269                 try_dup3 = 0;
00270                 ret = dup2(oldfd, newfd);
00271             }
00272         }
00273         else {
00274             ret = dup2(oldfd, newfd);
00275         }
00276 #else
00277         ret = dup2(oldfd, newfd);
00278 #endif
00279         if (ret == -1) return -1;
00280     }
00281     rb_maygvl_fd_fix_cloexec(ret);
00282     return ret;
00283 }
00284 
00285 int
00286 rb_cloexec_pipe(int fildes[2])
00287 {
00288     int ret;
00289 
00290 #if defined(HAVE_PIPE2)
00291     static int try_pipe2 = 1;
00292     if (try_pipe2) {
00293         ret = pipe2(fildes, O_CLOEXEC);
00294         if (ret != -1)
00295             return ret;
00296         /* pipe2 is available since Linux 2.6.27, glibc 2.9. */
00297         if (errno == ENOSYS) {
00298             try_pipe2 = 0;
00299             ret = pipe(fildes);
00300         }
00301     }
00302     else {
00303         ret = pipe(fildes);
00304     }
00305 #else
00306     ret = pipe(fildes);
00307 #endif
00308     if (ret == -1) return -1;
00309 #ifdef __CYGWIN__
00310     if (ret == 0 && fildes[1] == -1) {
00311         close(fildes[0]);
00312         fildes[0] = -1;
00313         errno = ENFILE;
00314         return -1;
00315     }
00316 #endif
00317     rb_maygvl_fd_fix_cloexec(fildes[0]);
00318     rb_maygvl_fd_fix_cloexec(fildes[1]);
00319     return ret;
00320 }
00321 
00322 int
00323 rb_cloexec_fcntl_dupfd(int fd, int minfd)
00324 {
00325     int ret;
00326 
00327 #if defined(HAVE_FCNTL) && defined(F_DUPFD_CLOEXEC) && defined(F_DUPFD)
00328     static int try_dupfd_cloexec = 1;
00329     if (try_dupfd_cloexec) {
00330         ret = fcntl(fd, F_DUPFD_CLOEXEC, minfd);
00331         if (ret != -1) {
00332             if (ret <= 2)
00333                 rb_maygvl_fd_fix_cloexec(ret);
00334             return ret;
00335         }
00336         /* F_DUPFD_CLOEXEC is available since Linux 2.6.24.  Linux 2.6.18 fails with EINVAL */
00337         if (errno == EINVAL) {
00338             ret = fcntl(fd, F_DUPFD, minfd);
00339             if (ret != -1) {
00340                 try_dupfd_cloexec = 0;
00341             }
00342         }
00343     }
00344     else {
00345         ret = fcntl(fd, F_DUPFD, minfd);
00346     }
00347 #elif defined(HAVE_FCNTL) && defined(F_DUPFD)
00348     ret = fcntl(fd, F_DUPFD, minfd);
00349 #elif defined(HAVE_DUP)
00350     ret = dup(fd);
00351     if (ret != -1 && ret < minfd) {
00352         const int prev_fd = ret;
00353         ret = rb_cloexec_fcntl_dupfd(fd, minfd);
00354         close(prev_fd);
00355     }
00356     return ret;
00357 #else
00358 # error "dup() or fcntl(F_DUPFD) must be supported."
00359 #endif
00360     if (ret == -1) return -1;
00361     rb_maygvl_fd_fix_cloexec(ret);
00362     return ret;
00363 }
00364 
00365 #define argf_of(obj) (*(struct argf *)DATA_PTR(obj))
00366 #define ARGF argf_of(argf)
00367 
00368 #ifdef _STDIO_USES_IOSTREAM  /* GNU libc */
00369 #  ifdef _IO_fpos_t
00370 #    define STDIO_READ_DATA_PENDING(fp) ((fp)->_IO_read_ptr != (fp)->_IO_read_end)
00371 #  else
00372 #    define STDIO_READ_DATA_PENDING(fp) ((fp)->_gptr < (fp)->_egptr)
00373 #  endif
00374 #elif defined(FILE_COUNT)
00375 #  define STDIO_READ_DATA_PENDING(fp) ((fp)->FILE_COUNT > 0)
00376 #elif defined(FILE_READEND)
00377 #  define STDIO_READ_DATA_PENDING(fp) ((fp)->FILE_READPTR < (fp)->FILE_READEND)
00378 #elif defined(__BEOS__) || defined(__HAIKU__)
00379 #  define STDIO_READ_DATA_PENDING(fp) ((fp)->_state._eof == 0)
00380 #else
00381 #  define STDIO_READ_DATA_PENDING(fp) (!feof(fp))
00382 #endif
00383 
00384 #define GetWriteIO(io) rb_io_get_write_io(io)
00385 
00386 #define READ_DATA_PENDING(fptr) ((fptr)->rbuf.len)
00387 #define READ_DATA_PENDING_COUNT(fptr) ((fptr)->rbuf.len)
00388 #define READ_DATA_PENDING_PTR(fptr) ((fptr)->rbuf.ptr+(fptr)->rbuf.off)
00389 #define READ_DATA_BUFFERED(fptr) READ_DATA_PENDING(fptr)
00390 
00391 #define READ_CHAR_PENDING(fptr) ((fptr)->cbuf.len)
00392 #define READ_CHAR_PENDING_COUNT(fptr) ((fptr)->cbuf.len)
00393 #define READ_CHAR_PENDING_PTR(fptr) ((fptr)->cbuf.ptr+(fptr)->cbuf.off)
00394 
00395 #if defined(_WIN32)
00396 #define WAIT_FD_IN_WIN32(fptr) \
00397     (rb_w32_io_cancelable_p((fptr)->fd) ? 0 : rb_thread_wait_fd((fptr)->fd))
00398 #else
00399 #define WAIT_FD_IN_WIN32(fptr)
00400 #endif
00401 
00402 #define READ_CHECK(fptr) do {\
00403     if (!READ_DATA_PENDING(fptr)) {\
00404         WAIT_FD_IN_WIN32(fptr);\
00405         rb_io_check_closed(fptr);\
00406      }\
00407 } while(0)
00408 
00409 #ifndef S_ISSOCK
00410 #  ifdef _S_ISSOCK
00411 #    define S_ISSOCK(m) _S_ISSOCK(m)
00412 #  else
00413 #    ifdef _S_IFSOCK
00414 #      define S_ISSOCK(m) (((m) & S_IFMT) == _S_IFSOCK)
00415 #    else
00416 #      ifdef S_IFSOCK
00417 #        define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
00418 #      endif
00419 #    endif
00420 #  endif
00421 #endif
00422 
00423 static int io_fflush(rb_io_t *);
00424 static rb_io_t *flush_before_seek(rb_io_t *fptr);
00425 
00426 #define NEED_NEWLINE_DECORATOR_ON_READ(fptr) ((fptr)->mode & FMODE_TEXTMODE)
00427 #define NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) ((fptr)->mode & FMODE_TEXTMODE)
00428 #if defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32)
00429 /* Windows */
00430 # define DEFAULT_TEXTMODE FMODE_TEXTMODE
00431 # define TEXTMODE_NEWLINE_DECORATOR_ON_WRITE ECONV_CRLF_NEWLINE_DECORATOR
00432 /*
00433  * CRLF newline is set as default newline decorator.
00434  * If only CRLF newline conversion is needed, we use binary IO process
00435  * with OS's text mode for IO performance improvement.
00436  * If encoding conversion is needed or a user sets text mode, we use encoding
00437  * conversion IO process and universal newline decorator by default.
00438  */
00439 #define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || (fptr)->encs.ecflags & ~ECONV_CRLF_NEWLINE_DECORATOR)
00440 #define NEED_WRITECONV(fptr) (((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || ((fptr)->encs.ecflags & ((ECONV_DECORATOR_MASK & ~ECONV_CRLF_NEWLINE_DECORATOR)|ECONV_STATEFUL_DECORATOR_MASK)))
00441 #define SET_BINARY_MODE(fptr) setmode((fptr)->fd, O_BINARY)
00442 
00443 #define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) do {\
00444     if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {\
00445         if (((fptr)->mode & FMODE_READABLE) &&\
00446             !((fptr)->encs.ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {\
00447             setmode((fptr)->fd, O_BINARY);\
00448         }\
00449         else {\
00450             setmode((fptr)->fd, O_TEXT);\
00451         }\
00452     }\
00453 } while(0)
00454 
00455 #define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) do {\
00456     if ((enc2) && ((ecflags) & ECONV_DEFAULT_NEWLINE_DECORATOR)) {\
00457         (ecflags) |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;\
00458     }\
00459 } while(0)
00460 
00461 /*
00462  * IO unread with taking care of removed '\r' in text mode.
00463  */
00464 static void
00465 io_unread(rb_io_t *fptr)
00466 {
00467     off_t r, pos;
00468     ssize_t read_size;
00469     long i;
00470     long newlines = 0;
00471     long extra_max;
00472     char *p;
00473     char *buf;
00474 
00475     rb_io_check_closed(fptr);
00476     if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX) {
00477         return;
00478     }
00479 
00480     errno = 0;
00481     if (!rb_w32_fd_is_text(fptr->fd)) {
00482         r = lseek(fptr->fd, -fptr->rbuf.len, SEEK_CUR);
00483         if (r < 0 && errno) {
00484             if (errno == ESPIPE)
00485                 fptr->mode |= FMODE_DUPLEX;
00486             return;
00487         }
00488 
00489         fptr->rbuf.off = 0;
00490         fptr->rbuf.len = 0;
00491         return;
00492     }
00493 
00494     pos = lseek(fptr->fd, 0, SEEK_CUR);
00495     if (pos < 0 && errno) {
00496         if (errno == ESPIPE)
00497             fptr->mode |= FMODE_DUPLEX;
00498         return;
00499     }
00500 
00501     /* add extra offset for removed '\r' in rbuf */
00502     extra_max = (long)(pos - fptr->rbuf.len);
00503     p = fptr->rbuf.ptr + fptr->rbuf.off;
00504 
00505     /* if the end of rbuf is '\r', rbuf doesn't have '\r' within rbuf.len */
00506     if (*(fptr->rbuf.ptr + fptr->rbuf.capa - 1) == '\r') {
00507         newlines++;
00508     }
00509 
00510     for (i = 0; i < fptr->rbuf.len; i++) {
00511         if (*p == '\n') newlines++;
00512         if (extra_max == newlines) break;
00513         p++;
00514     }
00515 
00516     buf = ALLOC_N(char, fptr->rbuf.len + newlines);
00517     while (newlines >= 0) {
00518         r = lseek(fptr->fd, pos - fptr->rbuf.len - newlines, SEEK_SET);
00519         if (newlines == 0) break;
00520         if (r < 0) {
00521             newlines--;
00522             continue;
00523         }
00524         read_size = _read(fptr->fd, buf, fptr->rbuf.len + newlines);
00525         if (read_size < 0) {
00526             free(buf);
00527             rb_sys_fail_path(fptr->pathv);
00528         }
00529         if (read_size == fptr->rbuf.len) {
00530             lseek(fptr->fd, r, SEEK_SET);
00531             break;
00532         }
00533         else {
00534             newlines--;
00535         }
00536     }
00537     free(buf);
00538     fptr->rbuf.off = 0;
00539     fptr->rbuf.len = 0;
00540     return;
00541 }
00542 
00543 /*
00544  * We use io_seek to back cursor position when changing mode from text to binary,
00545  * but stdin and pipe cannot seek back. Stdin and pipe read should use encoding
00546  * conversion for working properly with mode change.
00547  *
00548  * Return previous translation mode.
00549  */
00550 static inline int
00551 set_binary_mode_with_seek_cur(rb_io_t *fptr)
00552 {
00553     if (!rb_w32_fd_is_text(fptr->fd)) return O_BINARY;
00554 
00555     if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX) {
00556         return setmode(fptr->fd, O_BINARY);
00557     }
00558     flush_before_seek(fptr);
00559     return setmode(fptr->fd, O_BINARY);
00560 }
00561 #define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) set_binary_mode_with_seek_cur(fptr)
00562 
00563 #else
00564 /* Unix */
00565 # define DEFAULT_TEXTMODE 0
00566 #define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || NEED_NEWLINE_DECORATOR_ON_READ(fptr))
00567 #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)))
00568 #define SET_BINARY_MODE(fptr) (void)(fptr)
00569 #define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) (void)(fptr)
00570 #define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) ((void)(enc2), (void)(ecflags))
00571 #define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) (void)(fptr)
00572 #endif
00573 
00574 #if !defined HAVE_SHUTDOWN && !defined shutdown
00575 #define shutdown(a,b)   0
00576 #endif
00577 
00578 #if defined(_WIN32)
00579 #define is_socket(fd, path)     rb_w32_is_socket(fd)
00580 #elif !defined(S_ISSOCK)
00581 #define is_socket(fd, path)     0
00582 #else
00583 static int
00584 is_socket(int fd, VALUE path)
00585 {
00586     struct stat sbuf;
00587     if (fstat(fd, &sbuf) < 0)
00588         rb_sys_fail_path(path);
00589     return S_ISSOCK(sbuf.st_mode);
00590 }
00591 #endif
00592 
00593 static const char closed_stream[] = "closed stream";
00594 
00595 void
00596 rb_eof_error(void)
00597 {
00598     rb_raise(rb_eEOFError, "end of file reached");
00599 }
00600 
00601 VALUE
00602 rb_io_taint_check(VALUE io)
00603 {
00604     rb_check_frozen(io);
00605     return io;
00606 }
00607 
00608 void
00609 rb_io_check_initialized(rb_io_t *fptr)
00610 {
00611     if (!fptr) {
00612         rb_raise(rb_eIOError, "uninitialized stream");
00613     }
00614 }
00615 
00616 void
00617 rb_io_check_closed(rb_io_t *fptr)
00618 {
00619     rb_io_check_initialized(fptr);
00620     if (fptr->fd < 0) {
00621         rb_raise(rb_eIOError, closed_stream);
00622     }
00623 }
00624 
00625 
00626 VALUE
00627 rb_io_get_io(VALUE io)
00628 {
00629     return rb_convert_type(io, T_FILE, "IO", "to_io");
00630 }
00631 
00632 VALUE
00633 rb_io_check_io(VALUE io)
00634 {
00635     return rb_check_convert_type(io, T_FILE, "IO", "to_io");
00636 }
00637 
00638 VALUE
00639 rb_io_get_write_io(VALUE io)
00640 {
00641     VALUE write_io;
00642     rb_io_check_initialized(RFILE(io)->fptr);
00643     write_io = RFILE(io)->fptr->tied_io_for_writing;
00644     if (write_io) {
00645         return write_io;
00646     }
00647     return io;
00648 }
00649 
00650 VALUE
00651 rb_io_set_write_io(VALUE io, VALUE w)
00652 {
00653     VALUE write_io;
00654     rb_io_check_initialized(RFILE(io)->fptr);
00655     if (!RTEST(w)) {
00656         w = 0;
00657     }
00658     else {
00659         GetWriteIO(w);
00660     }
00661     write_io = RFILE(io)->fptr->tied_io_for_writing;
00662     RFILE(io)->fptr->tied_io_for_writing = w;
00663     return write_io ? write_io : Qnil;
00664 }
00665 
00666 /*
00667  *  call-seq:
00668  *     IO.try_convert(obj)  ->  io or nil
00669  *
00670  *  Try to convert <i>obj</i> into an IO, using to_io method.
00671  *  Returns converted IO or nil if <i>obj</i> cannot be converted
00672  *  for any reason.
00673  *
00674  *     IO.try_convert(STDOUT)     #=> STDOUT
00675  *     IO.try_convert("STDOUT")   #=> nil
00676  *
00677  *     require 'zlib'
00678  *     f = open("/tmp/zz.gz")       #=> #<File:/tmp/zz.gz>
00679  *     z = Zlib::GzipReader.open(f) #=> #<Zlib::GzipReader:0x81d8744>
00680  *     IO.try_convert(z)            #=> #<File:/tmp/zz.gz>
00681  *
00682  */
00683 static VALUE
00684 rb_io_s_try_convert(VALUE dummy, VALUE io)
00685 {
00686     return rb_io_check_io(io);
00687 }
00688 
00689 #if !(defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32))
00690 static void
00691 io_unread(rb_io_t *fptr)
00692 {
00693     off_t r;
00694     rb_io_check_closed(fptr);
00695     if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX)
00696         return;
00697     /* xxx: target position may be negative if buffer is filled by ungetc */
00698     errno = 0;
00699     r = lseek(fptr->fd, -fptr->rbuf.len, SEEK_CUR);
00700     if (r < 0 && errno) {
00701         if (errno == ESPIPE)
00702             fptr->mode |= FMODE_DUPLEX;
00703         return;
00704     }
00705     fptr->rbuf.off = 0;
00706     fptr->rbuf.len = 0;
00707     return;
00708 }
00709 #endif
00710 
00711 static rb_encoding *io_input_encoding(rb_io_t *fptr);
00712 
00713 static void
00714 io_ungetbyte(VALUE str, rb_io_t *fptr)
00715 {
00716     long len = RSTRING_LEN(str);
00717 
00718     if (fptr->rbuf.ptr == NULL) {
00719         const int min_capa = IO_RBUF_CAPA_FOR(fptr);
00720         fptr->rbuf.off = 0;
00721         fptr->rbuf.len = 0;
00722 #if SIZEOF_LONG > SIZEOF_INT
00723         if (len > INT_MAX)
00724             rb_raise(rb_eIOError, "ungetbyte failed");
00725 #endif
00726         if (len > min_capa)
00727             fptr->rbuf.capa = (int)len;
00728         else
00729             fptr->rbuf.capa = min_capa;
00730         fptr->rbuf.ptr = ALLOC_N(char, fptr->rbuf.capa);
00731     }
00732     if (fptr->rbuf.capa < len + fptr->rbuf.len) {
00733         rb_raise(rb_eIOError, "ungetbyte failed");
00734     }
00735     if (fptr->rbuf.off < len) {
00736         MEMMOVE(fptr->rbuf.ptr+fptr->rbuf.capa-fptr->rbuf.len,
00737                 fptr->rbuf.ptr+fptr->rbuf.off,
00738                 char, fptr->rbuf.len);
00739         fptr->rbuf.off = fptr->rbuf.capa-fptr->rbuf.len;
00740     }
00741     fptr->rbuf.off-=(int)len;
00742     fptr->rbuf.len+=(int)len;
00743     MEMMOVE(fptr->rbuf.ptr+fptr->rbuf.off, RSTRING_PTR(str), char, len);
00744 }
00745 
00746 static rb_io_t *
00747 flush_before_seek(rb_io_t *fptr)
00748 {
00749     if (io_fflush(fptr) < 0)
00750         rb_sys_fail(0);
00751     io_unread(fptr);
00752     errno = 0;
00753     return fptr;
00754 }
00755 
00756 #define io_seek(fptr, ofs, whence) (errno = 0, lseek(flush_before_seek(fptr)->fd, (ofs), (whence)))
00757 #define io_tell(fptr) lseek(flush_before_seek(fptr)->fd, 0, SEEK_CUR)
00758 
00759 #ifndef SEEK_CUR
00760 # define SEEK_SET 0
00761 # define SEEK_CUR 1
00762 # define SEEK_END 2
00763 #endif
00764 
00765 void
00766 rb_io_check_char_readable(rb_io_t *fptr)
00767 {
00768     rb_io_check_closed(fptr);
00769     if (!(fptr->mode & FMODE_READABLE)) {
00770         rb_raise(rb_eIOError, "not opened for reading");
00771     }
00772     if (fptr->wbuf.len) {
00773         if (io_fflush(fptr) < 0)
00774             rb_sys_fail(0);
00775     }
00776     if (fptr->tied_io_for_writing) {
00777         rb_io_t *wfptr;
00778         GetOpenFile(fptr->tied_io_for_writing, wfptr);
00779         if (io_fflush(wfptr) < 0)
00780             rb_sys_fail(0);
00781     }
00782 }
00783 
00784 void
00785 rb_io_check_byte_readable(rb_io_t *fptr)
00786 {
00787     rb_io_check_char_readable(fptr);
00788     if (READ_CHAR_PENDING(fptr)) {
00789         rb_raise(rb_eIOError, "byte oriented read for character buffered IO");
00790     }
00791 }
00792 
00793 void
00794 rb_io_check_readable(rb_io_t *fptr)
00795 {
00796     rb_io_check_byte_readable(fptr);
00797 }
00798 
00799 static rb_encoding*
00800 io_read_encoding(rb_io_t *fptr)
00801 {
00802     if (fptr->encs.enc) {
00803         return fptr->encs.enc;
00804     }
00805     return rb_default_external_encoding();
00806 }
00807 
00808 static rb_encoding*
00809 io_input_encoding(rb_io_t *fptr)
00810 {
00811     if (fptr->encs.enc2) {
00812         return fptr->encs.enc2;
00813     }
00814     return io_read_encoding(fptr);
00815 }
00816 
00817 void
00818 rb_io_check_writable(rb_io_t *fptr)
00819 {
00820     rb_io_check_closed(fptr);
00821     if (!(fptr->mode & FMODE_WRITABLE)) {
00822         rb_raise(rb_eIOError, "not opened for writing");
00823     }
00824     if (fptr->rbuf.len) {
00825         io_unread(fptr);
00826     }
00827 }
00828 
00829 int
00830 rb_io_read_pending(rb_io_t *fptr)
00831 {
00832     /* This function is used for bytes and chars.  Confusing. */
00833     if (READ_CHAR_PENDING(fptr))
00834         return 1; /* should raise? */
00835     return READ_DATA_PENDING(fptr);
00836 }
00837 
00838 void
00839 rb_read_check(FILE *fp)
00840 {
00841     if (!STDIO_READ_DATA_PENDING(fp)) {
00842         rb_thread_wait_fd(fileno(fp));
00843     }
00844 }
00845 
00846 void
00847 rb_io_read_check(rb_io_t *fptr)
00848 {
00849     if (!READ_DATA_PENDING(fptr)) {
00850         rb_thread_wait_fd(fptr->fd);
00851     }
00852     return;
00853 }
00854 
00855 static int
00856 ruby_dup(int orig)
00857 {
00858     int fd;
00859 
00860     fd = rb_cloexec_dup(orig);
00861     if (fd < 0) {
00862         if (errno == EMFILE || errno == ENFILE || errno == ENOMEM) {
00863             rb_gc();
00864             fd = rb_cloexec_dup(orig);
00865         }
00866         if (fd < 0) {
00867             rb_sys_fail(0);
00868         }
00869     }
00870     rb_update_max_fd(fd);
00871     return fd;
00872 }
00873 
00874 static VALUE
00875 io_alloc(VALUE klass)
00876 {
00877     NEWOBJ_OF(io, struct RFile, klass, T_FILE);
00878 
00879     io->fptr = 0;
00880 
00881     return (VALUE)io;
00882 }
00883 
00884 #ifndef S_ISREG
00885 #   define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
00886 #endif
00887 
00888 static int
00889 wsplit_p(rb_io_t *fptr)
00890 {
00891 #if defined(HAVE_FCNTL) && defined(F_GETFL) && defined(O_NONBLOCK)
00892     int r;
00893 #endif
00894 
00895     if (!(fptr->mode & FMODE_WSPLIT_INITIALIZED)) {
00896         struct stat buf;
00897         if (fstat(fptr->fd, &buf) == 0 &&
00898             !S_ISREG(buf.st_mode)
00899 #if defined(HAVE_FCNTL) && defined(F_GETFL) && defined(O_NONBLOCK)
00900             && (r = fcntl(fptr->fd, F_GETFL)) != -1 &&
00901             !(r & O_NONBLOCK)
00902 #endif
00903             ) {
00904             fptr->mode |= FMODE_WSPLIT;
00905         }
00906         fptr->mode |= FMODE_WSPLIT_INITIALIZED;
00907     }
00908     return fptr->mode & FMODE_WSPLIT;
00909 }
00910 
00911 struct io_internal_read_struct {
00912     int fd;
00913     void *buf;
00914     size_t capa;
00915 };
00916 
00917 struct io_internal_write_struct {
00918     int fd;
00919     const void *buf;
00920     size_t capa;
00921 };
00922 
00923 static VALUE
00924 internal_read_func(void *ptr)
00925 {
00926     struct io_internal_read_struct *iis = ptr;
00927     return read(iis->fd, iis->buf, iis->capa);
00928 }
00929 
00930 static VALUE
00931 internal_write_func(void *ptr)
00932 {
00933     struct io_internal_write_struct *iis = ptr;
00934     return write(iis->fd, iis->buf, iis->capa);
00935 }
00936 
00937 static void*
00938 internal_write_func2(void *ptr)
00939 {
00940     struct io_internal_write_struct *iis = ptr;
00941     return (void*)(intptr_t)write(iis->fd, iis->buf, iis->capa);
00942 }
00943 
00944 static ssize_t
00945 rb_read_internal(int fd, void *buf, size_t count)
00946 {
00947     struct io_internal_read_struct iis;
00948     iis.fd = fd;
00949     iis.buf = buf;
00950     iis.capa = count;
00951 
00952     return (ssize_t)rb_thread_io_blocking_region(internal_read_func, &iis, fd);
00953 }
00954 
00955 static ssize_t
00956 rb_write_internal(int fd, const void *buf, size_t count)
00957 {
00958     struct io_internal_write_struct iis;
00959     iis.fd = fd;
00960     iis.buf = buf;
00961     iis.capa = count;
00962 
00963     return (ssize_t)rb_thread_io_blocking_region(internal_write_func, &iis, fd);
00964 }
00965 
00966 static ssize_t
00967 rb_write_internal2(int fd, const void *buf, size_t count)
00968 {
00969     struct io_internal_write_struct iis;
00970     iis.fd = fd;
00971     iis.buf = buf;
00972     iis.capa = count;
00973 
00974     return (ssize_t)rb_thread_call_without_gvl2(internal_write_func2, &iis,
00975                                                 RUBY_UBF_IO, NULL);
00976 }
00977 
00978 static long
00979 io_writable_length(rb_io_t *fptr, long l)
00980 {
00981     if (PIPE_BUF < l &&
00982         !rb_thread_alone() &&
00983         wsplit_p(fptr)) {
00984         l = PIPE_BUF;
00985     }
00986     return l;
00987 }
00988 
00989 static VALUE
00990 io_flush_buffer_sync(void *arg)
00991 {
00992     rb_io_t *fptr = arg;
00993     long l = io_writable_length(fptr, fptr->wbuf.len);
00994     ssize_t r = write(fptr->fd, fptr->wbuf.ptr+fptr->wbuf.off, (size_t)l);
00995 
00996     if (fptr->wbuf.len <= r) {
00997         fptr->wbuf.off = 0;
00998         fptr->wbuf.len = 0;
00999         return 0;
01000     }
01001     if (0 <= r) {
01002         fptr->wbuf.off += (int)r;
01003         fptr->wbuf.len -= (int)r;
01004         errno = EAGAIN;
01005     }
01006     return (VALUE)-1;
01007 }
01008 
01009 static void*
01010 io_flush_buffer_sync2(void *arg)
01011 {
01012     VALUE result = io_flush_buffer_sync(arg);
01013 
01014     /*
01015      * rb_thread_call_without_gvl2 uses 0 as interrupted.
01016      * So, we need to avoid to use 0.
01017      */
01018     return !result ? (void*)1 : (void*)result;
01019 }
01020 
01021 static VALUE
01022 io_flush_buffer_async(VALUE arg)
01023 {
01024     rb_io_t *fptr = (rb_io_t *)arg;
01025     return rb_thread_io_blocking_region(io_flush_buffer_sync, fptr, fptr->fd);
01026 }
01027 
01028 static VALUE
01029 io_flush_buffer_async2(VALUE arg)
01030 {
01031     rb_io_t *fptr = (rb_io_t *)arg;
01032     VALUE ret;
01033 
01034     ret = (VALUE)rb_thread_call_without_gvl2(io_flush_buffer_sync2, fptr,
01035                                              RUBY_UBF_IO, NULL);
01036 
01037     if (!ret) {
01038         /* pending async interrupt is there. */
01039         errno = EAGAIN;
01040         return -1;
01041     } else if (ret == 1) {
01042         return 0;
01043     } else
01044         return ret;
01045 }
01046 
01047 static inline int
01048 io_flush_buffer(rb_io_t *fptr)
01049 {
01050     if (fptr->write_lock) {
01051         if (rb_mutex_owned_p(fptr->write_lock))
01052             return (int)io_flush_buffer_async2((VALUE)fptr);
01053         else
01054             return (int)rb_mutex_synchronize(fptr->write_lock, io_flush_buffer_async2, (VALUE)fptr);
01055     }
01056     else {
01057         return (int)io_flush_buffer_async((VALUE)fptr);
01058     }
01059 }
01060 
01061 static int
01062 io_fflush(rb_io_t *fptr)
01063 {
01064     rb_io_check_closed(fptr);
01065     if (fptr->wbuf.len == 0)
01066         return 0;
01067     rb_io_check_closed(fptr);
01068     while (fptr->wbuf.len > 0 && io_flush_buffer(fptr) != 0) {
01069         if (!rb_io_wait_writable(fptr->fd))
01070             return -1;
01071         rb_io_check_closed(fptr);
01072     }
01073     return 0;
01074 }
01075 
01076 int
01077 rb_io_wait_readable(int f)
01078 {
01079     if (f < 0) {
01080         rb_raise(rb_eIOError, closed_stream);
01081     }
01082     switch (errno) {
01083       case EINTR:
01084 #if defined(ERESTART)
01085       case ERESTART:
01086 #endif
01087         rb_thread_check_ints();
01088         return TRUE;
01089 
01090       case EAGAIN:
01091 #if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
01092       case EWOULDBLOCK:
01093 #endif
01094         rb_thread_wait_fd(f);
01095         return TRUE;
01096 
01097       default:
01098         return FALSE;
01099     }
01100 }
01101 
01102 int
01103 rb_io_wait_writable(int f)
01104 {
01105     if (f < 0) {
01106         rb_raise(rb_eIOError, closed_stream);
01107     }
01108     switch (errno) {
01109       case EINTR:
01110 #if defined(ERESTART)
01111       case ERESTART:
01112 #endif
01113         /*
01114          * In old Linux, several special files under /proc and /sys don't handle
01115          * select properly. Thus we need avoid to call if don't use O_NONBLOCK.
01116          * Otherwise, we face nasty hang up. Sigh.
01117          * e.g. http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=31b07093c44a7a442394d44423e21d783f5523b8
01118          * http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=31b07093c44a7a442394d44423e21d783f5523b8
01119          * In EINTR case, we only need to call RUBY_VM_CHECK_INTS_BLOCKING().
01120          * Then rb_thread_check_ints() is enough.
01121          */
01122         rb_thread_check_ints();
01123         return TRUE;
01124 
01125       case EAGAIN:
01126 #if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
01127       case EWOULDBLOCK:
01128 #endif
01129         rb_thread_fd_writable(f);
01130         return TRUE;
01131 
01132       default:
01133         return FALSE;
01134     }
01135 }
01136 
01137 static void
01138 make_writeconv(rb_io_t *fptr)
01139 {
01140     if (!fptr->writeconv_initialized) {
01141         const char *senc, *denc;
01142         rb_encoding *enc;
01143         int ecflags;
01144         VALUE ecopts;
01145 
01146         fptr->writeconv_initialized = 1;
01147 
01148         ecflags = fptr->encs.ecflags & ~ECONV_NEWLINE_DECORATOR_READ_MASK;
01149         ecopts = fptr->encs.ecopts;
01150 
01151         if (!fptr->encs.enc || (fptr->encs.enc == rb_ascii8bit_encoding() && !fptr->encs.enc2)) {
01152             /* no encoding conversion */
01153             fptr->writeconv_pre_ecflags = 0;
01154             fptr->writeconv_pre_ecopts = Qnil;
01155             fptr->writeconv = rb_econv_open_opts("", "", ecflags, ecopts);
01156             if (!fptr->writeconv)
01157                 rb_exc_raise(rb_econv_open_exc("", "", ecflags));
01158             fptr->writeconv_asciicompat = Qnil;
01159         }
01160         else {
01161             enc = fptr->encs.enc2 ? fptr->encs.enc2 : fptr->encs.enc;
01162             senc = rb_econv_asciicompat_encoding(rb_enc_name(enc));
01163             if (!senc && !(fptr->encs.ecflags & ECONV_STATEFUL_DECORATOR_MASK)) {
01164                 /* single conversion */
01165                 fptr->writeconv_pre_ecflags = ecflags;
01166                 fptr->writeconv_pre_ecopts = ecopts;
01167                 fptr->writeconv = NULL;
01168                 fptr->writeconv_asciicompat = Qnil;
01169             }
01170             else {
01171                 /* double conversion */
01172                 fptr->writeconv_pre_ecflags = ecflags & ~ECONV_STATEFUL_DECORATOR_MASK;
01173                 fptr->writeconv_pre_ecopts = ecopts;
01174                 if (senc) {
01175                     denc = rb_enc_name(enc);
01176                     fptr->writeconv_asciicompat = rb_str_new2(senc);
01177                 }
01178                 else {
01179                     senc = denc = "";
01180                     fptr->writeconv_asciicompat = rb_str_new2(rb_enc_name(enc));
01181                 }
01182                 ecflags = fptr->encs.ecflags & (ECONV_ERROR_HANDLER_MASK|ECONV_STATEFUL_DECORATOR_MASK);
01183                 ecopts = fptr->encs.ecopts;
01184                 fptr->writeconv = rb_econv_open_opts(senc, denc, ecflags, ecopts);
01185                 if (!fptr->writeconv)
01186                     rb_exc_raise(rb_econv_open_exc(senc, denc, ecflags));
01187             }
01188         }
01189     }
01190 }
01191 
01192 /* writing functions */
01193 struct binwrite_arg {
01194     rb_io_t *fptr;
01195     VALUE str;
01196     const char *ptr;
01197     long length;
01198 };
01199 
01200 struct write_arg {
01201     VALUE io;
01202     VALUE str;
01203     int nosync;
01204 };
01205 
01206 static VALUE
01207 io_binwrite_string(VALUE arg)
01208 {
01209     struct binwrite_arg *p = (struct binwrite_arg *)arg;
01210     long l = io_writable_length(p->fptr, p->length);
01211     return rb_write_internal2(p->fptr->fd, p->ptr, l);
01212 }
01213 
01214 static long
01215 io_binwrite(VALUE str, const char *ptr, long len, rb_io_t *fptr, int nosync)
01216 {
01217     long n, r, offset = 0;
01218 
01219     /* don't write anything if current thread has a pending interrupt. */
01220     rb_thread_check_ints();
01221 
01222     if ((n = len) <= 0) return n;
01223     if (fptr->wbuf.ptr == NULL && !(!nosync && (fptr->mode & FMODE_SYNC))) {
01224         fptr->wbuf.off = 0;
01225         fptr->wbuf.len = 0;
01226         fptr->wbuf.capa = IO_WBUF_CAPA_MIN;
01227         fptr->wbuf.ptr = ALLOC_N(char, fptr->wbuf.capa);
01228         fptr->write_lock = rb_mutex_new();
01229         rb_mutex_allow_trap(fptr->write_lock, 1);
01230     }
01231     if ((!nosync && (fptr->mode & (FMODE_SYNC|FMODE_TTY))) ||
01232         (fptr->wbuf.ptr && fptr->wbuf.capa <= fptr->wbuf.len + len)) {
01233         struct binwrite_arg arg;
01234 
01235         /*
01236          * xxx: use writev to avoid double write if available
01237          * writev may help avoid context switch between "a" and "\n" in
01238          * STDERR.puts "a" [ruby-dev:25080] (rebroken since native threads
01239          * introduced in 1.9)
01240          */
01241         if (fptr->wbuf.len && fptr->wbuf.len+len <= fptr->wbuf.capa) {
01242             if (fptr->wbuf.capa < fptr->wbuf.off+fptr->wbuf.len+len) {
01243                 MEMMOVE(fptr->wbuf.ptr, fptr->wbuf.ptr+fptr->wbuf.off, char, fptr->wbuf.len);
01244                 fptr->wbuf.off = 0;
01245             }
01246             MEMMOVE(fptr->wbuf.ptr+fptr->wbuf.off+fptr->wbuf.len, ptr+offset, char, len);
01247             fptr->wbuf.len += (int)len;
01248             n = 0;
01249         }
01250         if (io_fflush(fptr) < 0)
01251             return -1L;
01252         if (n == 0)
01253             return len;
01254 
01255         rb_io_check_closed(fptr);
01256         arg.fptr = fptr;
01257         arg.str = str;
01258       retry:
01259         arg.ptr = ptr + offset;
01260         arg.length = n;
01261         if (fptr->write_lock) {
01262             r = rb_mutex_synchronize(fptr->write_lock, io_binwrite_string, (VALUE)&arg);
01263         }
01264         else {
01265             long l = io_writable_length(fptr, n);
01266             r = rb_write_internal(fptr->fd, ptr+offset, l);
01267         }
01268         /* xxx: other threads may modify given string. */
01269         if (r == n) return len;
01270         if (0 <= r) {
01271             offset += r;
01272             n -= r;
01273             errno = EAGAIN;
01274         }
01275         if (rb_io_wait_writable(fptr->fd)) {
01276             rb_io_check_closed(fptr);
01277             if (offset < len)
01278                 goto retry;
01279         }
01280         return -1L;
01281     }
01282 
01283     if (fptr->wbuf.off) {
01284         if (fptr->wbuf.len)
01285             MEMMOVE(fptr->wbuf.ptr, fptr->wbuf.ptr+fptr->wbuf.off, char, fptr->wbuf.len);
01286         fptr->wbuf.off = 0;
01287     }
01288     MEMMOVE(fptr->wbuf.ptr+fptr->wbuf.off+fptr->wbuf.len, ptr+offset, char, len);
01289     fptr->wbuf.len += (int)len;
01290     return len;
01291 }
01292 
01293 # define MODE_BTMODE(a,b,c) ((fmode & FMODE_BINMODE) ? (b) : \
01294                              (fmode & FMODE_TEXTMODE) ? (c) : (a))
01295 static VALUE
01296 do_writeconv(VALUE str, rb_io_t *fptr)
01297 {
01298     if (NEED_WRITECONV(fptr)) {
01299         VALUE common_encoding = Qnil;
01300         SET_BINARY_MODE(fptr);
01301 
01302         make_writeconv(fptr);
01303 
01304         if (fptr->writeconv) {
01305 #define fmode (fptr->mode)
01306             if (!NIL_P(fptr->writeconv_asciicompat))
01307                 common_encoding = fptr->writeconv_asciicompat;
01308             else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1) && !rb_enc_asciicompat(rb_enc_get(str))) {
01309                 rb_raise(rb_eArgError, "ASCII incompatible string written for text mode IO without encoding conversion: %s",
01310                          rb_enc_name(rb_enc_get(str)));
01311             }
01312 #undef fmode
01313         }
01314         else {
01315             if (fptr->encs.enc2)
01316                 common_encoding = rb_enc_from_encoding(fptr->encs.enc2);
01317             else if (fptr->encs.enc != rb_ascii8bit_encoding())
01318                 common_encoding = rb_enc_from_encoding(fptr->encs.enc);
01319         }
01320 
01321         if (!NIL_P(common_encoding)) {
01322             str = rb_str_encode(str, common_encoding,
01323                 fptr->writeconv_pre_ecflags, fptr->writeconv_pre_ecopts);
01324         }
01325 
01326         if (fptr->writeconv) {
01327             str = rb_econv_str_convert(fptr->writeconv, str, ECONV_PARTIAL_INPUT);
01328         }
01329     }
01330 #if defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32)
01331 #define fmode (fptr->mode)
01332     else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1)) {
01333         if ((fptr->mode & FMODE_READABLE) &&
01334             !(fptr->encs.ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
01335             setmode(fptr->fd, O_BINARY);
01336         }
01337         else {
01338             setmode(fptr->fd, O_TEXT);
01339         }
01340         if (!rb_enc_asciicompat(rb_enc_get(str))) {
01341             rb_raise(rb_eArgError, "ASCII incompatible string written for text mode IO without encoding conversion: %s",
01342             rb_enc_name(rb_enc_get(str)));
01343         }
01344     }
01345 #undef fmode
01346 #endif
01347     return str;
01348 }
01349 
01350 static long
01351 io_fwrite(VALUE str, rb_io_t *fptr, int nosync)
01352 {
01353 #ifdef _WIN32
01354     if (fptr->mode & FMODE_TTY) {
01355         long len = rb_w32_write_console(str, fptr->fd);
01356         if (len > 0) return len;
01357     }
01358 #endif
01359     str = do_writeconv(str, fptr);
01360     return io_binwrite(str, RSTRING_PTR(str), RSTRING_LEN(str),
01361                        fptr, nosync);
01362 }
01363 
01364 ssize_t
01365 rb_io_bufwrite(VALUE io, const void *buf, size_t size)
01366 {
01367     rb_io_t *fptr;
01368 
01369     GetOpenFile(io, fptr);
01370     rb_io_check_writable(fptr);
01371     return (ssize_t)io_binwrite(0, buf, (long)size, fptr, 0);
01372 }
01373 
01374 static VALUE
01375 io_write(VALUE io, VALUE str, int nosync)
01376 {
01377     rb_io_t *fptr;
01378     long n;
01379     VALUE tmp;
01380 
01381     io = GetWriteIO(io);
01382     str = rb_obj_as_string(str);
01383     tmp = rb_io_check_io(io);
01384     if (NIL_P(tmp)) {
01385         /* port is not IO, call write method for it. */
01386         return rb_funcall(io, id_write, 1, str);
01387     }
01388     io = tmp;
01389     if (RSTRING_LEN(str) == 0) return INT2FIX(0);
01390 
01391     str = rb_str_new_frozen(str);
01392 
01393     GetOpenFile(io, fptr);
01394     rb_io_check_writable(fptr);
01395 
01396     n = io_fwrite(str, fptr, nosync);
01397     if (n == -1L) rb_sys_fail_path(fptr->pathv);
01398 
01399     return LONG2FIX(n);
01400 }
01401 
01402 /*
01403  *  call-seq:
01404  *     ios.write(string)    -> integer
01405  *
01406  *  Writes the given string to <em>ios</em>. The stream must be opened
01407  *  for writing. If the argument is not a string, it will be converted
01408  *  to a string using <code>to_s</code>. Returns the number of bytes
01409  *  written.
01410  *
01411  *     count = $stdout.write("This is a test\n")
01412  *     puts "That was #{count} bytes of data"
01413  *
01414  *  <em>produces:</em>
01415  *
01416  *     This is a test
01417  *     That was 15 bytes of data
01418  */
01419 
01420 static VALUE
01421 io_write_m(VALUE io, VALUE str)
01422 {
01423     return io_write(io, str, 0);
01424 }
01425 
01426 VALUE
01427 rb_io_write(VALUE io, VALUE str)
01428 {
01429     return rb_funcallv(io, id_write, 1, &str);
01430 }
01431 
01432 /*
01433  *  call-seq:
01434  *     ios << obj     -> ios
01435  *
01436  *  String Output---Writes <i>obj</i> to <em>ios</em>.
01437  *  <i>obj</i> will be converted to a string using
01438  *  <code>to_s</code>.
01439  *
01440  *     $stdout << "Hello " << "world!\n"
01441  *
01442  *  <em>produces:</em>
01443  *
01444  *     Hello world!
01445  */
01446 
01447 
01448 VALUE
01449 rb_io_addstr(VALUE io, VALUE str)
01450 {
01451     rb_io_write(io, str);
01452     return io;
01453 }
01454 
01455 #ifdef HAVE_FSYNC
01456 static VALUE
01457 nogvl_fsync(void *ptr)
01458 {
01459     rb_io_t *fptr = ptr;
01460 
01461     return (VALUE)fsync(fptr->fd);
01462 }
01463 #endif
01464 
01465 VALUE
01466 rb_io_flush_raw(VALUE io, int sync)
01467 {
01468     rb_io_t *fptr;
01469 
01470     if (!RB_TYPE_P(io, T_FILE)) {
01471         return rb_funcall(io, id_flush, 0);
01472     }
01473 
01474     io = GetWriteIO(io);
01475     GetOpenFile(io, fptr);
01476 
01477     if (fptr->mode & FMODE_WRITABLE) {
01478         if (io_fflush(fptr) < 0)
01479             rb_sys_fail(0);
01480 #ifdef _WIN32
01481         if (sync && GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->fd)) == FILE_TYPE_DISK) {
01482             rb_thread_io_blocking_region(nogvl_fsync, fptr, fptr->fd);
01483         }
01484 #endif
01485     }
01486     if (fptr->mode & FMODE_READABLE) {
01487         io_unread(fptr);
01488     }
01489 
01490     return io;
01491 }
01492 
01493 /*
01494  *  call-seq:
01495  *     ios.flush    -> ios
01496  *
01497  *  Flushes any buffered data within <em>ios</em> to the underlying
01498  *  operating system (note that this is Ruby internal buffering only;
01499  *  the OS may buffer the data as well).
01500  *
01501  *     $stdout.print "no newline"
01502  *     $stdout.flush
01503  *
01504  *  <em>produces:</em>
01505  *
01506  *     no newline
01507  */
01508 
01509 VALUE
01510 rb_io_flush(VALUE io)
01511 {
01512     return rb_io_flush_raw(io, 1);
01513 }
01514 
01515 /*
01516  *  call-seq:
01517  *     ios.pos     -> integer
01518  *     ios.tell    -> integer
01519  *
01520  *  Returns the current offset (in bytes) of <em>ios</em>.
01521  *
01522  *     f = File.new("testfile")
01523  *     f.pos    #=> 0
01524  *     f.gets   #=> "This is line one\n"
01525  *     f.pos    #=> 17
01526  */
01527 
01528 static VALUE
01529 rb_io_tell(VALUE io)
01530 {
01531     rb_io_t *fptr;
01532     off_t pos;
01533 
01534     GetOpenFile(io, fptr);
01535     pos = io_tell(fptr);
01536     if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
01537     pos -= fptr->rbuf.len;
01538     return OFFT2NUM(pos);
01539 }
01540 
01541 static VALUE
01542 rb_io_seek(VALUE io, VALUE offset, int whence)
01543 {
01544     rb_io_t *fptr;
01545     off_t pos;
01546 
01547     pos = NUM2OFFT(offset);
01548     GetOpenFile(io, fptr);
01549     pos = io_seek(fptr, pos, whence);
01550     if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
01551 
01552     return INT2FIX(0);
01553 }
01554 
01555 static int
01556 interpret_seek_whence(VALUE vwhence)
01557 {
01558     if (vwhence == sym_SET)
01559         return SEEK_SET;
01560     if (vwhence == sym_CUR)
01561         return SEEK_CUR;
01562     if (vwhence == sym_END)
01563         return SEEK_END;
01564 #ifdef SEEK_DATA
01565     if (vwhence == sym_DATA)
01566         return SEEK_DATA;
01567 #endif
01568 #ifdef SEEK_HOLE
01569     if (vwhence == sym_HOLE)
01570         return SEEK_HOLE;
01571 #endif
01572     return NUM2INT(vwhence);
01573 }
01574 
01575 /*
01576  *  call-seq:
01577  *     ios.seek(amount, whence=IO::SEEK_SET)  ->  0
01578  *
01579  *  Seeks to a given offset <i>anInteger</i> in the stream according to
01580  *  the value of <i>whence</i>:
01581  *
01582  *    :CUR or IO::SEEK_CUR  | Seeks to _amount_ plus current position
01583  *    ----------------------+--------------------------------------------------
01584  *    :END or IO::SEEK_END  | Seeks to _amount_ plus end of stream (you
01585  *                          | probably want a negative value for _amount_)
01586  *    ----------------------+--------------------------------------------------
01587  *    :SET or IO::SEEK_SET  | Seeks to the absolute location given by _amount_
01588  *
01589  *  Example:
01590  *
01591  *     f = File.new("testfile")
01592  *     f.seek(-13, IO::SEEK_END)   #=> 0
01593  *     f.readline                  #=> "And so on...\n"
01594  */
01595 
01596 static VALUE
01597 rb_io_seek_m(int argc, VALUE *argv, VALUE io)
01598 {
01599     VALUE offset, ptrname;
01600     int whence = SEEK_SET;
01601 
01602     if (rb_scan_args(argc, argv, "11", &offset, &ptrname) == 2) {
01603         whence = interpret_seek_whence(ptrname);
01604     }
01605 
01606     return rb_io_seek(io, offset, whence);
01607 }
01608 
01609 /*
01610  *  call-seq:
01611  *     ios.pos = integer    -> integer
01612  *
01613  *  Seeks to the given position (in bytes) in <em>ios</em>.
01614  *  It is not guaranteed that seeking to the right position when <em>ios</em>
01615  *  is textmode.
01616  *
01617  *     f = File.new("testfile")
01618  *     f.pos = 17
01619  *     f.gets   #=> "This is line two\n"
01620  */
01621 
01622 static VALUE
01623 rb_io_set_pos(VALUE io, VALUE offset)
01624 {
01625     rb_io_t *fptr;
01626     off_t pos;
01627 
01628     pos = NUM2OFFT(offset);
01629     GetOpenFile(io, fptr);
01630     pos = io_seek(fptr, pos, SEEK_SET);
01631     if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
01632 
01633     return OFFT2NUM(pos);
01634 }
01635 
01636 static void clear_readconv(rb_io_t *fptr);
01637 
01638 /*
01639  *  call-seq:
01640  *     ios.rewind    -> 0
01641  *
01642  *  Positions <em>ios</em> to the beginning of input, resetting
01643  *  <code>lineno</code> to zero.
01644  *
01645  *     f = File.new("testfile")
01646  *     f.readline   #=> "This is line one\n"
01647  *     f.rewind     #=> 0
01648  *     f.lineno     #=> 0
01649  *     f.readline   #=> "This is line one\n"
01650  *
01651  *  Note that it cannot be used with streams such as pipes, ttys, and sockets.
01652  */
01653 
01654 static VALUE
01655 rb_io_rewind(VALUE io)
01656 {
01657     rb_io_t *fptr;
01658 
01659     GetOpenFile(io, fptr);
01660     if (io_seek(fptr, 0L, 0) < 0 && errno) rb_sys_fail_path(fptr->pathv);
01661     if (io == ARGF.current_file) {
01662         ARGF.lineno -= fptr->lineno;
01663     }
01664     fptr->lineno = 0;
01665     if (fptr->readconv) {
01666         clear_readconv(fptr);
01667     }
01668 
01669     return INT2FIX(0);
01670 }
01671 
01672 static int
01673 io_fillbuf(rb_io_t *fptr)
01674 {
01675     ssize_t r;
01676 
01677     if (fptr->rbuf.ptr == NULL) {
01678         fptr->rbuf.off = 0;
01679         fptr->rbuf.len = 0;
01680         fptr->rbuf.capa = IO_RBUF_CAPA_FOR(fptr);
01681         fptr->rbuf.ptr = ALLOC_N(char, fptr->rbuf.capa);
01682 #ifdef _WIN32
01683         fptr->rbuf.capa--;
01684 #endif
01685     }
01686     if (fptr->rbuf.len == 0) {
01687       retry:
01688         {
01689             r = rb_read_internal(fptr->fd, fptr->rbuf.ptr, fptr->rbuf.capa);
01690         }
01691         if (r < 0) {
01692             if (rb_io_wait_readable(fptr->fd))
01693                 goto retry;
01694             {
01695                 VALUE path = rb_sprintf("fd:%d ", fptr->fd);
01696                 if (!NIL_P(fptr->pathv)) {
01697                     rb_str_append(path, fptr->pathv);
01698                 }
01699                 rb_sys_fail_path(path);
01700             }
01701         }
01702         fptr->rbuf.off = 0;
01703         fptr->rbuf.len = (int)r; /* r should be <= rbuf_capa */
01704         if (r == 0)
01705             return -1; /* EOF */
01706     }
01707     return 0;
01708 }
01709 
01710 /*
01711  *  call-seq:
01712  *     ios.eof     -> true or false
01713  *     ios.eof?    -> true or false
01714  *
01715  *  Returns true if <em>ios</em> is at end of file that means
01716  *  there are no more data to read.
01717  *  The stream must be opened for reading or an <code>IOError</code> will be
01718  *  raised.
01719  *
01720  *     f = File.new("testfile")
01721  *     dummy = f.readlines
01722  *     f.eof   #=> true
01723  *
01724  *  If <em>ios</em> is a stream such as pipe or socket, <code>IO#eof?</code>
01725  *  blocks until the other end sends some data or closes it.
01726  *
01727  *     r, w = IO.pipe
01728  *     Thread.new { sleep 1; w.close }
01729  *     r.eof?  #=> true after 1 second blocking
01730  *
01731  *     r, w = IO.pipe
01732  *     Thread.new { sleep 1; w.puts "a" }
01733  *     r.eof?  #=> false after 1 second blocking
01734  *
01735  *     r, w = IO.pipe
01736  *     r.eof?  # blocks forever
01737  *
01738  *  Note that <code>IO#eof?</code> reads data to the input byte buffer.
01739  *  So <code>IO#sysread</code> may not behave as you intend with
01740  *  <code>IO#eof?</code>, unless you call <code>IO#rewind</code>
01741  *  first (which is not available for some streams).
01742  */
01743 
01744 VALUE
01745 rb_io_eof(VALUE io)
01746 {
01747     rb_io_t *fptr;
01748 
01749     GetOpenFile(io, fptr);
01750     rb_io_check_char_readable(fptr);
01751 
01752     if (READ_CHAR_PENDING(fptr)) return Qfalse;
01753     if (READ_DATA_PENDING(fptr)) return Qfalse;
01754     READ_CHECK(fptr);
01755 #if defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32)
01756     if (!NEED_READCONV(fptr) && NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
01757         return eof(fptr->fd) ? Qtrue : Qfalse;
01758     }
01759 #endif
01760     if (io_fillbuf(fptr) < 0) {
01761         return Qtrue;
01762     }
01763     return Qfalse;
01764 }
01765 
01766 /*
01767  *  call-seq:
01768  *     ios.sync    -> true or false
01769  *
01770  *  Returns the current ``sync mode'' of <em>ios</em>. When sync mode is
01771  *  true, all output is immediately flushed to the underlying operating
01772  *  system and is not buffered by Ruby internally. See also
01773  *  <code>IO#fsync</code>.
01774  *
01775  *     f = File.new("testfile")
01776  *     f.sync   #=> false
01777  */
01778 
01779 static VALUE
01780 rb_io_sync(VALUE io)
01781 {
01782     rb_io_t *fptr;
01783 
01784     io = GetWriteIO(io);
01785     GetOpenFile(io, fptr);
01786     return (fptr->mode & FMODE_SYNC) ? Qtrue : Qfalse;
01787 }
01788 
01789 #ifdef HAVE_FSYNC
01790 
01791 /*
01792  *  call-seq:
01793  *     ios.sync = boolean   -> boolean
01794  *
01795  *  Sets the ``sync mode'' to <code>true</code> or <code>false</code>.
01796  *  When sync mode is true, all output is immediately flushed to the
01797  *  underlying operating system and is not buffered internally. Returns
01798  *  the new state. See also <code>IO#fsync</code>.
01799  *
01800  *     f = File.new("testfile")
01801  *     f.sync = true
01802  *
01803  *  <em>(produces no output)</em>
01804  */
01805 
01806 static VALUE
01807 rb_io_set_sync(VALUE io, VALUE sync)
01808 {
01809     rb_io_t *fptr;
01810 
01811     io = GetWriteIO(io);
01812     GetOpenFile(io, fptr);
01813     if (RTEST(sync)) {
01814         fptr->mode |= FMODE_SYNC;
01815     }
01816     else {
01817         fptr->mode &= ~FMODE_SYNC;
01818     }
01819     return sync;
01820 }
01821 
01822 /*
01823  *  call-seq:
01824  *     ios.fsync   -> 0 or nil
01825  *
01826  *  Immediately writes all buffered data in <em>ios</em> to disk.
01827  *  Note that <code>fsync</code> differs from
01828  *  using <code>IO#sync=</code>. The latter ensures that data is flushed
01829  *  from Ruby's buffers, but does not guarantee that the underlying
01830  *  operating system actually writes it to disk.
01831  *
01832  *  <code>NotImplementedError</code> is raised
01833  *  if the underlying operating system does not support <em>fsync(2)</em>.
01834  */
01835 
01836 static VALUE
01837 rb_io_fsync(VALUE io)
01838 {
01839     rb_io_t *fptr;
01840 
01841     io = GetWriteIO(io);
01842     GetOpenFile(io, fptr);
01843 
01844     if (io_fflush(fptr) < 0)
01845         rb_sys_fail(0);
01846 # ifndef _WIN32 /* already called in io_fflush() */
01847     if ((int)rb_thread_io_blocking_region(nogvl_fsync, fptr, fptr->fd) < 0)
01848         rb_sys_fail_path(fptr->pathv);
01849 # endif
01850     return INT2FIX(0);
01851 }
01852 #else
01853 # define rb_io_fsync rb_f_notimplement
01854 # define rb_io_sync rb_f_notimplement
01855 static VALUE
01856 rb_io_set_sync(VALUE io, VALUE sync)
01857 {
01858     rb_notimplement();
01859     UNREACHABLE;
01860 }
01861 #endif
01862 
01863 #ifdef HAVE_FDATASYNC
01864 static VALUE
01865 nogvl_fdatasync(void *ptr)
01866 {
01867     rb_io_t *fptr = ptr;
01868 
01869     return (VALUE)fdatasync(fptr->fd);
01870 }
01871 
01872 /*
01873  *  call-seq:
01874  *     ios.fdatasync   -> 0 or nil
01875  *
01876  *  Immediately writes all buffered data in <em>ios</em> to disk.
01877  *
01878  *  If the underlying operating system does not support <em>fdatasync(2)</em>,
01879  *  <code>IO#fsync</code> is called instead (which might raise a
01880  *  <code>NotImplementedError</code>).
01881  */
01882 
01883 static VALUE
01884 rb_io_fdatasync(VALUE io)
01885 {
01886     rb_io_t *fptr;
01887 
01888     io = GetWriteIO(io);
01889     GetOpenFile(io, fptr);
01890 
01891     if (io_fflush(fptr) < 0)
01892         rb_sys_fail(0);
01893 
01894     if ((int)rb_thread_io_blocking_region(nogvl_fdatasync, fptr, fptr->fd) == 0)
01895         return INT2FIX(0);
01896 
01897     /* fall back */
01898     return rb_io_fsync(io);
01899 }
01900 #else
01901 #define rb_io_fdatasync rb_io_fsync
01902 #endif
01903 
01904 /*
01905  *  call-seq:
01906  *     ios.fileno    -> fixnum
01907  *     ios.to_i      -> fixnum
01908  *
01909  *  Returns an integer representing the numeric file descriptor for
01910  *  <em>ios</em>.
01911  *
01912  *     $stdin.fileno    #=> 0
01913  *     $stdout.fileno   #=> 1
01914  */
01915 
01916 static VALUE
01917 rb_io_fileno(VALUE io)
01918 {
01919     rb_io_t *fptr = RFILE(io)->fptr;
01920     int fd;
01921 
01922     rb_io_check_closed(fptr);
01923     fd = fptr->fd;
01924     return INT2FIX(fd);
01925 }
01926 
01927 
01928 /*
01929  *  call-seq:
01930  *     ios.pid    -> fixnum
01931  *
01932  *  Returns the process ID of a child process associated with
01933  *  <em>ios</em>. This will be set by <code>IO.popen</code>.
01934  *
01935  *     pipe = IO.popen("-")
01936  *     if pipe
01937  *       $stderr.puts "In parent, child pid is #{pipe.pid}"
01938  *     else
01939  *       $stderr.puts "In child, pid is #{$$}"
01940  *     end
01941  *
01942  *  <em>produces:</em>
01943  *
01944  *     In child, pid is 26209
01945  *     In parent, child pid is 26209
01946  */
01947 
01948 static VALUE
01949 rb_io_pid(VALUE io)
01950 {
01951     rb_io_t *fptr;
01952 
01953     GetOpenFile(io, fptr);
01954     if (!fptr->pid)
01955         return Qnil;
01956     return PIDT2NUM(fptr->pid);
01957 }
01958 
01959 
01960 /*
01961  * call-seq:
01962  *   ios.inspect   -> string
01963  *
01964  * Return a string describing this IO object.
01965  */
01966 
01967 static VALUE
01968 rb_io_inspect(VALUE obj)
01969 {
01970     rb_io_t *fptr;
01971     VALUE result;
01972     static const char closed[] = " (closed)";
01973 
01974     fptr = RFILE(obj)->fptr;
01975     if (!fptr) return rb_any_to_s(obj);
01976     result = rb_str_new_cstr("#<");
01977     rb_str_append(result, rb_class_name(CLASS_OF(obj)));
01978     rb_str_cat2(result, ":");
01979     if (NIL_P(fptr->pathv)) {
01980         if (fptr->fd < 0) {
01981             rb_str_cat(result, closed+1, strlen(closed)-1);
01982         }
01983         else {
01984             rb_str_catf(result, "fd %d", fptr->fd);
01985         }
01986     }
01987     else {
01988         rb_str_append(result, fptr->pathv);
01989         if (fptr->fd < 0) {
01990             rb_str_cat(result, closed, strlen(closed));
01991         }
01992     }
01993     return rb_str_cat2(result, ">");
01994 }
01995 
01996 /*
01997  *  call-seq:
01998  *     ios.to_io  ->  ios
01999  *
02000  *  Returns <em>ios</em>.
02001  */
02002 
02003 static VALUE
02004 rb_io_to_io(VALUE io)
02005 {
02006     return io;
02007 }
02008 
02009 /* reading functions */
02010 static long
02011 read_buffered_data(char *ptr, long len, rb_io_t *fptr)
02012 {
02013     int n;
02014 
02015     n = READ_DATA_PENDING_COUNT(fptr);
02016     if (n <= 0) return 0;
02017     if (n > len) n = (int)len;
02018     MEMMOVE(ptr, fptr->rbuf.ptr+fptr->rbuf.off, char, n);
02019     fptr->rbuf.off += n;
02020     fptr->rbuf.len -= n;
02021     return n;
02022 }
02023 
02024 static long
02025 io_bufread(char *ptr, long len, rb_io_t *fptr)
02026 {
02027     long offset = 0;
02028     long n = len;
02029     long c;
02030 
02031     if (READ_DATA_PENDING(fptr) == 0) {
02032         while (n > 0) {
02033           again:
02034             c = rb_read_internal(fptr->fd, ptr+offset, n);
02035             if (c == 0) break;
02036             if (c < 0) {
02037                 if (rb_io_wait_readable(fptr->fd))
02038                     goto again;
02039                 return -1;
02040             }
02041             offset += c;
02042             if ((n -= c) <= 0) break;
02043         }
02044         return len - n;
02045     }
02046 
02047     while (n > 0) {
02048         c = read_buffered_data(ptr+offset, n, fptr);
02049         if (c > 0) {
02050             offset += c;
02051             if ((n -= c) <= 0) break;
02052         }
02053         rb_io_check_closed(fptr);
02054         if (io_fillbuf(fptr) < 0) {
02055             break;
02056         }
02057     }
02058     return len - n;
02059 }
02060 
02061 static void io_setstrbuf(VALUE *str, long len);
02062 
02063 struct bufread_arg {
02064     char *str_ptr;
02065     long len;
02066     rb_io_t *fptr;
02067 };
02068 
02069 static VALUE
02070 bufread_call(VALUE arg)
02071 {
02072     struct bufread_arg *p = (struct bufread_arg *)arg;
02073     p->len = io_bufread(p->str_ptr, p->len, p->fptr);
02074     return Qundef;
02075 }
02076 
02077 static long
02078 io_fread(VALUE str, long offset, long size, rb_io_t *fptr)
02079 {
02080     long len;
02081     struct bufread_arg arg;
02082 
02083     io_setstrbuf(&str, offset + size);
02084     arg.str_ptr = RSTRING_PTR(str) + offset;
02085     arg.len = size;
02086     arg.fptr = fptr;
02087     rb_str_locktmp_ensure(str, bufread_call, (VALUE)&arg);
02088     len = arg.len;
02089     if (len < 0) rb_sys_fail_path(fptr->pathv);
02090     return len;
02091 }
02092 
02093 ssize_t
02094 rb_io_bufread(VALUE io, void *buf, size_t size)
02095 {
02096     rb_io_t *fptr;
02097 
02098     GetOpenFile(io, fptr);
02099     rb_io_check_readable(fptr);
02100     return (ssize_t)io_bufread(buf, (long)size, fptr);
02101 }
02102 
02103 #define SMALLBUF 100
02104 
02105 static long
02106 remain_size(rb_io_t *fptr)
02107 {
02108     struct stat st;
02109     off_t siz = READ_DATA_PENDING_COUNT(fptr);
02110     off_t pos;
02111 
02112     if (fstat(fptr->fd, &st) == 0  && S_ISREG(st.st_mode)
02113 #if defined(__BEOS__) || defined(__HAIKU__)
02114         && (st.st_dev > 3)
02115 #endif
02116         )
02117     {
02118         if (io_fflush(fptr) < 0)
02119             rb_sys_fail(0);
02120         pos = lseek(fptr->fd, 0, SEEK_CUR);
02121         if (st.st_size >= pos && pos >= 0) {
02122             siz += st.st_size - pos;
02123             if (siz > LONG_MAX) {
02124                 rb_raise(rb_eIOError, "file too big for single read");
02125             }
02126         }
02127     }
02128     else {
02129         siz += BUFSIZ;
02130     }
02131     return (long)siz;
02132 }
02133 
02134 static VALUE
02135 io_enc_str(VALUE str, rb_io_t *fptr)
02136 {
02137     OBJ_TAINT(str);
02138     rb_enc_associate(str, io_read_encoding(fptr));
02139     return str;
02140 }
02141 
02142 static void
02143 make_readconv(rb_io_t *fptr, int size)
02144 {
02145     if (!fptr->readconv) {
02146         int ecflags;
02147         VALUE ecopts;
02148         const char *sname, *dname;
02149         ecflags = fptr->encs.ecflags & ~ECONV_NEWLINE_DECORATOR_WRITE_MASK;
02150         ecopts = fptr->encs.ecopts;
02151         if (fptr->encs.enc2) {
02152             sname = rb_enc_name(fptr->encs.enc2);
02153             dname = rb_enc_name(fptr->encs.enc);
02154         }
02155         else {
02156             sname = dname = "";
02157         }
02158         fptr->readconv = rb_econv_open_opts(sname, dname, ecflags, ecopts);
02159         if (!fptr->readconv)
02160             rb_exc_raise(rb_econv_open_exc(sname, dname, ecflags));
02161         fptr->cbuf.off = 0;
02162         fptr->cbuf.len = 0;
02163         if (size < IO_CBUF_CAPA_MIN) size = IO_CBUF_CAPA_MIN;
02164         fptr->cbuf.capa = size;
02165         fptr->cbuf.ptr = ALLOC_N(char, fptr->cbuf.capa);
02166     }
02167 }
02168 
02169 #define MORE_CHAR_SUSPENDED Qtrue
02170 #define MORE_CHAR_FINISHED Qnil
02171 static VALUE
02172 fill_cbuf(rb_io_t *fptr, int ec_flags)
02173 {
02174     const unsigned char *ss, *sp, *se;
02175     unsigned char *ds, *dp, *de;
02176     rb_econv_result_t res;
02177     int putbackable;
02178     int cbuf_len0;
02179     VALUE exc;
02180 
02181     ec_flags |= ECONV_PARTIAL_INPUT;
02182 
02183     if (fptr->cbuf.len == fptr->cbuf.capa)
02184         return MORE_CHAR_SUSPENDED; /* cbuf full */
02185     if (fptr->cbuf.len == 0)
02186         fptr->cbuf.off = 0;
02187     else if (fptr->cbuf.off + fptr->cbuf.len == fptr->cbuf.capa) {
02188         memmove(fptr->cbuf.ptr, fptr->cbuf.ptr+fptr->cbuf.off, fptr->cbuf.len);
02189         fptr->cbuf.off = 0;
02190     }
02191 
02192     cbuf_len0 = fptr->cbuf.len;
02193 
02194     while (1) {
02195         ss = sp = (const unsigned char *)fptr->rbuf.ptr + fptr->rbuf.off;
02196         se = sp + fptr->rbuf.len;
02197         ds = dp = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.off + fptr->cbuf.len;
02198         de = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.capa;
02199         res = rb_econv_convert(fptr->readconv, &sp, se, &dp, de, ec_flags);
02200         fptr->rbuf.off += (int)(sp - ss);
02201         fptr->rbuf.len -= (int)(sp - ss);
02202         fptr->cbuf.len += (int)(dp - ds);
02203 
02204         putbackable = rb_econv_putbackable(fptr->readconv);
02205         if (putbackable) {
02206             rb_econv_putback(fptr->readconv, (unsigned char *)fptr->rbuf.ptr + fptr->rbuf.off - putbackable, putbackable);
02207             fptr->rbuf.off -= putbackable;
02208             fptr->rbuf.len += putbackable;
02209         }
02210 
02211         exc = rb_econv_make_exception(fptr->readconv);
02212         if (!NIL_P(exc))
02213             return exc;
02214 
02215         if (cbuf_len0 != fptr->cbuf.len)
02216             return MORE_CHAR_SUSPENDED;
02217 
02218         if (res == econv_finished) {
02219             return MORE_CHAR_FINISHED;
02220         }
02221 
02222         if (res == econv_source_buffer_empty) {
02223             if (fptr->rbuf.len == 0) {
02224                 READ_CHECK(fptr);
02225                 if (io_fillbuf(fptr) == -1) {
02226                     if (!fptr->readconv) {
02227                         return MORE_CHAR_FINISHED;
02228                     }
02229                     ds = dp = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.off + fptr->cbuf.len;
02230                     de = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.capa;
02231                     res = rb_econv_convert(fptr->readconv, NULL, NULL, &dp, de, 0);
02232                     fptr->cbuf.len += (int)(dp - ds);
02233                     rb_econv_check_error(fptr->readconv);
02234                     break;
02235                 }
02236             }
02237         }
02238     }
02239     if (cbuf_len0 != fptr->cbuf.len)
02240         return MORE_CHAR_SUSPENDED;
02241 
02242     return MORE_CHAR_FINISHED;
02243 }
02244 
02245 static VALUE
02246 more_char(rb_io_t *fptr)
02247 {
02248     VALUE v;
02249     v = fill_cbuf(fptr, ECONV_AFTER_OUTPUT);
02250     if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED)
02251         rb_exc_raise(v);
02252     return v;
02253 }
02254 
02255 static VALUE
02256 io_shift_cbuf(rb_io_t *fptr, int len, VALUE *strp)
02257 {
02258     VALUE str = Qnil;
02259     if (strp) {
02260         str = *strp;
02261         if (NIL_P(str)) {
02262             *strp = str = rb_str_new(fptr->cbuf.ptr+fptr->cbuf.off, len);
02263         }
02264         else {
02265             rb_str_cat(str, fptr->cbuf.ptr+fptr->cbuf.off, len);
02266         }
02267         OBJ_TAINT(str);
02268         rb_enc_associate(str, fptr->encs.enc);
02269     }
02270     fptr->cbuf.off += len;
02271     fptr->cbuf.len -= len;
02272     /* xxx: set coderange */
02273     if (fptr->cbuf.len == 0)
02274         fptr->cbuf.off = 0;
02275     else if (fptr->cbuf.capa/2 < fptr->cbuf.off) {
02276         memmove(fptr->cbuf.ptr, fptr->cbuf.ptr+fptr->cbuf.off, fptr->cbuf.len);
02277         fptr->cbuf.off = 0;
02278     }
02279     return str;
02280 }
02281 
02282 static void
02283 io_setstrbuf(VALUE *str, long len)
02284 {
02285 #ifdef _WIN32
02286     len = (len + 1) & ~1L;      /* round up for wide char */
02287 #endif
02288     if (NIL_P(*str)) {
02289         *str = rb_str_new(0, 0);
02290     }
02291     else {
02292         VALUE s = StringValue(*str);
02293         long clen = RSTRING_LEN(s);
02294         if (clen >= len) {
02295             rb_str_modify(s);
02296             return;
02297         }
02298         len -= clen;
02299     }
02300     rb_str_modify_expand(*str, len);
02301 }
02302 
02303 static void
02304 io_set_read_length(VALUE str, long n)
02305 {
02306     if (RSTRING_LEN(str) != n) {
02307         rb_str_modify(str);
02308         rb_str_set_len(str, n);
02309     }
02310 }
02311 
02312 static VALUE
02313 read_all(rb_io_t *fptr, long siz, VALUE str)
02314 {
02315     long bytes;
02316     long n;
02317     long pos;
02318     rb_encoding *enc;
02319     int cr;
02320 
02321     if (NEED_READCONV(fptr)) {
02322         int first = !NIL_P(str);
02323         SET_BINARY_MODE(fptr);
02324         io_setstrbuf(&str,0);
02325         make_readconv(fptr, 0);
02326         while (1) {
02327             VALUE v;
02328             if (fptr->cbuf.len) {
02329                 if (first) rb_str_set_len(str, first = 0);
02330                 io_shift_cbuf(fptr, fptr->cbuf.len, &str);
02331             }
02332             v = fill_cbuf(fptr, 0);
02333             if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED) {
02334                 if (fptr->cbuf.len) {
02335                     if (first) rb_str_set_len(str, first = 0);
02336                     io_shift_cbuf(fptr, fptr->cbuf.len, &str);
02337                 }
02338                 rb_exc_raise(v);
02339             }
02340             if (v == MORE_CHAR_FINISHED) {
02341                 clear_readconv(fptr);
02342                 if (first) rb_str_set_len(str, first = 0);
02343                 return io_enc_str(str, fptr);
02344             }
02345         }
02346     }
02347 
02348     NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
02349     bytes = 0;
02350     pos = 0;
02351 
02352     enc = io_read_encoding(fptr);
02353     cr = 0;
02354 
02355     if (siz == 0) siz = BUFSIZ;
02356     io_setstrbuf(&str,siz);
02357     for (;;) {
02358         READ_CHECK(fptr);
02359         n = io_fread(str, bytes, siz - bytes, fptr);
02360         if (n == 0 && bytes == 0) {
02361             rb_str_set_len(str, 0);
02362             break;
02363         }
02364         bytes += n;
02365         rb_str_set_len(str, bytes);
02366         if (cr != ENC_CODERANGE_BROKEN)
02367             pos += rb_str_coderange_scan_restartable(RSTRING_PTR(str) + pos, RSTRING_PTR(str) + bytes, enc, &cr);
02368         if (bytes < siz) break;
02369         siz += BUFSIZ;
02370         rb_str_modify_expand(str, BUFSIZ);
02371     }
02372     str = io_enc_str(str, fptr);
02373     ENC_CODERANGE_SET(str, cr);
02374     return str;
02375 }
02376 
02377 void
02378 rb_io_set_nonblock(rb_io_t *fptr)
02379 {
02380     int oflags;
02381 #ifdef F_GETFL
02382     oflags = fcntl(fptr->fd, F_GETFL);
02383     if (oflags == -1) {
02384         rb_sys_fail_path(fptr->pathv);
02385     }
02386 #else
02387     oflags = 0;
02388 #endif
02389     if ((oflags & O_NONBLOCK) == 0) {
02390         oflags |= O_NONBLOCK;
02391         if (fcntl(fptr->fd, F_SETFL, oflags) == -1) {
02392             rb_sys_fail_path(fptr->pathv);
02393         }
02394     }
02395 }
02396 
02397 void
02398 rb_readwrite_sys_fail(int writable, const char *mesg);
02399 
02400 struct read_internal_arg {
02401     int fd;
02402     char *str_ptr;
02403     long len;
02404 };
02405 
02406 static VALUE
02407 read_internal_call(VALUE arg)
02408 {
02409     struct read_internal_arg *p = (struct read_internal_arg *)arg;
02410     p->len = rb_read_internal(p->fd, p->str_ptr, p->len);
02411     return Qundef;
02412 }
02413 
02414 static VALUE
02415 io_getpartial(int argc, VALUE *argv, VALUE io, int nonblock, int no_exception)
02416 {
02417     rb_io_t *fptr;
02418     VALUE length, str;
02419     long n, len;
02420     struct read_internal_arg arg;
02421 
02422     rb_scan_args(argc, argv, "11:", &length, &str, NULL);
02423 
02424     if ((len = NUM2LONG(length)) < 0) {
02425         rb_raise(rb_eArgError, "negative length %ld given", len);
02426     }
02427 
02428     io_setstrbuf(&str,len);
02429     OBJ_TAINT(str);
02430 
02431     GetOpenFile(io, fptr);
02432     rb_io_check_byte_readable(fptr);
02433 
02434     if (len == 0)
02435         return str;
02436 
02437     if (!nonblock)
02438         READ_CHECK(fptr);
02439     n = read_buffered_data(RSTRING_PTR(str), len, fptr);
02440     if (n <= 0) {
02441       again:
02442         if (nonblock) {
02443             rb_io_set_nonblock(fptr);
02444         }
02445         io_setstrbuf(&str, len);
02446         arg.fd = fptr->fd;
02447         arg.str_ptr = RSTRING_PTR(str);
02448         arg.len = len;
02449         rb_str_locktmp_ensure(str, read_internal_call, (VALUE)&arg);
02450         n = arg.len;
02451         if (n < 0) {
02452             if (!nonblock && rb_io_wait_readable(fptr->fd))
02453                 goto again;
02454             if (nonblock && (errno == EWOULDBLOCK || errno == EAGAIN)) {
02455                 if (no_exception)
02456                     return ID2SYM(rb_intern("wait_readable"));
02457                 else
02458                     rb_readwrite_sys_fail(RB_IO_WAIT_READABLE, "read would block");
02459             }
02460             rb_sys_fail_path(fptr->pathv);
02461         }
02462     }
02463     io_set_read_length(str, n);
02464 
02465     if (n == 0)
02466         return Qnil;
02467     else
02468         return str;
02469 }
02470 
02471 /*
02472  *  call-seq:
02473  *     ios.readpartial(maxlen)              -> string
02474  *     ios.readpartial(maxlen, outbuf)      -> outbuf
02475  *
02476  *  Reads at most <i>maxlen</i> bytes from the I/O stream.
02477  *  It blocks only if <em>ios</em> has no data immediately available.
02478  *  It doesn't block if some data available.
02479  *  If the optional <i>outbuf</i> argument is present,
02480  *  it must reference a String, which will receive the data.
02481  *  The <i>outbuf</i> will contain only the received data after the method call
02482  *  even if it is not empty at the beginning.
02483  *  It raises <code>EOFError</code> on end of file.
02484  *
02485  *  readpartial is designed for streams such as pipe, socket, tty, etc.
02486  *  It blocks only when no data immediately available.
02487  *  This means that it blocks only when following all conditions hold.
02488  *  * the byte buffer in the IO object is empty.
02489  *  * the content of the stream is empty.
02490  *  * the stream is not reached to EOF.
02491  *
02492  *  When readpartial blocks, it waits data or EOF on the stream.
02493  *  If some data is reached, readpartial returns with the data.
02494  *  If EOF is reached, readpartial raises EOFError.
02495  *
02496  *  When readpartial doesn't blocks, it returns or raises immediately.
02497  *  If the byte buffer is not empty, it returns the data in the buffer.
02498  *  Otherwise if the stream has some content,
02499  *  it returns the data in the stream.
02500  *  Otherwise if the stream is reached to EOF, it raises EOFError.
02501  *
02502  *     r, w = IO.pipe           #               buffer          pipe content
02503  *     w << "abc"               #               ""              "abc".
02504  *     r.readpartial(4096)      #=> "abc"       ""              ""
02505  *     r.readpartial(4096)      # blocks because buffer and pipe is empty.
02506  *
02507  *     r, w = IO.pipe           #               buffer          pipe content
02508  *     w << "abc"               #               ""              "abc"
02509  *     w.close                  #               ""              "abc" EOF
02510  *     r.readpartial(4096)      #=> "abc"       ""              EOF
02511  *     r.readpartial(4096)      # raises EOFError
02512  *
02513  *     r, w = IO.pipe           #               buffer          pipe content
02514  *     w << "abc\ndef\n"        #               ""              "abc\ndef\n"
02515  *     r.gets                   #=> "abc\n"     "def\n"         ""
02516  *     w << "ghi\n"             #               "def\n"         "ghi\n"
02517  *     r.readpartial(4096)      #=> "def\n"     ""              "ghi\n"
02518  *     r.readpartial(4096)      #=> "ghi\n"     ""              ""
02519  *
02520  *  Note that readpartial behaves similar to sysread.
02521  *  The differences are:
02522  *  * If the byte buffer is not empty, read from the byte buffer instead of "sysread for buffered IO (IOError)".
02523  *  * It doesn't cause Errno::EWOULDBLOCK and Errno::EINTR.  When readpartial meets EWOULDBLOCK and EINTR by read system call, readpartial retry the system call.
02524  *
02525  *  The later means that readpartial is nonblocking-flag insensitive.
02526  *  It blocks on the situation IO#sysread causes Errno::EWOULDBLOCK as if the fd is blocking mode.
02527  *
02528  */
02529 
02530 static VALUE
02531 io_readpartial(int argc, VALUE *argv, VALUE io)
02532 {
02533     VALUE ret;
02534 
02535     ret = io_getpartial(argc, argv, io, 0, 0);
02536     if (NIL_P(ret))
02537         rb_eof_error();
02538     return ret;
02539 }
02540 
02541 /*
02542  *  call-seq:
02543  *     ios.read_nonblock(maxlen)              -> string
02544  *     ios.read_nonblock(maxlen, outbuf)      -> outbuf
02545  *
02546  *  Reads at most <i>maxlen</i> bytes from <em>ios</em> using
02547  *  the read(2) system call after O_NONBLOCK is set for
02548  *  the underlying file descriptor.
02549  *
02550  *  If the optional <i>outbuf</i> argument is present,
02551  *  it must reference a String, which will receive the data.
02552  *  The <i>outbuf</i> will contain only the received data after the method call
02553  *  even if it is not empty at the beginning.
02554  *
02555  *  read_nonblock just calls the read(2) system call.
02556  *  It causes all errors the read(2) system call causes: Errno::EWOULDBLOCK, Errno::EINTR, etc.
02557  *  The caller should care such errors.
02558  *
02559  *  If the exception is Errno::EWOULDBLOCK or Errno::AGAIN,
02560  *  it is extended by IO::WaitReadable.
02561  *  So IO::WaitReadable can be used to rescue the exceptions for retrying read_nonblock.
02562  *
02563  *  read_nonblock causes EOFError on EOF.
02564  *
02565  *  If the read byte buffer is not empty,
02566  *  read_nonblock reads from the buffer like readpartial.
02567  *  In this case, the read(2) system call is not called.
02568  *
02569  *  When read_nonblock raises an exception kind of IO::WaitReadable,
02570  *  read_nonblock should not be called
02571  *  until io is readable for avoiding busy loop.
02572  *  This can be done as follows.
02573  *
02574  *    # emulates blocking read (readpartial).
02575  *    begin
02576  *      result = io.read_nonblock(maxlen)
02577  *    rescue IO::WaitReadable
02578  *      IO.select([io])
02579  *      retry
02580  *    end
02581  *
02582  *  Although IO#read_nonblock doesn't raise IO::WaitWritable.
02583  *  OpenSSL::Buffering#read_nonblock can raise IO::WaitWritable.
02584  *  If IO and SSL should be used polymorphically,
02585  *  IO::WaitWritable should be rescued too.
02586  *  See the document of OpenSSL::Buffering#read_nonblock for sample code.
02587  *
02588  *  Note that this method is identical to readpartial
02589  *  except the non-blocking flag is set.
02590  */
02591 
02592 static VALUE
02593 io_read_nonblock(int argc, VALUE *argv, VALUE io)
02594 {
02595     VALUE ret;
02596     VALUE opts = Qnil;
02597     int no_exception = 0;
02598 
02599     rb_scan_args(argc, argv, "11:", NULL, NULL, &opts);
02600 
02601     if (!NIL_P(opts) && Qfalse == rb_hash_aref(opts, sym_exception))
02602         no_exception = 1;
02603 
02604     ret = io_getpartial(argc, argv, io, 1, no_exception);
02605 
02606     if (NIL_P(ret)) {
02607         if (no_exception)
02608             return Qnil;
02609         else
02610             rb_eof_error();
02611     }
02612     return ret;
02613 }
02614 
02615 static VALUE
02616 io_write_nonblock(VALUE io, VALUE str, int no_exception)
02617 {
02618     rb_io_t *fptr;
02619     long n;
02620 
02621     if (!RB_TYPE_P(str, T_STRING))
02622         str = rb_obj_as_string(str);
02623 
02624     io = GetWriteIO(io);
02625     GetOpenFile(io, fptr);
02626     rb_io_check_writable(fptr);
02627 
02628     if (io_fflush(fptr) < 0)
02629         rb_sys_fail(0);
02630 
02631     rb_io_set_nonblock(fptr);
02632     n = write(fptr->fd, RSTRING_PTR(str), RSTRING_LEN(str));
02633 
02634     if (n == -1) {
02635         if (errno == EWOULDBLOCK || errno == EAGAIN) {
02636             if (no_exception) {
02637                 return ID2SYM(rb_intern("wait_writable"));
02638             } else {
02639                 rb_readwrite_sys_fail(RB_IO_WAIT_WRITABLE, "write would block");
02640             }
02641         }
02642         rb_sys_fail_path(fptr->pathv);
02643     }
02644 
02645     return LONG2FIX(n);
02646 }
02647 
02648 /*
02649  *  call-seq:
02650  *     ios.write_nonblock(string)   -> integer
02651  *     ios.write_nonblock(string [, options])   -> integer
02652  *
02653  *  Writes the given string to <em>ios</em> using
02654  *  the write(2) system call after O_NONBLOCK is set for
02655  *  the underlying file descriptor.
02656  *
02657  *  It returns the number of bytes written.
02658  *
02659  *  write_nonblock just calls the write(2) system call.
02660  *  It causes all errors the write(2) system call causes: Errno::EWOULDBLOCK, Errno::EINTR, etc.
02661  *  The result may also be smaller than string.length (partial write).
02662  *  The caller should care such errors and partial write.
02663  *
02664  *  If the exception is Errno::EWOULDBLOCK or Errno::AGAIN,
02665  *  it is extended by IO::WaitWritable.
02666  *  So IO::WaitWritable can be used to rescue the exceptions for retrying write_nonblock.
02667  *
02668  *    # Creates a pipe.
02669  *    r, w = IO.pipe
02670  *
02671  *    # write_nonblock writes only 65536 bytes and return 65536.
02672  *    # (The pipe size is 65536 bytes on this environment.)
02673  *    s = "a" * 100000
02674  *    p w.write_nonblock(s)     #=> 65536
02675  *
02676  *    # write_nonblock cannot write a byte and raise EWOULDBLOCK (EAGAIN).
02677  *    p w.write_nonblock("b")   # Resource temporarily unavailable (Errno::EAGAIN)
02678  *
02679  *  If the write buffer is not empty, it is flushed at first.
02680  *
02681  *  When write_nonblock raises an exception kind of IO::WaitWritable,
02682  *  write_nonblock should not be called
02683  *  until io is writable for avoiding busy loop.
02684  *  This can be done as follows.
02685  *
02686  *    begin
02687  *      result = io.write_nonblock(string)
02688  *    rescue IO::WaitWritable, Errno::EINTR
02689  *      IO.select(nil, [io])
02690  *      retry
02691  *    end
02692  *
02693  *  Note that this doesn't guarantee to write all data in string.
02694  *  The length written is reported as result and it should be checked later.
02695  *
02696  *  On some platforms such as Windows, write_nonblock is not supported
02697  *  according to the kind of the IO object.
02698  *  In such cases, write_nonblock raises <code>Errno::EBADF</code>.
02699  *
02700  *  By specifying `exception: false`, the options hash allows you to indicate
02701  *  that write_nonblock should not raise an IO::WaitWritable exception, but
02702  *  return the symbol :wait_writable instead.
02703  *
02704  */
02705 
02706 static VALUE
02707 rb_io_write_nonblock(int argc, VALUE *argv, VALUE io)
02708 {
02709     VALUE str;
02710     VALUE opts = Qnil;
02711     int no_exceptions = 0;
02712 
02713     rb_scan_args(argc, argv, "10:", &str, &opts);
02714 
02715     if (!NIL_P(opts) && Qfalse == rb_hash_aref(opts, sym_exception))
02716         no_exceptions = 1;
02717 
02718     return io_write_nonblock(io, str, no_exceptions);
02719 }
02720 
02721 /*
02722  *  call-seq:
02723  *     ios.read([length [, outbuf]])    -> string, outbuf, or nil
02724  *
02725  *  Reads <i>length</i> bytes from the I/O stream.
02726  *
02727  *  <i>length</i> must be a non-negative integer or <code>nil</code>.
02728  *
02729  *  If <i>length</i> is a positive integer,
02730  *  it try to read <i>length</i> bytes without any conversion (binary mode).
02731  *  It returns <code>nil</code> or a string whose length is 1 to <i>length</i> bytes.
02732  *  <code>nil</code> means it met EOF at beginning.
02733  *  The 1 to <i>length</i>-1 bytes string means it met EOF after reading the result.
02734  *  The <i>length</i> bytes string means it doesn't meet EOF.
02735  *  The resulted string is always ASCII-8BIT encoding.
02736  *
02737  *  If <i>length</i> is omitted or is <code>nil</code>,
02738  *  it reads until EOF and the encoding conversion is applied.
02739  *  It returns a string even if EOF is met at beginning.
02740  *
02741  *  If <i>length</i> is zero, it returns <code>""</code>.
02742  *
02743  *  If the optional <i>outbuf</i> argument is present, it must reference
02744  *  a String, which will receive the data.
02745  *  The <i>outbuf</i> will contain only the received data after the method call
02746  *  even if it is not empty at the beginning.
02747  *
02748  *  At end of file, it returns <code>nil</code> or <code>""</code>
02749  *  depend on <i>length</i>.
02750  *  <code><i>ios</i>.read()</code> and
02751  *  <code><i>ios</i>.read(nil)</code> returns <code>""</code>.
02752  *  <code><i>ios</i>.read(<i>positive-integer</i>)</code> returns <code>nil</code>.
02753  *
02754  *     f = File.new("testfile")
02755  *     f.read(16)   #=> "This is line one"
02756  *
02757  *     # reads whole file
02758  *     open("file") {|f|
02759  *       data = f.read # This returns a string even if the file is empty.
02760  *       ...
02761  *     }
02762  *
02763  *     # iterate over fixed length records.
02764  *     open("fixed-record-file") {|f|
02765  *       while record = f.read(256)
02766  *         ...
02767  *       end
02768  *     }
02769  *
02770  *     # iterate over variable length records.
02771  *     # record is prefixed by 32-bit length.
02772  *     open("variable-record-file") {|f|
02773  *       while len = f.read(4)
02774  *         len = len.unpack("N")[0] # 32-bit length
02775  *         record = f.read(len) # This returns a string even if len is 0.
02776  *       end
02777  *     }
02778  *
02779  *  Note that this method behaves like fread() function in C.
02780  *  This means it retry to invoke read(2) system call to read data with the specified length (or until EOF).
02781  *  This behavior is preserved even if <i>ios</i> is non-blocking mode.
02782  *  (This method is non-blocking flag insensitive as other methods.)
02783  *  If you need the behavior like single read(2) system call,
02784  *  consider readpartial, read_nonblock and sysread.
02785  */
02786 
02787 static VALUE
02788 io_read(int argc, VALUE *argv, VALUE io)
02789 {
02790     rb_io_t *fptr;
02791     long n, len;
02792     VALUE length, str;
02793 #if defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32)
02794     int previous_mode;
02795 #endif
02796 
02797     rb_scan_args(argc, argv, "02", &length, &str);
02798 
02799     if (NIL_P(length)) {
02800         GetOpenFile(io, fptr);
02801         rb_io_check_char_readable(fptr);
02802         return read_all(fptr, remain_size(fptr), str);
02803     }
02804     len = NUM2LONG(length);
02805     if (len < 0) {
02806         rb_raise(rb_eArgError, "negative length %ld given", len);
02807     }
02808 
02809     io_setstrbuf(&str,len);
02810 
02811     GetOpenFile(io, fptr);
02812     rb_io_check_byte_readable(fptr);
02813     if (len == 0) {
02814         io_set_read_length(str, 0);
02815         return str;
02816     }
02817 
02818     READ_CHECK(fptr);
02819 #if defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32)
02820     previous_mode = set_binary_mode_with_seek_cur(fptr);
02821 #endif
02822     n = io_fread(str, 0, len, fptr);
02823     io_set_read_length(str, n);
02824 #if defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32)
02825     if (previous_mode == O_TEXT) {
02826         setmode(fptr->fd, O_TEXT);
02827     }
02828 #endif
02829     if (n == 0) return Qnil;
02830     OBJ_TAINT(str);
02831 
02832     return str;
02833 }
02834 
02835 static void
02836 rscheck(const char *rsptr, long rslen, VALUE rs)
02837 {
02838     if (!rs) return;
02839     if (RSTRING_PTR(rs) != rsptr && RSTRING_LEN(rs) != rslen)
02840         rb_raise(rb_eRuntimeError, "rs modified");
02841 }
02842 
02843 static int
02844 appendline(rb_io_t *fptr, int delim, VALUE *strp, long *lp)
02845 {
02846     VALUE str = *strp;
02847     long limit = *lp;
02848 
02849     if (NEED_READCONV(fptr)) {
02850         SET_BINARY_MODE(fptr);
02851         make_readconv(fptr, 0);
02852         do {
02853             const char *p, *e;
02854             int searchlen = READ_CHAR_PENDING_COUNT(fptr);
02855             if (searchlen) {
02856                 p = READ_CHAR_PENDING_PTR(fptr);
02857                 if (0 < limit && limit < searchlen)
02858                     searchlen = (int)limit;
02859                 e = memchr(p, delim, searchlen);
02860                 if (e) {
02861                     int len = (int)(e-p+1);
02862                     if (NIL_P(str))
02863                         *strp = str = rb_str_new(p, len);
02864                     else
02865                         rb_str_buf_cat(str, p, len);
02866                     fptr->cbuf.off += len;
02867                     fptr->cbuf.len -= len;
02868                     limit -= len;
02869                     *lp = limit;
02870                     return delim;
02871                 }
02872 
02873                 if (NIL_P(str))
02874                     *strp = str = rb_str_new(p, searchlen);
02875                 else
02876                     rb_str_buf_cat(str, p, searchlen);
02877                 fptr->cbuf.off += searchlen;
02878                 fptr->cbuf.len -= searchlen;
02879                 limit -= searchlen;
02880 
02881                 if (limit == 0) {
02882                     *lp = limit;
02883                     return (unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
02884                 }
02885             }
02886         } while (more_char(fptr) != MORE_CHAR_FINISHED);
02887         clear_readconv(fptr);
02888         *lp = limit;
02889         return EOF;
02890     }
02891 
02892     NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
02893     do {
02894         long pending = READ_DATA_PENDING_COUNT(fptr);
02895         if (pending > 0) {
02896             const char *p = READ_DATA_PENDING_PTR(fptr);
02897             const char *e;
02898             long last;
02899 
02900             if (limit > 0 && pending > limit) pending = limit;
02901             e = memchr(p, delim, pending);
02902             if (e) pending = e - p + 1;
02903             if (!NIL_P(str)) {
02904                 last = RSTRING_LEN(str);
02905                 rb_str_resize(str, last + pending);
02906             }
02907             else {
02908                 last = 0;
02909                 *strp = str = rb_str_buf_new(pending);
02910                 rb_str_set_len(str, pending);
02911             }
02912             read_buffered_data(RSTRING_PTR(str) + last, pending, fptr); /* must not fail */
02913             limit -= pending;
02914             *lp = limit;
02915             if (e) return delim;
02916             if (limit == 0)
02917                 return (unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
02918         }
02919         READ_CHECK(fptr);
02920     } while (io_fillbuf(fptr) >= 0);
02921     *lp = limit;
02922     return EOF;
02923 }
02924 
02925 static inline int
02926 swallow(rb_io_t *fptr, int term)
02927 {
02928     if (NEED_READCONV(fptr)) {
02929         rb_encoding *enc = io_read_encoding(fptr);
02930         int needconv = rb_enc_mbminlen(enc) != 1;
02931         SET_BINARY_MODE(fptr);
02932         make_readconv(fptr, 0);
02933         do {
02934             size_t cnt;
02935             while ((cnt = READ_CHAR_PENDING_COUNT(fptr)) > 0) {
02936                 const char *p = READ_CHAR_PENDING_PTR(fptr);
02937                 int i;
02938                 if (!needconv) {
02939                     if (*p != term) return TRUE;
02940                     i = (int)cnt;
02941                     while (--i && *++p == term);
02942                 }
02943                 else {
02944                     const char *e = p + cnt;
02945                     if (rb_enc_ascget(p, e, &i, enc) != term) return TRUE;
02946                     while ((p += i) < e && rb_enc_ascget(p, e, &i, enc) == term);
02947                     i = (int)(e - p);
02948                 }
02949                 io_shift_cbuf(fptr, (int)cnt - i, NULL);
02950             }
02951         } while (more_char(fptr) != MORE_CHAR_FINISHED);
02952         return FALSE;
02953     }
02954 
02955     NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
02956     do {
02957         size_t cnt;
02958         while ((cnt = READ_DATA_PENDING_COUNT(fptr)) > 0) {
02959             char buf[1024];
02960             const char *p = READ_DATA_PENDING_PTR(fptr);
02961             int i;
02962             if (cnt > sizeof buf) cnt = sizeof buf;
02963             if (*p != term) return TRUE;
02964             i = (int)cnt;
02965             while (--i && *++p == term);
02966             if (!read_buffered_data(buf, cnt - i, fptr)) /* must not fail */
02967                 rb_sys_fail_path(fptr->pathv);
02968         }
02969         READ_CHECK(fptr);
02970     } while (io_fillbuf(fptr) == 0);
02971     return FALSE;
02972 }
02973 
02974 static VALUE
02975 rb_io_getline_fast(rb_io_t *fptr, rb_encoding *enc, VALUE io)
02976 {
02977     VALUE str = Qnil;
02978     int len = 0;
02979     long pos = 0;
02980     int cr = 0;
02981 
02982     do {
02983         int pending = READ_DATA_PENDING_COUNT(fptr);
02984 
02985         if (pending > 0) {
02986             const char *p = READ_DATA_PENDING_PTR(fptr);
02987             const char *e;
02988 
02989             e = memchr(p, '\n', pending);
02990             if (e) {
02991                 pending = (int)(e - p + 1);
02992             }
02993             if (NIL_P(str)) {
02994                 str = rb_str_new(p, pending);
02995                 fptr->rbuf.off += pending;
02996                 fptr->rbuf.len -= pending;
02997             }
02998             else {
02999                 rb_str_resize(str, len + pending);
03000                 read_buffered_data(RSTRING_PTR(str)+len, pending, fptr);
03001             }
03002             len += pending;
03003             if (cr != ENC_CODERANGE_BROKEN)
03004                 pos += rb_str_coderange_scan_restartable(RSTRING_PTR(str) + pos, RSTRING_PTR(str) + len, enc, &cr);
03005             if (e) break;
03006         }
03007         READ_CHECK(fptr);
03008     } while (io_fillbuf(fptr) >= 0);
03009     if (NIL_P(str)) return Qnil;
03010 
03011     str = io_enc_str(str, fptr);
03012     ENC_CODERANGE_SET(str, cr);
03013     fptr->lineno++;
03014     if (io == ARGF.current_file) {
03015         ARGF.lineno++;
03016         ARGF.last_lineno = ARGF.lineno;
03017     }
03018     else {
03019         ARGF.last_lineno = fptr->lineno;
03020     }
03021 
03022     return str;
03023 }
03024 
03025 static void
03026 prepare_getline_args(int argc, VALUE *argv, VALUE *rsp, long *limit, VALUE io)
03027 {
03028     VALUE rs = rb_rs, lim = Qnil;
03029     rb_io_t *fptr;
03030 
03031     if (argc == 1) {
03032         VALUE tmp = Qnil;
03033 
03034         if (NIL_P(argv[0]) || !NIL_P(tmp = rb_check_string_type(argv[0]))) {
03035             rs = tmp;
03036         }
03037         else {
03038             lim = argv[0];
03039         }
03040     }
03041     else if (2 <= argc) {
03042         rb_scan_args(argc, argv, "2", &rs, &lim);
03043         if (!NIL_P(rs))
03044             StringValue(rs);
03045     }
03046     if (!NIL_P(rs)) {
03047         rb_encoding *enc_rs, *enc_io;
03048 
03049         GetOpenFile(io, fptr);
03050         enc_rs = rb_enc_get(rs);
03051         enc_io = io_read_encoding(fptr);
03052         if (enc_io != enc_rs &&
03053             (rb_enc_str_coderange(rs) != ENC_CODERANGE_7BIT ||
03054              (RSTRING_LEN(rs) > 0 && !rb_enc_asciicompat(enc_io)))) {
03055             if (rs == rb_default_rs) {
03056                 rs = rb_enc_str_new(0, 0, enc_io);
03057                 rb_str_buf_cat_ascii(rs, "\n");
03058             }
03059             else {
03060                 rb_raise(rb_eArgError, "encoding mismatch: %s IO with %s RS",
03061                          rb_enc_name(enc_io),
03062                          rb_enc_name(enc_rs));
03063             }
03064         }
03065     }
03066     *rsp = rs;
03067     *limit = NIL_P(lim) ? -1L : NUM2LONG(lim);
03068 }
03069 
03070 static VALUE
03071 rb_io_getline_1(VALUE rs, long limit, VALUE io)
03072 {
03073     VALUE str = Qnil;
03074     rb_io_t *fptr;
03075     int nolimit = 0;
03076     rb_encoding *enc;
03077 
03078     GetOpenFile(io, fptr);
03079     rb_io_check_char_readable(fptr);
03080     if (NIL_P(rs) && limit < 0) {
03081         str = read_all(fptr, 0, Qnil);
03082         if (RSTRING_LEN(str) == 0) return Qnil;
03083     }
03084     else if (limit == 0) {
03085         return rb_enc_str_new(0, 0, io_read_encoding(fptr));
03086     }
03087     else if (rs == rb_default_rs && limit < 0 && !NEED_READCONV(fptr) &&
03088              rb_enc_asciicompat(enc = io_read_encoding(fptr))) {
03089         NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
03090         return rb_io_getline_fast(fptr, enc, io);
03091     }
03092     else {
03093         int c, newline = -1;
03094         const char *rsptr = 0;
03095         long rslen = 0;
03096         int rspara = 0;
03097         int extra_limit = 16;
03098 
03099         SET_BINARY_MODE(fptr);
03100         enc = io_read_encoding(fptr);
03101 
03102         if (!NIL_P(rs)) {
03103             rslen = RSTRING_LEN(rs);
03104             if (rslen == 0) {
03105                 rsptr = "\n\n";
03106                 rslen = 2;
03107                 rspara = 1;
03108                 swallow(fptr, '\n');
03109                 rs = 0;
03110                 if (!rb_enc_asciicompat(enc)) {
03111                     rs = rb_usascii_str_new(rsptr, rslen);
03112                     rs = rb_str_encode(rs, rb_enc_from_encoding(enc), 0, Qnil);
03113                     OBJ_FREEZE(rs);
03114                     rsptr = RSTRING_PTR(rs);
03115                     rslen = RSTRING_LEN(rs);
03116                 }
03117             }
03118             else {
03119                 rsptr = RSTRING_PTR(rs);
03120             }
03121             newline = (unsigned char)rsptr[rslen - 1];
03122         }
03123 
03124         /* MS - Optimisation */
03125         while ((c = appendline(fptr, newline, &str, &limit)) != EOF) {
03126             const char *s, *p, *pp, *e;
03127 
03128             if (c == newline) {
03129                 if (RSTRING_LEN(str) < rslen) continue;
03130                 s = RSTRING_PTR(str);
03131                 e = RSTRING_END(str);
03132                 p = e - rslen;
03133                 pp = rb_enc_left_char_head(s, p, e, enc);
03134                 if (pp != p) continue;
03135                 if (!rspara) rscheck(rsptr, rslen, rs);
03136                 if (memcmp(p, rsptr, rslen) == 0) break;
03137             }
03138             if (limit == 0) {
03139                 s = RSTRING_PTR(str);
03140                 p = RSTRING_END(str);
03141                 pp = rb_enc_left_char_head(s, p-1, p, enc);
03142                 if (extra_limit &&
03143                     MBCLEN_NEEDMORE_P(rb_enc_precise_mbclen(pp, p, enc))) {
03144                     /* relax the limit while incomplete character.
03145                      * extra_limit limits the relax length */
03146                     limit = 1;
03147                     extra_limit--;
03148                 }
03149                 else {
03150                     nolimit = 1;
03151                     break;
03152                 }
03153             }
03154         }
03155 
03156         if (rspara && c != EOF)
03157             swallow(fptr, '\n');
03158         if (!NIL_P(str))
03159             str = io_enc_str(str, fptr);
03160     }
03161 
03162     if (!NIL_P(str) && !nolimit) {
03163         fptr->lineno++;
03164         if (io == ARGF.current_file) {
03165             ARGF.lineno++;
03166             ARGF.last_lineno = ARGF.lineno;
03167         }
03168         else {
03169             ARGF.last_lineno = fptr->lineno;
03170         }
03171     }
03172 
03173     return str;
03174 }
03175 
03176 static VALUE
03177 rb_io_getline(int argc, VALUE *argv, VALUE io)
03178 {
03179     VALUE rs;
03180     long limit;
03181 
03182     prepare_getline_args(argc, argv, &rs, &limit, io);
03183     return rb_io_getline_1(rs, limit, io);
03184 }
03185 
03186 VALUE
03187 rb_io_gets(VALUE io)
03188 {
03189     return rb_io_getline_1(rb_default_rs, -1, io);
03190 }
03191 
03192 /*
03193  *  call-seq:
03194  *     ios.gets(sep=$/)     -> string or nil
03195  *     ios.gets(limit)      -> string or nil
03196  *     ios.gets(sep, limit) -> string or nil
03197  *
03198  *  Reads the next ``line'' from the I/O stream; lines are separated by
03199  *  <i>sep</i>. A separator of <code>nil</code> reads the entire
03200  *  contents, and a zero-length separator reads the input a paragraph at
03201  *  a time (two successive newlines in the input separate paragraphs).
03202  *  The stream must be opened for reading or an <code>IOError</code>
03203  *  will be raised. The line read in will be returned and also assigned
03204  *  to <code>$_</code>. Returns <code>nil</code> if called at end of
03205  *  file.  If the first argument is an integer, or optional second
03206  *  argument is given, the returning string would not be longer than the
03207  *  given value in bytes.
03208  *
03209  *     File.new("testfile").gets   #=> "This is line one\n"
03210  *     $_                          #=> "This is line one\n"
03211  */
03212 
03213 static VALUE
03214 rb_io_gets_m(int argc, VALUE *argv, VALUE io)
03215 {
03216     VALUE str;
03217 
03218     str = rb_io_getline(argc, argv, io);
03219     rb_lastline_set(str);
03220 
03221     return str;
03222 }
03223 
03224 /*
03225  *  call-seq:
03226  *     ios.lineno    -> integer
03227  *
03228  *  Returns the current line number in <em>ios</em>.  The stream must be
03229  *  opened for reading. <code>lineno</code> counts the number of times
03230  *  #gets is called rather than the number of newlines encountered.  The two
03231  *  values will differ if #gets is called with a separator other than newline.
03232  *
03233  *  Methods that use <code>$/</code> like #each, #lines and #readline will
03234  *  also increment <code>lineno</code>.
03235  *
03236  *  See also the <code>$.</code> variable.
03237  *
03238  *     f = File.new("testfile")
03239  *     f.lineno   #=> 0
03240  *     f.gets     #=> "This is line one\n"
03241  *     f.lineno   #=> 1
03242  *     f.gets     #=> "This is line two\n"
03243  *     f.lineno   #=> 2
03244  */
03245 
03246 static VALUE
03247 rb_io_lineno(VALUE io)
03248 {
03249     rb_io_t *fptr;
03250 
03251     GetOpenFile(io, fptr);
03252     rb_io_check_char_readable(fptr);
03253     return INT2NUM(fptr->lineno);
03254 }
03255 
03256 /*
03257  *  call-seq:
03258  *     ios.lineno = integer    -> integer
03259  *
03260  *  Manually sets the current line number to the given value.
03261  *  <code>$.</code> is updated only on the next read.
03262  *
03263  *     f = File.new("testfile")
03264  *     f.gets                     #=> "This is line one\n"
03265  *     $.                         #=> 1
03266  *     f.lineno = 1000
03267  *     f.lineno                   #=> 1000
03268  *     $.                         #=> 1         # lineno of last read
03269  *     f.gets                     #=> "This is line two\n"
03270  *     $.                         #=> 1001      # lineno of last read
03271  */
03272 
03273 static VALUE
03274 rb_io_set_lineno(VALUE io, VALUE lineno)
03275 {
03276     rb_io_t *fptr;
03277 
03278     GetOpenFile(io, fptr);
03279     rb_io_check_char_readable(fptr);
03280     fptr->lineno = NUM2INT(lineno);
03281     return lineno;
03282 }
03283 
03284 /*
03285  *  call-seq:
03286  *     ios.readline(sep=$/)     -> string
03287  *     ios.readline(limit)      -> string
03288  *     ios.readline(sep, limit) -> string
03289  *
03290  *  Reads a line as with <code>IO#gets</code>, but raises an
03291  *  <code>EOFError</code> on end of file.
03292  */
03293 
03294 static VALUE
03295 rb_io_readline(int argc, VALUE *argv, VALUE io)
03296 {
03297     VALUE line = rb_io_gets_m(argc, argv, io);
03298 
03299     if (NIL_P(line)) {
03300         rb_eof_error();
03301     }
03302     return line;
03303 }
03304 
03305 /*
03306  *  call-seq:
03307  *     ios.readlines(sep=$/)     -> array
03308  *     ios.readlines(limit)      -> array
03309  *     ios.readlines(sep, limit) -> array
03310  *
03311  *  Reads all of the lines in <em>ios</em>, and returns them in
03312  *  <i>anArray</i>. Lines are separated by the optional <i>sep</i>. If
03313  *  <i>sep</i> is <code>nil</code>, the rest of the stream is returned
03314  *  as a single record.  If the first argument is an integer, or
03315  *  optional second argument is given, the returning string would not be
03316  *  longer than the given value in bytes. The stream must be opened for
03317  *  reading or an <code>IOError</code> will be raised.
03318  *
03319  *     f = File.new("testfile")
03320  *     f.readlines[0]   #=> "This is line one\n"
03321  */
03322 
03323 static VALUE
03324 rb_io_readlines(int argc, VALUE *argv, VALUE io)
03325 {
03326     VALUE line, ary, rs;
03327     long limit;
03328 
03329     prepare_getline_args(argc, argv, &rs, &limit, io);
03330     if (limit == 0)
03331         rb_raise(rb_eArgError, "invalid limit: 0 for readlines");
03332     ary = rb_ary_new();
03333     while (!NIL_P(line = rb_io_getline_1(rs, limit, io))) {
03334         rb_ary_push(ary, line);
03335     }
03336     return ary;
03337 }
03338 
03339 /*
03340  *  call-seq:
03341  *     ios.each(sep=$/) {|line| block }         -> ios
03342  *     ios.each(limit) {|line| block }          -> ios
03343  *     ios.each(sep,limit) {|line| block }      -> ios
03344  *     ios.each(...)                            -> an_enumerator
03345  *
03346  *     ios.each_line(sep=$/) {|line| block }    -> ios
03347  *     ios.each_line(limit) {|line| block }     -> ios
03348  *     ios.each_line(sep,limit) {|line| block } -> ios
03349  *     ios.each_line(...)                       -> an_enumerator
03350  *
03351  *  Executes the block for every line in <em>ios</em>, where lines are
03352  *  separated by <i>sep</i>. <em>ios</em> must be opened for
03353  *  reading or an <code>IOError</code> will be raised.
03354  *
03355  *  If no block is given, an enumerator is returned instead.
03356  *
03357  *     f = File.new("testfile")
03358  *     f.each {|line| puts "#{f.lineno}: #{line}" }
03359  *
03360  *  <em>produces:</em>
03361  *
03362  *     1: This is line one
03363  *     2: This is line two
03364  *     3: This is line three
03365  *     4: And so on...
03366  */
03367 
03368 static VALUE
03369 rb_io_each_line(int argc, VALUE *argv, VALUE io)
03370 {
03371     VALUE str, rs;
03372     long limit;
03373 
03374     RETURN_ENUMERATOR(io, argc, argv);
03375     prepare_getline_args(argc, argv, &rs, &limit, io);
03376     if (limit == 0)
03377         rb_raise(rb_eArgError, "invalid limit: 0 for each_line");
03378     while (!NIL_P(str = rb_io_getline_1(rs, limit, io))) {
03379         rb_yield(str);
03380     }
03381     return io;
03382 }
03383 
03384 /*
03385  *  This is a deprecated alias for <code>each_line</code>.
03386  */
03387 
03388 static VALUE
03389 rb_io_lines(int argc, VALUE *argv, VALUE io)
03390 {
03391     rb_warn("IO#lines is deprecated; use #each_line instead");
03392     if (!rb_block_given_p())
03393         return rb_enumeratorize(io, ID2SYM(rb_intern("each_line")), argc, argv);
03394     return rb_io_each_line(argc, argv, io);
03395 }
03396 
03397 /*
03398  *  call-seq:
03399  *     ios.each_byte {|byte| block }  -> ios
03400  *     ios.each_byte                  -> an_enumerator
03401  *
03402  *  Calls the given block once for each byte (0..255) in <em>ios</em>,
03403  *  passing the byte as an argument. The stream must be opened for
03404  *  reading or an <code>IOError</code> will be raised.
03405  *
03406  *  If no block is given, an enumerator is returned instead.
03407  *
03408  *     f = File.new("testfile")
03409  *     checksum = 0
03410  *     f.each_byte {|x| checksum ^= x }   #=> #<File:testfile>
03411  *     checksum                           #=> 12
03412  */
03413 
03414 static VALUE
03415 rb_io_each_byte(VALUE io)
03416 {
03417     rb_io_t *fptr;
03418 
03419     RETURN_ENUMERATOR(io, 0, 0);
03420     GetOpenFile(io, fptr);
03421 
03422     do {
03423         while (fptr->rbuf.len > 0) {
03424             char *p = fptr->rbuf.ptr + fptr->rbuf.off++;
03425             fptr->rbuf.len--;
03426             rb_yield(INT2FIX(*p & 0xff));
03427             errno = 0;
03428         }
03429         rb_io_check_byte_readable(fptr);
03430         READ_CHECK(fptr);
03431     } while (io_fillbuf(fptr) >= 0);
03432     return io;
03433 }
03434 
03435 /*
03436  *  This is a deprecated alias for <code>each_byte</code>.
03437  */
03438 
03439 static VALUE
03440 rb_io_bytes(VALUE io)
03441 {
03442     rb_warn("IO#bytes is deprecated; use #each_byte instead");
03443     if (!rb_block_given_p())
03444         return rb_enumeratorize(io, ID2SYM(rb_intern("each_byte")), 0, 0);
03445     return rb_io_each_byte(io);
03446 }
03447 
03448 static VALUE
03449 io_getc(rb_io_t *fptr, rb_encoding *enc)
03450 {
03451     int r, n, cr = 0;
03452     VALUE str;
03453 
03454     if (NEED_READCONV(fptr)) {
03455         VALUE str = Qnil;
03456         rb_encoding *read_enc = io_read_encoding(fptr);
03457 
03458         SET_BINARY_MODE(fptr);
03459         make_readconv(fptr, 0);
03460 
03461         while (1) {
03462             if (fptr->cbuf.len) {
03463                 r = rb_enc_precise_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
03464                         fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
03465                         read_enc);
03466                 if (!MBCLEN_NEEDMORE_P(r))
03467                     break;
03468                 if (fptr->cbuf.len == fptr->cbuf.capa) {
03469                     rb_raise(rb_eIOError, "too long character");
03470                 }
03471             }
03472 
03473             if (more_char(fptr) == MORE_CHAR_FINISHED) {
03474                 if (fptr->cbuf.len == 0) {
03475                     clear_readconv(fptr);
03476                     return Qnil;
03477                 }
03478                 /* return an unit of an incomplete character just before EOF */
03479                 str = rb_enc_str_new(fptr->cbuf.ptr+fptr->cbuf.off, 1, read_enc);
03480                 fptr->cbuf.off += 1;
03481                 fptr->cbuf.len -= 1;
03482                 if (fptr->cbuf.len == 0) clear_readconv(fptr);
03483                 ENC_CODERANGE_SET(str, ENC_CODERANGE_BROKEN);
03484                 return str;
03485             }
03486         }
03487         if (MBCLEN_INVALID_P(r)) {
03488             r = rb_enc_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
03489                               fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
03490                               read_enc);
03491             io_shift_cbuf(fptr, r, &str);
03492             cr = ENC_CODERANGE_BROKEN;
03493         }
03494         else {
03495             io_shift_cbuf(fptr, MBCLEN_CHARFOUND_LEN(r), &str);
03496             cr = ENC_CODERANGE_VALID;
03497             if (MBCLEN_CHARFOUND_LEN(r) == 1 && rb_enc_asciicompat(read_enc) &&
03498                 ISASCII(RSTRING_PTR(str)[0])) {
03499                 cr = ENC_CODERANGE_7BIT;
03500             }
03501         }
03502         str = io_enc_str(str, fptr);
03503         ENC_CODERANGE_SET(str, cr);
03504         return str;
03505     }
03506 
03507     NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
03508     if (io_fillbuf(fptr) < 0) {
03509         return Qnil;
03510     }
03511     if (rb_enc_asciicompat(enc) && ISASCII(fptr->rbuf.ptr[fptr->rbuf.off])) {
03512         str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, 1);
03513         fptr->rbuf.off += 1;
03514         fptr->rbuf.len -= 1;
03515         cr = ENC_CODERANGE_7BIT;
03516     }
03517     else {
03518         r = rb_enc_precise_mbclen(fptr->rbuf.ptr+fptr->rbuf.off, fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
03519         if (MBCLEN_CHARFOUND_P(r) &&
03520             (n = MBCLEN_CHARFOUND_LEN(r)) <= fptr->rbuf.len) {
03521             str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, n);
03522             fptr->rbuf.off += n;
03523             fptr->rbuf.len -= n;
03524             cr = ENC_CODERANGE_VALID;
03525         }
03526         else if (MBCLEN_NEEDMORE_P(r)) {
03527             str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, fptr->rbuf.len);
03528             fptr->rbuf.len = 0;
03529           getc_needmore:
03530             if (io_fillbuf(fptr) != -1) {
03531                 rb_str_cat(str, fptr->rbuf.ptr+fptr->rbuf.off, 1);
03532                 fptr->rbuf.off++;
03533                 fptr->rbuf.len--;
03534                 r = rb_enc_precise_mbclen(RSTRING_PTR(str), RSTRING_PTR(str)+RSTRING_LEN(str), enc);
03535                 if (MBCLEN_NEEDMORE_P(r)) {
03536                     goto getc_needmore;
03537                 }
03538                 else if (MBCLEN_CHARFOUND_P(r)) {
03539                     cr = ENC_CODERANGE_VALID;
03540                 }
03541             }
03542         }
03543         else {
03544             str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, 1);
03545             fptr->rbuf.off++;
03546             fptr->rbuf.len--;
03547         }
03548     }
03549     if (!cr) cr = ENC_CODERANGE_BROKEN;
03550     str = io_enc_str(str, fptr);
03551     ENC_CODERANGE_SET(str, cr);
03552     return str;
03553 }
03554 
03555 /*
03556  *  call-seq:
03557  *     ios.each_char {|c| block }  -> ios
03558  *     ios.each_char               -> an_enumerator
03559  *
03560  *  Calls the given block once for each character in <em>ios</em>,
03561  *  passing the character as an argument. The stream must be opened for
03562  *  reading or an <code>IOError</code> will be raised.
03563  *
03564  *  If no block is given, an enumerator is returned instead.
03565  *
03566  *     f = File.new("testfile")
03567  *     f.each_char {|c| print c, ' ' }   #=> #<File:testfile>
03568  */
03569 
03570 static VALUE
03571 rb_io_each_char(VALUE io)
03572 {
03573     rb_io_t *fptr;
03574     rb_encoding *enc;
03575     VALUE c;
03576 
03577     RETURN_ENUMERATOR(io, 0, 0);
03578     GetOpenFile(io, fptr);
03579     rb_io_check_char_readable(fptr);
03580 
03581     enc = io_input_encoding(fptr);
03582     READ_CHECK(fptr);
03583     while (!NIL_P(c = io_getc(fptr, enc))) {
03584         rb_yield(c);
03585     }
03586     return io;
03587 }
03588 
03589 /*
03590  *  This is a deprecated alias for <code>each_char</code>.
03591  */
03592 
03593 static VALUE
03594 rb_io_chars(VALUE io)
03595 {
03596     rb_warn("IO#chars is deprecated; use #each_char instead");
03597     if (!rb_block_given_p())
03598         return rb_enumeratorize(io, ID2SYM(rb_intern("each_char")), 0, 0);
03599     return rb_io_each_char(io);
03600 }
03601 
03602 
03603 /*
03604  *  call-seq:
03605  *     ios.each_codepoint {|c| block }  -> ios
03606  *     ios.codepoints     {|c| block }  -> ios
03607  *     ios.each_codepoint               -> an_enumerator
03608  *     ios.codepoints                   -> an_enumerator
03609  *
03610  *  Passes the <code>Integer</code> ordinal of each character in <i>ios</i>,
03611  *  passing the codepoint as an argument. The stream must be opened for
03612  *  reading or an <code>IOError</code> will be raised.
03613  *
03614  *  If no block is given, an enumerator is returned instead.
03615  *
03616  */
03617 
03618 static VALUE
03619 rb_io_each_codepoint(VALUE io)
03620 {
03621     rb_io_t *fptr;
03622     rb_encoding *enc;
03623     unsigned int c;
03624     int r, n;
03625 
03626     RETURN_ENUMERATOR(io, 0, 0);
03627     GetOpenFile(io, fptr);
03628     rb_io_check_char_readable(fptr);
03629 
03630     READ_CHECK(fptr);
03631     if (NEED_READCONV(fptr)) {
03632         SET_BINARY_MODE(fptr);
03633         for (;;) {
03634             make_readconv(fptr, 0);
03635             for (;;) {
03636                 if (fptr->cbuf.len) {
03637                     if (fptr->encs.enc)
03638                         r = rb_enc_precise_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
03639                                                   fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
03640                                                   fptr->encs.enc);
03641                     else
03642                         r = ONIGENC_CONSTRUCT_MBCLEN_CHARFOUND(1);
03643                     if (!MBCLEN_NEEDMORE_P(r))
03644                         break;
03645                     if (fptr->cbuf.len == fptr->cbuf.capa) {
03646                         rb_raise(rb_eIOError, "too long character");
03647                     }
03648                 }
03649                 if (more_char(fptr) == MORE_CHAR_FINISHED) {
03650                     clear_readconv(fptr);
03651                     /* ignore an incomplete character before EOF */
03652                     return io;
03653                 }
03654             }
03655             if (MBCLEN_INVALID_P(r)) {
03656                 rb_raise(rb_eArgError, "invalid byte sequence in %s",
03657                          rb_enc_name(fptr->encs.enc));
03658             }
03659             n = MBCLEN_CHARFOUND_LEN(r);
03660             if (fptr->encs.enc) {
03661                 c = rb_enc_codepoint(fptr->cbuf.ptr+fptr->cbuf.off,
03662                                      fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
03663                                      fptr->encs.enc);
03664             }
03665             else {
03666                 c = (unsigned char)fptr->cbuf.ptr[fptr->cbuf.off];
03667             }
03668             fptr->cbuf.off += n;
03669             fptr->cbuf.len -= n;
03670             rb_yield(UINT2NUM(c));
03671         }
03672     }
03673     NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
03674     enc = io_input_encoding(fptr);
03675     while (io_fillbuf(fptr) >= 0) {
03676         r = rb_enc_precise_mbclen(fptr->rbuf.ptr+fptr->rbuf.off,
03677                                   fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
03678         if (MBCLEN_CHARFOUND_P(r) &&
03679             (n = MBCLEN_CHARFOUND_LEN(r)) <= fptr->rbuf.len) {
03680             c = rb_enc_codepoint(fptr->rbuf.ptr+fptr->rbuf.off,
03681                                  fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
03682             fptr->rbuf.off += n;
03683             fptr->rbuf.len -= n;
03684             rb_yield(UINT2NUM(c));
03685         }
03686         else if (MBCLEN_INVALID_P(r)) {
03687             rb_raise(rb_eArgError, "invalid byte sequence in %s", rb_enc_name(enc));
03688         }
03689         else {
03690             continue;
03691         }
03692     }
03693     return io;
03694 }
03695 
03696 /*
03697  *  This is a deprecated alias for <code>each_codepoint</code>.
03698  */
03699 
03700 static VALUE
03701 rb_io_codepoints(VALUE io)
03702 {
03703     rb_warn("IO#codepoints is deprecated; use #each_codepoint instead");
03704     if (!rb_block_given_p())
03705         return rb_enumeratorize(io, ID2SYM(rb_intern("each_codepoint")), 0, 0);
03706     return rb_io_each_codepoint(io);
03707 }
03708 
03709 
03710 /*
03711  *  call-seq:
03712  *     ios.getc   -> string or nil
03713  *
03714  *  Reads a one-character string from <em>ios</em>. Returns
03715  *  <code>nil</code> if called at end of file.
03716  *
03717  *     f = File.new("testfile")
03718  *     f.getc   #=> "h"
03719  *     f.getc   #=> "e"
03720  */
03721 
03722 static VALUE
03723 rb_io_getc(VALUE io)
03724 {
03725     rb_io_t *fptr;
03726     rb_encoding *enc;
03727 
03728     GetOpenFile(io, fptr);
03729     rb_io_check_char_readable(fptr);
03730 
03731     enc = io_input_encoding(fptr);
03732     READ_CHECK(fptr);
03733     return io_getc(fptr, enc);
03734 }
03735 
03736 /*
03737  *  call-seq:
03738  *     ios.readchar   -> string
03739  *
03740  *  Reads a one-character string from <em>ios</em>. Raises an
03741  *  <code>EOFError</code> on end of file.
03742  *
03743  *     f = File.new("testfile")
03744  *     f.readchar   #=> "h"
03745  *     f.readchar   #=> "e"
03746  */
03747 
03748 static VALUE
03749 rb_io_readchar(VALUE io)
03750 {
03751     VALUE c = rb_io_getc(io);
03752 
03753     if (NIL_P(c)) {
03754         rb_eof_error();
03755     }
03756     return c;
03757 }
03758 
03759 /*
03760  *  call-seq:
03761  *     ios.getbyte   -> fixnum or nil
03762  *
03763  *  Gets the next 8-bit byte (0..255) from <em>ios</em>. Returns
03764  *  <code>nil</code> if called at end of file.
03765  *
03766  *     f = File.new("testfile")
03767  *     f.getbyte   #=> 84
03768  *     f.getbyte   #=> 104
03769  */
03770 
03771 VALUE
03772 rb_io_getbyte(VALUE io)
03773 {
03774     rb_io_t *fptr;
03775     int c;
03776 
03777     GetOpenFile(io, fptr);
03778     rb_io_check_byte_readable(fptr);
03779     READ_CHECK(fptr);
03780     if (fptr->fd == 0 && (fptr->mode & FMODE_TTY) && RB_TYPE_P(rb_stdout, T_FILE)) {
03781         rb_io_t *ofp;
03782         GetOpenFile(rb_stdout, ofp);
03783         if (ofp->mode & FMODE_TTY) {
03784             rb_io_flush(rb_stdout);
03785         }
03786     }
03787     if (io_fillbuf(fptr) < 0) {
03788         return Qnil;
03789     }
03790     fptr->rbuf.off++;
03791     fptr->rbuf.len--;
03792     c = (unsigned char)fptr->rbuf.ptr[fptr->rbuf.off-1];
03793     return INT2FIX(c & 0xff);
03794 }
03795 
03796 /*
03797  *  call-seq:
03798  *     ios.readbyte   -> fixnum
03799  *
03800  *  Reads a byte as with <code>IO#getbyte</code>, but raises an
03801  *  <code>EOFError</code> on end of file.
03802  */
03803 
03804 static VALUE
03805 rb_io_readbyte(VALUE io)
03806 {
03807     VALUE c = rb_io_getbyte(io);
03808 
03809     if (NIL_P(c)) {
03810         rb_eof_error();
03811     }
03812     return c;
03813 }
03814 
03815 /*
03816  *  call-seq:
03817  *     ios.ungetbyte(string)   -> nil
03818  *     ios.ungetbyte(integer)   -> nil
03819  *
03820  *  Pushes back bytes (passed as a parameter) onto <em>ios</em>,
03821  *  such that a subsequent buffered read will return it. Only one byte
03822  *  may be pushed back before a subsequent read operation (that is,
03823  *  you will be able to read only the last of several bytes that have been pushed
03824  *  back). Has no effect with unbuffered reads (such as <code>IO#sysread</code>).
03825  *
03826  *     f = File.new("testfile")   #=> #<File:testfile>
03827  *     b = f.getbyte              #=> 0x38
03828  *     f.ungetbyte(b)             #=> nil
03829  *     f.getbyte                  #=> 0x38
03830  */
03831 
03832 VALUE
03833 rb_io_ungetbyte(VALUE io, VALUE b)
03834 {
03835     rb_io_t *fptr;
03836 
03837     GetOpenFile(io, fptr);
03838     rb_io_check_byte_readable(fptr);
03839     if (NIL_P(b)) return Qnil;
03840     if (FIXNUM_P(b)) {
03841         char cc = FIX2INT(b);
03842         b = rb_str_new(&cc, 1);
03843     }
03844     else {
03845         SafeStringValue(b);
03846     }
03847     io_ungetbyte(b, fptr);
03848     return Qnil;
03849 }
03850 
03851 /*
03852  *  call-seq:
03853  *     ios.ungetc(string)   -> nil
03854  *
03855  *  Pushes back one character (passed as a parameter) onto <em>ios</em>,
03856  *  such that a subsequent buffered character read will return it. Only one character
03857  *  may be pushed back before a subsequent read operation (that is,
03858  *  you will be able to read only the last of several characters that have been pushed
03859  *  back). Has no effect with unbuffered reads (such as <code>IO#sysread</code>).
03860  *
03861  *     f = File.new("testfile")   #=> #<File:testfile>
03862  *     c = f.getc                 #=> "8"
03863  *     f.ungetc(c)                #=> nil
03864  *     f.getc                     #=> "8"
03865  */
03866 
03867 VALUE
03868 rb_io_ungetc(VALUE io, VALUE c)
03869 {
03870     rb_io_t *fptr;
03871     long len;
03872 
03873     GetOpenFile(io, fptr);
03874     rb_io_check_char_readable(fptr);
03875     if (NIL_P(c)) return Qnil;
03876     if (FIXNUM_P(c)) {
03877         c = rb_enc_uint_chr(FIX2UINT(c), io_read_encoding(fptr));
03878     }
03879     else if (RB_TYPE_P(c, T_BIGNUM)) {
03880         c = rb_enc_uint_chr(NUM2UINT(c), io_read_encoding(fptr));
03881     }
03882     else {
03883         SafeStringValue(c);
03884     }
03885     if (NEED_READCONV(fptr)) {
03886         SET_BINARY_MODE(fptr);
03887         len = RSTRING_LEN(c);
03888 #if SIZEOF_LONG > SIZEOF_INT
03889         if (len > INT_MAX)
03890             rb_raise(rb_eIOError, "ungetc failed");
03891 #endif
03892         make_readconv(fptr, (int)len);
03893         if (fptr->cbuf.capa - fptr->cbuf.len < len)
03894             rb_raise(rb_eIOError, "ungetc failed");
03895         if (fptr->cbuf.off < len) {
03896             MEMMOVE(fptr->cbuf.ptr+fptr->cbuf.capa-fptr->cbuf.len,
03897                     fptr->cbuf.ptr+fptr->cbuf.off,
03898                     char, fptr->cbuf.len);
03899             fptr->cbuf.off = fptr->cbuf.capa-fptr->cbuf.len;
03900         }
03901         fptr->cbuf.off -= (int)len;
03902         fptr->cbuf.len += (int)len;
03903         MEMMOVE(fptr->cbuf.ptr+fptr->cbuf.off, RSTRING_PTR(c), char, len);
03904     }
03905     else {
03906         NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
03907         io_ungetbyte(c, fptr);
03908     }
03909     return Qnil;
03910 }
03911 
03912 /*
03913  *  call-seq:
03914  *     ios.isatty   -> true or false
03915  *     ios.tty?     -> true or false
03916  *
03917  *  Returns <code>true</code> if <em>ios</em> is associated with a
03918  *  terminal device (tty), <code>false</code> otherwise.
03919  *
03920  *     File.new("testfile").isatty   #=> false
03921  *     File.new("/dev/tty").isatty   #=> true
03922  */
03923 
03924 static VALUE
03925 rb_io_isatty(VALUE io)
03926 {
03927     rb_io_t *fptr;
03928 
03929     GetOpenFile(io, fptr);
03930     if (isatty(fptr->fd) == 0)
03931         return Qfalse;
03932     return Qtrue;
03933 }
03934 
03935 #if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
03936 /*
03937  *  call-seq:
03938  *     ios.close_on_exec?   -> true or false
03939  *
03940  *  Returns <code>true</code> if <em>ios</em> will be closed on exec.
03941  *
03942  *     f = open("/dev/null")
03943  *     f.close_on_exec?                 #=> false
03944  *     f.close_on_exec = true
03945  *     f.close_on_exec?                 #=> true
03946  *     f.close_on_exec = false
03947  *     f.close_on_exec?                 #=> false
03948  */
03949 
03950 static VALUE
03951 rb_io_close_on_exec_p(VALUE io)
03952 {
03953     rb_io_t *fptr;
03954     VALUE write_io;
03955     int fd, ret;
03956 
03957     write_io = GetWriteIO(io);
03958     if (io != write_io) {
03959         GetOpenFile(write_io, fptr);
03960         if (fptr && 0 <= (fd = fptr->fd)) {
03961             if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
03962             if (!(ret & FD_CLOEXEC)) return Qfalse;
03963         }
03964     }
03965 
03966     GetOpenFile(io, fptr);
03967     if (fptr && 0 <= (fd = fptr->fd)) {
03968         if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
03969         if (!(ret & FD_CLOEXEC)) return Qfalse;
03970     }
03971     return Qtrue;
03972 }
03973 #else
03974 #define rb_io_close_on_exec_p rb_f_notimplement
03975 #endif
03976 
03977 #if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
03978 /*
03979  *  call-seq:
03980  *     ios.close_on_exec = bool    -> true or false
03981  *
03982  *  Sets a close-on-exec flag.
03983  *
03984  *     f = open("/dev/null")
03985  *     f.close_on_exec = true
03986  *     system("cat", "/proc/self/fd/#{f.fileno}") # cat: /proc/self/fd/3: No such file or directory
03987  *     f.closed?                #=> false
03988  *
03989  *  Ruby sets close-on-exec flags of all file descriptors by default
03990  *  since Ruby 2.0.0.
03991  *  So you don't need to set by yourself.
03992  *  Also, unsetting a close-on-exec flag can cause file descriptor leak
03993  *  if another thread use fork() and exec() (via system() method for example).
03994  *  If you really needs file descriptor inheritance to child process,
03995  *  use spawn()'s argument such as fd=>fd.
03996  */
03997 
03998 static VALUE
03999 rb_io_set_close_on_exec(VALUE io, VALUE arg)
04000 {
04001     int flag = RTEST(arg) ? FD_CLOEXEC : 0;
04002     rb_io_t *fptr;
04003     VALUE write_io;
04004     int fd, ret;
04005 
04006     write_io = GetWriteIO(io);
04007     if (io != write_io) {
04008         GetOpenFile(write_io, fptr);
04009         if (fptr && 0 <= (fd = fptr->fd)) {
04010             if ((ret = fcntl(fptr->fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
04011             if ((ret & FD_CLOEXEC) != flag) {
04012                 ret = (ret & ~FD_CLOEXEC) | flag;
04013                 ret = fcntl(fd, F_SETFD, ret);
04014                 if (ret == -1) rb_sys_fail_path(fptr->pathv);
04015             }
04016         }
04017 
04018     }
04019 
04020     GetOpenFile(io, fptr);
04021     if (fptr && 0 <= (fd = fptr->fd)) {
04022         if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
04023         if ((ret & FD_CLOEXEC) != flag) {
04024             ret = (ret & ~FD_CLOEXEC) | flag;
04025             ret = fcntl(fd, F_SETFD, ret);
04026             if (ret == -1) rb_sys_fail_path(fptr->pathv);
04027         }
04028     }
04029     return Qnil;
04030 }
04031 #else
04032 #define rb_io_set_close_on_exec rb_f_notimplement
04033 #endif
04034 
04035 #define FMODE_PREP (1<<16)
04036 #define IS_PREP_STDIO(f) ((f)->mode & FMODE_PREP)
04037 #define PREP_STDIO_NAME(f) (RSTRING_PTR((f)->pathv))
04038 
04039 static VALUE
04040 finish_writeconv(rb_io_t *fptr, int noalloc)
04041 {
04042     unsigned char *ds, *dp, *de;
04043     rb_econv_result_t res;
04044 
04045     if (!fptr->wbuf.ptr) {
04046         unsigned char buf[1024];
04047         long r;
04048 
04049         res = econv_destination_buffer_full;
04050         while (res == econv_destination_buffer_full) {
04051             ds = dp = buf;
04052             de = buf + sizeof(buf);
04053             res = rb_econv_convert(fptr->writeconv, NULL, NULL, &dp, de, 0);
04054             while (dp-ds) {
04055               retry:
04056                 if (fptr->write_lock && rb_mutex_owned_p(fptr->write_lock))
04057                     r = rb_write_internal2(fptr->fd, ds, dp-ds);
04058                 else
04059                     r = rb_write_internal(fptr->fd, ds, dp-ds);
04060                 if (r == dp-ds)
04061                     break;
04062                 if (0 <= r) {
04063                     ds += r;
04064                 }
04065                 if (rb_io_wait_writable(fptr->fd)) {
04066                     if (fptr->fd < 0)
04067                         return noalloc ? Qtrue : rb_exc_new3(rb_eIOError, rb_str_new_cstr(closed_stream));
04068                     goto retry;
04069                 }
04070                 return noalloc ? Qtrue : INT2NUM(errno);
04071             }
04072             if (res == econv_invalid_byte_sequence ||
04073                 res == econv_incomplete_input ||
04074                 res == econv_undefined_conversion) {
04075                 return noalloc ? Qtrue : rb_econv_make_exception(fptr->writeconv);
04076             }
04077         }
04078 
04079         return Qnil;
04080     }
04081 
04082     res = econv_destination_buffer_full;
04083     while (res == econv_destination_buffer_full) {
04084         if (fptr->wbuf.len == fptr->wbuf.capa) {
04085             if (io_fflush(fptr) < 0)
04086                 return noalloc ? Qtrue : INT2NUM(errno);
04087         }
04088 
04089         ds = dp = (unsigned char *)fptr->wbuf.ptr + fptr->wbuf.off + fptr->wbuf.len;
04090         de = (unsigned char *)fptr->wbuf.ptr + fptr->wbuf.capa;
04091         res = rb_econv_convert(fptr->writeconv, NULL, NULL, &dp, de, 0);
04092         fptr->wbuf.len += (int)(dp - ds);
04093         if (res == econv_invalid_byte_sequence ||
04094             res == econv_incomplete_input ||
04095             res == econv_undefined_conversion) {
04096             return noalloc ? Qtrue : rb_econv_make_exception(fptr->writeconv);
04097         }
04098     }
04099     return Qnil;
04100 }
04101 
04102 struct finish_writeconv_arg {
04103     rb_io_t *fptr;
04104     int noalloc;
04105 };
04106 
04107 static VALUE
04108 finish_writeconv_sync(VALUE arg)
04109 {
04110     struct finish_writeconv_arg *p = (struct finish_writeconv_arg *)arg;
04111     return finish_writeconv(p->fptr, p->noalloc);
04112 }
04113 
04114 static void*
04115 nogvl_close(void *ptr)
04116 {
04117     int *fd = ptr;
04118 
04119     return (void*)(intptr_t)close(*fd);
04120 }
04121 
04122 static int
04123 maygvl_close(int fd, int keepgvl)
04124 {
04125     if (keepgvl)
04126         return close(fd);
04127 
04128     /*
04129      * close() may block for certain file types (NFS, SO_LINGER sockets,
04130      * inotify), so let other threads run.
04131      */
04132     return (int)(intptr_t)rb_thread_call_without_gvl(nogvl_close, &fd, RUBY_UBF_IO, 0);
04133 }
04134 
04135 static void*
04136 nogvl_fclose(void *ptr)
04137 {
04138     FILE *file = ptr;
04139 
04140     return (void*)(intptr_t)fclose(file);
04141 }
04142 
04143 static int
04144 maygvl_fclose(FILE *file, int keepgvl)
04145 {
04146     if (keepgvl)
04147         return fclose(file);
04148 
04149     return (int)(intptr_t)rb_thread_call_without_gvl(nogvl_fclose, file, RUBY_UBF_IO, 0);
04150 }
04151 
04152 static void
04153 fptr_finalize(rb_io_t *fptr, int noraise)
04154 {
04155     VALUE err = Qnil;
04156     int fd = fptr->fd;
04157     FILE *stdio_file = fptr->stdio_file;
04158 
04159     if (fptr->writeconv) {
04160         if (fptr->write_lock && !noraise) {
04161             struct finish_writeconv_arg arg;
04162             arg.fptr = fptr;
04163             arg.noalloc = noraise;
04164             err = rb_mutex_synchronize(fptr->write_lock, finish_writeconv_sync, (VALUE)&arg);
04165         }
04166         else {
04167             err = finish_writeconv(fptr, noraise);
04168         }
04169     }
04170     if (fptr->wbuf.len) {
04171         if (noraise) {
04172             if ((int)io_flush_buffer_sync(fptr) < 0 && NIL_P(err))
04173                 err = Qtrue;
04174         }
04175         else {
04176             if (io_fflush(fptr) < 0 && NIL_P(err))
04177                 err = INT2NUM(errno);
04178         }
04179     }
04180 
04181     fptr->fd = -1;
04182     fptr->stdio_file = 0;
04183     fptr->mode &= ~(FMODE_READABLE|FMODE_WRITABLE);
04184 
04185     if (IS_PREP_STDIO(fptr) || fd <= 2) {
04186         /* need to keep FILE objects of stdin, stdout and stderr */
04187     }
04188     else if (stdio_file) {
04189         /* stdio_file is deallocated anyway
04190          * even if fclose failed.  */
04191         if ((maygvl_fclose(stdio_file, noraise) < 0) && NIL_P(err))
04192             err = noraise ? Qtrue : INT2NUM(errno);
04193     }
04194     else if (0 <= fd) {
04195         /* fptr->fd may be closed even if close fails.
04196          * POSIX doesn't specify it.
04197          * We assumes it is closed.  */
04198         if ((maygvl_close(fd, noraise) < 0) && NIL_P(err))
04199             err = noraise ? Qtrue : INT2NUM(errno);
04200     }
04201 
04202     if (!NIL_P(err) && !noraise) {
04203         switch (TYPE(err)) {
04204           case T_FIXNUM:
04205           case T_BIGNUM:
04206             errno = NUM2INT(err);
04207             rb_sys_fail_path(fptr->pathv);
04208 
04209           default:
04210             rb_exc_raise(err);
04211         }
04212     }
04213 }
04214 
04215 static void
04216 rb_io_fptr_cleanup(rb_io_t *fptr, int noraise)
04217 {
04218     if (fptr->finalize) {
04219         (*fptr->finalize)(fptr, noraise);
04220     }
04221     else {
04222         fptr_finalize(fptr, noraise);
04223     }
04224 }
04225 
04226 static void
04227 clear_readconv(rb_io_t *fptr)
04228 {
04229     if (fptr->readconv) {
04230         rb_econv_close(fptr->readconv);
04231         fptr->readconv = NULL;
04232     }
04233     if (fptr->cbuf.ptr) {
04234         free(fptr->cbuf.ptr);
04235         fptr->cbuf.ptr = NULL;
04236     }
04237 }
04238 
04239 static void
04240 clear_writeconv(rb_io_t *fptr)
04241 {
04242     if (fptr->writeconv) {
04243         rb_econv_close(fptr->writeconv);
04244         fptr->writeconv = NULL;
04245     }
04246     fptr->writeconv_initialized = 0;
04247 }
04248 
04249 static void
04250 clear_codeconv(rb_io_t *fptr)
04251 {
04252     clear_readconv(fptr);
04253     clear_writeconv(fptr);
04254 }
04255 
04256 int
04257 rb_io_fptr_finalize(rb_io_t *fptr)
04258 {
04259     if (!fptr) return 0;
04260     fptr->pathv = Qnil;
04261     if (0 <= fptr->fd)
04262         rb_io_fptr_cleanup(fptr, TRUE);
04263     fptr->write_lock = 0;
04264     if (fptr->rbuf.ptr) {
04265         free(fptr->rbuf.ptr);
04266         fptr->rbuf.ptr = 0;
04267     }
04268     if (fptr->wbuf.ptr) {
04269         free(fptr->wbuf.ptr);
04270         fptr->wbuf.ptr = 0;
04271     }
04272     clear_codeconv(fptr);
04273     free(fptr);
04274     return 1;
04275 }
04276 
04277 size_t rb_econv_memsize(rb_econv_t *);
04278 
04279 RUBY_FUNC_EXPORTED size_t
04280 rb_io_memsize(const rb_io_t *fptr)
04281 {
04282     size_t size = sizeof(rb_io_t);
04283     size += fptr->rbuf.capa;
04284     size += fptr->wbuf.capa;
04285     size += fptr->cbuf.capa;
04286     if (fptr->readconv) size += rb_econv_memsize(fptr->readconv);
04287     if (fptr->writeconv) size += rb_econv_memsize(fptr->writeconv);
04288     return size;
04289 }
04290 
04291 VALUE
04292 rb_io_close(VALUE io)
04293 {
04294     rb_io_t *fptr;
04295     int fd;
04296     VALUE write_io;
04297     rb_io_t *write_fptr;
04298 
04299     write_io = GetWriteIO(io);
04300     if (io != write_io) {
04301         write_fptr = RFILE(write_io)->fptr;
04302         if (write_fptr && 0 <= write_fptr->fd) {
04303             rb_io_fptr_cleanup(write_fptr, TRUE);
04304         }
04305     }
04306 
04307     fptr = RFILE(io)->fptr;
04308     if (!fptr) return Qnil;
04309     if (fptr->fd < 0) return Qnil;
04310 
04311     fd = fptr->fd;
04312     rb_thread_fd_close(fd);
04313     rb_io_fptr_cleanup(fptr, FALSE);
04314 
04315     if (fptr->pid) {
04316         rb_last_status_clear();
04317         rb_syswait(fptr->pid);
04318         fptr->pid = 0;
04319     }
04320 
04321     return Qnil;
04322 }
04323 
04324 /*
04325  *  call-seq:
04326  *     ios.close   -> nil
04327  *
04328  *  Closes <em>ios</em> and flushes any pending writes to the operating
04329  *  system. The stream is unavailable for any further data operations;
04330  *  an <code>IOError</code> is raised if such an attempt is made. I/O
04331  *  streams are automatically closed when they are claimed by the
04332  *  garbage collector.
04333  *
04334  *  If <em>ios</em> is opened by <code>IO.popen</code>,
04335  *  <code>close</code> sets <code>$?</code>.
04336  */
04337 
04338 static VALUE
04339 rb_io_close_m(VALUE io)
04340 {
04341     rb_io_check_closed(RFILE(io)->fptr);
04342     rb_io_close(io);
04343     return Qnil;
04344 }
04345 
04346 static VALUE
04347 io_call_close(VALUE io)
04348 {
04349     rb_check_funcall(io, rb_intern("close"), 0, 0);
04350     return io;
04351 }
04352 
04353 static VALUE
04354 ignore_closed_stream(VALUE io, VALUE exc)
04355 {
04356     enum {mesg_len = sizeof(closed_stream)-1};
04357     VALUE mesg = rb_attr_get(exc, rb_intern("mesg"));
04358     if (!RB_TYPE_P(mesg, T_STRING) ||
04359         RSTRING_LEN(mesg) != mesg_len ||
04360         memcmp(RSTRING_PTR(mesg), closed_stream, mesg_len)) {
04361         rb_exc_raise(exc);
04362     }
04363     return io;
04364 }
04365 
04366 static VALUE
04367 io_close(VALUE io)
04368 {
04369     VALUE closed = rb_check_funcall(io, rb_intern("closed?"), 0, 0);
04370     if (closed != Qundef && RTEST(closed)) return io;
04371     rb_rescue2(io_call_close, io, ignore_closed_stream, io,
04372                rb_eIOError, (VALUE)0);
04373     return io;
04374 }
04375 
04376 /*
04377  *  call-seq:
04378  *     ios.closed?    -> true or false
04379  *
04380  *  Returns <code>true</code> if <em>ios</em> is completely closed (for
04381  *  duplex streams, both reader and writer), <code>false</code>
04382  *  otherwise.
04383  *
04384  *     f = File.new("testfile")
04385  *     f.close         #=> nil
04386  *     f.closed?       #=> true
04387  *     f = IO.popen("/bin/sh","r+")
04388  *     f.close_write   #=> nil
04389  *     f.closed?       #=> false
04390  *     f.close_read    #=> nil
04391  *     f.closed?       #=> true
04392  */
04393 
04394 
04395 static VALUE
04396 rb_io_closed(VALUE io)
04397 {
04398     rb_io_t *fptr;
04399     VALUE write_io;
04400     rb_io_t *write_fptr;
04401 
04402     write_io = GetWriteIO(io);
04403     if (io != write_io) {
04404         write_fptr = RFILE(write_io)->fptr;
04405         if (write_fptr && 0 <= write_fptr->fd) {
04406             return Qfalse;
04407         }
04408     }
04409 
04410     fptr = RFILE(io)->fptr;
04411     rb_io_check_initialized(fptr);
04412     return 0 <= fptr->fd ? Qfalse : Qtrue;
04413 }
04414 
04415 /*
04416  *  call-seq:
04417  *     ios.close_read    -> nil
04418  *
04419  *  Closes the read end of a duplex I/O stream (i.e., one that contains
04420  *  both a read and a write stream, such as a pipe). Will raise an
04421  *  <code>IOError</code> if the stream is not duplexed.
04422  *
04423  *     f = IO.popen("/bin/sh","r+")
04424  *     f.close_read
04425  *     f.readlines
04426  *
04427  *  <em>produces:</em>
04428  *
04429  *     prog.rb:3:in `readlines': not opened for reading (IOError)
04430  *      from prog.rb:3
04431  */
04432 
04433 static VALUE
04434 rb_io_close_read(VALUE io)
04435 {
04436     rb_io_t *fptr;
04437     VALUE write_io;
04438 
04439     GetOpenFile(io, fptr);
04440     if (is_socket(fptr->fd, fptr->pathv)) {
04441 #ifndef SHUT_RD
04442 # define SHUT_RD 0
04443 #endif
04444         if (shutdown(fptr->fd, SHUT_RD) < 0)
04445             rb_sys_fail_path(fptr->pathv);
04446         fptr->mode &= ~FMODE_READABLE;
04447         if (!(fptr->mode & FMODE_WRITABLE))
04448             return rb_io_close(io);
04449         return Qnil;
04450     }
04451 
04452     write_io = GetWriteIO(io);
04453     if (io != write_io) {
04454         rb_io_t *wfptr;
04455         GetOpenFile(write_io, wfptr);
04456         wfptr->pid = fptr->pid;
04457         fptr->pid = 0;
04458         RFILE(io)->fptr = wfptr;
04459         /* bind to write_io temporarily to get rid of memory/fd leak */
04460         fptr->tied_io_for_writing = 0;
04461         fptr->mode &= ~FMODE_DUPLEX;
04462         RFILE(write_io)->fptr = fptr;
04463         rb_io_fptr_cleanup(fptr, FALSE);
04464         /* should not finalize fptr because another thread may be reading it */
04465         return Qnil;
04466     }
04467 
04468     if (fptr->mode & FMODE_WRITABLE) {
04469         rb_raise(rb_eIOError, "closing non-duplex IO for reading");
04470     }
04471     return rb_io_close(io);
04472 }
04473 
04474 /*
04475  *  call-seq:
04476  *     ios.close_write   -> nil
04477  *
04478  *  Closes the write end of a duplex I/O stream (i.e., one that contains
04479  *  both a read and a write stream, such as a pipe). Will raise an
04480  *  <code>IOError</code> if the stream is not duplexed.
04481  *
04482  *     f = IO.popen("/bin/sh","r+")
04483  *     f.close_write
04484  *     f.print "nowhere"
04485  *
04486  *  <em>produces:</em>
04487  *
04488  *     prog.rb:3:in `write': not opened for writing (IOError)
04489  *      from prog.rb:3:in `print'
04490  *      from prog.rb:3
04491  */
04492 
04493 static VALUE
04494 rb_io_close_write(VALUE io)
04495 {
04496     rb_io_t *fptr;
04497     VALUE write_io;
04498 
04499     write_io = GetWriteIO(io);
04500     GetOpenFile(write_io, fptr);
04501     if (is_socket(fptr->fd, fptr->pathv)) {
04502 #ifndef SHUT_WR
04503 # define SHUT_WR 1
04504 #endif
04505         if (shutdown(fptr->fd, SHUT_WR) < 0)
04506             rb_sys_fail_path(fptr->pathv);
04507         fptr->mode &= ~FMODE_WRITABLE;
04508         if (!(fptr->mode & FMODE_READABLE))
04509             return rb_io_close(write_io);
04510         return Qnil;
04511     }
04512 
04513     if (fptr->mode & FMODE_READABLE) {
04514         rb_raise(rb_eIOError, "closing non-duplex IO for writing");
04515     }
04516 
04517     if (io != write_io) {
04518         GetOpenFile(io, fptr);
04519         fptr->tied_io_for_writing = 0;
04520         fptr->mode &= ~FMODE_DUPLEX;
04521     }
04522     rb_io_close(write_io);
04523     return Qnil;
04524 }
04525 
04526 /*
04527  *  call-seq:
04528  *     ios.sysseek(offset, whence=IO::SEEK_SET)   -> integer
04529  *
04530  *  Seeks to a given <i>offset</i> in the stream according to the value
04531  *  of <i>whence</i> (see <code>IO#seek</code> for values of
04532  *  <i>whence</i>). Returns the new offset into the file.
04533  *
04534  *     f = File.new("testfile")
04535  *     f.sysseek(-13, IO::SEEK_END)   #=> 53
04536  *     f.sysread(10)                  #=> "And so on."
04537  */
04538 
04539 static VALUE
04540 rb_io_sysseek(int argc, VALUE *argv, VALUE io)
04541 {
04542     VALUE offset, ptrname;
04543     int whence = SEEK_SET;
04544     rb_io_t *fptr;
04545     off_t pos;
04546 
04547     if (rb_scan_args(argc, argv, "11", &offset, &ptrname) == 2) {
04548         whence = interpret_seek_whence(ptrname);
04549     }
04550     pos = NUM2OFFT(offset);
04551     GetOpenFile(io, fptr);
04552     if ((fptr->mode & FMODE_READABLE) &&
04553         (READ_DATA_BUFFERED(fptr) || READ_CHAR_PENDING(fptr))) {
04554         rb_raise(rb_eIOError, "sysseek for buffered IO");
04555     }
04556     if ((fptr->mode & FMODE_WRITABLE) && fptr->wbuf.len) {
04557         rb_warn("sysseek for buffered IO");
04558     }
04559     errno = 0;
04560     pos = lseek(fptr->fd, pos, whence);
04561     if (pos == -1 && errno) rb_sys_fail_path(fptr->pathv);
04562 
04563     return OFFT2NUM(pos);
04564 }
04565 
04566 /*
04567  *  call-seq:
04568  *     ios.syswrite(string)   -> integer
04569  *
04570  *  Writes the given string to <em>ios</em> using a low-level write.
04571  *  Returns the number of bytes written. Do not mix with other methods
04572  *  that write to <em>ios</em> or you may get unpredictable results.
04573  *  Raises <code>SystemCallError</code> on error.
04574  *
04575  *     f = File.new("out", "w")
04576  *     f.syswrite("ABCDEF")   #=> 6
04577  */
04578 
04579 static VALUE
04580 rb_io_syswrite(VALUE io, VALUE str)
04581 {
04582     rb_io_t *fptr;
04583     long n;
04584 
04585     if (!RB_TYPE_P(str, T_STRING))
04586         str = rb_obj_as_string(str);
04587 
04588     io = GetWriteIO(io);
04589     GetOpenFile(io, fptr);
04590     rb_io_check_writable(fptr);
04591 
04592     str = rb_str_new_frozen(str);
04593 
04594     if (fptr->wbuf.len) {
04595         rb_warn("syswrite for buffered IO");
04596     }
04597 
04598     n = rb_write_internal(fptr->fd, RSTRING_PTR(str), RSTRING_LEN(str));
04599     RB_GC_GUARD(str);
04600 
04601     if (n == -1) rb_sys_fail_path(fptr->pathv);
04602 
04603     return LONG2FIX(n);
04604 }
04605 
04606 /*
04607  *  call-seq:
04608  *     ios.sysread(maxlen[, outbuf])    -> string
04609  *
04610  *  Reads <i>maxlen</i> bytes from <em>ios</em> using a low-level
04611  *  read and returns them as a string.  Do not mix with other methods
04612  *  that read from <em>ios</em> or you may get unpredictable results.
04613  *  If the optional <i>outbuf</i> argument is present, it must reference
04614  *  a String, which will receive the data.
04615  *  The <i>outbuf</i> will contain only the received data after the method call
04616  *  even if it is not empty at the beginning.
04617  *  Raises <code>SystemCallError</code> on error and
04618  *  <code>EOFError</code> at end of file.
04619  *
04620  *     f = File.new("testfile")
04621  *     f.sysread(16)   #=> "This is line one"
04622  */
04623 
04624 static VALUE
04625 rb_io_sysread(int argc, VALUE *argv, VALUE io)
04626 {
04627     VALUE len, str;
04628     rb_io_t *fptr;
04629     long n, ilen;
04630     struct read_internal_arg arg;
04631 
04632     rb_scan_args(argc, argv, "11", &len, &str);
04633     ilen = NUM2LONG(len);
04634 
04635     io_setstrbuf(&str,ilen);
04636     if (ilen == 0) return str;
04637 
04638     GetOpenFile(io, fptr);
04639     rb_io_check_byte_readable(fptr);
04640 
04641     if (READ_DATA_BUFFERED(fptr)) {
04642         rb_raise(rb_eIOError, "sysread for buffered IO");
04643     }
04644 
04645     n = fptr->fd;
04646 
04647     /*
04648      * FIXME: removing rb_thread_wait_fd() here changes sysread semantics
04649      * on non-blocking IOs.  However, it's still currently possible
04650      * for sysread to raise Errno::EAGAIN if another thread read()s
04651      * the IO after we return from rb_thread_wait_fd() but before
04652      * we call read()
04653      */
04654     rb_thread_wait_fd(fptr->fd);
04655 
04656     rb_io_check_closed(fptr);
04657 
04658     io_setstrbuf(&str, ilen);
04659     rb_str_locktmp(str);
04660     arg.fd = fptr->fd;
04661     arg.str_ptr = RSTRING_PTR(str);
04662     arg.len = ilen;
04663     rb_ensure(read_internal_call, (VALUE)&arg, rb_str_unlocktmp, str);
04664     n = arg.len;
04665 
04666     if (n == -1) {
04667         rb_sys_fail_path(fptr->pathv);
04668     }
04669     io_set_read_length(str, n);
04670     if (n == 0 && ilen > 0) {
04671         rb_eof_error();
04672     }
04673     OBJ_TAINT(str);
04674 
04675     return str;
04676 }
04677 
04678 VALUE
04679 rb_io_binmode(VALUE io)
04680 {
04681     rb_io_t *fptr;
04682 
04683     GetOpenFile(io, fptr);
04684     if (fptr->readconv)
04685         rb_econv_binmode(fptr->readconv);
04686     if (fptr->writeconv)
04687         rb_econv_binmode(fptr->writeconv);
04688     fptr->mode |= FMODE_BINMODE;
04689     fptr->mode &= ~FMODE_TEXTMODE;
04690     fptr->writeconv_pre_ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
04691 #ifdef O_BINARY
04692     if (!fptr->readconv) {
04693         SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
04694     }
04695     else {
04696         setmode(fptr->fd, O_BINARY);
04697     }
04698 #endif
04699     return io;
04700 }
04701 
04702 static void
04703 io_ascii8bit_binmode(rb_io_t *fptr)
04704 {
04705     if (fptr->readconv) {
04706         rb_econv_close(fptr->readconv);
04707         fptr->readconv = NULL;
04708     }
04709     if (fptr->writeconv) {
04710         rb_econv_close(fptr->writeconv);
04711         fptr->writeconv = NULL;
04712     }
04713     fptr->mode |= FMODE_BINMODE;
04714     fptr->mode &= ~FMODE_TEXTMODE;
04715     SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
04716 
04717     fptr->encs.enc = rb_ascii8bit_encoding();
04718     fptr->encs.enc2 = NULL;
04719     fptr->encs.ecflags = 0;
04720     fptr->encs.ecopts = Qnil;
04721     clear_codeconv(fptr);
04722 }
04723 
04724 VALUE
04725 rb_io_ascii8bit_binmode(VALUE io)
04726 {
04727     rb_io_t *fptr;
04728 
04729     GetOpenFile(io, fptr);
04730     io_ascii8bit_binmode(fptr);
04731 
04732     return io;
04733 }
04734 
04735 /*
04736  *  call-seq:
04737  *     ios.binmode    -> ios
04738  *
04739  *  Puts <em>ios</em> into binary mode.
04740  *  Once a stream is in binary mode, it cannot be reset to nonbinary mode.
04741  *
04742  *  - newline conversion disabled
04743  *  - encoding conversion disabled
04744  *  - content is treated as ASCII-8BIT
04745  *
04746  */
04747 
04748 static VALUE
04749 rb_io_binmode_m(VALUE io)
04750 {
04751     VALUE write_io;
04752 
04753     rb_io_ascii8bit_binmode(io);
04754 
04755     write_io = GetWriteIO(io);
04756     if (write_io != io)
04757         rb_io_ascii8bit_binmode(write_io);
04758     return io;
04759 }
04760 
04761 /*
04762  *  call-seq:
04763  *     ios.binmode?    -> true or false
04764  *
04765  *  Returns <code>true</code> if <em>ios</em> is binmode.
04766  */
04767 static VALUE
04768 rb_io_binmode_p(VALUE io)
04769 {
04770     rb_io_t *fptr;
04771     GetOpenFile(io, fptr);
04772     return fptr->mode & FMODE_BINMODE ? Qtrue : Qfalse;
04773 }
04774 
04775 static const char*
04776 rb_io_fmode_modestr(int fmode)
04777 {
04778     if (fmode & FMODE_APPEND) {
04779         if ((fmode & FMODE_READWRITE) == FMODE_READWRITE) {
04780             return MODE_BTMODE("a+", "ab+", "at+");
04781         }
04782         return MODE_BTMODE("a", "ab", "at");
04783     }
04784     switch (fmode & FMODE_READWRITE) {
04785       default:
04786         rb_raise(rb_eArgError, "invalid access fmode 0x%x", fmode);
04787       case FMODE_READABLE:
04788         return MODE_BTMODE("r", "rb", "rt");
04789       case FMODE_WRITABLE:
04790         return MODE_BTMODE("w", "wb", "wt");
04791       case FMODE_READWRITE:
04792         if (fmode & FMODE_CREATE) {
04793             return MODE_BTMODE("w+", "wb+", "wt+");
04794         }
04795         return MODE_BTMODE("r+", "rb+", "rt+");
04796     }
04797 }
04798 
04799 static int
04800 io_encname_bom_p(const char *name, long len)
04801 {
04802     static const char bom_prefix[] = "bom|utf-";
04803     enum {bom_prefix_len = (int)sizeof(bom_prefix) - 1};
04804     if (!len) {
04805         const char *p = strchr(name, ':');
04806         len = p ? (long)(p - name) : (long)strlen(name);
04807     }
04808     return len > bom_prefix_len && STRNCASECMP(name, bom_prefix, bom_prefix_len) == 0;
04809 }
04810 
04811 int
04812 rb_io_modestr_fmode(const char *modestr)
04813 {
04814     int fmode = 0;
04815     const char *m = modestr, *p = NULL;
04816 
04817     switch (*m++) {
04818       case 'r':
04819         fmode |= FMODE_READABLE;
04820         break;
04821       case 'w':
04822         fmode |= FMODE_WRITABLE | FMODE_TRUNC | FMODE_CREATE;
04823         break;
04824       case 'a':
04825         fmode |= FMODE_WRITABLE | FMODE_APPEND | FMODE_CREATE;
04826         break;
04827       default:
04828       error:
04829         rb_raise(rb_eArgError, "invalid access mode %s", modestr);
04830     }
04831 
04832     while (*m) {
04833         switch (*m++) {
04834           case 'b':
04835             fmode |= FMODE_BINMODE;
04836             break;
04837           case 't':
04838             fmode |= FMODE_TEXTMODE;
04839             break;
04840           case '+':
04841             fmode |= FMODE_READWRITE;
04842             break;
04843           default:
04844             goto error;
04845           case ':':
04846             p = m;
04847             goto finished;
04848         }
04849     }
04850 
04851   finished:
04852     if ((fmode & FMODE_BINMODE) && (fmode & FMODE_TEXTMODE))
04853         goto error;
04854     if (p && io_encname_bom_p(p, 0))
04855         fmode |= FMODE_SETENC_BY_BOM;
04856 
04857     return fmode;
04858 }
04859 
04860 int
04861 rb_io_oflags_fmode(int oflags)
04862 {
04863     int fmode = 0;
04864 
04865     switch (oflags & (O_RDONLY|O_WRONLY|O_RDWR)) {
04866       case O_RDONLY:
04867         fmode = FMODE_READABLE;
04868         break;
04869       case O_WRONLY:
04870         fmode = FMODE_WRITABLE;
04871         break;
04872       case O_RDWR:
04873         fmode = FMODE_READWRITE;
04874         break;
04875     }
04876 
04877     if (oflags & O_APPEND) {
04878         fmode |= FMODE_APPEND;
04879     }
04880     if (oflags & O_TRUNC) {
04881         fmode |= FMODE_TRUNC;
04882     }
04883     if (oflags & O_CREAT) {
04884         fmode |= FMODE_CREATE;
04885     }
04886 #ifdef O_BINARY
04887     if (oflags & O_BINARY) {
04888         fmode |= FMODE_BINMODE;
04889     }
04890 #endif
04891 
04892     return fmode;
04893 }
04894 
04895 static int
04896 rb_io_fmode_oflags(int fmode)
04897 {
04898     int oflags = 0;
04899 
04900     switch (fmode & FMODE_READWRITE) {
04901       case FMODE_READABLE:
04902         oflags |= O_RDONLY;
04903         break;
04904       case FMODE_WRITABLE:
04905         oflags |= O_WRONLY;
04906         break;
04907       case FMODE_READWRITE:
04908         oflags |= O_RDWR;
04909         break;
04910     }
04911 
04912     if (fmode & FMODE_APPEND) {
04913         oflags |= O_APPEND;
04914     }
04915     if (fmode & FMODE_TRUNC) {
04916         oflags |= O_TRUNC;
04917     }
04918     if (fmode & FMODE_CREATE) {
04919         oflags |= O_CREAT;
04920     }
04921 #ifdef O_BINARY
04922     if (fmode & FMODE_BINMODE) {
04923         oflags |= O_BINARY;
04924     }
04925 #endif
04926 
04927     return oflags;
04928 }
04929 
04930 int
04931 rb_io_modestr_oflags(const char *modestr)
04932 {
04933     return rb_io_fmode_oflags(rb_io_modestr_fmode(modestr));
04934 }
04935 
04936 static const char*
04937 rb_io_oflags_modestr(int oflags)
04938 {
04939 #ifdef O_BINARY
04940 # define MODE_BINARY(a,b) ((oflags & O_BINARY) ? (b) : (a))
04941 #else
04942 # define MODE_BINARY(a,b) (a)
04943 #endif
04944     int accmode = oflags & (O_RDONLY|O_WRONLY|O_RDWR);
04945     if (oflags & O_APPEND) {
04946         if (accmode == O_WRONLY) {
04947             return MODE_BINARY("a", "ab");
04948         }
04949         if (accmode == O_RDWR) {
04950             return MODE_BINARY("a+", "ab+");
04951         }
04952     }
04953     switch (oflags & (O_RDONLY|O_WRONLY|O_RDWR)) {
04954       default:
04955         rb_raise(rb_eArgError, "invalid access oflags 0x%x", oflags);
04956       case O_RDONLY:
04957         return MODE_BINARY("r", "rb");
04958       case O_WRONLY:
04959         return MODE_BINARY("w", "wb");
04960       case O_RDWR:
04961         return MODE_BINARY("r+", "rb+");
04962     }
04963 }
04964 
04965 /*
04966  * Convert external/internal encodings to enc/enc2
04967  * NULL => use default encoding
04968  * Qnil => no encoding specified (internal only)
04969  */
04970 static void
04971 rb_io_ext_int_to_encs(rb_encoding *ext, rb_encoding *intern, rb_encoding **enc, rb_encoding **enc2, int fmode)
04972 {
04973     int default_ext = 0;
04974 
04975     if (ext == NULL) {
04976         ext = rb_default_external_encoding();
04977         default_ext = 1;
04978     }
04979     if (ext == rb_ascii8bit_encoding()) {
04980         /* If external is ASCII-8BIT, no transcoding */
04981         intern = NULL;
04982     }
04983     else if (intern == NULL) {
04984         intern = rb_default_internal_encoding();
04985     }
04986     if (intern == NULL || intern == (rb_encoding *)Qnil ||
04987         (!(fmode & FMODE_SETENC_BY_BOM) && (intern == ext))) {
04988         /* No internal encoding => use external + no transcoding */
04989         *enc = (default_ext && intern != ext) ? NULL : ext;
04990         *enc2 = NULL;
04991     }
04992     else {
04993         *enc = intern;
04994         *enc2 = ext;
04995     }
04996 }
04997 
04998 static void
04999 unsupported_encoding(const char *name)
05000 {
05001     rb_warn("Unsupported encoding %s ignored", name);
05002 }
05003 
05004 static void
05005 parse_mode_enc(const char *estr, rb_encoding **enc_p, rb_encoding **enc2_p, int *fmode_p)
05006 {
05007     const char *p;
05008     char encname[ENCODING_MAXNAMELEN+1];
05009     int idx, idx2;
05010     int fmode = fmode_p ? *fmode_p : 0;
05011     rb_encoding *ext_enc, *int_enc;
05012 
05013     /* parse estr as "enc" or "enc2:enc" or "enc:-" */
05014 
05015     p = strrchr(estr, ':');
05016     if (p) {
05017         long len = (p++) - estr;
05018         if (len == 0 || len > ENCODING_MAXNAMELEN)
05019             idx = -1;
05020         else {
05021             if (io_encname_bom_p(estr, len)) {
05022                 fmode |= FMODE_SETENC_BY_BOM;
05023                 estr += 4;
05024                 len -= 4;
05025             }
05026             memcpy(encname, estr, len);
05027             encname[len] = '\0';
05028             estr = encname;
05029             idx = rb_enc_find_index(encname);
05030         }
05031     }
05032     else {
05033         long len = strlen(estr);
05034         if (io_encname_bom_p(estr, len)) {
05035             fmode |= FMODE_SETENC_BY_BOM;
05036             estr += 4;
05037             len -= 4;
05038             memcpy(encname, estr, len);
05039             encname[len] = '\0';
05040             estr = encname;
05041         }
05042         idx = rb_enc_find_index(estr);
05043     }
05044     if (fmode_p) *fmode_p = fmode;
05045 
05046     if (idx >= 0)
05047         ext_enc = rb_enc_from_index(idx);
05048     else {
05049         if (idx != -2)
05050             unsupported_encoding(estr);
05051         ext_enc = NULL;
05052     }
05053 
05054     int_enc = NULL;
05055     if (p) {
05056         if (*p == '-' && *(p+1) == '\0') {
05057             /* Special case - "-" => no transcoding */
05058             int_enc = (rb_encoding *)Qnil;
05059         }
05060         else {
05061             idx2 = rb_enc_find_index(p);
05062             if (idx2 < 0)
05063                 unsupported_encoding(p);
05064             else if (!(fmode & FMODE_SETENC_BY_BOM) && (idx2 == idx)) {
05065                 int_enc = (rb_encoding *)Qnil;
05066             }
05067             else
05068                 int_enc = rb_enc_from_index(idx2);
05069         }
05070     }
05071 
05072     rb_io_ext_int_to_encs(ext_enc, int_enc, enc_p, enc2_p, fmode);
05073 }
05074 
05075 int
05076 rb_io_extract_encoding_option(VALUE opt, rb_encoding **enc_p, rb_encoding **enc2_p, int *fmode_p)
05077 {
05078     VALUE encoding=Qnil, extenc=Qundef, intenc=Qundef, tmp;
05079     int extracted = 0;
05080     rb_encoding *extencoding = NULL;
05081     rb_encoding *intencoding = NULL;
05082 
05083     if (!NIL_P(opt)) {
05084         VALUE v;
05085         v = rb_hash_lookup2(opt, sym_encoding, Qnil);
05086         if (v != Qnil) encoding = v;
05087         v = rb_hash_lookup2(opt, sym_extenc, Qundef);
05088         if (v != Qnil) extenc = v;
05089         v = rb_hash_lookup2(opt, sym_intenc, Qundef);
05090         if (v != Qundef) intenc = v;
05091     }
05092     if ((extenc != Qundef || intenc != Qundef) && !NIL_P(encoding)) {
05093         if (!NIL_P(ruby_verbose)) {
05094             int idx = rb_to_encoding_index(encoding);
05095             rb_warn("Ignoring encoding parameter '%s': %s_encoding is used",
05096                     idx < 0 ? StringValueCStr(encoding) : rb_enc_name(rb_enc_from_index(idx)),
05097                     extenc == Qundef ? "internal" : "external");
05098         }
05099         encoding = Qnil;
05100     }
05101     if (extenc != Qundef && !NIL_P(extenc)) {
05102         extencoding = rb_to_encoding(extenc);
05103     }
05104     if (intenc != Qundef) {
05105         if (NIL_P(intenc)) {
05106             /* internal_encoding: nil => no transcoding */
05107             intencoding = (rb_encoding *)Qnil;
05108         }
05109         else if (!NIL_P(tmp = rb_check_string_type(intenc))) {
05110             char *p = StringValueCStr(tmp);
05111 
05112             if (*p == '-' && *(p+1) == '\0') {
05113                 /* Special case - "-" => no transcoding */
05114                 intencoding = (rb_encoding *)Qnil;
05115             }
05116             else {
05117                 intencoding = rb_to_encoding(intenc);
05118             }
05119         }
05120         else {
05121             intencoding = rb_to_encoding(intenc);
05122         }
05123         if (extencoding == intencoding) {
05124             intencoding = (rb_encoding *)Qnil;
05125         }
05126     }
05127     if (!NIL_P(encoding)) {
05128         extracted = 1;
05129         if (!NIL_P(tmp = rb_check_string_type(encoding))) {
05130             parse_mode_enc(StringValueCStr(tmp), enc_p, enc2_p, fmode_p);
05131         }
05132         else {
05133             rb_io_ext_int_to_encs(rb_to_encoding(encoding), NULL, enc_p, enc2_p, 0);
05134         }
05135     }
05136     else if (extenc != Qundef || intenc != Qundef) {
05137         extracted = 1;
05138         rb_io_ext_int_to_encs(extencoding, intencoding, enc_p, enc2_p, 0);
05139     }
05140     return extracted;
05141 }
05142 
05143 typedef struct rb_io_enc_t convconfig_t;
05144 
05145 static void
05146 validate_enc_binmode(int *fmode_p, int ecflags, rb_encoding *enc, rb_encoding *enc2)
05147 {
05148     int fmode = *fmode_p;
05149 
05150     if ((fmode & FMODE_READABLE) &&
05151         !enc2 &&
05152         !(fmode & FMODE_BINMODE) &&
05153         !rb_enc_asciicompat(enc ? enc : rb_default_external_encoding()))
05154         rb_raise(rb_eArgError, "ASCII incompatible encoding needs binmode");
05155 
05156     if (!(fmode & FMODE_BINMODE) &&
05157         (DEFAULT_TEXTMODE || (ecflags & ECONV_NEWLINE_DECORATOR_MASK))) {
05158         fmode |= DEFAULT_TEXTMODE;
05159         *fmode_p = fmode;
05160     }
05161 #if !DEFAULT_TEXTMODE
05162     else if (!(ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
05163         fmode &= ~FMODE_TEXTMODE;
05164         *fmode_p = fmode;
05165     }
05166 #endif
05167 }
05168 
05169 static void
05170 extract_binmode(VALUE opthash, int *fmode)
05171 {
05172     if (!NIL_P(opthash)) {
05173         VALUE v;
05174         v = rb_hash_aref(opthash, sym_textmode);
05175         if (!NIL_P(v)) {
05176             if (*fmode & FMODE_TEXTMODE)
05177                 rb_raise(rb_eArgError, "textmode specified twice");
05178             if (*fmode & FMODE_BINMODE)
05179                 rb_raise(rb_eArgError, "both textmode and binmode specified");
05180             if (RTEST(v))
05181                 *fmode |= FMODE_TEXTMODE;
05182         }
05183         v = rb_hash_aref(opthash, sym_binmode);
05184         if (!NIL_P(v)) {
05185             if (*fmode & FMODE_BINMODE)
05186                 rb_raise(rb_eArgError, "binmode specified twice");
05187             if (*fmode & FMODE_TEXTMODE)
05188                 rb_raise(rb_eArgError, "both textmode and binmode specified");
05189             if (RTEST(v))
05190                 *fmode |= FMODE_BINMODE;
05191         }
05192 
05193         if ((*fmode & FMODE_BINMODE) && (*fmode & FMODE_TEXTMODE))
05194             rb_raise(rb_eArgError, "both textmode and binmode specified");
05195     }
05196 }
05197 
05198 static void
05199 rb_io_extract_modeenc(VALUE *vmode_p, VALUE *vperm_p, VALUE opthash,
05200         int *oflags_p, int *fmode_p, convconfig_t *convconfig_p)
05201 {
05202     VALUE vmode;
05203     int oflags, fmode;
05204     rb_encoding *enc, *enc2;
05205     int ecflags;
05206     VALUE ecopts;
05207     int has_enc = 0, has_vmode = 0;
05208     VALUE intmode;
05209 
05210     vmode = *vmode_p;
05211 
05212     /* Set to defaults */
05213     rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
05214 
05215   vmode_handle:
05216     if (NIL_P(vmode)) {
05217         fmode = FMODE_READABLE;
05218         oflags = O_RDONLY;
05219     }
05220     else if (!NIL_P(intmode = rb_check_to_integer(vmode, "to_int"))) {
05221         vmode = intmode;
05222         oflags = NUM2INT(intmode);
05223         fmode = rb_io_oflags_fmode(oflags);
05224     }
05225     else {
05226         const char *p;
05227 
05228         SafeStringValue(vmode);
05229         p = StringValueCStr(vmode);
05230         fmode = rb_io_modestr_fmode(p);
05231         oflags = rb_io_fmode_oflags(fmode);
05232         p = strchr(p, ':');
05233         if (p) {
05234             has_enc = 1;
05235             parse_mode_enc(p+1, &enc, &enc2, &fmode);
05236         }
05237         else {
05238             rb_encoding *e;
05239 
05240             e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
05241             rb_io_ext_int_to_encs(e, NULL, &enc, &enc2, fmode);
05242         }
05243     }
05244 
05245     if (NIL_P(opthash)) {
05246         ecflags = (fmode & FMODE_READABLE) ?
05247             MODE_BTMODE(ECONV_DEFAULT_NEWLINE_DECORATOR,
05248                         0, ECONV_UNIVERSAL_NEWLINE_DECORATOR) : 0;
05249 #ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
05250         ecflags |= (fmode & FMODE_WRITABLE) ?
05251             MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
05252                         0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
05253 #endif
05254         SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
05255         ecopts = Qnil;
05256     }
05257     else {
05258         VALUE v;
05259         extract_binmode(opthash, &fmode);
05260         if (fmode & FMODE_BINMODE) {
05261 #ifdef O_BINARY
05262             oflags |= O_BINARY;
05263 #endif
05264             if (!has_enc)
05265                 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
05266         }
05267 #if DEFAULT_TEXTMODE
05268         else if (NIL_P(vmode)) {
05269             fmode |= DEFAULT_TEXTMODE;
05270         }
05271 #endif
05272         if (!has_vmode) {
05273             v = rb_hash_aref(opthash, sym_mode);
05274             if (!NIL_P(v)) {
05275                 if (!NIL_P(vmode)) {
05276                     rb_raise(rb_eArgError, "mode specified twice");
05277                 }
05278                 has_vmode = 1;
05279                 vmode = v;
05280                 goto vmode_handle;
05281             }
05282         }
05283         v = rb_hash_aref(opthash, sym_perm);
05284         if (!NIL_P(v)) {
05285             if (vperm_p) {
05286                 if (!NIL_P(*vperm_p)) {
05287                     rb_raise(rb_eArgError, "perm specified twice");
05288                 }
05289                 *vperm_p = v;
05290             }
05291             else {
05292                 /* perm no use, just ignore */
05293             }
05294         }
05295         ecflags = (fmode & FMODE_READABLE) ?
05296             MODE_BTMODE(ECONV_DEFAULT_NEWLINE_DECORATOR,
05297                         0, ECONV_UNIVERSAL_NEWLINE_DECORATOR) : 0;
05298 #ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
05299         ecflags |= (fmode & FMODE_WRITABLE) ?
05300             MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
05301                         0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
05302 #endif
05303 
05304         if (rb_io_extract_encoding_option(opthash, &enc, &enc2, &fmode)) {
05305             if (has_enc) {
05306                 rb_raise(rb_eArgError, "encoding specified twice");
05307             }
05308         }
05309         SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
05310         ecflags = rb_econv_prepare_options(opthash, &ecopts, ecflags);
05311     }
05312 
05313     validate_enc_binmode(&fmode, ecflags, enc, enc2);
05314 
05315     *vmode_p = vmode;
05316 
05317     *oflags_p = oflags;
05318     *fmode_p = fmode;
05319     convconfig_p->enc = enc;
05320     convconfig_p->enc2 = enc2;
05321     convconfig_p->ecflags = ecflags;
05322     convconfig_p->ecopts = ecopts;
05323 }
05324 
05325 struct sysopen_struct {
05326     VALUE fname;
05327     int oflags;
05328     mode_t perm;
05329 };
05330 
05331 static void *
05332 sysopen_func(void *ptr)
05333 {
05334     const struct sysopen_struct *data = ptr;
05335     const char *fname = RSTRING_PTR(data->fname);
05336     return (void *)(VALUE)rb_cloexec_open(fname, data->oflags, data->perm);
05337 }
05338 
05339 static inline int
05340 rb_sysopen_internal(struct sysopen_struct *data)
05341 {
05342     int fd;
05343     fd = (int)(VALUE)rb_thread_call_without_gvl(sysopen_func, data, RUBY_UBF_IO, 0);
05344     if (0 <= fd)
05345         rb_update_max_fd(fd);
05346     return fd;
05347 }
05348 
05349 static int
05350 rb_sysopen(VALUE fname, int oflags, mode_t perm)
05351 {
05352     int fd;
05353     struct sysopen_struct data;
05354 
05355     data.fname = rb_str_encode_ospath(fname);
05356     data.oflags = oflags;
05357     data.perm = perm;
05358 
05359     fd = rb_sysopen_internal(&data);
05360     if (fd < 0) {
05361         if (errno == EMFILE || errno == ENFILE) {
05362             rb_gc();
05363             fd = rb_sysopen_internal(&data);
05364         }
05365         if (fd < 0) {
05366             rb_sys_fail_path(fname);
05367         }
05368     }
05369     return fd;
05370 }
05371 
05372 FILE *
05373 rb_fdopen(int fd, const char *modestr)
05374 {
05375     FILE *file;
05376 
05377 #if defined(__sun)
05378     errno = 0;
05379 #endif
05380     file = fdopen(fd, modestr);
05381     if (!file) {
05382         if (
05383 #if defined(__sun)
05384             errno == 0 ||
05385 #endif
05386             errno == EMFILE || errno == ENFILE) {
05387             rb_gc();
05388 #if defined(__sun)
05389             errno = 0;
05390 #endif
05391             file = fdopen(fd, modestr);
05392         }
05393         if (!file) {
05394 #ifdef _WIN32
05395             if (errno == 0) errno = EINVAL;
05396 #elif defined(__sun)
05397             if (errno == 0) errno = EMFILE;
05398 #endif
05399             rb_sys_fail(0);
05400         }
05401     }
05402 
05403     /* xxx: should be _IONBF?  A buffer in FILE may have trouble. */
05404 #ifdef USE_SETVBUF
05405     if (setvbuf(file, NULL, _IOFBF, 0) != 0)
05406         rb_warn("setvbuf() can't be honoured (fd=%d)", fd);
05407 #endif
05408     return file;
05409 }
05410 
05411 static void
05412 io_check_tty(rb_io_t *fptr)
05413 {
05414     if (isatty(fptr->fd))
05415         fptr->mode |= FMODE_TTY|FMODE_DUPLEX;
05416 }
05417 
05418 static VALUE rb_io_internal_encoding(VALUE);
05419 static void io_encoding_set(rb_io_t *, VALUE, VALUE, VALUE);
05420 
05421 static int
05422 io_strip_bom(VALUE io)
05423 {
05424     VALUE b1, b2, b3, b4;
05425 
05426     if (NIL_P(b1 = rb_io_getbyte(io))) return 0;
05427     switch (b1) {
05428       case INT2FIX(0xEF):
05429         if (NIL_P(b2 = rb_io_getbyte(io))) break;
05430         if (b2 == INT2FIX(0xBB) && !NIL_P(b3 = rb_io_getbyte(io))) {
05431             if (b3 == INT2FIX(0xBF)) {
05432                 return rb_utf8_encindex();
05433             }
05434             rb_io_ungetbyte(io, b3);
05435         }
05436         rb_io_ungetbyte(io, b2);
05437         break;
05438 
05439       case INT2FIX(0xFE):
05440         if (NIL_P(b2 = rb_io_getbyte(io))) break;
05441         if (b2 == INT2FIX(0xFF)) {
05442             return ENCINDEX_UTF_16BE;
05443         }
05444         rb_io_ungetbyte(io, b2);
05445         break;
05446 
05447       case INT2FIX(0xFF):
05448         if (NIL_P(b2 = rb_io_getbyte(io))) break;
05449         if (b2 == INT2FIX(0xFE)) {
05450             b3 = rb_io_getbyte(io);
05451             if (b3 == INT2FIX(0) && !NIL_P(b4 = rb_io_getbyte(io))) {
05452                 if (b4 == INT2FIX(0)) {
05453                     return ENCINDEX_UTF_32LE;
05454                 }
05455                 rb_io_ungetbyte(io, b4);
05456                 rb_io_ungetbyte(io, b3);
05457             }
05458             else {
05459                 rb_io_ungetbyte(io, b3);
05460                 return ENCINDEX_UTF_16LE;
05461             }
05462         }
05463         rb_io_ungetbyte(io, b2);
05464         break;
05465 
05466       case INT2FIX(0):
05467         if (NIL_P(b2 = rb_io_getbyte(io))) break;
05468         if (b2 == INT2FIX(0) && !NIL_P(b3 = rb_io_getbyte(io))) {
05469             if (b3 == INT2FIX(0xFE) && !NIL_P(b4 = rb_io_getbyte(io))) {
05470                 if (b4 == INT2FIX(0xFF)) {
05471                     return ENCINDEX_UTF_32BE;
05472                 }
05473                 rb_io_ungetbyte(io, b4);
05474             }
05475             rb_io_ungetbyte(io, b3);
05476         }
05477         rb_io_ungetbyte(io, b2);
05478         break;
05479     }
05480     rb_io_ungetbyte(io, b1);
05481     return 0;
05482 }
05483 
05484 static void
05485 io_set_encoding_by_bom(VALUE io)
05486 {
05487     int idx = io_strip_bom(io);
05488     rb_io_t *fptr;
05489 
05490     GetOpenFile(io, fptr);
05491     if (idx) {
05492         io_encoding_set(fptr, rb_enc_from_encoding(rb_enc_from_index(idx)),
05493                 rb_io_internal_encoding(io), Qnil);
05494     }
05495     else {
05496         fptr->encs.enc2 = NULL;
05497     }
05498 }
05499 
05500 static VALUE
05501 rb_file_open_generic(VALUE io, VALUE filename, int oflags, int fmode, convconfig_t *convconfig, mode_t perm)
05502 {
05503     rb_io_t *fptr;
05504     convconfig_t cc;
05505     if (!convconfig) {
05506         /* Set to default encodings */
05507         rb_io_ext_int_to_encs(NULL, NULL, &cc.enc, &cc.enc2, fmode);
05508         cc.ecflags = 0;
05509         cc.ecopts = Qnil;
05510         convconfig = &cc;
05511     }
05512     validate_enc_binmode(&fmode, convconfig->ecflags,
05513                          convconfig->enc, convconfig->enc2);
05514 
05515     MakeOpenFile(io, fptr);
05516     fptr->mode = fmode;
05517     fptr->encs = *convconfig;
05518     fptr->pathv = rb_str_new_frozen(filename);
05519     fptr->fd = rb_sysopen(fptr->pathv, oflags, perm);
05520     io_check_tty(fptr);
05521     if (fmode & FMODE_SETENC_BY_BOM) io_set_encoding_by_bom(io);
05522 
05523     return io;
05524 }
05525 
05526 static VALUE
05527 rb_file_open_internal(VALUE io, VALUE filename, const char *modestr)
05528 {
05529     int fmode = rb_io_modestr_fmode(modestr);
05530     const char *p = strchr(modestr, ':');
05531     convconfig_t convconfig;
05532 
05533     if (p) {
05534         parse_mode_enc(p+1, &convconfig.enc, &convconfig.enc2, &fmode);
05535     }
05536     else {
05537         rb_encoding *e;
05538         /* Set to default encodings */
05539 
05540         e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
05541         rb_io_ext_int_to_encs(e, NULL, &convconfig.enc, &convconfig.enc2, fmode);
05542         convconfig.ecflags = 0;
05543         convconfig.ecopts = Qnil;
05544     }
05545 
05546     return rb_file_open_generic(io, filename,
05547             rb_io_fmode_oflags(fmode),
05548             fmode,
05549             &convconfig,
05550             0666);
05551 }
05552 
05553 VALUE
05554 rb_file_open_str(VALUE fname, const char *modestr)
05555 {
05556     FilePathValue(fname);
05557     return rb_file_open_internal(io_alloc(rb_cFile), fname, modestr);
05558 }
05559 
05560 VALUE
05561 rb_file_open(const char *fname, const char *modestr)
05562 {
05563     return rb_file_open_internal(io_alloc(rb_cFile), rb_str_new_cstr(fname), modestr);
05564 }
05565 
05566 #if defined(__CYGWIN__) || !defined(HAVE_FORK)
05567 static struct pipe_list {
05568     rb_io_t *fptr;
05569     struct pipe_list *next;
05570 } *pipe_list;
05571 
05572 static void
05573 pipe_add_fptr(rb_io_t *fptr)
05574 {
05575     struct pipe_list *list;
05576 
05577     list = ALLOC(struct pipe_list);
05578     list->fptr = fptr;
05579     list->next = pipe_list;
05580     pipe_list = list;
05581 }
05582 
05583 static void
05584 pipe_del_fptr(rb_io_t *fptr)
05585 {
05586     struct pipe_list *list = pipe_list;
05587     struct pipe_list *tmp;
05588 
05589     if (list->fptr == fptr) {
05590         pipe_list = list->next;
05591         free(list);
05592         return;
05593     }
05594 
05595     while (list->next) {
05596         if (list->next->fptr == fptr) {
05597             tmp = list->next;
05598             list->next = list->next->next;
05599             free(tmp);
05600             return;
05601         }
05602         list = list->next;
05603     }
05604 }
05605 
05606 static void
05607 pipe_atexit(void)
05608 {
05609     struct pipe_list *list = pipe_list;
05610     struct pipe_list *tmp;
05611 
05612     while (list) {
05613         tmp = list->next;
05614         rb_io_fptr_finalize(list->fptr);
05615         list = tmp;
05616     }
05617 }
05618 
05619 static void
05620 pipe_finalize(rb_io_t *fptr, int noraise)
05621 {
05622 #if !defined(HAVE_FORK) && !defined(_WIN32)
05623     int status = 0;
05624     if (fptr->stdio_file) {
05625         status = pclose(fptr->stdio_file);
05626     }
05627     fptr->fd = -1;
05628     fptr->stdio_file = 0;
05629     rb_last_status_set(status, fptr->pid);
05630 #else
05631     fptr_finalize(fptr, noraise);
05632 #endif
05633     pipe_del_fptr(fptr);
05634 }
05635 #endif
05636 
05637 void
05638 rb_io_synchronized(rb_io_t *fptr)
05639 {
05640     rb_io_check_initialized(fptr);
05641     fptr->mode |= FMODE_SYNC;
05642 }
05643 
05644 void
05645 rb_io_unbuffered(rb_io_t *fptr)
05646 {
05647     rb_io_synchronized(fptr);
05648 }
05649 
05650 int
05651 rb_pipe(int *pipes)
05652 {
05653     int ret;
05654     ret = rb_cloexec_pipe(pipes);
05655     if (ret == -1) {
05656         if (errno == EMFILE || errno == ENFILE) {
05657             rb_gc();
05658             ret = rb_cloexec_pipe(pipes);
05659         }
05660     }
05661     if (ret == 0) {
05662         rb_update_max_fd(pipes[0]);
05663         rb_update_max_fd(pipes[1]);
05664     }
05665     return ret;
05666 }
05667 
05668 #ifdef _WIN32
05669 #define HAVE_SPAWNV 1
05670 #define spawnv(mode, cmd, args) rb_w32_uaspawn((mode), (cmd), (args))
05671 #define spawn(mode, cmd) rb_w32_uspawn((mode), (cmd), 0)
05672 #endif
05673 
05674 #if defined(HAVE_FORK) || defined(HAVE_SPAWNV)
05675 struct popen_arg {
05676     VALUE execarg_obj;
05677     struct rb_execarg *eargp;
05678     int modef;
05679     int pair[2];
05680     int write_pair[2];
05681 };
05682 #endif
05683 
05684 #ifdef HAVE_FORK
05685 static void
05686 popen_redirect(struct popen_arg *p)
05687 {
05688     if ((p->modef & FMODE_READABLE) && (p->modef & FMODE_WRITABLE)) {
05689         close(p->write_pair[1]);
05690         if (p->write_pair[0] != 0) {
05691             dup2(p->write_pair[0], 0);
05692             close(p->write_pair[0]);
05693         }
05694         close(p->pair[0]);
05695         if (p->pair[1] != 1) {
05696             dup2(p->pair[1], 1);
05697             close(p->pair[1]);
05698         }
05699     }
05700     else if (p->modef & FMODE_READABLE) {
05701         close(p->pair[0]);
05702         if (p->pair[1] != 1) {
05703             dup2(p->pair[1], 1);
05704             close(p->pair[1]);
05705         }
05706     }
05707     else {
05708         close(p->pair[1]);
05709         if (p->pair[0] != 0) {
05710             dup2(p->pair[0], 0);
05711             close(p->pair[0]);
05712         }
05713     }
05714 }
05715 
05716 #if defined(__linux__)
05717 /* Linux /proc/self/status contains a line: "FDSize:\t<nnn>\n"
05718  * Since /proc may not be available, linux_get_maxfd is just a hint.
05719  * This function, linux_get_maxfd, must be async-signal-safe.
05720  * I.e. opendir() is not usable.
05721  *
05722  * Note that memchr() and memcmp is *not* async-signal-safe in POSIX.
05723  * However they are easy to re-implement in async-signal-safe manner.
05724  * (Also note that there is missing/memcmp.c.)
05725  */
05726 static int
05727 linux_get_maxfd(void)
05728 {
05729     int fd;
05730     char buf[4096], *p, *np, *e;
05731     ssize_t ss;
05732     fd = rb_cloexec_open("/proc/self/status", O_RDONLY|O_NOCTTY, 0);
05733     if (fd == -1) return -1;
05734     ss = read(fd, buf, sizeof(buf));
05735     if (ss == -1) goto err;
05736     p = buf;
05737     e = buf + ss;
05738     while ((int)sizeof("FDSize:\t0\n")-1 <= e-p &&
05739            (np = memchr(p, '\n', e-p)) != NULL) {
05740         if (memcmp(p, "FDSize:", sizeof("FDSize:")-1) == 0) {
05741             int fdsize;
05742             p += sizeof("FDSize:")-1;
05743             *np = '\0';
05744             fdsize = (int)ruby_strtoul(p, (char **)NULL, 10);
05745             close(fd);
05746             return fdsize;
05747         }
05748         p = np+1;
05749     }
05750     /* fall through */
05751 
05752   err:
05753     close(fd);
05754     return -1;
05755 }
05756 #endif
05757 
05758 /* This function should be async-signal-safe. */
05759 void
05760 rb_close_before_exec(int lowfd, int maxhint, VALUE noclose_fds)
05761 {
05762     int fd, ret;
05763     int max = (int)max_file_descriptor;
05764 #ifdef F_MAXFD
05765     /* F_MAXFD is available since NetBSD 2.0. */
05766     ret = fcntl(0, F_MAXFD); /* async-signal-safe */
05767     if (ret != -1)
05768         maxhint = max = ret;
05769 #elif defined(__linux__)
05770     ret = linux_get_maxfd();
05771     if (maxhint < ret)
05772         maxhint = ret;
05773     /* maxhint = max = ret; if (ret == -1) abort(); // test */
05774 #endif
05775     if (max < maxhint)
05776         max = maxhint;
05777     for (fd = lowfd; fd <= max; fd++) {
05778         if (!NIL_P(noclose_fds) &&
05779             RTEST(rb_hash_lookup(noclose_fds, INT2FIX(fd)))) /* async-signal-safe */
05780             continue;
05781         ret = fcntl(fd, F_GETFD); /* async-signal-safe */
05782         if (ret != -1 && !(ret & FD_CLOEXEC)) {
05783             fcntl(fd, F_SETFD, ret|FD_CLOEXEC); /* async-signal-safe */
05784         }
05785 #define CONTIGUOUS_CLOSED_FDS 20
05786         if (ret != -1) {
05787             if (max < fd + CONTIGUOUS_CLOSED_FDS)
05788                 max = fd + CONTIGUOUS_CLOSED_FDS;
05789         }
05790     }
05791 }
05792 
05793 static int
05794 popen_exec(void *pp, char *errmsg, size_t errmsg_len)
05795 {
05796     struct popen_arg *p = (struct popen_arg*)pp;
05797 
05798     return rb_exec_async_signal_safe(p->eargp, errmsg, errmsg_len);
05799 }
05800 #endif
05801 
05802 static VALUE
05803 pipe_open(VALUE execarg_obj, const char *modestr, int fmode, convconfig_t *convconfig)
05804 {
05805     struct rb_execarg *eargp = NIL_P(execarg_obj) ? NULL : rb_execarg_get(execarg_obj);
05806     VALUE prog = eargp ? (eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name) : Qfalse ;
05807     rb_pid_t pid = 0;
05808     rb_io_t *fptr;
05809     VALUE port;
05810     rb_io_t *write_fptr;
05811     VALUE write_port;
05812 #if defined(HAVE_FORK)
05813     int status;
05814     char errmsg[80] = { '\0' };
05815 #endif
05816 #if defined(HAVE_FORK) || defined(HAVE_SPAWNV)
05817     struct popen_arg arg;
05818     int e = 0;
05819 #endif
05820 #if defined(HAVE_SPAWNV)
05821 # if defined(HAVE_SPAWNVE)
05822 #   define DO_SPAWN(cmd, args, envp) ((args) ? \
05823                                       spawnve(P_NOWAIT, (cmd), (args), (envp)) : \
05824                                       spawne(P_NOWAIT, (cmd), (envp)))
05825 # else
05826 #   define DO_SPAWN(cmd, args, envp) ((args) ? \
05827                                       spawnv(P_NOWAIT, (cmd), (args)) : \
05828                                       spawn(P_NOWAIT, (cmd)))
05829 # endif
05830 # if !defined(HAVE_FORK)
05831     char **args = NULL;
05832 #   if defined(HAVE_SPAWNVE)
05833     char **envp = NULL;
05834 #   endif
05835 # endif
05836 #endif
05837 #if !defined(HAVE_FORK)
05838     struct rb_execarg sarg, *sargp = &sarg;
05839 #endif
05840     FILE *fp = 0;
05841     int fd = -1;
05842     int write_fd = -1;
05843 #if !defined(HAVE_FORK)
05844     const char *cmd = 0;
05845 #if !defined(HAVE_SPAWNV)
05846     int argc;
05847     VALUE *argv;
05848 #endif
05849 
05850     if (prog)
05851         cmd = StringValueCStr(prog);
05852 #endif
05853 
05854 #if defined(HAVE_FORK) || defined(HAVE_SPAWNV)
05855     arg.execarg_obj = execarg_obj;
05856     arg.eargp = eargp;
05857     arg.modef = fmode;
05858     arg.pair[0] = arg.pair[1] = -1;
05859     arg.write_pair[0] = arg.write_pair[1] = -1;
05860 # if !defined(HAVE_FORK)
05861     if (eargp && !eargp->use_shell) {
05862         args = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
05863     }
05864 # endif
05865     switch (fmode & (FMODE_READABLE|FMODE_WRITABLE)) {
05866       case FMODE_READABLE|FMODE_WRITABLE:
05867         if (rb_pipe(arg.write_pair) < 0)
05868             rb_sys_fail_str(prog);
05869         if (rb_pipe(arg.pair) < 0) {
05870             int e = errno;
05871             close(arg.write_pair[0]);
05872             close(arg.write_pair[1]);
05873             errno = e;
05874             rb_sys_fail_str(prog);
05875         }
05876         if (eargp) {
05877             rb_execarg_addopt(execarg_obj, INT2FIX(0), INT2FIX(arg.write_pair[0]));
05878             rb_execarg_addopt(execarg_obj, INT2FIX(1), INT2FIX(arg.pair[1]));
05879         }
05880         break;
05881       case FMODE_READABLE:
05882         if (rb_pipe(arg.pair) < 0)
05883             rb_sys_fail_str(prog);
05884         if (eargp)
05885             rb_execarg_addopt(execarg_obj, INT2FIX(1), INT2FIX(arg.pair[1]));
05886         break;
05887       case FMODE_WRITABLE:
05888         if (rb_pipe(arg.pair) < 0)
05889             rb_sys_fail_str(prog);
05890         if (eargp)
05891             rb_execarg_addopt(execarg_obj, INT2FIX(0), INT2FIX(arg.pair[0]));
05892         break;
05893       default:
05894         rb_sys_fail_str(prog);
05895     }
05896     if (!NIL_P(execarg_obj)) {
05897         rb_execarg_fixup(execarg_obj);
05898 # if defined(HAVE_FORK)
05899         pid = rb_fork_async_signal_safe(&status, popen_exec, &arg, arg.eargp->redirect_fds, errmsg, sizeof(errmsg));
05900 # else
05901         rb_execarg_run_options(eargp, sargp, NULL, 0);
05902 #   if defined(HAVE_SPAWNVE)
05903         if (eargp->envp_str) envp = (char **)RSTRING_PTR(eargp->envp_str);
05904 #   endif
05905         while ((pid = DO_SPAWN(cmd, args, envp)) == -1) {
05906             /* exec failed */
05907             switch (e = errno) {
05908               case EAGAIN:
05909 #   if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
05910               case EWOULDBLOCK:
05911 #   endif
05912                 rb_thread_sleep(1);
05913                 continue;
05914             }
05915             break;
05916         }
05917         if (eargp)
05918             rb_execarg_run_options(sargp, NULL, NULL, 0);
05919 # endif
05920     }
05921     else {
05922 # if defined(HAVE_FORK)
05923         pid = rb_fork_ruby(&status);
05924         if (pid == 0) {         /* child */
05925             rb_thread_atfork();
05926             popen_redirect(&arg);
05927             rb_io_synchronized(RFILE(orig_stdout)->fptr);
05928             rb_io_synchronized(RFILE(orig_stderr)->fptr);
05929             return Qnil;
05930         }
05931 # else
05932         rb_notimplement();
05933 # endif
05934     }
05935 
05936     /* parent */
05937     if (pid == -1) {
05938 # if defined(HAVE_FORK)
05939         e = errno;
05940 # endif
05941         close(arg.pair[0]);
05942         close(arg.pair[1]);
05943         if ((fmode & (FMODE_READABLE|FMODE_WRITABLE)) == (FMODE_READABLE|FMODE_WRITABLE)) {
05944             close(arg.write_pair[0]);
05945             close(arg.write_pair[1]);
05946         }
05947         errno = e;
05948 # if defined(HAVE_FORK)
05949         if (errmsg[0])
05950             rb_sys_fail(errmsg);
05951 # endif
05952         rb_sys_fail_str(prog);
05953     }
05954     if ((fmode & FMODE_READABLE) && (fmode & FMODE_WRITABLE)) {
05955         close(arg.pair[1]);
05956         fd = arg.pair[0];
05957         close(arg.write_pair[0]);
05958         write_fd = arg.write_pair[1];
05959     }
05960     else if (fmode & FMODE_READABLE) {
05961         close(arg.pair[1]);
05962         fd = arg.pair[0];
05963     }
05964     else {
05965         close(arg.pair[0]);
05966         fd = arg.pair[1];
05967     }
05968 #else
05969     if (argc) {
05970         prog = rb_ary_join(rb_ary_new4(argc, argv), rb_str_new2(" "));
05971         cmd = StringValueCStr(prog);
05972     }
05973     if (!NIL_P(execarg_obj)) {
05974         rb_execarg_fixup(execarg_obj);
05975         rb_execarg_run_options(eargp, sargp, NULL, 0);
05976     }
05977     fp = popen(cmd, modestr);
05978     if (eargp)
05979         rb_execarg_run_options(sargp, NULL, NULL, 0);
05980     if (!fp) rb_sys_fail_path(prog);
05981     fd = fileno(fp);
05982 #endif
05983 
05984     port = io_alloc(rb_cIO);
05985     MakeOpenFile(port, fptr);
05986     fptr->fd = fd;
05987     fptr->stdio_file = fp;
05988     fptr->mode = fmode | FMODE_SYNC|FMODE_DUPLEX;
05989     if (convconfig) {
05990         fptr->encs = *convconfig;
05991 #if defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32)
05992         if (fptr->encs.ecflags & ECONV_DEFAULT_NEWLINE_DECORATOR) {
05993             fptr->encs.ecflags |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;
05994         }
05995 #endif
05996     }
05997     else {
05998         if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
05999             fptr->encs.ecflags |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;
06000         }
06001 #ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
06002         if (NEED_NEWLINE_DECORATOR_ON_WRITE(fptr)) {
06003             fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
06004         }
06005 #endif
06006     }
06007     fptr->pid = pid;
06008 
06009     if (0 <= write_fd) {
06010         write_port = io_alloc(rb_cIO);
06011         MakeOpenFile(write_port, write_fptr);
06012         write_fptr->fd = write_fd;
06013         write_fptr->mode = (fmode & ~FMODE_READABLE)| FMODE_SYNC|FMODE_DUPLEX;
06014         fptr->mode &= ~FMODE_WRITABLE;
06015         fptr->tied_io_for_writing = write_port;
06016         rb_ivar_set(port, rb_intern("@tied_io_for_writing"), write_port);
06017     }
06018 
06019 #if defined (__CYGWIN__) || !defined(HAVE_FORK)
06020     fptr->finalize = pipe_finalize;
06021     pipe_add_fptr(fptr);
06022 #endif
06023     return port;
06024 }
06025 
06026 static int
06027 is_popen_fork(VALUE prog)
06028 {
06029     if (RSTRING_LEN(prog) == 1 && RSTRING_PTR(prog)[0] == '-') {
06030 #if !defined(HAVE_FORK)
06031         rb_raise(rb_eNotImpError,
06032                  "fork() function is unimplemented on this machine");
06033 #else
06034         return TRUE;
06035 #endif
06036     }
06037     return FALSE;
06038 }
06039 
06040 static VALUE
06041 pipe_open_s(VALUE prog, const char *modestr, int fmode, convconfig_t *convconfig)
06042 {
06043     int argc = 1;
06044     VALUE *argv = &prog;
06045     VALUE execarg_obj = Qnil;
06046 
06047     if (!is_popen_fork(prog))
06048         execarg_obj = rb_execarg_new(argc, argv, TRUE);
06049     return pipe_open(execarg_obj, modestr, fmode, convconfig);
06050 }
06051 
06052 /*
06053  *  call-seq:
06054  *     IO.popen([env,] cmd, mode="r" [, opt])               -> io
06055  *     IO.popen([env,] cmd, mode="r" [, opt]) {|io| block } -> obj
06056  *
06057  *  Runs the specified command as a subprocess; the subprocess's
06058  *  standard input and output will be connected to the returned
06059  *  <code>IO</code> object.
06060  *
06061  *  The PID of the started process can be obtained by IO#pid method.
06062  *
06063  *  _cmd_ is a string or an array as follows.
06064  *
06065  *    cmd:
06066  *      "-"                                      : fork
06067  *      commandline                              : command line string which is passed to a shell
06068  *      [env, cmdname, arg1, ..., opts]          : command name and zero or more arguments (no shell)
06069  *      [env, [cmdname, argv0], arg1, ..., opts] : command name, argv[0] and zero or more arguments (no shell)
06070  *    (env and opts are optional.)
06071  *
06072  *  If _cmd_ is a +String+ ``<code>-</code>'',
06073  *  then a new instance of Ruby is started as the subprocess.
06074  *
06075  *  If <i>cmd</i> is an +Array+ of +String+,
06076  *  then it will be used as the subprocess's +argv+ bypassing a shell.
06077  *  The array can contains a hash at first for environments and
06078  *  a hash at last for options similar to <code>spawn</code>.
06079  *
06080  *  The default mode for the new file object is ``r'',
06081  *  but <i>mode</i> may be set to any of the modes listed in the description for class IO.
06082  *  The last argument <i>opt</i> qualifies <i>mode</i>.
06083  *
06084  *    # set IO encoding
06085  *    IO.popen("nkf -e filename", :external_encoding=>"EUC-JP") {|nkf_io|
06086  *      euc_jp_string = nkf_io.read
06087  *    }
06088  *
06089  *    # merge standard output and standard error using
06090  *    # spawn option.  See the document of Kernel.spawn.
06091  *    IO.popen(["ls", "/", :err=>[:child, :out]]) {|ls_io|
06092  *      ls_result_with_error = ls_io.read
06093  *    }
06094  *
06095  *    # spawn options can be mixed with IO options
06096  *    IO.popen(["ls", "/"], :err=>[:child, :out]) {|ls_io|
06097  *      ls_result_with_error = ls_io.read
06098  *    }
06099  *
06100  *  Raises exceptions which <code>IO.pipe</code> and
06101  *  <code>Kernel.spawn</code> raise.
06102  *
06103  *  If a block is given, Ruby will run the command as a child connected
06104  *  to Ruby with a pipe. Ruby's end of the pipe will be passed as a
06105  *  parameter to the block.
06106  *  At the end of block, Ruby close the pipe and sets <code>$?</code>.
06107  *  In this case <code>IO.popen</code> returns
06108  *  the value of the block.
06109  *
06110  *  If a block is given with a _cmd_ of ``<code>-</code>'',
06111  *  the block will be run in two separate processes: once in the parent,
06112  *  and once in a child. The parent process will be passed the pipe
06113  *  object as a parameter to the block, the child version of the block
06114  *  will be passed <code>nil</code>, and the child's standard in and
06115  *  standard out will be connected to the parent through the pipe. Not
06116  *  available on all platforms.
06117  *
06118  *     f = IO.popen("uname")
06119  *     p f.readlines
06120  *     f.close
06121  *     puts "Parent is #{Process.pid}"
06122  *     IO.popen("date") { |f| puts f.gets }
06123  *     IO.popen("-") {|f| $stderr.puts "#{Process.pid} is here, f is #{f.inspect}"}
06124  *     p $?
06125  *     IO.popen(%w"sed -e s|^|<foo>| -e s&$&;zot;&", "r+") {|f|
06126  *       f.puts "bar"; f.close_write; puts f.gets
06127  *     }
06128  *
06129  *  <em>produces:</em>
06130  *
06131  *     ["Linux\n"]
06132  *     Parent is 21346
06133  *     Thu Jan 15 22:41:19 JST 2009
06134  *     21346 is here, f is #<IO:fd 3>
06135  *     21352 is here, f is nil
06136  *     #<Process::Status: pid 21352 exit 0>
06137  *     <foo>bar;zot;
06138  */
06139 
06140 static VALUE
06141 rb_io_s_popen(int argc, VALUE *argv, VALUE klass)
06142 {
06143     const char *modestr;
06144     VALUE pname, pmode = Qnil, port, tmp, opt = Qnil, env = Qnil, execarg_obj = Qnil;
06145     int oflags, fmode;
06146     convconfig_t convconfig;
06147 
06148     if (argc > 1 && !NIL_P(opt = rb_check_hash_type(argv[argc-1]))) --argc;
06149     if (argc > 1 && !NIL_P(env = rb_check_hash_type(argv[0]))) --argc, ++argv;
06150     switch (argc) {
06151       case 2:
06152         pmode = argv[1];
06153       case 1:
06154         pname = argv[0];
06155         break;
06156       default:
06157         {
06158             int ex = !NIL_P(opt);
06159             rb_error_arity(argc + ex, 1 + ex, 2 + ex);
06160         }
06161     }
06162 
06163     tmp = rb_check_array_type(pname);
06164     if (!NIL_P(tmp)) {
06165         long len = RARRAY_LEN(tmp);
06166 #if SIZEOF_LONG > SIZEOF_INT
06167         if (len > INT_MAX) {
06168             rb_raise(rb_eArgError, "too many arguments");
06169         }
06170 #endif
06171         tmp = rb_ary_dup(tmp);
06172         RBASIC_CLEAR_CLASS(tmp);
06173         execarg_obj = rb_execarg_new((int)len, RARRAY_PTR(tmp), FALSE);
06174         rb_ary_clear(tmp);
06175     }
06176     else {
06177         SafeStringValue(pname);
06178         execarg_obj = Qnil;
06179         if (!is_popen_fork(pname))
06180             execarg_obj = rb_execarg_new(1, &pname, TRUE);
06181     }
06182     if (!NIL_P(execarg_obj)) {
06183         if (!NIL_P(opt))
06184             opt = rb_execarg_extract_options(execarg_obj, opt);
06185         if (!NIL_P(env))
06186             rb_execarg_setenv(execarg_obj, env);
06187     }
06188     rb_io_extract_modeenc(&pmode, 0, opt, &oflags, &fmode, &convconfig);
06189     modestr = rb_io_oflags_modestr(oflags);
06190 
06191     port = pipe_open(execarg_obj, modestr, fmode, &convconfig);
06192     if (NIL_P(port)) {
06193         /* child */
06194         if (rb_block_given_p()) {
06195             rb_yield(Qnil);
06196             rb_io_flush(rb_stdout);
06197             rb_io_flush(rb_stderr);
06198             _exit(0);
06199         }
06200         return Qnil;
06201     }
06202     RBASIC_SET_CLASS(port, klass);
06203     if (rb_block_given_p()) {
06204         return rb_ensure(rb_yield, port, io_close, port);
06205     }
06206     return port;
06207 }
06208 
06209 static void
06210 rb_scan_open_args(int argc, const VALUE *argv,
06211         VALUE *fname_p, int *oflags_p, int *fmode_p,
06212         convconfig_t *convconfig_p, mode_t *perm_p)
06213 {
06214     VALUE opt, fname, vmode, vperm;
06215     int oflags, fmode;
06216     mode_t perm;
06217 
06218     argc = rb_scan_args(argc, argv, "12:", &fname, &vmode, &vperm, &opt);
06219     FilePathValue(fname);
06220 
06221     rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, convconfig_p);
06222 
06223     perm = NIL_P(vperm) ? 0666 :  NUM2MODET(vperm);
06224 
06225     *fname_p = fname;
06226     *oflags_p = oflags;
06227     *fmode_p = fmode;
06228     *perm_p = perm;
06229 }
06230 
06231 static VALUE
06232 rb_open_file(int argc, const VALUE *argv, VALUE io)
06233 {
06234     VALUE fname;
06235     int oflags, fmode;
06236     convconfig_t convconfig;
06237     mode_t perm;
06238 
06239     rb_scan_open_args(argc, argv, &fname, &oflags, &fmode, &convconfig, &perm);
06240     rb_file_open_generic(io, fname, oflags, fmode, &convconfig, perm);
06241 
06242     return io;
06243 }
06244 
06245 
06246 /*
06247  *  Document-method: File::open
06248  *
06249  *  call-seq:
06250  *     File.open(filename, mode="r" [, opt])                 -> file
06251  *     File.open(filename [, mode [, perm]] [, opt])         -> file
06252  *     File.open(filename, mode="r" [, opt]) {|file| block } -> obj
06253  *     File.open(filename [, mode [, perm]] [, opt]) {|file| block } -> obj
06254  *
06255  *  With no associated block, <code>File.open</code> is a synonym for
06256  *  File.new. If the optional code block is given, it will
06257  *  be passed the opened +file+ as an argument and the File object will
06258  *  automatically be closed when the block terminates.  The value of the block
06259  *  will be returned from <code>File.open</code>.
06260  *
06261  *  If a file is being created, its initial permissions may be set using the
06262  *  +perm+ parameter.  See File.new for further discussion.
06263  *
06264  *  See IO.new for a description of the +mode+ and +opt+ parameters.
06265  */
06266 
06267 /*
06268  *  Document-method: IO::open
06269  *
06270  *  call-seq:
06271  *     IO.open(fd, mode="r" [, opt])                -> io
06272  *     IO.open(fd, mode="r" [, opt]) { |io| block } -> obj
06273  *
06274  *  With no associated block, <code>IO.open</code> is a synonym for IO.new.  If
06275  *  the optional code block is given, it will be passed +io+ as an argument,
06276  *  and the IO object will automatically be closed when the block terminates.
06277  *  In this instance, IO.open returns the value of the block.
06278  *
06279  *  See IO.new for a description of the +fd+, +mode+ and +opt+ parameters.
06280  */
06281 
06282 static VALUE
06283 rb_io_s_open(int argc, VALUE *argv, VALUE klass)
06284 {
06285     VALUE io = rb_class_new_instance(argc, argv, klass);
06286 
06287     if (rb_block_given_p()) {
06288         return rb_ensure(rb_yield, io, io_close, io);
06289     }
06290 
06291     return io;
06292 }
06293 
06294 /*
06295  *  call-seq:
06296  *     IO.sysopen(path, [mode, [perm]])  -> fixnum
06297  *
06298  *  Opens the given path, returning the underlying file descriptor as a
06299  *  <code>Fixnum</code>.
06300  *
06301  *     IO.sysopen("testfile")   #=> 3
06302  */
06303 
06304 static VALUE
06305 rb_io_s_sysopen(int argc, VALUE *argv)
06306 {
06307     VALUE fname, vmode, vperm;
06308     VALUE intmode;
06309     int oflags, fd;
06310     mode_t perm;
06311 
06312     rb_scan_args(argc, argv, "12", &fname, &vmode, &vperm);
06313     FilePathValue(fname);
06314 
06315     if (NIL_P(vmode))
06316         oflags = O_RDONLY;
06317     else if (!NIL_P(intmode = rb_check_to_integer(vmode, "to_int")))
06318         oflags = NUM2INT(intmode);
06319     else {
06320         SafeStringValue(vmode);
06321         oflags = rb_io_modestr_oflags(StringValueCStr(vmode));
06322     }
06323     if (NIL_P(vperm)) perm = 0666;
06324     else              perm = NUM2MODET(vperm);
06325 
06326     RB_GC_GUARD(fname) = rb_str_new4(fname);
06327     fd = rb_sysopen(fname, oflags, perm);
06328     return INT2NUM(fd);
06329 }
06330 
06331 static VALUE
06332 check_pipe_command(VALUE filename_or_command)
06333 {
06334     char *s = RSTRING_PTR(filename_or_command);
06335     long l = RSTRING_LEN(filename_or_command);
06336     char *e = s + l;
06337     int chlen;
06338 
06339     if (rb_enc_ascget(s, e, &chlen, rb_enc_get(filename_or_command)) == '|') {
06340         VALUE cmd = rb_str_new(s+chlen, l-chlen);
06341         OBJ_INFECT(cmd, filename_or_command);
06342         return cmd;
06343     }
06344     return Qnil;
06345 }
06346 
06347 /*
06348  *  call-seq:
06349  *     open(path [, mode [, perm]] [, opt])                -> io or nil
06350  *     open(path [, mode [, perm]] [, opt]) {|io| block }  -> obj
06351  *
06352  *  Creates an IO object connected to the given stream, file, or subprocess.
06353  *
06354  *  If +path+ does not start with a pipe character (<code>|</code>), treat it
06355  *  as the name of a file to open using the specified mode (defaulting to
06356  *  "r").
06357  *
06358  *  The +mode+ is either a string or an integer.  If it is an integer, it
06359  *  must be bitwise-or of open(2) flags, such as File::RDWR or File::EXCL.  If
06360  *  it is a string, it is either "fmode", "fmode:ext_enc", or
06361  *  "fmode:ext_enc:int_enc".
06362  *
06363  *  See the documentation of IO.new for full documentation of the +mode+ string
06364  *  directives.
06365  *
06366  *  If a file is being created, its initial permissions may be set using the
06367  *  +perm+ parameter.  See File.new and the open(2) and chmod(2) man pages for
06368  *  a description of permissions.
06369  *
06370  *  If a block is specified, it will be invoked with the IO object as a
06371  *  parameter, and the IO will be automatically closed when the block
06372  *  terminates.  The call returns the value of the block.
06373  *
06374  *  If +path+ starts with a pipe character (<code>"|"</code>), a subprocess is
06375  *  created, connected to the caller by a pair of pipes.  The returned IO
06376  *  object may be used to write to the standard input and read from the
06377  *  standard output of this subprocess.
06378  *
06379  *  If the command following the pipe is a single minus sign
06380  *  (<code>"|-"</code>), Ruby forks, and this subprocess is connected to the
06381  *  parent.  If the command is not <code>"-"</code>, the subprocess runs the
06382  *  command.
06383  *
06384  *  When the subprocess is ruby (opened via <code>"|-"</code>), the +open+
06385  *  call returns +nil+.  If a block is associated with the open call, that
06386  *  block will run twice --- once in the parent and once in the child.
06387  *
06388  *  The block parameter will be an IO object in the parent and +nil+ in the
06389  *  child. The parent's +IO+ object will be connected to the child's $stdin
06390  *  and $stdout.  The subprocess will be terminated at the end of the block.
06391  *
06392  *  === Examples
06393  *
06394  *  Reading from "testfile":
06395  *
06396  *     open("testfile") do |f|
06397  *       print f.gets
06398  *     end
06399  *
06400  *  Produces:
06401  *
06402  *     This is line one
06403  *
06404  *  Open a subprocess and read its output:
06405  *
06406  *     cmd = open("|date")
06407  *     print cmd.gets
06408  *     cmd.close
06409  *
06410  *  Produces:
06411  *
06412  *     Wed Apr  9 08:56:31 CDT 2003
06413  *
06414  *  Open a subprocess running the same Ruby program:
06415  *
06416  *     f = open("|-", "w+")
06417  *     if f == nil
06418  *       puts "in Child"
06419  *       exit
06420  *     else
06421  *       puts "Got: #{f.gets}"
06422  *     end
06423  *
06424  *  Produces:
06425  *
06426  *     Got: in Child
06427  *
06428  *  Open a subprocess using a block to receive the IO object:
06429  *
06430  *     open "|-" do |f|
06431  *       if f then
06432  *         # parent process
06433  *         puts "Got: #{f.gets}"
06434  *       else
06435  *         # child process
06436  *         puts "in Child"
06437  *       end
06438  *     end
06439  *
06440  *  Produces:
06441  *
06442  *     Got: in Child
06443  */
06444 
06445 static VALUE
06446 rb_f_open(int argc, VALUE *argv)
06447 {
06448     ID to_open = 0;
06449     int redirect = FALSE;
06450 
06451     if (argc >= 1) {
06452         CONST_ID(to_open, "to_open");
06453         if (rb_respond_to(argv[0], to_open)) {
06454             redirect = TRUE;
06455         }
06456         else {
06457             VALUE tmp = argv[0];
06458             FilePathValue(tmp);
06459             if (NIL_P(tmp)) {
06460                 redirect = TRUE;
06461             }
06462             else {
06463                 VALUE cmd = check_pipe_command(tmp);
06464                 if (!NIL_P(cmd)) {
06465                     argv[0] = cmd;
06466                     return rb_io_s_popen(argc, argv, rb_cIO);
06467                 }
06468             }
06469         }
06470     }
06471     if (redirect) {
06472         VALUE io = rb_funcall2(argv[0], to_open, argc-1, argv+1);
06473 
06474         if (rb_block_given_p()) {
06475             return rb_ensure(rb_yield, io, io_close, io);
06476         }
06477         return io;
06478     }
06479     return rb_io_s_open(argc, argv, rb_cFile);
06480 }
06481 
06482 static VALUE
06483 rb_io_open(VALUE filename, VALUE vmode, VALUE vperm, VALUE opt)
06484 {
06485     VALUE cmd;
06486     int oflags, fmode;
06487     convconfig_t convconfig;
06488     mode_t perm;
06489 
06490     rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, &convconfig);
06491     perm = NIL_P(vperm) ? 0666 :  NUM2MODET(vperm);
06492 
06493     if (!NIL_P(cmd = check_pipe_command(filename))) {
06494         return pipe_open_s(cmd, rb_io_oflags_modestr(oflags), fmode, &convconfig);
06495     }
06496     else {
06497         return rb_file_open_generic(io_alloc(rb_cFile), filename,
06498                 oflags, fmode, &convconfig, perm);
06499     }
06500 }
06501 
06502 static VALUE
06503 rb_io_open_with_args(int argc, const VALUE *argv)
06504 {
06505     VALUE io;
06506 
06507     io = io_alloc(rb_cFile);
06508     rb_open_file(argc, argv, io);
06509     return io;
06510 }
06511 
06512 static VALUE
06513 io_reopen(VALUE io, VALUE nfile)
06514 {
06515     rb_io_t *fptr, *orig;
06516     int fd, fd2;
06517     off_t pos = 0;
06518 
06519     nfile = rb_io_get_io(nfile);
06520     GetOpenFile(io, fptr);
06521     GetOpenFile(nfile, orig);
06522 
06523     if (fptr == orig) return io;
06524     if (IS_PREP_STDIO(fptr)) {
06525         if ((fptr->stdio_file == stdin && !(orig->mode & FMODE_READABLE)) ||
06526             (fptr->stdio_file == stdout && !(orig->mode & FMODE_WRITABLE)) ||
06527             (fptr->stdio_file == stderr && !(orig->mode & FMODE_WRITABLE))) {
06528             rb_raise(rb_eArgError,
06529                      "%s can't change access mode from \"%s\" to \"%s\"",
06530                      PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->mode),
06531                      rb_io_fmode_modestr(orig->mode));
06532         }
06533     }
06534     if (fptr->mode & FMODE_WRITABLE) {
06535         if (io_fflush(fptr) < 0)
06536             rb_sys_fail(0);
06537     }
06538     else {
06539         io_tell(fptr);
06540     }
06541     if (orig->mode & FMODE_READABLE) {
06542         pos = io_tell(orig);
06543     }
06544     if (orig->mode & FMODE_WRITABLE) {
06545         if (io_fflush(orig) < 0)
06546             rb_sys_fail(0);
06547     }
06548 
06549     /* copy rb_io_t structure */
06550     fptr->mode = orig->mode | (fptr->mode & FMODE_PREP);
06551     fptr->pid = orig->pid;
06552     fptr->lineno = orig->lineno;
06553     if (RTEST(orig->pathv)) fptr->pathv = orig->pathv;
06554     else if (!IS_PREP_STDIO(fptr)) fptr->pathv = Qnil;
06555     fptr->finalize = orig->finalize;
06556 #if defined (__CYGWIN__) || !defined(HAVE_FORK)
06557     if (fptr->finalize == pipe_finalize)
06558         pipe_add_fptr(fptr);
06559 #endif
06560 
06561     fd = fptr->fd;
06562     fd2 = orig->fd;
06563     if (fd != fd2) {
06564         if (IS_PREP_STDIO(fptr) || fd <= 2 || !fptr->stdio_file) {
06565             /* need to keep FILE objects of stdin, stdout and stderr */
06566             if (rb_cloexec_dup2(fd2, fd) < 0)
06567                 rb_sys_fail_path(orig->pathv);
06568             rb_update_max_fd(fd);
06569         }
06570         else {
06571             fclose(fptr->stdio_file);
06572             fptr->stdio_file = 0;
06573             fptr->fd = -1;
06574             if (rb_cloexec_dup2(fd2, fd) < 0)
06575                 rb_sys_fail_path(orig->pathv);
06576             rb_update_max_fd(fd);
06577             fptr->fd = fd;
06578         }
06579         rb_thread_fd_close(fd);
06580         if ((orig->mode & FMODE_READABLE) && pos >= 0) {
06581             if (io_seek(fptr, pos, SEEK_SET) < 0 && errno) {
06582                 rb_sys_fail_path(fptr->pathv);
06583             }
06584             if (io_seek(orig, pos, SEEK_SET) < 0 && errno) {
06585                 rb_sys_fail_path(orig->pathv);
06586             }
06587         }
06588     }
06589 
06590     if (fptr->mode & FMODE_BINMODE) {
06591         rb_io_binmode(io);
06592     }
06593 
06594     RBASIC_SET_CLASS(io, rb_obj_class(nfile));
06595     return io;
06596 }
06597 
06598 /*
06599  *  call-seq:
06600  *     ios.reopen(other_IO)         -> ios
06601  *     ios.reopen(path, mode_str)   -> ios
06602  *
06603  *  Reassociates <em>ios</em> with the I/O stream given in
06604  *  <i>other_IO</i> or to a new stream opened on <i>path</i>. This may
06605  *  dynamically change the actual class of this stream.
06606  *
06607  *     f1 = File.new("testfile")
06608  *     f2 = File.new("testfile")
06609  *     f2.readlines[0]   #=> "This is line one\n"
06610  *     f2.reopen(f1)     #=> #<File:testfile>
06611  *     f2.readlines[0]   #=> "This is line one\n"
06612  */
06613 
06614 static VALUE
06615 rb_io_reopen(int argc, VALUE *argv, VALUE file)
06616 {
06617     VALUE fname, nmode, opt;
06618     int oflags;
06619     rb_io_t *fptr;
06620 
06621     if (rb_scan_args(argc, argv, "11:", &fname, &nmode, &opt) == 1) {
06622         VALUE tmp = rb_io_check_io(fname);
06623         if (!NIL_P(tmp)) {
06624             return io_reopen(file, tmp);
06625         }
06626     }
06627 
06628     FilePathValue(fname);
06629     rb_io_taint_check(file);
06630     fptr = RFILE(file)->fptr;
06631     if (!fptr) {
06632         fptr = RFILE(file)->fptr = ALLOC(rb_io_t);
06633         MEMZERO(fptr, rb_io_t, 1);
06634     }
06635 
06636     if (!NIL_P(nmode) || !NIL_P(opt)) {
06637         int fmode;
06638         convconfig_t convconfig;
06639 
06640         rb_io_extract_modeenc(&nmode, 0, opt, &oflags, &fmode, &convconfig);
06641         if (IS_PREP_STDIO(fptr) &&
06642             ((fptr->mode & FMODE_READWRITE) & (fmode & FMODE_READWRITE)) !=
06643             (fptr->mode & FMODE_READWRITE)) {
06644             rb_raise(rb_eArgError,
06645                      "%s can't change access mode from \"%s\" to \"%s\"",
06646                      PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->mode),
06647                      rb_io_fmode_modestr(fmode));
06648         }
06649         fptr->mode = fmode;
06650         fptr->encs = convconfig;
06651     }
06652     else {
06653         oflags = rb_io_fmode_oflags(fptr->mode);
06654     }
06655 
06656     fptr->pathv = rb_str_new_frozen(fname);
06657     if (fptr->fd < 0) {
06658         fptr->fd = rb_sysopen(fptr->pathv, oflags, 0666);
06659         fptr->stdio_file = 0;
06660         return file;
06661     }
06662 
06663     if (fptr->mode & FMODE_WRITABLE) {
06664         if (io_fflush(fptr) < 0)
06665             rb_sys_fail(0);
06666     }
06667     fptr->rbuf.off = fptr->rbuf.len = 0;
06668 
06669     if (fptr->stdio_file) {
06670         if (freopen(RSTRING_PTR(fptr->pathv), rb_io_oflags_modestr(oflags), fptr->stdio_file) == 0) {
06671             rb_sys_fail_path(fptr->pathv);
06672         }
06673         fptr->fd = fileno(fptr->stdio_file);
06674         rb_fd_fix_cloexec(fptr->fd);
06675 #ifdef USE_SETVBUF
06676         if (setvbuf(fptr->stdio_file, NULL, _IOFBF, 0) != 0)
06677             rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
06678 #endif
06679         if (fptr->stdio_file == stderr) {
06680             if (setvbuf(fptr->stdio_file, NULL, _IONBF, BUFSIZ) != 0)
06681                 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
06682         }
06683         else if (fptr->stdio_file == stdout && isatty(fptr->fd)) {
06684             if (setvbuf(fptr->stdio_file, NULL, _IOLBF, BUFSIZ) != 0)
06685                 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
06686         }
06687     }
06688     else {
06689         int tmpfd = rb_sysopen(fptr->pathv, oflags, 0666);
06690         int err = 0;
06691         if (rb_cloexec_dup2(tmpfd, fptr->fd) < 0)
06692             err = errno;
06693         (void)close(tmpfd);
06694         if (err) {
06695             rb_syserr_fail_path(err, fptr->pathv);
06696         }
06697     }
06698 
06699     return file;
06700 }
06701 
06702 /* :nodoc: */
06703 static VALUE
06704 rb_io_init_copy(VALUE dest, VALUE io)
06705 {
06706     rb_io_t *fptr, *orig;
06707     int fd;
06708     VALUE write_io;
06709     off_t pos;
06710 
06711     io = rb_io_get_io(io);
06712     if (!OBJ_INIT_COPY(dest, io)) return dest;
06713     GetOpenFile(io, orig);
06714     MakeOpenFile(dest, fptr);
06715 
06716     rb_io_flush(io);
06717 
06718     /* copy rb_io_t structure */
06719     fptr->mode = orig->mode & ~FMODE_PREP;
06720     fptr->encs = orig->encs;
06721     fptr->pid = orig->pid;
06722     fptr->lineno = orig->lineno;
06723     if (!NIL_P(orig->pathv)) fptr->pathv = orig->pathv;
06724     fptr->finalize = orig->finalize;
06725 #if defined (__CYGWIN__) || !defined(HAVE_FORK)
06726     if (fptr->finalize == pipe_finalize)
06727         pipe_add_fptr(fptr);
06728 #endif
06729 
06730     fd = ruby_dup(orig->fd);
06731     fptr->fd = fd;
06732     pos = io_tell(orig);
06733     if (0 <= pos)
06734         io_seek(fptr, pos, SEEK_SET);
06735     if (fptr->mode & FMODE_BINMODE) {
06736         rb_io_binmode(dest);
06737     }
06738 
06739     write_io = GetWriteIO(io);
06740     if (io != write_io) {
06741         write_io = rb_obj_dup(write_io);
06742         fptr->tied_io_for_writing = write_io;
06743         rb_ivar_set(dest, rb_intern("@tied_io_for_writing"), write_io);
06744     }
06745 
06746     return dest;
06747 }
06748 
06749 /*
06750  *  call-seq:
06751  *     ios.printf(format_string [, obj, ...])   -> nil
06752  *
06753  *  Formats and writes to <em>ios</em>, converting parameters under
06754  *  control of the format string. See <code>Kernel#sprintf</code>
06755  *  for details.
06756  */
06757 
06758 VALUE
06759 rb_io_printf(int argc, VALUE *argv, VALUE out)
06760 {
06761     rb_io_write(out, rb_f_sprintf(argc, argv));
06762     return Qnil;
06763 }
06764 
06765 /*
06766  *  call-seq:
06767  *     printf(io, string [, obj ... ])    -> nil
06768  *     printf(string [, obj ... ])        -> nil
06769  *
06770  *  Equivalent to:
06771  *     io.write(sprintf(string, obj, ...))
06772  *  or
06773  *     $stdout.write(sprintf(string, obj, ...))
06774  */
06775 
06776 static VALUE
06777 rb_f_printf(int argc, VALUE *argv)
06778 {
06779     VALUE out;
06780 
06781     if (argc == 0) return Qnil;
06782     if (RB_TYPE_P(argv[0], T_STRING)) {
06783         out = rb_stdout;
06784     }
06785     else {
06786         out = argv[0];
06787         argv++;
06788         argc--;
06789     }
06790     rb_io_write(out, rb_f_sprintf(argc, argv));
06791 
06792     return Qnil;
06793 }
06794 
06795 /*
06796  *  call-seq:
06797  *     ios.print()             -> nil
06798  *     ios.print(obj, ...)     -> nil
06799  *
06800  *  Writes the given object(s) to <em>ios</em>. The stream must be
06801  *  opened for writing. If the output field separator (<code>$,</code>)
06802  *  is not <code>nil</code>, it will be inserted between each object.
06803  *  If the output record separator (<code>$\</code>)
06804  *  is not <code>nil</code>, it will be appended to the output. If no
06805  *  arguments are given, prints <code>$_</code>. Objects that aren't
06806  *  strings will be converted by calling their <code>to_s</code> method.
06807  *  With no argument, prints the contents of the variable <code>$_</code>.
06808  *  Returns <code>nil</code>.
06809  *
06810  *     $stdout.print("This is ", 100, " percent.\n")
06811  *
06812  *  <em>produces:</em>
06813  *
06814  *     This is 100 percent.
06815  */
06816 
06817 VALUE
06818 rb_io_print(int argc, VALUE *argv, VALUE out)
06819 {
06820     int i;
06821     VALUE line;
06822 
06823     /* if no argument given, print `$_' */
06824     if (argc == 0) {
06825         argc = 1;
06826         line = rb_lastline_get();
06827         argv = &line;
06828     }
06829     for (i=0; i<argc; i++) {
06830         if (!NIL_P(rb_output_fs) && i>0) {
06831             rb_io_write(out, rb_output_fs);
06832         }
06833         rb_io_write(out, argv[i]);
06834     }
06835     if (argc > 0 && !NIL_P(rb_output_rs)) {
06836         rb_io_write(out, rb_output_rs);
06837     }
06838 
06839     return Qnil;
06840 }
06841 
06842 /*
06843  *  call-seq:
06844  *     print(obj, ...)    -> nil
06845  *
06846  *  Prints each object in turn to <code>$stdout</code>. If the output
06847  *  field separator (<code>$,</code>) is not +nil+, its
06848  *  contents will appear between each field. If the output record
06849  *  separator (<code>$\</code>) is not +nil+, it will be
06850  *  appended to the output. If no arguments are given, prints
06851  *  <code>$_</code>. Objects that aren't strings will be converted by
06852  *  calling their <code>to_s</code> method.
06853  *
06854  *     print "cat", [1,2,3], 99, "\n"
06855  *     $, = ", "
06856  *     $\ = "\n"
06857  *     print "cat", [1,2,3], 99
06858  *
06859  *  <em>produces:</em>
06860  *
06861  *     cat12399
06862  *     cat, 1, 2, 3, 99
06863  */
06864 
06865 static VALUE
06866 rb_f_print(int argc, VALUE *argv)
06867 {
06868     rb_io_print(argc, argv, rb_stdout);
06869     return Qnil;
06870 }
06871 
06872 /*
06873  *  call-seq:
06874  *     ios.putc(obj)    -> obj
06875  *
06876  *  If <i>obj</i> is <code>Numeric</code>, write the character whose code is
06877  *  the least-significant byte of <i>obj</i>, otherwise write the first byte
06878  *  of the string representation of <i>obj</i> to <em>ios</em>. Note: This
06879  *  method is not safe for use with multi-byte characters as it will truncate
06880  *  them.
06881  *
06882  *     $stdout.putc "A"
06883  *     $stdout.putc 65
06884  *
06885  *  <em>produces:</em>
06886  *
06887  *     AA
06888  */
06889 
06890 static VALUE
06891 rb_io_putc(VALUE io, VALUE ch)
06892 {
06893     VALUE str;
06894     if (RB_TYPE_P(ch, T_STRING)) {
06895         str = rb_str_substr(ch, 0, 1);
06896     }
06897     else {
06898         char c = NUM2CHR(ch);
06899         str = rb_str_new(&c, 1);
06900     }
06901     rb_io_write(io, str);
06902     return ch;
06903 }
06904 
06905 /*
06906  *  call-seq:
06907  *     putc(int)   -> int
06908  *
06909  *  Equivalent to:
06910  *
06911  *    $stdout.putc(int)
06912  *
06913  * Refer to the documentation for IO#putc for important information regarding
06914  * multi-byte characters.
06915  */
06916 
06917 static VALUE
06918 rb_f_putc(VALUE recv, VALUE ch)
06919 {
06920     if (recv == rb_stdout) {
06921         return rb_io_putc(recv, ch);
06922     }
06923     return rb_funcall2(rb_stdout, rb_intern("putc"), 1, &ch);
06924 }
06925 
06926 
06927 static int
06928 str_end_with_asciichar(VALUE str, int c)
06929 {
06930     long len = RSTRING_LEN(str);
06931     const char *ptr = RSTRING_PTR(str);
06932     rb_encoding *enc = rb_enc_from_index(ENCODING_GET(str));
06933     int n;
06934 
06935     if (len == 0) return 0;
06936     if ((n = rb_enc_mbminlen(enc)) == 1) {
06937         return ptr[len - 1] == c;
06938     }
06939     return rb_enc_ascget(ptr + ((len - 1) / n) * n, ptr + len, &n, enc) == c;
06940 }
06941 
06942 static VALUE
06943 io_puts_ary(VALUE ary, VALUE out, int recur)
06944 {
06945     VALUE tmp;
06946     long i;
06947 
06948     if (recur) {
06949         tmp = rb_str_new2("[...]");
06950         rb_io_puts(1, &tmp, out);
06951         return Qtrue;
06952     }
06953     ary = rb_check_array_type(ary);
06954     if (NIL_P(ary)) return Qfalse;
06955     for (i=0; i<RARRAY_LEN(ary); i++) {
06956         tmp = RARRAY_AREF(ary, i);
06957         rb_io_puts(1, &tmp, out);
06958     }
06959     return Qtrue;
06960 }
06961 
06962 /*
06963  *  call-seq:
06964  *     ios.puts(obj, ...)    -> nil
06965  *
06966  *  Writes the given objects to <em>ios</em> as with
06967  *  <code>IO#print</code>. Writes a record separator (typically a
06968  *  newline) after any that do not already end with a newline sequence.
06969  *  If called with an array argument, writes each element on a new line.
06970  *  If called without arguments, outputs a single record separator.
06971  *
06972  *     $stdout.puts("this", "is", "a", "test")
06973  *
06974  *  <em>produces:</em>
06975  *
06976  *     this
06977  *     is
06978  *     a
06979  *     test
06980  */
06981 
06982 VALUE
06983 rb_io_puts(int argc, VALUE *argv, VALUE out)
06984 {
06985     int i;
06986     VALUE line;
06987 
06988     /* if no argument given, print newline. */
06989     if (argc == 0) {
06990         rb_io_write(out, rb_default_rs);
06991         return Qnil;
06992     }
06993     for (i=0; i<argc; i++) {
06994         if (RB_TYPE_P(argv[i], T_STRING)) {
06995             line = argv[i];
06996             goto string;
06997         }
06998         if (rb_exec_recursive(io_puts_ary, argv[i], out)) {
06999             continue;
07000         }
07001         line = rb_obj_as_string(argv[i]);
07002       string:
07003         rb_io_write(out, line);
07004         if (RSTRING_LEN(line) == 0 ||
07005             !str_end_with_asciichar(line, '\n')) {
07006             rb_io_write(out, rb_default_rs);
07007         }
07008     }
07009 
07010     return Qnil;
07011 }
07012 
07013 /*
07014  *  call-seq:
07015  *     puts(obj, ...)    -> nil
07016  *
07017  *  Equivalent to
07018  *
07019  *      $stdout.puts(obj, ...)
07020  */
07021 
07022 static VALUE
07023 rb_f_puts(int argc, VALUE *argv, VALUE recv)
07024 {
07025     if (recv == rb_stdout) {
07026         return rb_io_puts(argc, argv, recv);
07027     }
07028     return rb_funcall2(rb_stdout, rb_intern("puts"), argc, argv);
07029 }
07030 
07031 void
07032 rb_p(VALUE obj) /* for debug print within C code */
07033 {
07034     VALUE str = rb_obj_as_string(rb_inspect(obj));
07035     if (RB_TYPE_P(rb_stdout, T_FILE) &&
07036         rb_method_basic_definition_p(CLASS_OF(rb_stdout), id_write)) {
07037         io_write(rb_stdout, str, 1);
07038         io_write(rb_stdout, rb_default_rs, 0);
07039     }
07040     else {
07041         rb_io_write(rb_stdout, str);
07042         rb_io_write(rb_stdout, rb_default_rs);
07043     }
07044 }
07045 
07046 struct rb_f_p_arg {
07047     int argc;
07048     VALUE *argv;
07049 };
07050 
07051 static VALUE
07052 rb_f_p_internal(VALUE arg)
07053 {
07054     struct rb_f_p_arg *arg1 = (struct rb_f_p_arg*)arg;
07055     int argc = arg1->argc;
07056     VALUE *argv = arg1->argv;
07057     int i;
07058     VALUE ret = Qnil;
07059 
07060     for (i=0; i<argc; i++) {
07061         rb_p(argv[i]);
07062     }
07063     if (argc == 1) {
07064         ret = argv[0];
07065     }
07066     else if (argc > 1) {
07067         ret = rb_ary_new4(argc, argv);
07068     }
07069     if (RB_TYPE_P(rb_stdout, T_FILE)) {
07070         rb_io_flush(rb_stdout);
07071     }
07072     return ret;
07073 }
07074 
07075 /*
07076  *  call-seq:
07077  *     p(obj)              -> obj
07078  *     p(obj1, obj2, ...)  -> [obj, ...]
07079  *     p()                 -> nil
07080  *
07081  *  For each object, directly writes _obj_.+inspect+ followed by a
07082  *  newline to the program's standard output.
07083  *
07084  *     S = Struct.new(:name, :state)
07085  *     s = S['dave', 'TX']
07086  *     p s
07087  *
07088  *  <em>produces:</em>
07089  *
07090  *     #<S name="dave", state="TX">
07091  */
07092 
07093 static VALUE
07094 rb_f_p(int argc, VALUE *argv, VALUE self)
07095 {
07096     struct rb_f_p_arg arg;
07097     arg.argc = argc;
07098     arg.argv = argv;
07099 
07100     return rb_uninterruptible(rb_f_p_internal, (VALUE)&arg);
07101 }
07102 
07103 /*
07104  *  call-seq:
07105  *     obj.display(port=$>)    -> nil
07106  *
07107  *  Prints <i>obj</i> on the given port (default <code>$></code>).
07108  *  Equivalent to:
07109  *
07110  *     def display(port=$>)
07111  *       port.write self
07112  *     end
07113  *
07114  *  For example:
07115  *
07116  *     1.display
07117  *     "cat".display
07118  *     [ 4, 5, 6 ].display
07119  *     puts
07120  *
07121  *  <em>produces:</em>
07122  *
07123  *     1cat456
07124  */
07125 
07126 static VALUE
07127 rb_obj_display(int argc, VALUE *argv, VALUE self)
07128 {
07129     VALUE out;
07130 
07131     if (argc == 0) {
07132         out = rb_stdout;
07133     }
07134     else {
07135         rb_scan_args(argc, argv, "01", &out);
07136     }
07137     rb_io_write(out, self);
07138 
07139     return Qnil;
07140 }
07141 
07142 void
07143 rb_write_error2(const char *mesg, long len)
07144 {
07145     if (rb_stderr == orig_stderr || RFILE(orig_stderr)->fptr->fd < 0) {
07146         if (fwrite(mesg, sizeof(char), (size_t)len, stderr) < (size_t)len) {
07147             /* failed to write to stderr, what can we do? */
07148             return;
07149         }
07150     }
07151     else {
07152         rb_io_write(rb_stderr, rb_str_new(mesg, len));
07153     }
07154 }
07155 
07156 void
07157 rb_write_error(const char *mesg)
07158 {
07159     rb_write_error2(mesg, strlen(mesg));
07160 }
07161 
07162 void
07163 rb_write_error_str(VALUE mesg)
07164 {
07165     /* a stopgap measure for the time being */
07166     if (rb_stderr == orig_stderr || RFILE(orig_stderr)->fptr->fd < 0) {
07167         size_t len = (size_t)RSTRING_LEN(mesg);
07168         if (fwrite(RSTRING_PTR(mesg), sizeof(char), len, stderr) < len) {
07169             RB_GC_GUARD(mesg);
07170             return;
07171         }
07172     }
07173     else {
07174         /* may unlock GVL, and  */
07175         rb_io_write(rb_stderr, mesg);
07176     }
07177 }
07178 
07179 static void
07180 must_respond_to(ID mid, VALUE val, ID id)
07181 {
07182     if (!rb_respond_to(val, mid)) {
07183         rb_raise(rb_eTypeError, "%s must have %s method, %s given",
07184                  rb_id2name(id), rb_id2name(mid),
07185                  rb_obj_classname(val));
07186     }
07187 }
07188 
07189 static void
07190 stdout_setter(VALUE val, ID id, VALUE *variable)
07191 {
07192     must_respond_to(id_write, val, id);
07193     *variable = val;
07194 }
07195 
07196 static VALUE
07197 prep_io(int fd, int fmode, VALUE klass, const char *path)
07198 {
07199     rb_io_t *fp;
07200     VALUE io = io_alloc(klass);
07201 
07202     MakeOpenFile(io, fp);
07203     fp->fd = fd;
07204 #ifdef __CYGWIN__
07205     if (!isatty(fd)) {
07206         fmode |= FMODE_BINMODE;
07207         setmode(fd, O_BINARY);
07208     }
07209 #endif
07210     fp->mode = fmode;
07211     io_check_tty(fp);
07212     if (path) fp->pathv = rb_obj_freeze(rb_str_new_cstr(path));
07213     rb_update_max_fd(fd);
07214 
07215     return io;
07216 }
07217 
07218 VALUE
07219 rb_io_fdopen(int fd, int oflags, const char *path)
07220 {
07221     VALUE klass = rb_cIO;
07222 
07223     if (path && strcmp(path, "-")) klass = rb_cFile;
07224     return prep_io(fd, rb_io_oflags_fmode(oflags), klass, path);
07225 }
07226 
07227 static VALUE
07228 prep_stdio(FILE *f, int fmode, VALUE klass, const char *path)
07229 {
07230     rb_io_t *fptr;
07231     VALUE io = prep_io(fileno(f), fmode|FMODE_PREP|DEFAULT_TEXTMODE, klass, path);
07232 
07233     GetOpenFile(io, fptr);
07234     fptr->encs.ecflags |= ECONV_DEFAULT_NEWLINE_DECORATOR;
07235 #ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
07236     fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
07237     if (fmode & FMODE_READABLE) {
07238         fptr->encs.ecflags |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;
07239     }
07240 #endif
07241     fptr->stdio_file = f;
07242 
07243     return io;
07244 }
07245 
07246 FILE *
07247 rb_io_stdio_file(rb_io_t *fptr)
07248 {
07249     if (!fptr->stdio_file) {
07250         int oflags = rb_io_fmode_oflags(fptr->mode);
07251         fptr->stdio_file = rb_fdopen(fptr->fd, rb_io_oflags_modestr(oflags));
07252     }
07253     return fptr->stdio_file;
07254 }
07255 
07256 /*
07257  *  call-seq:
07258  *     IO.new(fd [, mode] [, opt])   -> io
07259  *
07260  *  Returns a new IO object (a stream) for the given integer file descriptor
07261  *  +fd+ and +mode+ string.  +opt+ may be used to specify parts of +mode+ in a
07262  *  more readable fashion.  See also IO.sysopen and IO.for_fd.
07263  *
07264  *  IO.new is called by various File and IO opening methods such as IO::open,
07265  *  Kernel#open, and File::open.
07266  *
07267  *  === Open Mode
07268  *
07269  *  When +mode+ is an integer it must be combination of the modes defined in
07270  *  File::Constants (+File::RDONLY+, +File::WRONLY | File::CREAT+).  See the
07271  *  open(2) man page for more information.
07272  *
07273  *  When +mode+ is a string it must be in one of the following forms:
07274  *
07275  *    fmode
07276  *    fmode ":" ext_enc
07277  *    fmode ":" ext_enc ":" int_enc
07278  *    fmode ":" "BOM|UTF-*"
07279  *
07280  *  +fmode+ is an IO open mode string, +ext_enc+ is the external encoding for
07281  *  the IO and +int_enc+ is the internal encoding.
07282  *
07283  *  ==== IO Open Mode
07284  *
07285  *  Ruby allows the following open modes:
07286  *
07287  *      "r"  Read-only, starts at beginning of file  (default mode).
07288  *
07289  *      "r+" Read-write, starts at beginning of file.
07290  *
07291  *      "w"  Write-only, truncates existing file
07292  *           to zero length or creates a new file for writing.
07293  *
07294  *      "w+" Read-write, truncates existing file to zero length
07295  *           or creates a new file for reading and writing.
07296  *
07297  *      "a"  Write-only, each write call appends data at end of file.
07298  *           Creates a new file for writing if file does not exist.
07299  *
07300  *      "a+" Read-write, each write call appends data at end of file.
07301  *           Creates a new file for reading and writing if file does
07302  *           not exist.
07303  *
07304  *  The following modes must be used separately, and along with one or more of
07305  *  the modes seen above.
07306  *
07307  *      "b"  Binary file mode
07308  *           Suppresses EOL <-> CRLF conversion on Windows. And
07309  *           sets external encoding to ASCII-8BIT unless explicitly
07310  *           specified.
07311  *
07312  *      "t"  Text file mode
07313  *
07314  *  When the open mode of original IO is read only, the mode cannot be
07315  *  changed to be writable.  Similarly, the open mode cannot be changed from
07316  *  write only to readable.
07317  *
07318  *  When such a change is attempted the error is raised in different locations
07319  *  according to the platform.
07320  *
07321  *  === IO Encoding
07322  *
07323  *  When +ext_enc+ is specified, strings read will be tagged by the encoding
07324  *  when reading, and strings output will be converted to the specified
07325  *  encoding when writing.
07326  *
07327  *  When +ext_enc+ and +int_enc+ are specified read strings will be converted
07328  *  from +ext_enc+ to +int_enc+ upon input, and written strings will be
07329  *  converted from +int_enc+ to +ext_enc+ upon output.  See Encoding for
07330  *  further details of transcoding on input and output.
07331  *
07332  *  If "BOM|UTF-8", "BOM|UTF-16LE" or "BOM|UTF16-BE" are used, ruby checks for
07333  *  a Unicode BOM in the input document to help determine the encoding.  For
07334  *  UTF-16 encodings the file open mode must be binary.  When present, the BOM
07335  *  is stripped and the external encoding from the BOM is used.  When the BOM
07336  *  is missing the given Unicode encoding is used as +ext_enc+.  (The BOM-set
07337  *  encoding option is case insensitive, so "bom|utf-8" is also valid.)
07338  *
07339  *  === Options
07340  *
07341  *  +opt+ can be used instead of +mode+ for improved readability.  The
07342  *  following keys are supported:
07343  *
07344  *  :mode ::
07345  *    Same as +mode+ parameter
07346  *
07347  *  :\external_encoding ::
07348  *    External encoding for the IO.  "-" is a synonym for the default external
07349  *    encoding.
07350  *
07351  *  :\internal_encoding ::
07352  *    Internal encoding for the IO.  "-" is a synonym for the default internal
07353  *    encoding.
07354  *
07355  *    If the value is nil no conversion occurs.
07356  *
07357  *  :encoding ::
07358  *    Specifies external and internal encodings as "extern:intern".
07359  *
07360  *  :textmode ::
07361  *    If the value is truth value, same as "t" in argument +mode+.
07362  *
07363  *  :binmode ::
07364  *    If the value is truth value, same as "b" in argument +mode+.
07365  *
07366  *  :autoclose ::
07367  *    If the value is +false+, the +fd+ will be kept open after this IO
07368  *    instance gets finalized.
07369  *
07370  *  Also, +opt+ can have same keys in String#encode for controlling conversion
07371  *  between the external encoding and the internal encoding.
07372  *
07373  *  === Example 1
07374  *
07375  *    fd = IO.sysopen("/dev/tty", "w")
07376  *    a = IO.new(fd,"w")
07377  *    $stderr.puts "Hello"
07378  *    a.puts "World"
07379  *
07380  *  Produces:
07381  *
07382  *    Hello
07383  *    World
07384  *
07385  *  === Example 2
07386  *
07387  *    require 'fcntl'
07388  *
07389  *    fd = STDERR.fcntl(Fcntl::F_DUPFD)
07390  *    io = IO.new(fd, mode: 'w:UTF-16LE', cr_newline: true)
07391  *    io.puts "Hello, World!"
07392  *
07393  *    fd = STDERR.fcntl(Fcntl::F_DUPFD)
07394  *    io = IO.new(fd, mode: 'w', cr_newline: true,
07395  *                external_encoding: Encoding::UTF_16LE)
07396  *    io.puts "Hello, World!"
07397  *
07398  *  Both of above print "Hello, World!" in UTF-16LE to standard error output
07399  *  with converting EOL generated by <code>puts</code> to CR.
07400  */
07401 
07402 static VALUE
07403 rb_io_initialize(int argc, VALUE *argv, VALUE io)
07404 {
07405     VALUE fnum, vmode;
07406     rb_io_t *fp;
07407     int fd, fmode, oflags = O_RDONLY;
07408     convconfig_t convconfig;
07409     VALUE opt;
07410 #if defined(HAVE_FCNTL) && defined(F_GETFL)
07411     int ofmode;
07412 #else
07413     struct stat st;
07414 #endif
07415 
07416 
07417     argc = rb_scan_args(argc, argv, "11:", &fnum, &vmode, &opt);
07418     rb_io_extract_modeenc(&vmode, 0, opt, &oflags, &fmode, &convconfig);
07419 
07420     fd = NUM2INT(fnum);
07421     if (rb_reserved_fd_p(fd)) {
07422         rb_raise(rb_eArgError, "The given fd is not accessible because RubyVM reserves it");
07423     }
07424 #if defined(HAVE_FCNTL) && defined(F_GETFL)
07425     oflags = fcntl(fd, F_GETFL);
07426     if (oflags == -1) rb_sys_fail(0);
07427 #else
07428     if (fstat(fd, &st) == -1) rb_sys_fail(0);
07429 #endif
07430     rb_update_max_fd(fd);
07431 #if defined(HAVE_FCNTL) && defined(F_GETFL)
07432     ofmode = rb_io_oflags_fmode(oflags);
07433     if (NIL_P(vmode)) {
07434         fmode = ofmode;
07435     }
07436     else if ((~ofmode & fmode) & FMODE_READWRITE) {
07437         VALUE error = INT2FIX(EINVAL);
07438         rb_exc_raise(rb_class_new_instance(1, &error, rb_eSystemCallError));
07439     }
07440 #endif
07441     if (!NIL_P(opt) && rb_hash_aref(opt, sym_autoclose) == Qfalse) {
07442         fmode |= FMODE_PREP;
07443     }
07444     MakeOpenFile(io, fp);
07445     fp->fd = fd;
07446     fp->mode = fmode;
07447     fp->encs = convconfig;
07448     clear_codeconv(fp);
07449     io_check_tty(fp);
07450     if (fileno(stdin) == fd)
07451         fp->stdio_file = stdin;
07452     else if (fileno(stdout) == fd)
07453         fp->stdio_file = stdout;
07454     else if (fileno(stderr) == fd)
07455         fp->stdio_file = stderr;
07456 
07457     if (fmode & FMODE_SETENC_BY_BOM) io_set_encoding_by_bom(io);
07458     return io;
07459 }
07460 
07461 /*
07462  *  call-seq:
07463  *     File.new(filename, mode="r" [, opt])            -> file
07464  *     File.new(filename [, mode [, perm]] [, opt])    -> file
07465  *
07466  *  Opens the file named by +filename+ according to the given +mode+ and
07467  *  returns a new File object.
07468  *
07469  *  See IO.new for a description of +mode+ and +opt+.
07470  *
07471  *  If a file is being created, permission bits may be given in +perm+.  These
07472  *  mode and permission bits are platform dependent; on Unix systems, see
07473  *  open(2) and chmod(2) man pages for details.
07474  *
07475  *  === Examples
07476  *
07477  *    f = File.new("testfile", "r")
07478  *    f = File.new("newfile",  "w+")
07479  *    f = File.new("newfile", File::CREAT|File::TRUNC|File::RDWR, 0644)
07480  */
07481 
07482 static VALUE
07483 rb_file_initialize(int argc, VALUE *argv, VALUE io)
07484 {
07485     if (RFILE(io)->fptr) {
07486         rb_raise(rb_eRuntimeError, "reinitializing File");
07487     }
07488     if (0 < argc && argc < 3) {
07489         VALUE fd = rb_check_convert_type(argv[0], T_FIXNUM, "Fixnum", "to_int");
07490 
07491         if (!NIL_P(fd)) {
07492             argv[0] = fd;
07493             return rb_io_initialize(argc, argv, io);
07494         }
07495     }
07496     rb_open_file(argc, argv, io);
07497 
07498     return io;
07499 }
07500 
07501 /* :nodoc: */
07502 static VALUE
07503 rb_io_s_new(int argc, VALUE *argv, VALUE klass)
07504 {
07505     if (rb_block_given_p()) {
07506         const char *cname = rb_class2name(klass);
07507 
07508         rb_warn("%s::new() does not take block; use %s::open() instead",
07509                 cname, cname);
07510     }
07511     return rb_class_new_instance(argc, argv, klass);
07512 }
07513 
07514 
07515 /*
07516  *  call-seq:
07517  *     IO.for_fd(fd, mode [, opt])    -> io
07518  *
07519  *  Synonym for <code>IO.new</code>.
07520  *
07521  */
07522 
07523 static VALUE
07524 rb_io_s_for_fd(int argc, VALUE *argv, VALUE klass)
07525 {
07526     VALUE io = rb_obj_alloc(klass);
07527     rb_io_initialize(argc, argv, io);
07528     return io;
07529 }
07530 
07531 /*
07532  *  call-seq:
07533  *     ios.autoclose?   -> true or false
07534  *
07535  *  Returns +true+ if the underlying file descriptor of _ios_ will be
07536  *  closed automatically at its finalization, otherwise +false+.
07537  */
07538 
07539 static VALUE
07540 rb_io_autoclose_p(VALUE io)
07541 {
07542     rb_io_t *fptr = RFILE(io)->fptr;
07543     rb_io_check_closed(fptr);
07544     return (fptr->mode & FMODE_PREP) ? Qfalse : Qtrue;
07545 }
07546 
07547 /*
07548  *  call-seq:
07549  *     io.autoclose = bool    -> true or false
07550  *
07551  *  Sets auto-close flag.
07552  *
07553  *     f = open("/dev/null")
07554  *     IO.for_fd(f.fileno)
07555  *     # ...
07556  *     f.gets # may cause IOError
07557  *
07558  *     f = open("/dev/null")
07559  *     IO.for_fd(f.fileno).autoclose = true
07560  *     # ...
07561  *     f.gets # won't cause IOError
07562  */
07563 
07564 static VALUE
07565 rb_io_set_autoclose(VALUE io, VALUE autoclose)
07566 {
07567     rb_io_t *fptr;
07568     GetOpenFile(io, fptr);
07569     if (!RTEST(autoclose))
07570         fptr->mode |= FMODE_PREP;
07571     else
07572         fptr->mode &= ~FMODE_PREP;
07573     return io;
07574 }
07575 
07576 static void
07577 argf_mark(void *ptr)
07578 {
07579     struct argf *p = ptr;
07580     rb_gc_mark(p->filename);
07581     rb_gc_mark(p->current_file);
07582     rb_gc_mark(p->argv);
07583     rb_gc_mark(p->encs.ecopts);
07584 }
07585 
07586 static void
07587 argf_free(void *ptr)
07588 {
07589     struct argf *p = ptr;
07590     xfree(p->inplace);
07591     xfree(p);
07592 }
07593 
07594 static size_t
07595 argf_memsize(const void *ptr)
07596 {
07597     const struct argf *p = ptr;
07598     size_t size = sizeof(*p);
07599     if (!ptr) return 0;
07600     if (p->inplace) size += strlen(p->inplace) + 1;
07601     return size;
07602 }
07603 
07604 static const rb_data_type_t argf_type = {
07605     "ARGF",
07606     {argf_mark, argf_free, argf_memsize},
07607     NULL, NULL, RUBY_TYPED_FREE_IMMEDIATELY
07608 };
07609 
07610 static inline void
07611 argf_init(struct argf *p, VALUE v)
07612 {
07613     p->filename = Qnil;
07614     p->current_file = Qnil;
07615     p->lineno = 0;
07616     p->argv = v;
07617 }
07618 
07619 static VALUE
07620 argf_alloc(VALUE klass)
07621 {
07622     struct argf *p;
07623     VALUE argf = TypedData_Make_Struct(klass, struct argf, &argf_type, p);
07624 
07625     argf_init(p, Qnil);
07626     return argf;
07627 }
07628 
07629 #undef rb_argv
07630 
07631 /* :nodoc: */
07632 static VALUE
07633 argf_initialize(VALUE argf, VALUE argv)
07634 {
07635     memset(&ARGF, 0, sizeof(ARGF));
07636     argf_init(&ARGF, argv);
07637 
07638     return argf;
07639 }
07640 
07641 /* :nodoc: */
07642 static VALUE
07643 argf_initialize_copy(VALUE argf, VALUE orig)
07644 {
07645     if (!OBJ_INIT_COPY(argf, orig)) return argf;
07646     ARGF = argf_of(orig);
07647     ARGF.argv = rb_obj_dup(ARGF.argv);
07648     if (ARGF.inplace) {
07649         const char *inplace = ARGF.inplace;
07650         ARGF.inplace = 0;
07651         ARGF.inplace = ruby_strdup(inplace);
07652     }
07653     return argf;
07654 }
07655 
07656 /*
07657  *  call-seq:
07658  *     ARGF.lineno = integer  -> integer
07659  *
07660  *  Sets the line number of +ARGF+ as a whole to the given +Integer+.
07661  *
07662  *  +ARGF+ sets the line number automatically as you read data, so normally
07663  *  you will not need to set it explicitly. To access the current line number
07664  *  use +ARGF.lineno+.
07665  *
07666  *  For example:
07667  *
07668  *      ARGF.lineno      #=> 0
07669  *      ARGF.readline    #=> "This is line 1\n"
07670  *      ARGF.lineno      #=> 1
07671  *      ARGF.lineno = 0  #=> 0
07672  *      ARGF.lineno      #=> 0
07673  */
07674 static VALUE
07675 argf_set_lineno(VALUE argf, VALUE val)
07676 {
07677     ARGF.lineno = NUM2INT(val);
07678     ARGF.last_lineno = ARGF.lineno;
07679     return Qnil;
07680 }
07681 
07682 /*
07683  *  call-seq:
07684  *     ARGF.lineno -> integer
07685  *
07686  *  Returns the current line number of ARGF as a whole. This value
07687  *  can be set manually with +ARGF.lineno=+.
07688  *
07689  *  For example:
07690  *
07691  *      ARGF.lineno   #=> 0
07692  *      ARGF.readline #=> "This is line 1\n"
07693  *      ARGF.lineno   #=> 1
07694  */
07695 static VALUE
07696 argf_lineno(VALUE argf)
07697 {
07698     return INT2FIX(ARGF.lineno);
07699 }
07700 
07701 static VALUE
07702 argf_forward(int argc, VALUE *argv, VALUE argf)
07703 {
07704     return rb_funcall3(ARGF.current_file, rb_frame_this_func(), argc, argv);
07705 }
07706 
07707 #define next_argv() argf_next_argv(argf)
07708 #define ARGF_GENERIC_INPUT_P() \
07709     (ARGF.current_file == rb_stdin && !RB_TYPE_P(ARGF.current_file, T_FILE))
07710 #define ARGF_FORWARD(argc, argv) do {\
07711     if (ARGF_GENERIC_INPUT_P())\
07712         return argf_forward((argc), (argv), argf);\
07713 } while (0)
07714 #define NEXT_ARGF_FORWARD(argc, argv) do {\
07715     if (!next_argv()) return Qnil;\
07716     ARGF_FORWARD((argc), (argv));\
07717 } while (0)
07718 
07719 static void
07720 argf_close(VALUE argf)
07721 {
07722     VALUE file = ARGF.current_file;
07723     if (file == rb_stdin) return;
07724     if (RB_TYPE_P(file, T_FILE)) {
07725         rb_io_set_write_io(file, Qnil);
07726     }
07727     rb_funcall3(file, rb_intern("close"), 0, 0);
07728     ARGF.init_p = -1;
07729 }
07730 
07731 static int
07732 argf_next_argv(VALUE argf)
07733 {
07734     char *fn;
07735     rb_io_t *fptr;
07736     int stdout_binmode = 0;
07737     int fmode;
07738 
07739     if (RB_TYPE_P(rb_stdout, T_FILE)) {
07740         GetOpenFile(rb_stdout, fptr);
07741         if (fptr->mode & FMODE_BINMODE)
07742             stdout_binmode = 1;
07743     }
07744 
07745     if (ARGF.init_p == 0) {
07746         if (!NIL_P(ARGF.argv) && RARRAY_LEN(ARGF.argv) > 0) {
07747             ARGF.next_p = 1;
07748         }
07749         else {
07750             ARGF.next_p = -1;
07751         }
07752         ARGF.init_p = 1;
07753     }
07754     else {
07755         if (NIL_P(ARGF.argv)) {
07756             ARGF.next_p = -1;
07757         }
07758         else if (ARGF.next_p == -1 && RARRAY_LEN(ARGF.argv) > 0) {
07759             ARGF.next_p = 1;
07760         }
07761     }
07762 
07763     if (ARGF.next_p == 1) {
07764       retry:
07765         if (RARRAY_LEN(ARGF.argv) > 0) {
07766             ARGF.filename = rb_ary_shift(ARGF.argv);
07767             fn = StringValueCStr(ARGF.filename);
07768             if (strlen(fn) == 1 && fn[0] == '-') {
07769                 ARGF.current_file = rb_stdin;
07770                 if (ARGF.inplace) {
07771                     rb_warn("Can't do inplace edit for stdio; skipping");
07772                     goto retry;
07773                 }
07774             }
07775             else {
07776                 VALUE write_io = Qnil;
07777                 int fr = rb_sysopen(ARGF.filename, O_RDONLY, 0);
07778 
07779                 if (ARGF.inplace) {
07780                     struct stat st;
07781 #ifndef NO_SAFE_RENAME
07782                     struct stat st2;
07783 #endif
07784                     VALUE str;
07785                     int fw;
07786 
07787                     if (RB_TYPE_P(rb_stdout, T_FILE) && rb_stdout != orig_stdout) {
07788                         rb_io_close(rb_stdout);
07789                     }
07790                     fstat(fr, &st);
07791                     if (*ARGF.inplace) {
07792                         str = rb_str_new2(fn);
07793                         rb_str_cat2(str, ARGF.inplace);
07794 #ifdef NO_SAFE_RENAME
07795                         (void)close(fr);
07796                         (void)unlink(RSTRING_PTR(str));
07797                         if (rename(fn, RSTRING_PTR(str)) < 0) {
07798                             rb_warn("Can't rename %s to %s: %s, skipping file",
07799                                     fn, RSTRING_PTR(str), strerror(errno));
07800                             goto retry;
07801                         }
07802                         fr = rb_sysopen(str, O_RDONLY, 0);
07803 #else
07804                         if (rename(fn, RSTRING_PTR(str)) < 0) {
07805                             rb_warn("Can't rename %s to %s: %s, skipping file",
07806                                     fn, RSTRING_PTR(str), strerror(errno));
07807                             close(fr);
07808                             goto retry;
07809                         }
07810 #endif
07811                     }
07812                     else {
07813 #ifdef NO_SAFE_RENAME
07814                         rb_fatal("Can't do inplace edit without backup");
07815 #else
07816                         if (unlink(fn) < 0) {
07817                             rb_warn("Can't remove %s: %s, skipping file",
07818                                     fn, strerror(errno));
07819                             close(fr);
07820                             goto retry;
07821                         }
07822 #endif
07823                     }
07824                     fw = rb_sysopen(ARGF.filename, O_WRONLY|O_CREAT|O_TRUNC, 0666);
07825 #ifndef NO_SAFE_RENAME
07826                     fstat(fw, &st2);
07827 #ifdef HAVE_FCHMOD
07828                     fchmod(fw, st.st_mode);
07829 #else
07830                     chmod(fn, st.st_mode);
07831 #endif
07832                     if (st.st_uid!=st2.st_uid || st.st_gid!=st2.st_gid) {
07833                         int err;
07834 #ifdef HAVE_FCHOWN
07835                         err = fchown(fw, st.st_uid, st.st_gid);
07836 #else
07837                         err = chown(fn, st.st_uid, st.st_gid);
07838 #endif
07839                         if (err && getuid() == 0 && st2.st_uid == 0) {
07840                             const char *wkfn = RSTRING_PTR(ARGF.filename);
07841                             rb_warn("Can't set owner/group of %s to same as %s: %s, skipping file",
07842                                     wkfn, fn, strerror(errno));
07843                             (void)close(fr);
07844                             (void)close(fw);
07845                             (void)unlink(wkfn);
07846                             goto retry;
07847                         }
07848                     }
07849 #endif
07850                     write_io = prep_io(fw, FMODE_WRITABLE, rb_cFile, fn);
07851                     rb_stdout = write_io;
07852                     if (stdout_binmode) rb_io_binmode(rb_stdout);
07853                 }
07854                 fmode = FMODE_READABLE;
07855                 if (!ARGF.binmode) {
07856                     fmode |= DEFAULT_TEXTMODE;
07857                 }
07858                 ARGF.current_file = prep_io(fr, fmode, rb_cFile, fn);
07859                 if (!NIL_P(write_io)) {
07860                     rb_io_set_write_io(ARGF.current_file, write_io);
07861                 }
07862             }
07863             if (ARGF.binmode) rb_io_ascii8bit_binmode(ARGF.current_file);
07864             GetOpenFile(ARGF.current_file, fptr);
07865             if (ARGF.encs.enc) {
07866                 fptr->encs = ARGF.encs;
07867                 clear_codeconv(fptr);
07868             }
07869             else {
07870                 fptr->encs.ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
07871                 if (!ARGF.binmode) {
07872                     fptr->encs.ecflags |= ECONV_DEFAULT_NEWLINE_DECORATOR;
07873 #ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
07874                     fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
07875 #endif
07876                 }
07877             }
07878             ARGF.next_p = 0;
07879         }
07880         else {
07881             ARGF.next_p = 1;
07882             return FALSE;
07883         }
07884     }
07885     else if (ARGF.next_p == -1) {
07886         ARGF.current_file = rb_stdin;
07887         ARGF.filename = rb_str_new2("-");
07888         if (ARGF.inplace) {
07889             rb_warn("Can't do inplace edit for stdio");
07890             rb_stdout = orig_stdout;
07891         }
07892     }
07893     if (ARGF.init_p == -1) ARGF.init_p = 1;
07894     return TRUE;
07895 }
07896 
07897 static VALUE
07898 argf_getline(int argc, VALUE *argv, VALUE argf)
07899 {
07900     VALUE line;
07901     long lineno = ARGF.lineno;
07902 
07903   retry:
07904     if (!next_argv()) return Qnil;
07905     if (ARGF_GENERIC_INPUT_P()) {
07906         line = rb_funcall3(ARGF.current_file, idGets, argc, argv);
07907     }
07908     else {
07909         if (argc == 0 && rb_rs == rb_default_rs) {
07910             line = rb_io_gets(ARGF.current_file);
07911         }
07912         else {
07913             line = rb_io_getline(argc, argv, ARGF.current_file);
07914         }
07915         if (NIL_P(line) && ARGF.next_p != -1) {
07916             argf_close(argf);
07917             ARGF.next_p = 1;
07918             goto retry;
07919         }
07920     }
07921     if (!NIL_P(line)) {
07922         ARGF.lineno = ++lineno;
07923         ARGF.last_lineno = ARGF.lineno;
07924     }
07925     return line;
07926 }
07927 
07928 static VALUE
07929 argf_lineno_getter(ID id, VALUE *var)
07930 {
07931     VALUE argf = *var;
07932     return INT2FIX(ARGF.last_lineno);
07933 }
07934 
07935 static void
07936 argf_lineno_setter(VALUE val, ID id, VALUE *var)
07937 {
07938     VALUE argf = *var;
07939     int n = NUM2INT(val);
07940     ARGF.last_lineno = ARGF.lineno = n;
07941 }
07942 
07943 static VALUE argf_gets(int, VALUE *, VALUE);
07944 
07945 /*
07946  *  call-seq:
07947  *     gets(sep=$/)    -> string or nil
07948  *     gets(limit)     -> string or nil
07949  *     gets(sep,limit) -> string or nil
07950  *
07951  *  Returns (and assigns to <code>$_</code>) the next line from the list
07952  *  of files in +ARGV+ (or <code>$*</code>), or from standard input if
07953  *  no files are present on the command line. Returns +nil+ at end of
07954  *  file. The optional argument specifies the record separator. The
07955  *  separator is included with the contents of each record. A separator
07956  *  of +nil+ reads the entire contents, and a zero-length separator
07957  *  reads the input one paragraph at a time, where paragraphs are
07958  *  divided by two consecutive newlines.  If the first argument is an
07959  *  integer, or optional second argument is given, the returning string
07960  *  would not be longer than the given value in bytes.  If multiple
07961  *  filenames are present in +ARGV+, +gets(nil)+ will read the contents
07962  *  one file at a time.
07963  *
07964  *     ARGV << "testfile"
07965  *     print while gets
07966  *
07967  *  <em>produces:</em>
07968  *
07969  *     This is line one
07970  *     This is line two
07971  *     This is line three
07972  *     And so on...
07973  *
07974  *  The style of programming using <code>$_</code> as an implicit
07975  *  parameter is gradually losing favor in the Ruby community.
07976  */
07977 
07978 static VALUE
07979 rb_f_gets(int argc, VALUE *argv, VALUE recv)
07980 {
07981     if (recv == argf) {
07982         return argf_gets(argc, argv, argf);
07983     }
07984     return rb_funcall2(argf, idGets, argc, argv);
07985 }
07986 
07987 /*
07988  *  call-seq:
07989  *     ARGF.gets(sep=$/)     -> string or nil
07990  *     ARGF.gets(limit)      -> string or nil
07991  *     ARGF.gets(sep, limit) -> string or nil
07992  *
07993  *  Returns the next line from the current file in +ARGF+.
07994  *
07995  *  By default lines are assumed to be separated by +$/+; to use a different
07996  *  character as a separator, supply it as a +String+ for the _sep_ argument.
07997  *
07998  *  The optional _limit_ argument specifies how many characters of each line
07999  *  to return. By default all characters are returned.
08000  *
08001  */
08002 static VALUE
08003 argf_gets(int argc, VALUE *argv, VALUE argf)
08004 {
08005     VALUE line;
08006 
08007     line = argf_getline(argc, argv, argf);
08008     rb_lastline_set(line);
08009 
08010     return line;
08011 }
08012 
08013 VALUE
08014 rb_gets(void)
08015 {
08016     VALUE line;
08017 
08018     if (rb_rs != rb_default_rs) {
08019         return rb_f_gets(0, 0, argf);
08020     }
08021 
08022   retry:
08023     if (!next_argv()) return Qnil;
08024     line = rb_io_gets(ARGF.current_file);
08025     if (NIL_P(line) && ARGF.next_p != -1) {
08026         rb_io_close(ARGF.current_file);
08027         ARGF.next_p = 1;
08028         goto retry;
08029     }
08030     rb_lastline_set(line);
08031     if (!NIL_P(line)) {
08032         ARGF.lineno++;
08033         ARGF.last_lineno = ARGF.lineno;
08034     }
08035 
08036     return line;
08037 }
08038 
08039 static VALUE argf_readline(int, VALUE *, VALUE);
08040 
08041 /*
08042  *  call-seq:
08043  *     readline(sep=$/)     -> string
08044  *     readline(limit)      -> string
08045  *     readline(sep, limit) -> string
08046  *
08047  *  Equivalent to <code>Kernel::gets</code>, except
08048  *  +readline+ raises +EOFError+ at end of file.
08049  */
08050 
08051 static VALUE
08052 rb_f_readline(int argc, VALUE *argv, VALUE recv)
08053 {
08054     if (recv == argf) {
08055         return argf_readline(argc, argv, argf);
08056     }
08057     return rb_funcall2(argf, rb_intern("readline"), argc, argv);
08058 }
08059 
08060 
08061 /*
08062  *  call-seq:
08063  *     ARGF.readline(sep=$/)     -> string
08064  *     ARGF.readline(limit)      -> string
08065  *     ARGF.readline(sep, limit) -> string
08066  *
08067  *  Returns the next line from the current file in +ARGF+.
08068  *
08069  *  By default lines are assumed to be separated by +$/+; to use a different
08070  *  character as a separator, supply it as a +String+ for the _sep_ argument.
08071  *
08072  *  The optional  _limit_ argument specifies how many characters of each line
08073  *  to return. By default all characters are returned.
08074  *
08075  *  An +EOFError+ is raised at the end of the file.
08076  */
08077 static VALUE
08078 argf_readline(int argc, VALUE *argv, VALUE argf)
08079 {
08080     VALUE line;
08081 
08082     if (!next_argv()) rb_eof_error();
08083     ARGF_FORWARD(argc, argv);
08084     line = argf_gets(argc, argv, argf);
08085     if (NIL_P(line)) {
08086         rb_eof_error();
08087     }
08088 
08089     return line;
08090 }
08091 
08092 static VALUE argf_readlines(int, VALUE *, VALUE);
08093 
08094 /*
08095  *  call-seq:
08096  *     readlines(sep=$/)    -> array
08097  *     readlines(limit)     -> array
08098  *     readlines(sep,limit) -> array
08099  *
08100  *  Returns an array containing the lines returned by calling
08101  *  <code>Kernel.gets(<i>sep</i>)</code> until the end of file.
08102  */
08103 
08104 static VALUE
08105 rb_f_readlines(int argc, VALUE *argv, VALUE recv)
08106 {
08107     if (recv == argf) {
08108         return argf_readlines(argc, argv, argf);
08109     }
08110     return rb_funcall2(argf, rb_intern("readlines"), argc, argv);
08111 }
08112 
08113 /*
08114  *  call-seq:
08115  *     ARGF.readlines(sep=$/)     -> array
08116  *     ARGF.readlines(limit)      -> array
08117  *     ARGF.readlines(sep, limit) -> array
08118  *
08119  *     ARGF.to_a(sep=$/)     -> array
08120  *     ARGF.to_a(limit)      -> array
08121  *     ARGF.to_a(sep, limit) -> array
08122  *
08123  *  Reads +ARGF+'s current file in its entirety, returning an +Array+ of its
08124  *  lines, one line per element. Lines are assumed to be separated by _sep_.
08125  *
08126  *     lines = ARGF.readlines
08127  *     lines[0]                #=> "This is line one\n"
08128  */
08129 static VALUE
08130 argf_readlines(int argc, VALUE *argv, VALUE argf)
08131 {
08132     long lineno = ARGF.lineno;
08133     VALUE lines, ary;
08134 
08135     ary = rb_ary_new();
08136     while (next_argv()) {
08137         if (ARGF_GENERIC_INPUT_P()) {
08138             lines = rb_funcall3(ARGF.current_file, rb_intern("readlines"), argc, argv);
08139         }
08140         else {
08141             lines = rb_io_readlines(argc, argv, ARGF.current_file);
08142             argf_close(argf);
08143         }
08144         ARGF.next_p = 1;
08145         rb_ary_concat(ary, lines);
08146         ARGF.lineno = lineno + RARRAY_LEN(ary);
08147         ARGF.last_lineno = ARGF.lineno;
08148     }
08149     ARGF.init_p = 0;
08150     return ary;
08151 }
08152 
08153 /*
08154  *  call-seq:
08155  *     `cmd`    -> string
08156  *
08157  *  Returns the standard output of running _cmd_ in a subshell.
08158  *  The built-in syntax <code>%x{...}</code> uses
08159  *  this method. Sets <code>$?</code> to the process status.
08160  *
08161  *     `date`                   #=> "Wed Apr  9 08:56:30 CDT 2003\n"
08162  *     `ls testdir`.split[1]    #=> "main.rb"
08163  *     `echo oops && exit 99`   #=> "oops\n"
08164  *     $?.exitstatus            #=> 99
08165  */
08166 
08167 static VALUE
08168 rb_f_backquote(VALUE obj, VALUE str)
08169 {
08170     volatile VALUE port;
08171     VALUE result;
08172     rb_io_t *fptr;
08173 
08174     SafeStringValue(str);
08175     rb_last_status_clear();
08176     port = pipe_open_s(str, "r", FMODE_READABLE|DEFAULT_TEXTMODE, NULL);
08177     if (NIL_P(port)) return rb_str_new(0,0);
08178 
08179     GetOpenFile(port, fptr);
08180     result = read_all(fptr, remain_size(fptr), Qnil);
08181     rb_io_close(port);
08182 
08183     return result;
08184 }
08185 
08186 #ifdef HAVE_SYS_SELECT_H
08187 #include <sys/select.h>
08188 #endif
08189 
08190 static VALUE
08191 select_internal(VALUE read, VALUE write, VALUE except, struct timeval *tp, rb_fdset_t *fds)
08192 {
08193     VALUE res, list;
08194     rb_fdset_t *rp, *wp, *ep;
08195     rb_io_t *fptr;
08196     long i;
08197     int max = 0, n;
08198     int pending = 0;
08199     struct timeval timerec;
08200 
08201     if (!NIL_P(read)) {
08202         Check_Type(read, T_ARRAY);
08203         for (i=0; i<RARRAY_LEN(read); i++) {
08204             GetOpenFile(rb_io_get_io(RARRAY_AREF(read, i)), fptr);
08205             rb_fd_set(fptr->fd, &fds[0]);
08206             if (READ_DATA_PENDING(fptr) || READ_CHAR_PENDING(fptr)) { /* check for buffered data */
08207                 pending++;
08208                 rb_fd_set(fptr->fd, &fds[3]);
08209             }
08210             if (max < fptr->fd) max = fptr->fd;
08211         }
08212         if (pending) {          /* no blocking if there's buffered data */
08213             timerec.tv_sec = timerec.tv_usec = 0;
08214             tp = &timerec;
08215         }
08216         rp = &fds[0];
08217     }
08218     else
08219         rp = 0;
08220 
08221     if (!NIL_P(write)) {
08222         Check_Type(write, T_ARRAY);
08223         for (i=0; i<RARRAY_LEN(write); i++) {
08224             VALUE write_io = GetWriteIO(rb_io_get_io(RARRAY_AREF(write, i)));
08225             GetOpenFile(write_io, fptr);
08226             rb_fd_set(fptr->fd, &fds[1]);
08227             if (max < fptr->fd) max = fptr->fd;
08228         }
08229         wp = &fds[1];
08230     }
08231     else
08232         wp = 0;
08233 
08234     if (!NIL_P(except)) {
08235         Check_Type(except, T_ARRAY);
08236         for (i=0; i<RARRAY_LEN(except); i++) {
08237             VALUE io = rb_io_get_io(RARRAY_AREF(except, i));
08238             VALUE write_io = GetWriteIO(io);
08239             GetOpenFile(io, fptr);
08240             rb_fd_set(fptr->fd, &fds[2]);
08241             if (max < fptr->fd) max = fptr->fd;
08242             if (io != write_io) {
08243                 GetOpenFile(write_io, fptr);
08244                 rb_fd_set(fptr->fd, &fds[2]);
08245                 if (max < fptr->fd) max = fptr->fd;
08246             }
08247         }
08248         ep = &fds[2];
08249     }
08250     else {
08251         ep = 0;
08252     }
08253 
08254     max++;
08255 
08256     n = rb_thread_fd_select(max, rp, wp, ep, tp);
08257     if (n < 0) {
08258         rb_sys_fail(0);
08259     }
08260     if (!pending && n == 0) return Qnil; /* returns nil on timeout */
08261 
08262     res = rb_ary_new2(3);
08263     rb_ary_push(res, rp?rb_ary_new():rb_ary_new2(0));
08264     rb_ary_push(res, wp?rb_ary_new():rb_ary_new2(0));
08265     rb_ary_push(res, ep?rb_ary_new():rb_ary_new2(0));
08266 
08267     if (rp) {
08268         list = RARRAY_AREF(res, 0);
08269         for (i=0; i< RARRAY_LEN(read); i++) {
08270             VALUE obj = rb_ary_entry(read, i);
08271             VALUE io = rb_io_get_io(obj);
08272             GetOpenFile(io, fptr);
08273             if (rb_fd_isset(fptr->fd, &fds[0]) ||
08274                 rb_fd_isset(fptr->fd, &fds[3])) {
08275                 rb_ary_push(list, obj);
08276             }
08277         }
08278     }
08279 
08280     if (wp) {
08281         list = RARRAY_AREF(res, 1);
08282         for (i=0; i< RARRAY_LEN(write); i++) {
08283             VALUE obj = rb_ary_entry(write, i);
08284             VALUE io = rb_io_get_io(obj);
08285             VALUE write_io = GetWriteIO(io);
08286             GetOpenFile(write_io, fptr);
08287             if (rb_fd_isset(fptr->fd, &fds[1])) {
08288                 rb_ary_push(list, obj);
08289             }
08290         }
08291     }
08292 
08293     if (ep) {
08294         list = RARRAY_AREF(res, 2);
08295         for (i=0; i< RARRAY_LEN(except); i++) {
08296             VALUE obj = rb_ary_entry(except, i);
08297             VALUE io = rb_io_get_io(obj);
08298             VALUE write_io = GetWriteIO(io);
08299             GetOpenFile(io, fptr);
08300             if (rb_fd_isset(fptr->fd, &fds[2])) {
08301                 rb_ary_push(list, obj);
08302             }
08303             else if (io != write_io) {
08304                 GetOpenFile(write_io, fptr);
08305                 if (rb_fd_isset(fptr->fd, &fds[2])) {
08306                     rb_ary_push(list, obj);
08307                 }
08308             }
08309         }
08310     }
08311 
08312     return res;                 /* returns an empty array on interrupt */
08313 }
08314 
08315 struct select_args {
08316     VALUE read, write, except;
08317     struct timeval *timeout;
08318     rb_fdset_t fdsets[4];
08319 };
08320 
08321 static VALUE
08322 select_call(VALUE arg)
08323 {
08324     struct select_args *p = (struct select_args *)arg;
08325 
08326     return select_internal(p->read, p->write, p->except, p->timeout, p->fdsets);
08327 }
08328 
08329 static VALUE
08330 select_end(VALUE arg)
08331 {
08332     struct select_args *p = (struct select_args *)arg;
08333     int i;
08334 
08335     for (i = 0; i < numberof(p->fdsets); ++i)
08336         rb_fd_term(&p->fdsets[i]);
08337     return Qnil;
08338 }
08339 
08340 static VALUE sym_normal,   sym_sequential, sym_random,
08341              sym_willneed, sym_dontneed, sym_noreuse;
08342 
08343 #ifdef HAVE_POSIX_FADVISE
08344 struct io_advise_struct {
08345     int fd;
08346     off_t offset;
08347     off_t len;
08348     int advice;
08349 };
08350 
08351 static VALUE
08352 io_advise_internal(void *arg)
08353 {
08354     struct io_advise_struct *ptr = arg;
08355     return posix_fadvise(ptr->fd, ptr->offset, ptr->len, ptr->advice);
08356 }
08357 
08358 static VALUE
08359 io_advise_sym_to_const(VALUE sym)
08360 {
08361 #ifdef POSIX_FADV_NORMAL
08362     if (sym == sym_normal)
08363         return INT2NUM(POSIX_FADV_NORMAL);
08364 #endif
08365 
08366 #ifdef POSIX_FADV_RANDOM
08367     if (sym == sym_random)
08368         return INT2NUM(POSIX_FADV_RANDOM);
08369 #endif
08370 
08371 #ifdef POSIX_FADV_SEQUENTIAL
08372     if (sym == sym_sequential)
08373         return INT2NUM(POSIX_FADV_SEQUENTIAL);
08374 #endif
08375 
08376 #ifdef POSIX_FADV_WILLNEED
08377     if (sym == sym_willneed)
08378         return INT2NUM(POSIX_FADV_WILLNEED);
08379 #endif
08380 
08381 #ifdef POSIX_FADV_DONTNEED
08382     if (sym == sym_dontneed)
08383         return INT2NUM(POSIX_FADV_DONTNEED);
08384 #endif
08385 
08386 #ifdef POSIX_FADV_NOREUSE
08387     if (sym == sym_noreuse)
08388         return INT2NUM(POSIX_FADV_NOREUSE);
08389 #endif
08390 
08391     return Qnil;
08392 }
08393 
08394 static VALUE
08395 do_io_advise(rb_io_t *fptr, VALUE advice, off_t offset, off_t len)
08396 {
08397     int rv;
08398     struct io_advise_struct ias;
08399     VALUE num_adv;
08400 
08401     num_adv = io_advise_sym_to_const(advice);
08402 
08403     /*
08404      * The platform doesn't support this hint. We don't raise exception, instead
08405      * silently ignore it. Because IO::advise is only hint.
08406      */
08407     if (NIL_P(num_adv))
08408         return Qnil;
08409 
08410     ias.fd     = fptr->fd;
08411     ias.advice = NUM2INT(num_adv);
08412     ias.offset = offset;
08413     ias.len    = len;
08414 
08415     rv = (int)rb_thread_io_blocking_region(io_advise_internal, &ias, fptr->fd);
08416     if (rv) {
08417         /* posix_fadvise(2) doesn't set errno. On success it returns 0; otherwise
08418            it returns the error code. */
08419         rb_syserr_fail_str(rv, fptr->pathv);
08420     }
08421 
08422     return Qnil;
08423 }
08424 
08425 #endif /* HAVE_POSIX_FADVISE */
08426 
08427 static void
08428 advice_arg_check(VALUE advice)
08429 {
08430     if (!SYMBOL_P(advice))
08431         rb_raise(rb_eTypeError, "advice must be a Symbol");
08432 
08433     if (advice != sym_normal &&
08434         advice != sym_sequential &&
08435         advice != sym_random &&
08436         advice != sym_willneed &&
08437         advice != sym_dontneed &&
08438         advice != sym_noreuse) {
08439         VALUE symname = rb_inspect(advice);
08440         rb_raise(rb_eNotImpError, "Unsupported advice: %s",
08441                  StringValuePtr(symname));
08442     }
08443 }
08444 
08445 /*
08446  *  call-seq:
08447  *     ios.advise(advice, offset=0, len=0) -> nil
08448  *
08449  *  Announce an intention to access data from the current file in a
08450  *  specific pattern. On platforms that do not support the
08451  *  <em>posix_fadvise(2)</em> system call, this method is a no-op.
08452  *
08453  *  _advice_ is one of the following symbols:
08454  *
08455  *  :normal::     No advice to give; the default assumption for an open file.
08456  *  :sequential:: The data will be accessed sequentially
08457  *                with lower offsets read before higher ones.
08458  *  :random::     The data will be accessed in random order.
08459  *  :willneed::   The data will be accessed in the near future.
08460  *  :dontneed::   The data will not be accessed in the near future.
08461  *  :noreuse::    The data will only be accessed once.
08462  *
08463  *  The semantics of a piece of advice are platform-dependent. See
08464  *  <em>man 2 posix_fadvise</em> for details.
08465  *
08466  *  "data" means the region of the current file that begins at
08467  *  _offset_ and extends for _len_ bytes. If _len_ is 0, the region
08468  *  ends at the last byte of the file. By default, both _offset_ and
08469  *  _len_ are 0, meaning that the advice applies to the entire file.
08470  *
08471  *  If an error occurs, one of the following exceptions will be raised:
08472  *
08473  *  <code>IOError</code>:: The <code>IO</code> stream is closed.
08474  *  <code>Errno::EBADF</code>::
08475  *    The file descriptor of the current file is invalid.
08476  *  <code>Errno::EINVAL</code>:: An invalid value for _advice_ was given.
08477  *  <code>Errno::ESPIPE</code>::
08478  *    The file descriptor of the current file refers to a FIFO or
08479  *    pipe. (Linux raises <code>Errno::EINVAL</code> in this case).
08480  *  <code>TypeError</code>::
08481  *    Either _advice_ was not a Symbol, or one of the
08482  *    other arguments was not an <code>Integer</code>.
08483  *  <code>RangeError</code>:: One of the arguments given was too big/small.
08484  *
08485  *  This list is not exhaustive; other Errno:: exceptions are also possible.
08486  */
08487 static VALUE
08488 rb_io_advise(int argc, VALUE *argv, VALUE io)
08489 {
08490     VALUE advice, offset, len;
08491     off_t off, l;
08492     rb_io_t *fptr;
08493 
08494     rb_scan_args(argc, argv, "12", &advice, &offset, &len);
08495     advice_arg_check(advice);
08496 
08497     io = GetWriteIO(io);
08498     GetOpenFile(io, fptr);
08499 
08500     off = NIL_P(offset) ? 0 : NUM2OFFT(offset);
08501     l   = NIL_P(len)    ? 0 : NUM2OFFT(len);
08502 
08503 #ifdef HAVE_POSIX_FADVISE
08504     return do_io_advise(fptr, advice, off, l);
08505 #else
08506     ((void)off, (void)l);       /* Ignore all hint */
08507     return Qnil;
08508 #endif
08509 }
08510 
08511 /*
08512  *  call-seq:
08513  *     IO.select(read_array
08514  *               [, write_array
08515  *               [, error_array
08516  *               [, timeout]]]) -> array  or  nil
08517  *
08518  *  Calls select(2) system call.
08519  *  It monitors given arrays of <code>IO</code> objects, waits one or more
08520  *  of <code>IO</code> objects ready for reading, are ready for writing,
08521  *  and have pending exceptions respectively, and returns an array that
08522  *  contains arrays of those IO objects.  It will return <code>nil</code>
08523  *  if optional <i>timeout</i> value is given and no <code>IO</code> object
08524  *  is ready in <i>timeout</i> seconds.
08525  *
08526  *  <code>IO.select</code> peeks the buffer of <code>IO</code> objects for testing readability.
08527  *  If the <code>IO</code> buffer is not empty,
08528  *  <code>IO.select</code> immediately notify readability.
08529  *  This "peek" is only happen for <code>IO</code> objects.
08530  *  It is not happen for IO-like objects such as OpenSSL::SSL::SSLSocket.
08531  *
08532  *  The best way to use <code>IO.select</code> is invoking it
08533  *  after nonblocking methods such as <code>read_nonblock</code>, <code>write_nonblock</code>, etc.
08534  *  The methods raises an exception which is extended by
08535  *  <code>IO::WaitReadable</code> or <code>IO::WaitWritable</code>.
08536  *  The modules notify how the caller should wait with <code>IO.select</code>.
08537  *  If <code>IO::WaitReadable</code> is raised, the caller should wait for reading.
08538  *  If <code>IO::WaitWritable</code> is raised, the caller should wait for writing.
08539  *
08540  *  So, blocking read (<code>readpartial</code>) can be emulated using
08541  *  <code>read_nonblock</code> and <code>IO.select</code> as follows:
08542  *
08543  *    begin
08544  *      result = io_like.read_nonblock(maxlen)
08545  *    rescue IO::WaitReadable
08546  *      IO.select([io_like])
08547  *      retry
08548  *    rescue IO::WaitWritable
08549  *      IO.select(nil, [io_like])
08550  *      retry
08551  *    end
08552  *
08553  *  Especially, the combination of nonblocking methods and
08554  *  <code>IO.select</code> is preferred for <code>IO</code> like
08555  *  objects such as <code>OpenSSL::SSL::SSLSocket</code>.
08556  *  It has <code>to_io</code> method to return underlying <code>IO</code> object.
08557  *  <code>IO.select</code> calls <code>to_io</code> to obtain the file descriptor to wait.
08558  *
08559  *  This means that readability notified by <code>IO.select</code> doesn't mean
08560  *  readability from <code>OpenSSL::SSL::SSLSocket</code> object.
08561  *
08562  *  Most possible situation is <code>OpenSSL::SSL::SSLSocket</code> buffers some data.
08563  *  <code>IO.select</code> doesn't see the buffer.
08564  *  So <code>IO.select</code> can block when <code>OpenSSL::SSL::SSLSocket#readpartial</code> doesn't block.
08565  *
08566  *  However several more complicated situation exists.
08567  *
08568  *  SSL is a protocol which is sequence of records.
08569  *  The record consists multiple bytes.
08570  *  So, the remote side of SSL sends a partial record,
08571  *  <code>IO.select</code> notifies readability but
08572  *  <code>OpenSSL::SSL::SSLSocket</code> cannot decrypt a byte and
08573  *  <code>OpenSSL::SSL::SSLSocket#readpartial</code> will blocks.
08574  *
08575  *  Also, the remote side can request SSL renegotiation which forces
08576  *  the local SSL engine writes some data.
08577  *  This means <code>OpenSSL::SSL::SSLSocket#readpartial</code> may
08578  *  invoke <code>write</code> system call and it can block.
08579  *  In such situation, <code>OpenSSL::SSL::SSLSocket#read_nonblock</code>
08580  *  raises IO::WaitWritable instead of blocking.
08581  *  So, the caller should wait for ready for writability as above example.
08582  *
08583  *  The combination of nonblocking methods and <code>IO.select</code> is
08584  *  also useful for streams such as tty, pipe socket socket when
08585  *  multiple process read form a stream.
08586  *
08587  *  Finally, Linux kernel developers doesn't guarantee that
08588  *  readability of select(2) means readability of following read(2) even
08589  *  for single process.
08590  *  See select(2) manual on GNU/Linux system.
08591  *
08592  *  Invoking <code>IO.select</code> before <code>IO#readpartial</code> works well in usual.
08593  *  However it is not the best way to use <code>IO.select</code>.
08594  *
08595  *  The writability notified by select(2) doesn't show
08596  *  how many bytes writable.
08597  *  <code>IO#write</code> method blocks until given whole string is written.
08598  *  So, <code>IO#write(two or more bytes)</code> can block after writability is notified by <code>IO.select</code>.
08599  *  <code>IO#write_nonblock</code> is required to avoid the blocking.
08600  *
08601  *  Blocking write (<code>write</code>) can be emulated using
08602  *  <code>write_nonblock</code> and <code>IO.select</code> as follows:
08603  *  IO::WaitReadable should also be rescued for SSL renegotiation in <code>OpenSSL::SSL::SSLSocket</code>.
08604  *
08605  *    while 0 < string.bytesize
08606  *      begin
08607  *        written = io_like.write_nonblock(string)
08608  *      rescue IO::WaitReadable
08609  *        IO.select([io_like])
08610  *        retry
08611  *      rescue IO::WaitWritable
08612  *        IO.select(nil, [io_like])
08613  *        retry
08614  *      end
08615  *      string = string.byteslice(written..-1)
08616  *    end
08617  *
08618  *  === Parameters
08619  *  read_array:: an array of <code>IO</code> objects that wait until ready for read
08620  *  write_array:: an array of <code>IO</code> objects that wait until ready for write
08621  *  error_array:: an array of <code>IO</code> objects that wait for exceptions
08622  *  timeout:: a numeric value in second
08623  *
08624  *  === Example
08625  *
08626  *      rp, wp = IO.pipe
08627  *      mesg = "ping "
08628  *      100.times {
08629  *        # IO.select follows IO#read.  Not the best way to use IO.select.
08630  *        rs, ws, = IO.select([rp], [wp])
08631  *        if r = rs[0]
08632  *          ret = r.read(5)
08633  *          print ret
08634  *          case ret
08635  *          when /ping/
08636  *            mesg = "pong\n"
08637  *          when /pong/
08638  *            mesg = "ping "
08639  *          end
08640  *        end
08641  *        if w = ws[0]
08642  *          w.write(mesg)
08643  *        end
08644  *      }
08645  *
08646  *  <em>produces:</em>
08647  *
08648  *      ping pong
08649  *      ping pong
08650  *      ping pong
08651  *      (snipped)
08652  *      ping
08653  */
08654 
08655 static VALUE
08656 rb_f_select(int argc, VALUE *argv, VALUE obj)
08657 {
08658     VALUE timeout;
08659     struct select_args args;
08660     struct timeval timerec;
08661     int i;
08662 
08663     rb_scan_args(argc, argv, "13", &args.read, &args.write, &args.except, &timeout);
08664     if (NIL_P(timeout)) {
08665         args.timeout = 0;
08666     }
08667     else {
08668         timerec = rb_time_interval(timeout);
08669         args.timeout = &timerec;
08670     }
08671 
08672     for (i = 0; i < numberof(args.fdsets); ++i)
08673         rb_fd_init(&args.fdsets[i]);
08674 
08675     return rb_ensure(select_call, (VALUE)&args, select_end, (VALUE)&args);
08676 }
08677 
08678 #if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__)
08679  typedef unsigned long ioctl_req_t;
08680 # define NUM2IOCTLREQ(num) NUM2ULONG(num)
08681 #else
08682  typedef int ioctl_req_t;
08683 # define NUM2IOCTLREQ(num) NUM2INT(num)
08684 #endif
08685 
08686 struct ioctl_arg {
08687     int         fd;
08688     ioctl_req_t cmd;
08689     long        narg;
08690 };
08691 
08692 static VALUE
08693 nogvl_ioctl(void *ptr)
08694 {
08695     struct ioctl_arg *arg = ptr;
08696 
08697     return (VALUE)ioctl(arg->fd, arg->cmd, arg->narg);
08698 }
08699 
08700 static int
08701 do_ioctl(int fd, ioctl_req_t cmd, long narg)
08702 {
08703     int retval;
08704     struct ioctl_arg arg;
08705 
08706     arg.fd = fd;
08707     arg.cmd = cmd;
08708     arg.narg = narg;
08709 
08710     retval = (int)rb_thread_io_blocking_region(nogvl_ioctl, &arg, fd);
08711 
08712     return retval;
08713 }
08714 
08715 #define DEFULT_IOCTL_NARG_LEN (256)
08716 
08717 #if defined(__linux__) && defined(_IOC_SIZE)
08718 static long
08719 linux_iocparm_len(ioctl_req_t cmd)
08720 {
08721     long len;
08722 
08723     if ((cmd & 0xFFFF0000) == 0) {
08724         /* legacy and unstructured ioctl number. */
08725         return DEFULT_IOCTL_NARG_LEN;
08726     }
08727 
08728     len = _IOC_SIZE(cmd);
08729 
08730     /* paranoia check for silly drivers which don't keep ioctl convention */
08731     if (len < DEFULT_IOCTL_NARG_LEN)
08732         len = DEFULT_IOCTL_NARG_LEN;
08733 
08734     return len;
08735 }
08736 #endif
08737 
08738 static long
08739 ioctl_narg_len(ioctl_req_t cmd)
08740 {
08741     long len;
08742 
08743 #ifdef IOCPARM_MASK
08744 #ifndef IOCPARM_LEN
08745 #define IOCPARM_LEN(x)  (((x) >> 16) & IOCPARM_MASK)
08746 #endif
08747 #endif
08748 #ifdef IOCPARM_LEN
08749     len = IOCPARM_LEN(cmd);     /* on BSDish systems we're safe */
08750 #elif defined(__linux__) && defined(_IOC_SIZE)
08751     len = linux_iocparm_len(cmd);
08752 #else
08753     /* otherwise guess at what's safe */
08754     len = DEFULT_IOCTL_NARG_LEN;
08755 #endif
08756 
08757     return len;
08758 }
08759 
08760 #ifdef HAVE_FCNTL
08761 #ifdef __linux__
08762 typedef long fcntl_arg_t;
08763 #else
08764 /* posix */
08765 typedef int fcntl_arg_t;
08766 #endif
08767 
08768 static long
08769 fcntl_narg_len(int cmd)
08770 {
08771     long len;
08772 
08773     switch (cmd) {
08774 #ifdef F_DUPFD
08775       case F_DUPFD:
08776         len = sizeof(fcntl_arg_t);
08777         break;
08778 #endif
08779 #ifdef F_DUP2FD /* bsd specific */
08780       case F_DUP2FD:
08781         len = sizeof(int);
08782         break;
08783 #endif
08784 #ifdef F_DUPFD_CLOEXEC /* linux specific */
08785       case F_DUPFD_CLOEXEC:
08786         len = sizeof(fcntl_arg_t);
08787         break;
08788 #endif
08789 #ifdef F_GETFD
08790       case F_GETFD:
08791         len = 1;
08792         break;
08793 #endif
08794 #ifdef F_SETFD
08795       case F_SETFD:
08796         len = sizeof(fcntl_arg_t);
08797         break;
08798 #endif
08799 #ifdef F_GETFL
08800       case F_GETFL:
08801         len = 1;
08802         break;
08803 #endif
08804 #ifdef F_SETFL
08805       case F_SETFL:
08806         len = sizeof(fcntl_arg_t);
08807         break;
08808 #endif
08809 #ifdef F_GETOWN
08810       case F_GETOWN:
08811         len = 1;
08812         break;
08813 #endif
08814 #ifdef F_SETOWN
08815       case F_SETOWN:
08816         len = sizeof(fcntl_arg_t);
08817         break;
08818 #endif
08819 #ifdef F_GETOWN_EX /* linux specific */
08820       case F_GETOWN_EX:
08821         len = sizeof(struct f_owner_ex);
08822         break;
08823 #endif
08824 #ifdef F_SETOWN_EX /* linux specific */
08825       case F_SETOWN_EX:
08826         len = sizeof(struct f_owner_ex);
08827         break;
08828 #endif
08829 #ifdef F_GETLK
08830       case F_GETLK:
08831         len = sizeof(struct flock);
08832         break;
08833 #endif
08834 #ifdef F_SETLK
08835       case F_SETLK:
08836         len = sizeof(struct flock);
08837         break;
08838 #endif
08839 #ifdef F_SETLKW
08840       case F_SETLKW:
08841         len = sizeof(struct flock);
08842         break;
08843 #endif
08844 #ifdef F_READAHEAD /* bsd specific */
08845       case F_READAHEAD:
08846         len = sizeof(int);
08847         break;
08848 #endif
08849 #ifdef F_RDAHEAD /* Darwin specific */
08850       case F_RDAHEAD:
08851         len = sizeof(int);
08852         break;
08853 #endif
08854 #ifdef F_GETSIG /* linux specific */
08855       case F_GETSIG:
08856         len = 1;
08857         break;
08858 #endif
08859 #ifdef F_SETSIG /* linux specific */
08860       case F_SETSIG:
08861         len = sizeof(fcntl_arg_t);
08862         break;
08863 #endif
08864 #ifdef F_GETLEASE /* linux specific */
08865       case F_GETLEASE:
08866         len = 1;
08867         break;
08868 #endif
08869 #ifdef F_SETLEASE /* linux specific */
08870       case F_SETLEASE:
08871         len = sizeof(fcntl_arg_t);
08872         break;
08873 #endif
08874 #ifdef F_NOTIFY /* linux specific */
08875       case F_NOTIFY:
08876         len = sizeof(fcntl_arg_t);
08877         break;
08878 #endif
08879 
08880       default:
08881         len = 256;
08882         break;
08883     }
08884 
08885     return len;
08886 }
08887 #else /* HAVE_FCNTL */
08888 static long
08889 fcntl_narg_len(int cmd)
08890 {
08891     return 0;
08892 }
08893 #endif /* HAVE_FCNTL */
08894 
08895 static long
08896 setup_narg(ioctl_req_t cmd, VALUE *argp, int io_p)
08897 {
08898     long narg = 0;
08899     VALUE arg = *argp;
08900 
08901     if (NIL_P(arg) || arg == Qfalse) {
08902         narg = 0;
08903     }
08904     else if (FIXNUM_P(arg)) {
08905         narg = FIX2LONG(arg);
08906     }
08907     else if (arg == Qtrue) {
08908         narg = 1;
08909     }
08910     else {
08911         VALUE tmp = rb_check_string_type(arg);
08912 
08913         if (NIL_P(tmp)) {
08914             narg = NUM2LONG(arg);
08915         }
08916         else {
08917             long len;
08918 
08919             *argp = arg = tmp;
08920             if (io_p)
08921                 len = ioctl_narg_len(cmd);
08922             else
08923                 len = fcntl_narg_len((int)cmd);
08924             rb_str_modify(arg);
08925 
08926             /* expand for data + sentinel. */
08927             if (RSTRING_LEN(arg) < len+1) {
08928                 rb_str_resize(arg, len+1);
08929             }
08930             /* a little sanity check here */
08931             RSTRING_PTR(arg)[RSTRING_LEN(arg) - 1] = 17;
08932             narg = (long)(SIGNED_VALUE)RSTRING_PTR(arg);
08933         }
08934     }
08935 
08936     return narg;
08937 }
08938 
08939 static VALUE
08940 rb_ioctl(VALUE io, VALUE req, VALUE arg)
08941 {
08942     ioctl_req_t cmd = NUM2IOCTLREQ(req);
08943     rb_io_t *fptr;
08944     long narg;
08945     int retval;
08946 
08947     rb_secure(2);
08948 
08949     narg = setup_narg(cmd, &arg, 1);
08950     GetOpenFile(io, fptr);
08951     retval = do_ioctl(fptr->fd, cmd, narg);
08952     if (retval < 0) rb_sys_fail_path(fptr->pathv);
08953     if (RB_TYPE_P(arg, T_STRING)) {
08954         if (RSTRING_PTR(arg)[RSTRING_LEN(arg)-1] != 17)
08955             rb_raise(rb_eArgError, "return value overflowed string");
08956         RSTRING_PTR(arg)[RSTRING_LEN(arg)-1] = '\0';
08957     }
08958 
08959     return INT2NUM(retval);
08960 }
08961 
08962 /*
08963  *  call-seq:
08964  *     ios.ioctl(integer_cmd, arg)    -> integer
08965  *
08966  *  Provides a mechanism for issuing low-level commands to control or
08967  *  query I/O devices. Arguments and results are platform dependent. If
08968  *  <i>arg</i> is a number, its value is passed directly. If it is a
08969  *  string, it is interpreted as a binary sequence of bytes. On Unix
08970  *  platforms, see <code>ioctl(2)</code> for details. Not implemented on
08971  *  all platforms.
08972  */
08973 
08974 static VALUE
08975 rb_io_ioctl(int argc, VALUE *argv, VALUE io)
08976 {
08977     VALUE req, arg;
08978 
08979     rb_scan_args(argc, argv, "11", &req, &arg);
08980     return rb_ioctl(io, req, arg);
08981 }
08982 
08983 #ifdef HAVE_FCNTL
08984 struct fcntl_arg {
08985     int         fd;
08986     int         cmd;
08987     long        narg;
08988 };
08989 
08990 static VALUE
08991 nogvl_fcntl(void *ptr)
08992 {
08993     struct fcntl_arg *arg = ptr;
08994 
08995 #if defined(F_DUPFD)
08996     if (arg->cmd == F_DUPFD)
08997         return (VALUE)rb_cloexec_fcntl_dupfd(arg->fd, (int)arg->narg);
08998 #endif
08999     return (VALUE)fcntl(arg->fd, arg->cmd, arg->narg);
09000 }
09001 
09002 static int
09003 do_fcntl(int fd, int cmd, long narg)
09004 {
09005     int retval;
09006     struct fcntl_arg arg;
09007 
09008     arg.fd = fd;
09009     arg.cmd = cmd;
09010     arg.narg = narg;
09011 
09012     retval = (int)rb_thread_io_blocking_region(nogvl_fcntl, &arg, fd);
09013 #if defined(F_DUPFD)
09014     if (retval != -1 && cmd == F_DUPFD) {
09015         rb_update_max_fd(retval);
09016     }
09017 #endif
09018 
09019     return retval;
09020 }
09021 
09022 static VALUE
09023 rb_fcntl(VALUE io, VALUE req, VALUE arg)
09024 {
09025     int cmd = NUM2INT(req);
09026     rb_io_t *fptr;
09027     long narg;
09028     int retval;
09029 
09030     rb_secure(2);
09031 
09032     narg = setup_narg(cmd, &arg, 0);
09033     GetOpenFile(io, fptr);
09034     retval = do_fcntl(fptr->fd, cmd, narg);
09035     if (retval < 0) rb_sys_fail_path(fptr->pathv);
09036     if (RB_TYPE_P(arg, T_STRING)) {
09037         if (RSTRING_PTR(arg)[RSTRING_LEN(arg)-1] != 17)
09038             rb_raise(rb_eArgError, "return value overflowed string");
09039         RSTRING_PTR(arg)[RSTRING_LEN(arg)-1] = '\0';
09040     }
09041 
09042     if (cmd == F_SETFL) {
09043         if (narg & O_NONBLOCK) {
09044             fptr->mode |= FMODE_WSPLIT_INITIALIZED;
09045             fptr->mode &= ~FMODE_WSPLIT;
09046         }
09047         else {
09048             fptr->mode &= ~(FMODE_WSPLIT_INITIALIZED|FMODE_WSPLIT);
09049         }
09050     }
09051 
09052     return INT2NUM(retval);
09053 }
09054 
09055 /*
09056  *  call-seq:
09057  *     ios.fcntl(integer_cmd, arg)    -> integer
09058  *
09059  *  Provides a mechanism for issuing low-level commands to control or
09060  *  query file-oriented I/O streams. Arguments and results are platform
09061  *  dependent. If <i>arg</i> is a number, its value is passed
09062  *  directly. If it is a string, it is interpreted as a binary sequence
09063  *  of bytes (<code>Array#pack</code> might be a useful way to build this
09064  *  string). On Unix platforms, see <code>fcntl(2)</code> for details.
09065  *  Not implemented on all platforms.
09066  */
09067 
09068 static VALUE
09069 rb_io_fcntl(int argc, VALUE *argv, VALUE io)
09070 {
09071     VALUE req, arg;
09072 
09073     rb_scan_args(argc, argv, "11", &req, &arg);
09074     return rb_fcntl(io, req, arg);
09075 }
09076 #else
09077 #define rb_io_fcntl rb_f_notimplement
09078 #endif
09079 
09080 #if defined(HAVE_SYSCALL) || defined(HAVE___SYSCALL)
09081 /*
09082  *  call-seq:
09083  *     syscall(num [, args...])   -> integer
09084  *
09085  *  Calls the operating system function identified by _num_ and
09086  *  returns the result of the function or raises SystemCallError if
09087  *  it failed.
09088  *
09089  *  Arguments for the function can follow _num_. They must be either
09090  *  +String+ objects or +Integer+ objects. A +String+ object is passed
09091  *  as a pointer to the byte sequence. An +Integer+ object is passed
09092  *  as an integer whose bit size is same as a pointer.
09093  *  Up to nine parameters may be passed (14 on the Atari-ST).
09094  *
09095  *  The function identified by _num_ is system
09096  *  dependent. On some Unix systems, the numbers may be obtained from a
09097  *  header file called <code>syscall.h</code>.
09098  *
09099  *     syscall 4, 1, "hello\n", 6   # '4' is write(2) on our box
09100  *
09101  *  <em>produces:</em>
09102  *
09103  *     hello
09104  *
09105  *
09106  *  Calling +syscall+ on a platform which does not have any way to
09107  *  an arbitrary system function just fails with NotImplementedError.
09108  *
09109  * Note::
09110  *   +syscall+ is essentially unsafe and unportable. Feel free to shoot your foot.
09111  *   DL (Fiddle) library is preferred for safer and a bit more portable programming.
09112  */
09113 
09114 static VALUE
09115 rb_f_syscall(int argc, VALUE *argv)
09116 {
09117 #ifdef atarist
09118     VALUE arg[13]; /* yes, we really need that many ! */
09119 #else
09120     VALUE arg[8];
09121 #endif
09122 #if SIZEOF_VOIDP == 8 && defined(HAVE___SYSCALL) && SIZEOF_INT != 8 /* mainly *BSD */
09123 # define SYSCALL __syscall
09124 # define NUM2SYSCALLID(x) NUM2LONG(x)
09125 # define RETVAL2NUM(x) LONG2NUM(x)
09126 # if SIZEOF_LONG == 8
09127     long num, retval = -1;
09128 # elif SIZEOF_LONG_LONG == 8
09129     long long num, retval = -1;
09130 # else
09131 #  error ---->> it is asserted that __syscall takes the first argument and returns retval in 64bit signed integer. <<----
09132 # endif
09133 #elif defined(__linux__)
09134 # define SYSCALL syscall
09135 # define NUM2SYSCALLID(x) NUM2LONG(x)
09136 # define RETVAL2NUM(x) LONG2NUM(x)
09137     /*
09138      * Linux man page says, syscall(2) function prototype is below.
09139      *
09140      *     int syscall(int number, ...);
09141      *
09142      * But, it's incorrect. Actual one takes and returned long. (see unistd.h)
09143      */
09144     long num, retval = -1;
09145 #else
09146 # define SYSCALL syscall
09147 # define NUM2SYSCALLID(x) NUM2INT(x)
09148 # define RETVAL2NUM(x) INT2NUM(x)
09149     int num, retval = -1;
09150 #endif
09151     int i;
09152 
09153     if (RTEST(ruby_verbose)) {
09154         rb_warning("We plan to remove a syscall function at future release. DL(Fiddle) provides safer alternative.");
09155     }
09156 
09157     rb_secure(2);
09158     if (argc == 0)
09159         rb_raise(rb_eArgError, "too few arguments for syscall");
09160     if (argc > numberof(arg))
09161         rb_raise(rb_eArgError, "too many arguments for syscall");
09162     num = NUM2SYSCALLID(argv[0]); ++argv;
09163     for (i = argc - 1; i--; ) {
09164         VALUE v = rb_check_string_type(argv[i]);
09165 
09166         if (!NIL_P(v)) {
09167             SafeStringValue(v);
09168             rb_str_modify(v);
09169             arg[i] = (VALUE)StringValueCStr(v);
09170         }
09171         else {
09172             arg[i] = (VALUE)NUM2LONG(argv[i]);
09173         }
09174     }
09175 
09176     switch (argc) {
09177       case 1:
09178         retval = SYSCALL(num);
09179         break;
09180       case 2:
09181         retval = SYSCALL(num, arg[0]);
09182         break;
09183       case 3:
09184         retval = SYSCALL(num, arg[0],arg[1]);
09185         break;
09186       case 4:
09187         retval = SYSCALL(num, arg[0],arg[1],arg[2]);
09188         break;
09189       case 5:
09190         retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3]);
09191         break;
09192       case 6:
09193         retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4]);
09194         break;
09195       case 7:
09196         retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5]);
09197         break;
09198       case 8:
09199         retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6]);
09200         break;
09201 #ifdef atarist
09202       case 9:
09203         retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6],
09204           arg[7]);
09205         break;
09206       case 10:
09207         retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6],
09208           arg[7], arg[8]);
09209         break;
09210       case 11:
09211         retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6],
09212           arg[7], arg[8], arg[9]);
09213         break;
09214       case 12:
09215         retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6],
09216           arg[7], arg[8], arg[9], arg[10]);
09217         break;
09218       case 13:
09219         retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6],
09220           arg[7], arg[8], arg[9], arg[10], arg[11]);
09221         break;
09222       case 14:
09223         retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6],
09224           arg[7], arg[8], arg[9], arg[10], arg[11], arg[12]);
09225         break;
09226 #endif
09227     }
09228 
09229     if (retval == -1)
09230         rb_sys_fail(0);
09231     return RETVAL2NUM(retval);
09232 #undef SYSCALL
09233 #undef NUM2SYSCALLID
09234 #undef RETVAL2NUM
09235 }
09236 #else
09237 #define rb_f_syscall rb_f_notimplement
09238 #endif
09239 
09240 static VALUE
09241 io_new_instance(VALUE args)
09242 {
09243     return rb_class_new_instance(2, (VALUE*)args+1, *(VALUE*)args);
09244 }
09245 
09246 static rb_encoding *
09247 find_encoding(VALUE v)
09248 {
09249     rb_encoding *enc = rb_find_encoding(v);
09250     if (!enc) unsupported_encoding(StringValueCStr(v));
09251     return enc;
09252 }
09253 
09254 static void
09255 io_encoding_set(rb_io_t *fptr, VALUE v1, VALUE v2, VALUE opt)
09256 {
09257     rb_encoding *enc, *enc2;
09258     int ecflags = fptr->encs.ecflags;
09259     VALUE ecopts, tmp;
09260 
09261     if (!NIL_P(v2)) {
09262         enc2 = find_encoding(v1);
09263         tmp = rb_check_string_type(v2);
09264         if (!NIL_P(tmp)) {
09265             if (RSTRING_LEN(tmp) == 1 && RSTRING_PTR(tmp)[0] == '-') {
09266                 /* Special case - "-" => no transcoding */
09267                 enc = enc2;
09268                 enc2 = NULL;
09269             }
09270             else
09271                 enc = find_encoding(v2);
09272             if (enc == enc2) {
09273                 /* Special case - "-" => no transcoding */
09274                 enc2 = NULL;
09275             }
09276         }
09277         else {
09278             enc = find_encoding(v2);
09279             if (enc == enc2) {
09280                 /* Special case - "-" => no transcoding */
09281                 enc2 = NULL;
09282             }
09283         }
09284         SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
09285         ecflags = rb_econv_prepare_options(opt, &ecopts, ecflags);
09286     }
09287     else {
09288         if (NIL_P(v1)) {
09289             /* Set to default encodings */
09290             rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
09291             SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
09292             ecopts = Qnil;
09293         }
09294         else {
09295             tmp = rb_check_string_type(v1);
09296             if (!NIL_P(tmp) && rb_enc_asciicompat(rb_enc_get(tmp))) {
09297                 parse_mode_enc(RSTRING_PTR(tmp), &enc, &enc2, NULL);
09298                 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
09299                 ecflags = rb_econv_prepare_options(opt, &ecopts, ecflags);
09300             }
09301             else {
09302                 rb_io_ext_int_to_encs(find_encoding(v1), NULL, &enc, &enc2, 0);
09303                 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
09304                 ecopts = Qnil;
09305             }
09306         }
09307     }
09308     validate_enc_binmode(&fptr->mode, ecflags, enc, enc2);
09309     fptr->encs.enc = enc;
09310     fptr->encs.enc2 = enc2;
09311     fptr->encs.ecflags = ecflags;
09312     fptr->encs.ecopts = ecopts;
09313     clear_codeconv(fptr);
09314 
09315 }
09316 
09317 static VALUE
09318 pipe_pair_close(VALUE rw)
09319 {
09320     VALUE *rwp = (VALUE *)rw;
09321     return rb_ensure(io_close, rwp[0], io_close, rwp[1]);
09322 }
09323 
09324 /*
09325  *  call-seq:
09326  *     IO.pipe                             ->  [read_io, write_io]
09327  *     IO.pipe(ext_enc)                    ->  [read_io, write_io]
09328  *     IO.pipe("ext_enc:int_enc" [, opt])  ->  [read_io, write_io]
09329  *     IO.pipe(ext_enc, int_enc [, opt])   ->  [read_io, write_io]
09330  *
09331  *     IO.pipe(...) {|read_io, write_io| ... }
09332  *
09333  *  Creates a pair of pipe endpoints (connected to each other) and
09334  *  returns them as a two-element array of <code>IO</code> objects:
09335  *  <code>[</code> <i>read_io</i>, <i>write_io</i> <code>]</code>.
09336  *
09337  *  If a block is given, the block is called and
09338  *  returns the value of the block.
09339  *  <i>read_io</i> and <i>write_io</i> are sent to the block as arguments.
09340  *  If read_io and write_io are not closed when the block exits, they are closed.
09341  *  i.e. closing read_io and/or write_io doesn't cause an error.
09342  *
09343  *  Not available on all platforms.
09344  *
09345  *  If an encoding (encoding name or encoding object) is specified as an optional argument,
09346  *  read string from pipe is tagged with the encoding specified.
09347  *  If the argument is a colon separated two encoding names "A:B",
09348  *  the read string is converted from encoding A (external encoding)
09349  *  to encoding B (internal encoding), then tagged with B.
09350  *  If two optional arguments are specified, those must be
09351  *  encoding objects or encoding names,
09352  *  and the first one is the external encoding,
09353  *  and the second one is the internal encoding.
09354  *  If the external encoding and the internal encoding is specified,
09355  *  optional hash argument specify the conversion option.
09356  *
09357  *  In the example below, the two processes close the ends of the pipe
09358  *  that they are not using. This is not just a cosmetic nicety. The
09359  *  read end of a pipe will not generate an end of file condition if
09360  *  there are any writers with the pipe still open. In the case of the
09361  *  parent process, the <code>rd.read</code> will never return if it
09362  *  does not first issue a <code>wr.close</code>.
09363  *
09364  *     rd, wr = IO.pipe
09365  *
09366  *     if fork
09367  *       wr.close
09368  *       puts "Parent got: <#{rd.read}>"
09369  *       rd.close
09370  *       Process.wait
09371  *     else
09372  *       rd.close
09373  *       puts "Sending message to parent"
09374  *       wr.write "Hi Dad"
09375  *       wr.close
09376  *     end
09377  *
09378  *  <em>produces:</em>
09379  *
09380  *     Sending message to parent
09381  *     Parent got: <Hi Dad>
09382  */
09383 
09384 static VALUE
09385 rb_io_s_pipe(int argc, VALUE *argv, VALUE klass)
09386 {
09387     int pipes[2], state;
09388     VALUE r, w, args[3], v1, v2;
09389     VALUE opt;
09390     rb_io_t *fptr, *fptr2;
09391     int fmode = 0;
09392     VALUE ret;
09393 
09394     argc = rb_scan_args(argc, argv, "02:", &v1, &v2, &opt);
09395     if (rb_pipe(pipes) == -1)
09396         rb_sys_fail(0);
09397 
09398     args[0] = klass;
09399     args[1] = INT2NUM(pipes[0]);
09400     args[2] = INT2FIX(O_RDONLY);
09401     r = rb_protect(io_new_instance, (VALUE)args, &state);
09402     if (state) {
09403         close(pipes[0]);
09404         close(pipes[1]);
09405         rb_jump_tag(state);
09406     }
09407     GetOpenFile(r, fptr);
09408     io_encoding_set(fptr, v1, v2, opt);
09409     args[1] = INT2NUM(pipes[1]);
09410     args[2] = INT2FIX(O_WRONLY);
09411     w = rb_protect(io_new_instance, (VALUE)args, &state);
09412     if (state) {
09413         close(pipes[1]);
09414         if (!NIL_P(r)) rb_io_close(r);
09415         rb_jump_tag(state);
09416     }
09417     GetOpenFile(w, fptr2);
09418     rb_io_synchronized(fptr2);
09419 
09420     extract_binmode(opt, &fmode);
09421 #if DEFAULT_TEXTMODE
09422     if ((fptr->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
09423         fptr->mode &= ~FMODE_TEXTMODE;
09424         setmode(fptr->fd, O_BINARY);
09425     }
09426 #if defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32)
09427     if (fptr->encs.ecflags & ECONV_DEFAULT_NEWLINE_DECORATOR) {
09428         fptr->encs.ecflags |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;
09429     }
09430 #endif
09431 #endif
09432     fptr->mode |= fmode;
09433 #if DEFAULT_TEXTMODE
09434     if ((fptr2->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
09435         fptr2->mode &= ~FMODE_TEXTMODE;
09436         setmode(fptr2->fd, O_BINARY);
09437     }
09438 #endif
09439     fptr2->mode |= fmode;
09440 
09441     ret = rb_assoc_new(r, w);
09442     if (rb_block_given_p()) {
09443         VALUE rw[2];
09444         rw[0] = r;
09445         rw[1] = w;
09446         return rb_ensure(rb_yield, ret, pipe_pair_close, (VALUE)rw);
09447     }
09448     return ret;
09449 }
09450 
09451 struct foreach_arg {
09452     int argc;
09453     VALUE *argv;
09454     VALUE io;
09455 };
09456 
09457 static void
09458 open_key_args(int argc, VALUE *argv, VALUE opt, struct foreach_arg *arg)
09459 {
09460     VALUE path, v;
09461 
09462     path = *argv++;
09463     argc--;
09464     FilePathValue(path);
09465     arg->io = 0;
09466     arg->argc = argc;
09467     arg->argv = argv;
09468     if (NIL_P(opt)) {
09469         arg->io = rb_io_open(path, INT2NUM(O_RDONLY), INT2FIX(0666), Qnil);
09470         return;
09471     }
09472     v = rb_hash_aref(opt, sym_open_args);
09473     if (!NIL_P(v)) {
09474         VALUE args;
09475         long n;
09476 
09477         v = rb_convert_type(v, T_ARRAY, "Array", "to_ary");
09478         n = RARRAY_LEN(v) + 1;
09479 #if SIZEOF_LONG > SIZEOF_INT
09480         if (n > INT_MAX) {
09481             rb_raise(rb_eArgError, "too many arguments");
09482         }
09483 #endif
09484         args = rb_ary_tmp_new(n);
09485         rb_ary_push(args, path);
09486         rb_ary_concat(args, v);
09487         arg->io = rb_io_open_with_args((int)n, RARRAY_CONST_PTR(args));
09488         rb_ary_clear(args);     /* prevent from GC */
09489         return;
09490     }
09491     arg->io = rb_io_open(path, Qnil, Qnil, opt);
09492 }
09493 
09494 static VALUE
09495 io_s_foreach(struct foreach_arg *arg)
09496 {
09497     VALUE str;
09498 
09499     while (!NIL_P(str = rb_io_gets_m(arg->argc, arg->argv, arg->io))) {
09500         rb_yield(str);
09501     }
09502     return Qnil;
09503 }
09504 
09505 /*
09506  *  call-seq:
09507  *     IO.foreach(name, sep=$/ [, open_args]) {|line| block }     -> nil
09508  *     IO.foreach(name, limit [, open_args]) {|line| block }      -> nil
09509  *     IO.foreach(name, sep, limit [, open_args]) {|line| block } -> nil
09510  *     IO.foreach(...)                                            -> an_enumerator
09511  *
09512  *  Executes the block for every line in the named I/O port, where lines
09513  *  are separated by <em>sep</em>.
09514  *
09515  *  If no block is given, an enumerator is returned instead.
09516  *
09517  *     IO.foreach("testfile") {|x| print "GOT ", x }
09518  *
09519  *  <em>produces:</em>
09520  *
09521  *     GOT This is line one
09522  *     GOT This is line two
09523  *     GOT This is line three
09524  *     GOT And so on...
09525  *
09526  *  If the last argument is a hash, it's the keyword argument to open.
09527  *  See <code>IO.read</code> for detail.
09528  *
09529  */
09530 
09531 static VALUE
09532 rb_io_s_foreach(int argc, VALUE *argv, VALUE self)
09533 {
09534     VALUE opt;
09535     int orig_argc = argc;
09536     struct foreach_arg arg;
09537 
09538     argc = rb_scan_args(argc, argv, "13:", NULL, NULL, NULL, NULL, &opt);
09539     RETURN_ENUMERATOR(self, orig_argc, argv);
09540     open_key_args(argc, argv, opt, &arg);
09541     if (NIL_P(arg.io)) return Qnil;
09542     return rb_ensure(io_s_foreach, (VALUE)&arg, rb_io_close, arg.io);
09543 }
09544 
09545 static VALUE
09546 io_s_readlines(struct foreach_arg *arg)
09547 {
09548     return rb_io_readlines(arg->argc, arg->argv, arg->io);
09549 }
09550 
09551 /*
09552  *  call-seq:
09553  *     IO.readlines(name, sep=$/ [, open_args])     -> array
09554  *     IO.readlines(name, limit [, open_args])      -> array
09555  *     IO.readlines(name, sep, limit [, open_args]) -> array
09556  *
09557  *  Reads the entire file specified by <i>name</i> as individual
09558  *  lines, and returns those lines in an array. Lines are separated by
09559  *  <i>sep</i>.
09560  *
09561  *     a = IO.readlines("testfile")
09562  *     a[0]   #=> "This is line one\n"
09563  *
09564  *  If the last argument is a hash, it's the keyword argument to open.
09565  *  See <code>IO.read</code> for detail.
09566  *
09567  */
09568 
09569 static VALUE
09570 rb_io_s_readlines(int argc, VALUE *argv, VALUE io)
09571 {
09572     VALUE opt;
09573     struct foreach_arg arg;
09574 
09575     argc = rb_scan_args(argc, argv, "13:", NULL, NULL, NULL, NULL, &opt);
09576     open_key_args(argc, argv, opt, &arg);
09577     if (NIL_P(arg.io)) return Qnil;
09578     return rb_ensure(io_s_readlines, (VALUE)&arg, rb_io_close, arg.io);
09579 }
09580 
09581 static VALUE
09582 io_s_read(struct foreach_arg *arg)
09583 {
09584     return io_read(arg->argc, arg->argv, arg->io);
09585 }
09586 
09587 struct seek_arg {
09588     VALUE io;
09589     VALUE offset;
09590     int mode;
09591 };
09592 
09593 static VALUE
09594 seek_before_access(VALUE argp)
09595 {
09596     struct seek_arg *arg = (struct seek_arg *)argp;
09597     rb_io_binmode(arg->io);
09598     return rb_io_seek(arg->io, arg->offset, arg->mode);
09599 }
09600 
09601 /*
09602  *  call-seq:
09603  *     IO.read(name, [length [, offset]] )   -> string
09604  *     IO.read(name, [length [, offset]], open_args)   -> string
09605  *
09606  *  Opens the file, optionally seeks to the given +offset+, then returns
09607  *  +length+ bytes (defaulting to the rest of the file).  <code>read</code>
09608  *  ensures the file is closed before returning.
09609  *
09610  *  If the last argument is a hash, it specifies option for internal
09611  *  open().  The key would be the following.  open_args: is exclusive
09612  *  to others.
09613  *
09614  *  encoding::
09615  *    string or encoding
09616  *
09617  *    specifies encoding of the read string.  +encoding+ will be ignored
09618  *    if length is specified.
09619  *
09620  *  mode::
09621  *    string
09622  *
09623  *    specifies mode argument for open().  It should start with "r"
09624  *    otherwise it will cause an error.
09625  *
09626  *  open_args:: array of strings
09627  *
09628  *    specifies arguments for open() as an array.
09629  *
09630  *  Examples:
09631  *
09632  *    IO.read("testfile")           #=> "This is line one\nThis is line two\nThis is line three\nAnd so on...\n"
09633  *    IO.read("testfile", 20)       #=> "This is line one\nThi"
09634  *    IO.read("testfile", 20, 10)   #=> "ne one\nThis is line "
09635  */
09636 
09637 static VALUE
09638 rb_io_s_read(int argc, VALUE *argv, VALUE io)
09639 {
09640     VALUE opt, offset;
09641     struct foreach_arg arg;
09642 
09643     argc = rb_scan_args(argc, argv, "13:", NULL, NULL, &offset, NULL, &opt);
09644     open_key_args(argc, argv, opt, &arg);
09645     if (NIL_P(arg.io)) return Qnil;
09646     if (!NIL_P(offset)) {
09647         struct seek_arg sarg;
09648         int state = 0;
09649         sarg.io = arg.io;
09650         sarg.offset = offset;
09651         sarg.mode = SEEK_SET;
09652         rb_protect(seek_before_access, (VALUE)&sarg, &state);
09653         if (state) {
09654             rb_io_close(arg.io);
09655             rb_jump_tag(state);
09656         }
09657         if (arg.argc == 2) arg.argc = 1;
09658     }
09659     return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
09660 }
09661 
09662 /*
09663  *  call-seq:
09664  *     IO.binread(name, [length [, offset]] )   -> string
09665  *
09666  *  Opens the file, optionally seeks to the given <i>offset</i>, then returns
09667  *  <i>length</i> bytes (defaulting to the rest of the file).
09668  *  <code>binread</code> ensures the file is closed before returning.
09669  *  The open mode would be "rb:ASCII-8BIT".
09670  *
09671  *     IO.binread("testfile")           #=> "This is line one\nThis is line two\nThis is line three\nAnd so on...\n"
09672  *     IO.binread("testfile", 20)       #=> "This is line one\nThi"
09673  *     IO.binread("testfile", 20, 10)   #=> "ne one\nThis is line "
09674  */
09675 
09676 static VALUE
09677 rb_io_s_binread(int argc, VALUE *argv, VALUE io)
09678 {
09679     VALUE offset;
09680     struct foreach_arg arg;
09681 
09682     rb_scan_args(argc, argv, "12", NULL, NULL, &offset);
09683     FilePathValue(argv[0]);
09684     arg.io = rb_io_open(argv[0], rb_str_new_cstr("rb:ASCII-8BIT"), Qnil, Qnil);
09685     if (NIL_P(arg.io)) return Qnil;
09686     arg.argv = argv+1;
09687     arg.argc = (argc > 1) ? 1 : 0;
09688     if (!NIL_P(offset)) {
09689         rb_io_seek(arg.io, offset, SEEK_SET);
09690     }
09691     return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
09692 }
09693 
09694 static VALUE
09695 io_s_write0(struct write_arg *arg)
09696 {
09697     return io_write(arg->io,arg->str,arg->nosync);
09698 }
09699 
09700 static VALUE
09701 io_s_write(int argc, VALUE *argv, int binary)
09702 {
09703     VALUE string, offset, opt;
09704     struct foreach_arg arg;
09705     struct write_arg warg;
09706 
09707     rb_scan_args(argc, argv, "21:", NULL, &string, &offset, &opt);
09708 
09709     if (NIL_P(opt)) opt = rb_hash_new();
09710     else opt = rb_hash_dup(opt);
09711 
09712 
09713     if (NIL_P(rb_hash_aref(opt,sym_mode))) {
09714        int mode = O_WRONLY|O_CREAT;
09715 #ifdef O_BINARY
09716        if (binary) mode |= O_BINARY;
09717 #endif
09718        if (NIL_P(offset)) mode |= O_TRUNC;
09719        rb_hash_aset(opt,sym_mode,INT2NUM(mode));
09720     }
09721     open_key_args(argc,argv,opt,&arg);
09722 
09723 #ifndef O_BINARY
09724     if (binary) rb_io_binmode_m(arg.io);
09725 #endif
09726 
09727     if (NIL_P(arg.io)) return Qnil;
09728     if (!NIL_P(offset)) {
09729        struct seek_arg sarg;
09730        int state = 0;
09731        sarg.io = arg.io;
09732        sarg.offset = offset;
09733        sarg.mode = SEEK_SET;
09734        rb_protect(seek_before_access, (VALUE)&sarg, &state);
09735        if (state) {
09736            rb_io_close(arg.io);
09737            rb_jump_tag(state);
09738        }
09739     }
09740 
09741     warg.io = arg.io;
09742     warg.str = string;
09743     warg.nosync = 0;
09744 
09745     return rb_ensure(io_s_write0, (VALUE)&warg, rb_io_close, arg.io);
09746 }
09747 
09748 /*
09749  *  call-seq:
09750  *     IO.write(name, string, [offset] )   => fixnum
09751  *     IO.write(name, string, [offset], open_args )   => fixnum
09752  *
09753  *  Opens the file, optionally seeks to the given <i>offset</i>, writes
09754  *  <i>string</i>, then returns the length written.
09755  *  <code>write</code> ensures the file is closed before returning.
09756  *  If <i>offset</i> is not given, the file is truncated.  Otherwise,
09757  *  it is not truncated.
09758  *
09759  *  If the last argument is a hash, it specifies option for internal
09760  *  open().  The key would be the following.  open_args: is exclusive
09761  *  to others.
09762  *
09763  *   encoding: string or encoding
09764  *
09765  *    specifies encoding of the read string.  encoding will be ignored
09766  *    if length is specified.
09767  *
09768  *   mode: string
09769  *
09770  *    specifies mode argument for open().  it should start with "w" or "a" or "r+"
09771  *    otherwise it would cause error.
09772  *
09773  *   perm: fixnum
09774  *
09775  *    specifies perm argument for open().
09776  *
09777  *   open_args: array
09778  *
09779  *    specifies arguments for open() as an array.
09780  *
09781  *     IO.write("testfile", "0123456789", 20) # => 10
09782  *     # File could contain:  "This is line one\nThi0123456789two\nThis is line three\nAnd so on...\n"
09783  *     IO.write("testfile", "0123456789")      #=> 10
09784  *     # File would now read: "0123456789"
09785  */
09786 
09787 static VALUE
09788 rb_io_s_write(int argc, VALUE *argv, VALUE io)
09789 {
09790     return io_s_write(argc, argv, 0);
09791 }
09792 
09793 /*
09794  *  call-seq:
09795  *     IO.binwrite(name, string, [offset] )   => fixnum
09796  *     IO.binwrite(name, string, [offset], open_args )   => fixnum
09797  *
09798  *  Same as <code>IO.write</code> except opening the file in binary mode
09799  *  and ASCII-8BIT encoding ("wb:ASCII-8BIT").
09800  *
09801  */
09802 
09803 static VALUE
09804 rb_io_s_binwrite(int argc, VALUE *argv, VALUE io)
09805 {
09806     return io_s_write(argc, argv, 1);
09807 }
09808 
09809 struct copy_stream_struct {
09810     VALUE src;
09811     VALUE dst;
09812     off_t copy_length; /* (off_t)-1 if not specified */
09813     off_t src_offset; /* (off_t)-1 if not specified */
09814 
09815     int src_fd;
09816     int dst_fd;
09817     int close_src;
09818     int close_dst;
09819     off_t total;
09820     const char *syserr;
09821     int error_no;
09822     const char *notimp;
09823     rb_fdset_t fds;
09824     VALUE th;
09825 };
09826 
09827 static void *
09828 exec_interrupts(void *arg)
09829 {
09830     VALUE th = (VALUE)arg;
09831     rb_thread_execute_interrupts(th);
09832     return NULL;
09833 }
09834 
09835 /*
09836  * returns TRUE if the preceding system call was interrupted
09837  * so we can continue.  If the thread was interrupted, we
09838  * reacquire the GVL to execute interrupts before continuing.
09839  */
09840 static int
09841 maygvl_copy_stream_continue_p(int has_gvl, struct copy_stream_struct *stp)
09842 {
09843     switch (errno) {
09844       case EINTR:
09845 #if defined(ERESTART)
09846       case ERESTART:
09847 #endif
09848         if (rb_thread_interrupted(stp->th)) {
09849             if (has_gvl)
09850                 rb_thread_execute_interrupts(stp->th);
09851             else
09852                 rb_thread_call_with_gvl(exec_interrupts, (void *)stp->th);
09853         }
09854         return TRUE;
09855     }
09856     return FALSE;
09857 }
09858 
09859 static int
09860 maygvl_select(int has_gvl, int n, rb_fdset_t *rfds, rb_fdset_t *wfds, rb_fdset_t *efds, struct timeval *timeout)
09861 {
09862     if (has_gvl)
09863         return rb_thread_fd_select(n, rfds, wfds, efds, timeout);
09864     else
09865         return rb_fd_select(n, rfds, wfds, efds, timeout);
09866 }
09867 
09868 static int
09869 maygvl_copy_stream_wait_read(int has_gvl, struct copy_stream_struct *stp)
09870 {
09871     int ret;
09872 
09873     do {
09874         rb_fd_zero(&stp->fds);
09875         rb_fd_set(stp->src_fd, &stp->fds);
09876         ret = maygvl_select(has_gvl, rb_fd_max(&stp->fds), &stp->fds, NULL, NULL, NULL);
09877     } while (ret == -1 && maygvl_copy_stream_continue_p(has_gvl, stp));
09878 
09879     if (ret == -1) {
09880         stp->syserr = "select";
09881         stp->error_no = errno;
09882         return -1;
09883     }
09884     return 0;
09885 }
09886 
09887 static int
09888 nogvl_copy_stream_wait_write(struct copy_stream_struct *stp)
09889 {
09890     int ret;
09891 
09892     do {
09893         rb_fd_zero(&stp->fds);
09894         rb_fd_set(stp->dst_fd, &stp->fds);
09895         ret = rb_fd_select(rb_fd_max(&stp->fds), NULL, &stp->fds, NULL, NULL);
09896     } while (ret == -1 && maygvl_copy_stream_continue_p(0, stp));
09897 
09898     if (ret == -1) {
09899         stp->syserr = "select";
09900         stp->error_no = errno;
09901         return -1;
09902     }
09903     return 0;
09904 }
09905 
09906 #ifdef HAVE_SENDFILE
09907 
09908 # ifdef __linux__
09909 #  define USE_SENDFILE
09910 
09911 #  ifdef HAVE_SYS_SENDFILE_H
09912 #   include <sys/sendfile.h>
09913 #  endif
09914 
09915 static ssize_t
09916 simple_sendfile(int out_fd, int in_fd, off_t *offset, off_t count)
09917 {
09918     return sendfile(out_fd, in_fd, offset, (size_t)count);
09919 }
09920 
09921 # elif 0 /* defined(__FreeBSD__) || defined(__DragonFly__) */ || defined(__APPLE__)
09922 /* This runs on FreeBSD8.1 r30210, but sendfiles blocks its execution
09923  * without cpuset -l 0.
09924  */
09925 #  define USE_SENDFILE
09926 
09927 #  ifdef HAVE_SYS_UIO_H
09928 #   include <sys/uio.h>
09929 #  endif
09930 
09931 static ssize_t
09932 simple_sendfile(int out_fd, int in_fd, off_t *offset, off_t count)
09933 {
09934     int r;
09935     off_t pos = offset ? *offset : lseek(in_fd, 0, SEEK_CUR);
09936     off_t sbytes;
09937 #  ifdef __APPLE__
09938     r = sendfile(in_fd, out_fd, pos, &count, NULL, 0);
09939     sbytes = count;
09940 #  else
09941     r = sendfile(in_fd, out_fd, pos, (size_t)count, NULL, &sbytes, 0);
09942 #  endif
09943     if (r != 0 && sbytes == 0) return -1;
09944     if (offset) {
09945         *offset += sbytes;
09946     }
09947     else {
09948         lseek(in_fd, sbytes, SEEK_CUR);
09949     }
09950     return (ssize_t)sbytes;
09951 }
09952 
09953 # endif
09954 
09955 #endif
09956 
09957 #ifdef USE_SENDFILE
09958 static int
09959 nogvl_copy_stream_sendfile(struct copy_stream_struct *stp)
09960 {
09961     struct stat src_stat, dst_stat;
09962     ssize_t ss;
09963     int ret;
09964 
09965     off_t copy_length;
09966     off_t src_offset;
09967     int use_pread;
09968 
09969     ret = fstat(stp->src_fd, &src_stat);
09970     if (ret == -1) {
09971         stp->syserr = "fstat";
09972         stp->error_no = errno;
09973         return -1;
09974     }
09975     if (!S_ISREG(src_stat.st_mode))
09976         return 0;
09977 
09978     ret = fstat(stp->dst_fd, &dst_stat);
09979     if (ret == -1) {
09980         stp->syserr = "fstat";
09981         stp->error_no = errno;
09982         return -1;
09983     }
09984     if ((dst_stat.st_mode & S_IFMT) != S_IFSOCK)
09985         return 0;
09986 
09987     src_offset = stp->src_offset;
09988     use_pread = src_offset != (off_t)-1;
09989 
09990     copy_length = stp->copy_length;
09991     if (copy_length == (off_t)-1) {
09992         if (use_pread)
09993             copy_length = src_stat.st_size - src_offset;
09994         else {
09995             off_t cur;
09996             errno = 0;
09997             cur = lseek(stp->src_fd, 0, SEEK_CUR);
09998             if (cur == (off_t)-1 && errno) {
09999                 stp->syserr = "lseek";
10000                 stp->error_no = errno;
10001                 return -1;
10002             }
10003             copy_length = src_stat.st_size - cur;
10004         }
10005     }
10006 
10007   retry_sendfile:
10008 # if SIZEOF_OFF_T > SIZEOF_SIZE_T
10009     /* we are limited by the 32-bit ssize_t return value on 32-bit */
10010     ss = (copy_length > (off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
10011 # else
10012     ss = (ssize_t)copy_length;
10013 # endif
10014     if (use_pread) {
10015         ss = simple_sendfile(stp->dst_fd, stp->src_fd, &src_offset, ss);
10016     }
10017     else {
10018         ss = simple_sendfile(stp->dst_fd, stp->src_fd, NULL, ss);
10019     }
10020     if (0 < ss) {
10021         stp->total += ss;
10022         copy_length -= ss;
10023         if (0 < copy_length) {
10024             goto retry_sendfile;
10025         }
10026     }
10027     if (ss == -1) {
10028         if (maygvl_copy_stream_continue_p(0, stp))
10029             goto retry_sendfile;
10030         switch (errno) {
10031           case EINVAL:
10032 #ifdef ENOSYS
10033           case ENOSYS:
10034 #endif
10035             return 0;
10036           case EAGAIN:
10037 #if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
10038           case EWOULDBLOCK:
10039 #endif
10040 #ifndef __linux__
10041            /*
10042             * Linux requires stp->src_fd to be a mmap-able (regular) file,
10043             * select() reports regular files to always be "ready", so
10044             * there is no need to select() on it.
10045             * Other OSes may have the same limitation for sendfile() which
10046             * allow us to bypass maygvl_copy_stream_wait_read()...
10047             */
10048             if (maygvl_copy_stream_wait_read(0, stp) == -1)
10049                 return -1;
10050 #endif
10051             if (nogvl_copy_stream_wait_write(stp) == -1)
10052                 return -1;
10053             goto retry_sendfile;
10054         }
10055         stp->syserr = "sendfile";
10056         stp->error_no = errno;
10057         return -1;
10058     }
10059     return 1;
10060 }
10061 #endif
10062 
10063 static ssize_t
10064 maygvl_read(int has_gvl, int fd, void *buf, size_t count)
10065 {
10066     if (has_gvl)
10067         return rb_read_internal(fd, buf, count);
10068     else
10069         return read(fd, buf, count);
10070 }
10071 
10072 static ssize_t
10073 maygvl_copy_stream_read(int has_gvl, struct copy_stream_struct *stp, char *buf, size_t len, off_t offset)
10074 {
10075     ssize_t ss;
10076   retry_read:
10077     if (offset == (off_t)-1) {
10078         ss = maygvl_read(has_gvl, stp->src_fd, buf, len);
10079     }
10080     else {
10081 #ifdef HAVE_PREAD
10082         ss = pread(stp->src_fd, buf, len, offset);
10083 #else
10084         stp->notimp = "pread";
10085         return -1;
10086 #endif
10087     }
10088     if (ss == 0) {
10089         return 0;
10090     }
10091     if (ss == -1) {
10092         if (maygvl_copy_stream_continue_p(has_gvl, stp))
10093             goto retry_read;
10094         switch (errno) {
10095           case EAGAIN:
10096 #if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
10097           case EWOULDBLOCK:
10098 #endif
10099             if (maygvl_copy_stream_wait_read(has_gvl, stp) == -1)
10100                 return -1;
10101             goto retry_read;
10102 #ifdef ENOSYS
10103           case ENOSYS:
10104 #endif
10105             stp->notimp = "pread";
10106             return -1;
10107         }
10108         stp->syserr = offset == (off_t)-1 ?  "read" : "pread";
10109         stp->error_no = errno;
10110         return -1;
10111     }
10112     return ss;
10113 }
10114 
10115 static int
10116 nogvl_copy_stream_write(struct copy_stream_struct *stp, char *buf, size_t len)
10117 {
10118     ssize_t ss;
10119     int off = 0;
10120     while (len) {
10121         ss = write(stp->dst_fd, buf+off, len);
10122         if (ss == -1) {
10123             if (maygvl_copy_stream_continue_p(0, stp))
10124                 continue;
10125             if (errno == EAGAIN || errno == EWOULDBLOCK) {
10126                 if (nogvl_copy_stream_wait_write(stp) == -1)
10127                     return -1;
10128                 continue;
10129             }
10130             stp->syserr = "write";
10131             stp->error_no = errno;
10132             return -1;
10133         }
10134         off += (int)ss;
10135         len -= (int)ss;
10136         stp->total += ss;
10137     }
10138     return 0;
10139 }
10140 
10141 static void
10142 nogvl_copy_stream_read_write(struct copy_stream_struct *stp)
10143 {
10144     char buf[1024*16];
10145     size_t len;
10146     ssize_t ss;
10147     int ret;
10148     off_t copy_length;
10149     int use_eof;
10150     off_t src_offset;
10151     int use_pread;
10152 
10153     copy_length = stp->copy_length;
10154     use_eof = copy_length == (off_t)-1;
10155     src_offset = stp->src_offset;
10156     use_pread = src_offset != (off_t)-1;
10157 
10158     if (use_pread && stp->close_src) {
10159         off_t r;
10160         errno = 0;
10161         r = lseek(stp->src_fd, src_offset, SEEK_SET);
10162         if (r == (off_t)-1 && errno) {
10163             stp->syserr = "lseek";
10164             stp->error_no = errno;
10165             return;
10166         }
10167         src_offset = (off_t)-1;
10168         use_pread = 0;
10169     }
10170 
10171     while (use_eof || 0 < copy_length) {
10172         if (!use_eof && copy_length < (off_t)sizeof(buf)) {
10173             len = (size_t)copy_length;
10174         }
10175         else {
10176             len = sizeof(buf);
10177         }
10178         if (use_pread) {
10179             ss = maygvl_copy_stream_read(0, stp, buf, len, src_offset);
10180             if (0 < ss)
10181                 src_offset += ss;
10182         }
10183         else {
10184             ss = maygvl_copy_stream_read(0, stp, buf, len, (off_t)-1);
10185         }
10186         if (ss <= 0) /* EOF or error */
10187             return;
10188 
10189         ret = nogvl_copy_stream_write(stp, buf, ss);
10190         if (ret < 0)
10191             return;
10192 
10193         if (!use_eof)
10194             copy_length -= ss;
10195     }
10196 }
10197 
10198 static void *
10199 nogvl_copy_stream_func(void *arg)
10200 {
10201     struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
10202 #ifdef USE_SENDFILE
10203     int ret;
10204 #endif
10205 
10206 #ifdef USE_SENDFILE
10207     ret = nogvl_copy_stream_sendfile(stp);
10208     if (ret != 0)
10209         goto finish; /* error or success */
10210 #endif
10211 
10212     nogvl_copy_stream_read_write(stp);
10213 
10214 #ifdef USE_SENDFILE
10215   finish:
10216 #endif
10217     return 0;
10218 }
10219 
10220 static VALUE
10221 copy_stream_fallback_body(VALUE arg)
10222 {
10223     struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
10224     const int buflen = 16*1024;
10225     VALUE n;
10226     VALUE buf = rb_str_buf_new(buflen);
10227     off_t rest = stp->copy_length;
10228     off_t off = stp->src_offset;
10229     ID read_method = id_readpartial;
10230 
10231     if (stp->src_fd == -1) {
10232         if (!rb_respond_to(stp->src, read_method)) {
10233             read_method = id_read;
10234         }
10235     }
10236 
10237     while (1) {
10238         long numwrote;
10239         long l;
10240         if (stp->copy_length == (off_t)-1) {
10241             l = buflen;
10242         }
10243         else {
10244             if (rest == 0)
10245                 break;
10246             l = buflen < rest ? buflen : (long)rest;
10247         }
10248         if (stp->src_fd == -1) {
10249             VALUE rc = rb_funcall(stp->src, read_method, 2, INT2FIX(l), buf);
10250 
10251             if (read_method == id_read && NIL_P(rc))
10252                 break;
10253         }
10254         else {
10255             ssize_t ss;
10256             rb_str_resize(buf, buflen);
10257             ss = maygvl_copy_stream_read(1, stp, RSTRING_PTR(buf), l, off);
10258             if (ss == -1)
10259                 return Qnil;
10260             if (ss == 0)
10261                 rb_eof_error();
10262             rb_str_resize(buf, ss);
10263             if (off != (off_t)-1)
10264                 off += ss;
10265         }
10266         n = rb_io_write(stp->dst, buf);
10267         numwrote = NUM2LONG(n);
10268         stp->total += numwrote;
10269         rest -= numwrote;
10270         if (read_method == id_read && RSTRING_LEN(buf) == 0) {
10271             break;
10272         }
10273     }
10274 
10275     return Qnil;
10276 }
10277 
10278 static VALUE
10279 copy_stream_fallback(struct copy_stream_struct *stp)
10280 {
10281     if (stp->src_fd == -1 && stp->src_offset != (off_t)-1) {
10282         rb_raise(rb_eArgError, "cannot specify src_offset for non-IO");
10283     }
10284     rb_rescue2(copy_stream_fallback_body, (VALUE)stp,
10285                (VALUE (*) (ANYARGS))0, (VALUE)0,
10286                rb_eEOFError, (VALUE)0);
10287     return Qnil;
10288 }
10289 
10290 static VALUE
10291 copy_stream_body(VALUE arg)
10292 {
10293     struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
10294     VALUE src_io = stp->src, dst_io = stp->dst;
10295     rb_io_t *src_fptr = 0, *dst_fptr = 0;
10296     int src_fd, dst_fd;
10297     const int common_oflags = 0
10298 #ifdef O_NOCTTY
10299         | O_NOCTTY
10300 #endif
10301         ;
10302 
10303     stp->th = rb_thread_current();
10304 
10305     stp->total = 0;
10306 
10307     if (src_io == argf ||
10308         !(RB_TYPE_P(src_io, T_FILE) ||
10309           RB_TYPE_P(src_io, T_STRING) ||
10310           rb_respond_to(src_io, rb_intern("to_path")))) {
10311         src_fd = -1;
10312     }
10313     else {
10314         if (!RB_TYPE_P(src_io, T_FILE)) {
10315             VALUE args[2];
10316             FilePathValue(src_io);
10317             args[0] = src_io;
10318             args[1] = INT2NUM(O_RDONLY|common_oflags);
10319             src_io = rb_class_new_instance(2, args, rb_cFile);
10320             stp->src = src_io;
10321             stp->close_src = 1;
10322         }
10323         GetOpenFile(src_io, src_fptr);
10324         rb_io_check_byte_readable(src_fptr);
10325         src_fd = src_fptr->fd;
10326     }
10327     stp->src_fd = src_fd;
10328 
10329     if (dst_io == argf ||
10330         !(RB_TYPE_P(dst_io, T_FILE) ||
10331           RB_TYPE_P(dst_io, T_STRING) ||
10332           rb_respond_to(dst_io, rb_intern("to_path")))) {
10333         dst_fd = -1;
10334     }
10335     else {
10336         if (!RB_TYPE_P(dst_io, T_FILE)) {
10337             VALUE args[3];
10338             FilePathValue(dst_io);
10339             args[0] = dst_io;
10340             args[1] = INT2NUM(O_WRONLY|O_CREAT|O_TRUNC|common_oflags);
10341             args[2] = INT2FIX(0666);
10342             dst_io = rb_class_new_instance(3, args, rb_cFile);
10343             stp->dst = dst_io;
10344             stp->close_dst = 1;
10345         }
10346         else {
10347             dst_io = GetWriteIO(dst_io);
10348             stp->dst = dst_io;
10349         }
10350         GetOpenFile(dst_io, dst_fptr);
10351         rb_io_check_writable(dst_fptr);
10352         dst_fd = dst_fptr->fd;
10353     }
10354     stp->dst_fd = dst_fd;
10355 
10356 #ifdef O_BINARY
10357     if (src_fptr)
10358         SET_BINARY_MODE_WITH_SEEK_CUR(src_fptr);
10359 #endif
10360     if (dst_fptr)
10361         io_ascii8bit_binmode(dst_fptr);
10362 
10363     if (stp->src_offset == (off_t)-1 && src_fptr && src_fptr->rbuf.len) {
10364         size_t len = src_fptr->rbuf.len;
10365         VALUE str;
10366         if (stp->copy_length != (off_t)-1 && stp->copy_length < (off_t)len) {
10367             len = (size_t)stp->copy_length;
10368         }
10369         str = rb_str_buf_new(len);
10370         rb_str_resize(str,len);
10371         read_buffered_data(RSTRING_PTR(str), len, src_fptr);
10372         if (dst_fptr) { /* IO or filename */
10373             if (io_binwrite(str, RSTRING_PTR(str), RSTRING_LEN(str), dst_fptr, 0) < 0)
10374                 rb_sys_fail(0);
10375         }
10376         else /* others such as StringIO */
10377             rb_io_write(dst_io, str);
10378         stp->total += len;
10379         if (stp->copy_length != (off_t)-1)
10380             stp->copy_length -= len;
10381     }
10382 
10383     if (dst_fptr && io_fflush(dst_fptr) < 0) {
10384         rb_raise(rb_eIOError, "flush failed");
10385     }
10386 
10387     if (stp->copy_length == 0)
10388         return Qnil;
10389 
10390     if (src_fd == -1 || dst_fd == -1) {
10391         return copy_stream_fallback(stp);
10392     }
10393 
10394     rb_fd_set(src_fd, &stp->fds);
10395     rb_fd_set(dst_fd, &stp->fds);
10396 
10397     rb_thread_call_without_gvl(nogvl_copy_stream_func, (void*)stp, RUBY_UBF_IO, 0);
10398     return Qnil;
10399 }
10400 
10401 static VALUE
10402 copy_stream_finalize(VALUE arg)
10403 {
10404     struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
10405     if (stp->close_src) {
10406         rb_io_close_m(stp->src);
10407     }
10408     if (stp->close_dst) {
10409         rb_io_close_m(stp->dst);
10410     }
10411     rb_fd_term(&stp->fds);
10412     if (stp->syserr) {
10413         errno = stp->error_no;
10414         rb_sys_fail(stp->syserr);
10415     }
10416     if (stp->notimp) {
10417         rb_raise(rb_eNotImpError, "%s() not implemented", stp->notimp);
10418     }
10419     return Qnil;
10420 }
10421 
10422 /*
10423  *  call-seq:
10424  *     IO.copy_stream(src, dst)
10425  *     IO.copy_stream(src, dst, copy_length)
10426  *     IO.copy_stream(src, dst, copy_length, src_offset)
10427  *
10428  *  IO.copy_stream copies <i>src</i> to <i>dst</i>.
10429  *  <i>src</i> and <i>dst</i> is either a filename or an IO.
10430  *
10431  *  This method returns the number of bytes copied.
10432  *
10433  *  If optional arguments are not given,
10434  *  the start position of the copy is
10435  *  the beginning of the filename or
10436  *  the current file offset of the IO.
10437  *  The end position of the copy is the end of file.
10438  *
10439  *  If <i>copy_length</i> is given,
10440  *  No more than <i>copy_length</i> bytes are copied.
10441  *
10442  *  If <i>src_offset</i> is given,
10443  *  it specifies the start position of the copy.
10444  *
10445  *  When <i>src_offset</i> is specified and
10446  *  <i>src</i> is an IO,
10447  *  IO.copy_stream doesn't move the current file offset.
10448  *
10449  */
10450 static VALUE
10451 rb_io_s_copy_stream(int argc, VALUE *argv, VALUE io)
10452 {
10453     VALUE src, dst, length, src_offset;
10454     struct copy_stream_struct st;
10455 
10456     MEMZERO(&st, struct copy_stream_struct, 1);
10457 
10458     rb_scan_args(argc, argv, "22", &src, &dst, &length, &src_offset);
10459 
10460     st.src = src;
10461     st.dst = dst;
10462 
10463     if (NIL_P(length))
10464         st.copy_length = (off_t)-1;
10465     else
10466         st.copy_length = NUM2OFFT(length);
10467 
10468     if (NIL_P(src_offset))
10469         st.src_offset = (off_t)-1;
10470     else
10471         st.src_offset = NUM2OFFT(src_offset);
10472 
10473     rb_fd_init(&st.fds);
10474     rb_ensure(copy_stream_body, (VALUE)&st, copy_stream_finalize, (VALUE)&st);
10475 
10476     return OFFT2NUM(st.total);
10477 }
10478 
10479 /*
10480  *  call-seq:
10481  *     io.external_encoding   -> encoding
10482  *
10483  *  Returns the Encoding object that represents the encoding of the file.
10484  *  If io is write mode and no encoding is specified, returns <code>nil</code>.
10485  */
10486 
10487 static VALUE
10488 rb_io_external_encoding(VALUE io)
10489 {
10490     rb_io_t *fptr;
10491 
10492     GetOpenFile(io, fptr);
10493     if (fptr->encs.enc2) {
10494         return rb_enc_from_encoding(fptr->encs.enc2);
10495     }
10496     if (fptr->mode & FMODE_WRITABLE) {
10497         if (fptr->encs.enc)
10498             return rb_enc_from_encoding(fptr->encs.enc);
10499         return Qnil;
10500     }
10501     return rb_enc_from_encoding(io_read_encoding(fptr));
10502 }
10503 
10504 /*
10505  *  call-seq:
10506  *     io.internal_encoding   -> encoding
10507  *
10508  *  Returns the Encoding of the internal string if conversion is
10509  *  specified.  Otherwise returns nil.
10510  */
10511 
10512 static VALUE
10513 rb_io_internal_encoding(VALUE io)
10514 {
10515     rb_io_t *fptr;
10516 
10517     GetOpenFile(io, fptr);
10518     if (!fptr->encs.enc2) return Qnil;
10519     return rb_enc_from_encoding(io_read_encoding(fptr));
10520 }
10521 
10522 /*
10523  *  call-seq:
10524  *     io.set_encoding(ext_enc)                -> io
10525  *     io.set_encoding("ext_enc:int_enc")      -> io
10526  *     io.set_encoding(ext_enc, int_enc)       -> io
10527  *     io.set_encoding("ext_enc:int_enc", opt) -> io
10528  *     io.set_encoding(ext_enc, int_enc, opt)  -> io
10529  *
10530  *  If single argument is specified, read string from io is tagged
10531  *  with the encoding specified.  If encoding is a colon separated two
10532  *  encoding names "A:B", the read string is converted from encoding A
10533  *  (external encoding) to encoding B (internal encoding), then tagged
10534  *  with B.  If two arguments are specified, those must be encoding
10535  *  objects or encoding names, and the first one is the external encoding, and the
10536  *  second one is the internal encoding.
10537  *  If the external encoding and the internal encoding is specified,
10538  *  optional hash argument specify the conversion option.
10539  */
10540 
10541 static VALUE
10542 rb_io_set_encoding(int argc, VALUE *argv, VALUE io)
10543 {
10544     rb_io_t *fptr;
10545     VALUE v1, v2, opt;
10546 
10547     if (!RB_TYPE_P(io, T_FILE)) {
10548         return rb_funcall2(io, id_set_encoding, argc, argv);
10549     }
10550 
10551     argc = rb_scan_args(argc, argv, "11:", &v1, &v2, &opt);
10552     GetOpenFile(io, fptr);
10553     io_encoding_set(fptr, v1, v2, opt);
10554     return io;
10555 }
10556 
10557 void
10558 rb_stdio_set_default_encoding(void)
10559 {
10560     extern VALUE rb_stdin, rb_stdout, rb_stderr;
10561     VALUE val = Qnil;
10562 
10563     rb_io_set_encoding(1, &val, rb_stdin);
10564     rb_io_set_encoding(1, &val, rb_stdout);
10565     rb_io_set_encoding(1, &val, rb_stderr);
10566 }
10567 
10568 /*
10569  *  call-seq:
10570  *     ARGF.external_encoding   -> encoding
10571  *
10572  *  Returns the external encoding for files read from +ARGF+ as an +Encoding+
10573  *  object. The external encoding is the encoding of the text as stored in a
10574  *  file. Contrast with +ARGF.internal_encoding+, which is the encoding used
10575  *  to represent this text within Ruby.
10576  *
10577  *  To set the external encoding use +ARGF.set_encoding+.
10578  *
10579  * For example:
10580  *
10581  *     ARGF.external_encoding  #=>  #<Encoding:UTF-8>
10582  *
10583  */
10584 static VALUE
10585 argf_external_encoding(VALUE argf)
10586 {
10587     if (!RTEST(ARGF.current_file)) {
10588         return rb_enc_from_encoding(rb_default_external_encoding());
10589     }
10590     return rb_io_external_encoding(rb_io_check_io(ARGF.current_file));
10591 }
10592 
10593 /*
10594  *  call-seq:
10595  *     ARGF.internal_encoding   -> encoding
10596  *
10597  *  Returns the internal encoding for strings read from +ARGF+ as an
10598  *  +Encoding+ object.
10599  *
10600  *  If +ARGF.set_encoding+ has been called with two encoding names, the second
10601  *  is returned. Otherwise, if +Encoding.default_external+ has been set, that
10602  *  value is returned. Failing that, if a default external encoding was
10603  *  specified on the command-line, that value is used. If the encoding is
10604  *  unknown, nil is returned.
10605  */
10606 static VALUE
10607 argf_internal_encoding(VALUE argf)
10608 {
10609     if (!RTEST(ARGF.current_file)) {
10610         return rb_enc_from_encoding(rb_default_external_encoding());
10611     }
10612     return rb_io_internal_encoding(rb_io_check_io(ARGF.current_file));
10613 }
10614 
10615 /*
10616  *  call-seq:
10617  *     ARGF.set_encoding(ext_enc)                -> ARGF
10618  *     ARGF.set_encoding("ext_enc:int_enc")      -> ARGF
10619  *     ARGF.set_encoding(ext_enc, int_enc)       -> ARGF
10620  *     ARGF.set_encoding("ext_enc:int_enc", opt) -> ARGF
10621  *     ARGF.set_encoding(ext_enc, int_enc, opt)  -> ARGF
10622  *
10623  *  If single argument is specified, strings read from ARGF are tagged with
10624  *  the encoding specified.
10625  *
10626  *  If two encoding names separated by a colon are given, e.g. "ascii:utf-8",
10627  *  the read string is converted from the first encoding (external encoding)
10628  *  to the second encoding (internal encoding), then tagged with the second
10629  *  encoding.
10630  *
10631  *  If two arguments are specified, they must be encoding objects or encoding
10632  *  names. Again, the first specifies the external encoding; the second
10633  *  specifies the internal encoding.
10634  *
10635  *  If the external encoding and the internal encoding are specified, the
10636  *  optional +Hash+ argument can be used to adjust the conversion process. The
10637  *  structure of this hash is explained in the +String#encode+ documentation.
10638  *
10639  *  For example:
10640  *
10641  *      ARGF.set_encoding('ascii')         # Tag the input as US-ASCII text
10642  *      ARGF.set_encoding(Encoding::UTF_8) # Tag the input as UTF-8 text
10643  *      ARGF.set_encoding('utf-8','ascii') # Transcode the input from US-ASCII
10644  *                                         # to UTF-8.
10645  */
10646 static VALUE
10647 argf_set_encoding(int argc, VALUE *argv, VALUE argf)
10648 {
10649     rb_io_t *fptr;
10650 
10651     if (!next_argv()) {
10652         rb_raise(rb_eArgError, "no stream to set encoding");
10653     }
10654     rb_io_set_encoding(argc, argv, ARGF.current_file);
10655     GetOpenFile(ARGF.current_file, fptr);
10656     ARGF.encs = fptr->encs;
10657     return argf;
10658 }
10659 
10660 /*
10661  *  call-seq:
10662  *     ARGF.tell  -> Integer
10663  *     ARGF.pos   -> Integer
10664  *
10665  *  Returns the current offset (in bytes) of the current file in +ARGF+.
10666  *
10667  *     ARGF.pos    #=> 0
10668  *     ARGF.gets   #=> "This is line one\n"
10669  *     ARGF.pos    #=> 17
10670  *
10671  */
10672 static VALUE
10673 argf_tell(VALUE argf)
10674 {
10675     if (!next_argv()) {
10676         rb_raise(rb_eArgError, "no stream to tell");
10677     }
10678     ARGF_FORWARD(0, 0);
10679     return rb_io_tell(ARGF.current_file);
10680 }
10681 
10682 /*
10683  *  call-seq:
10684  *     ARGF.seek(amount, whence=IO::SEEK_SET)  ->  0
10685  *
10686  *  Seeks to offset _amount_ (an +Integer+) in the +ARGF+ stream according to
10687  *  the value of _whence_. See +IO#seek+ for further details.
10688  */
10689 static VALUE
10690 argf_seek_m(int argc, VALUE *argv, VALUE argf)
10691 {
10692     if (!next_argv()) {
10693         rb_raise(rb_eArgError, "no stream to seek");
10694     }
10695     ARGF_FORWARD(argc, argv);
10696     return rb_io_seek_m(argc, argv, ARGF.current_file);
10697 }
10698 
10699 /*
10700  *  call-seq:
10701  *     ARGF.pos = position  -> Integer
10702  *
10703  *  Seeks to the position given by _position_ (in bytes) in +ARGF+.
10704  *
10705  *  For example:
10706  *
10707  *      ARGF.pos = 17
10708  *      ARGF.gets   #=> "This is line two\n"
10709  */
10710 static VALUE
10711 argf_set_pos(VALUE argf, VALUE offset)
10712 {
10713     if (!next_argv()) {
10714         rb_raise(rb_eArgError, "no stream to set position");
10715     }
10716     ARGF_FORWARD(1, &offset);
10717     return rb_io_set_pos(ARGF.current_file, offset);
10718 }
10719 
10720 /*
10721  *  call-seq:
10722  *     ARGF.rewind   -> 0
10723  *
10724  *  Positions the current file to the beginning of input, resetting
10725  *  +ARGF.lineno+ to zero.
10726  *
10727  *     ARGF.readline   #=> "This is line one\n"
10728  *     ARGF.rewind     #=> 0
10729  *     ARGF.lineno     #=> 0
10730  *     ARGF.readline   #=> "This is line one\n"
10731  */
10732 static VALUE
10733 argf_rewind(VALUE argf)
10734 {
10735     if (!next_argv()) {
10736         rb_raise(rb_eArgError, "no stream to rewind");
10737     }
10738     ARGF_FORWARD(0, 0);
10739     return rb_io_rewind(ARGF.current_file);
10740 }
10741 
10742 /*
10743  *  call-seq:
10744  *     ARGF.fileno    -> fixnum
10745  *     ARGF.to_i      -> fixnum
10746  *
10747  *  Returns an integer representing the numeric file descriptor for
10748  *  the current file. Raises an +ArgumentError+ if there isn't a current file.
10749  *
10750  *     ARGF.fileno    #=> 3
10751  */
10752 static VALUE
10753 argf_fileno(VALUE argf)
10754 {
10755     if (!next_argv()) {
10756         rb_raise(rb_eArgError, "no stream");
10757     }
10758     ARGF_FORWARD(0, 0);
10759     return rb_io_fileno(ARGF.current_file);
10760 }
10761 
10762 /*
10763  *  call-seq:
10764  *     ARGF.to_io     -> IO
10765  *
10766  *  Returns an +IO+ object representing the current file. This will be a
10767  *  +File+ object unless the current file is a stream such as STDIN.
10768  *
10769  *  For example:
10770  *
10771  *     ARGF.to_io    #=> #<File:glark.txt>
10772  *     ARGF.to_io    #=> #<IO:<STDIN>>
10773  */
10774 static VALUE
10775 argf_to_io(VALUE argf)
10776 {
10777     next_argv();
10778     ARGF_FORWARD(0, 0);
10779     return ARGF.current_file;
10780 }
10781 
10782 /*
10783  *  call-seq:
10784  *     ARGF.eof?  -> true or false
10785  *     ARGF.eof   -> true or false
10786  *
10787  *  Returns true if the current file in +ARGF+ is at end of file, i.e. it has
10788  *  no data to read. The stream must be opened for reading or an +IOError+
10789  *  will be raised.
10790  *
10791  *     $ echo "eof" | ruby argf.rb
10792  *
10793  *     ARGF.eof?                 #=> false
10794  *     3.times { ARGF.readchar }
10795  *     ARGF.eof?                 #=> false
10796  *     ARGF.readchar             #=> "\n"
10797  *     ARGF.eof?                 #=> true
10798  */
10799 
10800 static VALUE
10801 argf_eof(VALUE argf)
10802 {
10803     next_argv();
10804     if (RTEST(ARGF.current_file)) {
10805         if (ARGF.init_p == 0) return Qtrue;
10806         next_argv();
10807         ARGF_FORWARD(0, 0);
10808         if (rb_io_eof(ARGF.current_file)) {
10809             return Qtrue;
10810         }
10811     }
10812     return Qfalse;
10813 }
10814 
10815 /*
10816  *  call-seq:
10817  *     ARGF.read([length [, outbuf]])    -> string, outbuf, or nil
10818  *
10819  *  Reads _length_ bytes from ARGF. The files named on the command line
10820  *  are concatenated and treated as a single file by this method, so when
10821  *  called without arguments the contents of this pseudo file are returned in
10822  *  their entirety.
10823  *
10824  *  _length_ must be a non-negative integer or nil. If it is a positive
10825  *  integer, +read+ tries to read at most _length_ bytes. It returns nil
10826  *  if an EOF was encountered before anything could be read. Fewer than
10827  *  _length_ bytes may be returned if an EOF is encountered during the read.
10828  *
10829  *  If _length_ is omitted or is _nil_, it reads until EOF. A String is
10830  *  returned even if EOF is encountered before any data is read.
10831  *
10832  *  If _length_ is zero, it returns _""_.
10833  *
10834  *  If the optional _outbuf_ argument is present, it must reference a String,
10835  *  which will receive the data.
10836  *  The <i>outbuf</i> will contain only the received data after the method call
10837  *  even if it is not empty at the beginning.
10838  *
10839  * For example:
10840  *
10841  *     $ echo "small" > small.txt
10842  *     $ echo "large" > large.txt
10843  *     $ ./glark.rb small.txt large.txt
10844  *
10845  *     ARGF.read      #=> "small\nlarge"
10846  *     ARGF.read(200) #=> "small\nlarge"
10847  *     ARGF.read(2)   #=> "sm"
10848  *     ARGF.read(0)   #=> ""
10849  *
10850  *  Note that this method behaves like fread() function in C.  If you need the
10851  *  behavior like read(2) system call, consider +ARGF.readpartial+.
10852  */
10853 
10854 static VALUE
10855 argf_read(int argc, VALUE *argv, VALUE argf)
10856 {
10857     VALUE tmp, str, length;
10858     long len = 0;
10859 
10860     rb_scan_args(argc, argv, "02", &length, &str);
10861     if (!NIL_P(length)) {
10862         len = NUM2LONG(argv[0]);
10863     }
10864     if (!NIL_P(str)) {
10865         StringValue(str);
10866         rb_str_resize(str,0);
10867         argv[1] = Qnil;
10868     }
10869 
10870   retry:
10871     if (!next_argv()) {
10872         return str;
10873     }
10874     if (ARGF_GENERIC_INPUT_P()) {
10875         tmp = argf_forward(argc, argv, argf);
10876     }
10877     else {
10878         tmp = io_read(argc, argv, ARGF.current_file);
10879     }
10880     if (NIL_P(str)) str = tmp;
10881     else if (!NIL_P(tmp)) rb_str_append(str, tmp);
10882     if (NIL_P(tmp) || NIL_P(length)) {
10883         if (ARGF.next_p != -1) {
10884             argf_close(argf);
10885             ARGF.next_p = 1;
10886             goto retry;
10887         }
10888     }
10889     else if (argc >= 1) {
10890         if (RSTRING_LEN(str) < len) {
10891             len -= RSTRING_LEN(str);
10892             argv[0] = INT2NUM(len);
10893             goto retry;
10894         }
10895     }
10896     return str;
10897 }
10898 
10899 struct argf_call_arg {
10900     int argc;
10901     VALUE *argv;
10902     VALUE argf;
10903 };
10904 
10905 static VALUE
10906 argf_forward_call(VALUE arg)
10907 {
10908     struct argf_call_arg *p = (struct argf_call_arg *)arg;
10909     argf_forward(p->argc, p->argv, p->argf);
10910     return Qnil;
10911 }
10912 
10913 static VALUE argf_getpartial(int argc, VALUE *argv, VALUE argf, int nonblock);
10914 
10915 /*
10916  *  call-seq:
10917  *     ARGF.readpartial(maxlen)              -> string
10918  *     ARGF.readpartial(maxlen, outbuf)      -> outbuf
10919  *
10920  *  Reads at most _maxlen_ bytes from the ARGF stream.
10921  *
10922  *  If the optional _outbuf_ argument is present,
10923  *  it must reference a String, which will receive the data.
10924  *  The <i>outbuf</i> will contain only the received data after the method call
10925  *  even if it is not empty at the beginning.
10926  *
10927  *  It raises <code>EOFError</code> on end of ARGF stream.
10928  *  Since ARGF stream is a concatenation of multiple files,
10929  *  internally EOF is occur for each file.
10930  *  ARGF.readpartial returns empty strings for EOFs except the last one and
10931  *  raises <code>EOFError</code> for the last one.
10932  *
10933  */
10934 
10935 static VALUE
10936 argf_readpartial(int argc, VALUE *argv, VALUE argf)
10937 {
10938     return argf_getpartial(argc, argv, argf, 0);
10939 }
10940 
10941 /*
10942  *  call-seq:
10943  *     ARGF.read_nonblock(maxlen)              -> string
10944  *     ARGF.read_nonblock(maxlen, outbuf)      -> outbuf
10945  *
10946  *  Reads at most _maxlen_ bytes from the ARGF stream in non-blocking mode.
10947  */
10948 
10949 static VALUE
10950 argf_read_nonblock(int argc, VALUE *argv, VALUE argf)
10951 {
10952     return argf_getpartial(argc, argv, argf, 1);
10953 }
10954 
10955 static VALUE
10956 argf_getpartial(int argc, VALUE *argv, VALUE argf, int nonblock)
10957 {
10958     VALUE tmp, str, length;
10959 
10960     rb_scan_args(argc, argv, "11", &length, &str);
10961     if (!NIL_P(str)) {
10962         StringValue(str);
10963         argv[1] = str;
10964     }
10965 
10966     if (!next_argv()) {
10967         rb_str_resize(str, 0);
10968         rb_eof_error();
10969     }
10970     if (ARGF_GENERIC_INPUT_P()) {
10971         struct argf_call_arg arg;
10972         arg.argc = argc;
10973         arg.argv = argv;
10974         arg.argf = argf;
10975         tmp = rb_rescue2(argf_forward_call, (VALUE)&arg,
10976                          RUBY_METHOD_FUNC(0), Qnil, rb_eEOFError, (VALUE)0);
10977     }
10978     else {
10979         tmp = io_getpartial(argc, argv, ARGF.current_file, nonblock, 0);
10980     }
10981     if (NIL_P(tmp)) {
10982         if (ARGF.next_p == -1) {
10983             rb_eof_error();
10984         }
10985         argf_close(argf);
10986         ARGF.next_p = 1;
10987         if (RARRAY_LEN(ARGF.argv) == 0)
10988             rb_eof_error();
10989         if (NIL_P(str))
10990             str = rb_str_new(NULL, 0);
10991         return str;
10992     }
10993     return tmp;
10994 }
10995 
10996 /*
10997  *  call-seq:
10998  *     ARGF.getc  -> String or nil
10999  *
11000  *  Reads the next character from +ARGF+ and returns it as a +String+. Returns
11001  *  +nil+ at the end of the stream.
11002  *
11003  *  +ARGF+ treats the files named on the command line as a single file created
11004  *  by concatenating their contents. After returning the last character of the
11005  *  first file, it returns the first character of the second file, and so on.
11006  *
11007  *  For example:
11008  *
11009  *     $ echo "foo" > file
11010  *     $ ruby argf.rb file
11011  *
11012  *     ARGF.getc  #=> "f"
11013  *     ARGF.getc  #=> "o"
11014  *     ARGF.getc  #=> "o"
11015  *     ARGF.getc  #=> "\n"
11016  *     ARGF.getc  #=> nil
11017  *     ARGF.getc  #=> nil
11018  */
11019 static VALUE
11020 argf_getc(VALUE argf)
11021 {
11022     VALUE ch;
11023 
11024   retry:
11025     if (!next_argv()) return Qnil;
11026     if (ARGF_GENERIC_INPUT_P()) {
11027         ch = rb_funcall3(ARGF.current_file, rb_intern("getc"), 0, 0);
11028     }
11029     else {
11030         ch = rb_io_getc(ARGF.current_file);
11031     }
11032     if (NIL_P(ch) && ARGF.next_p != -1) {
11033         argf_close(argf);
11034         ARGF.next_p = 1;
11035         goto retry;
11036     }
11037 
11038     return ch;
11039 }
11040 
11041 /*
11042  *  call-seq:
11043  *     ARGF.getbyte  -> Fixnum or nil
11044  *
11045  *  Gets the next 8-bit byte (0..255) from +ARGF+. Returns +nil+ if called at
11046  *  the end of the stream.
11047  *
11048  *  For example:
11049  *
11050  *     $ echo "foo" > file
11051  *     $ ruby argf.rb file
11052  *
11053  *     ARGF.getbyte #=> 102
11054  *     ARGF.getbyte #=> 111
11055  *     ARGF.getbyte #=> 111
11056  *     ARGF.getbyte #=> 10
11057  *     ARGF.getbyte #=> nil
11058  */
11059 static VALUE
11060 argf_getbyte(VALUE argf)
11061 {
11062     VALUE ch;
11063 
11064   retry:
11065     if (!next_argv()) return Qnil;
11066     if (!RB_TYPE_P(ARGF.current_file, T_FILE)) {
11067         ch = rb_funcall3(ARGF.current_file, rb_intern("getbyte"), 0, 0);
11068     }
11069     else {
11070         ch = rb_io_getbyte(ARGF.current_file);
11071     }
11072     if (NIL_P(ch) && ARGF.next_p != -1) {
11073         argf_close(argf);
11074         ARGF.next_p = 1;
11075         goto retry;
11076     }
11077 
11078     return ch;
11079 }
11080 
11081 /*
11082  *  call-seq:
11083  *     ARGF.readchar  -> String or nil
11084  *
11085  *  Reads the next character from +ARGF+ and returns it as a +String+. Raises
11086  *  an +EOFError+ after the last character of the last file has been read.
11087  *
11088  *  For example:
11089  *
11090  *     $ echo "foo" > file
11091  *     $ ruby argf.rb file
11092  *
11093  *     ARGF.readchar  #=> "f"
11094  *     ARGF.readchar  #=> "o"
11095  *     ARGF.readchar  #=> "o"
11096  *     ARGF.readchar  #=> "\n"
11097  *     ARGF.readchar  #=> end of file reached (EOFError)
11098  */
11099 static VALUE
11100 argf_readchar(VALUE argf)
11101 {
11102     VALUE ch;
11103 
11104   retry:
11105     if (!next_argv()) rb_eof_error();
11106     if (!RB_TYPE_P(ARGF.current_file, T_FILE)) {
11107         ch = rb_funcall3(ARGF.current_file, rb_intern("getc"), 0, 0);
11108     }
11109     else {
11110         ch = rb_io_getc(ARGF.current_file);
11111     }
11112     if (NIL_P(ch) && ARGF.next_p != -1) {
11113         argf_close(argf);
11114         ARGF.next_p = 1;
11115         goto retry;
11116     }
11117 
11118     return ch;
11119 }
11120 
11121 /*
11122  *  call-seq:
11123  *     ARGF.readbyte  -> Fixnum
11124  *
11125  *  Reads the next 8-bit byte from ARGF and returns it as a +Fixnum+. Raises
11126  *  an +EOFError+ after the last byte of the last file has been read.
11127  *
11128  *  For example:
11129  *
11130  *     $ echo "foo" > file
11131  *     $ ruby argf.rb file
11132  *
11133  *     ARGF.readbyte  #=> 102
11134  *     ARGF.readbyte  #=> 111
11135  *     ARGF.readbyte  #=> 111
11136  *     ARGF.readbyte  #=> 10
11137  *     ARGF.readbyte  #=> end of file reached (EOFError)
11138  */
11139 static VALUE
11140 argf_readbyte(VALUE argf)
11141 {
11142     VALUE c;
11143 
11144     NEXT_ARGF_FORWARD(0, 0);
11145     c = argf_getbyte(argf);
11146     if (NIL_P(c)) {
11147         rb_eof_error();
11148     }
11149     return c;
11150 }
11151 
11152 #define FOREACH_ARGF() while (next_argv())
11153 
11154 static VALUE
11155 argf_block_call_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, argf))
11156 {
11157     const VALUE current = ARGF.current_file;
11158     rb_yield_values2(argc, argv);
11159     if (ARGF.init_p == -1 || current != ARGF.current_file) {
11160         rb_iter_break_value(Qundef);
11161     }
11162     return Qnil;
11163 }
11164 
11165 static void
11166 argf_block_call(ID mid, int argc, VALUE *argv, VALUE argf)
11167 {
11168     VALUE ret = rb_block_call(ARGF.current_file, mid, argc, argv, argf_block_call_i, argf);
11169     if (ret != Qundef) ARGF.next_p = 1;
11170 }
11171 
11172 /*
11173  *  call-seq:
11174  *     ARGF.each(sep=$/)            {|line| block }  -> ARGF
11175  *     ARGF.each(sep=$/,limit)      {|line| block }  -> ARGF
11176  *     ARGF.each(...)                                -> an_enumerator
11177  *
11178  *     ARGF.each_line(sep=$/)       {|line| block }  -> ARGF
11179  *     ARGF.each_line(sep=$/,limit) {|line| block }  -> ARGF
11180  *     ARGF.each_line(...)                           -> an_enumerator
11181  *
11182  *  Returns an enumerator which iterates over each line (separated by _sep_,
11183  *  which defaults to your platform's newline character) of each file in
11184  *  +ARGV+. If a block is supplied, each line in turn will be yielded to the
11185  *  block, otherwise an enumerator is returned.
11186  *  The optional _limit_ argument is a +Fixnum+ specifying the maximum
11187  *  length of each line; longer lines will be split according to this limit.
11188  *
11189  *  This method allows you to treat the files supplied on the command line as
11190  *  a single file consisting of the concatenation of each named file. After
11191  *  the last line of the first file has been returned, the first line of the
11192  *  second file is returned. The +ARGF.filename+ and +ARGF.lineno+ methods can
11193  *  be used to determine the filename and line number, respectively, of the
11194  *  current line.
11195  *
11196  *  For example, the following code prints out each line of each named file
11197  *  prefixed with its line number, displaying the filename once per file:
11198  *
11199  *     ARGF.lines do |line|
11200  *       puts ARGF.filename if ARGF.lineno == 1
11201  *       puts "#{ARGF.lineno}: #{line}"
11202  *     end
11203  */
11204 static VALUE
11205 argf_each_line(int argc, VALUE *argv, VALUE argf)
11206 {
11207     RETURN_ENUMERATOR(argf, argc, argv);
11208     FOREACH_ARGF() {
11209         argf_block_call(rb_intern("each_line"), argc, argv, argf);
11210     }
11211     return argf;
11212 }
11213 
11214 /*
11215  *  This is a deprecated alias for <code>each_line</code>.
11216  */
11217 
11218 static VALUE
11219 argf_lines(int argc, VALUE *argv, VALUE argf)
11220 {
11221     rb_warn("ARGF#lines is deprecated; use #each_line instead");
11222     if (!rb_block_given_p())
11223         return rb_enumeratorize(argf, ID2SYM(rb_intern("each_line")), argc, argv);
11224     return argf_each_line(argc, argv, argf);
11225 }
11226 
11227 /*
11228  *  call-seq:
11229  *     ARGF.bytes     {|byte| block }  -> ARGF
11230  *     ARGF.bytes                      -> an_enumerator
11231  *
11232  *     ARGF.each_byte {|byte| block }  -> ARGF
11233  *     ARGF.each_byte                  -> an_enumerator
11234  *
11235  *  Iterates over each byte of each file in +ARGV+.
11236  *  A byte is returned as a +Fixnum+ in the range 0..255.
11237  *
11238  *  This method allows you to treat the files supplied on the command line as
11239  *  a single file consisting of the concatenation of each named file. After
11240  *  the last byte of the first file has been returned, the first byte of the
11241  *  second file is returned. The +ARGF.filename+ method can be used to
11242  *  determine the filename of the current byte.
11243  *
11244  *  If no block is given, an enumerator is returned instead.
11245  *
11246  * For example:
11247  *
11248  *     ARGF.bytes.to_a  #=> [35, 32, ... 95, 10]
11249  *
11250  */
11251 static VALUE
11252 argf_each_byte(VALUE argf)
11253 {
11254     RETURN_ENUMERATOR(argf, 0, 0);
11255     FOREACH_ARGF() {
11256         argf_block_call(rb_intern("each_byte"), 0, 0, argf);
11257     }
11258     return argf;
11259 }
11260 
11261 /*
11262  *  This is a deprecated alias for <code>each_byte</code>.
11263  */
11264 
11265 static VALUE
11266 argf_bytes(VALUE argf)
11267 {
11268     rb_warn("ARGF#bytes is deprecated; use #each_byte instead");
11269     if (!rb_block_given_p())
11270         return rb_enumeratorize(argf, ID2SYM(rb_intern("each_byte")), 0, 0);
11271     return argf_each_byte(argf);
11272 }
11273 
11274 /*
11275  *  call-seq:
11276  *     ARGF.each_char  {|char| block }  -> ARGF
11277  *     ARGF.each_char                   -> an_enumerator
11278  *
11279  *  Iterates over each character of each file in +ARGF+.
11280  *
11281  *  This method allows you to treat the files supplied on the command line as
11282  *  a single file consisting of the concatenation of each named file. After
11283  *  the last character of the first file has been returned, the first
11284  *  character of the second file is returned. The +ARGF.filename+ method can
11285  *  be used to determine the name of the file in which the current character
11286  *  appears.
11287  *
11288  *  If no block is given, an enumerator is returned instead.
11289  */
11290 static VALUE
11291 argf_each_char(VALUE argf)
11292 {
11293     RETURN_ENUMERATOR(argf, 0, 0);
11294     FOREACH_ARGF() {
11295         argf_block_call(rb_intern("each_char"), 0, 0, argf);
11296     }
11297     return argf;
11298 }
11299 
11300 /*
11301  *  This is a deprecated alias for <code>each_char</code>.
11302  */
11303 
11304 static VALUE
11305 argf_chars(VALUE argf)
11306 {
11307     rb_warn("ARGF#chars is deprecated; use #each_char instead");
11308     if (!rb_block_given_p())
11309         return rb_enumeratorize(argf, ID2SYM(rb_intern("each_char")), 0, 0);
11310     return argf_each_char(argf);
11311 }
11312 
11313 /*
11314  *  call-seq:
11315  *     ARGF.each_codepoint  {|codepoint| block }  -> ARGF
11316  *     ARGF.each_codepoint                   -> an_enumerator
11317  *
11318  *  Iterates over each codepoint of each file in +ARGF+.
11319  *
11320  *  This method allows you to treat the files supplied on the command line as
11321  *  a single file consisting of the concatenation of each named file. After
11322  *  the last codepoint of the first file has been returned, the first
11323  *  codepoint of the second file is returned. The +ARGF.filename+ method can
11324  *  be used to determine the name of the file in which the current codepoint
11325  *  appears.
11326  *
11327  *  If no block is given, an enumerator is returned instead.
11328  */
11329 static VALUE
11330 argf_each_codepoint(VALUE argf)
11331 {
11332     RETURN_ENUMERATOR(argf, 0, 0);
11333     FOREACH_ARGF() {
11334         argf_block_call(rb_intern("each_codepoint"), 0, 0, argf);
11335     }
11336     return argf;
11337 }
11338 
11339 /*
11340  *  This is a deprecated alias for <code>each_codepoint</code>.
11341  */
11342 
11343 static VALUE
11344 argf_codepoints(VALUE argf)
11345 {
11346     rb_warn("ARGF#codepoints is deprecated; use #each_codepoint instead");
11347     if (!rb_block_given_p())
11348         return rb_enumeratorize(argf, ID2SYM(rb_intern("each_codepoint")), 0, 0);
11349     return argf_each_codepoint(argf);
11350 }
11351 
11352 /*
11353  *  call-seq:
11354  *     ARGF.filename  -> String
11355  *     ARGF.path      -> String
11356  *
11357  *  Returns the current filename. "-" is returned when the current file is
11358  *  STDIN.
11359  *
11360  *  For example:
11361  *
11362  *     $ echo "foo" > foo
11363  *     $ echo "bar" > bar
11364  *     $ echo "glark" > glark
11365  *
11366  *     $ ruby argf.rb foo bar glark
11367  *
11368  *     ARGF.filename  #=> "foo"
11369  *     ARGF.read(5)   #=> "foo\nb"
11370  *     ARGF.filename  #=> "bar"
11371  *     ARGF.skip
11372  *     ARGF.filename  #=> "glark"
11373  */
11374 static VALUE
11375 argf_filename(VALUE argf)
11376 {
11377     next_argv();
11378     return ARGF.filename;
11379 }
11380 
11381 static VALUE
11382 argf_filename_getter(ID id, VALUE *var)
11383 {
11384     return argf_filename(*var);
11385 }
11386 
11387 /*
11388  *  call-seq:
11389  *     ARGF.file  -> IO or File object
11390  *
11391  *  Returns the current file as an +IO+ or +File+ object. #<IO:<STDIN>> is
11392  *  returned when the current file is STDIN.
11393  *
11394  *  For example:
11395  *
11396  *     $ echo "foo" > foo
11397  *     $ echo "bar" > bar
11398  *
11399  *     $ ruby argf.rb foo bar
11400  *
11401  *     ARGF.file      #=> #<File:foo>
11402  *     ARGF.read(5)   #=> "foo\nb"
11403  *     ARGF.file      #=> #<File:bar>
11404  */
11405 static VALUE
11406 argf_file(VALUE argf)
11407 {
11408     next_argv();
11409     return ARGF.current_file;
11410 }
11411 
11412 /*
11413  *  call-seq:
11414  *     ARGF.binmode  -> ARGF
11415  *
11416  *  Puts +ARGF+ into binary mode. Once a stream is in binary mode, it cannot
11417  *  be reset to non-binary mode. This option has the following effects:
11418  *
11419  *  *  Newline conversion is disabled.
11420  *  *  Encoding conversion is disabled.
11421  *  *  Content is treated as ASCII-8BIT.
11422  */
11423 static VALUE
11424 argf_binmode_m(VALUE argf)
11425 {
11426     ARGF.binmode = 1;
11427     next_argv();
11428     ARGF_FORWARD(0, 0);
11429     rb_io_ascii8bit_binmode(ARGF.current_file);
11430     return argf;
11431 }
11432 
11433 /*
11434  *  call-seq:
11435  *     ARGF.binmode?  -> true or false
11436  *
11437  *  Returns true if +ARGF+ is being read in binary mode; false otherwise. (To
11438  *  enable binary mode use +ARGF.binmode+.
11439  *
11440  * For example:
11441  *
11442  *     ARGF.binmode?  #=> false
11443  *     ARGF.binmode
11444  *     ARGF.binmode?  #=> true
11445  */
11446 static VALUE
11447 argf_binmode_p(VALUE argf)
11448 {
11449     return ARGF.binmode ? Qtrue : Qfalse;
11450 }
11451 
11452 /*
11453  *  call-seq:
11454  *     ARGF.skip  -> ARGF
11455  *
11456  *  Sets the current file to the next file in ARGV. If there aren't any more
11457  *  files it has no effect.
11458  *
11459  * For example:
11460  *
11461  *     $ ruby argf.rb foo bar
11462  *     ARGF.filename  #=> "foo"
11463  *     ARGF.skip
11464  *     ARGF.filename  #=> "bar"
11465  */
11466 static VALUE
11467 argf_skip(VALUE argf)
11468 {
11469     if (ARGF.init_p && ARGF.next_p == 0) {
11470         argf_close(argf);
11471         ARGF.next_p = 1;
11472     }
11473     return argf;
11474 }
11475 
11476 /*
11477  *  call-seq:
11478  *     ARGF.close  -> ARGF
11479  *
11480  *  Closes the current file and skips to the next in the stream. Trying to
11481  *  close a file that has already been closed causes an +IOError+ to be
11482  *  raised.
11483  *
11484  * For example:
11485  *
11486  *     $ ruby argf.rb foo bar
11487  *
11488  *     ARGF.filename  #=> "foo"
11489  *     ARGF.close
11490  *     ARGF.filename  #=> "bar"
11491  *     ARGF.close
11492  *     ARGF.close     #=> closed stream (IOError)
11493  */
11494 static VALUE
11495 argf_close_m(VALUE argf)
11496 {
11497     next_argv();
11498     argf_close(argf);
11499     if (ARGF.next_p != -1) {
11500         ARGF.next_p = 1;
11501     }
11502     ARGF.lineno = 0;
11503     return argf;
11504 }
11505 
11506 /*
11507  *  call-seq:
11508  *     ARGF.closed?  -> true or false
11509  *
11510  *  Returns _true_ if the current file has been closed; _false_ otherwise. Use
11511  *  +ARGF.close+ to actually close the current file.
11512  */
11513 static VALUE
11514 argf_closed(VALUE argf)
11515 {
11516     next_argv();
11517     ARGF_FORWARD(0, 0);
11518     return rb_io_closed(ARGF.current_file);
11519 }
11520 
11521 /*
11522  *  call-seq:
11523  *     ARGF.to_s  -> String
11524  *
11525  *  Returns "ARGF".
11526  */
11527 static VALUE
11528 argf_to_s(VALUE argf)
11529 {
11530     return rb_str_new2("ARGF");
11531 }
11532 
11533 /*
11534  *  call-seq:
11535  *     ARGF.inplace_mode  -> String
11536  *
11537  *  Returns the file extension appended to the names of modified files under
11538  *  inplace-edit mode. This value can be set using +ARGF.inplace_mode=+ or
11539  *  passing the +-i+ switch to the Ruby binary.
11540  */
11541 static VALUE
11542 argf_inplace_mode_get(VALUE argf)
11543 {
11544     if (!ARGF.inplace) return Qnil;
11545     return rb_str_new2(ARGF.inplace);
11546 }
11547 
11548 static VALUE
11549 opt_i_get(ID id, VALUE *var)
11550 {
11551     return argf_inplace_mode_get(*var);
11552 }
11553 
11554 /*
11555  *  call-seq:
11556  *     ARGF.inplace_mode = ext  -> ARGF
11557  *
11558  *  Sets the filename extension for inplace editing mode to the given String.
11559  *  Each file being edited has this value appended to its filename. The
11560  *  modified file is saved under this new name.
11561  *
11562  *  For example:
11563  *
11564  *      $ ruby argf.rb file.txt
11565  *
11566  *      ARGF.inplace_mode = '.bak'
11567  *      ARGF.lines do |line|
11568  *        print line.sub("foo","bar")
11569  *      end
11570  *
11571  * Each line of _file.txt_ has the first occurrence of "foo" replaced with
11572  * "bar", then the new line is written out to _file.txt.bak_.
11573  */
11574 static VALUE
11575 argf_inplace_mode_set(VALUE argf, VALUE val)
11576 {
11577     if (rb_safe_level() >= 1 && OBJ_TAINTED(val))
11578         rb_insecure_operation();
11579 
11580     if (!RTEST(val)) {
11581         if (ARGF.inplace) free(ARGF.inplace);
11582         ARGF.inplace = 0;
11583     }
11584     else {
11585         StringValue(val);
11586         if (ARGF.inplace) free(ARGF.inplace);
11587         ARGF.inplace = 0;
11588         ARGF.inplace = strdup(RSTRING_PTR(val));
11589     }
11590     return argf;
11591 }
11592 
11593 static void
11594 opt_i_set(VALUE val, ID id, VALUE *var)
11595 {
11596     argf_inplace_mode_set(*var, val);
11597 }
11598 
11599 const char *
11600 ruby_get_inplace_mode(void)
11601 {
11602     return ARGF.inplace;
11603 }
11604 
11605 void
11606 ruby_set_inplace_mode(const char *suffix)
11607 {
11608     if (ARGF.inplace) free(ARGF.inplace);
11609     ARGF.inplace = 0;
11610     if (suffix) ARGF.inplace = strdup(suffix);
11611 }
11612 
11613 /*
11614  *  call-seq:
11615  *     ARGF.argv  -> ARGV
11616  *
11617  *  Returns the +ARGV+ array, which contains the arguments passed to your
11618  *  script, one per element.
11619  *
11620  *  For example:
11621  *
11622  *      $ ruby argf.rb -v glark.txt
11623  *
11624  *      ARGF.argv   #=> ["-v", "glark.txt"]
11625  *
11626  */
11627 static VALUE
11628 argf_argv(VALUE argf)
11629 {
11630     return ARGF.argv;
11631 }
11632 
11633 static VALUE
11634 argf_argv_getter(ID id, VALUE *var)
11635 {
11636     return argf_argv(*var);
11637 }
11638 
11639 VALUE
11640 rb_get_argv(void)
11641 {
11642     return ARGF.argv;
11643 }
11644 
11645 /*
11646  *  call-seq:
11647  *     ARGF.to_write_io  -> io
11648  *
11649  *  Returns IO instance tied to _ARGF_ for writing if inplace mode is
11650  *  enabled.
11651  */
11652 static VALUE
11653 argf_write_io(VALUE argf)
11654 {
11655     if (!RTEST(ARGF.current_file)) {
11656         rb_raise(rb_eIOError, "not opened for writing");
11657     }
11658     return GetWriteIO(ARGF.current_file);
11659 }
11660 
11661 /*
11662  *  call-seq:
11663  *     ARGF.write(string)   -> integer
11664  *
11665  *  Writes _string_ if inplace mode.
11666  */
11667 static VALUE
11668 argf_write(VALUE argf, VALUE str)
11669 {
11670     return rb_io_write(argf_write_io(argf), str);
11671 }
11672 
11673 void
11674 rb_readwrite_sys_fail(int writable, const char *mesg)
11675 {
11676     VALUE arg;
11677     int n = errno;
11678     arg = mesg ? rb_str_new2(mesg) : Qnil;
11679     if (writable == RB_IO_WAIT_WRITABLE) {
11680         switch (n) {
11681           case EAGAIN:
11682             rb_exc_raise(rb_class_new_instance(1, &arg, rb_eEAGAINWaitWritable));
11683             break;
11684 #if EAGAIN != EWOULDBLOCK
11685           case EWOULDBLOCK:
11686             rb_exc_raise(rb_class_new_instance(1, &arg, rb_eEWOULDBLOCKWaitWritable));
11687             break;
11688 #endif
11689           case EINPROGRESS:
11690             rb_exc_raise(rb_class_new_instance(1, &arg, rb_eEINPROGRESSWaitWritable));
11691             break;
11692           default:
11693             rb_mod_sys_fail_str(rb_mWaitWritable, arg);
11694         }
11695     }
11696     else if (writable == RB_IO_WAIT_READABLE) {
11697         switch (n) {
11698           case EAGAIN:
11699             rb_exc_raise(rb_class_new_instance(1, &arg, rb_eEAGAINWaitReadable));
11700             break;
11701 #if EAGAIN != EWOULDBLOCK
11702           case EWOULDBLOCK:
11703             rb_exc_raise(rb_class_new_instance(1, &arg, rb_eEWOULDBLOCKWaitReadable));
11704             break;
11705 #endif
11706           case EINPROGRESS:
11707             rb_exc_raise(rb_class_new_instance(1, &arg, rb_eEINPROGRESSWaitReadable));
11708             break;
11709           default:
11710             rb_mod_sys_fail_str(rb_mWaitReadable, arg);
11711         }
11712     }
11713     else {
11714         rb_bug("invalid read/write type passed to rb_readwrite_sys_fail: %d", writable);
11715     }
11716 }
11717 
11718 /*
11719  * Document-class: IOError
11720  *
11721  * Raised when an IO operation fails.
11722  *
11723  *    File.open("/etc/hosts") {|f| f << "example"}
11724  *      #=> IOError: not opened for writing
11725  *
11726  *    File.open("/etc/hosts") {|f| f.close; f.read }
11727  *      #=> IOError: closed stream
11728  *
11729  * Note that some IO failures raise +SystemCallError+s and these are not
11730  * subclasses of IOError:
11731  *
11732  *    File.open("does/not/exist")
11733  *      #=> Errno::ENOENT: No such file or directory - does/not/exist
11734  */
11735 
11736 /*
11737  * Document-class: EOFError
11738  *
11739  * Raised by some IO operations when reaching the end of file. Many IO
11740  * methods exist in two forms,
11741  *
11742  * one that returns +nil+ when the end of file is reached, the other
11743  * raises EOFError +EOFError+.
11744  *
11745  * +EOFError+ is a subclass of +IOError+.
11746  *
11747  *    file = File.open("/etc/hosts")
11748  *    file.read
11749  *    file.gets     #=> nil
11750  *    file.readline #=> EOFError: end of file reached
11751  */
11752 
11753 /*
11754  * Document-class:  ARGF
11755  *
11756  * +ARGF+ is a stream designed for use in scripts that process files given as
11757  * command-line arguments or passed in via STDIN.
11758  *
11759  * The arguments passed to your script are stored in the +ARGV+ Array, one
11760  * argument per element. +ARGF+ assumes that any arguments that aren't
11761  * filenames have been removed from +ARGV+. For example:
11762  *
11763  *     $ ruby argf.rb --verbose file1 file2
11764  *
11765  *     ARGV  #=> ["--verbose", "file1", "file2"]
11766  *     option = ARGV.shift #=> "--verbose"
11767  *     ARGV  #=> ["file1", "file2"]
11768  *
11769  * You can now use +ARGF+ to work with a concatenation of each of these named
11770  * files. For instance, +ARGF.read+ will return the contents of _file1_
11771  * followed by the contents of _file2_.
11772  *
11773  * After a file in +ARGV+ has been read +ARGF+ removes it from the Array.
11774  * Thus, after all files have been read +ARGV+ will be empty.
11775  *
11776  * You can manipulate +ARGV+ yourself to control what +ARGF+ operates on. If
11777  * you remove a file from +ARGV+, it is ignored by +ARGF+; if you add files to
11778  * +ARGV+, they are treated as if they were named on the command line. For
11779  * example:
11780  *
11781  *     ARGV.replace ["file1"]
11782  *     ARGF.readlines # Returns the contents of file1 as an Array
11783  *     ARGV           #=> []
11784  *     ARGV.replace ["file2", "file3"]
11785  *     ARGF.read      # Returns the contents of file2 and file3
11786  *
11787  * If +ARGV+ is empty, +ARGF+ acts as if it contained STDIN, i.e. the data
11788  * piped to your script. For example:
11789  *
11790  *     $ echo "glark" | ruby -e 'p ARGF.read'
11791  *     "glark\n"
11792  */
11793 
11794 /*
11795  *  The IO class is the basis for all input and output in Ruby.
11796  *  An I/O stream may be <em>duplexed</em> (that is, bidirectional), and
11797  *  so may use more than one native operating system stream.
11798  *
11799  *  Many of the examples in this section use the File class, the only standard
11800  *  subclass of IO. The two classes are closely associated.  Like the File
11801  *  class, the Socket library subclasses from IO (such as TCPSocket or
11802  *  UDPSocket).
11803  *
11804  *  The Kernel#open method can create an IO (or File) object for these types
11805  *  of arguments:
11806  *
11807  *  * A plain string represents a filename suitable for the underlying
11808  *    operating system.
11809  *
11810  *  * A string starting with <code>"|"</code> indicates a subprocess.
11811  *    The remainder of the string following the <code>"|"</code> is
11812  *    invoked as a process with appropriate input/output channels
11813  *    connected to it.
11814  *
11815  *  * A string equal to <code>"|-"</code> will create another Ruby
11816  *    instance as a subprocess.
11817  *
11818  *  The IO may be opened with different file modes (read-only, write-only) and
11819  *  encodings for proper conversion.  See IO.new for these options.  See
11820  *  Kernel#open for details of the various command formats described above.
11821  *
11822  *  IO.popen, the Open3 library, or  Process#spawn may also be used to
11823  *  communicate with subprocesses through an IO.
11824  *
11825  *  Ruby will convert pathnames between different operating system
11826  *  conventions if possible.  For instance, on a Windows system the
11827  *  filename <code>"/gumby/ruby/test.rb"</code> will be opened as
11828  *  <code>"\gumby\ruby\test.rb"</code>.  When specifying a Windows-style
11829  *  filename in a Ruby string, remember to escape the backslashes:
11830  *
11831  *    "c:\\gumby\\ruby\\test.rb"
11832  *
11833  *  Our examples here will use the Unix-style forward slashes;
11834  *  File::ALT_SEPARATOR can be used to get the platform-specific separator
11835  *  character.
11836  *
11837  *  The global constant ARGF (also accessible as $<) provides an
11838  *  IO-like stream which allows access to all files mentioned on the
11839  *  command line (or STDIN if no files are mentioned). ARGF#path and its alias
11840  *  ARGF#filename are provided to access the name of the file currently being
11841  *  read.
11842  *
11843  *  == io/console
11844  *
11845  *  The io/console extension provides methods for interacting with the
11846  *  console.  The console can be accessed from IO.console or the standard
11847  *  input/output/error IO objects.
11848  *
11849  *  Requiring io/console adds the following methods:
11850  *
11851  *  * IO::console
11852  *  * IO#raw
11853  *  * IO#raw!
11854  *  * IO#cooked
11855  *  * IO#cooked!
11856  *  * IO#getch
11857  *  * IO#echo=
11858  *  * IO#echo?
11859  *  * IO#noecho
11860  *  * IO#winsize
11861  *  * IO#winsize=
11862  *  * IO#iflush
11863  *  * IO#ioflush
11864  *  * IO#oflush
11865  *
11866  *  Example:
11867  *
11868  *    require 'io/console'
11869  *    rows, columns = $stdin.winsize
11870  *    puts "Your screen is #{columns} wide and #{rows} tall"
11871  */
11872 
11873 void
11874 Init_IO(void)
11875 {
11876 #undef rb_intern
11877 #define rb_intern(str) rb_intern_const(str)
11878 
11879     VALUE rb_cARGF;
11880 #ifdef __CYGWIN__
11881 #include <sys/cygwin.h>
11882     static struct __cygwin_perfile pf[] =
11883     {
11884         {"", O_RDONLY | O_BINARY},
11885         {"", O_WRONLY | O_BINARY},
11886         {"", O_RDWR | O_BINARY},
11887         {"", O_APPEND | O_BINARY},
11888         {NULL, 0}
11889     };
11890     cygwin_internal(CW_PERFILE, pf);
11891 #endif
11892 
11893     rb_eIOError = rb_define_class("IOError", rb_eStandardError);
11894     rb_eEOFError = rb_define_class("EOFError", rb_eIOError);
11895 
11896     id_write = rb_intern("write");
11897     id_read = rb_intern("read");
11898     id_getc = rb_intern("getc");
11899     id_flush = rb_intern("flush");
11900     id_readpartial = rb_intern("readpartial");
11901     id_set_encoding = rb_intern("set_encoding");
11902 
11903     rb_define_global_function("syscall", rb_f_syscall, -1);
11904 
11905     rb_define_global_function("open", rb_f_open, -1);
11906     rb_define_global_function("printf", rb_f_printf, -1);
11907     rb_define_global_function("print", rb_f_print, -1);
11908     rb_define_global_function("putc", rb_f_putc, 1);
11909     rb_define_global_function("puts", rb_f_puts, -1);
11910     rb_define_global_function("gets", rb_f_gets, -1);
11911     rb_define_global_function("readline", rb_f_readline, -1);
11912     rb_define_global_function("select", rb_f_select, -1);
11913 
11914     rb_define_global_function("readlines", rb_f_readlines, -1);
11915 
11916     rb_define_global_function("`", rb_f_backquote, 1);
11917 
11918     rb_define_global_function("p", rb_f_p, -1);
11919     rb_define_method(rb_mKernel, "display", rb_obj_display, -1);
11920 
11921     rb_cIO = rb_define_class("IO", rb_cObject);
11922     rb_include_module(rb_cIO, rb_mEnumerable);
11923 
11924     rb_mWaitReadable = rb_define_module_under(rb_cIO, "WaitReadable");
11925     rb_mWaitWritable = rb_define_module_under(rb_cIO, "WaitWritable");
11926     rb_eEAGAINWaitReadable = rb_define_class_under(rb_cIO, "EAGAINWaitReadable", rb_eEAGAIN);
11927     rb_include_module(rb_eEAGAINWaitReadable, rb_mWaitReadable);
11928     rb_eEAGAINWaitWritable = rb_define_class_under(rb_cIO, "EAGAINWaitWritable", rb_eEAGAIN);
11929     rb_include_module(rb_eEAGAINWaitWritable, rb_mWaitWritable);
11930 #if EAGAIN == EWOULDBLOCK
11931     rb_eEWOULDBLOCKWaitReadable = rb_eEAGAINWaitReadable;
11932     /* same as IO::EAGAINWaitReadable */
11933     rb_define_const(rb_cIO, "EWOULDBLOCKWaitReadable", rb_eEAGAINWaitReadable);
11934     rb_eEWOULDBLOCKWaitWritable = rb_eEAGAINWaitWritable;
11935     /* same as IO::EAGAINWaitWritable */
11936     rb_define_const(rb_cIO, "EWOULDBLOCKWaitWritable", rb_eEAGAINWaitWritable);
11937 #else
11938     rb_eEWOULDBLOCKWaitReadable = rb_define_class_under(rb_cIO, "EWOULDBLOCKWaitReadable", rb_eEWOULDBLOCK);
11939     rb_include_module(rb_eEWOULDBLOCKWaitReadable, rb_mWaitReadable);
11940     rb_eEWOULDBLOCKWaitWritable = rb_define_class_under(rb_cIO, "EWOULDBLOCKWaitWritable", rb_eEWOULDBLOCK);
11941     rb_include_module(rb_eEWOULDBLOCKWaitWritable, rb_mWaitWritable);
11942 #endif
11943     rb_eEINPROGRESSWaitReadable = rb_define_class_under(rb_cIO, "EINPROGRESSWaitReadable", rb_eEINPROGRESS);
11944     rb_include_module(rb_eEINPROGRESSWaitReadable, rb_mWaitReadable);
11945     rb_eEINPROGRESSWaitWritable = rb_define_class_under(rb_cIO, "EINPROGRESSWaitWritable", rb_eEINPROGRESS);
11946     rb_include_module(rb_eEINPROGRESSWaitWritable, rb_mWaitWritable);
11947 
11948 #if 0
11949     /* This is necessary only for forcing rdoc handle File::open */
11950     rb_define_singleton_method(rb_cFile, "open",  rb_io_s_open, -1);
11951 #endif
11952 
11953     rb_define_alloc_func(rb_cIO, io_alloc);
11954     rb_define_singleton_method(rb_cIO, "new", rb_io_s_new, -1);
11955     rb_define_singleton_method(rb_cIO, "open",  rb_io_s_open, -1);
11956     rb_define_singleton_method(rb_cIO, "sysopen",  rb_io_s_sysopen, -1);
11957     rb_define_singleton_method(rb_cIO, "for_fd", rb_io_s_for_fd, -1);
11958     rb_define_singleton_method(rb_cIO, "popen", rb_io_s_popen, -1);
11959     rb_define_singleton_method(rb_cIO, "foreach", rb_io_s_foreach, -1);
11960     rb_define_singleton_method(rb_cIO, "readlines", rb_io_s_readlines, -1);
11961     rb_define_singleton_method(rb_cIO, "read", rb_io_s_read, -1);
11962     rb_define_singleton_method(rb_cIO, "binread", rb_io_s_binread, -1);
11963     rb_define_singleton_method(rb_cIO, "write", rb_io_s_write, -1);
11964     rb_define_singleton_method(rb_cIO, "binwrite", rb_io_s_binwrite, -1);
11965     rb_define_singleton_method(rb_cIO, "select", rb_f_select, -1);
11966     rb_define_singleton_method(rb_cIO, "pipe", rb_io_s_pipe, -1);
11967     rb_define_singleton_method(rb_cIO, "try_convert", rb_io_s_try_convert, 1);
11968     rb_define_singleton_method(rb_cIO, "copy_stream", rb_io_s_copy_stream, -1);
11969 
11970     rb_define_method(rb_cIO, "initialize", rb_io_initialize, -1);
11971 
11972     rb_output_fs = Qnil;
11973     rb_define_hooked_variable("$,", &rb_output_fs, 0, rb_str_setter);
11974 
11975     rb_rs = rb_default_rs = rb_usascii_str_new2("\n");
11976     rb_gc_register_mark_object(rb_default_rs);
11977     rb_output_rs = Qnil;
11978     OBJ_FREEZE(rb_default_rs);  /* avoid modifying RS_default */
11979     rb_define_hooked_variable("$/", &rb_rs, 0, rb_str_setter);
11980     rb_define_hooked_variable("$-0", &rb_rs, 0, rb_str_setter);
11981     rb_define_hooked_variable("$\\", &rb_output_rs, 0, rb_str_setter);
11982 
11983     rb_define_virtual_variable("$_", rb_lastline_get, rb_lastline_set);
11984 
11985     rb_define_method(rb_cIO, "initialize_copy", rb_io_init_copy, 1);
11986     rb_define_method(rb_cIO, "reopen", rb_io_reopen, -1);
11987 
11988     rb_define_method(rb_cIO, "print", rb_io_print, -1);
11989     rb_define_method(rb_cIO, "putc", rb_io_putc, 1);
11990     rb_define_method(rb_cIO, "puts", rb_io_puts, -1);
11991     rb_define_method(rb_cIO, "printf", rb_io_printf, -1);
11992 
11993     rb_define_method(rb_cIO, "each",  rb_io_each_line, -1);
11994     rb_define_method(rb_cIO, "each_line",  rb_io_each_line, -1);
11995     rb_define_method(rb_cIO, "each_byte",  rb_io_each_byte, 0);
11996     rb_define_method(rb_cIO, "each_char",  rb_io_each_char, 0);
11997     rb_define_method(rb_cIO, "each_codepoint",  rb_io_each_codepoint, 0);
11998     rb_define_method(rb_cIO, "lines",  rb_io_lines, -1);
11999     rb_define_method(rb_cIO, "bytes",  rb_io_bytes, 0);
12000     rb_define_method(rb_cIO, "chars",  rb_io_chars, 0);
12001     rb_define_method(rb_cIO, "codepoints",  rb_io_codepoints, 0);
12002 
12003     rb_define_method(rb_cIO, "syswrite", rb_io_syswrite, 1);
12004     rb_define_method(rb_cIO, "sysread",  rb_io_sysread, -1);
12005 
12006     rb_define_method(rb_cIO, "fileno", rb_io_fileno, 0);
12007     rb_define_alias(rb_cIO, "to_i", "fileno");
12008     rb_define_method(rb_cIO, "to_io", rb_io_to_io, 0);
12009 
12010     rb_define_method(rb_cIO, "fsync",   rb_io_fsync, 0);
12011     rb_define_method(rb_cIO, "fdatasync",   rb_io_fdatasync, 0);
12012     rb_define_method(rb_cIO, "sync",   rb_io_sync, 0);
12013     rb_define_method(rb_cIO, "sync=",  rb_io_set_sync, 1);
12014 
12015     rb_define_method(rb_cIO, "lineno",   rb_io_lineno, 0);
12016     rb_define_method(rb_cIO, "lineno=",  rb_io_set_lineno, 1);
12017 
12018     rb_define_method(rb_cIO, "readlines",  rb_io_readlines, -1);
12019 
12020     rb_define_method(rb_cIO, "read_nonblock",  io_read_nonblock, -1);
12021     rb_define_method(rb_cIO, "write_nonblock", rb_io_write_nonblock, -1);
12022     rb_define_method(rb_cIO, "readpartial",  io_readpartial, -1);
12023     rb_define_method(rb_cIO, "read",  io_read, -1);
12024     rb_define_method(rb_cIO, "write", io_write_m, 1);
12025     rb_define_method(rb_cIO, "gets",  rb_io_gets_m, -1);
12026     rb_define_method(rb_cIO, "readline",  rb_io_readline, -1);
12027     rb_define_method(rb_cIO, "getc",  rb_io_getc, 0);
12028     rb_define_method(rb_cIO, "getbyte",  rb_io_getbyte, 0);
12029     rb_define_method(rb_cIO, "readchar",  rb_io_readchar, 0);
12030     rb_define_method(rb_cIO, "readbyte",  rb_io_readbyte, 0);
12031     rb_define_method(rb_cIO, "ungetbyte",rb_io_ungetbyte, 1);
12032     rb_define_method(rb_cIO, "ungetc",rb_io_ungetc, 1);
12033     rb_define_method(rb_cIO, "<<",    rb_io_addstr, 1);
12034     rb_define_method(rb_cIO, "flush", rb_io_flush, 0);
12035     rb_define_method(rb_cIO, "tell", rb_io_tell, 0);
12036     rb_define_method(rb_cIO, "seek", rb_io_seek_m, -1);
12037     /* Set I/O position from the beginning */
12038     rb_define_const(rb_cIO, "SEEK_SET", INT2FIX(SEEK_SET));
12039     /* Set I/O position from the current position */
12040     rb_define_const(rb_cIO, "SEEK_CUR", INT2FIX(SEEK_CUR));
12041     /* Set I/O position from the end */
12042     rb_define_const(rb_cIO, "SEEK_END", INT2FIX(SEEK_END));
12043 #ifdef SEEK_DATA
12044     /* Set I/O position to the next location containing data */
12045     rb_define_const(rb_cIO, "SEEK_DATA", INT2FIX(SEEK_DATA));
12046 #endif
12047 #ifdef SEEK_HOLE
12048     /* Set I/O position to the next hole */
12049     rb_define_const(rb_cIO, "SEEK_HOLE", INT2FIX(SEEK_HOLE));
12050 #endif
12051     rb_define_method(rb_cIO, "rewind", rb_io_rewind, 0);
12052     rb_define_method(rb_cIO, "pos", rb_io_tell, 0);
12053     rb_define_method(rb_cIO, "pos=", rb_io_set_pos, 1);
12054     rb_define_method(rb_cIO, "eof", rb_io_eof, 0);
12055     rb_define_method(rb_cIO, "eof?", rb_io_eof, 0);
12056 
12057     rb_define_method(rb_cIO, "close_on_exec?", rb_io_close_on_exec_p, 0);
12058     rb_define_method(rb_cIO, "close_on_exec=", rb_io_set_close_on_exec, 1);
12059 
12060     rb_define_method(rb_cIO, "close", rb_io_close_m, 0);
12061     rb_define_method(rb_cIO, "closed?", rb_io_closed, 0);
12062     rb_define_method(rb_cIO, "close_read", rb_io_close_read, 0);
12063     rb_define_method(rb_cIO, "close_write", rb_io_close_write, 0);
12064 
12065     rb_define_method(rb_cIO, "isatty", rb_io_isatty, 0);
12066     rb_define_method(rb_cIO, "tty?", rb_io_isatty, 0);
12067     rb_define_method(rb_cIO, "binmode",  rb_io_binmode_m, 0);
12068     rb_define_method(rb_cIO, "binmode?", rb_io_binmode_p, 0);
12069     rb_define_method(rb_cIO, "sysseek", rb_io_sysseek, -1);
12070     rb_define_method(rb_cIO, "advise", rb_io_advise, -1);
12071 
12072     rb_define_method(rb_cIO, "ioctl", rb_io_ioctl, -1);
12073     rb_define_method(rb_cIO, "fcntl", rb_io_fcntl, -1);
12074     rb_define_method(rb_cIO, "pid", rb_io_pid, 0);
12075     rb_define_method(rb_cIO, "inspect",  rb_io_inspect, 0);
12076 
12077     rb_define_method(rb_cIO, "external_encoding", rb_io_external_encoding, 0);
12078     rb_define_method(rb_cIO, "internal_encoding", rb_io_internal_encoding, 0);
12079     rb_define_method(rb_cIO, "set_encoding", rb_io_set_encoding, -1);
12080 
12081     rb_define_method(rb_cIO, "autoclose?", rb_io_autoclose_p, 0);
12082     rb_define_method(rb_cIO, "autoclose=", rb_io_set_autoclose, 1);
12083 
12084     rb_define_variable("$stdin", &rb_stdin);
12085     rb_stdin = prep_stdio(stdin, FMODE_READABLE, rb_cIO, "<STDIN>");
12086     rb_define_hooked_variable("$stdout", &rb_stdout, 0, stdout_setter);
12087     rb_stdout = prep_stdio(stdout, FMODE_WRITABLE, rb_cIO, "<STDOUT>");
12088     rb_define_hooked_variable("$stderr", &rb_stderr, 0, stdout_setter);
12089     rb_stderr = prep_stdio(stderr, FMODE_WRITABLE|FMODE_SYNC, rb_cIO, "<STDERR>");
12090     rb_define_hooked_variable("$>", &rb_stdout, 0, stdout_setter);
12091     orig_stdout = rb_stdout;
12092     rb_deferr = orig_stderr = rb_stderr;
12093 
12094     /* Holds the original stdin */
12095     rb_define_global_const("STDIN", rb_stdin);
12096     /* Holds the original stdout */
12097     rb_define_global_const("STDOUT", rb_stdout);
12098     /* Holds the original stderr */
12099     rb_define_global_const("STDERR", rb_stderr);
12100 
12101 #if 0
12102     /* Hack to get rdoc to regard ARGF as a class: */
12103     rb_cARGF = rb_define_class("ARGF", rb_cObject);
12104 #endif
12105 
12106     rb_cARGF = rb_class_new(rb_cObject);
12107     rb_set_class_path(rb_cARGF, rb_cObject, "ARGF.class");
12108     rb_define_alloc_func(rb_cARGF, argf_alloc);
12109 
12110     rb_include_module(rb_cARGF, rb_mEnumerable);
12111 
12112     rb_define_method(rb_cARGF, "initialize", argf_initialize, -2);
12113     rb_define_method(rb_cARGF, "initialize_copy", argf_initialize_copy, 1);
12114     rb_define_method(rb_cARGF, "to_s", argf_to_s, 0);
12115     rb_define_alias(rb_cARGF, "inspect", "to_s");
12116     rb_define_method(rb_cARGF, "argv", argf_argv, 0);
12117 
12118     rb_define_method(rb_cARGF, "fileno", argf_fileno, 0);
12119     rb_define_method(rb_cARGF, "to_i", argf_fileno, 0);
12120     rb_define_method(rb_cARGF, "to_io", argf_to_io, 0);
12121     rb_define_method(rb_cARGF, "to_write_io", argf_write_io, 0);
12122     rb_define_method(rb_cARGF, "each",  argf_each_line, -1);
12123     rb_define_method(rb_cARGF, "each_line",  argf_each_line, -1);
12124     rb_define_method(rb_cARGF, "each_byte",  argf_each_byte, 0);
12125     rb_define_method(rb_cARGF, "each_char",  argf_each_char, 0);
12126     rb_define_method(rb_cARGF, "each_codepoint",  argf_each_codepoint, 0);
12127     rb_define_method(rb_cARGF, "lines", argf_lines, -1);
12128     rb_define_method(rb_cARGF, "bytes", argf_bytes, 0);
12129     rb_define_method(rb_cARGF, "chars", argf_chars, 0);
12130     rb_define_method(rb_cARGF, "codepoints", argf_codepoints, 0);
12131 
12132     rb_define_method(rb_cARGF, "read",  argf_read, -1);
12133     rb_define_method(rb_cARGF, "readpartial",  argf_readpartial, -1);
12134     rb_define_method(rb_cARGF, "read_nonblock",  argf_read_nonblock, -1);
12135     rb_define_method(rb_cARGF, "readlines", argf_readlines, -1);
12136     rb_define_method(rb_cARGF, "to_a", argf_readlines, -1);
12137     rb_define_method(rb_cARGF, "gets", argf_gets, -1);
12138     rb_define_method(rb_cARGF, "readline", argf_readline, -1);
12139     rb_define_method(rb_cARGF, "getc", argf_getc, 0);
12140     rb_define_method(rb_cARGF, "getbyte", argf_getbyte, 0);
12141     rb_define_method(rb_cARGF, "readchar", argf_readchar, 0);
12142     rb_define_method(rb_cARGF, "readbyte", argf_readbyte, 0);
12143     rb_define_method(rb_cARGF, "tell", argf_tell, 0);
12144     rb_define_method(rb_cARGF, "seek", argf_seek_m, -1);
12145     rb_define_method(rb_cARGF, "rewind", argf_rewind, 0);
12146     rb_define_method(rb_cARGF, "pos", argf_tell, 0);
12147     rb_define_method(rb_cARGF, "pos=", argf_set_pos, 1);
12148     rb_define_method(rb_cARGF, "eof", argf_eof, 0);
12149     rb_define_method(rb_cARGF, "eof?", argf_eof, 0);
12150     rb_define_method(rb_cARGF, "binmode", argf_binmode_m, 0);
12151     rb_define_method(rb_cARGF, "binmode?", argf_binmode_p, 0);
12152 
12153     rb_define_method(rb_cARGF, "write", argf_write, 1);
12154     rb_define_method(rb_cARGF, "print", rb_io_print, -1);
12155     rb_define_method(rb_cARGF, "putc", rb_io_putc, 1);
12156     rb_define_method(rb_cARGF, "puts", rb_io_puts, -1);
12157     rb_define_method(rb_cARGF, "printf", rb_io_printf, -1);
12158 
12159     rb_define_method(rb_cARGF, "filename", argf_filename, 0);
12160     rb_define_method(rb_cARGF, "path", argf_filename, 0);
12161     rb_define_method(rb_cARGF, "file", argf_file, 0);
12162     rb_define_method(rb_cARGF, "skip", argf_skip, 0);
12163     rb_define_method(rb_cARGF, "close", argf_close_m, 0);
12164     rb_define_method(rb_cARGF, "closed?", argf_closed, 0);
12165 
12166     rb_define_method(rb_cARGF, "lineno",   argf_lineno, 0);
12167     rb_define_method(rb_cARGF, "lineno=",  argf_set_lineno, 1);
12168 
12169     rb_define_method(rb_cARGF, "inplace_mode", argf_inplace_mode_get, 0);
12170     rb_define_method(rb_cARGF, "inplace_mode=", argf_inplace_mode_set, 1);
12171 
12172     rb_define_method(rb_cARGF, "external_encoding", argf_external_encoding, 0);
12173     rb_define_method(rb_cARGF, "internal_encoding", argf_internal_encoding, 0);
12174     rb_define_method(rb_cARGF, "set_encoding", argf_set_encoding, -1);
12175 
12176     argf = rb_class_new_instance(0, 0, rb_cARGF);
12177 
12178     rb_define_readonly_variable("$<", &argf);
12179     /*
12180      * ARGF is a stream designed for use in scripts that process files given
12181      * as command-line arguments or passed in via STDIN.
12182      *
12183      * See ARGF (the class) for more details.
12184      */
12185     rb_define_global_const("ARGF", argf);
12186 
12187     rb_define_hooked_variable("$.", &argf, argf_lineno_getter, argf_lineno_setter);
12188     rb_define_hooked_variable("$FILENAME", &argf, argf_filename_getter, rb_gvar_readonly_setter);
12189     ARGF.filename = rb_str_new2("-");
12190 
12191     rb_define_hooked_variable("$-i", &argf, opt_i_get, opt_i_set);
12192     rb_define_hooked_variable("$*", &argf, argf_argv_getter, rb_gvar_readonly_setter);
12193 
12194 #if defined (_WIN32) || defined(__CYGWIN__)
12195     atexit(pipe_atexit);
12196 #endif
12197 
12198     Init_File();
12199 
12200     rb_define_method(rb_cFile, "initialize",  rb_file_initialize, -1);
12201 
12202     sym_mode = ID2SYM(rb_intern("mode"));
12203     sym_perm = ID2SYM(rb_intern("perm"));
12204     sym_extenc = ID2SYM(rb_intern("external_encoding"));
12205     sym_intenc = ID2SYM(rb_intern("internal_encoding"));
12206     sym_encoding = ID2SYM(rb_intern("encoding"));
12207     sym_open_args = ID2SYM(rb_intern("open_args"));
12208     sym_textmode = ID2SYM(rb_intern("textmode"));
12209     sym_binmode = ID2SYM(rb_intern("binmode"));
12210     sym_autoclose = ID2SYM(rb_intern("autoclose"));
12211     sym_normal = ID2SYM(rb_intern("normal"));
12212     sym_sequential = ID2SYM(rb_intern("sequential"));
12213     sym_random = ID2SYM(rb_intern("random"));
12214     sym_willneed = ID2SYM(rb_intern("willneed"));
12215     sym_dontneed = ID2SYM(rb_intern("dontneed"));
12216     sym_noreuse = ID2SYM(rb_intern("noreuse"));
12217     sym_SET = ID2SYM(rb_intern("SET"));
12218     sym_CUR = ID2SYM(rb_intern("CUR"));
12219     sym_END = ID2SYM(rb_intern("END"));
12220 #ifdef SEEK_DATA
12221     sym_DATA = ID2SYM(rb_intern("DATA"));
12222 #endif
12223 #ifdef SEEK_HOLE
12224     sym_HOLE = ID2SYM(rb_intern("HOLE"));
12225 #endif
12226     sym_exception = ID2SYM(rb_intern("exception"));
12227 }
12228 

Generated on 19 Jul 2016 for Ruby by  doxygen 1.4.7