14#include "ruby/internal/config.h"
25# if defined(__linux__)
28# if defined(__FreeBSD_version) && __FreeBSD_version >= 1100000
38#define free(x) xfree(x)
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(__CYGWIN__) || defined(_WIN32)
52# define NO_SAFE_RENAME
55#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__sun) || defined(_nec_ews)
64#ifdef HAVE_SYS_IOCTL_H
67#if defined(HAVE_FCNTL_H)
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>
108# ifndef COPYFILE_STATE_COPIED
114# undef HAVE_FCOPYFILE
120# include <AvailabilityMacros.h>
124#include "ccan/list/list.h"
129#include "internal/class.h"
130#include "internal/encoding.h"
131#include "internal/error.h"
132#include "internal/inits.h"
133#include "internal/io.h"
134#include "internal/numeric.h"
135#include "internal/object.h"
136#include "internal/process.h"
137#include "internal/thread.h"
138#include "internal/transcode.h"
139#include "internal/variable.h"
142#include "ruby/missing.h"
145#include "ruby_atomic.h"
155#define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR)
159# ifdef _POSIX_PIPE_BUF
160# define PIPE_BUF _POSIX_PIPE_BUF
167# define EWOULDBLOCK EAGAIN
170#if defined(HAVE___SYSCALL) && (defined(__APPLE__) || defined(__OpenBSD__))
172off_t __syscall(quad_t number, ...);
175#define IO_RBUF_CAPA_MIN 8192
176#define IO_CBUF_CAPA_MIN (128*1024)
177#define IO_RBUF_CAPA_FOR(fptr) (NEED_READCONV(fptr) ? IO_CBUF_CAPA_MIN : IO_RBUF_CAPA_MIN)
178#define IO_WBUF_CAPA_MIN 8192
180#define IO_MAX_BUFFER_GROWTH 8 * 1024 * 1024
185#define open rb_w32_uopen
187#define rename(f, t) rb_w32_urename((f), (t))
188#include "win32/file.h"
198static VALUE rb_eEAGAINWaitReadable;
199static VALUE rb_eEAGAINWaitWritable;
200#if EAGAIN != EWOULDBLOCK
201static VALUE rb_eEWOULDBLOCKWaitReadable;
202static VALUE rb_eEWOULDBLOCKWaitWritable;
204static VALUE rb_eEINPROGRESSWaitWritable;
205static VALUE rb_eEINPROGRESSWaitReadable;
208static VALUE orig_stdout, orig_stderr;
217static ID id_write, id_read, id_flush, id_readpartial, id_set_encoding, id_fileno;
218static VALUE sym_mode, sym_perm, sym_flags, sym_extenc, sym_intenc, sym_encoding, sym_open_args;
219static VALUE sym_textmode, sym_binmode, sym_autoclose;
220static VALUE sym_SET, sym_CUR, sym_END;
221static VALUE sym_wait_readable, sym_wait_writable;
223static VALUE sym_DATA;
226static VALUE sym_HOLE;
229static VALUE prep_io(
int fd,
enum rb_io_mode fmode,
VALUE klass,
const char *path);
232rb_io_blocking_region_wait(
struct rb_io *io, rb_blocking_function_t *function,
void *argument,
enum rb_io_event events)
234 return rb_thread_io_blocking_call(io, function, argument, events);
237VALUE rb_io_blocking_region(
struct rb_io *io, rb_blocking_function_t *function,
void *argument)
239 return rb_io_blocking_region_wait(io, function, argument, 0);
243 VALUE filename, current_file;
249 int8_t init_p, next_p, binmode;
253#if defined(__APPLE__) && \
254 (!defined(MAC_OS_VERSION_27_0) || (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_VERSION_27_0))
256# if __has_attribute(availability) && __has_warning("-Wunguarded-availability-new")
262static inline int (*rb_dup3(
void))(int, int, int) {
return &dup3;}
263# define dup3 rb_dup3()
267static inline int (*rb_pipe2(
void))(
int [2], int) {
return &pipe2;}
268# define pipe2 rb_pipe2()
293 if (fd < 0 || afd <= max_fd)
296#if defined(HAVE_FCNTL) && defined(F_GETFL)
297 err = fcntl(fd, F_GETFL) == -1;
301 err = fstat(fd, &buf) != 0;
304 if (err &&
errno == EBADF) {
305 rb_bug(
"rb_update_max_fd: invalid fd (%d) given.", fd);
308 while (max_fd < afd) {
309 max_fd = ATOMIC_CAS(max_file_descriptor, max_fd, afd);
314rb_maygvl_fd_fix_cloexec(
int fd)
317#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
318 int flags, flags2, ret;
319 flags = fcntl(fd, F_GETFD);
321 rb_bug(
"rb_maygvl_fd_fix_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(
errno));
324 flags2 = flags & ~FD_CLOEXEC;
326 flags2 = flags | FD_CLOEXEC;
327 if (flags != flags2) {
328 ret = fcntl(fd, F_SETFD, flags2);
330 rb_bug(
"rb_maygvl_fd_fix_cloexec: fcntl(%d, F_SETFD, %d) failed: %s", fd, flags2, strerror(
errno));
339 rb_maygvl_fd_fix_cloexec(fd);
345rb_fix_detect_o_cloexec(
int fd)
347#if defined(O_CLOEXEC) && defined(F_GETFD)
348 int flags = fcntl(fd, F_GETFD);
351 rb_bug(
"rb_fix_detect_o_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(
errno));
353 if (flags & FD_CLOEXEC)
356 rb_maygvl_fd_fix_cloexec(fd);
363 return (e == EWOULDBLOCK) || (e == EAGAIN);
370 static int o_cloexec_state = -1;
372 static const int retry_interval = 0;
373 static const int retry_max_count = 10000;
380#elif defined O_NOINHERIT
381 flags |= O_NOINHERIT;
384 while ((ret = open(pathname, flags, mode)) == -1) {
386 if (!io_again_p(e))
break;
387 if (retry_count++ >= retry_max_count)
break;
389 sleep(retry_interval);
392 if (ret < 0)
return ret;
393 if (ret <= 2 || o_cloexec_state == 0) {
394 rb_maygvl_fd_fix_cloexec(ret);
396 else if (o_cloexec_state > 0) {
400 o_cloexec_state = rb_fix_detect_o_cloexec(ret);
419 if (oldfd == newfd) {
423#if defined(HAVE_DUP3) && defined(O_CLOEXEC)
424# if defined(__APPLE__)
425# define try_dup3 (dup3 != NULL)
426# define abandon_dup3() true
428 static bool try_dup3 =
true;
429# define abandon_dup3() (errno != ENOSYS || !!(try_dup3 = false))
435 ret = dup3(oldfd, newfd, O_CLOEXEC);
442 if (abandon_dup3())
return ret;
445 ret = dup2(oldfd, newfd);
446 if (ret < 0)
return ret;
448 rb_maygvl_fd_fix_cloexec(ret);
453rb_fd_set_nonblock(
int fd)
456 return rb_w32_set_nonblock(fd);
457#elif defined(F_GETFL)
458 int oflags = fcntl(fd, F_GETFL);
462 if (oflags & O_NONBLOCK)
464 oflags |= O_NONBLOCK;
465 return fcntl(fd, F_SETFL, oflags);
471cloexec_pipe(
int descriptors[2],
int flags,
bool force_cloexec)
475# if defined(__APPLE__)
476# define try_pipe2 (pipe2 != NULL)
477# define abandon_pipe2() true
479 static bool try_pipe2 =
true;
480# define abandon_pipe2() (errno != ENOSYS || !!(try_pipe2 = false))
483 result = pipe2(descriptors, O_CLOEXEC | flags);
484 if (result == 0)
return result;
485 if (abandon_pipe2())
return result;
488 if (result < 0 && (result = pipe(descriptors)) < 0)
492 if (result == 0 && descriptors[1] == -1) {
493 close(descriptors[0]);
500 if (!force_cloexec)
return result;
503 rb_maygvl_fd_fix_cloexec(descriptors[0]);
504 rb_maygvl_fd_fix_cloexec(descriptors[1]);
507 rb_fd_set_nonblock(descriptors[0]);
508 rb_fd_set_nonblock(descriptors[1]);
517 return cloexec_pipe(descriptors, O_NONBLOCK,
true);
525#if defined(HAVE_FCNTL) && defined(F_DUPFD_CLOEXEC) && defined(F_DUPFD)
526 static int try_dupfd_cloexec = 1;
527 if (try_dupfd_cloexec) {
528 ret = fcntl(fd, F_DUPFD_CLOEXEC, minfd);
531 rb_maygvl_fd_fix_cloexec(ret);
535 if (
errno == EINVAL) {
536 ret = fcntl(fd, F_DUPFD, minfd);
538 try_dupfd_cloexec = 0;
543 ret = fcntl(fd, F_DUPFD, minfd);
545#elif defined(HAVE_FCNTL) && defined(F_DUPFD)
546 ret = fcntl(fd, F_DUPFD, minfd);
549 if (ret >= 0 && ret < minfd) {
550 const int prev_fd = ret;
556 if (ret < 0)
return ret;
557 rb_maygvl_fd_fix_cloexec(ret);
561#define argf_of(obj) (*(struct argf *)DATA_PTR(obj))
562#define ARGF argf_of(argf)
563#define ARGF_SET(field, value) RB_OBJ_WRITE(argf, &ARGF.field, value)
565#define GetWriteIO(io) rb_io_get_write_io(io)
567#define READ_DATA_PENDING(fptr) ((fptr)->rbuf.len)
568#define READ_DATA_PENDING_COUNT(fptr) ((fptr)->rbuf.len)
569#define READ_DATA_PENDING_PTR(fptr) ((fptr)->rbuf.ptr+(fptr)->rbuf.off)
570#define READ_DATA_BUFFERED(fptr) READ_DATA_PENDING(fptr)
572#define READ_CHAR_PENDING(fptr) ((fptr)->cbuf.len)
573#define READ_CHAR_PENDING_COUNT(fptr) ((fptr)->cbuf.len)
574#define READ_CHAR_PENDING_PTR(fptr) ((fptr)->cbuf.ptr+(fptr)->cbuf.off)
577#define WAIT_FD_IN_WIN32(fptr) \
578 (rb_w32_io_cancelable_p((fptr)->fd) ? Qnil : rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_READABLE), RUBY_IO_TIMEOUT_DEFAULT))
580#define WAIT_FD_IN_WIN32(fptr)
583#define READ_CHECK(fptr) do {\
584 if (!READ_DATA_PENDING(fptr)) {\
585 WAIT_FD_IN_WIN32(fptr);\
586 rb_io_check_closed(fptr);\
592# define S_ISSOCK(m) _S_ISSOCK(m)
595# define S_ISSOCK(m) (((m) & S_IFMT) == _S_IFSOCK)
598# define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
604static int io_fflush(
rb_io_t *);
605static rb_io_t *flush_before_seek(
rb_io_t *fptr,
bool discard_rbuf);
606static void clear_readconv(
rb_io_t *fptr);
607static void clear_codeconv(
rb_io_t *fptr);
609#define FMODE_SIGNAL_ON_EPIPE (1<<17)
611#define fptr_signal_on_epipe(fptr) \
612 (((fptr)->mode & FMODE_SIGNAL_ON_EPIPE) != 0)
614#define fptr_set_signal_on_epipe(fptr, flag) \
616 (fptr)->mode |= FMODE_SIGNAL_ON_EPIPE : \
617 (fptr)->mode &= ~FMODE_SIGNAL_ON_EPIPE)
619extern ID ruby_static_id_signo;
621NORETURN(
static void rb_sys_fail_on_write(
rb_io_t *fptr));
623rb_sys_fail_on_write(
rb_io_t *fptr)
626 VALUE errinfo = rb_syserr_new_path(e, (fptr)->pathv);
628 if (fptr_signal_on_epipe(fptr) && (e == EPIPE)) {
640#define NEED_NEWLINE_DECORATOR_ON_READ(fptr) ((fptr)->mode & FMODE_TEXTMODE)
641#define NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) ((fptr)->mode & FMODE_TEXTMODE)
642#if defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32)
643# define RUBY_CRLF_ENVIRONMENT 1
645# define RUBY_CRLF_ENVIRONMENT 0
648#if RUBY_CRLF_ENVIRONMENT
650# define DEFAULT_TEXTMODE FMODE_TEXTMODE
651# define TEXTMODE_NEWLINE_DECORATOR_ON_WRITE ECONV_CRLF_NEWLINE_DECORATOR
659#define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || (fptr)->encs.ecflags & ~ECONV_CRLF_NEWLINE_DECORATOR)
660#define WRITECONV_MASK ( \
661 (ECONV_DECORATOR_MASK & ~ECONV_CRLF_NEWLINE_DECORATOR)|\
662 ECONV_STATEFUL_DECORATOR_MASK|\
664#define NEED_WRITECONV(fptr) ( \
665 ((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || \
666 ((fptr)->encs.ecflags & WRITECONV_MASK) || \
668#define SET_BINARY_MODE(fptr) setmode((fptr)->fd, O_BINARY)
670#define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) do {\
671 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {\
672 if (((fptr)->mode & FMODE_READABLE) &&\
673 !((fptr)->encs.ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {\
674 setmode((fptr)->fd, O_BINARY);\
677 setmode((fptr)->fd, O_TEXT);\
682#define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) do {\
683 if ((enc2) && ((ecflags) & ECONV_DEFAULT_NEWLINE_DECORATOR)) {\
684 (ecflags) |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;\
692io_unread(
rb_io_t *fptr,
bool discard_rbuf)
708 if (!rb_w32_fd_is_text(fptr->
fd)) {
709 r = lseek(fptr->
fd, -fptr->
rbuf.
len, SEEK_CUR);
710 if (r < 0 &&
errno) {
713 if (!discard_rbuf)
return;
719 pos = lseek(fptr->
fd, 0, SEEK_CUR);
720 if (pos < 0 &&
errno) {
723 if (!discard_rbuf)
goto end;
727 extra_max = (long)(pos - fptr->
rbuf.
len);
735 for (i = 0; i < fptr->
rbuf.
len; i++) {
736 if (*p ==
'\n') newlines++;
737 if (extra_max == newlines)
break;
742 while (newlines >= 0) {
743 r = lseek(fptr->
fd, pos - fptr->
rbuf.
len - newlines, SEEK_SET);
744 if (newlines == 0)
break;
749 read_size = _read(fptr->
fd, buf, fptr->
rbuf.
len + newlines);
753 rb_syserr_fail_path(e, fptr->
pathv);
755 if (read_size == fptr->
rbuf.
len) {
756 lseek(fptr->
fd, r, SEEK_SET);
767 clear_codeconv(fptr);
779set_binary_mode_with_seek_cur(
rb_io_t *fptr)
781 if (!rb_w32_fd_is_text(fptr->
fd))
return O_BINARY;
784 return setmode(fptr->
fd, O_BINARY);
786 flush_before_seek(fptr,
false);
787 return setmode(fptr->
fd, O_BINARY);
789#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) set_binary_mode_with_seek_cur(fptr)
793# define DEFAULT_TEXTMODE 0
794#define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || NEED_NEWLINE_DECORATOR_ON_READ(fptr))
795#define NEED_WRITECONV(fptr) ( \
796 ((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || \
797 NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) || \
798 ((fptr)->encs.ecflags & (ECONV_DECORATOR_MASK|ECONV_STATEFUL_DECORATOR_MASK)) || \
800#define SET_BINARY_MODE(fptr) (void)(fptr)
801#define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) (void)(fptr)
802#define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) ((void)(enc2), (void)(ecflags))
803#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) (void)(fptr)
806#if !defined HAVE_SHUTDOWN && !defined shutdown
807#define shutdown(a,b) 0
811#define is_socket(fd, path) rb_w32_is_socket(fd)
812#elif !defined(S_ISSOCK)
813#define is_socket(fd, path) 0
816is_socket(
int fd,
VALUE path)
819 if (fstat(fd, &sbuf) < 0)
820 rb_sys_fail_path(path);
821 return S_ISSOCK(sbuf.st_mode);
825static const char closed_stream[] =
"closed stream";
828io_fd_check_closed(
int fd)
861 io_fd_check_closed(fptr->
fd);
865rb_io_get_fptr(
VALUE io)
875 return rb_convert_type_with_id(io,
T_FILE,
"IO", idTo_io);
881 return rb_check_convert_type_with_id(io,
T_FILE,
"IO", idTo_io);
899 rb_io_t *fptr = rb_io_get_fptr(io);
908 return write_io ? write_io :
Qnil;
921 rb_io_t *fptr = rb_io_get_fptr(self);
951 if (
RTEST(timeout)) {
955 rb_io_t *fptr = rb_io_get_fptr(self);
980#if !RUBY_CRLF_ENVIRONMENT
982io_unread(
rb_io_t *fptr,
bool discard_rbuf)
990 r = lseek(fptr->
fd, -fptr->
rbuf.
len, SEEK_CUR);
991 if (r < 0 &&
errno) {
994 if (!discard_rbuf)
return;
998 clear_codeconv(fptr);
1008 long len = RSTRING_LEN(str);
1011 const int min_capa = IO_RBUF_CAPA_FOR(fptr);
1014#if SIZEOF_LONG > SIZEOF_INT
1041 long len = RSTRING_LEN(str);
1047 io_ungetbyte(str, fptr);
1051 int capa = (int)
len + pending;
1065flush_before_seek(
rb_io_t *fptr,
bool discard_rbuf)
1067 if (io_fflush(fptr) < 0)
1068 rb_sys_fail_on_write(fptr);
1069 io_unread(fptr, discard_rbuf);
1074#define io_seek(fptr, ofs, whence) (errno = 0, lseek(flush_before_seek(fptr, true)->fd, (ofs), (whence)))
1075#define io_tell(fptr) lseek(flush_before_seek(fptr, false)->fd, 0, SEEK_CUR)
1091 if (io_fflush(fptr) < 0)
1092 rb_sys_fail_on_write(fptr);
1097 if (io_fflush(wfptr) < 0)
1098 rb_sys_fail_on_write(wfptr);
1106 if (READ_CHAR_PENDING(fptr)) {
1107 rb_raise(
rb_eIOError,
"byte oriented read for character buffered IO");
1118io_read_encoding(
rb_io_t *fptr)
1123 return rb_default_external_encoding();
1127io_input_encoding(
rb_io_t *fptr)
1132 return io_read_encoding(fptr);
1143 io_unread(fptr,
true);
1148rb_io_read_pending(
rb_io_t *fptr)
1151 if (READ_CHAR_PENDING(fptr))
1153 return READ_DATA_PENDING(fptr);
1159 if (!READ_DATA_PENDING(fptr)) {
1166rb_gc_for_fd(
int err)
1168 if (err == EMFILE || err == ENFILE || err == ENOMEM) {
1178#define TRY_WITH_GC(expr) \
1179 for (int first_errno, retried_errno = 0, retried = 0; \
1182 (!rb_gc_for_fd(first_errno = errno) || !(expr)) && \
1183 (retried_errno = errno, 1)); \
1184 (void)retried_errno, retried = 1)
1199io_alloc(
VALUE klass)
1201 UNPROTECTED_NEWOBJ_OF(io,
struct RFile, klass,
T_FILE,
sizeof(
struct RFile));
1209# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
1235struct io_internal_writev_struct {
1242 const struct iovec *iov;
1255io_internal_wait(
VALUE thread,
rb_io_t *fptr,
int error,
int events,
struct timeval *timeout)
1257 if (!timeout && rb_thread_mn_schedulable(thread)) {
1262 int ready = nogvl_wait_for(thread, fptr, events, timeout);
1267 else if (ready == 0) {
1284internal_read_func(
void *ptr)
1289 if (iis->timeout && !iis->nonblock) {
1290 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_IN, iis->timeout) == -1) {
1296 result = read(iis->fd, iis->buf, iis->capa);
1298 if (result < 0 && !iis->nonblock) {
1299 if (io_again_p(
errno)) {
1300 if (io_internal_wait(iis->th, iis->fptr,
errno, RB_WAITFD_IN, iis->timeout) == -1) {
1312#if defined __APPLE__
1313# define do_write_retry(code) do {result = code;} while (result == -1 && errno == EPROTOTYPE)
1315# define do_write_retry(code) result = code
1319internal_write_func(
void *ptr)
1324 if (iis->timeout && !iis->nonblock) {
1325 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1331 do_write_retry(write(iis->fd, iis->buf, iis->capa));
1333 if (result < 0 && !iis->nonblock) {
1335 if (io_again_p(e)) {
1336 if (io_internal_wait(iis->th, iis->fptr,
errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1350internal_writev_func(
void *ptr)
1352 struct io_internal_writev_struct *iis = ptr;
1355 if (iis->timeout && !iis->nonblock) {
1356 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1362 do_write_retry(writev(iis->fd, iis->iov, iis->iovcnt));
1364 if (result < 0 && !iis->nonblock) {
1365 if (io_again_p(
errno)) {
1366 if (io_internal_wait(iis->th, iis->fptr,
errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1380rb_io_read_memory(
rb_io_t *fptr,
void *buf,
size_t count)
1384 if (scheduler !=
Qnil) {
1387 if (!UNDEF_P(result)) {
1403 struct timeval timeout_storage;
1407 iis.timeout = &timeout_storage;
1410 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_read_func, &iis,
RUBY_IO_READABLE);
1414rb_io_write_memory(
rb_io_t *fptr,
const void *buf,
size_t count)
1418 if (scheduler !=
Qnil) {
1421 if (!UNDEF_P(result)) {
1437 struct timeval timeout_storage;
1441 iis.timeout = &timeout_storage;
1444 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_write_func, &iis,
RUBY_IO_WRITABLE);
1449rb_writev_internal(
rb_io_t *fptr,
const struct iovec *iov,
int iovcnt)
1451 if (!iovcnt)
return 0;
1456 if (scheduler !=
Qnil) {
1460 if (!UNDEF_P(result)) {
1465 struct io_internal_writev_struct iis = {
1476 struct timeval timeout_storage;
1480 iis.timeout = &timeout_storage;
1483 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_writev_func, &iis,
RUBY_IO_WRITABLE);
1488io_flush_buffer_sync(
void *arg)
1510io_flush_buffer_fiber_scheduler(
VALUE scheduler,
rb_io_t *fptr)
1513 if (!UNDEF_P(ret)) {
1525io_flush_buffer_async(
VALUE arg)
1530 if (scheduler !=
Qnil) {
1531 VALUE result = io_flush_buffer_fiber_scheduler(scheduler, fptr);
1532 if (!UNDEF_P(result)) {
1537 return rb_io_blocking_region_wait(fptr, io_flush_buffer_sync, fptr,
RUBY_IO_WRITABLE);
1544 return (
int)io_flush_buffer_async((
VALUE)fptr);
1559 while (fptr->
wbuf.
len > 0 && io_flush_buffer(fptr) != 0) {
1575 if (scheduler !=
Qnil) {
1585 if (NIL_OR_UNDEF_P(timeout)) {
1589 if (timeout !=
Qnil) {
1594 int ready = rb_thread_io_wait(th, fptr,
RB_NUM2INT(events), tv);
1620 if (scheduler !=
Qnil) {
1626 return rb_thread_wait_for_single_fd(th, fd, events, timeout);
1632 io_fd_check_closed(f);
1639#if defined(ERESTART)
1646#if EWOULDBLOCK != EAGAIN
1649 if (scheduler !=
Qnil) {
1667 io_fd_check_closed(f);
1674#if defined(ERESTART)
1690#if EWOULDBLOCK != EAGAIN
1693 if (scheduler !=
Qnil) {
1713 return io_wait_for_single_fd(fd, events, timeout, th, scheduler);
1747#if defined(ERESTART)
1757#if EWOULDBLOCK != EAGAIN
1774 if (
RTEST(result)) {
1789 if (
RTEST(result)) {
1803 const char *senc, *denc;
1810 ecflags = fptr->
encs.
ecflags & ~ECONV_NEWLINE_DECORATOR_READ_MASK;
1837 denc = rb_enc_name(enc);
1869io_binwrite_string_internal(
rb_io_t *fptr,
const char *ptr,
long length)
1872 struct iovec iov[2];
1875 iov[0].iov_len = fptr->
wbuf.
len;
1876 iov[1].iov_base = (
void*)ptr;
1877 iov[1].iov_len = length;
1879 ssize_t result = rb_writev_internal(fptr, iov, 2);
1884 if (result >= fptr->
wbuf.
len) {
1892 fptr->
wbuf.
off += (int)result;
1893 fptr->
wbuf.
len -= (int)result;
1901 return rb_io_write_memory(fptr, ptr, length);
1906io_binwrite_string_internal(
rb_io_t *fptr,
const char *ptr,
long length)
1908 long remaining = length;
1911 if (fptr->
wbuf.
len+length <= fptr->wbuf.capa) {
1918 fptr->
wbuf.
len += (int)length;
1925 if (io_fflush(fptr) < 0) {
1930 if (remaining == 0) {
1936 return rb_io_write_memory(fptr, ptr, length);
1941io_binwrite_string(
VALUE arg)
1945 const char *ptr = p->ptr;
1946 size_t remaining = p->length;
1950 ssize_t result = io_binwrite_string_internal(p->fptr, ptr, remaining);
1956 else if (result > 0) {
1957 if ((
size_t)result == remaining)
break;
1959 remaining -= result;
1975io_allocate_write_buffer(
rb_io_t *fptr,
int sync)
1980 fptr->
wbuf.
capa = IO_WBUF_CAPA_MIN;
1991io_binwrite_requires_flush_write(
rb_io_t *fptr,
long len,
int nosync)
2006io_binwrite(
const char *ptr,
long len,
rb_io_t *fptr,
int nosync)
2008 if (
len <= 0)
return len;
2013 io_allocate_write_buffer(fptr, !nosync);
2015 if (io_binwrite_requires_flush_write(fptr,
len, nosync)) {
2026 return io_binwrite_string((
VALUE)&arg);
2043# define MODE_BTMODE(a,b,c) ((fmode & FMODE_BINMODE) ? (b) : \
2044 (fmode & FMODE_TEXTMODE) ? (c) : (a))
2046#define MODE_BTXMODE(a, b, c, d, e, f) ((fmode & FMODE_EXCL) ? \
2047 MODE_BTMODE(d, e, f) : \
2048 MODE_BTMODE(a, b, c))
2053 if (NEED_WRITECONV(fptr)) {
2055 SET_BINARY_MODE(fptr);
2057 make_writeconv(fptr);
2060#define fmode (fptr->mode)
2063 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1) && !rb_enc_asciicompat(rb_enc_get(str))) {
2064 rb_raise(rb_eArgError,
"ASCII incompatible string written for text mode IO without encoding conversion: %s",
2065 rb_enc_name(rb_enc_get(str)));
2071 common_encoding = rb_enc_from_encoding(fptr->
encs.
enc2);
2072 else if (fptr->
encs.
enc != rb_ascii8bit_encoding())
2073 common_encoding = rb_enc_from_encoding(fptr->
encs.
enc);
2076 if (!
NIL_P(common_encoding)) {
2087#if RUBY_CRLF_ENVIRONMENT
2088#define fmode (fptr->mode)
2089 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1)) {
2092 setmode(fptr->
fd, O_BINARY);
2095 setmode(fptr->
fd, O_TEXT);
2097 if (!rb_enc_asciicompat(rb_enc_get(str))) {
2098 rb_raise(rb_eArgError,
"ASCII incompatible string written for text mode IO without encoding conversion: %s",
2099 rb_enc_name(rb_enc_get(str)));
2117 if (rb_w32_write_console(str, fptr->
fd) > 0)
return RSTRING_LEN(str);
2121 str = do_writeconv(str, fptr, &converted);
2125 tmp = rb_str_tmp_frozen_no_embed_acquire(str);
2127 n = io_binwrite(ptr,
len, fptr, nosync);
2128 rb_str_tmp_frozen_release(str, tmp);
2140 return (ssize_t)io_binwrite(buf, (
long)size, fptr, 0);
2150 io = GetWriteIO(io);
2160 if (RSTRING_LEN(str) == 0)
return INT2FIX(0);
2165 n = io_fwrite(str, fptr, nosync);
2166 if (n < 0L) rb_sys_fail_on_write(fptr);
2172struct binwritev_arg {
2180io_binwritev_internal(
VALUE arg)
2182 struct binwritev_arg *p = (
struct binwritev_arg *)arg;
2184 size_t remaining = p->total;
2188 struct iovec *iov = p->iov;
2189 int iovcnt = p->iovcnt;
2192 long result = rb_writev_internal(fptr, iov, iovcnt);
2197 if (offset < (
size_t)fptr->
wbuf.
len) {
2202 offset -= (size_t)fptr->
wbuf.
len;
2208 if (offset == p->total) {
2212 while (result >= (ssize_t)iov->iov_len) {
2214 result -= iov->iov_len;
2224 iov->iov_base = (
char *)iov->iov_base + result;
2225 iov->iov_len -= result;
2239io_binwritev(
struct iovec *iov,
int iovcnt,
rb_io_t *fptr)
2244 if (iovcnt == 0)
return 0;
2247 for (
int i = 1; i < iovcnt; i++) total += iov[i].iov_len;
2249 io_allocate_write_buffer(fptr, 1);
2255 if (offset + total <= (
size_t)fptr->
wbuf.
capa) {
2256 for (
int i = 1; i < iovcnt; i++) {
2257 memcpy(fptr->
wbuf.
ptr+offset, iov[i].iov_base, iov[i].iov_len);
2258 offset += iov[i].iov_len;
2269 if (io_fflush(fptr) < 0)
return -1;
2275 iov[0].iov_len = fptr->
wbuf.
len;
2288 struct binwritev_arg arg;
2291 arg.iovcnt = iovcnt;
2298 return io_binwritev_internal((
VALUE)&arg);
2305 int i, converted, iovcnt = argc + 1;
2307 VALUE v1, v2, str, tmp, *tmp_array;
2313 for (i = 0; i < argc; i++) {
2316 str = do_writeconv(str, fptr, &converted);
2321 tmp = rb_str_tmp_frozen_acquire(str);
2325 iov[i+1].iov_base = RSTRING_PTR(tmp);
2326 iov[i+1].iov_len = RSTRING_LEN(tmp);
2329 n = io_binwritev(iov, iovcnt, fptr);
2332 for (i = 0; i < argc; i++) {
2333 rb_str_tmp_frozen_release(argv[i], tmp_array[i]);
2342iovcnt_ok(
int iovcnt)
2345 return iovcnt < IOV_MAX;
2353io_writev(
int argc,
const VALUE *argv,
VALUE io)
2360 io = GetWriteIO(io);
2373 for (i = 0; i < argc; i += cnt) {
2376 n = io_fwritev(cnt, &argv[i], fptr);
2387 rb_sys_fail_on_write(fptr);
2389 total = rb_fix_plus(
LONG2FIX(n), total);
2420 return io_writev(argc, argv, io);
2423 VALUE str = argv[0];
2424 return io_write(io, str, 0);
2435rb_io_writev(
VALUE io,
int argc,
const VALUE *argv)
2440 char sep = RCLASS_SINGLETON_P(klass) ? (klass = io,
'.') :
'#';
2443 " which accepts just one argument",
2448 do rb_io_write(io, *argv++);
while (--argc);
2479 rb_io_write(io, str);
2485nogvl_fsync(
void *ptr)
2490 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->
fd)) != FILE_TYPE_DISK)
2493 return (
VALUE)fsync(fptr->
fd);
2498rb_io_flush_raw(
VALUE io,
int sync)
2506 io = GetWriteIO(io);
2510 if (io_fflush(fptr) < 0)
2511 rb_sys_fail_on_write(fptr);
2514 io_unread(fptr,
true);
2535 return rb_io_flush_raw(io, 1);
2561 pos = io_tell(fptr);
2562 if (pos < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
2568rb_io_seek(
VALUE io,
VALUE offset,
int whence)
2575 pos = io_seek(fptr, pos, whence);
2576 if (pos < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
2577 if (fptr->
readconv) clear_readconv(fptr);
2583interpret_seek_whence(
VALUE vwhence)
2585 if (vwhence == sym_SET)
2587 if (vwhence == sym_CUR)
2589 if (vwhence == sym_END)
2592 if (vwhence == sym_DATA)
2596 if (vwhence == sym_HOLE)
2652 VALUE offset, ptrname;
2653 int whence = SEEK_SET;
2655 if (
rb_scan_args(argc, argv,
"11", &offset, &ptrname) == 2) {
2656 whence = interpret_seek_whence(ptrname);
2659 return rb_io_seek(io, offset, whence);
2687 pos = io_seek(fptr, pos, SEEK_SET);
2688 if (pos < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
2689 if (fptr->
readconv) clear_readconv(fptr);
2719rb_io_rewind(
VALUE io)
2724 if (io_seek(fptr, 0L, 0) < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
2725 if (io == ARGF.current_file) {
2726 ARGF.lineno -= fptr->
lineno;
2730 clear_readconv(fptr);
2737fptr_wait_readable(
rb_io_t *fptr)
2755 fptr->
rbuf.
capa = IO_RBUF_CAPA_FOR(fptr);
2763 if (fptr_wait_readable(fptr))
2767 VALUE path = rb_sprintf(
"fd:%d ", fptr->
fd);
2772 rb_syserr_fail_path(e, path);
2826 if (READ_CHAR_PENDING(fptr))
return Qfalse;
2827 if (READ_DATA_PENDING(fptr))
return Qfalse;
2829#if RUBY_CRLF_ENVIRONMENT
2830 if (!NEED_READCONV(fptr) && NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
2831 return RBOOL(eof(fptr->
fd));
2834 return RBOOL(io_fillbuf(fptr) < 0);
2858 io = GetWriteIO(io);
2895 io = GetWriteIO(io);
2901 fptr->
mode &= ~FMODE_SYNC;
2925rb_io_fsync(
VALUE io)
2929 io = GetWriteIO(io);
2932 if (io_fflush(fptr) < 0)
2933 rb_sys_fail_on_write(fptr);
2935 if ((
int)rb_io_blocking_region(fptr, nogvl_fsync, fptr))
2936 rb_sys_fail_path(fptr->
pathv);
2941# define rb_io_fsync rb_f_notimplement
2942# define rb_io_sync rb_f_notimplement
2951#ifdef HAVE_FDATASYNC
2953nogvl_fdatasync(
void *ptr)
2957 return (
VALUE)fdatasync(fptr->
fd);
2972rb_io_fdatasync(
VALUE io)
2976 io = GetWriteIO(io);
2979 if (io_fflush(fptr) < 0)
2980 rb_sys_fail_on_write(fptr);
2982 if ((
int)rb_io_blocking_region(fptr, nogvl_fdatasync, fptr) == 0)
2986 return rb_io_fsync(io);
2989#define rb_io_fdatasync rb_io_fsync
3007rb_io_fileno(
VALUE io)
3027 if (!UNDEF_P(fileno)) {
3120rb_io_inspect(
VALUE obj)
3124 static const char closed[] =
" (closed)";
3126 fptr =
RFILE(obj)->fptr;
3133 rb_str_cat(result, closed+1, strlen(closed)-1);
3136 rb_str_catf(result,
"fd %d", fptr->
fd);
3157rb_io_to_io(
VALUE io)
3164read_buffered_data(
char *ptr,
long len,
rb_io_t *fptr)
3168 n = READ_DATA_PENDING_COUNT(fptr);
3169 if (n <= 0)
return 0;
3170 if (n >
len) n = (int)
len;
3178io_bufread(
char *ptr,
long len,
rb_io_t *fptr,
long *read_len)
3185 if (READ_DATA_PENDING(fptr) == 0) {
3189 c = rb_io_read_memory(fptr, ptr+offset, n);
3192 if (fptr_wait_readable(fptr))
3198 if ((n -= c) <= 0)
break;
3204 c = read_buffered_data(ptr+offset, n, fptr);
3208 if ((n -= c) <= 0)
break;
3211 if (io_fillbuf(fptr) < 0) {
3218static int io_setstrbuf(
VALUE *str,
long len);
3229bufread_body(
VALUE arg)
3232 p->len = io_bufread(p->str_ptr + p->offset, p->len, p->fptr, &p->read_len);
3241 if (p->offset + p->read_len > 0) {
3243 io_restore_read_buffer(str, p->fptr);
3250bufread_call(
VALUE arg)
3255 return bufread_body(arg);
3257 return rb_rescue2(bufread_body, arg, bufread_timeout, arg,
3258 rb_eIOTimeoutError, (
VALUE)0);
3262io_fread(
VALUE str,
long offset,
long size,
rb_io_t *fptr)
3267 io_setstrbuf(&str, offset + size);
3268 arg.str_ptr = RSTRING_PTR(str);
3269 arg.offset = offset;
3273 rb_str_locktmp_ensure(str, bufread_call, (
VALUE)&arg);
3275 if (
len < 0) rb_sys_fail_path(fptr->
pathv);
3283 rb_off_t siz = READ_DATA_PENDING_COUNT(fptr);
3286 if (fstat(fptr->
fd, &st) == 0 && S_ISREG(st.st_mode)
3287#
if defined(__HAIKU__)
3292 if (io_fflush(fptr) < 0)
3293 rb_sys_fail_on_write(fptr);
3294 pos = lseek(fptr->
fd, 0, SEEK_CUR);
3295 if (st.st_size >= pos && pos >= 0) {
3296 siz += st.st_size - pos;
3297 if (siz > LONG_MAX) {
3298 rb_raise(
rb_eIOError,
"file too big for single read");
3311 rb_enc_associate(str, io_read_encoding(fptr));
3316make_readconv(
rb_io_t *fptr,
int size)
3321 const char *sname, *dname;
3322 ecflags = fptr->
encs.
ecflags & ~ECONV_NEWLINE_DECORATOR_WRITE_MASK;
3325 sname = rb_enc_name(fptr->
encs.
enc2);
3326 dname = rb_enc_name(io_read_encoding(fptr));
3336 if (size < IO_CBUF_CAPA_MIN) size = IO_CBUF_CAPA_MIN;
3342#define MORE_CHAR_SUSPENDED Qtrue
3343#define MORE_CHAR_FINISHED Qnil
3345fill_cbuf(
rb_io_t *fptr,
int ec_flags)
3347 const unsigned char *ss, *sp, *se;
3348 unsigned char *ds, *dp, *de;
3357 return MORE_CHAR_SUSPENDED;
3368 ss = sp = (
const unsigned char *)fptr->
rbuf.
ptr + fptr->
rbuf.
off;
3373 fptr->
rbuf.
off += (int)(sp - ss);
3374 fptr->
rbuf.
len -= (int)(sp - ss);
3375 fptr->
cbuf.
len += (int)(dp - ds);
3380 fptr->
rbuf.
off -= putbackable;
3381 fptr->
rbuf.
len += putbackable;
3388 if (cbuf_len0 != fptr->
cbuf.
len)
3389 return MORE_CHAR_SUSPENDED;
3392 return MORE_CHAR_FINISHED;
3398 if (io_fillbuf(fptr) < 0) {
3400 return MORE_CHAR_FINISHED;
3405 fptr->
cbuf.
len += (int)(dp - ds);
3412 if (cbuf_len0 != fptr->
cbuf.
len)
3413 return MORE_CHAR_SUSPENDED;
3415 return MORE_CHAR_FINISHED;
3423 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED)
3440 rb_enc_associate(str, fptr->
encs.
enc);
3465 long clen = RSTRING_LEN(s);
3477#define MAX_REALLOC_GAP 4096
3479io_shrink_read_string(
VALUE str,
long n)
3482 rb_str_resize(str, n);
3487io_set_read_length(
VALUE str,
long n,
int shrinkable)
3489 if (RSTRING_LEN(str) != n) {
3492 if (shrinkable) io_shrink_read_string(str, n);
3506 if (NEED_READCONV(fptr)) {
3507 int first = !
NIL_P(str);
3508 SET_BINARY_MODE(fptr);
3509 shrinkable = io_setstrbuf(&str,0);
3510 make_readconv(fptr, 0);
3515 io_shift_cbuf(fptr, fptr->
cbuf.
len, &str);
3517 v = fill_cbuf(fptr, 0);
3518 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED) {
3521 io_shift_cbuf(fptr, fptr->
cbuf.
len, &str);
3525 if (v == MORE_CHAR_FINISHED) {
3526 clear_readconv(fptr);
3528 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3529 return io_enc_str(str, fptr);
3534 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3538 enc = io_read_encoding(fptr);
3551 shrinkable = io_setstrbuf(&str, siz);
3554 n = io_fread(str, bytes, siz - bytes, fptr);
3555 if (n == 0 && bytes == 0) {
3563 if (bytes < siz)
break;
3567 if (
capa < (
size_t)RSTRING_LEN(str) + BUFSIZ) {
3568 if (
capa < BUFSIZ) {
3571 else if (
capa > IO_MAX_BUFFER_GROWTH) {
3572 capa = IO_MAX_BUFFER_GROWTH;
3577 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3578 str = io_enc_str(str, fptr);
3586 if (rb_fd_set_nonblock(fptr->
fd) != 0) {
3587 rb_sys_fail_path(fptr->
pathv);
3592io_read_memory_call(
VALUE arg)
3597 if (scheduler !=
Qnil) {
3600 if (!UNDEF_P(result)) {
3606 if (iis->nonblock) {
3607 return rb_io_blocking_region(iis->fptr, internal_read_func, iis);
3610 return rb_io_blocking_region_wait(iis->fptr, internal_read_func, iis,
RUBY_IO_READABLE);
3617 return (
long)rb_str_locktmp_ensure(str, io_read_memory_call, (
VALUE)iis);
3620#define no_exception_p(opts) !rb_opts_exception_p((opts), TRUE)
3623io_getpartial(
int argc,
VALUE *argv,
VALUE io,
int no_exception,
int nonblock)
3634 rb_raise(rb_eArgError,
"negative length %ld given",
len);
3637 shrinkable = io_setstrbuf(&str,
len);
3643 io_set_read_length(str, 0, shrinkable);
3649 n = read_buffered_data(RSTRING_PTR(str),
len, fptr);
3655 io_setstrbuf(&str,
len);
3658 iis.nonblock = nonblock;
3660 iis.buf = RSTRING_PTR(str);
3663 n = io_read_memory_locktmp(str, &iis);
3666 if (!nonblock && fptr_wait_readable(fptr))
3668 if (nonblock && (io_again_p(e))) {
3670 return sym_wait_readable;
3673 e,
"read would block");
3675 rb_syserr_fail_path(e, fptr->
pathv);
3678 io_set_read_length(str, n, shrinkable);
3779io_readpartial(
int argc,
VALUE *argv,
VALUE io)
3783 ret = io_getpartial(argc, argv, io,
Qnil, 0);
3790io_nonblock_eof(
int no_exception)
3792 if (!no_exception) {
3808 rb_raise(rb_eArgError,
"negative length %ld given",
len);
3811 shrinkable = io_setstrbuf(&str,
len);
3812 rb_bool_expected(ex,
"exception", TRUE);
3818 io_set_read_length(str, 0, shrinkable);
3822 n = read_buffered_data(RSTRING_PTR(str),
len, fptr);
3824 rb_fd_set_nonblock(fptr->
fd);
3825 shrinkable |= io_setstrbuf(&str,
len);
3829 iis.buf = RSTRING_PTR(str);
3832 n = io_read_memory_locktmp(str, &iis);
3835 if (io_again_p(e)) {
3836 if (!ex)
return sym_wait_readable;
3838 e,
"read would block");
3840 rb_syserr_fail_path(e, fptr->
pathv);
3843 io_set_read_length(str, n, shrinkable);
3846 if (!ex)
return Qnil;
3862 rb_bool_expected(ex,
"exception", TRUE);
3864 io = GetWriteIO(io);
3868 if (io_fflush(fptr) < 0)
3869 rb_sys_fail_on_write(fptr);
3871 rb_fd_set_nonblock(fptr->
fd);
3872 n = write(fptr->
fd, RSTRING_PTR(str), RSTRING_LEN(str));
3877 if (io_again_p(e)) {
3879 return sym_wait_writable;
3885 rb_syserr_fail_path(e, fptr->
pathv);
3969#if RUBY_CRLF_ENVIRONMENT
3975 if (
NIL_P(length)) {
3978 return read_all(fptr, remain_size(fptr), str);
3982 rb_raise(rb_eArgError,
"negative length %ld given",
len);
3985 shrinkable = io_setstrbuf(&str,
len);
3990 io_set_read_length(str, 0, shrinkable);
3995#if RUBY_CRLF_ENVIRONMENT
3996 previous_mode = set_binary_mode_with_seek_cur(fptr);
3998 n = io_fread(str, 0,
len, fptr);
3999 io_set_read_length(str, n, shrinkable);
4000#if RUBY_CRLF_ENVIRONMENT
4001 if (previous_mode == O_TEXT) {
4002 setmode(fptr->
fd, O_TEXT);
4005 if (n == 0)
return Qnil;
4011rscheck(
const char *rsptr,
long rslen,
VALUE rs)
4014 if (RSTRING_PTR(rs) != rsptr && RSTRING_LEN(rs) != rslen)
4019search_delim(
const char *p,
long len,
int delim,
rb_encoding *enc)
4021 if (rb_enc_mbminlen(enc) == 1) {
4022 p = memchr(p, delim,
len);
4023 if (p)
return p + 1;
4026 const char *end = p +
len;
4028 int r = rb_enc_precise_mbclen(p, end, enc);
4030 p += rb_enc_mbminlen(enc);
4034 if (rb_enc_mbc_to_codepoint(p, end, enc) == (
unsigned int)delim) {
4050 if (!READ_DATA_PENDING(fptr)) {
4052 if (io_fillbuf(fptr) < 0)
break;
4054 buf[n++] = *READ_DATA_PENDING_PTR(fptr);
4057 r = rb_enc_precise_mbclen(buf, buf + n, enc);
4064unread_raw_character(
rb_io_t *fptr,
const char *buf,
int len)
4076search_wide_delim(
const char *p,
long len,
const char *delim,
int width)
4078 const char *e = p +
len;
4081 while (index < width && delim[index] == 0) index++;
4082 if (index == width) index = 0;
4084 const char *candidate = p + index;
4085 while (candidate < e) {
4086 candidate = memchr(candidate, (
unsigned char)delim[index], e - candidate);
4087 if (candidate == NULL)
break;
4088 const char *start = candidate - index;
4089 if ((start - p) % width == 0 && start + width <= e &&
4090 memcmp(start, delim, width) == 0) {
4104 if (NEED_READCONV(fptr)) {
4105 SET_BINARY_MODE(fptr);
4106 make_readconv(fptr, 0);
4109 int searchlen = READ_CHAR_PENDING_COUNT(fptr);
4111 p = READ_CHAR_PENDING_PTR(fptr);
4112 if (0 < limit && limit < searchlen)
4113 searchlen = (int)limit;
4114 e = search_delim(p, searchlen, delim, enc);
4116 int len = (int)(e-p);
4138 return (
unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
4141 }
while (more_char(fptr) != MORE_CHAR_FINISHED);
4142 clear_readconv(fptr);
4147 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4148 if (rb_enc_mbminlen(enc) != 1) {
4149 char buf[ONIGENC_CODE_TO_MBC_MAXLEN];
4153 int width = rb_enc_mbminlen(enc);
4154 int delim_len = rb_enc_codelen(delim, enc);
4156 if (delim_len == width) {
4157 rb_enc_mbcput(delim, buf, enc);
4159 if (!READ_DATA_PENDING(fptr)) {
4161 if (io_fillbuf(fptr) < 0)
return EOF;
4163 long pending = READ_DATA_PENDING_COUNT(fptr);
4164 long complete = pending - pending % width;
4165 const char *p = READ_DATA_PENDING_PTR(fptr);
4166 const char *q = complete ? search_wide_delim(p, complete, buf, width) : NULL;
4167 long take = q ? q - p + width : complete;
4176 if (q)
return delim;
4177 if (complete == pending)
continue;
4179 len = read_raw_character(fptr, enc, buf);
4180 if (
len == 0)
return EOF;
4184 int r = rb_enc_precise_mbclen(buf, buf +
len, enc);
4186 rb_enc_mbc_to_codepoint(buf, buf +
len, enc) == (
unsigned int)delim)
4192 while ((
len = read_raw_character(fptr, enc, buf)) > 0) {
4199 return (
unsigned char)buf[
len - 1];
4203 int r = rb_enc_precise_mbclen(buf, buf +
len, enc);
4205 rb_enc_mbc_to_codepoint(buf, buf +
len, enc) == (
unsigned int)delim)
4208 return (
unsigned char)buf[
len - 1];
4214 long pending = READ_DATA_PENDING_COUNT(fptr);
4216 const char *p = READ_DATA_PENDING_PTR(fptr);
4220 if (limit > 0 && pending > limit) pending = limit;
4221 e = search_delim(p, pending, delim, enc);
4222 if (e) pending = e - p;
4224 last = RSTRING_LEN(str);
4225 rb_str_resize(str, last + pending);
4232 read_buffered_data(RSTRING_PTR(str) + last, pending, fptr);
4235 if (e)
return delim;
4237 return (
unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
4240 }
while (io_fillbuf(fptr) >= 0);
4246swallow(
rb_io_t *fptr,
int term)
4248 if (NEED_READCONV(fptr)) {
4250 int needconv = rb_enc_mbminlen(enc) != 1;
4251 SET_BINARY_MODE(fptr);
4252 make_readconv(fptr, 0);
4255 while ((cnt = READ_CHAR_PENDING_COUNT(fptr)) > 0) {
4256 const char *p = READ_CHAR_PENDING_PTR(fptr);
4259 if (*p != term)
return TRUE;
4261 while (--i && *++p == term);
4264 const char *e = p + cnt;
4265 if (rb_enc_ascget(p, e, &i, enc) != term)
return TRUE;
4266 while ((p += i) < e && rb_enc_ascget(p, e, &i, enc) == term);
4269 io_shift_cbuf(fptr, (
int)cnt - i, NULL);
4271 }
while (more_char(fptr) != MORE_CHAR_FINISHED);
4275 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4277 int widechar = rb_enc_mbminlen(enc) != 1;
4279 char buf[ONIGENC_CODE_TO_MBC_MAXLEN];
4282 while ((
len = read_raw_character(fptr, enc, buf)) > 0) {
4283 if (rb_enc_ascget(buf, buf +
len, NULL, enc) != term) {
4284 unread_raw_character(fptr, buf,
len);
4292 while ((cnt = READ_DATA_PENDING_COUNT(fptr)) > 0) {
4294 const char *p = READ_DATA_PENDING_PTR(fptr);
4296 if (cnt >
sizeof buf) cnt =
sizeof buf;
4297 if (*p != term)
return TRUE;
4299 while (--i && *++p == term);
4300 if (!read_buffered_data(buf, cnt - i, fptr))
4301 rb_sys_fail_path(fptr->
pathv);
4304 }
while (io_fillbuf(fptr) == 0);
4317 int pending = READ_DATA_PENDING_COUNT(fptr);
4320 const char *p = READ_DATA_PENDING_PTR(fptr);
4324 e = memchr(p,
'\n', pending);
4326 pending = (int)(e - p + 1);
4328 chomplen = (pending > 1 && *(e-1) ==
'\r') + 1;
4337 rb_str_resize(str,
len + pending - chomplen);
4338 read_buffered_data(RSTRING_PTR(str)+
len, pending - chomplen, fptr);
4341 if (pending == 1 && chomplen == 1 &&
len > 0) {
4342 if (RSTRING_PTR(str)[
len-1] ==
'\r') {
4343 rb_str_resize(str, --
len);
4348 len += pending - chomplen;
4354 }
while (io_fillbuf(fptr) >= 0);
4357 str = io_enc_str(str, fptr);
4368 unsigned int chomp: 1;
4382 chomp = (!UNDEF_P(vchomp)) &&
RTEST(vchomp);
4384 args->chomp = chomp;
4402 else if (2 <= argc) {
4403 rs = argv[0], lim = argv[1];
4412check_getline_args(
VALUE *rsp,
long *limit,
VALUE io)
4421 enc_rs = rb_enc_get(rs);
4422 enc_io = io_read_encoding(fptr);
4423 if (enc_io != enc_rs &&
4424 (!is_ascii_string(rs) ||
4425 (RSTRING_LEN(rs) > 0 && !rb_enc_asciicompat(enc_io)))) {
4426 if (rs == rb_default_rs) {
4427 rs = rb_enc_str_new(0, 0, enc_io);
4432 rb_raise(rb_eArgError,
"encoding mismatch: %s IO with %s RS",
4433 rb_enc_name(enc_io),
4434 rb_enc_name(enc_rs));
4444 argc =
rb_scan_args(argc, argv,
"02:", NULL, NULL, &opts);
4445 extract_getline_args(argc, argv, args);
4446 extract_getline_opts(opts, args);
4447 check_getline_args(&args->rs, &args->limit, io);
4451rb_io_getline_0(
VALUE rs,
long limit,
int chomp,
rb_io_t *fptr)
4458 if (
NIL_P(rs) && limit < 0) {
4459 str = read_all(fptr, 0,
Qnil);
4460 if (RSTRING_LEN(str) == 0)
return Qnil;
4462 else if (limit == 0) {
4463 return rb_enc_str_new(0, 0, io_read_encoding(fptr));
4465 else if (rs == rb_default_rs && limit < 0 && !NEED_READCONV(fptr) &&
4466 rb_enc_asciicompat(enc = io_read_encoding(fptr))) {
4467 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4468 return rb_io_getline_fast(fptr, enc, chomp);
4471 int c, newline = -1;
4472 const char *rsptr = 0;
4475 int extra_limit = 16;
4476 int chomp_cr = chomp;
4478 SET_BINARY_MODE(fptr);
4479 enc = io_read_encoding(fptr);
4482 rslen = RSTRING_LEN(rs);
4487 swallow(fptr,
'\n');
4489 if (!rb_enc_asciicompat(enc)) {
4493 rsptr = RSTRING_PTR(rs);
4494 rslen = RSTRING_LEN(rs);
4498 else if (rb_enc_mbminlen(enc) == 1) {
4499 rsptr = RSTRING_PTR(rs);
4500 newline = (
unsigned char)rsptr[rslen - 1];
4504 rsptr = RSTRING_PTR(rs);
4505 const char *e = rsptr + rslen;
4506 const char *last = rb_enc_prev_char(rsptr, e, e, enc);
4508 newline = rb_enc_codepoint_len(last, e, &n, enc);
4509 if (last + n != e) rb_raise(rb_eArgError,
"broken separator");
4511 chomp_cr = chomp && newline ==
'\n' && rslen == rb_enc_mbminlen(enc);
4515 while ((c = appendline(fptr, newline, &str, &limit, enc)) != EOF) {
4516 const char *s, *p, *pp, *e;
4518 if (c == newline && RSTRING_LEN(str) >= rslen) {
4519 s = RSTRING_PTR(str);
4522 if (at_char_boundary(s, p, e, enc)) {
4523 if (!rspara) rscheck(rsptr, rslen, rs);
4524 if (memcmp(p, rsptr, rslen) == 0) {
4526 if (chomp_cr && p > s && *(p-1) ==
'\r') --p;
4534 s = RSTRING_PTR(str);
4536 pp = rb_enc_prev_char(s, p, p, enc);
4537 if (extra_limit && pp &&
4551 if (rspara && c != EOF)
4552 swallow(fptr,
'\n');
4554 str = io_enc_str(str, fptr);
4557 if (!
NIL_P(str) && !nolimit) {
4565rb_io_getline_1(
VALUE rs,
long limit,
int chomp,
VALUE io)
4568 int old_lineno, new_lineno;
4572 old_lineno = fptr->
lineno;
4573 str = rb_io_getline_0(rs, limit, chomp, fptr);
4574 if (!
NIL_P(str) && (new_lineno = fptr->
lineno) != old_lineno) {
4575 if (io == ARGF.current_file) {
4576 ARGF.lineno += new_lineno - old_lineno;
4577 ARGF.last_lineno = ARGF.lineno;
4580 ARGF.last_lineno = new_lineno;
4588rb_io_getline(
int argc,
VALUE *argv,
VALUE io)
4592 prepare_getline_args(argc, argv, &args, io);
4593 return rb_io_getline_1(args.rs, args.limit, args.chomp, io);
4603rb_io_gets_limit_internal(
VALUE io,
long limit)
4607 return rb_io_getline_0(rb_default_rs, limit, FALSE, fptr);
4611rb_io_gets_internal(
VALUE io)
4613 return rb_io_gets_limit_internal(io, -1);
4693 str = rb_io_getline(argc, argv, io);
4709rb_io_lineno(
VALUE io)
4764 check_getline_args(&sep, &limit, io);
4766 VALUE line = rb_io_getline_1(sep, limit,
RTEST(chomp), io);
4767 rb_lastline_set_up(line, 1);
4842rb_io_readlines(
int argc,
VALUE *argv,
VALUE io)
4846 prepare_getline_args(argc, argv, &args, io);
4847 return io_readlines(&args, io);
4855 if (arg->limit == 0)
4856 rb_raise(rb_eArgError,
"invalid limit: 0 for readlines");
4858 while (!
NIL_P(line = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, io))) {
4971rb_io_each_line(
int argc,
VALUE *argv,
VALUE io)
4977 prepare_getline_args(argc, argv, &args, io);
4978 if (args.limit == 0)
4979 rb_raise(rb_eArgError,
"invalid limit: 0 for each_line");
4980 while (!
NIL_P(str = rb_io_getline_1(args.rs, args.limit, args.chomp, io))) {
5008rb_io_each_byte(
VALUE io)
5024 }
while (io_fillbuf(fptr) >= 0);
5034 if (NEED_READCONV(fptr)) {
5038 SET_BINARY_MODE(fptr);
5039 make_readconv(fptr, 0);
5053 if (more_char(fptr) == MORE_CHAR_FINISHED) {
5055 clear_readconv(fptr);
5059 str = rb_enc_str_new(fptr->
cbuf.
ptr+fptr->
cbuf.
off, 1, read_enc);
5062 if (fptr->
cbuf.
len == 0) clear_readconv(fptr);
5071 io_shift_cbuf(fptr, r, &str);
5078 ISASCII(RSTRING_PTR(str)[0])) {
5082 str = io_enc_str(str, fptr);
5087 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
5088 if (io_fillbuf(fptr) < 0) {
5110 if (io_fillbuf(fptr) != -1) {
5114 r = rb_enc_precise_mbclen(RSTRING_PTR(str), RSTRING_PTR(str)+RSTRING_LEN(str), enc);
5130 str = io_enc_str(str, fptr);
5157rb_io_each_char(
VALUE io)
5167 enc = io_input_encoding(fptr);
5169 while (!
NIL_P(c = io_getc(fptr, enc))) {
5196rb_io_each_codepoint(
VALUE io)
5208 enc = io_read_encoding(fptr);
5209 if (NEED_READCONV(fptr)) {
5210 SET_BINARY_MODE(fptr);
5213 make_readconv(fptr, 0);
5225 if (more_char(fptr) == MORE_CHAR_FINISHED) {
5226 clear_readconv(fptr);
5246 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
5247 while (io_fillbuf(fptr) >= 0) {
5262 char cbuf[8], *p = cbuf;
5264 if (more > numberof(cbuf))
goto invalid;
5266 if (more > numberof(cbuf))
goto invalid;
5267 while ((n = (
int)read_buffered_data(p, more, fptr)) > 0 &&
5268 (p += n, (more -= n) > 0)) {
5269 if (io_fillbuf(fptr) < 0)
goto invalid;
5270 if ((n = fptr->
rbuf.
len) > more) n = more;
5272 r = rb_enc_precise_mbclen(cbuf, p, enc);
5285 rb_raise(rb_eArgError,
"invalid byte sequence in %s", rb_enc_name(enc));
5318 enc = io_input_encoding(fptr);
5320 return io_getc(fptr, enc);
5344rb_io_readchar(
VALUE io)
5346 VALUE c = rb_io_getc(io);
5382 VALUE r_stdout = rb_ractor_stdout();
5387 rb_io_flush(r_stdout);
5390 if (io_fillbuf(fptr) < 0) {
5420rb_io_readbyte(
VALUE io)
5481 unsigned char c =
NUM2INT(v) & 0xFF;
5487 io_ungetbyte(b, fptr);
5543 else if (RB_BIGNUM_TYPE_P(c)) {
5549 if (NEED_READCONV(fptr)) {
5550 SET_BINARY_MODE(fptr);
5551 len = RSTRING_LEN(c);
5552#if SIZEOF_LONG > SIZEOF_INT
5556 make_readconv(fptr, (
int)
len);
5570 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
5571 io_ungetbyte(c, fptr);
5591rb_io_isatty(
VALUE io)
5596 return RBOOL(isatty(fptr->
fd) != 0);
5599#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5615rb_io_close_on_exec_p(
VALUE io)
5621 write_io = GetWriteIO(io);
5622 if (io != write_io) {
5624 if (fptr && 0 <= (fd = fptr->
fd)) {
5625 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->
pathv);
5626 if (!(ret & FD_CLOEXEC))
return Qfalse;
5631 if (fptr && 0 <= (fd = fptr->
fd)) {
5632 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->
pathv);
5633 if (!(ret & FD_CLOEXEC))
return Qfalse;
5638#define rb_io_close_on_exec_p rb_f_notimplement
5641#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5665 int flag =
RTEST(arg) ? FD_CLOEXEC : 0;
5670 write_io = GetWriteIO(io);
5671 if (io != write_io) {
5673 if (fptr && 0 <= (fd = fptr->
fd)) {
5674 if ((ret = fcntl(fptr->
fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->
pathv);
5675 if ((ret & FD_CLOEXEC) != flag) {
5676 ret = (ret & ~FD_CLOEXEC) | flag;
5677 ret = fcntl(fd, F_SETFD, ret);
5678 if (ret != 0) rb_sys_fail_path(fptr->
pathv);
5685 if (fptr && 0 <= (fd = fptr->
fd)) {
5686 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->
pathv);
5687 if ((ret & FD_CLOEXEC) != flag) {
5688 ret = (ret & ~FD_CLOEXEC) | flag;
5689 ret = fcntl(fd, F_SETFD, ret);
5690 if (ret != 0) rb_sys_fail_path(fptr->
pathv);
5696#define rb_io_set_close_on_exec rb_f_notimplement
5699#define RUBY_IO_EXTERNAL_P(f) ((f)->mode & FMODE_EXTERNAL)
5700#define PREP_STDIO_NAME(f) (RSTRING_PTR((f)->pathv))
5703finish_writeconv(
rb_io_t *fptr,
int noalloc)
5705 unsigned char *ds, *dp, *de;
5709 unsigned char buf[1024];
5714 de = buf +
sizeof(buf);
5717 size_t remaining = dp-ds;
5718 long result = rb_io_write_memory(fptr, ds, remaining);
5722 if ((
size_t)result == remaining)
break;
5745 if (io_fflush(fptr) < 0) {
5753 fptr->
wbuf.
len += (int)(dp - ds);
5769finish_writeconv_sync(
VALUE arg)
5772 return finish_writeconv(p->fptr, p->noalloc);
5776nogvl_close(
void *ptr)
5780 return (
void*)(intptr_t)close(*fd);
5784maygvl_close(
int fd,
int keepgvl)
5793 return IO_WITHOUT_GVL_INT(nogvl_close, &fd);
5797nogvl_fclose(
void *ptr)
5801 return (
void*)(intptr_t)fclose(file);
5805maygvl_fclose(
FILE *file,
int keepgvl)
5808 return fclose(file);
5810 return IO_WITHOUT_GVL_INT(nogvl_fclose, file);
5816fptr_finalize_flush(
rb_io_t *fptr,
int noraise,
int keepgvl)
5821 int mode = fptr->
mode;
5827 arg.noalloc = noraise;
5831 error = finish_writeconv(fptr, noraise);
5844 io_flush_buffer_sync(fptr);
5847 if (io_fflush(fptr) < 0 &&
NIL_P(error)) {
5855 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2) {
5865 rb_thread_io_close_wait(fptr);
5867 if (!done && stdio_file) {
5869 if ((maygvl_fclose(stdio_file, noraise) < 0) &&
NIL_P(error)) {
5879 if (!done && fd >= 0 && scheduler !=
Qnil) {
5882 if (!UNDEF_P(result)) {
5883 done =
RTEST(result);
5887 if (!done && fd >= 0) {
5893 if ((maygvl_close(fd, keepgvl) < 0) &&
NIL_P(error)) {
5902 if (!
NIL_P(error) && !noraise) {
5911fptr_finalize(
rb_io_t *fptr,
int noraise)
5913 fptr_finalize_flush(fptr, noraise, FALSE);
5914 free_io_buffer(&fptr->
rbuf);
5915 free_io_buffer(&fptr->
wbuf);
5916 clear_codeconv(fptr);
5920rb_io_fptr_cleanup(
rb_io_t *fptr,
int noraise)
5926 fptr_finalize(fptr, noraise);
5934 ruby_xfree_sized(buf->
ptr, (
size_t)buf->
capa);
5947 free_io_buffer(&fptr->
cbuf);
5963 clear_readconv(fptr);
5964 clear_writeconv(fptr);
5968rb_io_fptr_cleanup_all(
rb_io_t *fptr)
5972 rb_io_fptr_cleanup(fptr, TRUE);
5974 free_io_buffer(&fptr->
rbuf);
5975 free_io_buffer(&fptr->
wbuf);
5976 clear_codeconv(fptr);
5983 rb_io_fptr_cleanup_all(io);
5990rb_io_fptr_finalize_closed(
struct rb_io *io)
5992 if (!io)
return true;
5993 if (io->
fd >= 0)
return false;
5999rb_io_memsize(
const rb_io_t *io)
6001 size_t size =
sizeof(
rb_io_t);
6011 rb_serial_t fork_generation = GET_VM()->fork_gen;
6012 if (io->fork_generation == fork_generation) {
6023# define KEEPGVL TRUE
6025# define KEEPGVL FALSE
6029io_close_fptr(
VALUE io)
6035 write_io = GetWriteIO(io);
6036 if (io != write_io) {
6037 write_fptr =
RFILE(write_io)->fptr;
6038 if (write_fptr && 0 <= write_fptr->
fd) {
6039 rb_io_fptr_cleanup(write_fptr, TRUE);
6043 fptr =
RFILE(io)->fptr;
6044 if (!fptr)
return 0;
6045 if (fptr->
fd < 0)
return 0;
6048 if (rb_thread_io_close_interrupt(fptr)) {
6050 fptr_finalize_flush(fptr, FALSE, KEEPGVL);
6053 rb_io_fptr_cleanup(fptr, FALSE);
6058fptr_waitpid(
rb_io_t *fptr,
int nohang)
6062 rb_last_status_clear();
6071 rb_io_t *fptr = io_close_fptr(io);
6072 if (fptr) fptr_waitpid(fptr, 0);
6112rb_io_close_m(
VALUE io)
6114 rb_io_t *fptr = rb_io_get_fptr(io);
6123io_call_close(
VALUE io)
6132 enum {mesg_len =
sizeof(closed_stream)-1};
6133 VALUE mesg = rb_attr_get(exc, idMesg);
6135 RSTRING_LEN(mesg) != mesg_len ||
6136 memcmp(RSTRING_PTR(mesg), closed_stream, mesg_len)) {
6146 if (!UNDEF_P(closed) &&
RTEST(closed))
return io;
6147 rb_rescue2(io_call_close, io, ignore_closed_stream, io,
6183 write_io = GetWriteIO(io);
6184 if (io != write_io) {
6185 write_fptr =
RFILE(write_io)->fptr;
6186 if (write_fptr && 0 <= write_fptr->
fd) {
6191 fptr = rb_io_get_fptr(io);
6192 return RBOOL(0 > fptr->
fd);
6228rb_io_close_read(
VALUE io)
6234 if (fptr->
fd < 0)
return Qnil;
6235 if (is_socket(fptr->
fd, fptr->
pathv)) {
6239 if (shutdown(fptr->
fd, SHUT_RD) < 0)
6240 rb_sys_fail_path(fptr->
pathv);
6241 fptr->
mode &= ~FMODE_READABLE;
6247 write_io = GetWriteIO(io);
6248 if (io != write_io) {
6253 RFILE(io)->fptr = wfptr;
6256 RFILE(write_io)->fptr = fptr;
6257 rb_io_fptr_cleanup(fptr, FALSE);
6263 rb_raise(
rb_eIOError,
"closing non-duplex IO for reading");
6301rb_io_close_write(
VALUE io)
6306 write_io = GetWriteIO(io);
6308 if (fptr->
fd < 0)
return Qnil;
6309 if (is_socket(fptr->
fd, fptr->
pathv)) {
6320 if (io_fflush(fptr) < 0)
6321 rb_sys_fail_on_write(fptr);
6323 if (shutdown(fptr->
fd, SHUT_WR) < 0)
6324 rb_sys_fail_path(fptr->
pathv);
6325 fptr->
mode &= ~FMODE_WRITABLE;
6332 rb_raise(
rb_eIOError,
"closing non-duplex IO for writing");
6335 if (io != write_io) {
6355rb_io_sysseek(
int argc,
VALUE *argv,
VALUE io)
6357 VALUE offset, ptrname;
6358 int whence = SEEK_SET;
6362 if (
rb_scan_args(argc, argv,
"11", &offset, &ptrname) == 2) {
6363 whence = interpret_seek_whence(ptrname);
6368 (READ_DATA_BUFFERED(fptr) || READ_CHAR_PENDING(fptr))) {
6372 rb_warn(
"sysseek for buffered IO");
6375 pos = lseek(fptr->
fd, pos, whence);
6376 if (pos < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
6410 io = GetWriteIO(io);
6415 rb_warn(
"syswrite for buffered IO");
6418 tmp = rb_str_tmp_frozen_acquire(str);
6420 n = rb_io_write_memory(fptr, ptr,
len);
6421 if (n < 0) rb_sys_fail_path(fptr->
pathv);
6422 rb_str_tmp_frozen_release(str, tmp);
6439rb_io_sysread(
int argc,
VALUE *argv,
VALUE io)
6450 shrinkable = io_setstrbuf(&str, ilen);
6451 if (ilen == 0)
return str;
6456 if (READ_DATA_BUFFERED(fptr)) {
6462 io_setstrbuf(&str, ilen);
6467 iis.buf = RSTRING_PTR(str);
6470 n = io_read_memory_locktmp(str, &iis);
6473 rb_sys_fail_path(fptr->
pathv);
6476 io_set_read_length(str, n, shrinkable);
6478 if (n == 0 && ilen > 0) {
6494internal_pread_func(
void *_arg)
6498 return (
VALUE)pread(arg->fd, arg->buf, arg->count, arg->offset);
6502pread_internal_call(
VALUE _arg)
6507 if (scheduler !=
Qnil) {
6510 if (!UNDEF_P(result)) {
6515 return rb_io_blocking_region_wait(arg->io, internal_pread_func, arg,
RUBY_IO_READABLE);
6559 shrinkable = io_setstrbuf(&str, (
long)arg.count);
6560 if (arg.count == 0)
return str;
6561 arg.buf = RSTRING_PTR(str);
6574 rb_sys_fail_path(fptr->
pathv);
6576 io_set_read_length(str, n, shrinkable);
6577 if (n == 0 && arg.count > 0) {
6585internal_pwrite_func(
void *_arg)
6589 return (
VALUE)pwrite(arg->fd, arg->buf, arg->count, arg->offset);
6593pwrite_internal_call(
VALUE _arg)
6598 if (scheduler !=
Qnil) {
6601 if (!UNDEF_P(result)) {
6606 return rb_io_blocking_region_wait(arg->io, internal_pwrite_func, arg,
RUBY_IO_WRITABLE);
6647 io = GetWriteIO(io);
6654 tmp = rb_str_tmp_frozen_acquire(str);
6655 arg.buf = RSTRING_PTR(tmp);
6656 arg.count = (size_t)RSTRING_LEN(tmp);
6658 n = (ssize_t)pwrite_internal_call((
VALUE)&arg);
6659 if (n < 0) rb_sys_fail_path(fptr->
pathv);
6660 rb_str_tmp_frozen_release(str, tmp);
6676 fptr->
mode &= ~FMODE_TEXTMODE;
6680 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6683 setmode(fptr->
fd, O_BINARY);
6690io_ascii8bit_binmode(
rb_io_t *fptr)
6701 fptr->
mode &= ~FMODE_TEXTMODE;
6702 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6704 fptr->
encs.
enc = rb_ascii8bit_encoding();
6708 clear_codeconv(fptr);
6717 io_ascii8bit_binmode(fptr);
6734rb_io_binmode_m(
VALUE io)
6740 write_io = GetWriteIO(io);
6755rb_io_binmode_p(
VALUE io)
6763rb_io_fmode_modestr(
enum rb_io_mode fmode)
6767 return MODE_BTMODE(
"a+",
"ab+",
"at+");
6769 return MODE_BTMODE(
"a",
"ab",
"at");
6773 rb_raise(rb_eArgError,
"invalid access fmode 0x%x", fmode);
6775 return MODE_BTMODE(
"r",
"rb",
"rt");
6777 return MODE_BTXMODE(
"w",
"wb",
"wt",
"wx",
"wbx",
"wtx");
6780 return MODE_BTXMODE(
"w+",
"wb+",
"wt+",
"w+x",
"wb+x",
"wt+x");
6782 return MODE_BTMODE(
"r+",
"rb+",
"rt+");
6786static const char bom_prefix[] =
"bom|";
6787static const char utf_prefix[] =
"utf-";
6788enum {bom_prefix_len = (int)
sizeof(bom_prefix) - 1};
6789enum {utf_prefix_len = (int)
sizeof(utf_prefix) - 1};
6792io_encname_bom_p(
const char *name,
long len)
6794 return len > bom_prefix_len &&
STRNCASECMP(name, bom_prefix, bom_prefix_len) == 0;
6800 enum rb_io_mode fmode = 0;
6801 const char *m = modestr, *p = NULL;
6829 if (modestr[0] !=
'w')
6837 if (io_encname_bom_p(m, p ? (
long)(p - m) : (long)strlen(m)))
6850 rb_raise(rb_eArgError,
"invalid access mode %s", modestr);
6855rb_io_oflags_fmode(
int oflags)
6857 enum rb_io_mode fmode = 0;
6859 switch (oflags & O_ACCMODE) {
6871 if (oflags & O_APPEND) {
6874 if (oflags & O_TRUNC) {
6877 if (oflags & O_CREAT) {
6880 if (oflags & O_EXCL) {
6884 if (oflags & O_BINARY) {
6893rb_io_fmode_oflags(
enum rb_io_mode fmode)
6937rb_io_oflags_modestr(
int oflags)
6940# define MODE_BINARY(a,b) ((oflags & O_BINARY) ? (b) : (a))
6942# define MODE_BINARY(a,b) (a)
6945 if (oflags & O_EXCL) {
6946 rb_raise(rb_eArgError,
"exclusive access mode is not supported");
6948 accmode = oflags & (O_RDONLY|O_WRONLY|O_RDWR);
6949 if (oflags & O_APPEND) {
6950 if (accmode == O_WRONLY) {
6951 return MODE_BINARY(
"a",
"ab");
6953 if (accmode == O_RDWR) {
6954 return MODE_BINARY(
"a+",
"ab+");
6959 rb_raise(rb_eArgError,
"invalid access oflags 0x%x", oflags);
6961 return MODE_BINARY(
"r",
"rb");
6963 return MODE_BINARY(
"w",
"wb");
6965 if (oflags & O_TRUNC) {
6966 return MODE_BINARY(
"w+",
"wb+");
6968 return MODE_BINARY(
"r+",
"rb+");
6980 int default_ext = 0;
6983 ext = rb_default_external_encoding();
6986 if (rb_is_ascii8bit_enc(ext)) {
6990 else if (intern == NULL) {
6991 intern = rb_default_internal_encoding();
6996 *enc = (default_ext && intern != ext) ? NULL : ext;
7006unsupported_encoding(
const char *name,
rb_encoding *enc)
7008 rb_enc_warn(enc,
"Unsupported encoding %s ignored", name);
7012parse_mode_enc(
const char *estr,
rb_encoding *estr_enc,
7018 enum rb_io_mode fmode = fmode_p ? *fmode_p : 0;
7024 p = strrchr(estr,
':');
7025 len = p ? (p++ - estr) : (long)strlen(estr);
7027 estr += bom_prefix_len;
7028 len -= bom_prefix_len;
7029 if (!
STRNCASECMP(estr, utf_prefix, utf_prefix_len)) {
7033 rb_enc_warn(estr_enc,
"BOM with non-UTF encoding %s is nonsense", estr);
7034 fmode &= ~FMODE_SETENC_BY_BOM;
7042 memcpy(encname, estr,
len);
7043 encname[
len] =
'\0';
7046 idx = rb_enc_find_index(estr);
7048 if (fmode_p) *fmode_p = fmode;
7051 ext_enc = rb_enc_from_index(idx);
7054 unsupported_encoding(estr, estr_enc);
7060 if (*p ==
'-' && *(p+1) ==
'\0') {
7065 idx2 = rb_enc_find_index(p);
7067 unsupported_encoding(p, estr_enc);
7072 int_enc = rb_enc_from_index(idx2);
7076 rb_io_ext_int_to_encs(ext_enc, int_enc, enc_p, enc2_p, fmode);
7089 v = rb_hash_lookup2(opt, sym_encoding,
Qnil);
7090 if (v !=
Qnil) encoding = v;
7091 v = rb_hash_lookup2(opt, sym_extenc,
Qundef);
7092 if (v !=
Qnil) extenc = v;
7093 v = rb_hash_lookup2(opt, sym_intenc,
Qundef);
7094 if (!UNDEF_P(v)) intenc = v;
7096 if ((!UNDEF_P(extenc) || !UNDEF_P(intenc)) && !
NIL_P(encoding)) {
7098 int idx = rb_to_encoding_index(encoding);
7099 if (idx >= 0) encoding = rb_enc_from_encoding(rb_enc_from_index(idx));
7100 rb_warn(
"Ignoring encoding parameter '%"PRIsVALUE
"': %s_encoding is used",
7101 encoding, UNDEF_P(extenc) ?
"internal" :
"external");
7105 if (!UNDEF_P(extenc) && !
NIL_P(extenc)) {
7106 extencoding = rb_to_encoding(extenc);
7108 if (!UNDEF_P(intenc)) {
7109 if (
NIL_P(intenc)) {
7116 if (*p ==
'-' && *(p+1) ==
'\0') {
7121 intencoding = rb_to_encoding(intenc);
7125 intencoding = rb_to_encoding(intenc);
7127 if (extencoding == intencoding) {
7131 if (!
NIL_P(encoding)) {
7135 enc_p, enc2_p, fmode_p);
7138 rb_io_ext_int_to_encs(rb_to_encoding(encoding), NULL, enc_p, enc2_p, 0);
7141 else if (!UNDEF_P(extenc) || !UNDEF_P(intenc)) {
7143 rb_io_ext_int_to_encs(extencoding, intencoding, enc_p, enc2_p, 0);
7151 enum rb_io_mode fmode = *fmode_p;
7156 !rb_enc_asciicompat(enc ? enc : rb_default_external_encoding()))
7157 rb_raise(rb_eArgError,
"ASCII incompatible encoding needs binmode");
7160 rb_raise(rb_eArgError,
"newline decorator with binary mode");
7167#if !DEFAULT_TEXTMODE
7169 fmode &= ~FMODE_TEXTMODE;
7176extract_binmode(
VALUE opthash,
enum rb_io_mode *fmode)
7178 if (!
NIL_P(opthash)) {
7180 v = rb_hash_aref(opthash, sym_textmode);
7183 rb_raise(rb_eArgError,
"textmode specified twice");
7185 rb_raise(rb_eArgError,
"both textmode and binmode specified");
7189 v = rb_hash_aref(opthash, sym_binmode);
7192 rb_raise(rb_eArgError,
"binmode specified twice");
7194 rb_raise(rb_eArgError,
"both textmode and binmode specified");
7200 rb_raise(rb_eArgError,
"both textmode and binmode specified");
7206 int *oflags_p,
enum rb_io_mode *fmode_p,
struct rb_io_encoding *convconfig_p)
7210 enum rb_io_mode fmode;
7214 int has_enc = 0, has_vmode = 0;
7220 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
7230 fmode = rb_io_oflags_fmode(oflags);
7238 oflags = rb_io_fmode_oflags(fmode);
7242 parse_mode_enc(p+1, rb_enc_get(vmode), &enc, &enc2, &fmode);
7247 e = (fmode &
FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
7248 rb_io_ext_int_to_encs(e, NULL, &enc, &enc2, fmode);
7252 if (
NIL_P(opthash)) {
7256#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7258 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7259 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7261 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
7268 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
7271 else if (
NIL_P(vmode)) {
7272 fmode |= DEFAULT_TEXTMODE;
7279 v = rb_hash_aref(opthash, sym_mode);
7281 if (!
NIL_P(vmode)) {
7282 rb_raise(rb_eArgError,
"mode specified twice");
7289 v = rb_hash_aref(opthash, sym_flags);
7294 fmode = rb_io_oflags_fmode(oflags);
7296 extract_binmode(opthash, &fmode);
7302 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
7305 else if (
NIL_P(vmode)) {
7306 fmode |= DEFAULT_TEXTMODE;
7309 v = rb_hash_aref(opthash, sym_perm);
7312 if (!
NIL_P(*vperm_p)) {
7313 rb_raise(rb_eArgError,
"perm specified twice");
7324#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7326 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7327 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7332 rb_raise(rb_eArgError,
"encoding specified twice");
7335 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
7339 validate_enc_binmode(&fmode, ecflags, enc, enc2);
7345 convconfig_p->
enc = enc;
7346 convconfig_p->
enc2 = enc2;
7347 convconfig_p->
ecflags = ecflags;
7348 convconfig_p->
ecopts = ecopts;
7358sysopen_func(
void *ptr)
7361 const char *fname = RSTRING_PTR(data->fname);
7370 fd = IO_WITHOUT_GVL_INT(sysopen_func, data);
7371 }
while (fd < 0 &&
errno == EINTR);
7378rb_sysopen(
VALUE fname,
int oflags, mode_t perm)
7383 data.fname = rb_str_encode_ospath(fname);
7385 data.oflags = oflags;
7388 TRY_WITH_GC((fd = rb_sysopen_internal(&data)) >= 0) {
7389 rb_syserr_fail_path(first_errno, fname);
7395fdopen_internal(
int fd,
const char *modestr)
7402 file = fdopen(fd, modestr);
7418 TRY_WITH_GC((file = fdopen_internal(fd, modestr)) != 0) {
7424 if (setvbuf(file, NULL, _IOFBF, 0) != 0)
7425 rb_warn(
"setvbuf() can't be honoured (fd=%d)", fd);
7433 int t = isatty(fptr->
fd);
7443io_strip_bom(
VALUE io)
7445 VALUE b1, b2, b3, b4;
7456 return rb_utf8_encindex();
7466 return ENCINDEX_UTF_16BE;
7477 return ENCINDEX_UTF_32LE;
7482 return ENCINDEX_UTF_16LE;
7492 return ENCINDEX_UTF_32BE;
7506io_set_encoding_by_bom(
VALUE io)
7508 int idx = io_strip_bom(io);
7514 extenc = rb_enc_from_index(idx);
7515 io_encoding_set(fptr, rb_enc_from_encoding(extenc),
7516 rb_io_internal_encoding(io),
Qnil);
7525rb_file_open_generic(
VALUE io,
VALUE filename,
int oflags,
enum rb_io_mode fmode,
7533 rb_io_ext_int_to_encs(NULL, NULL, &cc.enc, &cc.enc2, fmode);
7538 validate_enc_binmode(&fmode, convconfig->
ecflags,
7539 convconfig->
enc, convconfig->
enc2);
7543 fptr->
encs = *convconfig;
7546 if (!(oflags & O_TMPFILE)) {
7547 fptr->
pathv = pathv;
7550 fptr->
pathv = pathv;
7552 fptr->
fd = rb_sysopen(pathv, oflags, perm);
7560rb_file_open_internal(
VALUE io,
VALUE filename,
const char *modestr)
7563 const char *p = strchr(modestr,
':');
7567 parse_mode_enc(p+1, rb_usascii_encoding(),
7568 &convconfig.
enc, &convconfig.
enc2, &fmode);
7574 e = (fmode &
FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
7575 rb_io_ext_int_to_encs(e, NULL, &convconfig.
enc, &convconfig.
enc2, fmode);
7581#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7583 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7584 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7586 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.
enc2, convconfig.
ecflags);
7589 return rb_file_open_generic(io, filename,
7590 rb_io_fmode_oflags(fmode),
7600 return rb_file_open_internal(io_alloc(
rb_cFile), fname, modestr);
7609#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7632 while ((tmp = *prev) != 0) {
7633 if (tmp->fptr == fptr) {
7642#if defined (_WIN32) || defined(__CYGWIN__)
7658pipe_finalize(
rb_io_t *fptr,
int noraise)
7660#if !defined(HAVE_WORKING_FORK) && !defined(_WIN32)
7669 fptr_finalize(fptr, noraise);
7671 pipe_del_fptr(fptr);
7678#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7679 void (*
const old_finalize)(
struct rb_io*,int) = fptr->
finalize;
7681 if (old_finalize == orig->finalize)
return;
7686#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7687 if (old_finalize != pipe_finalize) {
7689 for (list =
pipe_list; list; list = list->next) {
7690 if (list->fptr == fptr)
break;
7692 if (!list) pipe_add_fptr(fptr);
7695 pipe_del_fptr(fptr);
7721#define spawnv(mode, cmd, args) rb_w32_uaspawn((mode), (cmd), (args))
7722#define spawn(mode, cmd) rb_w32_uspawn((mode), (cmd), 0)
7725#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7735#ifdef HAVE_WORKING_FORK
7736# ifndef __EMSCRIPTEN__
7738popen_redirect(
struct popen_arg *p)
7741 close(p->write_pair[1]);
7742 if (p->write_pair[0] != 0) {
7743 dup2(p->write_pair[0], 0);
7744 close(p->write_pair[0]);
7747 if (p->pair[1] != 1) {
7748 dup2(p->pair[1], 1);
7754 if (p->pair[1] != 1) {
7755 dup2(p->pair[1], 1);
7761 if (p->pair[0] != 0) {
7762 dup2(p->pair[0], 0);
7769#if defined(__linux__)
7780linux_get_maxfd(
void)
7783 char buf[4096], *p, *np, *e;
7786 if (fd < 0)
return fd;
7787 ss = read(fd, buf,
sizeof(buf));
7788 if (ss < 0)
goto err;
7791 while ((
int)
sizeof(
"FDSize:\t0\n")-1 <= e-p &&
7792 (np = memchr(p,
'\n', e-p)) != NULL) {
7793 if (memcmp(p,
"FDSize:",
sizeof(
"FDSize:")-1) == 0) {
7795 p +=
sizeof(
"FDSize:")-1;
7815#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
7817 int max = (int)max_file_descriptor;
7820 ret = fcntl(0, F_MAXFD);
7822 maxhint = max = ret;
7823# elif defined(__linux__)
7824 ret = linux_get_maxfd();
7831 for (fd = lowfd; fd <= max; fd++) {
7832 if (!
NIL_P(noclose_fds) &&
7835 ret = fcntl(fd, F_GETFD);
7836 if (ret != -1 && !(ret & FD_CLOEXEC)) {
7837 fcntl(fd, F_SETFD, ret|FD_CLOEXEC);
7839# define CONTIGUOUS_CLOSED_FDS 20
7841 if (max < fd + CONTIGUOUS_CLOSED_FDS)
7842 max = fd + CONTIGUOUS_CLOSED_FDS;
7848# ifndef __EMSCRIPTEN__
7850popen_exec(
void *pp,
char *errmsg,
size_t errmsg_len)
7852 struct popen_arg *p = (
struct popen_arg*)pp;
7854 return rb_exec_async_signal_safe(p->eargp, errmsg, errmsg_len);
7859#if (defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)) && !defined __EMSCRIPTEN__
7861rb_execarg_fixup_v(
VALUE execarg_obj)
7863 rb_execarg_parent_start(execarg_obj);
7867char *rb_execarg_commandline(
const struct rb_execarg *eargp,
VALUE *prog);
7870#ifndef __EMSCRIPTEN__
7872pipe_open(
VALUE execarg_obj,
const char *modestr,
enum rb_io_mode fmode,
7875 struct rb_execarg *eargp =
NIL_P(execarg_obj) ? NULL : rb_execarg_get(execarg_obj);
7876 VALUE prog = eargp ? (eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name) :
Qfalse ;
7882#if defined(HAVE_WORKING_FORK)
7884 char errmsg[80] = {
'\0' };
7886#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7888 struct popen_arg arg;
7891#if defined(HAVE_SPAWNV)
7892# define DO_SPAWN(cmd, args) ((args) ? \
7893 spawnv(P_NOWAIT, (cmd), (args)) : \
7894 spawn(P_NOWAIT, (cmd)))
7895# if !defined(HAVE_WORKING_FORK)
7899#if !defined(HAVE_WORKING_FORK)
7905#if !defined(HAVE_WORKING_FORK)
7906 const char *cmd = 0;
7912#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7913 arg.execarg_obj = execarg_obj;
7916 arg.pair[0] = arg.pair[1] = -1;
7917 arg.write_pair[0] = arg.write_pair[1] = -1;
7918# if !defined(HAVE_WORKING_FORK)
7919 if (eargp && !eargp->use_shell) {
7920 args = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
7925 if (
rb_pipe(arg.write_pair) < 0)
7926 rb_sys_fail_str(prog);
7929 close(arg.write_pair[0]);
7930 close(arg.write_pair[1]);
7934 rb_execarg_addopt(execarg_obj,
INT2FIX(0),
INT2FIX(arg.write_pair[0]));
7935 rb_execarg_addopt(execarg_obj,
INT2FIX(1),
INT2FIX(arg.pair[1]));
7940 rb_sys_fail_str(prog);
7942 rb_execarg_addopt(execarg_obj,
INT2FIX(1),
INT2FIX(arg.pair[1]));
7946 rb_sys_fail_str(prog);
7948 rb_execarg_addopt(execarg_obj,
INT2FIX(0),
INT2FIX(arg.pair[0]));
7951 rb_sys_fail_str(prog);
7953 if (!
NIL_P(execarg_obj)) {
7954 rb_protect(rb_execarg_fixup_v, execarg_obj, &state);
7956 if (0 <= arg.write_pair[0]) close(arg.write_pair[0]);
7957 if (0 <= arg.write_pair[1]) close(arg.write_pair[1]);
7958 if (0 <= arg.pair[0]) close(arg.pair[0]);
7959 if (0 <= arg.pair[1]) close(arg.pair[1]);
7960 rb_execarg_parent_end(execarg_obj);
7964# if defined(HAVE_WORKING_FORK)
7965 pid = rb_fork_async_signal_safe(&status, popen_exec, &arg, arg.eargp->redirect_fds, errmsg,
sizeof(errmsg));
7967 rb_execarg_run_options(eargp, sargp, NULL, 0);
7968 while ((pid = DO_SPAWN(cmd, args)) < 0) {
7970 switch (e =
errno) {
7972# if EWOULDBLOCK != EAGAIN
7981 rb_execarg_run_options(sargp, NULL, NULL, 0);
7983 rb_execarg_parent_end(execarg_obj);
7986# if defined(HAVE_WORKING_FORK)
7987 pid = rb_call_proc__fork();
7989 popen_redirect(&arg);
8001# if defined(HAVE_WORKING_FORK)
8007 close(arg.write_pair[0]);
8008 close(arg.write_pair[1]);
8010# if defined(HAVE_WORKING_FORK)
8019 close(arg.write_pair[0]);
8020 write_fd = arg.write_pair[1];
8031 cmd = rb_execarg_commandline(eargp, &prog);
8032 if (!
NIL_P(execarg_obj)) {
8033 rb_execarg_parent_start(execarg_obj);
8034 rb_execarg_run_options(eargp, sargp, NULL, 0);
8036 fp = popen(cmd, modestr);
8039 rb_execarg_parent_end(execarg_obj);
8040 rb_execarg_run_options(sargp, NULL, NULL, 0);
8042 if (!fp) rb_syserr_fail_path(e, prog);
8052 fptr->
encs = *convconfig;
8053#if RUBY_CRLF_ENVIRONMENT
8060 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
8063#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
8064 if (NEED_NEWLINE_DECORATOR_ON_WRITE(fptr)) {
8065 fptr->
encs.
ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
8071 if (0 <= write_fd) {
8072 write_port = io_alloc(
rb_cIO);
8074 write_fptr->
fd = write_fd;
8076 fptr->
mode &= ~FMODE_WRITABLE;
8078 rb_ivar_set(port, rb_intern(
"@tied_io_for_writing"), write_port);
8081#if defined (__CYGWIN__) || !defined(HAVE_WORKING_FORK)
8083 pipe_add_fptr(fptr);
8089pipe_open(
VALUE execarg_obj,
const char *modestr,
enum rb_io_mode fmode,
8097is_popen_fork(
VALUE prog)
8099 if (RSTRING_LEN(prog) == 1 && RSTRING_PTR(prog)[0] ==
'-') {
8100#if !defined(HAVE_WORKING_FORK)
8102 "fork() function is unimplemented on this machine");
8111pipe_open_s(
VALUE prog,
const char *modestr,
enum rb_io_mode fmode,
8115 VALUE *argv = &prog;
8118 if (!is_popen_fork(prog))
8119 execarg_obj = rb_execarg_new(argc, argv, TRUE, FALSE);
8120 return pipe_open(execarg_obj, modestr, fmode, convconfig);
8126 rb_io_t *fptr = io_close_fptr(io);
8295rb_io_s_popen(
int argc,
VALUE *argv,
VALUE klass)
8299 if (argc > 1 && !
NIL_P(opt = rb_check_hash_type(argv[argc-1]))) --argc;
8300 if (argc > 1 && !
NIL_P(env = rb_check_hash_type(argv[0]))) --argc, ++argv;
8309 int ex = !
NIL_P(opt);
8310 rb_error_arity(argc + ex, 1 + ex, 2 + ex);
8313 return popen_finish(rb_io_popen(pname, pmode, env, opt), klass);
8319 const char *modestr;
8322 enum rb_io_mode fmode;
8328#if SIZEOF_LONG > SIZEOF_INT
8329 if (
len > INT_MAX) {
8330 rb_raise(rb_eArgError,
"too many arguments");
8339 if (!is_popen_fork(pname))
8340 execarg_obj = rb_execarg_new(1, &pname, TRUE, FALSE);
8342 if (!
NIL_P(execarg_obj)) {
8344 opt = rb_execarg_extract_options(execarg_obj, opt);
8346 rb_execarg_setenv(execarg_obj, env);
8349 modestr = rb_io_oflags_modestr(oflags);
8351 return pipe_open(execarg_obj, modestr, fmode, &convconfig);
8361 rb_io_flush(rb_ractor_stdout());
8362 rb_io_flush(rb_ractor_stderr());
8363 _exit(EXIT_SUCCESS);
8367 RBASIC_SET_CLASS(port, klass);
8374#if defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)
8375struct popen_writer_arg {
8377 struct popen_arg popen;
8381exec_popen_writer(
void *arg,
char *errmsg,
size_t buflen)
8383 struct popen_writer_arg *pw = arg;
8385 popen_redirect(&pw->popen);
8386 execv(pw->argv[0], pw->argv);
8387 strlcpy(errmsg, strerror(
errno), buflen);
8393ruby_popen_writer(
char *
const *argv, rb_pid_t *pid)
8395#if (defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)) || defined(_WIN32)
8396# ifdef HAVE_WORKING_FORK
8397 struct popen_writer_arg pw;
8398 int *
const write_pair = pw.popen.pair;
8404 if (cloexec_pipe(write_pair, 0,
false) == 0) {
8405# ifdef HAVE_WORKING_FORK
8408 char errmsg[80] = {
'\0'};
8409 *pid = rb_fork_async_signal_safe(&status, exec_popen_writer, &pw,
Qnil, errmsg,
sizeof(errmsg));
8411 *pid = rb_w32_uspawn_process(P_NOWAIT, argv[0], argv, write_pair[0], -1, -1, 0);
8412 const char *errmsg = (*pid < 0) ? strerror(
errno) : NULL;
8414 close(write_pair[0]);
8416 close(write_pair[1]);
8417 fprintf(stderr,
"ruby_popen_writer(%s): %s\n", argv[0], errmsg);
8420 return fdopen(write_pair[1],
"w");
8431 enum rb_io_mode fmode;
8440 rb_file_open_generic(io, fname, oflags, fmode, &convconfig, perm);
8492rb_io_s_open(
int argc,
VALUE *argv,
VALUE klass)
8524 VALUE fname, vmode, vperm;
8529 rb_scan_args(argc, argv,
"12", &fname, &vmode, &vperm);
8540 if (
NIL_P(vperm)) perm = 0666;
8544 fd = rb_sysopen(fname, oflags, perm);
8576 int redirect = FALSE;
8584 VALUE tmp = argv[0];
8602 return rb_io_s_open(argc, argv,
rb_cFile);
8606rb_io_open_generic(
VALUE klass,
VALUE filename,
int oflags,
enum rb_io_mode fmode,
8609 return rb_file_open_generic(io_alloc(klass), filename,
8610 oflags, fmode, convconfig, perm);
8617 enum rb_io_mode fmode;
8623 return rb_io_open_generic(io, filename, oflags, fmode, &convconfig, perm);
8637 if (fptr == orig)
return io;
8638 if (RUBY_IO_EXTERNAL_P(fptr)) {
8642 rb_raise(rb_eArgError,
8643 "%s can't change access mode from \"%s\" to \"%s\"",
8644 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->
mode),
8645 rb_io_fmode_modestr(orig->
mode));
8648 flush_before_seek(fptr,
true);
8650 clear_codeconv(fptr);
8652 pos = io_tell(orig);
8655 if (io_fflush(orig) < 0)
8656 rb_sys_fail_on_write(fptr);
8665 else if (!RUBY_IO_EXTERNAL_P(fptr)) fptr->
pathv =
Qnil;
8666 fptr_copy_finalizer(fptr, orig);
8672 rb_thread_io_close_interrupt(fptr);
8673 rb_thread_io_close_wait(fptr);
8675 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2 || !fptr->stdio_file) {
8678 rb_sys_fail_path(orig->
pathv);
8686 rb_sys_fail_path(orig->
pathv);
8692 if (io_seek(fptr, pos, SEEK_SET) < 0 &&
errno) {
8693 rb_sys_fail_path(fptr->
pathv);
8695 if (io_seek(orig, pos, SEEK_SET) < 0 &&
errno) {
8696 rb_sys_fail_path(orig->
pathv);
8710int rb_freopen(
VALUE fname,
const char *mode,
FILE *fp);
8713rb_freopen(
VALUE fname,
const char *mode,
FILE *fp)
8715 if (!freopen(RSTRING_PTR(fname), mode, fp)) {
8758rb_io_reopen(
int argc,
VALUE *argv,
VALUE file)
8760 VALUE fname, nmode, opt;
8764 if (
rb_scan_args(argc, argv,
"11:", &fname, &nmode, &opt) == 1) {
8767 return io_reopen(file, tmp);
8773 fptr =
RFILE(file)->fptr;
8779 enum rb_io_mode fmode;
8783 if (RUBY_IO_EXTERNAL_P(fptr) &&
8786 rb_raise(rb_eArgError,
8787 "%s can't change access mode from \"%s\" to \"%s\"",
8788 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->
mode),
8789 rb_io_fmode_modestr(fmode));
8792 fptr->
encs = convconfig;
8795 oflags = rb_io_fmode_oflags(fptr->
mode);
8798 fptr->
pathv = fname;
8800 fptr->
fd = rb_sysopen(fptr->
pathv, oflags, 0666);
8806 if (io_fflush(fptr) < 0)
8807 rb_sys_fail_on_write(fptr);
8810 clear_codeconv(fptr);
8813 int e = rb_freopen(rb_str_encode_ospath(fptr->
pathv),
8814 rb_io_oflags_modestr(oflags),
8816 if (e) rb_syserr_fail_path(e, fptr->
pathv);
8820 if (setvbuf(fptr->
stdio_file, NULL, _IOFBF, 0) != 0)
8821 rb_warn(
"setvbuf() can't be honoured for %"PRIsVALUE, fptr->
pathv);
8824 if (setvbuf(fptr->
stdio_file, NULL, _IONBF, BUFSIZ) != 0)
8825 rb_warn(
"setvbuf() can't be honoured for %"PRIsVALUE, fptr->
pathv);
8827 else if (fptr->
stdio_file == stdout && isatty(fptr->
fd)) {
8828 if (setvbuf(fptr->
stdio_file, NULL, _IOLBF, BUFSIZ) != 0)
8829 rb_warn(
"setvbuf() can't be honoured for %"PRIsVALUE, fptr->
pathv);
8833 int tmpfd = rb_sysopen(fptr->
pathv, oflags, 0666);
8839 rb_syserr_fail_path(err, fptr->
pathv);
8863 fptr->
mode = orig->
mode & ~FMODE_EXTERNAL;
8870 fptr->closing_ec = NULL;
8871 fptr->wakeup_mutex =
Qnil;
8872 fptr->fork_generation = GET_VM()->fork_gen;
8875 fptr_copy_finalizer(fptr, orig);
8877 fd = ruby_dup(orig->
fd);
8879 pos = io_tell(orig);
8881 io_seek(fptr, pos, SEEK_SET);
8886 write_io = GetWriteIO(io);
8887 if (io != write_io) {
8890 rb_ivar_set(dest, rb_intern(
"@tied_io_for_writing"), write_io);
8953 if (argc == 0)
return Qnil;
8955 out = rb_ractor_stdout();
8967extern void rb_deprecated_str_setter(
VALUE val,
ID id,
VALUE *var);
8972 rb_deprecated_str_setter(val,
id, &val);
8978 val = rb_str_frozen_bare_string(val);
9055 for (i=0; i<argc; i++) {
9059 rb_io_write(out, argv[i]);
9156 rb_io_write(io, str);
9160#define forward(obj, id, argc, argv) \
9161 rb_funcallv_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
9162#define forward_public(obj, id, argc, argv) \
9163 rb_funcallv_public_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
9164#define forward_current(id, argc, argv) \
9165 forward_public(ARGF.current_file, id, argc, argv)
9182 VALUE r_stdout = rb_ractor_stdout();
9183 if (recv == r_stdout) {
9184 return rb_io_putc(recv, ch);
9186 return forward(r_stdout, rb_intern(
"putc"), 1, &ch);
9191rb_str_end_with_asciichar(
VALUE str,
int c)
9193 long len = RSTRING_LEN(str);
9194 const char *
ptr = RSTRING_PTR(str);
9198 if (
len == 0)
return 0;
9199 if ((n = rb_enc_mbminlen(
enc)) == 1) {
9200 return ptr[
len - 1] == c;
9202 return rb_enc_ascget(
ptr + ((
len - 1) / n) * n,
ptr +
len, &n,
enc) == c;
9213 rb_io_puts(1, &tmp, out);
9220 rb_io_puts(1, &tmp, out);
9275 VALUE line, args[2];
9282 for (
int i = 0; i < argc; i++) {
9296 if (RSTRING_LEN(line) == 0) {
9301 if (!rb_str_end_with_asciichar(line,
'\n')) {
9306 rb_io_writev(out, n, args);
9324 VALUE r_stdout = rb_ractor_stdout();
9325 if (recv == r_stdout) {
9326 return rb_io_puts(argc, argv, recv);
9328 return forward(r_stdout, rb_intern(
"puts"), argc, argv);
9332rb_p_write(
VALUE str)
9337 VALUE r_stdout = rb_ractor_stdout();
9340 io_writev(2, args, r_stdout);
9343 rb_io_writev(r_stdout, 2, args);
9355rb_p_result(
int argc,
const VALUE *argv)
9362 else if (argc > 1) {
9365 VALUE r_stdout = rb_ractor_stdout();
9367 rb_uninterruptible(rb_io_flush, r_stdout);
9408 for (i=0; i<argc; i++) {
9410 rb_uninterruptible(rb_p_write, inspected);
9412 return rb_p_result(argc, argv);
9433rb_obj_display(
int argc,
VALUE *argv,
VALUE self)
9437 out = (!
rb_check_arity(argc, 0, 1) ? rb_ractor_stdout() : argv[0]);
9438 rb_io_write(out, self);
9444rb_stderr_to_original_p(
VALUE err)
9446 return (err == orig_stderr ||
RFILE(orig_stderr)->fptr->
fd < 0);
9452 VALUE out = rb_ractor_stderr();
9453 if (rb_stderr_to_original_p(out)) {
9455 if (isatty(fileno(stderr))) {
9456 if (rb_w32_write_console(
rb_str_new(mesg,
len), fileno(stderr)) > 0)
return;
9459 if (fwrite(mesg,
sizeof(
char), (
size_t)
len, stderr) < (
size_t)
len) {
9476rb_write_error_str(
VALUE mesg)
9478 VALUE out = rb_ractor_stderr();
9480 if (rb_stderr_to_original_p(out)) {
9481 size_t len = (size_t)RSTRING_LEN(mesg);
9483 if (isatty(fileno(stderr))) {
9484 if (rb_w32_write_console(mesg, fileno(stderr)) > 0)
return;
9487 if (fwrite(RSTRING_PTR(mesg),
sizeof(
char),
len, stderr) <
len) {
9494 rb_io_write(out, mesg);
9499rb_stderr_tty_p(
void)
9501 if (rb_stderr_to_original_p(rb_ractor_stderr()))
9502 return isatty(fileno(stderr));
9507must_respond_to(
ID mid,
VALUE val,
ID id)
9510 rb_raise(
rb_eTypeError,
"%"PRIsVALUE
" must have %"PRIsVALUE
" method, %"PRIsVALUE
" given",
9511 rb_id2str(
id), rb_id2str(mid),
9531 must_respond_to(id_write, val,
id);
9538 return rb_ractor_stdout();
9544 must_respond_to(id_write, val,
id);
9551 return rb_ractor_stderr();
9555allocate_and_open_new_file(
VALUE klass)
9557 VALUE self = io_alloc(klass);
9558 rb_io_make_open_file(self);
9566 VALUE self = rb_protect(allocate_and_open_new_file, klass, &state);
9574 maygvl_close(descriptor, 0);
9582 io->
fd = descriptor;
9600 io->closing_ec = NULL;
9601 io->wakeup_mutex =
Qnil;
9602 io->fork_generation = GET_VM()->fork_gen;
9605 io->
encs = *encoding;
9614prep_io(
int fd,
enum rb_io_mode fmode,
VALUE klass,
const char *path)
9624 e = (fmode &
FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
9625 rb_io_ext_int_to_encs(e, NULL, &convconfig.
enc, &convconfig.
enc2, fmode);
9629#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9631 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
9632 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
9634 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.
enc2, convconfig.
ecflags);
9640 if (!io_check_tty(io)) {
9643 setmode(fd, O_BINARY);
9655 if (path && strcmp(path,
"-")) klass =
rb_cFile;
9656 return prep_io(fd, rb_io_oflags_fmode(oflags), klass, path);
9660prep_stdio(
FILE *f,
enum rb_io_mode fmode,
VALUE klass,
const char *path)
9667#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9668 fptr->
encs.
ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
9679rb_io_prep_stdin(
void)
9685rb_io_prep_stdout(
void)
9691rb_io_prep_stderr(
void)
9700 int oflags = rb_io_fmode_oflags(fptr->
mode) & ~O_EXCL;
9727 rb_io_buffer_init(&fp->
wbuf);
9728 rb_io_buffer_init(&fp->
rbuf);
9729 rb_io_buffer_init(&fp->
cbuf);
9744 fp->closing_ec = NULL;
9745 fp->wakeup_mutex =
Qnil;
9746 fp->fork_generation = GET_VM()->fork_gen;
9751rb_io_make_open_file(
VALUE obj)
9756 if (
RFILE(obj)->fptr) {
9759 RFILE(obj)->fptr = 0;
9761 fp = rb_io_fptr_new();
9763 RFILE(obj)->fptr = fp;
9812rb_io_initialize(
int argc,
VALUE *argv,
VALUE io)
9818 return io_initialize(io, fnum, vmode, opt);
9825 int fd, oflags = O_RDONLY;
9826 enum rb_io_mode fmode;
9828#if defined(HAVE_FCNTL) && defined(F_GETFL)
9838 rb_raise(rb_eArgError,
"The given fd is not accessible because RubyVM reserves it");
9840#if defined(HAVE_FCNTL) && defined(F_GETFL)
9841 oflags = fcntl(fd, F_GETFL);
9842 if (oflags == -1) rb_sys_fail(0);
9844 if (fstat(fd, &st) < 0) rb_sys_fail(0);
9847#if defined(HAVE_FCNTL) && defined(F_GETFL)
9848 ofmode = rb_io_oflags_fmode(oflags);
9860 if (rb_hash_aref(opt, sym_autoclose) ==
Qfalse) {
9864 path = rb_hash_aref(opt,
RB_ID2SYM(idPath));
9875 fp->
encs = convconfig;
9879 fp->closing_ec = NULL;
9880 fp->wakeup_mutex =
Qnil;
9881 fp->fork_generation = GET_VM()->fork_gen;
9884 if (fileno(stdin) == fd)
9886 else if (fileno(stdout) == fd)
9888 else if (fileno(stderr) == fd)
9920rb_io_set_encoding_by_bom(
VALUE io)
9926 rb_raise(rb_eArgError,
"ASCII incompatible encoding needs binmode");
9929 rb_raise(rb_eArgError,
"encoding conversion is set");
9931 else if (fptr->
encs.
enc && fptr->
encs.
enc != rb_ascii8bit_encoding()) {
9932 rb_raise(rb_eArgError,
"encoding is set to %s already",
9935 if (!io_set_encoding_by_bom(io))
return Qnil;
9936 return rb_enc_from_encoding(fptr->
encs.
enc);
9989rb_file_initialize(
int argc,
VALUE *argv,
VALUE io)
9991 if (
RFILE(io)->fptr) {
9994 VALUE fname, vmode, vperm, opt;
9995 int posargc =
rb_scan_args(argc, argv,
"12:", &fname, &vmode, &vperm, &opt);
10000 return io_initialize(io, fd, vmode, opt);
10003 return rb_open_file(io, fname, vmode, vperm, opt);
10008rb_io_s_new(
int argc,
VALUE *argv,
VALUE klass)
10013 rb_warn(
"%"PRIsVALUE
"::new() does not take block; use %"PRIsVALUE
"::open() instead",
10029rb_io_s_for_fd(
int argc,
VALUE *argv,
VALUE klass)
10032 rb_io_initialize(argc, argv, io);
10045rb_io_autoclose_p(
VALUE io)
10070rb_io_set_autoclose(
VALUE io,
VALUE autoclose)
10074 if (!
RTEST(autoclose))
10077 fptr->
mode &= ~FMODE_EXTERNAL;
10082io_wait_event(
VALUE io,
int event,
VALUE timeout,
int return_io)
10092 if (mask & event) {
10114io_wait_readable(
int argc,
VALUE *argv,
VALUE io)
10121 if (rb_io_read_pending(fptr))
return Qtrue;
10124 VALUE timeout = (argc == 1 ? argv[0] :
Qnil);
10138io_wait_writable(
int argc,
VALUE *argv,
VALUE io)
10146 VALUE timeout = (argc == 1 ? argv[0] :
Qnil);
10161io_wait_priority(
int argc,
VALUE *argv,
VALUE io)
10168 if (rb_io_read_pending(fptr))
return Qtrue;
10171 VALUE timeout = argc == 1 ? argv[0] :
Qnil;
10177wait_mode_sym(
VALUE mode)
10179 if (mode ==
ID2SYM(rb_intern(
"r"))) {
10180 return RB_WAITFD_IN;
10182 if (mode ==
ID2SYM(rb_intern(
"read"))) {
10183 return RB_WAITFD_IN;
10185 if (mode ==
ID2SYM(rb_intern(
"readable"))) {
10186 return RB_WAITFD_IN;
10188 if (mode ==
ID2SYM(rb_intern(
"w"))) {
10189 return RB_WAITFD_OUT;
10191 if (mode ==
ID2SYM(rb_intern(
"write"))) {
10192 return RB_WAITFD_OUT;
10194 if (mode ==
ID2SYM(rb_intern(
"writable"))) {
10195 return RB_WAITFD_OUT;
10197 if (mode ==
ID2SYM(rb_intern(
"rw"))) {
10198 return RB_WAITFD_IN|RB_WAITFD_OUT;
10200 if (mode ==
ID2SYM(rb_intern(
"read_write"))) {
10201 return RB_WAITFD_IN|RB_WAITFD_OUT;
10203 if (mode ==
ID2SYM(rb_intern(
"readable_writable"))) {
10204 return RB_WAITFD_IN|RB_WAITFD_OUT;
10207 rb_raise(rb_eArgError,
"unsupported mode: %"PRIsVALUE, mode);
10211io_event_from_value(
VALUE value)
10215 if (events <= 0) rb_raise(rb_eArgError,
"Events must be positive integer!");
10253 for (
int i = 0; i < argc; i += 1) {
10255 events |= wait_mode_sym(argv[i]);
10257 else if (UNDEF_P(timeout)) {
10261 rb_raise(rb_eArgError,
"timeout given more than once");
10265 if (UNDEF_P(timeout)) timeout =
Qnil;
10273 events = io_event_from_value(argv[0]);
10281 if (rb_io_read_pending(fptr)) {
10283 if (return_io)
return Qtrue;
10289 return io_wait_event(io, events, timeout, return_io);
10293argf_mark_and_move(
void *ptr)
10295 struct argf *p = ptr;
10296 rb_gc_mark_and_move(&p->filename);
10297 rb_gc_mark_and_move(&p->current_file);
10298 rb_gc_mark_and_move(&p->argv);
10299 rb_gc_mark_and_move(&p->inplace);
10300 rb_gc_mark_and_move(&p->encs.
ecopts);
10304argf_memsize(
const void *ptr)
10306 const struct argf *p = ptr;
10307 size_t size =
sizeof(*p);
10314 0, 0, RUBY_TYPED_THREAD_SAFE_FREE | RUBY_TYPED_WB_PROTECTED
10320 p->filename =
Qnil;
10321 p->current_file =
Qnil;
10327argf_alloc(
VALUE klass)
10342 memset(&ARGF, 0,
sizeof(ARGF));
10343 argf_init(
argf, &ARGF, argv);
10353 ARGF = argf_of(orig);
10354 rb_gc_writebarrier_remember(
argf);
10381 ARGF.last_lineno = ARGF.lineno;
10407 return forward_current(rb_frame_this_func(), argc, argv);
10410#define next_argv() argf_next_argv(argf)
10411#define ARGF_GENERIC_INPUT_P() \
10412 (ARGF.current_file == rb_stdin && !RB_TYPE_P(ARGF.current_file, T_FILE))
10413#define ARGF_FORWARD(argc, argv) do {\
10414 if (ARGF_GENERIC_INPUT_P())\
10415 return argf_forward((argc), (argv), argf);\
10417#define NEXT_ARGF_FORWARD(argc, argv) do {\
10418 if (!next_argv()) return Qnil;\
10419 ARGF_FORWARD((argc), (argv));\
10425 VALUE file = ARGF.current_file;
10439 int stdout_binmode = 0;
10440 enum rb_io_mode fmode;
10442 VALUE r_stdout = rb_ractor_stdout();
10447 stdout_binmode = 1;
10450 if (ARGF.init_p == 0) {
10460 if (
NIL_P(ARGF.argv)) {
10463 else if (ARGF.next_p == -1 &&
RARRAY_LEN(ARGF.argv) > 0) {
10468 if (ARGF.next_p == 1) {
10469 if (ARGF.init_p == 1) argf_close(
argf);
10474 ARGF_SET(filename, filename);
10475 filename = rb_str_encode_ospath(filename);
10477 if (RSTRING_LEN(filename) == 1 && fn[0] ==
'-') {
10479 if (ARGF.inplace) {
10480 rb_warn(
"Can't do inplace edit for stdio; skipping");
10486 int fr = rb_sysopen(filename, O_RDONLY, 0);
10488 if (ARGF.inplace) {
10490#ifndef NO_SAFE_RENAME
10501 if (!
NIL_P(ARGF.inplace)) {
10502 VALUE suffix = ARGF.inplace;
10504 if (
NIL_P(rb_str_cat_conv_enc_opts(str, RSTRING_LEN(str),
10505 RSTRING_PTR(suffix), RSTRING_LEN(suffix),
10506 rb_enc_get(suffix), 0,
Qnil))) {
10509#ifdef NO_SAFE_RENAME
10511 (void)unlink(RSTRING_PTR(str));
10512 if (rename(fn, RSTRING_PTR(str)) < 0) {
10513 rb_warn(
"Can't rename %"PRIsVALUE
" to %"PRIsVALUE
": %s, skipping file",
10514 filename, str, strerror(
errno));
10517 fr = rb_sysopen(str, O_RDONLY, 0);
10519 if (rename(fn, RSTRING_PTR(str)) < 0) {
10520 rb_warn(
"Can't rename %"PRIsVALUE
" to %"PRIsVALUE
": %s, skipping file",
10521 filename, str, strerror(
errno));
10528#ifdef NO_SAFE_RENAME
10529 rb_fatal(
"Can't do inplace edit without backup");
10531 if (unlink(fn) < 0) {
10532 rb_warn(
"Can't remove %"PRIsVALUE
": %s, skipping file",
10533 filename, strerror(
errno));
10539 fw = rb_sysopen(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666);
10540#ifndef NO_SAFE_RENAME
10543 fchmod(fw, st.st_mode);
10545 chmod(fn, st.st_mode);
10547 if (st.st_uid!=st2.st_uid || st.st_gid!=st2.st_gid) {
10550 err = fchown(fw, st.st_uid, st.st_gid);
10552 err = chown(fn, st.st_uid, st.st_gid);
10554 if (err && getuid() == 0 && st2.st_uid == 0) {
10555 const char *wkfn = RSTRING_PTR(filename);
10556 rb_warn(
"Can't set owner/group of %"PRIsVALUE
" to same as %"PRIsVALUE
": %s, skipping file",
10557 filename, str, strerror(
errno));
10560 (void)unlink(wkfn);
10570 if (!ARGF.binmode) {
10571 fmode |= DEFAULT_TEXTMODE;
10573 ARGF_SET(current_file, prep_io(fr, fmode,
rb_cFile, fn));
10574 if (!
NIL_P(write_io)) {
10581 if (ARGF.encs.enc) {
10582 fptr->
encs = ARGF.encs;
10583 clear_codeconv(fptr);
10586 fptr->
encs.
ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
10587 if (!ARGF.binmode) {
10589#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
10590 fptr->
encs.
ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
10601 else if (ARGF.next_p == -1) {
10604 if (ARGF.inplace) {
10605 rb_warn(
"Can't do inplace edit for stdio");
10609 if (ARGF.init_p == -1) ARGF.init_p = 1;
10617 long lineno = ARGF.lineno;
10620 if (!next_argv())
return Qnil;
10621 if (ARGF_GENERIC_INPUT_P()) {
10622 line = forward_current(idGets, argc, argv);
10629 line = rb_io_getline(argc, argv, ARGF.current_file);
10631 if (
NIL_P(line) && ARGF.next_p != -1) {
10637 if (!
NIL_P(line)) {
10638 ARGF.lineno = ++lineno;
10639 ARGF.last_lineno = ARGF.lineno;
10645argf_lineno_getter(
ID id,
VALUE *var)
10648 return INT2FIX(ARGF.last_lineno);
10656 ARGF.last_lineno = ARGF.lineno = n;
10660rb_reset_argf_lineno(
long n)
10662 ARGF.last_lineno = ARGF.lineno = n;
10703 if (recv ==
argf) {
10704 return argf_gets(argc, argv,
argf);
10706 return forward(
argf, idGets, argc, argv);
10732 line = argf_getline(argc, argv,
argf);
10744 return rb_f_gets(0, 0,
argf);
10748 if (!next_argv())
return Qnil;
10750 if (
NIL_P(line) && ARGF.next_p != -1) {
10756 if (!
NIL_P(line)) {
10758 ARGF.last_lineno = ARGF.lineno;
10784rb_f_readline(
int argc,
VALUE *argv,
VALUE recv)
10786 if (recv ==
argf) {
10787 return argf_readline(argc, argv,
argf);
10789 return forward(
argf, rb_intern(
"readline"), argc, argv);
10815 if (!next_argv()) rb_eof_error();
10816 ARGF_FORWARD(argc, argv);
10817 line = argf_gets(argc, argv,
argf);
10887rb_f_readlines(
int argc,
VALUE *argv,
VALUE recv)
10889 if (recv ==
argf) {
10890 return argf_readlines(argc, argv,
argf);
10892 return forward(
argf, rb_intern(
"readlines"), argc, argv);
10916 long lineno = ARGF.lineno;
10920 while (next_argv()) {
10921 if (ARGF_GENERIC_INPUT_P()) {
10922 lines = forward_current(rb_intern(
"readlines"), argc, argv);
10925 lines = rb_io_readlines(argc, argv, ARGF.current_file);
10931 ARGF.last_lineno = ARGF.lineno;
10966 rb_last_status_clear();
10967 port = pipe_open_s(str,
"r",
FMODE_READABLE|DEFAULT_TEXTMODE, NULL);
10971 result = read_all(fptr, remain_size(fptr),
Qnil);
10973 rb_io_fptr_cleanup_all(fptr);
10979#ifdef HAVE_SYS_SELECT_H
10980#include <sys/select.h>
10994 if (!
NIL_P(read)) {
10999 if (READ_DATA_PENDING(fptr) || READ_CHAR_PENDING(fptr)) {
11003 if (max < fptr->fd) max = fptr->
fd;
11006 timerec.tv_sec = timerec.tv_usec = 0;
11014 if (!
NIL_P(write)) {
11020 if (max < fptr->fd) max = fptr->
fd;
11027 if (!
NIL_P(except)) {
11031 VALUE write_io = GetWriteIO(io);
11034 if (max < fptr->fd) max = fptr->
fd;
11035 if (io != write_io) {
11038 if (max < fptr->fd) max = fptr->
fd;
11053 if (!pending && n == 0)
return Qnil;
11078 VALUE write_io = GetWriteIO(io);
11091 VALUE write_io = GetWriteIO(io);
11096 else if (io != write_io) {
11109 VALUE read, write, except;
11115select_call(
VALUE arg)
11119 return select_internal(p->read, p->write, p->except, p->timeout, p->fdsets);
11123select_end(
VALUE arg)
11128 for (i = 0; i < numberof(p->fdsets); ++i)
11133static VALUE sym_normal, sym_sequential, sym_random,
11134 sym_willneed, sym_dontneed, sym_noreuse;
11136#ifdef HAVE_POSIX_FADVISE
11137struct io_advise_struct {
11145io_advise_internal(
void *arg)
11147 struct io_advise_struct *ptr = arg;
11148 return posix_fadvise(ptr->fd, ptr->offset, ptr->len, ptr->advice);
11152io_advise_sym_to_const(
VALUE sym)
11154#ifdef POSIX_FADV_NORMAL
11155 if (sym == sym_normal)
11156 return INT2NUM(POSIX_FADV_NORMAL);
11159#ifdef POSIX_FADV_RANDOM
11160 if (sym == sym_random)
11161 return INT2NUM(POSIX_FADV_RANDOM);
11164#ifdef POSIX_FADV_SEQUENTIAL
11165 if (sym == sym_sequential)
11166 return INT2NUM(POSIX_FADV_SEQUENTIAL);
11169#ifdef POSIX_FADV_WILLNEED
11170 if (sym == sym_willneed)
11171 return INT2NUM(POSIX_FADV_WILLNEED);
11174#ifdef POSIX_FADV_DONTNEED
11175 if (sym == sym_dontneed)
11176 return INT2NUM(POSIX_FADV_DONTNEED);
11179#ifdef POSIX_FADV_NOREUSE
11180 if (sym == sym_noreuse)
11181 return INT2NUM(POSIX_FADV_NOREUSE);
11188do_io_advise(
rb_io_t *fptr,
VALUE advice, rb_off_t offset, rb_off_t
len)
11191 struct io_advise_struct ias;
11194 num_adv = io_advise_sym_to_const(advice);
11200 if (
NIL_P(num_adv))
11204 ias.advice =
NUM2INT(num_adv);
11205 ias.offset = offset;
11208 rv = (int)rb_io_blocking_region(fptr, io_advise_internal, &ias);
11209 if (rv && rv != ENOSYS) {
11212 VALUE message = rb_sprintf(
"%"PRIsVALUE
" "
11216 fptr->
pathv, offset,
len, advice);
11226advice_arg_check(
VALUE advice)
11231 if (advice != sym_normal &&
11232 advice != sym_sequential &&
11233 advice != sym_random &&
11234 advice != sym_willneed &&
11235 advice != sym_dontneed &&
11236 advice != sym_noreuse) {
11237 rb_raise(
rb_eNotImpError,
"Unsupported advice: %+"PRIsVALUE, advice);
11275rb_io_advise(
int argc,
VALUE *argv,
VALUE io)
11282 advice_arg_check(advice);
11284 io = GetWriteIO(io);
11290#ifdef HAVE_POSIX_FADVISE
11291 return do_io_advise(fptr, advice,
off, l);
11293 ((void)
off, (
void)l);
11305 return isinf(f) && 0 < f;
11461rb_f_select(
int argc,
VALUE *argv,
VALUE obj)
11464 if (scheduler !=
Qnil) {
11467 if (!UNDEF_P(result))
return result;
11475 rb_scan_args(argc, argv,
"13", &args.read, &args.write, &args.except, &timeout);
11476 if (
NIL_P(timeout) || is_pos_inf(timeout)) {
11481 args.timeout = &timerec;
11484 for (i = 0; i < numberof(args.fdsets); ++i)
11490#ifdef IOCTL_REQ_TYPE
11491 typedef IOCTL_REQ_TYPE ioctl_req_t;
11493 typedef int ioctl_req_t;
11494# define NUM2IOCTLREQ(num) ((int)NUM2LONG(num))
11505nogvl_ioctl(
void *ptr)
11507 struct ioctl_arg *arg = ptr;
11509 return (
VALUE)ioctl(arg->fd, arg->cmd, arg->narg);
11513do_ioctl(
struct rb_io *io, ioctl_req_t cmd,
long narg)
11516 struct ioctl_arg arg;
11522 retval = (int)rb_io_blocking_region(io, nogvl_ioctl, &arg);
11528#define DEFAULT_IOCTL_NARG_LEN (256)
11530#if defined(__linux__) && defined(_IOC_SIZE)
11532linux_iocparm_len(ioctl_req_t cmd)
11536 if ((cmd & 0xFFFF0000) == 0) {
11538 return DEFAULT_IOCTL_NARG_LEN;
11541 len = _IOC_SIZE(cmd);
11544 if (
len < DEFAULT_IOCTL_NARG_LEN)
11545 len = DEFAULT_IOCTL_NARG_LEN;
11553ioctl_narg_len(ioctl_req_t cmd)
11559#define IOCPARM_LEN(x) (((x) >> 16) & IOCPARM_MASK)
11563 len = IOCPARM_LEN(cmd);
11564#elif defined(__linux__) && defined(_IOC_SIZE)
11565 len = linux_iocparm_len(cmd);
11568 len = DEFAULT_IOCTL_NARG_LEN;
11577typedef long fcntl_arg_t;
11580typedef int fcntl_arg_t;
11584fcntl_narg_len(ioctl_req_t cmd)
11591 len =
sizeof(fcntl_arg_t);
11599#ifdef F_DUPFD_CLOEXEC
11600 case F_DUPFD_CLOEXEC:
11601 len =
sizeof(fcntl_arg_t);
11611 len =
sizeof(fcntl_arg_t);
11621 len =
sizeof(fcntl_arg_t);
11631 len =
sizeof(fcntl_arg_t);
11636 len =
sizeof(
struct f_owner_ex);
11641 len =
sizeof(
struct f_owner_ex);
11646 len =
sizeof(
struct flock);
11651 len =
sizeof(
struct flock);
11656 len =
sizeof(
struct flock);
11676 len =
sizeof(fcntl_arg_t);
11686 len =
sizeof(fcntl_arg_t);
11691 len =
sizeof(fcntl_arg_t);
11704fcntl_narg_len(ioctl_req_t cmd)
11710#define NARG_SENTINEL 17
11713setup_narg(ioctl_req_t cmd,
VALUE *argp,
long (*narg_len)(ioctl_req_t))
11724 else if (arg ==
Qtrue) {
11738 len = narg_len(cmd);
11739 rb_str_modify(arg);
11741 slen = RSTRING_LEN(arg);
11743 if (slen <
len+1) {
11744 rb_str_resize(arg,
len+1);
11745 MEMZERO(RSTRING_PTR(arg)+slen,
char,
len-slen);
11749 ptr = RSTRING_PTR(arg);
11750 ptr[slen - 1] = NARG_SENTINEL;
11759finish_narg(
int retval,
VALUE arg,
const rb_io_t *fptr)
11761 if (retval < 0) rb_sys_fail_path(fptr->
pathv);
11766 if (ptr[slen-1] != NARG_SENTINEL)
11767 rb_raise(rb_eArgError,
"return value overflowed string");
11768 ptr[slen-1] =
'\0';
11778 ioctl_req_t cmd = NUM2IOCTLREQ(req);
11783 narg = setup_narg(cmd, &arg, ioctl_narg_len);
11785 retval = do_ioctl(fptr, cmd, narg);
11786 return finish_narg(retval, arg, fptr);
11813 return rb_ioctl(io, req, arg);
11816#define rb_io_ioctl rb_f_notimplement
11827nogvl_fcntl(
void *ptr)
11829 struct fcntl_arg *arg = ptr;
11831#if defined(F_DUPFD)
11832 if (arg->cmd == F_DUPFD)
11835 return (
VALUE)fcntl(arg->fd, arg->cmd, arg->narg);
11839do_fcntl(
struct rb_io *io,
int cmd,
long narg)
11842 struct fcntl_arg arg;
11848 retval = (int)rb_io_blocking_region(io, nogvl_fcntl, &arg);
11849 if (retval != -1) {
11851#if defined(F_DUPFD)
11854#if defined(F_DUPFD_CLOEXEC)
11855 case F_DUPFD_CLOEXEC:
11872 narg = setup_narg(cmd, &arg, fcntl_narg_len);
11874 retval = do_fcntl(fptr, cmd, narg);
11875 return finish_narg(retval, arg, fptr);
11901 return rb_fcntl(io, req, arg);
11904#define rb_io_fcntl rb_f_notimplement
11907#if defined(HAVE_SYSCALL) || defined(HAVE___SYSCALL)
11939#if SIZEOF_VOIDP == 8 && defined(HAVE___SYSCALL) && SIZEOF_INT != 8
11940# define SYSCALL __syscall
11941# define NUM2SYSCALLID(x) NUM2LONG(x)
11942# define RETVAL2NUM(x) LONG2NUM(x)
11943# if SIZEOF_LONG == 8
11944 long num, retval = -1;
11945# elif SIZEOF_LONG_LONG == 8
11946 long long num, retval = -1;
11948# error ---->> it is asserted that __syscall takes the first argument and returns retval in 64bit signed integer. <<----
11950#elif defined(__linux__)
11951# define SYSCALL syscall
11952# define NUM2SYSCALLID(x) NUM2LONG(x)
11953# define RETVAL2NUM(x) LONG2NUM(x)
11961 long num, retval = -1;
11963# define SYSCALL syscall
11964# define NUM2SYSCALLID(x) NUM2INT(x)
11965# define RETVAL2NUM(x) INT2NUM(x)
11966 int num, retval = -1;
11972 "We plan to remove a syscall function at future release. DL(Fiddle) provides safer alternative.");
11976 rb_raise(rb_eArgError,
"too few arguments for syscall");
11977 if (argc > numberof(arg))
11978 rb_raise(rb_eArgError,
"too many arguments for syscall");
11979 num = NUM2SYSCALLID(argv[0]); ++argv;
11980 for (i = argc - 1; i--; ) {
11995 retval = SYSCALL(num);
11998 retval = SYSCALL(num, arg[0]);
12001 retval = SYSCALL(num, arg[0],arg[1]);
12004 retval = SYSCALL(num, arg[0],arg[1],arg[2]);
12007 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3]);
12010 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4]);
12013 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5]);
12016 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6]);
12022 return RETVAL2NUM(retval);
12024#undef NUM2SYSCALLID
12028#define rb_f_syscall rb_f_notimplement
12032io_new_instance(
VALUE args)
12038find_encoding(
VALUE v)
12041 if (!enc)
rb_warn(
"Unsupported encoding %"PRIsVALUE
" ignored", v);
12053 enc2 = find_encoding(v1);
12056 if (RSTRING_LEN(tmp) == 1 && RSTRING_PTR(tmp)[0] ==
'-') {
12062 enc = find_encoding(v2);
12069 enc = find_encoding(v2);
12075 if (enc2 == rb_ascii8bit_encoding()) {
12080 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
12086 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
12087 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
12092 if (!
NIL_P(tmp) && rb_enc_asciicompat(enc = rb_enc_get(tmp))) {
12093 parse_mode_enc(RSTRING_PTR(tmp), enc, &enc, &enc2, NULL);
12094 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
12098 rb_io_ext_int_to_encs(find_encoding(v1), NULL, &enc, &enc2, 0);
12099 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
12104 validate_enc_binmode(&fptr->
mode, ecflags, enc, enc2);
12109 clear_codeconv(fptr);
12121io_encoding_set_v(
VALUE v)
12124 io_encoding_set(arg->fptr, arg->v1, arg->v2, arg->opt);
12129pipe_pair_close(
VALUE rw)
12132 return rb_ensure(io_close, rwp[0], io_close, rwp[1]);
12215rb_io_s_pipe(
int argc,
VALUE *argv,
VALUE klass)
12217 int pipes[2], state;
12218 VALUE r, w, args[3], v1, v2;
12222 enum rb_io_mode fmode = 0;
12225 argc =
rb_scan_args(argc, argv,
"02:", &v1, &v2, &opt);
12232 r = rb_protect(io_new_instance, (
VALUE)args, &state);
12236 rb_jump_tag(state);
12240 ies_args.fptr = fptr;
12243 ies_args.opt = opt;
12244 rb_protect(io_encoding_set_v, (
VALUE)&ies_args, &state);
12248 rb_jump_tag(state);
12253 w = rb_protect(io_new_instance, (
VALUE)args, &state);
12257 rb_jump_tag(state);
12262 extract_binmode(opt, &fmode);
12269#if DEFAULT_TEXTMODE
12271 fptr->
mode &= ~FMODE_TEXTMODE;
12272 setmode(fptr->
fd, O_BINARY);
12274#if RUBY_CRLF_ENVIRONMENT
12280 fptr->
mode |= fmode;
12281#if DEFAULT_TEXTMODE
12283 fptr2->
mode &= ~FMODE_TEXTMODE;
12284 setmode(fptr2->
fd, O_BINARY);
12287 fptr2->
mode |= fmode;
12321 else if (!
NIL_P(v = rb_hash_aref(opt, sym_open_args))) {
12324 v = rb_to_array_type(v);
12329 arg->io = rb_io_open(klass, path, vmode, vperm, opt);
12333io_s_foreach(
VALUE v)
12338 if (arg->limit == 0)
12339 rb_raise(rb_eArgError,
"invalid limit: 0 for foreach");
12340 while (!
NIL_P(str = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, arg->io))) {
12424rb_io_s_foreach(
int argc,
VALUE *argv,
VALUE self)
12427 int orig_argc = argc;
12431 argc =
rb_scan_args(argc, argv,
"12:", NULL, NULL, NULL, &opt);
12433 extract_getline_args(argc-1, argv+1, &garg);
12434 open_key_args(self, argc, argv, opt, &arg);
12436 extract_getline_opts(opt, &garg);
12437 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12438 return rb_ensure(io_s_foreach, (
VALUE)&garg, rb_io_close, arg.io);
12442io_s_readlines(
VALUE v)
12445 return io_readlines(arg, arg->io);
12498rb_io_s_readlines(
int argc,
VALUE *argv,
VALUE io)
12504 argc =
rb_scan_args(argc, argv,
"12:", NULL, NULL, NULL, &opt);
12505 extract_getline_args(argc-1, argv+1, &garg);
12506 open_key_args(io, argc, argv, opt, &arg);
12508 extract_getline_opts(opt, &garg);
12509 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12510 return rb_ensure(io_s_readlines, (
VALUE)&garg, rb_io_close, arg.io);
12517 return io_read(arg->argc, arg->argv, arg->io);
12527seek_before_access(
VALUE argp)
12531 return rb_io_seek(arg->io, arg->offset, arg->mode);
12598rb_io_s_read(
int argc,
VALUE *argv,
VALUE io)
12604 argc =
rb_scan_args(argc, argv,
"13:", NULL, NULL, &offset, NULL, &opt);
12606 rb_raise(rb_eArgError,
"negative offset %ld given",
off);
12608 open_key_args(io, argc, argv, opt, &arg);
12610 if (!
NIL_P(offset)) {
12614 sarg.offset = offset;
12615 sarg.mode = SEEK_SET;
12616 rb_protect(seek_before_access, (
VALUE)&sarg, &state);
12619 rb_jump_tag(state);
12621 if (arg.argc == 2) arg.argc = 1;
12636rb_io_s_binread(
int argc,
VALUE *argv,
VALUE io)
12651 convconfig.
enc = rb_ascii8bit_encoding();
12652 arg.io = rb_io_open_generic(io, argv[0], oflags, fmode, &convconfig, 0);
12655 arg.argc = (argc > 1) ? 1 : 0;
12656 if (!
NIL_P(offset)) {
12660 sarg.offset = offset;
12661 sarg.mode = SEEK_SET;
12662 rb_protect(seek_before_access, (
VALUE)&sarg, &state);
12665 rb_jump_tag(state);
12672io_s_write0(
VALUE v)
12675 return io_write(arg->io,arg->str,arg->nosync);
12679io_s_write(
int argc,
VALUE *argv,
VALUE klass,
int binary)
12681 VALUE string, offset, opt;
12685 rb_scan_args(argc, argv,
"21:", NULL, &
string, &offset, &opt);
12687 if (
NIL_P(opt)) opt = rb_hash_new();
12688 else opt = rb_hash_dup(opt);
12691 if (
NIL_P(rb_hash_aref(opt,sym_mode))) {
12692 int mode = O_WRONLY|O_CREAT;
12694 if (binary) mode |= O_BINARY;
12696 if (
NIL_P(offset)) mode |= O_TRUNC;
12697 rb_hash_aset(opt,sym_mode,
INT2NUM(mode));
12699 open_key_args(klass, argc, argv, opt, &arg);
12702 if (binary) rb_io_binmode_m(arg.io);
12706 if (!
NIL_P(offset)) {
12710 sarg.offset = offset;
12711 sarg.mode = SEEK_SET;
12712 rb_protect(seek_before_access, (
VALUE)&sarg, &state);
12715 rb_jump_tag(state);
12723 return rb_ensure(io_s_write0, (
VALUE)&warg, rb_io_close, arg.io);
12781rb_io_s_write(
int argc,
VALUE *argv,
VALUE io)
12783 return io_s_write(argc, argv, io, 0);
12796rb_io_s_binwrite(
int argc,
VALUE *argv,
VALUE io)
12798 return io_s_write(argc, argv, io, 1);
12804 rb_off_t copy_length;
12805 rb_off_t src_offset;
12809 unsigned close_src : 1;
12810 unsigned close_dst : 1;
12813 const char *syserr;
12814 const char *notimp;
12816 struct stat src_stat;
12817 struct stat dst_stat;
12818#ifdef HAVE_FCOPYFILE
12819 copyfile_state_t copyfile_state;
12824exec_interrupts(
void *arg)
12827 rb_thread_execute_interrupts(th);
12841#if defined(ERESTART)
12846 rb_thread_execute_interrupts(stp->th);
12865fiber_scheduler_wait_for(
void * _arguments)
12875# define IOWAIT_SYSCALL "poll"
12876STATIC_ASSERT(pollin_expected, POLLIN == RB_WAITFD_IN);
12877STATIC_ASSERT(pollout_expected, POLLOUT == RB_WAITFD_OUT);
12882 if (scheduler !=
Qnil) {
12885 return RTEST(args.result);
12889 if (fd == -1)
return 0;
12894 fds.events = events;
12896 int timeout_milliseconds = -1;
12899 timeout_milliseconds = (int)(timeout->tv_sec * 1000) + (int)(timeout->tv_usec / 1000);
12902 return poll(&fds, 1, timeout_milliseconds);
12905# define IOWAIT_SYSCALL "select"
12910 if (scheduler !=
Qnil) {
12913 return RTEST(args.result);
12933 case RB_WAITFD_OUT:
12937 VM_UNREACHABLE(nogvl_wait_for);
12957 ret = nogvl_wait_for(stp->th, stp->src_fptr, RB_WAITFD_IN, NULL);
12959 }
while (ret < 0 && maygvl_copy_stream_continue_p(has_gvl, stp));
12962 stp->syserr = IOWAIT_SYSCALL;
12963 stp->error_no =
errno;
12975 ret = nogvl_wait_for(stp->th, stp->dst_fptr, RB_WAITFD_OUT, NULL);
12976 }
while (ret < 0 && maygvl_copy_stream_continue_p(0, stp));
12979 stp->syserr = IOWAIT_SYSCALL;
12980 stp->error_no =
errno;
12986#ifdef USE_COPY_FILE_RANGE
12989simple_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)
12991#ifdef HAVE_COPY_FILE_RANGE
12992 return copy_file_range(in_fd, in_offset, out_fd, out_offset, count, flags);
12994 return syscall(__NR_copy_file_range, in_fd, in_offset, out_fd, out_offset, count, flags);
13003 rb_off_t copy_length, src_offset, *src_offset_ptr;
13005 if (!S_ISREG(stp->src_stat.st_mode))
13008 src_size = stp->src_stat.st_size;
13009 src_offset = stp->src_offset;
13010 if (src_offset >= (rb_off_t)0) {
13011 src_offset_ptr = &src_offset;
13014 src_offset_ptr = NULL;
13017 copy_length = stp->copy_length;
13018 if (copy_length < (rb_off_t)0) {
13019 if (src_offset < (rb_off_t)0) {
13020 rb_off_t current_offset;
13022 current_offset = lseek(stp->src_fptr->
fd, 0, SEEK_CUR);
13023 if (current_offset < (rb_off_t)0 &&
errno) {
13024 stp->syserr =
"lseek";
13025 stp->error_no =
errno;
13026 return (
int)current_offset;
13028 copy_length = src_size - current_offset;
13031 copy_length = src_size - src_offset;
13035 retry_copy_file_range:
13036# if SIZEOF_OFF_T > SIZEOF_SIZE_T
13038 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
13040 ss = (ssize_t)copy_length;
13042 ss = simple_copy_file_range(stp->src_fptr->
fd, src_offset_ptr, stp->dst_fptr->
fd, NULL, ss, 0);
13046 if (0 < copy_length) {
13047 goto retry_copy_file_range;
13051 if (maygvl_copy_stream_continue_p(0, stp)) {
13052 goto retry_copy_file_range;
13066#if EWOULDBLOCK != EAGAIN
13070 int ret = nogvl_copy_stream_wait_write(stp);
13071 if (ret < 0)
return ret;
13073 goto retry_copy_file_range;
13077 int flags = fcntl(stp->dst_fptr->
fd, F_GETFL);
13079 if (flags != -1 && flags & O_APPEND) {
13085 stp->syserr =
"copy_file_range";
13086 stp->error_no =
errno;
13093#ifdef HAVE_FCOPYFILE
13097 rb_off_t cur, ss = 0;
13098 const rb_off_t src_offset = stp->src_offset;
13101 if (stp->copy_length >= (rb_off_t)0) {
13106 if (!S_ISREG(stp->src_stat.st_mode))
13109 if (!S_ISREG(stp->dst_stat.st_mode))
13111 if (lseek(stp->dst_fptr->
fd, 0, SEEK_CUR) > (rb_off_t)0)
13113 if (fcntl(stp->dst_fptr->
fd, F_GETFL) & O_APPEND) {
13116 rb_off_t end = lseek(stp->dst_fptr->
fd, 0, SEEK_END);
13117 lseek(stp->dst_fptr->
fd, 0, SEEK_SET);
13118 if (end > (rb_off_t)0)
return 0;
13121 if (src_offset > (rb_off_t)0) {
13126 cur = lseek(stp->src_fptr->
fd, 0, SEEK_CUR);
13127 if (cur < (rb_off_t)0 &&
errno) {
13128 stp->error_no =
errno;
13133 r = lseek(stp->src_fptr->
fd, src_offset, SEEK_SET);
13134 if (r < (rb_off_t)0 &&
errno) {
13135 stp->error_no =
errno;
13140 stp->copyfile_state = copyfile_state_alloc();
13141 ret = fcopyfile(stp->src_fptr->
fd, stp->dst_fptr->
fd, stp->copyfile_state, COPYFILE_DATA);
13142 copyfile_state_get(stp->copyfile_state, COPYFILE_STATE_COPIED, &ss);
13146 if (src_offset > (rb_off_t)0) {
13150 r = lseek(stp->src_fptr->
fd, cur, SEEK_SET);
13151 if (r < (rb_off_t)0 &&
errno) {
13152 stp->error_no =
errno;
13164 stp->syserr =
"fcopyfile";
13165 stp->error_no =
errno;
13172#ifdef HAVE_SENDFILE
13175# define USE_SENDFILE
13177# ifdef HAVE_SYS_SENDFILE_H
13178# include <sys/sendfile.h>
13182simple_sendfile(
int out_fd,
int in_fd, rb_off_t *offset, rb_off_t count)
13184 return sendfile(out_fd, in_fd, offset, (
size_t)count);
13187# elif 0 || defined(__APPLE__)
13191# define USE_SENDFILE
13194simple_sendfile(
int out_fd,
int in_fd, rb_off_t *offset, rb_off_t count)
13197 rb_off_t pos = offset ? *offset : lseek(in_fd, 0, SEEK_CUR);
13200 r = sendfile(in_fd, out_fd, pos, &count, NULL, 0);
13203 r = sendfile(in_fd, out_fd, pos, (
size_t)count, NULL, &sbytes, 0);
13205 if (r != 0 && sbytes == 0)
return r;
13210 lseek(in_fd, sbytes, SEEK_CUR);
13212 return (ssize_t)sbytes;
13225 rb_off_t copy_length;
13226 rb_off_t src_offset;
13229 if (!S_ISREG(stp->src_stat.st_mode))
13232 src_size = stp->src_stat.st_size;
13234 if ((stp->dst_stat.st_mode & S_IFMT) != S_IFSOCK)
13238 src_offset = stp->src_offset;
13239 use_pread = src_offset >= (rb_off_t)0;
13241 copy_length = stp->copy_length;
13242 if (copy_length < (rb_off_t)0) {
13244 copy_length = src_size - src_offset;
13248 cur = lseek(stp->src_fptr->
fd, 0, SEEK_CUR);
13249 if (cur < (rb_off_t)0 &&
errno) {
13250 stp->syserr =
"lseek";
13251 stp->error_no =
errno;
13254 copy_length = src_size - cur;
13259# if SIZEOF_OFF_T > SIZEOF_SIZE_T
13261 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
13263 ss = (ssize_t)copy_length;
13266 ss = simple_sendfile(stp->dst_fptr->
fd, stp->src_fptr->
fd, &src_offset, ss);
13269 ss = simple_sendfile(stp->dst_fptr->
fd, stp->src_fptr->
fd, NULL, ss);
13274 if (0 < copy_length) {
13275 goto retry_sendfile;
13279 if (maygvl_copy_stream_continue_p(0, stp))
13280 goto retry_sendfile;
13293#if EWOULDBLOCK != EAGAIN
13306 ret = maygvl_copy_stream_wait_read(0, stp);
13307 if (ret < 0)
return ret;
13309 ret = nogvl_copy_stream_wait_write(stp);
13310 if (ret < 0)
return ret;
13312 goto retry_sendfile;
13314 stp->syserr =
"sendfile";
13315 stp->error_no =
errno;
13323maygvl_read(
int has_gvl,
rb_io_t *fptr,
void *buf,
size_t count)
13326 return rb_io_read_memory(fptr, buf, count);
13328 return read(fptr->
fd, buf, count);
13332maygvl_copy_stream_read(
int has_gvl,
struct copy_stream_struct *stp,
char *buf,
size_t len, rb_off_t offset)
13336 if (offset < (rb_off_t)0) {
13337 ss = maygvl_read(has_gvl, stp->src_fptr, buf,
len);
13340 ss = pread(stp->src_fptr->
fd, buf,
len, offset);
13346 if (maygvl_copy_stream_continue_p(has_gvl, stp))
13350#if EWOULDBLOCK != EAGAIN
13354 int ret = maygvl_copy_stream_wait_read(has_gvl, stp);
13355 if (ret < 0)
return ret;
13360 stp->notimp =
"pread";
13364 stp->syserr = offset < (rb_off_t)0 ?
"read" :
"pread";
13365 stp->error_no =
errno;
13376 ss = write(stp->dst_fptr->
fd, buf+
off,
len);
13378 if (maygvl_copy_stream_continue_p(0, stp))
13380 if (io_again_p(
errno)) {
13381 int ret = nogvl_copy_stream_wait_write(stp);
13382 if (ret < 0)
return ret;
13385 stp->syserr =
"write";
13386 stp->error_no =
errno;
13403 rb_off_t copy_length;
13404 rb_off_t src_offset;
13408 copy_length = stp->copy_length;
13409 use_eof = copy_length < (rb_off_t)0;
13410 src_offset = stp->src_offset;
13411 use_pread = src_offset >= (rb_off_t)0;
13413 if (use_pread && stp->close_src) {
13416 r = lseek(stp->src_fptr->
fd, src_offset, SEEK_SET);
13417 if (r < (rb_off_t)0 &&
errno) {
13418 stp->syserr =
"lseek";
13419 stp->error_no =
errno;
13422 src_offset = (rb_off_t)-1;
13426 while (use_eof || 0 < copy_length) {
13427 if (!use_eof && copy_length < (rb_off_t)
sizeof(buf)) {
13428 len = (size_t)copy_length;
13434 ss = maygvl_copy_stream_read(0, stp, buf,
len, src_offset);
13439 ss = maygvl_copy_stream_read(0, stp, buf,
len, (rb_off_t)-1);
13444 ret = nogvl_copy_stream_write(stp, buf, ss);
13454nogvl_copy_stream_func(
void *arg)
13457#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13461#ifdef USE_COPY_FILE_RANGE
13462 ret = nogvl_copy_file_range(stp);
13467#ifdef HAVE_FCOPYFILE
13468 ret = nogvl_fcopyfile(stp);
13474 ret = nogvl_copy_stream_sendfile(stp);
13479 nogvl_copy_stream_read_write(stp);
13481#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13488copy_stream_fallback_body(
VALUE arg)
13491 const int buflen = 16*1024;
13494 rb_off_t rest = stp->copy_length;
13495 rb_off_t
off = stp->src_offset;
13496 ID read_method = id_readpartial;
13498 if (!stp->src_fptr) {
13500 read_method = id_read;
13507 rb_str_make_independent(buf);
13508 if (stp->copy_length < (rb_off_t)0) {
13513 rb_str_resize(buf, 0);
13516 l = buflen < rest ? buflen : (long)rest;
13518 if (!stp->src_fptr) {
13521 if (read_method == id_read &&
NIL_P(rc))
13526 rb_str_resize(buf, buflen);
13527 ss = maygvl_copy_stream_read(1, stp, RSTRING_PTR(buf), l,
off);
13528 rb_str_resize(buf, ss > 0 ? ss : 0);
13533 if (
off >= (rb_off_t)0)
13536 n = rb_io_write(stp->dst, buf);
13538 stp->total += numwrote;
13540 if (read_method == id_read && RSTRING_LEN(buf) == 0) {
13551 if (!stp->src_fptr && stp->src_offset >= (rb_off_t)0) {
13552 rb_raise(rb_eArgError,
"cannot specify src_offset for non-IO");
13561copy_stream_body(
VALUE arg)
13564 VALUE src_io = stp->src, dst_io = stp->dst;
13565 const int common_oflags = 0
13575 if (src_io ==
argf ||
13579 stp->src_fptr = NULL;
13584 if (!
NIL_P(tmp_io)) {
13591 args[1] =
INT2NUM(O_RDONLY|common_oflags);
13594 stp->close_src = 1;
13599 stat_ret = fstat(stp->src_fptr->
fd, &stp->src_stat);
13600 if (stat_ret < 0) {
13601 stp->syserr =
"fstat";
13602 stp->error_no =
errno;
13607 if (dst_io ==
argf ||
13611 stp->dst_fptr = NULL;
13616 if (!
NIL_P(tmp_io)) {
13617 dst_io = GetWriteIO(tmp_io);
13623 args[1] =
INT2NUM(O_WRONLY|O_CREAT|O_TRUNC|common_oflags);
13627 stp->close_dst = 1;
13630 dst_io = GetWriteIO(dst_io);
13636 stat_ret = fstat(stp->dst_fptr->
fd, &stp->dst_stat);
13637 if (stat_ret < 0) {
13638 stp->syserr =
"fstat";
13639 stp->error_no =
errno;
13646 SET_BINARY_MODE_WITH_SEEK_CUR(stp->src_fptr);
13649 io_ascii8bit_binmode(stp->dst_fptr);
13651 if (stp->src_offset < (rb_off_t)0 && stp->src_fptr && stp->src_fptr->
rbuf.
len) {
13654 if (stp->copy_length >= (rb_off_t)0 && stp->copy_length < (rb_off_t)
len) {
13655 len = (size_t)stp->copy_length;
13658 rb_str_resize(str,
len);
13659 read_buffered_data(RSTRING_PTR(str),
len, stp->src_fptr);
13660 if (stp->dst_fptr) {
13661 if (io_binwrite(RSTRING_PTR(str), RSTRING_LEN(str), stp->dst_fptr, 0) < 0)
13662 rb_sys_fail_on_write(stp->dst_fptr);
13665 rb_io_write(dst_io, str);
13666 rb_str_resize(str, 0);
13668 if (stp->copy_length >= (rb_off_t)0)
13669 stp->copy_length -=
len;
13672 if (stp->dst_fptr && io_fflush(stp->dst_fptr) < 0) {
13676 if (stp->copy_length == 0)
13679 if (stp->src_fptr == NULL || stp->dst_fptr == NULL) {
13680 return copy_stream_fallback(stp);
13683 IO_WITHOUT_GVL(nogvl_copy_stream_func, stp);
13688copy_stream_finalize(
VALUE arg)
13692#ifdef HAVE_FCOPYFILE
13693 if (stp->copyfile_state) {
13694 copyfile_state_free(stp->copyfile_state);
13698 if (stp->close_src) {
13699 rb_io_close_m(stp->src);
13701 if (stp->close_dst) {
13702 rb_io_close_m(stp->dst);
13765rb_io_s_copy_stream(
int argc,
VALUE *argv,
VALUE io)
13767 VALUE src, dst, length, src_offset;
13772 rb_scan_args(argc, argv,
"22", &src, &dst, &length, &src_offset);
13777 st.src_fptr = NULL;
13778 st.dst_fptr = NULL;
13781 st.copy_length = (rb_off_t)-1;
13783 st.copy_length =
NUM2OFFT(length);
13785 if (
NIL_P(src_offset))
13786 st.src_offset = (rb_off_t)-1;
13788 st.src_offset =
NUM2OFFT(src_offset);
13807rb_io_external_encoding(
VALUE io)
13812 return rb_enc_from_encoding(fptr->
encs.
enc2);
13816 return rb_enc_from_encoding(fptr->
encs.
enc);
13819 return rb_enc_from_encoding(io_read_encoding(fptr));
13835rb_io_internal_encoding(
VALUE io)
13840 return rb_enc_from_encoding(io_read_encoding(fptr));
13874rb_io_set_encoding(
int argc,
VALUE *argv,
VALUE io)
13880 return forward(io, id_set_encoding, argc, argv);
13883 argc =
rb_scan_args(argc, argv,
"11:", &v1, &v2, &opt);
13885 io_encoding_set(fptr, v1, v2, opt);
13890rb_stdio_set_default_encoding(
void)
13895 if (isatty(fileno(stdin))) {
13897 rb_encoding *internal = rb_default_internal_encoding();
13898 if (!internal) internal = rb_default_external_encoding();
13900 rb_enc_from_encoding(external),
13901 rb_enc_from_encoding(internal),
13906 rb_io_set_encoding(1, &val,
rb_stdin);
13907 rb_io_set_encoding(1, &val,
rb_stdout);
13908 rb_io_set_encoding(1, &val,
rb_stderr);
13912global_argf_p(
VALUE arg)
13914 return arg ==
argf;
13917typedef VALUE (*argf_encoding_func)(
VALUE io);
13920argf_encoding(
VALUE argf, argf_encoding_func func)
13922 if (!
RTEST(ARGF.current_file)) {
13923 return rb_enc_default_external();
13947 return argf_encoding(
argf, rb_io_external_encoding);
13966 return argf_encoding(
argf, rb_io_internal_encoding);
14005 if (!next_argv()) {
14006 rb_raise(rb_eArgError,
"no stream to set encoding");
14008 rb_io_set_encoding(argc, argv, ARGF.current_file);
14010 ARGF.encs = fptr->
encs;
14030 if (!next_argv()) {
14031 rb_raise(rb_eArgError,
"no stream to tell");
14033 ARGF_FORWARD(0, 0);
14034 return rb_io_tell(ARGF.current_file);
14047 if (!next_argv()) {
14048 rb_raise(rb_eArgError,
"no stream to seek");
14050 ARGF_FORWARD(argc, argv);
14051 return rb_io_seek_m(argc, argv, ARGF.current_file);
14068 if (!next_argv()) {
14069 rb_raise(rb_eArgError,
"no stream to set position");
14071 ARGF_FORWARD(1, &offset);
14072 return rb_io_set_pos(ARGF.current_file, offset);
14093 if (!next_argv()) {
14094 rb_raise(rb_eArgError,
"no stream to rewind");
14096 ARGF_FORWARD(0, 0);
14097 old_lineno =
RFILE(ARGF.current_file)->fptr->lineno;
14098 ret = rb_io_rewind(ARGF.current_file);
14099 if (!global_argf_p(
argf)) {
14100 ARGF.last_lineno = ARGF.lineno -= old_lineno;
14118 if (!next_argv()) {
14119 rb_raise(rb_eArgError,
"no stream");
14121 ARGF_FORWARD(0, 0);
14122 return rb_io_fileno(ARGF.current_file);
14141 ARGF_FORWARD(0, 0);
14142 return ARGF.current_file;
14167 if (
RTEST(ARGF.current_file)) {
14168 if (ARGF.init_p == 0)
return Qtrue;
14170 ARGF_FORWARD(0, 0);
14229 VALUE tmp, str, length;
14233 if (!
NIL_P(length)) {
14238 rb_str_resize(str,0);
14243 if (!next_argv()) {
14246 if (ARGF_GENERIC_INPUT_P()) {
14247 tmp = argf_forward(argc, argv,
argf);
14250 tmp = io_read(argc, argv, ARGF.current_file);
14252 if (
NIL_P(str)) str = tmp;
14255 if (ARGF.next_p != -1) {
14261 else if (argc >= 1) {
14262 long slen = RSTRING_LEN(str);
14278argf_forward_call(
VALUE arg)
14281 argf_forward(p->argc, p->argv, p->argf);
14311 return argf_getpartial(argc, argv,
argf,
Qnil, 0);
14332 return argf_getpartial(argc, argv,
argf, opts, 1);
14338 VALUE tmp, str, length;
14346 no_exception = no_exception_p(opts);
14348 if (!next_argv()) {
14350 rb_str_resize(str, 0);
14354 if (ARGF_GENERIC_INPUT_P()) {
14364 tmp = io_getpartial(argc, argv, ARGF.current_file, no_exception, nonblock);
14367 if (ARGF.next_p == -1) {
14368 return io_nonblock_eof(no_exception);
14373 return io_nonblock_eof(no_exception);
14411 if (!next_argv())
return Qnil;
14412 if (ARGF_GENERIC_INPUT_P()) {
14413 ch = forward_current(rb_intern(
"getc"), 0, 0);
14416 ch = rb_io_getc(ARGF.current_file);
14418 if (
NIL_P(ch) && ARGF.next_p != -1) {
14451 if (!next_argv())
return Qnil;
14453 ch = forward_current(rb_intern(
"getbyte"), 0, 0);
14458 if (
NIL_P(ch) && ARGF.next_p != -1) {
14491 if (!next_argv()) rb_eof_error();
14493 ch = forward_current(rb_intern(
"getc"), 0, 0);
14496 ch = rb_io_getc(ARGF.current_file);
14498 if (
NIL_P(ch) && ARGF.next_p != -1) {
14530 NEXT_ARGF_FORWARD(0, 0);
14531 c = argf_getbyte(
argf);
14538#define FOREACH_ARGF() while (next_argv())
14543 const VALUE current = ARGF.current_file;
14545 if (ARGF.init_p == -1 || current != ARGF.current_file) {
14551#define ARGF_block_call(mid, argc, argv, func, argf) \
14552 rb_block_call_kw(ARGF.current_file, mid, argc, argv, \
14553 func, argf, rb_keyword_given_p())
14558 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_i,
argf);
14559 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14565 if (!global_argf_p(
argf)) {
14566 ARGF.last_lineno = ++ARGF.lineno;
14568 return argf_block_call_i(i,
argf, argc, argv, blockarg);
14574 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_line_i,
argf);
14575 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14623 argf_block_call_line(rb_intern(
"each_line"), argc, argv,
argf);
14654 argf_block_call(rb_intern(
"each_byte"), 0, 0,
argf);
14680 argf_block_call(rb_intern(
"each_char"), 0, 0,
argf);
14706 argf_block_call(rb_intern(
"each_codepoint"), 0, 0,
argf);
14737 return ARGF.filename;
14741argf_filename_getter(
ID id,
VALUE *var)
14743 return argf_filename(*var);
14768 return ARGF.current_file;
14787 ARGF_FORWARD(0, 0);
14808 return RBOOL(ARGF.binmode);
14828 if (ARGF.init_p && ARGF.next_p == 0) {
14857 if (ARGF.next_p != -1) {
14875 ARGF_FORWARD(0, 0);
14902 if (!ARGF.inplace)
return Qnil;
14910 return argf_inplace_mode_get(*var);
14941 ARGF.inplace =
Qnil;
14952 argf_inplace_mode_set(*var, val);
14956ruby_set_inplace_mode(
const char *suffix)
14982argf_argv_getter(
ID id,
VALUE *var)
14984 return argf_argv(*var);
15003 if (!
RTEST(ARGF.current_file)) {
15006 return GetWriteIO(ARGF.current_file);
15018 return rb_io_writev(argf_write_io(
argf), argc, argv);
15033 case RB_IO_WAIT_WRITABLE:
15036 c = rb_eEAGAINWaitWritable;
15038#if EAGAIN != EWOULDBLOCK
15040 c = rb_eEWOULDBLOCKWaitWritable;
15044 c = rb_eEINPROGRESSWaitWritable;
15050 case RB_IO_WAIT_READABLE:
15053 c = rb_eEAGAINWaitReadable;
15055#if EAGAIN != EWOULDBLOCK
15057 c = rb_eEWOULDBLOCKWaitReadable;
15061 c = rb_eEINPROGRESSWaitReadable;
15068 rb_bug(
"invalid read/write type passed to rb_readwrite_sys_fail: %d", waiting);
15074get_LAST_READ_LINE(
ID _x,
VALUE *_y)
15964#include <sys/cygwin.h>
15965 static struct __cygwin_perfile pf[] =
15967 {
"", O_RDONLY | O_BINARY},
15968 {
"", O_WRONLY | O_BINARY},
15969 {
"", O_RDWR | O_BINARY},
15970 {
"", O_APPEND | O_BINARY},
15973 cygwin_internal(CW_PERFILE, pf);
16022 rb_eEAGAINWaitReadable = rb_define_class_under(
rb_cIO,
"EAGAINWaitReadable", rb_eEAGAIN);
16025 rb_eEAGAINWaitWritable = rb_define_class_under(
rb_cIO,
"EAGAINWaitWritable", rb_eEAGAIN);
16027#if EAGAIN == EWOULDBLOCK
16029 rb_define_const(
rb_cIO,
"EWOULDBLOCKWaitReadable", rb_eEAGAINWaitReadable);
16031 rb_define_const(
rb_cIO,
"EWOULDBLOCKWaitWritable", rb_eEAGAINWaitWritable);
16034 rb_eEWOULDBLOCKWaitReadable = rb_define_class_under(
rb_cIO,
"EWOULDBLOCKWaitReadable", rb_eEWOULDBLOCK);
16037 rb_eEWOULDBLOCKWaitWritable = rb_define_class_under(
rb_cIO,
"EWOULDBLOCKWaitWritable", rb_eEWOULDBLOCK);
16041 rb_eEINPROGRESSWaitReadable = rb_define_class_under(
rb_cIO,
"EINPROGRESSWaitReadable", rb_eEINPROGRESS);
16044 rb_eEINPROGRESSWaitWritable = rb_define_class_under(
rb_cIO,
"EINPROGRESSWaitWritable", rb_eEINPROGRESS);
16079 rb_gvar_ractor_local(
"$/");
16081 rb_gvar_ractor_local(
"$-0");
16085 rb_gvar_ractor_local(
"$_");
16086 rb_gvar_box_dynamic(
"$_");
16202 rb_gvar_ractor_local(
"$stdin");
16203 rb_gvar_ractor_local(
"$stdout");
16204 rb_gvar_ractor_local(
"$>");
16205 rb_gvar_ractor_local(
"$stderr");
16207 rb_gvar_box_dynamic(
"$stdin");
16208 rb_gvar_box_dynamic(
"$stdout");
16209 rb_gvar_box_dynamic(
"$>");
16210 rb_gvar_box_dynamic(
"$stderr");
16231 rb_cARGF = rb_define_class(
"ARGF",
rb_cObject);
16296 rb_define_method(rb_cARGF,
"external_encoding", argf_external_encoding, 0);
16297 rb_define_method(rb_cARGF,
"internal_encoding", argf_internal_encoding, 0);
16316 rb_gvar_ractor_local(
"$-i");
16320#if defined (_WIN32) || defined(__CYGWIN__)
16321 atexit(pipe_atexit);
16333 sym_encoding =
ID2SYM(rb_id_encoding());
16357static void init_builtin_io(
void);
16358#define Init_builtin_io init_builtin_io
16360#undef Init_builtin_io
16363Init_builtin_io(
void)
#define RUBY_ASSERT(...)
Asserts that the given expression is truthy if and only if RUBY_DEBUG is truthy.
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_class_new(VALUE super)
Creates a new, anonymous class.
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 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 REALLOC_N
Old name of RB_REALLOC_N.
#define OBJ_INIT_COPY(obj, orig)
Old name of RB_OBJ_INIT_COPY.
#define ALLOC
Old name of RB_ALLOC.
#define RFLOAT_VALUE
Old name of rb_float_value.
#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 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_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_exc_raise(VALUE mesg)
Raises an exception in the current thread.
void rb_syserr_fail(int e, const char *mesg)
Raises appropriate exception that represents a C errno.
void rb_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_cObject
Object class.
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_obj_freeze(VALUE obj)
Same as RB_OBJ_FREEZE(), but returns the given object.
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.
#define RB_OBJ_WRITTEN(old, oldv, young)
Identical to RB_OBJ_WRITE(), except it doesn't write any values, but only a WB declaration.
#define RB_OBJ_WRITE(old, slot, young)
Declaration of a "back" pointer.
VALUE rb_fiber_scheduler_current(void)
Identical to rb_fiber_scheduler_get(), except it also returns RUBY_Qnil in case of a blocking fiber.
VALUE rb_fiber_scheduler_make_timeout(struct timeval *timeout)
Converts the passed timeout to an expression that rb_fiber_scheduler_block() etc.
VALUE rb_fiber_scheduler_io_wait_readable(VALUE scheduler, VALUE io)
Non-blocking wait until the passed IO is ready for reading.
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_pread_memory(VALUE scheduler, VALUE io, rb_off_t from, void *base, size_t size)
Non-blocking pread from the passed IO using a native buffer.
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_read_memory(VALUE scheduler, VALUE io, void *base, size_t size)
Non-blocking read from 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 value inst...
VALUE rb_fiber_scheduler_io_pwrite_memory(VALUE scheduler, VALUE io, rb_off_t from, const void *base, size_t size)
Non-blocking pwrite to the passed IO using a native buffer.
VALUE rb_fiber_scheduler_current_for_threadptr(struct rb_thread_struct *thread)
Identical to rb_fiber_scheduler_current_for_thread(), except it expects a threadptr instead of a thre...
VALUE rb_fiber_scheduler_io_wait_writable(VALUE scheduler, VALUE io)
Non-blocking wait until the passed IO is ready for writing.
VALUE rb_fiber_scheduler_io_close(VALUE scheduler, VALUE io)
Non-blocking close the given IO.
VALUE rb_fiber_scheduler_io_write_memory(VALUE scheduler, VALUE io, const void *base, size_t size)
Non-blocking write to the passed IO using a native buffer.
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_mbmaxlen(rb_encoding *enc)
Queries the maximum number of bytes that the passed encoding needs to represent a character.
VALUE rb_str_conv_enc(VALUE str, rb_encoding *from, rb_encoding *to)
Encoding conversion main routine.
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.
VALUE rb_funcallv(VALUE recv, ID mid, int argc, const VALUE *argv)
Identical to rb_funcall(), except it takes the method arguments as a C array.
Defines RBIMPL_HAS_BUILTIN.
VALUE rb_ary_concat(VALUE lhs, VALUE rhs)
Destructively appends the contents of latter into the end of former.
VALUE rb_ary_shift(VALUE ary)
Destructively deletes an element from the beginning of the passed array and returns what was deleted.
VALUE rb_check_array_type(VALUE obj)
Try converting an object to its array representation using its to_ary method, if any.
VALUE rb_ary_new(void)
Allocates a new, empty array.
VALUE rb_ary_new_capa(long capa)
Identical to rb_ary_new(), except it additionally specifies how many rooms of objects it should alloc...
VALUE rb_ary_push(VALUE ary, VALUE elem)
Special case of rb_ary_cat() that it adds only one element.
VALUE rb_ary_entry(VALUE ary, long off)
Queries an element of an array.
VALUE rb_assoc_new(VALUE car, VALUE cdr)
Identical to rb_ary_new_from_values(), except it expects exactly two parameters.
#define RETURN_ENUMERATOR(obj, argc, argv)
Identical to RETURN_SIZED_ENUMERATOR(), except its size is unknown.
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_output_fs
The field separator character for outputs, or the $,.
VALUE rb_file_open_str(VALUE fname, const char *fmode)
Identical to rb_file_open(), except it takes the pathname as a Ruby's string instead of C's.
int rb_cloexec_dup(int oldfd)
Identical to rb_cloexec_fcntl_dupfd(), except it implies minfd is 3.
VALUE rb_file_open(const char *fname, const char *fmode)
Opens a file located at the given path.
VALUE rb_io_close(VALUE io)
Closes the IO.
VALUE rb_default_rs
This is the default value of rb_rs, i.e.
void rb_provide(const char *feature)
Declares that the given feature is already provided by someone else.
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_new_frozen(VALUE str)
Creates a frozen copy of the string, if necessary.
VALUE rb_str_dup(VALUE str)
Duplicates a string.
VALUE rb_str_cat(VALUE dst, const char *src, long srclen)
Destructively appends the passed contents to the string.
VALUE rb_str_locktmp(VALUE str)
Obtains a "temporary lock" of the string.
VALUE rb_str_equal(VALUE str1, VALUE str2)
Equality of two strings.
void rb_str_set_len(VALUE str, long len)
Overwrites the length of the string.
VALUE rb_str_buf_cat_ascii(VALUE dst, const char *src)
Identical to rb_str_cat_cstr(), except it additionally assumes the source string be a NUL terminated ...
VALUE rb_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.
VALUE rb_str_buf_new(long capa)
Allocates a "string buffer".
#define rb_str_new_cstr(str)
Identical to rb_str_new, except it assumes the passed pointer is a pointer to a C string.
VALUE rb_obj_as_string(VALUE obj)
Try converting an object to its stringised representation using its to_s method, if any.
int rb_thread_interrupted(VALUE thval)
Checks if the thread's execution was recently interrupted.
VALUE rb_mutex_new(void)
Creates a mutex.
int rb_thread_fd_writable(int fd)
Identical to rb_thread_wait_fd(), except it blocks the current thread until the given file descriptor...
VALUE rb_exec_recursive(VALUE(*f)(VALUE g, VALUE h, int r), VALUE g, VALUE h)
"Recursion" API entry point.
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.
int rb_method_basic_definition_p(VALUE klass, ID mid)
Well... Let us hesitate from describing what a "basic definition" is.
VALUE rb_check_funcall(VALUE recv, ID mid, int argc, const VALUE *argv)
Identical to rb_funcallv(), except it returns RUBY_Qundef instead of raising rb_eNoMethodError.
void rb_define_alloc_func(VALUE klass, rb_alloc_func_t func)
Sets the allocator function of a class.
static ID rb_intern_const(const char *str)
This is a "tiny optimisation" over rb_intern().
#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.
#define FMODE_READABLE
The IO is opened for reading.
enum rb_io_mode 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.
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_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_extract_encoding_option(VALUE opt, rb_encoding **enc_p, rb_encoding **enc2_p, enum rb_io_mode *fmode_p)
This function breaks down the option hash that IO#initialize takes into components.
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_extract_modeenc(VALUE *vmode_p, VALUE *vperm_p, VALUE opthash, int *oflags_p, enum rb_io_mode *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...
void rb_io_check_initialized(rb_io_t *fptr)
Asserts that the passed IO is initialised.
#define FMODE_EXCL
This flag amends the effect of FMODE_CREATE, so that if there already is a file at the given path the...
#define FMODE_TEXTMODE
The IO is in "text mode".
int rb_io_fptr_finalize(rb_io_t *fptr)
Destroys the given IO.
VALUE rb_io_check_io(VALUE io)
Try converting an object to its IO representation using its to_io method, if any.
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".
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.
#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 StringValue(v)
Ensures that the parameter object is a String.
static char * RSTRING_END(VALUE str)
Queries the end of the contents pointer of the string.
#define RSTRING_GETMEM(str, ptrvar, lenvar)
Convenient macro to obtain the contents and length at once.
#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.
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.
rb_io_buffer_t wbuf
Write buffer.
enum rb_io_mode mode
mode flags: FMODE_XXXs
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
struct ccan_list_head blocking_operations
Threads that are performing a blocking operation without the GVL using this IO.
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_FLOAT_TYPE_P(VALUE obj)
Queries if the object is an instance of rb_cFloat.
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.
static bool RB_TYPE_P(VALUE obj, enum ruby_value_type t)
Queries if the given object is of given type.
#define RBIMPL_WARNING_IGNORED(flag)
Suppresses a warning.
#define RBIMPL_WARNING_PUSH()
Pushes compiler warning state.
#define RBIMPL_WARNING_POP()
Pops compiler warning state.