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