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