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)
1296 if (scheduler !=
Qnil) {
1299 if (!UNDEF_P(result)) {
1315 struct timeval timeout_storage;
1319 iis.timeout = &timeout_storage;
1322 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_read_func, &iis,
RUBY_IO_READABLE);
1326rb_io_write_memory(
rb_io_t *fptr,
const void *buf,
size_t count)
1330 if (scheduler !=
Qnil) {
1333 if (!UNDEF_P(result)) {
1349 struct timeval timeout_storage;
1353 iis.timeout = &timeout_storage;
1356 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_write_func, &iis,
RUBY_IO_WRITABLE);
1361rb_writev_internal(
rb_io_t *fptr,
const struct iovec *iov,
int iovcnt)
1363 if (!iovcnt)
return 0;
1368 if (scheduler !=
Qnil) {
1372 if (!UNDEF_P(result)) {
1377 struct io_internal_writev_struct iis = {
1388 struct timeval timeout_storage;
1392 iis.timeout = &timeout_storage;
1395 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_writev_func, &iis,
RUBY_IO_WRITABLE);
1400io_flush_buffer_sync(
void *arg)
1422io_flush_buffer_fiber_scheduler(
VALUE scheduler,
rb_io_t *fptr)
1425 if (!UNDEF_P(ret)) {
1437io_flush_buffer_async(
VALUE arg)
1442 if (scheduler !=
Qnil) {
1443 VALUE result = io_flush_buffer_fiber_scheduler(scheduler, fptr);
1444 if (!UNDEF_P(result)) {
1449 return rb_io_blocking_region_wait(fptr, io_flush_buffer_sync, fptr,
RUBY_IO_WRITABLE);
1456 return (
int)io_flush_buffer_async((
VALUE)fptr);
1471 while (fptr->
wbuf.
len > 0 && io_flush_buffer(fptr) != 0) {
1487 if (scheduler !=
Qnil) {
1497 if (NIL_OR_UNDEF_P(timeout)) {
1501 if (timeout !=
Qnil) {
1506 int ready = rb_thread_io_wait(th, fptr,
RB_NUM2INT(events), tv);
1532 if (scheduler !=
Qnil) {
1538 return rb_thread_wait_for_single_fd(th, fd, events, timeout);
1544 io_fd_check_closed(f);
1551#if defined(ERESTART)
1558#if EWOULDBLOCK != EAGAIN
1561 if (scheduler !=
Qnil) {
1579 io_fd_check_closed(f);
1586#if defined(ERESTART)
1602#if EWOULDBLOCK != EAGAIN
1605 if (scheduler !=
Qnil) {
1625 return io_wait_for_single_fd(fd, events, timeout, th, scheduler);
1659#if defined(ERESTART)
1669#if EWOULDBLOCK != EAGAIN
1686 if (
RTEST(result)) {
1701 if (
RTEST(result)) {
1715 const char *senc, *denc;
1722 ecflags = fptr->
encs.
ecflags & ~ECONV_NEWLINE_DECORATOR_READ_MASK;
1749 denc = rb_enc_name(enc);
1781io_binwrite_string_internal(
rb_io_t *fptr,
const char *ptr,
long length)
1784 struct iovec iov[2];
1787 iov[0].iov_len = fptr->
wbuf.
len;
1788 iov[1].iov_base = (
void*)ptr;
1789 iov[1].iov_len = length;
1791 ssize_t result = rb_writev_internal(fptr, iov, 2);
1796 if (result >= fptr->
wbuf.
len) {
1804 fptr->
wbuf.
off += (int)result;
1805 fptr->
wbuf.
len -= (int)result;
1813 return rb_io_write_memory(fptr, ptr, length);
1818io_binwrite_string_internal(
rb_io_t *fptr,
const char *ptr,
long length)
1820 long remaining = length;
1823 if (fptr->
wbuf.
len+length <= fptr->wbuf.capa) {
1830 fptr->
wbuf.
len += (int)length;
1837 if (io_fflush(fptr) < 0) {
1842 if (remaining == 0) {
1848 return rb_io_write_memory(fptr, ptr, length);
1853io_binwrite_string(
VALUE arg)
1857 const char *ptr = p->ptr;
1858 size_t remaining = p->length;
1862 ssize_t result = io_binwrite_string_internal(p->fptr, ptr, remaining);
1868 else if (result > 0) {
1869 if ((
size_t)result == remaining)
break;
1871 remaining -= result;
1887io_allocate_write_buffer(
rb_io_t *fptr,
int sync)
1892 fptr->
wbuf.
capa = IO_WBUF_CAPA_MIN;
1903io_binwrite_requires_flush_write(
rb_io_t *fptr,
long len,
int nosync)
1918io_binwrite(
const char *ptr,
long len,
rb_io_t *fptr,
int nosync)
1920 if (
len <= 0)
return len;
1925 io_allocate_write_buffer(fptr, !nosync);
1927 if (io_binwrite_requires_flush_write(fptr,
len, nosync)) {
1938 return io_binwrite_string((
VALUE)&arg);
1955# define MODE_BTMODE(a,b,c) ((fmode & FMODE_BINMODE) ? (b) : \
1956 (fmode & FMODE_TEXTMODE) ? (c) : (a))
1958#define MODE_BTXMODE(a, b, c, d, e, f) ((fmode & FMODE_EXCL) ? \
1959 MODE_BTMODE(d, e, f) : \
1960 MODE_BTMODE(a, b, c))
1965 if (NEED_WRITECONV(fptr)) {
1967 SET_BINARY_MODE(fptr);
1969 make_writeconv(fptr);
1972#define fmode (fptr->mode)
1975 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1) && !rb_enc_asciicompat(rb_enc_get(str))) {
1976 rb_raise(rb_eArgError,
"ASCII incompatible string written for text mode IO without encoding conversion: %s",
1977 rb_enc_name(rb_enc_get(str)));
1983 common_encoding = rb_enc_from_encoding(fptr->
encs.
enc2);
1984 else if (fptr->
encs.
enc != rb_ascii8bit_encoding())
1985 common_encoding = rb_enc_from_encoding(fptr->
encs.
enc);
1988 if (!
NIL_P(common_encoding)) {
1999#if RUBY_CRLF_ENVIRONMENT
2000#define fmode (fptr->mode)
2001 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1)) {
2004 setmode(fptr->
fd, O_BINARY);
2007 setmode(fptr->
fd, O_TEXT);
2009 if (!rb_enc_asciicompat(rb_enc_get(str))) {
2010 rb_raise(rb_eArgError,
"ASCII incompatible string written for text mode IO without encoding conversion: %s",
2011 rb_enc_name(rb_enc_get(str)));
2029 long len = rb_w32_write_console(str, fptr->
fd);
2034 str = do_writeconv(str, fptr, &converted);
2038 tmp = rb_str_tmp_frozen_no_embed_acquire(str);
2040 n = io_binwrite(ptr,
len, fptr, nosync);
2041 rb_str_tmp_frozen_release(str, tmp);
2053 return (ssize_t)io_binwrite(buf, (
long)size, fptr, 0);
2063 io = GetWriteIO(io);
2073 if (RSTRING_LEN(str) == 0)
return INT2FIX(0);
2078 n = io_fwrite(str, fptr, nosync);
2079 if (n < 0L) rb_sys_fail_on_write(fptr);
2085struct binwritev_arg {
2093io_binwritev_internal(
VALUE arg)
2095 struct binwritev_arg *p = (
struct binwritev_arg *)arg;
2097 size_t remaining = p->total;
2101 struct iovec *iov = p->iov;
2102 int iovcnt = p->iovcnt;
2105 long result = rb_writev_internal(fptr, iov, iovcnt);
2110 if (offset < (
size_t)fptr->
wbuf.
len) {
2115 offset -= (size_t)fptr->
wbuf.
len;
2121 if (offset == p->total) {
2125 while (result >= (ssize_t)iov->iov_len) {
2127 result -= iov->iov_len;
2137 iov->iov_base = (
char *)iov->iov_base + result;
2138 iov->iov_len -= result;
2152io_binwritev(
struct iovec *iov,
int iovcnt,
rb_io_t *fptr)
2157 if (iovcnt == 0)
return 0;
2160 for (
int i = 1; i < iovcnt; i++) total += iov[i].iov_len;
2162 io_allocate_write_buffer(fptr, 1);
2168 if (offset + total <= (
size_t)fptr->
wbuf.
capa) {
2169 for (
int i = 1; i < iovcnt; i++) {
2170 memcpy(fptr->
wbuf.
ptr+offset, iov[i].iov_base, iov[i].iov_len);
2171 offset += iov[i].iov_len;
2180 iov[0].iov_len = fptr->
wbuf.
len;
2193 struct binwritev_arg arg;
2196 arg.iovcnt = iovcnt;
2203 return io_binwritev_internal((
VALUE)&arg);
2210 int i, converted, iovcnt = argc + 1;
2212 VALUE v1, v2, str, tmp, *tmp_array;
2218 for (i = 0; i < argc; i++) {
2221 str = do_writeconv(str, fptr, &converted);
2226 tmp = rb_str_tmp_frozen_acquire(str);
2230 iov[i+1].iov_base = RSTRING_PTR(tmp);
2231 iov[i+1].iov_len = RSTRING_LEN(tmp);
2234 n = io_binwritev(iov, iovcnt, fptr);
2237 for (i = 0; i < argc; i++) {
2238 rb_str_tmp_frozen_release(argv[i], tmp_array[i]);
2247iovcnt_ok(
int iovcnt)
2250 return iovcnt < IOV_MAX;
2258io_writev(
int argc,
const VALUE *argv,
VALUE io)
2265 io = GetWriteIO(io);
2270 return rb_funcallv(io, id_write, argc, argv);
2278 for (i = 0; i < argc; i += cnt) {
2281 n = io_fwritev(cnt, &argv[i], fptr);
2292 rb_sys_fail_on_write(fptr);
2294 total = rb_fix_plus(
LONG2FIX(n), total);
2325 return io_writev(argc, argv, io);
2328 VALUE str = argv[0];
2329 return io_write(io, str, 0);
2336 return rb_funcallv(io, id_write, 1, &str);
2340rb_io_writev(
VALUE io,
int argc,
const VALUE *argv)
2345 char sep = RCLASS_SINGLETON_P(klass) ? (klass = io,
'.') :
'#';
2348 " which accepts just one argument",
2353 do rb_io_write(io, *argv++);
while (--argc);
2358 return rb_funcallv(io, id_write, argc, argv);
2384 rb_io_write(io, str);
2390nogvl_fsync(
void *ptr)
2395 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->
fd)) != FILE_TYPE_DISK)
2398 return (
VALUE)fsync(fptr->
fd);
2403rb_io_flush_raw(
VALUE io,
int sync)
2411 io = GetWriteIO(io);
2415 if (io_fflush(fptr) < 0)
2416 rb_sys_fail_on_write(fptr);
2419 io_unread(fptr,
true);
2440 return rb_io_flush_raw(io, 1);
2466 pos = io_tell(fptr);
2467 if (pos < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
2473rb_io_seek(
VALUE io,
VALUE offset,
int whence)
2480 pos = io_seek(fptr, pos, whence);
2481 if (pos < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
2487interpret_seek_whence(
VALUE vwhence)
2489 if (vwhence == sym_SET)
2491 if (vwhence == sym_CUR)
2493 if (vwhence == sym_END)
2496 if (vwhence == sym_DATA)
2500 if (vwhence == sym_HOLE)
2556 VALUE offset, ptrname;
2557 int whence = SEEK_SET;
2559 if (
rb_scan_args(argc, argv,
"11", &offset, &ptrname) == 2) {
2560 whence = interpret_seek_whence(ptrname);
2563 return rb_io_seek(io, offset, whence);
2591 pos = io_seek(fptr, pos, SEEK_SET);
2592 if (pos < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
2597static void clear_readconv(
rb_io_t *fptr);
2624rb_io_rewind(
VALUE io)
2629 if (io_seek(fptr, 0L, 0) < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
2630 if (io == ARGF.current_file) {
2631 ARGF.lineno -= fptr->
lineno;
2635 clear_readconv(fptr);
2642fptr_wait_readable(
rb_io_t *fptr)
2660 fptr->
rbuf.
capa = IO_RBUF_CAPA_FOR(fptr);
2671 if (fptr_wait_readable(fptr))
2675 VALUE path = rb_sprintf(
"fd:%d ", fptr->
fd);
2680 rb_syserr_fail_path(e, path);
2734 if (READ_CHAR_PENDING(fptr))
return Qfalse;
2735 if (READ_DATA_PENDING(fptr))
return Qfalse;
2737#if RUBY_CRLF_ENVIRONMENT
2738 if (!NEED_READCONV(fptr) && NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
2739 return RBOOL(eof(fptr->
fd));
2742 return RBOOL(io_fillbuf(fptr) < 0);
2766 io = GetWriteIO(io);
2803 io = GetWriteIO(io);
2809 fptr->
mode &= ~FMODE_SYNC;
2833rb_io_fsync(
VALUE io)
2837 io = GetWriteIO(io);
2840 if (io_fflush(fptr) < 0)
2841 rb_sys_fail_on_write(fptr);
2843 if ((
int)rb_io_blocking_region(fptr, nogvl_fsync, fptr))
2844 rb_sys_fail_path(fptr->
pathv);
2849# define rb_io_fsync rb_f_notimplement
2850# define rb_io_sync rb_f_notimplement
2859#ifdef HAVE_FDATASYNC
2861nogvl_fdatasync(
void *ptr)
2866 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->
fd)) != FILE_TYPE_DISK)
2869 return (
VALUE)fdatasync(fptr->
fd);
2884rb_io_fdatasync(
VALUE io)
2888 io = GetWriteIO(io);
2891 if (io_fflush(fptr) < 0)
2892 rb_sys_fail_on_write(fptr);
2894 if ((
int)rb_io_blocking_region(fptr, nogvl_fdatasync, fptr) == 0)
2898 return rb_io_fsync(io);
2901#define rb_io_fdatasync rb_io_fsync
2919rb_io_fileno(
VALUE io)
2939 if (!UNDEF_P(fileno)) {
3027rb_io_inspect(
VALUE obj)
3031 static const char closed[] =
" (closed)";
3033 fptr =
RFILE(obj)->fptr;
3040 rb_str_cat(result, closed+1, strlen(closed)-1);
3043 rb_str_catf(result,
"fd %d", fptr->
fd);
3064rb_io_to_io(
VALUE io)
3071read_buffered_data(
char *ptr,
long len,
rb_io_t *fptr)
3075 n = READ_DATA_PENDING_COUNT(fptr);
3076 if (n <= 0)
return 0;
3077 if (n >
len) n = (int)
len;
3085io_bufread(
char *ptr,
long len,
rb_io_t *fptr)
3091 if (READ_DATA_PENDING(fptr) == 0) {
3095 c = rb_io_read_memory(fptr, ptr+offset, n);
3098 if (fptr_wait_readable(fptr))
3103 if ((n -= c) <= 0)
break;
3109 c = read_buffered_data(ptr+offset, n, fptr);
3112 if ((n -= c) <= 0)
break;
3115 if (io_fillbuf(fptr) < 0) {
3122static int io_setstrbuf(
VALUE *str,
long len);
3131bufread_call(
VALUE arg)
3134 p->len = io_bufread(p->str_ptr, p->len, p->fptr);
3139io_fread(
VALUE str,
long offset,
long size,
rb_io_t *fptr)
3144 io_setstrbuf(&str, offset + size);
3145 arg.str_ptr = RSTRING_PTR(str) + offset;
3148 rb_str_locktmp_ensure(str, bufread_call, (
VALUE)&arg);
3150 if (
len < 0) rb_sys_fail_path(fptr->
pathv);
3158 rb_off_t siz = READ_DATA_PENDING_COUNT(fptr);
3161 if (fstat(fptr->
fd, &st) == 0 && S_ISREG(st.st_mode)
3162#
if defined(__HAIKU__)
3167 if (io_fflush(fptr) < 0)
3168 rb_sys_fail_on_write(fptr);
3169 pos = lseek(fptr->
fd, 0, SEEK_CUR);
3170 if (st.st_size >= pos && pos >= 0) {
3171 siz += st.st_size - pos;
3172 if (siz > LONG_MAX) {
3173 rb_raise(
rb_eIOError,
"file too big for single read");
3186 rb_enc_associate(str, io_read_encoding(fptr));
3191make_readconv(
rb_io_t *fptr,
int size)
3196 const char *sname, *dname;
3197 ecflags = fptr->
encs.
ecflags & ~ECONV_NEWLINE_DECORATOR_WRITE_MASK;
3200 sname = rb_enc_name(fptr->
encs.
enc2);
3201 dname = rb_enc_name(io_read_encoding(fptr));
3211 if (size < IO_CBUF_CAPA_MIN) size = IO_CBUF_CAPA_MIN;
3217#define MORE_CHAR_SUSPENDED Qtrue
3218#define MORE_CHAR_FINISHED Qnil
3220fill_cbuf(
rb_io_t *fptr,
int ec_flags)
3222 const unsigned char *ss, *sp, *se;
3223 unsigned char *ds, *dp, *de;
3232 return MORE_CHAR_SUSPENDED;
3243 ss = sp = (
const unsigned char *)fptr->
rbuf.
ptr + fptr->
rbuf.
off;
3248 fptr->
rbuf.
off += (int)(sp - ss);
3249 fptr->
rbuf.
len -= (int)(sp - ss);
3250 fptr->
cbuf.
len += (int)(dp - ds);
3255 fptr->
rbuf.
off -= putbackable;
3256 fptr->
rbuf.
len += putbackable;
3263 if (cbuf_len0 != fptr->
cbuf.
len)
3264 return MORE_CHAR_SUSPENDED;
3267 return MORE_CHAR_FINISHED;
3273 if (io_fillbuf(fptr) < 0) {
3275 return MORE_CHAR_FINISHED;
3280 fptr->
cbuf.
len += (int)(dp - ds);
3287 if (cbuf_len0 != fptr->
cbuf.
len)
3288 return MORE_CHAR_SUSPENDED;
3290 return MORE_CHAR_FINISHED;
3298 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED)
3315 rb_enc_associate(str, fptr->
encs.
enc);
3344 long clen = RSTRING_LEN(s);
3356#define MAX_REALLOC_GAP 4096
3358io_shrink_read_string(
VALUE str,
long n)
3361 rb_str_resize(str, n);
3366io_set_read_length(
VALUE str,
long n,
int shrinkable)
3368 if (RSTRING_LEN(str) != n) {
3371 if (shrinkable) io_shrink_read_string(str, n);
3385 if (NEED_READCONV(fptr)) {
3386 int first = !
NIL_P(str);
3387 SET_BINARY_MODE(fptr);
3388 shrinkable = io_setstrbuf(&str,0);
3389 make_readconv(fptr, 0);
3394 io_shift_cbuf(fptr, fptr->
cbuf.
len, &str);
3396 v = fill_cbuf(fptr, 0);
3397 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED) {
3400 io_shift_cbuf(fptr, fptr->
cbuf.
len, &str);
3404 if (v == MORE_CHAR_FINISHED) {
3405 clear_readconv(fptr);
3407 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3408 return io_enc_str(str, fptr);
3413 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3417 enc = io_read_encoding(fptr);
3420 if (siz == 0) siz = BUFSIZ;
3421 shrinkable = io_setstrbuf(&str, siz);
3424 n = io_fread(str, bytes, siz - bytes, fptr);
3425 if (n == 0 && bytes == 0) {
3433 if (bytes < siz)
break;
3437 if (
capa < (
size_t)RSTRING_LEN(str) + BUFSIZ) {
3438 if (
capa < BUFSIZ) {
3441 else if (
capa > IO_MAX_BUFFER_GROWTH) {
3442 capa = IO_MAX_BUFFER_GROWTH;
3447 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3448 str = io_enc_str(str, fptr);
3456 if (rb_fd_set_nonblock(fptr->
fd) != 0) {
3457 rb_sys_fail_path(fptr->
pathv);
3462io_read_memory_call(
VALUE arg)
3467 if (scheduler !=
Qnil) {
3470 if (!UNDEF_P(result)) {
3476 if (iis->nonblock) {
3477 return rb_io_blocking_region(iis->fptr, internal_read_func, iis);
3480 return rb_io_blocking_region_wait(iis->fptr, internal_read_func, iis,
RUBY_IO_READABLE);
3487 return (
long)rb_str_locktmp_ensure(str, io_read_memory_call, (
VALUE)iis);
3490#define no_exception_p(opts) !rb_opts_exception_p((opts), TRUE)
3493io_getpartial(
int argc,
VALUE *argv,
VALUE io,
int no_exception,
int nonblock)
3504 rb_raise(rb_eArgError,
"negative length %ld given",
len);
3507 shrinkable = io_setstrbuf(&str,
len);
3513 io_set_read_length(str, 0, shrinkable);
3519 n = read_buffered_data(RSTRING_PTR(str),
len, fptr);
3525 io_setstrbuf(&str,
len);
3528 iis.nonblock = nonblock;
3530 iis.buf = RSTRING_PTR(str);
3533 n = io_read_memory_locktmp(str, &iis);
3536 if (!nonblock && fptr_wait_readable(fptr))
3538 if (nonblock && (io_again_p(e))) {
3540 return sym_wait_readable;
3543 e,
"read would block");
3545 rb_syserr_fail_path(e, fptr->
pathv);
3548 io_set_read_length(str, n, shrinkable);
3649io_readpartial(
int argc,
VALUE *argv,
VALUE io)
3653 ret = io_getpartial(argc, argv, io,
Qnil, 0);
3660io_nonblock_eof(
int no_exception)
3662 if (!no_exception) {
3678 rb_raise(rb_eArgError,
"negative length %ld given",
len);
3681 shrinkable = io_setstrbuf(&str,
len);
3682 rb_bool_expected(ex,
"exception", TRUE);
3688 io_set_read_length(str, 0, shrinkable);
3692 n = read_buffered_data(RSTRING_PTR(str),
len, fptr);
3694 rb_fd_set_nonblock(fptr->
fd);
3695 shrinkable |= io_setstrbuf(&str,
len);
3699 iis.buf = RSTRING_PTR(str);
3702 n = io_read_memory_locktmp(str, &iis);
3705 if (io_again_p(e)) {
3706 if (!ex)
return sym_wait_readable;
3708 e,
"read would block");
3710 rb_syserr_fail_path(e, fptr->
pathv);
3713 io_set_read_length(str, n, shrinkable);
3716 if (!ex)
return Qnil;
3732 rb_bool_expected(ex,
"exception", TRUE);
3734 io = GetWriteIO(io);
3738 if (io_fflush(fptr) < 0)
3739 rb_sys_fail_on_write(fptr);
3741 rb_fd_set_nonblock(fptr->
fd);
3742 n = write(fptr->
fd, RSTRING_PTR(str), RSTRING_LEN(str));
3747 if (io_again_p(e)) {
3749 return sym_wait_writable;
3755 rb_syserr_fail_path(e, fptr->
pathv);
3839#if RUBY_CRLF_ENVIRONMENT
3845 if (
NIL_P(length)) {
3848 return read_all(fptr, remain_size(fptr), str);
3852 rb_raise(rb_eArgError,
"negative length %ld given",
len);
3855 shrinkable = io_setstrbuf(&str,
len);
3860 io_set_read_length(str, 0, shrinkable);
3865#if RUBY_CRLF_ENVIRONMENT
3866 previous_mode = set_binary_mode_with_seek_cur(fptr);
3868 n = io_fread(str, 0,
len, fptr);
3869 io_set_read_length(str, n, shrinkable);
3870#if RUBY_CRLF_ENVIRONMENT
3871 if (previous_mode == O_TEXT) {
3872 setmode(fptr->
fd, O_TEXT);
3875 if (n == 0)
return Qnil;
3881rscheck(
const char *rsptr,
long rslen,
VALUE rs)
3884 if (RSTRING_PTR(rs) != rsptr && RSTRING_LEN(rs) != rslen)
3889search_delim(
const char *p,
long len,
int delim,
rb_encoding *enc)
3891 if (rb_enc_mbminlen(enc) == 1) {
3892 p = memchr(p, delim,
len);
3893 if (p)
return p + 1;
3896 const char *end = p +
len;
3898 int r = rb_enc_precise_mbclen(p, end, enc);
3900 p += rb_enc_mbminlen(enc);
3904 if (rb_enc_mbc_to_codepoint(p, end, enc) == (
unsigned int)delim) {
3919 if (NEED_READCONV(fptr)) {
3920 SET_BINARY_MODE(fptr);
3921 make_readconv(fptr, 0);
3924 int searchlen = READ_CHAR_PENDING_COUNT(fptr);
3926 p = READ_CHAR_PENDING_PTR(fptr);
3927 if (0 < limit && limit < searchlen)
3928 searchlen = (int)limit;
3929 e = search_delim(p, searchlen, delim, enc);
3931 int len = (int)(e-p);
3953 return (
unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
3956 }
while (more_char(fptr) != MORE_CHAR_FINISHED);
3957 clear_readconv(fptr);
3962 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3964 long pending = READ_DATA_PENDING_COUNT(fptr);
3966 const char *p = READ_DATA_PENDING_PTR(fptr);
3970 if (limit > 0 && pending > limit) pending = limit;
3971 e = search_delim(p, pending, delim, enc);
3972 if (e) pending = e - p;
3974 last = RSTRING_LEN(str);
3975 rb_str_resize(str, last + pending);
3982 read_buffered_data(RSTRING_PTR(str) + last, pending, fptr);
3985 if (e)
return delim;
3987 return (
unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
3990 }
while (io_fillbuf(fptr) >= 0);
3996swallow(
rb_io_t *fptr,
int term)
3998 if (NEED_READCONV(fptr)) {
4000 int needconv = rb_enc_mbminlen(enc) != 1;
4001 SET_BINARY_MODE(fptr);
4002 make_readconv(fptr, 0);
4005 while ((cnt = READ_CHAR_PENDING_COUNT(fptr)) > 0) {
4006 const char *p = READ_CHAR_PENDING_PTR(fptr);
4009 if (*p != term)
return TRUE;
4011 while (--i && *++p == term);
4014 const char *e = p + cnt;
4015 if (rb_enc_ascget(p, e, &i, enc) != term)
return TRUE;
4016 while ((p += i) < e && rb_enc_ascget(p, e, &i, enc) == term);
4019 io_shift_cbuf(fptr, (
int)cnt - i, NULL);
4021 }
while (more_char(fptr) != MORE_CHAR_FINISHED);
4025 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4028 while ((cnt = READ_DATA_PENDING_COUNT(fptr)) > 0) {
4030 const char *p = READ_DATA_PENDING_PTR(fptr);
4032 if (cnt >
sizeof buf) cnt =
sizeof buf;
4033 if (*p != term)
return TRUE;
4035 while (--i && *++p == term);
4036 if (!read_buffered_data(buf, cnt - i, fptr))
4037 rb_sys_fail_path(fptr->
pathv);
4040 }
while (io_fillbuf(fptr) == 0);
4053 int pending = READ_DATA_PENDING_COUNT(fptr);
4056 const char *p = READ_DATA_PENDING_PTR(fptr);
4060 e = memchr(p,
'\n', pending);
4062 pending = (int)(e - p + 1);
4064 chomplen = (pending > 1 && *(e-1) ==
'\r') + 1;
4073 rb_str_resize(str,
len + pending - chomplen);
4074 read_buffered_data(RSTRING_PTR(str)+
len, pending - chomplen, fptr);
4077 if (pending == 1 && chomplen == 1 &&
len > 0) {
4078 if (RSTRING_PTR(str)[
len-1] ==
'\r') {
4079 rb_str_resize(str, --
len);
4084 len += pending - chomplen;
4090 }
while (io_fillbuf(fptr) >= 0);
4093 str = io_enc_str(str, fptr);
4104 unsigned int chomp: 1;
4118 chomp = (!UNDEF_P(vchomp)) &&
RTEST(vchomp);
4120 args->chomp = chomp;
4138 else if (2 <= argc) {
4139 rs = argv[0], lim = argv[1];
4148check_getline_args(
VALUE *rsp,
long *limit,
VALUE io)
4157 enc_rs = rb_enc_get(rs);
4158 enc_io = io_read_encoding(fptr);
4159 if (enc_io != enc_rs &&
4160 (!is_ascii_string(rs) ||
4161 (RSTRING_LEN(rs) > 0 && !rb_enc_asciicompat(enc_io)))) {
4162 if (rs == rb_default_rs) {
4163 rs = rb_enc_str_new(0, 0, enc_io);
4168 rb_raise(rb_eArgError,
"encoding mismatch: %s IO with %s RS",
4169 rb_enc_name(enc_io),
4170 rb_enc_name(enc_rs));
4180 argc =
rb_scan_args(argc, argv,
"02:", NULL, NULL, &opts);
4181 extract_getline_args(argc, argv, args);
4182 extract_getline_opts(opts, args);
4183 check_getline_args(&args->rs, &args->limit, io);
4187rb_io_getline_0(
VALUE rs,
long limit,
int chomp,
rb_io_t *fptr)
4194 if (
NIL_P(rs) && limit < 0) {
4195 str = read_all(fptr, 0,
Qnil);
4196 if (RSTRING_LEN(str) == 0)
return Qnil;
4198 else if (limit == 0) {
4199 return rb_enc_str_new(0, 0, io_read_encoding(fptr));
4201 else if (rs == rb_default_rs && limit < 0 && !NEED_READCONV(fptr) &&
4202 rb_enc_asciicompat(enc = io_read_encoding(fptr))) {
4203 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4204 return rb_io_getline_fast(fptr, enc, chomp);
4207 int c, newline = -1;
4208 const char *rsptr = 0;
4211 int extra_limit = 16;
4212 int chomp_cr = chomp;
4214 SET_BINARY_MODE(fptr);
4215 enc = io_read_encoding(fptr);
4218 rslen = RSTRING_LEN(rs);
4223 swallow(fptr,
'\n');
4225 if (!rb_enc_asciicompat(enc)) {
4229 rsptr = RSTRING_PTR(rs);
4230 rslen = RSTRING_LEN(rs);
4234 else if (rb_enc_mbminlen(enc) == 1) {
4235 rsptr = RSTRING_PTR(rs);
4236 newline = (
unsigned char)rsptr[rslen - 1];
4240 rsptr = RSTRING_PTR(rs);
4241 const char *e = rsptr + rslen;
4242 const char *last = rb_enc_prev_char(rsptr, e, e, enc);
4244 newline = rb_enc_codepoint_len(last, e, &n, enc);
4245 if (last + n != e) rb_raise(rb_eArgError,
"broken separator");
4247 chomp_cr = chomp && newline ==
'\n' && rslen == rb_enc_mbminlen(enc);
4251 while ((c = appendline(fptr, newline, &str, &limit, enc)) != EOF) {
4252 const char *s, *p, *pp, *e;
4255 if (RSTRING_LEN(str) < rslen)
continue;
4256 s = RSTRING_PTR(str);
4259 if (!at_char_boundary(s, p, e, enc))
continue;
4260 if (!rspara) rscheck(rsptr, rslen, rs);
4261 if (memcmp(p, rsptr, rslen) == 0) {
4263 if (chomp_cr && p > s && *(p-1) ==
'\r') --p;
4270 s = RSTRING_PTR(str);
4272 pp = rb_enc_prev_char(s, p, p, enc);
4273 if (extra_limit && pp &&
4287 if (rspara && c != EOF)
4288 swallow(fptr,
'\n');
4290 str = io_enc_str(str, fptr);
4293 if (!
NIL_P(str) && !nolimit) {
4301rb_io_getline_1(
VALUE rs,
long limit,
int chomp,
VALUE io)
4304 int old_lineno, new_lineno;
4308 old_lineno = fptr->
lineno;
4309 str = rb_io_getline_0(rs, limit, chomp, fptr);
4310 if (!
NIL_P(str) && (new_lineno = fptr->
lineno) != old_lineno) {
4311 if (io == ARGF.current_file) {
4312 ARGF.lineno += new_lineno - old_lineno;
4313 ARGF.last_lineno = ARGF.lineno;
4316 ARGF.last_lineno = new_lineno;
4324rb_io_getline(
int argc,
VALUE *argv,
VALUE io)
4328 prepare_getline_args(argc, argv, &args, io);
4329 return rb_io_getline_1(args.rs, args.limit, args.chomp, io);
4339rb_io_gets_limit_internal(
VALUE io,
long limit)
4343 return rb_io_getline_0(rb_default_rs, limit, FALSE, fptr);
4347rb_io_gets_internal(
VALUE io)
4349 return rb_io_gets_limit_internal(io, -1);
4429 str = rb_io_getline(argc, argv, io);
4445rb_io_lineno(
VALUE io)
4500 check_getline_args(&sep, &limit, io);
4502 VALUE line = rb_io_getline_1(sep, limit,
RTEST(chomp), io);
4503 rb_lastline_set_up(line, 1);
4578rb_io_readlines(
int argc,
VALUE *argv,
VALUE io)
4582 prepare_getline_args(argc, argv, &args, io);
4583 return io_readlines(&args, io);
4591 if (arg->limit == 0)
4592 rb_raise(rb_eArgError,
"invalid limit: 0 for readlines");
4594 while (!
NIL_P(line = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, io))) {
4707rb_io_each_line(
int argc,
VALUE *argv,
VALUE io)
4713 prepare_getline_args(argc, argv, &args, io);
4714 if (args.limit == 0)
4715 rb_raise(rb_eArgError,
"invalid limit: 0 for each_line");
4716 while (!
NIL_P(str = rb_io_getline_1(args.rs, args.limit, args.chomp, io))) {
4743rb_io_each_byte(
VALUE io)
4759 }
while (io_fillbuf(fptr) >= 0);
4769 if (NEED_READCONV(fptr)) {
4773 SET_BINARY_MODE(fptr);
4774 make_readconv(fptr, 0);
4788 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4790 clear_readconv(fptr);
4794 str = rb_enc_str_new(fptr->
cbuf.
ptr+fptr->
cbuf.
off, 1, read_enc);
4797 if (fptr->
cbuf.
len == 0) clear_readconv(fptr);
4806 io_shift_cbuf(fptr, r, &str);
4813 ISASCII(RSTRING_PTR(str)[0])) {
4817 str = io_enc_str(str, fptr);
4822 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4823 if (io_fillbuf(fptr) < 0) {
4845 if (io_fillbuf(fptr) != -1) {
4849 r = rb_enc_precise_mbclen(RSTRING_PTR(str), RSTRING_PTR(str)+RSTRING_LEN(str), enc);
4865 str = io_enc_str(str, fptr);
4891rb_io_each_char(
VALUE io)
4901 enc = io_input_encoding(fptr);
4903 while (!
NIL_P(c = io_getc(fptr, enc))) {
4929rb_io_each_codepoint(
VALUE io)
4941 enc = io_read_encoding(fptr);
4942 if (NEED_READCONV(fptr)) {
4943 SET_BINARY_MODE(fptr);
4946 make_readconv(fptr, 0);
4958 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4959 clear_readconv(fptr);
4979 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4980 while (io_fillbuf(fptr) >= 0) {
4995 char cbuf[8], *p = cbuf;
4997 if (more > numberof(cbuf))
goto invalid;
4999 if (more > numberof(cbuf))
goto invalid;
5000 while ((n = (
int)read_buffered_data(p, more, fptr)) > 0 &&
5001 (p += n, (more -= n) > 0)) {
5002 if (io_fillbuf(fptr) < 0)
goto invalid;
5003 if ((n = fptr->
rbuf.
len) > more) n = more;
5005 r = rb_enc_precise_mbclen(cbuf, p, enc);
5018 rb_raise(rb_eArgError,
"invalid byte sequence in %s", rb_enc_name(enc));
5050 enc = io_input_encoding(fptr);
5052 return io_getc(fptr, enc);
5075rb_io_readchar(
VALUE io)
5077 VALUE c = rb_io_getc(io);
5112 VALUE r_stdout = rb_ractor_stdout();
5117 rb_io_flush(r_stdout);
5120 if (io_fillbuf(fptr) < 0) {
5149rb_io_readbyte(
VALUE io)
5210 unsigned char c =
NUM2INT(v) & 0xFF;
5216 io_ungetbyte(b, fptr);
5272 else if (RB_BIGNUM_TYPE_P(c)) {
5278 if (NEED_READCONV(fptr)) {
5279 SET_BINARY_MODE(fptr);
5280 len = RSTRING_LEN(c);
5281#if SIZEOF_LONG > SIZEOF_INT
5285 make_readconv(fptr, (
int)
len);
5299 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
5300 io_ungetbyte(c, fptr);
5320rb_io_isatty(
VALUE io)
5325 return RBOOL(isatty(fptr->
fd) != 0);
5328#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5344rb_io_close_on_exec_p(
VALUE io)
5350 write_io = GetWriteIO(io);
5351 if (io != write_io) {
5353 if (fptr && 0 <= (fd = fptr->
fd)) {
5354 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->
pathv);
5355 if (!(ret & FD_CLOEXEC))
return Qfalse;
5360 if (fptr && 0 <= (fd = fptr->
fd)) {
5361 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->
pathv);
5362 if (!(ret & FD_CLOEXEC))
return Qfalse;
5367#define rb_io_close_on_exec_p rb_f_notimplement
5370#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5394 int flag =
RTEST(arg) ? FD_CLOEXEC : 0;
5399 write_io = GetWriteIO(io);
5400 if (io != write_io) {
5402 if (fptr && 0 <= (fd = fptr->
fd)) {
5403 if ((ret = fcntl(fptr->
fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->
pathv);
5404 if ((ret & FD_CLOEXEC) != flag) {
5405 ret = (ret & ~FD_CLOEXEC) | flag;
5406 ret = fcntl(fd, F_SETFD, ret);
5407 if (ret != 0) rb_sys_fail_path(fptr->
pathv);
5414 if (fptr && 0 <= (fd = fptr->
fd)) {
5415 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->
pathv);
5416 if ((ret & FD_CLOEXEC) != flag) {
5417 ret = (ret & ~FD_CLOEXEC) | flag;
5418 ret = fcntl(fd, F_SETFD, ret);
5419 if (ret != 0) rb_sys_fail_path(fptr->
pathv);
5425#define rb_io_set_close_on_exec rb_f_notimplement
5428#define RUBY_IO_EXTERNAL_P(f) ((f)->mode & FMODE_EXTERNAL)
5429#define PREP_STDIO_NAME(f) (RSTRING_PTR((f)->pathv))
5432finish_writeconv(
rb_io_t *fptr,
int noalloc)
5434 unsigned char *ds, *dp, *de;
5438 unsigned char buf[1024];
5443 de = buf +
sizeof(buf);
5446 size_t remaining = dp-ds;
5447 long result = rb_io_write_memory(fptr, ds, remaining);
5451 if ((
size_t)result == remaining)
break;
5474 if (io_fflush(fptr) < 0) {
5482 fptr->
wbuf.
len += (int)(dp - ds);
5498finish_writeconv_sync(
VALUE arg)
5501 return finish_writeconv(p->fptr, p->noalloc);
5505nogvl_close(
void *ptr)
5509 return (
void*)(intptr_t)close(*fd);
5513maygvl_close(
int fd,
int keepgvl)
5522 return IO_WITHOUT_GVL_INT(nogvl_close, &fd);
5526nogvl_fclose(
void *ptr)
5530 return (
void*)(intptr_t)fclose(file);
5534maygvl_fclose(
FILE *file,
int keepgvl)
5537 return fclose(file);
5539 return IO_WITHOUT_GVL_INT(nogvl_fclose, file);
5545fptr_finalize_flush(
rb_io_t *fptr,
int noraise,
int keepgvl)
5550 int mode = fptr->
mode;
5556 arg.noalloc = noraise;
5560 error = finish_writeconv(fptr, noraise);
5565 io_flush_buffer_sync(fptr);
5568 if (io_fflush(fptr) < 0 &&
NIL_P(error)) {
5576 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2) {
5586 rb_thread_io_close_wait(fptr);
5588 if (!done && stdio_file) {
5590 if ((maygvl_fclose(stdio_file, noraise) < 0) &&
NIL_P(error)) {
5600 if (!done && fd >= 0 && scheduler !=
Qnil) {
5603 if (!UNDEF_P(result)) {
5604 done =
RTEST(result);
5608 if (!done && fd >= 0) {
5614 if ((maygvl_close(fd, keepgvl) < 0) &&
NIL_P(error)) {
5623 if (!
NIL_P(error) && !noraise) {
5632fptr_finalize(
rb_io_t *fptr,
int noraise)
5634 fptr_finalize_flush(fptr, noraise, FALSE);
5635 free_io_buffer(&fptr->
rbuf);
5636 free_io_buffer(&fptr->
wbuf);
5637 clear_codeconv(fptr);
5641rb_io_fptr_cleanup(
rb_io_t *fptr,
int noraise)
5647 fptr_finalize(fptr, noraise);
5655 ruby_sized_xfree(buf->
ptr, (
size_t)buf->
capa);
5667 free_io_buffer(&fptr->
cbuf);
5683 clear_readconv(fptr);
5684 clear_writeconv(fptr);
5688rb_io_fptr_cleanup_all(
rb_io_t *fptr)
5692 rb_io_fptr_cleanup(fptr, TRUE);
5694 free_io_buffer(&fptr->
rbuf);
5695 free_io_buffer(&fptr->
wbuf);
5696 clear_codeconv(fptr);
5703 rb_io_fptr_cleanup_all(io);
5710rb_io_memsize(
const rb_io_t *io)
5712 size_t size =
sizeof(
rb_io_t);
5722 rb_serial_t fork_generation = GET_VM()->fork_gen;
5723 if (io->fork_generation == fork_generation) {
5734# define KEEPGVL TRUE
5736# define KEEPGVL FALSE
5740io_close_fptr(
VALUE io)
5746 write_io = GetWriteIO(io);
5747 if (io != write_io) {
5748 write_fptr =
RFILE(write_io)->fptr;
5749 if (write_fptr && 0 <= write_fptr->
fd) {
5750 rb_io_fptr_cleanup(write_fptr, TRUE);
5754 fptr =
RFILE(io)->fptr;
5755 if (!fptr)
return 0;
5756 if (fptr->
fd < 0)
return 0;
5759 if (rb_thread_io_close_interrupt(fptr)) {
5761 fptr_finalize_flush(fptr, FALSE, KEEPGVL);
5764 rb_io_fptr_cleanup(fptr, FALSE);
5769fptr_waitpid(
rb_io_t *fptr,
int nohang)
5773 rb_last_status_clear();
5782 rb_io_t *fptr = io_close_fptr(io);
5783 if (fptr) fptr_waitpid(fptr, 0);
5823rb_io_close_m(
VALUE io)
5825 rb_io_t *fptr = rb_io_get_fptr(io);
5834io_call_close(
VALUE io)
5843 enum {mesg_len =
sizeof(closed_stream)-1};
5844 VALUE mesg = rb_attr_get(exc, idMesg);
5846 RSTRING_LEN(mesg) != mesg_len ||
5847 memcmp(RSTRING_PTR(mesg), closed_stream, mesg_len)) {
5857 if (!UNDEF_P(closed) &&
RTEST(closed))
return io;
5858 rb_rescue2(io_call_close, io, ignore_closed_stream, io,
5894 write_io = GetWriteIO(io);
5895 if (io != write_io) {
5896 write_fptr =
RFILE(write_io)->fptr;
5897 if (write_fptr && 0 <= write_fptr->
fd) {
5902 fptr = rb_io_get_fptr(io);
5903 return RBOOL(0 > fptr->
fd);
5939rb_io_close_read(
VALUE io)
5945 if (fptr->
fd < 0)
return Qnil;
5946 if (is_socket(fptr->
fd, fptr->
pathv)) {
5950 if (shutdown(fptr->
fd, SHUT_RD) < 0)
5951 rb_sys_fail_path(fptr->
pathv);
5952 fptr->
mode &= ~FMODE_READABLE;
5958 write_io = GetWriteIO(io);
5959 if (io != write_io) {
5964 RFILE(io)->fptr = wfptr;
5967 RFILE(write_io)->fptr = fptr;
5968 rb_io_fptr_cleanup(fptr, FALSE);
5974 rb_raise(
rb_eIOError,
"closing non-duplex IO for reading");
6012rb_io_close_write(
VALUE io)
6017 write_io = GetWriteIO(io);
6019 if (fptr->
fd < 0)
return Qnil;
6020 if (is_socket(fptr->
fd, fptr->
pathv)) {
6024 if (shutdown(fptr->
fd, SHUT_WR) < 0)
6025 rb_sys_fail_path(fptr->
pathv);
6026 fptr->
mode &= ~FMODE_WRITABLE;
6033 rb_raise(
rb_eIOError,
"closing non-duplex IO for writing");
6036 if (io != write_io) {
6056rb_io_sysseek(
int argc,
VALUE *argv,
VALUE io)
6058 VALUE offset, ptrname;
6059 int whence = SEEK_SET;
6063 if (
rb_scan_args(argc, argv,
"11", &offset, &ptrname) == 2) {
6064 whence = interpret_seek_whence(ptrname);
6069 (READ_DATA_BUFFERED(fptr) || READ_CHAR_PENDING(fptr))) {
6073 rb_warn(
"sysseek for buffered IO");
6076 pos = lseek(fptr->
fd, pos, whence);
6077 if (pos < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
6111 io = GetWriteIO(io);
6116 rb_warn(
"syswrite for buffered IO");
6119 tmp = rb_str_tmp_frozen_acquire(str);
6121 n = rb_io_write_memory(fptr, ptr,
len);
6122 if (n < 0) rb_sys_fail_path(fptr->
pathv);
6123 rb_str_tmp_frozen_release(str, tmp);
6140rb_io_sysread(
int argc,
VALUE *argv,
VALUE io)
6151 shrinkable = io_setstrbuf(&str, ilen);
6152 if (ilen == 0)
return str;
6157 if (READ_DATA_BUFFERED(fptr)) {
6163 io_setstrbuf(&str, ilen);
6168 iis.buf = RSTRING_PTR(str);
6171 n = io_read_memory_locktmp(str, &iis);
6174 rb_sys_fail_path(fptr->
pathv);
6177 io_set_read_length(str, n, shrinkable);
6179 if (n == 0 && ilen > 0) {
6195internal_pread_func(
void *_arg)
6199 return (
VALUE)pread(arg->fd, arg->buf, arg->count, arg->offset);
6203pread_internal_call(
VALUE _arg)
6208 if (scheduler !=
Qnil) {
6211 if (!UNDEF_P(result)) {
6216 return rb_io_blocking_region_wait(arg->io, internal_pread_func, arg,
RUBY_IO_READABLE);
6260 shrinkable = io_setstrbuf(&str, (
long)arg.count);
6261 if (arg.count == 0)
return str;
6262 arg.buf = RSTRING_PTR(str);
6275 rb_sys_fail_path(fptr->
pathv);
6277 io_set_read_length(str, n, shrinkable);
6278 if (n == 0 && arg.count > 0) {
6286internal_pwrite_func(
void *_arg)
6290 return (
VALUE)pwrite(arg->fd, arg->buf, arg->count, arg->offset);
6294pwrite_internal_call(
VALUE _arg)
6299 if (scheduler !=
Qnil) {
6302 if (!UNDEF_P(result)) {
6307 return rb_io_blocking_region_wait(arg->io, internal_pwrite_func, arg,
RUBY_IO_WRITABLE);
6348 io = GetWriteIO(io);
6355 tmp = rb_str_tmp_frozen_acquire(str);
6356 arg.buf = RSTRING_PTR(tmp);
6357 arg.count = (size_t)RSTRING_LEN(tmp);
6359 n = (ssize_t)pwrite_internal_call((
VALUE)&arg);
6360 if (n < 0) rb_sys_fail_path(fptr->
pathv);
6361 rb_str_tmp_frozen_release(str, tmp);
6377 fptr->
mode &= ~FMODE_TEXTMODE;
6381 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6384 setmode(fptr->
fd, O_BINARY);
6391io_ascii8bit_binmode(
rb_io_t *fptr)
6402 fptr->
mode &= ~FMODE_TEXTMODE;
6403 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6405 fptr->
encs.
enc = rb_ascii8bit_encoding();
6409 clear_codeconv(fptr);
6418 io_ascii8bit_binmode(fptr);
6435rb_io_binmode_m(
VALUE io)
6441 write_io = GetWriteIO(io);
6456rb_io_binmode_p(
VALUE io)
6464rb_io_fmode_modestr(
enum rb_io_mode fmode)
6468 return MODE_BTMODE(
"a+",
"ab+",
"at+");
6470 return MODE_BTMODE(
"a",
"ab",
"at");
6474 rb_raise(rb_eArgError,
"invalid access fmode 0x%x", fmode);
6476 return MODE_BTMODE(
"r",
"rb",
"rt");
6478 return MODE_BTXMODE(
"w",
"wb",
"wt",
"wx",
"wbx",
"wtx");
6481 return MODE_BTXMODE(
"w+",
"wb+",
"wt+",
"w+x",
"wb+x",
"wt+x");
6483 return MODE_BTMODE(
"r+",
"rb+",
"rt+");
6487static const char bom_prefix[] =
"bom|";
6488static const char utf_prefix[] =
"utf-";
6489enum {bom_prefix_len = (int)
sizeof(bom_prefix) - 1};
6490enum {utf_prefix_len = (int)
sizeof(utf_prefix) - 1};
6493io_encname_bom_p(
const char *name,
long len)
6495 return len > bom_prefix_len &&
STRNCASECMP(name, bom_prefix, bom_prefix_len) == 0;
6501 enum rb_io_mode fmode = 0;
6502 const char *m = modestr, *p = NULL;
6530 if (modestr[0] !=
'w')
6538 if (io_encname_bom_p(m, p ? (
long)(p - m) : (long)strlen(m)))
6551 rb_raise(rb_eArgError,
"invalid access mode %s", modestr);
6556rb_io_oflags_fmode(
int oflags)
6558 enum rb_io_mode fmode = 0;
6560 switch (oflags & O_ACCMODE) {
6572 if (oflags & O_APPEND) {
6575 if (oflags & O_TRUNC) {
6578 if (oflags & O_CREAT) {
6581 if (oflags & O_EXCL) {
6585 if (oflags & O_BINARY) {
6594rb_io_fmode_oflags(
enum rb_io_mode fmode)
6638rb_io_oflags_modestr(
int oflags)
6641# define MODE_BINARY(a,b) ((oflags & O_BINARY) ? (b) : (a))
6643# define MODE_BINARY(a,b) (a)
6646 if (oflags & O_EXCL) {
6647 rb_raise(rb_eArgError,
"exclusive access mode is not supported");
6649 accmode = oflags & (O_RDONLY|O_WRONLY|O_RDWR);
6650 if (oflags & O_APPEND) {
6651 if (accmode == O_WRONLY) {
6652 return MODE_BINARY(
"a",
"ab");
6654 if (accmode == O_RDWR) {
6655 return MODE_BINARY(
"a+",
"ab+");
6660 rb_raise(rb_eArgError,
"invalid access oflags 0x%x", oflags);
6662 return MODE_BINARY(
"r",
"rb");
6664 return MODE_BINARY(
"w",
"wb");
6666 if (oflags & O_TRUNC) {
6667 return MODE_BINARY(
"w+",
"wb+");
6669 return MODE_BINARY(
"r+",
"rb+");
6681 int default_ext = 0;
6684 ext = rb_default_external_encoding();
6687 if (rb_is_ascii8bit_enc(ext)) {
6691 else if (intern == NULL) {
6692 intern = rb_default_internal_encoding();
6697 *enc = (default_ext && intern != ext) ? NULL : ext;
6707unsupported_encoding(
const char *name,
rb_encoding *enc)
6709 rb_enc_warn(enc,
"Unsupported encoding %s ignored", name);
6713parse_mode_enc(
const char *estr,
rb_encoding *estr_enc,
6719 enum rb_io_mode fmode = fmode_p ? *fmode_p : 0;
6725 p = strrchr(estr,
':');
6726 len = p ? (p++ - estr) : (long)strlen(estr);
6728 estr += bom_prefix_len;
6729 len -= bom_prefix_len;
6730 if (!
STRNCASECMP(estr, utf_prefix, utf_prefix_len)) {
6734 rb_enc_warn(estr_enc,
"BOM with non-UTF encoding %s is nonsense", estr);
6735 fmode &= ~FMODE_SETENC_BY_BOM;
6743 memcpy(encname, estr,
len);
6744 encname[
len] =
'\0';
6747 idx = rb_enc_find_index(estr);
6749 if (fmode_p) *fmode_p = fmode;
6752 ext_enc = rb_enc_from_index(idx);
6755 unsupported_encoding(estr, estr_enc);
6761 if (*p ==
'-' && *(p+1) ==
'\0') {
6766 idx2 = rb_enc_find_index(p);
6768 unsupported_encoding(p, estr_enc);
6773 int_enc = rb_enc_from_index(idx2);
6777 rb_io_ext_int_to_encs(ext_enc, int_enc, enc_p, enc2_p, fmode);
6790 v = rb_hash_lookup2(opt, sym_encoding,
Qnil);
6791 if (v !=
Qnil) encoding = v;
6792 v = rb_hash_lookup2(opt, sym_extenc,
Qundef);
6793 if (v !=
Qnil) extenc = v;
6794 v = rb_hash_lookup2(opt, sym_intenc,
Qundef);
6795 if (!UNDEF_P(v)) intenc = v;
6797 if ((!UNDEF_P(extenc) || !UNDEF_P(intenc)) && !
NIL_P(encoding)) {
6799 int idx = rb_to_encoding_index(encoding);
6800 if (idx >= 0) encoding = rb_enc_from_encoding(rb_enc_from_index(idx));
6801 rb_warn(
"Ignoring encoding parameter '%"PRIsVALUE
"': %s_encoding is used",
6802 encoding, UNDEF_P(extenc) ?
"internal" :
"external");
6806 if (!UNDEF_P(extenc) && !
NIL_P(extenc)) {
6807 extencoding = rb_to_encoding(extenc);
6809 if (!UNDEF_P(intenc)) {
6810 if (
NIL_P(intenc)) {
6817 if (*p ==
'-' && *(p+1) ==
'\0') {
6822 intencoding = rb_to_encoding(intenc);
6826 intencoding = rb_to_encoding(intenc);
6828 if (extencoding == intencoding) {
6832 if (!
NIL_P(encoding)) {
6836 enc_p, enc2_p, fmode_p);
6839 rb_io_ext_int_to_encs(rb_to_encoding(encoding), NULL, enc_p, enc2_p, 0);
6842 else if (!UNDEF_P(extenc) || !UNDEF_P(intenc)) {
6844 rb_io_ext_int_to_encs(extencoding, intencoding, enc_p, enc2_p, 0);
6852 enum rb_io_mode fmode = *fmode_p;
6857 !rb_enc_asciicompat(enc ? enc : rb_default_external_encoding()))
6858 rb_raise(rb_eArgError,
"ASCII incompatible encoding needs binmode");
6861 rb_raise(rb_eArgError,
"newline decorator with binary mode");
6868#if !DEFAULT_TEXTMODE
6870 fmode &= ~FMODE_TEXTMODE;
6877extract_binmode(
VALUE opthash,
enum rb_io_mode *fmode)
6879 if (!
NIL_P(opthash)) {
6881 v = rb_hash_aref(opthash, sym_textmode);
6884 rb_raise(rb_eArgError,
"textmode specified twice");
6886 rb_raise(rb_eArgError,
"both textmode and binmode specified");
6890 v = rb_hash_aref(opthash, sym_binmode);
6893 rb_raise(rb_eArgError,
"binmode specified twice");
6895 rb_raise(rb_eArgError,
"both textmode and binmode specified");
6901 rb_raise(rb_eArgError,
"both textmode and binmode specified");
6907 int *oflags_p,
enum rb_io_mode *fmode_p,
struct rb_io_encoding *convconfig_p)
6911 enum rb_io_mode fmode;
6915 int has_enc = 0, has_vmode = 0;
6921 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
6931 fmode = rb_io_oflags_fmode(oflags);
6939 oflags = rb_io_fmode_oflags(fmode);
6943 parse_mode_enc(p+1, rb_enc_get(vmode), &enc, &enc2, &fmode);
6948 e = (fmode &
FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
6949 rb_io_ext_int_to_encs(e, NULL, &enc, &enc2, fmode);
6953 if (
NIL_P(opthash)) {
6957#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
6959 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
6960 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
6962 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
6969 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
6972 else if (
NIL_P(vmode)) {
6973 fmode |= DEFAULT_TEXTMODE;
6980 v = rb_hash_aref(opthash, sym_mode);
6982 if (!
NIL_P(vmode)) {
6983 rb_raise(rb_eArgError,
"mode specified twice");
6990 v = rb_hash_aref(opthash, sym_flags);
6995 fmode = rb_io_oflags_fmode(oflags);
6997 extract_binmode(opthash, &fmode);
7003 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
7006 else if (
NIL_P(vmode)) {
7007 fmode |= DEFAULT_TEXTMODE;
7010 v = rb_hash_aref(opthash, sym_perm);
7013 if (!
NIL_P(*vperm_p)) {
7014 rb_raise(rb_eArgError,
"perm specified twice");
7025#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7027 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7028 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7033 rb_raise(rb_eArgError,
"encoding specified twice");
7036 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
7040 validate_enc_binmode(&fmode, ecflags, enc, enc2);
7046 convconfig_p->
enc = enc;
7047 convconfig_p->
enc2 = enc2;
7048 convconfig_p->
ecflags = ecflags;
7049 convconfig_p->
ecopts = ecopts;
7059sysopen_func(
void *ptr)
7062 const char *fname = RSTRING_PTR(data->fname);
7071 fd = IO_WITHOUT_GVL_INT(sysopen_func, data);
7072 }
while (fd < 0 &&
errno == EINTR);
7079rb_sysopen(
VALUE fname,
int oflags, mode_t perm)
7084 data.fname = rb_str_encode_ospath(fname);
7086 data.oflags = oflags;
7089 TRY_WITH_GC((fd = rb_sysopen_internal(&data)) >= 0) {
7090 rb_syserr_fail_path(first_errno, fname);
7096fdopen_internal(
int fd,
const char *modestr)
7103 file = fdopen(fd, modestr);
7119 TRY_WITH_GC((file = fdopen_internal(fd, modestr)) != 0) {
7125 if (setvbuf(file, NULL, _IOFBF, 0) != 0)
7126 rb_warn(
"setvbuf() can't be honoured (fd=%d)", fd);
7134 int t = isatty(fptr->
fd);
7144io_strip_bom(
VALUE io)
7146 VALUE b1, b2, b3, b4;
7157 return rb_utf8_encindex();
7167 return ENCINDEX_UTF_16BE;
7178 return ENCINDEX_UTF_32LE;
7183 return ENCINDEX_UTF_16LE;
7193 return ENCINDEX_UTF_32BE;
7207io_set_encoding_by_bom(
VALUE io)
7209 int idx = io_strip_bom(io);
7215 extenc = rb_enc_from_index(idx);
7216 io_encoding_set(fptr, rb_enc_from_encoding(extenc),
7217 rb_io_internal_encoding(io),
Qnil);
7226rb_file_open_generic(
VALUE io,
VALUE filename,
int oflags,
enum rb_io_mode fmode,
7234 rb_io_ext_int_to_encs(NULL, NULL, &cc.enc, &cc.enc2, fmode);
7239 validate_enc_binmode(&fmode, convconfig->
ecflags,
7240 convconfig->
enc, convconfig->
enc2);
7244 fptr->
encs = *convconfig;
7247 if (!(oflags & O_TMPFILE)) {
7248 fptr->
pathv = pathv;
7251 fptr->
pathv = pathv;
7253 fptr->
fd = rb_sysopen(pathv, oflags, perm);
7261rb_file_open_internal(
VALUE io,
VALUE filename,
const char *modestr)
7264 const char *p = strchr(modestr,
':');
7268 parse_mode_enc(p+1, rb_usascii_encoding(),
7269 &convconfig.
enc, &convconfig.
enc2, &fmode);
7275 e = (fmode &
FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
7276 rb_io_ext_int_to_encs(e, NULL, &convconfig.
enc, &convconfig.
enc2, fmode);
7282#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7284 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7285 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7287 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.
enc2, convconfig.
ecflags);
7290 return rb_file_open_generic(io, filename,
7291 rb_io_fmode_oflags(fmode),
7301 return rb_file_open_internal(io_alloc(
rb_cFile), fname, modestr);
7310#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7333 while ((tmp = *prev) != 0) {
7334 if (tmp->fptr == fptr) {
7343#if defined (_WIN32) || defined(__CYGWIN__)
7359pipe_finalize(
rb_io_t *fptr,
int noraise)
7361#if !defined(HAVE_WORKING_FORK) && !defined(_WIN32)
7370 fptr_finalize(fptr, noraise);
7372 pipe_del_fptr(fptr);
7379#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7380 void (*
const old_finalize)(
struct rb_io*,int) = fptr->
finalize;
7382 if (old_finalize == orig->finalize)
return;
7387#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7388 if (old_finalize != pipe_finalize) {
7390 for (list =
pipe_list; list; list = list->next) {
7391 if (list->fptr == fptr)
break;
7393 if (!list) pipe_add_fptr(fptr);
7396 pipe_del_fptr(fptr);
7409rb_io_unbuffered(
rb_io_t *fptr)
7427#define HAVE_SPAWNV 1
7428#define spawnv(mode, cmd, args) rb_w32_uaspawn((mode), (cmd), (args))
7429#define spawn(mode, cmd) rb_w32_uspawn((mode), (cmd), 0)
7432#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7442#ifdef HAVE_WORKING_FORK
7443# ifndef __EMSCRIPTEN__
7445popen_redirect(
struct popen_arg *p)
7448 close(p->write_pair[1]);
7449 if (p->write_pair[0] != 0) {
7450 dup2(p->write_pair[0], 0);
7451 close(p->write_pair[0]);
7454 if (p->pair[1] != 1) {
7455 dup2(p->pair[1], 1);
7461 if (p->pair[1] != 1) {
7462 dup2(p->pair[1], 1);
7468 if (p->pair[0] != 0) {
7469 dup2(p->pair[0], 0);
7476#if defined(__linux__)
7487linux_get_maxfd(
void)
7490 char buf[4096], *p, *np, *e;
7493 if (fd < 0)
return fd;
7494 ss = read(fd, buf,
sizeof(buf));
7495 if (ss < 0)
goto err;
7498 while ((
int)
sizeof(
"FDSize:\t0\n")-1 <= e-p &&
7499 (np = memchr(p,
'\n', e-p)) != NULL) {
7500 if (memcmp(p,
"FDSize:",
sizeof(
"FDSize:")-1) == 0) {
7502 p +=
sizeof(
"FDSize:")-1;
7522#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
7524 int max = (int)max_file_descriptor;
7527 ret = fcntl(0, F_MAXFD);
7529 maxhint = max = ret;
7530# elif defined(__linux__)
7531 ret = linux_get_maxfd();
7538 for (fd = lowfd; fd <= max; fd++) {
7539 if (!
NIL_P(noclose_fds) &&
7542 ret = fcntl(fd, F_GETFD);
7543 if (ret != -1 && !(ret & FD_CLOEXEC)) {
7544 fcntl(fd, F_SETFD, ret|FD_CLOEXEC);
7546# define CONTIGUOUS_CLOSED_FDS 20
7548 if (max < fd + CONTIGUOUS_CLOSED_FDS)
7549 max = fd + CONTIGUOUS_CLOSED_FDS;
7555# ifndef __EMSCRIPTEN__
7557popen_exec(
void *pp,
char *errmsg,
size_t errmsg_len)
7559 struct popen_arg *p = (
struct popen_arg*)pp;
7561 return rb_exec_async_signal_safe(p->eargp, errmsg, errmsg_len);
7566#if (defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)) && !defined __EMSCRIPTEN__
7568rb_execarg_fixup_v(
VALUE execarg_obj)
7570 rb_execarg_parent_start(execarg_obj);
7574char *rb_execarg_commandline(
const struct rb_execarg *eargp,
VALUE *prog);
7577#ifndef __EMSCRIPTEN__
7579pipe_open(
VALUE execarg_obj,
const char *modestr,
enum rb_io_mode fmode,
7582 struct rb_execarg *eargp =
NIL_P(execarg_obj) ? NULL : rb_execarg_get(execarg_obj);
7583 VALUE prog = eargp ? (eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name) :
Qfalse ;
7589#if defined(HAVE_WORKING_FORK)
7591 char errmsg[80] = {
'\0' };
7593#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7595 struct popen_arg arg;
7598#if defined(HAVE_SPAWNV)
7599# if defined(HAVE_SPAWNVE)
7600# define DO_SPAWN(cmd, args, envp) ((args) ? \
7601 spawnve(P_NOWAIT, (cmd), (args), (envp)) : \
7602 spawne(P_NOWAIT, (cmd), (envp)))
7604# define DO_SPAWN(cmd, args, envp) ((args) ? \
7605 spawnv(P_NOWAIT, (cmd), (args)) : \
7606 spawn(P_NOWAIT, (cmd)))
7608# if !defined(HAVE_WORKING_FORK)
7610# if defined(HAVE_SPAWNVE)
7615#if !defined(HAVE_WORKING_FORK)
7621#if !defined(HAVE_WORKING_FORK)
7622 const char *cmd = 0;
7628#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7629 arg.execarg_obj = execarg_obj;
7632 arg.pair[0] = arg.pair[1] = -1;
7633 arg.write_pair[0] = arg.write_pair[1] = -1;
7634# if !defined(HAVE_WORKING_FORK)
7635 if (eargp && !eargp->use_shell) {
7636 args = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
7641 if (
rb_pipe(arg.write_pair) < 0)
7642 rb_sys_fail_str(prog);
7645 close(arg.write_pair[0]);
7646 close(arg.write_pair[1]);
7650 rb_execarg_addopt(execarg_obj,
INT2FIX(0),
INT2FIX(arg.write_pair[0]));
7651 rb_execarg_addopt(execarg_obj,
INT2FIX(1),
INT2FIX(arg.pair[1]));
7656 rb_sys_fail_str(prog);
7658 rb_execarg_addopt(execarg_obj,
INT2FIX(1),
INT2FIX(arg.pair[1]));
7662 rb_sys_fail_str(prog);
7664 rb_execarg_addopt(execarg_obj,
INT2FIX(0),
INT2FIX(arg.pair[0]));
7667 rb_sys_fail_str(prog);
7669 if (!
NIL_P(execarg_obj)) {
7670 rb_protect(rb_execarg_fixup_v, execarg_obj, &state);
7672 if (0 <= arg.write_pair[0]) close(arg.write_pair[0]);
7673 if (0 <= arg.write_pair[1]) close(arg.write_pair[1]);
7674 if (0 <= arg.pair[0]) close(arg.pair[0]);
7675 if (0 <= arg.pair[1]) close(arg.pair[1]);
7676 rb_execarg_parent_end(execarg_obj);
7680# if defined(HAVE_WORKING_FORK)
7681 pid = rb_fork_async_signal_safe(&status, popen_exec, &arg, arg.eargp->redirect_fds, errmsg,
sizeof(errmsg));
7683 rb_execarg_run_options(eargp, sargp, NULL, 0);
7684# if defined(HAVE_SPAWNVE)
7685 if (eargp->envp_str) envp = (
char **)RSTRING_PTR(eargp->envp_str);
7687 while ((pid = DO_SPAWN(cmd, args, envp)) < 0) {
7689 switch (e =
errno) {
7691# if EWOULDBLOCK != EAGAIN
7700 rb_execarg_run_options(sargp, NULL, NULL, 0);
7702 rb_execarg_parent_end(execarg_obj);
7705# if defined(HAVE_WORKING_FORK)
7706 pid = rb_call_proc__fork();
7708 popen_redirect(&arg);
7720# if defined(HAVE_WORKING_FORK)
7726 close(arg.write_pair[0]);
7727 close(arg.write_pair[1]);
7729# if defined(HAVE_WORKING_FORK)
7738 close(arg.write_pair[0]);
7739 write_fd = arg.write_pair[1];
7750 cmd = rb_execarg_commandline(eargp, &prog);
7751 if (!
NIL_P(execarg_obj)) {
7752 rb_execarg_parent_start(execarg_obj);
7753 rb_execarg_run_options(eargp, sargp, NULL, 0);
7755 fp = popen(cmd, modestr);
7758 rb_execarg_parent_end(execarg_obj);
7759 rb_execarg_run_options(sargp, NULL, NULL, 0);
7761 if (!fp) rb_syserr_fail_path(e, prog);
7771 fptr->
encs = *convconfig;
7772#if RUBY_CRLF_ENVIRONMENT
7779 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
7782#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7783 if (NEED_NEWLINE_DECORATOR_ON_WRITE(fptr)) {
7784 fptr->
encs.
ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
7790 if (0 <= write_fd) {
7791 write_port = io_alloc(
rb_cIO);
7793 write_fptr->
fd = write_fd;
7795 fptr->
mode &= ~FMODE_WRITABLE;
7797 rb_ivar_set(port, rb_intern(
"@tied_io_for_writing"), write_port);
7800#if defined (__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7802 pipe_add_fptr(fptr);
7808pipe_open(
VALUE execarg_obj,
const char *modestr,
enum rb_io_mode fmode,
7816is_popen_fork(
VALUE prog)
7818 if (RSTRING_LEN(prog) == 1 && RSTRING_PTR(prog)[0] ==
'-') {
7819#if !defined(HAVE_WORKING_FORK)
7821 "fork() function is unimplemented on this machine");
7830pipe_open_s(
VALUE prog,
const char *modestr,
enum rb_io_mode fmode,
7834 VALUE *argv = &prog;
7837 if (!is_popen_fork(prog))
7838 execarg_obj = rb_execarg_new(argc, argv, TRUE, FALSE);
7839 return pipe_open(execarg_obj, modestr, fmode, convconfig);
7845 rb_io_t *fptr = io_close_fptr(io);
8014rb_io_s_popen(
int argc,
VALUE *argv,
VALUE klass)
8018 if (argc > 1 && !
NIL_P(opt = rb_check_hash_type(argv[argc-1]))) --argc;
8019 if (argc > 1 && !
NIL_P(env = rb_check_hash_type(argv[0]))) --argc, ++argv;
8028 int ex = !
NIL_P(opt);
8029 rb_error_arity(argc + ex, 1 + ex, 2 + ex);
8032 return popen_finish(rb_io_popen(pname, pmode, env, opt), klass);
8038 const char *modestr;
8041 enum rb_io_mode fmode;
8047#if SIZEOF_LONG > SIZEOF_INT
8048 if (
len > INT_MAX) {
8049 rb_raise(rb_eArgError,
"too many arguments");
8058 if (!is_popen_fork(pname))
8059 execarg_obj = rb_execarg_new(1, &pname, TRUE, FALSE);
8061 if (!
NIL_P(execarg_obj)) {
8063 opt = rb_execarg_extract_options(execarg_obj, opt);
8065 rb_execarg_setenv(execarg_obj, env);
8068 modestr = rb_io_oflags_modestr(oflags);
8070 return pipe_open(execarg_obj, modestr, fmode, &convconfig);
8080 rb_io_flush(rb_ractor_stdout());
8081 rb_io_flush(rb_ractor_stderr());
8086 RBASIC_SET_CLASS(port, klass);
8093#if defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)
8094struct popen_writer_arg {
8096 struct popen_arg popen;
8100exec_popen_writer(
void *arg,
char *errmsg,
size_t buflen)
8102 struct popen_writer_arg *pw = arg;
8104 popen_redirect(&pw->popen);
8105 execv(pw->argv[0], pw->argv);
8106 strlcpy(errmsg, strerror(
errno), buflen);
8112ruby_popen_writer(
char *
const *argv, rb_pid_t *pid)
8114#if (defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)) || defined(_WIN32)
8115# ifdef HAVE_WORKING_FORK
8116 struct popen_writer_arg pw;
8117 int *
const write_pair = pw.popen.pair;
8123 int result = pipe2(write_pair, O_CLOEXEC);
8125 int result = pipe(write_pair);
8130# ifdef HAVE_WORKING_FORK
8133 char errmsg[80] = {
'\0'};
8134 *pid = rb_fork_async_signal_safe(&status, exec_popen_writer, &pw,
Qnil, errmsg,
sizeof(errmsg));
8136 *pid = rb_w32_uspawn_process(P_NOWAIT, argv[0], argv, write_pair[0], -1, -1, 0);
8137 const char *errmsg = (*pid < 0) ? strerror(
errno) : NULL;
8139 close(write_pair[0]);
8141 close(write_pair[1]);
8142 fprintf(stderr,
"ruby_popen_writer(%s): %s\n", argv[0], errmsg);
8145 return fdopen(write_pair[1],
"w");
8156 enum rb_io_mode fmode;
8165 rb_file_open_generic(io, fname, oflags, fmode, &convconfig, perm);
8203rb_io_s_open(
int argc,
VALUE *argv,
VALUE klass)
8235 VALUE fname, vmode, vperm;
8240 rb_scan_args(argc, argv,
"12", &fname, &vmode, &vperm);
8251 if (
NIL_P(vperm)) perm = 0666;
8255 fd = rb_sysopen(fname, oflags, perm);
8290 int redirect = FALSE;
8298 VALUE tmp = argv[0];
8316 return rb_io_s_open(argc, argv,
rb_cFile);
8320rb_io_open_generic(
VALUE klass,
VALUE filename,
int oflags,
enum rb_io_mode fmode,
8323 return rb_file_open_generic(io_alloc(klass), filename,
8324 oflags, fmode, convconfig, perm);
8331 enum rb_io_mode fmode;
8337 return rb_io_open_generic(io, filename, oflags, fmode, &convconfig, perm);
8351 if (fptr == orig)
return io;
8352 if (RUBY_IO_EXTERNAL_P(fptr)) {
8356 rb_raise(rb_eArgError,
8357 "%s can't change access mode from \"%s\" to \"%s\"",
8358 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->
mode),
8359 rb_io_fmode_modestr(orig->
mode));
8363 if (io_fflush(fptr) < 0)
8364 rb_sys_fail_on_write(fptr);
8367 flush_before_seek(fptr,
true);
8370 pos = io_tell(orig);
8373 if (io_fflush(orig) < 0)
8374 rb_sys_fail_on_write(fptr);
8383 else if (!RUBY_IO_EXTERNAL_P(fptr)) fptr->
pathv =
Qnil;
8384 fptr_copy_finalizer(fptr, orig);
8390 rb_thread_io_close_interrupt(fptr);
8391 rb_thread_io_close_wait(fptr);
8393 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2 || !fptr->stdio_file) {
8396 rb_sys_fail_path(orig->
pathv);
8404 rb_sys_fail_path(orig->
pathv);
8410 if (io_seek(fptr, pos, SEEK_SET) < 0 &&
errno) {
8411 rb_sys_fail_path(fptr->
pathv);
8413 if (io_seek(orig, pos, SEEK_SET) < 0 &&
errno) {
8414 rb_sys_fail_path(orig->
pathv);
8428int rb_freopen(
VALUE fname,
const char *mode,
FILE *fp);
8431rb_freopen(
VALUE fname,
const char *mode,
FILE *fp)
8433 if (!freopen(RSTRING_PTR(fname), mode, fp)) {
8476rb_io_reopen(
int argc,
VALUE *argv,
VALUE file)
8478 VALUE fname, nmode, opt;
8482 if (
rb_scan_args(argc, argv,
"11:", &fname, &nmode, &opt) == 1) {
8485 return io_reopen(file, tmp);
8491 fptr =
RFILE(file)->fptr;
8497 enum rb_io_mode fmode;
8501 if (RUBY_IO_EXTERNAL_P(fptr) &&
8504 rb_raise(rb_eArgError,
8505 "%s can't change access mode from \"%s\" to \"%s\"",
8506 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->
mode),
8507 rb_io_fmode_modestr(fmode));
8510 fptr->
encs = convconfig;
8513 oflags = rb_io_fmode_oflags(fptr->
mode);
8516 fptr->
pathv = fname;
8518 fptr->
fd = rb_sysopen(fptr->
pathv, oflags, 0666);
8524 if (io_fflush(fptr) < 0)
8525 rb_sys_fail_on_write(fptr);
8530 int e = rb_freopen(rb_str_encode_ospath(fptr->
pathv),
8531 rb_io_oflags_modestr(oflags),
8533 if (e) rb_syserr_fail_path(e, fptr->
pathv);
8537 if (setvbuf(fptr->
stdio_file, NULL, _IOFBF, 0) != 0)
8538 rb_warn(
"setvbuf() can't be honoured for %"PRIsVALUE, fptr->
pathv);
8541 if (setvbuf(fptr->
stdio_file, NULL, _IONBF, BUFSIZ) != 0)
8542 rb_warn(
"setvbuf() can't be honoured for %"PRIsVALUE, fptr->
pathv);
8544 else if (fptr->
stdio_file == stdout && isatty(fptr->
fd)) {
8545 if (setvbuf(fptr->
stdio_file, NULL, _IOLBF, BUFSIZ) != 0)
8546 rb_warn(
"setvbuf() can't be honoured for %"PRIsVALUE, fptr->
pathv);
8550 int tmpfd = rb_sysopen(fptr->
pathv, oflags, 0666);
8556 rb_syserr_fail_path(err, fptr->
pathv);
8580 fptr->
mode = orig->
mode & ~FMODE_EXTERNAL;
8587 fptr->closing_ec = NULL;
8588 fptr->wakeup_mutex =
Qnil;
8589 fptr->fork_generation = GET_VM()->fork_gen;
8592 fptr_copy_finalizer(fptr, orig);
8594 fd = ruby_dup(orig->
fd);
8596 pos = io_tell(orig);
8598 io_seek(fptr, pos, SEEK_SET);
8603 write_io = GetWriteIO(io);
8604 if (io != write_io) {
8607 rb_ivar_set(dest, rb_intern(
"@tied_io_for_writing"), write_io);
8670 if (argc == 0)
return Qnil;
8672 out = rb_ractor_stdout();
8684extern void rb_deprecated_str_setter(
VALUE val,
ID id,
VALUE *var);
8689 rb_deprecated_str_setter(val,
id, &val);
8695 val = rb_str_frozen_bare_string(val);
8772 for (i=0; i<argc; i++) {
8776 rb_io_write(out, argv[i]);
8873 rb_io_write(io, str);
8877#define forward(obj, id, argc, argv) \
8878 rb_funcallv_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8879#define forward_public(obj, id, argc, argv) \
8880 rb_funcallv_public_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8881#define forward_current(id, argc, argv) \
8882 forward_public(ARGF.current_file, id, argc, argv)
8899 VALUE r_stdout = rb_ractor_stdout();
8900 if (recv == r_stdout) {
8901 return rb_io_putc(recv, ch);
8903 return forward(r_stdout, rb_intern(
"putc"), 1, &ch);
8908rb_str_end_with_asciichar(
VALUE str,
int c)
8910 long len = RSTRING_LEN(str);
8911 const char *
ptr = RSTRING_PTR(str);
8915 if (
len == 0)
return 0;
8916 if ((n = rb_enc_mbminlen(
enc)) == 1) {
8917 return ptr[
len - 1] == c;
8919 return rb_enc_ascget(
ptr + ((
len - 1) / n) * n,
ptr +
len, &n,
enc) == c;
8930 rb_io_puts(1, &tmp, out);
8937 rb_io_puts(1, &tmp, out);
8992 VALUE line, args[2];
8999 for (
int i = 0; i < argc; i++) {
9013 if (RSTRING_LEN(line) == 0) {
9018 if (!rb_str_end_with_asciichar(line,
'\n')) {
9023 rb_io_writev(out, n, args);
9041 VALUE r_stdout = rb_ractor_stdout();
9042 if (recv == r_stdout) {
9043 return rb_io_puts(argc, argv, recv);
9045 return forward(r_stdout, rb_intern(
"puts"), argc, argv);
9049rb_p_write(
VALUE str)
9054 VALUE r_stdout = rb_ractor_stdout();
9056 rb_method_basic_definition_p(
CLASS_OF(r_stdout), id_write)) {
9057 io_writev(2, args, r_stdout);
9060 rb_io_writev(r_stdout, 2, args);
9072rb_p_result(
int argc,
const VALUE *argv)
9079 else if (argc > 1) {
9082 VALUE r_stdout = rb_ractor_stdout();
9084 rb_uninterruptible(rb_io_flush, r_stdout);
9125 for (i=0; i<argc; i++) {
9127 rb_uninterruptible(rb_p_write, inspected);
9129 return rb_p_result(argc, argv);
9150rb_obj_display(
int argc,
VALUE *argv,
VALUE self)
9154 out = (!
rb_check_arity(argc, 0, 1) ? rb_ractor_stdout() : argv[0]);
9155 rb_io_write(out, self);
9161rb_stderr_to_original_p(
VALUE err)
9163 return (err == orig_stderr ||
RFILE(orig_stderr)->fptr->
fd < 0);
9169 VALUE out = rb_ractor_stderr();
9170 if (rb_stderr_to_original_p(out)) {
9172 if (isatty(fileno(stderr))) {
9173 if (rb_w32_write_console(
rb_str_new(mesg,
len), fileno(stderr)) > 0)
return;
9176 if (fwrite(mesg,
sizeof(
char), (
size_t)
len, stderr) < (
size_t)
len) {
9193rb_write_error_str(
VALUE mesg)
9195 VALUE out = rb_ractor_stderr();
9197 if (rb_stderr_to_original_p(out)) {
9198 size_t len = (size_t)RSTRING_LEN(mesg);
9200 if (isatty(fileno(stderr))) {
9201 if (rb_w32_write_console(mesg, fileno(stderr)) > 0)
return;
9204 if (fwrite(RSTRING_PTR(mesg),
sizeof(
char),
len, stderr) <
len) {
9211 rb_io_write(out, mesg);
9216rb_stderr_tty_p(
void)
9218 if (rb_stderr_to_original_p(rb_ractor_stderr()))
9219 return isatty(fileno(stderr));
9224must_respond_to(
ID mid,
VALUE val,
ID id)
9227 rb_raise(
rb_eTypeError,
"%"PRIsVALUE
" must have %"PRIsVALUE
" method, %"PRIsVALUE
" given",
9228 rb_id2str(
id), rb_id2str(mid),
9248 must_respond_to(id_write, val,
id);
9255 return rb_ractor_stdout();
9261 must_respond_to(id_write, val,
id);
9268 return rb_ractor_stderr();
9272allocate_and_open_new_file(
VALUE klass)
9274 VALUE self = io_alloc(klass);
9275 rb_io_make_open_file(self);
9283 VALUE self = rb_protect(allocate_and_open_new_file, klass, &state);
9291 maygvl_close(descriptor, 0);
9299 io->
fd = descriptor;
9317 io->closing_ec = NULL;
9318 io->wakeup_mutex =
Qnil;
9319 io->fork_generation = GET_VM()->fork_gen;
9322 io->
encs = *encoding;
9331prep_io(
int fd,
enum rb_io_mode fmode,
VALUE klass,
const char *path)
9341 e = (fmode &
FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
9342 rb_io_ext_int_to_encs(e, NULL, &convconfig.
enc, &convconfig.
enc2, fmode);
9346#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9348 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
9349 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
9351 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.
enc2, convconfig.
ecflags);
9357 if (!io_check_tty(io)) {
9360 setmode(fd, O_BINARY);
9372 if (path && strcmp(path,
"-")) klass =
rb_cFile;
9373 return prep_io(fd, rb_io_oflags_fmode(oflags), klass, path);
9377prep_stdio(
FILE *f,
enum rb_io_mode fmode,
VALUE klass,
const char *path)
9384#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9385 fptr->
encs.
ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
9396rb_io_prep_stdin(
void)
9402rb_io_prep_stdout(
void)
9408rb_io_prep_stderr(
void)
9417 int oflags = rb_io_fmode_oflags(fptr->
mode) & ~O_EXCL;
9444 rb_io_buffer_init(&fp->
wbuf);
9445 rb_io_buffer_init(&fp->
rbuf);
9446 rb_io_buffer_init(&fp->
cbuf);
9461 fp->closing_ec = NULL;
9462 fp->wakeup_mutex =
Qnil;
9463 fp->fork_generation = GET_VM()->fork_gen;
9468rb_io_make_open_file(
VALUE obj)
9473 if (
RFILE(obj)->fptr) {
9476 RFILE(obj)->fptr = 0;
9478 fp = rb_io_fptr_new();
9480 RFILE(obj)->fptr = fp;
9528rb_io_initialize(
int argc,
VALUE *argv,
VALUE io)
9534 return io_initialize(io, fnum, vmode, opt);
9541 int fd, oflags = O_RDONLY;
9542 enum rb_io_mode fmode;
9544#if defined(HAVE_FCNTL) && defined(F_GETFL)
9554 rb_raise(rb_eArgError,
"The given fd is not accessible because RubyVM reserves it");
9556#if defined(HAVE_FCNTL) && defined(F_GETFL)
9557 oflags = fcntl(fd, F_GETFL);
9558 if (oflags == -1) rb_sys_fail(0);
9560 if (fstat(fd, &st) < 0) rb_sys_fail(0);
9563#if defined(HAVE_FCNTL) && defined(F_GETFL)
9564 ofmode = rb_io_oflags_fmode(oflags);
9576 if (rb_hash_aref(opt, sym_autoclose) ==
Qfalse) {
9580 path = rb_hash_aref(opt,
RB_ID2SYM(idPath));
9591 fp->
encs = convconfig;
9595 fp->closing_ec = NULL;
9596 fp->wakeup_mutex =
Qnil;
9597 fp->fork_generation = GET_VM()->fork_gen;
9600 if (fileno(stdin) == fd)
9602 else if (fileno(stdout) == fd)
9604 else if (fileno(stderr) == fd)
9636rb_io_set_encoding_by_bom(
VALUE io)
9642 rb_raise(rb_eArgError,
"ASCII incompatible encoding needs binmode");
9645 rb_raise(rb_eArgError,
"encoding conversion is set");
9647 else if (fptr->
encs.
enc && fptr->
encs.
enc != rb_ascii8bit_encoding()) {
9648 rb_raise(rb_eArgError,
"encoding is set to %s already",
9651 if (!io_set_encoding_by_bom(io))
return Qnil;
9652 return rb_enc_from_encoding(fptr->
encs.
enc);
9697rb_file_initialize(
int argc,
VALUE *argv,
VALUE io)
9699 if (
RFILE(io)->fptr) {
9702 VALUE fname, vmode, vperm, opt;
9703 int posargc =
rb_scan_args(argc, argv,
"12:", &fname, &vmode, &vperm, &opt);
9708 return io_initialize(io, fd, vmode, opt);
9711 return rb_open_file(io, fname, vmode, vperm, opt);
9716rb_io_s_new(
int argc,
VALUE *argv,
VALUE klass)
9721 rb_warn(
"%"PRIsVALUE
"::new() does not take block; use %"PRIsVALUE
"::open() instead",
9737rb_io_s_for_fd(
int argc,
VALUE *argv,
VALUE klass)
9740 rb_io_initialize(argc, argv, io);
9753rb_io_autoclose_p(
VALUE io)
9778rb_io_set_autoclose(
VALUE io,
VALUE autoclose)
9782 if (!
RTEST(autoclose))
9785 fptr->
mode &= ~FMODE_EXTERNAL;
9790io_wait_event(
VALUE io,
int event,
VALUE timeout,
int return_io)
9822io_wait_readable(
int argc,
VALUE *argv,
VALUE io)
9829 if (rb_io_read_pending(fptr))
return Qtrue;
9832 VALUE timeout = (argc == 1 ? argv[0] :
Qnil);
9846io_wait_writable(
int argc,
VALUE *argv,
VALUE io)
9854 VALUE timeout = (argc == 1 ? argv[0] :
Qnil);
9869io_wait_priority(
int argc,
VALUE *argv,
VALUE io)
9876 if (rb_io_read_pending(fptr))
return Qtrue;
9879 VALUE timeout = argc == 1 ? argv[0] :
Qnil;
9885wait_mode_sym(
VALUE mode)
9887 if (mode ==
ID2SYM(rb_intern(
"r"))) {
9888 return RB_WAITFD_IN;
9890 if (mode ==
ID2SYM(rb_intern(
"read"))) {
9891 return RB_WAITFD_IN;
9893 if (mode ==
ID2SYM(rb_intern(
"readable"))) {
9894 return RB_WAITFD_IN;
9896 if (mode ==
ID2SYM(rb_intern(
"w"))) {
9897 return RB_WAITFD_OUT;
9899 if (mode ==
ID2SYM(rb_intern(
"write"))) {
9900 return RB_WAITFD_OUT;
9902 if (mode ==
ID2SYM(rb_intern(
"writable"))) {
9903 return RB_WAITFD_OUT;
9905 if (mode ==
ID2SYM(rb_intern(
"rw"))) {
9906 return RB_WAITFD_IN|RB_WAITFD_OUT;
9908 if (mode ==
ID2SYM(rb_intern(
"read_write"))) {
9909 return RB_WAITFD_IN|RB_WAITFD_OUT;
9911 if (mode ==
ID2SYM(rb_intern(
"readable_writable"))) {
9912 return RB_WAITFD_IN|RB_WAITFD_OUT;
9915 rb_raise(rb_eArgError,
"unsupported mode: %"PRIsVALUE, mode);
9919io_event_from_value(
VALUE value)
9923 if (events <= 0) rb_raise(rb_eArgError,
"Events must be positive integer!");
9961 for (
int i = 0; i < argc; i += 1) {
9963 events |= wait_mode_sym(argv[i]);
9965 else if (UNDEF_P(timeout)) {
9969 rb_raise(rb_eArgError,
"timeout given more than once");
9973 if (UNDEF_P(timeout)) timeout =
Qnil;
9981 events = io_event_from_value(argv[0]);
9989 if (rb_io_read_pending(fptr)) {
9991 if (return_io)
return Qtrue;
9997 return io_wait_event(io, events, timeout, return_io);
10001argf_mark_and_move(
void *ptr)
10003 struct argf *p = ptr;
10004 rb_gc_mark_and_move(&p->filename);
10005 rb_gc_mark_and_move(&p->current_file);
10006 rb_gc_mark_and_move(&p->argv);
10007 rb_gc_mark_and_move(&p->inplace);
10008 rb_gc_mark_and_move(&p->encs.
ecopts);
10012argf_memsize(
const void *ptr)
10014 const struct argf *p = ptr;
10015 size_t size =
sizeof(*p);
10022 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
10028 p->filename =
Qnil;
10029 p->current_file =
Qnil;
10035argf_alloc(
VALUE klass)
10040 argf_init(p,
Qnil);
10050 memset(&ARGF, 0,
sizeof(ARGF));
10051 argf_init(&ARGF, argv);
10061 ARGF = argf_of(orig);
10088 ARGF.last_lineno = ARGF.lineno;
10114 return forward_current(rb_frame_this_func(), argc, argv);
10117#define next_argv() argf_next_argv(argf)
10118#define ARGF_GENERIC_INPUT_P() \
10119 (ARGF.current_file == rb_stdin && !RB_TYPE_P(ARGF.current_file, T_FILE))
10120#define ARGF_FORWARD(argc, argv) do {\
10121 if (ARGF_GENERIC_INPUT_P())\
10122 return argf_forward((argc), (argv), argf);\
10124#define NEXT_ARGF_FORWARD(argc, argv) do {\
10125 if (!next_argv()) return Qnil;\
10126 ARGF_FORWARD((argc), (argv));\
10132 VALUE file = ARGF.current_file;
10146 int stdout_binmode = 0;
10147 enum rb_io_mode fmode;
10149 VALUE r_stdout = rb_ractor_stdout();
10154 stdout_binmode = 1;
10157 if (ARGF.init_p == 0) {
10167 if (
NIL_P(ARGF.argv)) {
10170 else if (ARGF.next_p == -1 &&
RARRAY_LEN(ARGF.argv) > 0) {
10175 if (ARGF.next_p == 1) {
10176 if (ARGF.init_p == 1) argf_close(
argf);
10181 ARGF.filename = filename;
10182 filename = rb_str_encode_ospath(filename);
10184 if (RSTRING_LEN(filename) == 1 && fn[0] ==
'-') {
10186 if (ARGF.inplace) {
10187 rb_warn(
"Can't do inplace edit for stdio; skipping");
10193 int fr = rb_sysopen(filename, O_RDONLY, 0);
10195 if (ARGF.inplace) {
10197#ifndef NO_SAFE_RENAME
10208 if (!
NIL_P(ARGF.inplace)) {
10209 VALUE suffix = ARGF.inplace;
10211 if (
NIL_P(rb_str_cat_conv_enc_opts(str, RSTRING_LEN(str),
10212 RSTRING_PTR(suffix), RSTRING_LEN(suffix),
10213 rb_enc_get(suffix), 0,
Qnil))) {
10216#ifdef NO_SAFE_RENAME
10218 (void)unlink(RSTRING_PTR(str));
10219 if (rename(fn, RSTRING_PTR(str)) < 0) {
10220 rb_warn(
"Can't rename %"PRIsVALUE
" to %"PRIsVALUE
": %s, skipping file",
10221 filename, str, strerror(
errno));
10224 fr = rb_sysopen(str, O_RDONLY, 0);
10226 if (rename(fn, RSTRING_PTR(str)) < 0) {
10227 rb_warn(
"Can't rename %"PRIsVALUE
" to %"PRIsVALUE
": %s, skipping file",
10228 filename, str, strerror(
errno));
10235#ifdef NO_SAFE_RENAME
10236 rb_fatal(
"Can't do inplace edit without backup");
10238 if (unlink(fn) < 0) {
10239 rb_warn(
"Can't remove %"PRIsVALUE
": %s, skipping file",
10240 filename, strerror(
errno));
10246 fw = rb_sysopen(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666);
10247#ifndef NO_SAFE_RENAME
10250 fchmod(fw, st.st_mode);
10252 chmod(fn, st.st_mode);
10254 if (st.st_uid!=st2.st_uid || st.st_gid!=st2.st_gid) {
10257 err = fchown(fw, st.st_uid, st.st_gid);
10259 err = chown(fn, st.st_uid, st.st_gid);
10261 if (err && getuid() == 0 && st2.st_uid == 0) {
10262 const char *wkfn = RSTRING_PTR(filename);
10263 rb_warn(
"Can't set owner/group of %"PRIsVALUE
" to same as %"PRIsVALUE
": %s, skipping file",
10264 filename, str, strerror(
errno));
10267 (void)unlink(wkfn);
10277 if (!ARGF.binmode) {
10278 fmode |= DEFAULT_TEXTMODE;
10280 ARGF.current_file = prep_io(fr, fmode,
rb_cFile, fn);
10281 if (!
NIL_P(write_io)) {
10288 if (ARGF.encs.enc) {
10289 fptr->
encs = ARGF.encs;
10290 clear_codeconv(fptr);
10293 fptr->
encs.
ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
10294 if (!ARGF.binmode) {
10296#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
10297 fptr->
encs.
ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
10308 else if (ARGF.next_p == -1) {
10311 if (ARGF.inplace) {
10312 rb_warn(
"Can't do inplace edit for stdio");
10316 if (ARGF.init_p == -1) ARGF.init_p = 1;
10324 long lineno = ARGF.lineno;
10327 if (!next_argv())
return Qnil;
10328 if (ARGF_GENERIC_INPUT_P()) {
10329 line = forward_current(idGets, argc, argv);
10336 line = rb_io_getline(argc, argv, ARGF.current_file);
10338 if (
NIL_P(line) && ARGF.next_p != -1) {
10344 if (!
NIL_P(line)) {
10345 ARGF.lineno = ++lineno;
10346 ARGF.last_lineno = ARGF.lineno;
10352argf_lineno_getter(
ID id,
VALUE *var)
10355 return INT2FIX(ARGF.last_lineno);
10363 ARGF.last_lineno = ARGF.lineno = n;
10367rb_reset_argf_lineno(
long n)
10369 ARGF.last_lineno = ARGF.lineno = n;
10410 if (recv ==
argf) {
10411 return argf_gets(argc, argv,
argf);
10413 return forward(
argf, idGets, argc, argv);
10439 line = argf_getline(argc, argv,
argf);
10451 return rb_f_gets(0, 0,
argf);
10455 if (!next_argv())
return Qnil;
10457 if (
NIL_P(line) && ARGF.next_p != -1) {
10463 if (!
NIL_P(line)) {
10465 ARGF.last_lineno = ARGF.lineno;
10491rb_f_readline(
int argc,
VALUE *argv,
VALUE recv)
10493 if (recv ==
argf) {
10494 return argf_readline(argc, argv,
argf);
10496 return forward(
argf, rb_intern(
"readline"), argc, argv);
10522 if (!next_argv()) rb_eof_error();
10523 ARGF_FORWARD(argc, argv);
10524 line = argf_gets(argc, argv,
argf);
10594rb_f_readlines(
int argc,
VALUE *argv,
VALUE recv)
10596 if (recv ==
argf) {
10597 return argf_readlines(argc, argv,
argf);
10599 return forward(
argf, rb_intern(
"readlines"), argc, argv);
10623 long lineno = ARGF.lineno;
10627 while (next_argv()) {
10628 if (ARGF_GENERIC_INPUT_P()) {
10629 lines = forward_current(rb_intern(
"readlines"), argc, argv);
10632 lines = rb_io_readlines(argc, argv, ARGF.current_file);
10638 ARGF.last_lineno = ARGF.lineno;
10673 rb_last_status_clear();
10674 port = pipe_open_s(str,
"r",
FMODE_READABLE|DEFAULT_TEXTMODE, NULL);
10678 result = read_all(fptr, remain_size(fptr),
Qnil);
10680 rb_io_fptr_cleanup_all(fptr);
10686#ifdef HAVE_SYS_SELECT_H
10687#include <sys/select.h>
10701 if (!
NIL_P(read)) {
10706 if (READ_DATA_PENDING(fptr) || READ_CHAR_PENDING(fptr)) {
10710 if (max < fptr->fd) max = fptr->
fd;
10713 timerec.tv_sec = timerec.tv_usec = 0;
10721 if (!
NIL_P(write)) {
10727 if (max < fptr->fd) max = fptr->
fd;
10734 if (!
NIL_P(except)) {
10738 VALUE write_io = GetWriteIO(io);
10741 if (max < fptr->fd) max = fptr->
fd;
10742 if (io != write_io) {
10745 if (max < fptr->fd) max = fptr->
fd;
10760 if (!pending && n == 0)
return Qnil;
10785 VALUE write_io = GetWriteIO(io);
10798 VALUE write_io = GetWriteIO(io);
10803 else if (io != write_io) {
10816 VALUE read, write, except;
10822select_call(
VALUE arg)
10826 return select_internal(p->read, p->write, p->except, p->timeout, p->fdsets);
10830select_end(
VALUE arg)
10835 for (i = 0; i < numberof(p->fdsets); ++i)
10840static VALUE sym_normal, sym_sequential, sym_random,
10841 sym_willneed, sym_dontneed, sym_noreuse;
10843#ifdef HAVE_POSIX_FADVISE
10844struct io_advise_struct {
10852io_advise_internal(
void *arg)
10854 struct io_advise_struct *ptr = arg;
10855 return posix_fadvise(ptr->fd, ptr->offset, ptr->len, ptr->advice);
10859io_advise_sym_to_const(
VALUE sym)
10861#ifdef POSIX_FADV_NORMAL
10862 if (sym == sym_normal)
10863 return INT2NUM(POSIX_FADV_NORMAL);
10866#ifdef POSIX_FADV_RANDOM
10867 if (sym == sym_random)
10868 return INT2NUM(POSIX_FADV_RANDOM);
10871#ifdef POSIX_FADV_SEQUENTIAL
10872 if (sym == sym_sequential)
10873 return INT2NUM(POSIX_FADV_SEQUENTIAL);
10876#ifdef POSIX_FADV_WILLNEED
10877 if (sym == sym_willneed)
10878 return INT2NUM(POSIX_FADV_WILLNEED);
10881#ifdef POSIX_FADV_DONTNEED
10882 if (sym == sym_dontneed)
10883 return INT2NUM(POSIX_FADV_DONTNEED);
10886#ifdef POSIX_FADV_NOREUSE
10887 if (sym == sym_noreuse)
10888 return INT2NUM(POSIX_FADV_NOREUSE);
10895do_io_advise(
rb_io_t *fptr,
VALUE advice, rb_off_t offset, rb_off_t
len)
10898 struct io_advise_struct ias;
10901 num_adv = io_advise_sym_to_const(advice);
10907 if (
NIL_P(num_adv))
10911 ias.advice =
NUM2INT(num_adv);
10912 ias.offset = offset;
10915 rv = (int)rb_io_blocking_region(fptr, io_advise_internal, &ias);
10916 if (rv && rv != ENOSYS) {
10919 VALUE message = rb_sprintf(
"%"PRIsVALUE
" "
10923 fptr->
pathv, offset,
len, advice);
10933advice_arg_check(
VALUE advice)
10938 if (advice != sym_normal &&
10939 advice != sym_sequential &&
10940 advice != sym_random &&
10941 advice != sym_willneed &&
10942 advice != sym_dontneed &&
10943 advice != sym_noreuse) {
10944 rb_raise(
rb_eNotImpError,
"Unsupported advice: %+"PRIsVALUE, advice);
10982rb_io_advise(
int argc,
VALUE *argv,
VALUE io)
10989 advice_arg_check(advice);
10991 io = GetWriteIO(io);
10997#ifdef HAVE_POSIX_FADVISE
10998 return do_io_advise(fptr, advice,
off, l);
11000 ((void)
off, (
void)l);
11012 return isinf(f) && 0 < f;
11168rb_f_select(
int argc,
VALUE *argv,
VALUE obj)
11171 if (scheduler !=
Qnil) {
11174 if (!UNDEF_P(result))
return result;
11182 rb_scan_args(argc, argv,
"13", &args.read, &args.write, &args.except, &timeout);
11183 if (
NIL_P(timeout) || is_pos_inf(timeout)) {
11188 args.timeout = &timerec;
11191 for (i = 0; i < numberof(args.fdsets); ++i)
11197#ifdef IOCTL_REQ_TYPE
11198 typedef IOCTL_REQ_TYPE ioctl_req_t;
11200 typedef int ioctl_req_t;
11201# define NUM2IOCTLREQ(num) ((int)NUM2LONG(num))
11212nogvl_ioctl(
void *ptr)
11214 struct ioctl_arg *arg = ptr;
11216 return (
VALUE)ioctl(arg->fd, arg->cmd, arg->narg);
11220do_ioctl(
struct rb_io *io, ioctl_req_t cmd,
long narg)
11223 struct ioctl_arg arg;
11229 retval = (int)rb_io_blocking_region(io, nogvl_ioctl, &arg);
11235#define DEFAULT_IOCTL_NARG_LEN (256)
11237#if defined(__linux__) && defined(_IOC_SIZE)
11239linux_iocparm_len(ioctl_req_t cmd)
11243 if ((cmd & 0xFFFF0000) == 0) {
11245 return DEFAULT_IOCTL_NARG_LEN;
11248 len = _IOC_SIZE(cmd);
11251 if (
len < DEFAULT_IOCTL_NARG_LEN)
11252 len = DEFAULT_IOCTL_NARG_LEN;
11260ioctl_narg_len(ioctl_req_t cmd)
11266#define IOCPARM_LEN(x) (((x) >> 16) & IOCPARM_MASK)
11270 len = IOCPARM_LEN(cmd);
11271#elif defined(__linux__) && defined(_IOC_SIZE)
11272 len = linux_iocparm_len(cmd);
11275 len = DEFAULT_IOCTL_NARG_LEN;
11284typedef long fcntl_arg_t;
11287typedef int fcntl_arg_t;
11291fcntl_narg_len(ioctl_req_t cmd)
11298 len =
sizeof(fcntl_arg_t);
11306#ifdef F_DUPFD_CLOEXEC
11307 case F_DUPFD_CLOEXEC:
11308 len =
sizeof(fcntl_arg_t);
11318 len =
sizeof(fcntl_arg_t);
11328 len =
sizeof(fcntl_arg_t);
11338 len =
sizeof(fcntl_arg_t);
11343 len =
sizeof(
struct f_owner_ex);
11348 len =
sizeof(
struct f_owner_ex);
11353 len =
sizeof(
struct flock);
11358 len =
sizeof(
struct flock);
11363 len =
sizeof(
struct flock);
11383 len =
sizeof(fcntl_arg_t);
11393 len =
sizeof(fcntl_arg_t);
11398 len =
sizeof(fcntl_arg_t);
11411fcntl_narg_len(ioctl_req_t cmd)
11417#define NARG_SENTINEL 17
11420setup_narg(ioctl_req_t cmd,
VALUE *argp,
long (*narg_len)(ioctl_req_t))
11431 else if (arg ==
Qtrue) {
11445 len = narg_len(cmd);
11446 rb_str_modify(arg);
11448 slen = RSTRING_LEN(arg);
11450 if (slen <
len+1) {
11451 rb_str_resize(arg,
len+1);
11452 MEMZERO(RSTRING_PTR(arg)+slen,
char,
len-slen);
11456 ptr = RSTRING_PTR(arg);
11457 ptr[slen - 1] = NARG_SENTINEL;
11466finish_narg(
int retval,
VALUE arg,
const rb_io_t *fptr)
11468 if (retval < 0) rb_sys_fail_path(fptr->
pathv);
11473 if (ptr[slen-1] != NARG_SENTINEL)
11474 rb_raise(rb_eArgError,
"return value overflowed string");
11475 ptr[slen-1] =
'\0';
11485 ioctl_req_t cmd = NUM2IOCTLREQ(req);
11490 narg = setup_narg(cmd, &arg, ioctl_narg_len);
11492 retval = do_ioctl(fptr, cmd, narg);
11493 return finish_narg(retval, arg, fptr);
11520 return rb_ioctl(io, req, arg);
11523#define rb_io_ioctl rb_f_notimplement
11534nogvl_fcntl(
void *ptr)
11536 struct fcntl_arg *arg = ptr;
11538#if defined(F_DUPFD)
11539 if (arg->cmd == F_DUPFD)
11542 return (
VALUE)fcntl(arg->fd, arg->cmd, arg->narg);
11546do_fcntl(
struct rb_io *io,
int cmd,
long narg)
11549 struct fcntl_arg arg;
11555 retval = (int)rb_io_blocking_region(io, nogvl_fcntl, &arg);
11556 if (retval != -1) {
11558#if defined(F_DUPFD)
11561#if defined(F_DUPFD_CLOEXEC)
11562 case F_DUPFD_CLOEXEC:
11579 narg = setup_narg(cmd, &arg, fcntl_narg_len);
11581 retval = do_fcntl(fptr, cmd, narg);
11582 return finish_narg(retval, arg, fptr);
11608 return rb_fcntl(io, req, arg);
11611#define rb_io_fcntl rb_f_notimplement
11614#if defined(HAVE_SYSCALL) || defined(HAVE___SYSCALL)
11646#if SIZEOF_VOIDP == 8 && defined(HAVE___SYSCALL) && SIZEOF_INT != 8
11647# define SYSCALL __syscall
11648# define NUM2SYSCALLID(x) NUM2LONG(x)
11649# define RETVAL2NUM(x) LONG2NUM(x)
11650# if SIZEOF_LONG == 8
11651 long num, retval = -1;
11652# elif SIZEOF_LONG_LONG == 8
11653 long long num, retval = -1;
11655# error ---->> it is asserted that __syscall takes the first argument and returns retval in 64bit signed integer. <<----
11657#elif defined(__linux__)
11658# define SYSCALL syscall
11659# define NUM2SYSCALLID(x) NUM2LONG(x)
11660# define RETVAL2NUM(x) LONG2NUM(x)
11668 long num, retval = -1;
11670# define SYSCALL syscall
11671# define NUM2SYSCALLID(x) NUM2INT(x)
11672# define RETVAL2NUM(x) INT2NUM(x)
11673 int num, retval = -1;
11679 "We plan to remove a syscall function at future release. DL(Fiddle) provides safer alternative.");
11683 rb_raise(rb_eArgError,
"too few arguments for syscall");
11684 if (argc > numberof(arg))
11685 rb_raise(rb_eArgError,
"too many arguments for syscall");
11686 num = NUM2SYSCALLID(argv[0]); ++argv;
11687 for (i = argc - 1; i--; ) {
11702 retval = SYSCALL(num);
11705 retval = SYSCALL(num, arg[0]);
11708 retval = SYSCALL(num, arg[0],arg[1]);
11711 retval = SYSCALL(num, arg[0],arg[1],arg[2]);
11714 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3]);
11717 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4]);
11720 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5]);
11723 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6]);
11729 return RETVAL2NUM(retval);
11731#undef NUM2SYSCALLID
11735#define rb_f_syscall rb_f_notimplement
11739io_new_instance(
VALUE args)
11745find_encoding(
VALUE v)
11748 if (!enc)
rb_warn(
"Unsupported encoding %"PRIsVALUE
" ignored", v);
11760 enc2 = find_encoding(v1);
11763 if (RSTRING_LEN(tmp) == 1 && RSTRING_PTR(tmp)[0] ==
'-') {
11769 enc = find_encoding(v2);
11776 enc = find_encoding(v2);
11782 if (enc2 == rb_ascii8bit_encoding()) {
11787 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11793 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
11794 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11799 if (!
NIL_P(tmp) && rb_enc_asciicompat(enc = rb_enc_get(tmp))) {
11800 parse_mode_enc(RSTRING_PTR(tmp), enc, &enc, &enc2, NULL);
11801 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11805 rb_io_ext_int_to_encs(find_encoding(v1), NULL, &enc, &enc2, 0);
11806 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11811 validate_enc_binmode(&fptr->
mode, ecflags, enc, enc2);
11816 clear_codeconv(fptr);
11828io_encoding_set_v(
VALUE v)
11831 io_encoding_set(arg->fptr, arg->v1, arg->v2, arg->opt);
11836pipe_pair_close(
VALUE rw)
11839 return rb_ensure(io_close, rwp[0], io_close, rwp[1]);
11922rb_io_s_pipe(
int argc,
VALUE *argv,
VALUE klass)
11924 int pipes[2], state;
11925 VALUE r, w, args[3], v1, v2;
11929 enum rb_io_mode fmode = 0;
11932 argc =
rb_scan_args(argc, argv,
"02:", &v1, &v2, &opt);
11939 r = rb_protect(io_new_instance, (
VALUE)args, &state);
11943 rb_jump_tag(state);
11947 ies_args.fptr = fptr;
11950 ies_args.opt = opt;
11951 rb_protect(io_encoding_set_v, (
VALUE)&ies_args, &state);
11955 rb_jump_tag(state);
11960 w = rb_protect(io_new_instance, (
VALUE)args, &state);
11964 rb_jump_tag(state);
11969 extract_binmode(opt, &fmode);
11976#if DEFAULT_TEXTMODE
11978 fptr->
mode &= ~FMODE_TEXTMODE;
11979 setmode(fptr->
fd, O_BINARY);
11981#if RUBY_CRLF_ENVIRONMENT
11987 fptr->
mode |= fmode;
11988#if DEFAULT_TEXTMODE
11990 fptr2->
mode &= ~FMODE_TEXTMODE;
11991 setmode(fptr2->
fd, O_BINARY);
11994 fptr2->
mode |= fmode;
12028 else if (!
NIL_P(v = rb_hash_aref(opt, sym_open_args))) {
12031 v = rb_to_array_type(v);
12036 arg->io = rb_io_open(klass, path, vmode, vperm, opt);
12040io_s_foreach(
VALUE v)
12045 if (arg->limit == 0)
12046 rb_raise(rb_eArgError,
"invalid limit: 0 for foreach");
12047 while (!
NIL_P(str = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, arg->io))) {
12135rb_io_s_foreach(
int argc,
VALUE *argv,
VALUE self)
12138 int orig_argc = argc;
12142 argc =
rb_scan_args(argc, argv,
"12:", NULL, NULL, NULL, &opt);
12144 extract_getline_args(argc-1, argv+1, &garg);
12145 open_key_args(self, argc, argv, opt, &arg);
12147 extract_getline_opts(opt, &garg);
12148 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12149 return rb_ensure(io_s_foreach, (
VALUE)&garg, rb_io_close, arg.io);
12153io_s_readlines(
VALUE v)
12156 return io_readlines(arg, arg->io);
12213rb_io_s_readlines(
int argc,
VALUE *argv,
VALUE io)
12219 argc =
rb_scan_args(argc, argv,
"12:", NULL, NULL, NULL, &opt);
12220 extract_getline_args(argc-1, argv+1, &garg);
12221 open_key_args(io, argc, argv, opt, &arg);
12223 extract_getline_opts(opt, &garg);
12224 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12225 return rb_ensure(io_s_readlines, (
VALUE)&garg, rb_io_close, arg.io);
12232 return io_read(arg->argc, arg->argv, arg->io);
12242seek_before_access(
VALUE argp)
12246 return rb_io_seek(arg->io, arg->offset, arg->mode);
12292rb_io_s_read(
int argc,
VALUE *argv,
VALUE io)
12298 argc =
rb_scan_args(argc, argv,
"13:", NULL, NULL, &offset, NULL, &opt);
12300 rb_raise(rb_eArgError,
"negative offset %ld given",
off);
12302 open_key_args(io, argc, argv, opt, &arg);
12304 if (!
NIL_P(offset)) {
12308 sarg.offset = offset;
12309 sarg.mode = SEEK_SET;
12310 rb_protect(seek_before_access, (
VALUE)&sarg, &state);
12313 rb_jump_tag(state);
12315 if (arg.argc == 2) arg.argc = 1;
12334rb_io_s_binread(
int argc,
VALUE *argv,
VALUE io)
12349 convconfig.
enc = rb_ascii8bit_encoding();
12350 arg.io = rb_io_open_generic(io, argv[0], oflags, fmode, &convconfig, 0);
12353 arg.argc = (argc > 1) ? 1 : 0;
12354 if (!
NIL_P(offset)) {
12358 sarg.offset = offset;
12359 sarg.mode = SEEK_SET;
12360 rb_protect(seek_before_access, (
VALUE)&sarg, &state);
12363 rb_jump_tag(state);
12370io_s_write0(
VALUE v)
12373 return io_write(arg->io,arg->str,arg->nosync);
12377io_s_write(
int argc,
VALUE *argv,
VALUE klass,
int binary)
12379 VALUE string, offset, opt;
12383 rb_scan_args(argc, argv,
"21:", NULL, &
string, &offset, &opt);
12385 if (
NIL_P(opt)) opt = rb_hash_new();
12386 else opt = rb_hash_dup(opt);
12389 if (
NIL_P(rb_hash_aref(opt,sym_mode))) {
12390 int mode = O_WRONLY|O_CREAT;
12392 if (binary) mode |= O_BINARY;
12394 if (
NIL_P(offset)) mode |= O_TRUNC;
12395 rb_hash_aset(opt,sym_mode,
INT2NUM(mode));
12397 open_key_args(klass, argc, argv, opt, &arg);
12400 if (binary) rb_io_binmode_m(arg.io);
12404 if (!
NIL_P(offset)) {
12408 sarg.offset = offset;
12409 sarg.mode = SEEK_SET;
12410 rb_protect(seek_before_access, (
VALUE)&sarg, &state);
12413 rb_jump_tag(state);
12421 return rb_ensure(io_s_write0, (
VALUE)&warg, rb_io_close, arg.io);
12469rb_io_s_write(
int argc,
VALUE *argv,
VALUE io)
12471 return io_s_write(argc, argv, io, 0);
12488rb_io_s_binwrite(
int argc,
VALUE *argv,
VALUE io)
12490 return io_s_write(argc, argv, io, 1);
12496 rb_off_t copy_length;
12497 rb_off_t src_offset;
12501 unsigned close_src : 1;
12502 unsigned close_dst : 1;
12505 const char *syserr;
12506 const char *notimp;
12508 struct stat src_stat;
12509 struct stat dst_stat;
12510#ifdef HAVE_FCOPYFILE
12511 copyfile_state_t copyfile_state;
12516exec_interrupts(
void *arg)
12519 rb_thread_execute_interrupts(th);
12533#if defined(ERESTART)
12538 rb_thread_execute_interrupts(stp->th);
12557fiber_scheduler_wait_for(
void * _arguments)
12567# define IOWAIT_SYSCALL "poll"
12568STATIC_ASSERT(pollin_expected, POLLIN == RB_WAITFD_IN);
12569STATIC_ASSERT(pollout_expected, POLLOUT == RB_WAITFD_OUT);
12574 if (scheduler !=
Qnil) {
12577 return RTEST(args.result);
12581 if (fd == -1)
return 0;
12586 fds.events = events;
12588 int timeout_milliseconds = -1;
12591 timeout_milliseconds = (int)(timeout->tv_sec * 1000) + (int)(timeout->tv_usec / 1000);
12594 return poll(&fds, 1, timeout_milliseconds);
12597# define IOWAIT_SYSCALL "select"
12602 if (scheduler !=
Qnil) {
12605 return RTEST(args.result);
12625 case RB_WAITFD_OUT:
12629 VM_UNREACHABLE(nogvl_wait_for);
12649 ret = nogvl_wait_for(stp->th, stp->src_fptr, RB_WAITFD_IN, NULL);
12651 }
while (ret < 0 && maygvl_copy_stream_continue_p(has_gvl, stp));
12654 stp->syserr = IOWAIT_SYSCALL;
12655 stp->error_no =
errno;
12667 ret = nogvl_wait_for(stp->th, stp->dst_fptr, RB_WAITFD_OUT, NULL);
12668 }
while (ret < 0 && maygvl_copy_stream_continue_p(0, stp));
12671 stp->syserr = IOWAIT_SYSCALL;
12672 stp->error_no =
errno;
12678#ifdef USE_COPY_FILE_RANGE
12681simple_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)
12683#ifdef HAVE_COPY_FILE_RANGE
12684 return copy_file_range(in_fd, in_offset, out_fd, out_offset, count, flags);
12686 return syscall(__NR_copy_file_range, in_fd, in_offset, out_fd, out_offset, count, flags);
12695 rb_off_t copy_length, src_offset, *src_offset_ptr;
12697 if (!S_ISREG(stp->src_stat.st_mode))
12700 src_size = stp->src_stat.st_size;
12701 src_offset = stp->src_offset;
12702 if (src_offset >= (rb_off_t)0) {
12703 src_offset_ptr = &src_offset;
12706 src_offset_ptr = NULL;
12709 copy_length = stp->copy_length;
12710 if (copy_length < (rb_off_t)0) {
12711 if (src_offset < (rb_off_t)0) {
12712 rb_off_t current_offset;
12714 current_offset = lseek(stp->src_fptr->
fd, 0, SEEK_CUR);
12715 if (current_offset < (rb_off_t)0 &&
errno) {
12716 stp->syserr =
"lseek";
12717 stp->error_no =
errno;
12718 return (
int)current_offset;
12720 copy_length = src_size - current_offset;
12723 copy_length = src_size - src_offset;
12727 retry_copy_file_range:
12728# if SIZEOF_OFF_T > SIZEOF_SIZE_T
12730 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
12732 ss = (ssize_t)copy_length;
12734 ss = simple_copy_file_range(stp->src_fptr->
fd, src_offset_ptr, stp->dst_fptr->
fd, NULL, ss, 0);
12738 if (0 < copy_length) {
12739 goto retry_copy_file_range;
12743 if (maygvl_copy_stream_continue_p(0, stp)) {
12744 goto retry_copy_file_range;
12758#if EWOULDBLOCK != EAGAIN
12762 int ret = nogvl_copy_stream_wait_write(stp);
12763 if (ret < 0)
return ret;
12765 goto retry_copy_file_range;
12769 int flags = fcntl(stp->dst_fptr->
fd, F_GETFL);
12771 if (flags != -1 && flags & O_APPEND) {
12777 stp->syserr =
"copy_file_range";
12778 stp->error_no =
errno;
12785#ifdef HAVE_FCOPYFILE
12789 rb_off_t cur, ss = 0;
12790 const rb_off_t src_offset = stp->src_offset;
12793 if (stp->copy_length >= (rb_off_t)0) {
12798 if (!S_ISREG(stp->src_stat.st_mode))
12801 if (!S_ISREG(stp->dst_stat.st_mode))
12803 if (lseek(stp->dst_fptr->
fd, 0, SEEK_CUR) > (rb_off_t)0)
12805 if (fcntl(stp->dst_fptr->
fd, F_GETFL) & O_APPEND) {
12808 rb_off_t end = lseek(stp->dst_fptr->
fd, 0, SEEK_END);
12809 lseek(stp->dst_fptr->
fd, 0, SEEK_SET);
12810 if (end > (rb_off_t)0)
return 0;
12813 if (src_offset > (rb_off_t)0) {
12818 cur = lseek(stp->src_fptr->
fd, 0, SEEK_CUR);
12819 if (cur < (rb_off_t)0 &&
errno) {
12820 stp->error_no =
errno;
12825 r = lseek(stp->src_fptr->
fd, src_offset, SEEK_SET);
12826 if (r < (rb_off_t)0 &&
errno) {
12827 stp->error_no =
errno;
12832 stp->copyfile_state = copyfile_state_alloc();
12833 ret = fcopyfile(stp->src_fptr->
fd, stp->dst_fptr->
fd, stp->copyfile_state, COPYFILE_DATA);
12834 copyfile_state_get(stp->copyfile_state, COPYFILE_STATE_COPIED, &ss);
12838 if (src_offset > (rb_off_t)0) {
12842 r = lseek(stp->src_fptr->
fd, cur, SEEK_SET);
12843 if (r < (rb_off_t)0 &&
errno) {
12844 stp->error_no =
errno;
12856 stp->syserr =
"fcopyfile";
12857 stp->error_no =
errno;
12864#ifdef HAVE_SENDFILE
12867# define USE_SENDFILE
12869# ifdef HAVE_SYS_SENDFILE_H
12870# include <sys/sendfile.h>
12874simple_sendfile(
int out_fd,
int in_fd, rb_off_t *offset, rb_off_t count)
12876 return sendfile(out_fd, in_fd, offset, (
size_t)count);
12879# elif 0 || defined(__APPLE__)
12883# define USE_SENDFILE
12886simple_sendfile(
int out_fd,
int in_fd, rb_off_t *offset, rb_off_t count)
12889 rb_off_t pos = offset ? *offset : lseek(in_fd, 0, SEEK_CUR);
12892 r = sendfile(in_fd, out_fd, pos, &count, NULL, 0);
12895 r = sendfile(in_fd, out_fd, pos, (
size_t)count, NULL, &sbytes, 0);
12897 if (r != 0 && sbytes == 0)
return r;
12902 lseek(in_fd, sbytes, SEEK_CUR);
12904 return (ssize_t)sbytes;
12917 rb_off_t copy_length;
12918 rb_off_t src_offset;
12921 if (!S_ISREG(stp->src_stat.st_mode))
12924 src_size = stp->src_stat.st_size;
12926 if ((stp->dst_stat.st_mode & S_IFMT) != S_IFSOCK)
12930 src_offset = stp->src_offset;
12931 use_pread = src_offset >= (rb_off_t)0;
12933 copy_length = stp->copy_length;
12934 if (copy_length < (rb_off_t)0) {
12936 copy_length = src_size - src_offset;
12940 cur = lseek(stp->src_fptr->
fd, 0, SEEK_CUR);
12941 if (cur < (rb_off_t)0 &&
errno) {
12942 stp->syserr =
"lseek";
12943 stp->error_no =
errno;
12946 copy_length = src_size - cur;
12951# if SIZEOF_OFF_T > SIZEOF_SIZE_T
12953 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
12955 ss = (ssize_t)copy_length;
12958 ss = simple_sendfile(stp->dst_fptr->
fd, stp->src_fptr->
fd, &src_offset, ss);
12961 ss = simple_sendfile(stp->dst_fptr->
fd, stp->src_fptr->
fd, NULL, ss);
12966 if (0 < copy_length) {
12967 goto retry_sendfile;
12971 if (maygvl_copy_stream_continue_p(0, stp))
12972 goto retry_sendfile;
12985#if EWOULDBLOCK != EAGAIN
12998 ret = maygvl_copy_stream_wait_read(0, stp);
12999 if (ret < 0)
return ret;
13001 ret = nogvl_copy_stream_wait_write(stp);
13002 if (ret < 0)
return ret;
13004 goto retry_sendfile;
13006 stp->syserr =
"sendfile";
13007 stp->error_no =
errno;
13015maygvl_read(
int has_gvl,
rb_io_t *fptr,
void *buf,
size_t count)
13018 return rb_io_read_memory(fptr, buf, count);
13020 return read(fptr->
fd, buf, count);
13024maygvl_copy_stream_read(
int has_gvl,
struct copy_stream_struct *stp,
char *buf,
size_t len, rb_off_t offset)
13028 if (offset < (rb_off_t)0) {
13029 ss = maygvl_read(has_gvl, stp->src_fptr, buf,
len);
13032 ss = pread(stp->src_fptr->
fd, buf,
len, offset);
13038 if (maygvl_copy_stream_continue_p(has_gvl, stp))
13042#if EWOULDBLOCK != EAGAIN
13046 int ret = maygvl_copy_stream_wait_read(has_gvl, stp);
13047 if (ret < 0)
return ret;
13052 stp->notimp =
"pread";
13056 stp->syserr = offset < (rb_off_t)0 ?
"read" :
"pread";
13057 stp->error_no =
errno;
13068 ss = write(stp->dst_fptr->
fd, buf+
off,
len);
13070 if (maygvl_copy_stream_continue_p(0, stp))
13072 if (io_again_p(
errno)) {
13073 int ret = nogvl_copy_stream_wait_write(stp);
13074 if (ret < 0)
return ret;
13077 stp->syserr =
"write";
13078 stp->error_no =
errno;
13095 rb_off_t copy_length;
13096 rb_off_t src_offset;
13100 copy_length = stp->copy_length;
13101 use_eof = copy_length < (rb_off_t)0;
13102 src_offset = stp->src_offset;
13103 use_pread = src_offset >= (rb_off_t)0;
13105 if (use_pread && stp->close_src) {
13108 r = lseek(stp->src_fptr->
fd, src_offset, SEEK_SET);
13109 if (r < (rb_off_t)0 &&
errno) {
13110 stp->syserr =
"lseek";
13111 stp->error_no =
errno;
13114 src_offset = (rb_off_t)-1;
13118 while (use_eof || 0 < copy_length) {
13119 if (!use_eof && copy_length < (rb_off_t)
sizeof(buf)) {
13120 len = (size_t)copy_length;
13126 ss = maygvl_copy_stream_read(0, stp, buf,
len, src_offset);
13131 ss = maygvl_copy_stream_read(0, stp, buf,
len, (rb_off_t)-1);
13136 ret = nogvl_copy_stream_write(stp, buf, ss);
13146nogvl_copy_stream_func(
void *arg)
13149#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13153#ifdef USE_COPY_FILE_RANGE
13154 ret = nogvl_copy_file_range(stp);
13159#ifdef HAVE_FCOPYFILE
13160 ret = nogvl_fcopyfile(stp);
13166 ret = nogvl_copy_stream_sendfile(stp);
13171 nogvl_copy_stream_read_write(stp);
13173#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13180copy_stream_fallback_body(
VALUE arg)
13183 const int buflen = 16*1024;
13186 rb_off_t rest = stp->copy_length;
13187 rb_off_t
off = stp->src_offset;
13188 ID read_method = id_readpartial;
13190 if (!stp->src_fptr) {
13192 read_method = id_read;
13199 rb_str_make_independent(buf);
13200 if (stp->copy_length < (rb_off_t)0) {
13205 rb_str_resize(buf, 0);
13208 l = buflen < rest ? buflen : (long)rest;
13210 if (!stp->src_fptr) {
13213 if (read_method == id_read &&
NIL_P(rc))
13218 rb_str_resize(buf, buflen);
13219 ss = maygvl_copy_stream_read(1, stp, RSTRING_PTR(buf), l,
off);
13220 rb_str_resize(buf, ss > 0 ? ss : 0);
13225 if (
off >= (rb_off_t)0)
13228 n = rb_io_write(stp->dst, buf);
13230 stp->total += numwrote;
13232 if (read_method == id_read && RSTRING_LEN(buf) == 0) {
13243 if (!stp->src_fptr && stp->src_offset >= (rb_off_t)0) {
13244 rb_raise(rb_eArgError,
"cannot specify src_offset for non-IO");
13253copy_stream_body(
VALUE arg)
13256 VALUE src_io = stp->src, dst_io = stp->dst;
13257 const int common_oflags = 0
13267 if (src_io ==
argf ||
13271 stp->src_fptr = NULL;
13276 if (!
NIL_P(tmp_io)) {
13283 args[1] =
INT2NUM(O_RDONLY|common_oflags);
13286 stp->close_src = 1;
13291 stat_ret = fstat(stp->src_fptr->
fd, &stp->src_stat);
13292 if (stat_ret < 0) {
13293 stp->syserr =
"fstat";
13294 stp->error_no =
errno;
13299 if (dst_io ==
argf ||
13303 stp->dst_fptr = NULL;
13308 if (!
NIL_P(tmp_io)) {
13309 dst_io = GetWriteIO(tmp_io);
13315 args[1] =
INT2NUM(O_WRONLY|O_CREAT|O_TRUNC|common_oflags);
13319 stp->close_dst = 1;
13322 dst_io = GetWriteIO(dst_io);
13328 stat_ret = fstat(stp->dst_fptr->
fd, &stp->dst_stat);
13329 if (stat_ret < 0) {
13330 stp->syserr =
"fstat";
13331 stp->error_no =
errno;
13338 SET_BINARY_MODE_WITH_SEEK_CUR(stp->src_fptr);
13341 io_ascii8bit_binmode(stp->dst_fptr);
13343 if (stp->src_offset < (rb_off_t)0 && stp->src_fptr && stp->src_fptr->
rbuf.
len) {
13346 if (stp->copy_length >= (rb_off_t)0 && stp->copy_length < (rb_off_t)
len) {
13347 len = (size_t)stp->copy_length;
13350 rb_str_resize(str,
len);
13351 read_buffered_data(RSTRING_PTR(str),
len, stp->src_fptr);
13352 if (stp->dst_fptr) {
13353 if (io_binwrite(RSTRING_PTR(str), RSTRING_LEN(str), stp->dst_fptr, 0) < 0)
13354 rb_sys_fail_on_write(stp->dst_fptr);
13357 rb_io_write(dst_io, str);
13358 rb_str_resize(str, 0);
13360 if (stp->copy_length >= (rb_off_t)0)
13361 stp->copy_length -=
len;
13364 if (stp->dst_fptr && io_fflush(stp->dst_fptr) < 0) {
13368 if (stp->copy_length == 0)
13371 if (stp->src_fptr == NULL || stp->dst_fptr == NULL) {
13372 return copy_stream_fallback(stp);
13375 IO_WITHOUT_GVL(nogvl_copy_stream_func, stp);
13380copy_stream_finalize(
VALUE arg)
13384#ifdef HAVE_FCOPYFILE
13385 if (stp->copyfile_state) {
13386 copyfile_state_free(stp->copyfile_state);
13390 if (stp->close_src) {
13391 rb_io_close_m(stp->src);
13393 if (stp->close_dst) {
13394 rb_io_close_m(stp->dst);
13457rb_io_s_copy_stream(
int argc,
VALUE *argv,
VALUE io)
13459 VALUE src, dst, length, src_offset;
13464 rb_scan_args(argc, argv,
"22", &src, &dst, &length, &src_offset);
13469 st.src_fptr = NULL;
13470 st.dst_fptr = NULL;
13473 st.copy_length = (rb_off_t)-1;
13475 st.copy_length =
NUM2OFFT(length);
13477 if (
NIL_P(src_offset))
13478 st.src_offset = (rb_off_t)-1;
13480 st.src_offset =
NUM2OFFT(src_offset);
13499rb_io_external_encoding(
VALUE io)
13504 return rb_enc_from_encoding(fptr->
encs.
enc2);
13508 return rb_enc_from_encoding(fptr->
encs.
enc);
13511 return rb_enc_from_encoding(io_read_encoding(fptr));
13527rb_io_internal_encoding(
VALUE io)
13532 return rb_enc_from_encoding(io_read_encoding(fptr));
13566rb_io_set_encoding(
int argc,
VALUE *argv,
VALUE io)
13572 return forward(io, id_set_encoding, argc, argv);
13575 argc =
rb_scan_args(argc, argv,
"11:", &v1, &v2, &opt);
13577 io_encoding_set(fptr, v1, v2, opt);
13582rb_stdio_set_default_encoding(
void)
13587 if (isatty(fileno(stdin))) {
13589 rb_encoding *internal = rb_default_internal_encoding();
13590 if (!internal) internal = rb_default_external_encoding();
13592 rb_enc_from_encoding(external),
13593 rb_enc_from_encoding(internal),
13598 rb_io_set_encoding(1, &val,
rb_stdin);
13599 rb_io_set_encoding(1, &val,
rb_stdout);
13600 rb_io_set_encoding(1, &val,
rb_stderr);
13604global_argf_p(
VALUE arg)
13606 return arg ==
argf;
13609typedef VALUE (*argf_encoding_func)(
VALUE io);
13612argf_encoding(
VALUE argf, argf_encoding_func func)
13614 if (!
RTEST(ARGF.current_file)) {
13615 return rb_enc_default_external();
13639 return argf_encoding(
argf, rb_io_external_encoding);
13658 return argf_encoding(
argf, rb_io_internal_encoding);
13697 if (!next_argv()) {
13698 rb_raise(rb_eArgError,
"no stream to set encoding");
13700 rb_io_set_encoding(argc, argv, ARGF.current_file);
13702 ARGF.encs = fptr->
encs;
13721 if (!next_argv()) {
13722 rb_raise(rb_eArgError,
"no stream to tell");
13724 ARGF_FORWARD(0, 0);
13725 return rb_io_tell(ARGF.current_file);
13738 if (!next_argv()) {
13739 rb_raise(rb_eArgError,
"no stream to seek");
13741 ARGF_FORWARD(argc, argv);
13742 return rb_io_seek_m(argc, argv, ARGF.current_file);
13759 if (!next_argv()) {
13760 rb_raise(rb_eArgError,
"no stream to set position");
13762 ARGF_FORWARD(1, &offset);
13763 return rb_io_set_pos(ARGF.current_file, offset);
13784 if (!next_argv()) {
13785 rb_raise(rb_eArgError,
"no stream to rewind");
13787 ARGF_FORWARD(0, 0);
13788 old_lineno =
RFILE(ARGF.current_file)->fptr->lineno;
13789 ret = rb_io_rewind(ARGF.current_file);
13790 if (!global_argf_p(
argf)) {
13791 ARGF.last_lineno = ARGF.lineno -= old_lineno;
13809 if (!next_argv()) {
13810 rb_raise(rb_eArgError,
"no stream");
13812 ARGF_FORWARD(0, 0);
13813 return rb_io_fileno(ARGF.current_file);
13832 ARGF_FORWARD(0, 0);
13833 return ARGF.current_file;
13858 if (
RTEST(ARGF.current_file)) {
13859 if (ARGF.init_p == 0)
return Qtrue;
13861 ARGF_FORWARD(0, 0);
13920 VALUE tmp, str, length;
13924 if (!
NIL_P(length)) {
13929 rb_str_resize(str,0);
13934 if (!next_argv()) {
13937 if (ARGF_GENERIC_INPUT_P()) {
13938 tmp = argf_forward(argc, argv,
argf);
13941 tmp = io_read(argc, argv, ARGF.current_file);
13943 if (
NIL_P(str)) str = tmp;
13946 if (ARGF.next_p != -1) {
13952 else if (argc >= 1) {
13953 long slen = RSTRING_LEN(str);
13969argf_forward_call(
VALUE arg)
13972 argf_forward(p->argc, p->argv, p->argf);
14002 return argf_getpartial(argc, argv,
argf,
Qnil, 0);
14023 return argf_getpartial(argc, argv,
argf, opts, 1);
14029 VALUE tmp, str, length;
14037 no_exception = no_exception_p(opts);
14039 if (!next_argv()) {
14041 rb_str_resize(str, 0);
14045 if (ARGF_GENERIC_INPUT_P()) {
14055 tmp = io_getpartial(argc, argv, ARGF.current_file, no_exception, nonblock);
14058 if (ARGF.next_p == -1) {
14059 return io_nonblock_eof(no_exception);
14064 return io_nonblock_eof(no_exception);
14102 if (!next_argv())
return Qnil;
14103 if (ARGF_GENERIC_INPUT_P()) {
14104 ch = forward_current(rb_intern(
"getc"), 0, 0);
14107 ch = rb_io_getc(ARGF.current_file);
14109 if (
NIL_P(ch) && ARGF.next_p != -1) {
14142 if (!next_argv())
return Qnil;
14144 ch = forward_current(rb_intern(
"getbyte"), 0, 0);
14149 if (
NIL_P(ch) && ARGF.next_p != -1) {
14182 if (!next_argv()) rb_eof_error();
14184 ch = forward_current(rb_intern(
"getc"), 0, 0);
14187 ch = rb_io_getc(ARGF.current_file);
14189 if (
NIL_P(ch) && ARGF.next_p != -1) {
14221 NEXT_ARGF_FORWARD(0, 0);
14222 c = argf_getbyte(
argf);
14229#define FOREACH_ARGF() while (next_argv())
14234 const VALUE current = ARGF.current_file;
14236 if (ARGF.init_p == -1 || current != ARGF.current_file) {
14242#define ARGF_block_call(mid, argc, argv, func, argf) \
14243 rb_block_call_kw(ARGF.current_file, mid, argc, argv, \
14244 func, argf, rb_keyword_given_p())
14249 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_i,
argf);
14250 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14256 if (!global_argf_p(
argf)) {
14257 ARGF.last_lineno = ++ARGF.lineno;
14259 return argf_block_call_i(i,
argf, argc, argv, blockarg);
14265 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_line_i,
argf);
14266 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14314 argf_block_call_line(rb_intern(
"each_line"), argc, argv,
argf);
14345 argf_block_call(rb_intern(
"each_byte"), 0, 0,
argf);
14371 argf_block_call(rb_intern(
"each_char"), 0, 0,
argf);
14397 argf_block_call(rb_intern(
"each_codepoint"), 0, 0,
argf);
14428 return ARGF.filename;
14432argf_filename_getter(
ID id,
VALUE *var)
14434 return argf_filename(*var);
14459 return ARGF.current_file;
14478 ARGF_FORWARD(0, 0);
14499 return RBOOL(ARGF.binmode);
14519 if (ARGF.init_p && ARGF.next_p == 0) {
14548 if (ARGF.next_p != -1) {
14566 ARGF_FORWARD(0, 0);
14593 if (!ARGF.inplace)
return Qnil;
14601 return argf_inplace_mode_get(*var);
14632 ARGF.inplace =
Qnil;
14643 argf_inplace_mode_set(*var, val);
14647ruby_set_inplace_mode(
const char *suffix)
14673argf_argv_getter(
ID id,
VALUE *var)
14675 return argf_argv(*var);
14694 if (!
RTEST(ARGF.current_file)) {
14697 return GetWriteIO(ARGF.current_file);
14709 return rb_io_writev(argf_write_io(
argf), argc, argv);
14724 case RB_IO_WAIT_WRITABLE:
14727 c = rb_eEAGAINWaitWritable;
14729#if EAGAIN != EWOULDBLOCK
14731 c = rb_eEWOULDBLOCKWaitWritable;
14735 c = rb_eEINPROGRESSWaitWritable;
14741 case RB_IO_WAIT_READABLE:
14744 c = rb_eEAGAINWaitReadable;
14746#if EAGAIN != EWOULDBLOCK
14748 c = rb_eEWOULDBLOCKWaitReadable;
14752 c = rb_eEINPROGRESSWaitReadable;
14759 rb_bug(
"invalid read/write type passed to rb_readwrite_sys_fail: %d", waiting);
14765get_LAST_READ_LINE(
ID _x,
VALUE *_y)
15650#include <sys/cygwin.h>
15651 static struct __cygwin_perfile pf[] =
15653 {
"", O_RDONLY | O_BINARY},
15654 {
"", O_WRONLY | O_BINARY},
15655 {
"", O_RDWR | O_BINARY},
15656 {
"", O_APPEND | O_BINARY},
15659 cygwin_internal(CW_PERFILE, pf);
15714#if EAGAIN == EWOULDBLOCK
15715 rb_eEWOULDBLOCKWaitReadable = rb_eEAGAINWaitReadable;
15717 rb_define_const(
rb_cIO,
"EWOULDBLOCKWaitReadable", rb_eEAGAINWaitReadable);
15718 rb_eEWOULDBLOCKWaitWritable = rb_eEAGAINWaitWritable;
15720 rb_define_const(
rb_cIO,
"EWOULDBLOCKWaitWritable", rb_eEAGAINWaitWritable);
15768 rb_gvar_ractor_local(
"$/");
15770 rb_gvar_ractor_local(
"$-0");
15774 rb_gvar_ractor_local(
"$_");
15890 rb_gvar_ractor_local(
"$stdin");
15891 rb_gvar_ractor_local(
"$stdout");
15892 rb_gvar_ractor_local(
"$>");
15893 rb_gvar_ractor_local(
"$stderr");
15979 rb_define_method(rb_cARGF,
"external_encoding", argf_external_encoding, 0);
15980 rb_define_method(rb_cARGF,
"internal_encoding", argf_internal_encoding, 0);
15999 rb_gvar_ractor_local(
"$-i");
16003#if defined (_WIN32) || defined(__CYGWIN__)
16004 atexit(pipe_atexit);
16016 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.
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.
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 value inst...
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_current_for_threadptr(struct rb_thread_struct *thread)
Identical to rb_fiber_scheduler_current_for_thread(), except it expects a threadptr instead of a thre...
VALUE rb_fiber_scheduler_io_wait_writable(VALUE scheduler, VALUE io)
Non-blocking wait until the passed IO is ready for writing.
VALUE rb_fiber_scheduler_io_close(VALUE scheduler, VALUE io)
Non-blocking close the given IO.
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.