• Main Page
  • Modules
  • Data Structures
  • Files
  • File List
  • Globals

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

Generated on Wed Sep 8 2010 09:55:53 for Ruby by  doxygen 1.7.1