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
1039flush_before_seek(
rb_io_t *fptr,
bool discard_rbuf)
1041 if (io_fflush(fptr) < 0)
1042 rb_sys_fail_on_write(fptr);
1043 io_unread(fptr, discard_rbuf);
1048#define io_seek(fptr, ofs, whence) (errno = 0, lseek(flush_before_seek(fptr, true)->fd, (ofs), (whence)))
1049#define io_tell(fptr) lseek(flush_before_seek(fptr, false)->fd, 0, SEEK_CUR)
1065 if (io_fflush(fptr) < 0)
1066 rb_sys_fail_on_write(fptr);
1071 if (io_fflush(wfptr) < 0)
1072 rb_sys_fail_on_write(wfptr);
1080 if (READ_CHAR_PENDING(fptr)) {
1081 rb_raise(
rb_eIOError,
"byte oriented read for character buffered IO");
1092io_read_encoding(
rb_io_t *fptr)
1097 return rb_default_external_encoding();
1101io_input_encoding(
rb_io_t *fptr)
1106 return io_read_encoding(fptr);
1117 io_unread(fptr,
true);
1122rb_io_read_pending(
rb_io_t *fptr)
1125 if (READ_CHAR_PENDING(fptr))
1127 return READ_DATA_PENDING(fptr);
1133 if (!READ_DATA_PENDING(fptr)) {
1140rb_gc_for_fd(
int err)
1142 if (err == EMFILE || err == ENFILE || err == ENOMEM) {
1152#define TRY_WITH_GC(expr) \
1153 for (int first_errno, retried_errno = 0, retried = 0; \
1156 (!rb_gc_for_fd(first_errno = errno) || !(expr)) && \
1157 (retried_errno = errno, 1)); \
1158 (void)retried_errno, retried = 1)
1173io_alloc(
VALUE klass)
1175 UNPROTECTED_NEWOBJ_OF(io,
struct RFile, klass,
T_FILE,
sizeof(
struct RFile));
1183# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
1209struct io_internal_writev_struct {
1216 const struct iovec *iov;
1229io_internal_wait(
VALUE thread,
rb_io_t *fptr,
int error,
int events,
struct timeval *timeout)
1231 if (!timeout && rb_thread_mn_schedulable(thread)) {
1236 int ready = nogvl_wait_for(thread, fptr, events, timeout);
1241 else if (ready == 0) {
1258internal_read_func(
void *ptr)
1263 if (iis->timeout && !iis->nonblock) {
1264 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_IN, iis->timeout) == -1) {
1270 result = read(iis->fd, iis->buf, iis->capa);
1272 if (result < 0 && !iis->nonblock) {
1273 if (io_again_p(
errno)) {
1274 if (io_internal_wait(iis->th, iis->fptr,
errno, RB_WAITFD_IN, iis->timeout) == -1) {
1286#if defined __APPLE__
1287# define do_write_retry(code) do {result = code;} while (result == -1 && errno == EPROTOTYPE)
1289# define do_write_retry(code) result = code
1293internal_write_func(
void *ptr)
1298 if (iis->timeout && !iis->nonblock) {
1299 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1305 do_write_retry(write(iis->fd, iis->buf, iis->capa));
1307 if (result < 0 && !iis->nonblock) {
1309 if (io_again_p(e)) {
1310 if (io_internal_wait(iis->th, iis->fptr,
errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1324internal_writev_func(
void *ptr)
1326 struct io_internal_writev_struct *iis = ptr;
1329 if (iis->timeout && !iis->nonblock) {
1330 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1336 do_write_retry(writev(iis->fd, iis->iov, iis->iovcnt));
1338 if (result < 0 && !iis->nonblock) {
1339 if (io_again_p(
errno)) {
1340 if (io_internal_wait(iis->th, iis->fptr,
errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1354rb_io_read_memory(
rb_io_t *fptr,
void *buf,
size_t count)
1358 if (scheduler !=
Qnil) {
1361 if (!UNDEF_P(result)) {
1377 struct timeval timeout_storage;
1381 iis.timeout = &timeout_storage;
1384 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_read_func, &iis,
RUBY_IO_READABLE);
1388rb_io_write_memory(
rb_io_t *fptr,
const void *buf,
size_t count)
1392 if (scheduler !=
Qnil) {
1395 if (!UNDEF_P(result)) {
1411 struct timeval timeout_storage;
1415 iis.timeout = &timeout_storage;
1418 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_write_func, &iis,
RUBY_IO_WRITABLE);
1423rb_writev_internal(
rb_io_t *fptr,
const struct iovec *iov,
int iovcnt)
1425 if (!iovcnt)
return 0;
1430 if (scheduler !=
Qnil) {
1434 if (!UNDEF_P(result)) {
1439 struct io_internal_writev_struct iis = {
1450 struct timeval timeout_storage;
1454 iis.timeout = &timeout_storage;
1457 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_writev_func, &iis,
RUBY_IO_WRITABLE);
1462io_flush_buffer_sync(
void *arg)
1484io_flush_buffer_fiber_scheduler(
VALUE scheduler,
rb_io_t *fptr)
1487 if (!UNDEF_P(ret)) {
1499io_flush_buffer_async(
VALUE arg)
1504 if (scheduler !=
Qnil) {
1505 VALUE result = io_flush_buffer_fiber_scheduler(scheduler, fptr);
1506 if (!UNDEF_P(result)) {
1511 return rb_io_blocking_region_wait(fptr, io_flush_buffer_sync, fptr,
RUBY_IO_WRITABLE);
1518 return (
int)io_flush_buffer_async((
VALUE)fptr);
1533 while (fptr->
wbuf.
len > 0 && io_flush_buffer(fptr) != 0) {
1549 if (scheduler !=
Qnil) {
1559 if (NIL_OR_UNDEF_P(timeout)) {
1563 if (timeout !=
Qnil) {
1568 int ready = rb_thread_io_wait(th, fptr,
RB_NUM2INT(events), tv);
1594 if (scheduler !=
Qnil) {
1600 return rb_thread_wait_for_single_fd(th, fd, events, timeout);
1606 io_fd_check_closed(f);
1613#if defined(ERESTART)
1620#if EWOULDBLOCK != EAGAIN
1623 if (scheduler !=
Qnil) {
1641 io_fd_check_closed(f);
1648#if defined(ERESTART)
1664#if EWOULDBLOCK != EAGAIN
1667 if (scheduler !=
Qnil) {
1687 return io_wait_for_single_fd(fd, events, timeout, th, scheduler);
1721#if defined(ERESTART)
1731#if EWOULDBLOCK != EAGAIN
1748 if (
RTEST(result)) {
1763 if (
RTEST(result)) {
1777 const char *senc, *denc;
1784 ecflags = fptr->
encs.
ecflags & ~ECONV_NEWLINE_DECORATOR_READ_MASK;
1811 denc = rb_enc_name(enc);
1843io_binwrite_string_internal(
rb_io_t *fptr,
const char *ptr,
long length)
1846 struct iovec iov[2];
1849 iov[0].iov_len = fptr->
wbuf.
len;
1850 iov[1].iov_base = (
void*)ptr;
1851 iov[1].iov_len = length;
1853 ssize_t result = rb_writev_internal(fptr, iov, 2);
1858 if (result >= fptr->
wbuf.
len) {
1866 fptr->
wbuf.
off += (int)result;
1867 fptr->
wbuf.
len -= (int)result;
1875 return rb_io_write_memory(fptr, ptr, length);
1880io_binwrite_string_internal(
rb_io_t *fptr,
const char *ptr,
long length)
1882 long remaining = length;
1885 if (fptr->
wbuf.
len+length <= fptr->wbuf.capa) {
1892 fptr->
wbuf.
len += (int)length;
1899 if (io_fflush(fptr) < 0) {
1904 if (remaining == 0) {
1910 return rb_io_write_memory(fptr, ptr, length);
1915io_binwrite_string(
VALUE arg)
1919 const char *ptr = p->ptr;
1920 size_t remaining = p->length;
1924 ssize_t result = io_binwrite_string_internal(p->fptr, ptr, remaining);
1930 else if (result > 0) {
1931 if ((
size_t)result == remaining)
break;
1933 remaining -= result;
1949io_allocate_write_buffer(
rb_io_t *fptr,
int sync)
1954 fptr->
wbuf.
capa = IO_WBUF_CAPA_MIN;
1965io_binwrite_requires_flush_write(
rb_io_t *fptr,
long len,
int nosync)
1980io_binwrite(
const char *ptr,
long len,
rb_io_t *fptr,
int nosync)
1982 if (
len <= 0)
return len;
1987 io_allocate_write_buffer(fptr, !nosync);
1989 if (io_binwrite_requires_flush_write(fptr,
len, nosync)) {
2000 return io_binwrite_string((
VALUE)&arg);
2017# define MODE_BTMODE(a,b,c) ((fmode & FMODE_BINMODE) ? (b) : \
2018 (fmode & FMODE_TEXTMODE) ? (c) : (a))
2020#define MODE_BTXMODE(a, b, c, d, e, f) ((fmode & FMODE_EXCL) ? \
2021 MODE_BTMODE(d, e, f) : \
2022 MODE_BTMODE(a, b, c))
2027 if (NEED_WRITECONV(fptr)) {
2029 SET_BINARY_MODE(fptr);
2031 make_writeconv(fptr);
2034#define fmode (fptr->mode)
2037 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1) && !rb_enc_asciicompat(rb_enc_get(str))) {
2038 rb_raise(rb_eArgError,
"ASCII incompatible string written for text mode IO without encoding conversion: %s",
2039 rb_enc_name(rb_enc_get(str)));
2045 common_encoding = rb_enc_from_encoding(fptr->
encs.
enc2);
2046 else if (fptr->
encs.
enc != rb_ascii8bit_encoding())
2047 common_encoding = rb_enc_from_encoding(fptr->
encs.
enc);
2050 if (!
NIL_P(common_encoding)) {
2061#if RUBY_CRLF_ENVIRONMENT
2062#define fmode (fptr->mode)
2063 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1)) {
2066 setmode(fptr->
fd, O_BINARY);
2069 setmode(fptr->
fd, O_TEXT);
2071 if (!rb_enc_asciicompat(rb_enc_get(str))) {
2072 rb_raise(rb_eArgError,
"ASCII incompatible string written for text mode IO without encoding conversion: %s",
2073 rb_enc_name(rb_enc_get(str)));
2091 long len = rb_w32_write_console(str, fptr->
fd);
2096 str = do_writeconv(str, fptr, &converted);
2100 tmp = rb_str_tmp_frozen_no_embed_acquire(str);
2102 n = io_binwrite(ptr,
len, fptr, nosync);
2103 rb_str_tmp_frozen_release(str, tmp);
2115 return (ssize_t)io_binwrite(buf, (
long)size, fptr, 0);
2125 io = GetWriteIO(io);
2135 if (RSTRING_LEN(str) == 0)
return INT2FIX(0);
2140 n = io_fwrite(str, fptr, nosync);
2141 if (n < 0L) rb_sys_fail_on_write(fptr);
2147struct binwritev_arg {
2155io_binwritev_internal(
VALUE arg)
2157 struct binwritev_arg *p = (
struct binwritev_arg *)arg;
2159 size_t remaining = p->total;
2163 struct iovec *iov = p->iov;
2164 int iovcnt = p->iovcnt;
2167 long result = rb_writev_internal(fptr, iov, iovcnt);
2172 if (offset < (
size_t)fptr->
wbuf.
len) {
2177 offset -= (size_t)fptr->
wbuf.
len;
2183 if (offset == p->total) {
2187 while (result >= (ssize_t)iov->iov_len) {
2189 result -= iov->iov_len;
2199 iov->iov_base = (
char *)iov->iov_base + result;
2200 iov->iov_len -= result;
2214io_binwritev(
struct iovec *iov,
int iovcnt,
rb_io_t *fptr)
2219 if (iovcnt == 0)
return 0;
2222 for (
int i = 1; i < iovcnt; i++) total += iov[i].iov_len;
2224 io_allocate_write_buffer(fptr, 1);
2230 if (offset + total <= (
size_t)fptr->
wbuf.
capa) {
2231 for (
int i = 1; i < iovcnt; i++) {
2232 memcpy(fptr->
wbuf.
ptr+offset, iov[i].iov_base, iov[i].iov_len);
2233 offset += iov[i].iov_len;
2244 if (io_fflush(fptr) < 0)
return -1;
2250 iov[0].iov_len = fptr->
wbuf.
len;
2263 struct binwritev_arg arg;
2266 arg.iovcnt = iovcnt;
2273 return io_binwritev_internal((
VALUE)&arg);
2280 int i, converted, iovcnt = argc + 1;
2282 VALUE v1, v2, str, tmp, *tmp_array;
2288 for (i = 0; i < argc; i++) {
2291 str = do_writeconv(str, fptr, &converted);
2296 tmp = rb_str_tmp_frozen_acquire(str);
2300 iov[i+1].iov_base = RSTRING_PTR(tmp);
2301 iov[i+1].iov_len = RSTRING_LEN(tmp);
2304 n = io_binwritev(iov, iovcnt, fptr);
2307 for (i = 0; i < argc; i++) {
2308 rb_str_tmp_frozen_release(argv[i], tmp_array[i]);
2317iovcnt_ok(
int iovcnt)
2320 return iovcnt < IOV_MAX;
2328io_writev(
int argc,
const VALUE *argv,
VALUE io)
2335 io = GetWriteIO(io);
2348 for (i = 0; i < argc; i += cnt) {
2351 n = io_fwritev(cnt, &argv[i], fptr);
2362 rb_sys_fail_on_write(fptr);
2364 total = rb_fix_plus(
LONG2FIX(n), total);
2395 return io_writev(argc, argv, io);
2398 VALUE str = argv[0];
2399 return io_write(io, str, 0);
2410rb_io_writev(
VALUE io,
int argc,
const VALUE *argv)
2415 char sep = RCLASS_SINGLETON_P(klass) ? (klass = io,
'.') :
'#';
2418 " which accepts just one argument",
2423 do rb_io_write(io, *argv++);
while (--argc);
2454 rb_io_write(io, str);
2460nogvl_fsync(
void *ptr)
2465 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->
fd)) != FILE_TYPE_DISK)
2468 return (
VALUE)fsync(fptr->
fd);
2473rb_io_flush_raw(
VALUE io,
int sync)
2481 io = GetWriteIO(io);
2485 if (io_fflush(fptr) < 0)
2486 rb_sys_fail_on_write(fptr);
2489 io_unread(fptr,
true);
2510 return rb_io_flush_raw(io, 1);
2536 pos = io_tell(fptr);
2537 if (pos < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
2543rb_io_seek(
VALUE io,
VALUE offset,
int whence)
2550 pos = io_seek(fptr, pos, whence);
2551 if (pos < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
2552 if (fptr->
readconv) clear_readconv(fptr);
2558interpret_seek_whence(
VALUE vwhence)
2560 if (vwhence == sym_SET)
2562 if (vwhence == sym_CUR)
2564 if (vwhence == sym_END)
2567 if (vwhence == sym_DATA)
2571 if (vwhence == sym_HOLE)
2627 VALUE offset, ptrname;
2628 int whence = SEEK_SET;
2630 if (
rb_scan_args(argc, argv,
"11", &offset, &ptrname) == 2) {
2631 whence = interpret_seek_whence(ptrname);
2634 return rb_io_seek(io, offset, whence);
2662 pos = io_seek(fptr, pos, SEEK_SET);
2663 if (pos < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
2664 if (fptr->
readconv) clear_readconv(fptr);
2694rb_io_rewind(
VALUE io)
2699 if (io_seek(fptr, 0L, 0) < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
2700 if (io == ARGF.current_file) {
2701 ARGF.lineno -= fptr->
lineno;
2705 clear_readconv(fptr);
2712fptr_wait_readable(
rb_io_t *fptr)
2730 fptr->
rbuf.
capa = IO_RBUF_CAPA_FOR(fptr);
2738 if (fptr_wait_readable(fptr))
2742 VALUE path = rb_sprintf(
"fd:%d ", fptr->
fd);
2747 rb_syserr_fail_path(e, path);
2801 if (READ_CHAR_PENDING(fptr))
return Qfalse;
2802 if (READ_DATA_PENDING(fptr))
return Qfalse;
2804#if RUBY_CRLF_ENVIRONMENT
2805 if (!NEED_READCONV(fptr) && NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
2806 return RBOOL(eof(fptr->
fd));
2809 return RBOOL(io_fillbuf(fptr) < 0);
2833 io = GetWriteIO(io);
2870 io = GetWriteIO(io);
2876 fptr->
mode &= ~FMODE_SYNC;
2900rb_io_fsync(
VALUE io)
2904 io = GetWriteIO(io);
2907 if (io_fflush(fptr) < 0)
2908 rb_sys_fail_on_write(fptr);
2910 if ((
int)rb_io_blocking_region(fptr, nogvl_fsync, fptr))
2911 rb_sys_fail_path(fptr->
pathv);
2916# define rb_io_fsync rb_f_notimplement
2917# define rb_io_sync rb_f_notimplement
2926#ifdef HAVE_FDATASYNC
2928nogvl_fdatasync(
void *ptr)
2932 return (
VALUE)fdatasync(fptr->
fd);
2947rb_io_fdatasync(
VALUE io)
2951 io = GetWriteIO(io);
2954 if (io_fflush(fptr) < 0)
2955 rb_sys_fail_on_write(fptr);
2957 if ((
int)rb_io_blocking_region(fptr, nogvl_fdatasync, fptr) == 0)
2961 return rb_io_fsync(io);
2964#define rb_io_fdatasync rb_io_fsync
2982rb_io_fileno(
VALUE io)
3002 if (!UNDEF_P(fileno)) {
3095rb_io_inspect(
VALUE obj)
3099 static const char closed[] =
" (closed)";
3101 fptr =
RFILE(obj)->fptr;
3108 rb_str_cat(result, closed+1, strlen(closed)-1);
3111 rb_str_catf(result,
"fd %d", fptr->
fd);
3132rb_io_to_io(
VALUE io)
3139read_buffered_data(
char *ptr,
long len,
rb_io_t *fptr)
3143 n = READ_DATA_PENDING_COUNT(fptr);
3144 if (n <= 0)
return 0;
3145 if (n >
len) n = (int)
len;
3153io_bufread(
char *ptr,
long len,
rb_io_t *fptr)
3159 if (READ_DATA_PENDING(fptr) == 0) {
3163 c = rb_io_read_memory(fptr, ptr+offset, n);
3166 if (fptr_wait_readable(fptr))
3171 if ((n -= c) <= 0)
break;
3177 c = read_buffered_data(ptr+offset, n, fptr);
3180 if ((n -= c) <= 0)
break;
3183 if (io_fillbuf(fptr) < 0) {
3190static int io_setstrbuf(
VALUE *str,
long len);
3199bufread_call(
VALUE arg)
3202 p->len = io_bufread(p->str_ptr, p->len, p->fptr);
3207io_fread(
VALUE str,
long offset,
long size,
rb_io_t *fptr)
3212 io_setstrbuf(&str, offset + size);
3213 arg.str_ptr = RSTRING_PTR(str) + offset;
3216 rb_str_locktmp_ensure(str, bufread_call, (
VALUE)&arg);
3218 if (
len < 0) rb_sys_fail_path(fptr->
pathv);
3226 rb_off_t siz = READ_DATA_PENDING_COUNT(fptr);
3229 if (fstat(fptr->
fd, &st) == 0 && S_ISREG(st.st_mode)
3230#
if defined(__HAIKU__)
3235 if (io_fflush(fptr) < 0)
3236 rb_sys_fail_on_write(fptr);
3237 pos = lseek(fptr->
fd, 0, SEEK_CUR);
3238 if (st.st_size >= pos && pos >= 0) {
3239 siz += st.st_size - pos;
3240 if (siz > LONG_MAX) {
3241 rb_raise(
rb_eIOError,
"file too big for single read");
3254 rb_enc_associate(str, io_read_encoding(fptr));
3259make_readconv(
rb_io_t *fptr,
int size)
3264 const char *sname, *dname;
3265 ecflags = fptr->
encs.
ecflags & ~ECONV_NEWLINE_DECORATOR_WRITE_MASK;
3268 sname = rb_enc_name(fptr->
encs.
enc2);
3269 dname = rb_enc_name(io_read_encoding(fptr));
3279 if (size < IO_CBUF_CAPA_MIN) size = IO_CBUF_CAPA_MIN;
3285#define MORE_CHAR_SUSPENDED Qtrue
3286#define MORE_CHAR_FINISHED Qnil
3288fill_cbuf(
rb_io_t *fptr,
int ec_flags)
3290 const unsigned char *ss, *sp, *se;
3291 unsigned char *ds, *dp, *de;
3300 return MORE_CHAR_SUSPENDED;
3311 ss = sp = (
const unsigned char *)fptr->
rbuf.
ptr + fptr->
rbuf.
off;
3316 fptr->
rbuf.
off += (int)(sp - ss);
3317 fptr->
rbuf.
len -= (int)(sp - ss);
3318 fptr->
cbuf.
len += (int)(dp - ds);
3323 fptr->
rbuf.
off -= putbackable;
3324 fptr->
rbuf.
len += putbackable;
3331 if (cbuf_len0 != fptr->
cbuf.
len)
3332 return MORE_CHAR_SUSPENDED;
3335 return MORE_CHAR_FINISHED;
3341 if (io_fillbuf(fptr) < 0) {
3343 return MORE_CHAR_FINISHED;
3348 fptr->
cbuf.
len += (int)(dp - ds);
3355 if (cbuf_len0 != fptr->
cbuf.
len)
3356 return MORE_CHAR_SUSPENDED;
3358 return MORE_CHAR_FINISHED;
3366 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED)
3383 rb_enc_associate(str, fptr->
encs.
enc);
3408 long clen = RSTRING_LEN(s);
3420#define MAX_REALLOC_GAP 4096
3422io_shrink_read_string(
VALUE str,
long n)
3425 rb_str_resize(str, n);
3430io_set_read_length(
VALUE str,
long n,
int shrinkable)
3432 if (RSTRING_LEN(str) != n) {
3435 if (shrinkable) io_shrink_read_string(str, n);
3449 if (NEED_READCONV(fptr)) {
3450 int first = !
NIL_P(str);
3451 SET_BINARY_MODE(fptr);
3452 shrinkable = io_setstrbuf(&str,0);
3453 make_readconv(fptr, 0);
3458 io_shift_cbuf(fptr, fptr->
cbuf.
len, &str);
3460 v = fill_cbuf(fptr, 0);
3461 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED) {
3464 io_shift_cbuf(fptr, fptr->
cbuf.
len, &str);
3468 if (v == MORE_CHAR_FINISHED) {
3469 clear_readconv(fptr);
3471 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3472 return io_enc_str(str, fptr);
3477 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3481 enc = io_read_encoding(fptr);
3494 shrinkable = io_setstrbuf(&str, siz);
3497 n = io_fread(str, bytes, siz - bytes, fptr);
3498 if (n == 0 && bytes == 0) {
3506 if (bytes < siz)
break;
3510 if (
capa < (
size_t)RSTRING_LEN(str) + BUFSIZ) {
3511 if (
capa < BUFSIZ) {
3514 else if (
capa > IO_MAX_BUFFER_GROWTH) {
3515 capa = IO_MAX_BUFFER_GROWTH;
3520 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3521 str = io_enc_str(str, fptr);
3529 if (rb_fd_set_nonblock(fptr->
fd) != 0) {
3530 rb_sys_fail_path(fptr->
pathv);
3535io_read_memory_call(
VALUE arg)
3540 if (scheduler !=
Qnil) {
3543 if (!UNDEF_P(result)) {
3549 if (iis->nonblock) {
3550 return rb_io_blocking_region(iis->fptr, internal_read_func, iis);
3553 return rb_io_blocking_region_wait(iis->fptr, internal_read_func, iis,
RUBY_IO_READABLE);
3560 return (
long)rb_str_locktmp_ensure(str, io_read_memory_call, (
VALUE)iis);
3563#define no_exception_p(opts) !rb_opts_exception_p((opts), TRUE)
3566io_getpartial(
int argc,
VALUE *argv,
VALUE io,
int no_exception,
int nonblock)
3577 rb_raise(rb_eArgError,
"negative length %ld given",
len);
3580 shrinkable = io_setstrbuf(&str,
len);
3586 io_set_read_length(str, 0, shrinkable);
3592 n = read_buffered_data(RSTRING_PTR(str),
len, fptr);
3598 io_setstrbuf(&str,
len);
3601 iis.nonblock = nonblock;
3603 iis.buf = RSTRING_PTR(str);
3606 n = io_read_memory_locktmp(str, &iis);
3609 if (!nonblock && fptr_wait_readable(fptr))
3611 if (nonblock && (io_again_p(e))) {
3613 return sym_wait_readable;
3616 e,
"read would block");
3618 rb_syserr_fail_path(e, fptr->
pathv);
3621 io_set_read_length(str, n, shrinkable);
3722io_readpartial(
int argc,
VALUE *argv,
VALUE io)
3726 ret = io_getpartial(argc, argv, io,
Qnil, 0);
3733io_nonblock_eof(
int no_exception)
3735 if (!no_exception) {
3751 rb_raise(rb_eArgError,
"negative length %ld given",
len);
3754 shrinkable = io_setstrbuf(&str,
len);
3755 rb_bool_expected(ex,
"exception", TRUE);
3761 io_set_read_length(str, 0, shrinkable);
3765 n = read_buffered_data(RSTRING_PTR(str),
len, fptr);
3767 rb_fd_set_nonblock(fptr->
fd);
3768 shrinkable |= io_setstrbuf(&str,
len);
3772 iis.buf = RSTRING_PTR(str);
3775 n = io_read_memory_locktmp(str, &iis);
3778 if (io_again_p(e)) {
3779 if (!ex)
return sym_wait_readable;
3781 e,
"read would block");
3783 rb_syserr_fail_path(e, fptr->
pathv);
3786 io_set_read_length(str, n, shrinkable);
3789 if (!ex)
return Qnil;
3805 rb_bool_expected(ex,
"exception", TRUE);
3807 io = GetWriteIO(io);
3811 if (io_fflush(fptr) < 0)
3812 rb_sys_fail_on_write(fptr);
3814 rb_fd_set_nonblock(fptr->
fd);
3815 n = write(fptr->
fd, RSTRING_PTR(str), RSTRING_LEN(str));
3820 if (io_again_p(e)) {
3822 return sym_wait_writable;
3828 rb_syserr_fail_path(e, fptr->
pathv);
3912#if RUBY_CRLF_ENVIRONMENT
3918 if (
NIL_P(length)) {
3921 return read_all(fptr, remain_size(fptr), str);
3925 rb_raise(rb_eArgError,
"negative length %ld given",
len);
3928 shrinkable = io_setstrbuf(&str,
len);
3933 io_set_read_length(str, 0, shrinkable);
3938#if RUBY_CRLF_ENVIRONMENT
3939 previous_mode = set_binary_mode_with_seek_cur(fptr);
3941 n = io_fread(str, 0,
len, fptr);
3942 io_set_read_length(str, n, shrinkable);
3943#if RUBY_CRLF_ENVIRONMENT
3944 if (previous_mode == O_TEXT) {
3945 setmode(fptr->
fd, O_TEXT);
3948 if (n == 0)
return Qnil;
3954rscheck(
const char *rsptr,
long rslen,
VALUE rs)
3957 if (RSTRING_PTR(rs) != rsptr && RSTRING_LEN(rs) != rslen)
3962search_delim(
const char *p,
long len,
int delim,
rb_encoding *enc)
3964 if (rb_enc_mbminlen(enc) == 1) {
3965 p = memchr(p, delim,
len);
3966 if (p)
return p + 1;
3969 const char *end = p +
len;
3971 int r = rb_enc_precise_mbclen(p, end, enc);
3973 p += rb_enc_mbminlen(enc);
3977 if (rb_enc_mbc_to_codepoint(p, end, enc) == (
unsigned int)delim) {
3992 if (NEED_READCONV(fptr)) {
3993 SET_BINARY_MODE(fptr);
3994 make_readconv(fptr, 0);
3997 int searchlen = READ_CHAR_PENDING_COUNT(fptr);
3999 p = READ_CHAR_PENDING_PTR(fptr);
4000 if (0 < limit && limit < searchlen)
4001 searchlen = (int)limit;
4002 e = search_delim(p, searchlen, delim, enc);
4004 int len = (int)(e-p);
4026 return (
unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
4029 }
while (more_char(fptr) != MORE_CHAR_FINISHED);
4030 clear_readconv(fptr);
4035 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4037 long pending = READ_DATA_PENDING_COUNT(fptr);
4039 const char *p = READ_DATA_PENDING_PTR(fptr);
4043 if (limit > 0 && pending > limit) pending = limit;
4044 e = search_delim(p, pending, delim, enc);
4045 if (e) pending = e - p;
4047 last = RSTRING_LEN(str);
4048 rb_str_resize(str, last + pending);
4055 read_buffered_data(RSTRING_PTR(str) + last, pending, fptr);
4058 if (e)
return delim;
4060 return (
unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
4063 }
while (io_fillbuf(fptr) >= 0);
4069swallow(
rb_io_t *fptr,
int term)
4071 if (NEED_READCONV(fptr)) {
4073 int needconv = rb_enc_mbminlen(enc) != 1;
4074 SET_BINARY_MODE(fptr);
4075 make_readconv(fptr, 0);
4078 while ((cnt = READ_CHAR_PENDING_COUNT(fptr)) > 0) {
4079 const char *p = READ_CHAR_PENDING_PTR(fptr);
4082 if (*p != term)
return TRUE;
4084 while (--i && *++p == term);
4087 const char *e = p + cnt;
4088 if (rb_enc_ascget(p, e, &i, enc) != term)
return TRUE;
4089 while ((p += i) < e && rb_enc_ascget(p, e, &i, enc) == term);
4092 io_shift_cbuf(fptr, (
int)cnt - i, NULL);
4094 }
while (more_char(fptr) != MORE_CHAR_FINISHED);
4098 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4101 while ((cnt = READ_DATA_PENDING_COUNT(fptr)) > 0) {
4103 const char *p = READ_DATA_PENDING_PTR(fptr);
4105 if (cnt >
sizeof buf) cnt =
sizeof buf;
4106 if (*p != term)
return TRUE;
4108 while (--i && *++p == term);
4109 if (!read_buffered_data(buf, cnt - i, fptr))
4110 rb_sys_fail_path(fptr->
pathv);
4113 }
while (io_fillbuf(fptr) == 0);
4126 int pending = READ_DATA_PENDING_COUNT(fptr);
4129 const char *p = READ_DATA_PENDING_PTR(fptr);
4133 e = memchr(p,
'\n', pending);
4135 pending = (int)(e - p + 1);
4137 chomplen = (pending > 1 && *(e-1) ==
'\r') + 1;
4146 rb_str_resize(str,
len + pending - chomplen);
4147 read_buffered_data(RSTRING_PTR(str)+
len, pending - chomplen, fptr);
4150 if (pending == 1 && chomplen == 1 &&
len > 0) {
4151 if (RSTRING_PTR(str)[
len-1] ==
'\r') {
4152 rb_str_resize(str, --
len);
4157 len += pending - chomplen;
4163 }
while (io_fillbuf(fptr) >= 0);
4166 str = io_enc_str(str, fptr);
4177 unsigned int chomp: 1;
4191 chomp = (!UNDEF_P(vchomp)) &&
RTEST(vchomp);
4193 args->chomp = chomp;
4211 else if (2 <= argc) {
4212 rs = argv[0], lim = argv[1];
4221check_getline_args(
VALUE *rsp,
long *limit,
VALUE io)
4230 enc_rs = rb_enc_get(rs);
4231 enc_io = io_read_encoding(fptr);
4232 if (enc_io != enc_rs &&
4233 (!is_ascii_string(rs) ||
4234 (RSTRING_LEN(rs) > 0 && !rb_enc_asciicompat(enc_io)))) {
4235 if (rs == rb_default_rs) {
4236 rs = rb_enc_str_new(0, 0, enc_io);
4241 rb_raise(rb_eArgError,
"encoding mismatch: %s IO with %s RS",
4242 rb_enc_name(enc_io),
4243 rb_enc_name(enc_rs));
4253 argc =
rb_scan_args(argc, argv,
"02:", NULL, NULL, &opts);
4254 extract_getline_args(argc, argv, args);
4255 extract_getline_opts(opts, args);
4256 check_getline_args(&args->rs, &args->limit, io);
4260rb_io_getline_0(
VALUE rs,
long limit,
int chomp,
rb_io_t *fptr)
4267 if (
NIL_P(rs) && limit < 0) {
4268 str = read_all(fptr, 0,
Qnil);
4269 if (RSTRING_LEN(str) == 0)
return Qnil;
4271 else if (limit == 0) {
4272 return rb_enc_str_new(0, 0, io_read_encoding(fptr));
4274 else if (rs == rb_default_rs && limit < 0 && !NEED_READCONV(fptr) &&
4275 rb_enc_asciicompat(enc = io_read_encoding(fptr))) {
4276 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4277 return rb_io_getline_fast(fptr, enc, chomp);
4280 int c, newline = -1;
4281 const char *rsptr = 0;
4284 int extra_limit = 16;
4285 int chomp_cr = chomp;
4287 SET_BINARY_MODE(fptr);
4288 enc = io_read_encoding(fptr);
4291 rslen = RSTRING_LEN(rs);
4296 swallow(fptr,
'\n');
4298 if (!rb_enc_asciicompat(enc)) {
4302 rsptr = RSTRING_PTR(rs);
4303 rslen = RSTRING_LEN(rs);
4307 else if (rb_enc_mbminlen(enc) == 1) {
4308 rsptr = RSTRING_PTR(rs);
4309 newline = (
unsigned char)rsptr[rslen - 1];
4313 rsptr = RSTRING_PTR(rs);
4314 const char *e = rsptr + rslen;
4315 const char *last = rb_enc_prev_char(rsptr, e, e, enc);
4317 newline = rb_enc_codepoint_len(last, e, &n, enc);
4318 if (last + n != e) rb_raise(rb_eArgError,
"broken separator");
4320 chomp_cr = chomp && newline ==
'\n' && rslen == rb_enc_mbminlen(enc);
4324 while ((c = appendline(fptr, newline, &str, &limit, enc)) != EOF) {
4325 const char *s, *p, *pp, *e;
4328 if (RSTRING_LEN(str) < rslen)
continue;
4329 s = RSTRING_PTR(str);
4332 if (!at_char_boundary(s, p, e, enc))
continue;
4333 if (!rspara) rscheck(rsptr, rslen, rs);
4334 if (memcmp(p, rsptr, rslen) == 0) {
4336 if (chomp_cr && p > s && *(p-1) ==
'\r') --p;
4343 s = RSTRING_PTR(str);
4345 pp = rb_enc_prev_char(s, p, p, enc);
4346 if (extra_limit && pp &&
4360 if (rspara && c != EOF)
4361 swallow(fptr,
'\n');
4363 str = io_enc_str(str, fptr);
4366 if (!
NIL_P(str) && !nolimit) {
4374rb_io_getline_1(
VALUE rs,
long limit,
int chomp,
VALUE io)
4377 int old_lineno, new_lineno;
4381 old_lineno = fptr->
lineno;
4382 str = rb_io_getline_0(rs, limit, chomp, fptr);
4383 if (!
NIL_P(str) && (new_lineno = fptr->
lineno) != old_lineno) {
4384 if (io == ARGF.current_file) {
4385 ARGF.lineno += new_lineno - old_lineno;
4386 ARGF.last_lineno = ARGF.lineno;
4389 ARGF.last_lineno = new_lineno;
4397rb_io_getline(
int argc,
VALUE *argv,
VALUE io)
4401 prepare_getline_args(argc, argv, &args, io);
4402 return rb_io_getline_1(args.rs, args.limit, args.chomp, io);
4412rb_io_gets_limit_internal(
VALUE io,
long limit)
4416 return rb_io_getline_0(rb_default_rs, limit, FALSE, fptr);
4420rb_io_gets_internal(
VALUE io)
4422 return rb_io_gets_limit_internal(io, -1);
4502 str = rb_io_getline(argc, argv, io);
4518rb_io_lineno(
VALUE io)
4573 check_getline_args(&sep, &limit, io);
4575 VALUE line = rb_io_getline_1(sep, limit,
RTEST(chomp), io);
4576 rb_lastline_set_up(line, 1);
4651rb_io_readlines(
int argc,
VALUE *argv,
VALUE io)
4655 prepare_getline_args(argc, argv, &args, io);
4656 return io_readlines(&args, io);
4664 if (arg->limit == 0)
4665 rb_raise(rb_eArgError,
"invalid limit: 0 for readlines");
4667 while (!
NIL_P(line = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, io))) {
4780rb_io_each_line(
int argc,
VALUE *argv,
VALUE io)
4786 prepare_getline_args(argc, argv, &args, io);
4787 if (args.limit == 0)
4788 rb_raise(rb_eArgError,
"invalid limit: 0 for each_line");
4789 while (!
NIL_P(str = rb_io_getline_1(args.rs, args.limit, args.chomp, io))) {
4817rb_io_each_byte(
VALUE io)
4833 }
while (io_fillbuf(fptr) >= 0);
4843 if (NEED_READCONV(fptr)) {
4847 SET_BINARY_MODE(fptr);
4848 make_readconv(fptr, 0);
4862 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4864 clear_readconv(fptr);
4868 str = rb_enc_str_new(fptr->
cbuf.
ptr+fptr->
cbuf.
off, 1, read_enc);
4871 if (fptr->
cbuf.
len == 0) clear_readconv(fptr);
4880 io_shift_cbuf(fptr, r, &str);
4887 ISASCII(RSTRING_PTR(str)[0])) {
4891 str = io_enc_str(str, fptr);
4896 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4897 if (io_fillbuf(fptr) < 0) {
4919 if (io_fillbuf(fptr) != -1) {
4923 r = rb_enc_precise_mbclen(RSTRING_PTR(str), RSTRING_PTR(str)+RSTRING_LEN(str), enc);
4939 str = io_enc_str(str, fptr);
4966rb_io_each_char(
VALUE io)
4976 enc = io_input_encoding(fptr);
4978 while (!
NIL_P(c = io_getc(fptr, enc))) {
5005rb_io_each_codepoint(
VALUE io)
5017 enc = io_read_encoding(fptr);
5018 if (NEED_READCONV(fptr)) {
5019 SET_BINARY_MODE(fptr);
5022 make_readconv(fptr, 0);
5034 if (more_char(fptr) == MORE_CHAR_FINISHED) {
5035 clear_readconv(fptr);
5055 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
5056 while (io_fillbuf(fptr) >= 0) {
5071 char cbuf[8], *p = cbuf;
5073 if (more > numberof(cbuf))
goto invalid;
5075 if (more > numberof(cbuf))
goto invalid;
5076 while ((n = (
int)read_buffered_data(p, more, fptr)) > 0 &&
5077 (p += n, (more -= n) > 0)) {
5078 if (io_fillbuf(fptr) < 0)
goto invalid;
5079 if ((n = fptr->
rbuf.
len) > more) n = more;
5081 r = rb_enc_precise_mbclen(cbuf, p, enc);
5094 rb_raise(rb_eArgError,
"invalid byte sequence in %s", rb_enc_name(enc));
5127 enc = io_input_encoding(fptr);
5129 return io_getc(fptr, enc);
5153rb_io_readchar(
VALUE io)
5155 VALUE c = rb_io_getc(io);
5191 VALUE r_stdout = rb_ractor_stdout();
5196 rb_io_flush(r_stdout);
5199 if (io_fillbuf(fptr) < 0) {
5229rb_io_readbyte(
VALUE io)
5290 unsigned char c =
NUM2INT(v) & 0xFF;
5296 io_ungetbyte(b, fptr);
5352 else if (RB_BIGNUM_TYPE_P(c)) {
5358 if (NEED_READCONV(fptr)) {
5359 SET_BINARY_MODE(fptr);
5360 len = RSTRING_LEN(c);
5361#if SIZEOF_LONG > SIZEOF_INT
5365 make_readconv(fptr, (
int)
len);
5379 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
5380 io_ungetbyte(c, fptr);
5400rb_io_isatty(
VALUE io)
5405 return RBOOL(isatty(fptr->
fd) != 0);
5408#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5424rb_io_close_on_exec_p(
VALUE io)
5430 write_io = GetWriteIO(io);
5431 if (io != write_io) {
5433 if (fptr && 0 <= (fd = fptr->
fd)) {
5434 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->
pathv);
5435 if (!(ret & FD_CLOEXEC))
return Qfalse;
5440 if (fptr && 0 <= (fd = fptr->
fd)) {
5441 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->
pathv);
5442 if (!(ret & FD_CLOEXEC))
return Qfalse;
5447#define rb_io_close_on_exec_p rb_f_notimplement
5450#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5474 int flag =
RTEST(arg) ? FD_CLOEXEC : 0;
5479 write_io = GetWriteIO(io);
5480 if (io != write_io) {
5482 if (fptr && 0 <= (fd = fptr->
fd)) {
5483 if ((ret = fcntl(fptr->
fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->
pathv);
5484 if ((ret & FD_CLOEXEC) != flag) {
5485 ret = (ret & ~FD_CLOEXEC) | flag;
5486 ret = fcntl(fd, F_SETFD, ret);
5487 if (ret != 0) rb_sys_fail_path(fptr->
pathv);
5494 if (fptr && 0 <= (fd = fptr->
fd)) {
5495 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->
pathv);
5496 if ((ret & FD_CLOEXEC) != flag) {
5497 ret = (ret & ~FD_CLOEXEC) | flag;
5498 ret = fcntl(fd, F_SETFD, ret);
5499 if (ret != 0) rb_sys_fail_path(fptr->
pathv);
5505#define rb_io_set_close_on_exec rb_f_notimplement
5508#define RUBY_IO_EXTERNAL_P(f) ((f)->mode & FMODE_EXTERNAL)
5509#define PREP_STDIO_NAME(f) (RSTRING_PTR((f)->pathv))
5512finish_writeconv(
rb_io_t *fptr,
int noalloc)
5514 unsigned char *ds, *dp, *de;
5518 unsigned char buf[1024];
5523 de = buf +
sizeof(buf);
5526 size_t remaining = dp-ds;
5527 long result = rb_io_write_memory(fptr, ds, remaining);
5531 if ((
size_t)result == remaining)
break;
5554 if (io_fflush(fptr) < 0) {
5562 fptr->
wbuf.
len += (int)(dp - ds);
5578finish_writeconv_sync(
VALUE arg)
5581 return finish_writeconv(p->fptr, p->noalloc);
5585nogvl_close(
void *ptr)
5589 return (
void*)(intptr_t)close(*fd);
5593maygvl_close(
int fd,
int keepgvl)
5602 return IO_WITHOUT_GVL_INT(nogvl_close, &fd);
5606nogvl_fclose(
void *ptr)
5610 return (
void*)(intptr_t)fclose(file);
5614maygvl_fclose(
FILE *file,
int keepgvl)
5617 return fclose(file);
5619 return IO_WITHOUT_GVL_INT(nogvl_fclose, file);
5625fptr_finalize_flush(
rb_io_t *fptr,
int noraise,
int keepgvl)
5630 int mode = fptr->
mode;
5636 arg.noalloc = noraise;
5640 error = finish_writeconv(fptr, noraise);
5653 io_flush_buffer_sync(fptr);
5656 if (io_fflush(fptr) < 0 &&
NIL_P(error)) {
5664 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2) {
5674 rb_thread_io_close_wait(fptr);
5676 if (!done && stdio_file) {
5678 if ((maygvl_fclose(stdio_file, noraise) < 0) &&
NIL_P(error)) {
5688 if (!done && fd >= 0 && scheduler !=
Qnil) {
5691 if (!UNDEF_P(result)) {
5692 done =
RTEST(result);
5696 if (!done && fd >= 0) {
5702 if ((maygvl_close(fd, keepgvl) < 0) &&
NIL_P(error)) {
5711 if (!
NIL_P(error) && !noraise) {
5720fptr_finalize(
rb_io_t *fptr,
int noraise)
5722 fptr_finalize_flush(fptr, noraise, FALSE);
5723 free_io_buffer(&fptr->
rbuf);
5724 free_io_buffer(&fptr->
wbuf);
5725 clear_codeconv(fptr);
5729rb_io_fptr_cleanup(
rb_io_t *fptr,
int noraise)
5735 fptr_finalize(fptr, noraise);
5743 ruby_xfree_sized(buf->
ptr, (
size_t)buf->
capa);
5756 free_io_buffer(&fptr->
cbuf);
5772 clear_readconv(fptr);
5773 clear_writeconv(fptr);
5777rb_io_fptr_cleanup_all(
rb_io_t *fptr)
5781 rb_io_fptr_cleanup(fptr, TRUE);
5783 free_io_buffer(&fptr->
rbuf);
5784 free_io_buffer(&fptr->
wbuf);
5785 clear_codeconv(fptr);
5792 rb_io_fptr_cleanup_all(io);
5799rb_io_fptr_finalize_closed(
struct rb_io *io)
5801 if (!io)
return true;
5802 if (io->
fd >= 0)
return false;
5808rb_io_memsize(
const rb_io_t *io)
5810 size_t size =
sizeof(
rb_io_t);
5820 rb_serial_t fork_generation = GET_VM()->fork_gen;
5821 if (io->fork_generation == fork_generation) {
5832# define KEEPGVL TRUE
5834# define KEEPGVL FALSE
5838io_close_fptr(
VALUE io)
5844 write_io = GetWriteIO(io);
5845 if (io != write_io) {
5846 write_fptr =
RFILE(write_io)->fptr;
5847 if (write_fptr && 0 <= write_fptr->
fd) {
5848 rb_io_fptr_cleanup(write_fptr, TRUE);
5852 fptr =
RFILE(io)->fptr;
5853 if (!fptr)
return 0;
5854 if (fptr->
fd < 0)
return 0;
5857 if (rb_thread_io_close_interrupt(fptr)) {
5859 fptr_finalize_flush(fptr, FALSE, KEEPGVL);
5862 rb_io_fptr_cleanup(fptr, FALSE);
5867fptr_waitpid(
rb_io_t *fptr,
int nohang)
5871 rb_last_status_clear();
5880 rb_io_t *fptr = io_close_fptr(io);
5881 if (fptr) fptr_waitpid(fptr, 0);
5921rb_io_close_m(
VALUE io)
5923 rb_io_t *fptr = rb_io_get_fptr(io);
5932io_call_close(
VALUE io)
5941 enum {mesg_len =
sizeof(closed_stream)-1};
5942 VALUE mesg = rb_attr_get(exc, idMesg);
5944 RSTRING_LEN(mesg) != mesg_len ||
5945 memcmp(RSTRING_PTR(mesg), closed_stream, mesg_len)) {
5955 if (!UNDEF_P(closed) &&
RTEST(closed))
return io;
5956 rb_rescue2(io_call_close, io, ignore_closed_stream, io,
5992 write_io = GetWriteIO(io);
5993 if (io != write_io) {
5994 write_fptr =
RFILE(write_io)->fptr;
5995 if (write_fptr && 0 <= write_fptr->
fd) {
6000 fptr = rb_io_get_fptr(io);
6001 return RBOOL(0 > fptr->
fd);
6037rb_io_close_read(
VALUE io)
6043 if (fptr->
fd < 0)
return Qnil;
6044 if (is_socket(fptr->
fd, fptr->
pathv)) {
6048 if (shutdown(fptr->
fd, SHUT_RD) < 0)
6049 rb_sys_fail_path(fptr->
pathv);
6050 fptr->
mode &= ~FMODE_READABLE;
6056 write_io = GetWriteIO(io);
6057 if (io != write_io) {
6062 RFILE(io)->fptr = wfptr;
6065 RFILE(write_io)->fptr = fptr;
6066 rb_io_fptr_cleanup(fptr, FALSE);
6072 rb_raise(
rb_eIOError,
"closing non-duplex IO for reading");
6110rb_io_close_write(
VALUE io)
6115 write_io = GetWriteIO(io);
6117 if (fptr->
fd < 0)
return Qnil;
6118 if (is_socket(fptr->
fd, fptr->
pathv)) {
6129 if (io_fflush(fptr) < 0)
6130 rb_sys_fail_on_write(fptr);
6132 if (shutdown(fptr->
fd, SHUT_WR) < 0)
6133 rb_sys_fail_path(fptr->
pathv);
6134 fptr->
mode &= ~FMODE_WRITABLE;
6141 rb_raise(
rb_eIOError,
"closing non-duplex IO for writing");
6144 if (io != write_io) {
6164rb_io_sysseek(
int argc,
VALUE *argv,
VALUE io)
6166 VALUE offset, ptrname;
6167 int whence = SEEK_SET;
6171 if (
rb_scan_args(argc, argv,
"11", &offset, &ptrname) == 2) {
6172 whence = interpret_seek_whence(ptrname);
6177 (READ_DATA_BUFFERED(fptr) || READ_CHAR_PENDING(fptr))) {
6181 rb_warn(
"sysseek for buffered IO");
6184 pos = lseek(fptr->
fd, pos, whence);
6185 if (pos < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
6219 io = GetWriteIO(io);
6224 rb_warn(
"syswrite for buffered IO");
6227 tmp = rb_str_tmp_frozen_acquire(str);
6229 n = rb_io_write_memory(fptr, ptr,
len);
6230 if (n < 0) rb_sys_fail_path(fptr->
pathv);
6231 rb_str_tmp_frozen_release(str, tmp);
6248rb_io_sysread(
int argc,
VALUE *argv,
VALUE io)
6259 shrinkable = io_setstrbuf(&str, ilen);
6260 if (ilen == 0)
return str;
6265 if (READ_DATA_BUFFERED(fptr)) {
6271 io_setstrbuf(&str, ilen);
6276 iis.buf = RSTRING_PTR(str);
6279 n = io_read_memory_locktmp(str, &iis);
6282 rb_sys_fail_path(fptr->
pathv);
6285 io_set_read_length(str, n, shrinkable);
6287 if (n == 0 && ilen > 0) {
6303internal_pread_func(
void *_arg)
6307 return (
VALUE)pread(arg->fd, arg->buf, arg->count, arg->offset);
6311pread_internal_call(
VALUE _arg)
6316 if (scheduler !=
Qnil) {
6319 if (!UNDEF_P(result)) {
6324 return rb_io_blocking_region_wait(arg->io, internal_pread_func, arg,
RUBY_IO_READABLE);
6368 shrinkable = io_setstrbuf(&str, (
long)arg.count);
6369 if (arg.count == 0)
return str;
6370 arg.buf = RSTRING_PTR(str);
6383 rb_sys_fail_path(fptr->
pathv);
6385 io_set_read_length(str, n, shrinkable);
6386 if (n == 0 && arg.count > 0) {
6394internal_pwrite_func(
void *_arg)
6398 return (
VALUE)pwrite(arg->fd, arg->buf, arg->count, arg->offset);
6402pwrite_internal_call(
VALUE _arg)
6407 if (scheduler !=
Qnil) {
6410 if (!UNDEF_P(result)) {
6415 return rb_io_blocking_region_wait(arg->io, internal_pwrite_func, arg,
RUBY_IO_WRITABLE);
6456 io = GetWriteIO(io);
6463 tmp = rb_str_tmp_frozen_acquire(str);
6464 arg.buf = RSTRING_PTR(tmp);
6465 arg.count = (size_t)RSTRING_LEN(tmp);
6467 n = (ssize_t)pwrite_internal_call((
VALUE)&arg);
6468 if (n < 0) rb_sys_fail_path(fptr->
pathv);
6469 rb_str_tmp_frozen_release(str, tmp);
6485 fptr->
mode &= ~FMODE_TEXTMODE;
6489 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6492 setmode(fptr->
fd, O_BINARY);
6499io_ascii8bit_binmode(
rb_io_t *fptr)
6510 fptr->
mode &= ~FMODE_TEXTMODE;
6511 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6513 fptr->
encs.
enc = rb_ascii8bit_encoding();
6517 clear_codeconv(fptr);
6526 io_ascii8bit_binmode(fptr);
6543rb_io_binmode_m(
VALUE io)
6549 write_io = GetWriteIO(io);
6564rb_io_binmode_p(
VALUE io)
6572rb_io_fmode_modestr(
enum rb_io_mode fmode)
6576 return MODE_BTMODE(
"a+",
"ab+",
"at+");
6578 return MODE_BTMODE(
"a",
"ab",
"at");
6582 rb_raise(rb_eArgError,
"invalid access fmode 0x%x", fmode);
6584 return MODE_BTMODE(
"r",
"rb",
"rt");
6586 return MODE_BTXMODE(
"w",
"wb",
"wt",
"wx",
"wbx",
"wtx");
6589 return MODE_BTXMODE(
"w+",
"wb+",
"wt+",
"w+x",
"wb+x",
"wt+x");
6591 return MODE_BTMODE(
"r+",
"rb+",
"rt+");
6595static const char bom_prefix[] =
"bom|";
6596static const char utf_prefix[] =
"utf-";
6597enum {bom_prefix_len = (int)
sizeof(bom_prefix) - 1};
6598enum {utf_prefix_len = (int)
sizeof(utf_prefix) - 1};
6601io_encname_bom_p(
const char *name,
long len)
6603 return len > bom_prefix_len &&
STRNCASECMP(name, bom_prefix, bom_prefix_len) == 0;
6609 enum rb_io_mode fmode = 0;
6610 const char *m = modestr, *p = NULL;
6638 if (modestr[0] !=
'w')
6646 if (io_encname_bom_p(m, p ? (
long)(p - m) : (long)strlen(m)))
6659 rb_raise(rb_eArgError,
"invalid access mode %s", modestr);
6664rb_io_oflags_fmode(
int oflags)
6666 enum rb_io_mode fmode = 0;
6668 switch (oflags & O_ACCMODE) {
6680 if (oflags & O_APPEND) {
6683 if (oflags & O_TRUNC) {
6686 if (oflags & O_CREAT) {
6689 if (oflags & O_EXCL) {
6693 if (oflags & O_BINARY) {
6702rb_io_fmode_oflags(
enum rb_io_mode fmode)
6746rb_io_oflags_modestr(
int oflags)
6749# define MODE_BINARY(a,b) ((oflags & O_BINARY) ? (b) : (a))
6751# define MODE_BINARY(a,b) (a)
6754 if (oflags & O_EXCL) {
6755 rb_raise(rb_eArgError,
"exclusive access mode is not supported");
6757 accmode = oflags & (O_RDONLY|O_WRONLY|O_RDWR);
6758 if (oflags & O_APPEND) {
6759 if (accmode == O_WRONLY) {
6760 return MODE_BINARY(
"a",
"ab");
6762 if (accmode == O_RDWR) {
6763 return MODE_BINARY(
"a+",
"ab+");
6768 rb_raise(rb_eArgError,
"invalid access oflags 0x%x", oflags);
6770 return MODE_BINARY(
"r",
"rb");
6772 return MODE_BINARY(
"w",
"wb");
6774 if (oflags & O_TRUNC) {
6775 return MODE_BINARY(
"w+",
"wb+");
6777 return MODE_BINARY(
"r+",
"rb+");
6789 int default_ext = 0;
6792 ext = rb_default_external_encoding();
6795 if (rb_is_ascii8bit_enc(ext)) {
6799 else if (intern == NULL) {
6800 intern = rb_default_internal_encoding();
6805 *enc = (default_ext && intern != ext) ? NULL : ext;
6815unsupported_encoding(
const char *name,
rb_encoding *enc)
6817 rb_enc_warn(enc,
"Unsupported encoding %s ignored", name);
6821parse_mode_enc(
const char *estr,
rb_encoding *estr_enc,
6827 enum rb_io_mode fmode = fmode_p ? *fmode_p : 0;
6833 p = strrchr(estr,
':');
6834 len = p ? (p++ - estr) : (long)strlen(estr);
6836 estr += bom_prefix_len;
6837 len -= bom_prefix_len;
6838 if (!
STRNCASECMP(estr, utf_prefix, utf_prefix_len)) {
6842 rb_enc_warn(estr_enc,
"BOM with non-UTF encoding %s is nonsense", estr);
6843 fmode &= ~FMODE_SETENC_BY_BOM;
6851 memcpy(encname, estr,
len);
6852 encname[
len] =
'\0';
6855 idx = rb_enc_find_index(estr);
6857 if (fmode_p) *fmode_p = fmode;
6860 ext_enc = rb_enc_from_index(idx);
6863 unsupported_encoding(estr, estr_enc);
6869 if (*p ==
'-' && *(p+1) ==
'\0') {
6874 idx2 = rb_enc_find_index(p);
6876 unsupported_encoding(p, estr_enc);
6881 int_enc = rb_enc_from_index(idx2);
6885 rb_io_ext_int_to_encs(ext_enc, int_enc, enc_p, enc2_p, fmode);
6898 v = rb_hash_lookup2(opt, sym_encoding,
Qnil);
6899 if (v !=
Qnil) encoding = v;
6900 v = rb_hash_lookup2(opt, sym_extenc,
Qundef);
6901 if (v !=
Qnil) extenc = v;
6902 v = rb_hash_lookup2(opt, sym_intenc,
Qundef);
6903 if (!UNDEF_P(v)) intenc = v;
6905 if ((!UNDEF_P(extenc) || !UNDEF_P(intenc)) && !
NIL_P(encoding)) {
6907 int idx = rb_to_encoding_index(encoding);
6908 if (idx >= 0) encoding = rb_enc_from_encoding(rb_enc_from_index(idx));
6909 rb_warn(
"Ignoring encoding parameter '%"PRIsVALUE
"': %s_encoding is used",
6910 encoding, UNDEF_P(extenc) ?
"internal" :
"external");
6914 if (!UNDEF_P(extenc) && !
NIL_P(extenc)) {
6915 extencoding = rb_to_encoding(extenc);
6917 if (!UNDEF_P(intenc)) {
6918 if (
NIL_P(intenc)) {
6925 if (*p ==
'-' && *(p+1) ==
'\0') {
6930 intencoding = rb_to_encoding(intenc);
6934 intencoding = rb_to_encoding(intenc);
6936 if (extencoding == intencoding) {
6940 if (!
NIL_P(encoding)) {
6944 enc_p, enc2_p, fmode_p);
6947 rb_io_ext_int_to_encs(rb_to_encoding(encoding), NULL, enc_p, enc2_p, 0);
6950 else if (!UNDEF_P(extenc) || !UNDEF_P(intenc)) {
6952 rb_io_ext_int_to_encs(extencoding, intencoding, enc_p, enc2_p, 0);
6960 enum rb_io_mode fmode = *fmode_p;
6965 !rb_enc_asciicompat(enc ? enc : rb_default_external_encoding()))
6966 rb_raise(rb_eArgError,
"ASCII incompatible encoding needs binmode");
6969 rb_raise(rb_eArgError,
"newline decorator with binary mode");
6976#if !DEFAULT_TEXTMODE
6978 fmode &= ~FMODE_TEXTMODE;
6985extract_binmode(
VALUE opthash,
enum rb_io_mode *fmode)
6987 if (!
NIL_P(opthash)) {
6989 v = rb_hash_aref(opthash, sym_textmode);
6992 rb_raise(rb_eArgError,
"textmode specified twice");
6994 rb_raise(rb_eArgError,
"both textmode and binmode specified");
6998 v = rb_hash_aref(opthash, sym_binmode);
7001 rb_raise(rb_eArgError,
"binmode specified twice");
7003 rb_raise(rb_eArgError,
"both textmode and binmode specified");
7009 rb_raise(rb_eArgError,
"both textmode and binmode specified");
7015 int *oflags_p,
enum rb_io_mode *fmode_p,
struct rb_io_encoding *convconfig_p)
7019 enum rb_io_mode fmode;
7023 int has_enc = 0, has_vmode = 0;
7029 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
7039 fmode = rb_io_oflags_fmode(oflags);
7047 oflags = rb_io_fmode_oflags(fmode);
7051 parse_mode_enc(p+1, rb_enc_get(vmode), &enc, &enc2, &fmode);
7056 e = (fmode &
FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
7057 rb_io_ext_int_to_encs(e, NULL, &enc, &enc2, fmode);
7061 if (
NIL_P(opthash)) {
7065#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7067 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7068 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7070 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
7077 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
7080 else if (
NIL_P(vmode)) {
7081 fmode |= DEFAULT_TEXTMODE;
7088 v = rb_hash_aref(opthash, sym_mode);
7090 if (!
NIL_P(vmode)) {
7091 rb_raise(rb_eArgError,
"mode specified twice");
7098 v = rb_hash_aref(opthash, sym_flags);
7103 fmode = rb_io_oflags_fmode(oflags);
7105 extract_binmode(opthash, &fmode);
7111 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
7114 else if (
NIL_P(vmode)) {
7115 fmode |= DEFAULT_TEXTMODE;
7118 v = rb_hash_aref(opthash, sym_perm);
7121 if (!
NIL_P(*vperm_p)) {
7122 rb_raise(rb_eArgError,
"perm specified twice");
7133#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7135 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7136 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7141 rb_raise(rb_eArgError,
"encoding specified twice");
7144 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
7148 validate_enc_binmode(&fmode, ecflags, enc, enc2);
7154 convconfig_p->
enc = enc;
7155 convconfig_p->
enc2 = enc2;
7156 convconfig_p->
ecflags = ecflags;
7157 convconfig_p->
ecopts = ecopts;
7167sysopen_func(
void *ptr)
7170 const char *fname = RSTRING_PTR(data->fname);
7179 fd = IO_WITHOUT_GVL_INT(sysopen_func, data);
7180 }
while (fd < 0 &&
errno == EINTR);
7187rb_sysopen(
VALUE fname,
int oflags, mode_t perm)
7192 data.fname = rb_str_encode_ospath(fname);
7194 data.oflags = oflags;
7197 TRY_WITH_GC((fd = rb_sysopen_internal(&data)) >= 0) {
7198 rb_syserr_fail_path(first_errno, fname);
7204fdopen_internal(
int fd,
const char *modestr)
7211 file = fdopen(fd, modestr);
7227 TRY_WITH_GC((file = fdopen_internal(fd, modestr)) != 0) {
7233 if (setvbuf(file, NULL, _IOFBF, 0) != 0)
7234 rb_warn(
"setvbuf() can't be honoured (fd=%d)", fd);
7242 int t = isatty(fptr->
fd);
7252io_strip_bom(
VALUE io)
7254 VALUE b1, b2, b3, b4;
7265 return rb_utf8_encindex();
7275 return ENCINDEX_UTF_16BE;
7286 return ENCINDEX_UTF_32LE;
7291 return ENCINDEX_UTF_16LE;
7301 return ENCINDEX_UTF_32BE;
7315io_set_encoding_by_bom(
VALUE io)
7317 int idx = io_strip_bom(io);
7323 extenc = rb_enc_from_index(idx);
7324 io_encoding_set(fptr, rb_enc_from_encoding(extenc),
7325 rb_io_internal_encoding(io),
Qnil);
7334rb_file_open_generic(
VALUE io,
VALUE filename,
int oflags,
enum rb_io_mode fmode,
7342 rb_io_ext_int_to_encs(NULL, NULL, &cc.enc, &cc.enc2, fmode);
7347 validate_enc_binmode(&fmode, convconfig->
ecflags,
7348 convconfig->
enc, convconfig->
enc2);
7352 fptr->
encs = *convconfig;
7355 if (!(oflags & O_TMPFILE)) {
7356 fptr->
pathv = pathv;
7359 fptr->
pathv = pathv;
7361 fptr->
fd = rb_sysopen(pathv, oflags, perm);
7369rb_file_open_internal(
VALUE io,
VALUE filename,
const char *modestr)
7372 const char *p = strchr(modestr,
':');
7376 parse_mode_enc(p+1, rb_usascii_encoding(),
7377 &convconfig.
enc, &convconfig.
enc2, &fmode);
7383 e = (fmode &
FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
7384 rb_io_ext_int_to_encs(e, NULL, &convconfig.
enc, &convconfig.
enc2, fmode);
7390#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7392 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7393 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7395 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.
enc2, convconfig.
ecflags);
7398 return rb_file_open_generic(io, filename,
7399 rb_io_fmode_oflags(fmode),
7409 return rb_file_open_internal(io_alloc(
rb_cFile), fname, modestr);
7418#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7441 while ((tmp = *prev) != 0) {
7442 if (tmp->fptr == fptr) {
7451#if defined (_WIN32) || defined(__CYGWIN__)
7467pipe_finalize(
rb_io_t *fptr,
int noraise)
7469#if !defined(HAVE_WORKING_FORK) && !defined(_WIN32)
7478 fptr_finalize(fptr, noraise);
7480 pipe_del_fptr(fptr);
7487#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7488 void (*
const old_finalize)(
struct rb_io*,int) = fptr->
finalize;
7490 if (old_finalize == orig->finalize)
return;
7495#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7496 if (old_finalize != pipe_finalize) {
7498 for (list =
pipe_list; list; list = list->next) {
7499 if (list->fptr == fptr)
break;
7501 if (!list) pipe_add_fptr(fptr);
7504 pipe_del_fptr(fptr);
7530#define spawnv(mode, cmd, args) rb_w32_uaspawn((mode), (cmd), (args))
7531#define spawn(mode, cmd) rb_w32_uspawn((mode), (cmd), 0)
7534#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7544#ifdef HAVE_WORKING_FORK
7545# ifndef __EMSCRIPTEN__
7547popen_redirect(
struct popen_arg *p)
7550 close(p->write_pair[1]);
7551 if (p->write_pair[0] != 0) {
7552 dup2(p->write_pair[0], 0);
7553 close(p->write_pair[0]);
7556 if (p->pair[1] != 1) {
7557 dup2(p->pair[1], 1);
7563 if (p->pair[1] != 1) {
7564 dup2(p->pair[1], 1);
7570 if (p->pair[0] != 0) {
7571 dup2(p->pair[0], 0);
7578#if defined(__linux__)
7589linux_get_maxfd(
void)
7592 char buf[4096], *p, *np, *e;
7595 if (fd < 0)
return fd;
7596 ss = read(fd, buf,
sizeof(buf));
7597 if (ss < 0)
goto err;
7600 while ((
int)
sizeof(
"FDSize:\t0\n")-1 <= e-p &&
7601 (np = memchr(p,
'\n', e-p)) != NULL) {
7602 if (memcmp(p,
"FDSize:",
sizeof(
"FDSize:")-1) == 0) {
7604 p +=
sizeof(
"FDSize:")-1;
7624#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
7626 int max = (int)max_file_descriptor;
7629 ret = fcntl(0, F_MAXFD);
7631 maxhint = max = ret;
7632# elif defined(__linux__)
7633 ret = linux_get_maxfd();
7640 for (fd = lowfd; fd <= max; fd++) {
7641 if (!
NIL_P(noclose_fds) &&
7644 ret = fcntl(fd, F_GETFD);
7645 if (ret != -1 && !(ret & FD_CLOEXEC)) {
7646 fcntl(fd, F_SETFD, ret|FD_CLOEXEC);
7648# define CONTIGUOUS_CLOSED_FDS 20
7650 if (max < fd + CONTIGUOUS_CLOSED_FDS)
7651 max = fd + CONTIGUOUS_CLOSED_FDS;
7657# ifndef __EMSCRIPTEN__
7659popen_exec(
void *pp,
char *errmsg,
size_t errmsg_len)
7661 struct popen_arg *p = (
struct popen_arg*)pp;
7663 return rb_exec_async_signal_safe(p->eargp, errmsg, errmsg_len);
7668#if (defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)) && !defined __EMSCRIPTEN__
7670rb_execarg_fixup_v(
VALUE execarg_obj)
7672 rb_execarg_parent_start(execarg_obj);
7676char *rb_execarg_commandline(
const struct rb_execarg *eargp,
VALUE *prog);
7679#ifndef __EMSCRIPTEN__
7681pipe_open(
VALUE execarg_obj,
const char *modestr,
enum rb_io_mode fmode,
7684 struct rb_execarg *eargp =
NIL_P(execarg_obj) ? NULL : rb_execarg_get(execarg_obj);
7685 VALUE prog = eargp ? (eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name) :
Qfalse ;
7691#if defined(HAVE_WORKING_FORK)
7693 char errmsg[80] = {
'\0' };
7695#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7697 struct popen_arg arg;
7700#if defined(HAVE_SPAWNV)
7701# define DO_SPAWN(cmd, args) ((args) ? \
7702 spawnv(P_NOWAIT, (cmd), (args)) : \
7703 spawn(P_NOWAIT, (cmd)))
7704# if !defined(HAVE_WORKING_FORK)
7708#if !defined(HAVE_WORKING_FORK)
7714#if !defined(HAVE_WORKING_FORK)
7715 const char *cmd = 0;
7721#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7722 arg.execarg_obj = execarg_obj;
7725 arg.pair[0] = arg.pair[1] = -1;
7726 arg.write_pair[0] = arg.write_pair[1] = -1;
7727# if !defined(HAVE_WORKING_FORK)
7728 if (eargp && !eargp->use_shell) {
7729 args = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
7734 if (
rb_pipe(arg.write_pair) < 0)
7735 rb_sys_fail_str(prog);
7738 close(arg.write_pair[0]);
7739 close(arg.write_pair[1]);
7743 rb_execarg_addopt(execarg_obj,
INT2FIX(0),
INT2FIX(arg.write_pair[0]));
7744 rb_execarg_addopt(execarg_obj,
INT2FIX(1),
INT2FIX(arg.pair[1]));
7749 rb_sys_fail_str(prog);
7751 rb_execarg_addopt(execarg_obj,
INT2FIX(1),
INT2FIX(arg.pair[1]));
7755 rb_sys_fail_str(prog);
7757 rb_execarg_addopt(execarg_obj,
INT2FIX(0),
INT2FIX(arg.pair[0]));
7760 rb_sys_fail_str(prog);
7762 if (!
NIL_P(execarg_obj)) {
7763 rb_protect(rb_execarg_fixup_v, execarg_obj, &state);
7765 if (0 <= arg.write_pair[0]) close(arg.write_pair[0]);
7766 if (0 <= arg.write_pair[1]) close(arg.write_pair[1]);
7767 if (0 <= arg.pair[0]) close(arg.pair[0]);
7768 if (0 <= arg.pair[1]) close(arg.pair[1]);
7769 rb_execarg_parent_end(execarg_obj);
7773# if defined(HAVE_WORKING_FORK)
7774 pid = rb_fork_async_signal_safe(&status, popen_exec, &arg, arg.eargp->redirect_fds, errmsg,
sizeof(errmsg));
7776 rb_execarg_run_options(eargp, sargp, NULL, 0);
7777 while ((pid = DO_SPAWN(cmd, args)) < 0) {
7779 switch (e =
errno) {
7781# if EWOULDBLOCK != EAGAIN
7790 rb_execarg_run_options(sargp, NULL, NULL, 0);
7792 rb_execarg_parent_end(execarg_obj);
7795# if defined(HAVE_WORKING_FORK)
7796 pid = rb_call_proc__fork();
7798 popen_redirect(&arg);
7810# if defined(HAVE_WORKING_FORK)
7816 close(arg.write_pair[0]);
7817 close(arg.write_pair[1]);
7819# if defined(HAVE_WORKING_FORK)
7828 close(arg.write_pair[0]);
7829 write_fd = arg.write_pair[1];
7840 cmd = rb_execarg_commandline(eargp, &prog);
7841 if (!
NIL_P(execarg_obj)) {
7842 rb_execarg_parent_start(execarg_obj);
7843 rb_execarg_run_options(eargp, sargp, NULL, 0);
7845 fp = popen(cmd, modestr);
7848 rb_execarg_parent_end(execarg_obj);
7849 rb_execarg_run_options(sargp, NULL, NULL, 0);
7851 if (!fp) rb_syserr_fail_path(e, prog);
7861 fptr->
encs = *convconfig;
7862#if RUBY_CRLF_ENVIRONMENT
7869 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
7872#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7873 if (NEED_NEWLINE_DECORATOR_ON_WRITE(fptr)) {
7874 fptr->
encs.
ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
7880 if (0 <= write_fd) {
7881 write_port = io_alloc(
rb_cIO);
7883 write_fptr->
fd = write_fd;
7885 fptr->
mode &= ~FMODE_WRITABLE;
7887 rb_ivar_set(port, rb_intern(
"@tied_io_for_writing"), write_port);
7890#if defined (__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7892 pipe_add_fptr(fptr);
7898pipe_open(
VALUE execarg_obj,
const char *modestr,
enum rb_io_mode fmode,
7906is_popen_fork(
VALUE prog)
7908 if (RSTRING_LEN(prog) == 1 && RSTRING_PTR(prog)[0] ==
'-') {
7909#if !defined(HAVE_WORKING_FORK)
7911 "fork() function is unimplemented on this machine");
7920pipe_open_s(
VALUE prog,
const char *modestr,
enum rb_io_mode fmode,
7924 VALUE *argv = &prog;
7927 if (!is_popen_fork(prog))
7928 execarg_obj = rb_execarg_new(argc, argv, TRUE, FALSE);
7929 return pipe_open(execarg_obj, modestr, fmode, convconfig);
7935 rb_io_t *fptr = io_close_fptr(io);
8104rb_io_s_popen(
int argc,
VALUE *argv,
VALUE klass)
8108 if (argc > 1 && !
NIL_P(opt = rb_check_hash_type(argv[argc-1]))) --argc;
8109 if (argc > 1 && !
NIL_P(env = rb_check_hash_type(argv[0]))) --argc, ++argv;
8118 int ex = !
NIL_P(opt);
8119 rb_error_arity(argc + ex, 1 + ex, 2 + ex);
8122 return popen_finish(rb_io_popen(pname, pmode, env, opt), klass);
8128 const char *modestr;
8131 enum rb_io_mode fmode;
8137#if SIZEOF_LONG > SIZEOF_INT
8138 if (
len > INT_MAX) {
8139 rb_raise(rb_eArgError,
"too many arguments");
8148 if (!is_popen_fork(pname))
8149 execarg_obj = rb_execarg_new(1, &pname, TRUE, FALSE);
8151 if (!
NIL_P(execarg_obj)) {
8153 opt = rb_execarg_extract_options(execarg_obj, opt);
8155 rb_execarg_setenv(execarg_obj, env);
8158 modestr = rb_io_oflags_modestr(oflags);
8160 return pipe_open(execarg_obj, modestr, fmode, &convconfig);
8170 rb_io_flush(rb_ractor_stdout());
8171 rb_io_flush(rb_ractor_stderr());
8172 _exit(EXIT_SUCCESS);
8176 RBASIC_SET_CLASS(port, klass);
8183#if defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)
8184struct popen_writer_arg {
8186 struct popen_arg popen;
8190exec_popen_writer(
void *arg,
char *errmsg,
size_t buflen)
8192 struct popen_writer_arg *pw = arg;
8194 popen_redirect(&pw->popen);
8195 execv(pw->argv[0], pw->argv);
8196 strlcpy(errmsg, strerror(
errno), buflen);
8202ruby_popen_writer(
char *
const *argv, rb_pid_t *pid)
8204#if (defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)) || defined(_WIN32)
8205# ifdef HAVE_WORKING_FORK
8206 struct popen_writer_arg pw;
8207 int *
const write_pair = pw.popen.pair;
8213 if (cloexec_pipe(write_pair, 0,
false) == 0) {
8214# ifdef HAVE_WORKING_FORK
8217 char errmsg[80] = {
'\0'};
8218 *pid = rb_fork_async_signal_safe(&status, exec_popen_writer, &pw,
Qnil, errmsg,
sizeof(errmsg));
8220 *pid = rb_w32_uspawn_process(P_NOWAIT, argv[0], argv, write_pair[0], -1, -1, 0);
8221 const char *errmsg = (*pid < 0) ? strerror(
errno) : NULL;
8223 close(write_pair[0]);
8225 close(write_pair[1]);
8226 fprintf(stderr,
"ruby_popen_writer(%s): %s\n", argv[0], errmsg);
8229 return fdopen(write_pair[1],
"w");
8240 enum rb_io_mode fmode;
8249 rb_file_open_generic(io, fname, oflags, fmode, &convconfig, perm);
8301rb_io_s_open(
int argc,
VALUE *argv,
VALUE klass)
8333 VALUE fname, vmode, vperm;
8338 rb_scan_args(argc, argv,
"12", &fname, &vmode, &vperm);
8349 if (
NIL_P(vperm)) perm = 0666;
8353 fd = rb_sysopen(fname, oflags, perm);
8385 int redirect = FALSE;
8393 VALUE tmp = argv[0];
8411 return rb_io_s_open(argc, argv,
rb_cFile);
8415rb_io_open_generic(
VALUE klass,
VALUE filename,
int oflags,
enum rb_io_mode fmode,
8418 return rb_file_open_generic(io_alloc(klass), filename,
8419 oflags, fmode, convconfig, perm);
8426 enum rb_io_mode fmode;
8432 return rb_io_open_generic(io, filename, oflags, fmode, &convconfig, perm);
8446 if (fptr == orig)
return io;
8447 if (RUBY_IO_EXTERNAL_P(fptr)) {
8451 rb_raise(rb_eArgError,
8452 "%s can't change access mode from \"%s\" to \"%s\"",
8453 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->
mode),
8454 rb_io_fmode_modestr(orig->
mode));
8457 flush_before_seek(fptr,
true);
8459 clear_codeconv(fptr);
8461 pos = io_tell(orig);
8464 if (io_fflush(orig) < 0)
8465 rb_sys_fail_on_write(fptr);
8474 else if (!RUBY_IO_EXTERNAL_P(fptr)) fptr->
pathv =
Qnil;
8475 fptr_copy_finalizer(fptr, orig);
8481 rb_thread_io_close_interrupt(fptr);
8482 rb_thread_io_close_wait(fptr);
8484 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2 || !fptr->stdio_file) {
8487 rb_sys_fail_path(orig->
pathv);
8495 rb_sys_fail_path(orig->
pathv);
8501 if (io_seek(fptr, pos, SEEK_SET) < 0 &&
errno) {
8502 rb_sys_fail_path(fptr->
pathv);
8504 if (io_seek(orig, pos, SEEK_SET) < 0 &&
errno) {
8505 rb_sys_fail_path(orig->
pathv);
8519int rb_freopen(
VALUE fname,
const char *mode,
FILE *fp);
8522rb_freopen(
VALUE fname,
const char *mode,
FILE *fp)
8524 if (!freopen(RSTRING_PTR(fname), mode, fp)) {
8567rb_io_reopen(
int argc,
VALUE *argv,
VALUE file)
8569 VALUE fname, nmode, opt;
8573 if (
rb_scan_args(argc, argv,
"11:", &fname, &nmode, &opt) == 1) {
8576 return io_reopen(file, tmp);
8582 fptr =
RFILE(file)->fptr;
8588 enum rb_io_mode fmode;
8592 if (RUBY_IO_EXTERNAL_P(fptr) &&
8595 rb_raise(rb_eArgError,
8596 "%s can't change access mode from \"%s\" to \"%s\"",
8597 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->
mode),
8598 rb_io_fmode_modestr(fmode));
8601 fptr->
encs = convconfig;
8604 oflags = rb_io_fmode_oflags(fptr->
mode);
8607 fptr->
pathv = fname;
8609 fptr->
fd = rb_sysopen(fptr->
pathv, oflags, 0666);
8615 if (io_fflush(fptr) < 0)
8616 rb_sys_fail_on_write(fptr);
8619 clear_codeconv(fptr);
8622 int e = rb_freopen(rb_str_encode_ospath(fptr->
pathv),
8623 rb_io_oflags_modestr(oflags),
8625 if (e) rb_syserr_fail_path(e, fptr->
pathv);
8629 if (setvbuf(fptr->
stdio_file, NULL, _IOFBF, 0) != 0)
8630 rb_warn(
"setvbuf() can't be honoured for %"PRIsVALUE, fptr->
pathv);
8633 if (setvbuf(fptr->
stdio_file, NULL, _IONBF, BUFSIZ) != 0)
8634 rb_warn(
"setvbuf() can't be honoured for %"PRIsVALUE, fptr->
pathv);
8636 else if (fptr->
stdio_file == stdout && isatty(fptr->
fd)) {
8637 if (setvbuf(fptr->
stdio_file, NULL, _IOLBF, BUFSIZ) != 0)
8638 rb_warn(
"setvbuf() can't be honoured for %"PRIsVALUE, fptr->
pathv);
8642 int tmpfd = rb_sysopen(fptr->
pathv, oflags, 0666);
8648 rb_syserr_fail_path(err, fptr->
pathv);
8672 fptr->
mode = orig->
mode & ~FMODE_EXTERNAL;
8679 fptr->closing_ec = NULL;
8680 fptr->wakeup_mutex =
Qnil;
8681 fptr->fork_generation = GET_VM()->fork_gen;
8684 fptr_copy_finalizer(fptr, orig);
8686 fd = ruby_dup(orig->
fd);
8688 pos = io_tell(orig);
8690 io_seek(fptr, pos, SEEK_SET);
8695 write_io = GetWriteIO(io);
8696 if (io != write_io) {
8699 rb_ivar_set(dest, rb_intern(
"@tied_io_for_writing"), write_io);
8762 if (argc == 0)
return Qnil;
8764 out = rb_ractor_stdout();
8776extern void rb_deprecated_str_setter(
VALUE val,
ID id,
VALUE *var);
8781 rb_deprecated_str_setter(val,
id, &val);
8787 val = rb_str_frozen_bare_string(val);
8864 for (i=0; i<argc; i++) {
8868 rb_io_write(out, argv[i]);
8965 rb_io_write(io, str);
8969#define forward(obj, id, argc, argv) \
8970 rb_funcallv_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8971#define forward_public(obj, id, argc, argv) \
8972 rb_funcallv_public_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8973#define forward_current(id, argc, argv) \
8974 forward_public(ARGF.current_file, id, argc, argv)
8991 VALUE r_stdout = rb_ractor_stdout();
8992 if (recv == r_stdout) {
8993 return rb_io_putc(recv, ch);
8995 return forward(r_stdout, rb_intern(
"putc"), 1, &ch);
9000rb_str_end_with_asciichar(
VALUE str,
int c)
9002 long len = RSTRING_LEN(str);
9003 const char *
ptr = RSTRING_PTR(str);
9007 if (
len == 0)
return 0;
9008 if ((n = rb_enc_mbminlen(
enc)) == 1) {
9009 return ptr[
len - 1] == c;
9011 return rb_enc_ascget(
ptr + ((
len - 1) / n) * n,
ptr +
len, &n,
enc) == c;
9022 rb_io_puts(1, &tmp, out);
9029 rb_io_puts(1, &tmp, out);
9084 VALUE line, args[2];
9091 for (
int i = 0; i < argc; i++) {
9105 if (RSTRING_LEN(line) == 0) {
9110 if (!rb_str_end_with_asciichar(line,
'\n')) {
9115 rb_io_writev(out, n, args);
9133 VALUE r_stdout = rb_ractor_stdout();
9134 if (recv == r_stdout) {
9135 return rb_io_puts(argc, argv, recv);
9137 return forward(r_stdout, rb_intern(
"puts"), argc, argv);
9141rb_p_write(
VALUE str)
9146 VALUE r_stdout = rb_ractor_stdout();
9149 io_writev(2, args, r_stdout);
9152 rb_io_writev(r_stdout, 2, args);
9164rb_p_result(
int argc,
const VALUE *argv)
9171 else if (argc > 1) {
9174 VALUE r_stdout = rb_ractor_stdout();
9176 rb_uninterruptible(rb_io_flush, r_stdout);
9217 for (i=0; i<argc; i++) {
9219 rb_uninterruptible(rb_p_write, inspected);
9221 return rb_p_result(argc, argv);
9242rb_obj_display(
int argc,
VALUE *argv,
VALUE self)
9246 out = (!
rb_check_arity(argc, 0, 1) ? rb_ractor_stdout() : argv[0]);
9247 rb_io_write(out, self);
9253rb_stderr_to_original_p(
VALUE err)
9255 return (err == orig_stderr ||
RFILE(orig_stderr)->fptr->
fd < 0);
9261 VALUE out = rb_ractor_stderr();
9262 if (rb_stderr_to_original_p(out)) {
9264 if (isatty(fileno(stderr))) {
9265 if (rb_w32_write_console(
rb_str_new(mesg,
len), fileno(stderr)) > 0)
return;
9268 if (fwrite(mesg,
sizeof(
char), (
size_t)
len, stderr) < (
size_t)
len) {
9285rb_write_error_str(
VALUE mesg)
9287 VALUE out = rb_ractor_stderr();
9289 if (rb_stderr_to_original_p(out)) {
9290 size_t len = (size_t)RSTRING_LEN(mesg);
9292 if (isatty(fileno(stderr))) {
9293 if (rb_w32_write_console(mesg, fileno(stderr)) > 0)
return;
9296 if (fwrite(RSTRING_PTR(mesg),
sizeof(
char),
len, stderr) <
len) {
9303 rb_io_write(out, mesg);
9308rb_stderr_tty_p(
void)
9310 if (rb_stderr_to_original_p(rb_ractor_stderr()))
9311 return isatty(fileno(stderr));
9316must_respond_to(
ID mid,
VALUE val,
ID id)
9319 rb_raise(
rb_eTypeError,
"%"PRIsVALUE
" must have %"PRIsVALUE
" method, %"PRIsVALUE
" given",
9320 rb_id2str(
id), rb_id2str(mid),
9340 must_respond_to(id_write, val,
id);
9347 return rb_ractor_stdout();
9353 must_respond_to(id_write, val,
id);
9360 return rb_ractor_stderr();
9364allocate_and_open_new_file(
VALUE klass)
9366 VALUE self = io_alloc(klass);
9367 rb_io_make_open_file(self);
9375 VALUE self = rb_protect(allocate_and_open_new_file, klass, &state);
9383 maygvl_close(descriptor, 0);
9391 io->
fd = descriptor;
9409 io->closing_ec = NULL;
9410 io->wakeup_mutex =
Qnil;
9411 io->fork_generation = GET_VM()->fork_gen;
9414 io->
encs = *encoding;
9423prep_io(
int fd,
enum rb_io_mode fmode,
VALUE klass,
const char *path)
9433 e = (fmode &
FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
9434 rb_io_ext_int_to_encs(e, NULL, &convconfig.
enc, &convconfig.
enc2, fmode);
9438#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9440 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
9441 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
9443 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.
enc2, convconfig.
ecflags);
9449 if (!io_check_tty(io)) {
9452 setmode(fd, O_BINARY);
9464 if (path && strcmp(path,
"-")) klass =
rb_cFile;
9465 return prep_io(fd, rb_io_oflags_fmode(oflags), klass, path);
9469prep_stdio(
FILE *f,
enum rb_io_mode fmode,
VALUE klass,
const char *path)
9476#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9477 fptr->
encs.
ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
9488rb_io_prep_stdin(
void)
9494rb_io_prep_stdout(
void)
9500rb_io_prep_stderr(
void)
9509 int oflags = rb_io_fmode_oflags(fptr->
mode) & ~O_EXCL;
9536 rb_io_buffer_init(&fp->
wbuf);
9537 rb_io_buffer_init(&fp->
rbuf);
9538 rb_io_buffer_init(&fp->
cbuf);
9553 fp->closing_ec = NULL;
9554 fp->wakeup_mutex =
Qnil;
9555 fp->fork_generation = GET_VM()->fork_gen;
9560rb_io_make_open_file(
VALUE obj)
9565 if (
RFILE(obj)->fptr) {
9568 RFILE(obj)->fptr = 0;
9570 fp = rb_io_fptr_new();
9572 RFILE(obj)->fptr = fp;
9621rb_io_initialize(
int argc,
VALUE *argv,
VALUE io)
9627 return io_initialize(io, fnum, vmode, opt);
9634 int fd, oflags = O_RDONLY;
9635 enum rb_io_mode fmode;
9637#if defined(HAVE_FCNTL) && defined(F_GETFL)
9647 rb_raise(rb_eArgError,
"The given fd is not accessible because RubyVM reserves it");
9649#if defined(HAVE_FCNTL) && defined(F_GETFL)
9650 oflags = fcntl(fd, F_GETFL);
9651 if (oflags == -1) rb_sys_fail(0);
9653 if (fstat(fd, &st) < 0) rb_sys_fail(0);
9656#if defined(HAVE_FCNTL) && defined(F_GETFL)
9657 ofmode = rb_io_oflags_fmode(oflags);
9669 if (rb_hash_aref(opt, sym_autoclose) ==
Qfalse) {
9673 path = rb_hash_aref(opt,
RB_ID2SYM(idPath));
9684 fp->
encs = convconfig;
9688 fp->closing_ec = NULL;
9689 fp->wakeup_mutex =
Qnil;
9690 fp->fork_generation = GET_VM()->fork_gen;
9693 if (fileno(stdin) == fd)
9695 else if (fileno(stdout) == fd)
9697 else if (fileno(stderr) == fd)
9729rb_io_set_encoding_by_bom(
VALUE io)
9735 rb_raise(rb_eArgError,
"ASCII incompatible encoding needs binmode");
9738 rb_raise(rb_eArgError,
"encoding conversion is set");
9740 else if (fptr->
encs.
enc && fptr->
encs.
enc != rb_ascii8bit_encoding()) {
9741 rb_raise(rb_eArgError,
"encoding is set to %s already",
9744 if (!io_set_encoding_by_bom(io))
return Qnil;
9745 return rb_enc_from_encoding(fptr->
encs.
enc);
9798rb_file_initialize(
int argc,
VALUE *argv,
VALUE io)
9800 if (
RFILE(io)->fptr) {
9803 VALUE fname, vmode, vperm, opt;
9804 int posargc =
rb_scan_args(argc, argv,
"12:", &fname, &vmode, &vperm, &opt);
9809 return io_initialize(io, fd, vmode, opt);
9812 return rb_open_file(io, fname, vmode, vperm, opt);
9817rb_io_s_new(
int argc,
VALUE *argv,
VALUE klass)
9822 rb_warn(
"%"PRIsVALUE
"::new() does not take block; use %"PRIsVALUE
"::open() instead",
9838rb_io_s_for_fd(
int argc,
VALUE *argv,
VALUE klass)
9841 rb_io_initialize(argc, argv, io);
9854rb_io_autoclose_p(
VALUE io)
9879rb_io_set_autoclose(
VALUE io,
VALUE autoclose)
9883 if (!
RTEST(autoclose))
9886 fptr->
mode &= ~FMODE_EXTERNAL;
9891io_wait_event(
VALUE io,
int event,
VALUE timeout,
int return_io)
9923io_wait_readable(
int argc,
VALUE *argv,
VALUE io)
9930 if (rb_io_read_pending(fptr))
return Qtrue;
9933 VALUE timeout = (argc == 1 ? argv[0] :
Qnil);
9947io_wait_writable(
int argc,
VALUE *argv,
VALUE io)
9955 VALUE timeout = (argc == 1 ? argv[0] :
Qnil);
9970io_wait_priority(
int argc,
VALUE *argv,
VALUE io)
9977 if (rb_io_read_pending(fptr))
return Qtrue;
9980 VALUE timeout = argc == 1 ? argv[0] :
Qnil;
9986wait_mode_sym(
VALUE mode)
9988 if (mode ==
ID2SYM(rb_intern(
"r"))) {
9989 return RB_WAITFD_IN;
9991 if (mode ==
ID2SYM(rb_intern(
"read"))) {
9992 return RB_WAITFD_IN;
9994 if (mode ==
ID2SYM(rb_intern(
"readable"))) {
9995 return RB_WAITFD_IN;
9997 if (mode ==
ID2SYM(rb_intern(
"w"))) {
9998 return RB_WAITFD_OUT;
10000 if (mode ==
ID2SYM(rb_intern(
"write"))) {
10001 return RB_WAITFD_OUT;
10003 if (mode ==
ID2SYM(rb_intern(
"writable"))) {
10004 return RB_WAITFD_OUT;
10006 if (mode ==
ID2SYM(rb_intern(
"rw"))) {
10007 return RB_WAITFD_IN|RB_WAITFD_OUT;
10009 if (mode ==
ID2SYM(rb_intern(
"read_write"))) {
10010 return RB_WAITFD_IN|RB_WAITFD_OUT;
10012 if (mode ==
ID2SYM(rb_intern(
"readable_writable"))) {
10013 return RB_WAITFD_IN|RB_WAITFD_OUT;
10016 rb_raise(rb_eArgError,
"unsupported mode: %"PRIsVALUE, mode);
10020io_event_from_value(
VALUE value)
10024 if (events <= 0) rb_raise(rb_eArgError,
"Events must be positive integer!");
10062 for (
int i = 0; i < argc; i += 1) {
10064 events |= wait_mode_sym(argv[i]);
10066 else if (UNDEF_P(timeout)) {
10070 rb_raise(rb_eArgError,
"timeout given more than once");
10074 if (UNDEF_P(timeout)) timeout =
Qnil;
10082 events = io_event_from_value(argv[0]);
10090 if (rb_io_read_pending(fptr)) {
10092 if (return_io)
return Qtrue;
10098 return io_wait_event(io, events, timeout, return_io);
10102argf_mark_and_move(
void *ptr)
10104 struct argf *p = ptr;
10105 rb_gc_mark_and_move(&p->filename);
10106 rb_gc_mark_and_move(&p->current_file);
10107 rb_gc_mark_and_move(&p->argv);
10108 rb_gc_mark_and_move(&p->inplace);
10109 rb_gc_mark_and_move(&p->encs.
ecopts);
10113argf_memsize(
const void *ptr)
10115 const struct argf *p = ptr;
10116 size_t size =
sizeof(*p);
10123 0, 0, RUBY_TYPED_THREAD_SAFE_FREE | RUBY_TYPED_WB_PROTECTED
10129 p->filename =
Qnil;
10130 p->current_file =
Qnil;
10136argf_alloc(
VALUE klass)
10151 memset(&ARGF, 0,
sizeof(ARGF));
10152 argf_init(
argf, &ARGF, argv);
10162 ARGF = argf_of(orig);
10163 rb_gc_writebarrier_remember(
argf);
10190 ARGF.last_lineno = ARGF.lineno;
10216 return forward_current(rb_frame_this_func(), argc, argv);
10219#define next_argv() argf_next_argv(argf)
10220#define ARGF_GENERIC_INPUT_P() \
10221 (ARGF.current_file == rb_stdin && !RB_TYPE_P(ARGF.current_file, T_FILE))
10222#define ARGF_FORWARD(argc, argv) do {\
10223 if (ARGF_GENERIC_INPUT_P())\
10224 return argf_forward((argc), (argv), argf);\
10226#define NEXT_ARGF_FORWARD(argc, argv) do {\
10227 if (!next_argv()) return Qnil;\
10228 ARGF_FORWARD((argc), (argv));\
10234 VALUE file = ARGF.current_file;
10248 int stdout_binmode = 0;
10249 enum rb_io_mode fmode;
10251 VALUE r_stdout = rb_ractor_stdout();
10256 stdout_binmode = 1;
10259 if (ARGF.init_p == 0) {
10269 if (
NIL_P(ARGF.argv)) {
10272 else if (ARGF.next_p == -1 &&
RARRAY_LEN(ARGF.argv) > 0) {
10277 if (ARGF.next_p == 1) {
10278 if (ARGF.init_p == 1) argf_close(
argf);
10283 ARGF_SET(filename, filename);
10284 filename = rb_str_encode_ospath(filename);
10286 if (RSTRING_LEN(filename) == 1 && fn[0] ==
'-') {
10288 if (ARGF.inplace) {
10289 rb_warn(
"Can't do inplace edit for stdio; skipping");
10295 int fr = rb_sysopen(filename, O_RDONLY, 0);
10297 if (ARGF.inplace) {
10299#ifndef NO_SAFE_RENAME
10310 if (!
NIL_P(ARGF.inplace)) {
10311 VALUE suffix = ARGF.inplace;
10313 if (
NIL_P(rb_str_cat_conv_enc_opts(str, RSTRING_LEN(str),
10314 RSTRING_PTR(suffix), RSTRING_LEN(suffix),
10315 rb_enc_get(suffix), 0,
Qnil))) {
10318#ifdef NO_SAFE_RENAME
10320 (void)unlink(RSTRING_PTR(str));
10321 if (rename(fn, RSTRING_PTR(str)) < 0) {
10322 rb_warn(
"Can't rename %"PRIsVALUE
" to %"PRIsVALUE
": %s, skipping file",
10323 filename, str, strerror(
errno));
10326 fr = rb_sysopen(str, O_RDONLY, 0);
10328 if (rename(fn, RSTRING_PTR(str)) < 0) {
10329 rb_warn(
"Can't rename %"PRIsVALUE
" to %"PRIsVALUE
": %s, skipping file",
10330 filename, str, strerror(
errno));
10337#ifdef NO_SAFE_RENAME
10338 rb_fatal(
"Can't do inplace edit without backup");
10340 if (unlink(fn) < 0) {
10341 rb_warn(
"Can't remove %"PRIsVALUE
": %s, skipping file",
10342 filename, strerror(
errno));
10348 fw = rb_sysopen(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666);
10349#ifndef NO_SAFE_RENAME
10352 fchmod(fw, st.st_mode);
10354 chmod(fn, st.st_mode);
10356 if (st.st_uid!=st2.st_uid || st.st_gid!=st2.st_gid) {
10359 err = fchown(fw, st.st_uid, st.st_gid);
10361 err = chown(fn, st.st_uid, st.st_gid);
10363 if (err && getuid() == 0 && st2.st_uid == 0) {
10364 const char *wkfn = RSTRING_PTR(filename);
10365 rb_warn(
"Can't set owner/group of %"PRIsVALUE
" to same as %"PRIsVALUE
": %s, skipping file",
10366 filename, str, strerror(
errno));
10369 (void)unlink(wkfn);
10379 if (!ARGF.binmode) {
10380 fmode |= DEFAULT_TEXTMODE;
10382 ARGF_SET(current_file, prep_io(fr, fmode,
rb_cFile, fn));
10383 if (!
NIL_P(write_io)) {
10390 if (ARGF.encs.enc) {
10391 fptr->
encs = ARGF.encs;
10392 clear_codeconv(fptr);
10395 fptr->
encs.
ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
10396 if (!ARGF.binmode) {
10398#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
10399 fptr->
encs.
ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
10410 else if (ARGF.next_p == -1) {
10413 if (ARGF.inplace) {
10414 rb_warn(
"Can't do inplace edit for stdio");
10418 if (ARGF.init_p == -1) ARGF.init_p = 1;
10426 long lineno = ARGF.lineno;
10429 if (!next_argv())
return Qnil;
10430 if (ARGF_GENERIC_INPUT_P()) {
10431 line = forward_current(idGets, argc, argv);
10438 line = rb_io_getline(argc, argv, ARGF.current_file);
10440 if (
NIL_P(line) && ARGF.next_p != -1) {
10446 if (!
NIL_P(line)) {
10447 ARGF.lineno = ++lineno;
10448 ARGF.last_lineno = ARGF.lineno;
10454argf_lineno_getter(
ID id,
VALUE *var)
10457 return INT2FIX(ARGF.last_lineno);
10465 ARGF.last_lineno = ARGF.lineno = n;
10469rb_reset_argf_lineno(
long n)
10471 ARGF.last_lineno = ARGF.lineno = n;
10512 if (recv ==
argf) {
10513 return argf_gets(argc, argv,
argf);
10515 return forward(
argf, idGets, argc, argv);
10541 line = argf_getline(argc, argv,
argf);
10553 return rb_f_gets(0, 0,
argf);
10557 if (!next_argv())
return Qnil;
10559 if (
NIL_P(line) && ARGF.next_p != -1) {
10565 if (!
NIL_P(line)) {
10567 ARGF.last_lineno = ARGF.lineno;
10593rb_f_readline(
int argc,
VALUE *argv,
VALUE recv)
10595 if (recv ==
argf) {
10596 return argf_readline(argc, argv,
argf);
10598 return forward(
argf, rb_intern(
"readline"), argc, argv);
10624 if (!next_argv()) rb_eof_error();
10625 ARGF_FORWARD(argc, argv);
10626 line = argf_gets(argc, argv,
argf);
10696rb_f_readlines(
int argc,
VALUE *argv,
VALUE recv)
10698 if (recv ==
argf) {
10699 return argf_readlines(argc, argv,
argf);
10701 return forward(
argf, rb_intern(
"readlines"), argc, argv);
10725 long lineno = ARGF.lineno;
10729 while (next_argv()) {
10730 if (ARGF_GENERIC_INPUT_P()) {
10731 lines = forward_current(rb_intern(
"readlines"), argc, argv);
10734 lines = rb_io_readlines(argc, argv, ARGF.current_file);
10740 ARGF.last_lineno = ARGF.lineno;
10775 rb_last_status_clear();
10776 port = pipe_open_s(str,
"r",
FMODE_READABLE|DEFAULT_TEXTMODE, NULL);
10780 result = read_all(fptr, remain_size(fptr),
Qnil);
10782 rb_io_fptr_cleanup_all(fptr);
10788#ifdef HAVE_SYS_SELECT_H
10789#include <sys/select.h>
10803 if (!
NIL_P(read)) {
10808 if (READ_DATA_PENDING(fptr) || READ_CHAR_PENDING(fptr)) {
10812 if (max < fptr->fd) max = fptr->
fd;
10815 timerec.tv_sec = timerec.tv_usec = 0;
10823 if (!
NIL_P(write)) {
10829 if (max < fptr->fd) max = fptr->
fd;
10836 if (!
NIL_P(except)) {
10840 VALUE write_io = GetWriteIO(io);
10843 if (max < fptr->fd) max = fptr->
fd;
10844 if (io != write_io) {
10847 if (max < fptr->fd) max = fptr->
fd;
10862 if (!pending && n == 0)
return Qnil;
10887 VALUE write_io = GetWriteIO(io);
10900 VALUE write_io = GetWriteIO(io);
10905 else if (io != write_io) {
10918 VALUE read, write, except;
10924select_call(
VALUE arg)
10928 return select_internal(p->read, p->write, p->except, p->timeout, p->fdsets);
10932select_end(
VALUE arg)
10937 for (i = 0; i < numberof(p->fdsets); ++i)
10942static VALUE sym_normal, sym_sequential, sym_random,
10943 sym_willneed, sym_dontneed, sym_noreuse;
10945#ifdef HAVE_POSIX_FADVISE
10946struct io_advise_struct {
10954io_advise_internal(
void *arg)
10956 struct io_advise_struct *ptr = arg;
10957 return posix_fadvise(ptr->fd, ptr->offset, ptr->len, ptr->advice);
10961io_advise_sym_to_const(
VALUE sym)
10963#ifdef POSIX_FADV_NORMAL
10964 if (sym == sym_normal)
10965 return INT2NUM(POSIX_FADV_NORMAL);
10968#ifdef POSIX_FADV_RANDOM
10969 if (sym == sym_random)
10970 return INT2NUM(POSIX_FADV_RANDOM);
10973#ifdef POSIX_FADV_SEQUENTIAL
10974 if (sym == sym_sequential)
10975 return INT2NUM(POSIX_FADV_SEQUENTIAL);
10978#ifdef POSIX_FADV_WILLNEED
10979 if (sym == sym_willneed)
10980 return INT2NUM(POSIX_FADV_WILLNEED);
10983#ifdef POSIX_FADV_DONTNEED
10984 if (sym == sym_dontneed)
10985 return INT2NUM(POSIX_FADV_DONTNEED);
10988#ifdef POSIX_FADV_NOREUSE
10989 if (sym == sym_noreuse)
10990 return INT2NUM(POSIX_FADV_NOREUSE);
10997do_io_advise(
rb_io_t *fptr,
VALUE advice, rb_off_t offset, rb_off_t
len)
11000 struct io_advise_struct ias;
11003 num_adv = io_advise_sym_to_const(advice);
11009 if (
NIL_P(num_adv))
11013 ias.advice =
NUM2INT(num_adv);
11014 ias.offset = offset;
11017 rv = (int)rb_io_blocking_region(fptr, io_advise_internal, &ias);
11018 if (rv && rv != ENOSYS) {
11021 VALUE message = rb_sprintf(
"%"PRIsVALUE
" "
11025 fptr->
pathv, offset,
len, advice);
11035advice_arg_check(
VALUE advice)
11040 if (advice != sym_normal &&
11041 advice != sym_sequential &&
11042 advice != sym_random &&
11043 advice != sym_willneed &&
11044 advice != sym_dontneed &&
11045 advice != sym_noreuse) {
11046 rb_raise(
rb_eNotImpError,
"Unsupported advice: %+"PRIsVALUE, advice);
11084rb_io_advise(
int argc,
VALUE *argv,
VALUE io)
11091 advice_arg_check(advice);
11093 io = GetWriteIO(io);
11099#ifdef HAVE_POSIX_FADVISE
11100 return do_io_advise(fptr, advice,
off, l);
11102 ((void)
off, (
void)l);
11114 return isinf(f) && 0 < f;
11270rb_f_select(
int argc,
VALUE *argv,
VALUE obj)
11273 if (scheduler !=
Qnil) {
11276 if (!UNDEF_P(result))
return result;
11284 rb_scan_args(argc, argv,
"13", &args.read, &args.write, &args.except, &timeout);
11285 if (
NIL_P(timeout) || is_pos_inf(timeout)) {
11290 args.timeout = &timerec;
11293 for (i = 0; i < numberof(args.fdsets); ++i)
11299#ifdef IOCTL_REQ_TYPE
11300 typedef IOCTL_REQ_TYPE ioctl_req_t;
11302 typedef int ioctl_req_t;
11303# define NUM2IOCTLREQ(num) ((int)NUM2LONG(num))
11314nogvl_ioctl(
void *ptr)
11316 struct ioctl_arg *arg = ptr;
11318 return (
VALUE)ioctl(arg->fd, arg->cmd, arg->narg);
11322do_ioctl(
struct rb_io *io, ioctl_req_t cmd,
long narg)
11325 struct ioctl_arg arg;
11331 retval = (int)rb_io_blocking_region(io, nogvl_ioctl, &arg);
11337#define DEFAULT_IOCTL_NARG_LEN (256)
11339#if defined(__linux__) && defined(_IOC_SIZE)
11341linux_iocparm_len(ioctl_req_t cmd)
11345 if ((cmd & 0xFFFF0000) == 0) {
11347 return DEFAULT_IOCTL_NARG_LEN;
11350 len = _IOC_SIZE(cmd);
11353 if (
len < DEFAULT_IOCTL_NARG_LEN)
11354 len = DEFAULT_IOCTL_NARG_LEN;
11362ioctl_narg_len(ioctl_req_t cmd)
11368#define IOCPARM_LEN(x) (((x) >> 16) & IOCPARM_MASK)
11372 len = IOCPARM_LEN(cmd);
11373#elif defined(__linux__) && defined(_IOC_SIZE)
11374 len = linux_iocparm_len(cmd);
11377 len = DEFAULT_IOCTL_NARG_LEN;
11386typedef long fcntl_arg_t;
11389typedef int fcntl_arg_t;
11393fcntl_narg_len(ioctl_req_t cmd)
11400 len =
sizeof(fcntl_arg_t);
11408#ifdef F_DUPFD_CLOEXEC
11409 case F_DUPFD_CLOEXEC:
11410 len =
sizeof(fcntl_arg_t);
11420 len =
sizeof(fcntl_arg_t);
11430 len =
sizeof(fcntl_arg_t);
11440 len =
sizeof(fcntl_arg_t);
11445 len =
sizeof(
struct f_owner_ex);
11450 len =
sizeof(
struct f_owner_ex);
11455 len =
sizeof(
struct flock);
11460 len =
sizeof(
struct flock);
11465 len =
sizeof(
struct flock);
11485 len =
sizeof(fcntl_arg_t);
11495 len =
sizeof(fcntl_arg_t);
11500 len =
sizeof(fcntl_arg_t);
11513fcntl_narg_len(ioctl_req_t cmd)
11519#define NARG_SENTINEL 17
11522setup_narg(ioctl_req_t cmd,
VALUE *argp,
long (*narg_len)(ioctl_req_t))
11533 else if (arg ==
Qtrue) {
11547 len = narg_len(cmd);
11548 rb_str_modify(arg);
11550 slen = RSTRING_LEN(arg);
11552 if (slen <
len+1) {
11553 rb_str_resize(arg,
len+1);
11554 MEMZERO(RSTRING_PTR(arg)+slen,
char,
len-slen);
11558 ptr = RSTRING_PTR(arg);
11559 ptr[slen - 1] = NARG_SENTINEL;
11568finish_narg(
int retval,
VALUE arg,
const rb_io_t *fptr)
11570 if (retval < 0) rb_sys_fail_path(fptr->
pathv);
11575 if (ptr[slen-1] != NARG_SENTINEL)
11576 rb_raise(rb_eArgError,
"return value overflowed string");
11577 ptr[slen-1] =
'\0';
11587 ioctl_req_t cmd = NUM2IOCTLREQ(req);
11592 narg = setup_narg(cmd, &arg, ioctl_narg_len);
11594 retval = do_ioctl(fptr, cmd, narg);
11595 return finish_narg(retval, arg, fptr);
11622 return rb_ioctl(io, req, arg);
11625#define rb_io_ioctl rb_f_notimplement
11636nogvl_fcntl(
void *ptr)
11638 struct fcntl_arg *arg = ptr;
11640#if defined(F_DUPFD)
11641 if (arg->cmd == F_DUPFD)
11644 return (
VALUE)fcntl(arg->fd, arg->cmd, arg->narg);
11648do_fcntl(
struct rb_io *io,
int cmd,
long narg)
11651 struct fcntl_arg arg;
11657 retval = (int)rb_io_blocking_region(io, nogvl_fcntl, &arg);
11658 if (retval != -1) {
11660#if defined(F_DUPFD)
11663#if defined(F_DUPFD_CLOEXEC)
11664 case F_DUPFD_CLOEXEC:
11681 narg = setup_narg(cmd, &arg, fcntl_narg_len);
11683 retval = do_fcntl(fptr, cmd, narg);
11684 return finish_narg(retval, arg, fptr);
11710 return rb_fcntl(io, req, arg);
11713#define rb_io_fcntl rb_f_notimplement
11716#if defined(HAVE_SYSCALL) || defined(HAVE___SYSCALL)
11748#if SIZEOF_VOIDP == 8 && defined(HAVE___SYSCALL) && SIZEOF_INT != 8
11749# define SYSCALL __syscall
11750# define NUM2SYSCALLID(x) NUM2LONG(x)
11751# define RETVAL2NUM(x) LONG2NUM(x)
11752# if SIZEOF_LONG == 8
11753 long num, retval = -1;
11754# elif SIZEOF_LONG_LONG == 8
11755 long long num, retval = -1;
11757# error ---->> it is asserted that __syscall takes the first argument and returns retval in 64bit signed integer. <<----
11759#elif defined(__linux__)
11760# define SYSCALL syscall
11761# define NUM2SYSCALLID(x) NUM2LONG(x)
11762# define RETVAL2NUM(x) LONG2NUM(x)
11770 long num, retval = -1;
11772# define SYSCALL syscall
11773# define NUM2SYSCALLID(x) NUM2INT(x)
11774# define RETVAL2NUM(x) INT2NUM(x)
11775 int num, retval = -1;
11781 "We plan to remove a syscall function at future release. DL(Fiddle) provides safer alternative.");
11785 rb_raise(rb_eArgError,
"too few arguments for syscall");
11786 if (argc > numberof(arg))
11787 rb_raise(rb_eArgError,
"too many arguments for syscall");
11788 num = NUM2SYSCALLID(argv[0]); ++argv;
11789 for (i = argc - 1; i--; ) {
11804 retval = SYSCALL(num);
11807 retval = SYSCALL(num, arg[0]);
11810 retval = SYSCALL(num, arg[0],arg[1]);
11813 retval = SYSCALL(num, arg[0],arg[1],arg[2]);
11816 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3]);
11819 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4]);
11822 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5]);
11825 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6]);
11831 return RETVAL2NUM(retval);
11833#undef NUM2SYSCALLID
11837#define rb_f_syscall rb_f_notimplement
11841io_new_instance(
VALUE args)
11847find_encoding(
VALUE v)
11850 if (!enc)
rb_warn(
"Unsupported encoding %"PRIsVALUE
" ignored", v);
11862 enc2 = find_encoding(v1);
11865 if (RSTRING_LEN(tmp) == 1 && RSTRING_PTR(tmp)[0] ==
'-') {
11871 enc = find_encoding(v2);
11878 enc = find_encoding(v2);
11884 if (enc2 == rb_ascii8bit_encoding()) {
11889 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11895 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
11896 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11901 if (!
NIL_P(tmp) && rb_enc_asciicompat(enc = rb_enc_get(tmp))) {
11902 parse_mode_enc(RSTRING_PTR(tmp), enc, &enc, &enc2, NULL);
11903 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11907 rb_io_ext_int_to_encs(find_encoding(v1), NULL, &enc, &enc2, 0);
11908 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11913 validate_enc_binmode(&fptr->
mode, ecflags, enc, enc2);
11918 clear_codeconv(fptr);
11930io_encoding_set_v(
VALUE v)
11933 io_encoding_set(arg->fptr, arg->v1, arg->v2, arg->opt);
11938pipe_pair_close(
VALUE rw)
11941 return rb_ensure(io_close, rwp[0], io_close, rwp[1]);
12024rb_io_s_pipe(
int argc,
VALUE *argv,
VALUE klass)
12026 int pipes[2], state;
12027 VALUE r, w, args[3], v1, v2;
12031 enum rb_io_mode fmode = 0;
12034 argc =
rb_scan_args(argc, argv,
"02:", &v1, &v2, &opt);
12041 r = rb_protect(io_new_instance, (
VALUE)args, &state);
12045 rb_jump_tag(state);
12049 ies_args.fptr = fptr;
12052 ies_args.opt = opt;
12053 rb_protect(io_encoding_set_v, (
VALUE)&ies_args, &state);
12057 rb_jump_tag(state);
12062 w = rb_protect(io_new_instance, (
VALUE)args, &state);
12066 rb_jump_tag(state);
12071 extract_binmode(opt, &fmode);
12078#if DEFAULT_TEXTMODE
12080 fptr->
mode &= ~FMODE_TEXTMODE;
12081 setmode(fptr->
fd, O_BINARY);
12083#if RUBY_CRLF_ENVIRONMENT
12089 fptr->
mode |= fmode;
12090#if DEFAULT_TEXTMODE
12092 fptr2->
mode &= ~FMODE_TEXTMODE;
12093 setmode(fptr2->
fd, O_BINARY);
12096 fptr2->
mode |= fmode;
12130 else if (!
NIL_P(v = rb_hash_aref(opt, sym_open_args))) {
12133 v = rb_to_array_type(v);
12138 arg->io = rb_io_open(klass, path, vmode, vperm, opt);
12142io_s_foreach(
VALUE v)
12147 if (arg->limit == 0)
12148 rb_raise(rb_eArgError,
"invalid limit: 0 for foreach");
12149 while (!
NIL_P(str = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, arg->io))) {
12233rb_io_s_foreach(
int argc,
VALUE *argv,
VALUE self)
12236 int orig_argc = argc;
12240 argc =
rb_scan_args(argc, argv,
"12:", NULL, NULL, NULL, &opt);
12242 extract_getline_args(argc-1, argv+1, &garg);
12243 open_key_args(self, argc, argv, opt, &arg);
12245 extract_getline_opts(opt, &garg);
12246 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12247 return rb_ensure(io_s_foreach, (
VALUE)&garg, rb_io_close, arg.io);
12251io_s_readlines(
VALUE v)
12254 return io_readlines(arg, arg->io);
12307rb_io_s_readlines(
int argc,
VALUE *argv,
VALUE io)
12313 argc =
rb_scan_args(argc, argv,
"12:", NULL, NULL, NULL, &opt);
12314 extract_getline_args(argc-1, argv+1, &garg);
12315 open_key_args(io, argc, argv, opt, &arg);
12317 extract_getline_opts(opt, &garg);
12318 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12319 return rb_ensure(io_s_readlines, (
VALUE)&garg, rb_io_close, arg.io);
12326 return io_read(arg->argc, arg->argv, arg->io);
12336seek_before_access(
VALUE argp)
12340 return rb_io_seek(arg->io, arg->offset, arg->mode);
12407rb_io_s_read(
int argc,
VALUE *argv,
VALUE io)
12413 argc =
rb_scan_args(argc, argv,
"13:", NULL, NULL, &offset, NULL, &opt);
12415 rb_raise(rb_eArgError,
"negative offset %ld given",
off);
12417 open_key_args(io, argc, argv, opt, &arg);
12419 if (!
NIL_P(offset)) {
12423 sarg.offset = offset;
12424 sarg.mode = SEEK_SET;
12425 rb_protect(seek_before_access, (
VALUE)&sarg, &state);
12428 rb_jump_tag(state);
12430 if (arg.argc == 2) arg.argc = 1;
12445rb_io_s_binread(
int argc,
VALUE *argv,
VALUE io)
12460 convconfig.
enc = rb_ascii8bit_encoding();
12461 arg.io = rb_io_open_generic(io, argv[0], oflags, fmode, &convconfig, 0);
12464 arg.argc = (argc > 1) ? 1 : 0;
12465 if (!
NIL_P(offset)) {
12469 sarg.offset = offset;
12470 sarg.mode = SEEK_SET;
12471 rb_protect(seek_before_access, (
VALUE)&sarg, &state);
12474 rb_jump_tag(state);
12481io_s_write0(
VALUE v)
12484 return io_write(arg->io,arg->str,arg->nosync);
12488io_s_write(
int argc,
VALUE *argv,
VALUE klass,
int binary)
12490 VALUE string, offset, opt;
12494 rb_scan_args(argc, argv,
"21:", NULL, &
string, &offset, &opt);
12496 if (
NIL_P(opt)) opt = rb_hash_new();
12497 else opt = rb_hash_dup(opt);
12500 if (
NIL_P(rb_hash_aref(opt,sym_mode))) {
12501 int mode = O_WRONLY|O_CREAT;
12503 if (binary) mode |= O_BINARY;
12505 if (
NIL_P(offset)) mode |= O_TRUNC;
12506 rb_hash_aset(opt,sym_mode,
INT2NUM(mode));
12508 open_key_args(klass, argc, argv, opt, &arg);
12511 if (binary) rb_io_binmode_m(arg.io);
12515 if (!
NIL_P(offset)) {
12519 sarg.offset = offset;
12520 sarg.mode = SEEK_SET;
12521 rb_protect(seek_before_access, (
VALUE)&sarg, &state);
12524 rb_jump_tag(state);
12532 return rb_ensure(io_s_write0, (
VALUE)&warg, rb_io_close, arg.io);
12590rb_io_s_write(
int argc,
VALUE *argv,
VALUE io)
12592 return io_s_write(argc, argv, io, 0);
12605rb_io_s_binwrite(
int argc,
VALUE *argv,
VALUE io)
12607 return io_s_write(argc, argv, io, 1);
12613 rb_off_t copy_length;
12614 rb_off_t src_offset;
12618 unsigned close_src : 1;
12619 unsigned close_dst : 1;
12622 const char *syserr;
12623 const char *notimp;
12625 struct stat src_stat;
12626 struct stat dst_stat;
12627#ifdef HAVE_FCOPYFILE
12628 copyfile_state_t copyfile_state;
12633exec_interrupts(
void *arg)
12636 rb_thread_execute_interrupts(th);
12650#if defined(ERESTART)
12655 rb_thread_execute_interrupts(stp->th);
12674fiber_scheduler_wait_for(
void * _arguments)
12684# define IOWAIT_SYSCALL "poll"
12685STATIC_ASSERT(pollin_expected, POLLIN == RB_WAITFD_IN);
12686STATIC_ASSERT(pollout_expected, POLLOUT == RB_WAITFD_OUT);
12691 if (scheduler !=
Qnil) {
12694 return RTEST(args.result);
12698 if (fd == -1)
return 0;
12703 fds.events = events;
12705 int timeout_milliseconds = -1;
12708 timeout_milliseconds = (int)(timeout->tv_sec * 1000) + (int)(timeout->tv_usec / 1000);
12711 return poll(&fds, 1, timeout_milliseconds);
12714# define IOWAIT_SYSCALL "select"
12719 if (scheduler !=
Qnil) {
12722 return RTEST(args.result);
12742 case RB_WAITFD_OUT:
12746 VM_UNREACHABLE(nogvl_wait_for);
12766 ret = nogvl_wait_for(stp->th, stp->src_fptr, RB_WAITFD_IN, NULL);
12768 }
while (ret < 0 && maygvl_copy_stream_continue_p(has_gvl, stp));
12771 stp->syserr = IOWAIT_SYSCALL;
12772 stp->error_no =
errno;
12784 ret = nogvl_wait_for(stp->th, stp->dst_fptr, RB_WAITFD_OUT, NULL);
12785 }
while (ret < 0 && maygvl_copy_stream_continue_p(0, stp));
12788 stp->syserr = IOWAIT_SYSCALL;
12789 stp->error_no =
errno;
12795#ifdef USE_COPY_FILE_RANGE
12798simple_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)
12800#ifdef HAVE_COPY_FILE_RANGE
12801 return copy_file_range(in_fd, in_offset, out_fd, out_offset, count, flags);
12803 return syscall(__NR_copy_file_range, in_fd, in_offset, out_fd, out_offset, count, flags);
12812 rb_off_t copy_length, src_offset, *src_offset_ptr;
12814 if (!S_ISREG(stp->src_stat.st_mode))
12817 src_size = stp->src_stat.st_size;
12818 src_offset = stp->src_offset;
12819 if (src_offset >= (rb_off_t)0) {
12820 src_offset_ptr = &src_offset;
12823 src_offset_ptr = NULL;
12826 copy_length = stp->copy_length;
12827 if (copy_length < (rb_off_t)0) {
12828 if (src_offset < (rb_off_t)0) {
12829 rb_off_t current_offset;
12831 current_offset = lseek(stp->src_fptr->
fd, 0, SEEK_CUR);
12832 if (current_offset < (rb_off_t)0 &&
errno) {
12833 stp->syserr =
"lseek";
12834 stp->error_no =
errno;
12835 return (
int)current_offset;
12837 copy_length = src_size - current_offset;
12840 copy_length = src_size - src_offset;
12844 retry_copy_file_range:
12845# if SIZEOF_OFF_T > SIZEOF_SIZE_T
12847 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
12849 ss = (ssize_t)copy_length;
12851 ss = simple_copy_file_range(stp->src_fptr->
fd, src_offset_ptr, stp->dst_fptr->
fd, NULL, ss, 0);
12855 if (0 < copy_length) {
12856 goto retry_copy_file_range;
12860 if (maygvl_copy_stream_continue_p(0, stp)) {
12861 goto retry_copy_file_range;
12875#if EWOULDBLOCK != EAGAIN
12879 int ret = nogvl_copy_stream_wait_write(stp);
12880 if (ret < 0)
return ret;
12882 goto retry_copy_file_range;
12886 int flags = fcntl(stp->dst_fptr->
fd, F_GETFL);
12888 if (flags != -1 && flags & O_APPEND) {
12894 stp->syserr =
"copy_file_range";
12895 stp->error_no =
errno;
12902#ifdef HAVE_FCOPYFILE
12906 rb_off_t cur, ss = 0;
12907 const rb_off_t src_offset = stp->src_offset;
12910 if (stp->copy_length >= (rb_off_t)0) {
12915 if (!S_ISREG(stp->src_stat.st_mode))
12918 if (!S_ISREG(stp->dst_stat.st_mode))
12920 if (lseek(stp->dst_fptr->
fd, 0, SEEK_CUR) > (rb_off_t)0)
12922 if (fcntl(stp->dst_fptr->
fd, F_GETFL) & O_APPEND) {
12925 rb_off_t end = lseek(stp->dst_fptr->
fd, 0, SEEK_END);
12926 lseek(stp->dst_fptr->
fd, 0, SEEK_SET);
12927 if (end > (rb_off_t)0)
return 0;
12930 if (src_offset > (rb_off_t)0) {
12935 cur = lseek(stp->src_fptr->
fd, 0, SEEK_CUR);
12936 if (cur < (rb_off_t)0 &&
errno) {
12937 stp->error_no =
errno;
12942 r = lseek(stp->src_fptr->
fd, src_offset, SEEK_SET);
12943 if (r < (rb_off_t)0 &&
errno) {
12944 stp->error_no =
errno;
12949 stp->copyfile_state = copyfile_state_alloc();
12950 ret = fcopyfile(stp->src_fptr->
fd, stp->dst_fptr->
fd, stp->copyfile_state, COPYFILE_DATA);
12951 copyfile_state_get(stp->copyfile_state, COPYFILE_STATE_COPIED, &ss);
12955 if (src_offset > (rb_off_t)0) {
12959 r = lseek(stp->src_fptr->
fd, cur, SEEK_SET);
12960 if (r < (rb_off_t)0 &&
errno) {
12961 stp->error_no =
errno;
12973 stp->syserr =
"fcopyfile";
12974 stp->error_no =
errno;
12981#ifdef HAVE_SENDFILE
12984# define USE_SENDFILE
12986# ifdef HAVE_SYS_SENDFILE_H
12987# include <sys/sendfile.h>
12991simple_sendfile(
int out_fd,
int in_fd, rb_off_t *offset, rb_off_t count)
12993 return sendfile(out_fd, in_fd, offset, (
size_t)count);
12996# elif 0 || defined(__APPLE__)
13000# define USE_SENDFILE
13003simple_sendfile(
int out_fd,
int in_fd, rb_off_t *offset, rb_off_t count)
13006 rb_off_t pos = offset ? *offset : lseek(in_fd, 0, SEEK_CUR);
13009 r = sendfile(in_fd, out_fd, pos, &count, NULL, 0);
13012 r = sendfile(in_fd, out_fd, pos, (
size_t)count, NULL, &sbytes, 0);
13014 if (r != 0 && sbytes == 0)
return r;
13019 lseek(in_fd, sbytes, SEEK_CUR);
13021 return (ssize_t)sbytes;
13034 rb_off_t copy_length;
13035 rb_off_t src_offset;
13038 if (!S_ISREG(stp->src_stat.st_mode))
13041 src_size = stp->src_stat.st_size;
13043 if ((stp->dst_stat.st_mode & S_IFMT) != S_IFSOCK)
13047 src_offset = stp->src_offset;
13048 use_pread = src_offset >= (rb_off_t)0;
13050 copy_length = stp->copy_length;
13051 if (copy_length < (rb_off_t)0) {
13053 copy_length = src_size - src_offset;
13057 cur = lseek(stp->src_fptr->
fd, 0, SEEK_CUR);
13058 if (cur < (rb_off_t)0 &&
errno) {
13059 stp->syserr =
"lseek";
13060 stp->error_no =
errno;
13063 copy_length = src_size - cur;
13068# if SIZEOF_OFF_T > SIZEOF_SIZE_T
13070 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
13072 ss = (ssize_t)copy_length;
13075 ss = simple_sendfile(stp->dst_fptr->
fd, stp->src_fptr->
fd, &src_offset, ss);
13078 ss = simple_sendfile(stp->dst_fptr->
fd, stp->src_fptr->
fd, NULL, ss);
13083 if (0 < copy_length) {
13084 goto retry_sendfile;
13088 if (maygvl_copy_stream_continue_p(0, stp))
13089 goto retry_sendfile;
13102#if EWOULDBLOCK != EAGAIN
13115 ret = maygvl_copy_stream_wait_read(0, stp);
13116 if (ret < 0)
return ret;
13118 ret = nogvl_copy_stream_wait_write(stp);
13119 if (ret < 0)
return ret;
13121 goto retry_sendfile;
13123 stp->syserr =
"sendfile";
13124 stp->error_no =
errno;
13132maygvl_read(
int has_gvl,
rb_io_t *fptr,
void *buf,
size_t count)
13135 return rb_io_read_memory(fptr, buf, count);
13137 return read(fptr->
fd, buf, count);
13141maygvl_copy_stream_read(
int has_gvl,
struct copy_stream_struct *stp,
char *buf,
size_t len, rb_off_t offset)
13145 if (offset < (rb_off_t)0) {
13146 ss = maygvl_read(has_gvl, stp->src_fptr, buf,
len);
13149 ss = pread(stp->src_fptr->
fd, buf,
len, offset);
13155 if (maygvl_copy_stream_continue_p(has_gvl, stp))
13159#if EWOULDBLOCK != EAGAIN
13163 int ret = maygvl_copy_stream_wait_read(has_gvl, stp);
13164 if (ret < 0)
return ret;
13169 stp->notimp =
"pread";
13173 stp->syserr = offset < (rb_off_t)0 ?
"read" :
"pread";
13174 stp->error_no =
errno;
13185 ss = write(stp->dst_fptr->
fd, buf+
off,
len);
13187 if (maygvl_copy_stream_continue_p(0, stp))
13189 if (io_again_p(
errno)) {
13190 int ret = nogvl_copy_stream_wait_write(stp);
13191 if (ret < 0)
return ret;
13194 stp->syserr =
"write";
13195 stp->error_no =
errno;
13212 rb_off_t copy_length;
13213 rb_off_t src_offset;
13217 copy_length = stp->copy_length;
13218 use_eof = copy_length < (rb_off_t)0;
13219 src_offset = stp->src_offset;
13220 use_pread = src_offset >= (rb_off_t)0;
13222 if (use_pread && stp->close_src) {
13225 r = lseek(stp->src_fptr->
fd, src_offset, SEEK_SET);
13226 if (r < (rb_off_t)0 &&
errno) {
13227 stp->syserr =
"lseek";
13228 stp->error_no =
errno;
13231 src_offset = (rb_off_t)-1;
13235 while (use_eof || 0 < copy_length) {
13236 if (!use_eof && copy_length < (rb_off_t)
sizeof(buf)) {
13237 len = (size_t)copy_length;
13243 ss = maygvl_copy_stream_read(0, stp, buf,
len, src_offset);
13248 ss = maygvl_copy_stream_read(0, stp, buf,
len, (rb_off_t)-1);
13253 ret = nogvl_copy_stream_write(stp, buf, ss);
13263nogvl_copy_stream_func(
void *arg)
13266#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13270#ifdef USE_COPY_FILE_RANGE
13271 ret = nogvl_copy_file_range(stp);
13276#ifdef HAVE_FCOPYFILE
13277 ret = nogvl_fcopyfile(stp);
13283 ret = nogvl_copy_stream_sendfile(stp);
13288 nogvl_copy_stream_read_write(stp);
13290#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13297copy_stream_fallback_body(
VALUE arg)
13300 const int buflen = 16*1024;
13303 rb_off_t rest = stp->copy_length;
13304 rb_off_t
off = stp->src_offset;
13305 ID read_method = id_readpartial;
13307 if (!stp->src_fptr) {
13309 read_method = id_read;
13316 rb_str_make_independent(buf);
13317 if (stp->copy_length < (rb_off_t)0) {
13322 rb_str_resize(buf, 0);
13325 l = buflen < rest ? buflen : (long)rest;
13327 if (!stp->src_fptr) {
13330 if (read_method == id_read &&
NIL_P(rc))
13335 rb_str_resize(buf, buflen);
13336 ss = maygvl_copy_stream_read(1, stp, RSTRING_PTR(buf), l,
off);
13337 rb_str_resize(buf, ss > 0 ? ss : 0);
13342 if (
off >= (rb_off_t)0)
13345 n = rb_io_write(stp->dst, buf);
13347 stp->total += numwrote;
13349 if (read_method == id_read && RSTRING_LEN(buf) == 0) {
13360 if (!stp->src_fptr && stp->src_offset >= (rb_off_t)0) {
13361 rb_raise(rb_eArgError,
"cannot specify src_offset for non-IO");
13370copy_stream_body(
VALUE arg)
13373 VALUE src_io = stp->src, dst_io = stp->dst;
13374 const int common_oflags = 0
13384 if (src_io ==
argf ||
13388 stp->src_fptr = NULL;
13393 if (!
NIL_P(tmp_io)) {
13400 args[1] =
INT2NUM(O_RDONLY|common_oflags);
13403 stp->close_src = 1;
13408 stat_ret = fstat(stp->src_fptr->
fd, &stp->src_stat);
13409 if (stat_ret < 0) {
13410 stp->syserr =
"fstat";
13411 stp->error_no =
errno;
13416 if (dst_io ==
argf ||
13420 stp->dst_fptr = NULL;
13425 if (!
NIL_P(tmp_io)) {
13426 dst_io = GetWriteIO(tmp_io);
13432 args[1] =
INT2NUM(O_WRONLY|O_CREAT|O_TRUNC|common_oflags);
13436 stp->close_dst = 1;
13439 dst_io = GetWriteIO(dst_io);
13445 stat_ret = fstat(stp->dst_fptr->
fd, &stp->dst_stat);
13446 if (stat_ret < 0) {
13447 stp->syserr =
"fstat";
13448 stp->error_no =
errno;
13455 SET_BINARY_MODE_WITH_SEEK_CUR(stp->src_fptr);
13458 io_ascii8bit_binmode(stp->dst_fptr);
13460 if (stp->src_offset < (rb_off_t)0 && stp->src_fptr && stp->src_fptr->
rbuf.
len) {
13463 if (stp->copy_length >= (rb_off_t)0 && stp->copy_length < (rb_off_t)
len) {
13464 len = (size_t)stp->copy_length;
13467 rb_str_resize(str,
len);
13468 read_buffered_data(RSTRING_PTR(str),
len, stp->src_fptr);
13469 if (stp->dst_fptr) {
13470 if (io_binwrite(RSTRING_PTR(str), RSTRING_LEN(str), stp->dst_fptr, 0) < 0)
13471 rb_sys_fail_on_write(stp->dst_fptr);
13474 rb_io_write(dst_io, str);
13475 rb_str_resize(str, 0);
13477 if (stp->copy_length >= (rb_off_t)0)
13478 stp->copy_length -=
len;
13481 if (stp->dst_fptr && io_fflush(stp->dst_fptr) < 0) {
13485 if (stp->copy_length == 0)
13488 if (stp->src_fptr == NULL || stp->dst_fptr == NULL) {
13489 return copy_stream_fallback(stp);
13492 IO_WITHOUT_GVL(nogvl_copy_stream_func, stp);
13497copy_stream_finalize(
VALUE arg)
13501#ifdef HAVE_FCOPYFILE
13502 if (stp->copyfile_state) {
13503 copyfile_state_free(stp->copyfile_state);
13507 if (stp->close_src) {
13508 rb_io_close_m(stp->src);
13510 if (stp->close_dst) {
13511 rb_io_close_m(stp->dst);
13574rb_io_s_copy_stream(
int argc,
VALUE *argv,
VALUE io)
13576 VALUE src, dst, length, src_offset;
13581 rb_scan_args(argc, argv,
"22", &src, &dst, &length, &src_offset);
13586 st.src_fptr = NULL;
13587 st.dst_fptr = NULL;
13590 st.copy_length = (rb_off_t)-1;
13592 st.copy_length =
NUM2OFFT(length);
13594 if (
NIL_P(src_offset))
13595 st.src_offset = (rb_off_t)-1;
13597 st.src_offset =
NUM2OFFT(src_offset);
13616rb_io_external_encoding(
VALUE io)
13621 return rb_enc_from_encoding(fptr->
encs.
enc2);
13625 return rb_enc_from_encoding(fptr->
encs.
enc);
13628 return rb_enc_from_encoding(io_read_encoding(fptr));
13644rb_io_internal_encoding(
VALUE io)
13649 return rb_enc_from_encoding(io_read_encoding(fptr));
13683rb_io_set_encoding(
int argc,
VALUE *argv,
VALUE io)
13689 return forward(io, id_set_encoding, argc, argv);
13692 argc =
rb_scan_args(argc, argv,
"11:", &v1, &v2, &opt);
13694 io_encoding_set(fptr, v1, v2, opt);
13699rb_stdio_set_default_encoding(
void)
13704 if (isatty(fileno(stdin))) {
13706 rb_encoding *internal = rb_default_internal_encoding();
13707 if (!internal) internal = rb_default_external_encoding();
13709 rb_enc_from_encoding(external),
13710 rb_enc_from_encoding(internal),
13715 rb_io_set_encoding(1, &val,
rb_stdin);
13716 rb_io_set_encoding(1, &val,
rb_stdout);
13717 rb_io_set_encoding(1, &val,
rb_stderr);
13721global_argf_p(
VALUE arg)
13723 return arg ==
argf;
13726typedef VALUE (*argf_encoding_func)(
VALUE io);
13729argf_encoding(
VALUE argf, argf_encoding_func func)
13731 if (!
RTEST(ARGF.current_file)) {
13732 return rb_enc_default_external();
13756 return argf_encoding(
argf, rb_io_external_encoding);
13775 return argf_encoding(
argf, rb_io_internal_encoding);
13814 if (!next_argv()) {
13815 rb_raise(rb_eArgError,
"no stream to set encoding");
13817 rb_io_set_encoding(argc, argv, ARGF.current_file);
13819 ARGF.encs = fptr->
encs;
13839 if (!next_argv()) {
13840 rb_raise(rb_eArgError,
"no stream to tell");
13842 ARGF_FORWARD(0, 0);
13843 return rb_io_tell(ARGF.current_file);
13856 if (!next_argv()) {
13857 rb_raise(rb_eArgError,
"no stream to seek");
13859 ARGF_FORWARD(argc, argv);
13860 return rb_io_seek_m(argc, argv, ARGF.current_file);
13877 if (!next_argv()) {
13878 rb_raise(rb_eArgError,
"no stream to set position");
13880 ARGF_FORWARD(1, &offset);
13881 return rb_io_set_pos(ARGF.current_file, offset);
13902 if (!next_argv()) {
13903 rb_raise(rb_eArgError,
"no stream to rewind");
13905 ARGF_FORWARD(0, 0);
13906 old_lineno =
RFILE(ARGF.current_file)->fptr->lineno;
13907 ret = rb_io_rewind(ARGF.current_file);
13908 if (!global_argf_p(
argf)) {
13909 ARGF.last_lineno = ARGF.lineno -= old_lineno;
13927 if (!next_argv()) {
13928 rb_raise(rb_eArgError,
"no stream");
13930 ARGF_FORWARD(0, 0);
13931 return rb_io_fileno(ARGF.current_file);
13950 ARGF_FORWARD(0, 0);
13951 return ARGF.current_file;
13976 if (
RTEST(ARGF.current_file)) {
13977 if (ARGF.init_p == 0)
return Qtrue;
13979 ARGF_FORWARD(0, 0);
14038 VALUE tmp, str, length;
14042 if (!
NIL_P(length)) {
14047 rb_str_resize(str,0);
14052 if (!next_argv()) {
14055 if (ARGF_GENERIC_INPUT_P()) {
14056 tmp = argf_forward(argc, argv,
argf);
14059 tmp = io_read(argc, argv, ARGF.current_file);
14061 if (
NIL_P(str)) str = tmp;
14064 if (ARGF.next_p != -1) {
14070 else if (argc >= 1) {
14071 long slen = RSTRING_LEN(str);
14087argf_forward_call(
VALUE arg)
14090 argf_forward(p->argc, p->argv, p->argf);
14120 return argf_getpartial(argc, argv,
argf,
Qnil, 0);
14141 return argf_getpartial(argc, argv,
argf, opts, 1);
14147 VALUE tmp, str, length;
14155 no_exception = no_exception_p(opts);
14157 if (!next_argv()) {
14159 rb_str_resize(str, 0);
14163 if (ARGF_GENERIC_INPUT_P()) {
14173 tmp = io_getpartial(argc, argv, ARGF.current_file, no_exception, nonblock);
14176 if (ARGF.next_p == -1) {
14177 return io_nonblock_eof(no_exception);
14182 return io_nonblock_eof(no_exception);
14220 if (!next_argv())
return Qnil;
14221 if (ARGF_GENERIC_INPUT_P()) {
14222 ch = forward_current(rb_intern(
"getc"), 0, 0);
14225 ch = rb_io_getc(ARGF.current_file);
14227 if (
NIL_P(ch) && ARGF.next_p != -1) {
14260 if (!next_argv())
return Qnil;
14262 ch = forward_current(rb_intern(
"getbyte"), 0, 0);
14267 if (
NIL_P(ch) && ARGF.next_p != -1) {
14300 if (!next_argv()) rb_eof_error();
14302 ch = forward_current(rb_intern(
"getc"), 0, 0);
14305 ch = rb_io_getc(ARGF.current_file);
14307 if (
NIL_P(ch) && ARGF.next_p != -1) {
14339 NEXT_ARGF_FORWARD(0, 0);
14340 c = argf_getbyte(
argf);
14347#define FOREACH_ARGF() while (next_argv())
14352 const VALUE current = ARGF.current_file;
14354 if (ARGF.init_p == -1 || current != ARGF.current_file) {
14360#define ARGF_block_call(mid, argc, argv, func, argf) \
14361 rb_block_call_kw(ARGF.current_file, mid, argc, argv, \
14362 func, argf, rb_keyword_given_p())
14367 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_i,
argf);
14368 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14374 if (!global_argf_p(
argf)) {
14375 ARGF.last_lineno = ++ARGF.lineno;
14377 return argf_block_call_i(i,
argf, argc, argv, blockarg);
14383 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_line_i,
argf);
14384 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14432 argf_block_call_line(rb_intern(
"each_line"), argc, argv,
argf);
14463 argf_block_call(rb_intern(
"each_byte"), 0, 0,
argf);
14489 argf_block_call(rb_intern(
"each_char"), 0, 0,
argf);
14515 argf_block_call(rb_intern(
"each_codepoint"), 0, 0,
argf);
14546 return ARGF.filename;
14550argf_filename_getter(
ID id,
VALUE *var)
14552 return argf_filename(*var);
14577 return ARGF.current_file;
14596 ARGF_FORWARD(0, 0);
14617 return RBOOL(ARGF.binmode);
14637 if (ARGF.init_p && ARGF.next_p == 0) {
14666 if (ARGF.next_p != -1) {
14684 ARGF_FORWARD(0, 0);
14711 if (!ARGF.inplace)
return Qnil;
14719 return argf_inplace_mode_get(*var);
14750 ARGF.inplace =
Qnil;
14761 argf_inplace_mode_set(*var, val);
14765ruby_set_inplace_mode(
const char *suffix)
14791argf_argv_getter(
ID id,
VALUE *var)
14793 return argf_argv(*var);
14812 if (!
RTEST(ARGF.current_file)) {
14815 return GetWriteIO(ARGF.current_file);
14827 return rb_io_writev(argf_write_io(
argf), argc, argv);
14842 case RB_IO_WAIT_WRITABLE:
14845 c = rb_eEAGAINWaitWritable;
14847#if EAGAIN != EWOULDBLOCK
14849 c = rb_eEWOULDBLOCKWaitWritable;
14853 c = rb_eEINPROGRESSWaitWritable;
14859 case RB_IO_WAIT_READABLE:
14862 c = rb_eEAGAINWaitReadable;
14864#if EAGAIN != EWOULDBLOCK
14866 c = rb_eEWOULDBLOCKWaitReadable;
14870 c = rb_eEINPROGRESSWaitReadable;
14877 rb_bug(
"invalid read/write type passed to rb_readwrite_sys_fail: %d", waiting);
14883get_LAST_READ_LINE(
ID _x,
VALUE *_y)
15773#include <sys/cygwin.h>
15774 static struct __cygwin_perfile pf[] =
15776 {
"", O_RDONLY | O_BINARY},
15777 {
"", O_WRONLY | O_BINARY},
15778 {
"", O_RDWR | O_BINARY},
15779 {
"", O_APPEND | O_BINARY},
15782 cygwin_internal(CW_PERFILE, pf);
15831 rb_eEAGAINWaitReadable = rb_define_class_under(
rb_cIO,
"EAGAINWaitReadable", rb_eEAGAIN);
15834 rb_eEAGAINWaitWritable = rb_define_class_under(
rb_cIO,
"EAGAINWaitWritable", rb_eEAGAIN);
15836#if EAGAIN == EWOULDBLOCK
15838 rb_define_const(
rb_cIO,
"EWOULDBLOCKWaitReadable", rb_eEAGAINWaitReadable);
15840 rb_define_const(
rb_cIO,
"EWOULDBLOCKWaitWritable", rb_eEAGAINWaitWritable);
15843 rb_eEWOULDBLOCKWaitReadable = rb_define_class_under(
rb_cIO,
"EWOULDBLOCKWaitReadable", rb_eEWOULDBLOCK);
15846 rb_eEWOULDBLOCKWaitWritable = rb_define_class_under(
rb_cIO,
"EWOULDBLOCKWaitWritable", rb_eEWOULDBLOCK);
15850 rb_eEINPROGRESSWaitReadable = rb_define_class_under(
rb_cIO,
"EINPROGRESSWaitReadable", rb_eEINPROGRESS);
15853 rb_eEINPROGRESSWaitWritable = rb_define_class_under(
rb_cIO,
"EINPROGRESSWaitWritable", rb_eEINPROGRESS);
15888 rb_gvar_ractor_local(
"$/");
15890 rb_gvar_ractor_local(
"$-0");
15894 rb_gvar_ractor_local(
"$_");
15895 rb_gvar_box_dynamic(
"$_");
16011 rb_gvar_ractor_local(
"$stdin");
16012 rb_gvar_ractor_local(
"$stdout");
16013 rb_gvar_ractor_local(
"$>");
16014 rb_gvar_ractor_local(
"$stderr");
16016 rb_gvar_box_dynamic(
"$stdin");
16017 rb_gvar_box_dynamic(
"$stdout");
16018 rb_gvar_box_dynamic(
"$>");
16019 rb_gvar_box_dynamic(
"$stderr");
16040 rb_cARGF = rb_define_class(
"ARGF",
rb_cObject);
16105 rb_define_method(rb_cARGF,
"external_encoding", argf_external_encoding, 0);
16106 rb_define_method(rb_cARGF,
"internal_encoding", argf_internal_encoding, 0);
16125 rb_gvar_ractor_local(
"$-i");
16129#if defined (_WIN32) || defined(__CYGWIN__)
16130 atexit(pipe_atexit);
16142 sym_encoding =
ID2SYM(rb_id_encoding());
16166static void init_builtin_io(
void);
16167#define Init_builtin_io init_builtin_io
16169#undef Init_builtin_io
16172Init_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 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.
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.