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