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