io.c

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

Generated on Wed Aug 10 09:17:08 2011 for Ruby by  doxygen 1.4.7