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