14#include "ruby/internal/config.h"
25# if defined(__linux__)
28# if defined(__FreeBSD_version) && __FreeBSD_version >= 1100000
38#define free(x) xfree(x)
40#if defined(DOSISH) || defined(__CYGWIN__)
45#if defined HAVE_NET_SOCKET_H
46# include <net/socket.h>
47#elif defined HAVE_SYS_SOCKET_H
48# include <sys/socket.h>
51#if defined(__BOW__) || defined(__CYGWIN__) || defined(_WIN32)
52# define NO_SAFE_RENAME
55#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__sun) || defined(_nec_ews)
64#if defined(HAVE_SYS_IOCTL_H) && !defined(_WIN32)
67#if defined(HAVE_FCNTL_H) || defined(_WIN32)
69#elif defined(HAVE_SYS_FCNTL_H)
79#if defined(HAVE_SYS_PARAM_H) || defined(__HIUX_MPP__)
80# include <sys/param.h>
93#elif defined HAVE_SYS_SYSCALL_H
94#include <sys/syscall.h>
101#ifdef HAVE_SYS_WAIT_H
102# include <sys/wait.h>
105#ifdef HAVE_COPYFILE_H
106# include <copyfile.h>
108# ifndef COPYFILE_STATE_COPIED
114# undef HAVE_FCOPYFILE
120#include "ccan/list/list.h"
125#include "internal/class.h"
126#include "internal/encoding.h"
127#include "internal/error.h"
128#include "internal/inits.h"
129#include "internal/io.h"
130#include "internal/numeric.h"
131#include "internal/object.h"
132#include "internal/process.h"
133#include "internal/thread.h"
134#include "internal/transcode.h"
135#include "internal/variable.h"
138#include "ruby/missing.h"
141#include "ruby_atomic.h"
151#define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR)
155# ifdef _POSIX_PIPE_BUF
156# define PIPE_BUF _POSIX_PIPE_BUF
163# define EWOULDBLOCK EAGAIN
166#if defined(HAVE___SYSCALL) && (defined(__APPLE__) || defined(__OpenBSD__))
168off_t __syscall(quad_t number, ...);
171#define IO_RBUF_CAPA_MIN 8192
172#define IO_CBUF_CAPA_MIN (128*1024)
173#define IO_RBUF_CAPA_FOR(fptr) (NEED_READCONV(fptr) ? IO_CBUF_CAPA_MIN : IO_RBUF_CAPA_MIN)
174#define IO_WBUF_CAPA_MIN 8192
176#define IO_MAX_BUFFER_GROWTH 8 * 1024 * 1024
181#define open rb_w32_uopen
183#define rename(f, t) rb_w32_urename((f), (t))
184#include "win32/file.h"
194static VALUE rb_eEAGAINWaitReadable;
195static VALUE rb_eEAGAINWaitWritable;
196static VALUE rb_eEWOULDBLOCKWaitReadable;
197static VALUE rb_eEWOULDBLOCKWaitWritable;
198static VALUE rb_eEINPROGRESSWaitWritable;
199static VALUE rb_eEINPROGRESSWaitReadable;
202static VALUE orig_stdout, orig_stderr;
211static ID id_write, id_read, id_getc, id_flush, id_readpartial, id_set_encoding, id_fileno;
212static VALUE sym_mode, sym_perm, sym_flags, sym_extenc, sym_intenc, sym_encoding, sym_open_args;
213static VALUE sym_textmode, sym_binmode, sym_autoclose;
214static VALUE sym_SET, sym_CUR, sym_END;
215static VALUE sym_wait_readable, sym_wait_writable;
217static VALUE sym_DATA;
220static VALUE sym_HOLE;
223static VALUE prep_io(
int fd,
enum rb_io_mode fmode,
VALUE klass,
const char *path);
226rb_io_blocking_region_wait(
struct rb_io *io, rb_blocking_function_t *function,
void *argument,
enum rb_io_event events)
228 return rb_thread_io_blocking_call(io, function, argument, events);
231VALUE rb_io_blocking_region(
struct rb_io *io, rb_blocking_function_t *function,
void *argument)
233 return rb_io_blocking_region_wait(io, function, argument, 0);
237 VALUE filename, current_file;
243 int8_t init_p, next_p, binmode;
254 if (fd < 0 || afd <= max_fd)
257#if defined(HAVE_FCNTL) && defined(F_GETFL)
258 err = fcntl(fd, F_GETFL) == -1;
262 err = fstat(fd, &buf) != 0;
265 if (err &&
errno == EBADF) {
266 rb_bug(
"rb_update_max_fd: invalid fd (%d) given.", fd);
269 while (max_fd < afd) {
270 max_fd = ATOMIC_CAS(max_file_descriptor, max_fd, afd);
275rb_maygvl_fd_fix_cloexec(
int fd)
278#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
279 int flags, flags2, ret;
280 flags = fcntl(fd, F_GETFD);
282 rb_bug(
"rb_maygvl_fd_fix_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(
errno));
285 flags2 = flags & ~FD_CLOEXEC;
287 flags2 = flags | FD_CLOEXEC;
288 if (flags != flags2) {
289 ret = fcntl(fd, F_SETFD, flags2);
291 rb_bug(
"rb_maygvl_fd_fix_cloexec: fcntl(%d, F_SETFD, %d) failed: %s", fd, flags2, strerror(
errno));
300 rb_maygvl_fd_fix_cloexec(fd);
306rb_fix_detect_o_cloexec(
int fd)
308#if defined(O_CLOEXEC) && defined(F_GETFD)
309 int flags = fcntl(fd, F_GETFD);
312 rb_bug(
"rb_fix_detect_o_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(
errno));
314 if (flags & FD_CLOEXEC)
317 rb_maygvl_fd_fix_cloexec(fd);
324 return (e == EWOULDBLOCK) || (e == EAGAIN);
331 static int o_cloexec_state = -1;
333 static const int retry_interval = 0;
334 static const int retry_max_count = 10000;
341#elif defined O_NOINHERIT
342 flags |= O_NOINHERIT;
345 while ((ret = open(pathname, flags, mode)) == -1) {
347 if (!io_again_p(e))
break;
348 if (retry_count++ >= retry_max_count)
break;
350 sleep(retry_interval);
353 if (ret < 0)
return ret;
354 if (ret <= 2 || o_cloexec_state == 0) {
355 rb_maygvl_fd_fix_cloexec(ret);
357 else if (o_cloexec_state > 0) {
361 o_cloexec_state = rb_fix_detect_o_cloexec(ret);
380 if (oldfd == newfd) {
384#if defined(HAVE_DUP3) && defined(O_CLOEXEC)
385 static int try_dup3 = 1;
386 if (2 < newfd && try_dup3) {
387 ret = dup3(oldfd, newfd, O_CLOEXEC);
391 if (
errno == ENOSYS) {
393 ret = dup2(oldfd, newfd);
397 ret = dup2(oldfd, newfd);
400 ret = dup2(oldfd, newfd);
402 if (ret < 0)
return ret;
404 rb_maygvl_fd_fix_cloexec(ret);
409rb_fd_set_nonblock(
int fd)
412 return rb_w32_set_nonblock(fd);
413#elif defined(F_GETFL)
414 int oflags = fcntl(fd, F_GETFL);
418 if (oflags & O_NONBLOCK)
420 oflags |= O_NONBLOCK;
421 return fcntl(fd, F_SETFL, oflags);
430 int result = pipe2(descriptors, O_CLOEXEC | O_NONBLOCK);
432 int result = pipe(descriptors);
439 if (result == 0 && descriptors[1] == -1) {
440 close(descriptors[0]);
448 rb_maygvl_fd_fix_cloexec(descriptors[0]);
449 rb_maygvl_fd_fix_cloexec(descriptors[1]);
452 rb_fd_set_nonblock(descriptors[0]);
453 rb_fd_set_nonblock(descriptors[1]);
465#if defined(HAVE_FCNTL) && defined(F_DUPFD_CLOEXEC) && defined(F_DUPFD)
466 static int try_dupfd_cloexec = 1;
467 if (try_dupfd_cloexec) {
468 ret = fcntl(fd, F_DUPFD_CLOEXEC, minfd);
471 rb_maygvl_fd_fix_cloexec(ret);
475 if (
errno == EINVAL) {
476 ret = fcntl(fd, F_DUPFD, minfd);
478 try_dupfd_cloexec = 0;
483 ret = fcntl(fd, F_DUPFD, minfd);
485#elif defined(HAVE_FCNTL) && defined(F_DUPFD)
486 ret = fcntl(fd, F_DUPFD, minfd);
489 if (ret >= 0 && ret < minfd) {
490 const int prev_fd = ret;
496 if (ret < 0)
return ret;
497 rb_maygvl_fd_fix_cloexec(ret);
501#define argf_of(obj) (*(struct argf *)DATA_PTR(obj))
502#define ARGF argf_of(argf)
504#define GetWriteIO(io) rb_io_get_write_io(io)
506#define READ_DATA_PENDING(fptr) ((fptr)->rbuf.len)
507#define READ_DATA_PENDING_COUNT(fptr) ((fptr)->rbuf.len)
508#define READ_DATA_PENDING_PTR(fptr) ((fptr)->rbuf.ptr+(fptr)->rbuf.off)
509#define READ_DATA_BUFFERED(fptr) READ_DATA_PENDING(fptr)
511#define READ_CHAR_PENDING(fptr) ((fptr)->cbuf.len)
512#define READ_CHAR_PENDING_COUNT(fptr) ((fptr)->cbuf.len)
513#define READ_CHAR_PENDING_PTR(fptr) ((fptr)->cbuf.ptr+(fptr)->cbuf.off)
516#define WAIT_FD_IN_WIN32(fptr) \
517 (rb_w32_io_cancelable_p((fptr)->fd) ? Qnil : rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_READABLE), RUBY_IO_TIMEOUT_DEFAULT))
519#define WAIT_FD_IN_WIN32(fptr)
522#define READ_CHECK(fptr) do {\
523 if (!READ_DATA_PENDING(fptr)) {\
524 WAIT_FD_IN_WIN32(fptr);\
525 rb_io_check_closed(fptr);\
531# define S_ISSOCK(m) _S_ISSOCK(m)
534# define S_ISSOCK(m) (((m) & S_IFMT) == _S_IFSOCK)
537# define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
543static int io_fflush(
rb_io_t *);
544static rb_io_t *flush_before_seek(
rb_io_t *fptr,
bool discard_rbuf);
545static void clear_codeconv(
rb_io_t *fptr);
547#define FMODE_SIGNAL_ON_EPIPE (1<<17)
549#define fptr_signal_on_epipe(fptr) \
550 (((fptr)->mode & FMODE_SIGNAL_ON_EPIPE) != 0)
552#define fptr_set_signal_on_epipe(fptr, flag) \
554 (fptr)->mode |= FMODE_SIGNAL_ON_EPIPE : \
555 (fptr)->mode &= ~FMODE_SIGNAL_ON_EPIPE)
557extern ID ruby_static_id_signo;
559NORETURN(
static void rb_sys_fail_on_write(
rb_io_t *fptr));
561rb_sys_fail_on_write(
rb_io_t *fptr)
564 VALUE errinfo = rb_syserr_new_path(e, (fptr)->pathv);
566 if (fptr_signal_on_epipe(fptr) && (e == EPIPE)) {
578#define NEED_NEWLINE_DECORATOR_ON_READ(fptr) ((fptr)->mode & FMODE_TEXTMODE)
579#define NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) ((fptr)->mode & FMODE_TEXTMODE)
580#if defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32)
581# define RUBY_CRLF_ENVIRONMENT 1
583# define RUBY_CRLF_ENVIRONMENT 0
586#if RUBY_CRLF_ENVIRONMENT
588# define DEFAULT_TEXTMODE FMODE_TEXTMODE
589# define TEXTMODE_NEWLINE_DECORATOR_ON_WRITE ECONV_CRLF_NEWLINE_DECORATOR
597#define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || (fptr)->encs.ecflags & ~ECONV_CRLF_NEWLINE_DECORATOR)
598#define WRITECONV_MASK ( \
599 (ECONV_DECORATOR_MASK & ~ECONV_CRLF_NEWLINE_DECORATOR)|\
600 ECONV_STATEFUL_DECORATOR_MASK|\
602#define NEED_WRITECONV(fptr) ( \
603 ((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || \
604 ((fptr)->encs.ecflags & WRITECONV_MASK) || \
606#define SET_BINARY_MODE(fptr) setmode((fptr)->fd, O_BINARY)
608#define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) do {\
609 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {\
610 if (((fptr)->mode & FMODE_READABLE) &&\
611 !((fptr)->encs.ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {\
612 setmode((fptr)->fd, O_BINARY);\
615 setmode((fptr)->fd, O_TEXT);\
620#define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) do {\
621 if ((enc2) && ((ecflags) & ECONV_DEFAULT_NEWLINE_DECORATOR)) {\
622 (ecflags) |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;\
630io_unread(
rb_io_t *fptr,
bool discard_rbuf)
646 if (!rb_w32_fd_is_text(fptr->
fd)) {
647 r = lseek(fptr->
fd, -fptr->
rbuf.
len, SEEK_CUR);
648 if (r < 0 &&
errno) {
651 if (!discard_rbuf)
return;
657 pos = lseek(fptr->
fd, 0, SEEK_CUR);
658 if (pos < 0 &&
errno) {
661 if (!discard_rbuf)
goto end;
665 extra_max = (long)(pos - fptr->
rbuf.
len);
673 for (i = 0; i < fptr->
rbuf.
len; i++) {
674 if (*p ==
'\n') newlines++;
675 if (extra_max == newlines)
break;
680 while (newlines >= 0) {
681 r = lseek(fptr->
fd, pos - fptr->
rbuf.
len - newlines, SEEK_SET);
682 if (newlines == 0)
break;
687 read_size = _read(fptr->
fd, buf, fptr->
rbuf.
len + newlines);
691 rb_syserr_fail_path(e, fptr->
pathv);
693 if (read_size == fptr->
rbuf.
len) {
694 lseek(fptr->
fd, r, SEEK_SET);
705 clear_codeconv(fptr);
717set_binary_mode_with_seek_cur(
rb_io_t *fptr)
719 if (!rb_w32_fd_is_text(fptr->
fd))
return O_BINARY;
722 return setmode(fptr->
fd, O_BINARY);
724 flush_before_seek(fptr,
false);
725 return setmode(fptr->
fd, O_BINARY);
727#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) set_binary_mode_with_seek_cur(fptr)
731# define DEFAULT_TEXTMODE 0
732#define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || NEED_NEWLINE_DECORATOR_ON_READ(fptr))
733#define NEED_WRITECONV(fptr) ( \
734 ((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || \
735 NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) || \
736 ((fptr)->encs.ecflags & (ECONV_DECORATOR_MASK|ECONV_STATEFUL_DECORATOR_MASK)) || \
738#define SET_BINARY_MODE(fptr) (void)(fptr)
739#define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) (void)(fptr)
740#define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) ((void)(enc2), (void)(ecflags))
741#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) (void)(fptr)
744#if !defined HAVE_SHUTDOWN && !defined shutdown
745#define shutdown(a,b) 0
749#define is_socket(fd, path) rb_w32_is_socket(fd)
750#elif !defined(S_ISSOCK)
751#define is_socket(fd, path) 0
754is_socket(
int fd,
VALUE path)
757 if (fstat(fd, &sbuf) < 0)
758 rb_sys_fail_path(path);
759 return S_ISSOCK(sbuf.st_mode);
763static const char closed_stream[] =
"closed stream";
766io_fd_check_closed(
int fd)
799 io_fd_check_closed(fptr->
fd);
803rb_io_get_fptr(
VALUE io)
813 return rb_convert_type_with_id(io,
T_FILE,
"IO", idTo_io);
819 return rb_check_convert_type_with_id(io,
T_FILE,
"IO", idTo_io);
837 rb_io_t *fptr = rb_io_get_fptr(io);
846 return write_io ? write_io :
Qnil;
859 rb_io_t *fptr = rb_io_get_fptr(self);
889 if (
RTEST(timeout)) {
893 rb_io_t *fptr = rb_io_get_fptr(self);
918#if !RUBY_CRLF_ENVIRONMENT
920io_unread(
rb_io_t *fptr,
bool discard_rbuf)
928 r = lseek(fptr->
fd, -fptr->
rbuf.
len, SEEK_CUR);
929 if (r < 0 &&
errno) {
932 if (!discard_rbuf)
return;
936 clear_codeconv(fptr);
946 long len = RSTRING_LEN(str);
949 const int min_capa = IO_RBUF_CAPA_FOR(fptr);
952#if SIZEOF_LONG > SIZEOF_INT
977flush_before_seek(
rb_io_t *fptr,
bool discard_rbuf)
979 if (io_fflush(fptr) < 0)
980 rb_sys_fail_on_write(fptr);
981 io_unread(fptr, discard_rbuf);
986#define io_seek(fptr, ofs, whence) (errno = 0, lseek(flush_before_seek(fptr, true)->fd, (ofs), (whence)))
987#define io_tell(fptr) lseek(flush_before_seek(fptr, false)->fd, 0, SEEK_CUR)
1003 if (io_fflush(fptr) < 0)
1004 rb_sys_fail_on_write(fptr);
1009 if (io_fflush(wfptr) < 0)
1010 rb_sys_fail_on_write(wfptr);
1018 if (READ_CHAR_PENDING(fptr)) {
1019 rb_raise(
rb_eIOError,
"byte oriented read for character buffered IO");
1030io_read_encoding(
rb_io_t *fptr)
1035 return rb_default_external_encoding();
1039io_input_encoding(
rb_io_t *fptr)
1044 return io_read_encoding(fptr);
1055 io_unread(fptr,
true);
1060rb_io_read_pending(
rb_io_t *fptr)
1063 if (READ_CHAR_PENDING(fptr))
1065 return READ_DATA_PENDING(fptr);
1071 if (!READ_DATA_PENDING(fptr)) {
1078rb_gc_for_fd(
int err)
1080 if (err == EMFILE || err == ENFILE || err == ENOMEM) {
1090#define TRY_WITH_GC(expr) \
1091 for (int first_errno, retried_errno = 0, retried = 0; \
1094 (!rb_gc_for_fd(first_errno = errno) || !(expr)) && \
1095 (retried_errno = errno, 1)); \
1096 (void)retried_errno, retried = 1)
1111io_alloc(
VALUE klass)
1121# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
1147struct io_internal_writev_struct {
1154 const struct iovec *iov;
1167io_internal_wait(
VALUE thread,
rb_io_t *fptr,
int error,
int events,
struct timeval *timeout)
1169 if (!timeout && rb_thread_mn_schedulable(thread)) {
1174 int ready = nogvl_wait_for(thread, fptr, events, timeout);
1179 else if (ready == 0) {
1196internal_read_func(
void *ptr)
1201 if (iis->timeout && !iis->nonblock) {
1202 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_IN, iis->timeout) == -1) {
1208 result = read(iis->fd, iis->buf, iis->capa);
1210 if (result < 0 && !iis->nonblock) {
1211 if (io_again_p(
errno)) {
1212 if (io_internal_wait(iis->th, iis->fptr,
errno, RB_WAITFD_IN, iis->timeout) == -1) {
1224#if defined __APPLE__
1225# define do_write_retry(code) do {result = code;} while (result == -1 && errno == EPROTOTYPE)
1227# define do_write_retry(code) result = code
1231internal_write_func(
void *ptr)
1236 if (iis->timeout && !iis->nonblock) {
1237 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1243 do_write_retry(write(iis->fd, iis->buf, iis->capa));
1245 if (result < 0 && !iis->nonblock) {
1247 if (io_again_p(e)) {
1248 if (io_internal_wait(iis->th, iis->fptr,
errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1262internal_writev_func(
void *ptr)
1264 struct io_internal_writev_struct *iis = ptr;
1267 if (iis->timeout && !iis->nonblock) {
1268 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1274 do_write_retry(writev(iis->fd, iis->iov, iis->iovcnt));
1276 if (result < 0 && !iis->nonblock) {
1277 if (io_again_p(
errno)) {
1278 if (io_internal_wait(iis->th, iis->fptr,
errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1292rb_io_read_memory(
rb_io_t *fptr,
void *buf,
size_t count)
1295 if (scheduler !=
Qnil) {
1298 if (!UNDEF_P(result)) {
1314 struct timeval timeout_storage;
1318 iis.timeout = &timeout_storage;
1321 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_read_func, &iis,
RUBY_IO_READABLE);
1325rb_io_write_memory(
rb_io_t *fptr,
const void *buf,
size_t count)
1328 if (scheduler !=
Qnil) {
1331 if (!UNDEF_P(result)) {
1347 struct timeval timeout_storage;
1351 iis.timeout = &timeout_storage;
1354 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_write_func, &iis,
RUBY_IO_WRITABLE);
1359rb_writev_internal(
rb_io_t *fptr,
const struct iovec *iov,
int iovcnt)
1361 if (!iovcnt)
return 0;
1364 if (scheduler !=
Qnil) {
1368 if (!UNDEF_P(result)) {
1373 struct io_internal_writev_struct iis = {
1384 struct timeval timeout_storage;
1388 iis.timeout = &timeout_storage;
1391 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_writev_func, &iis,
RUBY_IO_WRITABLE);
1396io_flush_buffer_sync(
void *arg)
1418io_flush_buffer_async(
VALUE arg)
1421 return rb_io_blocking_region_wait(fptr, io_flush_buffer_sync, fptr,
RUBY_IO_WRITABLE);
1428 return (
int)io_flush_buffer_async((
VALUE)fptr);
1443 while (fptr->
wbuf.
len > 0 && io_flush_buffer(fptr) != 0) {
1458 if (scheduler !=
Qnil) {
1468 if (NIL_OR_UNDEF_P(timeout)) {
1472 if (timeout !=
Qnil) {
1477 int ready = rb_thread_io_wait(fptr,
RB_NUM2INT(events), tv);
1501io_wait_for_single_fd(
int fd,
int events,
struct timeval *timeout)
1505 if (scheduler !=
Qnil) {
1511 return rb_thread_wait_for_single_fd(fd, events, timeout);
1517 io_fd_check_closed(f);
1523#if defined(ERESTART)
1530#if EWOULDBLOCK != EAGAIN
1533 if (scheduler !=
Qnil) {
1551 io_fd_check_closed(f);
1557#if defined(ERESTART)
1573#if EWOULDBLOCK != EAGAIN
1576 if (scheduler !=
Qnil) {
1594 return io_wait_for_single_fd(fd, events, timeout);
1628#if defined(ERESTART)
1638#if EWOULDBLOCK != EAGAIN
1655 if (
RTEST(result)) {
1670 if (
RTEST(result)) {
1684 const char *senc, *denc;
1691 ecflags = fptr->
encs.
ecflags & ~ECONV_NEWLINE_DECORATOR_READ_MASK;
1718 denc = rb_enc_name(enc);
1750io_binwrite_string_internal(
rb_io_t *fptr,
const char *ptr,
long length)
1753 struct iovec iov[2];
1756 iov[0].iov_len = fptr->
wbuf.
len;
1757 iov[1].iov_base = (
void*)ptr;
1758 iov[1].iov_len = length;
1760 ssize_t result = rb_writev_internal(fptr, iov, 2);
1765 if (result >= fptr->
wbuf.
len) {
1773 fptr->
wbuf.
off += (int)result;
1774 fptr->
wbuf.
len -= (int)result;
1782 return rb_io_write_memory(fptr, ptr, length);
1787io_binwrite_string_internal(
rb_io_t *fptr,
const char *ptr,
long length)
1789 long remaining = length;
1792 if (fptr->
wbuf.
len+length <= fptr->wbuf.capa) {
1799 fptr->
wbuf.
len += (int)length;
1806 if (io_fflush(fptr) < 0) {
1811 if (remaining == 0) {
1817 return rb_io_write_memory(fptr, ptr, length);
1822io_binwrite_string(
VALUE arg)
1826 const char *ptr = p->ptr;
1827 size_t remaining = p->length;
1831 ssize_t result = io_binwrite_string_internal(p->fptr, ptr, remaining);
1837 else if (result > 0) {
1838 if ((
size_t)result == remaining)
break;
1840 remaining -= result;
1856io_allocate_write_buffer(
rb_io_t *fptr,
int sync)
1861 fptr->
wbuf.
capa = IO_WBUF_CAPA_MIN;
1872io_binwrite_requires_flush_write(
rb_io_t *fptr,
long len,
int nosync)
1887io_binwrite(
const char *ptr,
long len,
rb_io_t *fptr,
int nosync)
1889 if (
len <= 0)
return len;
1894 io_allocate_write_buffer(fptr, !nosync);
1896 if (io_binwrite_requires_flush_write(fptr,
len, nosync)) {
1907 return io_binwrite_string((
VALUE)&arg);
1924# define MODE_BTMODE(a,b,c) ((fmode & FMODE_BINMODE) ? (b) : \
1925 (fmode & FMODE_TEXTMODE) ? (c) : (a))
1927#define MODE_BTXMODE(a, b, c, d, e, f) ((fmode & FMODE_EXCL) ? \
1928 MODE_BTMODE(d, e, f) : \
1929 MODE_BTMODE(a, b, c))
1934 if (NEED_WRITECONV(fptr)) {
1936 SET_BINARY_MODE(fptr);
1938 make_writeconv(fptr);
1941#define fmode (fptr->mode)
1944 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1) && !rb_enc_asciicompat(rb_enc_get(str))) {
1945 rb_raise(rb_eArgError,
"ASCII incompatible string written for text mode IO without encoding conversion: %s",
1946 rb_enc_name(rb_enc_get(str)));
1952 common_encoding = rb_enc_from_encoding(fptr->
encs.
enc2);
1953 else if (fptr->
encs.
enc != rb_ascii8bit_encoding())
1954 common_encoding = rb_enc_from_encoding(fptr->
encs.
enc);
1957 if (!
NIL_P(common_encoding)) {
1968#if RUBY_CRLF_ENVIRONMENT
1969#define fmode (fptr->mode)
1970 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1)) {
1973 setmode(fptr->
fd, O_BINARY);
1976 setmode(fptr->
fd, O_TEXT);
1978 if (!rb_enc_asciicompat(rb_enc_get(str))) {
1979 rb_raise(rb_eArgError,
"ASCII incompatible string written for text mode IO without encoding conversion: %s",
1980 rb_enc_name(rb_enc_get(str)));
1998 long len = rb_w32_write_console(str, fptr->
fd);
2003 str = do_writeconv(str, fptr, &converted);
2007 tmp = rb_str_tmp_frozen_no_embed_acquire(str);
2009 n = io_binwrite(ptr,
len, fptr, nosync);
2010 rb_str_tmp_frozen_release(str, tmp);
2022 return (ssize_t)io_binwrite(buf, (
long)size, fptr, 0);
2032 io = GetWriteIO(io);
2042 if (RSTRING_LEN(str) == 0)
return INT2FIX(0);
2047 n = io_fwrite(str, fptr, nosync);
2048 if (n < 0L) rb_sys_fail_on_write(fptr);
2054struct binwritev_arg {
2062io_binwritev_internal(
VALUE arg)
2064 struct binwritev_arg *p = (
struct binwritev_arg *)arg;
2066 size_t remaining = p->total;
2070 struct iovec *iov = p->iov;
2071 int iovcnt = p->iovcnt;
2074 long result = rb_writev_internal(fptr, iov, iovcnt);
2079 if (offset < (
size_t)fptr->
wbuf.
len) {
2084 offset -= (size_t)fptr->
wbuf.
len;
2090 if (offset == p->total) {
2094 while (result >= (ssize_t)iov->iov_len) {
2096 result -= iov->iov_len;
2106 iov->iov_base = (
char *)iov->iov_base + result;
2107 iov->iov_len -= result;
2121io_binwritev(
struct iovec *iov,
int iovcnt,
rb_io_t *fptr)
2126 if (iovcnt == 0)
return 0;
2129 for (
int i = 1; i < iovcnt; i++) total += iov[i].iov_len;
2131 io_allocate_write_buffer(fptr, 1);
2137 if (offset + total <= (
size_t)fptr->
wbuf.
capa) {
2138 for (
int i = 1; i < iovcnt; i++) {
2139 memcpy(fptr->
wbuf.
ptr+offset, iov[i].iov_base, iov[i].iov_len);
2140 offset += iov[i].iov_len;
2149 iov[0].iov_len = fptr->
wbuf.
len;
2162 struct binwritev_arg arg;
2165 arg.iovcnt = iovcnt;
2172 return io_binwritev_internal((
VALUE)&arg);
2179 int i, converted, iovcnt = argc + 1;
2181 VALUE v1, v2, str, tmp, *tmp_array;
2187 for (i = 0; i < argc; i++) {
2190 str = do_writeconv(str, fptr, &converted);
2195 tmp = rb_str_tmp_frozen_acquire(str);
2199 iov[i+1].iov_base = RSTRING_PTR(tmp);
2200 iov[i+1].iov_len = RSTRING_LEN(tmp);
2203 n = io_binwritev(iov, iovcnt, fptr);
2206 for (i = 0; i < argc; i++) {
2207 rb_str_tmp_frozen_release(argv[i], tmp_array[i]);
2216iovcnt_ok(
int iovcnt)
2219 return iovcnt < IOV_MAX;
2227io_writev(
int argc,
const VALUE *argv,
VALUE io)
2234 io = GetWriteIO(io);
2239 return rb_funcallv(io, id_write, argc, argv);
2247 for (i = 0; i < argc; i += cnt) {
2250 n = io_fwritev(cnt, &argv[i], fptr);
2261 rb_sys_fail_on_write(fptr);
2263 total = rb_fix_plus(
LONG2FIX(n), total);
2294 return io_writev(argc, argv, io);
2297 VALUE str = argv[0];
2298 return io_write(io, str, 0);
2305 return rb_funcallv(io, id_write, 1, &str);
2309rb_io_writev(
VALUE io,
int argc,
const VALUE *argv)
2314 char sep = RCLASS_SINGLETON_P(klass) ? (klass = io,
'.') :
'#';
2317 " which accepts just one argument",
2322 do rb_io_write(io, *argv++);
while (--argc);
2327 return rb_funcallv(io, id_write, argc, argv);
2353 rb_io_write(io, str);
2359nogvl_fsync(
void *ptr)
2364 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->
fd)) != FILE_TYPE_DISK)
2367 return (
VALUE)fsync(fptr->
fd);
2372rb_io_flush_raw(
VALUE io,
int sync)
2380 io = GetWriteIO(io);
2384 if (io_fflush(fptr) < 0)
2385 rb_sys_fail_on_write(fptr);
2388 io_unread(fptr,
true);
2409 return rb_io_flush_raw(io, 1);
2435 pos = io_tell(fptr);
2436 if (pos < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
2442rb_io_seek(
VALUE io,
VALUE offset,
int whence)
2449 pos = io_seek(fptr, pos, whence);
2450 if (pos < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
2456interpret_seek_whence(
VALUE vwhence)
2458 if (vwhence == sym_SET)
2460 if (vwhence == sym_CUR)
2462 if (vwhence == sym_END)
2465 if (vwhence == sym_DATA)
2469 if (vwhence == sym_HOLE)
2525 VALUE offset, ptrname;
2526 int whence = SEEK_SET;
2528 if (
rb_scan_args(argc, argv,
"11", &offset, &ptrname) == 2) {
2529 whence = interpret_seek_whence(ptrname);
2532 return rb_io_seek(io, offset, whence);
2560 pos = io_seek(fptr, pos, SEEK_SET);
2561 if (pos < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
2566static void clear_readconv(
rb_io_t *fptr);
2593rb_io_rewind(
VALUE io)
2598 if (io_seek(fptr, 0L, 0) < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
2599 if (io == ARGF.current_file) {
2600 ARGF.lineno -= fptr->
lineno;
2604 clear_readconv(fptr);
2611fptr_wait_readable(
rb_io_t *fptr)
2629 fptr->
rbuf.
capa = IO_RBUF_CAPA_FOR(fptr);
2640 if (fptr_wait_readable(fptr))
2644 VALUE path = rb_sprintf(
"fd:%d ", fptr->
fd);
2649 rb_syserr_fail_path(e, path);
2703 if (READ_CHAR_PENDING(fptr))
return Qfalse;
2704 if (READ_DATA_PENDING(fptr))
return Qfalse;
2706#if RUBY_CRLF_ENVIRONMENT
2707 if (!NEED_READCONV(fptr) && NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
2708 return RBOOL(eof(fptr->
fd));
2711 return RBOOL(io_fillbuf(fptr) < 0);
2735 io = GetWriteIO(io);
2772 io = GetWriteIO(io);
2778 fptr->
mode &= ~FMODE_SYNC;
2802rb_io_fsync(
VALUE io)
2806 io = GetWriteIO(io);
2809 if (io_fflush(fptr) < 0)
2810 rb_sys_fail_on_write(fptr);
2812 if ((
int)rb_io_blocking_region(fptr, nogvl_fsync, fptr))
2813 rb_sys_fail_path(fptr->
pathv);
2818# define rb_io_fsync rb_f_notimplement
2819# define rb_io_sync rb_f_notimplement
2828#ifdef HAVE_FDATASYNC
2830nogvl_fdatasync(
void *ptr)
2835 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->
fd)) != FILE_TYPE_DISK)
2838 return (
VALUE)fdatasync(fptr->
fd);
2853rb_io_fdatasync(
VALUE io)
2857 io = GetWriteIO(io);
2860 if (io_fflush(fptr) < 0)
2861 rb_sys_fail_on_write(fptr);
2863 if ((
int)rb_io_blocking_region(fptr, nogvl_fdatasync, fptr) == 0)
2867 return rb_io_fsync(io);
2870#define rb_io_fdatasync rb_io_fsync
2888rb_io_fileno(
VALUE io)
2908 if (!UNDEF_P(fileno)) {
2996rb_io_inspect(
VALUE obj)
3000 static const char closed[] =
" (closed)";
3002 fptr =
RFILE(obj)->fptr;
3009 rb_str_cat(result, closed+1, strlen(closed)-1);
3012 rb_str_catf(result,
"fd %d", fptr->
fd);
3033rb_io_to_io(
VALUE io)
3040read_buffered_data(
char *ptr,
long len,
rb_io_t *fptr)
3044 n = READ_DATA_PENDING_COUNT(fptr);
3045 if (n <= 0)
return 0;
3046 if (n >
len) n = (int)
len;
3054io_bufread(
char *ptr,
long len,
rb_io_t *fptr)
3060 if (READ_DATA_PENDING(fptr) == 0) {
3064 c = rb_io_read_memory(fptr, ptr+offset, n);
3067 if (fptr_wait_readable(fptr))
3072 if ((n -= c) <= 0)
break;
3078 c = read_buffered_data(ptr+offset, n, fptr);
3081 if ((n -= c) <= 0)
break;
3084 if (io_fillbuf(fptr) < 0) {
3091static int io_setstrbuf(
VALUE *str,
long len);
3100bufread_call(
VALUE arg)
3103 p->len = io_bufread(p->str_ptr, p->len, p->fptr);
3108io_fread(
VALUE str,
long offset,
long size,
rb_io_t *fptr)
3113 io_setstrbuf(&str, offset + size);
3114 arg.str_ptr = RSTRING_PTR(str) + offset;
3117 rb_str_locktmp_ensure(str, bufread_call, (
VALUE)&arg);
3119 if (
len < 0) rb_sys_fail_path(fptr->
pathv);
3127 rb_off_t siz = READ_DATA_PENDING_COUNT(fptr);
3130 if (fstat(fptr->
fd, &st) == 0 && S_ISREG(st.st_mode)
3131#
if defined(__HAIKU__)
3136 if (io_fflush(fptr) < 0)
3137 rb_sys_fail_on_write(fptr);
3138 pos = lseek(fptr->
fd, 0, SEEK_CUR);
3139 if (st.st_size >= pos && pos >= 0) {
3140 siz += st.st_size - pos;
3141 if (siz > LONG_MAX) {
3142 rb_raise(
rb_eIOError,
"file too big for single read");
3155 rb_enc_associate(str, io_read_encoding(fptr));
3162make_readconv(
rb_io_t *fptr,
int size)
3167 const char *sname, *dname;
3168 ecflags = fptr->
encs.
ecflags & ~ECONV_NEWLINE_DECORATOR_WRITE_MASK;
3171 sname = rb_enc_name(fptr->
encs.
enc2);
3172 dname = rb_enc_name(io_read_encoding(fptr));
3182 if (size < IO_CBUF_CAPA_MIN) size = IO_CBUF_CAPA_MIN;
3188#define MORE_CHAR_SUSPENDED Qtrue
3189#define MORE_CHAR_FINISHED Qnil
3191fill_cbuf(
rb_io_t *fptr,
int ec_flags)
3193 const unsigned char *ss, *sp, *se;
3194 unsigned char *ds, *dp, *de;
3203 return MORE_CHAR_SUSPENDED;
3214 ss = sp = (
const unsigned char *)fptr->
rbuf.
ptr + fptr->
rbuf.
off;
3219 fptr->
rbuf.
off += (int)(sp - ss);
3220 fptr->
rbuf.
len -= (int)(sp - ss);
3221 fptr->
cbuf.
len += (int)(dp - ds);
3226 fptr->
rbuf.
off -= putbackable;
3227 fptr->
rbuf.
len += putbackable;
3234 if (cbuf_len0 != fptr->
cbuf.
len)
3235 return MORE_CHAR_SUSPENDED;
3238 return MORE_CHAR_FINISHED;
3244 if (io_fillbuf(fptr) < 0) {
3246 return MORE_CHAR_FINISHED;
3251 fptr->
cbuf.
len += (int)(dp - ds);
3258 if (cbuf_len0 != fptr->
cbuf.
len)
3259 return MORE_CHAR_SUSPENDED;
3261 return MORE_CHAR_FINISHED;
3269 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED)
3286 rb_enc_associate(str, fptr->
encs.
enc);
3315 long clen = RSTRING_LEN(s);
3327#define MAX_REALLOC_GAP 4096
3329io_shrink_read_string(
VALUE str,
long n)
3332 rb_str_resize(str, n);
3337io_set_read_length(
VALUE str,
long n,
int shrinkable)
3339 if (RSTRING_LEN(str) != n) {
3342 if (shrinkable) io_shrink_read_string(str, n);
3356 if (NEED_READCONV(fptr)) {
3357 int first = !
NIL_P(str);
3358 SET_BINARY_MODE(fptr);
3359 shrinkable = io_setstrbuf(&str,0);
3360 make_readconv(fptr, 0);
3365 io_shift_cbuf(fptr, fptr->
cbuf.
len, &str);
3367 v = fill_cbuf(fptr, 0);
3368 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED) {
3371 io_shift_cbuf(fptr, fptr->
cbuf.
len, &str);
3375 if (v == MORE_CHAR_FINISHED) {
3376 clear_readconv(fptr);
3378 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3379 return io_enc_str(str, fptr);
3384 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3388 enc = io_read_encoding(fptr);
3391 if (siz == 0) siz = BUFSIZ;
3392 shrinkable = io_setstrbuf(&str, siz);
3395 n = io_fread(str, bytes, siz - bytes, fptr);
3396 if (n == 0 && bytes == 0) {
3404 if (bytes < siz)
break;
3408 if (
capa < (
size_t)RSTRING_LEN(str) + BUFSIZ) {
3409 if (
capa < BUFSIZ) {
3412 else if (
capa > IO_MAX_BUFFER_GROWTH) {
3413 capa = IO_MAX_BUFFER_GROWTH;
3418 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3419 str = io_enc_str(str, fptr);
3427 if (rb_fd_set_nonblock(fptr->
fd) != 0) {
3428 rb_sys_fail_path(fptr->
pathv);
3433io_read_memory_call(
VALUE arg)
3438 if (scheduler !=
Qnil) {
3441 if (!UNDEF_P(result)) {
3447 if (iis->nonblock) {
3448 return rb_io_blocking_region(iis->fptr, internal_read_func, iis);
3451 return rb_io_blocking_region_wait(iis->fptr, internal_read_func, iis,
RUBY_IO_READABLE);
3458 return (
long)rb_str_locktmp_ensure(str, io_read_memory_call, (
VALUE)iis);
3461#define no_exception_p(opts) !rb_opts_exception_p((opts), TRUE)
3464io_getpartial(
int argc,
VALUE *argv,
VALUE io,
int no_exception,
int nonblock)
3475 rb_raise(rb_eArgError,
"negative length %ld given",
len);
3478 shrinkable = io_setstrbuf(&str,
len);
3484 io_set_read_length(str, 0, shrinkable);
3490 n = read_buffered_data(RSTRING_PTR(str),
len, fptr);
3496 io_setstrbuf(&str,
len);
3499 iis.nonblock = nonblock;
3501 iis.buf = RSTRING_PTR(str);
3504 n = io_read_memory_locktmp(str, &iis);
3507 if (!nonblock && fptr_wait_readable(fptr))
3509 if (nonblock && (io_again_p(e))) {
3511 return sym_wait_readable;
3514 e,
"read would block");
3516 rb_syserr_fail_path(e, fptr->
pathv);
3519 io_set_read_length(str, n, shrinkable);
3620io_readpartial(
int argc,
VALUE *argv,
VALUE io)
3624 ret = io_getpartial(argc, argv, io,
Qnil, 0);
3631io_nonblock_eof(
int no_exception)
3633 if (!no_exception) {
3649 rb_raise(rb_eArgError,
"negative length %ld given",
len);
3652 shrinkable = io_setstrbuf(&str,
len);
3653 rb_bool_expected(ex,
"exception", TRUE);
3659 io_set_read_length(str, 0, shrinkable);
3663 n = read_buffered_data(RSTRING_PTR(str),
len, fptr);
3665 rb_fd_set_nonblock(fptr->
fd);
3666 shrinkable |= io_setstrbuf(&str,
len);
3670 iis.buf = RSTRING_PTR(str);
3673 n = io_read_memory_locktmp(str, &iis);
3676 if (io_again_p(e)) {
3677 if (!ex)
return sym_wait_readable;
3679 e,
"read would block");
3681 rb_syserr_fail_path(e, fptr->
pathv);
3684 io_set_read_length(str, n, shrinkable);
3687 if (!ex)
return Qnil;
3703 rb_bool_expected(ex,
"exception", TRUE);
3705 io = GetWriteIO(io);
3709 if (io_fflush(fptr) < 0)
3710 rb_sys_fail_on_write(fptr);
3712 rb_fd_set_nonblock(fptr->
fd);
3713 n = write(fptr->
fd, RSTRING_PTR(str), RSTRING_LEN(str));
3718 if (io_again_p(e)) {
3720 return sym_wait_writable;
3726 rb_syserr_fail_path(e, fptr->
pathv);
3810#if RUBY_CRLF_ENVIRONMENT
3816 if (
NIL_P(length)) {
3819 return read_all(fptr, remain_size(fptr), str);
3823 rb_raise(rb_eArgError,
"negative length %ld given",
len);
3826 shrinkable = io_setstrbuf(&str,
len);
3831 io_set_read_length(str, 0, shrinkable);
3836#if RUBY_CRLF_ENVIRONMENT
3837 previous_mode = set_binary_mode_with_seek_cur(fptr);
3839 n = io_fread(str, 0,
len, fptr);
3840 io_set_read_length(str, n, shrinkable);
3841#if RUBY_CRLF_ENVIRONMENT
3842 if (previous_mode == O_TEXT) {
3843 setmode(fptr->
fd, O_TEXT);
3846 if (n == 0)
return Qnil;
3852rscheck(
const char *rsptr,
long rslen,
VALUE rs)
3855 if (RSTRING_PTR(rs) != rsptr && RSTRING_LEN(rs) != rslen)
3860search_delim(
const char *p,
long len,
int delim,
rb_encoding *enc)
3862 if (rb_enc_mbminlen(enc) == 1) {
3863 p = memchr(p, delim,
len);
3864 if (p)
return p + 1;
3867 const char *end = p +
len;
3869 int r = rb_enc_precise_mbclen(p, end, enc);
3871 p += rb_enc_mbminlen(enc);
3875 if (rb_enc_mbc_to_codepoint(p, end, enc) == (
unsigned int)delim) {
3890 if (NEED_READCONV(fptr)) {
3891 SET_BINARY_MODE(fptr);
3892 make_readconv(fptr, 0);
3895 int searchlen = READ_CHAR_PENDING_COUNT(fptr);
3897 p = READ_CHAR_PENDING_PTR(fptr);
3898 if (0 < limit && limit < searchlen)
3899 searchlen = (int)limit;
3900 e = search_delim(p, searchlen, delim, enc);
3902 int len = (int)(e-p);
3924 return (
unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
3927 }
while (more_char(fptr) != MORE_CHAR_FINISHED);
3928 clear_readconv(fptr);
3933 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3935 long pending = READ_DATA_PENDING_COUNT(fptr);
3937 const char *p = READ_DATA_PENDING_PTR(fptr);
3941 if (limit > 0 && pending > limit) pending = limit;
3942 e = search_delim(p, pending, delim, enc);
3943 if (e) pending = e - p;
3945 last = RSTRING_LEN(str);
3946 rb_str_resize(str, last + pending);
3953 read_buffered_data(RSTRING_PTR(str) + last, pending, fptr);
3956 if (e)
return delim;
3958 return (
unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
3961 }
while (io_fillbuf(fptr) >= 0);
3967swallow(
rb_io_t *fptr,
int term)
3969 if (NEED_READCONV(fptr)) {
3971 int needconv = rb_enc_mbminlen(enc) != 1;
3972 SET_BINARY_MODE(fptr);
3973 make_readconv(fptr, 0);
3976 while ((cnt = READ_CHAR_PENDING_COUNT(fptr)) > 0) {
3977 const char *p = READ_CHAR_PENDING_PTR(fptr);
3980 if (*p != term)
return TRUE;
3982 while (--i && *++p == term);
3985 const char *e = p + cnt;
3986 if (rb_enc_ascget(p, e, &i, enc) != term)
return TRUE;
3987 while ((p += i) < e && rb_enc_ascget(p, e, &i, enc) == term);
3990 io_shift_cbuf(fptr, (
int)cnt - i, NULL);
3992 }
while (more_char(fptr) != MORE_CHAR_FINISHED);
3996 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3999 while ((cnt = READ_DATA_PENDING_COUNT(fptr)) > 0) {
4001 const char *p = READ_DATA_PENDING_PTR(fptr);
4003 if (cnt >
sizeof buf) cnt =
sizeof buf;
4004 if (*p != term)
return TRUE;
4006 while (--i && *++p == term);
4007 if (!read_buffered_data(buf, cnt - i, fptr))
4008 rb_sys_fail_path(fptr->
pathv);
4011 }
while (io_fillbuf(fptr) == 0);
4024 int pending = READ_DATA_PENDING_COUNT(fptr);
4027 const char *p = READ_DATA_PENDING_PTR(fptr);
4031 e = memchr(p,
'\n', pending);
4033 pending = (int)(e - p + 1);
4035 chomplen = (pending > 1 && *(e-1) ==
'\r') + 1;
4044 rb_str_resize(str,
len + pending - chomplen);
4045 read_buffered_data(RSTRING_PTR(str)+
len, pending - chomplen, fptr);
4048 if (pending == 1 && chomplen == 1 &&
len > 0) {
4049 if (RSTRING_PTR(str)[
len-1] ==
'\r') {
4050 rb_str_resize(str, --
len);
4055 len += pending - chomplen;
4061 }
while (io_fillbuf(fptr) >= 0);
4064 str = io_enc_str(str, fptr);
4075 unsigned int chomp: 1;
4089 chomp = (!UNDEF_P(vchomp)) &&
RTEST(vchomp);
4091 args->chomp = chomp;
4109 else if (2 <= argc) {
4110 rs = argv[0], lim = argv[1];
4119check_getline_args(
VALUE *rsp,
long *limit,
VALUE io)
4128 enc_rs = rb_enc_get(rs);
4129 enc_io = io_read_encoding(fptr);
4130 if (enc_io != enc_rs &&
4131 (!is_ascii_string(rs) ||
4132 (RSTRING_LEN(rs) > 0 && !rb_enc_asciicompat(enc_io)))) {
4133 if (rs == rb_default_rs) {
4134 rs = rb_enc_str_new(0, 0, enc_io);
4139 rb_raise(rb_eArgError,
"encoding mismatch: %s IO with %s RS",
4140 rb_enc_name(enc_io),
4141 rb_enc_name(enc_rs));
4151 argc =
rb_scan_args(argc, argv,
"02:", NULL, NULL, &opts);
4152 extract_getline_args(argc, argv, args);
4153 extract_getline_opts(opts, args);
4154 check_getline_args(&args->rs, &args->limit, io);
4158rb_io_getline_0(
VALUE rs,
long limit,
int chomp,
rb_io_t *fptr)
4165 if (
NIL_P(rs) && limit < 0) {
4166 str = read_all(fptr, 0,
Qnil);
4167 if (RSTRING_LEN(str) == 0)
return Qnil;
4169 else if (limit == 0) {
4170 return rb_enc_str_new(0, 0, io_read_encoding(fptr));
4172 else if (rs == rb_default_rs && limit < 0 && !NEED_READCONV(fptr) &&
4173 rb_enc_asciicompat(enc = io_read_encoding(fptr))) {
4174 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4175 return rb_io_getline_fast(fptr, enc, chomp);
4178 int c, newline = -1;
4179 const char *rsptr = 0;
4182 int extra_limit = 16;
4183 int chomp_cr = chomp;
4185 SET_BINARY_MODE(fptr);
4186 enc = io_read_encoding(fptr);
4189 rslen = RSTRING_LEN(rs);
4194 swallow(fptr,
'\n');
4196 if (!rb_enc_asciicompat(enc)) {
4200 rsptr = RSTRING_PTR(rs);
4201 rslen = RSTRING_LEN(rs);
4205 else if (rb_enc_mbminlen(enc) == 1) {
4206 rsptr = RSTRING_PTR(rs);
4207 newline = (
unsigned char)rsptr[rslen - 1];
4211 rsptr = RSTRING_PTR(rs);
4212 const char *e = rsptr + rslen;
4213 const char *last = rb_enc_prev_char(rsptr, e, e, enc);
4215 newline = rb_enc_codepoint_len(last, e, &n, enc);
4216 if (last + n != e) rb_raise(rb_eArgError,
"broken separator");
4218 chomp_cr = chomp && newline ==
'\n' && rslen == rb_enc_mbminlen(enc);
4222 while ((c = appendline(fptr, newline, &str, &limit, enc)) != EOF) {
4223 const char *s, *p, *pp, *e;
4226 if (RSTRING_LEN(str) < rslen)
continue;
4227 s = RSTRING_PTR(str);
4230 if (!at_char_boundary(s, p, e, enc))
continue;
4231 if (!rspara) rscheck(rsptr, rslen, rs);
4232 if (memcmp(p, rsptr, rslen) == 0) {
4234 if (chomp_cr && p > s && *(p-1) ==
'\r') --p;
4241 s = RSTRING_PTR(str);
4243 pp = rb_enc_prev_char(s, p, p, enc);
4244 if (extra_limit && pp &&
4258 if (rspara && c != EOF)
4259 swallow(fptr,
'\n');
4261 str = io_enc_str(str, fptr);
4264 if (!
NIL_P(str) && !nolimit) {
4272rb_io_getline_1(
VALUE rs,
long limit,
int chomp,
VALUE io)
4275 int old_lineno, new_lineno;
4279 old_lineno = fptr->
lineno;
4280 str = rb_io_getline_0(rs, limit, chomp, fptr);
4281 if (!
NIL_P(str) && (new_lineno = fptr->
lineno) != old_lineno) {
4282 if (io == ARGF.current_file) {
4283 ARGF.lineno += new_lineno - old_lineno;
4284 ARGF.last_lineno = ARGF.lineno;
4287 ARGF.last_lineno = new_lineno;
4295rb_io_getline(
int argc,
VALUE *argv,
VALUE io)
4299 prepare_getline_args(argc, argv, &args, io);
4300 return rb_io_getline_1(args.rs, args.limit, args.chomp, io);
4310rb_io_gets_limit_internal(
VALUE io,
long limit)
4314 return rb_io_getline_0(rb_default_rs, limit, FALSE, fptr);
4318rb_io_gets_internal(
VALUE io)
4320 return rb_io_gets_limit_internal(io, -1);
4400 str = rb_io_getline(argc, argv, io);
4416rb_io_lineno(
VALUE io)
4471 check_getline_args(&sep, &limit, io);
4473 VALUE line = rb_io_getline_1(sep, limit,
RTEST(chomp), io);
4474 rb_lastline_set_up(line, 1);
4549rb_io_readlines(
int argc,
VALUE *argv,
VALUE io)
4553 prepare_getline_args(argc, argv, &args, io);
4554 return io_readlines(&args, io);
4562 if (arg->limit == 0)
4563 rb_raise(rb_eArgError,
"invalid limit: 0 for readlines");
4565 while (!
NIL_P(line = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, io))) {
4678rb_io_each_line(
int argc,
VALUE *argv,
VALUE io)
4684 prepare_getline_args(argc, argv, &args, io);
4685 if (args.limit == 0)
4686 rb_raise(rb_eArgError,
"invalid limit: 0 for each_line");
4687 while (!
NIL_P(str = rb_io_getline_1(args.rs, args.limit, args.chomp, io))) {
4714rb_io_each_byte(
VALUE io)
4730 }
while (io_fillbuf(fptr) >= 0);
4740 if (NEED_READCONV(fptr)) {
4744 SET_BINARY_MODE(fptr);
4745 make_readconv(fptr, 0);
4759 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4761 clear_readconv(fptr);
4765 str = rb_enc_str_new(fptr->
cbuf.
ptr+fptr->
cbuf.
off, 1, read_enc);
4768 if (fptr->
cbuf.
len == 0) clear_readconv(fptr);
4777 io_shift_cbuf(fptr, r, &str);
4784 ISASCII(RSTRING_PTR(str)[0])) {
4788 str = io_enc_str(str, fptr);
4793 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4794 if (io_fillbuf(fptr) < 0) {
4816 if (io_fillbuf(fptr) != -1) {
4820 r = rb_enc_precise_mbclen(RSTRING_PTR(str), RSTRING_PTR(str)+RSTRING_LEN(str), enc);
4836 str = io_enc_str(str, fptr);
4862rb_io_each_char(
VALUE io)
4872 enc = io_input_encoding(fptr);
4874 while (!
NIL_P(c = io_getc(fptr, enc))) {
4900rb_io_each_codepoint(
VALUE io)
4912 if (NEED_READCONV(fptr)) {
4913 SET_BINARY_MODE(fptr);
4916 make_readconv(fptr, 0);
4924 r = ONIGENC_CONSTRUCT_MBCLEN_CHARFOUND(1);
4931 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4932 clear_readconv(fptr);
4959 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4960 enc = io_input_encoding(fptr);
4961 while (io_fillbuf(fptr) >= 0) {
4976 char cbuf[8], *p = cbuf;
4978 if (more > numberof(cbuf))
goto invalid;
4980 if (more > numberof(cbuf))
goto invalid;
4981 while ((n = (
int)read_buffered_data(p, more, fptr)) > 0 &&
4982 (p += n, (more -= n) > 0)) {
4983 if (io_fillbuf(fptr) < 0)
goto invalid;
4984 if ((n = fptr->
rbuf.
len) > more) n = more;
4986 r = rb_enc_precise_mbclen(cbuf, p, enc);
4999 rb_raise(rb_eArgError,
"invalid byte sequence in %s", rb_enc_name(enc));
5031 enc = io_input_encoding(fptr);
5033 return io_getc(fptr, enc);
5056rb_io_readchar(
VALUE io)
5058 VALUE c = rb_io_getc(io);
5093 VALUE r_stdout = rb_ractor_stdout();
5098 rb_io_flush(r_stdout);
5101 if (io_fillbuf(fptr) < 0) {
5130rb_io_readbyte(
VALUE io)
5191 unsigned char c =
NUM2INT(v) & 0xFF;
5197 io_ungetbyte(b, fptr);
5253 else if (RB_BIGNUM_TYPE_P(c)) {
5259 if (NEED_READCONV(fptr)) {
5260 SET_BINARY_MODE(fptr);
5261 len = RSTRING_LEN(c);
5262#if SIZEOF_LONG > SIZEOF_INT
5266 make_readconv(fptr, (
int)
len);
5280 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
5281 io_ungetbyte(c, fptr);
5301rb_io_isatty(
VALUE io)
5306 return RBOOL(isatty(fptr->
fd) != 0);
5309#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5325rb_io_close_on_exec_p(
VALUE io)
5331 write_io = GetWriteIO(io);
5332 if (io != write_io) {
5334 if (fptr && 0 <= (fd = fptr->
fd)) {
5335 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->
pathv);
5336 if (!(ret & FD_CLOEXEC))
return Qfalse;
5341 if (fptr && 0 <= (fd = fptr->
fd)) {
5342 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->
pathv);
5343 if (!(ret & FD_CLOEXEC))
return Qfalse;
5348#define rb_io_close_on_exec_p rb_f_notimplement
5351#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5375 int flag =
RTEST(arg) ? FD_CLOEXEC : 0;
5380 write_io = GetWriteIO(io);
5381 if (io != write_io) {
5383 if (fptr && 0 <= (fd = fptr->
fd)) {
5384 if ((ret = fcntl(fptr->
fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->
pathv);
5385 if ((ret & FD_CLOEXEC) != flag) {
5386 ret = (ret & ~FD_CLOEXEC) | flag;
5387 ret = fcntl(fd, F_SETFD, ret);
5388 if (ret != 0) rb_sys_fail_path(fptr->
pathv);
5395 if (fptr && 0 <= (fd = fptr->
fd)) {
5396 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->
pathv);
5397 if ((ret & FD_CLOEXEC) != flag) {
5398 ret = (ret & ~FD_CLOEXEC) | flag;
5399 ret = fcntl(fd, F_SETFD, ret);
5400 if (ret != 0) rb_sys_fail_path(fptr->
pathv);
5406#define rb_io_set_close_on_exec rb_f_notimplement
5409#define RUBY_IO_EXTERNAL_P(f) ((f)->mode & FMODE_EXTERNAL)
5410#define PREP_STDIO_NAME(f) (RSTRING_PTR((f)->pathv))
5413finish_writeconv(
rb_io_t *fptr,
int noalloc)
5415 unsigned char *ds, *dp, *de;
5419 unsigned char buf[1024];
5424 de = buf +
sizeof(buf);
5427 size_t remaining = dp-ds;
5428 long result = rb_io_write_memory(fptr, ds, remaining);
5432 if ((
size_t)result == remaining)
break;
5455 if (io_fflush(fptr) < 0) {
5463 fptr->
wbuf.
len += (int)(dp - ds);
5479finish_writeconv_sync(
VALUE arg)
5482 return finish_writeconv(p->fptr, p->noalloc);
5486nogvl_close(
void *ptr)
5490 return (
void*)(intptr_t)close(*fd);
5494maygvl_close(
int fd,
int keepgvl)
5503 return IO_WITHOUT_GVL_INT(nogvl_close, &fd);
5507nogvl_fclose(
void *ptr)
5511 return (
void*)(intptr_t)fclose(file);
5515maygvl_fclose(
FILE *file,
int keepgvl)
5518 return fclose(file);
5520 return IO_WITHOUT_GVL_INT(nogvl_fclose, file);
5526fptr_finalize_flush(
rb_io_t *fptr,
int noraise,
int keepgvl)
5531 int mode = fptr->
mode;
5537 arg.noalloc = noraise;
5541 error = finish_writeconv(fptr, noraise);
5546 io_flush_buffer_sync(fptr);
5549 if (io_fflush(fptr) < 0 &&
NIL_P(error)) {
5557 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2) {
5567 rb_thread_io_close_wait(fptr);
5578 if (!done && stdio_file) {
5580 if ((maygvl_fclose(stdio_file, noraise) < 0) &&
NIL_P(error)) {
5589 if (!done && fd >= 0) {
5595 if ((maygvl_close(fd, keepgvl) < 0) &&
NIL_P(error)) {
5604 if (!
NIL_P(error) && !noraise) {
5613fptr_finalize(
rb_io_t *fptr,
int noraise)
5615 fptr_finalize_flush(fptr, noraise, FALSE);
5616 free_io_buffer(&fptr->
rbuf);
5617 free_io_buffer(&fptr->
wbuf);
5618 clear_codeconv(fptr);
5622rb_io_fptr_cleanup(
rb_io_t *fptr,
int noraise)
5628 fptr_finalize(fptr, noraise);
5636 ruby_sized_xfree(buf->
ptr, (
size_t)buf->
capa);
5648 free_io_buffer(&fptr->
cbuf);
5664 clear_readconv(fptr);
5665 clear_writeconv(fptr);
5669rb_io_fptr_cleanup_all(
rb_io_t *fptr)
5673 rb_io_fptr_cleanup(fptr, TRUE);
5675 free_io_buffer(&fptr->
rbuf);
5676 free_io_buffer(&fptr->
wbuf);
5677 clear_codeconv(fptr);
5684 rb_io_fptr_cleanup_all(io);
5691rb_io_memsize(
const rb_io_t *io)
5693 size_t size =
sizeof(
rb_io_t);
5703 rb_serial_t fork_generation = GET_VM()->fork_gen;
5704 if (io->fork_generation == fork_generation) {
5715# define KEEPGVL TRUE
5717# define KEEPGVL FALSE
5721io_close_fptr(
VALUE io)
5727 write_io = GetWriteIO(io);
5728 if (io != write_io) {
5729 write_fptr =
RFILE(write_io)->fptr;
5730 if (write_fptr && 0 <= write_fptr->
fd) {
5731 rb_io_fptr_cleanup(write_fptr, TRUE);
5735 fptr =
RFILE(io)->fptr;
5736 if (!fptr)
return 0;
5737 if (fptr->
fd < 0)
return 0;
5739 if (rb_thread_io_close_interrupt(fptr)) {
5741 fptr_finalize_flush(fptr, FALSE, KEEPGVL);
5743 rb_io_fptr_cleanup(fptr, FALSE);
5748fptr_waitpid(
rb_io_t *fptr,
int nohang)
5752 rb_last_status_clear();
5761 rb_io_t *fptr = io_close_fptr(io);
5762 if (fptr) fptr_waitpid(fptr, 0);
5802rb_io_close_m(
VALUE io)
5804 rb_io_t *fptr = rb_io_get_fptr(io);
5813io_call_close(
VALUE io)
5822 enum {mesg_len =
sizeof(closed_stream)-1};
5823 VALUE mesg = rb_attr_get(exc, idMesg);
5825 RSTRING_LEN(mesg) != mesg_len ||
5826 memcmp(RSTRING_PTR(mesg), closed_stream, mesg_len)) {
5836 if (!UNDEF_P(closed) &&
RTEST(closed))
return io;
5837 rb_rescue2(io_call_close, io, ignore_closed_stream, io,
5873 write_io = GetWriteIO(io);
5874 if (io != write_io) {
5875 write_fptr =
RFILE(write_io)->fptr;
5876 if (write_fptr && 0 <= write_fptr->
fd) {
5881 fptr = rb_io_get_fptr(io);
5882 return RBOOL(0 > fptr->
fd);
5918rb_io_close_read(
VALUE io)
5924 if (fptr->
fd < 0)
return Qnil;
5925 if (is_socket(fptr->
fd, fptr->
pathv)) {
5929 if (shutdown(fptr->
fd, SHUT_RD) < 0)
5930 rb_sys_fail_path(fptr->
pathv);
5931 fptr->
mode &= ~FMODE_READABLE;
5937 write_io = GetWriteIO(io);
5938 if (io != write_io) {
5943 RFILE(io)->fptr = wfptr;
5946 RFILE(write_io)->fptr = fptr;
5947 rb_io_fptr_cleanup(fptr, FALSE);
5953 rb_raise(
rb_eIOError,
"closing non-duplex IO for reading");
5991rb_io_close_write(
VALUE io)
5996 write_io = GetWriteIO(io);
5998 if (fptr->
fd < 0)
return Qnil;
5999 if (is_socket(fptr->
fd, fptr->
pathv)) {
6003 if (shutdown(fptr->
fd, SHUT_WR) < 0)
6004 rb_sys_fail_path(fptr->
pathv);
6005 fptr->
mode &= ~FMODE_WRITABLE;
6012 rb_raise(
rb_eIOError,
"closing non-duplex IO for writing");
6015 if (io != write_io) {
6035rb_io_sysseek(
int argc,
VALUE *argv,
VALUE io)
6037 VALUE offset, ptrname;
6038 int whence = SEEK_SET;
6042 if (
rb_scan_args(argc, argv,
"11", &offset, &ptrname) == 2) {
6043 whence = interpret_seek_whence(ptrname);
6048 (READ_DATA_BUFFERED(fptr) || READ_CHAR_PENDING(fptr))) {
6052 rb_warn(
"sysseek for buffered IO");
6055 pos = lseek(fptr->
fd, pos, whence);
6056 if (pos < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
6090 io = GetWriteIO(io);
6095 rb_warn(
"syswrite for buffered IO");
6098 tmp = rb_str_tmp_frozen_acquire(str);
6100 n = rb_io_write_memory(fptr, ptr,
len);
6101 if (n < 0) rb_sys_fail_path(fptr->
pathv);
6102 rb_str_tmp_frozen_release(str, tmp);
6119rb_io_sysread(
int argc,
VALUE *argv,
VALUE io)
6130 shrinkable = io_setstrbuf(&str, ilen);
6131 if (ilen == 0)
return str;
6136 if (READ_DATA_BUFFERED(fptr)) {
6142 io_setstrbuf(&str, ilen);
6147 iis.buf = RSTRING_PTR(str);
6150 n = io_read_memory_locktmp(str, &iis);
6153 rb_sys_fail_path(fptr->
pathv);
6156 io_set_read_length(str, n, shrinkable);
6158 if (n == 0 && ilen > 0) {
6174internal_pread_func(
void *_arg)
6178 return (
VALUE)pread(arg->fd, arg->buf, arg->count, arg->offset);
6182pread_internal_call(
VALUE _arg)
6187 if (scheduler !=
Qnil) {
6190 if (!UNDEF_P(result)) {
6195 return rb_io_blocking_region_wait(arg->io, internal_pread_func, arg,
RUBY_IO_READABLE);
6239 shrinkable = io_setstrbuf(&str, (
long)arg.count);
6240 if (arg.count == 0)
return str;
6241 arg.buf = RSTRING_PTR(str);
6254 rb_sys_fail_path(fptr->
pathv);
6256 io_set_read_length(str, n, shrinkable);
6257 if (n == 0 && arg.count > 0) {
6265internal_pwrite_func(
void *_arg)
6270 if (scheduler !=
Qnil) {
6273 if (!UNDEF_P(result)) {
6279 return (
VALUE)pwrite(arg->fd, arg->buf, arg->count, arg->offset);
6320 io = GetWriteIO(io);
6327 tmp = rb_str_tmp_frozen_acquire(str);
6328 arg.buf = RSTRING_PTR(tmp);
6329 arg.count = (size_t)RSTRING_LEN(tmp);
6331 n = (ssize_t)rb_io_blocking_region_wait(fptr, internal_pwrite_func, &arg,
RUBY_IO_WRITABLE);
6332 if (n < 0) rb_sys_fail_path(fptr->
pathv);
6333 rb_str_tmp_frozen_release(str, tmp);
6349 fptr->
mode &= ~FMODE_TEXTMODE;
6353 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6356 setmode(fptr->
fd, O_BINARY);
6363io_ascii8bit_binmode(
rb_io_t *fptr)
6374 fptr->
mode &= ~FMODE_TEXTMODE;
6375 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6377 fptr->
encs.
enc = rb_ascii8bit_encoding();
6381 clear_codeconv(fptr);
6390 io_ascii8bit_binmode(fptr);
6407rb_io_binmode_m(
VALUE io)
6413 write_io = GetWriteIO(io);
6428rb_io_binmode_p(
VALUE io)
6436rb_io_fmode_modestr(
enum rb_io_mode fmode)
6440 return MODE_BTMODE(
"a+",
"ab+",
"at+");
6442 return MODE_BTMODE(
"a",
"ab",
"at");
6446 rb_raise(rb_eArgError,
"invalid access fmode 0x%x", fmode);
6448 return MODE_BTMODE(
"r",
"rb",
"rt");
6450 return MODE_BTXMODE(
"w",
"wb",
"wt",
"wx",
"wbx",
"wtx");
6453 return MODE_BTXMODE(
"w+",
"wb+",
"wt+",
"w+x",
"wb+x",
"wt+x");
6455 return MODE_BTMODE(
"r+",
"rb+",
"rt+");
6459static const char bom_prefix[] =
"bom|";
6460static const char utf_prefix[] =
"utf-";
6461enum {bom_prefix_len = (int)
sizeof(bom_prefix) - 1};
6462enum {utf_prefix_len = (int)
sizeof(utf_prefix) - 1};
6465io_encname_bom_p(
const char *name,
long len)
6467 return len > bom_prefix_len &&
STRNCASECMP(name, bom_prefix, bom_prefix_len) == 0;
6473 enum rb_io_mode fmode = 0;
6474 const char *m = modestr, *p = NULL;
6502 if (modestr[0] !=
'w')
6510 if (io_encname_bom_p(m, p ? (
long)(p - m) : (long)strlen(m)))
6523 rb_raise(rb_eArgError,
"invalid access mode %s", modestr);
6528rb_io_oflags_fmode(
int oflags)
6530 enum rb_io_mode fmode = 0;
6532 switch (oflags & O_ACCMODE) {
6544 if (oflags & O_APPEND) {
6547 if (oflags & O_TRUNC) {
6550 if (oflags & O_CREAT) {
6553 if (oflags & O_EXCL) {
6557 if (oflags & O_BINARY) {
6566rb_io_fmode_oflags(
enum rb_io_mode fmode)
6610rb_io_oflags_modestr(
int oflags)
6613# define MODE_BINARY(a,b) ((oflags & O_BINARY) ? (b) : (a))
6615# define MODE_BINARY(a,b) (a)
6618 if (oflags & O_EXCL) {
6619 rb_raise(rb_eArgError,
"exclusive access mode is not supported");
6621 accmode = oflags & (O_RDONLY|O_WRONLY|O_RDWR);
6622 if (oflags & O_APPEND) {
6623 if (accmode == O_WRONLY) {
6624 return MODE_BINARY(
"a",
"ab");
6626 if (accmode == O_RDWR) {
6627 return MODE_BINARY(
"a+",
"ab+");
6632 rb_raise(rb_eArgError,
"invalid access oflags 0x%x", oflags);
6634 return MODE_BINARY(
"r",
"rb");
6636 return MODE_BINARY(
"w",
"wb");
6638 if (oflags & O_TRUNC) {
6639 return MODE_BINARY(
"w+",
"wb+");
6641 return MODE_BINARY(
"r+",
"rb+");
6653 int default_ext = 0;
6656 ext = rb_default_external_encoding();
6659 if (rb_is_ascii8bit_enc(ext)) {
6663 else if (intern == NULL) {
6664 intern = rb_default_internal_encoding();
6669 *enc = (default_ext && intern != ext) ? NULL : ext;
6679unsupported_encoding(
const char *name,
rb_encoding *enc)
6681 rb_enc_warn(enc,
"Unsupported encoding %s ignored", name);
6685parse_mode_enc(
const char *estr,
rb_encoding *estr_enc,
6691 enum rb_io_mode fmode = fmode_p ? *fmode_p : 0;
6697 p = strrchr(estr,
':');
6698 len = p ? (p++ - estr) : (long)strlen(estr);
6700 estr += bom_prefix_len;
6701 len -= bom_prefix_len;
6702 if (!
STRNCASECMP(estr, utf_prefix, utf_prefix_len)) {
6706 rb_enc_warn(estr_enc,
"BOM with non-UTF encoding %s is nonsense", estr);
6707 fmode &= ~FMODE_SETENC_BY_BOM;
6715 memcpy(encname, estr,
len);
6716 encname[
len] =
'\0';
6719 idx = rb_enc_find_index(estr);
6721 if (fmode_p) *fmode_p = fmode;
6724 ext_enc = rb_enc_from_index(idx);
6727 unsupported_encoding(estr, estr_enc);
6733 if (*p ==
'-' && *(p+1) ==
'\0') {
6738 idx2 = rb_enc_find_index(p);
6740 unsupported_encoding(p, estr_enc);
6745 int_enc = rb_enc_from_index(idx2);
6749 rb_io_ext_int_to_encs(ext_enc, int_enc, enc_p, enc2_p, fmode);
6762 v = rb_hash_lookup2(opt, sym_encoding,
Qnil);
6763 if (v !=
Qnil) encoding = v;
6764 v = rb_hash_lookup2(opt, sym_extenc,
Qundef);
6765 if (v !=
Qnil) extenc = v;
6766 v = rb_hash_lookup2(opt, sym_intenc,
Qundef);
6767 if (!UNDEF_P(v)) intenc = v;
6769 if ((!UNDEF_P(extenc) || !UNDEF_P(intenc)) && !
NIL_P(encoding)) {
6771 int idx = rb_to_encoding_index(encoding);
6772 if (idx >= 0) encoding = rb_enc_from_encoding(rb_enc_from_index(idx));
6773 rb_warn(
"Ignoring encoding parameter '%"PRIsVALUE
"': %s_encoding is used",
6774 encoding, UNDEF_P(extenc) ?
"internal" :
"external");
6778 if (!UNDEF_P(extenc) && !
NIL_P(extenc)) {
6779 extencoding = rb_to_encoding(extenc);
6781 if (!UNDEF_P(intenc)) {
6782 if (
NIL_P(intenc)) {
6789 if (*p ==
'-' && *(p+1) ==
'\0') {
6794 intencoding = rb_to_encoding(intenc);
6798 intencoding = rb_to_encoding(intenc);
6800 if (extencoding == intencoding) {
6804 if (!
NIL_P(encoding)) {
6808 enc_p, enc2_p, fmode_p);
6811 rb_io_ext_int_to_encs(rb_to_encoding(encoding), NULL, enc_p, enc2_p, 0);
6814 else if (!UNDEF_P(extenc) || !UNDEF_P(intenc)) {
6816 rb_io_ext_int_to_encs(extencoding, intencoding, enc_p, enc2_p, 0);
6824 enum rb_io_mode fmode = *fmode_p;
6829 !rb_enc_asciicompat(enc ? enc : rb_default_external_encoding()))
6830 rb_raise(rb_eArgError,
"ASCII incompatible encoding needs binmode");
6833 rb_raise(rb_eArgError,
"newline decorator with binary mode");
6840#if !DEFAULT_TEXTMODE
6842 fmode &= ~FMODE_TEXTMODE;
6849extract_binmode(
VALUE opthash,
enum rb_io_mode *fmode)
6851 if (!
NIL_P(opthash)) {
6853 v = rb_hash_aref(opthash, sym_textmode);
6856 rb_raise(rb_eArgError,
"textmode specified twice");
6858 rb_raise(rb_eArgError,
"both textmode and binmode specified");
6862 v = rb_hash_aref(opthash, sym_binmode);
6865 rb_raise(rb_eArgError,
"binmode specified twice");
6867 rb_raise(rb_eArgError,
"both textmode and binmode specified");
6873 rb_raise(rb_eArgError,
"both textmode and binmode specified");
6879 int *oflags_p,
enum rb_io_mode *fmode_p,
struct rb_io_encoding *convconfig_p)
6883 enum rb_io_mode fmode;
6887 int has_enc = 0, has_vmode = 0;
6893 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
6903 fmode = rb_io_oflags_fmode(oflags);
6911 oflags = rb_io_fmode_oflags(fmode);
6915 parse_mode_enc(p+1, rb_enc_get(vmode), &enc, &enc2, &fmode);
6920 e = (fmode &
FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
6921 rb_io_ext_int_to_encs(e, NULL, &enc, &enc2, fmode);
6925 if (
NIL_P(opthash)) {
6929#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
6931 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
6932 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
6934 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
6941 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
6944 else if (
NIL_P(vmode)) {
6945 fmode |= DEFAULT_TEXTMODE;
6952 v = rb_hash_aref(opthash, sym_mode);
6954 if (!
NIL_P(vmode)) {
6955 rb_raise(rb_eArgError,
"mode specified twice");
6962 v = rb_hash_aref(opthash, sym_flags);
6967 fmode = rb_io_oflags_fmode(oflags);
6969 extract_binmode(opthash, &fmode);
6975 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
6978 else if (
NIL_P(vmode)) {
6979 fmode |= DEFAULT_TEXTMODE;
6982 v = rb_hash_aref(opthash, sym_perm);
6985 if (!
NIL_P(*vperm_p)) {
6986 rb_raise(rb_eArgError,
"perm specified twice");
6997#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
6999 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7000 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7005 rb_raise(rb_eArgError,
"encoding specified twice");
7008 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
7012 validate_enc_binmode(&fmode, ecflags, enc, enc2);
7018 convconfig_p->
enc = enc;
7019 convconfig_p->
enc2 = enc2;
7020 convconfig_p->
ecflags = ecflags;
7021 convconfig_p->
ecopts = ecopts;
7031sysopen_func(
void *ptr)
7034 const char *fname = RSTRING_PTR(data->fname);
7043 fd = IO_WITHOUT_GVL_INT(sysopen_func, data);
7044 }
while (fd < 0 &&
errno == EINTR);
7051rb_sysopen(
VALUE fname,
int oflags, mode_t perm)
7056 data.fname = rb_str_encode_ospath(fname);
7058 data.oflags = oflags;
7061 TRY_WITH_GC((fd = rb_sysopen_internal(&data)) >= 0) {
7062 rb_syserr_fail_path(first_errno, fname);
7068fdopen_internal(
int fd,
const char *modestr)
7075 file = fdopen(fd, modestr);
7091 TRY_WITH_GC((file = fdopen_internal(fd, modestr)) != 0) {
7097 if (setvbuf(file, NULL, _IOFBF, 0) != 0)
7098 rb_warn(
"setvbuf() can't be honoured (fd=%d)", fd);
7106 int t = isatty(fptr->
fd);
7116io_strip_bom(
VALUE io)
7118 VALUE b1, b2, b3, b4;
7129 return rb_utf8_encindex();
7139 return ENCINDEX_UTF_16BE;
7150 return ENCINDEX_UTF_32LE;
7155 return ENCINDEX_UTF_16LE;
7165 return ENCINDEX_UTF_32BE;
7179io_set_encoding_by_bom(
VALUE io)
7181 int idx = io_strip_bom(io);
7187 extenc = rb_enc_from_index(idx);
7188 io_encoding_set(fptr, rb_enc_from_encoding(extenc),
7189 rb_io_internal_encoding(io),
Qnil);
7198rb_file_open_generic(
VALUE io,
VALUE filename,
int oflags,
enum rb_io_mode fmode,
7206 rb_io_ext_int_to_encs(NULL, NULL, &cc.enc, &cc.enc2, fmode);
7211 validate_enc_binmode(&fmode, convconfig->
ecflags,
7212 convconfig->
enc, convconfig->
enc2);
7216 fptr->
encs = *convconfig;
7219 if (!(oflags & O_TMPFILE)) {
7220 fptr->
pathv = pathv;
7223 fptr->
pathv = pathv;
7225 fptr->
fd = rb_sysopen(pathv, oflags, perm);
7233rb_file_open_internal(
VALUE io,
VALUE filename,
const char *modestr)
7236 const char *p = strchr(modestr,
':');
7240 parse_mode_enc(p+1, rb_usascii_encoding(),
7241 &convconfig.
enc, &convconfig.
enc2, &fmode);
7247 e = (fmode &
FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
7248 rb_io_ext_int_to_encs(e, NULL, &convconfig.
enc, &convconfig.
enc2, fmode);
7254#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7256 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7257 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7259 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.
enc2, convconfig.
ecflags);
7262 return rb_file_open_generic(io, filename,
7263 rb_io_fmode_oflags(fmode),
7273 return rb_file_open_internal(io_alloc(
rb_cFile), fname, modestr);
7282#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7305 while ((tmp = *prev) != 0) {
7306 if (tmp->fptr == fptr) {
7315#if defined (_WIN32) || defined(__CYGWIN__)
7331pipe_finalize(
rb_io_t *fptr,
int noraise)
7333#if !defined(HAVE_WORKING_FORK) && !defined(_WIN32)
7342 fptr_finalize(fptr, noraise);
7344 pipe_del_fptr(fptr);
7351#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7352 void (*
const old_finalize)(
struct rb_io*,int) = fptr->
finalize;
7354 if (old_finalize == orig->finalize)
return;
7359#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7360 if (old_finalize != pipe_finalize) {
7362 for (list =
pipe_list; list; list = list->next) {
7363 if (list->fptr == fptr)
break;
7365 if (!list) pipe_add_fptr(fptr);
7368 pipe_del_fptr(fptr);
7381rb_io_unbuffered(
rb_io_t *fptr)
7399#define HAVE_SPAWNV 1
7400#define spawnv(mode, cmd, args) rb_w32_uaspawn((mode), (cmd), (args))
7401#define spawn(mode, cmd) rb_w32_uspawn((mode), (cmd), 0)
7404#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7414#ifdef HAVE_WORKING_FORK
7415# ifndef __EMSCRIPTEN__
7417popen_redirect(
struct popen_arg *p)
7420 close(p->write_pair[1]);
7421 if (p->write_pair[0] != 0) {
7422 dup2(p->write_pair[0], 0);
7423 close(p->write_pair[0]);
7426 if (p->pair[1] != 1) {
7427 dup2(p->pair[1], 1);
7433 if (p->pair[1] != 1) {
7434 dup2(p->pair[1], 1);
7440 if (p->pair[0] != 0) {
7441 dup2(p->pair[0], 0);
7448#if defined(__linux__)
7459linux_get_maxfd(
void)
7462 char buf[4096], *p, *np, *e;
7465 if (fd < 0)
return fd;
7466 ss = read(fd, buf,
sizeof(buf));
7467 if (ss < 0)
goto err;
7470 while ((
int)
sizeof(
"FDSize:\t0\n")-1 <= e-p &&
7471 (np = memchr(p,
'\n', e-p)) != NULL) {
7472 if (memcmp(p,
"FDSize:",
sizeof(
"FDSize:")-1) == 0) {
7474 p +=
sizeof(
"FDSize:")-1;
7494#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
7496 int max = (int)max_file_descriptor;
7499 ret = fcntl(0, F_MAXFD);
7501 maxhint = max = ret;
7502# elif defined(__linux__)
7503 ret = linux_get_maxfd();
7510 for (fd = lowfd; fd <= max; fd++) {
7511 if (!
NIL_P(noclose_fds) &&
7514 ret = fcntl(fd, F_GETFD);
7515 if (ret != -1 && !(ret & FD_CLOEXEC)) {
7516 fcntl(fd, F_SETFD, ret|FD_CLOEXEC);
7518# define CONTIGUOUS_CLOSED_FDS 20
7520 if (max < fd + CONTIGUOUS_CLOSED_FDS)
7521 max = fd + CONTIGUOUS_CLOSED_FDS;
7527# ifndef __EMSCRIPTEN__
7529popen_exec(
void *pp,
char *errmsg,
size_t errmsg_len)
7531 struct popen_arg *p = (
struct popen_arg*)pp;
7533 return rb_exec_async_signal_safe(p->eargp, errmsg, errmsg_len);
7538#if (defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)) && !defined __EMSCRIPTEN__
7540rb_execarg_fixup_v(
VALUE execarg_obj)
7542 rb_execarg_parent_start(execarg_obj);
7546char *rb_execarg_commandline(
const struct rb_execarg *eargp,
VALUE *prog);
7549#ifndef __EMSCRIPTEN__
7551pipe_open(
VALUE execarg_obj,
const char *modestr,
enum rb_io_mode fmode,
7554 struct rb_execarg *eargp =
NIL_P(execarg_obj) ? NULL : rb_execarg_get(execarg_obj);
7555 VALUE prog = eargp ? (eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name) :
Qfalse ;
7561#if defined(HAVE_WORKING_FORK)
7563 char errmsg[80] = {
'\0' };
7565#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7567 struct popen_arg arg;
7570#if defined(HAVE_SPAWNV)
7571# if defined(HAVE_SPAWNVE)
7572# define DO_SPAWN(cmd, args, envp) ((args) ? \
7573 spawnve(P_NOWAIT, (cmd), (args), (envp)) : \
7574 spawne(P_NOWAIT, (cmd), (envp)))
7576# define DO_SPAWN(cmd, args, envp) ((args) ? \
7577 spawnv(P_NOWAIT, (cmd), (args)) : \
7578 spawn(P_NOWAIT, (cmd)))
7580# if !defined(HAVE_WORKING_FORK)
7582# if defined(HAVE_SPAWNVE)
7587#if !defined(HAVE_WORKING_FORK)
7593#if !defined(HAVE_WORKING_FORK)
7594 const char *cmd = 0;
7600#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7601 arg.execarg_obj = execarg_obj;
7604 arg.pair[0] = arg.pair[1] = -1;
7605 arg.write_pair[0] = arg.write_pair[1] = -1;
7606# if !defined(HAVE_WORKING_FORK)
7607 if (eargp && !eargp->use_shell) {
7608 args = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
7613 if (
rb_pipe(arg.write_pair) < 0)
7614 rb_sys_fail_str(prog);
7617 close(arg.write_pair[0]);
7618 close(arg.write_pair[1]);
7622 rb_execarg_addopt(execarg_obj,
INT2FIX(0),
INT2FIX(arg.write_pair[0]));
7623 rb_execarg_addopt(execarg_obj,
INT2FIX(1),
INT2FIX(arg.pair[1]));
7628 rb_sys_fail_str(prog);
7630 rb_execarg_addopt(execarg_obj,
INT2FIX(1),
INT2FIX(arg.pair[1]));
7634 rb_sys_fail_str(prog);
7636 rb_execarg_addopt(execarg_obj,
INT2FIX(0),
INT2FIX(arg.pair[0]));
7639 rb_sys_fail_str(prog);
7641 if (!
NIL_P(execarg_obj)) {
7642 rb_protect(rb_execarg_fixup_v, execarg_obj, &state);
7644 if (0 <= arg.write_pair[0]) close(arg.write_pair[0]);
7645 if (0 <= arg.write_pair[1]) close(arg.write_pair[1]);
7646 if (0 <= arg.pair[0]) close(arg.pair[0]);
7647 if (0 <= arg.pair[1]) close(arg.pair[1]);
7648 rb_execarg_parent_end(execarg_obj);
7652# if defined(HAVE_WORKING_FORK)
7653 pid = rb_fork_async_signal_safe(&status, popen_exec, &arg, arg.eargp->redirect_fds, errmsg,
sizeof(errmsg));
7655 rb_execarg_run_options(eargp, sargp, NULL, 0);
7656# if defined(HAVE_SPAWNVE)
7657 if (eargp->envp_str) envp = (
char **)RSTRING_PTR(eargp->envp_str);
7659 while ((pid = DO_SPAWN(cmd, args, envp)) < 0) {
7661 switch (e =
errno) {
7663# if EWOULDBLOCK != EAGAIN
7672 rb_execarg_run_options(sargp, NULL, NULL, 0);
7674 rb_execarg_parent_end(execarg_obj);
7677# if defined(HAVE_WORKING_FORK)
7678 pid = rb_call_proc__fork();
7680 popen_redirect(&arg);
7692# if defined(HAVE_WORKING_FORK)
7698 close(arg.write_pair[0]);
7699 close(arg.write_pair[1]);
7701# if defined(HAVE_WORKING_FORK)
7710 close(arg.write_pair[0]);
7711 write_fd = arg.write_pair[1];
7722 cmd = rb_execarg_commandline(eargp, &prog);
7723 if (!
NIL_P(execarg_obj)) {
7724 rb_execarg_parent_start(execarg_obj);
7725 rb_execarg_run_options(eargp, sargp, NULL, 0);
7727 fp = popen(cmd, modestr);
7730 rb_execarg_parent_end(execarg_obj);
7731 rb_execarg_run_options(sargp, NULL, NULL, 0);
7733 if (!fp) rb_syserr_fail_path(e, prog);
7743 fptr->
encs = *convconfig;
7744#if RUBY_CRLF_ENVIRONMENT
7751 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
7754#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7755 if (NEED_NEWLINE_DECORATOR_ON_WRITE(fptr)) {
7756 fptr->
encs.
ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
7762 if (0 <= write_fd) {
7763 write_port = io_alloc(
rb_cIO);
7765 write_fptr->
fd = write_fd;
7767 fptr->
mode &= ~FMODE_WRITABLE;
7769 rb_ivar_set(port, rb_intern(
"@tied_io_for_writing"), write_port);
7772#if defined (__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7774 pipe_add_fptr(fptr);
7780pipe_open(
VALUE execarg_obj,
const char *modestr,
enum rb_io_mode fmode,
7788is_popen_fork(
VALUE prog)
7790 if (RSTRING_LEN(prog) == 1 && RSTRING_PTR(prog)[0] ==
'-') {
7791#if !defined(HAVE_WORKING_FORK)
7793 "fork() function is unimplemented on this machine");
7802pipe_open_s(
VALUE prog,
const char *modestr,
enum rb_io_mode fmode,
7806 VALUE *argv = &prog;
7809 if (!is_popen_fork(prog))
7810 execarg_obj = rb_execarg_new(argc, argv, TRUE, FALSE);
7811 return pipe_open(execarg_obj, modestr, fmode, convconfig);
7817 rb_io_t *fptr = io_close_fptr(io);
7986rb_io_s_popen(
int argc,
VALUE *argv,
VALUE klass)
7990 if (argc > 1 && !
NIL_P(opt = rb_check_hash_type(argv[argc-1]))) --argc;
7991 if (argc > 1 && !
NIL_P(env = rb_check_hash_type(argv[0]))) --argc, ++argv;
8000 int ex = !
NIL_P(opt);
8001 rb_error_arity(argc + ex, 1 + ex, 2 + ex);
8004 return popen_finish(rb_io_popen(pname, pmode, env, opt), klass);
8010 const char *modestr;
8013 enum rb_io_mode fmode;
8019#if SIZEOF_LONG > SIZEOF_INT
8020 if (
len > INT_MAX) {
8021 rb_raise(rb_eArgError,
"too many arguments");
8030 if (!is_popen_fork(pname))
8031 execarg_obj = rb_execarg_new(1, &pname, TRUE, FALSE);
8033 if (!
NIL_P(execarg_obj)) {
8035 opt = rb_execarg_extract_options(execarg_obj, opt);
8037 rb_execarg_setenv(execarg_obj, env);
8040 modestr = rb_io_oflags_modestr(oflags);
8042 return pipe_open(execarg_obj, modestr, fmode, &convconfig);
8052 rb_io_flush(rb_ractor_stdout());
8053 rb_io_flush(rb_ractor_stderr());
8058 RBASIC_SET_CLASS(port, klass);
8065#if defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)
8066struct popen_writer_arg {
8068 struct popen_arg popen;
8072exec_popen_writer(
void *arg,
char *errmsg,
size_t buflen)
8074 struct popen_writer_arg *pw = arg;
8076 popen_redirect(&pw->popen);
8077 execv(pw->argv[0], pw->argv);
8078 strlcpy(errmsg, strerror(
errno), buflen);
8084ruby_popen_writer(
char *
const *argv, rb_pid_t *pid)
8086#if (defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)) || defined(_WIN32)
8087# ifdef HAVE_WORKING_FORK
8088 struct popen_writer_arg pw;
8089 int *
const write_pair = pw.popen.pair;
8097# ifdef HAVE_WORKING_FORK
8100 char errmsg[80] = {
'\0'};
8101 *pid = rb_fork_async_signal_safe(&status, exec_popen_writer, &pw,
Qnil, errmsg,
sizeof(errmsg));
8103 *pid = rb_w32_uspawn_process(P_NOWAIT, argv[0], argv, write_pair[0], -1, -1, 0);
8104 const char *errmsg = (*pid < 0) ? strerror(
errno) : NULL;
8106 close(write_pair[0]);
8108 close(write_pair[1]);
8109 fprintf(stderr,
"ruby_popen_writer(%s): %s\n", argv[0], errmsg);
8112 return fdopen(write_pair[1],
"w");
8123 enum rb_io_mode fmode;
8132 rb_file_open_generic(io, fname, oflags, fmode, &convconfig, perm);
8170rb_io_s_open(
int argc,
VALUE *argv,
VALUE klass)
8202 VALUE fname, vmode, vperm;
8207 rb_scan_args(argc, argv,
"12", &fname, &vmode, &vperm);
8218 if (
NIL_P(vperm)) perm = 0666;
8222 fd = rb_sysopen(fname, oflags, perm);
8227check_pipe_command(
VALUE filename_or_command)
8229 char *s = RSTRING_PTR(filename_or_command);
8230 long l = RSTRING_LEN(filename_or_command);
8234 if (rb_enc_ascget(s, e, &chlen, rb_enc_get(filename_or_command)) ==
'|') {
8272 int redirect = FALSE;
8280 VALUE tmp = argv[0];
8286 VALUE cmd = check_pipe_command(tmp);
8289 rb_warn_deprecated_to_remove_at(4.0,
"Calling Kernel#open with a leading '|'",
"IO.popen");
8291 return rb_io_s_popen(argc, argv,
rb_cIO);
8304 return rb_io_s_open(argc, argv,
rb_cFile);
8308rb_io_open_generic(
VALUE klass,
VALUE filename,
int oflags,
enum rb_io_mode fmode,
8312 if (klass ==
rb_cIO && !
NIL_P(cmd = check_pipe_command(filename))) {
8314 rb_warn_deprecated_to_remove_at(4.0,
"IO process creation with a leading '|'",
"IO.popen");
8315 return pipe_open_s(cmd, rb_io_oflags_modestr(oflags), fmode, convconfig);
8318 return rb_file_open_generic(io_alloc(klass), filename,
8319 oflags, fmode, convconfig, perm);
8327 enum rb_io_mode fmode;
8333 return rb_io_open_generic(io, filename, oflags, fmode, &convconfig, perm);
8347 if (fptr == orig)
return io;
8348 if (RUBY_IO_EXTERNAL_P(fptr)) {
8352 rb_raise(rb_eArgError,
8353 "%s can't change access mode from \"%s\" to \"%s\"",
8354 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->
mode),
8355 rb_io_fmode_modestr(orig->
mode));
8359 if (io_fflush(fptr) < 0)
8360 rb_sys_fail_on_write(fptr);
8363 flush_before_seek(fptr,
true);
8366 pos = io_tell(orig);
8369 if (io_fflush(orig) < 0)
8370 rb_sys_fail_on_write(fptr);
8379 else if (!RUBY_IO_EXTERNAL_P(fptr)) fptr->
pathv =
Qnil;
8380 fptr_copy_finalizer(fptr, orig);
8386 rb_thread_io_close_interrupt(fptr);
8387 rb_thread_io_close_wait(fptr);
8389 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2 || !fptr->stdio_file) {
8392 rb_sys_fail_path(orig->
pathv);
8400 rb_sys_fail_path(orig->
pathv);
8406 if (io_seek(fptr, pos, SEEK_SET) < 0 &&
errno) {
8407 rb_sys_fail_path(fptr->
pathv);
8409 if (io_seek(orig, pos, SEEK_SET) < 0 &&
errno) {
8410 rb_sys_fail_path(orig->
pathv);
8424int rb_freopen(
VALUE fname,
const char *mode,
FILE *fp);
8427rb_freopen(
VALUE fname,
const char *mode,
FILE *fp)
8429 if (!freopen(RSTRING_PTR(fname), mode, fp)) {
8472rb_io_reopen(
int argc,
VALUE *argv,
VALUE file)
8474 VALUE fname, nmode, opt;
8478 if (
rb_scan_args(argc, argv,
"11:", &fname, &nmode, &opt) == 1) {
8481 return io_reopen(file, tmp);
8487 fptr =
RFILE(file)->fptr;
8493 enum rb_io_mode fmode;
8497 if (RUBY_IO_EXTERNAL_P(fptr) &&
8500 rb_raise(rb_eArgError,
8501 "%s can't change access mode from \"%s\" to \"%s\"",
8502 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->
mode),
8503 rb_io_fmode_modestr(fmode));
8506 fptr->
encs = convconfig;
8509 oflags = rb_io_fmode_oflags(fptr->
mode);
8512 fptr->
pathv = fname;
8514 fptr->
fd = rb_sysopen(fptr->
pathv, oflags, 0666);
8520 if (io_fflush(fptr) < 0)
8521 rb_sys_fail_on_write(fptr);
8526 int e = rb_freopen(rb_str_encode_ospath(fptr->
pathv),
8527 rb_io_oflags_modestr(oflags),
8529 if (e) rb_syserr_fail_path(e, fptr->
pathv);
8533 if (setvbuf(fptr->
stdio_file, NULL, _IOFBF, 0) != 0)
8534 rb_warn(
"setvbuf() can't be honoured for %"PRIsVALUE, fptr->
pathv);
8537 if (setvbuf(fptr->
stdio_file, NULL, _IONBF, BUFSIZ) != 0)
8538 rb_warn(
"setvbuf() can't be honoured for %"PRIsVALUE, fptr->
pathv);
8540 else if (fptr->
stdio_file == stdout && isatty(fptr->
fd)) {
8541 if (setvbuf(fptr->
stdio_file, NULL, _IOLBF, BUFSIZ) != 0)
8542 rb_warn(
"setvbuf() can't be honoured for %"PRIsVALUE, fptr->
pathv);
8546 int tmpfd = rb_sysopen(fptr->
pathv, oflags, 0666);
8552 rb_syserr_fail_path(err, fptr->
pathv);
8576 fptr->
mode = orig->
mode & ~FMODE_EXTERNAL;
8583 fptr->closing_ec = NULL;
8584 fptr->wakeup_mutex =
Qnil;
8585 fptr->fork_generation = GET_VM()->fork_gen;
8588 fptr_copy_finalizer(fptr, orig);
8590 fd = ruby_dup(orig->
fd);
8592 pos = io_tell(orig);
8594 io_seek(fptr, pos, SEEK_SET);
8599 write_io = GetWriteIO(io);
8600 if (io != write_io) {
8603 rb_ivar_set(dest, rb_intern(
"@tied_io_for_writing"), write_io);
8666 if (argc == 0)
return Qnil;
8668 out = rb_ractor_stdout();
8685 rb_warn_deprecated(
"'%s'", NULL, rb_id2name(
id));
8695 rb_raise(
rb_eTypeError,
"value of %"PRIsVALUE
" must be String", rb_id2str(
id));
8701 val = rb_str_frozen_bare_string(val);
8704 rb_warn_deprecated(
"'%s'", NULL, rb_id2name(
id));
8780 for (i=0; i<argc; i++) {
8784 rb_io_write(out, argv[i]);
8881 rb_io_write(io, str);
8885#define forward(obj, id, argc, argv) \
8886 rb_funcallv_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8887#define forward_public(obj, id, argc, argv) \
8888 rb_funcallv_public_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8889#define forward_current(id, argc, argv) \
8890 forward_public(ARGF.current_file, id, argc, argv)
8907 VALUE r_stdout = rb_ractor_stdout();
8908 if (recv == r_stdout) {
8909 return rb_io_putc(recv, ch);
8911 return forward(r_stdout, rb_intern(
"putc"), 1, &ch);
8916rb_str_end_with_asciichar(
VALUE str,
int c)
8918 long len = RSTRING_LEN(str);
8919 const char *
ptr = RSTRING_PTR(str);
8923 if (
len == 0)
return 0;
8924 if ((n = rb_enc_mbminlen(
enc)) == 1) {
8925 return ptr[
len - 1] == c;
8927 return rb_enc_ascget(
ptr + ((
len - 1) / n) * n,
ptr +
len, &n,
enc) == c;
8938 rb_io_puts(1, &tmp, out);
8945 rb_io_puts(1, &tmp, out);
9000 VALUE line, args[2];
9007 for (
int i = 0; i < argc; i++) {
9021 if (RSTRING_LEN(line) == 0) {
9026 if (!rb_str_end_with_asciichar(line,
'\n')) {
9031 rb_io_writev(out, n, args);
9049 VALUE r_stdout = rb_ractor_stdout();
9050 if (recv == r_stdout) {
9051 return rb_io_puts(argc, argv, recv);
9053 return forward(r_stdout, rb_intern(
"puts"), argc, argv);
9057rb_p_write(
VALUE str)
9062 VALUE r_stdout = rb_ractor_stdout();
9064 rb_method_basic_definition_p(
CLASS_OF(r_stdout), id_write)) {
9065 io_writev(2, args, r_stdout);
9068 rb_io_writev(r_stdout, 2, args);
9080rb_p_result(
int argc,
const VALUE *argv)
9087 else if (argc > 1) {
9090 VALUE r_stdout = rb_ractor_stdout();
9092 rb_uninterruptible(rb_io_flush, r_stdout);
9133 for (i=0; i<argc; i++) {
9135 rb_uninterruptible(rb_p_write, inspected);
9137 return rb_p_result(argc, argv);
9158rb_obj_display(
int argc,
VALUE *argv,
VALUE self)
9162 out = (!
rb_check_arity(argc, 0, 1) ? rb_ractor_stdout() : argv[0]);
9163 rb_io_write(out, self);
9169rb_stderr_to_original_p(
VALUE err)
9171 return (err == orig_stderr ||
RFILE(orig_stderr)->fptr->
fd < 0);
9177 VALUE out = rb_ractor_stderr();
9178 if (rb_stderr_to_original_p(out)) {
9180 if (isatty(fileno(stderr))) {
9181 if (rb_w32_write_console(
rb_str_new(mesg,
len), fileno(stderr)) > 0)
return;
9184 if (fwrite(mesg,
sizeof(
char), (
size_t)
len, stderr) < (
size_t)
len) {
9201rb_write_error_str(
VALUE mesg)
9203 VALUE out = rb_ractor_stderr();
9205 if (rb_stderr_to_original_p(out)) {
9206 size_t len = (size_t)RSTRING_LEN(mesg);
9208 if (isatty(fileno(stderr))) {
9209 if (rb_w32_write_console(mesg, fileno(stderr)) > 0)
return;
9212 if (fwrite(RSTRING_PTR(mesg),
sizeof(
char),
len, stderr) <
len) {
9219 rb_io_write(out, mesg);
9224rb_stderr_tty_p(
void)
9226 if (rb_stderr_to_original_p(rb_ractor_stderr()))
9227 return isatty(fileno(stderr));
9232must_respond_to(
ID mid,
VALUE val,
ID id)
9235 rb_raise(
rb_eTypeError,
"%"PRIsVALUE
" must have %"PRIsVALUE
" method, %"PRIsVALUE
" given",
9236 rb_id2str(
id), rb_id2str(mid),
9256 must_respond_to(id_write, val,
id);
9263 return rb_ractor_stdout();
9269 must_respond_to(id_write, val,
id);
9276 return rb_ractor_stderr();
9280allocate_and_open_new_file(
VALUE klass)
9282 VALUE self = io_alloc(klass);
9283 rb_io_make_open_file(self);
9291 VALUE self = rb_protect(allocate_and_open_new_file, klass, &state);
9299 maygvl_close(descriptor, 0);
9307 io->
fd = descriptor;
9325 io->closing_ec = NULL;
9326 io->wakeup_mutex =
Qnil;
9327 io->fork_generation = GET_VM()->fork_gen;
9330 io->
encs = *encoding;
9339prep_io(
int fd,
enum rb_io_mode fmode,
VALUE klass,
const char *path)
9349 e = (fmode &
FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
9350 rb_io_ext_int_to_encs(e, NULL, &convconfig.
enc, &convconfig.
enc2, fmode);
9354#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9356 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
9357 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
9359 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.
enc2, convconfig.
ecflags);
9365 if (!io_check_tty(io)) {
9368 setmode(fd, O_BINARY);
9380 if (path && strcmp(path,
"-")) klass =
rb_cFile;
9381 return prep_io(fd, rb_io_oflags_fmode(oflags), klass, path);
9385prep_stdio(
FILE *f,
enum rb_io_mode fmode,
VALUE klass,
const char *path)
9392#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9393 fptr->
encs.
ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
9404rb_io_prep_stdin(
void)
9410rb_io_prep_stdout(
void)
9416rb_io_prep_stderr(
void)
9425 int oflags = rb_io_fmode_oflags(fptr->
mode) & ~O_EXCL;
9452 rb_io_buffer_init(&fp->
wbuf);
9453 rb_io_buffer_init(&fp->
rbuf);
9454 rb_io_buffer_init(&fp->
cbuf);
9469 fp->closing_ec = NULL;
9470 fp->wakeup_mutex =
Qnil;
9471 fp->fork_generation = GET_VM()->fork_gen;
9476rb_io_make_open_file(
VALUE obj)
9481 if (
RFILE(obj)->fptr) {
9484 RFILE(obj)->fptr = 0;
9486 fp = rb_io_fptr_new();
9488 RFILE(obj)->fptr = fp;
9536rb_io_initialize(
int argc,
VALUE *argv,
VALUE io)
9542 return io_initialize(io, fnum, vmode, opt);
9549 int fd, oflags = O_RDONLY;
9550 enum rb_io_mode fmode;
9552#if defined(HAVE_FCNTL) && defined(F_GETFL)
9562 rb_raise(rb_eArgError,
"The given fd is not accessible because RubyVM reserves it");
9564#if defined(HAVE_FCNTL) && defined(F_GETFL)
9565 oflags = fcntl(fd, F_GETFL);
9566 if (oflags == -1) rb_sys_fail(0);
9568 if (fstat(fd, &st) < 0) rb_sys_fail(0);
9571#if defined(HAVE_FCNTL) && defined(F_GETFL)
9572 ofmode = rb_io_oflags_fmode(oflags);
9584 if (rb_hash_aref(opt, sym_autoclose) ==
Qfalse) {
9588 path = rb_hash_aref(opt,
RB_ID2SYM(idPath));
9599 fp->
encs = convconfig;
9603 fp->closing_ec = NULL;
9604 fp->wakeup_mutex =
Qnil;
9605 fp->fork_generation = GET_VM()->fork_gen;
9608 if (fileno(stdin) == fd)
9610 else if (fileno(stdout) == fd)
9612 else if (fileno(stderr) == fd)
9644rb_io_set_encoding_by_bom(
VALUE io)
9650 rb_raise(rb_eArgError,
"ASCII incompatible encoding needs binmode");
9653 rb_raise(rb_eArgError,
"encoding conversion is set");
9655 else if (fptr->
encs.
enc && fptr->
encs.
enc != rb_ascii8bit_encoding()) {
9656 rb_raise(rb_eArgError,
"encoding is set to %s already",
9659 if (!io_set_encoding_by_bom(io))
return Qnil;
9660 return rb_enc_from_encoding(fptr->
encs.
enc);
9705rb_file_initialize(
int argc,
VALUE *argv,
VALUE io)
9707 if (
RFILE(io)->fptr) {
9710 VALUE fname, vmode, vperm, opt;
9711 int posargc =
rb_scan_args(argc, argv,
"12:", &fname, &vmode, &vperm, &opt);
9716 return io_initialize(io, fd, vmode, opt);
9719 return rb_open_file(io, fname, vmode, vperm, opt);
9724rb_io_s_new(
int argc,
VALUE *argv,
VALUE klass)
9729 rb_warn(
"%"PRIsVALUE
"::new() does not take block; use %"PRIsVALUE
"::open() instead",
9745rb_io_s_for_fd(
int argc,
VALUE *argv,
VALUE klass)
9748 rb_io_initialize(argc, argv, io);
9761rb_io_autoclose_p(
VALUE io)
9786rb_io_set_autoclose(
VALUE io,
VALUE autoclose)
9790 if (!
RTEST(autoclose))
9793 fptr->
mode &= ~FMODE_EXTERNAL;
9798io_wait_event(
VALUE io,
int event,
VALUE timeout,
int return_io)
9830io_wait_readable(
int argc,
VALUE *argv,
VALUE io)
9837 if (rb_io_read_pending(fptr))
return Qtrue;
9840 VALUE timeout = (argc == 1 ? argv[0] :
Qnil);
9854io_wait_writable(
int argc,
VALUE *argv,
VALUE io)
9862 VALUE timeout = (argc == 1 ? argv[0] :
Qnil);
9877io_wait_priority(
int argc,
VALUE *argv,
VALUE io)
9884 if (rb_io_read_pending(fptr))
return Qtrue;
9887 VALUE timeout = argc == 1 ? argv[0] :
Qnil;
9893wait_mode_sym(
VALUE mode)
9895 if (mode ==
ID2SYM(rb_intern(
"r"))) {
9896 return RB_WAITFD_IN;
9898 if (mode ==
ID2SYM(rb_intern(
"read"))) {
9899 return RB_WAITFD_IN;
9901 if (mode ==
ID2SYM(rb_intern(
"readable"))) {
9902 return RB_WAITFD_IN;
9904 if (mode ==
ID2SYM(rb_intern(
"w"))) {
9905 return RB_WAITFD_OUT;
9907 if (mode ==
ID2SYM(rb_intern(
"write"))) {
9908 return RB_WAITFD_OUT;
9910 if (mode ==
ID2SYM(rb_intern(
"writable"))) {
9911 return RB_WAITFD_OUT;
9913 if (mode ==
ID2SYM(rb_intern(
"rw"))) {
9914 return RB_WAITFD_IN|RB_WAITFD_OUT;
9916 if (mode ==
ID2SYM(rb_intern(
"read_write"))) {
9917 return RB_WAITFD_IN|RB_WAITFD_OUT;
9919 if (mode ==
ID2SYM(rb_intern(
"readable_writable"))) {
9920 return RB_WAITFD_IN|RB_WAITFD_OUT;
9923 rb_raise(rb_eArgError,
"unsupported mode: %"PRIsVALUE, mode);
9927io_event_from_value(
VALUE value)
9931 if (events <= 0) rb_raise(rb_eArgError,
"Events must be positive integer!");
9969 for (
int i = 0; i < argc; i += 1) {
9971 events |= wait_mode_sym(argv[i]);
9973 else if (UNDEF_P(timeout)) {
9977 rb_raise(rb_eArgError,
"timeout given more than once");
9981 if (UNDEF_P(timeout)) timeout =
Qnil;
9989 events = io_event_from_value(argv[0]);
9997 if (rb_io_read_pending(fptr)) {
9999 if (return_io)
return Qtrue;
10005 return io_wait_event(io, events, timeout, return_io);
10009argf_mark_and_move(
void *ptr)
10011 struct argf *p = ptr;
10012 rb_gc_mark_and_move(&p->filename);
10013 rb_gc_mark_and_move(&p->current_file);
10014 rb_gc_mark_and_move(&p->argv);
10015 rb_gc_mark_and_move(&p->inplace);
10016 rb_gc_mark_and_move(&p->encs.
ecopts);
10020argf_memsize(
const void *ptr)
10022 const struct argf *p = ptr;
10023 size_t size =
sizeof(*p);
10030 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
10036 p->filename =
Qnil;
10037 p->current_file =
Qnil;
10043argf_alloc(
VALUE klass)
10048 argf_init(p,
Qnil);
10058 memset(&ARGF, 0,
sizeof(ARGF));
10059 argf_init(&ARGF, argv);
10069 ARGF = argf_of(orig);
10096 ARGF.last_lineno = ARGF.lineno;
10122 return forward_current(rb_frame_this_func(), argc, argv);
10125#define next_argv() argf_next_argv(argf)
10126#define ARGF_GENERIC_INPUT_P() \
10127 (ARGF.current_file == rb_stdin && !RB_TYPE_P(ARGF.current_file, T_FILE))
10128#define ARGF_FORWARD(argc, argv) do {\
10129 if (ARGF_GENERIC_INPUT_P())\
10130 return argf_forward((argc), (argv), argf);\
10132#define NEXT_ARGF_FORWARD(argc, argv) do {\
10133 if (!next_argv()) return Qnil;\
10134 ARGF_FORWARD((argc), (argv));\
10140 VALUE file = ARGF.current_file;
10154 int stdout_binmode = 0;
10155 enum rb_io_mode fmode;
10157 VALUE r_stdout = rb_ractor_stdout();
10162 stdout_binmode = 1;
10165 if (ARGF.init_p == 0) {
10175 if (
NIL_P(ARGF.argv)) {
10178 else if (ARGF.next_p == -1 &&
RARRAY_LEN(ARGF.argv) > 0) {
10183 if (ARGF.next_p == 1) {
10184 if (ARGF.init_p == 1) argf_close(
argf);
10189 ARGF.filename = filename;
10190 filename = rb_str_encode_ospath(filename);
10192 if (RSTRING_LEN(filename) == 1 && fn[0] ==
'-') {
10194 if (ARGF.inplace) {
10195 rb_warn(
"Can't do inplace edit for stdio; skipping");
10201 int fr = rb_sysopen(filename, O_RDONLY, 0);
10203 if (ARGF.inplace) {
10205#ifndef NO_SAFE_RENAME
10216 if (!
NIL_P(ARGF.inplace)) {
10217 VALUE suffix = ARGF.inplace;
10219 if (
NIL_P(rb_str_cat_conv_enc_opts(str, RSTRING_LEN(str),
10220 RSTRING_PTR(suffix), RSTRING_LEN(suffix),
10221 rb_enc_get(suffix), 0,
Qnil))) {
10224#ifdef NO_SAFE_RENAME
10226 (void)unlink(RSTRING_PTR(str));
10227 if (rename(fn, RSTRING_PTR(str)) < 0) {
10228 rb_warn(
"Can't rename %"PRIsVALUE
" to %"PRIsVALUE
": %s, skipping file",
10229 filename, str, strerror(
errno));
10232 fr = rb_sysopen(str, O_RDONLY, 0);
10234 if (rename(fn, RSTRING_PTR(str)) < 0) {
10235 rb_warn(
"Can't rename %"PRIsVALUE
" to %"PRIsVALUE
": %s, skipping file",
10236 filename, str, strerror(
errno));
10243#ifdef NO_SAFE_RENAME
10244 rb_fatal(
"Can't do inplace edit without backup");
10246 if (unlink(fn) < 0) {
10247 rb_warn(
"Can't remove %"PRIsVALUE
": %s, skipping file",
10248 filename, strerror(
errno));
10254 fw = rb_sysopen(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666);
10255#ifndef NO_SAFE_RENAME
10258 fchmod(fw, st.st_mode);
10260 chmod(fn, st.st_mode);
10262 if (st.st_uid!=st2.st_uid || st.st_gid!=st2.st_gid) {
10265 err = fchown(fw, st.st_uid, st.st_gid);
10267 err = chown(fn, st.st_uid, st.st_gid);
10269 if (err && getuid() == 0 && st2.st_uid == 0) {
10270 const char *wkfn = RSTRING_PTR(filename);
10271 rb_warn(
"Can't set owner/group of %"PRIsVALUE
" to same as %"PRIsVALUE
": %s, skipping file",
10272 filename, str, strerror(
errno));
10275 (void)unlink(wkfn);
10285 if (!ARGF.binmode) {
10286 fmode |= DEFAULT_TEXTMODE;
10288 ARGF.current_file = prep_io(fr, fmode,
rb_cFile, fn);
10289 if (!
NIL_P(write_io)) {
10296 if (ARGF.encs.enc) {
10297 fptr->
encs = ARGF.encs;
10298 clear_codeconv(fptr);
10301 fptr->
encs.
ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
10302 if (!ARGF.binmode) {
10304#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
10305 fptr->
encs.
ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
10316 else if (ARGF.next_p == -1) {
10319 if (ARGF.inplace) {
10320 rb_warn(
"Can't do inplace edit for stdio");
10324 if (ARGF.init_p == -1) ARGF.init_p = 1;
10332 long lineno = ARGF.lineno;
10335 if (!next_argv())
return Qnil;
10336 if (ARGF_GENERIC_INPUT_P()) {
10337 line = forward_current(idGets, argc, argv);
10344 line = rb_io_getline(argc, argv, ARGF.current_file);
10346 if (
NIL_P(line) && ARGF.next_p != -1) {
10352 if (!
NIL_P(line)) {
10353 ARGF.lineno = ++lineno;
10354 ARGF.last_lineno = ARGF.lineno;
10360argf_lineno_getter(
ID id,
VALUE *var)
10363 return INT2FIX(ARGF.last_lineno);
10371 ARGF.last_lineno = ARGF.lineno = n;
10375rb_reset_argf_lineno(
long n)
10377 ARGF.last_lineno = ARGF.lineno = n;
10418 if (recv ==
argf) {
10419 return argf_gets(argc, argv,
argf);
10421 return forward(
argf, idGets, argc, argv);
10447 line = argf_getline(argc, argv,
argf);
10459 return rb_f_gets(0, 0,
argf);
10463 if (!next_argv())
return Qnil;
10465 if (
NIL_P(line) && ARGF.next_p != -1) {
10471 if (!
NIL_P(line)) {
10473 ARGF.last_lineno = ARGF.lineno;
10499rb_f_readline(
int argc,
VALUE *argv,
VALUE recv)
10501 if (recv ==
argf) {
10502 return argf_readline(argc, argv,
argf);
10504 return forward(
argf, rb_intern(
"readline"), argc, argv);
10530 if (!next_argv()) rb_eof_error();
10531 ARGF_FORWARD(argc, argv);
10532 line = argf_gets(argc, argv,
argf);
10602rb_f_readlines(
int argc,
VALUE *argv,
VALUE recv)
10604 if (recv ==
argf) {
10605 return argf_readlines(argc, argv,
argf);
10607 return forward(
argf, rb_intern(
"readlines"), argc, argv);
10631 long lineno = ARGF.lineno;
10635 while (next_argv()) {
10636 if (ARGF_GENERIC_INPUT_P()) {
10637 lines = forward_current(rb_intern(
"readlines"), argc, argv);
10640 lines = rb_io_readlines(argc, argv, ARGF.current_file);
10646 ARGF.last_lineno = ARGF.lineno;
10681 rb_last_status_clear();
10682 port = pipe_open_s(str,
"r",
FMODE_READABLE|DEFAULT_TEXTMODE, NULL);
10686 result = read_all(fptr, remain_size(fptr),
Qnil);
10688 rb_io_fptr_cleanup_all(fptr);
10694#ifdef HAVE_SYS_SELECT_H
10695#include <sys/select.h>
10709 if (!
NIL_P(read)) {
10714 if (READ_DATA_PENDING(fptr) || READ_CHAR_PENDING(fptr)) {
10718 if (max < fptr->fd) max = fptr->
fd;
10721 timerec.tv_sec = timerec.tv_usec = 0;
10729 if (!
NIL_P(write)) {
10735 if (max < fptr->fd) max = fptr->
fd;
10742 if (!
NIL_P(except)) {
10746 VALUE write_io = GetWriteIO(io);
10749 if (max < fptr->fd) max = fptr->
fd;
10750 if (io != write_io) {
10753 if (max < fptr->fd) max = fptr->
fd;
10768 if (!pending && n == 0)
return Qnil;
10793 VALUE write_io = GetWriteIO(io);
10806 VALUE write_io = GetWriteIO(io);
10811 else if (io != write_io) {
10824 VALUE read, write, except;
10830select_call(
VALUE arg)
10834 return select_internal(p->read, p->write, p->except, p->timeout, p->fdsets);
10838select_end(
VALUE arg)
10843 for (i = 0; i < numberof(p->fdsets); ++i)
10848static VALUE sym_normal, sym_sequential, sym_random,
10849 sym_willneed, sym_dontneed, sym_noreuse;
10851#ifdef HAVE_POSIX_FADVISE
10852struct io_advise_struct {
10860io_advise_internal(
void *arg)
10862 struct io_advise_struct *ptr = arg;
10863 return posix_fadvise(ptr->fd, ptr->offset, ptr->len, ptr->advice);
10867io_advise_sym_to_const(
VALUE sym)
10869#ifdef POSIX_FADV_NORMAL
10870 if (sym == sym_normal)
10871 return INT2NUM(POSIX_FADV_NORMAL);
10874#ifdef POSIX_FADV_RANDOM
10875 if (sym == sym_random)
10876 return INT2NUM(POSIX_FADV_RANDOM);
10879#ifdef POSIX_FADV_SEQUENTIAL
10880 if (sym == sym_sequential)
10881 return INT2NUM(POSIX_FADV_SEQUENTIAL);
10884#ifdef POSIX_FADV_WILLNEED
10885 if (sym == sym_willneed)
10886 return INT2NUM(POSIX_FADV_WILLNEED);
10889#ifdef POSIX_FADV_DONTNEED
10890 if (sym == sym_dontneed)
10891 return INT2NUM(POSIX_FADV_DONTNEED);
10894#ifdef POSIX_FADV_NOREUSE
10895 if (sym == sym_noreuse)
10896 return INT2NUM(POSIX_FADV_NOREUSE);
10903do_io_advise(
rb_io_t *fptr,
VALUE advice, rb_off_t offset, rb_off_t
len)
10906 struct io_advise_struct ias;
10909 num_adv = io_advise_sym_to_const(advice);
10915 if (
NIL_P(num_adv))
10919 ias.advice =
NUM2INT(num_adv);
10920 ias.offset = offset;
10923 rv = (int)rb_io_blocking_region(fptr, io_advise_internal, &ias);
10924 if (rv && rv != ENOSYS) {
10927 VALUE message = rb_sprintf(
"%"PRIsVALUE
" "
10931 fptr->
pathv, offset,
len, advice);
10941advice_arg_check(
VALUE advice)
10946 if (advice != sym_normal &&
10947 advice != sym_sequential &&
10948 advice != sym_random &&
10949 advice != sym_willneed &&
10950 advice != sym_dontneed &&
10951 advice != sym_noreuse) {
10952 rb_raise(
rb_eNotImpError,
"Unsupported advice: %+"PRIsVALUE, advice);
10990rb_io_advise(
int argc,
VALUE *argv,
VALUE io)
10997 advice_arg_check(advice);
10999 io = GetWriteIO(io);
11005#ifdef HAVE_POSIX_FADVISE
11006 return do_io_advise(fptr, advice,
off, l);
11008 ((void)
off, (
void)l);
11020 return isinf(f) && 0 < f;
11176rb_f_select(
int argc,
VALUE *argv,
VALUE obj)
11179 if (scheduler !=
Qnil) {
11182 if (!UNDEF_P(result))
return result;
11190 rb_scan_args(argc, argv,
"13", &args.read, &args.write, &args.except, &timeout);
11191 if (
NIL_P(timeout) || is_pos_inf(timeout)) {
11196 args.timeout = &timerec;
11199 for (i = 0; i < numberof(args.fdsets); ++i)
11205#ifdef IOCTL_REQ_TYPE
11206 typedef IOCTL_REQ_TYPE ioctl_req_t;
11208 typedef int ioctl_req_t;
11209# define NUM2IOCTLREQ(num) ((int)NUM2LONG(num))
11220nogvl_ioctl(
void *ptr)
11222 struct ioctl_arg *arg = ptr;
11224 return (
VALUE)ioctl(arg->fd, arg->cmd, arg->narg);
11228do_ioctl(
struct rb_io *io, ioctl_req_t cmd,
long narg)
11231 struct ioctl_arg arg;
11237 retval = (int)rb_io_blocking_region(io, nogvl_ioctl, &arg);
11243#define DEFAULT_IOCTL_NARG_LEN (256)
11245#if defined(__linux__) && defined(_IOC_SIZE)
11247linux_iocparm_len(ioctl_req_t cmd)
11251 if ((cmd & 0xFFFF0000) == 0) {
11253 return DEFAULT_IOCTL_NARG_LEN;
11256 len = _IOC_SIZE(cmd);
11259 if (
len < DEFAULT_IOCTL_NARG_LEN)
11260 len = DEFAULT_IOCTL_NARG_LEN;
11268ioctl_narg_len(ioctl_req_t cmd)
11274#define IOCPARM_LEN(x) (((x) >> 16) & IOCPARM_MASK)
11278 len = IOCPARM_LEN(cmd);
11279#elif defined(__linux__) && defined(_IOC_SIZE)
11280 len = linux_iocparm_len(cmd);
11283 len = DEFAULT_IOCTL_NARG_LEN;
11292typedef long fcntl_arg_t;
11295typedef int fcntl_arg_t;
11299fcntl_narg_len(ioctl_req_t cmd)
11306 len =
sizeof(fcntl_arg_t);
11314#ifdef F_DUPFD_CLOEXEC
11315 case F_DUPFD_CLOEXEC:
11316 len =
sizeof(fcntl_arg_t);
11326 len =
sizeof(fcntl_arg_t);
11336 len =
sizeof(fcntl_arg_t);
11346 len =
sizeof(fcntl_arg_t);
11351 len =
sizeof(
struct f_owner_ex);
11356 len =
sizeof(
struct f_owner_ex);
11361 len =
sizeof(
struct flock);
11366 len =
sizeof(
struct flock);
11371 len =
sizeof(
struct flock);
11391 len =
sizeof(fcntl_arg_t);
11401 len =
sizeof(fcntl_arg_t);
11406 len =
sizeof(fcntl_arg_t);
11419fcntl_narg_len(ioctl_req_t cmd)
11425#define NARG_SENTINEL 17
11428setup_narg(ioctl_req_t cmd,
VALUE *argp,
long (*narg_len)(ioctl_req_t))
11439 else if (arg ==
Qtrue) {
11453 len = narg_len(cmd);
11454 rb_str_modify(arg);
11456 slen = RSTRING_LEN(arg);
11458 if (slen <
len+1) {
11459 rb_str_resize(arg,
len+1);
11460 MEMZERO(RSTRING_PTR(arg)+slen,
char,
len-slen);
11464 ptr = RSTRING_PTR(arg);
11465 ptr[slen - 1] = NARG_SENTINEL;
11474finish_narg(
int retval,
VALUE arg,
const rb_io_t *fptr)
11476 if (retval < 0) rb_sys_fail_path(fptr->
pathv);
11481 if (ptr[slen-1] != NARG_SENTINEL)
11482 rb_raise(rb_eArgError,
"return value overflowed string");
11483 ptr[slen-1] =
'\0';
11493 ioctl_req_t cmd = NUM2IOCTLREQ(req);
11498 narg = setup_narg(cmd, &arg, ioctl_narg_len);
11500 retval = do_ioctl(fptr, cmd, narg);
11501 return finish_narg(retval, arg, fptr);
11528 return rb_ioctl(io, req, arg);
11531#define rb_io_ioctl rb_f_notimplement
11542nogvl_fcntl(
void *ptr)
11544 struct fcntl_arg *arg = ptr;
11546#if defined(F_DUPFD)
11547 if (arg->cmd == F_DUPFD)
11550 return (
VALUE)fcntl(arg->fd, arg->cmd, arg->narg);
11554do_fcntl(
struct rb_io *io,
int cmd,
long narg)
11557 struct fcntl_arg arg;
11563 retval = (int)rb_io_blocking_region(io, nogvl_fcntl, &arg);
11564 if (retval != -1) {
11566#if defined(F_DUPFD)
11569#if defined(F_DUPFD_CLOEXEC)
11570 case F_DUPFD_CLOEXEC:
11587 narg = setup_narg(cmd, &arg, fcntl_narg_len);
11589 retval = do_fcntl(fptr, cmd, narg);
11590 return finish_narg(retval, arg, fptr);
11616 return rb_fcntl(io, req, arg);
11619#define rb_io_fcntl rb_f_notimplement
11622#if defined(HAVE_SYSCALL) || defined(HAVE___SYSCALL)
11654#if SIZEOF_VOIDP == 8 && defined(HAVE___SYSCALL) && SIZEOF_INT != 8
11655# define SYSCALL __syscall
11656# define NUM2SYSCALLID(x) NUM2LONG(x)
11657# define RETVAL2NUM(x) LONG2NUM(x)
11658# if SIZEOF_LONG == 8
11659 long num, retval = -1;
11660# elif SIZEOF_LONG_LONG == 8
11661 long long num, retval = -1;
11663# error ---->> it is asserted that __syscall takes the first argument and returns retval in 64bit signed integer. <<----
11665#elif defined(__linux__)
11666# define SYSCALL syscall
11667# define NUM2SYSCALLID(x) NUM2LONG(x)
11668# define RETVAL2NUM(x) LONG2NUM(x)
11676 long num, retval = -1;
11678# define SYSCALL syscall
11679# define NUM2SYSCALLID(x) NUM2INT(x)
11680# define RETVAL2NUM(x) INT2NUM(x)
11681 int num, retval = -1;
11687 "We plan to remove a syscall function at future release. DL(Fiddle) provides safer alternative.");
11691 rb_raise(rb_eArgError,
"too few arguments for syscall");
11692 if (argc > numberof(arg))
11693 rb_raise(rb_eArgError,
"too many arguments for syscall");
11694 num = NUM2SYSCALLID(argv[0]); ++argv;
11695 for (i = argc - 1; i--; ) {
11710 retval = SYSCALL(num);
11713 retval = SYSCALL(num, arg[0]);
11716 retval = SYSCALL(num, arg[0],arg[1]);
11719 retval = SYSCALL(num, arg[0],arg[1],arg[2]);
11722 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3]);
11725 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4]);
11728 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5]);
11731 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6]);
11737 return RETVAL2NUM(retval);
11739#undef NUM2SYSCALLID
11743#define rb_f_syscall rb_f_notimplement
11747io_new_instance(
VALUE args)
11753find_encoding(
VALUE v)
11756 if (!enc)
rb_warn(
"Unsupported encoding %"PRIsVALUE
" ignored", v);
11768 enc2 = find_encoding(v1);
11771 if (RSTRING_LEN(tmp) == 1 && RSTRING_PTR(tmp)[0] ==
'-') {
11777 enc = find_encoding(v2);
11784 enc = find_encoding(v2);
11790 if (enc2 == rb_ascii8bit_encoding()) {
11795 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11801 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
11802 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11807 if (!
NIL_P(tmp) && rb_enc_asciicompat(enc = rb_enc_get(tmp))) {
11808 parse_mode_enc(RSTRING_PTR(tmp), enc, &enc, &enc2, NULL);
11809 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11813 rb_io_ext_int_to_encs(find_encoding(v1), NULL, &enc, &enc2, 0);
11814 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11819 validate_enc_binmode(&fptr->
mode, ecflags, enc, enc2);
11824 clear_codeconv(fptr);
11836io_encoding_set_v(
VALUE v)
11839 io_encoding_set(arg->fptr, arg->v1, arg->v2, arg->opt);
11844pipe_pair_close(
VALUE rw)
11847 return rb_ensure(io_close, rwp[0], io_close, rwp[1]);
11930rb_io_s_pipe(
int argc,
VALUE *argv,
VALUE klass)
11932 int pipes[2], state;
11933 VALUE r, w, args[3], v1, v2;
11937 enum rb_io_mode fmode = 0;
11940 argc =
rb_scan_args(argc, argv,
"02:", &v1, &v2, &opt);
11947 r = rb_protect(io_new_instance, (
VALUE)args, &state);
11951 rb_jump_tag(state);
11955 ies_args.fptr = fptr;
11958 ies_args.opt = opt;
11959 rb_protect(io_encoding_set_v, (
VALUE)&ies_args, &state);
11963 rb_jump_tag(state);
11968 w = rb_protect(io_new_instance, (
VALUE)args, &state);
11972 rb_jump_tag(state);
11977 extract_binmode(opt, &fmode);
11984#if DEFAULT_TEXTMODE
11986 fptr->
mode &= ~FMODE_TEXTMODE;
11987 setmode(fptr->
fd, O_BINARY);
11989#if RUBY_CRLF_ENVIRONMENT
11995 fptr->
mode |= fmode;
11996#if DEFAULT_TEXTMODE
11998 fptr2->
mode &= ~FMODE_TEXTMODE;
11999 setmode(fptr2->
fd, O_BINARY);
12002 fptr2->
mode |= fmode;
12036 else if (!
NIL_P(v = rb_hash_aref(opt, sym_open_args))) {
12039 v = rb_to_array_type(v);
12044 arg->io = rb_io_open(klass, path, vmode, vperm, opt);
12048io_s_foreach(
VALUE v)
12053 if (arg->limit == 0)
12054 rb_raise(rb_eArgError,
"invalid limit: 0 for foreach");
12055 while (!
NIL_P(str = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, arg->io))) {
12143rb_io_s_foreach(
int argc,
VALUE *argv,
VALUE self)
12146 int orig_argc = argc;
12150 argc =
rb_scan_args(argc, argv,
"12:", NULL, NULL, NULL, &opt);
12152 extract_getline_args(argc-1, argv+1, &garg);
12153 open_key_args(self, argc, argv, opt, &arg);
12155 extract_getline_opts(opt, &garg);
12156 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12157 return rb_ensure(io_s_foreach, (
VALUE)&garg, rb_io_close, arg.io);
12161io_s_readlines(
VALUE v)
12164 return io_readlines(arg, arg->io);
12221rb_io_s_readlines(
int argc,
VALUE *argv,
VALUE io)
12227 argc =
rb_scan_args(argc, argv,
"12:", NULL, NULL, NULL, &opt);
12228 extract_getline_args(argc-1, argv+1, &garg);
12229 open_key_args(io, argc, argv, opt, &arg);
12231 extract_getline_opts(opt, &garg);
12232 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12233 return rb_ensure(io_s_readlines, (
VALUE)&garg, rb_io_close, arg.io);
12240 return io_read(arg->argc, arg->argv, arg->io);
12250seek_before_access(
VALUE argp)
12254 return rb_io_seek(arg->io, arg->offset, arg->mode);
12300rb_io_s_read(
int argc,
VALUE *argv,
VALUE io)
12306 argc =
rb_scan_args(argc, argv,
"13:", NULL, NULL, &offset, NULL, &opt);
12308 rb_raise(rb_eArgError,
"negative offset %ld given",
off);
12310 open_key_args(io, argc, argv, opt, &arg);
12312 if (!
NIL_P(offset)) {
12316 sarg.offset = offset;
12317 sarg.mode = SEEK_SET;
12318 rb_protect(seek_before_access, (
VALUE)&sarg, &state);
12321 rb_jump_tag(state);
12323 if (arg.argc == 2) arg.argc = 1;
12342rb_io_s_binread(
int argc,
VALUE *argv,
VALUE io)
12357 convconfig.
enc = rb_ascii8bit_encoding();
12358 arg.io = rb_io_open_generic(io, argv[0], oflags, fmode, &convconfig, 0);
12361 arg.argc = (argc > 1) ? 1 : 0;
12362 if (!
NIL_P(offset)) {
12366 sarg.offset = offset;
12367 sarg.mode = SEEK_SET;
12368 rb_protect(seek_before_access, (
VALUE)&sarg, &state);
12371 rb_jump_tag(state);
12378io_s_write0(
VALUE v)
12381 return io_write(arg->io,arg->str,arg->nosync);
12385io_s_write(
int argc,
VALUE *argv,
VALUE klass,
int binary)
12387 VALUE string, offset, opt;
12391 rb_scan_args(argc, argv,
"21:", NULL, &
string, &offset, &opt);
12393 if (
NIL_P(opt)) opt = rb_hash_new();
12394 else opt = rb_hash_dup(opt);
12397 if (
NIL_P(rb_hash_aref(opt,sym_mode))) {
12398 int mode = O_WRONLY|O_CREAT;
12400 if (binary) mode |= O_BINARY;
12402 if (
NIL_P(offset)) mode |= O_TRUNC;
12403 rb_hash_aset(opt,sym_mode,
INT2NUM(mode));
12405 open_key_args(klass, argc, argv, opt, &arg);
12408 if (binary) rb_io_binmode_m(arg.io);
12412 if (!
NIL_P(offset)) {
12416 sarg.offset = offset;
12417 sarg.mode = SEEK_SET;
12418 rb_protect(seek_before_access, (
VALUE)&sarg, &state);
12421 rb_jump_tag(state);
12429 return rb_ensure(io_s_write0, (
VALUE)&warg, rb_io_close, arg.io);
12477rb_io_s_write(
int argc,
VALUE *argv,
VALUE io)
12479 return io_s_write(argc, argv, io, 0);
12496rb_io_s_binwrite(
int argc,
VALUE *argv,
VALUE io)
12498 return io_s_write(argc, argv, io, 1);
12504 rb_off_t copy_length;
12505 rb_off_t src_offset;
12509 unsigned close_src : 1;
12510 unsigned close_dst : 1;
12513 const char *syserr;
12514 const char *notimp;
12516 struct stat src_stat;
12517 struct stat dst_stat;
12518#ifdef HAVE_FCOPYFILE
12519 copyfile_state_t copyfile_state;
12524exec_interrupts(
void *arg)
12527 rb_thread_execute_interrupts(th);
12541#if defined(ERESTART)
12546 rb_thread_execute_interrupts(stp->th);
12565fiber_scheduler_wait_for(
void * _arguments)
12575# define IOWAIT_SYSCALL "poll"
12576STATIC_ASSERT(pollin_expected, POLLIN == RB_WAITFD_IN);
12577STATIC_ASSERT(pollout_expected, POLLOUT == RB_WAITFD_OUT);
12582 if (scheduler !=
Qnil) {
12585 return RTEST(args.result);
12589 if (fd == -1)
return 0;
12594 fds.events = events;
12596 int timeout_milliseconds = -1;
12599 timeout_milliseconds = (int)(timeout->tv_sec * 1000) + (int)(timeout->tv_usec / 1000);
12602 return poll(&fds, 1, timeout_milliseconds);
12605# define IOWAIT_SYSCALL "select"
12610 if (scheduler !=
Qnil) {
12613 return RTEST(args.result);
12633 case RB_WAITFD_OUT:
12637 VM_UNREACHABLE(nogvl_wait_for);
12657 ret = nogvl_wait_for(stp->th, stp->src_fptr, RB_WAITFD_IN, NULL);
12659 }
while (ret < 0 && maygvl_copy_stream_continue_p(has_gvl, stp));
12662 stp->syserr = IOWAIT_SYSCALL;
12663 stp->error_no =
errno;
12675 ret = nogvl_wait_for(stp->th, stp->dst_fptr, RB_WAITFD_OUT, NULL);
12676 }
while (ret < 0 && maygvl_copy_stream_continue_p(0, stp));
12679 stp->syserr = IOWAIT_SYSCALL;
12680 stp->error_no =
errno;
12686#ifdef USE_COPY_FILE_RANGE
12689simple_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)
12691#ifdef HAVE_COPY_FILE_RANGE
12692 return copy_file_range(in_fd, in_offset, out_fd, out_offset, count, flags);
12694 return syscall(__NR_copy_file_range, in_fd, in_offset, out_fd, out_offset, count, flags);
12703 rb_off_t copy_length, src_offset, *src_offset_ptr;
12705 if (!S_ISREG(stp->src_stat.st_mode))
12708 src_size = stp->src_stat.st_size;
12709 src_offset = stp->src_offset;
12710 if (src_offset >= (rb_off_t)0) {
12711 src_offset_ptr = &src_offset;
12714 src_offset_ptr = NULL;
12717 copy_length = stp->copy_length;
12718 if (copy_length < (rb_off_t)0) {
12719 if (src_offset < (rb_off_t)0) {
12720 rb_off_t current_offset;
12722 current_offset = lseek(stp->src_fptr->
fd, 0, SEEK_CUR);
12723 if (current_offset < (rb_off_t)0 &&
errno) {
12724 stp->syserr =
"lseek";
12725 stp->error_no =
errno;
12726 return (
int)current_offset;
12728 copy_length = src_size - current_offset;
12731 copy_length = src_size - src_offset;
12735 retry_copy_file_range:
12736# if SIZEOF_OFF_T > SIZEOF_SIZE_T
12738 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
12740 ss = (ssize_t)copy_length;
12742 ss = simple_copy_file_range(stp->src_fptr->
fd, src_offset_ptr, stp->dst_fptr->
fd, NULL, ss, 0);
12746 if (0 < copy_length) {
12747 goto retry_copy_file_range;
12751 if (maygvl_copy_stream_continue_p(0, stp)) {
12752 goto retry_copy_file_range;
12766#if EWOULDBLOCK != EAGAIN
12770 int ret = nogvl_copy_stream_wait_write(stp);
12771 if (ret < 0)
return ret;
12773 goto retry_copy_file_range;
12777 int flags = fcntl(stp->dst_fptr->
fd, F_GETFL);
12779 if (flags != -1 && flags & O_APPEND) {
12785 stp->syserr =
"copy_file_range";
12786 stp->error_no =
errno;
12793#ifdef HAVE_FCOPYFILE
12797 rb_off_t cur, ss = 0;
12798 const rb_off_t src_offset = stp->src_offset;
12801 if (stp->copy_length >= (rb_off_t)0) {
12806 if (!S_ISREG(stp->src_stat.st_mode))
12809 if (!S_ISREG(stp->dst_stat.st_mode))
12811 if (lseek(stp->dst_fptr->
fd, 0, SEEK_CUR) > (rb_off_t)0)
12813 if (fcntl(stp->dst_fptr->
fd, F_GETFL) & O_APPEND) {
12816 rb_off_t end = lseek(stp->dst_fptr->
fd, 0, SEEK_END);
12817 lseek(stp->dst_fptr->
fd, 0, SEEK_SET);
12818 if (end > (rb_off_t)0)
return 0;
12821 if (src_offset > (rb_off_t)0) {
12826 cur = lseek(stp->src_fptr->
fd, 0, SEEK_CUR);
12827 if (cur < (rb_off_t)0 &&
errno) {
12828 stp->error_no =
errno;
12833 r = lseek(stp->src_fptr->
fd, src_offset, SEEK_SET);
12834 if (r < (rb_off_t)0 &&
errno) {
12835 stp->error_no =
errno;
12840 stp->copyfile_state = copyfile_state_alloc();
12841 ret = fcopyfile(stp->src_fptr->
fd, stp->dst_fptr->
fd, stp->copyfile_state, COPYFILE_DATA);
12842 copyfile_state_get(stp->copyfile_state, COPYFILE_STATE_COPIED, &ss);
12846 if (src_offset > (rb_off_t)0) {
12850 r = lseek(stp->src_fptr->
fd, cur, SEEK_SET);
12851 if (r < (rb_off_t)0 &&
errno) {
12852 stp->error_no =
errno;
12864 stp->syserr =
"fcopyfile";
12865 stp->error_no =
errno;
12872#ifdef HAVE_SENDFILE
12875# define USE_SENDFILE
12877# ifdef HAVE_SYS_SENDFILE_H
12878# include <sys/sendfile.h>
12882simple_sendfile(
int out_fd,
int in_fd, rb_off_t *offset, rb_off_t count)
12884 return sendfile(out_fd, in_fd, offset, (
size_t)count);
12887# elif 0 || defined(__APPLE__)
12891# define USE_SENDFILE
12894simple_sendfile(
int out_fd,
int in_fd, rb_off_t *offset, rb_off_t count)
12897 rb_off_t pos = offset ? *offset : lseek(in_fd, 0, SEEK_CUR);
12900 r = sendfile(in_fd, out_fd, pos, &count, NULL, 0);
12903 r = sendfile(in_fd, out_fd, pos, (
size_t)count, NULL, &sbytes, 0);
12905 if (r != 0 && sbytes == 0)
return r;
12910 lseek(in_fd, sbytes, SEEK_CUR);
12912 return (ssize_t)sbytes;
12925 rb_off_t copy_length;
12926 rb_off_t src_offset;
12929 if (!S_ISREG(stp->src_stat.st_mode))
12932 src_size = stp->src_stat.st_size;
12934 if ((stp->dst_stat.st_mode & S_IFMT) != S_IFSOCK)
12938 src_offset = stp->src_offset;
12939 use_pread = src_offset >= (rb_off_t)0;
12941 copy_length = stp->copy_length;
12942 if (copy_length < (rb_off_t)0) {
12944 copy_length = src_size - src_offset;
12948 cur = lseek(stp->src_fptr->
fd, 0, SEEK_CUR);
12949 if (cur < (rb_off_t)0 &&
errno) {
12950 stp->syserr =
"lseek";
12951 stp->error_no =
errno;
12954 copy_length = src_size - cur;
12959# if SIZEOF_OFF_T > SIZEOF_SIZE_T
12961 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
12963 ss = (ssize_t)copy_length;
12966 ss = simple_sendfile(stp->dst_fptr->
fd, stp->src_fptr->
fd, &src_offset, ss);
12969 ss = simple_sendfile(stp->dst_fptr->
fd, stp->src_fptr->
fd, NULL, ss);
12974 if (0 < copy_length) {
12975 goto retry_sendfile;
12979 if (maygvl_copy_stream_continue_p(0, stp))
12980 goto retry_sendfile;
12993#if EWOULDBLOCK != EAGAIN
13006 ret = maygvl_copy_stream_wait_read(0, stp);
13007 if (ret < 0)
return ret;
13009 ret = nogvl_copy_stream_wait_write(stp);
13010 if (ret < 0)
return ret;
13012 goto retry_sendfile;
13014 stp->syserr =
"sendfile";
13015 stp->error_no =
errno;
13023maygvl_read(
int has_gvl,
rb_io_t *fptr,
void *buf,
size_t count)
13026 return rb_io_read_memory(fptr, buf, count);
13028 return read(fptr->
fd, buf, count);
13032maygvl_copy_stream_read(
int has_gvl,
struct copy_stream_struct *stp,
char *buf,
size_t len, rb_off_t offset)
13036 if (offset < (rb_off_t)0) {
13037 ss = maygvl_read(has_gvl, stp->src_fptr, buf,
len);
13040 ss = pread(stp->src_fptr->
fd, buf,
len, offset);
13046 if (maygvl_copy_stream_continue_p(has_gvl, stp))
13050#if EWOULDBLOCK != EAGAIN
13054 int ret = maygvl_copy_stream_wait_read(has_gvl, stp);
13055 if (ret < 0)
return ret;
13060 stp->notimp =
"pread";
13064 stp->syserr = offset < (rb_off_t)0 ?
"read" :
"pread";
13065 stp->error_no =
errno;
13076 ss = write(stp->dst_fptr->
fd, buf+
off,
len);
13078 if (maygvl_copy_stream_continue_p(0, stp))
13080 if (io_again_p(
errno)) {
13081 int ret = nogvl_copy_stream_wait_write(stp);
13082 if (ret < 0)
return ret;
13085 stp->syserr =
"write";
13086 stp->error_no =
errno;
13103 rb_off_t copy_length;
13104 rb_off_t src_offset;
13108 copy_length = stp->copy_length;
13109 use_eof = copy_length < (rb_off_t)0;
13110 src_offset = stp->src_offset;
13111 use_pread = src_offset >= (rb_off_t)0;
13113 if (use_pread && stp->close_src) {
13116 r = lseek(stp->src_fptr->
fd, src_offset, SEEK_SET);
13117 if (r < (rb_off_t)0 &&
errno) {
13118 stp->syserr =
"lseek";
13119 stp->error_no =
errno;
13122 src_offset = (rb_off_t)-1;
13126 while (use_eof || 0 < copy_length) {
13127 if (!use_eof && copy_length < (rb_off_t)
sizeof(buf)) {
13128 len = (size_t)copy_length;
13134 ss = maygvl_copy_stream_read(0, stp, buf,
len, src_offset);
13139 ss = maygvl_copy_stream_read(0, stp, buf,
len, (rb_off_t)-1);
13144 ret = nogvl_copy_stream_write(stp, buf, ss);
13154nogvl_copy_stream_func(
void *arg)
13157#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13161#ifdef USE_COPY_FILE_RANGE
13162 ret = nogvl_copy_file_range(stp);
13167#ifdef HAVE_FCOPYFILE
13168 ret = nogvl_fcopyfile(stp);
13174 ret = nogvl_copy_stream_sendfile(stp);
13179 nogvl_copy_stream_read_write(stp);
13181#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13188copy_stream_fallback_body(
VALUE arg)
13191 const int buflen = 16*1024;
13194 rb_off_t rest = stp->copy_length;
13195 rb_off_t
off = stp->src_offset;
13196 ID read_method = id_readpartial;
13198 if (!stp->src_fptr) {
13200 read_method = id_read;
13207 rb_str_make_independent(buf);
13208 if (stp->copy_length < (rb_off_t)0) {
13213 rb_str_resize(buf, 0);
13216 l = buflen < rest ? buflen : (long)rest;
13218 if (!stp->src_fptr) {
13221 if (read_method == id_read &&
NIL_P(rc))
13226 rb_str_resize(buf, buflen);
13227 ss = maygvl_copy_stream_read(1, stp, RSTRING_PTR(buf), l,
off);
13228 rb_str_resize(buf, ss > 0 ? ss : 0);
13233 if (
off >= (rb_off_t)0)
13236 n = rb_io_write(stp->dst, buf);
13238 stp->total += numwrote;
13240 if (read_method == id_read && RSTRING_LEN(buf) == 0) {
13251 if (!stp->src_fptr && stp->src_offset >= (rb_off_t)0) {
13252 rb_raise(rb_eArgError,
"cannot specify src_offset for non-IO");
13261copy_stream_body(
VALUE arg)
13264 VALUE src_io = stp->src, dst_io = stp->dst;
13265 const int common_oflags = 0
13275 if (src_io ==
argf ||
13279 stp->src_fptr = NULL;
13284 if (!
NIL_P(tmp_io)) {
13291 args[1] =
INT2NUM(O_RDONLY|common_oflags);
13294 stp->close_src = 1;
13299 stat_ret = fstat(stp->src_fptr->
fd, &stp->src_stat);
13300 if (stat_ret < 0) {
13301 stp->syserr =
"fstat";
13302 stp->error_no =
errno;
13307 if (dst_io ==
argf ||
13311 stp->dst_fptr = NULL;
13316 if (!
NIL_P(tmp_io)) {
13317 dst_io = GetWriteIO(tmp_io);
13323 args[1] =
INT2NUM(O_WRONLY|O_CREAT|O_TRUNC|common_oflags);
13327 stp->close_dst = 1;
13330 dst_io = GetWriteIO(dst_io);
13336 stat_ret = fstat(stp->dst_fptr->
fd, &stp->dst_stat);
13337 if (stat_ret < 0) {
13338 stp->syserr =
"fstat";
13339 stp->error_no =
errno;
13346 SET_BINARY_MODE_WITH_SEEK_CUR(stp->src_fptr);
13349 io_ascii8bit_binmode(stp->dst_fptr);
13351 if (stp->src_offset < (rb_off_t)0 && stp->src_fptr && stp->src_fptr->
rbuf.
len) {
13354 if (stp->copy_length >= (rb_off_t)0 && stp->copy_length < (rb_off_t)
len) {
13355 len = (size_t)stp->copy_length;
13358 rb_str_resize(str,
len);
13359 read_buffered_data(RSTRING_PTR(str),
len, stp->src_fptr);
13360 if (stp->dst_fptr) {
13361 if (io_binwrite(RSTRING_PTR(str), RSTRING_LEN(str), stp->dst_fptr, 0) < 0)
13362 rb_sys_fail_on_write(stp->dst_fptr);
13365 rb_io_write(dst_io, str);
13366 rb_str_resize(str, 0);
13368 if (stp->copy_length >= (rb_off_t)0)
13369 stp->copy_length -=
len;
13372 if (stp->dst_fptr && io_fflush(stp->dst_fptr) < 0) {
13376 if (stp->copy_length == 0)
13379 if (stp->src_fptr == NULL || stp->dst_fptr == NULL) {
13380 return copy_stream_fallback(stp);
13383 IO_WITHOUT_GVL(nogvl_copy_stream_func, stp);
13388copy_stream_finalize(
VALUE arg)
13392#ifdef HAVE_FCOPYFILE
13393 if (stp->copyfile_state) {
13394 copyfile_state_free(stp->copyfile_state);
13398 if (stp->close_src) {
13399 rb_io_close_m(stp->src);
13401 if (stp->close_dst) {
13402 rb_io_close_m(stp->dst);
13465rb_io_s_copy_stream(
int argc,
VALUE *argv,
VALUE io)
13467 VALUE src, dst, length, src_offset;
13472 rb_scan_args(argc, argv,
"22", &src, &dst, &length, &src_offset);
13477 st.src_fptr = NULL;
13478 st.dst_fptr = NULL;
13481 st.copy_length = (rb_off_t)-1;
13483 st.copy_length =
NUM2OFFT(length);
13485 if (
NIL_P(src_offset))
13486 st.src_offset = (rb_off_t)-1;
13488 st.src_offset =
NUM2OFFT(src_offset);
13507rb_io_external_encoding(
VALUE io)
13512 return rb_enc_from_encoding(fptr->
encs.
enc2);
13516 return rb_enc_from_encoding(fptr->
encs.
enc);
13519 return rb_enc_from_encoding(io_read_encoding(fptr));
13535rb_io_internal_encoding(
VALUE io)
13540 return rb_enc_from_encoding(io_read_encoding(fptr));
13574rb_io_set_encoding(
int argc,
VALUE *argv,
VALUE io)
13580 return forward(io, id_set_encoding, argc, argv);
13583 argc =
rb_scan_args(argc, argv,
"11:", &v1, &v2, &opt);
13585 io_encoding_set(fptr, v1, v2, opt);
13590rb_stdio_set_default_encoding(
void)
13595 if (isatty(fileno(stdin))) {
13597 rb_encoding *internal = rb_default_internal_encoding();
13598 if (!internal) internal = rb_default_external_encoding();
13600 rb_enc_from_encoding(external),
13601 rb_enc_from_encoding(internal),
13606 rb_io_set_encoding(1, &val,
rb_stdin);
13607 rb_io_set_encoding(1, &val,
rb_stdout);
13608 rb_io_set_encoding(1, &val,
rb_stderr);
13612global_argf_p(
VALUE arg)
13614 return arg ==
argf;
13617typedef VALUE (*argf_encoding_func)(
VALUE io);
13620argf_encoding(
VALUE argf, argf_encoding_func func)
13622 if (!
RTEST(ARGF.current_file)) {
13623 return rb_enc_default_external();
13647 return argf_encoding(
argf, rb_io_external_encoding);
13666 return argf_encoding(
argf, rb_io_internal_encoding);
13705 if (!next_argv()) {
13706 rb_raise(rb_eArgError,
"no stream to set encoding");
13708 rb_io_set_encoding(argc, argv, ARGF.current_file);
13710 ARGF.encs = fptr->
encs;
13729 if (!next_argv()) {
13730 rb_raise(rb_eArgError,
"no stream to tell");
13732 ARGF_FORWARD(0, 0);
13733 return rb_io_tell(ARGF.current_file);
13746 if (!next_argv()) {
13747 rb_raise(rb_eArgError,
"no stream to seek");
13749 ARGF_FORWARD(argc, argv);
13750 return rb_io_seek_m(argc, argv, ARGF.current_file);
13767 if (!next_argv()) {
13768 rb_raise(rb_eArgError,
"no stream to set position");
13770 ARGF_FORWARD(1, &offset);
13771 return rb_io_set_pos(ARGF.current_file, offset);
13792 if (!next_argv()) {
13793 rb_raise(rb_eArgError,
"no stream to rewind");
13795 ARGF_FORWARD(0, 0);
13796 old_lineno =
RFILE(ARGF.current_file)->fptr->lineno;
13797 ret = rb_io_rewind(ARGF.current_file);
13798 if (!global_argf_p(
argf)) {
13799 ARGF.last_lineno = ARGF.lineno -= old_lineno;
13817 if (!next_argv()) {
13818 rb_raise(rb_eArgError,
"no stream");
13820 ARGF_FORWARD(0, 0);
13821 return rb_io_fileno(ARGF.current_file);
13840 ARGF_FORWARD(0, 0);
13841 return ARGF.current_file;
13866 if (
RTEST(ARGF.current_file)) {
13867 if (ARGF.init_p == 0)
return Qtrue;
13869 ARGF_FORWARD(0, 0);
13928 VALUE tmp, str, length;
13932 if (!
NIL_P(length)) {
13937 rb_str_resize(str,0);
13942 if (!next_argv()) {
13945 if (ARGF_GENERIC_INPUT_P()) {
13946 tmp = argf_forward(argc, argv,
argf);
13949 tmp = io_read(argc, argv, ARGF.current_file);
13951 if (
NIL_P(str)) str = tmp;
13954 if (ARGF.next_p != -1) {
13960 else if (argc >= 1) {
13961 long slen = RSTRING_LEN(str);
13977argf_forward_call(
VALUE arg)
13980 argf_forward(p->argc, p->argv, p->argf);
14010 return argf_getpartial(argc, argv,
argf,
Qnil, 0);
14031 return argf_getpartial(argc, argv,
argf, opts, 1);
14037 VALUE tmp, str, length;
14045 no_exception = no_exception_p(opts);
14047 if (!next_argv()) {
14049 rb_str_resize(str, 0);
14053 if (ARGF_GENERIC_INPUT_P()) {
14063 tmp = io_getpartial(argc, argv, ARGF.current_file, no_exception, nonblock);
14066 if (ARGF.next_p == -1) {
14067 return io_nonblock_eof(no_exception);
14072 return io_nonblock_eof(no_exception);
14110 if (!next_argv())
return Qnil;
14111 if (ARGF_GENERIC_INPUT_P()) {
14112 ch = forward_current(rb_intern(
"getc"), 0, 0);
14115 ch = rb_io_getc(ARGF.current_file);
14117 if (
NIL_P(ch) && ARGF.next_p != -1) {
14150 if (!next_argv())
return Qnil;
14152 ch = forward_current(rb_intern(
"getbyte"), 0, 0);
14157 if (
NIL_P(ch) && ARGF.next_p != -1) {
14190 if (!next_argv()) rb_eof_error();
14192 ch = forward_current(rb_intern(
"getc"), 0, 0);
14195 ch = rb_io_getc(ARGF.current_file);
14197 if (
NIL_P(ch) && ARGF.next_p != -1) {
14229 NEXT_ARGF_FORWARD(0, 0);
14230 c = argf_getbyte(
argf);
14237#define FOREACH_ARGF() while (next_argv())
14242 const VALUE current = ARGF.current_file;
14244 if (ARGF.init_p == -1 || current != ARGF.current_file) {
14250#define ARGF_block_call(mid, argc, argv, func, argf) \
14251 rb_block_call_kw(ARGF.current_file, mid, argc, argv, \
14252 func, argf, rb_keyword_given_p())
14257 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_i,
argf);
14258 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14264 if (!global_argf_p(
argf)) {
14265 ARGF.last_lineno = ++ARGF.lineno;
14267 return argf_block_call_i(i,
argf, argc, argv, blockarg);
14273 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_line_i,
argf);
14274 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14322 argf_block_call_line(rb_intern(
"each_line"), argc, argv,
argf);
14353 argf_block_call(rb_intern(
"each_byte"), 0, 0,
argf);
14379 argf_block_call(rb_intern(
"each_char"), 0, 0,
argf);
14405 argf_block_call(rb_intern(
"each_codepoint"), 0, 0,
argf);
14436 return ARGF.filename;
14440argf_filename_getter(
ID id,
VALUE *var)
14442 return argf_filename(*var);
14467 return ARGF.current_file;
14486 ARGF_FORWARD(0, 0);
14507 return RBOOL(ARGF.binmode);
14527 if (ARGF.init_p && ARGF.next_p == 0) {
14556 if (ARGF.next_p != -1) {
14574 ARGF_FORWARD(0, 0);
14601 if (!ARGF.inplace)
return Qnil;
14609 return argf_inplace_mode_get(*var);
14640 ARGF.inplace =
Qnil;
14651 argf_inplace_mode_set(*var, val);
14655ruby_set_inplace_mode(
const char *suffix)
14681argf_argv_getter(
ID id,
VALUE *var)
14683 return argf_argv(*var);
14702 if (!
RTEST(ARGF.current_file)) {
14705 return GetWriteIO(ARGF.current_file);
14717 return rb_io_writev(argf_write_io(
argf), argc, argv);
14732 case RB_IO_WAIT_WRITABLE:
14735 c = rb_eEAGAINWaitWritable;
14737#if EAGAIN != EWOULDBLOCK
14739 c = rb_eEWOULDBLOCKWaitWritable;
14743 c = rb_eEINPROGRESSWaitWritable;
14749 case RB_IO_WAIT_READABLE:
14752 c = rb_eEAGAINWaitReadable;
14754#if EAGAIN != EWOULDBLOCK
14756 c = rb_eEWOULDBLOCKWaitReadable;
14760 c = rb_eEINPROGRESSWaitReadable;
14767 rb_bug(
"invalid read/write type passed to rb_readwrite_sys_fail: %d", waiting);
14773get_LAST_READ_LINE(
ID _x,
VALUE *_y)
15658#include <sys/cygwin.h>
15659 static struct __cygwin_perfile pf[] =
15661 {
"", O_RDONLY | O_BINARY},
15662 {
"", O_WRONLY | O_BINARY},
15663 {
"", O_RDWR | O_BINARY},
15664 {
"", O_APPEND | O_BINARY},
15667 cygwin_internal(CW_PERFILE, pf);
15722#if EAGAIN == EWOULDBLOCK
15723 rb_eEWOULDBLOCKWaitReadable = rb_eEAGAINWaitReadable;
15725 rb_define_const(
rb_cIO,
"EWOULDBLOCKWaitReadable", rb_eEAGAINWaitReadable);
15726 rb_eEWOULDBLOCKWaitWritable = rb_eEAGAINWaitWritable;
15728 rb_define_const(
rb_cIO,
"EWOULDBLOCKWaitWritable", rb_eEAGAINWaitWritable);
15776 rb_gvar_ractor_local(
"$/");
15778 rb_gvar_ractor_local(
"$-0");
15782 rb_gvar_ractor_local(
"$_");
15898 rb_gvar_ractor_local(
"$stdin");
15899 rb_gvar_ractor_local(
"$stdout");
15900 rb_gvar_ractor_local(
"$>");
15901 rb_gvar_ractor_local(
"$stderr");
15987 rb_define_method(rb_cARGF,
"external_encoding", argf_external_encoding, 0);
15988 rb_define_method(rb_cARGF,
"internal_encoding", argf_internal_encoding, 0);
16007 rb_gvar_ractor_local(
"$-i");
16011#if defined (_WIN32) || defined(__CYGWIN__)
16012 atexit(pipe_atexit);
16024 sym_encoding =
ID2SYM(rb_id_encoding());
#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_define_class(const char *name, VALUE super)
Defines a top-level class.
VALUE rb_class_new(VALUE super)
Creates a new, anonymous class.
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
VALUE rb_define_module_under(VALUE outer, const char *name)
Defines a module under the namespace of outer.
void rb_define_alias(VALUE klass, const char *name1, const char *name2)
Defines an alias of a method.
int rb_scan_args_kw(int kw_flag, int argc, const VALUE *argv, const char *fmt,...)
Identical to rb_scan_args(), except it also accepts kw_splat.
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Retrieves argument from argc and argv to given VALUE references according to the format string.
int rb_block_given_p(void)
Determines if the current method is given a block.
int rb_get_kwargs(VALUE keyword_hash, const ID *table, int required, int optional, VALUE *values)
Keyword argument deconstructor.
#define ECONV_AFTER_OUTPUT
Old name of RUBY_ECONV_AFTER_OUTPUT.
#define rb_str_new2
Old name of rb_str_new_cstr.
#define TYPE(_)
Old name of rb_type.
#define 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_notimplement(void)
void rb_category_warn(rb_warning_category_t category, const char *fmt,...)
Identical to rb_category_warning(), except it reports unless $VERBOSE is nil.
void rb_category_warning(rb_warning_category_t category, const char *fmt,...)
Identical to rb_warning(), except it takes additional "category" parameter.
VALUE rb_eNotImpError
NotImplementedError exception.
void rb_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_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)
Just calls rb_obj_freeze_inline() inside.
VALUE rb_check_to_integer(VALUE val, const char *mid)
Identical to rb_check_convert_type(), except the return value type is fixed to rb_cInteger.
VALUE rb_cFile
File class.
VALUE rb_stdout
STDOUT constant.
VALUE rb_to_int(VALUE val)
Identical to rb_check_to_int(), except it raises in case of conversion mismatch.
static 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.
int rb_enc_str_coderange(VALUE str)
Scans the passed string to collect its code range.
VALUE rb_enc_uint_chr(unsigned int code, rb_encoding *enc)
Encodes the passed code point into a series of bytes.
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.
Defines RBIMPL_HAS_BUILTIN.
VALUE rb_ary_concat(VALUE lhs, VALUE rhs)
Destructively appends the contents of latter into the end of former.
VALUE rb_ary_shift(VALUE ary)
Destructively deletes an element from the beginning of the passed array and returns what was deleted.
VALUE rb_check_array_type(VALUE obj)
Try converting an object to its array representation using its to_ary method, if any.
VALUE rb_ary_new(void)
Allocates a new, empty array.
VALUE rb_ary_push(VALUE ary, VALUE elem)
Special case of rb_ary_cat() that it adds only one element.
VALUE rb_ary_entry(VALUE ary, long off)
Queries an element of an array.
VALUE rb_assoc_new(VALUE car, VALUE cdr)
Identical to rb_ary_new_from_values(), except it expects exactly two parameters.
#define RETURN_ENUMERATOR(obj, argc, argv)
Identical to RETURN_SIZED_ENUMERATOR(), except its size is unknown.
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_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.
rb_gvar_setter_t rb_str_setter
This is a rb_gvar_setter_t that refutes non-string assignments.
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.
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.
VALUE rb_fiber_scheduler_current(void)
Identical to rb_fiber_scheduler_get(), except it also returns RUBY_Qnil in case of a blocking fiber.
VALUE rb_fiber_scheduler_io_pread_memory(VALUE scheduler, VALUE io, rb_off_t from, void *base, size_t size, size_t length)
Non-blocking pread from the passed IO using a native buffer.
VALUE rb_fiber_scheduler_make_timeout(struct timeval *timeout)
Converts the passed timeout to an expression that rb_fiber_scheduler_block() etc.
VALUE rb_fiber_scheduler_io_wait_readable(VALUE scheduler, VALUE io)
Non-blocking wait until the passed IO is ready for reading.
VALUE rb_fiber_scheduler_io_read_memory(VALUE scheduler, VALUE io, void *base, size_t size, size_t length)
Non-blocking read from the passed IO using a native buffer.
VALUE rb_fiber_scheduler_io_wait(VALUE scheduler, VALUE io, VALUE events, VALUE timeout)
Non-blocking version of rb_io_wait().
static ssize_t rb_fiber_scheduler_io_result_apply(VALUE result)
Apply an io result to the local thread, returning the value of the original system call that created ...
VALUE rb_fiber_scheduler_io_selectv(VALUE scheduler, int argc, VALUE *argv)
Non-blocking version of IO.select, argv variant.
VALUE rb_fiber_scheduler_io_pwrite_memory(VALUE scheduler, VALUE io, rb_off_t from, const void *base, size_t size, size_t length)
Non-blocking pwrite to the passed IO using a native buffer.
VALUE rb_fiber_scheduler_current_for_thread(VALUE thread)
Identical to rb_fiber_scheduler_current(), except it queries for that of the passed thread instead of...
VALUE rb_fiber_scheduler_io_write_memory(VALUE scheduler, VALUE io, const void *base, size_t size, size_t length)
Non-blocking write to the passed IO using a native buffer.
VALUE rb_fiber_scheduler_io_wait_writable(VALUE scheduler, VALUE io)
Non-blocking wait until the passed IO is ready for writing.
int rb_thread_fd_select(int nfds, rb_fdset_t *rfds, rb_fdset_t *wfds, rb_fdset_t *efds, struct timeval *timeout)
Waits for multiple file descriptors at once.
static bool RB_TEST(VALUE obj)
Emulates Ruby's "if" statement.
#define RTEST
This is an old name of RB_TEST.
#define _(args)
This was a transition path from K&R to ANSI.
This is the struct that holds necessary info for a struct.
The data structure which wraps the fd_set bitmap used by select(2).
Decomposed encoding flags (e.g.
VALUE ecopts
Flags as Ruby hash.
rb_encoding * enc2
External encoding.
rb_encoding * enc
Internal encoding.
char * ptr
Pointer to the underlying memory region, of at least capa bytes.
int off
Offset inside of ptr.
int len
Length of the buffer.
int capa
Designed capacity of the buffer.
Ruby's IO, metadata and buffers.
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.