14#include "ruby/internal/config.h"
30# if defined(__linux__)
33# if defined(__FreeBSD_version) && __FreeBSD_version >= 1100000
43#define free(x) xfree(x)
45#if defined(DOSISH) || defined(__CYGWIN__)
50#if defined HAVE_NET_SOCKET_H
51# include <net/socket.h>
52#elif defined HAVE_SYS_SOCKET_H
53# include <sys/socket.h>
56#if defined(__BOW__) || defined(__CYGWIN__) || defined(_WIN32)
57# define NO_SAFE_RENAME
60#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__sun) || defined(_nec_ews)
69#if defined(HAVE_SYS_IOCTL_H) && !defined(_WIN32)
72#if defined(HAVE_FCNTL_H) || defined(_WIN32)
74#elif defined(HAVE_SYS_FCNTL_H)
78#if !HAVE_OFF_T && !defined(off_t)
88#if defined(HAVE_SYS_PARAM_H) || defined(__HIUX_MPP__)
89# include <sys/param.h>
102#elif defined HAVE_SYS_SYSCALL_H
103#include <sys/syscall.h>
110#ifdef HAVE_SYS_WAIT_H
111# include <sys/wait.h>
114#ifdef HAVE_COPYFILE_H
115# include <copyfile.h>
119#include "ccan/list/list.h"
124#include "internal/encoding.h"
125#include "internal/error.h"
126#include "internal/inits.h"
127#include "internal/io.h"
128#include "internal/numeric.h"
129#include "internal/object.h"
130#include "internal/process.h"
131#include "internal/thread.h"
132#include "internal/transcode.h"
133#include "internal/variable.h"
138#include "ruby_atomic.h"
148#define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR)
151#if SIZEOF_OFF_T > SIZEOF_LONG && !defined(HAVE_LONG_LONG)
152# error off_t is bigger than long, but you have no long long...
156# ifdef _POSIX_PIPE_BUF
157# define PIPE_BUF _POSIX_PIPE_BUF
164# define EWOULDBLOCK EAGAIN
167#if defined(HAVE___SYSCALL) && (defined(__APPLE__) || defined(__OpenBSD__))
169off_t __syscall(quad_t number, ...);
172#define IO_RBUF_CAPA_MIN 8192
173#define IO_CBUF_CAPA_MIN (128*1024)
174#define IO_RBUF_CAPA_FOR(fptr) (NEED_READCONV(fptr) ? IO_CBUF_CAPA_MIN : IO_RBUF_CAPA_MIN)
175#define IO_WBUF_CAPA_MIN 8192
180#define open rb_w32_uopen
182#define rename(f, t) rb_w32_urename((f), (t))
191static VALUE rb_eEAGAINWaitReadable;
192static VALUE rb_eEAGAINWaitWritable;
193static VALUE rb_eEWOULDBLOCKWaitReadable;
194static VALUE rb_eEWOULDBLOCKWaitWritable;
195static VALUE rb_eEINPROGRESSWaitWritable;
196static VALUE rb_eEINPROGRESSWaitReadable;
199static VALUE orig_stdout, orig_stderr;
208static ID id_write, id_read, id_getc, id_flush, id_readpartial, id_set_encoding, id_fileno;
209static VALUE sym_mode, sym_perm, sym_flags, sym_extenc, sym_intenc, sym_encoding, sym_open_args;
210static VALUE sym_textmode, sym_binmode, sym_autoclose;
211static VALUE sym_SET, sym_CUR, sym_END;
212static VALUE sym_wait_readable, sym_wait_writable;
214static VALUE sym_DATA;
217static VALUE sym_HOLE;
220static VALUE prep_io(
int fd,
int fmode, VALUE klass,
const char *path);
223 VALUE filename, current_file;
229 int8_t init_p, next_p, binmode;
232static rb_atomic_t max_file_descriptor = NOFILE;
237 rb_atomic_t max_fd = max_file_descriptor;
240 if (fd < 0 || afd <= max_fd)
243#if defined(HAVE_FCNTL) && defined(F_GETFL)
244 err = fcntl(fd, F_GETFL) == -1;
248 err = fstat(fd, &buf) != 0;
251 if (err && errno == EBADF) {
252 rb_bug(
"rb_update_max_fd: invalid fd (%d) given.", fd);
255 while (max_fd < afd) {
256 max_fd = ATOMIC_CAS(max_file_descriptor, max_fd, afd);
261rb_maygvl_fd_fix_cloexec(
int fd)
264#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
265 int flags, flags2, ret;
266 flags = fcntl(fd, F_GETFD);
268 rb_bug(
"rb_maygvl_fd_fix_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(errno));
271 flags2 = flags & ~FD_CLOEXEC;
273 flags2 = flags | FD_CLOEXEC;
274 if (flags != flags2) {
275 ret = fcntl(fd, F_SETFD, flags2);
277 rb_bug(
"rb_maygvl_fd_fix_cloexec: fcntl(%d, F_SETFD, %d) failed: %s", fd, flags2, strerror(errno));
286 rb_maygvl_fd_fix_cloexec(fd);
292rb_fix_detect_o_cloexec(
int fd)
294#if defined(O_CLOEXEC) && defined(F_GETFD)
295 int flags = fcntl(fd, F_GETFD);
298 rb_bug(
"rb_fix_detect_o_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(errno));
300 if (flags & FD_CLOEXEC)
303 rb_maygvl_fd_fix_cloexec(fd);
310 return (e == EWOULDBLOCK) || (e == EAGAIN);
317 static int o_cloexec_state = -1;
319 static const int retry_interval = 0;
320 static const int retry_max_count = 10000;
327#elif defined O_NOINHERIT
328 flags |= O_NOINHERIT;
331 while ((ret = open(pathname, flags, mode)) == -1) {
333 if (!io_again_p(e))
break;
334 if (retry_count++ >= retry_max_count)
break;
336 sleep(retry_interval);
339 if (ret < 0)
return ret;
340 if (ret <= 2 || o_cloexec_state == 0) {
341 rb_maygvl_fd_fix_cloexec(ret);
343 else if (o_cloexec_state > 0) {
347 o_cloexec_state = rb_fix_detect_o_cloexec(ret);
366 if (oldfd == newfd) {
370#if defined(HAVE_DUP3) && defined(O_CLOEXEC)
371 static int try_dup3 = 1;
372 if (2 < newfd && try_dup3) {
373 ret = dup3(oldfd, newfd, O_CLOEXEC);
377 if (errno == ENOSYS) {
379 ret = dup2(oldfd, newfd);
383 ret = dup2(oldfd, newfd);
386 ret = dup2(oldfd, newfd);
388 if (ret < 0)
return ret;
390 rb_maygvl_fd_fix_cloexec(ret);
395rb_fd_set_nonblock(
int fd)
398 return rb_w32_set_nonblock(fd);
399#elif defined(F_GETFL)
400 int oflags = fcntl(fd, F_GETFL);
404 if (oflags & O_NONBLOCK)
406 oflags |= O_NONBLOCK;
407 return fcntl(fd, F_SETFL, oflags);
416 int result = pipe2(descriptors, O_CLOEXEC | O_NONBLOCK);
418 int result = pipe(descriptors);
425 if (result == 0 && descriptors[1] == -1) {
426 close(descriptors[0]);
434 rb_maygvl_fd_fix_cloexec(descriptors[0]);
435 rb_maygvl_fd_fix_cloexec(descriptors[1]);
438 rb_fd_set_nonblock(descriptors[0]);
439 rb_fd_set_nonblock(descriptors[1]);
451#if defined(HAVE_FCNTL) && defined(F_DUPFD_CLOEXEC) && defined(F_DUPFD)
452 static int try_dupfd_cloexec = 1;
453 if (try_dupfd_cloexec) {
454 ret = fcntl(fd, F_DUPFD_CLOEXEC, minfd);
457 rb_maygvl_fd_fix_cloexec(ret);
461 if (errno == EINVAL) {
462 ret = fcntl(fd, F_DUPFD, minfd);
464 try_dupfd_cloexec = 0;
469 ret = fcntl(fd, F_DUPFD, minfd);
471#elif defined(HAVE_FCNTL) && defined(F_DUPFD)
472 ret = fcntl(fd, F_DUPFD, minfd);
475 if (ret >= 0 && ret < minfd) {
476 const int prev_fd = ret;
482 if (ret < 0)
return ret;
483 rb_maygvl_fd_fix_cloexec(ret);
487#define argf_of(obj) (*(struct argf *)DATA_PTR(obj))
488#define ARGF argf_of(argf)
490#define GetWriteIO(io) rb_io_get_write_io(io)
492#define READ_DATA_PENDING(fptr) ((fptr)->rbuf.len)
493#define READ_DATA_PENDING_COUNT(fptr) ((fptr)->rbuf.len)
494#define READ_DATA_PENDING_PTR(fptr) ((fptr)->rbuf.ptr+(fptr)->rbuf.off)
495#define READ_DATA_BUFFERED(fptr) READ_DATA_PENDING(fptr)
497#define READ_CHAR_PENDING(fptr) ((fptr)->cbuf.len)
498#define READ_CHAR_PENDING_COUNT(fptr) ((fptr)->cbuf.len)
499#define READ_CHAR_PENDING_PTR(fptr) ((fptr)->cbuf.ptr+(fptr)->cbuf.off)
502#define WAIT_FD_IN_WIN32(fptr) \
503 (rb_w32_io_cancelable_p((fptr)->fd) ? Qnil : rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_READABLE), Qnil))
505#define WAIT_FD_IN_WIN32(fptr)
508#define READ_CHECK(fptr) do {\
509 if (!READ_DATA_PENDING(fptr)) {\
510 WAIT_FD_IN_WIN32(fptr);\
511 rb_io_check_closed(fptr);\
517# define S_ISSOCK(m) _S_ISSOCK(m)
520# define S_ISSOCK(m) (((m) & S_IFMT) == _S_IFSOCK)
523# define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
529static int io_fflush(
rb_io_t *);
532#define FMODE_PREP (1<<16)
533#define FMODE_SIGNAL_ON_EPIPE (1<<17)
535#define fptr_signal_on_epipe(fptr) \
536 (((fptr)->mode & FMODE_SIGNAL_ON_EPIPE) != 0)
538#define fptr_set_signal_on_epipe(fptr, flag) \
540 (fptr)->mode |= FMODE_SIGNAL_ON_EPIPE : \
541 (fptr)->mode &= ~FMODE_SIGNAL_ON_EPIPE)
543extern ID ruby_static_id_signo;
545NORETURN(
static void raise_on_write(
rb_io_t *fptr,
int e, VALUE errinfo));
547raise_on_write(
rb_io_t *fptr,
int e, VALUE errinfo)
550 if (fptr_signal_on_epipe(fptr) && (e == EPIPE)) {
562#define rb_sys_fail_on_write(fptr) \
565 raise_on_write(fptr, e, rb_syserr_new_path(e, (fptr)->pathv)); \
568#define NEED_NEWLINE_DECORATOR_ON_READ(fptr) ((fptr)->mode & FMODE_TEXTMODE)
569#define NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) ((fptr)->mode & FMODE_TEXTMODE)
570#if defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32)
571# define RUBY_CRLF_ENVIRONMENT 1
573# define RUBY_CRLF_ENVIRONMENT 0
576#if RUBY_CRLF_ENVIRONMENT
578# define DEFAULT_TEXTMODE FMODE_TEXTMODE
579# define TEXTMODE_NEWLINE_DECORATOR_ON_WRITE ECONV_CRLF_NEWLINE_DECORATOR
587#define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || (fptr)->encs.ecflags & ~ECONV_CRLF_NEWLINE_DECORATOR)
588#define WRITECONV_MASK ( \
589 (ECONV_DECORATOR_MASK & ~ECONV_CRLF_NEWLINE_DECORATOR)|\
590 ECONV_STATEFUL_DECORATOR_MASK|\
592#define NEED_WRITECONV(fptr) ( \
593 ((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || \
594 ((fptr)->encs.ecflags & WRITECONV_MASK) || \
596#define SET_BINARY_MODE(fptr) setmode((fptr)->fd, O_BINARY)
598#define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) do {\
599 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {\
600 if (((fptr)->mode & FMODE_READABLE) &&\
601 !((fptr)->encs.ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {\
602 setmode((fptr)->fd, O_BINARY);\
605 setmode((fptr)->fd, O_TEXT);\
610#define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) do {\
611 if ((enc2) && ((ecflags) & ECONV_DEFAULT_NEWLINE_DECORATOR)) {\
612 (ecflags) |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;\
636 if (!rb_w32_fd_is_text(fptr->
fd)) {
637 r = lseek(fptr->
fd, -fptr->
rbuf.
len, SEEK_CUR);
638 if (r < 0 && errno) {
649 pos = lseek(fptr->
fd, 0, SEEK_CUR);
650 if (pos < 0 && errno) {
657 extra_max = (long)(pos - fptr->
rbuf.
len);
665 for (i = 0; i < fptr->
rbuf.
len; i++) {
666 if (*p ==
'\n') newlines++;
667 if (extra_max == newlines)
break;
672 while (newlines >= 0) {
673 r = lseek(fptr->
fd, pos - fptr->
rbuf.
len - newlines, SEEK_SET);
674 if (newlines == 0)
break;
679 read_size = _read(fptr->
fd, buf, fptr->
rbuf.
len + newlines);
683 rb_syserr_fail_path(e, fptr->
pathv);
685 if (read_size == fptr->
rbuf.
len) {
686 lseek(fptr->
fd, r, SEEK_SET);
707set_binary_mode_with_seek_cur(
rb_io_t *fptr)
709 if (!rb_w32_fd_is_text(fptr->
fd))
return O_BINARY;
712 return setmode(fptr->
fd, O_BINARY);
714 flush_before_seek(fptr);
715 return setmode(fptr->
fd, O_BINARY);
717#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) set_binary_mode_with_seek_cur(fptr)
721# define DEFAULT_TEXTMODE 0
722#define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || NEED_NEWLINE_DECORATOR_ON_READ(fptr))
723#define NEED_WRITECONV(fptr) ( \
724 ((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || \
725 NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) || \
726 ((fptr)->encs.ecflags & (ECONV_DECORATOR_MASK|ECONV_STATEFUL_DECORATOR_MASK)) || \
728#define SET_BINARY_MODE(fptr) (void)(fptr)
729#define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) (void)(fptr)
730#define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) ((void)(enc2), (void)(ecflags))
731#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) (void)(fptr)
734#if !defined HAVE_SHUTDOWN && !defined shutdown
735#define shutdown(a,b) 0
739#define is_socket(fd, path) rb_w32_is_socket(fd)
740#elif !defined(S_ISSOCK)
741#define is_socket(fd, path) 0
744is_socket(
int fd, VALUE path)
747 if (fstat(fd, &sbuf) < 0)
748 rb_sys_fail_path(path);
749 return S_ISSOCK(sbuf.st_mode);
753static const char closed_stream[] =
"closed stream";
756io_fd_check_closed(
int fd)
789 io_fd_check_closed(fptr->
fd);
793rb_io_get_fptr(VALUE io)
803 return rb_convert_type_with_id(io,
T_FILE,
"IO", idTo_io);
809 return rb_check_convert_type_with_id(io,
T_FILE,
"IO", idTo_io);
827 rb_io_t *fptr = rb_io_get_fptr(io);
836 return write_io ? write_io :
Qnil;
852rb_io_s_try_convert(VALUE dummy, VALUE io)
857#if !RUBY_CRLF_ENVIRONMENT
867 r = lseek(fptr->
fd, -fptr->
rbuf.
len, SEEK_CUR);
868 if (r < 0 && errno) {
882io_ungetbyte(VALUE str,
rb_io_t *fptr)
887 const int min_capa = IO_RBUF_CAPA_FOR(fptr);
890#if SIZEOF_LONG > SIZEOF_INT
915flush_before_seek(
rb_io_t *fptr)
917 if (io_fflush(fptr) < 0)
918 rb_sys_fail_on_write(fptr);
924#define io_seek(fptr, ofs, whence) (errno = 0, lseek(flush_before_seek(fptr)->fd, (ofs), (whence)))
925#define io_tell(fptr) lseek(flush_before_seek(fptr)->fd, 0, SEEK_CUR)
941 if (io_fflush(fptr) < 0)
942 rb_sys_fail_on_write(fptr);
947 if (io_fflush(wfptr) < 0)
948 rb_sys_fail_on_write(wfptr);
956 if (READ_CHAR_PENDING(fptr)) {
977io_input_encoding(
rb_io_t *fptr)
982 return io_read_encoding(fptr);
998rb_io_read_pending(
rb_io_t *fptr)
1001 if (READ_CHAR_PENDING(fptr))
1003 return READ_DATA_PENDING(fptr);
1009 if (!READ_DATA_PENDING(fptr)) {
1016rb_gc_for_fd(
int err)
1018 if (err == EMFILE || err == ENFILE || err == ENOMEM) {
1033 if (rb_gc_for_fd(e)) {
1045io_alloc(VALUE klass)
1055# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
1073struct io_internal_writev_struct {
1076 const struct iovec *iov;
1080static int nogvl_wait_for(VALUE th,
rb_io_t *fptr,
short events);
1082internal_read_func(
void *ptr)
1087 r = read(iis->fptr->
fd, iis->buf, iis->capa);
1088 if (r < 0 && !iis->nonblock) {
1090 if (io_again_p(e)) {
1091 if (nogvl_wait_for(iis->th, iis->fptr, RB_WAITFD_IN) != -1) {
1100#if defined __APPLE__
1101# define do_write_retry(code) do {ret = code;} while (ret == -1 && errno == EPROTOTYPE)
1103# define do_write_retry(code) ret = code
1106internal_write_func(
void *ptr)
1110 do_write_retry(write(iis->fd, iis->buf, iis->capa));
1115internal_write_func2(
void *ptr)
1117 return (
void*)internal_write_func(ptr);
1122internal_writev_func(
void *ptr)
1124 struct io_internal_writev_struct *iis = ptr;
1126 do_write_retry(writev(iis->fd, iis->iov, iis->iovcnt));
1132rb_read_internal(
rb_io_t *fptr,
void *buf,
size_t count)
1135 if (scheduler !=
Qnil) {
1151 return (ssize_t)rb_thread_io_blocking_region(internal_read_func, &iis, fptr->
fd);
1155rb_write_internal(
rb_io_t *fptr,
const void *buf,
size_t count)
1158 if (scheduler !=
Qnil) {
1175 return (ssize_t)rb_thread_io_blocking_region(internal_write_func, &iis, fptr->
fd);
1180rb_writev_internal(
rb_io_t *fptr,
const struct iovec *iov,
int iovcnt)
1183 if (scheduler !=
Qnil) {
1184 for (
int i = 0; i < iovcnt; i += 1) {
1193 struct io_internal_writev_struct iis = {
1199 return (ssize_t)rb_thread_io_blocking_region(internal_writev_func, &iis, fptr->
fd);
1204io_flush_buffer_sync(
void *arg)
1224io_flush_buffer_sync2(
void *arg)
1226 VALUE result = io_flush_buffer_sync(arg);
1232 return !result ? (
void*)1 : (
void*)result;
1236io_flush_buffer_async(VALUE arg)
1239 return rb_thread_io_blocking_region(io_flush_buffer_sync, fptr, fptr->
fd);
1243io_flush_buffer_async2(VALUE arg)
1255 else if (ret == 1) {
1266 return (
int)io_flush_buffer_async2((VALUE)fptr);
1271 return (
int)io_flush_buffer_async((VALUE)fptr);
1283 while (fptr->
wbuf.
len > 0 && io_flush_buffer(fptr) != 0) {
1298 if (scheduler !=
Qnil) {
1308 if (timeout !=
Qnil) {
1313 int ready = rb_thread_wait_for_single_fd(fptr->
fd,
RB_NUM2INT(events), tv);
1333 return prep_io(fd, FMODE_PREP,
rb_cIO, NULL);
1337io_wait_for_single_fd(
int fd,
int events,
struct timeval *timeout)
1341 if (scheduler !=
Qnil) {
1347 return rb_thread_wait_for_single_fd(fd, events, timeout);
1353 io_fd_check_closed(f);
1359#if defined(ERESTART)
1366#if EWOULDBLOCK != EAGAIN
1369 if (scheduler !=
Qnil) {
1387 io_fd_check_closed(f);
1393#if defined(ERESTART)
1409#if EWOULDBLOCK != EAGAIN
1412 if (scheduler !=
Qnil) {
1430 return io_wait_for_single_fd(fd, events, timeout);
1464#if defined(ERESTART)
1474#if EWOULDBLOCK != EAGAIN
1491 if (
RTEST(result)) {
1504 if (
RTEST(result)) {
1516 const char *senc, *denc;
1523 ecflags = fptr->
encs.
ecflags & ~ECONV_NEWLINE_DECORATOR_READ_MASK;
1583io_binwrite_string(VALUE arg)
1590 struct iovec iov[2];
1593 iov[0].iov_len = fptr->
wbuf.
len;
1594 iov[1].iov_base = (
char *)p->ptr;
1595 iov[1].iov_len = p->length;
1597 r = rb_writev_internal(fptr, iov, 2);
1614 r = rb_write_internal(fptr, p->ptr, p->length);
1621io_binwrite_string(VALUE arg)
1627 l = len = p->length;
1630 if (fptr->
wbuf.
len+len <= fptr->wbuf.capa) {
1639 if (io_fflush(fptr) < 0)
1645 return rb_write_internal(p->fptr, p->ptr, p->length);
1650io_binwrite(VALUE str,
const char *ptr,
long len,
rb_io_t *fptr,
int nosync)
1652 long n, r, offset = 0;
1657 if ((n = len) <= 0)
return n;
1662 fptr->
wbuf.
capa = IO_WBUF_CAPA_MIN;
1675 arg.ptr = ptr + offset;
1682 r = io_binwrite_string((VALUE)&arg);
1686 if (r == n)
return len;
1717# define MODE_BTMODE(a,b,c) ((fmode & FMODE_BINMODE) ? (b) : \
1718 (fmode & FMODE_TEXTMODE) ? (c) : (a))
1720#define MODE_BTXMODE(a, b, c, d, e, f) ((fmode & FMODE_EXCL) ? \
1721 MODE_BTMODE(d, e, f) : \
1722 MODE_BTMODE(a, b, c))
1725do_writeconv(VALUE str,
rb_io_t *fptr,
int *converted)
1727 if (NEED_WRITECONV(fptr)) {
1728 VALUE common_encoding =
Qnil;
1729 SET_BINARY_MODE(fptr);
1731 make_writeconv(fptr);
1734#define fmode (fptr->mode)
1738 rb_raise(rb_eArgError,
"ASCII incompatible string written for text mode IO without encoding conversion: %s",
1750 if (!
NIL_P(common_encoding)) {
1761#if RUBY_CRLF_ENVIRONMENT
1762#define fmode (fptr->mode)
1763 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1)) {
1766 setmode(fptr->
fd, O_BINARY);
1769 setmode(fptr->
fd, O_TEXT);
1772 rb_raise(rb_eArgError,
"ASCII incompatible string written for text mode IO without encoding conversion: %s",
1782io_fwrite(VALUE str,
rb_io_t *fptr,
int nosync)
1790 long len = rb_w32_write_console(str, fptr->
fd);
1791 if (len > 0)
return len;
1794 str = do_writeconv(str, fptr, &converted);
1798 tmp = rb_str_tmp_frozen_acquire(str);
1800 n = io_binwrite(tmp, ptr, len, fptr, nosync);
1801 rb_str_tmp_frozen_release(str, tmp);
1813 return (ssize_t)io_binwrite(0, buf, (
long)size, fptr, 0);
1817io_write(VALUE io, VALUE str,
int nosync)
1823 io = GetWriteIO(io);
1836 n = io_fwrite(str, fptr, nosync);
1837 if (n < 0L) rb_sys_fail_on_write(fptr);
1843struct binwritev_arg {
1845 const struct iovec *iov;
1850call_writev_internal(VALUE arg)
1852 struct binwritev_arg *p = (
struct binwritev_arg *)arg;
1853 return rb_writev_internal(p->fptr, p->iov, p->iovcnt);
1857io_binwritev(
struct iovec *iov,
int iovcnt,
rb_io_t *fptr)
1860 long r, total = 0, written_len = 0;
1865 if (iovcnt == 0)
return 0;
1866 for (i = 1; i < iovcnt; i++) total += iov[i].iov_len;
1871 fptr->
wbuf.
capa = IO_WBUF_CAPA_MIN;
1879 if (offset + total <= fptr->wbuf.capa) {
1880 for (i = 1; i < iovcnt; i++) {
1881 memcpy(fptr->
wbuf.
ptr+offset, iov[i].iov_base, iov[i].iov_len);
1882 offset += iov[i].iov_len;
1889 iov[0].iov_len = fptr->
wbuf.
len;
1894 if (!--iovcnt)
return 0;
1899 struct binwritev_arg arg;
1902 arg.iovcnt = iovcnt;
1906 r = rb_writev_internal(fptr, iov, iovcnt);
1912 if (written_len < fptr->wbuf.len) {
1917 written_len -= fptr->
wbuf.
len;
1922 if (written_len == total)
return total;
1924 while (r >= (ssize_t)iov->iov_len) {
1929 if (!--iovcnt)
return total;
1932 iov->iov_base = (
char *)iov->iov_base + r;
1946io_fwritev(
int argc,
const VALUE *argv,
rb_io_t *fptr)
1948 int i, converted, iovcnt = argc + 1;
1950 VALUE v1, v2, str, tmp, *tmp_array;
1954 tmp_array =
ALLOCV_N(VALUE, v2, argc);
1956 for (i = 0; i < argc; i++) {
1959 str = do_writeconv(str, fptr, &converted);
1963 tmp = rb_str_tmp_frozen_acquire(str);
1970 n = io_binwritev(iov, iovcnt, fptr);
1973 for (i = 0; i < argc; i++) {
1974 rb_str_tmp_frozen_release(argv[i], tmp_array[i]);
1983iovcnt_ok(
int iovcnt)
1986 return iovcnt < IOV_MAX;
1994io_writev(
int argc,
const VALUE *argv, VALUE io)
1998 VALUE tmp, total =
INT2FIX(0);
2001 io = GetWriteIO(io);
2012 for (i = 0; i < argc; i += cnt) {
2015 n = io_fwritev(cnt, &argv[i], fptr);
2024 if (n < 0L) rb_sys_fail_on_write(fptr);
2025 total = rb_fix_plus(
LONG2FIX(n), total);
2051io_write_m(
int argc, VALUE *argv, VALUE io)
2054 return io_writev(argc, argv, io);
2057 VALUE str = argv[0];
2058 return io_write(io, str, 0);
2069rb_io_writev(VALUE io,
int argc,
const VALUE *argv)
2076 " which accepts just one argument",
2114nogvl_fsync(
void *ptr)
2119 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->
fd)) != FILE_TYPE_DISK)
2122 return (VALUE)fsync(fptr->
fd);
2127rb_io_flush_raw(VALUE io,
int sync)
2135 io = GetWriteIO(io);
2139 if (io_fflush(fptr) < 0)
2140 rb_sys_fail_on_write(fptr);
2164 return rb_io_flush_raw(io, 1);
2192 pos = io_tell(fptr);
2193 if (pos < 0 && errno) rb_sys_fail_path(fptr->
pathv);
2199rb_io_seek(VALUE io, VALUE offset,
int whence)
2206 pos = io_seek(fptr, pos, whence);
2207 if (pos < 0 && errno) rb_sys_fail_path(fptr->
pathv);
2213interpret_seek_whence(VALUE vwhence)
2215 if (vwhence == sym_SET)
2217 if (vwhence == sym_CUR)
2219 if (vwhence == sym_END)
2222 if (vwhence == sym_DATA)
2226 if (vwhence == sym_HOLE)
2277rb_io_seek_m(
int argc, VALUE *argv, VALUE io)
2279 VALUE offset, ptrname;
2280 int whence = SEEK_SET;
2282 if (
rb_scan_args(argc, argv,
"11", &offset, &ptrname) == 2) {
2283 whence = interpret_seek_whence(ptrname);
2286 return rb_io_seek(io, offset, whence);
2306rb_io_set_pos(VALUE io, VALUE offset)
2313 pos = io_seek(fptr, pos, SEEK_SET);
2314 if (pos < 0 && errno) rb_sys_fail_path(fptr->
pathv);
2319static void clear_readconv(
rb_io_t *fptr);
2345rb_io_rewind(VALUE io)
2350 if (io_seek(fptr, 0L, 0) < 0 && errno) rb_sys_fail_path(fptr->
pathv);
2351 if (io == ARGF.current_file) {
2352 ARGF.lineno -= fptr->
lineno;
2356 clear_readconv(fptr);
2363fptr_wait_readable(
rb_io_t *fptr)
2381 fptr->
rbuf.
capa = IO_RBUF_CAPA_FOR(fptr);
2392 if (fptr_wait_readable(fptr))
2401 rb_syserr_fail_path(e, path);
2457 if (READ_CHAR_PENDING(fptr))
return Qfalse;
2458 if (READ_DATA_PENDING(fptr))
return Qfalse;
2460#if RUBY_CRLF_ENVIRONMENT
2461 if (!NEED_READCONV(fptr) && NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
2462 return RBOOL(eof(fptr->
fd));;
2465 return RBOOL(io_fillbuf(fptr) < 0);
2488 io = GetWriteIO(io);
2520rb_io_set_sync(VALUE io, VALUE sync)
2524 io = GetWriteIO(io);
2530 fptr->
mode &= ~FMODE_SYNC;
2554rb_io_fsync(VALUE io)
2558 io = GetWriteIO(io);
2561 if (io_fflush(fptr) < 0)
2562 rb_sys_fail_on_write(fptr);
2563 if ((
int)rb_thread_io_blocking_region(nogvl_fsync, fptr, fptr->
fd) < 0)
2564 rb_sys_fail_path(fptr->
pathv);
2568# define rb_io_fsync rb_f_notimplement
2569# define rb_io_sync rb_f_notimplement
2571rb_io_set_sync(VALUE io, VALUE sync)
2578#ifdef HAVE_FDATASYNC
2580nogvl_fdatasync(
void *ptr)
2585 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->
fd)) != FILE_TYPE_DISK)
2588 return (VALUE)fdatasync(fptr->
fd);
2603rb_io_fdatasync(VALUE io)
2607 io = GetWriteIO(io);
2610 if (io_fflush(fptr) < 0)
2611 rb_sys_fail_on_write(fptr);
2613 if ((
int)rb_thread_io_blocking_region(nogvl_fdatasync, fptr, fptr->
fd) == 0)
2617 return rb_io_fsync(io);
2620#define rb_io_fdatasync rb_io_fsync
2639rb_io_fileno(VALUE io)
2708rb_io_inspect(VALUE obj)
2712 static const char closed[] =
" (closed)";
2714 fptr =
RFILE(obj)->fptr;
2715 if (!fptr)
return rb_any_to_s(obj);
2721 rb_str_cat(result, closed+1, strlen(closed)-1);
2745rb_io_to_io(VALUE io)
2752read_buffered_data(
char *ptr,
long len,
rb_io_t *fptr)
2756 n = READ_DATA_PENDING_COUNT(fptr);
2757 if (n <= 0)
return 0;
2758 if (n > len) n = (int)len;
2766io_bufread(
char *ptr,
long len,
rb_io_t *fptr)
2772 if (READ_DATA_PENDING(fptr) == 0) {
2776 c = rb_read_internal(fptr, ptr+offset, n);
2779 if (fptr_wait_readable(fptr))
2784 if ((n -= c) <= 0)
break;
2790 c = read_buffered_data(ptr+offset, n, fptr);
2793 if ((n -= c) <= 0)
break;
2796 if (io_fillbuf(fptr) < 0) {
2803static int io_setstrbuf(VALUE *str,
long len);
2812bufread_call(VALUE arg)
2815 p->len = io_bufread(p->str_ptr, p->len, p->fptr);
2820io_fread(VALUE str,
long offset,
long size,
rb_io_t *fptr)
2825 io_setstrbuf(&str, offset + size);
2829 rb_str_locktmp_ensure(str, bufread_call, (VALUE)&arg);
2831 if (len < 0) rb_sys_fail_path(fptr->
pathv);
2839 off_t siz = READ_DATA_PENDING_COUNT(fptr);
2842 if (fstat(fptr->
fd, &st) == 0 && S_ISREG(st.st_mode)
2843#
if defined(__HAIKU__)
2848 if (io_fflush(fptr) < 0)
2849 rb_sys_fail_on_write(fptr);
2850 pos = lseek(fptr->
fd, 0, SEEK_CUR);
2851 if (st.st_size >= pos && pos >= 0) {
2852 siz += st.st_size - pos;
2853 if (siz > LONG_MAX) {
2865io_enc_str(VALUE str,
rb_io_t *fptr)
2872make_readconv(
rb_io_t *fptr,
int size)
2877 const char *sname, *dname;
2878 ecflags = fptr->
encs.
ecflags & ~ECONV_NEWLINE_DECORATOR_WRITE_MASK;
2892 if (size < IO_CBUF_CAPA_MIN) size = IO_CBUF_CAPA_MIN;
2898#define MORE_CHAR_SUSPENDED Qtrue
2899#define MORE_CHAR_FINISHED Qnil
2901fill_cbuf(
rb_io_t *fptr,
int ec_flags)
2903 const unsigned char *ss, *sp, *se;
2904 unsigned char *ds, *dp, *de;
2905 rb_econv_result_t res;
2913 return MORE_CHAR_SUSPENDED;
2924 ss = sp = (
const unsigned char *)fptr->
rbuf.
ptr + fptr->
rbuf.
off;
2929 fptr->
rbuf.
off += (int)(sp - ss);
2930 fptr->
rbuf.
len -= (int)(sp - ss);
2931 fptr->
cbuf.
len += (int)(dp - ds);
2936 fptr->
rbuf.
off -= putbackable;
2937 fptr->
rbuf.
len += putbackable;
2944 if (cbuf_len0 != fptr->
cbuf.
len)
2945 return MORE_CHAR_SUSPENDED;
2948 return MORE_CHAR_FINISHED;
2954 if (io_fillbuf(fptr) < 0) {
2956 return MORE_CHAR_FINISHED;
2961 fptr->
cbuf.
len += (int)(dp - ds);
2968 if (cbuf_len0 != fptr->
cbuf.
len)
2969 return MORE_CHAR_SUSPENDED;
2971 return MORE_CHAR_FINISHED;
2979 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED)
2985io_shift_cbuf(
rb_io_t *fptr,
int len, VALUE *strp)
3011io_setstrbuf(VALUE *str,
long len)
3014 len = (len + 1) & ~1L;
3033#define MAX_REALLOC_GAP 4096
3035io_shrink_read_string(VALUE str,
long n)
3043io_set_read_length(VALUE str,
long n,
int shrinkable)
3048 if (shrinkable) io_shrink_read_string(str, n);
3053read_all(
rb_io_t *fptr,
long siz, VALUE str)
3062 if (NEED_READCONV(fptr)) {
3063 int first = !
NIL_P(str);
3064 SET_BINARY_MODE(fptr);
3065 shrinkable = io_setstrbuf(&str,0);
3066 make_readconv(fptr, 0);
3071 io_shift_cbuf(fptr, fptr->
cbuf.
len, &str);
3073 v = fill_cbuf(fptr, 0);
3074 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED) {
3077 io_shift_cbuf(fptr, fptr->
cbuf.
len, &str);
3081 if (v == MORE_CHAR_FINISHED) {
3082 clear_readconv(fptr);
3084 if (shrinkable) io_shrink_read_string(str,
RSTRING_LEN(str));
3085 return io_enc_str(str, fptr);
3090 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3094 enc = io_read_encoding(fptr);
3097 if (siz == 0) siz = BUFSIZ;
3098 shrinkable = io_setstrbuf(&str, siz);
3101 n = io_fread(str, bytes, siz - bytes, fptr);
3102 if (n == 0 && bytes == 0) {
3110 if (bytes < siz)
break;
3114 if (shrinkable) io_shrink_read_string(str,
RSTRING_LEN(str));
3115 str = io_enc_str(str, fptr);
3123 if (rb_fd_set_nonblock(fptr->
fd) != 0) {
3124 rb_sys_fail_path(fptr->
pathv);
3129read_internal_call(VALUE arg)
3134 if (scheduler !=
Qnil) {
3143 return rb_thread_io_blocking_region(internal_read_func, iis, iis->fptr->
fd);
3149 return (
long)rb_str_locktmp_ensure(str, read_internal_call, (VALUE)iis);
3152#define no_exception_p(opts) !rb_opts_exception_p((opts), TRUE)
3155io_getpartial(
int argc, VALUE *argv, VALUE io,
int no_exception,
int nonblock)
3165 if ((len =
NUM2LONG(length)) < 0) {
3166 rb_raise(rb_eArgError,
"negative length %ld given", len);
3169 shrinkable = io_setstrbuf(&str, len);
3175 io_set_read_length(str, 0, shrinkable);
3181 n = read_buffered_data(
RSTRING_PTR(str), len, fptr);
3187 io_setstrbuf(&str, len);
3190 iis.nonblock = nonblock;
3193 n = read_internal_locktmp(str, &iis);
3196 if (!nonblock && fptr_wait_readable(fptr))
3198 if (nonblock && (io_again_p(e))) {
3200 return sym_wait_readable;
3203 e,
"read would block");
3205 rb_syserr_fail_path(e, fptr->
pathv);
3208 io_set_read_length(str, n, shrinkable);
3308io_readpartial(
int argc, VALUE *argv, VALUE io)
3312 ret = io_getpartial(argc, argv, io,
Qnil, 0);
3319io_nonblock_eof(
int no_exception)
3321 if (!no_exception) {
3336 if ((len =
NUM2LONG(length)) < 0) {
3337 rb_raise(rb_eArgError,
"negative length %ld given", len);
3340 shrinkable = io_setstrbuf(&str, len);
3341 rb_bool_expected(ex,
"exception");
3347 io_set_read_length(str, 0, shrinkable);
3351 n = read_buffered_data(
RSTRING_PTR(str), len, fptr);
3354 shrinkable |= io_setstrbuf(&str, len);
3359 n = read_internal_locktmp(str, &iis);
3362 if (io_again_p(e)) {
3363 if (!ex)
return sym_wait_readable;
3365 e,
"read would block");
3367 rb_syserr_fail_path(e, fptr->
pathv);
3370 io_set_read_length(str, n, shrinkable);
3373 if (!ex)
return Qnil;
3389 rb_bool_expected(ex,
"exception");
3391 io = GetWriteIO(io);
3395 if (io_fflush(fptr) < 0)
3396 rb_sys_fail_on_write(fptr);
3404 if (io_again_p(e)) {
3406 return sym_wait_writable;
3412 rb_syserr_fail_path(e, fptr->
pathv);
3488io_read(
int argc, VALUE *argv, VALUE io)
3494#if RUBY_CRLF_ENVIRONMENT
3500 if (
NIL_P(length)) {
3503 return read_all(fptr, remain_size(fptr), str);
3507 rb_raise(rb_eArgError,
"negative length %ld given", len);
3510 shrinkable = io_setstrbuf(&str,len);
3515 io_set_read_length(str, 0, shrinkable);
3520#if RUBY_CRLF_ENVIRONMENT
3521 previous_mode = set_binary_mode_with_seek_cur(fptr);
3523 n = io_fread(str, 0, len, fptr);
3524 io_set_read_length(str, n, shrinkable);
3525#if RUBY_CRLF_ENVIRONMENT
3526 if (previous_mode == O_TEXT) {
3527 setmode(fptr->
fd, O_TEXT);
3530 if (n == 0)
return Qnil;
3536rscheck(
const char *rsptr,
long rslen, VALUE rs)
3540 rb_raise(rb_eRuntimeError,
"rs modified");
3544appendline(
rb_io_t *fptr,
int delim, VALUE *strp,
long *lp)
3549 if (NEED_READCONV(fptr)) {
3550 SET_BINARY_MODE(fptr);
3551 make_readconv(fptr, 0);
3554 int searchlen = READ_CHAR_PENDING_COUNT(fptr);
3556 p = READ_CHAR_PENDING_PTR(fptr);
3557 if (0 < limit && limit < searchlen)
3558 searchlen = (int)limit;
3559 e = memchr(p, delim, searchlen);
3561 int len = (int)(e-p+1);
3586 }
while (more_char(fptr) != MORE_CHAR_FINISHED);
3587 clear_readconv(fptr);
3592 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3594 long pending = READ_DATA_PENDING_COUNT(fptr);
3596 const char *p = READ_DATA_PENDING_PTR(fptr);
3600 if (limit > 0 && pending > limit) pending = limit;
3601 e = memchr(p, delim, pending);
3602 if (e) pending = e - p + 1;
3612 read_buffered_data(
RSTRING_PTR(str) + last, pending, fptr);
3615 if (e)
return delim;
3620 }
while (io_fillbuf(fptr) >= 0);
3626swallow(
rb_io_t *fptr,
int term)
3628 if (NEED_READCONV(fptr)) {
3631 SET_BINARY_MODE(fptr);
3632 make_readconv(fptr, 0);
3635 while ((cnt = READ_CHAR_PENDING_COUNT(fptr)) > 0) {
3636 const char *p = READ_CHAR_PENDING_PTR(fptr);
3639 if (*p != term)
return TRUE;
3641 while (--i && *++p == term);
3644 const char *e = p + cnt;
3646 while ((p += i) < e &&
rb_enc_ascget(p, e, &i, enc) == term);
3649 io_shift_cbuf(fptr, (
int)cnt - i, NULL);
3651 }
while (more_char(fptr) != MORE_CHAR_FINISHED);
3655 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3658 while ((cnt = READ_DATA_PENDING_COUNT(fptr)) > 0) {
3660 const char *p = READ_DATA_PENDING_PTR(fptr);
3662 if (cnt >
sizeof buf) cnt =
sizeof buf;
3663 if (*p != term)
return TRUE;
3665 while (--i && *++p == term);
3666 if (!read_buffered_data(buf, cnt - i, fptr))
3667 rb_sys_fail_path(fptr->
pathv);
3670 }
while (io_fillbuf(fptr) == 0);
3683 int pending = READ_DATA_PENDING_COUNT(fptr);
3686 const char *p = READ_DATA_PENDING_PTR(fptr);
3690 e = memchr(p,
'\n', pending);
3692 pending = (int)(e - p + 1);
3694 chomplen = (pending > 1 && *(e-1) ==
'\r') + 1;
3704 read_buffered_data(
RSTRING_PTR(str)+len, pending - chomplen, fptr);
3707 if (pending == 1 && chomplen == 1 && len > 0) {
3714 len += pending - chomplen;
3720 }
while (io_fillbuf(fptr) >= 0);
3723 str = io_enc_str(str, fptr);
3734 unsigned int chomp: 1;
3738extract_getline_opts(VALUE opts,
struct getline_arg *args)
3750 args->chomp = chomp;
3754extract_getline_args(
int argc, VALUE *argv,
struct getline_arg *args)
3768 else if (2 <= argc) {
3769 rs = argv[0], lim = argv[1];
3778check_getline_args(VALUE *rsp,
long *limit, VALUE io)
3788 enc_io = io_read_encoding(fptr);
3789 if (enc_io != enc_rs &&
3798 rb_raise(rb_eArgError,
"encoding mismatch: %s IO with %s RS",
3807prepare_getline_args(
int argc, VALUE *argv,
struct getline_arg *args, VALUE io)
3810 argc =
rb_scan_args(argc, argv,
"02:", NULL, NULL, &opts);
3811 extract_getline_args(argc, argv, args);
3812 extract_getline_opts(opts, args);
3813 check_getline_args(&args->rs, &args->limit, io);
3817rb_io_getline_0(VALUE rs,
long limit,
int chomp,
rb_io_t *fptr)
3824 if (
NIL_P(rs) && limit < 0) {
3825 str = read_all(fptr, 0,
Qnil);
3829 else if (limit == 0) {
3832 else if (rs ==
rb_default_rs && limit < 0 && !NEED_READCONV(fptr) &&
3834 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3835 return rb_io_getline_fast(fptr, enc, chomp);
3838 int c, newline = -1;
3839 const char *rsptr = 0;
3842 int extra_limit = 16;
3843 int chomp_cr = chomp;
3845 SET_BINARY_MODE(fptr);
3846 enc = io_read_encoding(fptr);
3854 swallow(fptr,
'\n');
3867 newline = (
unsigned char)rsptr[rslen - 1];
3868 chomp_cr = chomp && rslen == 1 && newline ==
'\n';
3872 while ((c = appendline(fptr, newline, &str, &limit)) != EOF) {
3873 const char *s, *p, *pp, *e;
3881 if (pp != p)
continue;
3882 if (!rspara) rscheck(rsptr, rslen, rs);
3883 if (memcmp(p, rsptr, rslen) == 0) {
3885 if (chomp_cr && p > s && *(p-1) ==
'\r') --p;
3909 if (rspara && c != EOF)
3910 swallow(fptr,
'\n');
3912 str = io_enc_str(str, fptr);
3915 if (!
NIL_P(str) && !nolimit) {
3923rb_io_getline_1(VALUE rs,
long limit,
int chomp, VALUE io)
3926 int old_lineno, new_lineno;
3930 old_lineno = fptr->
lineno;
3931 str = rb_io_getline_0(rs, limit, chomp, fptr);
3932 if (!
NIL_P(str) && (new_lineno = fptr->
lineno) != old_lineno) {
3933 if (io == ARGF.current_file) {
3934 ARGF.lineno += new_lineno - old_lineno;
3935 ARGF.last_lineno = ARGF.lineno;
3938 ARGF.last_lineno = new_lineno;
3946rb_io_getline(
int argc, VALUE *argv, VALUE io)
3950 prepare_getline_args(argc, argv, &args, io);
3951 return rb_io_getline_1(args.rs, args.limit, args.chomp, io);
3961rb_io_gets_internal(VALUE io)
4043rb_io_gets_m(
int argc, VALUE *argv, VALUE io)
4047 str = rb_io_getline(argc, argv, io);
4076rb_io_lineno(VALUE io)
4103rb_io_set_lineno(VALUE io, VALUE lineno)
4123rb_io_readline(
int argc, VALUE *argv, VALUE io)
4125 VALUE line = rb_io_gets_m(argc, argv, io);
4133static VALUE io_readlines(
const struct getline_arg *arg, VALUE io);
4160rb_io_readlines(
int argc, VALUE *argv, VALUE io)
4164 prepare_getline_args(argc, argv, &args, io);
4165 return io_readlines(&args, io);
4169io_readlines(
const struct getline_arg *arg, VALUE io)
4173 if (arg->limit == 0)
4174 rb_raise(rb_eArgError,
"invalid limit: 0 for readlines");
4176 while (!
NIL_P(line = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, io))) {
4214rb_io_each_line(
int argc, VALUE *argv, VALUE io)
4220 prepare_getline_args(argc, argv, &args, io);
4221 if (args.limit == 0)
4222 rb_raise(rb_eArgError,
"invalid limit: 0 for each_line");
4223 while (!
NIL_P(str = rb_io_getline_1(args.rs, args.limit, args.chomp, io))) {
4247rb_io_each_byte(VALUE io)
4263 }
while (io_fillbuf(fptr) >= 0);
4273 if (NEED_READCONV(fptr)) {
4277 SET_BINARY_MODE(fptr);
4278 make_readconv(fptr, 0);
4292 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4294 clear_readconv(fptr);
4301 if (fptr->
cbuf.
len == 0) clear_readconv(fptr);
4310 io_shift_cbuf(fptr, r, &str);
4321 str = io_enc_str(str, fptr);
4326 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4327 if (io_fillbuf(fptr) < 0) {
4349 if (io_fillbuf(fptr) != -1) {
4369 str = io_enc_str(str, fptr);
4390rb_io_each_char(VALUE io)
4400 enc = io_input_encoding(fptr);
4402 while (!
NIL_P(c = io_getc(fptr, enc))) {
4422rb_io_each_codepoint(VALUE io)
4434 if (NEED_READCONV(fptr)) {
4435 SET_BINARY_MODE(fptr);
4438 make_readconv(fptr, 0);
4446 r = ONIGENC_CONSTRUCT_MBCLEN_CHARFOUND(1);
4453 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4454 clear_readconv(fptr);
4481 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4482 enc = io_input_encoding(fptr);
4483 while (io_fillbuf(fptr) >= 0) {
4498 char cbuf[8], *p = cbuf;
4500 if (more > numberof(cbuf))
goto invalid;
4502 if (more > numberof(cbuf))
goto invalid;
4503 while ((n = (
int)read_buffered_data(p, more, fptr)) > 0 &&
4504 (p += n, (more -= n) > 0)) {
4505 if (io_fillbuf(fptr) < 0)
goto invalid;
4506 if ((n = fptr->
rbuf.
len) > more) n = more;
4546 enc = io_input_encoding(fptr);
4548 return io_getc(fptr, enc);
4564rb_io_readchar(VALUE io)
4566 VALUE c = rb_io_getc(io);
4603 if (io_fillbuf(fptr) < 0) {
4621rb_io_readbyte(VALUE io)
4679 VALUE v = rb_int_modulo(b,
INT2FIX(256));
4680 unsigned char c =
NUM2INT(v) & 0xFF;
4686 io_ungetbyte(b, fptr);
4733 else if (RB_BIGNUM_TYPE_P(c)) {
4739 if (NEED_READCONV(fptr)) {
4740 SET_BINARY_MODE(fptr);
4742#if SIZEOF_LONG > SIZEOF_INT
4746 make_readconv(fptr, (
int)len);
4760 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4761 io_ungetbyte(c, fptr);
4779rb_io_isatty(VALUE io)
4784 return RBOOL(isatty(fptr->
fd) != 0);
4787#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
4803rb_io_close_on_exec_p(VALUE io)
4809 write_io = GetWriteIO(io);
4810 if (io != write_io) {
4812 if (fptr && 0 <= (fd = fptr->
fd)) {
4813 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->
pathv);
4814 if (!(ret & FD_CLOEXEC))
return Qfalse;
4819 if (fptr && 0 <= (fd = fptr->
fd)) {
4820 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->
pathv);
4821 if (!(ret & FD_CLOEXEC))
return Qfalse;
4826#define rb_io_close_on_exec_p rb_f_notimplement
4829#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
4851rb_io_set_close_on_exec(VALUE io, VALUE arg)
4853 int flag =
RTEST(arg) ? FD_CLOEXEC : 0;
4858 write_io = GetWriteIO(io);
4859 if (io != write_io) {
4861 if (fptr && 0 <= (fd = fptr->
fd)) {
4862 if ((ret = fcntl(fptr->
fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->
pathv);
4863 if ((ret & FD_CLOEXEC) != flag) {
4864 ret = (ret & ~FD_CLOEXEC) | flag;
4865 ret = fcntl(fd, F_SETFD, ret);
4866 if (ret != 0) rb_sys_fail_path(fptr->
pathv);
4873 if (fptr && 0 <= (fd = fptr->
fd)) {
4874 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->
pathv);
4875 if ((ret & FD_CLOEXEC) != flag) {
4876 ret = (ret & ~FD_CLOEXEC) | flag;
4877 ret = fcntl(fd, F_SETFD, ret);
4878 if (ret != 0) rb_sys_fail_path(fptr->
pathv);
4884#define rb_io_set_close_on_exec rb_f_notimplement
4887#define IS_PREP_STDIO(f) ((f)->mode & FMODE_PREP)
4888#define PREP_STDIO_NAME(f) (RSTRING_PTR((f)->pathv))
4891finish_writeconv(
rb_io_t *fptr,
int noalloc)
4893 unsigned char *ds, *dp, *de;
4894 rb_econv_result_t res;
4897 unsigned char buf[1024];
4903 de = buf +
sizeof(buf);
4907 r = rb_write_internal(fptr, ds, dp-ds);
4933 if (io_fflush(fptr) < 0)
4940 fptr->
wbuf.
len += (int)(dp - ds);
4956finish_writeconv_sync(VALUE arg)
4959 return finish_writeconv(p->fptr, p->noalloc);
4963nogvl_close(
void *ptr)
4967 return (
void*)(intptr_t)close(*fd);
4971maygvl_close(
int fd,
int keepgvl)
4984nogvl_fclose(
void *ptr)
4988 return (
void*)(intptr_t)fclose(file);
4992maygvl_fclose(
FILE *file,
int keepgvl)
4995 return fclose(file);
5001static void clear_codeconv(
rb_io_t *fptr);
5004fptr_finalize_flush(
rb_io_t *fptr,
int noraise,
int keepgvl,
5010 int mode = fptr->
mode;
5016 arg.noalloc = noraise;
5020 err = finish_writeconv(fptr, noraise);
5025 io_flush_buffer_sync(fptr);
5028 if (io_fflush(fptr) < 0 &&
NIL_P(err))
5035 if (IS_PREP_STDIO(fptr) || fd <= 2) {
5059 if (!done && stdio_file) {
5061 if ((maygvl_fclose(stdio_file, noraise) < 0) &&
NIL_P(err))
5062 if (!noraise) err =
INT2NUM(errno);
5067 if (!done && fd >= 0) {
5073 if ((maygvl_close(fd, keepgvl) < 0) &&
NIL_P(err))
5074 if (!noraise) err =
INT2NUM(errno);
5079 if (!
NIL_P(err) && !noraise) {
5088fptr_finalize(
rb_io_t *fptr,
int noraise)
5090 fptr_finalize_flush(fptr, noraise, FALSE, 0);
5091 free_io_buffer(&fptr->
rbuf);
5092 free_io_buffer(&fptr->
wbuf);
5093 clear_codeconv(fptr);
5097rb_io_fptr_cleanup(
rb_io_t *fptr,
int noraise)
5103 fptr_finalize(fptr, noraise);
5111 ruby_sized_xfree(buf->ptr, (
size_t)buf->capa);
5123 free_io_buffer(&fptr->
cbuf);
5139 clear_readconv(fptr);
5140 clear_writeconv(fptr);
5144rb_io_fptr_finalize_internal(
void *ptr)
5151 rb_io_fptr_cleanup(fptr, TRUE);
5153 free_io_buffer(&fptr->
rbuf);
5154 free_io_buffer(&fptr->
wbuf);
5155 clear_codeconv(fptr);
5159#undef rb_io_fptr_finalize
5167 rb_io_fptr_finalize_internal(fptr);
5171#define rb_io_fptr_finalize(fptr) rb_io_fptr_finalize_internal(fptr)
5173RUBY_FUNC_EXPORTED
size_t
5174rb_io_memsize(
const rb_io_t *fptr)
5176 size_t size =
sizeof(
rb_io_t);
5187# define KEEPGVL TRUE
5189# define KEEPGVL FALSE
5192int rb_notify_fd_close(
int fd,
struct list_head *);
5194io_close_fptr(VALUE io)
5201 list_head_init(&busy);
5202 write_io = GetWriteIO(io);
5203 if (io != write_io) {
5204 write_fptr =
RFILE(write_io)->fptr;
5205 if (write_fptr && 0 <= write_fptr->
fd) {
5206 rb_io_fptr_cleanup(write_fptr, TRUE);
5210 fptr =
RFILE(io)->fptr;
5211 if (!fptr)
return 0;
5212 if (fptr->
fd < 0)
return 0;
5214 if (rb_notify_fd_close(fptr->
fd, &busy)) {
5216 fptr_finalize_flush(fptr, FALSE, KEEPGVL, &busy);
5218 rb_io_fptr_cleanup(fptr, FALSE);
5223fptr_waitpid(
rb_io_t *fptr,
int nohang)
5227 rb_last_status_clear();
5236 rb_io_t *fptr = io_close_fptr(io);
5237 if (fptr) fptr_waitpid(fptr, 0);
5257rb_io_close_m(VALUE io)
5259 rb_io_t *fptr = rb_io_get_fptr(io);
5268io_call_close(VALUE io)
5275ignore_closed_stream(VALUE io, VALUE exc)
5277 enum {mesg_len =
sizeof(closed_stream)-1};
5281 memcmp(
RSTRING_PTR(mesg), closed_stream, mesg_len)) {
5292 rb_rescue2(io_call_close, io, ignore_closed_stream, io,
5317rb_io_closed(VALUE io)
5323 write_io = GetWriteIO(io);
5324 if (io != write_io) {
5325 write_fptr =
RFILE(write_io)->fptr;
5326 if (write_fptr && 0 <= write_fptr->
fd) {
5331 fptr = rb_io_get_fptr(io);
5332 return RBOOL(0 > fptr->
fd);
5356rb_io_close_read(VALUE io)
5362 if (fptr->
fd < 0)
return Qnil;
5363 if (is_socket(fptr->
fd, fptr->
pathv)) {
5367 if (shutdown(fptr->
fd, SHUT_RD) < 0)
5368 rb_sys_fail_path(fptr->
pathv);
5369 fptr->
mode &= ~FMODE_READABLE;
5375 write_io = GetWriteIO(io);
5376 if (io != write_io) {
5381 RFILE(io)->fptr = wfptr;
5384 RFILE(write_io)->fptr = fptr;
5385 rb_io_fptr_cleanup(fptr, FALSE);
5418rb_io_close_write(VALUE io)
5423 write_io = GetWriteIO(io);
5425 if (fptr->
fd < 0)
return Qnil;
5426 if (is_socket(fptr->
fd, fptr->
pathv)) {
5430 if (shutdown(fptr->
fd, SHUT_WR) < 0)
5431 rb_sys_fail_path(fptr->
pathv);
5432 fptr->
mode &= ~FMODE_WRITABLE;
5442 if (io != write_io) {
5464rb_io_sysseek(
int argc, VALUE *argv, VALUE io)
5466 VALUE offset, ptrname;
5467 int whence = SEEK_SET;
5471 if (
rb_scan_args(argc, argv,
"11", &offset, &ptrname) == 2) {
5472 whence = interpret_seek_whence(ptrname);
5477 (READ_DATA_BUFFERED(fptr) || READ_CHAR_PENDING(fptr))) {
5481 rb_warn(
"sysseek for buffered IO");
5484 pos = lseek(fptr->
fd, pos, whence);
5485 if (pos < 0 && errno) rb_sys_fail_path(fptr->
pathv);
5504rb_io_syswrite(VALUE io, VALUE str)
5514 io = GetWriteIO(io);
5519 rb_warn(
"syswrite for buffered IO");
5522 tmp = rb_str_tmp_frozen_acquire(str);
5524 n = rb_write_internal(fptr, ptr, len);
5525 if (n < 0) rb_sys_fail_path(fptr->
pathv);
5526 rb_str_tmp_frozen_release(str, tmp);
5551rb_io_sysread(
int argc, VALUE *argv, VALUE io)
5562 shrinkable = io_setstrbuf(&str, ilen);
5563 if (ilen == 0)
return str;
5568 if (READ_DATA_BUFFERED(fptr)) {
5574 io_setstrbuf(&str, ilen);
5580 n = read_internal_locktmp(str, &iis);
5583 rb_sys_fail_path(fptr->
pathv);
5586 io_set_read_length(str, n, shrinkable);
5588 if (n == 0 && ilen > 0) {
5595#if defined(HAVE_PREAD) || defined(HAVE_PWRITE)
5596struct prdwr_internal_arg {
5604#if defined(HAVE_PREAD)
5606internal_pread_func(
void *arg)
5608 struct prdwr_internal_arg *p = arg;
5609 return (VALUE)pread(p->fd, p->buf, p->count, p->offset);
5613pread_internal_call(VALUE arg)
5615 struct prdwr_internal_arg *p = (
struct prdwr_internal_arg *)arg;
5616 return rb_thread_io_blocking_region(internal_pread_func, p, p->fd);
5642rb_io_pread(
int argc, VALUE *argv, VALUE io)
5644 VALUE len, offset, str;
5647 struct prdwr_internal_arg arg;
5654 shrinkable = io_setstrbuf(&str, (
long)arg.count);
5655 if (arg.count == 0)
return str;
5668 rb_sys_fail_path(fptr->
pathv);
5670 io_set_read_length(str, n, shrinkable);
5671 if (n == 0 && arg.count > 0) {
5678# define rb_io_pread rb_f_notimplement
5681#if defined(HAVE_PWRITE)
5683internal_pwrite_func(
void *ptr)
5685 struct prdwr_internal_arg *arg = ptr;
5687 return (VALUE)pwrite(arg->fd, arg->buf, arg->count, arg->offset);
5710rb_io_pwrite(VALUE io, VALUE str, VALUE offset)
5714 struct prdwr_internal_arg arg;
5722 io = GetWriteIO(io);
5727 tmp = rb_str_tmp_frozen_acquire(str);
5731 n = (ssize_t)rb_thread_io_blocking_region(internal_pwrite_func, &arg, fptr->
fd);
5732 if (n < 0) rb_sys_fail_path(fptr->
pathv);
5733 rb_str_tmp_frozen_release(str, tmp);
5738# define rb_io_pwrite rb_f_notimplement
5752 fptr->
mode &= ~FMODE_TEXTMODE;
5756 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
5759 setmode(fptr->
fd, O_BINARY);
5766io_ascii8bit_binmode(
rb_io_t *fptr)
5777 fptr->
mode &= ~FMODE_TEXTMODE;
5778 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
5784 clear_codeconv(fptr);
5793 io_ascii8bit_binmode(fptr);
5811rb_io_binmode_m(VALUE io)
5817 write_io = GetWriteIO(io);
5830rb_io_binmode_p(VALUE io)
5838rb_io_fmode_modestr(
int fmode)
5842 return MODE_BTMODE(
"a+",
"ab+",
"at+");
5844 return MODE_BTMODE(
"a",
"ab",
"at");
5848 rb_raise(rb_eArgError,
"invalid access fmode 0x%x", fmode);
5850 return MODE_BTMODE(
"r",
"rb",
"rt");
5852 return MODE_BTXMODE(
"w",
"wb",
"wt",
"wx",
"wbx",
"wtx");
5855 return MODE_BTXMODE(
"w+",
"wb+",
"wt+",
"w+x",
"wb+x",
"wt+x");
5857 return MODE_BTMODE(
"r+",
"rb+",
"rt+");
5861static const char bom_prefix[] =
"bom|";
5862static const char utf_prefix[] =
"utf-";
5863enum {bom_prefix_len = (int)
sizeof(bom_prefix) - 1};
5864enum {utf_prefix_len = (int)
sizeof(utf_prefix) - 1};
5867io_encname_bom_p(
const char *name,
long len)
5869 return len > bom_prefix_len &&
STRNCASECMP(name, bom_prefix, bom_prefix_len) == 0;
5876 const char *m = modestr, *p = NULL;
5904 if (modestr[0] !=
'w')
5912 if (io_encname_bom_p(m, p ? (
long)(p - m) : (
long)strlen(m)))
5925 rb_raise(rb_eArgError,
"invalid access mode %s", modestr);
5930rb_io_oflags_fmode(
int oflags)
5934 switch (oflags & O_ACCMODE) {
5946 if (oflags & O_APPEND) {
5949 if (oflags & O_TRUNC) {
5952 if (oflags & O_CREAT) {
5955 if (oflags & O_EXCL) {
5959 if (oflags & O_BINARY) {
5968rb_io_fmode_oflags(
int fmode)
6012rb_io_oflags_modestr(
int oflags)
6015# define MODE_BINARY(a,b) ((oflags & O_BINARY) ? (b) : (a))
6017# define MODE_BINARY(a,b) (a)
6020 if (oflags & O_EXCL) {
6021 rb_raise(rb_eArgError,
"exclusive access mode is not supported");
6023 accmode = oflags & (O_RDONLY|O_WRONLY|O_RDWR);
6024 if (oflags & O_APPEND) {
6025 if (accmode == O_WRONLY) {
6026 return MODE_BINARY(
"a",
"ab");
6028 if (accmode == O_RDWR) {
6029 return MODE_BINARY(
"a+",
"ab+");
6034 rb_raise(rb_eArgError,
"invalid access oflags 0x%x", oflags);
6036 return MODE_BINARY(
"r",
"rb");
6038 return MODE_BINARY(
"w",
"wb");
6040 if (oflags & O_TRUNC) {
6041 return MODE_BINARY(
"w+",
"wb+");
6043 return MODE_BINARY(
"r+",
"rb+");
6055 int default_ext = 0;
6065 else if (intern == NULL) {
6071 *enc = (default_ext && intern != ext) ? NULL : ext;
6081unsupported_encoding(
const char *name,
rb_encoding *enc)
6083 rb_enc_warn(enc,
"Unsupported encoding %s ignored", name);
6087parse_mode_enc(
const char *estr,
rb_encoding *estr_enc,
6093 int fmode = fmode_p ? *fmode_p : 0;
6099 p = strrchr(estr,
':');
6100 len = p ? (p++ - estr) : (
long)strlen(estr);
6102 estr += bom_prefix_len;
6103 len -= bom_prefix_len;
6104 if (!
STRNCASECMP(estr, utf_prefix, utf_prefix_len)) {
6108 rb_enc_warn(estr_enc,
"BOM with non-UTF encoding %s is nonsense", estr);
6109 fmode &= ~FMODE_SETENC_BY_BOM;
6117 memcpy(encname, estr, len);
6118 encname[len] =
'\0';
6123 if (fmode_p) *fmode_p = fmode;
6129 unsupported_encoding(estr, estr_enc);
6135 if (*p ==
'-' && *(p+1) ==
'\0') {
6142 unsupported_encoding(p, estr_enc);
6151 rb_io_ext_int_to_encs(ext_enc, int_enc, enc_p, enc2_p, fmode);
6165 if (v !=
Qnil) encoding = v;
6167 if (v !=
Qnil) extenc = v;
6169 if (v !=
Qundef) intenc = v;
6175 rb_warn(
"Ignoring encoding parameter '%"PRIsVALUE
"': %s_encoding is used",
6176 encoding, extenc ==
Qundef ?
"internal" :
"external");
6184 if (
NIL_P(intenc)) {
6191 if (*p ==
'-' && *(p+1) ==
'\0') {
6202 if (extencoding == intencoding) {
6206 if (!
NIL_P(encoding)) {
6210 enc_p, enc2_p, fmode_p);
6213 rb_io_ext_int_to_encs(
rb_to_encoding(encoding), NULL, enc_p, enc2_p, 0);
6218 rb_io_ext_int_to_encs(extencoding, intencoding, enc_p, enc2_p, 0);
6228 int fmode = *fmode_p;
6234 rb_raise(rb_eArgError,
"ASCII incompatible encoding needs binmode");
6237 rb_raise(rb_eArgError,
"newline decorator with binary mode");
6244#if !DEFAULT_TEXTMODE
6246 fmode &= ~FMODE_TEXTMODE;
6253extract_binmode(VALUE opthash,
int *fmode)
6255 if (!
NIL_P(opthash)) {
6260 rb_raise(rb_eArgError,
"textmode specified twice");
6262 rb_raise(rb_eArgError,
"both textmode and binmode specified");
6269 rb_raise(rb_eArgError,
"binmode specified twice");
6271 rb_raise(rb_eArgError,
"both textmode and binmode specified");
6277 rb_raise(rb_eArgError,
"both textmode and binmode specified");
6283 int *oflags_p,
int *fmode_p, convconfig_t *convconfig_p)
6290 int has_enc = 0, has_vmode = 0;
6296 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
6306 fmode = rb_io_oflags_fmode(oflags);
6314 oflags = rb_io_fmode_oflags(fmode);
6318 parse_mode_enc(p+1,
rb_enc_get(vmode), &enc, &enc2, &fmode);
6324 rb_io_ext_int_to_encs(e, NULL, &enc, &enc2, fmode);
6328 if (
NIL_P(opthash)) {
6332#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
6334 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
6335 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
6337 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
6347 else if (
NIL_P(vmode)) {
6348 fmode |= DEFAULT_TEXTMODE;
6357 if (!
NIL_P(vmode)) {
6358 rb_raise(rb_eArgError,
"mode specified twice");
6370 fmode = rb_io_oflags_fmode(oflags);
6372 extract_binmode(opthash, &fmode);
6381 else if (
NIL_P(vmode)) {
6382 fmode |= DEFAULT_TEXTMODE;
6388 if (!
NIL_P(*vperm_p)) {
6389 rb_raise(rb_eArgError,
"perm specified twice");
6400#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
6402 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
6403 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
6408 rb_raise(rb_eArgError,
"encoding specified twice");
6411 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
6415 validate_enc_binmode(&fmode, ecflags, enc, enc2);
6421 convconfig_p->enc = enc;
6422 convconfig_p->enc2 = enc2;
6423 convconfig_p->ecflags = ecflags;
6424 convconfig_p->ecopts = ecopts;
6434sysopen_func(
void *ptr)
6452rb_sysopen(VALUE fname,
int oflags, mode_t perm)
6459 data.oflags = oflags;
6462 fd = rb_sysopen_internal(&data);
6465 if (rb_gc_for_fd(e)) {
6466 fd = rb_sysopen_internal(&data);
6469 rb_syserr_fail_path(e, fname);
6483 file = fdopen(fd, modestr);
6490 file = fdopen(fd, modestr);
6494 if (rb_gc_for_fd(e)) {
6495 file = fdopen(fd, modestr);
6499 if (e == 0) e = EINVAL;
6501 if (e == 0) e = EMFILE;
6509 if (setvbuf(file, NULL, _IOFBF, 0) != 0)
6510 rb_warn(
"setvbuf() can't be honoured (fd=%d)", fd);
6518 int t = isatty(fptr->
fd);
6524static VALUE rb_io_internal_encoding(VALUE);
6525static void io_encoding_set(
rb_io_t *, VALUE, VALUE, VALUE);
6528io_strip_bom(VALUE io)
6530 VALUE b1, b2, b3, b4;
6551 return ENCINDEX_UTF_16BE;
6562 return ENCINDEX_UTF_32LE;
6567 return ENCINDEX_UTF_16LE;
6577 return ENCINDEX_UTF_32BE;
6591io_set_encoding_by_bom(VALUE io)
6593 int idx = io_strip_bom(io);
6601 rb_io_internal_encoding(io),
Qnil);
6610rb_file_open_generic(VALUE io, VALUE filename,
int oflags,
int fmode,
6611 const convconfig_t *convconfig, mode_t perm)
6618 rb_io_ext_int_to_encs(NULL, NULL, &cc.enc, &cc.enc2, fmode);
6623 validate_enc_binmode(&fmode, convconfig->ecflags,
6624 convconfig->enc, convconfig->enc2);
6628 fptr->
encs = *convconfig;
6631 if (!(oflags & O_TMPFILE)) {
6632 fptr->
pathv = pathv;
6635 fptr->
pathv = pathv;
6637 fptr->
fd = rb_sysopen(pathv, oflags, perm);
6645rb_file_open_internal(VALUE io, VALUE filename,
const char *modestr)
6648 const char *p = strchr(modestr,
':');
6649 convconfig_t convconfig;
6653 &convconfig.enc, &convconfig.enc2, &fmode);
6654 convconfig.ecflags = 0;
6655 convconfig.ecopts =
Qnil;
6662 rb_io_ext_int_to_encs(e, NULL, &convconfig.enc, &convconfig.enc2, fmode);
6663 convconfig.ecflags = 0;
6664 convconfig.ecopts =
Qnil;
6667 return rb_file_open_generic(io, filename,
6668 rb_io_fmode_oflags(fmode),
6678 return rb_file_open_internal(io_alloc(
rb_cFile), fname, modestr);
6687#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
6710 while ((tmp = *prev) != 0) {
6711 if (tmp->fptr == fptr) {
6720#if defined (_WIN32) || defined(__CYGWIN__)
6736pipe_finalize(
rb_io_t *fptr,
int noraise)
6738#if !defined(HAVE_WORKING_FORK) && !defined(_WIN32)
6747 fptr_finalize(fptr, noraise);
6749 pipe_del_fptr(fptr);
6756#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
6759 if (old_finalize == orig->
finalize)
return;
6764#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
6765 if (old_finalize != pipe_finalize) {
6767 for (list =
pipe_list; list; list = list->next) {
6768 if (list->fptr == fptr)
break;
6770 if (!list) pipe_add_fptr(fptr);
6773 pipe_del_fptr(fptr);
6786rb_io_unbuffered(
rb_io_t *fptr)
6797 if (rb_gc_for_fd(errno)) {
6809#define HAVE_SPAWNV 1
6810#define spawnv(mode, cmd, args) rb_w32_uaspawn((mode), (cmd), (args))
6811#define spawn(mode, cmd) rb_w32_uspawn((mode), (cmd), 0)
6814#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
6824#ifdef HAVE_WORKING_FORK
6825# ifndef __EMSCRIPTEN__
6827popen_redirect(
struct popen_arg *p)
6830 close(p->write_pair[1]);
6831 if (p->write_pair[0] != 0) {
6832 dup2(p->write_pair[0], 0);
6833 close(p->write_pair[0]);
6836 if (p->pair[1] != 1) {
6837 dup2(p->pair[1], 1);
6843 if (p->pair[1] != 1) {
6844 dup2(p->pair[1], 1);
6850 if (p->pair[0] != 0) {
6851 dup2(p->pair[0], 0);
6858#if defined(__linux__)
6869linux_get_maxfd(
void)
6872 char buf[4096], *p, *np, *e;
6875 if (fd < 0)
return fd;
6876 ss = read(fd, buf,
sizeof(buf));
6877 if (ss < 0)
goto err;
6880 while ((
int)
sizeof(
"FDSize:\t0\n")-1 <= e-p &&
6881 (np = memchr(p,
'\n', e-p)) != NULL) {
6882 if (memcmp(p,
"FDSize:",
sizeof(
"FDSize:")-1) == 0) {
6884 p +=
sizeof(
"FDSize:")-1;
6904#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
6906 int max = (int)max_file_descriptor;
6909 ret = fcntl(0, F_MAXFD);
6911 maxhint = max = ret;
6912# elif defined(__linux__)
6913 ret = linux_get_maxfd();
6920 for (fd = lowfd; fd <= max; fd++) {
6921 if (!
NIL_P(noclose_fds) &&
6924 ret = fcntl(fd, F_GETFD);
6925 if (ret != -1 && !(ret & FD_CLOEXEC)) {
6926 fcntl(fd, F_SETFD, ret|FD_CLOEXEC);
6928# define CONTIGUOUS_CLOSED_FDS 20
6930 if (max < fd + CONTIGUOUS_CLOSED_FDS)
6931 max = fd + CONTIGUOUS_CLOSED_FDS;
6937# ifndef __EMSCRIPTEN__
6939popen_exec(
void *pp,
char *errmsg,
size_t errmsg_len)
6941 struct popen_arg *p = (
struct popen_arg*)pp;
6943 return rb_exec_async_signal_safe(p->eargp, errmsg, errmsg_len);
6948#if (defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)) && !defined __EMSCRIPTEN__
6950rb_execarg_fixup_v(VALUE execarg_obj)
6952 rb_execarg_parent_start(execarg_obj);
6956char *rb_execarg_commandline(
const struct rb_execarg *eargp, VALUE *prog);
6959#ifndef __EMSCRIPTEN__
6961pipe_open(VALUE execarg_obj,
const char *modestr,
int fmode,
6962 const convconfig_t *convconfig)
6964 struct rb_execarg *eargp =
NIL_P(execarg_obj) ? NULL : rb_execarg_get(execarg_obj);
6965 VALUE prog = eargp ? (eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name) :
Qfalse ;
6971#if defined(HAVE_WORKING_FORK)
6973 char errmsg[80] = {
'\0' };
6975#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
6977 struct popen_arg arg;
6980#if defined(HAVE_SPAWNV)
6981# if defined(HAVE_SPAWNVE)
6982# define DO_SPAWN(cmd, args, envp) ((args) ? \
6983 spawnve(P_NOWAIT, (cmd), (args), (envp)) : \
6984 spawne(P_NOWAIT, (cmd), (envp)))
6986# define DO_SPAWN(cmd, args, envp) ((args) ? \
6987 spawnv(P_NOWAIT, (cmd), (args)) : \
6988 spawn(P_NOWAIT, (cmd)))
6990# if !defined(HAVE_WORKING_FORK)
6992# if defined(HAVE_SPAWNVE)
6997#if !defined(HAVE_WORKING_FORK)
7003#if !defined(HAVE_WORKING_FORK)
7004 const char *cmd = 0;
7010#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7011 arg.execarg_obj = execarg_obj;
7014 arg.pair[0] = arg.pair[1] = -1;
7015 arg.write_pair[0] = arg.write_pair[1] = -1;
7016# if !defined(HAVE_WORKING_FORK)
7017 if (eargp && !eargp->use_shell) {
7018 args = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
7023 if (
rb_pipe(arg.write_pair) < 0)
7027 close(arg.write_pair[0]);
7028 close(arg.write_pair[1]);
7032 rb_execarg_addopt(execarg_obj,
INT2FIX(0),
INT2FIX(arg.write_pair[0]));
7033 rb_execarg_addopt(execarg_obj,
INT2FIX(1),
INT2FIX(arg.pair[1]));
7040 rb_execarg_addopt(execarg_obj,
INT2FIX(1),
INT2FIX(arg.pair[1]));
7046 rb_execarg_addopt(execarg_obj,
INT2FIX(0),
INT2FIX(arg.pair[0]));
7051 if (!
NIL_P(execarg_obj)) {
7052 rb_protect(rb_execarg_fixup_v, execarg_obj, &state);
7054 if (0 <= arg.write_pair[0]) close(arg.write_pair[0]);
7055 if (0 <= arg.write_pair[1]) close(arg.write_pair[1]);
7056 if (0 <= arg.pair[0]) close(arg.pair[0]);
7057 if (0 <= arg.pair[1]) close(arg.pair[1]);
7058 rb_execarg_parent_end(execarg_obj);
7062# if defined(HAVE_WORKING_FORK)
7063 pid = rb_fork_async_signal_safe(&status, popen_exec, &arg, arg.eargp->redirect_fds, errmsg,
sizeof(errmsg));
7065 rb_execarg_run_options(eargp, sargp, NULL, 0);
7066# if defined(HAVE_SPAWNVE)
7067 if (eargp->envp_str) envp = (
char **)
RSTRING_PTR(eargp->envp_str);
7069 while ((pid = DO_SPAWN(cmd, args, envp)) < 0) {
7071 switch (e = errno) {
7073# if EWOULDBLOCK != EAGAIN
7082 rb_execarg_run_options(sargp, NULL, NULL, 0);
7084 rb_execarg_parent_end(execarg_obj);
7087# if defined(HAVE_WORKING_FORK)
7088 pid = rb_call_proc__fork();
7090 popen_redirect(&arg);
7102# if defined(HAVE_WORKING_FORK)
7108 close(arg.write_pair[0]);
7109 close(arg.write_pair[1]);
7111# if defined(HAVE_WORKING_FORK)
7120 close(arg.write_pair[0]);
7121 write_fd = arg.write_pair[1];
7132 cmd = rb_execarg_commandline(eargp, &prog);
7133 if (!
NIL_P(execarg_obj)) {
7134 rb_execarg_parent_start(execarg_obj);
7135 rb_execarg_run_options(eargp, sargp, NULL, 0);
7137 fp = popen(cmd, modestr);
7140 rb_execarg_parent_end(execarg_obj);
7141 rb_execarg_run_options(sargp, NULL, NULL, 0);
7143 if (!fp) rb_syserr_fail_path(e, prog);
7153 fptr->
encs = *convconfig;
7154#if RUBY_CRLF_ENVIRONMENT
7161 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
7164#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7165 if (NEED_NEWLINE_DECORATOR_ON_WRITE(fptr)) {
7166 fptr->
encs.
ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
7172 if (0 <= write_fd) {
7173 write_port = io_alloc(
rb_cIO);
7175 write_fptr->
fd = write_fd;
7177 fptr->
mode &= ~FMODE_WRITABLE;
7182#if defined (__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7184 pipe_add_fptr(fptr);
7190pipe_open(VALUE execarg_obj,
const char *modestr,
int fmode,
7191 const convconfig_t *convconfig)
7193 rb_raise(rb_eNotImpError,
"popen() is not available");
7198is_popen_fork(VALUE prog)
7201#if !defined(HAVE_WORKING_FORK)
7203 "fork() function is unimplemented on this machine");
7212pipe_open_s(VALUE prog,
const char *modestr,
int fmode,
7213 const convconfig_t *convconfig)
7216 VALUE *argv = &prog;
7217 VALUE execarg_obj =
Qnil;
7219 if (!is_popen_fork(prog))
7220 execarg_obj = rb_execarg_new(argc, argv, TRUE, FALSE);
7221 return pipe_open(execarg_obj, modestr, fmode, convconfig);
7227 rb_io_t *fptr = io_close_fptr(io);
7234static VALUE popen_finish(VALUE port, VALUE klass);
7323rb_io_s_popen(
int argc, VALUE *argv, VALUE klass)
7337 int ex = !
NIL_P(opt);
7338 rb_error_arity(argc + ex, 1 + ex, 2 + ex);
7341 return popen_finish(rb_io_popen(pname, pmode, env, opt), klass);
7345rb_io_popen(VALUE pname, VALUE pmode, VALUE env, VALUE opt)
7347 const char *modestr;
7348 VALUE tmp, execarg_obj =
Qnil;
7350 convconfig_t convconfig;
7355#if SIZEOF_LONG > SIZEOF_INT
7356 if (len > INT_MAX) {
7357 rb_raise(rb_eArgError,
"too many arguments");
7360 execarg_obj = rb_execarg_new((
int)len,
RARRAY_CONST_PTR(tmp), FALSE, FALSE);
7366 if (!is_popen_fork(pname))
7367 execarg_obj = rb_execarg_new(1, &pname, TRUE, FALSE);
7369 if (!
NIL_P(execarg_obj)) {
7371 opt = rb_execarg_extract_options(execarg_obj, opt);
7373 rb_execarg_setenv(execarg_obj, env);
7376 modestr = rb_io_oflags_modestr(oflags);
7378 return pipe_open(execarg_obj, modestr, fmode, &convconfig);
7382popen_finish(VALUE port, VALUE klass)
7394 RBASIC_SET_CLASS(port, klass);
7402rb_scan_open_args(
int argc,
const VALUE *argv,
7403 VALUE *fname_p,
int *oflags_p,
int *fmode_p,
7404 convconfig_t *convconfig_p, mode_t *perm_p)
7406 VALUE opt, fname, vmode, vperm;
7410 argc =
rb_scan_args(argc, argv,
"12:", &fname, &vmode, &vperm, &opt);
7424rb_open_file(
int argc,
const VALUE *argv, VALUE io)
7428 convconfig_t convconfig;
7431 rb_scan_open_args(argc, argv, &fname, &oflags, &fmode, &convconfig, &perm);
7432 rb_file_open_generic(io, fname, oflags, fmode, &convconfig, perm);
7475rb_io_s_open(
int argc, VALUE *argv, VALUE klass)
7497rb_io_s_sysopen(
int argc, VALUE *argv, VALUE
_)
7499 VALUE fname, vmode, vperm;
7504 rb_scan_args(argc, argv,
"12", &fname, &vmode, &vperm);
7515 if (
NIL_P(vperm)) perm = 0666;
7519 fd = rb_sysopen(fname, oflags, perm);
7524check_pipe_command(VALUE filename_or_command)
7638rb_f_open(
int argc, VALUE *argv, VALUE
_)
7641 int redirect = FALSE;
7649 VALUE tmp = argv[0];
7655 VALUE cmd = check_pipe_command(tmp);
7658 return rb_io_s_popen(argc, argv,
rb_cIO);
7671 return rb_io_s_open(argc, argv,
rb_cFile);
7674static VALUE rb_io_open_generic(VALUE, VALUE,
int,
int,
const convconfig_t *, mode_t);
7677rb_io_open(VALUE io, VALUE filename, VALUE vmode, VALUE vperm, VALUE opt)
7680 convconfig_t convconfig;
7685 return rb_io_open_generic(io, filename, oflags, fmode, &convconfig, perm);
7689rb_io_open_generic(VALUE klass, VALUE filename,
int oflags,
int fmode,
7690 const convconfig_t *convconfig, mode_t perm)
7693 if (klass ==
rb_cIO && !
NIL_P(cmd = check_pipe_command(filename))) {
7694 return pipe_open_s(cmd, rb_io_oflags_modestr(oflags), fmode, convconfig);
7697 return rb_file_open_generic(io_alloc(klass), filename,
7698 oflags, fmode, convconfig, perm);
7703io_reopen(VALUE io, VALUE nfile)
7713 if (fptr == orig)
return io;
7714 if (IS_PREP_STDIO(fptr)) {
7719 "%s can't change access mode from \"%s\" to \"%s\"",
7720 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->
mode),
7721 rb_io_fmode_modestr(orig->
mode));
7725 if (io_fflush(fptr) < 0)
7726 rb_sys_fail_on_write(fptr);
7729 flush_before_seek(fptr);
7732 pos = io_tell(orig);
7735 if (io_fflush(orig) < 0)
7736 rb_sys_fail_on_write(fptr);
7744 else if (!IS_PREP_STDIO(fptr)) fptr->
pathv =
Qnil;
7745 fptr_copy_finalizer(fptr, orig);
7750 if (IS_PREP_STDIO(fptr) || fd <= 2 || !fptr->
stdio_file) {
7753 rb_sys_fail_path(orig->
pathv);
7761 rb_sys_fail_path(orig->
pathv);
7767 if (io_seek(fptr, pos, SEEK_SET) < 0 && errno) {
7768 rb_sys_fail_path(fptr->
pathv);
7770 if (io_seek(orig, pos, SEEK_SET) < 0 && errno) {
7771 rb_sys_fail_path(orig->
pathv);
7780 RBASIC_SET_CLASS(io, rb_obj_class(nfile));
7785int rb_freopen(VALUE fname,
const char *mode,
FILE *fp);
7788rb_freopen(VALUE fname,
const char *mode,
FILE *fp)
7816rb_io_reopen(
int argc, VALUE *argv, VALUE file)
7818 VALUE fname, nmode, opt;
7822 if (
rb_scan_args(argc, argv,
"11:", &fname, &nmode, &opt) == 1) {
7825 return io_reopen(file, tmp);
7831 fptr =
RFILE(file)->fptr;
7838 convconfig_t convconfig;
7841 if (IS_PREP_STDIO(fptr) &&
7845 "%s can't change access mode from \"%s\" to \"%s\"",
7846 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->
mode),
7847 rb_io_fmode_modestr(fmode));
7850 fptr->
encs = convconfig;
7853 oflags = rb_io_fmode_oflags(fptr->
mode);
7856 fptr->
pathv = fname;
7858 fptr->
fd = rb_sysopen(fptr->
pathv, oflags, 0666);
7864 if (io_fflush(fptr) < 0)
7865 rb_sys_fail_on_write(fptr);
7871 rb_io_oflags_modestr(oflags),
7873 if (e) rb_syserr_fail_path(e, fptr->
pathv);
7877 if (setvbuf(fptr->
stdio_file, NULL, _IOFBF, 0) != 0)
7878 rb_warn(
"setvbuf() can't be honoured for %"PRIsVALUE, fptr->
pathv);
7881 if (setvbuf(fptr->
stdio_file, NULL, _IONBF, BUFSIZ) != 0)
7882 rb_warn(
"setvbuf() can't be honoured for %"PRIsVALUE, fptr->
pathv);
7884 else if (fptr->
stdio_file == stdout && isatty(fptr->
fd)) {
7885 if (setvbuf(fptr->
stdio_file, NULL, _IOLBF, BUFSIZ) != 0)
7886 rb_warn(
"setvbuf() can't be honoured for %"PRIsVALUE, fptr->
pathv);
7890 int tmpfd = rb_sysopen(fptr->
pathv, oflags, 0666);
7896 rb_syserr_fail_path(err, fptr->
pathv);
7905rb_io_init_copy(VALUE dest, VALUE io)
7920 fptr->
mode = orig->
mode & ~FMODE_PREP;
7925 fptr_copy_finalizer(fptr, orig);
7927 fd = ruby_dup(orig->
fd);
7929 pos = io_tell(orig);
7931 io_seek(fptr, pos, SEEK_SET);
7936 write_io = GetWriteIO(io);
7937 if (io != write_io) {
7938 write_io = rb_obj_dup(write_io);
7973rb_f_printf(
int argc, VALUE *argv, VALUE
_)
7977 if (argc == 0)
return Qnil;
7992deprecated_str_setter(VALUE val, ID
id, VALUE *var)
7996 rb_warn_deprecated(
"`%s'", NULL,
rb_id2name(
id));
8040 for (i=0; i<argc; i++) {
8077rb_f_print(
int argc,
const VALUE *argv, VALUE
_)
8101rb_io_putc(VALUE io, VALUE ch)
8115#define forward(obj, id, argc, argv) \
8116 rb_funcallv_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8117#define forward_public(obj, id, argc, argv) \
8118 rb_funcallv_public_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8119#define forward_current(id, argc, argv) \
8120 forward_public(ARGF.current_file, id, argc, argv)
8135rb_f_putc(VALUE recv, VALUE ch)
8138 if (recv == r_stdout) {
8139 return rb_io_putc(recv, ch);
8141 return forward(r_stdout,
rb_intern(
"putc"), 1, &ch);
8146rb_str_end_with_asciichar(VALUE str,
int c)
8153 if (len == 0)
return 0;
8155 return ptr[len - 1] == c;
8157 return rb_enc_ascget(ptr + ((len - 1) / n) * n, ptr + len, &n, enc) == c;
8161io_puts_ary(VALUE ary, VALUE out,
int recur)
8211 VALUE line, args[2];
8218 for (i=0; i<argc; i++) {
8231 !rb_str_end_with_asciichar(line,
'\n')) {
8234 rb_io_writev(out, n, args);
8250rb_f_puts(
int argc, VALUE *argv, VALUE recv)
8253 if (recv == r_stdout) {
8256 return forward(r_stdout,
rb_intern(
"puts"), argc, argv);
8260rb_p_write(VALUE str)
8268 io_writev(2, args, r_stdout);
8271 rb_io_writev(r_stdout, 2, args);
8283rb_p_result(
int argc,
const VALUE *argv)
8290 else if (argc > 1) {
8319rb_f_p(
int argc, VALUE *argv, VALUE
self)
8322 for (i=0; i<argc; i++) {
8324 rb_uninterruptible(rb_p_write, inspected);
8326 return rb_p_result(argc, argv);
8354rb_obj_display(
int argc, VALUE *argv, VALUE
self)
8365rb_stderr_to_original_p(VALUE err)
8367 return (err == orig_stderr ||
RFILE(orig_stderr)->fptr->
fd < 0);
8374 if (rb_stderr_to_original_p(out)) {
8376 if (isatty(fileno(stderr))) {
8377 if (rb_w32_write_console(
rb_str_new(mesg, len), fileno(stderr)) > 0)
return;
8380 if (fwrite(mesg,
sizeof(
char), (
size_t)len, stderr) < (
size_t)len) {
8397rb_write_error_str(VALUE mesg)
8401 if (rb_stderr_to_original_p(out)) {
8404 if (isatty(fileno(stderr))) {
8405 if (rb_w32_write_console(mesg, fileno(stderr)) > 0)
return;
8408 if (fwrite(
RSTRING_PTR(mesg),
sizeof(
char), len, stderr) < len) {
8420rb_stderr_tty_p(
void)
8423 return isatty(fileno(stderr));
8428must_respond_to(ID mid, VALUE val, ID
id)
8431 rb_raise(rb_eTypeError,
"%"PRIsVALUE
" must have %"PRIsVALUE
" method, %"PRIsVALUE
" given",
8438stdin_setter(VALUE val, ID
id, VALUE *ptr)
8444stdin_getter(ID
id, VALUE *ptr)
8450stdout_setter(VALUE val, ID
id, VALUE *ptr)
8452 must_respond_to(id_write, val,
id);
8457stdout_getter(ID
id, VALUE *ptr)
8463stderr_setter(VALUE val, ID
id, VALUE *ptr)
8465 must_respond_to(id_write, val,
id);
8470stderr_getter(ID
id, VALUE *ptr)
8476prep_io(
int fd,
int fmode, VALUE klass,
const char *path)
8479 VALUE io = io_alloc(klass);
8485 if (!io_check_tty(fp)) {
8488 setmode(fd, O_BINARY);
8502 if (path && strcmp(path,
"-")) klass =
rb_cFile;
8503 return prep_io(fd, rb_io_oflags_fmode(oflags), klass, path);
8507prep_stdio(
FILE *f,
int fmode, VALUE klass,
const char *path)
8510 VALUE io = prep_io(fileno(f), fmode|FMODE_PREP|DEFAULT_TEXTMODE, klass, path);
8514#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
8515 fptr->
encs.
ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
8526rb_io_prep_stdin(
void)
8532rb_io_prep_stdout(
void)
8538rb_io_prep_stderr(
void)
8547 int oflags = rb_io_fmode_oflags(fptr->
mode) & ~O_EXCL;
8574 rb_io_buffer_init(&fp->
wbuf);
8575 rb_io_buffer_init(&fp->
rbuf);
8576 rb_io_buffer_init(&fp->
cbuf);
8593rb_io_make_open_file(VALUE obj)
8598 if (
RFILE(obj)->fptr) {
8601 RFILE(obj)->fptr = 0;
8603 fp = rb_io_fptr_new();
8605 RFILE(obj)->fptr = fp;
8763rb_io_initialize(
int argc, VALUE *argv, VALUE io)
8767 int fd, fmode, oflags = O_RDONLY;
8768 convconfig_t convconfig;
8770#if defined(HAVE_FCNTL) && defined(F_GETFL)
8777 argc =
rb_scan_args(argc, argv,
"11:", &fnum, &vmode, &opt);
8782 rb_raise(rb_eArgError,
"The given fd is not accessible because RubyVM reserves it");
8784#if defined(HAVE_FCNTL) && defined(F_GETFL)
8785 oflags = fcntl(fd, F_GETFL);
8791#if defined(HAVE_FCNTL) && defined(F_GETFL)
8792 ofmode = rb_io_oflags_fmode(oflags);
8797 VALUE error =
INT2FIX(EINVAL);
8798 rb_exc_raise(rb_class_new_instance(1, &error, rb_eSystemCallError));
8802 fmode |= FMODE_PREP;
8808 fp->
encs = convconfig;
8811 if (fileno(stdin) == fd)
8813 else if (fileno(stdout) == fd)
8815 else if (fileno(stderr) == fd)
8841rb_io_set_encoding_by_bom(VALUE io)
8847 rb_raise(rb_eArgError,
"ASCII incompatible encoding needs binmode");
8850 rb_raise(rb_eArgError,
"encoding conversion is set");
8853 rb_raise(rb_eArgError,
"encoding is set to %s already",
8856 if (!io_set_encoding_by_bom(io))
return Qnil;
8886rb_file_initialize(
int argc, VALUE *argv, VALUE io)
8888 if (
RFILE(io)->fptr) {
8889 rb_raise(rb_eRuntimeError,
"reinitializing File");
8891 if (0 < argc && argc < 3) {
8892 VALUE fd = rb_check_to_int(argv[0]);
8896 return rb_io_initialize(argc, argv, io);
8899 rb_open_file(argc, argv, io);
8906rb_io_s_new(
int argc, VALUE *argv, VALUE klass)
8911 rb_warn(
"%"PRIsVALUE
"::new() does not take block; use %"PRIsVALUE
"::open() instead",
8927rb_io_s_for_fd(
int argc, VALUE *argv, VALUE klass)
8929 VALUE io = rb_obj_alloc(klass);
8930 rb_io_initialize(argc, argv, io);
8943rb_io_autoclose_p(VALUE io)
8968rb_io_set_autoclose(VALUE io, VALUE autoclose)
8972 if (!
RTEST(autoclose))
8973 fptr->
mode |= FMODE_PREP;
8975 fptr->
mode &= ~FMODE_PREP;
8982 struct argf *p = ptr;
8991argf_memsize(
const void *ptr)
8993 const struct argf *p = ptr;
8994 size_t size =
sizeof(*p);
9001 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
9005argf_init(
struct argf *p, VALUE v)
9008 p->current_file =
Qnil;
9014argf_alloc(VALUE klass)
9027argf_initialize(VALUE
argf, VALUE argv)
9029 memset(&ARGF, 0,
sizeof(ARGF));
9030 argf_init(&ARGF, argv);
9037argf_initialize_copy(VALUE
argf, VALUE orig)
9040 ARGF = argf_of(orig);
9041 ARGF.argv = rb_obj_dup(ARGF.argv);
9064argf_set_lineno(VALUE
argf, VALUE val)
9067 ARGF.last_lineno = ARGF.lineno;
9085argf_lineno(VALUE
argf)
9091argf_forward(
int argc, VALUE *argv, VALUE
argf)
9096#define next_argv() argf_next_argv(argf)
9097#define ARGF_GENERIC_INPUT_P() \
9098 (ARGF.current_file == rb_stdin && !RB_TYPE_P(ARGF.current_file, T_FILE))
9099#define ARGF_FORWARD(argc, argv) do {\
9100 if (ARGF_GENERIC_INPUT_P())\
9101 return argf_forward((argc), (argv), argf);\
9103#define NEXT_ARGF_FORWARD(argc, argv) do {\
9104 if (!next_argv()) return Qnil;\
9105 ARGF_FORWARD((argc), (argv));\
9109argf_close(VALUE
argf)
9111 VALUE file = ARGF.current_file;
9121argf_next_argv(VALUE
argf)
9125 int stdout_binmode = 0;
9136 if (ARGF.init_p == 0) {
9146 if (
NIL_P(ARGF.argv)) {
9149 else if (ARGF.next_p == -1 &&
RARRAY_LEN(ARGF.argv) > 0) {
9154 if (ARGF.next_p == 1) {
9155 if (ARGF.init_p == 1) argf_close(
argf);
9160 ARGF.filename = filename;
9166 rb_warn(
"Can't do inplace edit for stdio; skipping");
9171 VALUE write_io =
Qnil;
9172 int fr = rb_sysopen(filename, O_RDONLY, 0);
9176#ifndef NO_SAFE_RENAME
9187 if (!
NIL_P(ARGF.inplace)) {
9188 VALUE suffix = ARGF.inplace;
9195#ifdef NO_SAFE_RENAME
9199 rb_warn(
"Can't rename %"PRIsVALUE
" to %"PRIsVALUE
": %s, skipping file",
9200 filename, str, strerror(errno));
9203 fr = rb_sysopen(str, O_RDONLY, 0);
9206 rb_warn(
"Can't rename %"PRIsVALUE
" to %"PRIsVALUE
": %s, skipping file",
9207 filename, str, strerror(errno));
9214#ifdef NO_SAFE_RENAME
9215 rb_fatal(
"Can't do inplace edit without backup");
9217 if (unlink(fn) < 0) {
9218 rb_warn(
"Can't remove %"PRIsVALUE
": %s, skipping file",
9219 filename, strerror(errno));
9225 fw = rb_sysopen(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666);
9226#ifndef NO_SAFE_RENAME
9229 fchmod(fw, st.st_mode);
9231 chmod(fn, st.st_mode);
9233 if (st.st_uid!=st2.st_uid || st.st_gid!=st2.st_gid) {
9236 err = fchown(fw, st.st_uid, st.st_gid);
9238 err = chown(fn, st.st_uid, st.st_gid);
9240 if (err && getuid() == 0 && st2.st_uid == 0) {
9242 rb_warn(
"Can't set owner/group of %"PRIsVALUE
" to same as %"PRIsVALUE
": %s, skipping file",
9243 filename, str, strerror(errno));
9256 if (!ARGF.binmode) {
9257 fmode |= DEFAULT_TEXTMODE;
9259 ARGF.current_file = prep_io(fr, fmode,
rb_cFile, fn);
9260 if (!
NIL_P(write_io)) {
9267 if (ARGF.encs.enc) {
9268 fptr->
encs = ARGF.encs;
9269 clear_codeconv(fptr);
9272 fptr->
encs.
ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
9273 if (!ARGF.binmode) {
9275#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9276 fptr->
encs.
ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
9287 else if (ARGF.next_p == -1) {
9291 rb_warn(
"Can't do inplace edit for stdio");
9295 if (ARGF.init_p == -1) ARGF.init_p = 1;
9300argf_getline(
int argc, VALUE *argv, VALUE
argf)
9303 long lineno = ARGF.lineno;
9306 if (!next_argv())
return Qnil;
9307 if (ARGF_GENERIC_INPUT_P()) {
9308 line = forward_current(idGets, argc, argv);
9315 line = rb_io_getline(argc, argv, ARGF.current_file);
9317 if (
NIL_P(line) && ARGF.next_p != -1) {
9324 ARGF.lineno = ++lineno;
9325 ARGF.last_lineno = ARGF.lineno;
9331argf_lineno_getter(ID
id, VALUE *var)
9334 return INT2FIX(ARGF.last_lineno);
9338argf_lineno_setter(VALUE val, ID
id, VALUE *var)
9342 ARGF.last_lineno = ARGF.lineno = n;
9345static VALUE argf_gets(
int, VALUE *, VALUE);
9381rb_f_gets(
int argc, VALUE *argv, VALUE recv)
9384 return argf_gets(argc, argv,
argf);
9386 return forward(
argf, idGets, argc, argv);
9408argf_gets(
int argc, VALUE *argv, VALUE
argf)
9412 line = argf_getline(argc, argv,
argf);
9424 return rb_f_gets(0, 0,
argf);
9428 if (!next_argv())
return Qnil;
9430 if (
NIL_P(line) && ARGF.next_p != -1) {
9438 ARGF.last_lineno = ARGF.lineno;
9444static VALUE argf_readline(
int, VALUE *, VALUE);
9457rb_f_readline(
int argc, VALUE *argv, VALUE recv)
9460 return argf_readline(argc, argv,
argf);
9484argf_readline(
int argc, VALUE *argv, VALUE
argf)
9488 if (!next_argv()) rb_eof_error();
9489 ARGF_FORWARD(argc, argv);
9490 line = argf_gets(argc, argv,
argf);
9498static VALUE argf_readlines(
int, VALUE *, VALUE);
9511rb_f_readlines(
int argc, VALUE *argv, VALUE recv)
9514 return argf_readlines(argc, argv,
argf);
9536argf_readlines(
int argc, VALUE *argv, VALUE
argf)
9538 long lineno = ARGF.lineno;
9542 while (next_argv()) {
9543 if (ARGF_GENERIC_INPUT_P()) {
9544 lines = forward_current(
rb_intern(
"readlines"), argc, argv);
9547 lines = rb_io_readlines(argc, argv, ARGF.current_file);
9553 ARGF.last_lineno = ARGF.lineno;
9574rb_f_backquote(VALUE obj, VALUE str)
9581 rb_last_status_clear();
9582 port = pipe_open_s(str,
"r",
FMODE_READABLE|DEFAULT_TEXTMODE, NULL);
9586 result = read_all(fptr, remain_size(fptr),
Qnil);
9588 RFILE(port)->fptr = NULL;
9595#ifdef HAVE_SYS_SELECT_H
9596#include <sys/select.h>
9600select_internal(VALUE read, VALUE write, VALUE except,
struct timeval *tp,
rb_fdset_t *fds)
9615 if (READ_DATA_PENDING(fptr) || READ_CHAR_PENDING(fptr)) {
9619 if (max < fptr->fd) max = fptr->
fd;
9622 timerec.tv_sec = timerec.tv_usec = 0;
9630 if (!
NIL_P(write)) {
9636 if (max < fptr->fd) max = fptr->
fd;
9643 if (!
NIL_P(except)) {
9647 VALUE write_io = GetWriteIO(io);
9650 if (max < fptr->fd) max = fptr->
fd;
9651 if (io != write_io) {
9654 if (max < fptr->fd) max = fptr->
fd;
9669 if (!pending && n == 0)
return Qnil;
9694 VALUE write_io = GetWriteIO(io);
9707 VALUE write_io = GetWriteIO(io);
9712 else if (io != write_io) {
9725 VALUE read, write, except;
9731select_call(VALUE arg)
9735 return select_internal(p->read, p->write, p->except, p->timeout, p->fdsets);
9739select_end(VALUE arg)
9744 for (i = 0; i < numberof(p->fdsets); ++i)
9749static VALUE sym_normal, sym_sequential, sym_random,
9750 sym_willneed, sym_dontneed, sym_noreuse;
9752#ifdef HAVE_POSIX_FADVISE
9753struct io_advise_struct {
9761io_advise_internal(
void *arg)
9763 struct io_advise_struct *ptr = arg;
9764 return posix_fadvise(ptr->fd, ptr->offset, ptr->len, ptr->advice);
9768io_advise_sym_to_const(VALUE sym)
9770#ifdef POSIX_FADV_NORMAL
9771 if (sym == sym_normal)
9772 return INT2NUM(POSIX_FADV_NORMAL);
9775#ifdef POSIX_FADV_RANDOM
9776 if (sym == sym_random)
9777 return INT2NUM(POSIX_FADV_RANDOM);
9780#ifdef POSIX_FADV_SEQUENTIAL
9781 if (sym == sym_sequential)
9782 return INT2NUM(POSIX_FADV_SEQUENTIAL);
9785#ifdef POSIX_FADV_WILLNEED
9786 if (sym == sym_willneed)
9787 return INT2NUM(POSIX_FADV_WILLNEED);
9790#ifdef POSIX_FADV_DONTNEED
9791 if (sym == sym_dontneed)
9792 return INT2NUM(POSIX_FADV_DONTNEED);
9795#ifdef POSIX_FADV_NOREUSE
9796 if (sym == sym_noreuse)
9797 return INT2NUM(POSIX_FADV_NOREUSE);
9804do_io_advise(
rb_io_t *fptr, VALUE advice, off_t offset, off_t len)
9807 struct io_advise_struct ias;
9810 num_adv = io_advise_sym_to_const(advice);
9820 ias.advice =
NUM2INT(num_adv);
9821 ias.offset = offset;
9824 rv = (int)rb_thread_io_blocking_region(io_advise_internal, &ias, fptr->
fd);
9825 if (rv && rv != ENOSYS) {
9832 fptr->
pathv, offset, len, advice);
9842advice_arg_check(VALUE advice)
9845 rb_raise(rb_eTypeError,
"advice must be a Symbol");
9847 if (advice != sym_normal &&
9848 advice != sym_sequential &&
9849 advice != sym_random &&
9850 advice != sym_willneed &&
9851 advice != sym_dontneed &&
9852 advice != sym_noreuse) {
9853 rb_raise(rb_eNotImpError,
"Unsupported advice: %+"PRIsVALUE, advice);
9900rb_io_advise(
int argc, VALUE *argv, VALUE io)
9902 VALUE advice, offset, len;
9906 rb_scan_args(argc, argv,
"12", &advice, &offset, &len);
9907 advice_arg_check(advice);
9909 io = GetWriteIO(io);
9915#ifdef HAVE_POSIX_FADVISE
9916 return do_io_advise(fptr, advice, off, l);
9918 ((void)off, (
void)l);
10064rb_f_select(
int argc, VALUE *argv, VALUE obj)
10071 rb_scan_args(argc, argv,
"13", &args.read, &args.write, &args.except, &timeout);
10072 if (
NIL_P(timeout)) {
10077 args.timeout = &timerec;
10080 for (i = 0; i < numberof(args.fdsets); ++i)
10083 return rb_ensure(select_call, (VALUE)&args, select_end, (VALUE)&args);
10086#ifdef IOCTL_REQ_TYPE
10087 typedef IOCTL_REQ_TYPE ioctl_req_t;
10089 typedef int ioctl_req_t;
10090# define NUM2IOCTLREQ(num) ((int)NUM2LONG(num))
10101nogvl_ioctl(
void *ptr)
10103 struct ioctl_arg *arg = ptr;
10105 return (VALUE)ioctl(arg->fd, arg->cmd, arg->narg);
10109do_ioctl(
int fd, ioctl_req_t cmd,
long narg)
10112 struct ioctl_arg arg;
10118 retval = (int)rb_thread_io_blocking_region(nogvl_ioctl, &arg, fd);
10124#define DEFAULT_IOCTL_NARG_LEN (256)
10126#if defined(__linux__) && defined(_IOC_SIZE)
10128linux_iocparm_len(ioctl_req_t cmd)
10132 if ((cmd & 0xFFFF0000) == 0) {
10134 return DEFAULT_IOCTL_NARG_LEN;
10137 len = _IOC_SIZE(cmd);
10140 if (len < DEFAULT_IOCTL_NARG_LEN)
10141 len = DEFAULT_IOCTL_NARG_LEN;
10148ioctl_narg_len(ioctl_req_t cmd)
10154#define IOCPARM_LEN(x) (((x) >> 16) & IOCPARM_MASK)
10158 len = IOCPARM_LEN(cmd);
10159#elif defined(__linux__) && defined(_IOC_SIZE)
10160 len = linux_iocparm_len(cmd);
10163 len = DEFAULT_IOCTL_NARG_LEN;
10171typedef long fcntl_arg_t;
10174typedef int fcntl_arg_t;
10178fcntl_narg_len(ioctl_req_t cmd)
10185 len =
sizeof(fcntl_arg_t);
10193#ifdef F_DUPFD_CLOEXEC
10194 case F_DUPFD_CLOEXEC:
10195 len =
sizeof(fcntl_arg_t);
10205 len =
sizeof(fcntl_arg_t);
10215 len =
sizeof(fcntl_arg_t);
10225 len =
sizeof(fcntl_arg_t);
10230 len =
sizeof(
struct f_owner_ex);
10235 len =
sizeof(
struct f_owner_ex);
10240 len =
sizeof(
struct flock);
10245 len =
sizeof(
struct flock);
10250 len =
sizeof(
struct flock);
10270 len =
sizeof(fcntl_arg_t);
10280 len =
sizeof(fcntl_arg_t);
10285 len =
sizeof(fcntl_arg_t);
10298fcntl_narg_len(ioctl_req_t cmd)
10304#define NARG_SENTINEL 17
10307setup_narg(ioctl_req_t cmd, VALUE *argp,
long (*narg_len)(ioctl_req_t))
10318 else if (arg ==
Qtrue) {
10332 len = narg_len(cmd);
10337 if (slen < len+1) {
10344 ptr[slen - 1] = NARG_SENTINEL;
10353finish_narg(
int retval, VALUE arg,
const rb_io_t *fptr)
10355 if (retval < 0) rb_sys_fail_path(fptr->
pathv);
10360 if (ptr[slen-1] != NARG_SENTINEL)
10361 rb_raise(rb_eArgError,
"return value overflowed string");
10362 ptr[slen-1] =
'\0';
10370rb_ioctl(VALUE io, VALUE req, VALUE arg)
10372 ioctl_req_t cmd = NUM2IOCTLREQ(req);
10377 narg = setup_narg(cmd, &arg, ioctl_narg_len);
10379 retval = do_ioctl(fptr->
fd, cmd, narg);
10380 return finish_narg(retval, arg, fptr);
10396rb_io_ioctl(
int argc, VALUE *argv, VALUE io)
10401 return rb_ioctl(io, req, arg);
10404#define rb_io_ioctl rb_f_notimplement
10415nogvl_fcntl(
void *ptr)
10417 struct fcntl_arg *arg = ptr;
10419#if defined(F_DUPFD)
10420 if (arg->cmd == F_DUPFD)
10423 return (VALUE)fcntl(arg->fd, arg->cmd, arg->narg);
10427do_fcntl(
int fd,
int cmd,
long narg)
10430 struct fcntl_arg arg;
10436 retval = (int)rb_thread_io_blocking_region(nogvl_fcntl, &arg, fd);
10437 if (retval != -1) {
10439#if defined(F_DUPFD)
10442#if defined(F_DUPFD_CLOEXEC)
10443 case F_DUPFD_CLOEXEC:
10453rb_fcntl(VALUE io, VALUE req, VALUE arg)
10460 narg = setup_narg(cmd, &arg, fcntl_narg_len);
10462 retval = do_fcntl(fptr->
fd, cmd, narg);
10463 return finish_narg(retval, arg, fptr);
10480rb_io_fcntl(
int argc, VALUE *argv, VALUE io)
10485 return rb_fcntl(io, req, arg);
10488#define rb_io_fcntl rb_f_notimplement
10491#if defined(HAVE_SYSCALL) || defined(HAVE___SYSCALL)
10527rb_f_syscall(
int argc, VALUE *argv, VALUE
_)
10530#if SIZEOF_VOIDP == 8 && defined(HAVE___SYSCALL) && SIZEOF_INT != 8
10531# define SYSCALL __syscall
10532# define NUM2SYSCALLID(x) NUM2LONG(x)
10533# define RETVAL2NUM(x) LONG2NUM(x)
10534# if SIZEOF_LONG == 8
10535 long num, retval = -1;
10536# elif SIZEOF_LONG_LONG == 8
10537 long long num, retval = -1;
10539# error ---->> it is asserted that __syscall takes the first argument and returns retval in 64bit signed integer. <<----
10541#elif defined(__linux__)
10542# define SYSCALL syscall
10543# define NUM2SYSCALLID(x) NUM2LONG(x)
10544# define RETVAL2NUM(x) LONG2NUM(x)
10552 long num, retval = -1;
10554# define SYSCALL syscall
10555# define NUM2SYSCALLID(x) NUM2INT(x)
10556# define RETVAL2NUM(x) INT2NUM(x)
10557 int num, retval = -1;
10563 "We plan to remove a syscall function at future release. DL(Fiddle) provides safer alternative.");
10567 rb_raise(rb_eArgError,
"too few arguments for syscall");
10568 if (argc > numberof(arg))
10569 rb_raise(rb_eArgError,
"too many arguments for syscall");
10570 num = NUM2SYSCALLID(argv[0]); ++argv;
10571 for (i = argc - 1; i--; ) {
10586 retval = SYSCALL(num);
10589 retval = SYSCALL(num, arg[0]);
10592 retval = SYSCALL(num, arg[0],arg[1]);
10595 retval = SYSCALL(num, arg[0],arg[1],arg[2]);
10598 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3]);
10601 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4]);
10604 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5]);
10607 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6]);
10613 return RETVAL2NUM(retval);
10615#undef NUM2SYSCALLID
10619#define rb_f_syscall rb_f_notimplement
10623io_new_instance(VALUE args)
10625 return rb_class_new_instance(2, (VALUE*)args+1, *(VALUE*)args);
10629find_encoding(VALUE v)
10632 if (!enc)
rb_warn(
"Unsupported encoding %"PRIsVALUE
" ignored", v);
10637io_encoding_set(
rb_io_t *fptr, VALUE v1, VALUE v2, VALUE opt)
10644 enc2 = find_encoding(v1);
10653 enc = find_encoding(v2);
10660 enc = find_encoding(v2);
10666 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
10672 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
10673 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
10679 parse_mode_enc(
RSTRING_PTR(tmp), enc, &enc, &enc2, NULL);
10680 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
10684 rb_io_ext_int_to_encs(find_encoding(v1), NULL, &enc, &enc2, 0);
10685 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
10690 validate_enc_binmode(&fptr->
mode, ecflags, enc, enc2);
10695 clear_codeconv(fptr);
10707io_encoding_set_v(VALUE v)
10710 io_encoding_set(arg->fptr, arg->v1, arg->v2, arg->opt);
10715pipe_pair_close(VALUE rw)
10717 VALUE *rwp = (VALUE *)rw;
10718 return rb_ensure(io_close, rwp[0], io_close, rwp[1]);
10782rb_io_s_pipe(
int argc, VALUE *argv, VALUE klass)
10784 int pipes[2], state;
10785 VALUE r, w, args[3], v1, v2;
10792 argc =
rb_scan_args(argc, argv,
"02:", &v1, &v2, &opt);
10799 r =
rb_protect(io_new_instance, (VALUE)args, &state);
10807 ies_args.fptr = fptr;
10810 ies_args.opt = opt;
10811 rb_protect(io_encoding_set_v, (VALUE)&ies_args, &state);
10820 w =
rb_protect(io_new_instance, (VALUE)args, &state);
10829 extract_binmode(opt, &fmode);
10836#if DEFAULT_TEXTMODE
10838 fptr->
mode &= ~FMODE_TEXTMODE;
10839 setmode(fptr->
fd, O_BINARY);
10841#if RUBY_CRLF_ENVIRONMENT
10847 fptr->
mode |= fmode;
10848#if DEFAULT_TEXTMODE
10850 fptr2->
mode &= ~FMODE_TEXTMODE;
10851 setmode(fptr2->
fd, O_BINARY);
10854 fptr2->
mode |= fmode;
10873open_key_args(VALUE klass,
int argc, VALUE *argv, VALUE opt,
struct foreach_arg *arg)
10891 v = rb_to_array_type(v);
10896 arg->io = rb_io_open(klass, path, vmode, vperm, opt);
10900io_s_foreach(VALUE v)
10905 while (!
NIL_P(str = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, arg->io))) {
10951rb_io_s_foreach(
int argc, VALUE *argv, VALUE
self)
10954 int orig_argc = argc;
10958 argc =
rb_scan_args(argc, argv,
"13:", NULL, NULL, NULL, NULL, &opt);
10960 extract_getline_args(argc-1, argv+1, &garg);
10961 open_key_args(
self, argc, argv, opt, &arg);
10963 extract_getline_opts(opt, &garg);
10964 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
10969io_s_readlines(VALUE v)
10972 return io_readlines(arg, arg->io);
11016rb_io_s_readlines(
int argc, VALUE *argv, VALUE io)
11022 argc =
rb_scan_args(argc, argv,
"13:", NULL, NULL, NULL, NULL, &opt);
11023 extract_getline_args(argc-1, argv+1, &garg);
11024 open_key_args(io, argc, argv, opt, &arg);
11026 extract_getline_opts(opt, &garg);
11027 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
11035 return io_read(arg->argc, arg->argv, arg->io);
11045seek_before_access(VALUE argp)
11049 return rb_io_seek(arg->io, arg->offset, arg->mode);
11099rb_io_s_read(
int argc, VALUE *argv, VALUE io)
11104 argc =
rb_scan_args(argc, argv,
"13:", NULL, NULL, &offset, NULL, &opt);
11105 open_key_args(io, argc, argv, opt, &arg);
11107 if (!
NIL_P(offset)) {
11111 sarg.offset = offset;
11112 sarg.mode = SEEK_SET;
11113 rb_protect(seek_before_access, (VALUE)&sarg, &state);
11118 if (arg.argc == 2) arg.argc = 1;
11147rb_io_s_binread(
int argc, VALUE *argv, VALUE io)
11158 convconfig_t convconfig = {NULL, NULL, 0,
Qnil};
11163 arg.io = rb_io_open_generic(io, argv[0], oflags, fmode, &convconfig, 0);
11166 arg.argc = (argc > 1) ? 1 : 0;
11167 if (!
NIL_P(offset)) {
11171 sarg.offset = offset;
11172 sarg.mode = SEEK_SET;
11173 rb_protect(seek_before_access, (VALUE)&sarg, &state);
11183io_s_write0(VALUE v)
11186 return io_write(arg->io,arg->str,arg->nosync);
11190io_s_write(
int argc, VALUE *argv, VALUE klass,
int binary)
11192 VALUE string, offset, opt;
11196 rb_scan_args(argc, argv,
"21:", NULL, &
string, &offset, &opt);
11203 int mode = O_WRONLY|O_CREAT;
11205 if (binary) mode |= O_BINARY;
11207 if (
NIL_P(offset)) mode |= O_TRUNC;
11210 open_key_args(klass, argc, argv, opt, &arg);
11213 if (binary) rb_io_binmode_m(arg.io);
11217 if (!
NIL_P(offset)) {
11221 sarg.offset = offset;
11222 sarg.mode = SEEK_SET;
11223 rb_protect(seek_before_access, (VALUE)&sarg, &state);
11292rb_io_s_write(
int argc, VALUE *argv, VALUE io)
11294 return io_s_write(argc, argv, io, 0);
11316rb_io_s_binwrite(
int argc, VALUE *argv, VALUE io)
11318 return io_s_write(argc, argv, io, 1);
11329 unsigned close_src : 1;
11330 unsigned close_dst : 1;
11333 const char *syserr;
11334 const char *notimp;
11336 struct stat src_stat;
11337 struct stat dst_stat;
11338#ifdef HAVE_FCOPYFILE
11339 copyfile_state_t copyfile_state;
11344exec_interrupts(
void *arg)
11346 VALUE th = (
VALUE)arg;
11347 rb_thread_execute_interrupts(th);
11361#if defined(ERESTART)
11366 rb_thread_execute_interrupts(stp->th);
11385rb_thread_fiber_scheduler_wait_for(
void * _args)
11395# define IOWAIT_SYSCALL "poll"
11396STATIC_ASSERT(pollin_expected, POLLIN == RB_WAITFD_IN);
11397STATIC_ASSERT(pollout_expected, POLLOUT == RB_WAITFD_OUT);
11399nogvl_wait_for(VALUE th,
rb_io_t *fptr,
short events)
11402 if (scheduler !=
Qnil) {
11403 struct wait_for_single_fd args = {.scheduler = scheduler, .fptr = fptr, .events = events};
11405 return RTEST(args.result);
11409 if (fd == -1)
return 0;
11414 fds.events = events;
11416 return poll(&fds, 1, -1);
11419# define IOWAIT_SYSCALL "select"
11421nogvl_wait_for(VALUE th,
rb_io_t *fptr,
short events)
11424 if (scheduler !=
Qnil) {
11425 struct wait_for_single_fd args = {.scheduler = scheduler, .fptr = fptr, .events = events};
11427 return RTEST(args.result);
11431 if (fd == -1)
return 0;
11443 case RB_WAITFD_OUT:
11447 VM_UNREACHABLE(nogvl_wait_for);
11465 ret = nogvl_wait_for(stp->th, stp->src_fptr, RB_WAITFD_IN);
11467 }
while (ret < 0 && maygvl_copy_stream_continue_p(has_gvl, stp));
11470 stp->syserr = IOWAIT_SYSCALL;
11471 stp->error_no = errno;
11483 ret = nogvl_wait_for(stp->th, stp->dst_fptr, RB_WAITFD_OUT);
11484 }
while (ret < 0 && maygvl_copy_stream_continue_p(0, stp));
11487 stp->syserr = IOWAIT_SYSCALL;
11488 stp->error_no = errno;
11494#ifdef USE_COPY_FILE_RANGE
11497simple_copy_file_range(
int in_fd, off_t *in_offset,
int out_fd, off_t *out_offset,
size_t count,
unsigned int flags)
11499#ifdef HAVE_COPY_FILE_RANGE
11500 return copy_file_range(in_fd, in_offset, out_fd, out_offset, count, flags);
11502 return syscall(__NR_copy_file_range, in_fd, in_offset, out_fd, out_offset, count, flags);
11511 off_t copy_length, src_offset, *src_offset_ptr;
11513 if (!S_ISREG(stp->src_stat.st_mode))
11516 src_size = stp->src_stat.st_size;
11517 src_offset = stp->src_offset;
11518 if (src_offset >= (off_t)0) {
11519 src_offset_ptr = &src_offset;
11522 src_offset_ptr = NULL;
11525 copy_length = stp->copy_length;
11526 if (copy_length < (off_t)0) {
11527 if (src_offset < (off_t)0) {
11528 off_t current_offset;
11530 current_offset = lseek(stp->src_fptr->
fd, 0, SEEK_CUR);
11531 if (current_offset < (off_t)0 && errno) {
11532 stp->syserr =
"lseek";
11533 stp->error_no = errno;
11534 return (
int)current_offset;
11536 copy_length = src_size - current_offset;
11539 copy_length = src_size - src_offset;
11543 retry_copy_file_range:
11544# if SIZEOF_OFF_T > SIZEOF_SIZE_T
11546 ss = (copy_length > (off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
11548 ss = (ssize_t)copy_length;
11550 ss = simple_copy_file_range(stp->src_fptr->
fd, src_offset_ptr, stp->dst_fptr->
fd, NULL, ss, 0);
11554 if (0 < copy_length) {
11555 goto retry_copy_file_range;
11559 if (maygvl_copy_stream_continue_p(0, stp)) {
11560 goto retry_copy_file_range;
11574#if EWOULDBLOCK != EAGAIN
11578 int ret = nogvl_copy_stream_wait_write(stp);
11579 if (ret < 0)
return ret;
11581 goto retry_copy_file_range;
11585 int flags = fcntl(stp->dst_fptr->
fd, F_GETFL);
11587 if (flags != -1 && flags & O_APPEND) {
11593 stp->syserr =
"copy_file_range";
11594 stp->error_no = errno;
11601#ifdef HAVE_FCOPYFILE
11606 const off_t src_offset = stp->src_offset;
11609 if (stp->copy_length >= (off_t)0) {
11614 if (!S_ISREG(stp->src_stat.st_mode))
11617 if (!S_ISREG(stp->dst_stat.st_mode))
11619 if (lseek(stp->dst_fptr->
fd, 0, SEEK_CUR) > (off_t)0)
11621 if (fcntl(stp->dst_fptr->
fd, F_GETFL) & O_APPEND) {
11624 off_t end = lseek(stp->dst_fptr->
fd, 0, SEEK_END);
11625 lseek(stp->dst_fptr->
fd, 0, SEEK_SET);
11626 if (end > (off_t)0)
return 0;
11629 if (src_offset > (off_t)0) {
11634 cur = lseek(stp->src_fptr->
fd, 0, SEEK_CUR);
11635 if (cur < (off_t)0 && errno) {
11636 stp->error_no = errno;
11641 r = lseek(stp->src_fptr->
fd, src_offset, SEEK_SET);
11642 if (r < (off_t)0 && errno) {
11643 stp->error_no = errno;
11648 stp->copyfile_state = copyfile_state_alloc();
11649 ret = fcopyfile(stp->src_fptr->
fd, stp->dst_fptr->
fd, stp->copyfile_state, COPYFILE_DATA);
11650 copyfile_state_get(stp->copyfile_state, COPYFILE_STATE_COPIED, &ss);
11654 if (src_offset > (off_t)0) {
11658 r = lseek(stp->src_fptr->
fd, cur, SEEK_SET);
11659 if (r < (off_t)0 && errno) {
11660 stp->error_no = errno;
11672 stp->syserr =
"fcopyfile";
11673 stp->error_no = errno;
11680#ifdef HAVE_SENDFILE
11683# define USE_SENDFILE
11685# ifdef HAVE_SYS_SENDFILE_H
11686# include <sys/sendfile.h>
11690simple_sendfile(
int out_fd,
int in_fd, off_t *offset, off_t count)
11692 return sendfile(out_fd, in_fd, offset, (
size_t)count);
11695# elif 0 || defined(__APPLE__)
11699# define USE_SENDFILE
11702simple_sendfile(
int out_fd,
int in_fd, off_t *offset, off_t count)
11705 off_t pos = offset ? *offset : lseek(in_fd, 0, SEEK_CUR);
11708 r = sendfile(in_fd, out_fd, pos, &count, NULL, 0);
11711 r = sendfile(in_fd, out_fd, pos, (
size_t)count, NULL, &sbytes, 0);
11713 if (r != 0 && sbytes == 0)
return r;
11718 lseek(in_fd, sbytes, SEEK_CUR);
11720 return (ssize_t)sbytes;
11737 if (!S_ISREG(stp->src_stat.st_mode))
11740 src_size = stp->src_stat.st_size;
11742 if ((stp->dst_stat.st_mode & S_IFMT) != S_IFSOCK)
11746 src_offset = stp->src_offset;
11747 use_pread = src_offset >= (off_t)0;
11749 copy_length = stp->copy_length;
11750 if (copy_length < (off_t)0) {
11752 copy_length = src_size - src_offset;
11756 cur = lseek(stp->src_fptr->
fd, 0, SEEK_CUR);
11757 if (cur < (off_t)0 && errno) {
11758 stp->syserr =
"lseek";
11759 stp->error_no = errno;
11762 copy_length = src_size - cur;
11767# if SIZEOF_OFF_T > SIZEOF_SIZE_T
11769 ss = (copy_length > (off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
11771 ss = (ssize_t)copy_length;
11774 ss = simple_sendfile(stp->dst_fptr->
fd, stp->src_fptr->
fd, &src_offset, ss);
11777 ss = simple_sendfile(stp->dst_fptr->
fd, stp->src_fptr->
fd, NULL, ss);
11782 if (0 < copy_length) {
11783 goto retry_sendfile;
11787 if (maygvl_copy_stream_continue_p(0, stp))
11788 goto retry_sendfile;
11801#if EWOULDBLOCK != EAGAIN
11814 ret = maygvl_copy_stream_wait_read(0, stp);
11815 if (ret < 0)
return ret;
11817 ret = nogvl_copy_stream_wait_write(stp);
11818 if (ret < 0)
return ret;
11820 goto retry_sendfile;
11822 stp->syserr =
"sendfile";
11823 stp->error_no = errno;
11831maygvl_read(
int has_gvl,
rb_io_t *fptr,
void *buf,
size_t count)
11834 return rb_read_internal(fptr, buf, count);
11836 return read(fptr->
fd, buf, count);
11840maygvl_copy_stream_read(
int has_gvl,
struct copy_stream_struct *stp,
char *buf,
size_t len, off_t offset)
11844 if (offset < (off_t)0) {
11845 ss = maygvl_read(has_gvl, stp->src_fptr, buf, len);
11849 ss = pread(stp->src_fptr->
fd, buf, len, offset);
11851 stp->notimp =
"pread";
11859 if (maygvl_copy_stream_continue_p(has_gvl, stp))
11863#if EWOULDBLOCK != EAGAIN
11867 int ret = maygvl_copy_stream_wait_read(has_gvl, stp);
11868 if (ret < 0)
return ret;
11873 stp->notimp =
"pread";
11877 stp->syserr = offset < (off_t)0 ?
"read" :
"pread";
11878 stp->error_no = errno;
11889 ss = write(stp->dst_fptr->
fd, buf+off, len);
11891 if (maygvl_copy_stream_continue_p(0, stp))
11893 if (io_again_p(errno)) {
11894 int ret = nogvl_copy_stream_wait_write(stp);
11895 if (ret < 0)
return ret;
11898 stp->syserr =
"write";
11899 stp->error_no = errno;
11921 copy_length = stp->copy_length;
11922 use_eof = copy_length < (off_t)0;
11923 src_offset = stp->src_offset;
11924 use_pread = src_offset >= (off_t)0;
11926 if (use_pread && stp->close_src) {
11929 r = lseek(stp->src_fptr->
fd, src_offset, SEEK_SET);
11930 if (r < (off_t)0 && errno) {
11931 stp->syserr =
"lseek";
11932 stp->error_no = errno;
11935 src_offset = (off_t)-1;
11939 while (use_eof || 0 < copy_length) {
11940 if (!use_eof && copy_length < (off_t)
sizeof(buf)) {
11941 len = (size_t)copy_length;
11947 ss = maygvl_copy_stream_read(0, stp, buf, len, src_offset);
11952 ss = maygvl_copy_stream_read(0, stp, buf, len, (off_t)-1);
11957 ret = nogvl_copy_stream_write(stp, buf, ss);
11967nogvl_copy_stream_func(
void *arg)
11970#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
11974#ifdef USE_COPY_FILE_RANGE
11975 ret = nogvl_copy_file_range(stp);
11980#ifdef HAVE_FCOPYFILE
11981 ret = nogvl_fcopyfile(stp);
11987 ret = nogvl_copy_stream_sendfile(stp);
11992 nogvl_copy_stream_read_write(stp);
11994#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
12001copy_stream_fallback_body(VALUE arg)
12004 const int buflen = 16*1024;
12007 off_t rest = stp->copy_length;
12008 off_t off = stp->src_offset;
12009 ID read_method = id_readpartial;
12011 if (!stp->src_fptr) {
12013 read_method = id_read;
12020 if (stp->copy_length < (off_t)0) {
12028 l = buflen < rest ? buflen : (long)rest;
12030 if (!stp->src_fptr) {
12033 if (read_method == id_read &&
NIL_P(rc))
12039 ss = maygvl_copy_stream_read(1, stp,
RSTRING_PTR(buf), l, off);
12045 if (off >= (off_t)0)
12050 stp->total += numwrote;
12052 if (read_method == id_read &&
RSTRING_LEN(buf) == 0) {
12063 if (!stp->src_fptr && stp->src_offset >= (off_t)0) {
12064 rb_raise(rb_eArgError,
"cannot specify src_offset for non-IO");
12066 rb_rescue2(copy_stream_fallback_body, (VALUE)stp,
12067 (VALUE (*) (VALUE, VALUE))0, (VALUE)0,
12073copy_stream_body(VALUE arg)
12076 VALUE src_io = stp->src, dst_io = stp->dst;
12077 const int common_oflags = 0
12087 if (src_io ==
argf ||
12091 stp->src_fptr = NULL;
12096 if (!
NIL_P(tmp_io)) {
12103 args[1] =
INT2NUM(O_RDONLY|common_oflags);
12104 src_io = rb_class_new_instance(2, args,
rb_cFile);
12106 stp->close_src = 1;
12111 stat_ret = fstat(stp->src_fptr->
fd, &stp->src_stat);
12112 if (stat_ret < 0) {
12113 stp->syserr =
"fstat";
12114 stp->error_no = errno;
12119 if (dst_io ==
argf ||
12123 stp->dst_fptr = NULL;
12128 if (!
NIL_P(tmp_io)) {
12129 dst_io = GetWriteIO(tmp_io);
12135 args[1] =
INT2NUM(O_WRONLY|O_CREAT|O_TRUNC|common_oflags);
12137 dst_io = rb_class_new_instance(3, args,
rb_cFile);
12139 stp->close_dst = 1;
12142 dst_io = GetWriteIO(dst_io);
12148 stat_ret = fstat(stp->dst_fptr->
fd, &stp->dst_stat);
12149 if (stat_ret < 0) {
12150 stp->syserr =
"fstat";
12151 stp->error_no = errno;
12158 SET_BINARY_MODE_WITH_SEEK_CUR(stp->src_fptr);
12161 io_ascii8bit_binmode(stp->dst_fptr);
12163 if (stp->src_offset < (off_t)0 && stp->src_fptr && stp->src_fptr->
rbuf.
len) {
12164 size_t len = stp->src_fptr->
rbuf.
len;
12166 if (stp->copy_length >= (off_t)0 && stp->copy_length < (off_t)len) {
12167 len = (size_t)stp->copy_length;
12171 read_buffered_data(
RSTRING_PTR(str), len, stp->src_fptr);
12172 if (stp->dst_fptr) {
12174 rb_sys_fail_on_write(stp->dst_fptr);
12180 if (stp->copy_length >= (off_t)0)
12181 stp->copy_length -= len;
12184 if (stp->dst_fptr && io_fflush(stp->dst_fptr) < 0) {
12188 if (stp->copy_length == 0)
12191 if (stp->src_fptr == NULL || stp->dst_fptr == NULL) {
12192 return copy_stream_fallback(stp);
12200copy_stream_finalize(VALUE arg)
12204#ifdef HAVE_FCOPYFILE
12205 if (stp->copyfile_state) {
12206 copyfile_state_free(stp->copyfile_state);
12210 if (stp->close_src) {
12211 rb_io_close_m(stp->src);
12213 if (stp->close_dst) {
12214 rb_io_close_m(stp->dst);
12220 rb_raise(rb_eNotImpError,
"%s() not implemented", stp->notimp);
12258rb_io_s_copy_stream(
int argc, VALUE *argv, VALUE io)
12260 VALUE src, dst, length, src_offset;
12265 rb_scan_args(argc, argv,
"22", &src, &dst, &length, &src_offset);
12270 st.src_fptr = NULL;
12271 st.dst_fptr = NULL;
12274 st.copy_length = (off_t)-1;
12276 st.copy_length =
NUM2OFFT(length);
12278 if (
NIL_P(src_offset))
12279 st.src_offset = (off_t)-1;
12281 st.src_offset =
NUM2OFFT(src_offset);
12283 rb_ensure(copy_stream_body, (VALUE)&st, copy_stream_finalize, (VALUE)&st);
12297rb_io_external_encoding(VALUE io)
12321rb_io_internal_encoding(VALUE io)
12349rb_io_set_encoding(
int argc, VALUE *argv, VALUE io)
12355 return forward(io, id_set_encoding, argc, argv);
12358 argc =
rb_scan_args(argc, argv,
"11:", &v1, &v2, &opt);
12360 io_encoding_set(fptr, v1, v2, opt);
12365rb_stdio_set_default_encoding(
void)
12370 if (isatty(fileno(stdin))) {
12381 rb_io_set_encoding(1, &val,
rb_stdin);
12382 rb_io_set_encoding(1, &val,
rb_stdout);
12383 rb_io_set_encoding(1, &val,
rb_stderr);
12387global_argf_p(VALUE arg)
12389 return arg ==
argf;
12409argf_external_encoding(VALUE
argf)
12411 if (!
RTEST(ARGF.current_file)) {
12414 return rb_io_external_encoding(
rb_io_check_io(ARGF.current_file));
12431argf_internal_encoding(VALUE
argf)
12433 if (!
RTEST(ARGF.current_file)) {
12436 return rb_io_internal_encoding(
rb_io_check_io(ARGF.current_file));
12471argf_set_encoding(
int argc, VALUE *argv, VALUE
argf)
12475 if (!next_argv()) {
12476 rb_raise(rb_eArgError,
"no stream to set encoding");
12478 rb_io_set_encoding(argc, argv, ARGF.current_file);
12480 ARGF.encs = fptr->
encs;
12497argf_tell(VALUE
argf)
12499 if (!next_argv()) {
12500 rb_raise(rb_eArgError,
"no stream to tell");
12502 ARGF_FORWARD(0, 0);
12503 return rb_io_tell(ARGF.current_file);
12514argf_seek_m(
int argc, VALUE *argv, VALUE
argf)
12516 if (!next_argv()) {
12517 rb_raise(rb_eArgError,
"no stream to seek");
12519 ARGF_FORWARD(argc, argv);
12520 return rb_io_seek_m(argc, argv, ARGF.current_file);
12535argf_set_pos(VALUE
argf, VALUE offset)
12537 if (!next_argv()) {
12538 rb_raise(rb_eArgError,
"no stream to set position");
12540 ARGF_FORWARD(1, &offset);
12541 return rb_io_set_pos(ARGF.current_file, offset);
12557argf_rewind(VALUE
argf)
12562 if (!next_argv()) {
12563 rb_raise(rb_eArgError,
"no stream to rewind");
12565 ARGF_FORWARD(0, 0);
12566 old_lineno =
RFILE(ARGF.current_file)->fptr->lineno;
12567 ret = rb_io_rewind(ARGF.current_file);
12568 if (!global_argf_p(
argf)) {
12569 ARGF.last_lineno = ARGF.lineno -= old_lineno;
12585argf_fileno(VALUE
argf)
12587 if (!next_argv()) {
12588 rb_raise(rb_eArgError,
"no stream");
12590 ARGF_FORWARD(0, 0);
12591 return rb_io_fileno(ARGF.current_file);
12607argf_to_io(VALUE
argf)
12610 ARGF_FORWARD(0, 0);
12611 return ARGF.current_file;
12633argf_eof(VALUE
argf)
12636 if (
RTEST(ARGF.current_file)) {
12637 if (ARGF.init_p == 0)
return Qtrue;
12639 ARGF_FORWARD(0, 0);
12696argf_read(
int argc, VALUE *argv, VALUE
argf)
12698 VALUE tmp, str, length;
12702 if (!
NIL_P(length)) {
12712 if (!next_argv()) {
12715 if (ARGF_GENERIC_INPUT_P()) {
12716 tmp = argf_forward(argc, argv,
argf);
12719 tmp = io_read(argc, argv, ARGF.current_file);
12721 if (
NIL_P(str)) str = tmp;
12724 if (ARGF.next_p != -1) {
12730 else if (argc >= 1) {
12747argf_forward_call(VALUE arg)
12750 argf_forward(p->argc, p->argv, p->argf);
12754static VALUE argf_getpartial(
int argc, VALUE *argv, VALUE
argf, VALUE opts,
12778argf_readpartial(
int argc, VALUE *argv, VALUE
argf)
12780 return argf_getpartial(argc, argv,
argf,
Qnil, 0);
12792argf_read_nonblock(
int argc, VALUE *argv, VALUE
argf)
12801 return argf_getpartial(argc, argv,
argf, opts, 1);
12805argf_getpartial(
int argc, VALUE *argv, VALUE
argf, VALUE opts,
int nonblock)
12807 VALUE tmp, str, length;
12815 no_exception = no_exception_p(opts);
12817 if (!next_argv()) {
12823 if (ARGF_GENERIC_INPUT_P()) {
12829 tmp =
rb_rescue2(argf_forward_call, (VALUE)&arg,
12833 tmp = io_getpartial(argc, argv, ARGF.current_file, no_exception, nonblock);
12836 if (ARGF.next_p == -1) {
12837 return io_nonblock_eof(no_exception);
12842 return io_nonblock_eof(no_exception);
12875argf_getc(VALUE
argf)
12880 if (!next_argv())
return Qnil;
12881 if (ARGF_GENERIC_INPUT_P()) {
12882 ch = forward_current(
rb_intern(
"getc"), 0, 0);
12885 ch = rb_io_getc(ARGF.current_file);
12887 if (
NIL_P(ch) && ARGF.next_p != -1) {
12915argf_getbyte(VALUE
argf)
12920 if (!next_argv())
return Qnil;
12922 ch = forward_current(
rb_intern(
"getbyte"), 0, 0);
12927 if (
NIL_P(ch) && ARGF.next_p != -1) {
12955argf_readchar(VALUE
argf)
12960 if (!next_argv()) rb_eof_error();
12962 ch = forward_current(
rb_intern(
"getc"), 0, 0);
12965 ch = rb_io_getc(ARGF.current_file);
12967 if (
NIL_P(ch) && ARGF.next_p != -1) {
12995argf_readbyte(VALUE
argf)
12999 NEXT_ARGF_FORWARD(0, 0);
13000 c = argf_getbyte(
argf);
13007#define FOREACH_ARGF() while (next_argv())
13012 const VALUE current = ARGF.current_file;
13014 if (ARGF.init_p == -1 || current != ARGF.current_file) {
13020#define ARGF_block_call(mid, argc, argv, func, argf) \
13021 rb_block_call_kw(ARGF.current_file, mid, argc, argv, \
13022 func, argf, rb_keyword_given_p())
13025argf_block_call(ID mid,
int argc, VALUE *argv, VALUE
argf)
13027 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_i,
argf);
13028 if (ret !=
Qundef) ARGF.next_p = 1;
13034 if (!global_argf_p(
argf)) {
13035 ARGF.last_lineno = ++ARGF.lineno;
13037 return argf_block_call_i(i,
argf, argc, argv, blockarg);
13041argf_block_call_line(ID mid,
int argc, VALUE *argv, VALUE
argf)
13043 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_line_i,
argf);
13044 if (ret !=
Qundef) ARGF.next_p = 1;
13088argf_each_line(
int argc, VALUE *argv, VALUE
argf)
13092 argf_block_call_line(
rb_intern(
"each_line"), argc, argv,
argf);
13119argf_each_byte(VALUE
argf)
13145argf_each_char(VALUE
argf)
13171argf_each_codepoint(VALUE
argf)
13203argf_filename(VALUE
argf)
13206 return ARGF.filename;
13210argf_filename_getter(ID
id, VALUE *var)
13212 return argf_filename(*var);
13234argf_file(VALUE
argf)
13237 return ARGF.current_file;
13252argf_binmode_m(VALUE
argf)
13256 ARGF_FORWARD(0, 0);
13275argf_binmode_p(VALUE
argf)
13277 return RBOOL(ARGF.binmode);
13295argf_skip(VALUE
argf)
13297 if (ARGF.init_p && ARGF.next_p == 0) {
13322argf_close_m(VALUE
argf)
13326 if (ARGF.next_p != -1) {
13341argf_closed(VALUE
argf)
13344 ARGF_FORWARD(0, 0);
13345 return rb_io_closed(ARGF.current_file);
13355argf_to_s(VALUE
argf)
13369argf_inplace_mode_get(VALUE
argf)
13371 if (!ARGF.inplace)
return Qnil;
13377opt_i_get(ID
id, VALUE *var)
13379 return argf_inplace_mode_get(*var);
13403argf_inplace_mode_set(VALUE
argf, VALUE val)
13409 ARGF.inplace =
Qnil;
13418opt_i_set(VALUE val, ID
id, VALUE *var)
13420 argf_inplace_mode_set(*var, val);
13424ruby_set_inplace_mode(
const char *suffix)
13444argf_argv(VALUE
argf)
13450argf_argv_getter(ID
id, VALUE *var)
13452 return argf_argv(*var);
13469argf_write_io(VALUE
argf)
13471 if (!
RTEST(ARGF.current_file)) {
13474 return GetWriteIO(ARGF.current_file);
13484argf_write(VALUE
argf, VALUE str)
13498 VALUE arg, c =
Qnil;
13501 case RB_IO_WAIT_WRITABLE:
13504 c = rb_eEAGAINWaitWritable;
13506#if EAGAIN != EWOULDBLOCK
13508 c = rb_eEWOULDBLOCKWaitWritable;
13512 c = rb_eEINPROGRESSWaitWritable;
13518 case RB_IO_WAIT_READABLE:
13521 c = rb_eEAGAINWaitReadable;
13523#if EAGAIN != EWOULDBLOCK
13525 c = rb_eEWOULDBLOCKWaitReadable;
13529 c = rb_eEINPROGRESSWaitReadable;
13536 rb_bug(
"invalid read/write type passed to rb_readwrite_sys_fail: %d", waiting);
13542get_LAST_READ_LINE(ID _x, VALUE *_y)
13548set_LAST_READ_LINE(VALUE val, ID _x, VALUE *_y)
14133#include <sys/cygwin.h>
14134 static struct __cygwin_perfile pf[] =
14136 {
"", O_RDONLY | O_BINARY},
14137 {
"", O_WRONLY | O_BINARY},
14138 {
"", O_RDWR | O_BINARY},
14139 {
"", O_APPEND | O_BINARY},
14142 cygwin_internal(CW_PERFILE, pf);
14191#if EAGAIN == EWOULDBLOCK
14192 rb_eEWOULDBLOCKWaitReadable = rb_eEAGAINWaitReadable;
14195 rb_eEWOULDBLOCKWaitWritable = rb_eEAGAINWaitWritable;
14249 rb_gvar_ractor_local(
"$_");
14353 rb_gvar_ractor_local(
"$stdin");
14354 rb_gvar_ractor_local(
"$stdout");
14355 rb_gvar_ractor_local(
"$>");
14356 rb_gvar_ractor_local(
"$stderr");
14381 rb_cARGF = rb_class_new(rb_cObject);
14443 rb_define_method(rb_cARGF,
"external_encoding", argf_external_encoding, 0);
14444 rb_define_method(rb_cARGF,
"internal_encoding", argf_internal_encoding, 0);
14447 argf = rb_class_new_instance(0, 0, rb_cARGF);
14463 rb_gvar_ractor_local(
"$-i");
14467#if defined (_WIN32) || defined(__CYGWIN__)
14468 atexit(pipe_atexit);
14480 sym_encoding =
ID2SYM(rb_id_encoding());
std::atomic< unsigned > rb_atomic_t
Type that is eligible for atomic operations.
unsigned long ruby_strtoul(const char *str, char **endptr, int base)
Our own locale-insensitive version of strtoul(3).
#define rb_define_singleton_method(klass, mid, func, arity)
Defines klass.mid.
void rb_include_module(VALUE klass, VALUE module)
Includes a module to a class.
VALUE rb_define_class(const char *name, VALUE super)
Defines a top-level class.
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
VALUE rb_define_module_under(VALUE outer, const char *name)
Defines a module under the namespace of outer.
void rb_define_alias(VALUE klass, const char *name1, const char *name2)
Defines an alias of a method.
int rb_scan_args_kw(int kw_flag, int argc, const VALUE *argv, const char *fmt,...)
Identical to rb_scan_args(), except it also accepts kw_splat.
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Retrieves argument from argc and argv to given VALUE references according to the format string.
void rb_define_method(VALUE klass, const char *name, VALUE(*func)(ANYARGS), int argc)
Defines a method.
int rb_block_given_p(void)
Determines if the current method is given a block.
int rb_get_kwargs(VALUE keyword_hash, const ID *table, int required, int optional, VALUE *values)
Keyword argument deconstructor.
void rb_define_global_function(const char *name, VALUE(*func)(ANYARGS), int argc)
Defines a global function.
#define ECONV_AFTER_OUTPUT
Old name of RUBY_ECONV_AFTER_OUTPUT.
#define rb_str_new2
Old name of rb_str_new_cstr.
#define TYPE(_)
Old name of rb_type.
#define NEWOBJ_OF
Old name of RB_NEWOBJ_OF.
#define FL_SINGLETON
Old name of RUBY_FL_SINGLETON.
#define RB_INTEGER_TYPE_P
Old name of rb_integer_type_p.
#define ENC_CODERANGE_7BIT
Old name of RUBY_ENC_CODERANGE_7BIT.
#define T_FILE
Old name of RUBY_T_FILE.
#define ENC_CODERANGE_VALID
Old name of RUBY_ENC_CODERANGE_VALID.
#define ECONV_UNIVERSAL_NEWLINE_DECORATOR
Old name of RUBY_ECONV_UNIVERSAL_NEWLINE_DECORATOR.
#define OBJ_INIT_COPY(obj, orig)
Old name of RB_OBJ_INIT_COPY.
#define ALLOC
Old name of RB_ALLOC.
#define T_STRING
Old name of RUBY_T_STRING.
#define Qundef
Old name of RUBY_Qundef.
#define INT2FIX
Old name of RB_INT2FIX.
#define T_NIL
Old name of RUBY_T_NIL.
#define UNREACHABLE
Old name of RBIMPL_UNREACHABLE.
#define ID2SYM
Old name of RB_ID2SYM.
#define T_BIGNUM
Old name of RUBY_T_BIGNUM.
#define OBJ_FREEZE
Old name of RB_OBJ_FREEZE.
#define T_FIXNUM
Old name of RUBY_T_FIXNUM.
#define UNREACHABLE_RETURN
Old name of RBIMPL_UNREACHABLE_RETURN.
#define FIX2UINT
Old name of RB_FIX2UINT.
#define SSIZET2NUM
Old name of RB_SSIZE2NUM.
#define ZALLOC
Old name of RB_ZALLOC.
#define CLASS_OF
Old name of rb_class_of.
#define rb_ary_new4
Old name of rb_ary_new_from_values.
#define ENCODING_MAXNAMELEN
Old name of RUBY_ENCODING_MAXNAMELEN.
#define MBCLEN_NEEDMORE_LEN(ret)
Old name of ONIGENC_MBCLEN_NEEDMORE_LEN.
#define ENCODING_GET(obj)
Old name of RB_ENCODING_GET.
#define LONG2FIX
Old name of RB_INT2FIX.
#define NUM2UINT
Old name of RB_NUM2UINT.
#define ALLOC_N
Old name of RB_ALLOC_N.
#define MBCLEN_CHARFOUND_LEN(ret)
Old name of ONIGENC_MBCLEN_CHARFOUND_LEN.
#define LONG2NUM
Old name of RB_LONG2NUM.
#define rb_exc_new3
Old name of rb_exc_new_str.
#define STRNCASECMP
Old name of st_locale_insensitive_strncasecmp.
#define MBCLEN_INVALID_P(ret)
Old name of ONIGENC_MBCLEN_INVALID_P.
#define ISASCII
Old name of rb_isascii.
#define ECONV_STATEFUL_DECORATOR_MASK
Old name of RUBY_ECONV_STATEFUL_DECORATOR_MASK.
#define Qtrue
Old name of RUBY_Qtrue.
#define MBCLEN_NEEDMORE_P(ret)
Old name of ONIGENC_MBCLEN_NEEDMORE_P.
#define ECONV_PARTIAL_INPUT
Old name of RUBY_ECONV_PARTIAL_INPUT.
#define NUM2INT
Old name of RB_NUM2INT.
#define ECONV_ERROR_HANDLER_MASK
Old name of RUBY_ECONV_ERROR_HANDLER_MASK.
#define INT2NUM
Old name of RB_INT2NUM.
#define Qnil
Old name of RUBY_Qnil.
#define Qfalse
Old name of RUBY_Qfalse.
#define FIX2LONG
Old name of RB_FIX2LONG.
#define ENC_CODERANGE_BROKEN
Old name of RUBY_ENC_CODERANGE_BROKEN.
#define T_ARRAY
Old name of RUBY_T_ARRAY.
#define NIL_P
Old name of RB_NIL_P.
#define ALLOCV_N
Old name of RB_ALLOCV_N.
#define MBCLEN_CHARFOUND_P(ret)
Old name of ONIGENC_MBCLEN_CHARFOUND_P.
#define NUM2CHR
Old name of RB_NUM2CHR.
#define FL_TEST
Old name of RB_FL_TEST.
#define NUM2LONG
Old name of RB_NUM2LONG.
#define UINT2NUM
Old name of RB_UINT2NUM.
#define FIXNUM_P
Old name of RB_FIXNUM_P.
#define ECONV_NEWLINE_DECORATOR_MASK
Old name of RUBY_ECONV_NEWLINE_DECORATOR_MASK.
#define CONST_ID
Old name of RUBY_CONST_ID.
#define rb_ary_new2
Old name of rb_ary_new_capa.
#define NUM2SIZET
Old name of RB_NUM2SIZE.
#define ENC_CODERANGE_SET(obj, cr)
Old name of RB_ENC_CODERANGE_SET.
#define rb_str_new4
Old name of rb_str_new_frozen.
#define ALLOCV_END
Old name of RB_ALLOCV_END.
#define SYMBOL_P
Old name of RB_SYMBOL_P.
#define ECONV_DEFAULT_NEWLINE_DECORATOR
Old name of RUBY_ECONV_DEFAULT_NEWLINE_DECORATOR.
void rb_notimplement(void)
void rb_category_warn(rb_warning_category_t cat, const char *fmt,...)
Identical to rb_category_warning(), except it reports always regardless of runtime -W flag.
void rb_raise(VALUE exc, const char *fmt,...)
Exception entry point.
void rb_category_warning(rb_warning_category_t cat, const char *fmt,...)
Identical to rb_warning(), except it takes additional "category" parameter.
VALUE rb_rescue2(VALUE(*b_proc)(VALUE), VALUE data1, VALUE(*r_proc)(VALUE, VALUE), VALUE data2,...)
An equivalent of rescue clause.
void rb_exc_raise(VALUE mesg)
Raises an exception in the current thread.
void rb_syserr_fail(int e, const char *mesg)
Raises appropriate exception that represents a C errno.
void rb_bug(const char *fmt,...)
Interpreter panic switch.
void rb_sys_fail(const char *mesg)
Converts a C errno into a Ruby exception, then raises it.
void rb_readwrite_syserr_fail(enum rb_io_wait_readwrite waiting, int n, const char *mesg)
Identical to rb_readwrite_sys_fail(), except it does not depend on C global variable errno.
VALUE rb_eIOError
IOError exception.
void rb_mod_syserr_fail_str(VALUE mod, int e, VALUE mesg)
Identical to rb_mod_syserr_fail(), except it takes the message in Ruby's String instead of C's.
void rb_syserr_fail_str(int e, VALUE mesg)
Identical to rb_syserr_fail(), except it takes the message in Ruby's String instead of C's.
#define ruby_verbose
This variable controls whether the interpreter is in debug mode.
VALUE rb_eEOFError
EOFError exception.
void rb_fatal(const char *fmt,...)
Raises the unsung "fatal" exception.
void rb_readwrite_sys_fail(enum rb_io_wait_readwrite waiting, const char *mesg)
Raises appropriate exception using the parameters.
void rb_iter_break_value(VALUE val)
Identical to rb_iter_break(), except it additionally takes the "value" of this breakage.
void rb_warn(const char *fmt,...)
Identical to rb_warning(), except it reports always regardless of runtime -W flag.
VALUE rb_ensure(VALUE(*b_proc)(VALUE), VALUE data1, VALUE(*e_proc)(VALUE), VALUE data2)
An equivalent to ensure clause.
void rb_sys_fail_str(VALUE mesg)
Identical to rb_sys_fail(), except it takes the message in Ruby's String instead of C's.
@ RB_WARN_CATEGORY_DEPRECATED
Warning is for deprecated features.
VALUE rb_mEnumerable
Enumerable module.
VALUE rb_stdin
STDIN constant.
VALUE rb_stderr
STDERR constant.
VALUE rb_mWaitReadable
IO::WaitReadable module.
VALUE rb_mWaitWritable
IO::WaitReadable module.
VALUE rb_check_to_integer(VALUE val, const char *mid)
Identical to rb_check_convert_type(), except the return value type is fixed to rb_cInteger.
VALUE rb_cFile
File class.
VALUE rb_stdout
STDOUT constant.
int rb_enc_precise_mbclen(const char *p, const char *e, rb_encoding *enc)
Queries the number of bytes of the character at the passed pointer.
int rb_to_encoding_index(VALUE obj)
Obtains a encoding index from a wider range of objects (than rb_enc_find_index()).
VALUE rb_enc_associate(VALUE obj, rb_encoding *enc)
Identical to rb_enc_associate(), except it takes an encoding itself instead of its index.
rb_encoding * rb_ascii8bit_encoding(void)
Queries the encoding that represents ASCII-8BIT a.k.a.
rb_encoding * rb_to_encoding(VALUE obj)
Identical to rb_find_encoding(), except it raises an exception instead of returning NULL.
static const char * rb_enc_name(rb_encoding *enc)
Queries the (canonical) name of the passed encoding.
rb_encoding * rb_default_internal_encoding(void)
Queries the "default internal" encoding.
static char * rb_enc_left_char_head(const char *s, const char *p, const char *e, rb_encoding *enc)
Queries the left boundary of a character.
int rb_utf8_encindex(void)
Identical to rb_utf8_encoding(), except it returns the encoding's index instead of the encoding itsel...
rb_encoding * rb_enc_get(VALUE obj)
Identical to rb_enc_get_index(), except the return type.
rb_encoding * rb_enc_from_index(int idx)
Identical to rb_find_encoding(), except it takes an encoding index instead of a Ruby object.
VALUE rb_enc_from_encoding(rb_encoding *enc)
Queries the Ruby-level counterpart instance of rb_cEncoding that corresponds to the passed encoding.
rb_encoding * rb_find_encoding(VALUE obj)
Identical to rb_to_encoding_index(), except the return type.
static bool rb_enc_asciicompat(rb_encoding *enc)
Queries if the passed encoding is in some sense compatible with ASCII.
static unsigned int rb_enc_codepoint(const char *p, const char *e, rb_encoding *enc)
Queries the code point of character pointed by the passed pointer.
rb_encoding * rb_default_external_encoding(void)
Queries the "default external" encoding.
int rb_enc_mbclen(const char *p, const char *e, rb_encoding *enc)
Queries the number of bytes of the character at the passed pointer.
rb_encoding * rb_locale_encoding(void)
Queries the encoding that represents the current locale.
rb_encoding * rb_usascii_encoding(void)
Queries the encoding that represents US-ASCII.
int rb_enc_find_index(const char *name)
Queries the index of the encoding.
static int rb_enc_mbminlen(rb_encoding *enc)
Queries the minimum number of bytes that the passed encoding needs to represent a character.
int rb_enc_ascget(const char *p, const char *e, int *len, rb_encoding *enc)
Queries the code point of character pointed by the passed pointer.
int rb_enc_str_coderange(VALUE str)
Scans the passed string to collect its code range.
VALUE rb_enc_uint_chr(unsigned int code, rb_encoding *enc)
Encodes the passed code point into a series of bytes.
VALUE rb_enc_str_new(const char *ptr, long len, rb_encoding *enc)
Identical to rb_enc_str_new(), except it additionally takes an encoding.
long rb_str_coderange_scan_restartable(const char *str, const char *end, rb_encoding *enc, int *cr)
Scans the passed string until it finds something odd.
int rb_econv_prepare_options(VALUE opthash, VALUE *ecopts, int ecflags)
Identical to rb_econv_prepare_opts(), except it additionally takes the initial value of flags.
VALUE rb_econv_open_exc(const char *senc, const char *denc, int ecflags)
Creates a rb_eConverterNotFoundError exception object (but does not raise).
rb_econv_result_t rb_econv_convert(rb_econv_t *ec, const unsigned char **source_buffer_ptr, const unsigned char *source_buffer_end, unsigned char **destination_buffer_ptr, unsigned char *destination_buffer_end, int flags)
Converts a string from an encoding to another.
@ econv_incomplete_input
The conversion stopped in middle of reading a character, possibly due to a partial read of a socket e...
@ econv_finished
The conversion stopped after converting everything.
@ econv_undefined_conversion
The conversion stopped when it found a character in the input which cannot be representable in the ou...
@ econv_source_buffer_empty
The conversion stopped because there is no input.
@ econv_destination_buffer_full
The conversion stopped because there is no destination.
@ econv_invalid_byte_sequence
The conversion stopped when it found an invalid sequence.
int rb_econv_putbackable(rb_econv_t *ec)
Queries if rb_econv_putback() makes sense, i.e.
const char * rb_econv_asciicompat_encoding(const char *encname)
Queries the passed encoding's corresponding ASCII compatible encoding.
VALUE rb_econv_str_convert(rb_econv_t *ec, VALUE src, int flags)
Identical to rb_econv_convert(), except it takes Ruby's string instead of C's pointer.
rb_econv_t * rb_econv_open_opts(const char *source_encoding, const char *destination_encoding, int ecflags, VALUE ecopts)
Identical to rb_econv_open(), except it additionally takes a hash of optional strings.
void rb_econv_binmode(rb_econv_t *ec)
This badly named function does not set the destination encoding to binary, but instead just nullifies...
VALUE rb_str_encode(VALUE str, VALUE to, int ecflags, VALUE ecopts)
Converts the contents of the passed string from its encoding to the passed one.
VALUE rb_econv_make_exception(rb_econv_t *ec)
This function makes sense right after rb_econv_convert() returns.
void rb_econv_check_error(rb_econv_t *ec)
This is a rb_econv_make_exception() + rb_exc_raise() combo.
void rb_econv_close(rb_econv_t *ec)
Destructs a converter.
void rb_econv_putback(rb_econv_t *ec, unsigned char *p, int n)
Puts back the bytes.
VALUE rb_funcall(VALUE recv, ID mid, int n,...)
Calls a method.
VALUE rb_funcallv_kw(VALUE recv, ID mid, int argc, const VALUE *argv, int kw_splat)
Identical to rb_funcallv(), except you can specify how to handle the last element of the given array.
VALUE rb_funcallv(VALUE recv, ID mid, int argc, const VALUE *argv)
Identical to rb_funcall(), except it takes the method arguments as a C array.
void rb_global_variable(VALUE *)
An alias for rb_gc_register_address().
void rb_gc_register_mark_object(VALUE object)
Inform the garbage collector that object is a live Ruby object that should not be moved.
Defines RBIMPL_HAS_BUILTIN.
VALUE rb_ary_concat(VALUE lhs, VALUE rhs)
Destructively appends the contents of latter into the end of former.
VALUE rb_ary_shift(VALUE ary)
Destructively deletes an element from the beginning of the passed array and returns what was deleted.
VALUE rb_check_array_type(VALUE obj)
Try converting an object to its array representation using its to_ary method, if any.
VALUE rb_ary_new(void)
Allocates a new, empty array.
VALUE rb_ary_push(VALUE ary, VALUE elem)
Special case of rb_ary_cat() that it adds only one element.
VALUE rb_ary_entry(VALUE ary, long off)
Queries an element of an array.
VALUE rb_assoc_new(VALUE car, VALUE cdr)
Identical to rb_ary_new_from_values(), except it expects exactly two parameters.
#define RETURN_ENUMERATOR(obj, argc, argv)
Identical to RETURN_SIZED_ENUMERATOR(), except its size is unknown.
#define rb_check_frozen
Just another name of rb_check_frozen.
static int rb_check_arity(int argc, int min, int max)
Ensures that the passed integer is in the passed range.
ID rb_frame_this_func(void)
Queries the name of the Ruby level method that is calling this function.
void rb_jump_tag(int state)
This function is to re-throw global escapes.
VALUE rb_str_encode_ospath(VALUE path)
Converts a string into an "OS Path" encoding, if any.
void rb_gc_mark(VALUE obj)
Marks an object.
void rb_gc(void)
Triggers a GC process.
VALUE rb_check_hash_type(VALUE obj)
Try converting an object to its hash representation using its to_hash method, if any.
VALUE rb_hash_lookup2(VALUE hash, VALUE key, VALUE def)
Identical to rb_hash_lookup(), except you can specify what to return on misshits.
VALUE rb_hash_aref(VALUE hash, VALUE key)
Queries the given key in the given hash table.
VALUE rb_hash_aset(VALUE hash, VALUE key, VALUE val)
Inserts or replaces ("upsert"s) the objects into the given hash table.
VALUE rb_hash_lookup(VALUE hash, VALUE key)
Identical to rb_hash_aref(), except it always returns RUBY_Qnil for misshits.
VALUE rb_hash_dup(VALUE hash)
Duplicates a hash.
VALUE rb_hash_new(void)
Creates a new, empty hash object.
VALUE rb_io_printf(int argc, const VALUE *argv, VALUE io)
This is a rb_f_sprintf() + rb_io_write() combo.
VALUE rb_io_gets(VALUE io)
Reads a "line" from the given IO.
int rb_cloexec_pipe(int fildes[2])
Opens a pipe with closing on exec.
VALUE rb_rs
The record separator character for inputs, or the $/.
VALUE rb_io_print(int argc, const VALUE *argv, VALUE io)
Iterates over the passed array to apply rb_io_write() individually.
VALUE rb_io_addstr(VALUE io, VALUE str)
Identical to rb_io_write(), except it always returns the passed IO.
void rb_write_error(const char *str)
Writes the given error message to somewhere applicable.
VALUE rb_io_ungetbyte(VALUE io, VALUE b)
Identical to rb_io_ungetc(), except it doesn't take the encoding of the passed IO into account.
VALUE rb_io_getbyte(VALUE io)
Reads a byte from the given IO.
VALUE rb_io_puts(int argc, const VALUE *argv, VALUE io)
Iterates over the passed array to apply rb_io_write() individually.
int rb_cloexec_dup2(int oldfd, int newfd)
Identical to rb_cloexec_dup(), except you can specify the destination file descriptor.
VALUE rb_io_fdopen(int fd, int flags, const char *path)
Creates an IO instance whose backend is the given file descriptor.
void rb_update_max_fd(int fd)
Informs the interpreter that the passed fd can be the max.
VALUE rb_io_write(VALUE io, VALUE str)
Writes the given string to the given IO.
int rb_cloexec_open(const char *pathname, int flags, mode_t mode)
Opens a file that closes on exec.
VALUE rb_output_rs
The record separator character for outputs, or the $\.
VALUE rb_io_eof(VALUE io)
Queries if the passed IO is at the end of file.
void rb_write_error2(const char *str, long len)
Identical to rb_write_error(), except it additionally takes the message's length.
void rb_close_before_exec(int lowfd, int maxhint, VALUE noclose_fds)
Closes everything.
int rb_reserved_fd_p(int fd)
Queries if the given FD is reserved or not.
void rb_fd_fix_cloexec(int fd)
Sets or clears the close-on-exec flag of the passed file descriptor to the desired state.
VALUE rb_io_flush(VALUE io)
Flushes any buffered data within the passed IO to the underlying operating system.
VALUE rb_io_ascii8bit_binmode(VALUE io)
Forces no conversions be applied to the passed IO.
VALUE rb_io_binmode(VALUE io)
Sets the binmode.
VALUE rb_io_ungetc(VALUE io, VALUE c)
"Unget"s a string.
int rb_pipe(int *pipes)
This is an rb_cloexec_pipe() + rb_update_max_fd() combo.
VALUE rb_gets(void)
Much like rb_io_gets(), but it reads from the mysterious ARGF object.
int rb_cloexec_fcntl_dupfd(int fd, int minfd)
Duplicates a file descriptor with closing on exec.
VALUE rb_output_fs
The field separator character for outputs, or the $,.
VALUE rb_file_open_str(VALUE fname, const char *fmode)
Identical to rb_file_open(), except it takes the pathname as a Ruby's string instead of C's.
int rb_cloexec_dup(int oldfd)
Identical to rb_cloexec_fcntl_dupfd(), except it implies minfd is 3.
VALUE rb_file_open(const char *fname, const char *fmode)
Opens a file located at the given path.
VALUE rb_io_close(VALUE io)
Closes the IO.
VALUE rb_default_rs
This is the default value of rb_rs, i.e.
void rb_lastline_set(VALUE str)
Updates $_.
VALUE rb_lastline_get(void)
Queries the last line, or the $_.
int rb_obj_method_arity(VALUE obj, ID mid)
Identical to rb_mod_method_arity(), except it searches for singleton methods rather than instance met...
VALUE rb_protect(VALUE(*func)(VALUE args), VALUE args, int *state)
Protects a function call from potential global escapes from the function.
rb_pid_t rb_waitpid(rb_pid_t pid, int *status, int flags)
Waits for a process, with releasing GVL.
void rb_last_status_set(int status, rb_pid_t pid)
Sets the "last status", or the $?.
VALUE rb_str_append(VALUE dst, VALUE src)
Identical to rb_str_buf_append(), except it converts the right hand side before concatenating.
VALUE rb_str_buf_cat(VALUE, const char *, long)
Just another name of rb_str_cat.
size_t rb_str_capacity(VALUE str)
Queries the capacity of the given string.
VALUE rb_str_new_frozen(VALUE str)
Creates a frozen copy of the string, if necessary.
VALUE rb_str_cat2(VALUE, const char *)
Just another name of rb_str_cat_cstr.
VALUE rb_str_dup(VALUE str)
Duplicates a string.
void rb_str_modify(VALUE str)
Declares that the string is about to be modified.
VALUE rb_str_cat(VALUE dst, const char *src, long srclen)
Destructively appends the passed contents to the string.
VALUE rb_str_locktmp(VALUE str)
Obtains a "temporary lock" of the string.
VALUE rb_usascii_str_new(const char *ptr, long len)
Identical to rb_str_new(), except it generates a string of "US ASCII" encoding.
rb_gvar_setter_t rb_str_setter
This is a rb_gvar_setter_t that refutes non-string assignments.
void rb_str_set_len(VALUE str, long len)
Overwrites the length of the string.
VALUE rb_str_buf_cat_ascii(VALUE dst, const char *src)
Identical to rb_str_cat_cstr(), except it additionally assumes the source string be a NUL terminated ...
VALUE rb_str_new(const char *ptr, long len)
Allocates an instance of rb_cString.
VALUE rb_check_string_type(VALUE obj)
Try converting an object to its stringised representation using its to_str method,...
VALUE rb_str_substr(VALUE str, long beg, long len)
This is the implementation of two-argumented String#slice.
VALUE rb_str_unlocktmp(VALUE str)
Releases a lock formerly obtained by rb_str_locktmp().
VALUE rb_str_new_cstr(const char *ptr)
Identical to rb_str_new(), except it assumes the passed pointer is a pointer to a C string.
VALUE rb_str_resize(VALUE str, long len)
Overwrites the length of the string.
void rb_str_modify_expand(VALUE str, long capa)
Identical to rb_str_modify(), except it additionally expands the capacity of the receiver.
VALUE rb_str_buf_new(long capa)
Allocates a "string buffer".
VALUE rb_obj_as_string(VALUE obj)
Try converting an object to its stringised representation using its to_s method, if any.
int rb_thread_interrupted(VALUE thval)
Checks if the thread's execution was recently interrupted.
VALUE rb_mutex_new(void)
Creates a mutex.
int rb_thread_fd_writable(int fd)
Identical to rb_thread_wait_fd(), except it blocks the current thread until the given file descriptor...
#define RUBY_UBF_IO
A special UBF for blocking IO operations.
VALUE rb_exec_recursive(VALUE(*f)(VALUE g, VALUE h, int r), VALUE g, VALUE h)
"Recursion" API entry point.
void rb_thread_fd_close(int fd)
Notifies a closing of a file descriptor to other threads.
VALUE rb_mutex_synchronize(VALUE mutex, VALUE(*func)(VALUE arg), VALUE arg)
Obtains the lock, runs the passed function, and releases the lock when it completes.
void rb_thread_check_ints(void)
Checks for interrupts.
VALUE rb_thread_current(void)
Obtains the "current" thread.
int rb_thread_wait_fd(int fd)
Blocks the current thread until the given file descriptor is ready to be read.
void rb_thread_schedule(void)
Tries to switch to another thread.
void rb_thread_sleep(int sec)
Blocks for the given period of time.
struct timeval rb_time_interval(VALUE num)
Creates a "time interval".
VALUE rb_attr_get(VALUE obj, ID name)
Identical to rb_ivar_get()
void rb_set_class_path(VALUE klass, VALUE space, const char *name)
Names a class.
VALUE rb_ivar_set(VALUE obj, ID name, VALUE val)
Identical to rb_iv_set(), except it accepts the name as an ID instead of a C string.
VALUE rb_class_name(VALUE obj)
Queries the name of the given object's class.
int rb_respond_to(VALUE obj, ID mid)
Queries if the object responds to the method.
int rb_method_basic_definition_p(VALUE klass, ID mid)
Well... Let us hesitate from describing what a "basic definition" is.
VALUE rb_check_funcall(VALUE recv, ID mid, int argc, const VALUE *argv)
Identical to rb_funcallv(), except it returns RUBY_Qundef instead of raising rb_eNoMethodError.
void rb_define_alloc_func(VALUE klass, rb_alloc_func_t func)
Sets the allocator function of a class.
static ID rb_intern_const(const char *str)
This is a "tiny optimisation" over rb_intern().
ID rb_intern(const char *name)
Finds or creates a symbol of the given name.
const char * rb_id2name(ID id)
Retrieves the name mapped to the given id.
VALUE rb_id2str(ID id)
Identical to rb_id2name(), except it returns a Ruby's String instead of C's.
void rb_define_global_const(const char *name, VALUE val)
Identical to rb_define_const(), except it defines that of "global", i.e.
void rb_define_readonly_variable(const char *name, const VALUE *var)
Identical to rb_define_variable(), except it does not allow Ruby programs to assign values to such gl...
rb_gvar_setter_t rb_gvar_readonly_setter
This function just raises rb_eNameError.
void rb_define_virtual_variable(const char *name, rb_gvar_getter_t *getter, rb_gvar_setter_t *setter)
Defines a global variable that is purely function-backended.
void rb_define_const(VALUE klass, const char *name, VALUE val)
Defines a Ruby level constant under a namespace.
void rb_define_hooked_variable(const char *name, VALUE *var, rb_gvar_getter_t *getter, rb_gvar_setter_t *setter)
Identical to rb_define_virtual_variable(), but can also specify a storage.
#define FMODE_READABLE
The IO is opened for reading.
int rb_io_modestr_fmode(const char *modestr)
Maps a file mode string (that rb_file_open() takes) into a mixture of FMODE_ flags.
VALUE rb_io_get_io(VALUE io)
Identical to rb_io_check_io(), except it raises exceptions on conversion failures.
VALUE rb_io_taint_check(VALUE obj)
void rb_io_read_check(rb_io_t *fptr)
Blocks until there is a pending read in the passed IO.
int rb_io_modestr_oflags(const char *modestr)
Identical to rb_io_modestr_fmode(), except it returns a mixture of O_ flags.
#define FMODE_SETENC_BY_BOM
This flag amends the encoding of the IO so that the BOM of the contents of the IO takes effect.
#define FMODE_READWRITE
The IO is opened for both read/write.
#define GetOpenFile
This is an old name of RB_IO_POINTER.
void rb_io_check_byte_readable(rb_io_t *fptr)
Asserts that an IO is opened for byte-based reading.
#define FMODE_TTY
The IO is a TTY.
#define FMODE_CREATE
The IO is opened for creating.
void rb_io_check_readable(rb_io_t *fptr)
Just another name of rb_io_check_byte_readable.
int rb_io_extract_encoding_option(VALUE opt, rb_encoding **enc_p, rb_encoding **enc2_p, int *fmode_p)
This function breaks down the option hash that IO#initialize takes into components.
struct rb_io_t rb_io_t
Ruby's IO, metadata and buffers.
int rb_wait_for_single_fd(int fd, int events, struct timeval *tv)
Blocks until the passed file descriptor is ready for the passed events.
struct rb_io_enc_t rb_io_enc_t
Just another name of rb_io_enc_t.
FILE * rb_fdopen(int fd, const char *modestr)
Identical to rb_io_stdio_file(), except it takes file descriptors instead of Ruby's IO.
int rb_io_descriptor(VALUE io)
Returns an integer representing the numeric file descriptor for io.
#define FMODE_WRITABLE
The IO is opened for writing.
FILE * rb_io_stdio_file(rb_io_t *fptr)
Finds or creates a stdio's file structure from a Ruby's one.
#define FMODE_APPEND
The IO is opened for appending.
#define MakeOpenFile
This is an old name of RB_IO_OPEN.
#define FMODE_DUPLEX
Ruby eventually detects that the IO is bidirectional.
#define FMODE_BINMODE
The IO is in "binary mode".
int rb_io_maybe_wait_readable(int error, VALUE io, VALUE timeout)
Blocks until the passed IO is ready for reading, if that makes sense for the passed errno.
#define RB_IO_POINTER(obj, fp)
Queries the underlying IO pointer.
VALUE rb_io_maybe_wait(int error, VALUE io, VALUE events, VALUE timeout)
Identical to rb_io_wait() except it additionally takes previous errno.
#define FMODE_SYNC
The IO is in "sync mode".
void rb_io_check_initialized(rb_io_t *fptr)
Asserts that the passed IO is initialised.
#define FMODE_EXCL
This flag amends the effect of FMODE_CREATE, so that if there already is a file at the given path the...
#define FMODE_TEXTMODE
The IO is in "text mode".
int rb_io_fptr_finalize(rb_io_t *fptr)
Destroys the given IO.
VALUE rb_io_check_io(VALUE io)
Try converting an object to its IO representation using its to_io method, if any.
ssize_t rb_io_bufwrite(VALUE io, const void *buf, size_t size)
Buffered write to the passed IO.
void rb_io_check_char_readable(rb_io_t *fptr)
Asserts that an IO is opened for character-based reading.
#define FMODE_TRUNC
This flag amends the effect of FMODE_CREATE, so that if there already is a file at the given path it ...
VALUE rb_io_get_write_io(VALUE io)
Queries the tied IO for writing.
void rb_io_set_nonblock(rb_io_t *fptr)
Sets an IO to a "nonblock mode".
void rb_io_extract_modeenc(VALUE *vmode_p, VALUE *vperm_p, VALUE opthash, int *oflags_p, int *fmode_p, rb_io_enc_t *convconfig_p)
This function can be seen as an extended version of rb_io_extract_encoding_option() that not only con...
int rb_io_wait_writable(int fd)
Blocks until the passed file descriptor gets writable.
VALUE rb_io_set_write_io(VALUE io, VALUE w)
Assigns the tied IO for writing.
void rb_io_check_writable(rb_io_t *fptr)
Asserts that an IO is opened for writing.
int rb_io_maybe_wait_writable(int error, VALUE io, VALUE timeout)
Blocks until the passed IO is ready for writing, if that makes sense for the passed errno.
void rb_io_check_closed(rb_io_t *fptr)
This badly named function asserts that the passed IO is open.
@ RUBY_IO_READABLE
IO::READABLE
@ RUBY_IO_PRIORITY
IO::PRIORITY
@ RUBY_IO_WRITABLE
IO::WRITABLE
int rb_io_wait_readable(int fd)
Blocks until the passed file descriptor gets readable.
void rb_io_synchronized(rb_io_t *fptr)
Sets FMODE_SYNC.
VALUE rb_io_wait(VALUE io, VALUE events, VALUE timeout)
Blocks until the passed IO is ready for the passed events.
void * rb_thread_call_with_gvl(void *(*func)(void *), void *data1)
(Re-)acquires the GVL.
void * rb_thread_call_without_gvl2(void *(*func)(void *), void *data1, rb_unblock_function_t *ubf, void *data2)
Identical to rb_thread_call_without_gvl(), except it does not interface with signals etc.
void * rb_thread_call_without_gvl(void *(*func)(void *), void *data1, rb_unblock_function_t *ubf, void *data2)
Allows the passed function to run in parallel with other Ruby threads.
#define RB_NUM2INT
Just another name of rb_num2int_inline.
#define RB_INT2NUM
Just another name of rb_int2num_inline.
VALUE rb_f_sprintf(int argc, const VALUE *argv)
Identical to rb_str_format(), except how the arguments are arranged.
VALUE rb_sprintf(const char *fmt,...)
Ruby's extended sprintf(3).
VALUE rb_str_catf(VALUE dst, const char *fmt,...)
Identical to rb_sprintf(), except it renders the output to the specified object rather than creating ...
#define RB_BLOCK_CALL_FUNC_ARGLIST(yielded_arg, callback_arg)
Shim for block function parameters.
VALUE rb_yield_values2(int n, const VALUE *argv)
Identical to rb_yield_values(), except it takes the parameters as a C array instead of variadic argum...
VALUE rb_yield(VALUE val)
Yields the block.
int rb_fd_select(int nfds, rb_fdset_t *rfds, rb_fdset_t *wfds, rb_fdset_t *efds, struct timeval *timeout)
Waits for multiple file descriptors at once.
int rb_fd_isset(int fd, const rb_fdset_t *f)
Queries if the given FD is in the given set.
void rb_fd_term(rb_fdset_t *f)
Destroys the rb_fdset_t, releasing any memory and resources it used.
#define MEMZERO(p, type, n)
Handy macro to erase a region of memory.
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
#define MEMMOVE(p1, p2, type, n)
Handy macro to call memmove.
#define NUM2MODET
Converts a C's mode_t into an instance of rb_cInteger.
#define PRI_OFFT_PREFIX
A rb_sprintf() format prefix to be used for an off_t parameter.
#define OFFT2NUM
Converts a C's off_t into an instance of rb_cInteger.
#define NUM2OFFT
Converts an instance of rb_cNumeric into C's off_t.
#define PIDT2NUM
Converts a C's pid_t into an instance of rb_cInteger.
#define rb_fd_init
Initialises the :given :rb_fdset_t.
#define rb_fd_set
Sets the given fd to the rb_fdset_t.
VALUE rb_ractor_stderr(void)
Queries the standard error of the current Ractor that is calling this function.
VALUE rb_ractor_stdin(void)
Queries the standard input of the current Ractor that is calling this function.
void rb_ractor_stderr_set(VALUE io)
Assigns an IO to the standard error of the Ractor that is calling this function.
VALUE rb_ractor_stdout(void)
Queries the standard output of the current Ractor that is calling this function.
void rb_ractor_stdout_set(VALUE io)
Assigns an IO to the standard output of the Ractor that is calling this function.
void rb_ractor_stdin_set(VALUE io)
Assigns an IO to the standard input of the Ractor that is calling this function.
#define RARRAY_LEN
Just another name of rb_array_len.
static int RARRAY_LENINT(VALUE ary)
Identical to rb_array_len(), except it differs for the return type.
#define RARRAY_AREF(a, i)
#define RARRAY_CONST_PTR
Just another name of rb_array_const_ptr.
#define RFILE(obj)
Convenient casting macro.
#define SafeStringValue(v)
#define StringValue(v)
Ensures that the parameter object is a String.
static char * RSTRING_END(VALUE str)
Queries the end of the contents pointer of the string.
#define RSTRING_GETMEM(str, ptrvar, lenvar)
Convenient macro to obtain the contents and length at once.
static long RSTRING_LEN(VALUE str)
Queries the length of the string.
static char * RSTRING_PTR(VALUE str)
Queries the contents pointer of the string.
#define StringValueCStr(v)
Identical to StringValuePtr, except it additionally checks for the contents for viability as a C stri...
#define RUBY_TYPED_DEFAULT_FREE
This is a value you can set to rb_data_type_struct::dfree.
#define TypedData_Make_Struct(klass, type, data_type, sval)
Identical to TypedData_Wrap_Struct, except it allocates a new data region internally instead of takin...
VALUE rb_get_argv(void)
Queries the arguments passed to the current process that you can access from Ruby as ARGV.
void rb_p(VALUE obj)
Inspects an object.
#define FilePathValue(v)
Ensures that the parameter object is a path.
#define RB_SCAN_ARGS_LAST_HASH_KEYWORDS
Treat a final argument as keywords if it is a hash, and not as keywords otherwise.
#define RB_PASS_CALLED_KEYWORDS
Pass keywords if current method is called with keywords, useful for argument delegation.
VALUE rb_fiber_scheduler_current(void)
Identical to rb_fiber_scheduler_get(), except it also returns RUBY_Qnil in case of a blocking fiber.
VALUE rb_fiber_scheduler_make_timeout(struct timeval *timeout)
Converts the passed timeout to an expression that rb_fiber_scheduler_block() etc.
VALUE rb_fiber_scheduler_io_wait_readable(VALUE scheduler, VALUE io)
Nonblocking wait until the passed IO is ready for reading.
VALUE rb_fiber_scheduler_io_wait(VALUE scheduler, VALUE io, VALUE events, VALUE timeout)
Nonblocking version of rb_io_wait().
static ssize_t rb_fiber_scheduler_io_result_apply(VALUE result)
Apply an io result to the local thread, returning the value of the original system call that created ...
VALUE rb_fiber_scheduler_current_for_thread(VALUE thread)
Identical to rb_fiber_scheduler_current(), except it queries for that of the passed thread instead of...
VALUE rb_fiber_scheduler_io_wait_writable(VALUE scheduler, VALUE io)
Nonblocking wait until the passed IO is ready for writing.
VALUE rb_fiber_scheduler_io_write_memory(VALUE scheduler, VALUE io, const void *buffer, size_t size, size_t length)
Nonblocking write to the passed IO using a native buffer.
VALUE rb_fiber_scheduler_io_read_memory(VALUE scheduler, VALUE io, void *buffer, size_t size, size_t length)
Nonblocking read from the passed IO using a native buffer.
int rb_thread_fd_select(int nfds, rb_fdset_t *rfds, rb_fdset_t *wfds, rb_fdset_t *efds, struct timeval *timeout)
Waits for multiple file descriptors at once.
#define RTEST
This is an old name of RB_TEST.
#define _(args)
This was a transition path from K&R to ANSI.
This is the struct that holds necessary info for a struct.
The data structure which wraps the fd_set bitmap used by select(2).
int len
Length of the buffer.
char * ptr
Pointer to the underlying memory region, of at least capa bytes.
int off
Offset inside of ptr.
int capa
Designed capacity of the buffer.
rb_encoding * enc
Internal encoding.
rb_encoding * enc2
External encoding.
VALUE ecopts
Flags as Ruby hash.
Ruby's IO, metadata and buffers.
struct rb_io_t::rb_io_enc_t encs
Decomposed encoding flags.
int lineno
number of lines read
rb_econv_t * writeconv
Encoding converter used when writing to this IO.
rb_pid_t pid
child's pid (for pipes)
rb_io_buffer_t wbuf
Write buffer.
rb_econv_t * readconv
Encoding converter used when reading from this IO.
VALUE writeconv_asciicompat
This is, when set, an instance of rb_cString which holds the "common" encoding.
FILE * stdio_file
stdio ptr for read/write, if available.
int writeconv_initialized
Whether rb_io_t::writeconv is already set up.
VALUE pathv
pathname for file
int mode
mode flags: FMODE_XXXs
int writeconv_pre_ecflags
Value of rb_io_t::rb_io_enc_t::ecflags stored right before initialising rb_io_t::writeconv.
VALUE write_lock
This is a Ruby level mutex.
rb_io_buffer_t cbuf
rb_io_ungetc() destination.
VALUE self
The IO's Ruby level counterpart.
VALUE writeconv_pre_ecopts
Value of rb_io_t::rb_io_enc_t::ecopts stored right before initialising rb_io_t::writeconv.
VALUE tied_io_for_writing
Duplex IO object, if set.
void(* finalize)(struct rb_io_t *, int)
finalize proc
rb_io_buffer_t rbuf
(Byte) read buffer.
intptr_t SIGNED_VALUE
A signed integer type that has the same width with VALUE.
uintptr_t VALUE
Type that represents a Ruby object.
static void Check_Type(VALUE v, enum ruby_value_type t)
Identical to RB_TYPE_P(), except it raises exceptions on predication failure.
static bool RB_TYPE_P(VALUE obj, enum ruby_value_type t)
Queries if the given object is of given type.