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