Ruby 1.9.2p136(2010-12-25revision30365)

io.c

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