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));
3160make_readconv(
rb_io_t *fptr,
int size)
3165 const char *sname, *dname;
3166 ecflags = fptr->
encs.
ecflags & ~ECONV_NEWLINE_DECORATOR_WRITE_MASK;
3169 sname = rb_enc_name(fptr->
encs.
enc2);
3170 dname = rb_enc_name(io_read_encoding(fptr));
3180 if (size < IO_CBUF_CAPA_MIN) size = IO_CBUF_CAPA_MIN;
3186#define MORE_CHAR_SUSPENDED Qtrue
3187#define MORE_CHAR_FINISHED Qnil
3189fill_cbuf(
rb_io_t *fptr,
int ec_flags)
3191 const unsigned char *ss, *sp, *se;
3192 unsigned char *ds, *dp, *de;
3201 return MORE_CHAR_SUSPENDED;
3212 ss = sp = (
const unsigned char *)fptr->
rbuf.
ptr + fptr->
rbuf.
off;
3217 fptr->
rbuf.
off += (int)(sp - ss);
3218 fptr->
rbuf.
len -= (int)(sp - ss);
3219 fptr->
cbuf.
len += (int)(dp - ds);
3224 fptr->
rbuf.
off -= putbackable;
3225 fptr->
rbuf.
len += putbackable;
3232 if (cbuf_len0 != fptr->
cbuf.
len)
3233 return MORE_CHAR_SUSPENDED;
3236 return MORE_CHAR_FINISHED;
3242 if (io_fillbuf(fptr) < 0) {
3244 return MORE_CHAR_FINISHED;
3249 fptr->
cbuf.
len += (int)(dp - ds);
3256 if (cbuf_len0 != fptr->
cbuf.
len)
3257 return MORE_CHAR_SUSPENDED;
3259 return MORE_CHAR_FINISHED;
3267 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED)
3284 rb_enc_associate(str, fptr->
encs.
enc);
3313 long clen = RSTRING_LEN(s);
3325#define MAX_REALLOC_GAP 4096
3327io_shrink_read_string(
VALUE str,
long n)
3330 rb_str_resize(str, n);
3335io_set_read_length(
VALUE str,
long n,
int shrinkable)
3337 if (RSTRING_LEN(str) != n) {
3340 if (shrinkable) io_shrink_read_string(str, n);
3354 if (NEED_READCONV(fptr)) {
3355 int first = !
NIL_P(str);
3356 SET_BINARY_MODE(fptr);
3357 shrinkable = io_setstrbuf(&str,0);
3358 make_readconv(fptr, 0);
3363 io_shift_cbuf(fptr, fptr->
cbuf.
len, &str);
3365 v = fill_cbuf(fptr, 0);
3366 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED) {
3369 io_shift_cbuf(fptr, fptr->
cbuf.
len, &str);
3373 if (v == MORE_CHAR_FINISHED) {
3374 clear_readconv(fptr);
3376 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3377 return io_enc_str(str, fptr);
3382 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3386 enc = io_read_encoding(fptr);
3389 if (siz == 0) siz = BUFSIZ;
3390 shrinkable = io_setstrbuf(&str, siz);
3393 n = io_fread(str, bytes, siz - bytes, fptr);
3394 if (n == 0 && bytes == 0) {
3402 if (bytes < siz)
break;
3406 if (
capa < (
size_t)RSTRING_LEN(str) + BUFSIZ) {
3407 if (
capa < BUFSIZ) {
3410 else if (
capa > IO_MAX_BUFFER_GROWTH) {
3411 capa = IO_MAX_BUFFER_GROWTH;
3416 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3417 str = io_enc_str(str, fptr);
3425 if (rb_fd_set_nonblock(fptr->
fd) != 0) {
3426 rb_sys_fail_path(fptr->
pathv);
3431io_read_memory_call(
VALUE arg)
3436 if (scheduler !=
Qnil) {
3439 if (!UNDEF_P(result)) {
3445 if (iis->nonblock) {
3446 return rb_io_blocking_region(iis->fptr, internal_read_func, iis);
3449 return rb_io_blocking_region_wait(iis->fptr, internal_read_func, iis,
RUBY_IO_READABLE);
3456 return (
long)rb_str_locktmp_ensure(str, io_read_memory_call, (
VALUE)iis);
3459#define no_exception_p(opts) !rb_opts_exception_p((opts), TRUE)
3462io_getpartial(
int argc,
VALUE *argv,
VALUE io,
int no_exception,
int nonblock)
3473 rb_raise(rb_eArgError,
"negative length %ld given",
len);
3476 shrinkable = io_setstrbuf(&str,
len);
3482 io_set_read_length(str, 0, shrinkable);
3488 n = read_buffered_data(RSTRING_PTR(str),
len, fptr);
3494 io_setstrbuf(&str,
len);
3497 iis.nonblock = nonblock;
3499 iis.buf = RSTRING_PTR(str);
3502 n = io_read_memory_locktmp(str, &iis);
3505 if (!nonblock && fptr_wait_readable(fptr))
3507 if (nonblock && (io_again_p(e))) {
3509 return sym_wait_readable;
3512 e,
"read would block");
3514 rb_syserr_fail_path(e, fptr->
pathv);
3517 io_set_read_length(str, n, shrinkable);
3618io_readpartial(
int argc,
VALUE *argv,
VALUE io)
3622 ret = io_getpartial(argc, argv, io,
Qnil, 0);
3629io_nonblock_eof(
int no_exception)
3631 if (!no_exception) {
3647 rb_raise(rb_eArgError,
"negative length %ld given",
len);
3650 shrinkable = io_setstrbuf(&str,
len);
3651 rb_bool_expected(ex,
"exception", TRUE);
3657 io_set_read_length(str, 0, shrinkable);
3661 n = read_buffered_data(RSTRING_PTR(str),
len, fptr);
3663 rb_fd_set_nonblock(fptr->
fd);
3664 shrinkable |= io_setstrbuf(&str,
len);
3668 iis.buf = RSTRING_PTR(str);
3671 n = io_read_memory_locktmp(str, &iis);
3674 if (io_again_p(e)) {
3675 if (!ex)
return sym_wait_readable;
3677 e,
"read would block");
3679 rb_syserr_fail_path(e, fptr->
pathv);
3682 io_set_read_length(str, n, shrinkable);
3685 if (!ex)
return Qnil;
3701 rb_bool_expected(ex,
"exception", TRUE);
3703 io = GetWriteIO(io);
3707 if (io_fflush(fptr) < 0)
3708 rb_sys_fail_on_write(fptr);
3710 rb_fd_set_nonblock(fptr->
fd);
3711 n = write(fptr->
fd, RSTRING_PTR(str), RSTRING_LEN(str));
3716 if (io_again_p(e)) {
3718 return sym_wait_writable;
3724 rb_syserr_fail_path(e, fptr->
pathv);
3808#if RUBY_CRLF_ENVIRONMENT
3814 if (
NIL_P(length)) {
3817 return read_all(fptr, remain_size(fptr), str);
3821 rb_raise(rb_eArgError,
"negative length %ld given",
len);
3824 shrinkable = io_setstrbuf(&str,
len);
3829 io_set_read_length(str, 0, shrinkable);
3834#if RUBY_CRLF_ENVIRONMENT
3835 previous_mode = set_binary_mode_with_seek_cur(fptr);
3837 n = io_fread(str, 0,
len, fptr);
3838 io_set_read_length(str, n, shrinkable);
3839#if RUBY_CRLF_ENVIRONMENT
3840 if (previous_mode == O_TEXT) {
3841 setmode(fptr->
fd, O_TEXT);
3844 if (n == 0)
return Qnil;
3850rscheck(
const char *rsptr,
long rslen,
VALUE rs)
3853 if (RSTRING_PTR(rs) != rsptr && RSTRING_LEN(rs) != rslen)
3858search_delim(
const char *p,
long len,
int delim,
rb_encoding *enc)
3860 if (rb_enc_mbminlen(enc) == 1) {
3861 p = memchr(p, delim,
len);
3862 if (p)
return p + 1;
3865 const char *end = p +
len;
3867 int r = rb_enc_precise_mbclen(p, end, enc);
3869 p += rb_enc_mbminlen(enc);
3873 if (rb_enc_mbc_to_codepoint(p, end, enc) == (
unsigned int)delim) {
3888 if (NEED_READCONV(fptr)) {
3889 SET_BINARY_MODE(fptr);
3890 make_readconv(fptr, 0);
3893 int searchlen = READ_CHAR_PENDING_COUNT(fptr);
3895 p = READ_CHAR_PENDING_PTR(fptr);
3896 if (0 < limit && limit < searchlen)
3897 searchlen = (int)limit;
3898 e = search_delim(p, searchlen, delim, enc);
3900 int len = (int)(e-p);
3922 return (
unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
3925 }
while (more_char(fptr) != MORE_CHAR_FINISHED);
3926 clear_readconv(fptr);
3931 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3933 long pending = READ_DATA_PENDING_COUNT(fptr);
3935 const char *p = READ_DATA_PENDING_PTR(fptr);
3939 if (limit > 0 && pending > limit) pending = limit;
3940 e = search_delim(p, pending, delim, enc);
3941 if (e) pending = e - p;
3943 last = RSTRING_LEN(str);
3944 rb_str_resize(str, last + pending);
3951 read_buffered_data(RSTRING_PTR(str) + last, pending, fptr);
3954 if (e)
return delim;
3956 return (
unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
3959 }
while (io_fillbuf(fptr) >= 0);
3965swallow(
rb_io_t *fptr,
int term)
3967 if (NEED_READCONV(fptr)) {
3969 int needconv = rb_enc_mbminlen(enc) != 1;
3970 SET_BINARY_MODE(fptr);
3971 make_readconv(fptr, 0);
3974 while ((cnt = READ_CHAR_PENDING_COUNT(fptr)) > 0) {
3975 const char *p = READ_CHAR_PENDING_PTR(fptr);
3978 if (*p != term)
return TRUE;
3980 while (--i && *++p == term);
3983 const char *e = p + cnt;
3984 if (rb_enc_ascget(p, e, &i, enc) != term)
return TRUE;
3985 while ((p += i) < e && rb_enc_ascget(p, e, &i, enc) == term);
3988 io_shift_cbuf(fptr, (
int)cnt - i, NULL);
3990 }
while (more_char(fptr) != MORE_CHAR_FINISHED);
3994 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3997 while ((cnt = READ_DATA_PENDING_COUNT(fptr)) > 0) {
3999 const char *p = READ_DATA_PENDING_PTR(fptr);
4001 if (cnt >
sizeof buf) cnt =
sizeof buf;
4002 if (*p != term)
return TRUE;
4004 while (--i && *++p == term);
4005 if (!read_buffered_data(buf, cnt - i, fptr))
4006 rb_sys_fail_path(fptr->
pathv);
4009 }
while (io_fillbuf(fptr) == 0);
4022 int pending = READ_DATA_PENDING_COUNT(fptr);
4025 const char *p = READ_DATA_PENDING_PTR(fptr);
4029 e = memchr(p,
'\n', pending);
4031 pending = (int)(e - p + 1);
4033 chomplen = (pending > 1 && *(e-1) ==
'\r') + 1;
4042 rb_str_resize(str,
len + pending - chomplen);
4043 read_buffered_data(RSTRING_PTR(str)+
len, pending - chomplen, fptr);
4046 if (pending == 1 && chomplen == 1 &&
len > 0) {
4047 if (RSTRING_PTR(str)[
len-1] ==
'\r') {
4048 rb_str_resize(str, --
len);
4053 len += pending - chomplen;
4059 }
while (io_fillbuf(fptr) >= 0);
4062 str = io_enc_str(str, fptr);
4073 unsigned int chomp: 1;
4087 chomp = (!UNDEF_P(vchomp)) &&
RTEST(vchomp);
4089 args->chomp = chomp;
4107 else if (2 <= argc) {
4108 rs = argv[0], lim = argv[1];
4117check_getline_args(
VALUE *rsp,
long *limit,
VALUE io)
4126 enc_rs = rb_enc_get(rs);
4127 enc_io = io_read_encoding(fptr);
4128 if (enc_io != enc_rs &&
4129 (!is_ascii_string(rs) ||
4130 (RSTRING_LEN(rs) > 0 && !rb_enc_asciicompat(enc_io)))) {
4131 if (rs == rb_default_rs) {
4132 rs = rb_enc_str_new(0, 0, enc_io);
4137 rb_raise(rb_eArgError,
"encoding mismatch: %s IO with %s RS",
4138 rb_enc_name(enc_io),
4139 rb_enc_name(enc_rs));
4149 argc =
rb_scan_args(argc, argv,
"02:", NULL, NULL, &opts);
4150 extract_getline_args(argc, argv, args);
4151 extract_getline_opts(opts, args);
4152 check_getline_args(&args->rs, &args->limit, io);
4156rb_io_getline_0(
VALUE rs,
long limit,
int chomp,
rb_io_t *fptr)
4163 if (
NIL_P(rs) && limit < 0) {
4164 str = read_all(fptr, 0,
Qnil);
4165 if (RSTRING_LEN(str) == 0)
return Qnil;
4167 else if (limit == 0) {
4168 return rb_enc_str_new(0, 0, io_read_encoding(fptr));
4170 else if (rs == rb_default_rs && limit < 0 && !NEED_READCONV(fptr) &&
4171 rb_enc_asciicompat(enc = io_read_encoding(fptr))) {
4172 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4173 return rb_io_getline_fast(fptr, enc, chomp);
4176 int c, newline = -1;
4177 const char *rsptr = 0;
4180 int extra_limit = 16;
4181 int chomp_cr = chomp;
4183 SET_BINARY_MODE(fptr);
4184 enc = io_read_encoding(fptr);
4187 rslen = RSTRING_LEN(rs);
4192 swallow(fptr,
'\n');
4194 if (!rb_enc_asciicompat(enc)) {
4198 rsptr = RSTRING_PTR(rs);
4199 rslen = RSTRING_LEN(rs);
4203 else if (rb_enc_mbminlen(enc) == 1) {
4204 rsptr = RSTRING_PTR(rs);
4205 newline = (
unsigned char)rsptr[rslen - 1];
4209 rsptr = RSTRING_PTR(rs);
4210 const char *e = rsptr + rslen;
4211 const char *last = rb_enc_prev_char(rsptr, e, e, enc);
4213 newline = rb_enc_codepoint_len(last, e, &n, enc);
4214 if (last + n != e) rb_raise(rb_eArgError,
"broken separator");
4216 chomp_cr = chomp && newline ==
'\n' && rslen == rb_enc_mbminlen(enc);
4220 while ((c = appendline(fptr, newline, &str, &limit, enc)) != EOF) {
4221 const char *s, *p, *pp, *e;
4224 if (RSTRING_LEN(str) < rslen)
continue;
4225 s = RSTRING_PTR(str);
4228 if (!at_char_boundary(s, p, e, enc))
continue;
4229 if (!rspara) rscheck(rsptr, rslen, rs);
4230 if (memcmp(p, rsptr, rslen) == 0) {
4232 if (chomp_cr && p > s && *(p-1) ==
'\r') --p;
4239 s = RSTRING_PTR(str);
4241 pp = rb_enc_prev_char(s, p, p, enc);
4242 if (extra_limit && pp &&
4256 if (rspara && c != EOF)
4257 swallow(fptr,
'\n');
4259 str = io_enc_str(str, fptr);
4262 if (!
NIL_P(str) && !nolimit) {
4270rb_io_getline_1(
VALUE rs,
long limit,
int chomp,
VALUE io)
4273 int old_lineno, new_lineno;
4277 old_lineno = fptr->
lineno;
4278 str = rb_io_getline_0(rs, limit, chomp, fptr);
4279 if (!
NIL_P(str) && (new_lineno = fptr->
lineno) != old_lineno) {
4280 if (io == ARGF.current_file) {
4281 ARGF.lineno += new_lineno - old_lineno;
4282 ARGF.last_lineno = ARGF.lineno;
4285 ARGF.last_lineno = new_lineno;
4293rb_io_getline(
int argc,
VALUE *argv,
VALUE io)
4297 prepare_getline_args(argc, argv, &args, io);
4298 return rb_io_getline_1(args.rs, args.limit, args.chomp, io);
4308rb_io_gets_limit_internal(
VALUE io,
long limit)
4312 return rb_io_getline_0(rb_default_rs, limit, FALSE, fptr);
4316rb_io_gets_internal(
VALUE io)
4318 return rb_io_gets_limit_internal(io, -1);
4398 str = rb_io_getline(argc, argv, io);
4414rb_io_lineno(
VALUE io)
4469 check_getline_args(&sep, &limit, io);
4471 VALUE line = rb_io_getline_1(sep, limit,
RTEST(chomp), io);
4472 rb_lastline_set_up(line, 1);
4547rb_io_readlines(
int argc,
VALUE *argv,
VALUE io)
4551 prepare_getline_args(argc, argv, &args, io);
4552 return io_readlines(&args, io);
4560 if (arg->limit == 0)
4561 rb_raise(rb_eArgError,
"invalid limit: 0 for readlines");
4563 while (!
NIL_P(line = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, io))) {
4676rb_io_each_line(
int argc,
VALUE *argv,
VALUE io)
4682 prepare_getline_args(argc, argv, &args, io);
4683 if (args.limit == 0)
4684 rb_raise(rb_eArgError,
"invalid limit: 0 for each_line");
4685 while (!
NIL_P(str = rb_io_getline_1(args.rs, args.limit, args.chomp, io))) {
4712rb_io_each_byte(
VALUE io)
4728 }
while (io_fillbuf(fptr) >= 0);
4738 if (NEED_READCONV(fptr)) {
4742 SET_BINARY_MODE(fptr);
4743 make_readconv(fptr, 0);
4757 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4759 clear_readconv(fptr);
4763 str = rb_enc_str_new(fptr->
cbuf.
ptr+fptr->
cbuf.
off, 1, read_enc);
4766 if (fptr->
cbuf.
len == 0) clear_readconv(fptr);
4775 io_shift_cbuf(fptr, r, &str);
4782 ISASCII(RSTRING_PTR(str)[0])) {
4786 str = io_enc_str(str, fptr);
4791 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4792 if (io_fillbuf(fptr) < 0) {
4814 if (io_fillbuf(fptr) != -1) {
4818 r = rb_enc_precise_mbclen(RSTRING_PTR(str), RSTRING_PTR(str)+RSTRING_LEN(str), enc);
4834 str = io_enc_str(str, fptr);
4860rb_io_each_char(
VALUE io)
4870 enc = io_input_encoding(fptr);
4872 while (!
NIL_P(c = io_getc(fptr, enc))) {
4898rb_io_each_codepoint(
VALUE io)
4910 enc = io_read_encoding(fptr);
4911 if (NEED_READCONV(fptr)) {
4912 SET_BINARY_MODE(fptr);
4915 make_readconv(fptr, 0);
4927 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4928 clear_readconv(fptr);
4948 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4949 while (io_fillbuf(fptr) >= 0) {
4964 char cbuf[8], *p = cbuf;
4966 if (more > numberof(cbuf))
goto invalid;
4968 if (more > numberof(cbuf))
goto invalid;
4969 while ((n = (
int)read_buffered_data(p, more, fptr)) > 0 &&
4970 (p += n, (more -= n) > 0)) {
4971 if (io_fillbuf(fptr) < 0)
goto invalid;
4972 if ((n = fptr->
rbuf.
len) > more) n = more;
4974 r = rb_enc_precise_mbclen(cbuf, p, enc);
4987 rb_raise(rb_eArgError,
"invalid byte sequence in %s", rb_enc_name(enc));
5019 enc = io_input_encoding(fptr);
5021 return io_getc(fptr, enc);
5044rb_io_readchar(
VALUE io)
5046 VALUE c = rb_io_getc(io);
5081 VALUE r_stdout = rb_ractor_stdout();
5086 rb_io_flush(r_stdout);
5089 if (io_fillbuf(fptr) < 0) {
5118rb_io_readbyte(
VALUE io)
5179 unsigned char c =
NUM2INT(v) & 0xFF;
5185 io_ungetbyte(b, fptr);
5241 else if (RB_BIGNUM_TYPE_P(c)) {
5247 if (NEED_READCONV(fptr)) {
5248 SET_BINARY_MODE(fptr);
5249 len = RSTRING_LEN(c);
5250#if SIZEOF_LONG > SIZEOF_INT
5254 make_readconv(fptr, (
int)
len);
5268 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
5269 io_ungetbyte(c, fptr);
5289rb_io_isatty(
VALUE io)
5294 return RBOOL(isatty(fptr->
fd) != 0);
5297#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5313rb_io_close_on_exec_p(
VALUE io)
5319 write_io = GetWriteIO(io);
5320 if (io != write_io) {
5322 if (fptr && 0 <= (fd = fptr->
fd)) {
5323 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->
pathv);
5324 if (!(ret & FD_CLOEXEC))
return Qfalse;
5329 if (fptr && 0 <= (fd = fptr->
fd)) {
5330 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->
pathv);
5331 if (!(ret & FD_CLOEXEC))
return Qfalse;
5336#define rb_io_close_on_exec_p rb_f_notimplement
5339#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5363 int flag =
RTEST(arg) ? FD_CLOEXEC : 0;
5368 write_io = GetWriteIO(io);
5369 if (io != write_io) {
5371 if (fptr && 0 <= (fd = fptr->
fd)) {
5372 if ((ret = fcntl(fptr->
fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->
pathv);
5373 if ((ret & FD_CLOEXEC) != flag) {
5374 ret = (ret & ~FD_CLOEXEC) | flag;
5375 ret = fcntl(fd, F_SETFD, ret);
5376 if (ret != 0) rb_sys_fail_path(fptr->
pathv);
5383 if (fptr && 0 <= (fd = fptr->
fd)) {
5384 if ((ret = fcntl(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);
5394#define rb_io_set_close_on_exec rb_f_notimplement
5397#define RUBY_IO_EXTERNAL_P(f) ((f)->mode & FMODE_EXTERNAL)
5398#define PREP_STDIO_NAME(f) (RSTRING_PTR((f)->pathv))
5401finish_writeconv(
rb_io_t *fptr,
int noalloc)
5403 unsigned char *ds, *dp, *de;
5407 unsigned char buf[1024];
5412 de = buf +
sizeof(buf);
5415 size_t remaining = dp-ds;
5416 long result = rb_io_write_memory(fptr, ds, remaining);
5420 if ((
size_t)result == remaining)
break;
5443 if (io_fflush(fptr) < 0) {
5451 fptr->
wbuf.
len += (int)(dp - ds);
5467finish_writeconv_sync(
VALUE arg)
5470 return finish_writeconv(p->fptr, p->noalloc);
5474nogvl_close(
void *ptr)
5478 return (
void*)(intptr_t)close(*fd);
5482maygvl_close(
int fd,
int keepgvl)
5491 return IO_WITHOUT_GVL_INT(nogvl_close, &fd);
5495nogvl_fclose(
void *ptr)
5499 return (
void*)(intptr_t)fclose(file);
5503maygvl_fclose(
FILE *file,
int keepgvl)
5506 return fclose(file);
5508 return IO_WITHOUT_GVL_INT(nogvl_fclose, file);
5514fptr_finalize_flush(
rb_io_t *fptr,
int noraise,
int keepgvl)
5519 int mode = fptr->
mode;
5525 arg.noalloc = noraise;
5529 error = finish_writeconv(fptr, noraise);
5534 io_flush_buffer_sync(fptr);
5537 if (io_fflush(fptr) < 0 &&
NIL_P(error)) {
5545 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2) {
5555 rb_thread_io_close_wait(fptr);
5566 if (!done && stdio_file) {
5568 if ((maygvl_fclose(stdio_file, noraise) < 0) &&
NIL_P(error)) {
5577 if (!done && fd >= 0) {
5583 if ((maygvl_close(fd, keepgvl) < 0) &&
NIL_P(error)) {
5592 if (!
NIL_P(error) && !noraise) {
5601fptr_finalize(
rb_io_t *fptr,
int noraise)
5603 fptr_finalize_flush(fptr, noraise, FALSE);
5604 free_io_buffer(&fptr->
rbuf);
5605 free_io_buffer(&fptr->
wbuf);
5606 clear_codeconv(fptr);
5610rb_io_fptr_cleanup(
rb_io_t *fptr,
int noraise)
5616 fptr_finalize(fptr, noraise);
5624 ruby_sized_xfree(buf->
ptr, (
size_t)buf->
capa);
5636 free_io_buffer(&fptr->
cbuf);
5652 clear_readconv(fptr);
5653 clear_writeconv(fptr);
5657rb_io_fptr_cleanup_all(
rb_io_t *fptr)
5661 rb_io_fptr_cleanup(fptr, TRUE);
5663 free_io_buffer(&fptr->
rbuf);
5664 free_io_buffer(&fptr->
wbuf);
5665 clear_codeconv(fptr);
5672 rb_io_fptr_cleanup_all(io);
5679rb_io_memsize(
const rb_io_t *io)
5681 size_t size =
sizeof(
rb_io_t);
5691 rb_serial_t fork_generation = GET_VM()->fork_gen;
5692 if (io->fork_generation == fork_generation) {
5703# define KEEPGVL TRUE
5705# define KEEPGVL FALSE
5709io_close_fptr(
VALUE io)
5715 write_io = GetWriteIO(io);
5716 if (io != write_io) {
5717 write_fptr =
RFILE(write_io)->fptr;
5718 if (write_fptr && 0 <= write_fptr->
fd) {
5719 rb_io_fptr_cleanup(write_fptr, TRUE);
5723 fptr =
RFILE(io)->fptr;
5724 if (!fptr)
return 0;
5725 if (fptr->
fd < 0)
return 0;
5727 if (rb_thread_io_close_interrupt(fptr)) {
5729 fptr_finalize_flush(fptr, FALSE, KEEPGVL);
5731 rb_io_fptr_cleanup(fptr, FALSE);
5736fptr_waitpid(
rb_io_t *fptr,
int nohang)
5740 rb_last_status_clear();
5749 rb_io_t *fptr = io_close_fptr(io);
5750 if (fptr) fptr_waitpid(fptr, 0);
5790rb_io_close_m(
VALUE io)
5792 rb_io_t *fptr = rb_io_get_fptr(io);
5801io_call_close(
VALUE io)
5810 enum {mesg_len =
sizeof(closed_stream)-1};
5811 VALUE mesg = rb_attr_get(exc, idMesg);
5813 RSTRING_LEN(mesg) != mesg_len ||
5814 memcmp(RSTRING_PTR(mesg), closed_stream, mesg_len)) {
5824 if (!UNDEF_P(closed) &&
RTEST(closed))
return io;
5825 rb_rescue2(io_call_close, io, ignore_closed_stream, io,
5861 write_io = GetWriteIO(io);
5862 if (io != write_io) {
5863 write_fptr =
RFILE(write_io)->fptr;
5864 if (write_fptr && 0 <= write_fptr->
fd) {
5869 fptr = rb_io_get_fptr(io);
5870 return RBOOL(0 > fptr->
fd);
5906rb_io_close_read(
VALUE io)
5912 if (fptr->
fd < 0)
return Qnil;
5913 if (is_socket(fptr->
fd, fptr->
pathv)) {
5917 if (shutdown(fptr->
fd, SHUT_RD) < 0)
5918 rb_sys_fail_path(fptr->
pathv);
5919 fptr->
mode &= ~FMODE_READABLE;
5925 write_io = GetWriteIO(io);
5926 if (io != write_io) {
5931 RFILE(io)->fptr = wfptr;
5934 RFILE(write_io)->fptr = fptr;
5935 rb_io_fptr_cleanup(fptr, FALSE);
5941 rb_raise(
rb_eIOError,
"closing non-duplex IO for reading");
5979rb_io_close_write(
VALUE io)
5984 write_io = GetWriteIO(io);
5986 if (fptr->
fd < 0)
return Qnil;
5987 if (is_socket(fptr->
fd, fptr->
pathv)) {
5991 if (shutdown(fptr->
fd, SHUT_WR) < 0)
5992 rb_sys_fail_path(fptr->
pathv);
5993 fptr->
mode &= ~FMODE_WRITABLE;
6000 rb_raise(
rb_eIOError,
"closing non-duplex IO for writing");
6003 if (io != write_io) {
6023rb_io_sysseek(
int argc,
VALUE *argv,
VALUE io)
6025 VALUE offset, ptrname;
6026 int whence = SEEK_SET;
6030 if (
rb_scan_args(argc, argv,
"11", &offset, &ptrname) == 2) {
6031 whence = interpret_seek_whence(ptrname);
6036 (READ_DATA_BUFFERED(fptr) || READ_CHAR_PENDING(fptr))) {
6040 rb_warn(
"sysseek for buffered IO");
6043 pos = lseek(fptr->
fd, pos, whence);
6044 if (pos < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
6078 io = GetWriteIO(io);
6083 rb_warn(
"syswrite for buffered IO");
6086 tmp = rb_str_tmp_frozen_acquire(str);
6088 n = rb_io_write_memory(fptr, ptr,
len);
6089 if (n < 0) rb_sys_fail_path(fptr->
pathv);
6090 rb_str_tmp_frozen_release(str, tmp);
6107rb_io_sysread(
int argc,
VALUE *argv,
VALUE io)
6118 shrinkable = io_setstrbuf(&str, ilen);
6119 if (ilen == 0)
return str;
6124 if (READ_DATA_BUFFERED(fptr)) {
6130 io_setstrbuf(&str, ilen);
6135 iis.buf = RSTRING_PTR(str);
6138 n = io_read_memory_locktmp(str, &iis);
6141 rb_sys_fail_path(fptr->
pathv);
6144 io_set_read_length(str, n, shrinkable);
6146 if (n == 0 && ilen > 0) {
6162internal_pread_func(
void *_arg)
6166 return (
VALUE)pread(arg->fd, arg->buf, arg->count, arg->offset);
6170pread_internal_call(
VALUE _arg)
6175 if (scheduler !=
Qnil) {
6178 if (!UNDEF_P(result)) {
6183 return rb_io_blocking_region_wait(arg->io, internal_pread_func, arg,
RUBY_IO_READABLE);
6227 shrinkable = io_setstrbuf(&str, (
long)arg.count);
6228 if (arg.count == 0)
return str;
6229 arg.buf = RSTRING_PTR(str);
6242 rb_sys_fail_path(fptr->
pathv);
6244 io_set_read_length(str, n, shrinkable);
6245 if (n == 0 && arg.count > 0) {
6253internal_pwrite_func(
void *_arg)
6258 if (scheduler !=
Qnil) {
6261 if (!UNDEF_P(result)) {
6267 return (
VALUE)pwrite(arg->fd, arg->buf, arg->count, arg->offset);
6308 io = GetWriteIO(io);
6315 tmp = rb_str_tmp_frozen_acquire(str);
6316 arg.buf = RSTRING_PTR(tmp);
6317 arg.count = (size_t)RSTRING_LEN(tmp);
6319 n = (ssize_t)rb_io_blocking_region_wait(fptr, internal_pwrite_func, &arg,
RUBY_IO_WRITABLE);
6320 if (n < 0) rb_sys_fail_path(fptr->
pathv);
6321 rb_str_tmp_frozen_release(str, tmp);
6337 fptr->
mode &= ~FMODE_TEXTMODE;
6341 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6344 setmode(fptr->
fd, O_BINARY);
6351io_ascii8bit_binmode(
rb_io_t *fptr)
6362 fptr->
mode &= ~FMODE_TEXTMODE;
6363 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6365 fptr->
encs.
enc = rb_ascii8bit_encoding();
6369 clear_codeconv(fptr);
6378 io_ascii8bit_binmode(fptr);
6395rb_io_binmode_m(
VALUE io)
6401 write_io = GetWriteIO(io);
6416rb_io_binmode_p(
VALUE io)
6424rb_io_fmode_modestr(
enum rb_io_mode fmode)
6428 return MODE_BTMODE(
"a+",
"ab+",
"at+");
6430 return MODE_BTMODE(
"a",
"ab",
"at");
6434 rb_raise(rb_eArgError,
"invalid access fmode 0x%x", fmode);
6436 return MODE_BTMODE(
"r",
"rb",
"rt");
6438 return MODE_BTXMODE(
"w",
"wb",
"wt",
"wx",
"wbx",
"wtx");
6441 return MODE_BTXMODE(
"w+",
"wb+",
"wt+",
"w+x",
"wb+x",
"wt+x");
6443 return MODE_BTMODE(
"r+",
"rb+",
"rt+");
6447static const char bom_prefix[] =
"bom|";
6448static const char utf_prefix[] =
"utf-";
6449enum {bom_prefix_len = (int)
sizeof(bom_prefix) - 1};
6450enum {utf_prefix_len = (int)
sizeof(utf_prefix) - 1};
6453io_encname_bom_p(
const char *name,
long len)
6455 return len > bom_prefix_len &&
STRNCASECMP(name, bom_prefix, bom_prefix_len) == 0;
6461 enum rb_io_mode fmode = 0;
6462 const char *m = modestr, *p = NULL;
6490 if (modestr[0] !=
'w')
6498 if (io_encname_bom_p(m, p ? (
long)(p - m) : (long)strlen(m)))
6511 rb_raise(rb_eArgError,
"invalid access mode %s", modestr);
6516rb_io_oflags_fmode(
int oflags)
6518 enum rb_io_mode fmode = 0;
6520 switch (oflags & O_ACCMODE) {
6532 if (oflags & O_APPEND) {
6535 if (oflags & O_TRUNC) {
6538 if (oflags & O_CREAT) {
6541 if (oflags & O_EXCL) {
6545 if (oflags & O_BINARY) {
6554rb_io_fmode_oflags(
enum rb_io_mode fmode)
6598rb_io_oflags_modestr(
int oflags)
6601# define MODE_BINARY(a,b) ((oflags & O_BINARY) ? (b) : (a))
6603# define MODE_BINARY(a,b) (a)
6606 if (oflags & O_EXCL) {
6607 rb_raise(rb_eArgError,
"exclusive access mode is not supported");
6609 accmode = oflags & (O_RDONLY|O_WRONLY|O_RDWR);
6610 if (oflags & O_APPEND) {
6611 if (accmode == O_WRONLY) {
6612 return MODE_BINARY(
"a",
"ab");
6614 if (accmode == O_RDWR) {
6615 return MODE_BINARY(
"a+",
"ab+");
6620 rb_raise(rb_eArgError,
"invalid access oflags 0x%x", oflags);
6622 return MODE_BINARY(
"r",
"rb");
6624 return MODE_BINARY(
"w",
"wb");
6626 if (oflags & O_TRUNC) {
6627 return MODE_BINARY(
"w+",
"wb+");
6629 return MODE_BINARY(
"r+",
"rb+");
6641 int default_ext = 0;
6644 ext = rb_default_external_encoding();
6647 if (rb_is_ascii8bit_enc(ext)) {
6651 else if (intern == NULL) {
6652 intern = rb_default_internal_encoding();
6657 *enc = (default_ext && intern != ext) ? NULL : ext;
6667unsupported_encoding(
const char *name,
rb_encoding *enc)
6669 rb_enc_warn(enc,
"Unsupported encoding %s ignored", name);
6673parse_mode_enc(
const char *estr,
rb_encoding *estr_enc,
6679 enum rb_io_mode fmode = fmode_p ? *fmode_p : 0;
6685 p = strrchr(estr,
':');
6686 len = p ? (p++ - estr) : (long)strlen(estr);
6688 estr += bom_prefix_len;
6689 len -= bom_prefix_len;
6690 if (!
STRNCASECMP(estr, utf_prefix, utf_prefix_len)) {
6694 rb_enc_warn(estr_enc,
"BOM with non-UTF encoding %s is nonsense", estr);
6695 fmode &= ~FMODE_SETENC_BY_BOM;
6703 memcpy(encname, estr,
len);
6704 encname[
len] =
'\0';
6707 idx = rb_enc_find_index(estr);
6709 if (fmode_p) *fmode_p = fmode;
6712 ext_enc = rb_enc_from_index(idx);
6715 unsupported_encoding(estr, estr_enc);
6721 if (*p ==
'-' && *(p+1) ==
'\0') {
6726 idx2 = rb_enc_find_index(p);
6728 unsupported_encoding(p, estr_enc);
6733 int_enc = rb_enc_from_index(idx2);
6737 rb_io_ext_int_to_encs(ext_enc, int_enc, enc_p, enc2_p, fmode);
6750 v = rb_hash_lookup2(opt, sym_encoding,
Qnil);
6751 if (v !=
Qnil) encoding = v;
6752 v = rb_hash_lookup2(opt, sym_extenc,
Qundef);
6753 if (v !=
Qnil) extenc = v;
6754 v = rb_hash_lookup2(opt, sym_intenc,
Qundef);
6755 if (!UNDEF_P(v)) intenc = v;
6757 if ((!UNDEF_P(extenc) || !UNDEF_P(intenc)) && !
NIL_P(encoding)) {
6759 int idx = rb_to_encoding_index(encoding);
6760 if (idx >= 0) encoding = rb_enc_from_encoding(rb_enc_from_index(idx));
6761 rb_warn(
"Ignoring encoding parameter '%"PRIsVALUE
"': %s_encoding is used",
6762 encoding, UNDEF_P(extenc) ?
"internal" :
"external");
6766 if (!UNDEF_P(extenc) && !
NIL_P(extenc)) {
6767 extencoding = rb_to_encoding(extenc);
6769 if (!UNDEF_P(intenc)) {
6770 if (
NIL_P(intenc)) {
6777 if (*p ==
'-' && *(p+1) ==
'\0') {
6782 intencoding = rb_to_encoding(intenc);
6786 intencoding = rb_to_encoding(intenc);
6788 if (extencoding == intencoding) {
6792 if (!
NIL_P(encoding)) {
6796 enc_p, enc2_p, fmode_p);
6799 rb_io_ext_int_to_encs(rb_to_encoding(encoding), NULL, enc_p, enc2_p, 0);
6802 else if (!UNDEF_P(extenc) || !UNDEF_P(intenc)) {
6804 rb_io_ext_int_to_encs(extencoding, intencoding, enc_p, enc2_p, 0);
6812 enum rb_io_mode fmode = *fmode_p;
6817 !rb_enc_asciicompat(enc ? enc : rb_default_external_encoding()))
6818 rb_raise(rb_eArgError,
"ASCII incompatible encoding needs binmode");
6821 rb_raise(rb_eArgError,
"newline decorator with binary mode");
6828#if !DEFAULT_TEXTMODE
6830 fmode &= ~FMODE_TEXTMODE;
6837extract_binmode(
VALUE opthash,
enum rb_io_mode *fmode)
6839 if (!
NIL_P(opthash)) {
6841 v = rb_hash_aref(opthash, sym_textmode);
6844 rb_raise(rb_eArgError,
"textmode specified twice");
6846 rb_raise(rb_eArgError,
"both textmode and binmode specified");
6850 v = rb_hash_aref(opthash, sym_binmode);
6853 rb_raise(rb_eArgError,
"binmode specified twice");
6855 rb_raise(rb_eArgError,
"both textmode and binmode specified");
6861 rb_raise(rb_eArgError,
"both textmode and binmode specified");
6867 int *oflags_p,
enum rb_io_mode *fmode_p,
struct rb_io_encoding *convconfig_p)
6871 enum rb_io_mode fmode;
6875 int has_enc = 0, has_vmode = 0;
6881 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
6891 fmode = rb_io_oflags_fmode(oflags);
6899 oflags = rb_io_fmode_oflags(fmode);
6903 parse_mode_enc(p+1, rb_enc_get(vmode), &enc, &enc2, &fmode);
6908 e = (fmode &
FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
6909 rb_io_ext_int_to_encs(e, NULL, &enc, &enc2, fmode);
6913 if (
NIL_P(opthash)) {
6917#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
6919 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
6920 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
6922 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
6929 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
6932 else if (
NIL_P(vmode)) {
6933 fmode |= DEFAULT_TEXTMODE;
6940 v = rb_hash_aref(opthash, sym_mode);
6942 if (!
NIL_P(vmode)) {
6943 rb_raise(rb_eArgError,
"mode specified twice");
6950 v = rb_hash_aref(opthash, sym_flags);
6955 fmode = rb_io_oflags_fmode(oflags);
6957 extract_binmode(opthash, &fmode);
6963 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
6966 else if (
NIL_P(vmode)) {
6967 fmode |= DEFAULT_TEXTMODE;
6970 v = rb_hash_aref(opthash, sym_perm);
6973 if (!
NIL_P(*vperm_p)) {
6974 rb_raise(rb_eArgError,
"perm specified twice");
6985#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
6987 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
6988 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
6993 rb_raise(rb_eArgError,
"encoding specified twice");
6996 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
7000 validate_enc_binmode(&fmode, ecflags, enc, enc2);
7006 convconfig_p->
enc = enc;
7007 convconfig_p->
enc2 = enc2;
7008 convconfig_p->
ecflags = ecflags;
7009 convconfig_p->
ecopts = ecopts;
7019sysopen_func(
void *ptr)
7022 const char *fname = RSTRING_PTR(data->fname);
7031 fd = IO_WITHOUT_GVL_INT(sysopen_func, data);
7032 }
while (fd < 0 &&
errno == EINTR);
7039rb_sysopen(
VALUE fname,
int oflags, mode_t perm)
7044 data.fname = rb_str_encode_ospath(fname);
7046 data.oflags = oflags;
7049 TRY_WITH_GC((fd = rb_sysopen_internal(&data)) >= 0) {
7050 rb_syserr_fail_path(first_errno, fname);
7056fdopen_internal(
int fd,
const char *modestr)
7063 file = fdopen(fd, modestr);
7079 TRY_WITH_GC((file = fdopen_internal(fd, modestr)) != 0) {
7085 if (setvbuf(file, NULL, _IOFBF, 0) != 0)
7086 rb_warn(
"setvbuf() can't be honoured (fd=%d)", fd);
7094 int t = isatty(fptr->
fd);
7104io_strip_bom(
VALUE io)
7106 VALUE b1, b2, b3, b4;
7117 return rb_utf8_encindex();
7127 return ENCINDEX_UTF_16BE;
7138 return ENCINDEX_UTF_32LE;
7143 return ENCINDEX_UTF_16LE;
7153 return ENCINDEX_UTF_32BE;
7167io_set_encoding_by_bom(
VALUE io)
7169 int idx = io_strip_bom(io);
7175 extenc = rb_enc_from_index(idx);
7176 io_encoding_set(fptr, rb_enc_from_encoding(extenc),
7177 rb_io_internal_encoding(io),
Qnil);
7186rb_file_open_generic(
VALUE io,
VALUE filename,
int oflags,
enum rb_io_mode fmode,
7194 rb_io_ext_int_to_encs(NULL, NULL, &cc.enc, &cc.enc2, fmode);
7199 validate_enc_binmode(&fmode, convconfig->
ecflags,
7200 convconfig->
enc, convconfig->
enc2);
7204 fptr->
encs = *convconfig;
7207 if (!(oflags & O_TMPFILE)) {
7208 fptr->
pathv = pathv;
7211 fptr->
pathv = pathv;
7213 fptr->
fd = rb_sysopen(pathv, oflags, perm);
7221rb_file_open_internal(
VALUE io,
VALUE filename,
const char *modestr)
7224 const char *p = strchr(modestr,
':');
7228 parse_mode_enc(p+1, rb_usascii_encoding(),
7229 &convconfig.
enc, &convconfig.
enc2, &fmode);
7235 e = (fmode &
FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
7236 rb_io_ext_int_to_encs(e, NULL, &convconfig.
enc, &convconfig.
enc2, fmode);
7242#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7244 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7245 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7247 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.
enc2, convconfig.
ecflags);
7250 return rb_file_open_generic(io, filename,
7251 rb_io_fmode_oflags(fmode),
7261 return rb_file_open_internal(io_alloc(
rb_cFile), fname, modestr);
7270#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7293 while ((tmp = *prev) != 0) {
7294 if (tmp->fptr == fptr) {
7303#if defined (_WIN32) || defined(__CYGWIN__)
7319pipe_finalize(
rb_io_t *fptr,
int noraise)
7321#if !defined(HAVE_WORKING_FORK) && !defined(_WIN32)
7330 fptr_finalize(fptr, noraise);
7332 pipe_del_fptr(fptr);
7339#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7340 void (*
const old_finalize)(
struct rb_io*,int) = fptr->
finalize;
7342 if (old_finalize == orig->finalize)
return;
7347#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7348 if (old_finalize != pipe_finalize) {
7350 for (list =
pipe_list; list; list = list->next) {
7351 if (list->fptr == fptr)
break;
7353 if (!list) pipe_add_fptr(fptr);
7356 pipe_del_fptr(fptr);
7369rb_io_unbuffered(
rb_io_t *fptr)
7387#define HAVE_SPAWNV 1
7388#define spawnv(mode, cmd, args) rb_w32_uaspawn((mode), (cmd), (args))
7389#define spawn(mode, cmd) rb_w32_uspawn((mode), (cmd), 0)
7392#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7402#ifdef HAVE_WORKING_FORK
7403# ifndef __EMSCRIPTEN__
7405popen_redirect(
struct popen_arg *p)
7408 close(p->write_pair[1]);
7409 if (p->write_pair[0] != 0) {
7410 dup2(p->write_pair[0], 0);
7411 close(p->write_pair[0]);
7414 if (p->pair[1] != 1) {
7415 dup2(p->pair[1], 1);
7421 if (p->pair[1] != 1) {
7422 dup2(p->pair[1], 1);
7428 if (p->pair[0] != 0) {
7429 dup2(p->pair[0], 0);
7436#if defined(__linux__)
7447linux_get_maxfd(
void)
7450 char buf[4096], *p, *np, *e;
7453 if (fd < 0)
return fd;
7454 ss = read(fd, buf,
sizeof(buf));
7455 if (ss < 0)
goto err;
7458 while ((
int)
sizeof(
"FDSize:\t0\n")-1 <= e-p &&
7459 (np = memchr(p,
'\n', e-p)) != NULL) {
7460 if (memcmp(p,
"FDSize:",
sizeof(
"FDSize:")-1) == 0) {
7462 p +=
sizeof(
"FDSize:")-1;
7482#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
7484 int max = (int)max_file_descriptor;
7487 ret = fcntl(0, F_MAXFD);
7489 maxhint = max = ret;
7490# elif defined(__linux__)
7491 ret = linux_get_maxfd();
7498 for (fd = lowfd; fd <= max; fd++) {
7499 if (!
NIL_P(noclose_fds) &&
7502 ret = fcntl(fd, F_GETFD);
7503 if (ret != -1 && !(ret & FD_CLOEXEC)) {
7504 fcntl(fd, F_SETFD, ret|FD_CLOEXEC);
7506# define CONTIGUOUS_CLOSED_FDS 20
7508 if (max < fd + CONTIGUOUS_CLOSED_FDS)
7509 max = fd + CONTIGUOUS_CLOSED_FDS;
7515# ifndef __EMSCRIPTEN__
7517popen_exec(
void *pp,
char *errmsg,
size_t errmsg_len)
7519 struct popen_arg *p = (
struct popen_arg*)pp;
7521 return rb_exec_async_signal_safe(p->eargp, errmsg, errmsg_len);
7526#if (defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)) && !defined __EMSCRIPTEN__
7528rb_execarg_fixup_v(
VALUE execarg_obj)
7530 rb_execarg_parent_start(execarg_obj);
7534char *rb_execarg_commandline(
const struct rb_execarg *eargp,
VALUE *prog);
7537#ifndef __EMSCRIPTEN__
7539pipe_open(
VALUE execarg_obj,
const char *modestr,
enum rb_io_mode fmode,
7542 struct rb_execarg *eargp =
NIL_P(execarg_obj) ? NULL : rb_execarg_get(execarg_obj);
7543 VALUE prog = eargp ? (eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name) :
Qfalse ;
7549#if defined(HAVE_WORKING_FORK)
7551 char errmsg[80] = {
'\0' };
7553#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7555 struct popen_arg arg;
7558#if defined(HAVE_SPAWNV)
7559# if defined(HAVE_SPAWNVE)
7560# define DO_SPAWN(cmd, args, envp) ((args) ? \
7561 spawnve(P_NOWAIT, (cmd), (args), (envp)) : \
7562 spawne(P_NOWAIT, (cmd), (envp)))
7564# define DO_SPAWN(cmd, args, envp) ((args) ? \
7565 spawnv(P_NOWAIT, (cmd), (args)) : \
7566 spawn(P_NOWAIT, (cmd)))
7568# if !defined(HAVE_WORKING_FORK)
7570# if defined(HAVE_SPAWNVE)
7575#if !defined(HAVE_WORKING_FORK)
7581#if !defined(HAVE_WORKING_FORK)
7582 const char *cmd = 0;
7588#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7589 arg.execarg_obj = execarg_obj;
7592 arg.pair[0] = arg.pair[1] = -1;
7593 arg.write_pair[0] = arg.write_pair[1] = -1;
7594# if !defined(HAVE_WORKING_FORK)
7595 if (eargp && !eargp->use_shell) {
7596 args = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
7601 if (
rb_pipe(arg.write_pair) < 0)
7602 rb_sys_fail_str(prog);
7605 close(arg.write_pair[0]);
7606 close(arg.write_pair[1]);
7610 rb_execarg_addopt(execarg_obj,
INT2FIX(0),
INT2FIX(arg.write_pair[0]));
7611 rb_execarg_addopt(execarg_obj,
INT2FIX(1),
INT2FIX(arg.pair[1]));
7616 rb_sys_fail_str(prog);
7618 rb_execarg_addopt(execarg_obj,
INT2FIX(1),
INT2FIX(arg.pair[1]));
7622 rb_sys_fail_str(prog);
7624 rb_execarg_addopt(execarg_obj,
INT2FIX(0),
INT2FIX(arg.pair[0]));
7627 rb_sys_fail_str(prog);
7629 if (!
NIL_P(execarg_obj)) {
7630 rb_protect(rb_execarg_fixup_v, execarg_obj, &state);
7632 if (0 <= arg.write_pair[0]) close(arg.write_pair[0]);
7633 if (0 <= arg.write_pair[1]) close(arg.write_pair[1]);
7634 if (0 <= arg.pair[0]) close(arg.pair[0]);
7635 if (0 <= arg.pair[1]) close(arg.pair[1]);
7636 rb_execarg_parent_end(execarg_obj);
7640# if defined(HAVE_WORKING_FORK)
7641 pid = rb_fork_async_signal_safe(&status, popen_exec, &arg, arg.eargp->redirect_fds, errmsg,
sizeof(errmsg));
7643 rb_execarg_run_options(eargp, sargp, NULL, 0);
7644# if defined(HAVE_SPAWNVE)
7645 if (eargp->envp_str) envp = (
char **)RSTRING_PTR(eargp->envp_str);
7647 while ((pid = DO_SPAWN(cmd, args, envp)) < 0) {
7649 switch (e =
errno) {
7651# if EWOULDBLOCK != EAGAIN
7660 rb_execarg_run_options(sargp, NULL, NULL, 0);
7662 rb_execarg_parent_end(execarg_obj);
7665# if defined(HAVE_WORKING_FORK)
7666 pid = rb_call_proc__fork();
7668 popen_redirect(&arg);
7680# if defined(HAVE_WORKING_FORK)
7686 close(arg.write_pair[0]);
7687 close(arg.write_pair[1]);
7689# if defined(HAVE_WORKING_FORK)
7698 close(arg.write_pair[0]);
7699 write_fd = arg.write_pair[1];
7710 cmd = rb_execarg_commandline(eargp, &prog);
7711 if (!
NIL_P(execarg_obj)) {
7712 rb_execarg_parent_start(execarg_obj);
7713 rb_execarg_run_options(eargp, sargp, NULL, 0);
7715 fp = popen(cmd, modestr);
7718 rb_execarg_parent_end(execarg_obj);
7719 rb_execarg_run_options(sargp, NULL, NULL, 0);
7721 if (!fp) rb_syserr_fail_path(e, prog);
7731 fptr->
encs = *convconfig;
7732#if RUBY_CRLF_ENVIRONMENT
7739 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
7742#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7743 if (NEED_NEWLINE_DECORATOR_ON_WRITE(fptr)) {
7744 fptr->
encs.
ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
7750 if (0 <= write_fd) {
7751 write_port = io_alloc(
rb_cIO);
7753 write_fptr->
fd = write_fd;
7755 fptr->
mode &= ~FMODE_WRITABLE;
7757 rb_ivar_set(port, rb_intern(
"@tied_io_for_writing"), write_port);
7760#if defined (__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7762 pipe_add_fptr(fptr);
7768pipe_open(
VALUE execarg_obj,
const char *modestr,
enum rb_io_mode fmode,
7776is_popen_fork(
VALUE prog)
7778 if (RSTRING_LEN(prog) == 1 && RSTRING_PTR(prog)[0] ==
'-') {
7779#if !defined(HAVE_WORKING_FORK)
7781 "fork() function is unimplemented on this machine");
7790pipe_open_s(
VALUE prog,
const char *modestr,
enum rb_io_mode fmode,
7794 VALUE *argv = &prog;
7797 if (!is_popen_fork(prog))
7798 execarg_obj = rb_execarg_new(argc, argv, TRUE, FALSE);
7799 return pipe_open(execarg_obj, modestr, fmode, convconfig);
7805 rb_io_t *fptr = io_close_fptr(io);
7974rb_io_s_popen(
int argc,
VALUE *argv,
VALUE klass)
7978 if (argc > 1 && !
NIL_P(opt = rb_check_hash_type(argv[argc-1]))) --argc;
7979 if (argc > 1 && !
NIL_P(env = rb_check_hash_type(argv[0]))) --argc, ++argv;
7988 int ex = !
NIL_P(opt);
7989 rb_error_arity(argc + ex, 1 + ex, 2 + ex);
7992 return popen_finish(rb_io_popen(pname, pmode, env, opt), klass);
7998 const char *modestr;
8001 enum rb_io_mode fmode;
8007#if SIZEOF_LONG > SIZEOF_INT
8008 if (
len > INT_MAX) {
8009 rb_raise(rb_eArgError,
"too many arguments");
8018 if (!is_popen_fork(pname))
8019 execarg_obj = rb_execarg_new(1, &pname, TRUE, FALSE);
8021 if (!
NIL_P(execarg_obj)) {
8023 opt = rb_execarg_extract_options(execarg_obj, opt);
8025 rb_execarg_setenv(execarg_obj, env);
8028 modestr = rb_io_oflags_modestr(oflags);
8030 return pipe_open(execarg_obj, modestr, fmode, &convconfig);
8040 rb_io_flush(rb_ractor_stdout());
8041 rb_io_flush(rb_ractor_stderr());
8046 RBASIC_SET_CLASS(port, klass);
8053#if defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)
8054struct popen_writer_arg {
8056 struct popen_arg popen;
8060exec_popen_writer(
void *arg,
char *errmsg,
size_t buflen)
8062 struct popen_writer_arg *pw = arg;
8064 popen_redirect(&pw->popen);
8065 execv(pw->argv[0], pw->argv);
8066 strlcpy(errmsg, strerror(
errno), buflen);
8072ruby_popen_writer(
char *
const *argv, rb_pid_t *pid)
8074#if (defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)) || defined(_WIN32)
8075# ifdef HAVE_WORKING_FORK
8076 struct popen_writer_arg pw;
8077 int *
const write_pair = pw.popen.pair;
8083 int result = pipe2(write_pair, O_CLOEXEC);
8085 int result = pipe(write_pair);
8090# ifdef HAVE_WORKING_FORK
8093 char errmsg[80] = {
'\0'};
8094 *pid = rb_fork_async_signal_safe(&status, exec_popen_writer, &pw,
Qnil, errmsg,
sizeof(errmsg));
8096 *pid = rb_w32_uspawn_process(P_NOWAIT, argv[0], argv, write_pair[0], -1, -1, 0);
8097 const char *errmsg = (*pid < 0) ? strerror(
errno) : NULL;
8099 close(write_pair[0]);
8101 close(write_pair[1]);
8102 fprintf(stderr,
"ruby_popen_writer(%s): %s\n", argv[0], errmsg);
8105 return fdopen(write_pair[1],
"w");
8116 enum rb_io_mode fmode;
8125 rb_file_open_generic(io, fname, oflags, fmode, &convconfig, perm);
8163rb_io_s_open(
int argc,
VALUE *argv,
VALUE klass)
8195 VALUE fname, vmode, vperm;
8200 rb_scan_args(argc, argv,
"12", &fname, &vmode, &vperm);
8211 if (
NIL_P(vperm)) perm = 0666;
8215 fd = rb_sysopen(fname, oflags, perm);
8250 int redirect = FALSE;
8258 VALUE tmp = argv[0];
8276 return rb_io_s_open(argc, argv,
rb_cFile);
8280rb_io_open_generic(
VALUE klass,
VALUE filename,
int oflags,
enum rb_io_mode fmode,
8283 return rb_file_open_generic(io_alloc(klass), filename,
8284 oflags, fmode, convconfig, perm);
8291 enum rb_io_mode fmode;
8297 return rb_io_open_generic(io, filename, oflags, fmode, &convconfig, perm);
8311 if (fptr == orig)
return io;
8312 if (RUBY_IO_EXTERNAL_P(fptr)) {
8316 rb_raise(rb_eArgError,
8317 "%s can't change access mode from \"%s\" to \"%s\"",
8318 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->
mode),
8319 rb_io_fmode_modestr(orig->
mode));
8323 if (io_fflush(fptr) < 0)
8324 rb_sys_fail_on_write(fptr);
8327 flush_before_seek(fptr,
true);
8330 pos = io_tell(orig);
8333 if (io_fflush(orig) < 0)
8334 rb_sys_fail_on_write(fptr);
8343 else if (!RUBY_IO_EXTERNAL_P(fptr)) fptr->
pathv =
Qnil;
8344 fptr_copy_finalizer(fptr, orig);
8350 rb_thread_io_close_interrupt(fptr);
8351 rb_thread_io_close_wait(fptr);
8353 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2 || !fptr->stdio_file) {
8356 rb_sys_fail_path(orig->
pathv);
8364 rb_sys_fail_path(orig->
pathv);
8370 if (io_seek(fptr, pos, SEEK_SET) < 0 &&
errno) {
8371 rb_sys_fail_path(fptr->
pathv);
8373 if (io_seek(orig, pos, SEEK_SET) < 0 &&
errno) {
8374 rb_sys_fail_path(orig->
pathv);
8388int rb_freopen(
VALUE fname,
const char *mode,
FILE *fp);
8391rb_freopen(
VALUE fname,
const char *mode,
FILE *fp)
8393 if (!freopen(RSTRING_PTR(fname), mode, fp)) {
8436rb_io_reopen(
int argc,
VALUE *argv,
VALUE file)
8438 VALUE fname, nmode, opt;
8442 if (
rb_scan_args(argc, argv,
"11:", &fname, &nmode, &opt) == 1) {
8445 return io_reopen(file, tmp);
8451 fptr =
RFILE(file)->fptr;
8457 enum rb_io_mode fmode;
8461 if (RUBY_IO_EXTERNAL_P(fptr) &&
8464 rb_raise(rb_eArgError,
8465 "%s can't change access mode from \"%s\" to \"%s\"",
8466 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->
mode),
8467 rb_io_fmode_modestr(fmode));
8470 fptr->
encs = convconfig;
8473 oflags = rb_io_fmode_oflags(fptr->
mode);
8476 fptr->
pathv = fname;
8478 fptr->
fd = rb_sysopen(fptr->
pathv, oflags, 0666);
8484 if (io_fflush(fptr) < 0)
8485 rb_sys_fail_on_write(fptr);
8490 int e = rb_freopen(rb_str_encode_ospath(fptr->
pathv),
8491 rb_io_oflags_modestr(oflags),
8493 if (e) rb_syserr_fail_path(e, fptr->
pathv);
8497 if (setvbuf(fptr->
stdio_file, NULL, _IOFBF, 0) != 0)
8498 rb_warn(
"setvbuf() can't be honoured for %"PRIsVALUE, fptr->
pathv);
8501 if (setvbuf(fptr->
stdio_file, NULL, _IONBF, BUFSIZ) != 0)
8502 rb_warn(
"setvbuf() can't be honoured for %"PRIsVALUE, fptr->
pathv);
8504 else if (fptr->
stdio_file == stdout && isatty(fptr->
fd)) {
8505 if (setvbuf(fptr->
stdio_file, NULL, _IOLBF, BUFSIZ) != 0)
8506 rb_warn(
"setvbuf() can't be honoured for %"PRIsVALUE, fptr->
pathv);
8510 int tmpfd = rb_sysopen(fptr->
pathv, oflags, 0666);
8516 rb_syserr_fail_path(err, fptr->
pathv);
8540 fptr->
mode = orig->
mode & ~FMODE_EXTERNAL;
8547 fptr->closing_ec = NULL;
8548 fptr->wakeup_mutex =
Qnil;
8549 fptr->fork_generation = GET_VM()->fork_gen;
8552 fptr_copy_finalizer(fptr, orig);
8554 fd = ruby_dup(orig->
fd);
8556 pos = io_tell(orig);
8558 io_seek(fptr, pos, SEEK_SET);
8563 write_io = GetWriteIO(io);
8564 if (io != write_io) {
8567 rb_ivar_set(dest, rb_intern(
"@tied_io_for_writing"), write_io);
8630 if (argc == 0)
return Qnil;
8632 out = rb_ractor_stdout();
8649 rb_warn_deprecated(
"'%s'", NULL, rb_id2name(
id));
8659 rb_raise(
rb_eTypeError,
"value of %"PRIsVALUE
" must be String", rb_id2str(
id));
8665 val = rb_str_frozen_bare_string(val);
8668 rb_warn_deprecated(
"'%s'", NULL, rb_id2name(
id));
8744 for (i=0; i<argc; i++) {
8748 rb_io_write(out, argv[i]);
8845 rb_io_write(io, str);
8849#define forward(obj, id, argc, argv) \
8850 rb_funcallv_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8851#define forward_public(obj, id, argc, argv) \
8852 rb_funcallv_public_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8853#define forward_current(id, argc, argv) \
8854 forward_public(ARGF.current_file, id, argc, argv)
8871 VALUE r_stdout = rb_ractor_stdout();
8872 if (recv == r_stdout) {
8873 return rb_io_putc(recv, ch);
8875 return forward(r_stdout, rb_intern(
"putc"), 1, &ch);
8880rb_str_end_with_asciichar(
VALUE str,
int c)
8882 long len = RSTRING_LEN(str);
8883 const char *
ptr = RSTRING_PTR(str);
8887 if (
len == 0)
return 0;
8888 if ((n = rb_enc_mbminlen(
enc)) == 1) {
8889 return ptr[
len - 1] == c;
8891 return rb_enc_ascget(
ptr + ((
len - 1) / n) * n,
ptr +
len, &n,
enc) == c;
8902 rb_io_puts(1, &tmp, out);
8909 rb_io_puts(1, &tmp, out);
8964 VALUE line, args[2];
8971 for (
int i = 0; i < argc; i++) {
8985 if (RSTRING_LEN(line) == 0) {
8990 if (!rb_str_end_with_asciichar(line,
'\n')) {
8995 rb_io_writev(out, n, args);
9013 VALUE r_stdout = rb_ractor_stdout();
9014 if (recv == r_stdout) {
9015 return rb_io_puts(argc, argv, recv);
9017 return forward(r_stdout, rb_intern(
"puts"), argc, argv);
9021rb_p_write(
VALUE str)
9026 VALUE r_stdout = rb_ractor_stdout();
9028 rb_method_basic_definition_p(
CLASS_OF(r_stdout), id_write)) {
9029 io_writev(2, args, r_stdout);
9032 rb_io_writev(r_stdout, 2, args);
9044rb_p_result(
int argc,
const VALUE *argv)
9051 else if (argc > 1) {
9054 VALUE r_stdout = rb_ractor_stdout();
9056 rb_uninterruptible(rb_io_flush, r_stdout);
9097 for (i=0; i<argc; i++) {
9099 rb_uninterruptible(rb_p_write, inspected);
9101 return rb_p_result(argc, argv);
9122rb_obj_display(
int argc,
VALUE *argv,
VALUE self)
9126 out = (!
rb_check_arity(argc, 0, 1) ? rb_ractor_stdout() : argv[0]);
9127 rb_io_write(out, self);
9133rb_stderr_to_original_p(
VALUE err)
9135 return (err == orig_stderr ||
RFILE(orig_stderr)->fptr->
fd < 0);
9141 VALUE out = rb_ractor_stderr();
9142 if (rb_stderr_to_original_p(out)) {
9144 if (isatty(fileno(stderr))) {
9145 if (rb_w32_write_console(
rb_str_new(mesg,
len), fileno(stderr)) > 0)
return;
9148 if (fwrite(mesg,
sizeof(
char), (
size_t)
len, stderr) < (
size_t)
len) {
9165rb_write_error_str(
VALUE mesg)
9167 VALUE out = rb_ractor_stderr();
9169 if (rb_stderr_to_original_p(out)) {
9170 size_t len = (size_t)RSTRING_LEN(mesg);
9172 if (isatty(fileno(stderr))) {
9173 if (rb_w32_write_console(mesg, fileno(stderr)) > 0)
return;
9176 if (fwrite(RSTRING_PTR(mesg),
sizeof(
char),
len, stderr) <
len) {
9183 rb_io_write(out, mesg);
9188rb_stderr_tty_p(
void)
9190 if (rb_stderr_to_original_p(rb_ractor_stderr()))
9191 return isatty(fileno(stderr));
9196must_respond_to(
ID mid,
VALUE val,
ID id)
9199 rb_raise(
rb_eTypeError,
"%"PRIsVALUE
" must have %"PRIsVALUE
" method, %"PRIsVALUE
" given",
9200 rb_id2str(
id), rb_id2str(mid),
9220 must_respond_to(id_write, val,
id);
9227 return rb_ractor_stdout();
9233 must_respond_to(id_write, val,
id);
9240 return rb_ractor_stderr();
9244allocate_and_open_new_file(
VALUE klass)
9246 VALUE self = io_alloc(klass);
9247 rb_io_make_open_file(self);
9255 VALUE self = rb_protect(allocate_and_open_new_file, klass, &state);
9263 maygvl_close(descriptor, 0);
9271 io->
fd = descriptor;
9289 io->closing_ec = NULL;
9290 io->wakeup_mutex =
Qnil;
9291 io->fork_generation = GET_VM()->fork_gen;
9294 io->
encs = *encoding;
9303prep_io(
int fd,
enum rb_io_mode fmode,
VALUE klass,
const char *path)
9313 e = (fmode &
FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
9314 rb_io_ext_int_to_encs(e, NULL, &convconfig.
enc, &convconfig.
enc2, fmode);
9318#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9320 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
9321 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
9323 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.
enc2, convconfig.
ecflags);
9329 if (!io_check_tty(io)) {
9332 setmode(fd, O_BINARY);
9344 if (path && strcmp(path,
"-")) klass =
rb_cFile;
9345 return prep_io(fd, rb_io_oflags_fmode(oflags), klass, path);
9349prep_stdio(
FILE *f,
enum rb_io_mode fmode,
VALUE klass,
const char *path)
9356#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9357 fptr->
encs.
ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
9368rb_io_prep_stdin(
void)
9374rb_io_prep_stdout(
void)
9380rb_io_prep_stderr(
void)
9389 int oflags = rb_io_fmode_oflags(fptr->
mode) & ~O_EXCL;
9416 rb_io_buffer_init(&fp->
wbuf);
9417 rb_io_buffer_init(&fp->
rbuf);
9418 rb_io_buffer_init(&fp->
cbuf);
9433 fp->closing_ec = NULL;
9434 fp->wakeup_mutex =
Qnil;
9435 fp->fork_generation = GET_VM()->fork_gen;
9440rb_io_make_open_file(
VALUE obj)
9445 if (
RFILE(obj)->fptr) {
9448 RFILE(obj)->fptr = 0;
9450 fp = rb_io_fptr_new();
9452 RFILE(obj)->fptr = fp;
9500rb_io_initialize(
int argc,
VALUE *argv,
VALUE io)
9506 return io_initialize(io, fnum, vmode, opt);
9513 int fd, oflags = O_RDONLY;
9514 enum rb_io_mode fmode;
9516#if defined(HAVE_FCNTL) && defined(F_GETFL)
9526 rb_raise(rb_eArgError,
"The given fd is not accessible because RubyVM reserves it");
9528#if defined(HAVE_FCNTL) && defined(F_GETFL)
9529 oflags = fcntl(fd, F_GETFL);
9530 if (oflags == -1) rb_sys_fail(0);
9532 if (fstat(fd, &st) < 0) rb_sys_fail(0);
9535#if defined(HAVE_FCNTL) && defined(F_GETFL)
9536 ofmode = rb_io_oflags_fmode(oflags);
9548 if (rb_hash_aref(opt, sym_autoclose) ==
Qfalse) {
9552 path = rb_hash_aref(opt,
RB_ID2SYM(idPath));
9563 fp->
encs = convconfig;
9567 fp->closing_ec = NULL;
9568 fp->wakeup_mutex =
Qnil;
9569 fp->fork_generation = GET_VM()->fork_gen;
9572 if (fileno(stdin) == fd)
9574 else if (fileno(stdout) == fd)
9576 else if (fileno(stderr) == fd)
9608rb_io_set_encoding_by_bom(
VALUE io)
9614 rb_raise(rb_eArgError,
"ASCII incompatible encoding needs binmode");
9617 rb_raise(rb_eArgError,
"encoding conversion is set");
9619 else if (fptr->
encs.
enc && fptr->
encs.
enc != rb_ascii8bit_encoding()) {
9620 rb_raise(rb_eArgError,
"encoding is set to %s already",
9623 if (!io_set_encoding_by_bom(io))
return Qnil;
9624 return rb_enc_from_encoding(fptr->
encs.
enc);
9669rb_file_initialize(
int argc,
VALUE *argv,
VALUE io)
9671 if (
RFILE(io)->fptr) {
9674 VALUE fname, vmode, vperm, opt;
9675 int posargc =
rb_scan_args(argc, argv,
"12:", &fname, &vmode, &vperm, &opt);
9680 return io_initialize(io, fd, vmode, opt);
9683 return rb_open_file(io, fname, vmode, vperm, opt);
9688rb_io_s_new(
int argc,
VALUE *argv,
VALUE klass)
9693 rb_warn(
"%"PRIsVALUE
"::new() does not take block; use %"PRIsVALUE
"::open() instead",
9709rb_io_s_for_fd(
int argc,
VALUE *argv,
VALUE klass)
9712 rb_io_initialize(argc, argv, io);
9725rb_io_autoclose_p(
VALUE io)
9750rb_io_set_autoclose(
VALUE io,
VALUE autoclose)
9754 if (!
RTEST(autoclose))
9757 fptr->
mode &= ~FMODE_EXTERNAL;
9762io_wait_event(
VALUE io,
int event,
VALUE timeout,
int return_io)
9794io_wait_readable(
int argc,
VALUE *argv,
VALUE io)
9801 if (rb_io_read_pending(fptr))
return Qtrue;
9804 VALUE timeout = (argc == 1 ? argv[0] :
Qnil);
9818io_wait_writable(
int argc,
VALUE *argv,
VALUE io)
9826 VALUE timeout = (argc == 1 ? argv[0] :
Qnil);
9841io_wait_priority(
int argc,
VALUE *argv,
VALUE io)
9848 if (rb_io_read_pending(fptr))
return Qtrue;
9851 VALUE timeout = argc == 1 ? argv[0] :
Qnil;
9857wait_mode_sym(
VALUE mode)
9859 if (mode ==
ID2SYM(rb_intern(
"r"))) {
9860 return RB_WAITFD_IN;
9862 if (mode ==
ID2SYM(rb_intern(
"read"))) {
9863 return RB_WAITFD_IN;
9865 if (mode ==
ID2SYM(rb_intern(
"readable"))) {
9866 return RB_WAITFD_IN;
9868 if (mode ==
ID2SYM(rb_intern(
"w"))) {
9869 return RB_WAITFD_OUT;
9871 if (mode ==
ID2SYM(rb_intern(
"write"))) {
9872 return RB_WAITFD_OUT;
9874 if (mode ==
ID2SYM(rb_intern(
"writable"))) {
9875 return RB_WAITFD_OUT;
9877 if (mode ==
ID2SYM(rb_intern(
"rw"))) {
9878 return RB_WAITFD_IN|RB_WAITFD_OUT;
9880 if (mode ==
ID2SYM(rb_intern(
"read_write"))) {
9881 return RB_WAITFD_IN|RB_WAITFD_OUT;
9883 if (mode ==
ID2SYM(rb_intern(
"readable_writable"))) {
9884 return RB_WAITFD_IN|RB_WAITFD_OUT;
9887 rb_raise(rb_eArgError,
"unsupported mode: %"PRIsVALUE, mode);
9891io_event_from_value(
VALUE value)
9895 if (events <= 0) rb_raise(rb_eArgError,
"Events must be positive integer!");
9933 for (
int i = 0; i < argc; i += 1) {
9935 events |= wait_mode_sym(argv[i]);
9937 else if (UNDEF_P(timeout)) {
9941 rb_raise(rb_eArgError,
"timeout given more than once");
9945 if (UNDEF_P(timeout)) timeout =
Qnil;
9953 events = io_event_from_value(argv[0]);
9961 if (rb_io_read_pending(fptr)) {
9963 if (return_io)
return Qtrue;
9969 return io_wait_event(io, events, timeout, return_io);
9973argf_mark_and_move(
void *ptr)
9975 struct argf *p = ptr;
9976 rb_gc_mark_and_move(&p->filename);
9977 rb_gc_mark_and_move(&p->current_file);
9978 rb_gc_mark_and_move(&p->argv);
9979 rb_gc_mark_and_move(&p->inplace);
9980 rb_gc_mark_and_move(&p->encs.
ecopts);
9984argf_memsize(
const void *ptr)
9986 const struct argf *p = ptr;
9987 size_t size =
sizeof(*p);
9994 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
10000 p->filename =
Qnil;
10001 p->current_file =
Qnil;
10007argf_alloc(
VALUE klass)
10012 argf_init(p,
Qnil);
10022 memset(&ARGF, 0,
sizeof(ARGF));
10023 argf_init(&ARGF, argv);
10033 ARGF = argf_of(orig);
10060 ARGF.last_lineno = ARGF.lineno;
10086 return forward_current(rb_frame_this_func(), argc, argv);
10089#define next_argv() argf_next_argv(argf)
10090#define ARGF_GENERIC_INPUT_P() \
10091 (ARGF.current_file == rb_stdin && !RB_TYPE_P(ARGF.current_file, T_FILE))
10092#define ARGF_FORWARD(argc, argv) do {\
10093 if (ARGF_GENERIC_INPUT_P())\
10094 return argf_forward((argc), (argv), argf);\
10096#define NEXT_ARGF_FORWARD(argc, argv) do {\
10097 if (!next_argv()) return Qnil;\
10098 ARGF_FORWARD((argc), (argv));\
10104 VALUE file = ARGF.current_file;
10118 int stdout_binmode = 0;
10119 enum rb_io_mode fmode;
10121 VALUE r_stdout = rb_ractor_stdout();
10126 stdout_binmode = 1;
10129 if (ARGF.init_p == 0) {
10139 if (
NIL_P(ARGF.argv)) {
10142 else if (ARGF.next_p == -1 &&
RARRAY_LEN(ARGF.argv) > 0) {
10147 if (ARGF.next_p == 1) {
10148 if (ARGF.init_p == 1) argf_close(
argf);
10153 ARGF.filename = filename;
10154 filename = rb_str_encode_ospath(filename);
10156 if (RSTRING_LEN(filename) == 1 && fn[0] ==
'-') {
10158 if (ARGF.inplace) {
10159 rb_warn(
"Can't do inplace edit for stdio; skipping");
10165 int fr = rb_sysopen(filename, O_RDONLY, 0);
10167 if (ARGF.inplace) {
10169#ifndef NO_SAFE_RENAME
10180 if (!
NIL_P(ARGF.inplace)) {
10181 VALUE suffix = ARGF.inplace;
10183 if (
NIL_P(rb_str_cat_conv_enc_opts(str, RSTRING_LEN(str),
10184 RSTRING_PTR(suffix), RSTRING_LEN(suffix),
10185 rb_enc_get(suffix), 0,
Qnil))) {
10188#ifdef NO_SAFE_RENAME
10190 (void)unlink(RSTRING_PTR(str));
10191 if (rename(fn, RSTRING_PTR(str)) < 0) {
10192 rb_warn(
"Can't rename %"PRIsVALUE
" to %"PRIsVALUE
": %s, skipping file",
10193 filename, str, strerror(
errno));
10196 fr = rb_sysopen(str, O_RDONLY, 0);
10198 if (rename(fn, RSTRING_PTR(str)) < 0) {
10199 rb_warn(
"Can't rename %"PRIsVALUE
" to %"PRIsVALUE
": %s, skipping file",
10200 filename, str, strerror(
errno));
10207#ifdef NO_SAFE_RENAME
10208 rb_fatal(
"Can't do inplace edit without backup");
10210 if (unlink(fn) < 0) {
10211 rb_warn(
"Can't remove %"PRIsVALUE
": %s, skipping file",
10212 filename, strerror(
errno));
10218 fw = rb_sysopen(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666);
10219#ifndef NO_SAFE_RENAME
10222 fchmod(fw, st.st_mode);
10224 chmod(fn, st.st_mode);
10226 if (st.st_uid!=st2.st_uid || st.st_gid!=st2.st_gid) {
10229 err = fchown(fw, st.st_uid, st.st_gid);
10231 err = chown(fn, st.st_uid, st.st_gid);
10233 if (err && getuid() == 0 && st2.st_uid == 0) {
10234 const char *wkfn = RSTRING_PTR(filename);
10235 rb_warn(
"Can't set owner/group of %"PRIsVALUE
" to same as %"PRIsVALUE
": %s, skipping file",
10236 filename, str, strerror(
errno));
10239 (void)unlink(wkfn);
10249 if (!ARGF.binmode) {
10250 fmode |= DEFAULT_TEXTMODE;
10252 ARGF.current_file = prep_io(fr, fmode,
rb_cFile, fn);
10253 if (!
NIL_P(write_io)) {
10260 if (ARGF.encs.enc) {
10261 fptr->
encs = ARGF.encs;
10262 clear_codeconv(fptr);
10265 fptr->
encs.
ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
10266 if (!ARGF.binmode) {
10268#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
10269 fptr->
encs.
ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
10280 else if (ARGF.next_p == -1) {
10283 if (ARGF.inplace) {
10284 rb_warn(
"Can't do inplace edit for stdio");
10288 if (ARGF.init_p == -1) ARGF.init_p = 1;
10296 long lineno = ARGF.lineno;
10299 if (!next_argv())
return Qnil;
10300 if (ARGF_GENERIC_INPUT_P()) {
10301 line = forward_current(idGets, argc, argv);
10308 line = rb_io_getline(argc, argv, ARGF.current_file);
10310 if (
NIL_P(line) && ARGF.next_p != -1) {
10316 if (!
NIL_P(line)) {
10317 ARGF.lineno = ++lineno;
10318 ARGF.last_lineno = ARGF.lineno;
10324argf_lineno_getter(
ID id,
VALUE *var)
10327 return INT2FIX(ARGF.last_lineno);
10335 ARGF.last_lineno = ARGF.lineno = n;
10339rb_reset_argf_lineno(
long n)
10341 ARGF.last_lineno = ARGF.lineno = n;
10382 if (recv ==
argf) {
10383 return argf_gets(argc, argv,
argf);
10385 return forward(
argf, idGets, argc, argv);
10411 line = argf_getline(argc, argv,
argf);
10423 return rb_f_gets(0, 0,
argf);
10427 if (!next_argv())
return Qnil;
10429 if (
NIL_P(line) && ARGF.next_p != -1) {
10435 if (!
NIL_P(line)) {
10437 ARGF.last_lineno = ARGF.lineno;
10463rb_f_readline(
int argc,
VALUE *argv,
VALUE recv)
10465 if (recv ==
argf) {
10466 return argf_readline(argc, argv,
argf);
10468 return forward(
argf, rb_intern(
"readline"), argc, argv);
10494 if (!next_argv()) rb_eof_error();
10495 ARGF_FORWARD(argc, argv);
10496 line = argf_gets(argc, argv,
argf);
10566rb_f_readlines(
int argc,
VALUE *argv,
VALUE recv)
10568 if (recv ==
argf) {
10569 return argf_readlines(argc, argv,
argf);
10571 return forward(
argf, rb_intern(
"readlines"), argc, argv);
10595 long lineno = ARGF.lineno;
10599 while (next_argv()) {
10600 if (ARGF_GENERIC_INPUT_P()) {
10601 lines = forward_current(rb_intern(
"readlines"), argc, argv);
10604 lines = rb_io_readlines(argc, argv, ARGF.current_file);
10610 ARGF.last_lineno = ARGF.lineno;
10645 rb_last_status_clear();
10646 port = pipe_open_s(str,
"r",
FMODE_READABLE|DEFAULT_TEXTMODE, NULL);
10650 result = read_all(fptr, remain_size(fptr),
Qnil);
10652 rb_io_fptr_cleanup_all(fptr);
10658#ifdef HAVE_SYS_SELECT_H
10659#include <sys/select.h>
10673 if (!
NIL_P(read)) {
10678 if (READ_DATA_PENDING(fptr) || READ_CHAR_PENDING(fptr)) {
10682 if (max < fptr->fd) max = fptr->
fd;
10685 timerec.tv_sec = timerec.tv_usec = 0;
10693 if (!
NIL_P(write)) {
10699 if (max < fptr->fd) max = fptr->
fd;
10706 if (!
NIL_P(except)) {
10710 VALUE write_io = GetWriteIO(io);
10713 if (max < fptr->fd) max = fptr->
fd;
10714 if (io != write_io) {
10717 if (max < fptr->fd) max = fptr->
fd;
10732 if (!pending && n == 0)
return Qnil;
10757 VALUE write_io = GetWriteIO(io);
10770 VALUE write_io = GetWriteIO(io);
10775 else if (io != write_io) {
10788 VALUE read, write, except;
10794select_call(
VALUE arg)
10798 return select_internal(p->read, p->write, p->except, p->timeout, p->fdsets);
10802select_end(
VALUE arg)
10807 for (i = 0; i < numberof(p->fdsets); ++i)
10812static VALUE sym_normal, sym_sequential, sym_random,
10813 sym_willneed, sym_dontneed, sym_noreuse;
10815#ifdef HAVE_POSIX_FADVISE
10816struct io_advise_struct {
10824io_advise_internal(
void *arg)
10826 struct io_advise_struct *ptr = arg;
10827 return posix_fadvise(ptr->fd, ptr->offset, ptr->len, ptr->advice);
10831io_advise_sym_to_const(
VALUE sym)
10833#ifdef POSIX_FADV_NORMAL
10834 if (sym == sym_normal)
10835 return INT2NUM(POSIX_FADV_NORMAL);
10838#ifdef POSIX_FADV_RANDOM
10839 if (sym == sym_random)
10840 return INT2NUM(POSIX_FADV_RANDOM);
10843#ifdef POSIX_FADV_SEQUENTIAL
10844 if (sym == sym_sequential)
10845 return INT2NUM(POSIX_FADV_SEQUENTIAL);
10848#ifdef POSIX_FADV_WILLNEED
10849 if (sym == sym_willneed)
10850 return INT2NUM(POSIX_FADV_WILLNEED);
10853#ifdef POSIX_FADV_DONTNEED
10854 if (sym == sym_dontneed)
10855 return INT2NUM(POSIX_FADV_DONTNEED);
10858#ifdef POSIX_FADV_NOREUSE
10859 if (sym == sym_noreuse)
10860 return INT2NUM(POSIX_FADV_NOREUSE);
10867do_io_advise(
rb_io_t *fptr,
VALUE advice, rb_off_t offset, rb_off_t
len)
10870 struct io_advise_struct ias;
10873 num_adv = io_advise_sym_to_const(advice);
10879 if (
NIL_P(num_adv))
10883 ias.advice =
NUM2INT(num_adv);
10884 ias.offset = offset;
10887 rv = (int)rb_io_blocking_region(fptr, io_advise_internal, &ias);
10888 if (rv && rv != ENOSYS) {
10891 VALUE message = rb_sprintf(
"%"PRIsVALUE
" "
10895 fptr->
pathv, offset,
len, advice);
10905advice_arg_check(
VALUE advice)
10910 if (advice != sym_normal &&
10911 advice != sym_sequential &&
10912 advice != sym_random &&
10913 advice != sym_willneed &&
10914 advice != sym_dontneed &&
10915 advice != sym_noreuse) {
10916 rb_raise(
rb_eNotImpError,
"Unsupported advice: %+"PRIsVALUE, advice);
10954rb_io_advise(
int argc,
VALUE *argv,
VALUE io)
10961 advice_arg_check(advice);
10963 io = GetWriteIO(io);
10969#ifdef HAVE_POSIX_FADVISE
10970 return do_io_advise(fptr, advice,
off, l);
10972 ((void)
off, (
void)l);
10984 return isinf(f) && 0 < f;
11140rb_f_select(
int argc,
VALUE *argv,
VALUE obj)
11143 if (scheduler !=
Qnil) {
11146 if (!UNDEF_P(result))
return result;
11154 rb_scan_args(argc, argv,
"13", &args.read, &args.write, &args.except, &timeout);
11155 if (
NIL_P(timeout) || is_pos_inf(timeout)) {
11160 args.timeout = &timerec;
11163 for (i = 0; i < numberof(args.fdsets); ++i)
11169#ifdef IOCTL_REQ_TYPE
11170 typedef IOCTL_REQ_TYPE ioctl_req_t;
11172 typedef int ioctl_req_t;
11173# define NUM2IOCTLREQ(num) ((int)NUM2LONG(num))
11184nogvl_ioctl(
void *ptr)
11186 struct ioctl_arg *arg = ptr;
11188 return (
VALUE)ioctl(arg->fd, arg->cmd, arg->narg);
11192do_ioctl(
struct rb_io *io, ioctl_req_t cmd,
long narg)
11195 struct ioctl_arg arg;
11201 retval = (int)rb_io_blocking_region(io, nogvl_ioctl, &arg);
11207#define DEFAULT_IOCTL_NARG_LEN (256)
11209#if defined(__linux__) && defined(_IOC_SIZE)
11211linux_iocparm_len(ioctl_req_t cmd)
11215 if ((cmd & 0xFFFF0000) == 0) {
11217 return DEFAULT_IOCTL_NARG_LEN;
11220 len = _IOC_SIZE(cmd);
11223 if (
len < DEFAULT_IOCTL_NARG_LEN)
11224 len = DEFAULT_IOCTL_NARG_LEN;
11232ioctl_narg_len(ioctl_req_t cmd)
11238#define IOCPARM_LEN(x) (((x) >> 16) & IOCPARM_MASK)
11242 len = IOCPARM_LEN(cmd);
11243#elif defined(__linux__) && defined(_IOC_SIZE)
11244 len = linux_iocparm_len(cmd);
11247 len = DEFAULT_IOCTL_NARG_LEN;
11256typedef long fcntl_arg_t;
11259typedef int fcntl_arg_t;
11263fcntl_narg_len(ioctl_req_t cmd)
11270 len =
sizeof(fcntl_arg_t);
11278#ifdef F_DUPFD_CLOEXEC
11279 case F_DUPFD_CLOEXEC:
11280 len =
sizeof(fcntl_arg_t);
11290 len =
sizeof(fcntl_arg_t);
11300 len =
sizeof(fcntl_arg_t);
11310 len =
sizeof(fcntl_arg_t);
11315 len =
sizeof(
struct f_owner_ex);
11320 len =
sizeof(
struct f_owner_ex);
11325 len =
sizeof(
struct flock);
11330 len =
sizeof(
struct flock);
11335 len =
sizeof(
struct flock);
11355 len =
sizeof(fcntl_arg_t);
11365 len =
sizeof(fcntl_arg_t);
11370 len =
sizeof(fcntl_arg_t);
11383fcntl_narg_len(ioctl_req_t cmd)
11389#define NARG_SENTINEL 17
11392setup_narg(ioctl_req_t cmd,
VALUE *argp,
long (*narg_len)(ioctl_req_t))
11403 else if (arg ==
Qtrue) {
11417 len = narg_len(cmd);
11418 rb_str_modify(arg);
11420 slen = RSTRING_LEN(arg);
11422 if (slen <
len+1) {
11423 rb_str_resize(arg,
len+1);
11424 MEMZERO(RSTRING_PTR(arg)+slen,
char,
len-slen);
11428 ptr = RSTRING_PTR(arg);
11429 ptr[slen - 1] = NARG_SENTINEL;
11438finish_narg(
int retval,
VALUE arg,
const rb_io_t *fptr)
11440 if (retval < 0) rb_sys_fail_path(fptr->
pathv);
11445 if (ptr[slen-1] != NARG_SENTINEL)
11446 rb_raise(rb_eArgError,
"return value overflowed string");
11447 ptr[slen-1] =
'\0';
11457 ioctl_req_t cmd = NUM2IOCTLREQ(req);
11462 narg = setup_narg(cmd, &arg, ioctl_narg_len);
11464 retval = do_ioctl(fptr, cmd, narg);
11465 return finish_narg(retval, arg, fptr);
11492 return rb_ioctl(io, req, arg);
11495#define rb_io_ioctl rb_f_notimplement
11506nogvl_fcntl(
void *ptr)
11508 struct fcntl_arg *arg = ptr;
11510#if defined(F_DUPFD)
11511 if (arg->cmd == F_DUPFD)
11514 return (
VALUE)fcntl(arg->fd, arg->cmd, arg->narg);
11518do_fcntl(
struct rb_io *io,
int cmd,
long narg)
11521 struct fcntl_arg arg;
11527 retval = (int)rb_io_blocking_region(io, nogvl_fcntl, &arg);
11528 if (retval != -1) {
11530#if defined(F_DUPFD)
11533#if defined(F_DUPFD_CLOEXEC)
11534 case F_DUPFD_CLOEXEC:
11551 narg = setup_narg(cmd, &arg, fcntl_narg_len);
11553 retval = do_fcntl(fptr, cmd, narg);
11554 return finish_narg(retval, arg, fptr);
11580 return rb_fcntl(io, req, arg);
11583#define rb_io_fcntl rb_f_notimplement
11586#if defined(HAVE_SYSCALL) || defined(HAVE___SYSCALL)
11618#if SIZEOF_VOIDP == 8 && defined(HAVE___SYSCALL) && SIZEOF_INT != 8
11619# define SYSCALL __syscall
11620# define NUM2SYSCALLID(x) NUM2LONG(x)
11621# define RETVAL2NUM(x) LONG2NUM(x)
11622# if SIZEOF_LONG == 8
11623 long num, retval = -1;
11624# elif SIZEOF_LONG_LONG == 8
11625 long long num, retval = -1;
11627# error ---->> it is asserted that __syscall takes the first argument and returns retval in 64bit signed integer. <<----
11629#elif defined(__linux__)
11630# define SYSCALL syscall
11631# define NUM2SYSCALLID(x) NUM2LONG(x)
11632# define RETVAL2NUM(x) LONG2NUM(x)
11640 long num, retval = -1;
11642# define SYSCALL syscall
11643# define NUM2SYSCALLID(x) NUM2INT(x)
11644# define RETVAL2NUM(x) INT2NUM(x)
11645 int num, retval = -1;
11651 "We plan to remove a syscall function at future release. DL(Fiddle) provides safer alternative.");
11655 rb_raise(rb_eArgError,
"too few arguments for syscall");
11656 if (argc > numberof(arg))
11657 rb_raise(rb_eArgError,
"too many arguments for syscall");
11658 num = NUM2SYSCALLID(argv[0]); ++argv;
11659 for (i = argc - 1; i--; ) {
11674 retval = SYSCALL(num);
11677 retval = SYSCALL(num, arg[0]);
11680 retval = SYSCALL(num, arg[0],arg[1]);
11683 retval = SYSCALL(num, arg[0],arg[1],arg[2]);
11686 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3]);
11689 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4]);
11692 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5]);
11695 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6]);
11701 return RETVAL2NUM(retval);
11703#undef NUM2SYSCALLID
11707#define rb_f_syscall rb_f_notimplement
11711io_new_instance(
VALUE args)
11717find_encoding(
VALUE v)
11720 if (!enc)
rb_warn(
"Unsupported encoding %"PRIsVALUE
" ignored", v);
11732 enc2 = find_encoding(v1);
11735 if (RSTRING_LEN(tmp) == 1 && RSTRING_PTR(tmp)[0] ==
'-') {
11741 enc = find_encoding(v2);
11748 enc = find_encoding(v2);
11754 if (enc2 == rb_ascii8bit_encoding()) {
11759 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11765 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
11766 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11771 if (!
NIL_P(tmp) && rb_enc_asciicompat(enc = rb_enc_get(tmp))) {
11772 parse_mode_enc(RSTRING_PTR(tmp), enc, &enc, &enc2, NULL);
11773 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11777 rb_io_ext_int_to_encs(find_encoding(v1), NULL, &enc, &enc2, 0);
11778 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11783 validate_enc_binmode(&fptr->
mode, ecflags, enc, enc2);
11788 clear_codeconv(fptr);
11800io_encoding_set_v(
VALUE v)
11803 io_encoding_set(arg->fptr, arg->v1, arg->v2, arg->opt);
11808pipe_pair_close(
VALUE rw)
11811 return rb_ensure(io_close, rwp[0], io_close, rwp[1]);
11894rb_io_s_pipe(
int argc,
VALUE *argv,
VALUE klass)
11896 int pipes[2], state;
11897 VALUE r, w, args[3], v1, v2;
11901 enum rb_io_mode fmode = 0;
11904 argc =
rb_scan_args(argc, argv,
"02:", &v1, &v2, &opt);
11911 r = rb_protect(io_new_instance, (
VALUE)args, &state);
11915 rb_jump_tag(state);
11919 ies_args.fptr = fptr;
11922 ies_args.opt = opt;
11923 rb_protect(io_encoding_set_v, (
VALUE)&ies_args, &state);
11927 rb_jump_tag(state);
11932 w = rb_protect(io_new_instance, (
VALUE)args, &state);
11936 rb_jump_tag(state);
11941 extract_binmode(opt, &fmode);
11948#if DEFAULT_TEXTMODE
11950 fptr->
mode &= ~FMODE_TEXTMODE;
11951 setmode(fptr->
fd, O_BINARY);
11953#if RUBY_CRLF_ENVIRONMENT
11959 fptr->
mode |= fmode;
11960#if DEFAULT_TEXTMODE
11962 fptr2->
mode &= ~FMODE_TEXTMODE;
11963 setmode(fptr2->
fd, O_BINARY);
11966 fptr2->
mode |= fmode;
12000 else if (!
NIL_P(v = rb_hash_aref(opt, sym_open_args))) {
12003 v = rb_to_array_type(v);
12008 arg->io = rb_io_open(klass, path, vmode, vperm, opt);
12012io_s_foreach(
VALUE v)
12017 if (arg->limit == 0)
12018 rb_raise(rb_eArgError,
"invalid limit: 0 for foreach");
12019 while (!
NIL_P(str = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, arg->io))) {
12107rb_io_s_foreach(
int argc,
VALUE *argv,
VALUE self)
12110 int orig_argc = argc;
12114 argc =
rb_scan_args(argc, argv,
"12:", NULL, NULL, NULL, &opt);
12116 extract_getline_args(argc-1, argv+1, &garg);
12117 open_key_args(self, argc, argv, opt, &arg);
12119 extract_getline_opts(opt, &garg);
12120 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12121 return rb_ensure(io_s_foreach, (
VALUE)&garg, rb_io_close, arg.io);
12125io_s_readlines(
VALUE v)
12128 return io_readlines(arg, arg->io);
12185rb_io_s_readlines(
int argc,
VALUE *argv,
VALUE io)
12191 argc =
rb_scan_args(argc, argv,
"12:", NULL, NULL, NULL, &opt);
12192 extract_getline_args(argc-1, argv+1, &garg);
12193 open_key_args(io, argc, argv, opt, &arg);
12195 extract_getline_opts(opt, &garg);
12196 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12197 return rb_ensure(io_s_readlines, (
VALUE)&garg, rb_io_close, arg.io);
12204 return io_read(arg->argc, arg->argv, arg->io);
12214seek_before_access(
VALUE argp)
12218 return rb_io_seek(arg->io, arg->offset, arg->mode);
12264rb_io_s_read(
int argc,
VALUE *argv,
VALUE io)
12270 argc =
rb_scan_args(argc, argv,
"13:", NULL, NULL, &offset, NULL, &opt);
12272 rb_raise(rb_eArgError,
"negative offset %ld given",
off);
12274 open_key_args(io, argc, argv, opt, &arg);
12276 if (!
NIL_P(offset)) {
12280 sarg.offset = offset;
12281 sarg.mode = SEEK_SET;
12282 rb_protect(seek_before_access, (
VALUE)&sarg, &state);
12285 rb_jump_tag(state);
12287 if (arg.argc == 2) arg.argc = 1;
12306rb_io_s_binread(
int argc,
VALUE *argv,
VALUE io)
12321 convconfig.
enc = rb_ascii8bit_encoding();
12322 arg.io = rb_io_open_generic(io, argv[0], oflags, fmode, &convconfig, 0);
12325 arg.argc = (argc > 1) ? 1 : 0;
12326 if (!
NIL_P(offset)) {
12330 sarg.offset = offset;
12331 sarg.mode = SEEK_SET;
12332 rb_protect(seek_before_access, (
VALUE)&sarg, &state);
12335 rb_jump_tag(state);
12342io_s_write0(
VALUE v)
12345 return io_write(arg->io,arg->str,arg->nosync);
12349io_s_write(
int argc,
VALUE *argv,
VALUE klass,
int binary)
12351 VALUE string, offset, opt;
12355 rb_scan_args(argc, argv,
"21:", NULL, &
string, &offset, &opt);
12357 if (
NIL_P(opt)) opt = rb_hash_new();
12358 else opt = rb_hash_dup(opt);
12361 if (
NIL_P(rb_hash_aref(opt,sym_mode))) {
12362 int mode = O_WRONLY|O_CREAT;
12364 if (binary) mode |= O_BINARY;
12366 if (
NIL_P(offset)) mode |= O_TRUNC;
12367 rb_hash_aset(opt,sym_mode,
INT2NUM(mode));
12369 open_key_args(klass, argc, argv, opt, &arg);
12372 if (binary) rb_io_binmode_m(arg.io);
12376 if (!
NIL_P(offset)) {
12380 sarg.offset = offset;
12381 sarg.mode = SEEK_SET;
12382 rb_protect(seek_before_access, (
VALUE)&sarg, &state);
12385 rb_jump_tag(state);
12393 return rb_ensure(io_s_write0, (
VALUE)&warg, rb_io_close, arg.io);
12441rb_io_s_write(
int argc,
VALUE *argv,
VALUE io)
12443 return io_s_write(argc, argv, io, 0);
12460rb_io_s_binwrite(
int argc,
VALUE *argv,
VALUE io)
12462 return io_s_write(argc, argv, io, 1);
12468 rb_off_t copy_length;
12469 rb_off_t src_offset;
12473 unsigned close_src : 1;
12474 unsigned close_dst : 1;
12477 const char *syserr;
12478 const char *notimp;
12480 struct stat src_stat;
12481 struct stat dst_stat;
12482#ifdef HAVE_FCOPYFILE
12483 copyfile_state_t copyfile_state;
12488exec_interrupts(
void *arg)
12491 rb_thread_execute_interrupts(th);
12505#if defined(ERESTART)
12510 rb_thread_execute_interrupts(stp->th);
12529fiber_scheduler_wait_for(
void * _arguments)
12539# define IOWAIT_SYSCALL "poll"
12540STATIC_ASSERT(pollin_expected, POLLIN == RB_WAITFD_IN);
12541STATIC_ASSERT(pollout_expected, POLLOUT == RB_WAITFD_OUT);
12546 if (scheduler !=
Qnil) {
12549 return RTEST(args.result);
12553 if (fd == -1)
return 0;
12558 fds.events = events;
12560 int timeout_milliseconds = -1;
12563 timeout_milliseconds = (int)(timeout->tv_sec * 1000) + (int)(timeout->tv_usec / 1000);
12566 return poll(&fds, 1, timeout_milliseconds);
12569# define IOWAIT_SYSCALL "select"
12574 if (scheduler !=
Qnil) {
12577 return RTEST(args.result);
12597 case RB_WAITFD_OUT:
12601 VM_UNREACHABLE(nogvl_wait_for);
12621 ret = nogvl_wait_for(stp->th, stp->src_fptr, RB_WAITFD_IN, NULL);
12623 }
while (ret < 0 && maygvl_copy_stream_continue_p(has_gvl, stp));
12626 stp->syserr = IOWAIT_SYSCALL;
12627 stp->error_no =
errno;
12639 ret = nogvl_wait_for(stp->th, stp->dst_fptr, RB_WAITFD_OUT, NULL);
12640 }
while (ret < 0 && maygvl_copy_stream_continue_p(0, stp));
12643 stp->syserr = IOWAIT_SYSCALL;
12644 stp->error_no =
errno;
12650#ifdef USE_COPY_FILE_RANGE
12653simple_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)
12655#ifdef HAVE_COPY_FILE_RANGE
12656 return copy_file_range(in_fd, in_offset, out_fd, out_offset, count, flags);
12658 return syscall(__NR_copy_file_range, in_fd, in_offset, out_fd, out_offset, count, flags);
12667 rb_off_t copy_length, src_offset, *src_offset_ptr;
12669 if (!S_ISREG(stp->src_stat.st_mode))
12672 src_size = stp->src_stat.st_size;
12673 src_offset = stp->src_offset;
12674 if (src_offset >= (rb_off_t)0) {
12675 src_offset_ptr = &src_offset;
12678 src_offset_ptr = NULL;
12681 copy_length = stp->copy_length;
12682 if (copy_length < (rb_off_t)0) {
12683 if (src_offset < (rb_off_t)0) {
12684 rb_off_t current_offset;
12686 current_offset = lseek(stp->src_fptr->
fd, 0, SEEK_CUR);
12687 if (current_offset < (rb_off_t)0 &&
errno) {
12688 stp->syserr =
"lseek";
12689 stp->error_no =
errno;
12690 return (
int)current_offset;
12692 copy_length = src_size - current_offset;
12695 copy_length = src_size - src_offset;
12699 retry_copy_file_range:
12700# if SIZEOF_OFF_T > SIZEOF_SIZE_T
12702 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
12704 ss = (ssize_t)copy_length;
12706 ss = simple_copy_file_range(stp->src_fptr->
fd, src_offset_ptr, stp->dst_fptr->
fd, NULL, ss, 0);
12710 if (0 < copy_length) {
12711 goto retry_copy_file_range;
12715 if (maygvl_copy_stream_continue_p(0, stp)) {
12716 goto retry_copy_file_range;
12730#if EWOULDBLOCK != EAGAIN
12734 int ret = nogvl_copy_stream_wait_write(stp);
12735 if (ret < 0)
return ret;
12737 goto retry_copy_file_range;
12741 int flags = fcntl(stp->dst_fptr->
fd, F_GETFL);
12743 if (flags != -1 && flags & O_APPEND) {
12749 stp->syserr =
"copy_file_range";
12750 stp->error_no =
errno;
12757#ifdef HAVE_FCOPYFILE
12761 rb_off_t cur, ss = 0;
12762 const rb_off_t src_offset = stp->src_offset;
12765 if (stp->copy_length >= (rb_off_t)0) {
12770 if (!S_ISREG(stp->src_stat.st_mode))
12773 if (!S_ISREG(stp->dst_stat.st_mode))
12775 if (lseek(stp->dst_fptr->
fd, 0, SEEK_CUR) > (rb_off_t)0)
12777 if (fcntl(stp->dst_fptr->
fd, F_GETFL) & O_APPEND) {
12780 rb_off_t end = lseek(stp->dst_fptr->
fd, 0, SEEK_END);
12781 lseek(stp->dst_fptr->
fd, 0, SEEK_SET);
12782 if (end > (rb_off_t)0)
return 0;
12785 if (src_offset > (rb_off_t)0) {
12790 cur = lseek(stp->src_fptr->
fd, 0, SEEK_CUR);
12791 if (cur < (rb_off_t)0 &&
errno) {
12792 stp->error_no =
errno;
12797 r = lseek(stp->src_fptr->
fd, src_offset, SEEK_SET);
12798 if (r < (rb_off_t)0 &&
errno) {
12799 stp->error_no =
errno;
12804 stp->copyfile_state = copyfile_state_alloc();
12805 ret = fcopyfile(stp->src_fptr->
fd, stp->dst_fptr->
fd, stp->copyfile_state, COPYFILE_DATA);
12806 copyfile_state_get(stp->copyfile_state, COPYFILE_STATE_COPIED, &ss);
12810 if (src_offset > (rb_off_t)0) {
12814 r = lseek(stp->src_fptr->
fd, cur, SEEK_SET);
12815 if (r < (rb_off_t)0 &&
errno) {
12816 stp->error_no =
errno;
12828 stp->syserr =
"fcopyfile";
12829 stp->error_no =
errno;
12836#ifdef HAVE_SENDFILE
12839# define USE_SENDFILE
12841# ifdef HAVE_SYS_SENDFILE_H
12842# include <sys/sendfile.h>
12846simple_sendfile(
int out_fd,
int in_fd, rb_off_t *offset, rb_off_t count)
12848 return sendfile(out_fd, in_fd, offset, (
size_t)count);
12851# elif 0 || defined(__APPLE__)
12855# define USE_SENDFILE
12858simple_sendfile(
int out_fd,
int in_fd, rb_off_t *offset, rb_off_t count)
12861 rb_off_t pos = offset ? *offset : lseek(in_fd, 0, SEEK_CUR);
12864 r = sendfile(in_fd, out_fd, pos, &count, NULL, 0);
12867 r = sendfile(in_fd, out_fd, pos, (
size_t)count, NULL, &sbytes, 0);
12869 if (r != 0 && sbytes == 0)
return r;
12874 lseek(in_fd, sbytes, SEEK_CUR);
12876 return (ssize_t)sbytes;
12889 rb_off_t copy_length;
12890 rb_off_t src_offset;
12893 if (!S_ISREG(stp->src_stat.st_mode))
12896 src_size = stp->src_stat.st_size;
12898 if ((stp->dst_stat.st_mode & S_IFMT) != S_IFSOCK)
12902 src_offset = stp->src_offset;
12903 use_pread = src_offset >= (rb_off_t)0;
12905 copy_length = stp->copy_length;
12906 if (copy_length < (rb_off_t)0) {
12908 copy_length = src_size - src_offset;
12912 cur = lseek(stp->src_fptr->
fd, 0, SEEK_CUR);
12913 if (cur < (rb_off_t)0 &&
errno) {
12914 stp->syserr =
"lseek";
12915 stp->error_no =
errno;
12918 copy_length = src_size - cur;
12923# if SIZEOF_OFF_T > SIZEOF_SIZE_T
12925 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
12927 ss = (ssize_t)copy_length;
12930 ss = simple_sendfile(stp->dst_fptr->
fd, stp->src_fptr->
fd, &src_offset, ss);
12933 ss = simple_sendfile(stp->dst_fptr->
fd, stp->src_fptr->
fd, NULL, ss);
12938 if (0 < copy_length) {
12939 goto retry_sendfile;
12943 if (maygvl_copy_stream_continue_p(0, stp))
12944 goto retry_sendfile;
12957#if EWOULDBLOCK != EAGAIN
12970 ret = maygvl_copy_stream_wait_read(0, stp);
12971 if (ret < 0)
return ret;
12973 ret = nogvl_copy_stream_wait_write(stp);
12974 if (ret < 0)
return ret;
12976 goto retry_sendfile;
12978 stp->syserr =
"sendfile";
12979 stp->error_no =
errno;
12987maygvl_read(
int has_gvl,
rb_io_t *fptr,
void *buf,
size_t count)
12990 return rb_io_read_memory(fptr, buf, count);
12992 return read(fptr->
fd, buf, count);
12996maygvl_copy_stream_read(
int has_gvl,
struct copy_stream_struct *stp,
char *buf,
size_t len, rb_off_t offset)
13000 if (offset < (rb_off_t)0) {
13001 ss = maygvl_read(has_gvl, stp->src_fptr, buf,
len);
13004 ss = pread(stp->src_fptr->
fd, buf,
len, offset);
13010 if (maygvl_copy_stream_continue_p(has_gvl, stp))
13014#if EWOULDBLOCK != EAGAIN
13018 int ret = maygvl_copy_stream_wait_read(has_gvl, stp);
13019 if (ret < 0)
return ret;
13024 stp->notimp =
"pread";
13028 stp->syserr = offset < (rb_off_t)0 ?
"read" :
"pread";
13029 stp->error_no =
errno;
13040 ss = write(stp->dst_fptr->
fd, buf+
off,
len);
13042 if (maygvl_copy_stream_continue_p(0, stp))
13044 if (io_again_p(
errno)) {
13045 int ret = nogvl_copy_stream_wait_write(stp);
13046 if (ret < 0)
return ret;
13049 stp->syserr =
"write";
13050 stp->error_no =
errno;
13067 rb_off_t copy_length;
13068 rb_off_t src_offset;
13072 copy_length = stp->copy_length;
13073 use_eof = copy_length < (rb_off_t)0;
13074 src_offset = stp->src_offset;
13075 use_pread = src_offset >= (rb_off_t)0;
13077 if (use_pread && stp->close_src) {
13080 r = lseek(stp->src_fptr->
fd, src_offset, SEEK_SET);
13081 if (r < (rb_off_t)0 &&
errno) {
13082 stp->syserr =
"lseek";
13083 stp->error_no =
errno;
13086 src_offset = (rb_off_t)-1;
13090 while (use_eof || 0 < copy_length) {
13091 if (!use_eof && copy_length < (rb_off_t)
sizeof(buf)) {
13092 len = (size_t)copy_length;
13098 ss = maygvl_copy_stream_read(0, stp, buf,
len, src_offset);
13103 ss = maygvl_copy_stream_read(0, stp, buf,
len, (rb_off_t)-1);
13108 ret = nogvl_copy_stream_write(stp, buf, ss);
13118nogvl_copy_stream_func(
void *arg)
13121#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13125#ifdef USE_COPY_FILE_RANGE
13126 ret = nogvl_copy_file_range(stp);
13131#ifdef HAVE_FCOPYFILE
13132 ret = nogvl_fcopyfile(stp);
13138 ret = nogvl_copy_stream_sendfile(stp);
13143 nogvl_copy_stream_read_write(stp);
13145#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13152copy_stream_fallback_body(
VALUE arg)
13155 const int buflen = 16*1024;
13158 rb_off_t rest = stp->copy_length;
13159 rb_off_t
off = stp->src_offset;
13160 ID read_method = id_readpartial;
13162 if (!stp->src_fptr) {
13164 read_method = id_read;
13171 rb_str_make_independent(buf);
13172 if (stp->copy_length < (rb_off_t)0) {
13177 rb_str_resize(buf, 0);
13180 l = buflen < rest ? buflen : (long)rest;
13182 if (!stp->src_fptr) {
13185 if (read_method == id_read &&
NIL_P(rc))
13190 rb_str_resize(buf, buflen);
13191 ss = maygvl_copy_stream_read(1, stp, RSTRING_PTR(buf), l,
off);
13192 rb_str_resize(buf, ss > 0 ? ss : 0);
13197 if (
off >= (rb_off_t)0)
13200 n = rb_io_write(stp->dst, buf);
13202 stp->total += numwrote;
13204 if (read_method == id_read && RSTRING_LEN(buf) == 0) {
13215 if (!stp->src_fptr && stp->src_offset >= (rb_off_t)0) {
13216 rb_raise(rb_eArgError,
"cannot specify src_offset for non-IO");
13225copy_stream_body(
VALUE arg)
13228 VALUE src_io = stp->src, dst_io = stp->dst;
13229 const int common_oflags = 0
13239 if (src_io ==
argf ||
13243 stp->src_fptr = NULL;
13248 if (!
NIL_P(tmp_io)) {
13255 args[1] =
INT2NUM(O_RDONLY|common_oflags);
13258 stp->close_src = 1;
13263 stat_ret = fstat(stp->src_fptr->
fd, &stp->src_stat);
13264 if (stat_ret < 0) {
13265 stp->syserr =
"fstat";
13266 stp->error_no =
errno;
13271 if (dst_io ==
argf ||
13275 stp->dst_fptr = NULL;
13280 if (!
NIL_P(tmp_io)) {
13281 dst_io = GetWriteIO(tmp_io);
13287 args[1] =
INT2NUM(O_WRONLY|O_CREAT|O_TRUNC|common_oflags);
13291 stp->close_dst = 1;
13294 dst_io = GetWriteIO(dst_io);
13300 stat_ret = fstat(stp->dst_fptr->
fd, &stp->dst_stat);
13301 if (stat_ret < 0) {
13302 stp->syserr =
"fstat";
13303 stp->error_no =
errno;
13310 SET_BINARY_MODE_WITH_SEEK_CUR(stp->src_fptr);
13313 io_ascii8bit_binmode(stp->dst_fptr);
13315 if (stp->src_offset < (rb_off_t)0 && stp->src_fptr && stp->src_fptr->
rbuf.
len) {
13318 if (stp->copy_length >= (rb_off_t)0 && stp->copy_length < (rb_off_t)
len) {
13319 len = (size_t)stp->copy_length;
13322 rb_str_resize(str,
len);
13323 read_buffered_data(RSTRING_PTR(str),
len, stp->src_fptr);
13324 if (stp->dst_fptr) {
13325 if (io_binwrite(RSTRING_PTR(str), RSTRING_LEN(str), stp->dst_fptr, 0) < 0)
13326 rb_sys_fail_on_write(stp->dst_fptr);
13329 rb_io_write(dst_io, str);
13330 rb_str_resize(str, 0);
13332 if (stp->copy_length >= (rb_off_t)0)
13333 stp->copy_length -=
len;
13336 if (stp->dst_fptr && io_fflush(stp->dst_fptr) < 0) {
13340 if (stp->copy_length == 0)
13343 if (stp->src_fptr == NULL || stp->dst_fptr == NULL) {
13344 return copy_stream_fallback(stp);
13347 IO_WITHOUT_GVL(nogvl_copy_stream_func, stp);
13352copy_stream_finalize(
VALUE arg)
13356#ifdef HAVE_FCOPYFILE
13357 if (stp->copyfile_state) {
13358 copyfile_state_free(stp->copyfile_state);
13362 if (stp->close_src) {
13363 rb_io_close_m(stp->src);
13365 if (stp->close_dst) {
13366 rb_io_close_m(stp->dst);
13429rb_io_s_copy_stream(
int argc,
VALUE *argv,
VALUE io)
13431 VALUE src, dst, length, src_offset;
13436 rb_scan_args(argc, argv,
"22", &src, &dst, &length, &src_offset);
13441 st.src_fptr = NULL;
13442 st.dst_fptr = NULL;
13445 st.copy_length = (rb_off_t)-1;
13447 st.copy_length =
NUM2OFFT(length);
13449 if (
NIL_P(src_offset))
13450 st.src_offset = (rb_off_t)-1;
13452 st.src_offset =
NUM2OFFT(src_offset);
13471rb_io_external_encoding(
VALUE io)
13476 return rb_enc_from_encoding(fptr->
encs.
enc2);
13480 return rb_enc_from_encoding(fptr->
encs.
enc);
13483 return rb_enc_from_encoding(io_read_encoding(fptr));
13499rb_io_internal_encoding(
VALUE io)
13504 return rb_enc_from_encoding(io_read_encoding(fptr));
13538rb_io_set_encoding(
int argc,
VALUE *argv,
VALUE io)
13544 return forward(io, id_set_encoding, argc, argv);
13547 argc =
rb_scan_args(argc, argv,
"11:", &v1, &v2, &opt);
13549 io_encoding_set(fptr, v1, v2, opt);
13554rb_stdio_set_default_encoding(
void)
13559 if (isatty(fileno(stdin))) {
13561 rb_encoding *internal = rb_default_internal_encoding();
13562 if (!internal) internal = rb_default_external_encoding();
13564 rb_enc_from_encoding(external),
13565 rb_enc_from_encoding(internal),
13570 rb_io_set_encoding(1, &val,
rb_stdin);
13571 rb_io_set_encoding(1, &val,
rb_stdout);
13572 rb_io_set_encoding(1, &val,
rb_stderr);
13576global_argf_p(
VALUE arg)
13578 return arg ==
argf;
13581typedef VALUE (*argf_encoding_func)(
VALUE io);
13584argf_encoding(
VALUE argf, argf_encoding_func func)
13586 if (!
RTEST(ARGF.current_file)) {
13587 return rb_enc_default_external();
13611 return argf_encoding(
argf, rb_io_external_encoding);
13630 return argf_encoding(
argf, rb_io_internal_encoding);
13669 if (!next_argv()) {
13670 rb_raise(rb_eArgError,
"no stream to set encoding");
13672 rb_io_set_encoding(argc, argv, ARGF.current_file);
13674 ARGF.encs = fptr->
encs;
13693 if (!next_argv()) {
13694 rb_raise(rb_eArgError,
"no stream to tell");
13696 ARGF_FORWARD(0, 0);
13697 return rb_io_tell(ARGF.current_file);
13710 if (!next_argv()) {
13711 rb_raise(rb_eArgError,
"no stream to seek");
13713 ARGF_FORWARD(argc, argv);
13714 return rb_io_seek_m(argc, argv, ARGF.current_file);
13731 if (!next_argv()) {
13732 rb_raise(rb_eArgError,
"no stream to set position");
13734 ARGF_FORWARD(1, &offset);
13735 return rb_io_set_pos(ARGF.current_file, offset);
13756 if (!next_argv()) {
13757 rb_raise(rb_eArgError,
"no stream to rewind");
13759 ARGF_FORWARD(0, 0);
13760 old_lineno =
RFILE(ARGF.current_file)->fptr->lineno;
13761 ret = rb_io_rewind(ARGF.current_file);
13762 if (!global_argf_p(
argf)) {
13763 ARGF.last_lineno = ARGF.lineno -= old_lineno;
13781 if (!next_argv()) {
13782 rb_raise(rb_eArgError,
"no stream");
13784 ARGF_FORWARD(0, 0);
13785 return rb_io_fileno(ARGF.current_file);
13804 ARGF_FORWARD(0, 0);
13805 return ARGF.current_file;
13830 if (
RTEST(ARGF.current_file)) {
13831 if (ARGF.init_p == 0)
return Qtrue;
13833 ARGF_FORWARD(0, 0);
13892 VALUE tmp, str, length;
13896 if (!
NIL_P(length)) {
13901 rb_str_resize(str,0);
13906 if (!next_argv()) {
13909 if (ARGF_GENERIC_INPUT_P()) {
13910 tmp = argf_forward(argc, argv,
argf);
13913 tmp = io_read(argc, argv, ARGF.current_file);
13915 if (
NIL_P(str)) str = tmp;
13918 if (ARGF.next_p != -1) {
13924 else if (argc >= 1) {
13925 long slen = RSTRING_LEN(str);
13941argf_forward_call(
VALUE arg)
13944 argf_forward(p->argc, p->argv, p->argf);
13974 return argf_getpartial(argc, argv,
argf,
Qnil, 0);
13995 return argf_getpartial(argc, argv,
argf, opts, 1);
14001 VALUE tmp, str, length;
14009 no_exception = no_exception_p(opts);
14011 if (!next_argv()) {
14013 rb_str_resize(str, 0);
14017 if (ARGF_GENERIC_INPUT_P()) {
14027 tmp = io_getpartial(argc, argv, ARGF.current_file, no_exception, nonblock);
14030 if (ARGF.next_p == -1) {
14031 return io_nonblock_eof(no_exception);
14036 return io_nonblock_eof(no_exception);
14074 if (!next_argv())
return Qnil;
14075 if (ARGF_GENERIC_INPUT_P()) {
14076 ch = forward_current(rb_intern(
"getc"), 0, 0);
14079 ch = rb_io_getc(ARGF.current_file);
14081 if (
NIL_P(ch) && ARGF.next_p != -1) {
14114 if (!next_argv())
return Qnil;
14116 ch = forward_current(rb_intern(
"getbyte"), 0, 0);
14121 if (
NIL_P(ch) && ARGF.next_p != -1) {
14154 if (!next_argv()) rb_eof_error();
14156 ch = forward_current(rb_intern(
"getc"), 0, 0);
14159 ch = rb_io_getc(ARGF.current_file);
14161 if (
NIL_P(ch) && ARGF.next_p != -1) {
14193 NEXT_ARGF_FORWARD(0, 0);
14194 c = argf_getbyte(
argf);
14201#define FOREACH_ARGF() while (next_argv())
14206 const VALUE current = ARGF.current_file;
14208 if (ARGF.init_p == -1 || current != ARGF.current_file) {
14214#define ARGF_block_call(mid, argc, argv, func, argf) \
14215 rb_block_call_kw(ARGF.current_file, mid, argc, argv, \
14216 func, argf, rb_keyword_given_p())
14221 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_i,
argf);
14222 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14228 if (!global_argf_p(
argf)) {
14229 ARGF.last_lineno = ++ARGF.lineno;
14231 return argf_block_call_i(i,
argf, argc, argv, blockarg);
14237 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_line_i,
argf);
14238 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14286 argf_block_call_line(rb_intern(
"each_line"), argc, argv,
argf);
14317 argf_block_call(rb_intern(
"each_byte"), 0, 0,
argf);
14343 argf_block_call(rb_intern(
"each_char"), 0, 0,
argf);
14369 argf_block_call(rb_intern(
"each_codepoint"), 0, 0,
argf);
14400 return ARGF.filename;
14404argf_filename_getter(
ID id,
VALUE *var)
14406 return argf_filename(*var);
14431 return ARGF.current_file;
14450 ARGF_FORWARD(0, 0);
14471 return RBOOL(ARGF.binmode);
14491 if (ARGF.init_p && ARGF.next_p == 0) {
14520 if (ARGF.next_p != -1) {
14538 ARGF_FORWARD(0, 0);
14565 if (!ARGF.inplace)
return Qnil;
14573 return argf_inplace_mode_get(*var);
14604 ARGF.inplace =
Qnil;
14615 argf_inplace_mode_set(*var, val);
14619ruby_set_inplace_mode(
const char *suffix)
14645argf_argv_getter(
ID id,
VALUE *var)
14647 return argf_argv(*var);
14666 if (!
RTEST(ARGF.current_file)) {
14669 return GetWriteIO(ARGF.current_file);
14681 return rb_io_writev(argf_write_io(
argf), argc, argv);
14696 case RB_IO_WAIT_WRITABLE:
14699 c = rb_eEAGAINWaitWritable;
14701#if EAGAIN != EWOULDBLOCK
14703 c = rb_eEWOULDBLOCKWaitWritable;
14707 c = rb_eEINPROGRESSWaitWritable;
14713 case RB_IO_WAIT_READABLE:
14716 c = rb_eEAGAINWaitReadable;
14718#if EAGAIN != EWOULDBLOCK
14720 c = rb_eEWOULDBLOCKWaitReadable;
14724 c = rb_eEINPROGRESSWaitReadable;
14731 rb_bug(
"invalid read/write type passed to rb_readwrite_sys_fail: %d", waiting);
14737get_LAST_READ_LINE(
ID _x,
VALUE *_y)
15622#include <sys/cygwin.h>
15623 static struct __cygwin_perfile pf[] =
15625 {
"", O_RDONLY | O_BINARY},
15626 {
"", O_WRONLY | O_BINARY},
15627 {
"", O_RDWR | O_BINARY},
15628 {
"", O_APPEND | O_BINARY},
15631 cygwin_internal(CW_PERFILE, pf);
15686#if EAGAIN == EWOULDBLOCK
15687 rb_eEWOULDBLOCKWaitReadable = rb_eEAGAINWaitReadable;
15689 rb_define_const(
rb_cIO,
"EWOULDBLOCKWaitReadable", rb_eEAGAINWaitReadable);
15690 rb_eEWOULDBLOCKWaitWritable = rb_eEAGAINWaitWritable;
15692 rb_define_const(
rb_cIO,
"EWOULDBLOCKWaitWritable", rb_eEAGAINWaitWritable);
15740 rb_gvar_ractor_local(
"$/");
15742 rb_gvar_ractor_local(
"$-0");
15746 rb_gvar_ractor_local(
"$_");
15862 rb_gvar_ractor_local(
"$stdin");
15863 rb_gvar_ractor_local(
"$stdout");
15864 rb_gvar_ractor_local(
"$>");
15865 rb_gvar_ractor_local(
"$stderr");
15951 rb_define_method(rb_cARGF,
"external_encoding", argf_external_encoding, 0);
15952 rb_define_method(rb_cARGF,
"internal_encoding", argf_internal_encoding, 0);
15971 rb_gvar_ractor_local(
"$-i");
15975#if defined (_WIN32) || defined(__CYGWIN__)
15976 atexit(pipe_atexit);
15988 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.