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