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

Generated on Thu Sep 8 2011 03:50:42 for Ruby by  doxygen 1.7.1