14#include "ruby/internal/config.h"
25# if defined(__linux__)
28# if defined(__FreeBSD_version) && __FreeBSD_version >= 1100000
38#define free(x) xfree(x)
40#if defined(DOSISH) || defined(__CYGWIN__)
45#if defined HAVE_NET_SOCKET_H
46# include <net/socket.h>
47#elif defined HAVE_SYS_SOCKET_H
48# include <sys/socket.h>
51#if defined(__BOW__) || defined(__CYGWIN__) || defined(_WIN32)
52# define NO_SAFE_RENAME
55#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__sun) || defined(_nec_ews)
64#if defined(HAVE_SYS_IOCTL_H) && !defined(_WIN32)
67#if defined(HAVE_FCNTL_H) || defined(_WIN32)
69#elif defined(HAVE_SYS_FCNTL_H)
79#if defined(HAVE_SYS_PARAM_H) || defined(__HIUX_MPP__)
80# include <sys/param.h>
93#elif defined HAVE_SYS_SYSCALL_H
94#include <sys/syscall.h>
101#ifdef HAVE_SYS_WAIT_H
102# include <sys/wait.h>
105#ifdef HAVE_COPYFILE_H
106# include <copyfile.h>
110#include "ccan/list/list.h"
115#include "internal/encoding.h"
116#include "internal/error.h"
117#include "internal/inits.h"
118#include "internal/io.h"
119#include "internal/numeric.h"
120#include "internal/object.h"
121#include "internal/process.h"
122#include "internal/thread.h"
123#include "internal/transcode.h"
124#include "internal/variable.h"
127#include "ruby/missing.h"
130#include "ruby_atomic.h"
140#define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR)
144# ifdef _POSIX_PIPE_BUF
145# define PIPE_BUF _POSIX_PIPE_BUF
152# define EWOULDBLOCK EAGAIN
155#if defined(HAVE___SYSCALL) && (defined(__APPLE__) || defined(__OpenBSD__))
157off_t __syscall(quad_t number, ...);
160#define IO_RBUF_CAPA_MIN 8192
161#define IO_CBUF_CAPA_MIN (128*1024)
162#define IO_RBUF_CAPA_FOR(fptr) (NEED_READCONV(fptr) ? IO_CBUF_CAPA_MIN : IO_RBUF_CAPA_MIN)
163#define IO_WBUF_CAPA_MIN 8192
165#define IO_MAX_BUFFER_GROWTH 8 * 1024 * 1024
170#define open rb_w32_uopen
172#define rename(f, t) rb_w32_urename((f), (t))
173#include "win32/file.h"
183static VALUE rb_eEAGAINWaitReadable;
184static VALUE rb_eEAGAINWaitWritable;
185static VALUE rb_eEWOULDBLOCKWaitReadable;
186static VALUE rb_eEWOULDBLOCKWaitWritable;
187static VALUE rb_eEINPROGRESSWaitWritable;
188static VALUE rb_eEINPROGRESSWaitReadable;
191static VALUE orig_stdout, orig_stderr;
200static ID id_write, id_read, id_getc, id_flush, id_readpartial, id_set_encoding, id_fileno;
201static VALUE sym_mode, sym_perm, sym_flags, sym_extenc, sym_intenc, sym_encoding, sym_open_args;
202static VALUE sym_textmode, sym_binmode, sym_autoclose;
203static VALUE sym_SET, sym_CUR, sym_END;
204static VALUE sym_wait_readable, sym_wait_writable;
206static VALUE sym_DATA;
209static VALUE sym_HOLE;
212static VALUE prep_io(
int fd,
int fmode,
VALUE klass,
const char *path);
215 VALUE filename, current_file;
221 int8_t init_p, next_p, binmode;
232 if (fd < 0 || afd <= max_fd)
235#if defined(HAVE_FCNTL) && defined(F_GETFL)
236 err = fcntl(fd, F_GETFL) == -1;
240 err = fstat(fd, &buf) != 0;
243 if (err &&
errno == EBADF) {
244 rb_bug(
"rb_update_max_fd: invalid fd (%d) given.", fd);
247 while (max_fd < afd) {
248 max_fd = ATOMIC_CAS(max_file_descriptor, max_fd, afd);
253rb_maygvl_fd_fix_cloexec(
int fd)
256#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
257 int flags, flags2, ret;
258 flags = fcntl(fd, F_GETFD);
260 rb_bug(
"rb_maygvl_fd_fix_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(
errno));
263 flags2 = flags & ~FD_CLOEXEC;
265 flags2 = flags | FD_CLOEXEC;
266 if (flags != flags2) {
267 ret = fcntl(fd, F_SETFD, flags2);
269 rb_bug(
"rb_maygvl_fd_fix_cloexec: fcntl(%d, F_SETFD, %d) failed: %s", fd, flags2, strerror(
errno));
278 rb_maygvl_fd_fix_cloexec(fd);
284rb_fix_detect_o_cloexec(
int fd)
286#if defined(O_CLOEXEC) && defined(F_GETFD)
287 int flags = fcntl(fd, F_GETFD);
290 rb_bug(
"rb_fix_detect_o_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(
errno));
292 if (flags & FD_CLOEXEC)
295 rb_maygvl_fd_fix_cloexec(fd);
302 return (e == EWOULDBLOCK) || (e == EAGAIN);
309 static int o_cloexec_state = -1;
311 static const int retry_interval = 0;
312 static const int retry_max_count = 10000;
319#elif defined O_NOINHERIT
320 flags |= O_NOINHERIT;
323 while ((ret = open(pathname, flags, mode)) == -1) {
325 if (!io_again_p(e))
break;
326 if (retry_count++ >= retry_max_count)
break;
328 sleep(retry_interval);
331 if (ret < 0)
return ret;
332 if (ret <= 2 || o_cloexec_state == 0) {
333 rb_maygvl_fd_fix_cloexec(ret);
335 else if (o_cloexec_state > 0) {
339 o_cloexec_state = rb_fix_detect_o_cloexec(ret);
358 if (oldfd == newfd) {
362#if defined(HAVE_DUP3) && defined(O_CLOEXEC)
363 static int try_dup3 = 1;
364 if (2 < newfd && try_dup3) {
365 ret = dup3(oldfd, newfd, O_CLOEXEC);
369 if (
errno == ENOSYS) {
371 ret = dup2(oldfd, newfd);
375 ret = dup2(oldfd, newfd);
378 ret = dup2(oldfd, newfd);
380 if (ret < 0)
return ret;
382 rb_maygvl_fd_fix_cloexec(ret);
387rb_fd_set_nonblock(
int fd)
390 return rb_w32_set_nonblock(fd);
391#elif defined(F_GETFL)
392 int oflags = fcntl(fd, F_GETFL);
396 if (oflags & O_NONBLOCK)
398 oflags |= O_NONBLOCK;
399 return fcntl(fd, F_SETFL, oflags);
408 int result = pipe2(descriptors, O_CLOEXEC | O_NONBLOCK);
410 int result = pipe(descriptors);
417 if (result == 0 && descriptors[1] == -1) {
418 close(descriptors[0]);
426 rb_maygvl_fd_fix_cloexec(descriptors[0]);
427 rb_maygvl_fd_fix_cloexec(descriptors[1]);
430 rb_fd_set_nonblock(descriptors[0]);
431 rb_fd_set_nonblock(descriptors[1]);
443#if defined(HAVE_FCNTL) && defined(F_DUPFD_CLOEXEC) && defined(F_DUPFD)
444 static int try_dupfd_cloexec = 1;
445 if (try_dupfd_cloexec) {
446 ret = fcntl(fd, F_DUPFD_CLOEXEC, minfd);
449 rb_maygvl_fd_fix_cloexec(ret);
453 if (
errno == EINVAL) {
454 ret = fcntl(fd, F_DUPFD, minfd);
456 try_dupfd_cloexec = 0;
461 ret = fcntl(fd, F_DUPFD, minfd);
463#elif defined(HAVE_FCNTL) && defined(F_DUPFD)
464 ret = fcntl(fd, F_DUPFD, minfd);
467 if (ret >= 0 && ret < minfd) {
468 const int prev_fd = ret;
474 if (ret < 0)
return ret;
475 rb_maygvl_fd_fix_cloexec(ret);
479#define argf_of(obj) (*(struct argf *)DATA_PTR(obj))
480#define ARGF argf_of(argf)
482#define GetWriteIO(io) rb_io_get_write_io(io)
484#define READ_DATA_PENDING(fptr) ((fptr)->rbuf.len)
485#define READ_DATA_PENDING_COUNT(fptr) ((fptr)->rbuf.len)
486#define READ_DATA_PENDING_PTR(fptr) ((fptr)->rbuf.ptr+(fptr)->rbuf.off)
487#define READ_DATA_BUFFERED(fptr) READ_DATA_PENDING(fptr)
489#define READ_CHAR_PENDING(fptr) ((fptr)->cbuf.len)
490#define READ_CHAR_PENDING_COUNT(fptr) ((fptr)->cbuf.len)
491#define READ_CHAR_PENDING_PTR(fptr) ((fptr)->cbuf.ptr+(fptr)->cbuf.off)
494#define WAIT_FD_IN_WIN32(fptr) \
495 (rb_w32_io_cancelable_p((fptr)->fd) ? Qnil : rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_READABLE), RUBY_IO_TIMEOUT_DEFAULT))
497#define WAIT_FD_IN_WIN32(fptr)
500#define READ_CHECK(fptr) do {\
501 if (!READ_DATA_PENDING(fptr)) {\
502 WAIT_FD_IN_WIN32(fptr);\
503 rb_io_check_closed(fptr);\
509# define S_ISSOCK(m) _S_ISSOCK(m)
512# define S_ISSOCK(m) (((m) & S_IFMT) == _S_IFSOCK)
515# define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
521static int io_fflush(
rb_io_t *);
524#define FMODE_SIGNAL_ON_EPIPE (1<<17)
526#define fptr_signal_on_epipe(fptr) \
527 (((fptr)->mode & FMODE_SIGNAL_ON_EPIPE) != 0)
529#define fptr_set_signal_on_epipe(fptr, flag) \
531 (fptr)->mode |= FMODE_SIGNAL_ON_EPIPE : \
532 (fptr)->mode &= ~FMODE_SIGNAL_ON_EPIPE)
534extern ID ruby_static_id_signo;
536NORETURN(
static void raise_on_write(
rb_io_t *fptr,
int e,
VALUE errinfo));
541 if (fptr_signal_on_epipe(fptr) && (e == EPIPE)) {
550 rb_exc_raise(errinfo);
553#define rb_sys_fail_on_write(fptr) \
556 raise_on_write(fptr, e, rb_syserr_new_path(e, (fptr)->pathv)); \
559#define NEED_NEWLINE_DECORATOR_ON_READ(fptr) ((fptr)->mode & FMODE_TEXTMODE)
560#define NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) ((fptr)->mode & FMODE_TEXTMODE)
561#if defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32)
562# define RUBY_CRLF_ENVIRONMENT 1
564# define RUBY_CRLF_ENVIRONMENT 0
567#if RUBY_CRLF_ENVIRONMENT
569# define DEFAULT_TEXTMODE FMODE_TEXTMODE
570# define TEXTMODE_NEWLINE_DECORATOR_ON_WRITE ECONV_CRLF_NEWLINE_DECORATOR
578#define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || (fptr)->encs.ecflags & ~ECONV_CRLF_NEWLINE_DECORATOR)
579#define WRITECONV_MASK ( \
580 (ECONV_DECORATOR_MASK & ~ECONV_CRLF_NEWLINE_DECORATOR)|\
581 ECONV_STATEFUL_DECORATOR_MASK|\
583#define NEED_WRITECONV(fptr) ( \
584 ((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || \
585 ((fptr)->encs.ecflags & WRITECONV_MASK) || \
587#define SET_BINARY_MODE(fptr) setmode((fptr)->fd, O_BINARY)
589#define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) do {\
590 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {\
591 if (((fptr)->mode & FMODE_READABLE) &&\
592 !((fptr)->encs.ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {\
593 setmode((fptr)->fd, O_BINARY);\
596 setmode((fptr)->fd, O_TEXT);\
601#define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) do {\
602 if ((enc2) && ((ecflags) & ECONV_DEFAULT_NEWLINE_DECORATOR)) {\
603 (ecflags) |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;\
627 if (!rb_w32_fd_is_text(fptr->
fd)) {
628 r = lseek(fptr->
fd, -fptr->
rbuf.
len, SEEK_CUR);
629 if (r < 0 &&
errno) {
640 pos = lseek(fptr->
fd, 0, SEEK_CUR);
641 if (pos < 0 &&
errno) {
648 extra_max = (long)(pos - fptr->
rbuf.
len);
656 for (i = 0; i < fptr->
rbuf.
len; i++) {
657 if (*p ==
'\n') newlines++;
658 if (extra_max == newlines)
break;
663 while (newlines >= 0) {
664 r = lseek(fptr->
fd, pos - fptr->
rbuf.
len - newlines, SEEK_SET);
665 if (newlines == 0)
break;
670 read_size = _read(fptr->
fd, buf, fptr->
rbuf.
len + newlines);
674 rb_syserr_fail_path(e, fptr->
pathv);
676 if (read_size == fptr->
rbuf.
len) {
677 lseek(fptr->
fd, r, SEEK_SET);
698set_binary_mode_with_seek_cur(
rb_io_t *fptr)
700 if (!rb_w32_fd_is_text(fptr->
fd))
return O_BINARY;
703 return setmode(fptr->
fd, O_BINARY);
705 flush_before_seek(fptr);
706 return setmode(fptr->
fd, O_BINARY);
708#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) set_binary_mode_with_seek_cur(fptr)
712# define DEFAULT_TEXTMODE 0
713#define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || NEED_NEWLINE_DECORATOR_ON_READ(fptr))
714#define NEED_WRITECONV(fptr) ( \
715 ((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || \
716 NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) || \
717 ((fptr)->encs.ecflags & (ECONV_DECORATOR_MASK|ECONV_STATEFUL_DECORATOR_MASK)) || \
719#define SET_BINARY_MODE(fptr) (void)(fptr)
720#define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) (void)(fptr)
721#define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) ((void)(enc2), (void)(ecflags))
722#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) (void)(fptr)
725#if !defined HAVE_SHUTDOWN && !defined shutdown
726#define shutdown(a,b) 0
730#define is_socket(fd, path) rb_w32_is_socket(fd)
731#elif !defined(S_ISSOCK)
732#define is_socket(fd, path) 0
735is_socket(
int fd,
VALUE path)
738 if (fstat(fd, &sbuf) < 0)
739 rb_sys_fail_path(path);
740 return S_ISSOCK(sbuf.st_mode);
744static const char closed_stream[] =
"closed stream";
747io_fd_check_closed(
int fd)
780 io_fd_check_closed(fptr->
fd);
784rb_io_get_fptr(
VALUE io)
794 return rb_convert_type_with_id(io,
T_FILE,
"IO", idTo_io);
800 return rb_check_convert_type_with_id(io,
T_FILE,
"IO", idTo_io);
818 rb_io_t *fptr = rb_io_get_fptr(io);
827 return write_io ? write_io :
Qnil;
840 rb_io_t *fptr = rb_io_get_fptr(self);
870 if (
RTEST(timeout)) {
874 rb_io_t *fptr = rb_io_get_fptr(self);
899#if !RUBY_CRLF_ENVIRONMENT
909 r = lseek(fptr->
fd, -fptr->
rbuf.
len, SEEK_CUR);
910 if (r < 0 &&
errno) {
926 long len = RSTRING_LEN(str);
929 const int min_capa = IO_RBUF_CAPA_FOR(fptr);
932#if SIZEOF_LONG > SIZEOF_INT
957flush_before_seek(
rb_io_t *fptr)
959 if (io_fflush(fptr) < 0)
960 rb_sys_fail_on_write(fptr);
966#define io_seek(fptr, ofs, whence) (errno = 0, lseek(flush_before_seek(fptr)->fd, (ofs), (whence)))
967#define io_tell(fptr) lseek(flush_before_seek(fptr)->fd, 0, SEEK_CUR)
983 if (io_fflush(fptr) < 0)
984 rb_sys_fail_on_write(fptr);
989 if (io_fflush(wfptr) < 0)
990 rb_sys_fail_on_write(wfptr);
998 if (READ_CHAR_PENDING(fptr)) {
999 rb_raise(
rb_eIOError,
"byte oriented read for character buffered IO");
1010io_read_encoding(
rb_io_t *fptr)
1015 return rb_default_external_encoding();
1019io_input_encoding(
rb_io_t *fptr)
1024 return io_read_encoding(fptr);
1040rb_io_read_pending(
rb_io_t *fptr)
1043 if (READ_CHAR_PENDING(fptr))
1045 return READ_DATA_PENDING(fptr);
1051 if (!READ_DATA_PENDING(fptr)) {
1058rb_gc_for_fd(
int err)
1060 if (err == EMFILE || err == ENFILE || err == ENOMEM) {
1070#define TRY_WITH_GC(expr) \
1071 for (int first_errno, retried_errno = 0, retried = 0; \
1074 (!rb_gc_for_fd(first_errno = errno) || !(expr)) && \
1075 (retried_errno = errno, 1)); \
1076 (void)retried_errno, retried = 1)
1091io_alloc(
VALUE klass)
1101# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
1127struct io_internal_writev_struct {
1134 const struct iovec *iov;
1147io_internal_wait(
VALUE thread,
rb_io_t *fptr,
int error,
int events,
struct timeval *timeout)
1149 int ready = nogvl_wait_for(thread, fptr, events, timeout);
1154 else if (ready == 0) {
1164internal_read_func(
void *ptr)
1169 if (iis->timeout && !iis->nonblock) {
1170 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_IN, iis->timeout) == -1) {
1176 result = read(iis->fd, iis->buf, iis->capa);
1178 if (result < 0 && !iis->nonblock) {
1179 if (io_again_p(
errno)) {
1180 if (io_internal_wait(iis->th, iis->fptr,
errno, RB_WAITFD_IN, iis->timeout) == -1) {
1192#if defined __APPLE__
1193# define do_write_retry(code) do {result = code;} while (result == -1 && errno == EPROTOTYPE)
1195# define do_write_retry(code) result = code
1199internal_write_func(
void *ptr)
1204 if (iis->timeout && !iis->nonblock) {
1205 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1211 do_write_retry(write(iis->fd, iis->buf, iis->capa));
1213 if (result < 0 && !iis->nonblock) {
1215 if (io_again_p(e)) {
1216 if (io_internal_wait(iis->th, iis->fptr,
errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1230internal_writev_func(
void *ptr)
1232 struct io_internal_writev_struct *iis = ptr;
1235 if (iis->timeout && !iis->nonblock) {
1236 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1242 do_write_retry(writev(iis->fd, iis->iov, iis->iovcnt));
1244 if (result < 0 && !iis->nonblock) {
1245 if (io_again_p(
errno)) {
1246 if (io_internal_wait(iis->th, iis->fptr,
errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1260rb_io_read_memory(
rb_io_t *fptr,
void *buf,
size_t count)
1263 if (scheduler !=
Qnil) {
1266 if (!UNDEF_P(result)) {
1282 struct timeval timeout_storage;
1286 iis.timeout = &timeout_storage;
1289 return (ssize_t)rb_thread_io_blocking_call(internal_read_func, &iis, fptr->
fd, RB_WAITFD_IN);
1293rb_io_write_memory(
rb_io_t *fptr,
const void *buf,
size_t count)
1296 if (scheduler !=
Qnil) {
1299 if (!UNDEF_P(result)) {
1315 struct timeval timeout_storage;
1319 iis.timeout = &timeout_storage;
1322 return (ssize_t)rb_thread_io_blocking_call(internal_write_func, &iis, fptr->
fd, RB_WAITFD_OUT);
1327rb_writev_internal(
rb_io_t *fptr,
const struct iovec *iov,
int iovcnt)
1329 if (!iovcnt)
return 0;
1332 if (scheduler !=
Qnil) {
1336 if (!UNDEF_P(result)) {
1341 struct io_internal_writev_struct iis = {
1352 struct timeval timeout_storage;
1356 iis.timeout = &timeout_storage;
1359 return (ssize_t)rb_thread_io_blocking_call(internal_writev_func, &iis, fptr->
fd, RB_WAITFD_OUT);
1364io_flush_buffer_sync(
void *arg)
1386io_flush_buffer_async(
VALUE arg)
1389 return rb_thread_io_blocking_call(io_flush_buffer_sync, fptr, fptr->
fd, RB_WAITFD_OUT);
1396 return (
int)io_flush_buffer_async((
VALUE)fptr);
1411 while (fptr->
wbuf.
len > 0 && io_flush_buffer(fptr) != 0) {
1426 if (scheduler !=
Qnil) {
1436 if (NIL_OR_UNDEF_P(timeout)) {
1440 if (timeout !=
Qnil) {
1445 int ready = rb_thread_wait_for_single_fd(fptr->
fd,
RB_NUM2INT(events), tv);
1469io_wait_for_single_fd(
int fd,
int events,
struct timeval *timeout)
1473 if (scheduler !=
Qnil) {
1479 return rb_thread_wait_for_single_fd(fd, events, timeout);
1485 io_fd_check_closed(f);
1491#if defined(ERESTART)
1498#if EWOULDBLOCK != EAGAIN
1501 if (scheduler !=
Qnil) {
1519 io_fd_check_closed(f);
1525#if defined(ERESTART)
1541#if EWOULDBLOCK != EAGAIN
1544 if (scheduler !=
Qnil) {
1562 return io_wait_for_single_fd(fd, events, timeout);
1596#if defined(ERESTART)
1606#if EWOULDBLOCK != EAGAIN
1623 if (
RTEST(result)) {
1636 if (
RTEST(result)) {
1648 const char *senc, *denc;
1655 ecflags = fptr->
encs.
ecflags & ~ECONV_NEWLINE_DECORATOR_READ_MASK;
1682 denc = rb_enc_name(enc);
1715io_binwrite_string_internal(
rb_io_t *fptr,
const char *ptr,
long length)
1718 struct iovec iov[2];
1721 iov[0].iov_len = fptr->
wbuf.
len;
1722 iov[1].iov_base = (
void*)ptr;
1723 iov[1].iov_len = length;
1725 ssize_t result = rb_writev_internal(fptr, iov, 2);
1730 if (result >= fptr->
wbuf.
len) {
1738 fptr->
wbuf.
off += (int)result;
1739 fptr->
wbuf.
len -= (int)result;
1747 return rb_io_write_memory(fptr, ptr, length);
1752io_binwrite_string_internal(
rb_io_t *fptr,
const char *ptr,
long length)
1754 long remaining = length;
1757 if (fptr->
wbuf.
len+length <= fptr->wbuf.capa) {
1764 fptr->
wbuf.
len += (int)length;
1771 if (io_fflush(fptr) < 0) {
1776 if (remaining == 0) {
1782 return rb_io_write_memory(fptr, ptr, length);
1787io_binwrite_string(
VALUE arg)
1791 const char *ptr = p->ptr;
1792 size_t remaining = p->length;
1796 ssize_t result = io_binwrite_string_internal(p->fptr, ptr, remaining);
1801 errno = EWOULDBLOCK;
1805 if ((
size_t)result == remaining)
break;
1807 remaining -= result;
1823io_allocate_write_buffer(
rb_io_t *fptr,
int sync)
1828 fptr->
wbuf.
capa = IO_WBUF_CAPA_MIN;
1839io_binwrite_requires_flush_write(
rb_io_t *fptr,
long len,
int nosync)
1854io_binwrite(
VALUE str,
const char *ptr,
long len,
rb_io_t *fptr,
int nosync)
1856 if (
len <= 0)
return len;
1861 io_allocate_write_buffer(fptr, !nosync);
1863 if (io_binwrite_requires_flush_write(fptr,
len, nosync)) {
1875 return io_binwrite_string((
VALUE)&arg);
1892# define MODE_BTMODE(a,b,c) ((fmode & FMODE_BINMODE) ? (b) : \
1893 (fmode & FMODE_TEXTMODE) ? (c) : (a))
1895#define MODE_BTXMODE(a, b, c, d, e, f) ((fmode & FMODE_EXCL) ? \
1896 MODE_BTMODE(d, e, f) : \
1897 MODE_BTMODE(a, b, c))
1902 if (NEED_WRITECONV(fptr)) {
1904 SET_BINARY_MODE(fptr);
1906 make_writeconv(fptr);
1909#define fmode (fptr->mode)
1912 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1) && !rb_enc_asciicompat(rb_enc_get(str))) {
1913 rb_raise(rb_eArgError,
"ASCII incompatible string written for text mode IO without encoding conversion: %s",
1914 rb_enc_name(rb_enc_get(str)));
1920 common_encoding = rb_enc_from_encoding(fptr->
encs.
enc2);
1921 else if (fptr->
encs.
enc != rb_ascii8bit_encoding())
1922 common_encoding = rb_enc_from_encoding(fptr->
encs.
enc);
1925 if (!
NIL_P(common_encoding)) {
1936#if RUBY_CRLF_ENVIRONMENT
1937#define fmode (fptr->mode)
1938 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1)) {
1941 setmode(fptr->
fd, O_BINARY);
1944 setmode(fptr->
fd, O_TEXT);
1946 if (!rb_enc_asciicompat(rb_enc_get(str))) {
1947 rb_raise(rb_eArgError,
"ASCII incompatible string written for text mode IO without encoding conversion: %s",
1948 rb_enc_name(rb_enc_get(str)));
1966 long len = rb_w32_write_console(str, fptr->
fd);
1971 str = do_writeconv(str, fptr, &converted);
1975 tmp = rb_str_tmp_frozen_acquire(str);
1977 n = io_binwrite(tmp, ptr,
len, fptr, nosync);
1978 rb_str_tmp_frozen_release(str, tmp);
1990 return (ssize_t)io_binwrite(0, buf, (
long)size, fptr, 0);
2000 io = GetWriteIO(io);
2001 str = rb_obj_as_string(str);
2010 if (RSTRING_LEN(str) == 0)
return INT2FIX(0);
2015 n = io_fwrite(str, fptr, nosync);
2016 if (n < 0L) rb_sys_fail_on_write(fptr);
2022struct binwritev_arg {
2030io_binwritev_internal(
VALUE arg)
2032 struct binwritev_arg *p = (
struct binwritev_arg *)arg;
2034 size_t remaining = p->total;
2038 struct iovec *iov = p->iov;
2039 int iovcnt = p->iovcnt;
2042 long result = rb_writev_internal(fptr, iov, iovcnt);
2047 if (offset < (
size_t)fptr->
wbuf.
len) {
2052 offset -= (size_t)fptr->
wbuf.
len;
2058 if (offset == p->total) {
2062 while (result >= (ssize_t)iov->iov_len) {
2064 result -= iov->iov_len;
2074 iov->iov_base = (
char *)iov->iov_base + result;
2075 iov->iov_len -= result;
2089io_binwritev(
struct iovec *iov,
int iovcnt,
rb_io_t *fptr)
2094 if (iovcnt == 0)
return 0;
2097 for (
int i = 1; i < iovcnt; i++) total += iov[i].iov_len;
2099 io_allocate_write_buffer(fptr, 1);
2105 if (offset + total <= (
size_t)fptr->
wbuf.
capa) {
2106 for (
int i = 1; i < iovcnt; i++) {
2107 memcpy(fptr->
wbuf.
ptr+offset, iov[i].iov_base, iov[i].iov_len);
2108 offset += iov[i].iov_len;
2117 iov[0].iov_len = fptr->
wbuf.
len;
2130 struct binwritev_arg arg;
2133 arg.iovcnt = iovcnt;
2140 return io_binwritev_internal((
VALUE)&arg);
2147 int i, converted, iovcnt = argc + 1;
2149 VALUE v1, v2, str, tmp, *tmp_array;
2155 for (i = 0; i < argc; i++) {
2156 str = rb_obj_as_string(argv[i]);
2158 str = do_writeconv(str, fptr, &converted);
2163 tmp = rb_str_tmp_frozen_acquire(str);
2167 iov[i+1].iov_base = RSTRING_PTR(tmp);
2168 iov[i+1].iov_len = RSTRING_LEN(tmp);
2171 n = io_binwritev(iov, iovcnt, fptr);
2174 for (i = 0; i < argc; i++) {
2175 rb_str_tmp_frozen_release(argv[i], tmp_array[i]);
2184iovcnt_ok(
int iovcnt)
2187 return iovcnt < IOV_MAX;
2195io_writev(
int argc,
const VALUE *argv,
VALUE io)
2202 io = GetWriteIO(io);
2207 return rb_funcallv(io, id_write, argc, argv);
2215 for (i = 0; i < argc; i += cnt) {
2218 n = io_fwritev(cnt, &argv[i], fptr);
2225 n = io_fwrite(rb_obj_as_string(argv[i]), fptr, (i < argc-1));
2229 rb_sys_fail_on_write(fptr);
2231 total = rb_fix_plus(
LONG2FIX(n), total);
2262 return io_writev(argc, argv, io);
2265 VALUE str = argv[0];
2266 return io_write(io, str, 0);
2273 return rb_funcallv(io, id_write, 1, &str);
2277rb_io_writev(
VALUE io,
int argc,
const VALUE *argv)
2285 " which accepts just one argument",
2290 do rb_io_write(io, *argv++);
while (--argc);
2295 return rb_funcallv(io, id_write, argc, argv);
2321 rb_io_write(io, str);
2327nogvl_fsync(
void *ptr)
2332 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->
fd)) != FILE_TYPE_DISK)
2335 return (
VALUE)fsync(fptr->
fd);
2340rb_io_flush_raw(
VALUE io,
int sync)
2344 if (!RB_TYPE_P(io,
T_FILE)) {
2348 io = GetWriteIO(io);
2352 if (io_fflush(fptr) < 0)
2353 rb_sys_fail_on_write(fptr);
2377 return rb_io_flush_raw(io, 1);
2403 pos = io_tell(fptr);
2404 if (pos < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
2410rb_io_seek(
VALUE io,
VALUE offset,
int whence)
2417 pos = io_seek(fptr, pos, whence);
2418 if (pos < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
2424interpret_seek_whence(
VALUE vwhence)
2426 if (vwhence == sym_SET)
2428 if (vwhence == sym_CUR)
2430 if (vwhence == sym_END)
2433 if (vwhence == sym_DATA)
2437 if (vwhence == sym_HOLE)
2493 VALUE offset, ptrname;
2494 int whence = SEEK_SET;
2496 if (
rb_scan_args(argc, argv,
"11", &offset, &ptrname) == 2) {
2497 whence = interpret_seek_whence(ptrname);
2500 return rb_io_seek(io, offset, whence);
2528 pos = io_seek(fptr, pos, SEEK_SET);
2529 if (pos < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
2534static void clear_readconv(
rb_io_t *fptr);
2561rb_io_rewind(
VALUE io)
2566 if (io_seek(fptr, 0L, 0) < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
2567 if (io == ARGF.current_file) {
2568 ARGF.lineno -= fptr->
lineno;
2572 clear_readconv(fptr);
2579fptr_wait_readable(
rb_io_t *fptr)
2597 fptr->
rbuf.
capa = IO_RBUF_CAPA_FOR(fptr);
2608 if (fptr_wait_readable(fptr))
2612 VALUE path = rb_sprintf(
"fd:%d ", fptr->
fd);
2617 rb_syserr_fail_path(e, path);
2671 if (READ_CHAR_PENDING(fptr))
return Qfalse;
2672 if (READ_DATA_PENDING(fptr))
return Qfalse;
2674#if RUBY_CRLF_ENVIRONMENT
2675 if (!NEED_READCONV(fptr) && NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
2676 return RBOOL(eof(fptr->
fd));;
2679 return RBOOL(io_fillbuf(fptr) < 0);
2703 io = GetWriteIO(io);
2740 io = GetWriteIO(io);
2746 fptr->
mode &= ~FMODE_SYNC;
2770rb_io_fsync(
VALUE io)
2774 io = GetWriteIO(io);
2777 if (io_fflush(fptr) < 0)
2778 rb_sys_fail_on_write(fptr);
2779 if ((
int)rb_thread_io_blocking_region(nogvl_fsync, fptr, fptr->
fd) < 0)
2780 rb_sys_fail_path(fptr->
pathv);
2784# define rb_io_fsync rb_f_notimplement
2785# define rb_io_sync rb_f_notimplement
2794#ifdef HAVE_FDATASYNC
2796nogvl_fdatasync(
void *ptr)
2801 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->
fd)) != FILE_TYPE_DISK)
2804 return (
VALUE)fdatasync(fptr->
fd);
2819rb_io_fdatasync(
VALUE io)
2823 io = GetWriteIO(io);
2826 if (io_fflush(fptr) < 0)
2827 rb_sys_fail_on_write(fptr);
2829 if ((
int)rb_thread_io_blocking_region(nogvl_fdatasync, fptr, fptr->
fd) == 0)
2833 return rb_io_fsync(io);
2836#define rb_io_fdatasync rb_io_fsync
2854rb_io_fileno(
VALUE io)
2867 if (RB_TYPE_P(io,
T_FILE)) {
2874 if (!UNDEF_P(fileno)) {
2962rb_io_inspect(
VALUE obj)
2966 static const char closed[] =
" (closed)";
2968 fptr =
RFILE(obj)->fptr;
2975 rb_str_cat(result, closed+1, strlen(closed)-1);
2978 rb_str_catf(result,
"fd %d", fptr->
fd);
2984 rb_str_cat(result, closed, strlen(closed));
2999rb_io_to_io(
VALUE io)
3006read_buffered_data(
char *ptr,
long len,
rb_io_t *fptr)
3010 n = READ_DATA_PENDING_COUNT(fptr);
3011 if (n <= 0)
return 0;
3012 if (n >
len) n = (int)
len;
3020io_bufread(
char *ptr,
long len,
rb_io_t *fptr)
3026 if (READ_DATA_PENDING(fptr) == 0) {
3030 c = rb_io_read_memory(fptr, ptr+offset, n);
3033 if (fptr_wait_readable(fptr))
3038 if ((n -= c) <= 0)
break;
3044 c = read_buffered_data(ptr+offset, n, fptr);
3047 if ((n -= c) <= 0)
break;
3050 if (io_fillbuf(fptr) < 0) {
3057static int io_setstrbuf(
VALUE *str,
long len);
3066bufread_call(
VALUE arg)
3069 p->len = io_bufread(p->str_ptr, p->len, p->fptr);
3074io_fread(
VALUE str,
long offset,
long size,
rb_io_t *fptr)
3079 io_setstrbuf(&str, offset + size);
3080 arg.str_ptr = RSTRING_PTR(str) + offset;
3083 rb_str_locktmp_ensure(str, bufread_call, (
VALUE)&arg);
3085 if (
len < 0) rb_sys_fail_path(fptr->
pathv);
3093 rb_off_t siz = READ_DATA_PENDING_COUNT(fptr);
3096 if (fstat(fptr->
fd, &st) == 0 && S_ISREG(st.st_mode)
3097#
if defined(__HAIKU__)
3102 if (io_fflush(fptr) < 0)
3103 rb_sys_fail_on_write(fptr);
3104 pos = lseek(fptr->
fd, 0, SEEK_CUR);
3105 if (st.st_size >= pos && pos >= 0) {
3106 siz += st.st_size - pos;
3107 if (siz > LONG_MAX) {
3108 rb_raise(
rb_eIOError,
"file too big for single read");
3121 rb_enc_associate(str, io_read_encoding(fptr));
3128make_readconv(
rb_io_t *fptr,
int size)
3133 const char *sname, *dname;
3134 ecflags = fptr->
encs.
ecflags & ~ECONV_NEWLINE_DECORATOR_WRITE_MASK;
3137 sname = rb_enc_name(fptr->
encs.
enc2);
3138 dname = rb_enc_name(io_read_encoding(fptr));
3148 if (size < IO_CBUF_CAPA_MIN) size = IO_CBUF_CAPA_MIN;
3154#define MORE_CHAR_SUSPENDED Qtrue
3155#define MORE_CHAR_FINISHED Qnil
3157fill_cbuf(
rb_io_t *fptr,
int ec_flags)
3159 const unsigned char *ss, *sp, *se;
3160 unsigned char *ds, *dp, *de;
3169 return MORE_CHAR_SUSPENDED;
3180 ss = sp = (
const unsigned char *)fptr->
rbuf.
ptr + fptr->
rbuf.
off;
3185 fptr->
rbuf.
off += (int)(sp - ss);
3186 fptr->
rbuf.
len -= (int)(sp - ss);
3187 fptr->
cbuf.
len += (int)(dp - ds);
3192 fptr->
rbuf.
off -= putbackable;
3193 fptr->
rbuf.
len += putbackable;
3200 if (cbuf_len0 != fptr->
cbuf.
len)
3201 return MORE_CHAR_SUSPENDED;
3204 return MORE_CHAR_FINISHED;
3210 if (io_fillbuf(fptr) < 0) {
3212 return MORE_CHAR_FINISHED;
3217 fptr->
cbuf.
len += (int)(dp - ds);
3224 if (cbuf_len0 != fptr->
cbuf.
len)
3225 return MORE_CHAR_SUSPENDED;
3227 return MORE_CHAR_FINISHED;
3235 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED)
3252 rb_enc_associate(str, fptr->
encs.
enc);
3281 long clen = RSTRING_LEN(s);
3293#define MAX_REALLOC_GAP 4096
3295io_shrink_read_string(
VALUE str,
long n)
3298 rb_str_resize(str, n);
3303io_set_read_length(
VALUE str,
long n,
int shrinkable)
3305 if (RSTRING_LEN(str) != n) {
3307 rb_str_set_len(str, n);
3308 if (shrinkable) io_shrink_read_string(str, n);
3322 if (NEED_READCONV(fptr)) {
3323 int first = !
NIL_P(str);
3324 SET_BINARY_MODE(fptr);
3325 shrinkable = io_setstrbuf(&str,0);
3326 make_readconv(fptr, 0);
3330 if (first) rb_str_set_len(str, first = 0);
3331 io_shift_cbuf(fptr, fptr->
cbuf.
len, &str);
3333 v = fill_cbuf(fptr, 0);
3334 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED) {
3336 if (first) rb_str_set_len(str, first = 0);
3337 io_shift_cbuf(fptr, fptr->
cbuf.
len, &str);
3341 if (v == MORE_CHAR_FINISHED) {
3342 clear_readconv(fptr);
3343 if (first) rb_str_set_len(str, first = 0);
3344 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3345 return io_enc_str(str, fptr);
3350 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3354 enc = io_read_encoding(fptr);
3357 if (siz == 0) siz = BUFSIZ;
3358 shrinkable = io_setstrbuf(&str, siz);
3361 n = io_fread(str, bytes, siz - bytes, fptr);
3362 if (n == 0 && bytes == 0) {
3363 rb_str_set_len(str, 0);
3367 rb_str_set_len(str, bytes);
3370 if (bytes < siz)
break;
3374 if (
capa < (
size_t)RSTRING_LEN(str) + BUFSIZ) {
3375 if (
capa < BUFSIZ) {
3378 else if (
capa > IO_MAX_BUFFER_GROWTH) {
3379 capa = IO_MAX_BUFFER_GROWTH;
3384 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3385 str = io_enc_str(str, fptr);
3393 if (rb_fd_set_nonblock(fptr->
fd) != 0) {
3394 rb_sys_fail_path(fptr->
pathv);
3399io_read_memory_call(
VALUE arg)
3404 if (scheduler !=
Qnil) {
3407 if (!UNDEF_P(result)) {
3413 if (iis->nonblock) {
3414 return rb_thread_io_blocking_call(internal_read_func, iis, iis->fptr->
fd, 0);
3417 return rb_thread_io_blocking_call(internal_read_func, iis, iis->fptr->
fd, RB_WAITFD_IN);
3424 return (
long)rb_str_locktmp_ensure(str, io_read_memory_call, (
VALUE)iis);
3427#define no_exception_p(opts) !rb_opts_exception_p((opts), TRUE)
3430io_getpartial(
int argc,
VALUE *argv,
VALUE io,
int no_exception,
int nonblock)
3441 rb_raise(rb_eArgError,
"negative length %ld given",
len);
3444 shrinkable = io_setstrbuf(&str,
len);
3450 io_set_read_length(str, 0, shrinkable);
3456 n = read_buffered_data(RSTRING_PTR(str),
len, fptr);
3462 io_setstrbuf(&str,
len);
3465 iis.nonblock = nonblock;
3467 iis.buf = RSTRING_PTR(str);
3470 n = io_read_memory_locktmp(str, &iis);
3473 if (!nonblock && fptr_wait_readable(fptr))
3475 if (nonblock && (io_again_p(e))) {
3477 return sym_wait_readable;
3480 e,
"read would block");
3482 rb_syserr_fail_path(e, fptr->
pathv);
3485 io_set_read_length(str, n, shrinkable);
3586io_readpartial(
int argc,
VALUE *argv,
VALUE io)
3590 ret = io_getpartial(argc, argv, io,
Qnil, 0);
3597io_nonblock_eof(
int no_exception)
3599 if (!no_exception) {
3615 rb_raise(rb_eArgError,
"negative length %ld given",
len);
3618 shrinkable = io_setstrbuf(&str,
len);
3619 rb_bool_expected(ex,
"exception", TRUE);
3625 io_set_read_length(str, 0, shrinkable);
3629 n = read_buffered_data(RSTRING_PTR(str),
len, fptr);
3631 rb_fd_set_nonblock(fptr->
fd);
3632 shrinkable |= io_setstrbuf(&str,
len);
3636 iis.buf = RSTRING_PTR(str);
3639 n = io_read_memory_locktmp(str, &iis);
3642 if (io_again_p(e)) {
3643 if (!ex)
return sym_wait_readable;
3645 e,
"read would block");
3647 rb_syserr_fail_path(e, fptr->
pathv);
3650 io_set_read_length(str, n, shrinkable);
3653 if (!ex)
return Qnil;
3668 str = rb_obj_as_string(str);
3669 rb_bool_expected(ex,
"exception", TRUE);
3671 io = GetWriteIO(io);
3675 if (io_fflush(fptr) < 0)
3676 rb_sys_fail_on_write(fptr);
3678 rb_fd_set_nonblock(fptr->
fd);
3679 n = write(fptr->
fd, RSTRING_PTR(str), RSTRING_LEN(str));
3684 if (io_again_p(e)) {
3686 return sym_wait_writable;
3692 rb_syserr_fail_path(e, fptr->
pathv);
3776#if RUBY_CRLF_ENVIRONMENT
3782 if (
NIL_P(length)) {
3785 return read_all(fptr, remain_size(fptr), str);
3789 rb_raise(rb_eArgError,
"negative length %ld given",
len);
3792 shrinkable = io_setstrbuf(&str,
len);
3797 io_set_read_length(str, 0, shrinkable);
3802#if RUBY_CRLF_ENVIRONMENT
3803 previous_mode = set_binary_mode_with_seek_cur(fptr);
3805 n = io_fread(str, 0,
len, fptr);
3806 io_set_read_length(str, n, shrinkable);
3807#if RUBY_CRLF_ENVIRONMENT
3808 if (previous_mode == O_TEXT) {
3809 setmode(fptr->
fd, O_TEXT);
3812 if (n == 0)
return Qnil;
3818rscheck(
const char *rsptr,
long rslen,
VALUE rs)
3821 if (RSTRING_PTR(rs) != rsptr && RSTRING_LEN(rs) != rslen)
3826appendline(
rb_io_t *fptr,
int delim,
VALUE *strp,
long *lp)
3831 if (NEED_READCONV(fptr)) {
3832 SET_BINARY_MODE(fptr);
3833 make_readconv(fptr, 0);
3836 int searchlen = READ_CHAR_PENDING_COUNT(fptr);
3838 p = READ_CHAR_PENDING_PTR(fptr);
3839 if (0 < limit && limit < searchlen)
3840 searchlen = (int)limit;
3841 e = memchr(p, delim, searchlen);
3843 int len = (int)(e-p+1);
3865 return (
unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
3868 }
while (more_char(fptr) != MORE_CHAR_FINISHED);
3869 clear_readconv(fptr);
3874 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3876 long pending = READ_DATA_PENDING_COUNT(fptr);
3878 const char *p = READ_DATA_PENDING_PTR(fptr);
3882 if (limit > 0 && pending > limit) pending = limit;
3883 e = memchr(p, delim, pending);
3884 if (e) pending = e - p + 1;
3886 last = RSTRING_LEN(str);
3887 rb_str_resize(str, last + pending);
3891 *strp = str = rb_str_buf_new(pending);
3892 rb_str_set_len(str, pending);
3894 read_buffered_data(RSTRING_PTR(str) + last, pending, fptr);
3897 if (e)
return delim;
3899 return (
unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
3902 }
while (io_fillbuf(fptr) >= 0);
3908swallow(
rb_io_t *fptr,
int term)
3910 if (NEED_READCONV(fptr)) {
3913 SET_BINARY_MODE(fptr);
3914 make_readconv(fptr, 0);
3917 while ((cnt = READ_CHAR_PENDING_COUNT(fptr)) > 0) {
3918 const char *p = READ_CHAR_PENDING_PTR(fptr);
3921 if (*p != term)
return TRUE;
3923 while (--i && *++p == term);
3926 const char *e = p + cnt;
3927 if (rb_enc_ascget(p, e, &i, enc) != term)
return TRUE;
3928 while ((p += i) < e && rb_enc_ascget(p, e, &i, enc) == term);
3931 io_shift_cbuf(fptr, (
int)cnt - i, NULL);
3933 }
while (more_char(fptr) != MORE_CHAR_FINISHED);
3937 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3940 while ((cnt = READ_DATA_PENDING_COUNT(fptr)) > 0) {
3942 const char *p = READ_DATA_PENDING_PTR(fptr);
3944 if (cnt >
sizeof buf) cnt =
sizeof buf;
3945 if (*p != term)
return TRUE;
3947 while (--i && *++p == term);
3948 if (!read_buffered_data(buf, cnt - i, fptr))
3949 rb_sys_fail_path(fptr->
pathv);
3952 }
while (io_fillbuf(fptr) == 0);
3965 int pending = READ_DATA_PENDING_COUNT(fptr);
3968 const char *p = READ_DATA_PENDING_PTR(fptr);
3972 e = memchr(p,
'\n', pending);
3974 pending = (int)(e - p + 1);
3976 chomplen = (pending > 1 && *(e-1) ==
'\r') + 1;
3985 rb_str_resize(str,
len + pending - chomplen);
3986 read_buffered_data(RSTRING_PTR(str)+
len, pending - chomplen, fptr);
3989 if (pending == 1 && chomplen == 1 &&
len > 0) {
3990 if (RSTRING_PTR(str)[
len-1] ==
'\r') {
3991 rb_str_resize(str, --
len);
3996 len += pending - chomplen;
4002 }
while (io_fillbuf(fptr) >= 0);
4005 str = io_enc_str(str, fptr);
4016 unsigned int chomp: 1;
4030 chomp = (!UNDEF_P(vchomp)) &&
RTEST(vchomp);
4032 args->chomp = chomp;
4050 else if (2 <= argc) {
4051 rs = argv[0], lim = argv[1];
4060check_getline_args(
VALUE *rsp,
long *limit,
VALUE io)
4069 enc_rs = rb_enc_get(rs);
4070 enc_io = io_read_encoding(fptr);
4071 if (enc_io != enc_rs &&
4072 (!is_ascii_string(rs) ||
4073 (RSTRING_LEN(rs) > 0 && !rb_enc_asciicompat(enc_io)))) {
4074 if (rs == rb_default_rs) {
4075 rs = rb_enc_str_new(0, 0, enc_io);
4080 rb_raise(rb_eArgError,
"encoding mismatch: %s IO with %s RS",
4081 rb_enc_name(enc_io),
4082 rb_enc_name(enc_rs));
4092 argc =
rb_scan_args(argc, argv,
"02:", NULL, NULL, &opts);
4093 extract_getline_args(argc, argv, args);
4094 extract_getline_opts(opts, args);
4095 check_getline_args(&args->rs, &args->limit, io);
4099rb_io_getline_0(
VALUE rs,
long limit,
int chomp,
rb_io_t *fptr)
4106 if (
NIL_P(rs) && limit < 0) {
4107 str = read_all(fptr, 0,
Qnil);
4108 if (RSTRING_LEN(str) == 0)
return Qnil;
4110 else if (limit == 0) {
4111 return rb_enc_str_new(0, 0, io_read_encoding(fptr));
4113 else if (rs == rb_default_rs && limit < 0 && !NEED_READCONV(fptr) &&
4114 rb_enc_asciicompat(enc = io_read_encoding(fptr))) {
4115 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4116 return rb_io_getline_fast(fptr, enc, chomp);
4119 int c, newline = -1;
4120 const char *rsptr = 0;
4123 int extra_limit = 16;
4124 int chomp_cr = chomp;
4126 SET_BINARY_MODE(fptr);
4127 enc = io_read_encoding(fptr);
4130 rslen = RSTRING_LEN(rs);
4135 swallow(fptr,
'\n');
4137 if (!rb_enc_asciicompat(enc)) {
4141 rsptr = RSTRING_PTR(rs);
4142 rslen = RSTRING_LEN(rs);
4146 rsptr = RSTRING_PTR(rs);
4148 newline = (
unsigned char)rsptr[rslen - 1];
4149 chomp_cr = chomp && rslen == 1 && newline ==
'\n';
4153 while ((c = appendline(fptr, newline, &str, &limit)) != EOF) {
4154 const char *s, *p, *pp, *e;
4157 if (RSTRING_LEN(str) < rslen)
continue;
4158 s = RSTRING_PTR(str);
4159 e = RSTRING_END(str);
4161 if (!at_char_boundary(s, p, e, enc))
continue;
4162 if (!rspara) rscheck(rsptr, rslen, rs);
4163 if (memcmp(p, rsptr, rslen) == 0) {
4165 if (chomp_cr && p > s && *(p-1) ==
'\r') --p;
4166 rb_str_set_len(str, p - s);
4172 s = RSTRING_PTR(str);
4173 p = RSTRING_END(str);
4189 if (rspara && c != EOF)
4190 swallow(fptr,
'\n');
4192 str = io_enc_str(str, fptr);
4195 if (!
NIL_P(str) && !nolimit) {
4203rb_io_getline_1(
VALUE rs,
long limit,
int chomp,
VALUE io)
4206 int old_lineno, new_lineno;
4210 old_lineno = fptr->
lineno;
4211 str = rb_io_getline_0(rs, limit, chomp, fptr);
4212 if (!
NIL_P(str) && (new_lineno = fptr->
lineno) != old_lineno) {
4213 if (io == ARGF.current_file) {
4214 ARGF.lineno += new_lineno - old_lineno;
4215 ARGF.last_lineno = ARGF.lineno;
4218 ARGF.last_lineno = new_lineno;
4226rb_io_getline(
int argc,
VALUE *argv,
VALUE io)
4230 prepare_getline_args(argc, argv, &args, io);
4231 return rb_io_getline_1(args.rs, args.limit, args.chomp, io);
4237 return rb_io_getline_1(rb_default_rs, -1, FALSE, io);
4241rb_io_gets_internal(
VALUE io)
4245 return rb_io_getline_0(rb_default_rs, -1, FALSE, fptr);
4328 str = rb_io_getline(argc, argv, io);
4344rb_io_lineno(
VALUE io)
4394 rb_lastline_set_up(line, 1);
4471rb_io_readlines(
int argc,
VALUE *argv,
VALUE io)
4475 prepare_getline_args(argc, argv, &args, io);
4476 return io_readlines(&args, io);
4484 if (arg->limit == 0)
4485 rb_raise(rb_eArgError,
"invalid limit: 0 for readlines");
4487 while (!
NIL_P(line = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, io))) {
4488 rb_ary_push(ary, line);
4602rb_io_each_line(
int argc,
VALUE *argv,
VALUE io)
4608 prepare_getline_args(argc, argv, &args, io);
4609 if (args.limit == 0)
4610 rb_raise(rb_eArgError,
"invalid limit: 0 for each_line");
4611 while (!
NIL_P(str = rb_io_getline_1(args.rs, args.limit, args.chomp, io))) {
4638rb_io_each_byte(
VALUE io)
4654 }
while (io_fillbuf(fptr) >= 0);
4664 if (NEED_READCONV(fptr)) {
4668 SET_BINARY_MODE(fptr);
4669 make_readconv(fptr, 0);
4683 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4685 clear_readconv(fptr);
4689 str = rb_enc_str_new(fptr->
cbuf.
ptr+fptr->
cbuf.
off, 1, read_enc);
4692 if (fptr->
cbuf.
len == 0) clear_readconv(fptr);
4701 io_shift_cbuf(fptr, r, &str);
4708 ISASCII(RSTRING_PTR(str)[0])) {
4712 str = io_enc_str(str, fptr);
4717 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4718 if (io_fillbuf(fptr) < 0) {
4740 if (io_fillbuf(fptr) != -1) {
4744 r = rb_enc_precise_mbclen(RSTRING_PTR(str), RSTRING_PTR(str)+RSTRING_LEN(str), enc);
4760 str = io_enc_str(str, fptr);
4786rb_io_each_char(
VALUE io)
4796 enc = io_input_encoding(fptr);
4798 while (!
NIL_P(c = io_getc(fptr, enc))) {
4824rb_io_each_codepoint(
VALUE io)
4836 if (NEED_READCONV(fptr)) {
4837 SET_BINARY_MODE(fptr);
4840 make_readconv(fptr, 0);
4848 r = ONIGENC_CONSTRUCT_MBCLEN_CHARFOUND(1);
4855 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4856 clear_readconv(fptr);
4883 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4884 enc = io_input_encoding(fptr);
4885 while (io_fillbuf(fptr) >= 0) {
4900 char cbuf[8], *p = cbuf;
4902 if (more > numberof(cbuf))
goto invalid;
4904 if (more > numberof(cbuf))
goto invalid;
4905 while ((n = (
int)read_buffered_data(p, more, fptr)) > 0 &&
4906 (p += n, (more -= n) > 0)) {
4907 if (io_fillbuf(fptr) < 0)
goto invalid;
4908 if ((n = fptr->
rbuf.
len) > more) n = more;
4910 r = rb_enc_precise_mbclen(cbuf, p, enc);
4923 rb_raise(rb_eArgError,
"invalid byte sequence in %s", rb_enc_name(enc));
4955 enc = io_input_encoding(fptr);
4957 return io_getc(fptr, enc);
4980rb_io_readchar(
VALUE io)
4982 VALUE c = rb_io_getc(io);
5017 VALUE r_stdout = rb_ractor_stdout();
5022 rb_io_flush(r_stdout);
5025 if (io_fillbuf(fptr) < 0) {
5054rb_io_readbyte(
VALUE io)
5115 unsigned char c =
NUM2INT(v) & 0xFF;
5121 io_ungetbyte(b, fptr);
5177 else if (RB_BIGNUM_TYPE_P(c)) {
5183 if (NEED_READCONV(fptr)) {
5184 SET_BINARY_MODE(fptr);
5185 len = RSTRING_LEN(c);
5186#if SIZEOF_LONG > SIZEOF_INT
5190 make_readconv(fptr, (
int)
len);
5204 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
5205 io_ungetbyte(c, fptr);
5225rb_io_isatty(
VALUE io)
5230 return RBOOL(isatty(fptr->
fd) != 0);
5233#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5249rb_io_close_on_exec_p(
VALUE io)
5255 write_io = GetWriteIO(io);
5256 if (io != write_io) {
5258 if (fptr && 0 <= (fd = fptr->
fd)) {
5259 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->
pathv);
5260 if (!(ret & FD_CLOEXEC))
return Qfalse;
5265 if (fptr && 0 <= (fd = fptr->
fd)) {
5266 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->
pathv);
5267 if (!(ret & FD_CLOEXEC))
return Qfalse;
5272#define rb_io_close_on_exec_p rb_f_notimplement
5275#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5299 int flag =
RTEST(arg) ? FD_CLOEXEC : 0;
5304 write_io = GetWriteIO(io);
5305 if (io != write_io) {
5307 if (fptr && 0 <= (fd = fptr->
fd)) {
5308 if ((ret = fcntl(fptr->
fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->
pathv);
5309 if ((ret & FD_CLOEXEC) != flag) {
5310 ret = (ret & ~FD_CLOEXEC) | flag;
5311 ret = fcntl(fd, F_SETFD, ret);
5312 if (ret != 0) rb_sys_fail_path(fptr->
pathv);
5319 if (fptr && 0 <= (fd = fptr->
fd)) {
5320 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->
pathv);
5321 if ((ret & FD_CLOEXEC) != flag) {
5322 ret = (ret & ~FD_CLOEXEC) | flag;
5323 ret = fcntl(fd, F_SETFD, ret);
5324 if (ret != 0) rb_sys_fail_path(fptr->
pathv);
5330#define rb_io_set_close_on_exec rb_f_notimplement
5333#define RUBY_IO_EXTERNAL_P(f) ((f)->mode & FMODE_EXTERNAL)
5334#define PREP_STDIO_NAME(f) (RSTRING_PTR((f)->pathv))
5337finish_writeconv(
rb_io_t *fptr,
int noalloc)
5339 unsigned char *ds, *dp, *de;
5343 unsigned char buf[1024];
5348 de = buf +
sizeof(buf);
5351 size_t remaining = dp-ds;
5352 long result = rb_io_write_memory(fptr, ds, remaining);
5356 if ((
size_t)result == remaining)
break;
5379 if (io_fflush(fptr) < 0) {
5387 fptr->
wbuf.
len += (int)(dp - ds);
5403finish_writeconv_sync(
VALUE arg)
5406 return finish_writeconv(p->fptr, p->noalloc);
5410nogvl_close(
void *ptr)
5414 return (
void*)(intptr_t)close(*fd);
5418maygvl_close(
int fd,
int keepgvl)
5431nogvl_fclose(
void *ptr)
5435 return (
void*)(intptr_t)fclose(file);
5439maygvl_fclose(
FILE *file,
int keepgvl)
5442 return fclose(file);
5448static void clear_codeconv(
rb_io_t *fptr);
5451fptr_finalize_flush(
rb_io_t *fptr,
int noraise,
int keepgvl,
5457 int mode = fptr->
mode;
5463 arg.noalloc = noraise;
5467 error = finish_writeconv(fptr, noraise);
5472 io_flush_buffer_sync(fptr);
5475 if (io_fflush(fptr) < 0 &&
NIL_P(error)) {
5483 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2) {
5495 rb_notify_fd_close_wait(busy);
5507 if (!done && stdio_file) {
5509 if ((maygvl_fclose(stdio_file, noraise) < 0) &&
NIL_P(error)) {
5518 if (!done && fd >= 0) {
5524 if ((maygvl_close(fd, keepgvl) < 0) &&
NIL_P(error)) {
5533 if (!
NIL_P(error) && !noraise) {
5537 rb_exc_raise(error);
5542fptr_finalize(
rb_io_t *fptr,
int noraise)
5544 fptr_finalize_flush(fptr, noraise, FALSE, 0);
5545 free_io_buffer(&fptr->
rbuf);
5546 free_io_buffer(&fptr->
wbuf);
5547 clear_codeconv(fptr);
5551rb_io_fptr_cleanup(
rb_io_t *fptr,
int noraise)
5557 fptr_finalize(fptr, noraise);
5565 ruby_sized_xfree(buf->
ptr, (
size_t)buf->
capa);
5577 free_io_buffer(&fptr->
cbuf);
5593 clear_readconv(fptr);
5594 clear_writeconv(fptr);
5598rb_io_fptr_cleanup_all(
rb_io_t *fptr)
5602 rb_io_fptr_cleanup(fptr, TRUE);
5604 free_io_buffer(&fptr->
rbuf);
5605 free_io_buffer(&fptr->
wbuf);
5606 clear_codeconv(fptr);
5610rb_io_fptr_finalize_internal(
void *ptr)
5613 rb_io_fptr_cleanup_all(ptr);
5617#undef rb_io_fptr_finalize
5625 rb_io_fptr_finalize_internal(fptr);
5629#define rb_io_fptr_finalize(fptr) rb_io_fptr_finalize_internal(fptr)
5631RUBY_FUNC_EXPORTED
size_t
5632rb_io_memsize(
const rb_io_t *fptr)
5634 size_t size =
sizeof(
rb_io_t);
5645# define KEEPGVL TRUE
5647# define KEEPGVL FALSE
5651io_close_fptr(
VALUE io)
5658 write_io = GetWriteIO(io);
5659 if (io != write_io) {
5660 write_fptr =
RFILE(write_io)->fptr;
5661 if (write_fptr && 0 <= write_fptr->
fd) {
5662 rb_io_fptr_cleanup(write_fptr, TRUE);
5666 fptr =
RFILE(io)->fptr;
5667 if (!fptr)
return 0;
5668 if (fptr->
fd < 0)
return 0;
5670 if (rb_notify_fd_close(fptr->
fd, &busy)) {
5672 fptr_finalize_flush(fptr, FALSE, KEEPGVL, &busy);
5674 rb_io_fptr_cleanup(fptr, FALSE);
5679fptr_waitpid(
rb_io_t *fptr,
int nohang)
5683 rb_last_status_clear();
5692 rb_io_t *fptr = io_close_fptr(io);
5693 if (fptr) fptr_waitpid(fptr, 0);
5730rb_io_close_m(
VALUE io)
5732 rb_io_t *fptr = rb_io_get_fptr(io);
5741io_call_close(
VALUE io)
5750 enum {mesg_len =
sizeof(closed_stream)-1};
5751 VALUE mesg = rb_attr_get(exc, idMesg);
5753 RSTRING_LEN(mesg) != mesg_len ||
5754 memcmp(RSTRING_PTR(mesg), closed_stream, mesg_len)) {
5764 if (!UNDEF_P(closed) &&
RTEST(closed))
return io;
5765 rb_rescue2(io_call_close, io, ignore_closed_stream, io,
5801 write_io = GetWriteIO(io);
5802 if (io != write_io) {
5803 write_fptr =
RFILE(write_io)->fptr;
5804 if (write_fptr && 0 <= write_fptr->
fd) {
5809 fptr = rb_io_get_fptr(io);
5810 return RBOOL(0 > fptr->
fd);
5846rb_io_close_read(
VALUE io)
5852 if (fptr->
fd < 0)
return Qnil;
5853 if (is_socket(fptr->
fd, fptr->
pathv)) {
5857 if (shutdown(fptr->
fd, SHUT_RD) < 0)
5858 rb_sys_fail_path(fptr->
pathv);
5859 fptr->
mode &= ~FMODE_READABLE;
5865 write_io = GetWriteIO(io);
5866 if (io != write_io) {
5871 RFILE(io)->fptr = wfptr;
5874 RFILE(write_io)->fptr = fptr;
5875 rb_io_fptr_cleanup(fptr, FALSE);
5881 rb_raise(
rb_eIOError,
"closing non-duplex IO for reading");
5919rb_io_close_write(
VALUE io)
5924 write_io = GetWriteIO(io);
5926 if (fptr->
fd < 0)
return Qnil;
5927 if (is_socket(fptr->
fd, fptr->
pathv)) {
5931 if (shutdown(fptr->
fd, SHUT_WR) < 0)
5932 rb_sys_fail_path(fptr->
pathv);
5933 fptr->
mode &= ~FMODE_WRITABLE;
5940 rb_raise(
rb_eIOError,
"closing non-duplex IO for writing");
5943 if (io != write_io) {
5963rb_io_sysseek(
int argc,
VALUE *argv,
VALUE io)
5965 VALUE offset, ptrname;
5966 int whence = SEEK_SET;
5970 if (
rb_scan_args(argc, argv,
"11", &offset, &ptrname) == 2) {
5971 whence = interpret_seek_whence(ptrname);
5976 (READ_DATA_BUFFERED(fptr) || READ_CHAR_PENDING(fptr))) {
5980 rb_warn(
"sysseek for buffered IO");
5983 pos = lseek(fptr->
fd, pos, whence);
5984 if (pos < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
6016 str = rb_obj_as_string(str);
6018 io = GetWriteIO(io);
6023 rb_warn(
"syswrite for buffered IO");
6026 tmp = rb_str_tmp_frozen_acquire(str);
6028 n = rb_io_write_memory(fptr, ptr,
len);
6029 if (n < 0) rb_sys_fail_path(fptr->
pathv);
6030 rb_str_tmp_frozen_release(str, tmp);
6047rb_io_sysread(
int argc,
VALUE *argv,
VALUE io)
6058 shrinkable = io_setstrbuf(&str, ilen);
6059 if (ilen == 0)
return str;
6064 if (READ_DATA_BUFFERED(fptr)) {
6070 io_setstrbuf(&str, ilen);
6075 iis.buf = RSTRING_PTR(str);
6078 n = io_read_memory_locktmp(str, &iis);
6081 rb_sys_fail_path(fptr->
pathv);
6084 io_set_read_length(str, n, shrinkable);
6086 if (n == 0 && ilen > 0) {
6102internal_pread_func(
void *_arg)
6106 return (
VALUE)pread(arg->fd, arg->buf, arg->count, arg->offset);
6110pread_internal_call(
VALUE _arg)
6115 if (scheduler !=
Qnil) {
6118 if (!UNDEF_P(result)) {
6123 return rb_thread_io_blocking_call(internal_pread_func, arg, arg->fd, RB_WAITFD_IN);
6167 shrinkable = io_setstrbuf(&str, (
long)arg.count);
6168 if (arg.count == 0)
return str;
6169 arg.buf = RSTRING_PTR(str);
6181 rb_sys_fail_path(fptr->
pathv);
6183 io_set_read_length(str, n, shrinkable);
6184 if (n == 0 && arg.count > 0) {
6192internal_pwrite_func(
void *_arg)
6197 if (scheduler !=
Qnil) {
6200 if (!UNDEF_P(result)) {
6206 return (
VALUE)pwrite(arg->fd, arg->buf, arg->count, arg->offset);
6243 str = rb_obj_as_string(str);
6247 io = GetWriteIO(io);
6252 tmp = rb_str_tmp_frozen_acquire(str);
6253 arg.buf = RSTRING_PTR(tmp);
6254 arg.count = (size_t)RSTRING_LEN(tmp);
6256 n = (ssize_t)rb_thread_io_blocking_call(internal_pwrite_func, &arg, fptr->
fd, RB_WAITFD_OUT);
6257 if (n < 0) rb_sys_fail_path(fptr->
pathv);
6258 rb_str_tmp_frozen_release(str, tmp);
6274 fptr->
mode &= ~FMODE_TEXTMODE;
6278 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6281 setmode(fptr->
fd, O_BINARY);
6288io_ascii8bit_binmode(
rb_io_t *fptr)
6299 fptr->
mode &= ~FMODE_TEXTMODE;
6300 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6302 fptr->
encs.
enc = rb_ascii8bit_encoding();
6306 clear_codeconv(fptr);
6315 io_ascii8bit_binmode(fptr);
6332rb_io_binmode_m(
VALUE io)
6338 write_io = GetWriteIO(io);
6353rb_io_binmode_p(
VALUE io)
6361rb_io_fmode_modestr(
int fmode)
6365 return MODE_BTMODE(
"a+",
"ab+",
"at+");
6367 return MODE_BTMODE(
"a",
"ab",
"at");
6371 rb_raise(rb_eArgError,
"invalid access fmode 0x%x", fmode);
6373 return MODE_BTMODE(
"r",
"rb",
"rt");
6375 return MODE_BTXMODE(
"w",
"wb",
"wt",
"wx",
"wbx",
"wtx");
6378 return MODE_BTXMODE(
"w+",
"wb+",
"wt+",
"w+x",
"wb+x",
"wt+x");
6380 return MODE_BTMODE(
"r+",
"rb+",
"rt+");
6384static const char bom_prefix[] =
"bom|";
6385static const char utf_prefix[] =
"utf-";
6386enum {bom_prefix_len = (int)
sizeof(bom_prefix) - 1};
6387enum {utf_prefix_len = (int)
sizeof(utf_prefix) - 1};
6390io_encname_bom_p(
const char *name,
long len)
6392 return len > bom_prefix_len &&
STRNCASECMP(name, bom_prefix, bom_prefix_len) == 0;
6399 const char *m = modestr, *p = NULL;
6427 if (modestr[0] !=
'w')
6435 if (io_encname_bom_p(m, p ? (
long)(p - m) : (long)strlen(m)))
6448 rb_raise(rb_eArgError,
"invalid access mode %s", modestr);
6453rb_io_oflags_fmode(
int oflags)
6457 switch (oflags & O_ACCMODE) {
6469 if (oflags & O_APPEND) {
6472 if (oflags & O_TRUNC) {
6475 if (oflags & O_CREAT) {
6478 if (oflags & O_EXCL) {
6482 if (oflags & O_BINARY) {
6491rb_io_fmode_oflags(
int fmode)
6535rb_io_oflags_modestr(
int oflags)
6538# define MODE_BINARY(a,b) ((oflags & O_BINARY) ? (b) : (a))
6540# define MODE_BINARY(a,b) (a)
6543 if (oflags & O_EXCL) {
6544 rb_raise(rb_eArgError,
"exclusive access mode is not supported");
6546 accmode = oflags & (O_RDONLY|O_WRONLY|O_RDWR);
6547 if (oflags & O_APPEND) {
6548 if (accmode == O_WRONLY) {
6549 return MODE_BINARY(
"a",
"ab");
6551 if (accmode == O_RDWR) {
6552 return MODE_BINARY(
"a+",
"ab+");
6557 rb_raise(rb_eArgError,
"invalid access oflags 0x%x", oflags);
6559 return MODE_BINARY(
"r",
"rb");
6561 return MODE_BINARY(
"w",
"wb");
6563 if (oflags & O_TRUNC) {
6564 return MODE_BINARY(
"w+",
"wb+");
6566 return MODE_BINARY(
"r+",
"rb+");
6578 int default_ext = 0;
6581 ext = rb_default_external_encoding();
6584 if (rb_is_ascii8bit_enc(ext)) {
6588 else if (intern == NULL) {
6589 intern = rb_default_internal_encoding();
6594 *enc = (default_ext && intern != ext) ? NULL : ext;
6604unsupported_encoding(
const char *name,
rb_encoding *enc)
6606 rb_enc_warn(enc,
"Unsupported encoding %s ignored", name);
6610parse_mode_enc(
const char *estr,
rb_encoding *estr_enc,
6616 int fmode = fmode_p ? *fmode_p : 0;
6622 p = strrchr(estr,
':');
6623 len = p ? (p++ - estr) : (long)strlen(estr);
6625 estr += bom_prefix_len;
6626 len -= bom_prefix_len;
6627 if (!
STRNCASECMP(estr, utf_prefix, utf_prefix_len)) {
6631 rb_enc_warn(estr_enc,
"BOM with non-UTF encoding %s is nonsense", estr);
6632 fmode &= ~FMODE_SETENC_BY_BOM;
6640 memcpy(encname, estr,
len);
6641 encname[
len] =
'\0';
6644 idx = rb_enc_find_index(estr);
6646 if (fmode_p) *fmode_p = fmode;
6649 ext_enc = rb_enc_from_index(idx);
6652 unsupported_encoding(estr, estr_enc);
6658 if (*p ==
'-' && *(p+1) ==
'\0') {
6663 idx2 = rb_enc_find_index(p);
6665 unsupported_encoding(p, estr_enc);
6670 int_enc = rb_enc_from_index(idx2);
6674 rb_io_ext_int_to_encs(ext_enc, int_enc, enc_p, enc2_p, fmode);
6687 v = rb_hash_lookup2(opt, sym_encoding,
Qnil);
6688 if (v !=
Qnil) encoding = v;
6689 v = rb_hash_lookup2(opt, sym_extenc,
Qundef);
6690 if (v !=
Qnil) extenc = v;
6691 v = rb_hash_lookup2(opt, sym_intenc,
Qundef);
6692 if (!UNDEF_P(v)) intenc = v;
6694 if ((!UNDEF_P(extenc) || !UNDEF_P(intenc)) && !
NIL_P(encoding)) {
6696 int idx = rb_to_encoding_index(encoding);
6697 if (idx >= 0) encoding = rb_enc_from_encoding(rb_enc_from_index(idx));
6698 rb_warn(
"Ignoring encoding parameter '%"PRIsVALUE
"': %s_encoding is used",
6699 encoding, UNDEF_P(extenc) ?
"internal" :
"external");
6703 if (!UNDEF_P(extenc) && !
NIL_P(extenc)) {
6704 extencoding = rb_to_encoding(extenc);
6706 if (!UNDEF_P(intenc)) {
6707 if (
NIL_P(intenc)) {
6714 if (*p ==
'-' && *(p+1) ==
'\0') {
6719 intencoding = rb_to_encoding(intenc);
6723 intencoding = rb_to_encoding(intenc);
6725 if (extencoding == intencoding) {
6729 if (!
NIL_P(encoding)) {
6733 enc_p, enc2_p, fmode_p);
6736 rb_io_ext_int_to_encs(rb_to_encoding(encoding), NULL, enc_p, enc2_p, 0);
6739 else if (!UNDEF_P(extenc) || !UNDEF_P(intenc)) {
6741 rb_io_ext_int_to_encs(extencoding, intencoding, enc_p, enc2_p, 0);
6749 int fmode = *fmode_p;
6754 !rb_enc_asciicompat(enc ? enc : rb_default_external_encoding()))
6755 rb_raise(rb_eArgError,
"ASCII incompatible encoding needs binmode");
6758 rb_raise(rb_eArgError,
"newline decorator with binary mode");
6765#if !DEFAULT_TEXTMODE
6767 fmode &= ~FMODE_TEXTMODE;
6774extract_binmode(
VALUE opthash,
int *fmode)
6776 if (!
NIL_P(opthash)) {
6778 v = rb_hash_aref(opthash, sym_textmode);
6781 rb_raise(rb_eArgError,
"textmode specified twice");
6783 rb_raise(rb_eArgError,
"both textmode and binmode specified");
6787 v = rb_hash_aref(opthash, sym_binmode);
6790 rb_raise(rb_eArgError,
"binmode specified twice");
6792 rb_raise(rb_eArgError,
"both textmode and binmode specified");
6798 rb_raise(rb_eArgError,
"both textmode and binmode specified");
6804 int *oflags_p,
int *fmode_p,
struct rb_io_encoding *convconfig_p)
6811 int has_enc = 0, has_vmode = 0;
6817 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
6827 fmode = rb_io_oflags_fmode(oflags);
6835 oflags = rb_io_fmode_oflags(fmode);
6839 parse_mode_enc(p+1, rb_enc_get(vmode), &enc, &enc2, &fmode);
6844 e = (fmode &
FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
6845 rb_io_ext_int_to_encs(e, NULL, &enc, &enc2, fmode);
6849 if (
NIL_P(opthash)) {
6853#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
6855 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
6856 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
6858 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
6865 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
6868 else if (
NIL_P(vmode)) {
6869 fmode |= DEFAULT_TEXTMODE;
6876 v = rb_hash_aref(opthash, sym_mode);
6878 if (!
NIL_P(vmode)) {
6879 rb_raise(rb_eArgError,
"mode specified twice");
6886 v = rb_hash_aref(opthash, sym_flags);
6891 fmode = rb_io_oflags_fmode(oflags);
6893 extract_binmode(opthash, &fmode);
6899 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
6902 else if (
NIL_P(vmode)) {
6903 fmode |= DEFAULT_TEXTMODE;
6906 v = rb_hash_aref(opthash, sym_perm);
6909 if (!
NIL_P(*vperm_p)) {
6910 rb_raise(rb_eArgError,
"perm specified twice");
6921#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
6923 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
6924 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
6929 rb_raise(rb_eArgError,
"encoding specified twice");
6932 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
6936 validate_enc_binmode(&fmode, ecflags, enc, enc2);
6942 convconfig_p->
enc = enc;
6943 convconfig_p->
enc2 = enc2;
6944 convconfig_p->
ecflags = ecflags;
6945 convconfig_p->
ecopts = ecopts;
6955sysopen_func(
void *ptr)
6958 const char *fname = RSTRING_PTR(data->fname);
6973rb_sysopen(
VALUE fname,
int oflags, mode_t perm)
6978 data.fname = rb_str_encode_ospath(fname);
6980 data.oflags = oflags;
6983 TRY_WITH_GC((fd = rb_sysopen_internal(&data)) >= 0) {
6984 rb_syserr_fail_path(first_errno, fname);
6990fdopen_internal(
int fd,
const char *modestr)
6997 file = fdopen(fd, modestr);
7013 TRY_WITH_GC((file = fdopen_internal(fd, modestr)) != 0) {
7019 if (setvbuf(file, NULL, _IOFBF, 0) != 0)
7020 rb_warn(
"setvbuf() can't be honoured (fd=%d)", fd);
7028 int t = isatty(fptr->
fd);
7038io_strip_bom(
VALUE io)
7040 VALUE b1, b2, b3, b4;
7051 return rb_utf8_encindex();
7061 return ENCINDEX_UTF_16BE;
7072 return ENCINDEX_UTF_32LE;
7077 return ENCINDEX_UTF_16LE;
7087 return ENCINDEX_UTF_32BE;
7101io_set_encoding_by_bom(
VALUE io)
7103 int idx = io_strip_bom(io);
7109 extenc = rb_enc_from_index(idx);
7110 io_encoding_set(fptr, rb_enc_from_encoding(extenc),
7111 rb_io_internal_encoding(io),
Qnil);
7120rb_file_open_generic(
VALUE io,
VALUE filename,
int oflags,
int fmode,
7128 rb_io_ext_int_to_encs(NULL, NULL, &cc.enc, &cc.enc2, fmode);
7133 validate_enc_binmode(&fmode, convconfig->
ecflags,
7134 convconfig->
enc, convconfig->
enc2);
7138 fptr->
encs = *convconfig;
7139 pathv = rb_str_new_frozen(filename);
7141 if (!(oflags & O_TMPFILE)) {
7142 fptr->
pathv = pathv;
7145 fptr->
pathv = pathv;
7147 fptr->
fd = rb_sysopen(pathv, oflags, perm);
7155rb_file_open_internal(
VALUE io,
VALUE filename,
const char *modestr)
7158 const char *p = strchr(modestr,
':');
7162 parse_mode_enc(p+1, rb_usascii_encoding(),
7163 &convconfig.
enc, &convconfig.
enc2, &fmode);
7171 e = (fmode &
FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
7172 rb_io_ext_int_to_encs(e, NULL, &convconfig.
enc, &convconfig.
enc2, fmode);
7177 return rb_file_open_generic(io, filename,
7178 rb_io_fmode_oflags(fmode),
7188 return rb_file_open_internal(io_alloc(
rb_cFile), fname, modestr);
7197#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7220 while ((tmp = *prev) != 0) {
7221 if (tmp->fptr == fptr) {
7230#if defined (_WIN32) || defined(__CYGWIN__)
7239 rb_io_fptr_finalize(list->fptr);
7246pipe_finalize(
rb_io_t *fptr,
int noraise)
7248#if !defined(HAVE_WORKING_FORK) && !defined(_WIN32)
7257 fptr_finalize(fptr, noraise);
7259 pipe_del_fptr(fptr);
7266#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7267 void (*
const old_finalize)(
struct rb_io*,int) = fptr->
finalize;
7269 if (old_finalize == orig->finalize)
return;
7274#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7275 if (old_finalize != pipe_finalize) {
7277 for (list =
pipe_list; list; list = list->next) {
7278 if (list->fptr == fptr)
break;
7280 if (!list) pipe_add_fptr(fptr);
7283 pipe_del_fptr(fptr);
7296rb_io_unbuffered(
rb_io_t *fptr)
7314#define HAVE_SPAWNV 1
7315#define spawnv(mode, cmd, args) rb_w32_uaspawn((mode), (cmd), (args))
7316#define spawn(mode, cmd) rb_w32_uspawn((mode), (cmd), 0)
7319#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7329#ifdef HAVE_WORKING_FORK
7330# ifndef __EMSCRIPTEN__
7332popen_redirect(
struct popen_arg *p)
7335 close(p->write_pair[1]);
7336 if (p->write_pair[0] != 0) {
7337 dup2(p->write_pair[0], 0);
7338 close(p->write_pair[0]);
7341 if (p->pair[1] != 1) {
7342 dup2(p->pair[1], 1);
7348 if (p->pair[1] != 1) {
7349 dup2(p->pair[1], 1);
7355 if (p->pair[0] != 0) {
7356 dup2(p->pair[0], 0);
7363#if defined(__linux__)
7374linux_get_maxfd(
void)
7377 char buf[4096], *p, *np, *e;
7380 if (fd < 0)
return fd;
7381 ss = read(fd, buf,
sizeof(buf));
7382 if (ss < 0)
goto err;
7385 while ((
int)
sizeof(
"FDSize:\t0\n")-1 <= e-p &&
7386 (np = memchr(p,
'\n', e-p)) != NULL) {
7387 if (memcmp(p,
"FDSize:",
sizeof(
"FDSize:")-1) == 0) {
7389 p +=
sizeof(
"FDSize:")-1;
7409#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
7411 int max = (int)max_file_descriptor;
7414 ret = fcntl(0, F_MAXFD);
7416 maxhint = max = ret;
7417# elif defined(__linux__)
7418 ret = linux_get_maxfd();
7425 for (fd = lowfd; fd <= max; fd++) {
7426 if (!
NIL_P(noclose_fds) &&
7429 ret = fcntl(fd, F_GETFD);
7430 if (ret != -1 && !(ret & FD_CLOEXEC)) {
7431 fcntl(fd, F_SETFD, ret|FD_CLOEXEC);
7433# define CONTIGUOUS_CLOSED_FDS 20
7435 if (max < fd + CONTIGUOUS_CLOSED_FDS)
7436 max = fd + CONTIGUOUS_CLOSED_FDS;
7442# ifndef __EMSCRIPTEN__
7444popen_exec(
void *pp,
char *errmsg,
size_t errmsg_len)
7446 struct popen_arg *p = (
struct popen_arg*)pp;
7448 return rb_exec_async_signal_safe(p->eargp, errmsg, errmsg_len);
7453#if (defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)) && !defined __EMSCRIPTEN__
7455rb_execarg_fixup_v(
VALUE execarg_obj)
7457 rb_execarg_parent_start(execarg_obj);
7461char *rb_execarg_commandline(
const struct rb_execarg *eargp,
VALUE *prog);
7464#ifndef __EMSCRIPTEN__
7466pipe_open(
VALUE execarg_obj,
const char *modestr,
int fmode,
7469 struct rb_execarg *eargp =
NIL_P(execarg_obj) ? NULL : rb_execarg_get(execarg_obj);
7470 VALUE prog = eargp ? (eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name) :
Qfalse ;
7476#if defined(HAVE_WORKING_FORK)
7478 char errmsg[80] = {
'\0' };
7480#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7482 struct popen_arg arg;
7485#if defined(HAVE_SPAWNV)
7486# if defined(HAVE_SPAWNVE)
7487# define DO_SPAWN(cmd, args, envp) ((args) ? \
7488 spawnve(P_NOWAIT, (cmd), (args), (envp)) : \
7489 spawne(P_NOWAIT, (cmd), (envp)))
7491# define DO_SPAWN(cmd, args, envp) ((args) ? \
7492 spawnv(P_NOWAIT, (cmd), (args)) : \
7493 spawn(P_NOWAIT, (cmd)))
7495# if !defined(HAVE_WORKING_FORK)
7497# if defined(HAVE_SPAWNVE)
7502#if !defined(HAVE_WORKING_FORK)
7508#if !defined(HAVE_WORKING_FORK)
7509 const char *cmd = 0;
7515#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7516 arg.execarg_obj = execarg_obj;
7519 arg.pair[0] = arg.pair[1] = -1;
7520 arg.write_pair[0] = arg.write_pair[1] = -1;
7521# if !defined(HAVE_WORKING_FORK)
7522 if (eargp && !eargp->use_shell) {
7523 args = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
7528 if (
rb_pipe(arg.write_pair) < 0)
7529 rb_sys_fail_str(prog);
7532 close(arg.write_pair[0]);
7533 close(arg.write_pair[1]);
7537 rb_execarg_addopt(execarg_obj,
INT2FIX(0),
INT2FIX(arg.write_pair[0]));
7538 rb_execarg_addopt(execarg_obj,
INT2FIX(1),
INT2FIX(arg.pair[1]));
7543 rb_sys_fail_str(prog);
7545 rb_execarg_addopt(execarg_obj,
INT2FIX(1),
INT2FIX(arg.pair[1]));
7549 rb_sys_fail_str(prog);
7551 rb_execarg_addopt(execarg_obj,
INT2FIX(0),
INT2FIX(arg.pair[0]));
7554 rb_sys_fail_str(prog);
7556 if (!
NIL_P(execarg_obj)) {
7557 rb_protect(rb_execarg_fixup_v, execarg_obj, &state);
7559 if (0 <= arg.write_pair[0]) close(arg.write_pair[0]);
7560 if (0 <= arg.write_pair[1]) close(arg.write_pair[1]);
7561 if (0 <= arg.pair[0]) close(arg.pair[0]);
7562 if (0 <= arg.pair[1]) close(arg.pair[1]);
7563 rb_execarg_parent_end(execarg_obj);
7567# if defined(HAVE_WORKING_FORK)
7568 pid = rb_fork_async_signal_safe(&status, popen_exec, &arg, arg.eargp->redirect_fds, errmsg,
sizeof(errmsg));
7570 rb_execarg_run_options(eargp, sargp, NULL, 0);
7571# if defined(HAVE_SPAWNVE)
7572 if (eargp->envp_str) envp = (
char **)RSTRING_PTR(eargp->envp_str);
7574 while ((pid = DO_SPAWN(cmd, args, envp)) < 0) {
7576 switch (e =
errno) {
7578# if EWOULDBLOCK != EAGAIN
7587 rb_execarg_run_options(sargp, NULL, NULL, 0);
7589 rb_execarg_parent_end(execarg_obj);
7592# if defined(HAVE_WORKING_FORK)
7593 pid = rb_call_proc__fork();
7595 popen_redirect(&arg);
7607# if defined(HAVE_WORKING_FORK)
7613 close(arg.write_pair[0]);
7614 close(arg.write_pair[1]);
7616# if defined(HAVE_WORKING_FORK)
7625 close(arg.write_pair[0]);
7626 write_fd = arg.write_pair[1];
7637 cmd = rb_execarg_commandline(eargp, &prog);
7638 if (!
NIL_P(execarg_obj)) {
7639 rb_execarg_parent_start(execarg_obj);
7640 rb_execarg_run_options(eargp, sargp, NULL, 0);
7642 fp = popen(cmd, modestr);
7645 rb_execarg_parent_end(execarg_obj);
7646 rb_execarg_run_options(sargp, NULL, NULL, 0);
7648 if (!fp) rb_syserr_fail_path(e, prog);
7658 fptr->
encs = *convconfig;
7659#if RUBY_CRLF_ENVIRONMENT
7666 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
7669#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7670 if (NEED_NEWLINE_DECORATOR_ON_WRITE(fptr)) {
7671 fptr->
encs.
ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
7677 if (0 <= write_fd) {
7678 write_port = io_alloc(
rb_cIO);
7680 write_fptr->
fd = write_fd;
7682 fptr->
mode &= ~FMODE_WRITABLE;
7684 rb_ivar_set(port, rb_intern(
"@tied_io_for_writing"), write_port);
7687#if defined (__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7689 pipe_add_fptr(fptr);
7695pipe_open(
VALUE execarg_obj,
const char *modestr,
int fmode,
7703is_popen_fork(
VALUE prog)
7705 if (RSTRING_LEN(prog) == 1 && RSTRING_PTR(prog)[0] ==
'-') {
7706#if !defined(HAVE_WORKING_FORK)
7708 "fork() function is unimplemented on this machine");
7717pipe_open_s(
VALUE prog,
const char *modestr,
int fmode,
7721 VALUE *argv = &prog;
7724 if (!is_popen_fork(prog))
7725 execarg_obj = rb_execarg_new(argc, argv, TRUE, FALSE);
7726 return pipe_open(execarg_obj, modestr, fmode, convconfig);
7732 rb_io_t *fptr = io_close_fptr(io);
7900rb_io_s_popen(
int argc,
VALUE *argv,
VALUE klass)
7904 if (argc > 1 && !
NIL_P(opt = rb_check_hash_type(argv[argc-1]))) --argc;
7905 if (argc > 1 && !
NIL_P(env = rb_check_hash_type(argv[0]))) --argc, ++argv;
7914 int ex = !
NIL_P(opt);
7915 rb_error_arity(argc + ex, 1 + ex, 2 + ex);
7918 return popen_finish(rb_io_popen(pname, pmode, env, opt), klass);
7924 const char *modestr;
7929 tmp = rb_check_array_type(pname);
7932#if SIZEOF_LONG > SIZEOF_INT
7933 if (
len > INT_MAX) {
7934 rb_raise(rb_eArgError,
"too many arguments");
7943 if (!is_popen_fork(pname))
7944 execarg_obj = rb_execarg_new(1, &pname, TRUE, FALSE);
7946 if (!
NIL_P(execarg_obj)) {
7948 opt = rb_execarg_extract_options(execarg_obj, opt);
7950 rb_execarg_setenv(execarg_obj, env);
7953 modestr = rb_io_oflags_modestr(oflags);
7955 return pipe_open(execarg_obj, modestr, fmode, &convconfig);
7965 rb_io_flush(rb_ractor_stdout());
7966 rb_io_flush(rb_ractor_stderr());
7971 RBASIC_SET_CLASS(port, klass);
7978#if defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)
7979struct popen_writer_arg {
7981 struct popen_arg popen;
7985exec_popen_writer(
void *arg,
char *errmsg,
size_t buflen)
7987 struct popen_writer_arg *pw = arg;
7989 popen_redirect(&pw->popen);
7990 execv(pw->argv[0], pw->argv);
7991 strlcpy(errmsg, strerror(
errno), buflen);
7997ruby_popen_writer(
char *
const *argv, rb_pid_t *pid)
7999#if (defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)) || defined(_WIN32)
8000# ifdef HAVE_WORKING_FORK
8001 struct popen_writer_arg pw;
8002 int *
const write_pair = pw.popen.pair;
8010# ifdef HAVE_WORKING_FORK
8013 char errmsg[80] = {
'\0'};
8014 *pid = rb_fork_async_signal_safe(&status, exec_popen_writer, &pw,
Qnil, errmsg,
sizeof(errmsg));
8016 *pid = rb_w32_uspawn_process(P_NOWAIT, argv[0], argv, write_pair[0], -1, -1, 0);
8017 const char *errmsg = (*pid < 0) ? strerror(
errno) : NULL;
8019 close(write_pair[0]);
8021 close(write_pair[1]);
8022 fprintf(stderr,
"ruby_popen_writer(%s): %s\n", argv[0], errmsg);
8025 return fdopen(write_pair[1],
"w");
8033rb_scan_open_args(
int argc,
const VALUE *argv,
8034 VALUE *fname_p,
int *oflags_p,
int *fmode_p,
8037 VALUE opt, fname, vmode, vperm;
8041 argc =
rb_scan_args(argc, argv,
"12:", &fname, &vmode, &vperm, &opt);
8055rb_open_file(
int argc,
const VALUE *argv,
VALUE io)
8062 rb_scan_open_args(argc, argv, &fname, &oflags, &fmode, &convconfig, &perm);
8063 rb_file_open_generic(io, fname, oflags, fmode, &convconfig, perm);
8101rb_io_s_open(
int argc,
VALUE *argv,
VALUE klass)
8133 VALUE fname, vmode, vperm;
8138 rb_scan_args(argc, argv,
"12", &fname, &vmode, &vperm);
8149 if (
NIL_P(vperm)) perm = 0666;
8153 fd = rb_sysopen(fname, oflags, perm);
8158check_pipe_command(
VALUE filename_or_command)
8160 char *s = RSTRING_PTR(filename_or_command);
8161 long l = RSTRING_LEN(filename_or_command);
8165 if (rb_enc_ascget(s, e, &chlen, rb_enc_get(filename_or_command)) ==
'|') {
8203 int redirect = FALSE;
8211 VALUE tmp = argv[0];
8217 VALUE cmd = check_pipe_command(tmp);
8220 rb_warn_deprecated_to_remove_at(4.0,
"Calling Kernel#open with a leading '|'",
"IO.popen");
8222 return rb_io_s_popen(argc, argv,
rb_cIO);
8235 return rb_io_s_open(argc, argv,
rb_cFile);
8249 return rb_io_open_generic(io, filename, oflags, fmode, &convconfig, perm);
8253rb_io_open_generic(
VALUE klass,
VALUE filename,
int oflags,
int fmode,
8257 if (klass ==
rb_cIO && !
NIL_P(cmd = check_pipe_command(filename))) {
8259 rb_warn_deprecated_to_remove_at(4.0,
"IO process creation with a leading '|'",
"IO.popen");
8260 return pipe_open_s(cmd, rb_io_oflags_modestr(oflags), fmode, convconfig);
8263 return rb_file_open_generic(io_alloc(klass), filename,
8264 oflags, fmode, convconfig, perm);
8279 if (fptr == orig)
return io;
8280 if (RUBY_IO_EXTERNAL_P(fptr)) {
8284 rb_raise(rb_eArgError,
8285 "%s can't change access mode from \"%s\" to \"%s\"",
8286 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->
mode),
8287 rb_io_fmode_modestr(orig->
mode));
8291 if (io_fflush(fptr) < 0)
8292 rb_sys_fail_on_write(fptr);
8295 flush_before_seek(fptr);
8298 pos = io_tell(orig);
8301 if (io_fflush(orig) < 0)
8302 rb_sys_fail_on_write(fptr);
8310 else if (!RUBY_IO_EXTERNAL_P(fptr)) fptr->
pathv =
Qnil;
8311 fptr_copy_finalizer(fptr, orig);
8316 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2 || !fptr->stdio_file) {
8319 rb_sys_fail_path(orig->
pathv);
8327 rb_sys_fail_path(orig->
pathv);
8333 if (io_seek(fptr, pos, SEEK_SET) < 0 &&
errno) {
8334 rb_sys_fail_path(fptr->
pathv);
8336 if (io_seek(orig, pos, SEEK_SET) < 0 &&
errno) {
8337 rb_sys_fail_path(orig->
pathv);
8351int rb_freopen(
VALUE fname,
const char *mode,
FILE *fp);
8354rb_freopen(
VALUE fname,
const char *mode,
FILE *fp)
8356 if (!freopen(RSTRING_PTR(fname), mode, fp)) {
8399rb_io_reopen(
int argc,
VALUE *argv,
VALUE file)
8401 VALUE fname, nmode, opt;
8405 if (
rb_scan_args(argc, argv,
"11:", &fname, &nmode, &opt) == 1) {
8408 return io_reopen(file, tmp);
8414 fptr =
RFILE(file)->fptr;
8424 if (RUBY_IO_EXTERNAL_P(fptr) &&
8427 rb_raise(rb_eArgError,
8428 "%s can't change access mode from \"%s\" to \"%s\"",
8429 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->
mode),
8430 rb_io_fmode_modestr(fmode));
8433 fptr->
encs = convconfig;
8436 oflags = rb_io_fmode_oflags(fptr->
mode);
8439 fptr->
pathv = fname;
8441 fptr->
fd = rb_sysopen(fptr->
pathv, oflags, 0666);
8447 if (io_fflush(fptr) < 0)
8448 rb_sys_fail_on_write(fptr);
8453 int e = rb_freopen(rb_str_encode_ospath(fptr->
pathv),
8454 rb_io_oflags_modestr(oflags),
8456 if (e) rb_syserr_fail_path(e, fptr->
pathv);
8460 if (setvbuf(fptr->
stdio_file, NULL, _IOFBF, 0) != 0)
8461 rb_warn(
"setvbuf() can't be honoured for %"PRIsVALUE, fptr->
pathv);
8464 if (setvbuf(fptr->
stdio_file, NULL, _IONBF, BUFSIZ) != 0)
8465 rb_warn(
"setvbuf() can't be honoured for %"PRIsVALUE, fptr->
pathv);
8467 else if (fptr->
stdio_file == stdout && isatty(fptr->
fd)) {
8468 if (setvbuf(fptr->
stdio_file, NULL, _IOLBF, BUFSIZ) != 0)
8469 rb_warn(
"setvbuf() can't be honoured for %"PRIsVALUE, fptr->
pathv);
8473 int tmpfd = rb_sysopen(fptr->
pathv, oflags, 0666);
8479 rb_syserr_fail_path(err, fptr->
pathv);
8503 fptr->
mode = orig->
mode & ~FMODE_EXTERNAL;
8509 fptr_copy_finalizer(fptr, orig);
8511 fd = ruby_dup(orig->
fd);
8513 pos = io_tell(orig);
8515 io_seek(fptr, pos, SEEK_SET);
8520 write_io = GetWriteIO(io);
8521 if (io != write_io) {
8524 rb_ivar_set(dest, rb_intern(
"@tied_io_for_writing"), write_io);
8587 if (argc == 0)
return Qnil;
8588 if (RB_TYPE_P(argv[0],
T_STRING)) {
8589 out = rb_ractor_stdout();
8606 rb_warn_deprecated(
"`%s'", NULL, rb_id2name(
id));
8679 if (argc > 1 && !
NIL_P(rb_output_fs)) {
8682 for (i=0; i<argc; i++) {
8683 if (!
NIL_P(rb_output_fs) && i>0) {
8684 rb_io_write(out, rb_output_fs);
8686 rb_io_write(out, argv[i]);
8783 rb_io_write(io, str);
8787#define forward(obj, id, argc, argv) \
8788 rb_funcallv_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8789#define forward_public(obj, id, argc, argv) \
8790 rb_funcallv_public_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8791#define forward_current(id, argc, argv) \
8792 forward_public(ARGF.current_file, id, argc, argv)
8809 VALUE r_stdout = rb_ractor_stdout();
8810 if (recv == r_stdout) {
8811 return rb_io_putc(recv, ch);
8813 return forward(r_stdout, rb_intern(
"putc"), 1, &ch);
8818rb_str_end_with_asciichar(
VALUE str,
int c)
8820 long len = RSTRING_LEN(str);
8821 const char *
ptr = RSTRING_PTR(str);
8825 if (
len == 0)
return 0;
8827 return ptr[
len - 1] == c;
8829 return rb_enc_ascget(
ptr + ((
len - 1) / n) * n,
ptr +
len, &n,
enc) == c;
8840 rb_io_puts(1, &tmp, out);
8843 ary = rb_check_array_type(ary);
8847 rb_io_puts(1, &tmp, out);
8902 VALUE line, args[2];
8906 rb_io_write(out, rb_default_rs);
8909 for (
int i = 0; i < argc; i++) {
8911 if (RB_TYPE_P(argv[i],
T_STRING)) {
8918 line = rb_obj_as_string(argv[i]);
8923 if (RSTRING_LEN(line) == 0) {
8924 args[n++] = rb_default_rs;
8928 if (!rb_str_end_with_asciichar(line,
'\n')) {
8929 args[n++] = rb_default_rs;
8933 rb_io_writev(out, n, args);
8951 VALUE r_stdout = rb_ractor_stdout();
8952 if (recv == r_stdout) {
8953 return rb_io_puts(argc, argv, recv);
8955 return forward(r_stdout, rb_intern(
"puts"), argc, argv);
8959rb_p_write(
VALUE str)
8963 args[1] = rb_default_rs;
8964 VALUE r_stdout = rb_ractor_stdout();
8965 if (RB_TYPE_P(r_stdout,
T_FILE) &&
8966 rb_method_basic_definition_p(
CLASS_OF(r_stdout), id_write)) {
8967 io_writev(2, args, r_stdout);
8970 rb_io_writev(r_stdout, 2, args);
8978 rb_p_write(rb_obj_as_string(
rb_inspect(obj)));
8982rb_p_result(
int argc,
const VALUE *argv)
8989 else if (argc > 1) {
8992 VALUE r_stdout = rb_ractor_stdout();
8993 if (RB_TYPE_P(r_stdout,
T_FILE)) {
8994 rb_uninterruptible(rb_io_flush, r_stdout);
9035 for (i=0; i<argc; i++) {
9037 rb_uninterruptible(rb_p_write, inspected);
9039 return rb_p_result(argc, argv);
9060rb_obj_display(
int argc,
VALUE *argv,
VALUE self)
9064 out = (!
rb_check_arity(argc, 0, 1) ? rb_ractor_stdout() : argv[0]);
9065 rb_io_write(out, self);
9071rb_stderr_to_original_p(
VALUE err)
9073 return (err == orig_stderr ||
RFILE(orig_stderr)->fptr->
fd < 0);
9079 VALUE out = rb_ractor_stderr();
9080 if (rb_stderr_to_original_p(out)) {
9082 if (isatty(fileno(stderr))) {
9083 if (rb_w32_write_console(
rb_str_new(mesg,
len), fileno(stderr)) > 0)
return;
9086 if (fwrite(mesg,
sizeof(
char), (
size_t)
len, stderr) < (
size_t)
len) {
9103rb_write_error_str(
VALUE mesg)
9105 VALUE out = rb_ractor_stderr();
9107 if (rb_stderr_to_original_p(out)) {
9108 size_t len = (size_t)RSTRING_LEN(mesg);
9110 if (isatty(fileno(stderr))) {
9111 if (rb_w32_write_console(mesg, fileno(stderr)) > 0)
return;
9114 if (fwrite(RSTRING_PTR(mesg),
sizeof(
char),
len, stderr) <
len) {
9121 rb_io_write(out, mesg);
9126rb_stderr_tty_p(
void)
9128 if (rb_stderr_to_original_p(rb_ractor_stderr()))
9129 return isatty(fileno(stderr));
9134must_respond_to(
ID mid,
VALUE val,
ID id)
9137 rb_raise(
rb_eTypeError,
"%"PRIsVALUE
" must have %"PRIsVALUE
" method, %"PRIsVALUE
" given",
9138 rb_id2str(
id), rb_id2str(mid),
9158 must_respond_to(id_write, val,
id);
9165 return rb_ractor_stdout();
9171 must_respond_to(id_write, val,
id);
9178 return rb_ractor_stderr();
9182allocate_and_open_new_file(
VALUE klass)
9184 VALUE self = io_alloc(klass);
9185 rb_io_make_open_file(self);
9193 VALUE self = rb_protect(allocate_and_open_new_file, klass, &state);
9201 maygvl_close(descriptor, 0);
9209 io->
fd = descriptor;
9221 io->
pathv = rb_str_new_frozen(path);
9227 io->
encs = *encoding;
9236prep_io(
int fd,
int fmode,
VALUE klass,
const char *path)
9246 if (!io_check_tty(io)) {
9249 setmode(fd, O_BINARY);
9261 if (path && strcmp(path,
"-")) klass =
rb_cFile;
9262 return prep_io(fd, rb_io_oflags_fmode(oflags), klass, path);
9266prep_stdio(
FILE *f,
int fmode,
VALUE klass,
const char *path)
9273#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9274 fptr->
encs.
ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
9285rb_io_prep_stdin(
void)
9291rb_io_prep_stdout(
void)
9297rb_io_prep_stderr(
void)
9306 int oflags = rb_io_fmode_oflags(fptr->
mode) & ~O_EXCL;
9333 rb_io_buffer_init(&fp->
wbuf);
9334 rb_io_buffer_init(&fp->
rbuf);
9335 rb_io_buffer_init(&fp->
cbuf);
9353rb_io_make_open_file(
VALUE obj)
9358 if (
RFILE(obj)->fptr) {
9360 rb_io_fptr_finalize(
RFILE(obj)->fptr);
9361 RFILE(obj)->fptr = 0;
9363 fp = rb_io_fptr_new();
9365 RFILE(obj)->fptr = fp;
9411rb_io_initialize(
int argc,
VALUE *argv,
VALUE io)
9415 int fd, fmode, oflags = O_RDONLY;
9418#if defined(HAVE_FCNTL) && defined(F_GETFL)
9425 argc =
rb_scan_args(argc, argv,
"11:", &fnum, &vmode, &opt);
9430 rb_raise(rb_eArgError,
"The given fd is not accessible because RubyVM reserves it");
9432#if defined(HAVE_FCNTL) && defined(F_GETFL)
9433 oflags = fcntl(fd, F_GETFL);
9434 if (oflags == -1) rb_sys_fail(0);
9436 if (fstat(fd, &st) < 0) rb_sys_fail(0);
9439#if defined(HAVE_FCNTL) && defined(F_GETFL)
9440 ofmode = rb_io_oflags_fmode(oflags);
9452 if (rb_hash_aref(opt, sym_autoclose) ==
Qfalse) {
9456 path = rb_hash_aref(opt,
RB_ID2SYM(idPath));
9459 path = rb_str_new_frozen(path);
9467 fp->
encs = convconfig;
9472 if (fileno(stdin) == fd)
9474 else if (fileno(stdout) == fd)
9476 else if (fileno(stderr) == fd)
9508rb_io_set_encoding_by_bom(
VALUE io)
9514 rb_raise(rb_eArgError,
"ASCII incompatible encoding needs binmode");
9517 rb_raise(rb_eArgError,
"encoding conversion is set");
9519 else if (fptr->
encs.
enc && fptr->
encs.
enc != rb_ascii8bit_encoding()) {
9520 rb_raise(rb_eArgError,
"encoding is set to %s already",
9523 if (!io_set_encoding_by_bom(io))
return Qnil;
9524 return rb_enc_from_encoding(fptr->
encs.
enc);
9569rb_file_initialize(
int argc,
VALUE *argv,
VALUE io)
9571 if (
RFILE(io)->fptr) {
9574 if (0 < argc && argc < 3) {
9579 return rb_io_initialize(argc, argv, io);
9582 rb_open_file(argc, argv, io);
9589rb_io_s_new(
int argc,
VALUE *argv,
VALUE klass)
9592 VALUE cname = rb_obj_as_string(klass);
9594 rb_warn(
"%"PRIsVALUE
"::new() does not take block; use %"PRIsVALUE
"::open() instead",
9610rb_io_s_for_fd(
int argc,
VALUE *argv,
VALUE klass)
9613 rb_io_initialize(argc, argv, io);
9626rb_io_autoclose_p(
VALUE io)
9651rb_io_set_autoclose(
VALUE io,
VALUE autoclose)
9655 if (!
RTEST(autoclose))
9658 fptr->
mode &= ~FMODE_EXTERNAL;
9663io_wait_event(
VALUE io,
int event,
VALUE timeout,
int return_io)
9695io_wait_readable(
int argc,
VALUE *argv,
VALUE io)
9702 if (rb_io_read_pending(fptr))
return Qtrue;
9705 VALUE timeout = (argc == 1 ? argv[0] :
Qnil);
9719io_wait_writable(
int argc,
VALUE *argv,
VALUE io)
9727 VALUE timeout = (argc == 1 ? argv[0] :
Qnil);
9742io_wait_priority(
int argc,
VALUE *argv,
VALUE io)
9749 if (rb_io_read_pending(fptr))
return Qtrue;
9752 VALUE timeout = argc == 1 ? argv[0] :
Qnil;
9758wait_mode_sym(
VALUE mode)
9760 if (mode ==
ID2SYM(rb_intern(
"r"))) {
9761 return RB_WAITFD_IN;
9763 if (mode ==
ID2SYM(rb_intern(
"read"))) {
9764 return RB_WAITFD_IN;
9766 if (mode ==
ID2SYM(rb_intern(
"readable"))) {
9767 return RB_WAITFD_IN;
9769 if (mode ==
ID2SYM(rb_intern(
"w"))) {
9770 return RB_WAITFD_OUT;
9772 if (mode ==
ID2SYM(rb_intern(
"write"))) {
9773 return RB_WAITFD_OUT;
9775 if (mode ==
ID2SYM(rb_intern(
"writable"))) {
9776 return RB_WAITFD_OUT;
9778 if (mode ==
ID2SYM(rb_intern(
"rw"))) {
9779 return RB_WAITFD_IN|RB_WAITFD_OUT;
9781 if (mode ==
ID2SYM(rb_intern(
"read_write"))) {
9782 return RB_WAITFD_IN|RB_WAITFD_OUT;
9784 if (mode ==
ID2SYM(rb_intern(
"readable_writable"))) {
9785 return RB_WAITFD_IN|RB_WAITFD_OUT;
9788 rb_raise(rb_eArgError,
"unsupported mode: %"PRIsVALUE, mode);
9792io_event_from_value(
VALUE value)
9796 if (events <= 0) rb_raise(rb_eArgError,
"Events must be positive integer!");
9834 for (
int i = 0; i < argc; i += 1) {
9836 events |= wait_mode_sym(argv[i]);
9838 else if (UNDEF_P(timeout)) {
9842 rb_raise(rb_eArgError,
"timeout given more than once");
9846 if (UNDEF_P(timeout)) timeout =
Qnil;
9854 events = io_event_from_value(argv[0]);
9862 if (rb_io_read_pending(fptr)) {
9864 if (return_io)
return Qtrue;
9870 return io_wait_event(io, events, timeout, return_io);
9876 struct argf *p = ptr;
9877 rb_gc_mark(p->filename);
9878 rb_gc_mark(p->current_file);
9879 rb_gc_mark(p->argv);
9880 rb_gc_mark(p->inplace);
9881 rb_gc_mark(p->encs.
ecopts);
9885argf_memsize(
const void *ptr)
9887 const struct argf *p = ptr;
9888 size_t size =
sizeof(*p);
9895 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
9902 p->current_file =
Qnil;
9908argf_alloc(
VALUE klass)
9923 memset(&ARGF, 0,
sizeof(ARGF));
9924 argf_init(&ARGF, argv);
9934 ARGF = argf_of(orig);
9961 ARGF.last_lineno = ARGF.lineno;
9987 return forward_current(rb_frame_this_func(), argc, argv);
9990#define next_argv() argf_next_argv(argf)
9991#define ARGF_GENERIC_INPUT_P() \
9992 (ARGF.current_file == rb_stdin && !RB_TYPE_P(ARGF.current_file, T_FILE))
9993#define ARGF_FORWARD(argc, argv) do {\
9994 if (ARGF_GENERIC_INPUT_P())\
9995 return argf_forward((argc), (argv), argf);\
9997#define NEXT_ARGF_FORWARD(argc, argv) do {\
9998 if (!next_argv()) return Qnil;\
9999 ARGF_FORWARD((argc), (argv));\
10005 VALUE file = ARGF.current_file;
10007 if (RB_TYPE_P(file,
T_FILE)) {
10019 int stdout_binmode = 0;
10022 VALUE r_stdout = rb_ractor_stdout();
10024 if (RB_TYPE_P(r_stdout,
T_FILE)) {
10027 stdout_binmode = 1;
10030 if (ARGF.init_p == 0) {
10040 if (
NIL_P(ARGF.argv)) {
10043 else if (ARGF.next_p == -1 &&
RARRAY_LEN(ARGF.argv) > 0) {
10048 if (ARGF.next_p == 1) {
10049 if (ARGF.init_p == 1) argf_close(
argf);
10052 VALUE filename = rb_ary_shift(ARGF.argv);
10054 ARGF.filename = filename;
10055 filename = rb_str_encode_ospath(filename);
10057 if (RSTRING_LEN(filename) == 1 && fn[0] ==
'-') {
10059 if (ARGF.inplace) {
10060 rb_warn(
"Can't do inplace edit for stdio; skipping");
10066 int fr = rb_sysopen(filename, O_RDONLY, 0);
10068 if (ARGF.inplace) {
10070#ifndef NO_SAFE_RENAME
10076 if (RB_TYPE_P(r_stdout,
T_FILE) && r_stdout != orig_stdout) {
10081 if (!
NIL_P(ARGF.inplace)) {
10082 VALUE suffix = ARGF.inplace;
10083 str = rb_str_dup(str);
10084 if (
NIL_P(rb_str_cat_conv_enc_opts(str, RSTRING_LEN(str),
10085 RSTRING_PTR(suffix), RSTRING_LEN(suffix),
10086 rb_enc_get(suffix), 0,
Qnil))) {
10089#ifdef NO_SAFE_RENAME
10091 (void)unlink(RSTRING_PTR(str));
10092 if (rename(fn, RSTRING_PTR(str)) < 0) {
10093 rb_warn(
"Can't rename %"PRIsVALUE
" to %"PRIsVALUE
": %s, skipping file",
10094 filename, str, strerror(
errno));
10097 fr = rb_sysopen(str, O_RDONLY, 0);
10099 if (rename(fn, RSTRING_PTR(str)) < 0) {
10100 rb_warn(
"Can't rename %"PRIsVALUE
" to %"PRIsVALUE
": %s, skipping file",
10101 filename, str, strerror(
errno));
10108#ifdef NO_SAFE_RENAME
10109 rb_fatal(
"Can't do inplace edit without backup");
10111 if (unlink(fn) < 0) {
10112 rb_warn(
"Can't remove %"PRIsVALUE
": %s, skipping file",
10113 filename, strerror(
errno));
10119 fw = rb_sysopen(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666);
10120#ifndef NO_SAFE_RENAME
10123 fchmod(fw, st.st_mode);
10125 chmod(fn, st.st_mode);
10127 if (st.st_uid!=st2.st_uid || st.st_gid!=st2.st_gid) {
10130 err = fchown(fw, st.st_uid, st.st_gid);
10132 err = chown(fn, st.st_uid, st.st_gid);
10134 if (err && getuid() == 0 && st2.st_uid == 0) {
10135 const char *wkfn = RSTRING_PTR(filename);
10136 rb_warn(
"Can't set owner/group of %"PRIsVALUE
" to same as %"PRIsVALUE
": %s, skipping file",
10137 filename, str, strerror(
errno));
10140 (void)unlink(wkfn);
10150 if (!ARGF.binmode) {
10151 fmode |= DEFAULT_TEXTMODE;
10153 ARGF.current_file = prep_io(fr, fmode,
rb_cFile, fn);
10154 if (!
NIL_P(write_io)) {
10161 if (ARGF.encs.enc) {
10162 fptr->
encs = ARGF.encs;
10163 clear_codeconv(fptr);
10166 fptr->
encs.
ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
10167 if (!ARGF.binmode) {
10169#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
10170 fptr->
encs.
ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
10181 else if (ARGF.next_p == -1) {
10184 if (ARGF.inplace) {
10185 rb_warn(
"Can't do inplace edit for stdio");
10189 if (ARGF.init_p == -1) ARGF.init_p = 1;
10197 long lineno = ARGF.lineno;
10200 if (!next_argv())
return Qnil;
10201 if (ARGF_GENERIC_INPUT_P()) {
10202 line = forward_current(idGets, argc, argv);
10205 if (argc == 0 && rb_rs == rb_default_rs) {
10209 line = rb_io_getline(argc, argv, ARGF.current_file);
10211 if (
NIL_P(line) && ARGF.next_p != -1) {
10217 if (!
NIL_P(line)) {
10218 ARGF.lineno = ++lineno;
10219 ARGF.last_lineno = ARGF.lineno;
10225argf_lineno_getter(
ID id,
VALUE *var)
10228 return INT2FIX(ARGF.last_lineno);
10236 ARGF.last_lineno = ARGF.lineno = n;
10240rb_reset_argf_lineno(
long n)
10242 ARGF.last_lineno = ARGF.lineno = n;
10283 if (recv ==
argf) {
10284 return argf_gets(argc, argv,
argf);
10286 return forward(
argf, idGets, argc, argv);
10312 line = argf_getline(argc, argv,
argf);
10323 if (rb_rs != rb_default_rs) {
10324 return rb_f_gets(0, 0,
argf);
10328 if (!next_argv())
return Qnil;
10330 if (
NIL_P(line) && ARGF.next_p != -1) {
10336 if (!
NIL_P(line)) {
10338 ARGF.last_lineno = ARGF.lineno;
10364rb_f_readline(
int argc,
VALUE *argv,
VALUE recv)
10366 if (recv ==
argf) {
10367 return argf_readline(argc, argv,
argf);
10369 return forward(
argf, rb_intern(
"readline"), argc, argv);
10395 if (!next_argv()) rb_eof_error();
10396 ARGF_FORWARD(argc, argv);
10397 line = argf_gets(argc, argv,
argf);
10466rb_f_readlines(
int argc,
VALUE *argv,
VALUE recv)
10468 if (recv ==
argf) {
10469 return argf_readlines(argc, argv,
argf);
10471 return forward(
argf, rb_intern(
"readlines"), argc, argv);
10495 long lineno = ARGF.lineno;
10498 ary = rb_ary_new();
10499 while (next_argv()) {
10500 if (ARGF_GENERIC_INPUT_P()) {
10501 lines = forward_current(rb_intern(
"readlines"), argc, argv);
10504 lines = rb_io_readlines(argc, argv, ARGF.current_file);
10508 rb_ary_concat(ary, lines);
10510 ARGF.last_lineno = ARGF.lineno;
10545 rb_last_status_clear();
10546 port = pipe_open_s(str,
"r",
FMODE_READABLE|DEFAULT_TEXTMODE, NULL);
10550 result = read_all(fptr, remain_size(fptr),
Qnil);
10552 rb_io_fptr_cleanup_all(fptr);
10558#ifdef HAVE_SYS_SELECT_H
10559#include <sys/select.h>
10573 if (!
NIL_P(read)) {
10578 if (READ_DATA_PENDING(fptr) || READ_CHAR_PENDING(fptr)) {
10582 if (max < fptr->fd) max = fptr->
fd;
10585 timerec.tv_sec = timerec.tv_usec = 0;
10593 if (!
NIL_P(write)) {
10599 if (max < fptr->fd) max = fptr->
fd;
10606 if (!
NIL_P(except)) {
10610 VALUE write_io = GetWriteIO(io);
10613 if (max < fptr->fd) max = fptr->
fd;
10614 if (io != write_io) {
10617 if (max < fptr->fd) max = fptr->
fd;
10632 if (!pending && n == 0)
return Qnil;
10635 rb_ary_push(res, rp?rb_ary_new():
rb_ary_new2(0));
10636 rb_ary_push(res, wp?rb_ary_new():
rb_ary_new2(0));
10637 rb_ary_push(res, ep?rb_ary_new():
rb_ary_new2(0));
10642 VALUE obj = rb_ary_entry(read, i);
10647 rb_ary_push(list, obj);
10655 VALUE obj = rb_ary_entry(write, i);
10657 VALUE write_io = GetWriteIO(io);
10660 rb_ary_push(list, obj);
10668 VALUE obj = rb_ary_entry(except, i);
10670 VALUE write_io = GetWriteIO(io);
10673 rb_ary_push(list, obj);
10675 else if (io != write_io) {
10678 rb_ary_push(list, obj);
10688 VALUE read, write, except;
10694select_call(
VALUE arg)
10698 return select_internal(p->read, p->write, p->except, p->timeout, p->fdsets);
10702select_end(
VALUE arg)
10707 for (i = 0; i < numberof(p->fdsets); ++i)
10712static VALUE sym_normal, sym_sequential, sym_random,
10713 sym_willneed, sym_dontneed, sym_noreuse;
10715#ifdef HAVE_POSIX_FADVISE
10716struct io_advise_struct {
10724io_advise_internal(
void *arg)
10726 struct io_advise_struct *ptr = arg;
10727 return posix_fadvise(ptr->fd, ptr->offset, ptr->len, ptr->advice);
10731io_advise_sym_to_const(
VALUE sym)
10733#ifdef POSIX_FADV_NORMAL
10734 if (sym == sym_normal)
10735 return INT2NUM(POSIX_FADV_NORMAL);
10738#ifdef POSIX_FADV_RANDOM
10739 if (sym == sym_random)
10740 return INT2NUM(POSIX_FADV_RANDOM);
10743#ifdef POSIX_FADV_SEQUENTIAL
10744 if (sym == sym_sequential)
10745 return INT2NUM(POSIX_FADV_SEQUENTIAL);
10748#ifdef POSIX_FADV_WILLNEED
10749 if (sym == sym_willneed)
10750 return INT2NUM(POSIX_FADV_WILLNEED);
10753#ifdef POSIX_FADV_DONTNEED
10754 if (sym == sym_dontneed)
10755 return INT2NUM(POSIX_FADV_DONTNEED);
10758#ifdef POSIX_FADV_NOREUSE
10759 if (sym == sym_noreuse)
10760 return INT2NUM(POSIX_FADV_NOREUSE);
10767do_io_advise(
rb_io_t *fptr,
VALUE advice, rb_off_t offset, rb_off_t
len)
10770 struct io_advise_struct ias;
10773 num_adv = io_advise_sym_to_const(advice);
10779 if (
NIL_P(num_adv))
10783 ias.advice =
NUM2INT(num_adv);
10784 ias.offset = offset;
10787 rv = (int)rb_thread_io_blocking_region(io_advise_internal, &ias, fptr->
fd);
10788 if (rv && rv != ENOSYS) {
10791 VALUE message = rb_sprintf(
"%"PRIsVALUE
" "
10795 fptr->
pathv, offset,
len, advice);
10805advice_arg_check(
VALUE advice)
10810 if (advice != sym_normal &&
10811 advice != sym_sequential &&
10812 advice != sym_random &&
10813 advice != sym_willneed &&
10814 advice != sym_dontneed &&
10815 advice != sym_noreuse) {
10816 rb_raise(
rb_eNotImpError,
"Unsupported advice: %+"PRIsVALUE, advice);
10854rb_io_advise(
int argc,
VALUE *argv,
VALUE io)
10861 advice_arg_check(advice);
10863 io = GetWriteIO(io);
10869#ifdef HAVE_POSIX_FADVISE
10870 return do_io_advise(fptr, advice,
off, l);
10872 ((void)
off, (
void)l);
11027rb_f_select(
int argc,
VALUE *argv,
VALUE obj)
11030 if (scheduler !=
Qnil) {
11033 if (!UNDEF_P(result))
return result;
11041 rb_scan_args(argc, argv,
"13", &args.read, &args.write, &args.except, &timeout);
11042 if (
NIL_P(timeout)) {
11047 args.timeout = &timerec;
11050 for (i = 0; i < numberof(args.fdsets); ++i)
11056#ifdef IOCTL_REQ_TYPE
11057 typedef IOCTL_REQ_TYPE ioctl_req_t;
11059 typedef int ioctl_req_t;
11060# define NUM2IOCTLREQ(num) ((int)NUM2LONG(num))
11071nogvl_ioctl(
void *ptr)
11073 struct ioctl_arg *arg = ptr;
11075 return (
VALUE)ioctl(arg->fd, arg->cmd, arg->narg);
11079do_ioctl(
int fd, ioctl_req_t cmd,
long narg)
11082 struct ioctl_arg arg;
11088 retval = (int)rb_thread_io_blocking_region(nogvl_ioctl, &arg, fd);
11094#define DEFAULT_IOCTL_NARG_LEN (256)
11096#if defined(__linux__) && defined(_IOC_SIZE)
11098linux_iocparm_len(ioctl_req_t cmd)
11102 if ((cmd & 0xFFFF0000) == 0) {
11104 return DEFAULT_IOCTL_NARG_LEN;
11107 len = _IOC_SIZE(cmd);
11110 if (
len < DEFAULT_IOCTL_NARG_LEN)
11111 len = DEFAULT_IOCTL_NARG_LEN;
11119ioctl_narg_len(ioctl_req_t cmd)
11125#define IOCPARM_LEN(x) (((x) >> 16) & IOCPARM_MASK)
11129 len = IOCPARM_LEN(cmd);
11130#elif defined(__linux__) && defined(_IOC_SIZE)
11131 len = linux_iocparm_len(cmd);
11134 len = DEFAULT_IOCTL_NARG_LEN;
11143typedef long fcntl_arg_t;
11146typedef int fcntl_arg_t;
11150fcntl_narg_len(ioctl_req_t cmd)
11157 len =
sizeof(fcntl_arg_t);
11165#ifdef F_DUPFD_CLOEXEC
11166 case F_DUPFD_CLOEXEC:
11167 len =
sizeof(fcntl_arg_t);
11177 len =
sizeof(fcntl_arg_t);
11187 len =
sizeof(fcntl_arg_t);
11197 len =
sizeof(fcntl_arg_t);
11202 len =
sizeof(
struct f_owner_ex);
11207 len =
sizeof(
struct f_owner_ex);
11212 len =
sizeof(
struct flock);
11217 len =
sizeof(
struct flock);
11222 len =
sizeof(
struct flock);
11242 len =
sizeof(fcntl_arg_t);
11252 len =
sizeof(fcntl_arg_t);
11257 len =
sizeof(fcntl_arg_t);
11270fcntl_narg_len(ioctl_req_t cmd)
11276#define NARG_SENTINEL 17
11279setup_narg(ioctl_req_t cmd,
VALUE *argp,
long (*narg_len)(ioctl_req_t))
11290 else if (arg ==
Qtrue) {
11304 len = narg_len(cmd);
11305 rb_str_modify(arg);
11307 slen = RSTRING_LEN(arg);
11309 if (slen <
len+1) {
11310 rb_str_resize(arg,
len+1);
11311 MEMZERO(RSTRING_PTR(arg)+slen,
char,
len-slen);
11315 ptr = RSTRING_PTR(arg);
11316 ptr[slen - 1] = NARG_SENTINEL;
11325finish_narg(
int retval,
VALUE arg,
const rb_io_t *fptr)
11327 if (retval < 0) rb_sys_fail_path(fptr->
pathv);
11332 if (ptr[slen-1] != NARG_SENTINEL)
11333 rb_raise(rb_eArgError,
"return value overflowed string");
11334 ptr[slen-1] =
'\0';
11344 ioctl_req_t cmd = NUM2IOCTLREQ(req);
11349 narg = setup_narg(cmd, &arg, ioctl_narg_len);
11351 retval = do_ioctl(fptr->
fd, cmd, narg);
11352 return finish_narg(retval, arg, fptr);
11379 return rb_ioctl(io, req, arg);
11382#define rb_io_ioctl rb_f_notimplement
11393nogvl_fcntl(
void *ptr)
11395 struct fcntl_arg *arg = ptr;
11397#if defined(F_DUPFD)
11398 if (arg->cmd == F_DUPFD)
11401 return (
VALUE)fcntl(arg->fd, arg->cmd, arg->narg);
11405do_fcntl(
int fd,
int cmd,
long narg)
11408 struct fcntl_arg arg;
11414 retval = (int)rb_thread_io_blocking_region(nogvl_fcntl, &arg, fd);
11415 if (retval != -1) {
11417#if defined(F_DUPFD)
11420#if defined(F_DUPFD_CLOEXEC)
11421 case F_DUPFD_CLOEXEC:
11438 narg = setup_narg(cmd, &arg, fcntl_narg_len);
11440 retval = do_fcntl(fptr->
fd, cmd, narg);
11441 return finish_narg(retval, arg, fptr);
11467 return rb_fcntl(io, req, arg);
11470#define rb_io_fcntl rb_f_notimplement
11473#if defined(HAVE_SYSCALL) || defined(HAVE___SYSCALL)
11505#if SIZEOF_VOIDP == 8 && defined(HAVE___SYSCALL) && SIZEOF_INT != 8
11506# define SYSCALL __syscall
11507# define NUM2SYSCALLID(x) NUM2LONG(x)
11508# define RETVAL2NUM(x) LONG2NUM(x)
11509# if SIZEOF_LONG == 8
11510 long num, retval = -1;
11511# elif SIZEOF_LONG_LONG == 8
11512 long long num, retval = -1;
11514# error ---->> it is asserted that __syscall takes the first argument and returns retval in 64bit signed integer. <<----
11516#elif defined(__linux__)
11517# define SYSCALL syscall
11518# define NUM2SYSCALLID(x) NUM2LONG(x)
11519# define RETVAL2NUM(x) LONG2NUM(x)
11527 long num, retval = -1;
11529# define SYSCALL syscall
11530# define NUM2SYSCALLID(x) NUM2INT(x)
11531# define RETVAL2NUM(x) INT2NUM(x)
11532 int num, retval = -1;
11538 "We plan to remove a syscall function at future release. DL(Fiddle) provides safer alternative.");
11542 rb_raise(rb_eArgError,
"too few arguments for syscall");
11543 if (argc > numberof(arg))
11544 rb_raise(rb_eArgError,
"too many arguments for syscall");
11545 num = NUM2SYSCALLID(argv[0]); ++argv;
11546 for (i = argc - 1; i--; ) {
11561 retval = SYSCALL(num);
11564 retval = SYSCALL(num, arg[0]);
11567 retval = SYSCALL(num, arg[0],arg[1]);
11570 retval = SYSCALL(num, arg[0],arg[1],arg[2]);
11573 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3]);
11576 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4]);
11579 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5]);
11582 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6]);
11588 return RETVAL2NUM(retval);
11590#undef NUM2SYSCALLID
11594#define rb_f_syscall rb_f_notimplement
11598io_new_instance(
VALUE args)
11604find_encoding(
VALUE v)
11607 if (!enc)
rb_warn(
"Unsupported encoding %"PRIsVALUE
" ignored", v);
11619 enc2 = find_encoding(v1);
11622 if (RSTRING_LEN(tmp) == 1 && RSTRING_PTR(tmp)[0] ==
'-') {
11628 enc = find_encoding(v2);
11635 enc = find_encoding(v2);
11641 if (enc2 == rb_ascii8bit_encoding()) {
11646 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11652 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
11653 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11658 if (!
NIL_P(tmp) && rb_enc_asciicompat(enc = rb_enc_get(tmp))) {
11659 parse_mode_enc(RSTRING_PTR(tmp), enc, &enc, &enc2, NULL);
11660 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11664 rb_io_ext_int_to_encs(find_encoding(v1), NULL, &enc, &enc2, 0);
11665 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11670 validate_enc_binmode(&fptr->
mode, ecflags, enc, enc2);
11675 clear_codeconv(fptr);
11687io_encoding_set_v(
VALUE v)
11690 io_encoding_set(arg->fptr, arg->v1, arg->v2, arg->opt);
11695pipe_pair_close(
VALUE rw)
11698 return rb_ensure(io_close, rwp[0], io_close, rwp[1]);
11781rb_io_s_pipe(
int argc,
VALUE *argv,
VALUE klass)
11783 int pipes[2], state;
11784 VALUE r, w, args[3], v1, v2;
11791 argc =
rb_scan_args(argc, argv,
"02:", &v1, &v2, &opt);
11798 r = rb_protect(io_new_instance, (
VALUE)args, &state);
11802 rb_jump_tag(state);
11806 ies_args.fptr = fptr;
11809 ies_args.opt = opt;
11810 rb_protect(io_encoding_set_v, (
VALUE)&ies_args, &state);
11814 rb_jump_tag(state);
11819 w = rb_protect(io_new_instance, (
VALUE)args, &state);
11823 rb_jump_tag(state);
11828 extract_binmode(opt, &fmode);
11835#if DEFAULT_TEXTMODE
11837 fptr->
mode &= ~FMODE_TEXTMODE;
11838 setmode(fptr->
fd, O_BINARY);
11840#if RUBY_CRLF_ENVIRONMENT
11846 fptr->
mode |= fmode;
11847#if DEFAULT_TEXTMODE
11849 fptr2->
mode &= ~FMODE_TEXTMODE;
11850 setmode(fptr2->
fd, O_BINARY);
11853 fptr2->
mode |= fmode;
11855 ret = rb_assoc_new(r, w);
11887 else if (!
NIL_P(v = rb_hash_aref(opt, sym_open_args))) {
11890 v = rb_to_array_type(v);
11895 arg->io = rb_io_open(klass, path, vmode, vperm, opt);
11899io_s_foreach(
VALUE v)
11904 if (arg->limit == 0)
11905 rb_raise(rb_eArgError,
"invalid limit: 0 for foreach");
11906 while (!
NIL_P(str = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, arg->io))) {
11995rb_io_s_foreach(
int argc,
VALUE *argv,
VALUE self)
11998 int orig_argc = argc;
12002 argc =
rb_scan_args(argc, argv,
"12:", NULL, NULL, NULL, &opt);
12004 extract_getline_args(argc-1, argv+1, &garg);
12005 open_key_args(self, argc, argv, opt, &arg);
12007 extract_getline_opts(opt, &garg);
12008 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12009 return rb_ensure(io_s_foreach, (
VALUE)&garg, rb_io_close, arg.io);
12013io_s_readlines(
VALUE v)
12016 return io_readlines(arg, arg->io);
12074rb_io_s_readlines(
int argc,
VALUE *argv,
VALUE io)
12080 argc =
rb_scan_args(argc, argv,
"12:", NULL, NULL, NULL, &opt);
12081 extract_getline_args(argc-1, argv+1, &garg);
12082 open_key_args(io, argc, argv, opt, &arg);
12084 extract_getline_opts(opt, &garg);
12085 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12086 return rb_ensure(io_s_readlines, (
VALUE)&garg, rb_io_close, arg.io);
12093 return io_read(arg->argc, arg->argv, arg->io);
12103seek_before_access(
VALUE argp)
12107 return rb_io_seek(arg->io, arg->offset, arg->mode);
12153rb_io_s_read(
int argc,
VALUE *argv,
VALUE io)
12159 argc =
rb_scan_args(argc, argv,
"13:", NULL, NULL, &offset, NULL, &opt);
12161 rb_raise(rb_eArgError,
"negative offset %ld given",
off);
12163 open_key_args(io, argc, argv, opt, &arg);
12165 if (!
NIL_P(offset)) {
12169 sarg.offset = offset;
12170 sarg.mode = SEEK_SET;
12171 rb_protect(seek_before_access, (
VALUE)&sarg, &state);
12174 rb_jump_tag(state);
12176 if (arg.argc == 2) arg.argc = 1;
12195rb_io_s_binread(
int argc,
VALUE *argv,
VALUE io)
12210 convconfig.
enc = rb_ascii8bit_encoding();
12211 arg.io = rb_io_open_generic(io, argv[0], oflags, fmode, &convconfig, 0);
12214 arg.argc = (argc > 1) ? 1 : 0;
12215 if (!
NIL_P(offset)) {
12219 sarg.offset = offset;
12220 sarg.mode = SEEK_SET;
12221 rb_protect(seek_before_access, (
VALUE)&sarg, &state);
12224 rb_jump_tag(state);
12231io_s_write0(
VALUE v)
12234 return io_write(arg->io,arg->str,arg->nosync);
12238io_s_write(
int argc,
VALUE *argv,
VALUE klass,
int binary)
12240 VALUE string, offset, opt;
12244 rb_scan_args(argc, argv,
"21:", NULL, &
string, &offset, &opt);
12246 if (
NIL_P(opt)) opt = rb_hash_new();
12247 else opt = rb_hash_dup(opt);
12250 if (
NIL_P(rb_hash_aref(opt,sym_mode))) {
12251 int mode = O_WRONLY|O_CREAT;
12253 if (binary) mode |= O_BINARY;
12255 if (
NIL_P(offset)) mode |= O_TRUNC;
12256 rb_hash_aset(opt,sym_mode,
INT2NUM(mode));
12258 open_key_args(klass, argc, argv, opt, &arg);
12261 if (binary) rb_io_binmode_m(arg.io);
12265 if (!
NIL_P(offset)) {
12269 sarg.offset = offset;
12270 sarg.mode = SEEK_SET;
12271 rb_protect(seek_before_access, (
VALUE)&sarg, &state);
12274 rb_jump_tag(state);
12282 return rb_ensure(io_s_write0, (
VALUE)&warg, rb_io_close, arg.io);
12330rb_io_s_write(
int argc,
VALUE *argv,
VALUE io)
12332 return io_s_write(argc, argv, io, 0);
12349rb_io_s_binwrite(
int argc,
VALUE *argv,
VALUE io)
12351 return io_s_write(argc, argv, io, 1);
12357 rb_off_t copy_length;
12358 rb_off_t src_offset;
12362 unsigned close_src : 1;
12363 unsigned close_dst : 1;
12366 const char *syserr;
12367 const char *notimp;
12369 struct stat src_stat;
12370 struct stat dst_stat;
12371#ifdef HAVE_FCOPYFILE
12372 copyfile_state_t copyfile_state;
12377exec_interrupts(
void *arg)
12380 rb_thread_execute_interrupts(th);
12394#if defined(ERESTART)
12399 rb_thread_execute_interrupts(stp->th);
12418fiber_scheduler_wait_for(
void * _arguments)
12428# define IOWAIT_SYSCALL "poll"
12429STATIC_ASSERT(pollin_expected, POLLIN == RB_WAITFD_IN);
12430STATIC_ASSERT(pollout_expected, POLLOUT == RB_WAITFD_OUT);
12435 if (scheduler !=
Qnil) {
12438 return RTEST(args.result);
12442 if (fd == -1)
return 0;
12447 fds.events = events;
12449 int timeout_milliseconds = -1;
12452 timeout_milliseconds = (int)(timeout->tv_sec * 1000) + (int)(timeout->tv_usec / 1000);
12455 return poll(&fds, 1, timeout_milliseconds);
12458# define IOWAIT_SYSCALL "select"
12463 if (scheduler !=
Qnil) {
12466 return RTEST(args.result);
12486 case RB_WAITFD_OUT:
12490 VM_UNREACHABLE(nogvl_wait_for);
12510 ret = nogvl_wait_for(stp->th, stp->src_fptr, RB_WAITFD_IN, NULL);
12512 }
while (ret < 0 && maygvl_copy_stream_continue_p(has_gvl, stp));
12515 stp->syserr = IOWAIT_SYSCALL;
12516 stp->error_no =
errno;
12528 ret = nogvl_wait_for(stp->th, stp->dst_fptr, RB_WAITFD_OUT, NULL);
12529 }
while (ret < 0 && maygvl_copy_stream_continue_p(0, stp));
12532 stp->syserr = IOWAIT_SYSCALL;
12533 stp->error_no =
errno;
12539#ifdef USE_COPY_FILE_RANGE
12542simple_copy_file_range(
int in_fd, rb_off_t *in_offset,
int out_fd, rb_off_t *out_offset,
size_t count,
unsigned int flags)
12544#ifdef HAVE_COPY_FILE_RANGE
12545 return copy_file_range(in_fd, in_offset, out_fd, out_offset, count, flags);
12547 return syscall(__NR_copy_file_range, in_fd, in_offset, out_fd, out_offset, count, flags);
12556 rb_off_t copy_length, src_offset, *src_offset_ptr;
12558 if (!S_ISREG(stp->src_stat.st_mode))
12561 src_size = stp->src_stat.st_size;
12562 src_offset = stp->src_offset;
12563 if (src_offset >= (rb_off_t)0) {
12564 src_offset_ptr = &src_offset;
12567 src_offset_ptr = NULL;
12570 copy_length = stp->copy_length;
12571 if (copy_length < (rb_off_t)0) {
12572 if (src_offset < (rb_off_t)0) {
12573 rb_off_t current_offset;
12575 current_offset = lseek(stp->src_fptr->
fd, 0, SEEK_CUR);
12576 if (current_offset < (rb_off_t)0 &&
errno) {
12577 stp->syserr =
"lseek";
12578 stp->error_no =
errno;
12579 return (
int)current_offset;
12581 copy_length = src_size - current_offset;
12584 copy_length = src_size - src_offset;
12588 retry_copy_file_range:
12589# if SIZEOF_OFF_T > SIZEOF_SIZE_T
12591 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
12593 ss = (ssize_t)copy_length;
12595 ss = simple_copy_file_range(stp->src_fptr->
fd, src_offset_ptr, stp->dst_fptr->
fd, NULL, ss, 0);
12599 if (0 < copy_length) {
12600 goto retry_copy_file_range;
12604 if (maygvl_copy_stream_continue_p(0, stp)) {
12605 goto retry_copy_file_range;
12619#if EWOULDBLOCK != EAGAIN
12623 int ret = nogvl_copy_stream_wait_write(stp);
12624 if (ret < 0)
return ret;
12626 goto retry_copy_file_range;
12630 int flags = fcntl(stp->dst_fptr->
fd, F_GETFL);
12632 if (flags != -1 && flags & O_APPEND) {
12638 stp->syserr =
"copy_file_range";
12639 stp->error_no =
errno;
12646#ifdef HAVE_FCOPYFILE
12650 rb_off_t cur, ss = 0;
12651 const rb_off_t src_offset = stp->src_offset;
12654 if (stp->copy_length >= (rb_off_t)0) {
12659 if (!S_ISREG(stp->src_stat.st_mode))
12662 if (!S_ISREG(stp->dst_stat.st_mode))
12664 if (lseek(stp->dst_fptr->
fd, 0, SEEK_CUR) > (rb_off_t)0)
12666 if (fcntl(stp->dst_fptr->
fd, F_GETFL) & O_APPEND) {
12669 rb_off_t end = lseek(stp->dst_fptr->
fd, 0, SEEK_END);
12670 lseek(stp->dst_fptr->
fd, 0, SEEK_SET);
12671 if (end > (rb_off_t)0)
return 0;
12674 if (src_offset > (rb_off_t)0) {
12679 cur = lseek(stp->src_fptr->
fd, 0, SEEK_CUR);
12680 if (cur < (rb_off_t)0 &&
errno) {
12681 stp->error_no =
errno;
12686 r = lseek(stp->src_fptr->
fd, src_offset, SEEK_SET);
12687 if (r < (rb_off_t)0 &&
errno) {
12688 stp->error_no =
errno;
12693 stp->copyfile_state = copyfile_state_alloc();
12694 ret = fcopyfile(stp->src_fptr->
fd, stp->dst_fptr->
fd, stp->copyfile_state, COPYFILE_DATA);
12695 copyfile_state_get(stp->copyfile_state, COPYFILE_STATE_COPIED, &ss);
12699 if (src_offset > (rb_off_t)0) {
12703 r = lseek(stp->src_fptr->
fd, cur, SEEK_SET);
12704 if (r < (rb_off_t)0 &&
errno) {
12705 stp->error_no =
errno;
12717 stp->syserr =
"fcopyfile";
12718 stp->error_no =
errno;
12725#ifdef HAVE_SENDFILE
12728# define USE_SENDFILE
12730# ifdef HAVE_SYS_SENDFILE_H
12731# include <sys/sendfile.h>
12735simple_sendfile(
int out_fd,
int in_fd, rb_off_t *offset, rb_off_t count)
12737 return sendfile(out_fd, in_fd, offset, (
size_t)count);
12740# elif 0 || defined(__APPLE__)
12744# define USE_SENDFILE
12747simple_sendfile(
int out_fd,
int in_fd, rb_off_t *offset, rb_off_t count)
12750 rb_off_t pos = offset ? *offset : lseek(in_fd, 0, SEEK_CUR);
12753 r = sendfile(in_fd, out_fd, pos, &count, NULL, 0);
12756 r = sendfile(in_fd, out_fd, pos, (
size_t)count, NULL, &sbytes, 0);
12758 if (r != 0 && sbytes == 0)
return r;
12763 lseek(in_fd, sbytes, SEEK_CUR);
12765 return (ssize_t)sbytes;
12778 rb_off_t copy_length;
12779 rb_off_t src_offset;
12782 if (!S_ISREG(stp->src_stat.st_mode))
12785 src_size = stp->src_stat.st_size;
12787 if ((stp->dst_stat.st_mode & S_IFMT) != S_IFSOCK)
12791 src_offset = stp->src_offset;
12792 use_pread = src_offset >= (rb_off_t)0;
12794 copy_length = stp->copy_length;
12795 if (copy_length < (rb_off_t)0) {
12797 copy_length = src_size - src_offset;
12801 cur = lseek(stp->src_fptr->
fd, 0, SEEK_CUR);
12802 if (cur < (rb_off_t)0 &&
errno) {
12803 stp->syserr =
"lseek";
12804 stp->error_no =
errno;
12807 copy_length = src_size - cur;
12812# if SIZEOF_OFF_T > SIZEOF_SIZE_T
12814 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
12816 ss = (ssize_t)copy_length;
12819 ss = simple_sendfile(stp->dst_fptr->
fd, stp->src_fptr->
fd, &src_offset, ss);
12822 ss = simple_sendfile(stp->dst_fptr->
fd, stp->src_fptr->
fd, NULL, ss);
12827 if (0 < copy_length) {
12828 goto retry_sendfile;
12832 if (maygvl_copy_stream_continue_p(0, stp))
12833 goto retry_sendfile;
12846#if EWOULDBLOCK != EAGAIN
12859 ret = maygvl_copy_stream_wait_read(0, stp);
12860 if (ret < 0)
return ret;
12862 ret = nogvl_copy_stream_wait_write(stp);
12863 if (ret < 0)
return ret;
12865 goto retry_sendfile;
12867 stp->syserr =
"sendfile";
12868 stp->error_no =
errno;
12876maygvl_read(
int has_gvl,
rb_io_t *fptr,
void *buf,
size_t count)
12879 return rb_io_read_memory(fptr, buf, count);
12881 return read(fptr->
fd, buf, count);
12885maygvl_copy_stream_read(
int has_gvl,
struct copy_stream_struct *stp,
char *buf,
size_t len, rb_off_t offset)
12889 if (offset < (rb_off_t)0) {
12890 ss = maygvl_read(has_gvl, stp->src_fptr, buf,
len);
12893 ss = pread(stp->src_fptr->
fd, buf,
len, offset);
12899 if (maygvl_copy_stream_continue_p(has_gvl, stp))
12903#if EWOULDBLOCK != EAGAIN
12907 int ret = maygvl_copy_stream_wait_read(has_gvl, stp);
12908 if (ret < 0)
return ret;
12913 stp->notimp =
"pread";
12917 stp->syserr = offset < (rb_off_t)0 ?
"read" :
"pread";
12918 stp->error_no =
errno;
12929 ss = write(stp->dst_fptr->
fd, buf+
off,
len);
12931 if (maygvl_copy_stream_continue_p(0, stp))
12933 if (io_again_p(
errno)) {
12934 int ret = nogvl_copy_stream_wait_write(stp);
12935 if (ret < 0)
return ret;
12938 stp->syserr =
"write";
12939 stp->error_no =
errno;
12956 rb_off_t copy_length;
12957 rb_off_t src_offset;
12961 copy_length = stp->copy_length;
12962 use_eof = copy_length < (rb_off_t)0;
12963 src_offset = stp->src_offset;
12964 use_pread = src_offset >= (rb_off_t)0;
12966 if (use_pread && stp->close_src) {
12969 r = lseek(stp->src_fptr->
fd, src_offset, SEEK_SET);
12970 if (r < (rb_off_t)0 &&
errno) {
12971 stp->syserr =
"lseek";
12972 stp->error_no =
errno;
12975 src_offset = (rb_off_t)-1;
12979 while (use_eof || 0 < copy_length) {
12980 if (!use_eof && copy_length < (rb_off_t)
sizeof(buf)) {
12981 len = (size_t)copy_length;
12987 ss = maygvl_copy_stream_read(0, stp, buf,
len, src_offset);
12992 ss = maygvl_copy_stream_read(0, stp, buf,
len, (rb_off_t)-1);
12997 ret = nogvl_copy_stream_write(stp, buf, ss);
13007nogvl_copy_stream_func(
void *arg)
13010#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13014#ifdef USE_COPY_FILE_RANGE
13015 ret = nogvl_copy_file_range(stp);
13020#ifdef HAVE_FCOPYFILE
13021 ret = nogvl_fcopyfile(stp);
13027 ret = nogvl_copy_stream_sendfile(stp);
13032 nogvl_copy_stream_read_write(stp);
13034#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13041copy_stream_fallback_body(
VALUE arg)
13044 const int buflen = 16*1024;
13046 VALUE buf = rb_str_buf_new(buflen);
13047 rb_off_t rest = stp->copy_length;
13048 rb_off_t
off = stp->src_offset;
13049 ID read_method = id_readpartial;
13051 if (!stp->src_fptr) {
13053 read_method = id_read;
13060 if (stp->copy_length < (rb_off_t)0) {
13065 rb_str_resize(buf, 0);
13068 l = buflen < rest ? buflen : (long)rest;
13070 if (!stp->src_fptr) {
13073 if (read_method == id_read &&
NIL_P(rc))
13078 rb_str_resize(buf, buflen);
13079 ss = maygvl_copy_stream_read(1, stp, RSTRING_PTR(buf), l,
off);
13080 rb_str_resize(buf, ss > 0 ? ss : 0);
13085 if (
off >= (rb_off_t)0)
13088 n = rb_io_write(stp->dst, buf);
13090 stp->total += numwrote;
13092 if (read_method == id_read && RSTRING_LEN(buf) == 0) {
13103 if (!stp->src_fptr && stp->src_offset >= (rb_off_t)0) {
13104 rb_raise(rb_eArgError,
"cannot specify src_offset for non-IO");
13113copy_stream_body(
VALUE arg)
13116 VALUE src_io = stp->src, dst_io = stp->dst;
13117 const int common_oflags = 0
13127 if (src_io ==
argf ||
13128 !(RB_TYPE_P(src_io,
T_FILE) ||
13131 stp->src_fptr = NULL;
13136 if (!
NIL_P(tmp_io)) {
13139 else if (!RB_TYPE_P(src_io,
T_FILE)) {
13143 args[1] =
INT2NUM(O_RDONLY|common_oflags);
13146 stp->close_src = 1;
13151 stat_ret = fstat(stp->src_fptr->
fd, &stp->src_stat);
13152 if (stat_ret < 0) {
13153 stp->syserr =
"fstat";
13154 stp->error_no =
errno;
13159 if (dst_io ==
argf ||
13160 !(RB_TYPE_P(dst_io,
T_FILE) ||
13163 stp->dst_fptr = NULL;
13168 if (!
NIL_P(tmp_io)) {
13169 dst_io = GetWriteIO(tmp_io);
13171 else if (!RB_TYPE_P(dst_io,
T_FILE)) {
13175 args[1] =
INT2NUM(O_WRONLY|O_CREAT|O_TRUNC|common_oflags);
13179 stp->close_dst = 1;
13182 dst_io = GetWriteIO(dst_io);
13188 stat_ret = fstat(stp->dst_fptr->
fd, &stp->dst_stat);
13189 if (stat_ret < 0) {
13190 stp->syserr =
"fstat";
13191 stp->error_no =
errno;
13198 SET_BINARY_MODE_WITH_SEEK_CUR(stp->src_fptr);
13201 io_ascii8bit_binmode(stp->dst_fptr);
13203 if (stp->src_offset < (rb_off_t)0 && stp->src_fptr && stp->src_fptr->
rbuf.
len) {
13206 if (stp->copy_length >= (rb_off_t)0 && stp->copy_length < (rb_off_t)
len) {
13207 len = (size_t)stp->copy_length;
13209 str = rb_str_buf_new(
len);
13210 rb_str_resize(str,
len);
13211 read_buffered_data(RSTRING_PTR(str),
len, stp->src_fptr);
13212 if (stp->dst_fptr) {
13213 if (io_binwrite(str, RSTRING_PTR(str), RSTRING_LEN(str), stp->dst_fptr, 0) < 0)
13214 rb_sys_fail_on_write(stp->dst_fptr);
13217 rb_io_write(dst_io, str);
13218 rb_str_resize(str, 0);
13220 if (stp->copy_length >= (rb_off_t)0)
13221 stp->copy_length -=
len;
13224 if (stp->dst_fptr && io_fflush(stp->dst_fptr) < 0) {
13228 if (stp->copy_length == 0)
13231 if (stp->src_fptr == NULL || stp->dst_fptr == NULL) {
13232 return copy_stream_fallback(stp);
13240copy_stream_finalize(
VALUE arg)
13244#ifdef HAVE_FCOPYFILE
13245 if (stp->copyfile_state) {
13246 copyfile_state_free(stp->copyfile_state);
13250 if (stp->close_src) {
13251 rb_io_close_m(stp->src);
13253 if (stp->close_dst) {
13254 rb_io_close_m(stp->dst);
13317rb_io_s_copy_stream(
int argc,
VALUE *argv,
VALUE io)
13319 VALUE src, dst, length, src_offset;
13324 rb_scan_args(argc, argv,
"22", &src, &dst, &length, &src_offset);
13329 st.src_fptr = NULL;
13330 st.dst_fptr = NULL;
13333 st.copy_length = (rb_off_t)-1;
13335 st.copy_length =
NUM2OFFT(length);
13337 if (
NIL_P(src_offset))
13338 st.src_offset = (rb_off_t)-1;
13340 st.src_offset =
NUM2OFFT(src_offset);
13359rb_io_external_encoding(
VALUE io)
13364 return rb_enc_from_encoding(fptr->
encs.
enc2);
13368 return rb_enc_from_encoding(fptr->
encs.
enc);
13371 return rb_enc_from_encoding(io_read_encoding(fptr));
13387rb_io_internal_encoding(
VALUE io)
13392 return rb_enc_from_encoding(io_read_encoding(fptr));
13426rb_io_set_encoding(
int argc,
VALUE *argv,
VALUE io)
13431 if (!RB_TYPE_P(io,
T_FILE)) {
13432 return forward(io, id_set_encoding, argc, argv);
13435 argc =
rb_scan_args(argc, argv,
"11:", &v1, &v2, &opt);
13437 io_encoding_set(fptr, v1, v2, opt);
13442rb_stdio_set_default_encoding(
void)
13447 if (isatty(fileno(stdin))) {
13449 rb_encoding *internal = rb_default_internal_encoding();
13450 if (!internal) internal = rb_default_external_encoding();
13452 rb_enc_from_encoding(external),
13453 rb_enc_from_encoding(internal),
13458 rb_io_set_encoding(1, &val,
rb_stdin);
13459 rb_io_set_encoding(1, &val,
rb_stdout);
13460 rb_io_set_encoding(1, &val,
rb_stderr);
13464global_argf_p(
VALUE arg)
13466 return arg ==
argf;
13469typedef VALUE (*argf_encoding_func)(
VALUE io);
13472argf_encoding(
VALUE argf, argf_encoding_func func)
13474 if (!
RTEST(ARGF.current_file)) {
13475 return rb_enc_default_external();
13499 return argf_encoding(
argf, rb_io_external_encoding);
13518 return argf_encoding(
argf, rb_io_internal_encoding);
13557 if (!next_argv()) {
13558 rb_raise(rb_eArgError,
"no stream to set encoding");
13560 rb_io_set_encoding(argc, argv, ARGF.current_file);
13562 ARGF.encs = fptr->
encs;
13581 if (!next_argv()) {
13582 rb_raise(rb_eArgError,
"no stream to tell");
13584 ARGF_FORWARD(0, 0);
13585 return rb_io_tell(ARGF.current_file);
13598 if (!next_argv()) {
13599 rb_raise(rb_eArgError,
"no stream to seek");
13601 ARGF_FORWARD(argc, argv);
13602 return rb_io_seek_m(argc, argv, ARGF.current_file);
13619 if (!next_argv()) {
13620 rb_raise(rb_eArgError,
"no stream to set position");
13622 ARGF_FORWARD(1, &offset);
13623 return rb_io_set_pos(ARGF.current_file, offset);
13644 if (!next_argv()) {
13645 rb_raise(rb_eArgError,
"no stream to rewind");
13647 ARGF_FORWARD(0, 0);
13648 old_lineno =
RFILE(ARGF.current_file)->fptr->lineno;
13649 ret = rb_io_rewind(ARGF.current_file);
13650 if (!global_argf_p(
argf)) {
13651 ARGF.last_lineno = ARGF.lineno -= old_lineno;
13669 if (!next_argv()) {
13670 rb_raise(rb_eArgError,
"no stream");
13672 ARGF_FORWARD(0, 0);
13673 return rb_io_fileno(ARGF.current_file);
13692 ARGF_FORWARD(0, 0);
13693 return ARGF.current_file;
13718 if (
RTEST(ARGF.current_file)) {
13719 if (ARGF.init_p == 0)
return Qtrue;
13721 ARGF_FORWARD(0, 0);
13780 VALUE tmp, str, length;
13784 if (!
NIL_P(length)) {
13789 rb_str_resize(str,0);
13794 if (!next_argv()) {
13797 if (ARGF_GENERIC_INPUT_P()) {
13798 tmp = argf_forward(argc, argv,
argf);
13801 tmp = io_read(argc, argv, ARGF.current_file);
13803 if (
NIL_P(str)) str = tmp;
13806 if (ARGF.next_p != -1) {
13812 else if (argc >= 1) {
13813 long slen = RSTRING_LEN(str);
13829argf_forward_call(
VALUE arg)
13832 argf_forward(p->argc, p->argv, p->argf);
13862 return argf_getpartial(argc, argv,
argf,
Qnil, 0);
13883 return argf_getpartial(argc, argv,
argf, opts, 1);
13889 VALUE tmp, str, length;
13897 no_exception = no_exception_p(opts);
13899 if (!next_argv()) {
13901 rb_str_resize(str, 0);
13905 if (ARGF_GENERIC_INPUT_P()) {
13915 tmp = io_getpartial(argc, argv, ARGF.current_file, no_exception, nonblock);
13918 if (ARGF.next_p == -1) {
13919 return io_nonblock_eof(no_exception);
13924 return io_nonblock_eof(no_exception);
13962 if (!next_argv())
return Qnil;
13963 if (ARGF_GENERIC_INPUT_P()) {
13964 ch = forward_current(rb_intern(
"getc"), 0, 0);
13967 ch = rb_io_getc(ARGF.current_file);
13969 if (
NIL_P(ch) && ARGF.next_p != -1) {
14002 if (!next_argv())
return Qnil;
14003 if (!RB_TYPE_P(ARGF.current_file,
T_FILE)) {
14004 ch = forward_current(rb_intern(
"getbyte"), 0, 0);
14009 if (
NIL_P(ch) && ARGF.next_p != -1) {
14042 if (!next_argv()) rb_eof_error();
14043 if (!RB_TYPE_P(ARGF.current_file,
T_FILE)) {
14044 ch = forward_current(rb_intern(
"getc"), 0, 0);
14047 ch = rb_io_getc(ARGF.current_file);
14049 if (
NIL_P(ch) && ARGF.next_p != -1) {
14081 NEXT_ARGF_FORWARD(0, 0);
14082 c = argf_getbyte(
argf);
14089#define FOREACH_ARGF() while (next_argv())
14094 const VALUE current = ARGF.current_file;
14096 if (ARGF.init_p == -1 || current != ARGF.current_file) {
14102#define ARGF_block_call(mid, argc, argv, func, argf) \
14103 rb_block_call_kw(ARGF.current_file, mid, argc, argv, \
14104 func, argf, rb_keyword_given_p())
14109 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_i,
argf);
14110 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14116 if (!global_argf_p(
argf)) {
14117 ARGF.last_lineno = ++ARGF.lineno;
14119 return argf_block_call_i(i,
argf, argc, argv, blockarg);
14125 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_line_i,
argf);
14126 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14174 argf_block_call_line(rb_intern(
"each_line"), argc, argv,
argf);
14205 argf_block_call(rb_intern(
"each_byte"), 0, 0,
argf);
14231 argf_block_call(rb_intern(
"each_char"), 0, 0,
argf);
14257 argf_block_call(rb_intern(
"each_codepoint"), 0, 0,
argf);
14288 return ARGF.filename;
14292argf_filename_getter(
ID id,
VALUE *var)
14294 return argf_filename(*var);
14319 return ARGF.current_file;
14338 ARGF_FORWARD(0, 0);
14359 return RBOOL(ARGF.binmode);
14379 if (ARGF.init_p && ARGF.next_p == 0) {
14408 if (ARGF.next_p != -1) {
14426 ARGF_FORWARD(0, 0);
14453 if (!ARGF.inplace)
return Qnil;
14455 return rb_str_dup(ARGF.inplace);
14461 return argf_inplace_mode_get(*var);
14492 ARGF.inplace =
Qnil;
14495 ARGF.inplace = rb_str_new_frozen(val);
14503 argf_inplace_mode_set(*var, val);
14507ruby_set_inplace_mode(
const char *suffix)
14533argf_argv_getter(
ID id,
VALUE *var)
14535 return argf_argv(*var);
14554 if (!
RTEST(ARGF.current_file)) {
14557 return GetWriteIO(ARGF.current_file);
14569 return rb_io_write(argf_write_io(
argf), str);
14584 case RB_IO_WAIT_WRITABLE:
14587 c = rb_eEAGAINWaitWritable;
14589#if EAGAIN != EWOULDBLOCK
14591 c = rb_eEWOULDBLOCKWaitWritable;
14595 c = rb_eEINPROGRESSWaitWritable;
14601 case RB_IO_WAIT_READABLE:
14604 c = rb_eEAGAINWaitReadable;
14606#if EAGAIN != EWOULDBLOCK
14608 c = rb_eEWOULDBLOCKWaitReadable;
14612 c = rb_eEINPROGRESSWaitReadable;
14619 rb_bug(
"invalid read/write type passed to rb_readwrite_sys_fail: %d", waiting);
14625get_LAST_READ_LINE(
ID _x,
VALUE *_y)
15282#include <sys/cygwin.h>
15283 static struct __cygwin_perfile pf[] =
15285 {
"", O_RDONLY | O_BINARY},
15286 {
"", O_WRONLY | O_BINARY},
15287 {
"", O_RDWR | O_BINARY},
15288 {
"", O_APPEND | O_BINARY},
15291 cygwin_internal(CW_PERFILE, pf);
15346#if EAGAIN == EWOULDBLOCK
15347 rb_eEWOULDBLOCKWaitReadable = rb_eEAGAINWaitReadable;
15350 rb_eEWOULDBLOCKWaitWritable = rb_eEAGAINWaitWritable;
15392 rb_output_fs =
Qnil;
15395 rb_default_rs = rb_fstring_lit(
"\n");
15396 rb_gc_register_mark_object(rb_default_rs);
15397 rb_rs = rb_default_rs;
15404 rb_gvar_ractor_local(
"$_");
15520 rb_gvar_ractor_local(
"$stdin");
15521 rb_gvar_ractor_local(
"$stdout");
15522 rb_gvar_ractor_local(
"$>");
15523 rb_gvar_ractor_local(
"$stderr");
15609 rb_define_method(rb_cARGF,
"external_encoding", argf_external_encoding, 0);
15610 rb_define_method(rb_cARGF,
"internal_encoding", argf_internal_encoding, 0);
15629 rb_gvar_ractor_local(
"$-i");
15633#if defined (_WIN32) || defined(__CYGWIN__)
15634 atexit(pipe_atexit);
15646 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_method(klass, mid, func, arity)
Defines klass#mid.
#define rb_define_singleton_method(klass, mid, func, arity)
Defines klass.mid.
#define rb_define_global_function(mid, func, arity)
Defines rb_mKernel #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_class_new(VALUE super)
Creates a new, anonymous 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.
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.
#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 rb_str_cat2
Old name of rb_str_cat_cstr.
#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 category, const char *fmt,...)
Identical to rb_category_warning(), except it reports unless $VERBOSE is nil.
void rb_category_warning(rb_warning_category_t category, const char *fmt,...)
Identical to rb_warning(), except it takes additional "category" parameter.
VALUE rb_eNotImpError
NotImplementedError exception.
void rb_syserr_fail(int e, const char *mesg)
Raises appropriate exception that represents a C errno.
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.
VALUE rb_eStandardError
StandardError 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_eTypeError
TypeError exception.
VALUE rb_eEOFError
EOFError 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.
rb_io_wait_readwrite
for rb_readwrite_sys_fail first argument
VALUE rb_eRuntimeError
RuntimeError exception.
void rb_warn(const char *fmt,...)
Identical to rb_warning(), except it reports unless $VERBOSE is nil.
VALUE rb_eSystemCallError
SystemCallError exception.
@ RB_WARN_CATEGORY_DEPRECATED
Warning is for deprecated features.
VALUE rb_mKernel
Kernel module.
VALUE rb_check_to_int(VALUE val)
Identical to rb_check_to_integer(), except it uses #to_int for conversion.
VALUE rb_any_to_s(VALUE obj)
Generates a textual representation of the given object.
VALUE rb_obj_alloc(VALUE klass)
Allocates an instance of the given class.
VALUE rb_class_new_instance(int argc, const VALUE *argv, VALUE klass)
Allocates, then initialises an instance of the given class.
VALUE rb_class_new_instance_kw(int argc, const VALUE *argv, VALUE klass, int kw_splat)
Identical to rb_class_new_instance(), except you can specify how to handle the last element of the gi...
VALUE rb_mEnumerable
Enumerable module.
VALUE rb_stdin
STDIN constant.
VALUE rb_stderr
STDERR constant.
VALUE rb_obj_class(VALUE obj)
Queries the class of an object.
VALUE rb_obj_dup(VALUE obj)
Duplicates the given object.
VALUE rb_inspect(VALUE obj)
Generates a human-readable textual representation of the given object.
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.
VALUE rb_to_int(VALUE val)
Identical to rb_check_to_int(), except it raises in case of conversion mismatch.
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.
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.
static int rb_enc_mbminlen(rb_encoding *enc)
Queries the minimum number of bytes that the passed encoding needs to represent a character.
VALUE rb_enc_uint_chr(unsigned int code, rb_encoding *enc)
Encodes the passed code point into a series of bytes.
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.
rb_econv_result_t
return value of rb_econv_convert()
@ 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.
#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.
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_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.
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.
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_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_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.
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...
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.
#define rb_str_new(str, len)
Allocates an instance of rb_cString.
#define rb_str_buf_cat
Just another name of rb_str_cat.
#define rb_usascii_str_new(str, len)
Identical to rb_str_new, except it generates a string of "US ASCII" encoding.
size_t rb_str_capacity(VALUE str)
Queries the capacity of the given string.
VALUE rb_str_locktmp(VALUE str)
Obtains a "temporary lock" of the string.
rb_gvar_setter_t rb_str_setter
This is a rb_gvar_setter_t that refutes non-string assignments.
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_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().
void rb_str_modify_expand(VALUE str, long capa)
Identical to rb_str_modify(), except it additionally expands the capacity of the receiver.
#define rb_str_new_cstr(str)
Identical to rb_str_new, except it assumes the passed pointer is a pointer to a C string.
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_sleep(int sec)
Blocks for the given period of time.
struct timeval rb_time_interval(VALUE num)
Creates a "time interval".
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.
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().
#define RB_ID2SYM
Just another name of rb_id2sym.
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_const(VALUE klass, const char *name, VALUE val)
Defines a Ruby level constant under a namespace.
#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_timeout(VALUE io)
Get the timeout associated with the specified io object.
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.
int rb_io_mode(VALUE io)
Get the mode of the IO.
rb_io_event
Type of events that an IO can wait.
@ RUBY_IO_READABLE
IO::READABLE
@ RUBY_IO_PRIORITY
IO::PRIORITY
@ RUBY_IO_WRITABLE
IO::WRITABLE
#define FMODE_READWRITE
The IO is opened for both read/write.
#define FMODE_EXTERNAL
This flag means that an IO object is wrapping an "external" file descriptor, which is owned by someth...
#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.
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.
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.
int capa
Designed capacity of the buffer.
#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.
VALUE rb_eIOTimeoutError
Indicates that a timeout has occurred while performing an IO operation.
char * ptr
Pointer to the underlying memory region, of at least capa bytes.
#define FMODE_SYNC
The IO is in "sync mode".
int off
Offset inside of ptr.
VALUE rb_io_path(VALUE io)
Returns the path for the given IO.
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".
VALUE rb_io_check_io(VALUE io)
Try converting an object to its IO representation using its to_io method, if any.
VALUE rb_io_closed_p(VALUE io)
Returns whether or not the underlying IO is closed.
VALUE rb_io_set_timeout(VALUE io, VALUE timeout)
Set the timeout associated with the specified io object.
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)
Instructs the OS to put its internal file structure into "nonblocking 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_open_descriptor(VALUE klass, int descriptor, int mode, VALUE path, VALUE timeout, struct rb_io_encoding *encoding)
Allocate a new IO object, with the given file descriptor.
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.
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.
int len
Length of the buffer.
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.
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.
void * rb_thread_call_with_gvl(void *(*func)(void *), void *data1)
(Re-)acquires the GVL.
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.
#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.
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.
void rb_define_hooked_variable(const char *q, VALUE *w, type *e, void_type *r)
Define a function-backended global variable.
void rb_define_virtual_variable(const char *q, type *w, void_type *e)
Define a function-backended global variable.
VALUE rb_rescue2(type *q, VALUE w, type *e, VALUE r,...)
An equivalent of rescue clause.
VALUE rb_ensure(type *q, VALUE w, type *e, VALUE r)
An equivalent of ensure clause.
#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_isset
Queries if the given fd is in the rb_fdset_t.
#define rb_fd_select
Waits for multiple file descriptors at once.
#define rb_fd_init
Initialises the :given :rb_fdset_t.
#define rb_fd_set
Sets the given fd to the rb_fdset_t.
#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.
#define RSTRING_GETMEM(str, ptrvar, lenvar)
Convenient macro to obtain the contents and length at once.
#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 errno
Ractor-aware version of errno.
#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_io_pread_memory(VALUE scheduler, VALUE io, rb_off_t from, void *base, size_t size, size_t length)
Non-blocking pread from the passed IO using a native buffer.
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)
Non-blocking wait until the passed IO is ready for reading.
VALUE rb_fiber_scheduler_io_read_memory(VALUE scheduler, VALUE io, void *base, size_t size, size_t length)
Non-blocking read from the passed IO using a native buffer.
VALUE rb_fiber_scheduler_io_wait(VALUE scheduler, VALUE io, VALUE events, VALUE timeout)
Non-blocking 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_io_selectv(VALUE scheduler, int argc, VALUE *argv)
Non-blocking version of IO.select, argv variant.
VALUE rb_fiber_scheduler_io_pwrite_memory(VALUE scheduler, VALUE io, rb_off_t from, const void *base, size_t size, size_t length)
Non-blocking pwrite to the passed IO using a native buffer.
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_write_memory(VALUE scheduler, VALUE io, const void *base, size_t size, size_t length)
Non-blocking write to the passed IO using a native buffer.
VALUE rb_fiber_scheduler_io_wait_writable(VALUE scheduler, VALUE io)
Non-blocking wait until the passed IO is ready for writing.
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.
static bool RB_TEST(VALUE obj)
Emulates Ruby's "if" statement.
#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).
Decomposed encoding flags (e.g.
VALUE ecopts
Flags as Ruby hash.
rb_encoding * enc2
External encoding.
rb_encoding * enc
Internal encoding.
char * ptr
Pointer to the underlying memory region, of at least capa bytes.
int off
Offset inside of ptr.
int len
Length of the buffer.
int capa
Designed capacity of the buffer.
Ruby's IO, metadata and buffers.
int mode
mode flags: FMODE_XXXs
rb_io_buffer_t wbuf
Write buffer.
void(* finalize)(struct rb_io *, int)
finalize proc
rb_econv_t * readconv
Encoding converter used when reading from this IO.
rb_econv_t * writeconv
Encoding converter used when writing to this IO.
struct rb_io_encoding encs
Decomposed encoding flags.
VALUE self
The IO's Ruby level counterpart.
VALUE write_lock
This is a Ruby level mutex.
VALUE timeout
The timeout associated with this IO when performing blocking operations.
FILE * stdio_file
stdio ptr for read/write, if available.
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.
int writeconv_initialized
Whether rb_io_t::writeconv is already set up.
rb_io_buffer_t rbuf
(Byte) read buffer.
int lineno
number of lines read
VALUE writeconv_asciicompat
This is, when set, an instance of rb_cString which holds the "common" encoding.
rb_io_buffer_t cbuf
rb_io_ungetc() destination.
rb_pid_t pid
child's pid (for pipes)
int writeconv_pre_ecflags
Value of ::rb_io_t::rb_io_enc_t::ecflags stored right before initialising rb_io_t::writeconv.
VALUE pathv
pathname for file
intptr_t SIGNED_VALUE
A signed integer type that has the same width with VALUE.
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
uintptr_t VALUE
Type that represents a Ruby object.
static bool RB_SYMBOL_P(VALUE obj)
Queries if the object is an instance of rb_cSymbol.
static void Check_Type(VALUE v, enum ruby_value_type t)
Identical to RB_TYPE_P(), except it raises exceptions on predication failure.