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;
196#if EAGAIN != EWOULDBLOCK
197static VALUE rb_eEWOULDBLOCKWaitReadable;
198static VALUE rb_eEWOULDBLOCKWaitWritable;
200static VALUE rb_eEINPROGRESSWaitWritable;
201static VALUE rb_eEINPROGRESSWaitReadable;
204static VALUE orig_stdout, orig_stderr;
213static ID id_write, id_read, id_flush, id_readpartial, id_set_encoding, id_fileno;
214static VALUE sym_mode, sym_perm, sym_flags, sym_extenc, sym_intenc, sym_encoding, sym_open_args;
215static VALUE sym_textmode, sym_binmode, sym_autoclose;
216static VALUE sym_SET, sym_CUR, sym_END;
217static VALUE sym_wait_readable, sym_wait_writable;
219static VALUE sym_DATA;
222static VALUE sym_HOLE;
225static VALUE prep_io(
int fd,
enum rb_io_mode fmode,
VALUE klass,
const char *path);
228rb_io_blocking_region_wait(
struct rb_io *io, rb_blocking_function_t *function,
void *argument,
enum rb_io_event events)
230 return rb_thread_io_blocking_call(io, function, argument, events);
233VALUE rb_io_blocking_region(
struct rb_io *io, rb_blocking_function_t *function,
void *argument)
235 return rb_io_blocking_region_wait(io, function, argument, 0);
239 VALUE filename, current_file;
245 int8_t init_p, next_p, binmode;
256 if (fd < 0 || afd <= max_fd)
259#if defined(HAVE_FCNTL) && defined(F_GETFL)
260 err = fcntl(fd, F_GETFL) == -1;
264 err = fstat(fd, &buf) != 0;
267 if (err &&
errno == EBADF) {
268 rb_bug(
"rb_update_max_fd: invalid fd (%d) given.", fd);
271 while (max_fd < afd) {
272 max_fd = ATOMIC_CAS(max_file_descriptor, max_fd, afd);
277rb_maygvl_fd_fix_cloexec(
int fd)
280#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
281 int flags, flags2, ret;
282 flags = fcntl(fd, F_GETFD);
284 rb_bug(
"rb_maygvl_fd_fix_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(
errno));
287 flags2 = flags & ~FD_CLOEXEC;
289 flags2 = flags | FD_CLOEXEC;
290 if (flags != flags2) {
291 ret = fcntl(fd, F_SETFD, flags2);
293 rb_bug(
"rb_maygvl_fd_fix_cloexec: fcntl(%d, F_SETFD, %d) failed: %s", fd, flags2, strerror(
errno));
302 rb_maygvl_fd_fix_cloexec(fd);
308rb_fix_detect_o_cloexec(
int fd)
310#if defined(O_CLOEXEC) && defined(F_GETFD)
311 int flags = fcntl(fd, F_GETFD);
314 rb_bug(
"rb_fix_detect_o_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(
errno));
316 if (flags & FD_CLOEXEC)
319 rb_maygvl_fd_fix_cloexec(fd);
326 return (e == EWOULDBLOCK) || (e == EAGAIN);
333 static int o_cloexec_state = -1;
335 static const int retry_interval = 0;
336 static const int retry_max_count = 10000;
343#elif defined O_NOINHERIT
344 flags |= O_NOINHERIT;
347 while ((ret = open(pathname, flags, mode)) == -1) {
349 if (!io_again_p(e))
break;
350 if (retry_count++ >= retry_max_count)
break;
352 sleep(retry_interval);
355 if (ret < 0)
return ret;
356 if (ret <= 2 || o_cloexec_state == 0) {
357 rb_maygvl_fd_fix_cloexec(ret);
359 else if (o_cloexec_state > 0) {
363 o_cloexec_state = rb_fix_detect_o_cloexec(ret);
382 if (oldfd == newfd) {
386#if defined(HAVE_DUP3) && defined(O_CLOEXEC)
387 static int try_dup3 = 1;
388 if (2 < newfd && try_dup3) {
389 ret = dup3(oldfd, newfd, O_CLOEXEC);
393 if (
errno == ENOSYS) {
395 ret = dup2(oldfd, newfd);
399 ret = dup2(oldfd, newfd);
402 ret = dup2(oldfd, newfd);
404 if (ret < 0)
return ret;
406 rb_maygvl_fd_fix_cloexec(ret);
411rb_fd_set_nonblock(
int fd)
414 return rb_w32_set_nonblock(fd);
415#elif defined(F_GETFL)
416 int oflags = fcntl(fd, F_GETFL);
420 if (oflags & O_NONBLOCK)
422 oflags |= O_NONBLOCK;
423 return fcntl(fd, F_SETFL, oflags);
432 int result = pipe2(descriptors, O_CLOEXEC | O_NONBLOCK);
434 int result = pipe(descriptors);
441 if (result == 0 && descriptors[1] == -1) {
442 close(descriptors[0]);
450 rb_maygvl_fd_fix_cloexec(descriptors[0]);
451 rb_maygvl_fd_fix_cloexec(descriptors[1]);
454 rb_fd_set_nonblock(descriptors[0]);
455 rb_fd_set_nonblock(descriptors[1]);
467#if defined(HAVE_FCNTL) && defined(F_DUPFD_CLOEXEC) && defined(F_DUPFD)
468 static int try_dupfd_cloexec = 1;
469 if (try_dupfd_cloexec) {
470 ret = fcntl(fd, F_DUPFD_CLOEXEC, minfd);
473 rb_maygvl_fd_fix_cloexec(ret);
477 if (
errno == EINVAL) {
478 ret = fcntl(fd, F_DUPFD, minfd);
480 try_dupfd_cloexec = 0;
485 ret = fcntl(fd, F_DUPFD, minfd);
487#elif defined(HAVE_FCNTL) && defined(F_DUPFD)
488 ret = fcntl(fd, F_DUPFD, minfd);
491 if (ret >= 0 && ret < minfd) {
492 const int prev_fd = ret;
498 if (ret < 0)
return ret;
499 rb_maygvl_fd_fix_cloexec(ret);
503#define argf_of(obj) (*(struct argf *)DATA_PTR(obj))
504#define ARGF argf_of(argf)
505#define ARGF_SET(field, value) RB_OBJ_WRITE(argf, &ARGF.field, value)
507#define GetWriteIO(io) rb_io_get_write_io(io)
509#define READ_DATA_PENDING(fptr) ((fptr)->rbuf.len)
510#define READ_DATA_PENDING_COUNT(fptr) ((fptr)->rbuf.len)
511#define READ_DATA_PENDING_PTR(fptr) ((fptr)->rbuf.ptr+(fptr)->rbuf.off)
512#define READ_DATA_BUFFERED(fptr) READ_DATA_PENDING(fptr)
514#define READ_CHAR_PENDING(fptr) ((fptr)->cbuf.len)
515#define READ_CHAR_PENDING_COUNT(fptr) ((fptr)->cbuf.len)
516#define READ_CHAR_PENDING_PTR(fptr) ((fptr)->cbuf.ptr+(fptr)->cbuf.off)
519#define WAIT_FD_IN_WIN32(fptr) \
520 (rb_w32_io_cancelable_p((fptr)->fd) ? Qnil : rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_READABLE), RUBY_IO_TIMEOUT_DEFAULT))
522#define WAIT_FD_IN_WIN32(fptr)
525#define READ_CHECK(fptr) do {\
526 if (!READ_DATA_PENDING(fptr)) {\
527 WAIT_FD_IN_WIN32(fptr);\
528 rb_io_check_closed(fptr);\
534# define S_ISSOCK(m) _S_ISSOCK(m)
537# define S_ISSOCK(m) (((m) & S_IFMT) == _S_IFSOCK)
540# define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
546static int io_fflush(
rb_io_t *);
547static rb_io_t *flush_before_seek(
rb_io_t *fptr,
bool discard_rbuf);
548static void clear_readconv(
rb_io_t *fptr);
549static void clear_codeconv(
rb_io_t *fptr);
551#define FMODE_SIGNAL_ON_EPIPE (1<<17)
553#define fptr_signal_on_epipe(fptr) \
554 (((fptr)->mode & FMODE_SIGNAL_ON_EPIPE) != 0)
556#define fptr_set_signal_on_epipe(fptr, flag) \
558 (fptr)->mode |= FMODE_SIGNAL_ON_EPIPE : \
559 (fptr)->mode &= ~FMODE_SIGNAL_ON_EPIPE)
561extern ID ruby_static_id_signo;
563NORETURN(
static void rb_sys_fail_on_write(
rb_io_t *fptr));
565rb_sys_fail_on_write(
rb_io_t *fptr)
568 VALUE errinfo = rb_syserr_new_path(e, (fptr)->pathv);
570 if (fptr_signal_on_epipe(fptr) && (e == EPIPE)) {
582#define NEED_NEWLINE_DECORATOR_ON_READ(fptr) ((fptr)->mode & FMODE_TEXTMODE)
583#define NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) ((fptr)->mode & FMODE_TEXTMODE)
584#if defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32)
585# define RUBY_CRLF_ENVIRONMENT 1
587# define RUBY_CRLF_ENVIRONMENT 0
590#if RUBY_CRLF_ENVIRONMENT
592# define DEFAULT_TEXTMODE FMODE_TEXTMODE
593# define TEXTMODE_NEWLINE_DECORATOR_ON_WRITE ECONV_CRLF_NEWLINE_DECORATOR
601#define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || (fptr)->encs.ecflags & ~ECONV_CRLF_NEWLINE_DECORATOR)
602#define WRITECONV_MASK ( \
603 (ECONV_DECORATOR_MASK & ~ECONV_CRLF_NEWLINE_DECORATOR)|\
604 ECONV_STATEFUL_DECORATOR_MASK|\
606#define NEED_WRITECONV(fptr) ( \
607 ((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || \
608 ((fptr)->encs.ecflags & WRITECONV_MASK) || \
610#define SET_BINARY_MODE(fptr) setmode((fptr)->fd, O_BINARY)
612#define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) do {\
613 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {\
614 if (((fptr)->mode & FMODE_READABLE) &&\
615 !((fptr)->encs.ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {\
616 setmode((fptr)->fd, O_BINARY);\
619 setmode((fptr)->fd, O_TEXT);\
624#define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) do {\
625 if ((enc2) && ((ecflags) & ECONV_DEFAULT_NEWLINE_DECORATOR)) {\
626 (ecflags) |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;\
634io_unread(
rb_io_t *fptr,
bool discard_rbuf)
650 if (!rb_w32_fd_is_text(fptr->
fd)) {
651 r = lseek(fptr->
fd, -fptr->
rbuf.
len, SEEK_CUR);
652 if (r < 0 &&
errno) {
655 if (!discard_rbuf)
return;
661 pos = lseek(fptr->
fd, 0, SEEK_CUR);
662 if (pos < 0 &&
errno) {
665 if (!discard_rbuf)
goto end;
669 extra_max = (long)(pos - fptr->
rbuf.
len);
677 for (i = 0; i < fptr->
rbuf.
len; i++) {
678 if (*p ==
'\n') newlines++;
679 if (extra_max == newlines)
break;
684 while (newlines >= 0) {
685 r = lseek(fptr->
fd, pos - fptr->
rbuf.
len - newlines, SEEK_SET);
686 if (newlines == 0)
break;
691 read_size = _read(fptr->
fd, buf, fptr->
rbuf.
len + newlines);
695 rb_syserr_fail_path(e, fptr->
pathv);
697 if (read_size == fptr->
rbuf.
len) {
698 lseek(fptr->
fd, r, SEEK_SET);
709 clear_codeconv(fptr);
721set_binary_mode_with_seek_cur(
rb_io_t *fptr)
723 if (!rb_w32_fd_is_text(fptr->
fd))
return O_BINARY;
726 return setmode(fptr->
fd, O_BINARY);
728 flush_before_seek(fptr,
false);
729 return setmode(fptr->
fd, O_BINARY);
731#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) set_binary_mode_with_seek_cur(fptr)
735# define DEFAULT_TEXTMODE 0
736#define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || NEED_NEWLINE_DECORATOR_ON_READ(fptr))
737#define NEED_WRITECONV(fptr) ( \
738 ((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || \
739 NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) || \
740 ((fptr)->encs.ecflags & (ECONV_DECORATOR_MASK|ECONV_STATEFUL_DECORATOR_MASK)) || \
742#define SET_BINARY_MODE(fptr) (void)(fptr)
743#define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) (void)(fptr)
744#define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) ((void)(enc2), (void)(ecflags))
745#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) (void)(fptr)
748#if !defined HAVE_SHUTDOWN && !defined shutdown
749#define shutdown(a,b) 0
753#define is_socket(fd, path) rb_w32_is_socket(fd)
754#elif !defined(S_ISSOCK)
755#define is_socket(fd, path) 0
758is_socket(
int fd,
VALUE path)
761 if (fstat(fd, &sbuf) < 0)
762 rb_sys_fail_path(path);
763 return S_ISSOCK(sbuf.st_mode);
767static const char closed_stream[] =
"closed stream";
770io_fd_check_closed(
int fd)
803 io_fd_check_closed(fptr->
fd);
807rb_io_get_fptr(
VALUE io)
817 return rb_convert_type_with_id(io,
T_FILE,
"IO", idTo_io);
823 return rb_check_convert_type_with_id(io,
T_FILE,
"IO", idTo_io);
841 rb_io_t *fptr = rb_io_get_fptr(io);
850 return write_io ? write_io :
Qnil;
863 rb_io_t *fptr = rb_io_get_fptr(self);
893 if (
RTEST(timeout)) {
897 rb_io_t *fptr = rb_io_get_fptr(self);
922#if !RUBY_CRLF_ENVIRONMENT
924io_unread(
rb_io_t *fptr,
bool discard_rbuf)
932 r = lseek(fptr->
fd, -fptr->
rbuf.
len, SEEK_CUR);
933 if (r < 0 &&
errno) {
936 if (!discard_rbuf)
return;
940 clear_codeconv(fptr);
950 long len = RSTRING_LEN(str);
953 const int min_capa = IO_RBUF_CAPA_FOR(fptr);
956#if SIZEOF_LONG > SIZEOF_INT
981flush_before_seek(
rb_io_t *fptr,
bool discard_rbuf)
983 if (io_fflush(fptr) < 0)
984 rb_sys_fail_on_write(fptr);
985 io_unread(fptr, discard_rbuf);
990#define io_seek(fptr, ofs, whence) (errno = 0, lseek(flush_before_seek(fptr, true)->fd, (ofs), (whence)))
991#define io_tell(fptr) lseek(flush_before_seek(fptr, false)->fd, 0, SEEK_CUR)
1007 if (io_fflush(fptr) < 0)
1008 rb_sys_fail_on_write(fptr);
1013 if (io_fflush(wfptr) < 0)
1014 rb_sys_fail_on_write(wfptr);
1022 if (READ_CHAR_PENDING(fptr)) {
1023 rb_raise(
rb_eIOError,
"byte oriented read for character buffered IO");
1034io_read_encoding(
rb_io_t *fptr)
1039 return rb_default_external_encoding();
1043io_input_encoding(
rb_io_t *fptr)
1048 return io_read_encoding(fptr);
1059 io_unread(fptr,
true);
1064rb_io_read_pending(
rb_io_t *fptr)
1067 if (READ_CHAR_PENDING(fptr))
1069 return READ_DATA_PENDING(fptr);
1075 if (!READ_DATA_PENDING(fptr)) {
1082rb_gc_for_fd(
int err)
1084 if (err == EMFILE || err == ENFILE || err == ENOMEM) {
1094#define TRY_WITH_GC(expr) \
1095 for (int first_errno, retried_errno = 0, retried = 0; \
1098 (!rb_gc_for_fd(first_errno = errno) || !(expr)) && \
1099 (retried_errno = errno, 1)); \
1100 (void)retried_errno, retried = 1)
1115io_alloc(
VALUE klass)
1117 UNPROTECTED_NEWOBJ_OF(io,
struct RFile, klass,
T_FILE,
sizeof(
struct RFile));
1125# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
1151struct io_internal_writev_struct {
1158 const struct iovec *iov;
1171io_internal_wait(
VALUE thread,
rb_io_t *fptr,
int error,
int events,
struct timeval *timeout)
1173 if (!timeout && rb_thread_mn_schedulable(thread)) {
1178 int ready = nogvl_wait_for(thread, fptr, events, timeout);
1183 else if (ready == 0) {
1200internal_read_func(
void *ptr)
1205 if (iis->timeout && !iis->nonblock) {
1206 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_IN, iis->timeout) == -1) {
1212 result = read(iis->fd, iis->buf, iis->capa);
1214 if (result < 0 && !iis->nonblock) {
1215 if (io_again_p(
errno)) {
1216 if (io_internal_wait(iis->th, iis->fptr,
errno, RB_WAITFD_IN, iis->timeout) == -1) {
1228#if defined __APPLE__
1229# define do_write_retry(code) do {result = code;} while (result == -1 && errno == EPROTOTYPE)
1231# define do_write_retry(code) result = code
1235internal_write_func(
void *ptr)
1240 if (iis->timeout && !iis->nonblock) {
1241 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1247 do_write_retry(write(iis->fd, iis->buf, iis->capa));
1249 if (result < 0 && !iis->nonblock) {
1251 if (io_again_p(e)) {
1252 if (io_internal_wait(iis->th, iis->fptr,
errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1266internal_writev_func(
void *ptr)
1268 struct io_internal_writev_struct *iis = ptr;
1271 if (iis->timeout && !iis->nonblock) {
1272 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1278 do_write_retry(writev(iis->fd, iis->iov, iis->iovcnt));
1280 if (result < 0 && !iis->nonblock) {
1281 if (io_again_p(
errno)) {
1282 if (io_internal_wait(iis->th, iis->fptr,
errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1296rb_io_read_memory(
rb_io_t *fptr,
void *buf,
size_t count)
1300 if (scheduler !=
Qnil) {
1303 if (!UNDEF_P(result)) {
1319 struct timeval timeout_storage;
1323 iis.timeout = &timeout_storage;
1326 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_read_func, &iis,
RUBY_IO_READABLE);
1330rb_io_write_memory(
rb_io_t *fptr,
const void *buf,
size_t count)
1334 if (scheduler !=
Qnil) {
1337 if (!UNDEF_P(result)) {
1353 struct timeval timeout_storage;
1357 iis.timeout = &timeout_storage;
1360 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_write_func, &iis,
RUBY_IO_WRITABLE);
1365rb_writev_internal(
rb_io_t *fptr,
const struct iovec *iov,
int iovcnt)
1367 if (!iovcnt)
return 0;
1372 if (scheduler !=
Qnil) {
1376 if (!UNDEF_P(result)) {
1381 struct io_internal_writev_struct iis = {
1392 struct timeval timeout_storage;
1396 iis.timeout = &timeout_storage;
1399 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_writev_func, &iis,
RUBY_IO_WRITABLE);
1404io_flush_buffer_sync(
void *arg)
1426io_flush_buffer_fiber_scheduler(
VALUE scheduler,
rb_io_t *fptr)
1429 if (!UNDEF_P(ret)) {
1441io_flush_buffer_async(
VALUE arg)
1446 if (scheduler !=
Qnil) {
1447 VALUE result = io_flush_buffer_fiber_scheduler(scheduler, fptr);
1448 if (!UNDEF_P(result)) {
1453 return rb_io_blocking_region_wait(fptr, io_flush_buffer_sync, fptr,
RUBY_IO_WRITABLE);
1460 return (
int)io_flush_buffer_async((
VALUE)fptr);
1475 while (fptr->
wbuf.
len > 0 && io_flush_buffer(fptr) != 0) {
1491 if (scheduler !=
Qnil) {
1501 if (NIL_OR_UNDEF_P(timeout)) {
1505 if (timeout !=
Qnil) {
1510 int ready = rb_thread_io_wait(th, fptr,
RB_NUM2INT(events), tv);
1536 if (scheduler !=
Qnil) {
1542 return rb_thread_wait_for_single_fd(th, fd, events, timeout);
1548 io_fd_check_closed(f);
1555#if defined(ERESTART)
1562#if EWOULDBLOCK != EAGAIN
1565 if (scheduler !=
Qnil) {
1583 io_fd_check_closed(f);
1590#if defined(ERESTART)
1606#if EWOULDBLOCK != EAGAIN
1609 if (scheduler !=
Qnil) {
1629 return io_wait_for_single_fd(fd, events, timeout, th, scheduler);
1663#if defined(ERESTART)
1673#if EWOULDBLOCK != EAGAIN
1690 if (
RTEST(result)) {
1705 if (
RTEST(result)) {
1719 const char *senc, *denc;
1726 ecflags = fptr->
encs.
ecflags & ~ECONV_NEWLINE_DECORATOR_READ_MASK;
1753 denc = rb_enc_name(enc);
1785io_binwrite_string_internal(
rb_io_t *fptr,
const char *ptr,
long length)
1788 struct iovec iov[2];
1791 iov[0].iov_len = fptr->
wbuf.
len;
1792 iov[1].iov_base = (
void*)ptr;
1793 iov[1].iov_len = length;
1795 ssize_t result = rb_writev_internal(fptr, iov, 2);
1800 if (result >= fptr->
wbuf.
len) {
1808 fptr->
wbuf.
off += (int)result;
1809 fptr->
wbuf.
len -= (int)result;
1817 return rb_io_write_memory(fptr, ptr, length);
1822io_binwrite_string_internal(
rb_io_t *fptr,
const char *ptr,
long length)
1824 long remaining = length;
1827 if (fptr->
wbuf.
len+length <= fptr->wbuf.capa) {
1834 fptr->
wbuf.
len += (int)length;
1841 if (io_fflush(fptr) < 0) {
1846 if (remaining == 0) {
1852 return rb_io_write_memory(fptr, ptr, length);
1857io_binwrite_string(
VALUE arg)
1861 const char *ptr = p->ptr;
1862 size_t remaining = p->length;
1866 ssize_t result = io_binwrite_string_internal(p->fptr, ptr, remaining);
1872 else if (result > 0) {
1873 if ((
size_t)result == remaining)
break;
1875 remaining -= result;
1891io_allocate_write_buffer(
rb_io_t *fptr,
int sync)
1896 fptr->
wbuf.
capa = IO_WBUF_CAPA_MIN;
1907io_binwrite_requires_flush_write(
rb_io_t *fptr,
long len,
int nosync)
1922io_binwrite(
const char *ptr,
long len,
rb_io_t *fptr,
int nosync)
1924 if (
len <= 0)
return len;
1929 io_allocate_write_buffer(fptr, !nosync);
1931 if (io_binwrite_requires_flush_write(fptr,
len, nosync)) {
1942 return io_binwrite_string((
VALUE)&arg);
1959# define MODE_BTMODE(a,b,c) ((fmode & FMODE_BINMODE) ? (b) : \
1960 (fmode & FMODE_TEXTMODE) ? (c) : (a))
1962#define MODE_BTXMODE(a, b, c, d, e, f) ((fmode & FMODE_EXCL) ? \
1963 MODE_BTMODE(d, e, f) : \
1964 MODE_BTMODE(a, b, c))
1969 if (NEED_WRITECONV(fptr)) {
1971 SET_BINARY_MODE(fptr);
1973 make_writeconv(fptr);
1976#define fmode (fptr->mode)
1979 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1) && !rb_enc_asciicompat(rb_enc_get(str))) {
1980 rb_raise(rb_eArgError,
"ASCII incompatible string written for text mode IO without encoding conversion: %s",
1981 rb_enc_name(rb_enc_get(str)));
1987 common_encoding = rb_enc_from_encoding(fptr->
encs.
enc2);
1988 else if (fptr->
encs.
enc != rb_ascii8bit_encoding())
1989 common_encoding = rb_enc_from_encoding(fptr->
encs.
enc);
1992 if (!
NIL_P(common_encoding)) {
2003#if RUBY_CRLF_ENVIRONMENT
2004#define fmode (fptr->mode)
2005 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1)) {
2008 setmode(fptr->
fd, O_BINARY);
2011 setmode(fptr->
fd, O_TEXT);
2013 if (!rb_enc_asciicompat(rb_enc_get(str))) {
2014 rb_raise(rb_eArgError,
"ASCII incompatible string written for text mode IO without encoding conversion: %s",
2015 rb_enc_name(rb_enc_get(str)));
2033 long len = rb_w32_write_console(str, fptr->
fd);
2038 str = do_writeconv(str, fptr, &converted);
2042 tmp = rb_str_tmp_frozen_no_embed_acquire(str);
2044 n = io_binwrite(ptr,
len, fptr, nosync);
2045 rb_str_tmp_frozen_release(str, tmp);
2057 return (ssize_t)io_binwrite(buf, (
long)size, fptr, 0);
2067 io = GetWriteIO(io);
2077 if (RSTRING_LEN(str) == 0)
return INT2FIX(0);
2082 n = io_fwrite(str, fptr, nosync);
2083 if (n < 0L) rb_sys_fail_on_write(fptr);
2089struct binwritev_arg {
2097io_binwritev_internal(
VALUE arg)
2099 struct binwritev_arg *p = (
struct binwritev_arg *)arg;
2101 size_t remaining = p->total;
2105 struct iovec *iov = p->iov;
2106 int iovcnt = p->iovcnt;
2109 long result = rb_writev_internal(fptr, iov, iovcnt);
2114 if (offset < (
size_t)fptr->
wbuf.
len) {
2119 offset -= (size_t)fptr->
wbuf.
len;
2125 if (offset == p->total) {
2129 while (result >= (ssize_t)iov->iov_len) {
2131 result -= iov->iov_len;
2141 iov->iov_base = (
char *)iov->iov_base + result;
2142 iov->iov_len -= result;
2156io_binwritev(
struct iovec *iov,
int iovcnt,
rb_io_t *fptr)
2161 if (iovcnt == 0)
return 0;
2164 for (
int i = 1; i < iovcnt; i++) total += iov[i].iov_len;
2166 io_allocate_write_buffer(fptr, 1);
2172 if (offset + total <= (
size_t)fptr->
wbuf.
capa) {
2173 for (
int i = 1; i < iovcnt; i++) {
2174 memcpy(fptr->
wbuf.
ptr+offset, iov[i].iov_base, iov[i].iov_len);
2175 offset += iov[i].iov_len;
2184 iov[0].iov_len = fptr->
wbuf.
len;
2197 struct binwritev_arg arg;
2200 arg.iovcnt = iovcnt;
2207 return io_binwritev_internal((
VALUE)&arg);
2214 int i, converted, iovcnt = argc + 1;
2216 VALUE v1, v2, str, tmp, *tmp_array;
2222 for (i = 0; i < argc; i++) {
2225 str = do_writeconv(str, fptr, &converted);
2230 tmp = rb_str_tmp_frozen_acquire(str);
2234 iov[i+1].iov_base = RSTRING_PTR(tmp);
2235 iov[i+1].iov_len = RSTRING_LEN(tmp);
2238 n = io_binwritev(iov, iovcnt, fptr);
2241 for (i = 0; i < argc; i++) {
2242 rb_str_tmp_frozen_release(argv[i], tmp_array[i]);
2251iovcnt_ok(
int iovcnt)
2254 return iovcnt < IOV_MAX;
2262io_writev(
int argc,
const VALUE *argv,
VALUE io)
2269 io = GetWriteIO(io);
2282 for (i = 0; i < argc; i += cnt) {
2285 n = io_fwritev(cnt, &argv[i], fptr);
2296 rb_sys_fail_on_write(fptr);
2298 total = rb_fix_plus(
LONG2FIX(n), total);
2329 return io_writev(argc, argv, io);
2332 VALUE str = argv[0];
2333 return io_write(io, str, 0);
2344rb_io_writev(
VALUE io,
int argc,
const VALUE *argv)
2349 char sep = RCLASS_SINGLETON_P(klass) ? (klass = io,
'.') :
'#';
2352 " which accepts just one argument",
2357 do rb_io_write(io, *argv++);
while (--argc);
2388 rb_io_write(io, str);
2394nogvl_fsync(
void *ptr)
2399 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->
fd)) != FILE_TYPE_DISK)
2402 return (
VALUE)fsync(fptr->
fd);
2407rb_io_flush_raw(
VALUE io,
int sync)
2415 io = GetWriteIO(io);
2419 if (io_fflush(fptr) < 0)
2420 rb_sys_fail_on_write(fptr);
2423 io_unread(fptr,
true);
2444 return rb_io_flush_raw(io, 1);
2470 pos = io_tell(fptr);
2471 if (pos < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
2477rb_io_seek(
VALUE io,
VALUE offset,
int whence)
2484 pos = io_seek(fptr, pos, whence);
2485 if (pos < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
2486 if (fptr->
readconv) clear_readconv(fptr);
2492interpret_seek_whence(
VALUE vwhence)
2494 if (vwhence == sym_SET)
2496 if (vwhence == sym_CUR)
2498 if (vwhence == sym_END)
2501 if (vwhence == sym_DATA)
2505 if (vwhence == sym_HOLE)
2561 VALUE offset, ptrname;
2562 int whence = SEEK_SET;
2564 if (
rb_scan_args(argc, argv,
"11", &offset, &ptrname) == 2) {
2565 whence = interpret_seek_whence(ptrname);
2568 return rb_io_seek(io, offset, whence);
2596 pos = io_seek(fptr, pos, SEEK_SET);
2597 if (pos < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
2598 if (fptr->
readconv) clear_readconv(fptr);
2628rb_io_rewind(
VALUE io)
2633 if (io_seek(fptr, 0L, 0) < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
2634 if (io == ARGF.current_file) {
2635 ARGF.lineno -= fptr->
lineno;
2639 clear_readconv(fptr);
2646fptr_wait_readable(
rb_io_t *fptr)
2664 fptr->
rbuf.
capa = IO_RBUF_CAPA_FOR(fptr);
2672 if (fptr_wait_readable(fptr))
2676 VALUE path = rb_sprintf(
"fd:%d ", fptr->
fd);
2681 rb_syserr_fail_path(e, path);
2735 if (READ_CHAR_PENDING(fptr))
return Qfalse;
2736 if (READ_DATA_PENDING(fptr))
return Qfalse;
2738#if RUBY_CRLF_ENVIRONMENT
2739 if (!NEED_READCONV(fptr) && NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
2740 return RBOOL(eof(fptr->
fd));
2743 return RBOOL(io_fillbuf(fptr) < 0);
2767 io = GetWriteIO(io);
2804 io = GetWriteIO(io);
2810 fptr->
mode &= ~FMODE_SYNC;
2834rb_io_fsync(
VALUE io)
2838 io = GetWriteIO(io);
2841 if (io_fflush(fptr) < 0)
2842 rb_sys_fail_on_write(fptr);
2844 if ((
int)rb_io_blocking_region(fptr, nogvl_fsync, fptr))
2845 rb_sys_fail_path(fptr->
pathv);
2850# define rb_io_fsync rb_f_notimplement
2851# define rb_io_sync rb_f_notimplement
2860#ifdef HAVE_FDATASYNC
2862nogvl_fdatasync(
void *ptr)
2867 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->
fd)) != FILE_TYPE_DISK)
2870 return (
VALUE)fdatasync(fptr->
fd);
2885rb_io_fdatasync(
VALUE io)
2889 io = GetWriteIO(io);
2892 if (io_fflush(fptr) < 0)
2893 rb_sys_fail_on_write(fptr);
2895 if ((
int)rb_io_blocking_region(fptr, nogvl_fdatasync, fptr) == 0)
2899 return rb_io_fsync(io);
2902#define rb_io_fdatasync rb_io_fsync
2920rb_io_fileno(
VALUE io)
2940 if (!UNDEF_P(fileno)) {
3028rb_io_inspect(
VALUE obj)
3032 static const char closed[] =
" (closed)";
3034 fptr =
RFILE(obj)->fptr;
3041 rb_str_cat(result, closed+1, strlen(closed)-1);
3044 rb_str_catf(result,
"fd %d", fptr->
fd);
3065rb_io_to_io(
VALUE io)
3072read_buffered_data(
char *ptr,
long len,
rb_io_t *fptr)
3076 n = READ_DATA_PENDING_COUNT(fptr);
3077 if (n <= 0)
return 0;
3078 if (n >
len) n = (int)
len;
3086io_bufread(
char *ptr,
long len,
rb_io_t *fptr)
3092 if (READ_DATA_PENDING(fptr) == 0) {
3096 c = rb_io_read_memory(fptr, ptr+offset, n);
3099 if (fptr_wait_readable(fptr))
3104 if ((n -= c) <= 0)
break;
3110 c = read_buffered_data(ptr+offset, n, fptr);
3113 if ((n -= c) <= 0)
break;
3116 if (io_fillbuf(fptr) < 0) {
3123static int io_setstrbuf(
VALUE *str,
long len);
3132bufread_call(
VALUE arg)
3135 p->len = io_bufread(p->str_ptr, p->len, p->fptr);
3140io_fread(
VALUE str,
long offset,
long size,
rb_io_t *fptr)
3145 io_setstrbuf(&str, offset + size);
3146 arg.str_ptr = RSTRING_PTR(str) + offset;
3149 rb_str_locktmp_ensure(str, bufread_call, (
VALUE)&arg);
3151 if (
len < 0) rb_sys_fail_path(fptr->
pathv);
3159 rb_off_t siz = READ_DATA_PENDING_COUNT(fptr);
3162 if (fstat(fptr->
fd, &st) == 0 && S_ISREG(st.st_mode)
3163#
if defined(__HAIKU__)
3168 if (io_fflush(fptr) < 0)
3169 rb_sys_fail_on_write(fptr);
3170 pos = lseek(fptr->
fd, 0, SEEK_CUR);
3171 if (st.st_size >= pos && pos >= 0) {
3172 siz += st.st_size - pos;
3173 if (siz > LONG_MAX) {
3174 rb_raise(
rb_eIOError,
"file too big for single read");
3187 rb_enc_associate(str, io_read_encoding(fptr));
3192make_readconv(
rb_io_t *fptr,
int size)
3197 const char *sname, *dname;
3198 ecflags = fptr->
encs.
ecflags & ~ECONV_NEWLINE_DECORATOR_WRITE_MASK;
3201 sname = rb_enc_name(fptr->
encs.
enc2);
3202 dname = rb_enc_name(io_read_encoding(fptr));
3212 if (size < IO_CBUF_CAPA_MIN) size = IO_CBUF_CAPA_MIN;
3218#define MORE_CHAR_SUSPENDED Qtrue
3219#define MORE_CHAR_FINISHED Qnil
3221fill_cbuf(
rb_io_t *fptr,
int ec_flags)
3223 const unsigned char *ss, *sp, *se;
3224 unsigned char *ds, *dp, *de;
3233 return MORE_CHAR_SUSPENDED;
3244 ss = sp = (
const unsigned char *)fptr->
rbuf.
ptr + fptr->
rbuf.
off;
3249 fptr->
rbuf.
off += (int)(sp - ss);
3250 fptr->
rbuf.
len -= (int)(sp - ss);
3251 fptr->
cbuf.
len += (int)(dp - ds);
3256 fptr->
rbuf.
off -= putbackable;
3257 fptr->
rbuf.
len += putbackable;
3264 if (cbuf_len0 != fptr->
cbuf.
len)
3265 return MORE_CHAR_SUSPENDED;
3268 return MORE_CHAR_FINISHED;
3274 if (io_fillbuf(fptr) < 0) {
3276 return MORE_CHAR_FINISHED;
3281 fptr->
cbuf.
len += (int)(dp - ds);
3288 if (cbuf_len0 != fptr->
cbuf.
len)
3289 return MORE_CHAR_SUSPENDED;
3291 return MORE_CHAR_FINISHED;
3299 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED)
3316 rb_enc_associate(str, fptr->
encs.
enc);
3341 long clen = RSTRING_LEN(s);
3353#define MAX_REALLOC_GAP 4096
3355io_shrink_read_string(
VALUE str,
long n)
3358 rb_str_resize(str, n);
3363io_set_read_length(
VALUE str,
long n,
int shrinkable)
3365 if (RSTRING_LEN(str) != n) {
3368 if (shrinkable) io_shrink_read_string(str, n);
3382 if (NEED_READCONV(fptr)) {
3383 int first = !
NIL_P(str);
3384 SET_BINARY_MODE(fptr);
3385 shrinkable = io_setstrbuf(&str,0);
3386 make_readconv(fptr, 0);
3391 io_shift_cbuf(fptr, fptr->
cbuf.
len, &str);
3393 v = fill_cbuf(fptr, 0);
3394 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED) {
3397 io_shift_cbuf(fptr, fptr->
cbuf.
len, &str);
3401 if (v == MORE_CHAR_FINISHED) {
3402 clear_readconv(fptr);
3404 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3405 return io_enc_str(str, fptr);
3410 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3414 enc = io_read_encoding(fptr);
3427 shrinkable = io_setstrbuf(&str, siz);
3430 n = io_fread(str, bytes, siz - bytes, fptr);
3431 if (n == 0 && bytes == 0) {
3439 if (bytes < siz)
break;
3443 if (
capa < (
size_t)RSTRING_LEN(str) + BUFSIZ) {
3444 if (
capa < BUFSIZ) {
3447 else if (
capa > IO_MAX_BUFFER_GROWTH) {
3448 capa = IO_MAX_BUFFER_GROWTH;
3453 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3454 str = io_enc_str(str, fptr);
3462 if (rb_fd_set_nonblock(fptr->
fd) != 0) {
3463 rb_sys_fail_path(fptr->
pathv);
3468io_read_memory_call(
VALUE arg)
3473 if (scheduler !=
Qnil) {
3476 if (!UNDEF_P(result)) {
3482 if (iis->nonblock) {
3483 return rb_io_blocking_region(iis->fptr, internal_read_func, iis);
3486 return rb_io_blocking_region_wait(iis->fptr, internal_read_func, iis,
RUBY_IO_READABLE);
3493 return (
long)rb_str_locktmp_ensure(str, io_read_memory_call, (
VALUE)iis);
3496#define no_exception_p(opts) !rb_opts_exception_p((opts), TRUE)
3499io_getpartial(
int argc,
VALUE *argv,
VALUE io,
int no_exception,
int nonblock)
3510 rb_raise(rb_eArgError,
"negative length %ld given",
len);
3513 shrinkable = io_setstrbuf(&str,
len);
3519 io_set_read_length(str, 0, shrinkable);
3525 n = read_buffered_data(RSTRING_PTR(str),
len, fptr);
3531 io_setstrbuf(&str,
len);
3534 iis.nonblock = nonblock;
3536 iis.buf = RSTRING_PTR(str);
3539 n = io_read_memory_locktmp(str, &iis);
3542 if (!nonblock && fptr_wait_readable(fptr))
3544 if (nonblock && (io_again_p(e))) {
3546 return sym_wait_readable;
3549 e,
"read would block");
3551 rb_syserr_fail_path(e, fptr->
pathv);
3554 io_set_read_length(str, n, shrinkable);
3655io_readpartial(
int argc,
VALUE *argv,
VALUE io)
3659 ret = io_getpartial(argc, argv, io,
Qnil, 0);
3666io_nonblock_eof(
int no_exception)
3668 if (!no_exception) {
3684 rb_raise(rb_eArgError,
"negative length %ld given",
len);
3687 shrinkable = io_setstrbuf(&str,
len);
3688 rb_bool_expected(ex,
"exception", TRUE);
3694 io_set_read_length(str, 0, shrinkable);
3698 n = read_buffered_data(RSTRING_PTR(str),
len, fptr);
3700 rb_fd_set_nonblock(fptr->
fd);
3701 shrinkable |= io_setstrbuf(&str,
len);
3705 iis.buf = RSTRING_PTR(str);
3708 n = io_read_memory_locktmp(str, &iis);
3711 if (io_again_p(e)) {
3712 if (!ex)
return sym_wait_readable;
3714 e,
"read would block");
3716 rb_syserr_fail_path(e, fptr->
pathv);
3719 io_set_read_length(str, n, shrinkable);
3722 if (!ex)
return Qnil;
3738 rb_bool_expected(ex,
"exception", TRUE);
3740 io = GetWriteIO(io);
3744 if (io_fflush(fptr) < 0)
3745 rb_sys_fail_on_write(fptr);
3747 rb_fd_set_nonblock(fptr->
fd);
3748 n = write(fptr->
fd, RSTRING_PTR(str), RSTRING_LEN(str));
3753 if (io_again_p(e)) {
3755 return sym_wait_writable;
3761 rb_syserr_fail_path(e, fptr->
pathv);
3845#if RUBY_CRLF_ENVIRONMENT
3851 if (
NIL_P(length)) {
3854 return read_all(fptr, remain_size(fptr), str);
3858 rb_raise(rb_eArgError,
"negative length %ld given",
len);
3861 shrinkable = io_setstrbuf(&str,
len);
3866 io_set_read_length(str, 0, shrinkable);
3871#if RUBY_CRLF_ENVIRONMENT
3872 previous_mode = set_binary_mode_with_seek_cur(fptr);
3874 n = io_fread(str, 0,
len, fptr);
3875 io_set_read_length(str, n, shrinkable);
3876#if RUBY_CRLF_ENVIRONMENT
3877 if (previous_mode == O_TEXT) {
3878 setmode(fptr->
fd, O_TEXT);
3881 if (n == 0)
return Qnil;
3887rscheck(
const char *rsptr,
long rslen,
VALUE rs)
3890 if (RSTRING_PTR(rs) != rsptr && RSTRING_LEN(rs) != rslen)
3895search_delim(
const char *p,
long len,
int delim,
rb_encoding *enc)
3897 if (rb_enc_mbminlen(enc) == 1) {
3898 p = memchr(p, delim,
len);
3899 if (p)
return p + 1;
3902 const char *end = p +
len;
3904 int r = rb_enc_precise_mbclen(p, end, enc);
3906 p += rb_enc_mbminlen(enc);
3910 if (rb_enc_mbc_to_codepoint(p, end, enc) == (
unsigned int)delim) {
3925 if (NEED_READCONV(fptr)) {
3926 SET_BINARY_MODE(fptr);
3927 make_readconv(fptr, 0);
3930 int searchlen = READ_CHAR_PENDING_COUNT(fptr);
3932 p = READ_CHAR_PENDING_PTR(fptr);
3933 if (0 < limit && limit < searchlen)
3934 searchlen = (int)limit;
3935 e = search_delim(p, searchlen, delim, enc);
3937 int len = (int)(e-p);
3959 return (
unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
3962 }
while (more_char(fptr) != MORE_CHAR_FINISHED);
3963 clear_readconv(fptr);
3968 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3970 long pending = READ_DATA_PENDING_COUNT(fptr);
3972 const char *p = READ_DATA_PENDING_PTR(fptr);
3976 if (limit > 0 && pending > limit) pending = limit;
3977 e = search_delim(p, pending, delim, enc);
3978 if (e) pending = e - p;
3980 last = RSTRING_LEN(str);
3981 rb_str_resize(str, last + pending);
3988 read_buffered_data(RSTRING_PTR(str) + last, pending, fptr);
3991 if (e)
return delim;
3993 return (
unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
3996 }
while (io_fillbuf(fptr) >= 0);
4002swallow(
rb_io_t *fptr,
int term)
4004 if (NEED_READCONV(fptr)) {
4006 int needconv = rb_enc_mbminlen(enc) != 1;
4007 SET_BINARY_MODE(fptr);
4008 make_readconv(fptr, 0);
4011 while ((cnt = READ_CHAR_PENDING_COUNT(fptr)) > 0) {
4012 const char *p = READ_CHAR_PENDING_PTR(fptr);
4015 if (*p != term)
return TRUE;
4017 while (--i && *++p == term);
4020 const char *e = p + cnt;
4021 if (rb_enc_ascget(p, e, &i, enc) != term)
return TRUE;
4022 while ((p += i) < e && rb_enc_ascget(p, e, &i, enc) == term);
4025 io_shift_cbuf(fptr, (
int)cnt - i, NULL);
4027 }
while (more_char(fptr) != MORE_CHAR_FINISHED);
4031 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4034 while ((cnt = READ_DATA_PENDING_COUNT(fptr)) > 0) {
4036 const char *p = READ_DATA_PENDING_PTR(fptr);
4038 if (cnt >
sizeof buf) cnt =
sizeof buf;
4039 if (*p != term)
return TRUE;
4041 while (--i && *++p == term);
4042 if (!read_buffered_data(buf, cnt - i, fptr))
4043 rb_sys_fail_path(fptr->
pathv);
4046 }
while (io_fillbuf(fptr) == 0);
4059 int pending = READ_DATA_PENDING_COUNT(fptr);
4062 const char *p = READ_DATA_PENDING_PTR(fptr);
4066 e = memchr(p,
'\n', pending);
4068 pending = (int)(e - p + 1);
4070 chomplen = (pending > 1 && *(e-1) ==
'\r') + 1;
4079 rb_str_resize(str,
len + pending - chomplen);
4080 read_buffered_data(RSTRING_PTR(str)+
len, pending - chomplen, fptr);
4083 if (pending == 1 && chomplen == 1 &&
len > 0) {
4084 if (RSTRING_PTR(str)[
len-1] ==
'\r') {
4085 rb_str_resize(str, --
len);
4090 len += pending - chomplen;
4096 }
while (io_fillbuf(fptr) >= 0);
4099 str = io_enc_str(str, fptr);
4110 unsigned int chomp: 1;
4124 chomp = (!UNDEF_P(vchomp)) &&
RTEST(vchomp);
4126 args->chomp = chomp;
4144 else if (2 <= argc) {
4145 rs = argv[0], lim = argv[1];
4154check_getline_args(
VALUE *rsp,
long *limit,
VALUE io)
4163 enc_rs = rb_enc_get(rs);
4164 enc_io = io_read_encoding(fptr);
4165 if (enc_io != enc_rs &&
4166 (!is_ascii_string(rs) ||
4167 (RSTRING_LEN(rs) > 0 && !rb_enc_asciicompat(enc_io)))) {
4168 if (rs == rb_default_rs) {
4169 rs = rb_enc_str_new(0, 0, enc_io);
4174 rb_raise(rb_eArgError,
"encoding mismatch: %s IO with %s RS",
4175 rb_enc_name(enc_io),
4176 rb_enc_name(enc_rs));
4186 argc =
rb_scan_args(argc, argv,
"02:", NULL, NULL, &opts);
4187 extract_getline_args(argc, argv, args);
4188 extract_getline_opts(opts, args);
4189 check_getline_args(&args->rs, &args->limit, io);
4193rb_io_getline_0(
VALUE rs,
long limit,
int chomp,
rb_io_t *fptr)
4200 if (
NIL_P(rs) && limit < 0) {
4201 str = read_all(fptr, 0,
Qnil);
4202 if (RSTRING_LEN(str) == 0)
return Qnil;
4204 else if (limit == 0) {
4205 return rb_enc_str_new(0, 0, io_read_encoding(fptr));
4207 else if (rs == rb_default_rs && limit < 0 && !NEED_READCONV(fptr) &&
4208 rb_enc_asciicompat(enc = io_read_encoding(fptr))) {
4209 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4210 return rb_io_getline_fast(fptr, enc, chomp);
4213 int c, newline = -1;
4214 const char *rsptr = 0;
4217 int extra_limit = 16;
4218 int chomp_cr = chomp;
4220 SET_BINARY_MODE(fptr);
4221 enc = io_read_encoding(fptr);
4224 rslen = RSTRING_LEN(rs);
4229 swallow(fptr,
'\n');
4231 if (!rb_enc_asciicompat(enc)) {
4235 rsptr = RSTRING_PTR(rs);
4236 rslen = RSTRING_LEN(rs);
4240 else if (rb_enc_mbminlen(enc) == 1) {
4241 rsptr = RSTRING_PTR(rs);
4242 newline = (
unsigned char)rsptr[rslen - 1];
4246 rsptr = RSTRING_PTR(rs);
4247 const char *e = rsptr + rslen;
4248 const char *last = rb_enc_prev_char(rsptr, e, e, enc);
4250 newline = rb_enc_codepoint_len(last, e, &n, enc);
4251 if (last + n != e) rb_raise(rb_eArgError,
"broken separator");
4253 chomp_cr = chomp && newline ==
'\n' && rslen == rb_enc_mbminlen(enc);
4257 while ((c = appendline(fptr, newline, &str, &limit, enc)) != EOF) {
4258 const char *s, *p, *pp, *e;
4261 if (RSTRING_LEN(str) < rslen)
continue;
4262 s = RSTRING_PTR(str);
4265 if (!at_char_boundary(s, p, e, enc))
continue;
4266 if (!rspara) rscheck(rsptr, rslen, rs);
4267 if (memcmp(p, rsptr, rslen) == 0) {
4269 if (chomp_cr && p > s && *(p-1) ==
'\r') --p;
4276 s = RSTRING_PTR(str);
4278 pp = rb_enc_prev_char(s, p, p, enc);
4279 if (extra_limit && pp &&
4293 if (rspara && c != EOF)
4294 swallow(fptr,
'\n');
4296 str = io_enc_str(str, fptr);
4299 if (!
NIL_P(str) && !nolimit) {
4307rb_io_getline_1(
VALUE rs,
long limit,
int chomp,
VALUE io)
4310 int old_lineno, new_lineno;
4314 old_lineno = fptr->
lineno;
4315 str = rb_io_getline_0(rs, limit, chomp, fptr);
4316 if (!
NIL_P(str) && (new_lineno = fptr->
lineno) != old_lineno) {
4317 if (io == ARGF.current_file) {
4318 ARGF.lineno += new_lineno - old_lineno;
4319 ARGF.last_lineno = ARGF.lineno;
4322 ARGF.last_lineno = new_lineno;
4330rb_io_getline(
int argc,
VALUE *argv,
VALUE io)
4334 prepare_getline_args(argc, argv, &args, io);
4335 return rb_io_getline_1(args.rs, args.limit, args.chomp, io);
4345rb_io_gets_limit_internal(
VALUE io,
long limit)
4349 return rb_io_getline_0(rb_default_rs, limit, FALSE, fptr);
4353rb_io_gets_internal(
VALUE io)
4355 return rb_io_gets_limit_internal(io, -1);
4435 str = rb_io_getline(argc, argv, io);
4451rb_io_lineno(
VALUE io)
4506 check_getline_args(&sep, &limit, io);
4508 VALUE line = rb_io_getline_1(sep, limit,
RTEST(chomp), io);
4509 rb_lastline_set_up(line, 1);
4584rb_io_readlines(
int argc,
VALUE *argv,
VALUE io)
4588 prepare_getline_args(argc, argv, &args, io);
4589 return io_readlines(&args, io);
4597 if (arg->limit == 0)
4598 rb_raise(rb_eArgError,
"invalid limit: 0 for readlines");
4600 while (!
NIL_P(line = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, io))) {
4713rb_io_each_line(
int argc,
VALUE *argv,
VALUE io)
4719 prepare_getline_args(argc, argv, &args, io);
4720 if (args.limit == 0)
4721 rb_raise(rb_eArgError,
"invalid limit: 0 for each_line");
4722 while (!
NIL_P(str = rb_io_getline_1(args.rs, args.limit, args.chomp, io))) {
4750rb_io_each_byte(
VALUE io)
4766 }
while (io_fillbuf(fptr) >= 0);
4776 if (NEED_READCONV(fptr)) {
4780 SET_BINARY_MODE(fptr);
4781 make_readconv(fptr, 0);
4795 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4797 clear_readconv(fptr);
4801 str = rb_enc_str_new(fptr->
cbuf.
ptr+fptr->
cbuf.
off, 1, read_enc);
4804 if (fptr->
cbuf.
len == 0) clear_readconv(fptr);
4813 io_shift_cbuf(fptr, r, &str);
4820 ISASCII(RSTRING_PTR(str)[0])) {
4824 str = io_enc_str(str, fptr);
4829 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4830 if (io_fillbuf(fptr) < 0) {
4852 if (io_fillbuf(fptr) != -1) {
4856 r = rb_enc_precise_mbclen(RSTRING_PTR(str), RSTRING_PTR(str)+RSTRING_LEN(str), enc);
4872 str = io_enc_str(str, fptr);
4899rb_io_each_char(
VALUE io)
4909 enc = io_input_encoding(fptr);
4911 while (!
NIL_P(c = io_getc(fptr, enc))) {
4938rb_io_each_codepoint(
VALUE io)
4950 enc = io_read_encoding(fptr);
4951 if (NEED_READCONV(fptr)) {
4952 SET_BINARY_MODE(fptr);
4955 make_readconv(fptr, 0);
4967 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4968 clear_readconv(fptr);
4988 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4989 while (io_fillbuf(fptr) >= 0) {
5004 char cbuf[8], *p = cbuf;
5006 if (more > numberof(cbuf))
goto invalid;
5008 if (more > numberof(cbuf))
goto invalid;
5009 while ((n = (
int)read_buffered_data(p, more, fptr)) > 0 &&
5010 (p += n, (more -= n) > 0)) {
5011 if (io_fillbuf(fptr) < 0)
goto invalid;
5012 if ((n = fptr->
rbuf.
len) > more) n = more;
5014 r = rb_enc_precise_mbclen(cbuf, p, enc);
5027 rb_raise(rb_eArgError,
"invalid byte sequence in %s", rb_enc_name(enc));
5060 enc = io_input_encoding(fptr);
5062 return io_getc(fptr, enc);
5086rb_io_readchar(
VALUE io)
5088 VALUE c = rb_io_getc(io);
5124 VALUE r_stdout = rb_ractor_stdout();
5129 rb_io_flush(r_stdout);
5132 if (io_fillbuf(fptr) < 0) {
5162rb_io_readbyte(
VALUE io)
5223 unsigned char c =
NUM2INT(v) & 0xFF;
5229 io_ungetbyte(b, fptr);
5285 else if (RB_BIGNUM_TYPE_P(c)) {
5291 if (NEED_READCONV(fptr)) {
5292 SET_BINARY_MODE(fptr);
5293 len = RSTRING_LEN(c);
5294#if SIZEOF_LONG > SIZEOF_INT
5298 make_readconv(fptr, (
int)
len);
5312 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
5313 io_ungetbyte(c, fptr);
5333rb_io_isatty(
VALUE io)
5338 return RBOOL(isatty(fptr->
fd) != 0);
5341#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5357rb_io_close_on_exec_p(
VALUE io)
5363 write_io = GetWriteIO(io);
5364 if (io != write_io) {
5366 if (fptr && 0 <= (fd = fptr->
fd)) {
5367 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->
pathv);
5368 if (!(ret & FD_CLOEXEC))
return Qfalse;
5373 if (fptr && 0 <= (fd = fptr->
fd)) {
5374 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->
pathv);
5375 if (!(ret & FD_CLOEXEC))
return Qfalse;
5380#define rb_io_close_on_exec_p rb_f_notimplement
5383#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5407 int flag =
RTEST(arg) ? FD_CLOEXEC : 0;
5412 write_io = GetWriteIO(io);
5413 if (io != write_io) {
5415 if (fptr && 0 <= (fd = fptr->
fd)) {
5416 if ((ret = fcntl(fptr->
fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->
pathv);
5417 if ((ret & FD_CLOEXEC) != flag) {
5418 ret = (ret & ~FD_CLOEXEC) | flag;
5419 ret = fcntl(fd, F_SETFD, ret);
5420 if (ret != 0) rb_sys_fail_path(fptr->
pathv);
5427 if (fptr && 0 <= (fd = fptr->
fd)) {
5428 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->
pathv);
5429 if ((ret & FD_CLOEXEC) != flag) {
5430 ret = (ret & ~FD_CLOEXEC) | flag;
5431 ret = fcntl(fd, F_SETFD, ret);
5432 if (ret != 0) rb_sys_fail_path(fptr->
pathv);
5438#define rb_io_set_close_on_exec rb_f_notimplement
5441#define RUBY_IO_EXTERNAL_P(f) ((f)->mode & FMODE_EXTERNAL)
5442#define PREP_STDIO_NAME(f) (RSTRING_PTR((f)->pathv))
5445finish_writeconv(
rb_io_t *fptr,
int noalloc)
5447 unsigned char *ds, *dp, *de;
5451 unsigned char buf[1024];
5456 de = buf +
sizeof(buf);
5459 size_t remaining = dp-ds;
5460 long result = rb_io_write_memory(fptr, ds, remaining);
5464 if ((
size_t)result == remaining)
break;
5487 if (io_fflush(fptr) < 0) {
5495 fptr->
wbuf.
len += (int)(dp - ds);
5511finish_writeconv_sync(
VALUE arg)
5514 return finish_writeconv(p->fptr, p->noalloc);
5518nogvl_close(
void *ptr)
5522 return (
void*)(intptr_t)close(*fd);
5526maygvl_close(
int fd,
int keepgvl)
5535 return IO_WITHOUT_GVL_INT(nogvl_close, &fd);
5539nogvl_fclose(
void *ptr)
5543 return (
void*)(intptr_t)fclose(file);
5547maygvl_fclose(
FILE *file,
int keepgvl)
5550 return fclose(file);
5552 return IO_WITHOUT_GVL_INT(nogvl_fclose, file);
5558fptr_finalize_flush(
rb_io_t *fptr,
int noraise,
int keepgvl)
5563 int mode = fptr->
mode;
5569 arg.noalloc = noraise;
5573 error = finish_writeconv(fptr, noraise);
5578 io_flush_buffer_sync(fptr);
5581 if (io_fflush(fptr) < 0 &&
NIL_P(error)) {
5589 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2) {
5599 rb_thread_io_close_wait(fptr);
5601 if (!done && stdio_file) {
5603 if ((maygvl_fclose(stdio_file, noraise) < 0) &&
NIL_P(error)) {
5613 if (!done && fd >= 0 && scheduler !=
Qnil) {
5616 if (!UNDEF_P(result)) {
5617 done =
RTEST(result);
5621 if (!done && fd >= 0) {
5627 if ((maygvl_close(fd, keepgvl) < 0) &&
NIL_P(error)) {
5636 if (!
NIL_P(error) && !noraise) {
5645fptr_finalize(
rb_io_t *fptr,
int noraise)
5647 fptr_finalize_flush(fptr, noraise, FALSE);
5648 free_io_buffer(&fptr->
rbuf);
5649 free_io_buffer(&fptr->
wbuf);
5650 clear_codeconv(fptr);
5654rb_io_fptr_cleanup(
rb_io_t *fptr,
int noraise)
5660 fptr_finalize(fptr, noraise);
5668 ruby_xfree_sized(buf->
ptr, (
size_t)buf->
capa);
5681 free_io_buffer(&fptr->
cbuf);
5697 clear_readconv(fptr);
5698 clear_writeconv(fptr);
5702rb_io_fptr_cleanup_all(
rb_io_t *fptr)
5706 rb_io_fptr_cleanup(fptr, TRUE);
5708 free_io_buffer(&fptr->
rbuf);
5709 free_io_buffer(&fptr->
wbuf);
5710 clear_codeconv(fptr);
5717 rb_io_fptr_cleanup_all(io);
5724rb_io_fptr_finalize_closed(
struct rb_io *io)
5726 if (!io)
return true;
5727 if (io->
fd >= 0)
return false;
5733rb_io_memsize(
const rb_io_t *io)
5735 size_t size =
sizeof(
rb_io_t);
5745 rb_serial_t fork_generation = GET_VM()->fork_gen;
5746 if (io->fork_generation == fork_generation) {
5757# define KEEPGVL TRUE
5759# define KEEPGVL FALSE
5763io_close_fptr(
VALUE io)
5769 write_io = GetWriteIO(io);
5770 if (io != write_io) {
5771 write_fptr =
RFILE(write_io)->fptr;
5772 if (write_fptr && 0 <= write_fptr->
fd) {
5773 rb_io_fptr_cleanup(write_fptr, TRUE);
5777 fptr =
RFILE(io)->fptr;
5778 if (!fptr)
return 0;
5779 if (fptr->
fd < 0)
return 0;
5782 if (rb_thread_io_close_interrupt(fptr)) {
5784 fptr_finalize_flush(fptr, FALSE, KEEPGVL);
5787 rb_io_fptr_cleanup(fptr, FALSE);
5792fptr_waitpid(
rb_io_t *fptr,
int nohang)
5796 rb_last_status_clear();
5805 rb_io_t *fptr = io_close_fptr(io);
5806 if (fptr) fptr_waitpid(fptr, 0);
5846rb_io_close_m(
VALUE io)
5848 rb_io_t *fptr = rb_io_get_fptr(io);
5857io_call_close(
VALUE io)
5866 enum {mesg_len =
sizeof(closed_stream)-1};
5867 VALUE mesg = rb_attr_get(exc, idMesg);
5869 RSTRING_LEN(mesg) != mesg_len ||
5870 memcmp(RSTRING_PTR(mesg), closed_stream, mesg_len)) {
5880 if (!UNDEF_P(closed) &&
RTEST(closed))
return io;
5881 rb_rescue2(io_call_close, io, ignore_closed_stream, io,
5917 write_io = GetWriteIO(io);
5918 if (io != write_io) {
5919 write_fptr =
RFILE(write_io)->fptr;
5920 if (write_fptr && 0 <= write_fptr->
fd) {
5925 fptr = rb_io_get_fptr(io);
5926 return RBOOL(0 > fptr->
fd);
5962rb_io_close_read(
VALUE io)
5968 if (fptr->
fd < 0)
return Qnil;
5969 if (is_socket(fptr->
fd, fptr->
pathv)) {
5973 if (shutdown(fptr->
fd, SHUT_RD) < 0)
5974 rb_sys_fail_path(fptr->
pathv);
5975 fptr->
mode &= ~FMODE_READABLE;
5981 write_io = GetWriteIO(io);
5982 if (io != write_io) {
5987 RFILE(io)->fptr = wfptr;
5990 RFILE(write_io)->fptr = fptr;
5991 rb_io_fptr_cleanup(fptr, FALSE);
5997 rb_raise(
rb_eIOError,
"closing non-duplex IO for reading");
6035rb_io_close_write(
VALUE io)
6040 write_io = GetWriteIO(io);
6042 if (fptr->
fd < 0)
return Qnil;
6043 if (is_socket(fptr->
fd, fptr->
pathv)) {
6047 if (shutdown(fptr->
fd, SHUT_WR) < 0)
6048 rb_sys_fail_path(fptr->
pathv);
6049 fptr->
mode &= ~FMODE_WRITABLE;
6056 rb_raise(
rb_eIOError,
"closing non-duplex IO for writing");
6059 if (io != write_io) {
6079rb_io_sysseek(
int argc,
VALUE *argv,
VALUE io)
6081 VALUE offset, ptrname;
6082 int whence = SEEK_SET;
6086 if (
rb_scan_args(argc, argv,
"11", &offset, &ptrname) == 2) {
6087 whence = interpret_seek_whence(ptrname);
6092 (READ_DATA_BUFFERED(fptr) || READ_CHAR_PENDING(fptr))) {
6096 rb_warn(
"sysseek for buffered IO");
6099 pos = lseek(fptr->
fd, pos, whence);
6100 if (pos < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
6134 io = GetWriteIO(io);
6139 rb_warn(
"syswrite for buffered IO");
6142 tmp = rb_str_tmp_frozen_acquire(str);
6144 n = rb_io_write_memory(fptr, ptr,
len);
6145 if (n < 0) rb_sys_fail_path(fptr->
pathv);
6146 rb_str_tmp_frozen_release(str, tmp);
6163rb_io_sysread(
int argc,
VALUE *argv,
VALUE io)
6174 shrinkable = io_setstrbuf(&str, ilen);
6175 if (ilen == 0)
return str;
6180 if (READ_DATA_BUFFERED(fptr)) {
6186 io_setstrbuf(&str, ilen);
6191 iis.buf = RSTRING_PTR(str);
6194 n = io_read_memory_locktmp(str, &iis);
6197 rb_sys_fail_path(fptr->
pathv);
6200 io_set_read_length(str, n, shrinkable);
6202 if (n == 0 && ilen > 0) {
6218internal_pread_func(
void *_arg)
6222 return (
VALUE)pread(arg->fd, arg->buf, arg->count, arg->offset);
6226pread_internal_call(
VALUE _arg)
6231 if (scheduler !=
Qnil) {
6234 if (!UNDEF_P(result)) {
6239 return rb_io_blocking_region_wait(arg->io, internal_pread_func, arg,
RUBY_IO_READABLE);
6283 shrinkable = io_setstrbuf(&str, (
long)arg.count);
6284 if (arg.count == 0)
return str;
6285 arg.buf = RSTRING_PTR(str);
6298 rb_sys_fail_path(fptr->
pathv);
6300 io_set_read_length(str, n, shrinkable);
6301 if (n == 0 && arg.count > 0) {
6309internal_pwrite_func(
void *_arg)
6313 return (
VALUE)pwrite(arg->fd, arg->buf, arg->count, arg->offset);
6317pwrite_internal_call(
VALUE _arg)
6322 if (scheduler !=
Qnil) {
6325 if (!UNDEF_P(result)) {
6330 return rb_io_blocking_region_wait(arg->io, internal_pwrite_func, arg,
RUBY_IO_WRITABLE);
6371 io = GetWriteIO(io);
6378 tmp = rb_str_tmp_frozen_acquire(str);
6379 arg.buf = RSTRING_PTR(tmp);
6380 arg.count = (size_t)RSTRING_LEN(tmp);
6382 n = (ssize_t)pwrite_internal_call((
VALUE)&arg);
6383 if (n < 0) rb_sys_fail_path(fptr->
pathv);
6384 rb_str_tmp_frozen_release(str, tmp);
6400 fptr->
mode &= ~FMODE_TEXTMODE;
6404 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6407 setmode(fptr->
fd, O_BINARY);
6414io_ascii8bit_binmode(
rb_io_t *fptr)
6425 fptr->
mode &= ~FMODE_TEXTMODE;
6426 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6428 fptr->
encs.
enc = rb_ascii8bit_encoding();
6432 clear_codeconv(fptr);
6441 io_ascii8bit_binmode(fptr);
6458rb_io_binmode_m(
VALUE io)
6464 write_io = GetWriteIO(io);
6479rb_io_binmode_p(
VALUE io)
6487rb_io_fmode_modestr(
enum rb_io_mode fmode)
6491 return MODE_BTMODE(
"a+",
"ab+",
"at+");
6493 return MODE_BTMODE(
"a",
"ab",
"at");
6497 rb_raise(rb_eArgError,
"invalid access fmode 0x%x", fmode);
6499 return MODE_BTMODE(
"r",
"rb",
"rt");
6501 return MODE_BTXMODE(
"w",
"wb",
"wt",
"wx",
"wbx",
"wtx");
6504 return MODE_BTXMODE(
"w+",
"wb+",
"wt+",
"w+x",
"wb+x",
"wt+x");
6506 return MODE_BTMODE(
"r+",
"rb+",
"rt+");
6510static const char bom_prefix[] =
"bom|";
6511static const char utf_prefix[] =
"utf-";
6512enum {bom_prefix_len = (int)
sizeof(bom_prefix) - 1};
6513enum {utf_prefix_len = (int)
sizeof(utf_prefix) - 1};
6516io_encname_bom_p(
const char *name,
long len)
6518 return len > bom_prefix_len &&
STRNCASECMP(name, bom_prefix, bom_prefix_len) == 0;
6524 enum rb_io_mode fmode = 0;
6525 const char *m = modestr, *p = NULL;
6553 if (modestr[0] !=
'w')
6561 if (io_encname_bom_p(m, p ? (
long)(p - m) : (long)strlen(m)))
6574 rb_raise(rb_eArgError,
"invalid access mode %s", modestr);
6579rb_io_oflags_fmode(
int oflags)
6581 enum rb_io_mode fmode = 0;
6583 switch (oflags & O_ACCMODE) {
6595 if (oflags & O_APPEND) {
6598 if (oflags & O_TRUNC) {
6601 if (oflags & O_CREAT) {
6604 if (oflags & O_EXCL) {
6608 if (oflags & O_BINARY) {
6617rb_io_fmode_oflags(
enum rb_io_mode fmode)
6661rb_io_oflags_modestr(
int oflags)
6664# define MODE_BINARY(a,b) ((oflags & O_BINARY) ? (b) : (a))
6666# define MODE_BINARY(a,b) (a)
6669 if (oflags & O_EXCL) {
6670 rb_raise(rb_eArgError,
"exclusive access mode is not supported");
6672 accmode = oflags & (O_RDONLY|O_WRONLY|O_RDWR);
6673 if (oflags & O_APPEND) {
6674 if (accmode == O_WRONLY) {
6675 return MODE_BINARY(
"a",
"ab");
6677 if (accmode == O_RDWR) {
6678 return MODE_BINARY(
"a+",
"ab+");
6683 rb_raise(rb_eArgError,
"invalid access oflags 0x%x", oflags);
6685 return MODE_BINARY(
"r",
"rb");
6687 return MODE_BINARY(
"w",
"wb");
6689 if (oflags & O_TRUNC) {
6690 return MODE_BINARY(
"w+",
"wb+");
6692 return MODE_BINARY(
"r+",
"rb+");
6704 int default_ext = 0;
6707 ext = rb_default_external_encoding();
6710 if (rb_is_ascii8bit_enc(ext)) {
6714 else if (intern == NULL) {
6715 intern = rb_default_internal_encoding();
6720 *enc = (default_ext && intern != ext) ? NULL : ext;
6730unsupported_encoding(
const char *name,
rb_encoding *enc)
6732 rb_enc_warn(enc,
"Unsupported encoding %s ignored", name);
6736parse_mode_enc(
const char *estr,
rb_encoding *estr_enc,
6742 enum rb_io_mode fmode = fmode_p ? *fmode_p : 0;
6748 p = strrchr(estr,
':');
6749 len = p ? (p++ - estr) : (long)strlen(estr);
6751 estr += bom_prefix_len;
6752 len -= bom_prefix_len;
6753 if (!
STRNCASECMP(estr, utf_prefix, utf_prefix_len)) {
6757 rb_enc_warn(estr_enc,
"BOM with non-UTF encoding %s is nonsense", estr);
6758 fmode &= ~FMODE_SETENC_BY_BOM;
6766 memcpy(encname, estr,
len);
6767 encname[
len] =
'\0';
6770 idx = rb_enc_find_index(estr);
6772 if (fmode_p) *fmode_p = fmode;
6775 ext_enc = rb_enc_from_index(idx);
6778 unsupported_encoding(estr, estr_enc);
6784 if (*p ==
'-' && *(p+1) ==
'\0') {
6789 idx2 = rb_enc_find_index(p);
6791 unsupported_encoding(p, estr_enc);
6796 int_enc = rb_enc_from_index(idx2);
6800 rb_io_ext_int_to_encs(ext_enc, int_enc, enc_p, enc2_p, fmode);
6813 v = rb_hash_lookup2(opt, sym_encoding,
Qnil);
6814 if (v !=
Qnil) encoding = v;
6815 v = rb_hash_lookup2(opt, sym_extenc,
Qundef);
6816 if (v !=
Qnil) extenc = v;
6817 v = rb_hash_lookup2(opt, sym_intenc,
Qundef);
6818 if (!UNDEF_P(v)) intenc = v;
6820 if ((!UNDEF_P(extenc) || !UNDEF_P(intenc)) && !
NIL_P(encoding)) {
6822 int idx = rb_to_encoding_index(encoding);
6823 if (idx >= 0) encoding = rb_enc_from_encoding(rb_enc_from_index(idx));
6824 rb_warn(
"Ignoring encoding parameter '%"PRIsVALUE
"': %s_encoding is used",
6825 encoding, UNDEF_P(extenc) ?
"internal" :
"external");
6829 if (!UNDEF_P(extenc) && !
NIL_P(extenc)) {
6830 extencoding = rb_to_encoding(extenc);
6832 if (!UNDEF_P(intenc)) {
6833 if (
NIL_P(intenc)) {
6840 if (*p ==
'-' && *(p+1) ==
'\0') {
6845 intencoding = rb_to_encoding(intenc);
6849 intencoding = rb_to_encoding(intenc);
6851 if (extencoding == intencoding) {
6855 if (!
NIL_P(encoding)) {
6859 enc_p, enc2_p, fmode_p);
6862 rb_io_ext_int_to_encs(rb_to_encoding(encoding), NULL, enc_p, enc2_p, 0);
6865 else if (!UNDEF_P(extenc) || !UNDEF_P(intenc)) {
6867 rb_io_ext_int_to_encs(extencoding, intencoding, enc_p, enc2_p, 0);
6875 enum rb_io_mode fmode = *fmode_p;
6880 !rb_enc_asciicompat(enc ? enc : rb_default_external_encoding()))
6881 rb_raise(rb_eArgError,
"ASCII incompatible encoding needs binmode");
6884 rb_raise(rb_eArgError,
"newline decorator with binary mode");
6891#if !DEFAULT_TEXTMODE
6893 fmode &= ~FMODE_TEXTMODE;
6900extract_binmode(
VALUE opthash,
enum rb_io_mode *fmode)
6902 if (!
NIL_P(opthash)) {
6904 v = rb_hash_aref(opthash, sym_textmode);
6907 rb_raise(rb_eArgError,
"textmode specified twice");
6909 rb_raise(rb_eArgError,
"both textmode and binmode specified");
6913 v = rb_hash_aref(opthash, sym_binmode);
6916 rb_raise(rb_eArgError,
"binmode specified twice");
6918 rb_raise(rb_eArgError,
"both textmode and binmode specified");
6924 rb_raise(rb_eArgError,
"both textmode and binmode specified");
6930 int *oflags_p,
enum rb_io_mode *fmode_p,
struct rb_io_encoding *convconfig_p)
6934 enum rb_io_mode fmode;
6938 int has_enc = 0, has_vmode = 0;
6944 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
6954 fmode = rb_io_oflags_fmode(oflags);
6962 oflags = rb_io_fmode_oflags(fmode);
6966 parse_mode_enc(p+1, rb_enc_get(vmode), &enc, &enc2, &fmode);
6971 e = (fmode &
FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
6972 rb_io_ext_int_to_encs(e, NULL, &enc, &enc2, fmode);
6976 if (
NIL_P(opthash)) {
6980#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
6982 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
6983 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
6985 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
6992 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
6995 else if (
NIL_P(vmode)) {
6996 fmode |= DEFAULT_TEXTMODE;
7003 v = rb_hash_aref(opthash, sym_mode);
7005 if (!
NIL_P(vmode)) {
7006 rb_raise(rb_eArgError,
"mode specified twice");
7013 v = rb_hash_aref(opthash, sym_flags);
7018 fmode = rb_io_oflags_fmode(oflags);
7020 extract_binmode(opthash, &fmode);
7026 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
7029 else if (
NIL_P(vmode)) {
7030 fmode |= DEFAULT_TEXTMODE;
7033 v = rb_hash_aref(opthash, sym_perm);
7036 if (!
NIL_P(*vperm_p)) {
7037 rb_raise(rb_eArgError,
"perm specified twice");
7048#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7050 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7051 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7056 rb_raise(rb_eArgError,
"encoding specified twice");
7059 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
7063 validate_enc_binmode(&fmode, ecflags, enc, enc2);
7069 convconfig_p->
enc = enc;
7070 convconfig_p->
enc2 = enc2;
7071 convconfig_p->
ecflags = ecflags;
7072 convconfig_p->
ecopts = ecopts;
7082sysopen_func(
void *ptr)
7085 const char *fname = RSTRING_PTR(data->fname);
7094 fd = IO_WITHOUT_GVL_INT(sysopen_func, data);
7095 }
while (fd < 0 &&
errno == EINTR);
7102rb_sysopen(
VALUE fname,
int oflags, mode_t perm)
7107 data.fname = rb_str_encode_ospath(fname);
7109 data.oflags = oflags;
7112 TRY_WITH_GC((fd = rb_sysopen_internal(&data)) >= 0) {
7113 rb_syserr_fail_path(first_errno, fname);
7119fdopen_internal(
int fd,
const char *modestr)
7126 file = fdopen(fd, modestr);
7142 TRY_WITH_GC((file = fdopen_internal(fd, modestr)) != 0) {
7148 if (setvbuf(file, NULL, _IOFBF, 0) != 0)
7149 rb_warn(
"setvbuf() can't be honoured (fd=%d)", fd);
7157 int t = isatty(fptr->
fd);
7167io_strip_bom(
VALUE io)
7169 VALUE b1, b2, b3, b4;
7180 return rb_utf8_encindex();
7190 return ENCINDEX_UTF_16BE;
7201 return ENCINDEX_UTF_32LE;
7206 return ENCINDEX_UTF_16LE;
7216 return ENCINDEX_UTF_32BE;
7230io_set_encoding_by_bom(
VALUE io)
7232 int idx = io_strip_bom(io);
7238 extenc = rb_enc_from_index(idx);
7239 io_encoding_set(fptr, rb_enc_from_encoding(extenc),
7240 rb_io_internal_encoding(io),
Qnil);
7249rb_file_open_generic(
VALUE io,
VALUE filename,
int oflags,
enum rb_io_mode fmode,
7257 rb_io_ext_int_to_encs(NULL, NULL, &cc.enc, &cc.enc2, fmode);
7262 validate_enc_binmode(&fmode, convconfig->
ecflags,
7263 convconfig->
enc, convconfig->
enc2);
7267 fptr->
encs = *convconfig;
7270 if (!(oflags & O_TMPFILE)) {
7271 fptr->
pathv = pathv;
7274 fptr->
pathv = pathv;
7276 fptr->
fd = rb_sysopen(pathv, oflags, perm);
7284rb_file_open_internal(
VALUE io,
VALUE filename,
const char *modestr)
7287 const char *p = strchr(modestr,
':');
7291 parse_mode_enc(p+1, rb_usascii_encoding(),
7292 &convconfig.
enc, &convconfig.
enc2, &fmode);
7298 e = (fmode &
FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
7299 rb_io_ext_int_to_encs(e, NULL, &convconfig.
enc, &convconfig.
enc2, fmode);
7305#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7307 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7308 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7310 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.
enc2, convconfig.
ecflags);
7313 return rb_file_open_generic(io, filename,
7314 rb_io_fmode_oflags(fmode),
7324 return rb_file_open_internal(io_alloc(
rb_cFile), fname, modestr);
7333#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7356 while ((tmp = *prev) != 0) {
7357 if (tmp->fptr == fptr) {
7366#if defined (_WIN32) || defined(__CYGWIN__)
7382pipe_finalize(
rb_io_t *fptr,
int noraise)
7384#if !defined(HAVE_WORKING_FORK) && !defined(_WIN32)
7393 fptr_finalize(fptr, noraise);
7395 pipe_del_fptr(fptr);
7402#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7403 void (*
const old_finalize)(
struct rb_io*,int) = fptr->
finalize;
7405 if (old_finalize == orig->finalize)
return;
7410#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7411 if (old_finalize != pipe_finalize) {
7413 for (list =
pipe_list; list; list = list->next) {
7414 if (list->fptr == fptr)
break;
7416 if (!list) pipe_add_fptr(fptr);
7419 pipe_del_fptr(fptr);
7432rb_io_unbuffered(
rb_io_t *fptr)
7450#define HAVE_SPAWNV 1
7451#define spawnv(mode, cmd, args) rb_w32_uaspawn((mode), (cmd), (args))
7452#define spawn(mode, cmd) rb_w32_uspawn((mode), (cmd), 0)
7455#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7465#ifdef HAVE_WORKING_FORK
7466# ifndef __EMSCRIPTEN__
7468popen_redirect(
struct popen_arg *p)
7471 close(p->write_pair[1]);
7472 if (p->write_pair[0] != 0) {
7473 dup2(p->write_pair[0], 0);
7474 close(p->write_pair[0]);
7477 if (p->pair[1] != 1) {
7478 dup2(p->pair[1], 1);
7484 if (p->pair[1] != 1) {
7485 dup2(p->pair[1], 1);
7491 if (p->pair[0] != 0) {
7492 dup2(p->pair[0], 0);
7499#if defined(__linux__)
7510linux_get_maxfd(
void)
7513 char buf[4096], *p, *np, *e;
7516 if (fd < 0)
return fd;
7517 ss = read(fd, buf,
sizeof(buf));
7518 if (ss < 0)
goto err;
7521 while ((
int)
sizeof(
"FDSize:\t0\n")-1 <= e-p &&
7522 (np = memchr(p,
'\n', e-p)) != NULL) {
7523 if (memcmp(p,
"FDSize:",
sizeof(
"FDSize:")-1) == 0) {
7525 p +=
sizeof(
"FDSize:")-1;
7545#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
7547 int max = (int)max_file_descriptor;
7550 ret = fcntl(0, F_MAXFD);
7552 maxhint = max = ret;
7553# elif defined(__linux__)
7554 ret = linux_get_maxfd();
7561 for (fd = lowfd; fd <= max; fd++) {
7562 if (!
NIL_P(noclose_fds) &&
7565 ret = fcntl(fd, F_GETFD);
7566 if (ret != -1 && !(ret & FD_CLOEXEC)) {
7567 fcntl(fd, F_SETFD, ret|FD_CLOEXEC);
7569# define CONTIGUOUS_CLOSED_FDS 20
7571 if (max < fd + CONTIGUOUS_CLOSED_FDS)
7572 max = fd + CONTIGUOUS_CLOSED_FDS;
7578# ifndef __EMSCRIPTEN__
7580popen_exec(
void *pp,
char *errmsg,
size_t errmsg_len)
7582 struct popen_arg *p = (
struct popen_arg*)pp;
7584 return rb_exec_async_signal_safe(p->eargp, errmsg, errmsg_len);
7589#if (defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)) && !defined __EMSCRIPTEN__
7591rb_execarg_fixup_v(
VALUE execarg_obj)
7593 rb_execarg_parent_start(execarg_obj);
7597char *rb_execarg_commandline(
const struct rb_execarg *eargp,
VALUE *prog);
7600#ifndef __EMSCRIPTEN__
7602pipe_open(
VALUE execarg_obj,
const char *modestr,
enum rb_io_mode fmode,
7605 struct rb_execarg *eargp =
NIL_P(execarg_obj) ? NULL : rb_execarg_get(execarg_obj);
7606 VALUE prog = eargp ? (eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name) :
Qfalse ;
7612#if defined(HAVE_WORKING_FORK)
7614 char errmsg[80] = {
'\0' };
7616#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7618 struct popen_arg arg;
7621#if defined(HAVE_SPAWNV)
7622# if defined(HAVE_SPAWNVE)
7623# define DO_SPAWN(cmd, args, envp) ((args) ? \
7624 spawnve(P_NOWAIT, (cmd), (args), (envp)) : \
7625 spawne(P_NOWAIT, (cmd), (envp)))
7627# define DO_SPAWN(cmd, args, envp) ((args) ? \
7628 spawnv(P_NOWAIT, (cmd), (args)) : \
7629 spawn(P_NOWAIT, (cmd)))
7631# if !defined(HAVE_WORKING_FORK)
7633# if defined(HAVE_SPAWNVE)
7638#if !defined(HAVE_WORKING_FORK)
7644#if !defined(HAVE_WORKING_FORK)
7645 const char *cmd = 0;
7651#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7652 arg.execarg_obj = execarg_obj;
7655 arg.pair[0] = arg.pair[1] = -1;
7656 arg.write_pair[0] = arg.write_pair[1] = -1;
7657# if !defined(HAVE_WORKING_FORK)
7658 if (eargp && !eargp->use_shell) {
7659 args = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
7664 if (
rb_pipe(arg.write_pair) < 0)
7665 rb_sys_fail_str(prog);
7668 close(arg.write_pair[0]);
7669 close(arg.write_pair[1]);
7673 rb_execarg_addopt(execarg_obj,
INT2FIX(0),
INT2FIX(arg.write_pair[0]));
7674 rb_execarg_addopt(execarg_obj,
INT2FIX(1),
INT2FIX(arg.pair[1]));
7679 rb_sys_fail_str(prog);
7681 rb_execarg_addopt(execarg_obj,
INT2FIX(1),
INT2FIX(arg.pair[1]));
7685 rb_sys_fail_str(prog);
7687 rb_execarg_addopt(execarg_obj,
INT2FIX(0),
INT2FIX(arg.pair[0]));
7690 rb_sys_fail_str(prog);
7692 if (!
NIL_P(execarg_obj)) {
7693 rb_protect(rb_execarg_fixup_v, execarg_obj, &state);
7695 if (0 <= arg.write_pair[0]) close(arg.write_pair[0]);
7696 if (0 <= arg.write_pair[1]) close(arg.write_pair[1]);
7697 if (0 <= arg.pair[0]) close(arg.pair[0]);
7698 if (0 <= arg.pair[1]) close(arg.pair[1]);
7699 rb_execarg_parent_end(execarg_obj);
7703# if defined(HAVE_WORKING_FORK)
7704 pid = rb_fork_async_signal_safe(&status, popen_exec, &arg, arg.eargp->redirect_fds, errmsg,
sizeof(errmsg));
7706 rb_execarg_run_options(eargp, sargp, NULL, 0);
7707# if defined(HAVE_SPAWNVE)
7708 if (eargp->envp_str) envp = (
char **)RSTRING_PTR(eargp->envp_str);
7710 while ((pid = DO_SPAWN(cmd, args, envp)) < 0) {
7712 switch (e =
errno) {
7714# if EWOULDBLOCK != EAGAIN
7723 rb_execarg_run_options(sargp, NULL, NULL, 0);
7725 rb_execarg_parent_end(execarg_obj);
7728# if defined(HAVE_WORKING_FORK)
7729 pid = rb_call_proc__fork();
7731 popen_redirect(&arg);
7743# if defined(HAVE_WORKING_FORK)
7749 close(arg.write_pair[0]);
7750 close(arg.write_pair[1]);
7752# if defined(HAVE_WORKING_FORK)
7761 close(arg.write_pair[0]);
7762 write_fd = arg.write_pair[1];
7773 cmd = rb_execarg_commandline(eargp, &prog);
7774 if (!
NIL_P(execarg_obj)) {
7775 rb_execarg_parent_start(execarg_obj);
7776 rb_execarg_run_options(eargp, sargp, NULL, 0);
7778 fp = popen(cmd, modestr);
7781 rb_execarg_parent_end(execarg_obj);
7782 rb_execarg_run_options(sargp, NULL, NULL, 0);
7784 if (!fp) rb_syserr_fail_path(e, prog);
7794 fptr->
encs = *convconfig;
7795#if RUBY_CRLF_ENVIRONMENT
7802 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
7805#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7806 if (NEED_NEWLINE_DECORATOR_ON_WRITE(fptr)) {
7807 fptr->
encs.
ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
7813 if (0 <= write_fd) {
7814 write_port = io_alloc(
rb_cIO);
7816 write_fptr->
fd = write_fd;
7818 fptr->
mode &= ~FMODE_WRITABLE;
7820 rb_ivar_set(port, rb_intern(
"@tied_io_for_writing"), write_port);
7823#if defined (__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7825 pipe_add_fptr(fptr);
7831pipe_open(
VALUE execarg_obj,
const char *modestr,
enum rb_io_mode fmode,
7839is_popen_fork(
VALUE prog)
7841 if (RSTRING_LEN(prog) == 1 && RSTRING_PTR(prog)[0] ==
'-') {
7842#if !defined(HAVE_WORKING_FORK)
7844 "fork() function is unimplemented on this machine");
7853pipe_open_s(
VALUE prog,
const char *modestr,
enum rb_io_mode fmode,
7857 VALUE *argv = &prog;
7860 if (!is_popen_fork(prog))
7861 execarg_obj = rb_execarg_new(argc, argv, TRUE, FALSE);
7862 return pipe_open(execarg_obj, modestr, fmode, convconfig);
7868 rb_io_t *fptr = io_close_fptr(io);
8037rb_io_s_popen(
int argc,
VALUE *argv,
VALUE klass)
8041 if (argc > 1 && !
NIL_P(opt = rb_check_hash_type(argv[argc-1]))) --argc;
8042 if (argc > 1 && !
NIL_P(env = rb_check_hash_type(argv[0]))) --argc, ++argv;
8051 int ex = !
NIL_P(opt);
8052 rb_error_arity(argc + ex, 1 + ex, 2 + ex);
8055 return popen_finish(rb_io_popen(pname, pmode, env, opt), klass);
8061 const char *modestr;
8064 enum rb_io_mode fmode;
8070#if SIZEOF_LONG > SIZEOF_INT
8071 if (
len > INT_MAX) {
8072 rb_raise(rb_eArgError,
"too many arguments");
8081 if (!is_popen_fork(pname))
8082 execarg_obj = rb_execarg_new(1, &pname, TRUE, FALSE);
8084 if (!
NIL_P(execarg_obj)) {
8086 opt = rb_execarg_extract_options(execarg_obj, opt);
8088 rb_execarg_setenv(execarg_obj, env);
8091 modestr = rb_io_oflags_modestr(oflags);
8093 return pipe_open(execarg_obj, modestr, fmode, &convconfig);
8103 rb_io_flush(rb_ractor_stdout());
8104 rb_io_flush(rb_ractor_stderr());
8105 _exit(EXIT_SUCCESS);
8109 RBASIC_SET_CLASS(port, klass);
8116#if defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)
8117struct popen_writer_arg {
8119 struct popen_arg popen;
8123exec_popen_writer(
void *arg,
char *errmsg,
size_t buflen)
8125 struct popen_writer_arg *pw = arg;
8127 popen_redirect(&pw->popen);
8128 execv(pw->argv[0], pw->argv);
8129 strlcpy(errmsg, strerror(
errno), buflen);
8135ruby_popen_writer(
char *
const *argv, rb_pid_t *pid)
8137#if (defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)) || defined(_WIN32)
8138# ifdef HAVE_WORKING_FORK
8139 struct popen_writer_arg pw;
8140 int *
const write_pair = pw.popen.pair;
8146 int result = pipe2(write_pair, O_CLOEXEC);
8148 int result = pipe(write_pair);
8153# ifdef HAVE_WORKING_FORK
8156 char errmsg[80] = {
'\0'};
8157 *pid = rb_fork_async_signal_safe(&status, exec_popen_writer, &pw,
Qnil, errmsg,
sizeof(errmsg));
8159 *pid = rb_w32_uspawn_process(P_NOWAIT, argv[0], argv, write_pair[0], -1, -1, 0);
8160 const char *errmsg = (*pid < 0) ? strerror(
errno) : NULL;
8162 close(write_pair[0]);
8164 close(write_pair[1]);
8165 fprintf(stderr,
"ruby_popen_writer(%s): %s\n", argv[0], errmsg);
8168 return fdopen(write_pair[1],
"w");
8179 enum rb_io_mode fmode;
8188 rb_file_open_generic(io, fname, oflags, fmode, &convconfig, perm);
8226rb_io_s_open(
int argc,
VALUE *argv,
VALUE klass)
8258 VALUE fname, vmode, vperm;
8263 rb_scan_args(argc, argv,
"12", &fname, &vmode, &vperm);
8274 if (
NIL_P(vperm)) perm = 0666;
8278 fd = rb_sysopen(fname, oflags, perm);
8310 int redirect = FALSE;
8318 VALUE tmp = argv[0];
8336 return rb_io_s_open(argc, argv,
rb_cFile);
8340rb_io_open_generic(
VALUE klass,
VALUE filename,
int oflags,
enum rb_io_mode fmode,
8343 return rb_file_open_generic(io_alloc(klass), filename,
8344 oflags, fmode, convconfig, perm);
8351 enum rb_io_mode fmode;
8357 return rb_io_open_generic(io, filename, oflags, fmode, &convconfig, perm);
8371 if (fptr == orig)
return io;
8372 if (RUBY_IO_EXTERNAL_P(fptr)) {
8376 rb_raise(rb_eArgError,
8377 "%s can't change access mode from \"%s\" to \"%s\"",
8378 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->
mode),
8379 rb_io_fmode_modestr(orig->
mode));
8382 flush_before_seek(fptr,
true);
8384 clear_codeconv(fptr);
8386 pos = io_tell(orig);
8389 if (io_fflush(orig) < 0)
8390 rb_sys_fail_on_write(fptr);
8399 else if (!RUBY_IO_EXTERNAL_P(fptr)) fptr->
pathv =
Qnil;
8400 fptr_copy_finalizer(fptr, orig);
8406 rb_thread_io_close_interrupt(fptr);
8407 rb_thread_io_close_wait(fptr);
8409 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2 || !fptr->stdio_file) {
8412 rb_sys_fail_path(orig->
pathv);
8420 rb_sys_fail_path(orig->
pathv);
8426 if (io_seek(fptr, pos, SEEK_SET) < 0 &&
errno) {
8427 rb_sys_fail_path(fptr->
pathv);
8429 if (io_seek(orig, pos, SEEK_SET) < 0 &&
errno) {
8430 rb_sys_fail_path(orig->
pathv);
8444int rb_freopen(
VALUE fname,
const char *mode,
FILE *fp);
8447rb_freopen(
VALUE fname,
const char *mode,
FILE *fp)
8449 if (!freopen(RSTRING_PTR(fname), mode, fp)) {
8492rb_io_reopen(
int argc,
VALUE *argv,
VALUE file)
8494 VALUE fname, nmode, opt;
8498 if (
rb_scan_args(argc, argv,
"11:", &fname, &nmode, &opt) == 1) {
8501 return io_reopen(file, tmp);
8507 fptr =
RFILE(file)->fptr;
8513 enum rb_io_mode fmode;
8517 if (RUBY_IO_EXTERNAL_P(fptr) &&
8520 rb_raise(rb_eArgError,
8521 "%s can't change access mode from \"%s\" to \"%s\"",
8522 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->
mode),
8523 rb_io_fmode_modestr(fmode));
8526 fptr->
encs = convconfig;
8529 oflags = rb_io_fmode_oflags(fptr->
mode);
8532 fptr->
pathv = fname;
8534 fptr->
fd = rb_sysopen(fptr->
pathv, oflags, 0666);
8540 if (io_fflush(fptr) < 0)
8541 rb_sys_fail_on_write(fptr);
8544 clear_codeconv(fptr);
8547 int e = rb_freopen(rb_str_encode_ospath(fptr->
pathv),
8548 rb_io_oflags_modestr(oflags),
8550 if (e) rb_syserr_fail_path(e, fptr->
pathv);
8554 if (setvbuf(fptr->
stdio_file, NULL, _IOFBF, 0) != 0)
8555 rb_warn(
"setvbuf() can't be honoured for %"PRIsVALUE, fptr->
pathv);
8558 if (setvbuf(fptr->
stdio_file, NULL, _IONBF, BUFSIZ) != 0)
8559 rb_warn(
"setvbuf() can't be honoured for %"PRIsVALUE, fptr->
pathv);
8561 else if (fptr->
stdio_file == stdout && isatty(fptr->
fd)) {
8562 if (setvbuf(fptr->
stdio_file, NULL, _IOLBF, BUFSIZ) != 0)
8563 rb_warn(
"setvbuf() can't be honoured for %"PRIsVALUE, fptr->
pathv);
8567 int tmpfd = rb_sysopen(fptr->
pathv, oflags, 0666);
8573 rb_syserr_fail_path(err, fptr->
pathv);
8597 fptr->
mode = orig->
mode & ~FMODE_EXTERNAL;
8604 fptr->closing_ec = NULL;
8605 fptr->wakeup_mutex =
Qnil;
8606 fptr->fork_generation = GET_VM()->fork_gen;
8609 fptr_copy_finalizer(fptr, orig);
8611 fd = ruby_dup(orig->
fd);
8613 pos = io_tell(orig);
8615 io_seek(fptr, pos, SEEK_SET);
8620 write_io = GetWriteIO(io);
8621 if (io != write_io) {
8624 rb_ivar_set(dest, rb_intern(
"@tied_io_for_writing"), write_io);
8687 if (argc == 0)
return Qnil;
8689 out = rb_ractor_stdout();
8701extern void rb_deprecated_str_setter(
VALUE val,
ID id,
VALUE *var);
8706 rb_deprecated_str_setter(val,
id, &val);
8712 val = rb_str_frozen_bare_string(val);
8789 for (i=0; i<argc; i++) {
8793 rb_io_write(out, argv[i]);
8890 rb_io_write(io, str);
8894#define forward(obj, id, argc, argv) \
8895 rb_funcallv_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8896#define forward_public(obj, id, argc, argv) \
8897 rb_funcallv_public_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8898#define forward_current(id, argc, argv) \
8899 forward_public(ARGF.current_file, id, argc, argv)
8916 VALUE r_stdout = rb_ractor_stdout();
8917 if (recv == r_stdout) {
8918 return rb_io_putc(recv, ch);
8920 return forward(r_stdout, rb_intern(
"putc"), 1, &ch);
8925rb_str_end_with_asciichar(
VALUE str,
int c)
8927 long len = RSTRING_LEN(str);
8928 const char *
ptr = RSTRING_PTR(str);
8932 if (
len == 0)
return 0;
8933 if ((n = rb_enc_mbminlen(
enc)) == 1) {
8934 return ptr[
len - 1] == c;
8936 return rb_enc_ascget(
ptr + ((
len - 1) / n) * n,
ptr +
len, &n,
enc) == c;
8947 rb_io_puts(1, &tmp, out);
8954 rb_io_puts(1, &tmp, out);
9009 VALUE line, args[2];
9016 for (
int i = 0; i < argc; i++) {
9030 if (RSTRING_LEN(line) == 0) {
9035 if (!rb_str_end_with_asciichar(line,
'\n')) {
9040 rb_io_writev(out, n, args);
9058 VALUE r_stdout = rb_ractor_stdout();
9059 if (recv == r_stdout) {
9060 return rb_io_puts(argc, argv, recv);
9062 return forward(r_stdout, rb_intern(
"puts"), argc, argv);
9066rb_p_write(
VALUE str)
9071 VALUE r_stdout = rb_ractor_stdout();
9074 io_writev(2, args, r_stdout);
9077 rb_io_writev(r_stdout, 2, args);
9089rb_p_result(
int argc,
const VALUE *argv)
9096 else if (argc > 1) {
9099 VALUE r_stdout = rb_ractor_stdout();
9101 rb_uninterruptible(rb_io_flush, r_stdout);
9142 for (i=0; i<argc; i++) {
9144 rb_uninterruptible(rb_p_write, inspected);
9146 return rb_p_result(argc, argv);
9167rb_obj_display(
int argc,
VALUE *argv,
VALUE self)
9171 out = (!
rb_check_arity(argc, 0, 1) ? rb_ractor_stdout() : argv[0]);
9172 rb_io_write(out, self);
9178rb_stderr_to_original_p(
VALUE err)
9180 return (err == orig_stderr ||
RFILE(orig_stderr)->fptr->
fd < 0);
9186 VALUE out = rb_ractor_stderr();
9187 if (rb_stderr_to_original_p(out)) {
9189 if (isatty(fileno(stderr))) {
9190 if (rb_w32_write_console(
rb_str_new(mesg,
len), fileno(stderr)) > 0)
return;
9193 if (fwrite(mesg,
sizeof(
char), (
size_t)
len, stderr) < (
size_t)
len) {
9210rb_write_error_str(
VALUE mesg)
9212 VALUE out = rb_ractor_stderr();
9214 if (rb_stderr_to_original_p(out)) {
9215 size_t len = (size_t)RSTRING_LEN(mesg);
9217 if (isatty(fileno(stderr))) {
9218 if (rb_w32_write_console(mesg, fileno(stderr)) > 0)
return;
9221 if (fwrite(RSTRING_PTR(mesg),
sizeof(
char),
len, stderr) <
len) {
9228 rb_io_write(out, mesg);
9233rb_stderr_tty_p(
void)
9235 if (rb_stderr_to_original_p(rb_ractor_stderr()))
9236 return isatty(fileno(stderr));
9241must_respond_to(
ID mid,
VALUE val,
ID id)
9244 rb_raise(
rb_eTypeError,
"%"PRIsVALUE
" must have %"PRIsVALUE
" method, %"PRIsVALUE
" given",
9245 rb_id2str(
id), rb_id2str(mid),
9265 must_respond_to(id_write, val,
id);
9272 return rb_ractor_stdout();
9278 must_respond_to(id_write, val,
id);
9285 return rb_ractor_stderr();
9289allocate_and_open_new_file(
VALUE klass)
9291 VALUE self = io_alloc(klass);
9292 rb_io_make_open_file(self);
9300 VALUE self = rb_protect(allocate_and_open_new_file, klass, &state);
9308 maygvl_close(descriptor, 0);
9316 io->
fd = descriptor;
9334 io->closing_ec = NULL;
9335 io->wakeup_mutex =
Qnil;
9336 io->fork_generation = GET_VM()->fork_gen;
9339 io->
encs = *encoding;
9348prep_io(
int fd,
enum rb_io_mode fmode,
VALUE klass,
const char *path)
9358 e = (fmode &
FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
9359 rb_io_ext_int_to_encs(e, NULL, &convconfig.
enc, &convconfig.
enc2, fmode);
9363#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9365 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
9366 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
9368 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.
enc2, convconfig.
ecflags);
9374 if (!io_check_tty(io)) {
9377 setmode(fd, O_BINARY);
9389 if (path && strcmp(path,
"-")) klass =
rb_cFile;
9390 return prep_io(fd, rb_io_oflags_fmode(oflags), klass, path);
9394prep_stdio(
FILE *f,
enum rb_io_mode fmode,
VALUE klass,
const char *path)
9401#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9402 fptr->
encs.
ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
9413rb_io_prep_stdin(
void)
9419rb_io_prep_stdout(
void)
9425rb_io_prep_stderr(
void)
9434 int oflags = rb_io_fmode_oflags(fptr->
mode) & ~O_EXCL;
9461 rb_io_buffer_init(&fp->
wbuf);
9462 rb_io_buffer_init(&fp->
rbuf);
9463 rb_io_buffer_init(&fp->
cbuf);
9478 fp->closing_ec = NULL;
9479 fp->wakeup_mutex =
Qnil;
9480 fp->fork_generation = GET_VM()->fork_gen;
9485rb_io_make_open_file(
VALUE obj)
9490 if (
RFILE(obj)->fptr) {
9493 RFILE(obj)->fptr = 0;
9495 fp = rb_io_fptr_new();
9497 RFILE(obj)->fptr = fp;
9546rb_io_initialize(
int argc,
VALUE *argv,
VALUE io)
9552 return io_initialize(io, fnum, vmode, opt);
9559 int fd, oflags = O_RDONLY;
9560 enum rb_io_mode fmode;
9562#if defined(HAVE_FCNTL) && defined(F_GETFL)
9572 rb_raise(rb_eArgError,
"The given fd is not accessible because RubyVM reserves it");
9574#if defined(HAVE_FCNTL) && defined(F_GETFL)
9575 oflags = fcntl(fd, F_GETFL);
9576 if (oflags == -1) rb_sys_fail(0);
9578 if (fstat(fd, &st) < 0) rb_sys_fail(0);
9581#if defined(HAVE_FCNTL) && defined(F_GETFL)
9582 ofmode = rb_io_oflags_fmode(oflags);
9594 if (rb_hash_aref(opt, sym_autoclose) ==
Qfalse) {
9598 path = rb_hash_aref(opt,
RB_ID2SYM(idPath));
9609 fp->
encs = convconfig;
9613 fp->closing_ec = NULL;
9614 fp->wakeup_mutex =
Qnil;
9615 fp->fork_generation = GET_VM()->fork_gen;
9618 if (fileno(stdin) == fd)
9620 else if (fileno(stdout) == fd)
9622 else if (fileno(stderr) == fd)
9654rb_io_set_encoding_by_bom(
VALUE io)
9660 rb_raise(rb_eArgError,
"ASCII incompatible encoding needs binmode");
9663 rb_raise(rb_eArgError,
"encoding conversion is set");
9665 else if (fptr->
encs.
enc && fptr->
encs.
enc != rb_ascii8bit_encoding()) {
9666 rb_raise(rb_eArgError,
"encoding is set to %s already",
9669 if (!io_set_encoding_by_bom(io))
return Qnil;
9670 return rb_enc_from_encoding(fptr->
encs.
enc);
9715rb_file_initialize(
int argc,
VALUE *argv,
VALUE io)
9717 if (
RFILE(io)->fptr) {
9720 VALUE fname, vmode, vperm, opt;
9721 int posargc =
rb_scan_args(argc, argv,
"12:", &fname, &vmode, &vperm, &opt);
9726 return io_initialize(io, fd, vmode, opt);
9729 return rb_open_file(io, fname, vmode, vperm, opt);
9734rb_io_s_new(
int argc,
VALUE *argv,
VALUE klass)
9739 rb_warn(
"%"PRIsVALUE
"::new() does not take block; use %"PRIsVALUE
"::open() instead",
9755rb_io_s_for_fd(
int argc,
VALUE *argv,
VALUE klass)
9758 rb_io_initialize(argc, argv, io);
9771rb_io_autoclose_p(
VALUE io)
9796rb_io_set_autoclose(
VALUE io,
VALUE autoclose)
9800 if (!
RTEST(autoclose))
9803 fptr->
mode &= ~FMODE_EXTERNAL;
9808io_wait_event(
VALUE io,
int event,
VALUE timeout,
int return_io)
9840io_wait_readable(
int argc,
VALUE *argv,
VALUE io)
9847 if (rb_io_read_pending(fptr))
return Qtrue;
9850 VALUE timeout = (argc == 1 ? argv[0] :
Qnil);
9864io_wait_writable(
int argc,
VALUE *argv,
VALUE io)
9872 VALUE timeout = (argc == 1 ? argv[0] :
Qnil);
9887io_wait_priority(
int argc,
VALUE *argv,
VALUE io)
9894 if (rb_io_read_pending(fptr))
return Qtrue;
9897 VALUE timeout = argc == 1 ? argv[0] :
Qnil;
9903wait_mode_sym(
VALUE mode)
9905 if (mode ==
ID2SYM(rb_intern(
"r"))) {
9906 return RB_WAITFD_IN;
9908 if (mode ==
ID2SYM(rb_intern(
"read"))) {
9909 return RB_WAITFD_IN;
9911 if (mode ==
ID2SYM(rb_intern(
"readable"))) {
9912 return RB_WAITFD_IN;
9914 if (mode ==
ID2SYM(rb_intern(
"w"))) {
9915 return RB_WAITFD_OUT;
9917 if (mode ==
ID2SYM(rb_intern(
"write"))) {
9918 return RB_WAITFD_OUT;
9920 if (mode ==
ID2SYM(rb_intern(
"writable"))) {
9921 return RB_WAITFD_OUT;
9923 if (mode ==
ID2SYM(rb_intern(
"rw"))) {
9924 return RB_WAITFD_IN|RB_WAITFD_OUT;
9926 if (mode ==
ID2SYM(rb_intern(
"read_write"))) {
9927 return RB_WAITFD_IN|RB_WAITFD_OUT;
9929 if (mode ==
ID2SYM(rb_intern(
"readable_writable"))) {
9930 return RB_WAITFD_IN|RB_WAITFD_OUT;
9933 rb_raise(rb_eArgError,
"unsupported mode: %"PRIsVALUE, mode);
9937io_event_from_value(
VALUE value)
9941 if (events <= 0) rb_raise(rb_eArgError,
"Events must be positive integer!");
9979 for (
int i = 0; i < argc; i += 1) {
9981 events |= wait_mode_sym(argv[i]);
9983 else if (UNDEF_P(timeout)) {
9987 rb_raise(rb_eArgError,
"timeout given more than once");
9991 if (UNDEF_P(timeout)) timeout =
Qnil;
9999 events = io_event_from_value(argv[0]);
10007 if (rb_io_read_pending(fptr)) {
10009 if (return_io)
return Qtrue;
10015 return io_wait_event(io, events, timeout, return_io);
10019argf_mark_and_move(
void *ptr)
10021 struct argf *p = ptr;
10022 rb_gc_mark_and_move(&p->filename);
10023 rb_gc_mark_and_move(&p->current_file);
10024 rb_gc_mark_and_move(&p->argv);
10025 rb_gc_mark_and_move(&p->inplace);
10026 rb_gc_mark_and_move(&p->encs.
ecopts);
10030argf_memsize(
const void *ptr)
10032 const struct argf *p = ptr;
10033 size_t size =
sizeof(*p);
10040 0, 0, RUBY_TYPED_THREAD_SAFE_FREE | RUBY_TYPED_WB_PROTECTED
10046 p->filename =
Qnil;
10047 p->current_file =
Qnil;
10053argf_alloc(
VALUE klass)
10068 memset(&ARGF, 0,
sizeof(ARGF));
10069 argf_init(
argf, &ARGF, argv);
10079 ARGF = argf_of(orig);
10080 rb_gc_writebarrier_remember(
argf);
10107 ARGF.last_lineno = ARGF.lineno;
10133 return forward_current(rb_frame_this_func(), argc, argv);
10136#define next_argv() argf_next_argv(argf)
10137#define ARGF_GENERIC_INPUT_P() \
10138 (ARGF.current_file == rb_stdin && !RB_TYPE_P(ARGF.current_file, T_FILE))
10139#define ARGF_FORWARD(argc, argv) do {\
10140 if (ARGF_GENERIC_INPUT_P())\
10141 return argf_forward((argc), (argv), argf);\
10143#define NEXT_ARGF_FORWARD(argc, argv) do {\
10144 if (!next_argv()) return Qnil;\
10145 ARGF_FORWARD((argc), (argv));\
10151 VALUE file = ARGF.current_file;
10165 int stdout_binmode = 0;
10166 enum rb_io_mode fmode;
10168 VALUE r_stdout = rb_ractor_stdout();
10173 stdout_binmode = 1;
10176 if (ARGF.init_p == 0) {
10186 if (
NIL_P(ARGF.argv)) {
10189 else if (ARGF.next_p == -1 &&
RARRAY_LEN(ARGF.argv) > 0) {
10194 if (ARGF.next_p == 1) {
10195 if (ARGF.init_p == 1) argf_close(
argf);
10200 ARGF_SET(filename, filename);
10201 filename = rb_str_encode_ospath(filename);
10203 if (RSTRING_LEN(filename) == 1 && fn[0] ==
'-') {
10205 if (ARGF.inplace) {
10206 rb_warn(
"Can't do inplace edit for stdio; skipping");
10212 int fr = rb_sysopen(filename, O_RDONLY, 0);
10214 if (ARGF.inplace) {
10216#ifndef NO_SAFE_RENAME
10227 if (!
NIL_P(ARGF.inplace)) {
10228 VALUE suffix = ARGF.inplace;
10230 if (
NIL_P(rb_str_cat_conv_enc_opts(str, RSTRING_LEN(str),
10231 RSTRING_PTR(suffix), RSTRING_LEN(suffix),
10232 rb_enc_get(suffix), 0,
Qnil))) {
10235#ifdef NO_SAFE_RENAME
10237 (void)unlink(RSTRING_PTR(str));
10238 if (rename(fn, RSTRING_PTR(str)) < 0) {
10239 rb_warn(
"Can't rename %"PRIsVALUE
" to %"PRIsVALUE
": %s, skipping file",
10240 filename, str, strerror(
errno));
10243 fr = rb_sysopen(str, O_RDONLY, 0);
10245 if (rename(fn, RSTRING_PTR(str)) < 0) {
10246 rb_warn(
"Can't rename %"PRIsVALUE
" to %"PRIsVALUE
": %s, skipping file",
10247 filename, str, strerror(
errno));
10254#ifdef NO_SAFE_RENAME
10255 rb_fatal(
"Can't do inplace edit without backup");
10257 if (unlink(fn) < 0) {
10258 rb_warn(
"Can't remove %"PRIsVALUE
": %s, skipping file",
10259 filename, strerror(
errno));
10265 fw = rb_sysopen(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666);
10266#ifndef NO_SAFE_RENAME
10269 fchmod(fw, st.st_mode);
10271 chmod(fn, st.st_mode);
10273 if (st.st_uid!=st2.st_uid || st.st_gid!=st2.st_gid) {
10276 err = fchown(fw, st.st_uid, st.st_gid);
10278 err = chown(fn, st.st_uid, st.st_gid);
10280 if (err && getuid() == 0 && st2.st_uid == 0) {
10281 const char *wkfn = RSTRING_PTR(filename);
10282 rb_warn(
"Can't set owner/group of %"PRIsVALUE
" to same as %"PRIsVALUE
": %s, skipping file",
10283 filename, str, strerror(
errno));
10286 (void)unlink(wkfn);
10296 if (!ARGF.binmode) {
10297 fmode |= DEFAULT_TEXTMODE;
10299 ARGF_SET(current_file, prep_io(fr, fmode,
rb_cFile, fn));
10300 if (!
NIL_P(write_io)) {
10307 if (ARGF.encs.enc) {
10308 fptr->
encs = ARGF.encs;
10309 clear_codeconv(fptr);
10312 fptr->
encs.
ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
10313 if (!ARGF.binmode) {
10315#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
10316 fptr->
encs.
ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
10327 else if (ARGF.next_p == -1) {
10330 if (ARGF.inplace) {
10331 rb_warn(
"Can't do inplace edit for stdio");
10335 if (ARGF.init_p == -1) ARGF.init_p = 1;
10343 long lineno = ARGF.lineno;
10346 if (!next_argv())
return Qnil;
10347 if (ARGF_GENERIC_INPUT_P()) {
10348 line = forward_current(idGets, argc, argv);
10355 line = rb_io_getline(argc, argv, ARGF.current_file);
10357 if (
NIL_P(line) && ARGF.next_p != -1) {
10363 if (!
NIL_P(line)) {
10364 ARGF.lineno = ++lineno;
10365 ARGF.last_lineno = ARGF.lineno;
10371argf_lineno_getter(
ID id,
VALUE *var)
10374 return INT2FIX(ARGF.last_lineno);
10382 ARGF.last_lineno = ARGF.lineno = n;
10386rb_reset_argf_lineno(
long n)
10388 ARGF.last_lineno = ARGF.lineno = n;
10429 if (recv ==
argf) {
10430 return argf_gets(argc, argv,
argf);
10432 return forward(
argf, idGets, argc, argv);
10458 line = argf_getline(argc, argv,
argf);
10470 return rb_f_gets(0, 0,
argf);
10474 if (!next_argv())
return Qnil;
10476 if (
NIL_P(line) && ARGF.next_p != -1) {
10482 if (!
NIL_P(line)) {
10484 ARGF.last_lineno = ARGF.lineno;
10510rb_f_readline(
int argc,
VALUE *argv,
VALUE recv)
10512 if (recv ==
argf) {
10513 return argf_readline(argc, argv,
argf);
10515 return forward(
argf, rb_intern(
"readline"), argc, argv);
10541 if (!next_argv()) rb_eof_error();
10542 ARGF_FORWARD(argc, argv);
10543 line = argf_gets(argc, argv,
argf);
10613rb_f_readlines(
int argc,
VALUE *argv,
VALUE recv)
10615 if (recv ==
argf) {
10616 return argf_readlines(argc, argv,
argf);
10618 return forward(
argf, rb_intern(
"readlines"), argc, argv);
10642 long lineno = ARGF.lineno;
10646 while (next_argv()) {
10647 if (ARGF_GENERIC_INPUT_P()) {
10648 lines = forward_current(rb_intern(
"readlines"), argc, argv);
10651 lines = rb_io_readlines(argc, argv, ARGF.current_file);
10657 ARGF.last_lineno = ARGF.lineno;
10692 rb_last_status_clear();
10693 port = pipe_open_s(str,
"r",
FMODE_READABLE|DEFAULT_TEXTMODE, NULL);
10697 result = read_all(fptr, remain_size(fptr),
Qnil);
10699 rb_io_fptr_cleanup_all(fptr);
10705#ifdef HAVE_SYS_SELECT_H
10706#include <sys/select.h>
10720 if (!
NIL_P(read)) {
10725 if (READ_DATA_PENDING(fptr) || READ_CHAR_PENDING(fptr)) {
10729 if (max < fptr->fd) max = fptr->
fd;
10732 timerec.tv_sec = timerec.tv_usec = 0;
10740 if (!
NIL_P(write)) {
10746 if (max < fptr->fd) max = fptr->
fd;
10753 if (!
NIL_P(except)) {
10757 VALUE write_io = GetWriteIO(io);
10760 if (max < fptr->fd) max = fptr->
fd;
10761 if (io != write_io) {
10764 if (max < fptr->fd) max = fptr->
fd;
10779 if (!pending && n == 0)
return Qnil;
10804 VALUE write_io = GetWriteIO(io);
10817 VALUE write_io = GetWriteIO(io);
10822 else if (io != write_io) {
10835 VALUE read, write, except;
10841select_call(
VALUE arg)
10845 return select_internal(p->read, p->write, p->except, p->timeout, p->fdsets);
10849select_end(
VALUE arg)
10854 for (i = 0; i < numberof(p->fdsets); ++i)
10859static VALUE sym_normal, sym_sequential, sym_random,
10860 sym_willneed, sym_dontneed, sym_noreuse;
10862#ifdef HAVE_POSIX_FADVISE
10863struct io_advise_struct {
10871io_advise_internal(
void *arg)
10873 struct io_advise_struct *ptr = arg;
10874 return posix_fadvise(ptr->fd, ptr->offset, ptr->len, ptr->advice);
10878io_advise_sym_to_const(
VALUE sym)
10880#ifdef POSIX_FADV_NORMAL
10881 if (sym == sym_normal)
10882 return INT2NUM(POSIX_FADV_NORMAL);
10885#ifdef POSIX_FADV_RANDOM
10886 if (sym == sym_random)
10887 return INT2NUM(POSIX_FADV_RANDOM);
10890#ifdef POSIX_FADV_SEQUENTIAL
10891 if (sym == sym_sequential)
10892 return INT2NUM(POSIX_FADV_SEQUENTIAL);
10895#ifdef POSIX_FADV_WILLNEED
10896 if (sym == sym_willneed)
10897 return INT2NUM(POSIX_FADV_WILLNEED);
10900#ifdef POSIX_FADV_DONTNEED
10901 if (sym == sym_dontneed)
10902 return INT2NUM(POSIX_FADV_DONTNEED);
10905#ifdef POSIX_FADV_NOREUSE
10906 if (sym == sym_noreuse)
10907 return INT2NUM(POSIX_FADV_NOREUSE);
10914do_io_advise(
rb_io_t *fptr,
VALUE advice, rb_off_t offset, rb_off_t
len)
10917 struct io_advise_struct ias;
10920 num_adv = io_advise_sym_to_const(advice);
10926 if (
NIL_P(num_adv))
10930 ias.advice =
NUM2INT(num_adv);
10931 ias.offset = offset;
10934 rv = (int)rb_io_blocking_region(fptr, io_advise_internal, &ias);
10935 if (rv && rv != ENOSYS) {
10938 VALUE message = rb_sprintf(
"%"PRIsVALUE
" "
10942 fptr->
pathv, offset,
len, advice);
10952advice_arg_check(
VALUE advice)
10957 if (advice != sym_normal &&
10958 advice != sym_sequential &&
10959 advice != sym_random &&
10960 advice != sym_willneed &&
10961 advice != sym_dontneed &&
10962 advice != sym_noreuse) {
10963 rb_raise(
rb_eNotImpError,
"Unsupported advice: %+"PRIsVALUE, advice);
11001rb_io_advise(
int argc,
VALUE *argv,
VALUE io)
11008 advice_arg_check(advice);
11010 io = GetWriteIO(io);
11016#ifdef HAVE_POSIX_FADVISE
11017 return do_io_advise(fptr, advice,
off, l);
11019 ((void)
off, (
void)l);
11031 return isinf(f) && 0 < f;
11187rb_f_select(
int argc,
VALUE *argv,
VALUE obj)
11190 if (scheduler !=
Qnil) {
11193 if (!UNDEF_P(result))
return result;
11201 rb_scan_args(argc, argv,
"13", &args.read, &args.write, &args.except, &timeout);
11202 if (
NIL_P(timeout) || is_pos_inf(timeout)) {
11207 args.timeout = &timerec;
11210 for (i = 0; i < numberof(args.fdsets); ++i)
11216#ifdef IOCTL_REQ_TYPE
11217 typedef IOCTL_REQ_TYPE ioctl_req_t;
11219 typedef int ioctl_req_t;
11220# define NUM2IOCTLREQ(num) ((int)NUM2LONG(num))
11231nogvl_ioctl(
void *ptr)
11233 struct ioctl_arg *arg = ptr;
11235 return (
VALUE)ioctl(arg->fd, arg->cmd, arg->narg);
11239do_ioctl(
struct rb_io *io, ioctl_req_t cmd,
long narg)
11242 struct ioctl_arg arg;
11248 retval = (int)rb_io_blocking_region(io, nogvl_ioctl, &arg);
11254#define DEFAULT_IOCTL_NARG_LEN (256)
11256#if defined(__linux__) && defined(_IOC_SIZE)
11258linux_iocparm_len(ioctl_req_t cmd)
11262 if ((cmd & 0xFFFF0000) == 0) {
11264 return DEFAULT_IOCTL_NARG_LEN;
11267 len = _IOC_SIZE(cmd);
11270 if (
len < DEFAULT_IOCTL_NARG_LEN)
11271 len = DEFAULT_IOCTL_NARG_LEN;
11279ioctl_narg_len(ioctl_req_t cmd)
11285#define IOCPARM_LEN(x) (((x) >> 16) & IOCPARM_MASK)
11289 len = IOCPARM_LEN(cmd);
11290#elif defined(__linux__) && defined(_IOC_SIZE)
11291 len = linux_iocparm_len(cmd);
11294 len = DEFAULT_IOCTL_NARG_LEN;
11303typedef long fcntl_arg_t;
11306typedef int fcntl_arg_t;
11310fcntl_narg_len(ioctl_req_t cmd)
11317 len =
sizeof(fcntl_arg_t);
11325#ifdef F_DUPFD_CLOEXEC
11326 case F_DUPFD_CLOEXEC:
11327 len =
sizeof(fcntl_arg_t);
11337 len =
sizeof(fcntl_arg_t);
11347 len =
sizeof(fcntl_arg_t);
11357 len =
sizeof(fcntl_arg_t);
11362 len =
sizeof(
struct f_owner_ex);
11367 len =
sizeof(
struct f_owner_ex);
11372 len =
sizeof(
struct flock);
11377 len =
sizeof(
struct flock);
11382 len =
sizeof(
struct flock);
11402 len =
sizeof(fcntl_arg_t);
11412 len =
sizeof(fcntl_arg_t);
11417 len =
sizeof(fcntl_arg_t);
11430fcntl_narg_len(ioctl_req_t cmd)
11436#define NARG_SENTINEL 17
11439setup_narg(ioctl_req_t cmd,
VALUE *argp,
long (*narg_len)(ioctl_req_t))
11450 else if (arg ==
Qtrue) {
11464 len = narg_len(cmd);
11465 rb_str_modify(arg);
11467 slen = RSTRING_LEN(arg);
11469 if (slen <
len+1) {
11470 rb_str_resize(arg,
len+1);
11471 MEMZERO(RSTRING_PTR(arg)+slen,
char,
len-slen);
11475 ptr = RSTRING_PTR(arg);
11476 ptr[slen - 1] = NARG_SENTINEL;
11485finish_narg(
int retval,
VALUE arg,
const rb_io_t *fptr)
11487 if (retval < 0) rb_sys_fail_path(fptr->
pathv);
11492 if (ptr[slen-1] != NARG_SENTINEL)
11493 rb_raise(rb_eArgError,
"return value overflowed string");
11494 ptr[slen-1] =
'\0';
11504 ioctl_req_t cmd = NUM2IOCTLREQ(req);
11509 narg = setup_narg(cmd, &arg, ioctl_narg_len);
11511 retval = do_ioctl(fptr, cmd, narg);
11512 return finish_narg(retval, arg, fptr);
11539 return rb_ioctl(io, req, arg);
11542#define rb_io_ioctl rb_f_notimplement
11553nogvl_fcntl(
void *ptr)
11555 struct fcntl_arg *arg = ptr;
11557#if defined(F_DUPFD)
11558 if (arg->cmd == F_DUPFD)
11561 return (
VALUE)fcntl(arg->fd, arg->cmd, arg->narg);
11565do_fcntl(
struct rb_io *io,
int cmd,
long narg)
11568 struct fcntl_arg arg;
11574 retval = (int)rb_io_blocking_region(io, nogvl_fcntl, &arg);
11575 if (retval != -1) {
11577#if defined(F_DUPFD)
11580#if defined(F_DUPFD_CLOEXEC)
11581 case F_DUPFD_CLOEXEC:
11598 narg = setup_narg(cmd, &arg, fcntl_narg_len);
11600 retval = do_fcntl(fptr, cmd, narg);
11601 return finish_narg(retval, arg, fptr);
11627 return rb_fcntl(io, req, arg);
11630#define rb_io_fcntl rb_f_notimplement
11633#if defined(HAVE_SYSCALL) || defined(HAVE___SYSCALL)
11665#if SIZEOF_VOIDP == 8 && defined(HAVE___SYSCALL) && SIZEOF_INT != 8
11666# define SYSCALL __syscall
11667# define NUM2SYSCALLID(x) NUM2LONG(x)
11668# define RETVAL2NUM(x) LONG2NUM(x)
11669# if SIZEOF_LONG == 8
11670 long num, retval = -1;
11671# elif SIZEOF_LONG_LONG == 8
11672 long long num, retval = -1;
11674# error ---->> it is asserted that __syscall takes the first argument and returns retval in 64bit signed integer. <<----
11676#elif defined(__linux__)
11677# define SYSCALL syscall
11678# define NUM2SYSCALLID(x) NUM2LONG(x)
11679# define RETVAL2NUM(x) LONG2NUM(x)
11687 long num, retval = -1;
11689# define SYSCALL syscall
11690# define NUM2SYSCALLID(x) NUM2INT(x)
11691# define RETVAL2NUM(x) INT2NUM(x)
11692 int num, retval = -1;
11698 "We plan to remove a syscall function at future release. DL(Fiddle) provides safer alternative.");
11702 rb_raise(rb_eArgError,
"too few arguments for syscall");
11703 if (argc > numberof(arg))
11704 rb_raise(rb_eArgError,
"too many arguments for syscall");
11705 num = NUM2SYSCALLID(argv[0]); ++argv;
11706 for (i = argc - 1; i--; ) {
11721 retval = SYSCALL(num);
11724 retval = SYSCALL(num, arg[0]);
11727 retval = SYSCALL(num, arg[0],arg[1]);
11730 retval = SYSCALL(num, arg[0],arg[1],arg[2]);
11733 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3]);
11736 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4]);
11739 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5]);
11742 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6]);
11748 return RETVAL2NUM(retval);
11750#undef NUM2SYSCALLID
11754#define rb_f_syscall rb_f_notimplement
11758io_new_instance(
VALUE args)
11764find_encoding(
VALUE v)
11767 if (!enc)
rb_warn(
"Unsupported encoding %"PRIsVALUE
" ignored", v);
11779 enc2 = find_encoding(v1);
11782 if (RSTRING_LEN(tmp) == 1 && RSTRING_PTR(tmp)[0] ==
'-') {
11788 enc = find_encoding(v2);
11795 enc = find_encoding(v2);
11801 if (enc2 == rb_ascii8bit_encoding()) {
11806 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11812 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
11813 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11818 if (!
NIL_P(tmp) && rb_enc_asciicompat(enc = rb_enc_get(tmp))) {
11819 parse_mode_enc(RSTRING_PTR(tmp), enc, &enc, &enc2, NULL);
11820 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11824 rb_io_ext_int_to_encs(find_encoding(v1), NULL, &enc, &enc2, 0);
11825 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11830 validate_enc_binmode(&fptr->
mode, ecflags, enc, enc2);
11835 clear_codeconv(fptr);
11847io_encoding_set_v(
VALUE v)
11850 io_encoding_set(arg->fptr, arg->v1, arg->v2, arg->opt);
11855pipe_pair_close(
VALUE rw)
11858 return rb_ensure(io_close, rwp[0], io_close, rwp[1]);
11941rb_io_s_pipe(
int argc,
VALUE *argv,
VALUE klass)
11943 int pipes[2], state;
11944 VALUE r, w, args[3], v1, v2;
11948 enum rb_io_mode fmode = 0;
11951 argc =
rb_scan_args(argc, argv,
"02:", &v1, &v2, &opt);
11958 r = rb_protect(io_new_instance, (
VALUE)args, &state);
11962 rb_jump_tag(state);
11966 ies_args.fptr = fptr;
11969 ies_args.opt = opt;
11970 rb_protect(io_encoding_set_v, (
VALUE)&ies_args, &state);
11974 rb_jump_tag(state);
11979 w = rb_protect(io_new_instance, (
VALUE)args, &state);
11983 rb_jump_tag(state);
11988 extract_binmode(opt, &fmode);
11995#if DEFAULT_TEXTMODE
11997 fptr->
mode &= ~FMODE_TEXTMODE;
11998 setmode(fptr->
fd, O_BINARY);
12000#if RUBY_CRLF_ENVIRONMENT
12006 fptr->
mode |= fmode;
12007#if DEFAULT_TEXTMODE
12009 fptr2->
mode &= ~FMODE_TEXTMODE;
12010 setmode(fptr2->
fd, O_BINARY);
12013 fptr2->
mode |= fmode;
12047 else if (!
NIL_P(v = rb_hash_aref(opt, sym_open_args))) {
12050 v = rb_to_array_type(v);
12055 arg->io = rb_io_open(klass, path, vmode, vperm, opt);
12059io_s_foreach(
VALUE v)
12064 if (arg->limit == 0)
12065 rb_raise(rb_eArgError,
"invalid limit: 0 for foreach");
12066 while (!
NIL_P(str = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, arg->io))) {
12150rb_io_s_foreach(
int argc,
VALUE *argv,
VALUE self)
12153 int orig_argc = argc;
12157 argc =
rb_scan_args(argc, argv,
"12:", NULL, NULL, NULL, &opt);
12159 extract_getline_args(argc-1, argv+1, &garg);
12160 open_key_args(self, argc, argv, opt, &arg);
12162 extract_getline_opts(opt, &garg);
12163 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12164 return rb_ensure(io_s_foreach, (
VALUE)&garg, rb_io_close, arg.io);
12168io_s_readlines(
VALUE v)
12171 return io_readlines(arg, arg->io);
12224rb_io_s_readlines(
int argc,
VALUE *argv,
VALUE io)
12230 argc =
rb_scan_args(argc, argv,
"12:", NULL, NULL, NULL, &opt);
12231 extract_getline_args(argc-1, argv+1, &garg);
12232 open_key_args(io, argc, argv, opt, &arg);
12234 extract_getline_opts(opt, &garg);
12235 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12236 return rb_ensure(io_s_readlines, (
VALUE)&garg, rb_io_close, arg.io);
12243 return io_read(arg->argc, arg->argv, arg->io);
12253seek_before_access(
VALUE argp)
12257 return rb_io_seek(arg->io, arg->offset, arg->mode);
12324rb_io_s_read(
int argc,
VALUE *argv,
VALUE io)
12330 argc =
rb_scan_args(argc, argv,
"13:", NULL, NULL, &offset, NULL, &opt);
12332 rb_raise(rb_eArgError,
"negative offset %ld given",
off);
12334 open_key_args(io, argc, argv, opt, &arg);
12336 if (!
NIL_P(offset)) {
12340 sarg.offset = offset;
12341 sarg.mode = SEEK_SET;
12342 rb_protect(seek_before_access, (
VALUE)&sarg, &state);
12345 rb_jump_tag(state);
12347 if (arg.argc == 2) arg.argc = 1;
12362rb_io_s_binread(
int argc,
VALUE *argv,
VALUE io)
12377 convconfig.
enc = rb_ascii8bit_encoding();
12378 arg.io = rb_io_open_generic(io, argv[0], oflags, fmode, &convconfig, 0);
12381 arg.argc = (argc > 1) ? 1 : 0;
12382 if (!
NIL_P(offset)) {
12386 sarg.offset = offset;
12387 sarg.mode = SEEK_SET;
12388 rb_protect(seek_before_access, (
VALUE)&sarg, &state);
12391 rb_jump_tag(state);
12398io_s_write0(
VALUE v)
12401 return io_write(arg->io,arg->str,arg->nosync);
12405io_s_write(
int argc,
VALUE *argv,
VALUE klass,
int binary)
12407 VALUE string, offset, opt;
12411 rb_scan_args(argc, argv,
"21:", NULL, &
string, &offset, &opt);
12413 if (
NIL_P(opt)) opt = rb_hash_new();
12414 else opt = rb_hash_dup(opt);
12417 if (
NIL_P(rb_hash_aref(opt,sym_mode))) {
12418 int mode = O_WRONLY|O_CREAT;
12420 if (binary) mode |= O_BINARY;
12422 if (
NIL_P(offset)) mode |= O_TRUNC;
12423 rb_hash_aset(opt,sym_mode,
INT2NUM(mode));
12425 open_key_args(klass, argc, argv, opt, &arg);
12428 if (binary) rb_io_binmode_m(arg.io);
12432 if (!
NIL_P(offset)) {
12436 sarg.offset = offset;
12437 sarg.mode = SEEK_SET;
12438 rb_protect(seek_before_access, (
VALUE)&sarg, &state);
12441 rb_jump_tag(state);
12449 return rb_ensure(io_s_write0, (
VALUE)&warg, rb_io_close, arg.io);
12507rb_io_s_write(
int argc,
VALUE *argv,
VALUE io)
12509 return io_s_write(argc, argv, io, 0);
12522rb_io_s_binwrite(
int argc,
VALUE *argv,
VALUE io)
12524 return io_s_write(argc, argv, io, 1);
12530 rb_off_t copy_length;
12531 rb_off_t src_offset;
12535 unsigned close_src : 1;
12536 unsigned close_dst : 1;
12539 const char *syserr;
12540 const char *notimp;
12542 struct stat src_stat;
12543 struct stat dst_stat;
12544#ifdef HAVE_FCOPYFILE
12545 copyfile_state_t copyfile_state;
12550exec_interrupts(
void *arg)
12553 rb_thread_execute_interrupts(th);
12567#if defined(ERESTART)
12572 rb_thread_execute_interrupts(stp->th);
12591fiber_scheduler_wait_for(
void * _arguments)
12601# define IOWAIT_SYSCALL "poll"
12602STATIC_ASSERT(pollin_expected, POLLIN == RB_WAITFD_IN);
12603STATIC_ASSERT(pollout_expected, POLLOUT == RB_WAITFD_OUT);
12608 if (scheduler !=
Qnil) {
12611 return RTEST(args.result);
12615 if (fd == -1)
return 0;
12620 fds.events = events;
12622 int timeout_milliseconds = -1;
12625 timeout_milliseconds = (int)(timeout->tv_sec * 1000) + (int)(timeout->tv_usec / 1000);
12628 return poll(&fds, 1, timeout_milliseconds);
12631# define IOWAIT_SYSCALL "select"
12636 if (scheduler !=
Qnil) {
12639 return RTEST(args.result);
12659 case RB_WAITFD_OUT:
12663 VM_UNREACHABLE(nogvl_wait_for);
12683 ret = nogvl_wait_for(stp->th, stp->src_fptr, RB_WAITFD_IN, NULL);
12685 }
while (ret < 0 && maygvl_copy_stream_continue_p(has_gvl, stp));
12688 stp->syserr = IOWAIT_SYSCALL;
12689 stp->error_no =
errno;
12701 ret = nogvl_wait_for(stp->th, stp->dst_fptr, RB_WAITFD_OUT, NULL);
12702 }
while (ret < 0 && maygvl_copy_stream_continue_p(0, stp));
12705 stp->syserr = IOWAIT_SYSCALL;
12706 stp->error_no =
errno;
12712#ifdef USE_COPY_FILE_RANGE
12715simple_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)
12717#ifdef HAVE_COPY_FILE_RANGE
12718 return copy_file_range(in_fd, in_offset, out_fd, out_offset, count, flags);
12720 return syscall(__NR_copy_file_range, in_fd, in_offset, out_fd, out_offset, count, flags);
12729 rb_off_t copy_length, src_offset, *src_offset_ptr;
12731 if (!S_ISREG(stp->src_stat.st_mode))
12734 src_size = stp->src_stat.st_size;
12735 src_offset = stp->src_offset;
12736 if (src_offset >= (rb_off_t)0) {
12737 src_offset_ptr = &src_offset;
12740 src_offset_ptr = NULL;
12743 copy_length = stp->copy_length;
12744 if (copy_length < (rb_off_t)0) {
12745 if (src_offset < (rb_off_t)0) {
12746 rb_off_t current_offset;
12748 current_offset = lseek(stp->src_fptr->
fd, 0, SEEK_CUR);
12749 if (current_offset < (rb_off_t)0 &&
errno) {
12750 stp->syserr =
"lseek";
12751 stp->error_no =
errno;
12752 return (
int)current_offset;
12754 copy_length = src_size - current_offset;
12757 copy_length = src_size - src_offset;
12761 retry_copy_file_range:
12762# if SIZEOF_OFF_T > SIZEOF_SIZE_T
12764 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
12766 ss = (ssize_t)copy_length;
12768 ss = simple_copy_file_range(stp->src_fptr->
fd, src_offset_ptr, stp->dst_fptr->
fd, NULL, ss, 0);
12772 if (0 < copy_length) {
12773 goto retry_copy_file_range;
12777 if (maygvl_copy_stream_continue_p(0, stp)) {
12778 goto retry_copy_file_range;
12792#if EWOULDBLOCK != EAGAIN
12796 int ret = nogvl_copy_stream_wait_write(stp);
12797 if (ret < 0)
return ret;
12799 goto retry_copy_file_range;
12803 int flags = fcntl(stp->dst_fptr->
fd, F_GETFL);
12805 if (flags != -1 && flags & O_APPEND) {
12811 stp->syserr =
"copy_file_range";
12812 stp->error_no =
errno;
12819#ifdef HAVE_FCOPYFILE
12823 rb_off_t cur, ss = 0;
12824 const rb_off_t src_offset = stp->src_offset;
12827 if (stp->copy_length >= (rb_off_t)0) {
12832 if (!S_ISREG(stp->src_stat.st_mode))
12835 if (!S_ISREG(stp->dst_stat.st_mode))
12837 if (lseek(stp->dst_fptr->
fd, 0, SEEK_CUR) > (rb_off_t)0)
12839 if (fcntl(stp->dst_fptr->
fd, F_GETFL) & O_APPEND) {
12842 rb_off_t end = lseek(stp->dst_fptr->
fd, 0, SEEK_END);
12843 lseek(stp->dst_fptr->
fd, 0, SEEK_SET);
12844 if (end > (rb_off_t)0)
return 0;
12847 if (src_offset > (rb_off_t)0) {
12852 cur = lseek(stp->src_fptr->
fd, 0, SEEK_CUR);
12853 if (cur < (rb_off_t)0 &&
errno) {
12854 stp->error_no =
errno;
12859 r = lseek(stp->src_fptr->
fd, src_offset, SEEK_SET);
12860 if (r < (rb_off_t)0 &&
errno) {
12861 stp->error_no =
errno;
12866 stp->copyfile_state = copyfile_state_alloc();
12867 ret = fcopyfile(stp->src_fptr->
fd, stp->dst_fptr->
fd, stp->copyfile_state, COPYFILE_DATA);
12868 copyfile_state_get(stp->copyfile_state, COPYFILE_STATE_COPIED, &ss);
12872 if (src_offset > (rb_off_t)0) {
12876 r = lseek(stp->src_fptr->
fd, cur, SEEK_SET);
12877 if (r < (rb_off_t)0 &&
errno) {
12878 stp->error_no =
errno;
12890 stp->syserr =
"fcopyfile";
12891 stp->error_no =
errno;
12898#ifdef HAVE_SENDFILE
12901# define USE_SENDFILE
12903# ifdef HAVE_SYS_SENDFILE_H
12904# include <sys/sendfile.h>
12908simple_sendfile(
int out_fd,
int in_fd, rb_off_t *offset, rb_off_t count)
12910 return sendfile(out_fd, in_fd, offset, (
size_t)count);
12913# elif 0 || defined(__APPLE__)
12917# define USE_SENDFILE
12920simple_sendfile(
int out_fd,
int in_fd, rb_off_t *offset, rb_off_t count)
12923 rb_off_t pos = offset ? *offset : lseek(in_fd, 0, SEEK_CUR);
12926 r = sendfile(in_fd, out_fd, pos, &count, NULL, 0);
12929 r = sendfile(in_fd, out_fd, pos, (
size_t)count, NULL, &sbytes, 0);
12931 if (r != 0 && sbytes == 0)
return r;
12936 lseek(in_fd, sbytes, SEEK_CUR);
12938 return (ssize_t)sbytes;
12951 rb_off_t copy_length;
12952 rb_off_t src_offset;
12955 if (!S_ISREG(stp->src_stat.st_mode))
12958 src_size = stp->src_stat.st_size;
12960 if ((stp->dst_stat.st_mode & S_IFMT) != S_IFSOCK)
12964 src_offset = stp->src_offset;
12965 use_pread = src_offset >= (rb_off_t)0;
12967 copy_length = stp->copy_length;
12968 if (copy_length < (rb_off_t)0) {
12970 copy_length = src_size - src_offset;
12974 cur = lseek(stp->src_fptr->
fd, 0, SEEK_CUR);
12975 if (cur < (rb_off_t)0 &&
errno) {
12976 stp->syserr =
"lseek";
12977 stp->error_no =
errno;
12980 copy_length = src_size - cur;
12985# if SIZEOF_OFF_T > SIZEOF_SIZE_T
12987 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
12989 ss = (ssize_t)copy_length;
12992 ss = simple_sendfile(stp->dst_fptr->
fd, stp->src_fptr->
fd, &src_offset, ss);
12995 ss = simple_sendfile(stp->dst_fptr->
fd, stp->src_fptr->
fd, NULL, ss);
13000 if (0 < copy_length) {
13001 goto retry_sendfile;
13005 if (maygvl_copy_stream_continue_p(0, stp))
13006 goto retry_sendfile;
13019#if EWOULDBLOCK != EAGAIN
13032 ret = maygvl_copy_stream_wait_read(0, stp);
13033 if (ret < 0)
return ret;
13035 ret = nogvl_copy_stream_wait_write(stp);
13036 if (ret < 0)
return ret;
13038 goto retry_sendfile;
13040 stp->syserr =
"sendfile";
13041 stp->error_no =
errno;
13049maygvl_read(
int has_gvl,
rb_io_t *fptr,
void *buf,
size_t count)
13052 return rb_io_read_memory(fptr, buf, count);
13054 return read(fptr->
fd, buf, count);
13058maygvl_copy_stream_read(
int has_gvl,
struct copy_stream_struct *stp,
char *buf,
size_t len, rb_off_t offset)
13062 if (offset < (rb_off_t)0) {
13063 ss = maygvl_read(has_gvl, stp->src_fptr, buf,
len);
13066 ss = pread(stp->src_fptr->
fd, buf,
len, offset);
13072 if (maygvl_copy_stream_continue_p(has_gvl, stp))
13076#if EWOULDBLOCK != EAGAIN
13080 int ret = maygvl_copy_stream_wait_read(has_gvl, stp);
13081 if (ret < 0)
return ret;
13086 stp->notimp =
"pread";
13090 stp->syserr = offset < (rb_off_t)0 ?
"read" :
"pread";
13091 stp->error_no =
errno;
13102 ss = write(stp->dst_fptr->
fd, buf+
off,
len);
13104 if (maygvl_copy_stream_continue_p(0, stp))
13106 if (io_again_p(
errno)) {
13107 int ret = nogvl_copy_stream_wait_write(stp);
13108 if (ret < 0)
return ret;
13111 stp->syserr =
"write";
13112 stp->error_no =
errno;
13129 rb_off_t copy_length;
13130 rb_off_t src_offset;
13134 copy_length = stp->copy_length;
13135 use_eof = copy_length < (rb_off_t)0;
13136 src_offset = stp->src_offset;
13137 use_pread = src_offset >= (rb_off_t)0;
13139 if (use_pread && stp->close_src) {
13142 r = lseek(stp->src_fptr->
fd, src_offset, SEEK_SET);
13143 if (r < (rb_off_t)0 &&
errno) {
13144 stp->syserr =
"lseek";
13145 stp->error_no =
errno;
13148 src_offset = (rb_off_t)-1;
13152 while (use_eof || 0 < copy_length) {
13153 if (!use_eof && copy_length < (rb_off_t)
sizeof(buf)) {
13154 len = (size_t)copy_length;
13160 ss = maygvl_copy_stream_read(0, stp, buf,
len, src_offset);
13165 ss = maygvl_copy_stream_read(0, stp, buf,
len, (rb_off_t)-1);
13170 ret = nogvl_copy_stream_write(stp, buf, ss);
13180nogvl_copy_stream_func(
void *arg)
13183#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13187#ifdef USE_COPY_FILE_RANGE
13188 ret = nogvl_copy_file_range(stp);
13193#ifdef HAVE_FCOPYFILE
13194 ret = nogvl_fcopyfile(stp);
13200 ret = nogvl_copy_stream_sendfile(stp);
13205 nogvl_copy_stream_read_write(stp);
13207#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13214copy_stream_fallback_body(
VALUE arg)
13217 const int buflen = 16*1024;
13220 rb_off_t rest = stp->copy_length;
13221 rb_off_t
off = stp->src_offset;
13222 ID read_method = id_readpartial;
13224 if (!stp->src_fptr) {
13226 read_method = id_read;
13233 rb_str_make_independent(buf);
13234 if (stp->copy_length < (rb_off_t)0) {
13239 rb_str_resize(buf, 0);
13242 l = buflen < rest ? buflen : (long)rest;
13244 if (!stp->src_fptr) {
13247 if (read_method == id_read &&
NIL_P(rc))
13252 rb_str_resize(buf, buflen);
13253 ss = maygvl_copy_stream_read(1, stp, RSTRING_PTR(buf), l,
off);
13254 rb_str_resize(buf, ss > 0 ? ss : 0);
13259 if (
off >= (rb_off_t)0)
13262 n = rb_io_write(stp->dst, buf);
13264 stp->total += numwrote;
13266 if (read_method == id_read && RSTRING_LEN(buf) == 0) {
13277 if (!stp->src_fptr && stp->src_offset >= (rb_off_t)0) {
13278 rb_raise(rb_eArgError,
"cannot specify src_offset for non-IO");
13287copy_stream_body(
VALUE arg)
13290 VALUE src_io = stp->src, dst_io = stp->dst;
13291 const int common_oflags = 0
13301 if (src_io ==
argf ||
13305 stp->src_fptr = NULL;
13310 if (!
NIL_P(tmp_io)) {
13317 args[1] =
INT2NUM(O_RDONLY|common_oflags);
13320 stp->close_src = 1;
13325 stat_ret = fstat(stp->src_fptr->
fd, &stp->src_stat);
13326 if (stat_ret < 0) {
13327 stp->syserr =
"fstat";
13328 stp->error_no =
errno;
13333 if (dst_io ==
argf ||
13337 stp->dst_fptr = NULL;
13342 if (!
NIL_P(tmp_io)) {
13343 dst_io = GetWriteIO(tmp_io);
13349 args[1] =
INT2NUM(O_WRONLY|O_CREAT|O_TRUNC|common_oflags);
13353 stp->close_dst = 1;
13356 dst_io = GetWriteIO(dst_io);
13362 stat_ret = fstat(stp->dst_fptr->
fd, &stp->dst_stat);
13363 if (stat_ret < 0) {
13364 stp->syserr =
"fstat";
13365 stp->error_no =
errno;
13372 SET_BINARY_MODE_WITH_SEEK_CUR(stp->src_fptr);
13375 io_ascii8bit_binmode(stp->dst_fptr);
13377 if (stp->src_offset < (rb_off_t)0 && stp->src_fptr && stp->src_fptr->
rbuf.
len) {
13380 if (stp->copy_length >= (rb_off_t)0 && stp->copy_length < (rb_off_t)
len) {
13381 len = (size_t)stp->copy_length;
13384 rb_str_resize(str,
len);
13385 read_buffered_data(RSTRING_PTR(str),
len, stp->src_fptr);
13386 if (stp->dst_fptr) {
13387 if (io_binwrite(RSTRING_PTR(str), RSTRING_LEN(str), stp->dst_fptr, 0) < 0)
13388 rb_sys_fail_on_write(stp->dst_fptr);
13391 rb_io_write(dst_io, str);
13392 rb_str_resize(str, 0);
13394 if (stp->copy_length >= (rb_off_t)0)
13395 stp->copy_length -=
len;
13398 if (stp->dst_fptr && io_fflush(stp->dst_fptr) < 0) {
13402 if (stp->copy_length == 0)
13405 if (stp->src_fptr == NULL || stp->dst_fptr == NULL) {
13406 return copy_stream_fallback(stp);
13409 IO_WITHOUT_GVL(nogvl_copy_stream_func, stp);
13414copy_stream_finalize(
VALUE arg)
13418#ifdef HAVE_FCOPYFILE
13419 if (stp->copyfile_state) {
13420 copyfile_state_free(stp->copyfile_state);
13424 if (stp->close_src) {
13425 rb_io_close_m(stp->src);
13427 if (stp->close_dst) {
13428 rb_io_close_m(stp->dst);
13491rb_io_s_copy_stream(
int argc,
VALUE *argv,
VALUE io)
13493 VALUE src, dst, length, src_offset;
13498 rb_scan_args(argc, argv,
"22", &src, &dst, &length, &src_offset);
13503 st.src_fptr = NULL;
13504 st.dst_fptr = NULL;
13507 st.copy_length = (rb_off_t)-1;
13509 st.copy_length =
NUM2OFFT(length);
13511 if (
NIL_P(src_offset))
13512 st.src_offset = (rb_off_t)-1;
13514 st.src_offset =
NUM2OFFT(src_offset);
13533rb_io_external_encoding(
VALUE io)
13538 return rb_enc_from_encoding(fptr->
encs.
enc2);
13542 return rb_enc_from_encoding(fptr->
encs.
enc);
13545 return rb_enc_from_encoding(io_read_encoding(fptr));
13561rb_io_internal_encoding(
VALUE io)
13566 return rb_enc_from_encoding(io_read_encoding(fptr));
13600rb_io_set_encoding(
int argc,
VALUE *argv,
VALUE io)
13606 return forward(io, id_set_encoding, argc, argv);
13609 argc =
rb_scan_args(argc, argv,
"11:", &v1, &v2, &opt);
13611 io_encoding_set(fptr, v1, v2, opt);
13616rb_stdio_set_default_encoding(
void)
13621 if (isatty(fileno(stdin))) {
13623 rb_encoding *internal = rb_default_internal_encoding();
13624 if (!internal) internal = rb_default_external_encoding();
13626 rb_enc_from_encoding(external),
13627 rb_enc_from_encoding(internal),
13632 rb_io_set_encoding(1, &val,
rb_stdin);
13633 rb_io_set_encoding(1, &val,
rb_stdout);
13634 rb_io_set_encoding(1, &val,
rb_stderr);
13638global_argf_p(
VALUE arg)
13640 return arg ==
argf;
13643typedef VALUE (*argf_encoding_func)(
VALUE io);
13646argf_encoding(
VALUE argf, argf_encoding_func func)
13648 if (!
RTEST(ARGF.current_file)) {
13649 return rb_enc_default_external();
13673 return argf_encoding(
argf, rb_io_external_encoding);
13692 return argf_encoding(
argf, rb_io_internal_encoding);
13731 if (!next_argv()) {
13732 rb_raise(rb_eArgError,
"no stream to set encoding");
13734 rb_io_set_encoding(argc, argv, ARGF.current_file);
13736 ARGF.encs = fptr->
encs;
13756 if (!next_argv()) {
13757 rb_raise(rb_eArgError,
"no stream to tell");
13759 ARGF_FORWARD(0, 0);
13760 return rb_io_tell(ARGF.current_file);
13773 if (!next_argv()) {
13774 rb_raise(rb_eArgError,
"no stream to seek");
13776 ARGF_FORWARD(argc, argv);
13777 return rb_io_seek_m(argc, argv, ARGF.current_file);
13794 if (!next_argv()) {
13795 rb_raise(rb_eArgError,
"no stream to set position");
13797 ARGF_FORWARD(1, &offset);
13798 return rb_io_set_pos(ARGF.current_file, offset);
13819 if (!next_argv()) {
13820 rb_raise(rb_eArgError,
"no stream to rewind");
13822 ARGF_FORWARD(0, 0);
13823 old_lineno =
RFILE(ARGF.current_file)->fptr->lineno;
13824 ret = rb_io_rewind(ARGF.current_file);
13825 if (!global_argf_p(
argf)) {
13826 ARGF.last_lineno = ARGF.lineno -= old_lineno;
13844 if (!next_argv()) {
13845 rb_raise(rb_eArgError,
"no stream");
13847 ARGF_FORWARD(0, 0);
13848 return rb_io_fileno(ARGF.current_file);
13867 ARGF_FORWARD(0, 0);
13868 return ARGF.current_file;
13893 if (
RTEST(ARGF.current_file)) {
13894 if (ARGF.init_p == 0)
return Qtrue;
13896 ARGF_FORWARD(0, 0);
13955 VALUE tmp, str, length;
13959 if (!
NIL_P(length)) {
13964 rb_str_resize(str,0);
13969 if (!next_argv()) {
13972 if (ARGF_GENERIC_INPUT_P()) {
13973 tmp = argf_forward(argc, argv,
argf);
13976 tmp = io_read(argc, argv, ARGF.current_file);
13978 if (
NIL_P(str)) str = tmp;
13981 if (ARGF.next_p != -1) {
13987 else if (argc >= 1) {
13988 long slen = RSTRING_LEN(str);
14004argf_forward_call(
VALUE arg)
14007 argf_forward(p->argc, p->argv, p->argf);
14037 return argf_getpartial(argc, argv,
argf,
Qnil, 0);
14058 return argf_getpartial(argc, argv,
argf, opts, 1);
14064 VALUE tmp, str, length;
14072 no_exception = no_exception_p(opts);
14074 if (!next_argv()) {
14076 rb_str_resize(str, 0);
14080 if (ARGF_GENERIC_INPUT_P()) {
14090 tmp = io_getpartial(argc, argv, ARGF.current_file, no_exception, nonblock);
14093 if (ARGF.next_p == -1) {
14094 return io_nonblock_eof(no_exception);
14099 return io_nonblock_eof(no_exception);
14137 if (!next_argv())
return Qnil;
14138 if (ARGF_GENERIC_INPUT_P()) {
14139 ch = forward_current(rb_intern(
"getc"), 0, 0);
14142 ch = rb_io_getc(ARGF.current_file);
14144 if (
NIL_P(ch) && ARGF.next_p != -1) {
14177 if (!next_argv())
return Qnil;
14179 ch = forward_current(rb_intern(
"getbyte"), 0, 0);
14184 if (
NIL_P(ch) && ARGF.next_p != -1) {
14217 if (!next_argv()) rb_eof_error();
14219 ch = forward_current(rb_intern(
"getc"), 0, 0);
14222 ch = rb_io_getc(ARGF.current_file);
14224 if (
NIL_P(ch) && ARGF.next_p != -1) {
14256 NEXT_ARGF_FORWARD(0, 0);
14257 c = argf_getbyte(
argf);
14264#define FOREACH_ARGF() while (next_argv())
14269 const VALUE current = ARGF.current_file;
14271 if (ARGF.init_p == -1 || current != ARGF.current_file) {
14277#define ARGF_block_call(mid, argc, argv, func, argf) \
14278 rb_block_call_kw(ARGF.current_file, mid, argc, argv, \
14279 func, argf, rb_keyword_given_p())
14284 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_i,
argf);
14285 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14291 if (!global_argf_p(
argf)) {
14292 ARGF.last_lineno = ++ARGF.lineno;
14294 return argf_block_call_i(i,
argf, argc, argv, blockarg);
14300 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_line_i,
argf);
14301 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14349 argf_block_call_line(rb_intern(
"each_line"), argc, argv,
argf);
14380 argf_block_call(rb_intern(
"each_byte"), 0, 0,
argf);
14406 argf_block_call(rb_intern(
"each_char"), 0, 0,
argf);
14432 argf_block_call(rb_intern(
"each_codepoint"), 0, 0,
argf);
14463 return ARGF.filename;
14467argf_filename_getter(
ID id,
VALUE *var)
14469 return argf_filename(*var);
14494 return ARGF.current_file;
14513 ARGF_FORWARD(0, 0);
14534 return RBOOL(ARGF.binmode);
14554 if (ARGF.init_p && ARGF.next_p == 0) {
14583 if (ARGF.next_p != -1) {
14601 ARGF_FORWARD(0, 0);
14628 if (!ARGF.inplace)
return Qnil;
14636 return argf_inplace_mode_get(*var);
14667 ARGF.inplace =
Qnil;
14678 argf_inplace_mode_set(*var, val);
14682ruby_set_inplace_mode(
const char *suffix)
14708argf_argv_getter(
ID id,
VALUE *var)
14710 return argf_argv(*var);
14729 if (!
RTEST(ARGF.current_file)) {
14732 return GetWriteIO(ARGF.current_file);
14744 return rb_io_writev(argf_write_io(
argf), argc, argv);
14759 case RB_IO_WAIT_WRITABLE:
14762 c = rb_eEAGAINWaitWritable;
14764#if EAGAIN != EWOULDBLOCK
14766 c = rb_eEWOULDBLOCKWaitWritable;
14770 c = rb_eEINPROGRESSWaitWritable;
14776 case RB_IO_WAIT_READABLE:
14779 c = rb_eEAGAINWaitReadable;
14781#if EAGAIN != EWOULDBLOCK
14783 c = rb_eEWOULDBLOCKWaitReadable;
14787 c = rb_eEINPROGRESSWaitReadable;
14794 rb_bug(
"invalid read/write type passed to rb_readwrite_sys_fail: %d", waiting);
14800get_LAST_READ_LINE(
ID _x,
VALUE *_y)
15690#include <sys/cygwin.h>
15691 static struct __cygwin_perfile pf[] =
15693 {
"", O_RDONLY | O_BINARY},
15694 {
"", O_WRONLY | O_BINARY},
15695 {
"", O_RDWR | O_BINARY},
15696 {
"", O_APPEND | O_BINARY},
15699 cygwin_internal(CW_PERFILE, pf);
15748 rb_eEAGAINWaitReadable = rb_define_class_under(
rb_cIO,
"EAGAINWaitReadable", rb_eEAGAIN);
15751 rb_eEAGAINWaitWritable = rb_define_class_under(
rb_cIO,
"EAGAINWaitWritable", rb_eEAGAIN);
15753#if EAGAIN == EWOULDBLOCK
15755 rb_define_const(
rb_cIO,
"EWOULDBLOCKWaitReadable", rb_eEAGAINWaitReadable);
15757 rb_define_const(
rb_cIO,
"EWOULDBLOCKWaitWritable", rb_eEAGAINWaitWritable);
15760 rb_eEWOULDBLOCKWaitReadable = rb_define_class_under(
rb_cIO,
"EWOULDBLOCKWaitReadable", rb_eEWOULDBLOCK);
15763 rb_eEWOULDBLOCKWaitWritable = rb_define_class_under(
rb_cIO,
"EWOULDBLOCKWaitWritable", rb_eEWOULDBLOCK);
15767 rb_eEINPROGRESSWaitReadable = rb_define_class_under(
rb_cIO,
"EINPROGRESSWaitReadable", rb_eEINPROGRESS);
15770 rb_eEINPROGRESSWaitWritable = rb_define_class_under(
rb_cIO,
"EINPROGRESSWaitWritable", rb_eEINPROGRESS);
15805 rb_gvar_ractor_local(
"$/");
15807 rb_gvar_ractor_local(
"$-0");
15811 rb_gvar_ractor_local(
"$_");
15812 rb_gvar_box_dynamic(
"$_");
15928 rb_gvar_ractor_local(
"$stdin");
15929 rb_gvar_ractor_local(
"$stdout");
15930 rb_gvar_ractor_local(
"$>");
15931 rb_gvar_ractor_local(
"$stderr");
15952 rb_cARGF = rb_define_class(
"ARGF",
rb_cObject);
16017 rb_define_method(rb_cARGF,
"external_encoding", argf_external_encoding, 0);
16018 rb_define_method(rb_cARGF,
"internal_encoding", argf_internal_encoding, 0);
16037 rb_gvar_ractor_local(
"$-i");
16041#if defined (_WIN32) || defined(__CYGWIN__)
16042 atexit(pipe_atexit);
16054 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_class_new(VALUE super)
Creates a new, anonymous class.
void rb_define_alias(VALUE klass, const char *name1, const char *name2)
Defines an alias of a method.
int rb_scan_args_kw(int kw_flag, int argc, const VALUE *argv, const char *fmt,...)
Identical to rb_scan_args(), except it also accepts kw_splat.
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Retrieves argument from argc and argv to given VALUE references according to the format string.
int rb_block_given_p(void)
Determines if the current method is given a block.
int rb_get_kwargs(VALUE keyword_hash, const ID *table, int required, int optional, VALUE *values)
Keyword argument deconstructor.
#define ECONV_AFTER_OUTPUT
Old name of RUBY_ECONV_AFTER_OUTPUT.
#define rb_str_new2
Old name of rb_str_new_cstr.
#define TYPE(_)
Old name of rb_type.
#define RB_INTEGER_TYPE_P
Old name of rb_integer_type_p.
#define ENC_CODERANGE_7BIT
Old name of RUBY_ENC_CODERANGE_7BIT.
#define T_FILE
Old name of RUBY_T_FILE.
#define ENC_CODERANGE_VALID
Old name of RUBY_ENC_CODERANGE_VALID.
#define ECONV_UNIVERSAL_NEWLINE_DECORATOR
Old name of RUBY_ECONV_UNIVERSAL_NEWLINE_DECORATOR.
#define OBJ_INIT_COPY(obj, orig)
Old name of RB_OBJ_INIT_COPY.
#define ALLOC
Old name of RB_ALLOC.
#define RFLOAT_VALUE
Old name of rb_float_value.
#define T_STRING
Old name of RUBY_T_STRING.
#define Qundef
Old name of RUBY_Qundef.
#define INT2FIX
Old name of RB_INT2FIX.
#define rb_str_cat2
Old name of rb_str_cat_cstr.
#define T_NIL
Old name of RUBY_T_NIL.
#define UNREACHABLE
Old name of RBIMPL_UNREACHABLE.
#define ID2SYM
Old name of RB_ID2SYM.
#define T_BIGNUM
Old name of RUBY_T_BIGNUM.
#define OBJ_FREEZE
Old name of RB_OBJ_FREEZE.
#define T_FIXNUM
Old name of RUBY_T_FIXNUM.
#define UNREACHABLE_RETURN
Old name of RBIMPL_UNREACHABLE_RETURN.
#define FIX2UINT
Old name of RB_FIX2UINT.
#define SSIZET2NUM
Old name of RB_SSIZE2NUM.
#define ZALLOC
Old name of RB_ZALLOC.
#define CLASS_OF
Old name of rb_class_of.
#define rb_ary_new4
Old name of rb_ary_new_from_values.
#define ENCODING_MAXNAMELEN
Old name of RUBY_ENCODING_MAXNAMELEN.
#define MBCLEN_NEEDMORE_LEN(ret)
Old name of ONIGENC_MBCLEN_NEEDMORE_LEN.
#define ENCODING_GET(obj)
Old name of RB_ENCODING_GET.
#define LONG2FIX
Old name of RB_INT2FIX.
#define NUM2UINT
Old name of RB_NUM2UINT.
#define ALLOC_N
Old name of RB_ALLOC_N.
#define MBCLEN_CHARFOUND_LEN(ret)
Old name of ONIGENC_MBCLEN_CHARFOUND_LEN.
#define LONG2NUM
Old name of RB_LONG2NUM.
#define rb_exc_new3
Old name of rb_exc_new_str.
#define STRNCASECMP
Old name of st_locale_insensitive_strncasecmp.
#define MBCLEN_INVALID_P(ret)
Old name of ONIGENC_MBCLEN_INVALID_P.
#define ISASCII
Old name of rb_isascii.
#define ECONV_STATEFUL_DECORATOR_MASK
Old name of RUBY_ECONV_STATEFUL_DECORATOR_MASK.
#define Qtrue
Old name of RUBY_Qtrue.
#define MBCLEN_NEEDMORE_P(ret)
Old name of ONIGENC_MBCLEN_NEEDMORE_P.
#define ECONV_PARTIAL_INPUT
Old name of RUBY_ECONV_PARTIAL_INPUT.
#define NUM2INT
Old name of RB_NUM2INT.
#define ECONV_ERROR_HANDLER_MASK
Old name of RUBY_ECONV_ERROR_HANDLER_MASK.
#define INT2NUM
Old name of RB_INT2NUM.
#define Qnil
Old name of RUBY_Qnil.
#define Qfalse
Old name of RUBY_Qfalse.
#define FIX2LONG
Old name of RB_FIX2LONG.
#define ENC_CODERANGE_BROKEN
Old name of RUBY_ENC_CODERANGE_BROKEN.
#define T_ARRAY
Old name of RUBY_T_ARRAY.
#define NIL_P
Old name of RB_NIL_P.
#define ALLOCV_N
Old name of RB_ALLOCV_N.
#define MBCLEN_CHARFOUND_P(ret)
Old name of ONIGENC_MBCLEN_CHARFOUND_P.
#define NUM2CHR
Old name of RB_NUM2CHR.
#define NUM2LONG
Old name of RB_NUM2LONG.
#define UINT2NUM
Old name of RB_UINT2NUM.
#define FIXNUM_P
Old name of RB_FIXNUM_P.
#define ECONV_NEWLINE_DECORATOR_MASK
Old name of RUBY_ECONV_NEWLINE_DECORATOR_MASK.
#define CONST_ID
Old name of RUBY_CONST_ID.
#define rb_ary_new2
Old name of rb_ary_new_capa.
#define NUM2SIZET
Old name of RB_NUM2SIZE.
#define ENC_CODERANGE_SET(obj, cr)
Old name of RB_ENC_CODERANGE_SET.
#define rb_str_new4
Old name of rb_str_new_frozen.
#define ALLOCV_END
Old name of RB_ALLOCV_END.
#define SYMBOL_P
Old name of RB_SYMBOL_P.
#define ECONV_DEFAULT_NEWLINE_DECORATOR
Old name of RUBY_ECONV_DEFAULT_NEWLINE_DECORATOR.
void rb_category_warn(rb_warning_category_t category, const char *fmt,...)
Identical to rb_category_warning(), except it reports unless $VERBOSE is nil.
void rb_category_warning(rb_warning_category_t category, const char *fmt,...)
Identical to rb_warning(), except it takes additional "category" parameter.
VALUE rb_eNotImpError
NotImplementedError exception.
void rb_exc_raise(VALUE mesg)
Raises an exception in the current thread.
void rb_syserr_fail(int e, const char *mesg)
Raises appropriate exception that represents a C errno.
void rb_readwrite_syserr_fail(enum rb_io_wait_readwrite waiting, int n, const char *mesg)
Identical to rb_readwrite_sys_fail(), except it does not depend on C global variable errno.
VALUE rb_eIOError
IOError exception.
VALUE rb_eStandardError
StandardError exception.
void rb_mod_syserr_fail_str(VALUE mod, int e, VALUE mesg)
Identical to rb_mod_syserr_fail(), except it takes the message in Ruby's String instead of C's.
void rb_syserr_fail_str(int e, VALUE mesg)
Identical to rb_syserr_fail(), except it takes the message in Ruby's String instead of C's.
#define ruby_verbose
This variable controls whether the interpreter is in debug mode.
VALUE rb_eTypeError
TypeError exception.
VALUE rb_eEOFError
EOFError exception.
void rb_readwrite_sys_fail(enum rb_io_wait_readwrite waiting, const char *mesg)
Raises appropriate exception using the parameters.
void rb_iter_break_value(VALUE val)
Identical to rb_iter_break(), except it additionally takes the "value" of this breakage.
rb_io_wait_readwrite
for rb_readwrite_sys_fail first argument
VALUE rb_eRuntimeError
RuntimeError exception.
void rb_warn(const char *fmt,...)
Identical to rb_warning(), except it reports unless $VERBOSE is nil.
VALUE rb_eSystemCallError
SystemCallError exception.
@ RB_WARN_CATEGORY_DEPRECATED
Warning is for deprecated features.
VALUE rb_mKernel
Kernel module.
VALUE rb_check_to_int(VALUE val)
Identical to rb_check_to_integer(), except it uses #to_int for conversion.
VALUE rb_cObject
Object class.
VALUE rb_any_to_s(VALUE obj)
Generates a textual representation of the given object.
VALUE rb_obj_alloc(VALUE klass)
Allocates an instance of the given class.
VALUE rb_class_new_instance(int argc, const VALUE *argv, VALUE klass)
Allocates, then initialises an instance of the given class.
VALUE rb_class_new_instance_kw(int argc, const VALUE *argv, VALUE klass, int kw_splat)
Identical to rb_class_new_instance(), except you can specify how to handle the last element of the gi...
VALUE rb_mEnumerable
Enumerable module.
VALUE rb_stdin
STDIN constant.
VALUE rb_stderr
STDERR constant.
VALUE rb_obj_class(VALUE obj)
Queries the class of an object.
VALUE rb_obj_dup(VALUE obj)
Duplicates the given object.
VALUE rb_inspect(VALUE obj)
Generates a human-readable textual representation of the given object.
VALUE rb_mWaitReadable
IO::WaitReadable module.
VALUE rb_mWaitWritable
IO::WaitReadable module.
VALUE rb_obj_freeze(VALUE obj)
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.
#define RB_OBJ_WRITTEN(old, oldv, young)
Identical to RB_OBJ_WRITE(), except it doesn't write any values, but only a WB declaration.
#define RB_OBJ_WRITE(old, slot, young)
Declaration of a "back" pointer.
static unsigned int rb_enc_codepoint(const char *p, const char *e, rb_encoding *enc)
Queries the code point of character pointed by the passed pointer.
VALUE rb_str_conv_enc(VALUE str, rb_encoding *from, rb_encoding *to)
Encoding conversion main routine.
VALUE rb_enc_uint_chr(unsigned int code, rb_encoding *enc)
Encodes the passed code point into a series of bytes.
long rb_str_coderange_scan_restartable(const char *str, const char *end, rb_encoding *enc, int *cr)
Scans the passed string until it finds something odd.
int rb_econv_prepare_options(VALUE opthash, VALUE *ecopts, int ecflags)
Identical to rb_econv_prepare_opts(), except it additionally takes the initial value of flags.
VALUE rb_econv_open_exc(const char *senc, const char *denc, int ecflags)
Creates a rb_eConverterNotFoundError exception object (but does not raise).
rb_econv_result_t rb_econv_convert(rb_econv_t *ec, const unsigned char **source_buffer_ptr, const unsigned char *source_buffer_end, unsigned char **destination_buffer_ptr, unsigned char *destination_buffer_end, int flags)
Converts a string from an encoding to another.
rb_econv_result_t
return value of rb_econv_convert()
@ econv_incomplete_input
The conversion stopped in middle of reading a character, possibly due to a partial read of a socket e...
@ econv_finished
The conversion stopped after converting everything.
@ econv_undefined_conversion
The conversion stopped when it found a character in the input which cannot be representable in the ou...
@ econv_source_buffer_empty
The conversion stopped because there is no input.
@ econv_destination_buffer_full
The conversion stopped because there is no destination.
@ econv_invalid_byte_sequence
The conversion stopped when it found an invalid sequence.
int rb_econv_putbackable(rb_econv_t *ec)
Queries if rb_econv_putback() makes sense, i.e.
const char * rb_econv_asciicompat_encoding(const char *encname)
Queries the passed encoding's corresponding ASCII compatible encoding.
VALUE rb_econv_str_convert(rb_econv_t *ec, VALUE src, int flags)
Identical to rb_econv_convert(), except it takes Ruby's string instead of C's pointer.
rb_econv_t * rb_econv_open_opts(const char *source_encoding, const char *destination_encoding, int ecflags, VALUE ecopts)
Identical to rb_econv_open(), except it additionally takes a hash of optional strings.
void rb_econv_binmode(rb_econv_t *ec)
This badly named function does not set the destination encoding to binary, but instead just nullifies...
VALUE rb_str_encode(VALUE str, VALUE to, int ecflags, VALUE ecopts)
Converts the contents of the passed string from its encoding to the passed one.
VALUE rb_econv_make_exception(rb_econv_t *ec)
This function makes sense right after rb_econv_convert() returns.
void rb_econv_check_error(rb_econv_t *ec)
This is a rb_econv_make_exception() + rb_exc_raise() combo.
void rb_econv_close(rb_econv_t *ec)
Destructs a converter.
void rb_econv_putback(rb_econv_t *ec, unsigned char *p, int n)
Puts back the bytes.
VALUE rb_funcall(VALUE recv, ID mid, int n,...)
Calls a method.
VALUE rb_funcallv_kw(VALUE recv, ID mid, int argc, const VALUE *argv, int kw_splat)
Identical to rb_funcallv(), except you can specify how to handle the last element of the given array.
VALUE rb_funcallv(VALUE recv, ID mid, int argc, const VALUE *argv)
Identical to rb_funcall(), except it takes the method arguments as a C array.
Defines RBIMPL_HAS_BUILTIN.
VALUE rb_ary_concat(VALUE lhs, VALUE rhs)
Destructively appends the contents of latter into the end of former.
VALUE rb_ary_shift(VALUE ary)
Destructively deletes an element from the beginning of the passed array and returns what was deleted.
VALUE rb_check_array_type(VALUE obj)
Try converting an object to its array representation using its to_ary method, if any.
VALUE rb_ary_new(void)
Allocates a new, empty array.
VALUE rb_ary_new_capa(long capa)
Identical to rb_ary_new(), except it additionally specifies how many rooms of objects it should alloc...
VALUE rb_ary_push(VALUE ary, VALUE elem)
Special case of rb_ary_cat() that it adds only one element.
VALUE rb_ary_entry(VALUE ary, long off)
Queries an element of an array.
VALUE rb_assoc_new(VALUE car, VALUE cdr)
Identical to rb_ary_new_from_values(), except it expects exactly two parameters.
#define RETURN_ENUMERATOR(obj, argc, argv)
Identical to RETURN_SIZED_ENUMERATOR(), except its size is unknown.
static int rb_check_arity(int argc, int min, int max)
Ensures that the passed integer is in the passed range.
VALUE rb_io_printf(int argc, const VALUE *argv, VALUE io)
This is a rb_f_sprintf() + rb_io_write() combo.
VALUE rb_io_gets(VALUE io)
Reads a "line" from the given IO.
int rb_cloexec_pipe(int fildes[2])
Opens a pipe with closing on exec.
VALUE rb_io_print(int argc, const VALUE *argv, VALUE io)
Iterates over the passed array to apply rb_io_write() individually.
VALUE rb_io_addstr(VALUE io, VALUE str)
Identical to rb_io_write(), except it always returns the passed IO.
void rb_write_error(const char *str)
Writes the given error message to somewhere applicable.
VALUE rb_io_ungetbyte(VALUE io, VALUE b)
Identical to rb_io_ungetc(), except it doesn't take the encoding of the passed IO into account.
VALUE rb_io_getbyte(VALUE io)
Reads a byte from the given IO.
int rb_cloexec_dup2(int oldfd, int newfd)
Identical to rb_cloexec_dup(), except you can specify the destination file descriptor.
VALUE rb_io_fdopen(int fd, int flags, const char *path)
Creates an IO instance whose backend is the given file descriptor.
void rb_update_max_fd(int fd)
Informs the interpreter that the passed fd can be the max.
int rb_cloexec_open(const char *pathname, int flags, mode_t mode)
Opens a file that closes on exec.
VALUE rb_output_rs
The record separator character for outputs, or the $\.
VALUE rb_io_eof(VALUE io)
Queries if the passed IO is at the end of file.
void rb_write_error2(const char *str, long len)
Identical to rb_write_error(), except it additionally takes the message's length.
void rb_close_before_exec(int lowfd, int maxhint, VALUE noclose_fds)
Closes everything.
int rb_reserved_fd_p(int fd)
Queries if the given FD is reserved or not.
void rb_fd_fix_cloexec(int fd)
Sets or clears the close-on-exec flag of the passed file descriptor to the desired state.
VALUE rb_io_ascii8bit_binmode(VALUE io)
Forces no conversions be applied to the passed IO.
VALUE rb_io_binmode(VALUE io)
Sets the binmode.
VALUE rb_io_ungetc(VALUE io, VALUE c)
"Unget"s a string.
int rb_pipe(int *pipes)
This is an rb_cloexec_pipe() + rb_update_max_fd() combo.
VALUE rb_gets(void)
Much like rb_io_gets(), but it reads from the mysterious ARGF object.
int rb_cloexec_fcntl_dupfd(int fd, int minfd)
Duplicates a file descriptor with closing on exec.
VALUE rb_output_fs
The field separator character for outputs, or the $,.
VALUE rb_file_open_str(VALUE fname, const char *fmode)
Identical to rb_file_open(), except it takes the pathname as a Ruby's string instead of C's.
int rb_cloexec_dup(int oldfd)
Identical to rb_cloexec_fcntl_dupfd(), except it implies minfd is 3.
VALUE rb_file_open(const char *fname, const char *fmode)
Opens a file located at the given path.
VALUE rb_io_close(VALUE io)
Closes the IO.
VALUE rb_default_rs
This is the default value of rb_rs, i.e.
void rb_lastline_set(VALUE str)
Updates $_.
VALUE rb_lastline_get(void)
Queries the last line, or the $_.
int rb_obj_method_arity(VALUE obj, ID mid)
Identical to rb_mod_method_arity(), except it searches for singleton methods rather than instance met...
rb_pid_t rb_waitpid(rb_pid_t pid, int *status, int flags)
Waits for a process, with releasing GVL.
void rb_last_status_set(int status, rb_pid_t pid)
Sets the "last status", or the $?.
VALUE rb_str_append(VALUE dst, VALUE src)
Identical to rb_str_buf_append(), except it converts the right hand side before concatenating.
#define rb_str_new(str, len)
Allocates an instance of rb_cString.
#define rb_str_buf_cat
Just another name of rb_str_cat.
#define rb_usascii_str_new(str, len)
Identical to rb_str_new, except it generates a string of "US ASCII" encoding.
size_t rb_str_capacity(VALUE str)
Queries the capacity of the given string.
VALUE rb_str_new_frozen(VALUE str)
Creates a frozen copy of the string, if necessary.
VALUE rb_str_dup(VALUE str)
Duplicates a string.
VALUE rb_str_cat(VALUE dst, const char *src, long srclen)
Destructively appends the passed contents to the string.
VALUE rb_str_locktmp(VALUE str)
Obtains a "temporary lock" of the string.
VALUE rb_str_equal(VALUE str1, VALUE str2)
Equality of two strings.
void rb_str_set_len(VALUE str, long len)
Overwrites the length of the string.
VALUE rb_str_buf_cat_ascii(VALUE dst, const char *src)
Identical to rb_str_cat_cstr(), except it additionally assumes the source string be a NUL terminated ...
VALUE rb_check_string_type(VALUE obj)
Try converting an object to its stringised representation using its to_str method,...
VALUE rb_str_substr(VALUE str, long beg, long len)
This is the implementation of two-argumented String#slice.
VALUE rb_str_unlocktmp(VALUE str)
Releases a lock formerly obtained by rb_str_locktmp().
void rb_str_modify_expand(VALUE str, long capa)
Identical to rb_str_modify(), except it additionally expands the capacity of the receiver.
VALUE rb_str_buf_new(long capa)
Allocates a "string buffer".
#define rb_str_new_cstr(str)
Identical to rb_str_new, except it assumes the passed pointer is a pointer to a C string.
VALUE rb_obj_as_string(VALUE obj)
Try converting an object to its stringised representation using its to_s method, if any.
int rb_thread_interrupted(VALUE thval)
Checks if the thread's execution was recently interrupted.
VALUE rb_mutex_new(void)
Creates a mutex.
int rb_thread_fd_writable(int fd)
Identical to rb_thread_wait_fd(), except it blocks the current thread until the given file descriptor...
VALUE rb_exec_recursive(VALUE(*f)(VALUE g, VALUE h, int r), VALUE g, VALUE h)
"Recursion" API entry point.
VALUE rb_mutex_synchronize(VALUE mutex, VALUE(*func)(VALUE arg), VALUE arg)
Obtains the lock, runs the passed function, and releases the lock when it completes.
void rb_thread_check_ints(void)
Checks for interrupts.
VALUE rb_thread_current(void)
Obtains the "current" thread.
int rb_thread_wait_fd(int fd)
Blocks the current thread until the given file descriptor is ready to be read.
void rb_thread_sleep(int sec)
Blocks for the given period of time.
struct timeval rb_time_interval(VALUE num)
Creates a "time interval".
void rb_set_class_path(VALUE klass, VALUE space, const char *name)
Names a class.
VALUE rb_ivar_set(VALUE obj, ID name, VALUE val)
Identical to rb_iv_set(), except it accepts the name as an ID instead of a C string.
VALUE rb_class_name(VALUE obj)
Queries the name of the given object's class.
int rb_respond_to(VALUE obj, ID mid)
Queries if the object responds to the method.
int rb_method_basic_definition_p(VALUE klass, ID mid)
Well... Let us hesitate from describing what a "basic definition" is.
VALUE rb_check_funcall(VALUE recv, ID mid, int argc, const VALUE *argv)
Identical to rb_funcallv(), except it returns RUBY_Qundef instead of raising rb_eNoMethodError.
void rb_define_alloc_func(VALUE klass, rb_alloc_func_t func)
Sets the allocator function of a class.
static ID rb_intern_const(const char *str)
This is a "tiny optimisation" over rb_intern().
#define RB_ID2SYM
Just another name of rb_id2sym.
void rb_define_global_const(const char *name, VALUE val)
Identical to rb_define_const(), except it defines that of "global", i.e.
void rb_define_readonly_variable(const char *name, const VALUE *var)
Identical to rb_define_variable(), except it does not allow Ruby programs to assign values to such gl...
rb_gvar_setter_t rb_gvar_readonly_setter
This function just raises rb_eNameError.
#define FMODE_READABLE
The IO is opened for reading.
enum rb_io_mode rb_io_modestr_fmode(const char *modestr)
Maps a file mode string (that rb_file_open() takes) into a mixture of FMODE_ flags.
VALUE rb_io_get_io(VALUE io)
Identical to rb_io_check_io(), except it raises exceptions on conversion failures.
VALUE rb_io_timeout(VALUE io)
Get the timeout associated with the specified io object.
VALUE rb_io_taint_check(VALUE obj)
void rb_io_read_check(rb_io_t *fptr)
Blocks until there is a pending read in the passed IO.
int rb_io_modestr_oflags(const char *modestr)
Identical to rb_io_modestr_fmode(), except it returns a mixture of O_ flags.
#define FMODE_SETENC_BY_BOM
This flag amends the encoding of the IO so that the BOM of the contents of the IO takes effect.
rb_io_event
Type of events that an IO can wait.
@ RUBY_IO_READABLE
IO::READABLE
@ RUBY_IO_PRIORITY
IO::PRIORITY
@ RUBY_IO_WRITABLE
IO::WRITABLE
#define FMODE_READWRITE
The IO is opened for both read/write.
#define FMODE_EXTERNAL
This flag means that an IO object is wrapping an "external" file descriptor, which is owned by someth...
#define GetOpenFile
This is an old name of RB_IO_POINTER.
void rb_io_check_byte_readable(rb_io_t *fptr)
Asserts that an IO is opened for byte-based reading.
#define FMODE_TTY
The IO is a TTY.
#define FMODE_CREATE
The IO is opened for creating.
void rb_io_check_readable(rb_io_t *fptr)
Just another name of rb_io_check_byte_readable.
int rb_wait_for_single_fd(int fd, int events, struct timeval *tv)
Blocks until the passed file descriptor is ready for the passed events.
FILE * rb_fdopen(int fd, const char *modestr)
Identical to rb_io_stdio_file(), except it takes file descriptors instead of Ruby's IO.
int rb_io_extract_encoding_option(VALUE opt, rb_encoding **enc_p, rb_encoding **enc2_p, enum rb_io_mode *fmode_p)
This function breaks down the option hash that IO#initialize takes into components.
int rb_io_descriptor(VALUE io)
Returns an integer representing the numeric file descriptor for io.
#define FMODE_WRITABLE
The IO is opened for writing.
FILE * rb_io_stdio_file(rb_io_t *fptr)
Finds or creates a stdio's file structure from a Ruby's one.
#define FMODE_APPEND
The IO is opened for appending.
#define MakeOpenFile
This is an old name of RB_IO_OPEN.
#define FMODE_DUPLEX
Ruby eventually detects that the IO is bidirectional.
#define FMODE_BINMODE
The IO is in "binary mode".
int rb_io_maybe_wait_readable(int error, VALUE io, VALUE timeout)
Blocks until the passed IO is ready for reading, if that makes sense for the passed errno.
int capa
Designed capacity of the buffer.
#define RB_IO_POINTER(obj, fp)
Queries the underlying IO pointer.
VALUE rb_io_maybe_wait(int error, VALUE io, VALUE events, VALUE timeout)
Identical to rb_io_wait() except it additionally takes previous errno.
VALUE rb_eIOTimeoutError
Indicates that a timeout has occurred while performing an IO operation.
char * ptr
Pointer to the underlying memory region, of at least capa bytes.
#define FMODE_SYNC
The IO is in "sync mode".
int off
Offset inside of ptr.
VALUE rb_io_path(VALUE io)
Returns the path for the given IO.
void rb_io_extract_modeenc(VALUE *vmode_p, VALUE *vperm_p, VALUE opthash, int *oflags_p, enum rb_io_mode *fmode_p, rb_io_enc_t *convconfig_p)
This function can be seen as an extended version of rb_io_extract_encoding_option() that not only con...
void rb_io_check_initialized(rb_io_t *fptr)
Asserts that the passed IO is initialised.
#define FMODE_EXCL
This flag amends the effect of FMODE_CREATE, so that if there already is a file at the given path the...
#define FMODE_TEXTMODE
The IO is in "text mode".
int rb_io_fptr_finalize(rb_io_t *fptr)
Destroys the given IO.
VALUE rb_io_check_io(VALUE io)
Try converting an object to its IO representation using its to_io method, if any.
VALUE rb_io_closed_p(VALUE io)
Returns whether or not the underlying IO is closed.
VALUE rb_io_set_timeout(VALUE io, VALUE timeout)
Set the timeout associated with the specified io object.
ssize_t rb_io_bufwrite(VALUE io, const void *buf, size_t size)
Buffered write to the passed IO.
void rb_io_check_char_readable(rb_io_t *fptr)
Asserts that an IO is opened for character-based reading.
#define FMODE_TRUNC
This flag amends the effect of FMODE_CREATE, so that if there already is a file at the given path it ...
VALUE rb_io_get_write_io(VALUE io)
Queries the tied IO for writing.
void rb_io_set_nonblock(rb_io_t *fptr)
Instructs the OS to put its internal file structure into "nonblocking mode".
int rb_io_wait_writable(int fd)
Blocks until the passed file descriptor gets writable.
VALUE rb_io_open_descriptor(VALUE klass, int descriptor, int mode, VALUE path, VALUE timeout, struct rb_io_encoding *encoding)
Allocate a new IO object, with the given file descriptor.
VALUE rb_io_set_write_io(VALUE io, VALUE w)
Assigns the tied IO for writing.
void rb_io_check_writable(rb_io_t *fptr)
Asserts that an IO is opened for writing.
int rb_io_maybe_wait_writable(int error, VALUE io, VALUE timeout)
Blocks until the passed IO is ready for writing, if that makes sense for the passed errno.
void rb_io_check_closed(rb_io_t *fptr)
This badly named function asserts that the passed IO is open.
int rb_io_wait_readable(int fd)
Blocks until the passed file descriptor gets readable.
void rb_io_synchronized(rb_io_t *fptr)
Sets FMODE_SYNC.
VALUE rb_io_wait(VALUE io, VALUE events, VALUE timeout)
Blocks until the passed IO is ready for the passed events.
int len
Length of the buffer.
VALUE rb_ractor_stdin(void)
Queries the standard input of the current Ractor that is calling this function.
void rb_ractor_stderr_set(VALUE io)
Assigns an IO to the standard error of the Ractor that is calling this function.
void rb_ractor_stdout_set(VALUE io)
Assigns an IO to the standard output of the Ractor that is calling this function.
void rb_ractor_stdin_set(VALUE io)
Assigns an IO to the standard input of the Ractor that is calling this function.
void * rb_thread_call_with_gvl(void *(*func)(void *), void *data1)
(Re-)acquires the GVL.
#define RB_NUM2INT
Just another name of rb_num2int_inline.
#define RB_INT2NUM
Just another name of rb_int2num_inline.
VALUE rb_f_sprintf(int argc, const VALUE *argv)
Identical to rb_str_format(), except how the arguments are arranged.
#define RB_BLOCK_CALL_FUNC_ARGLIST(yielded_arg, callback_arg)
Shim for block function parameters.
VALUE rb_yield_values2(int n, const VALUE *argv)
Identical to rb_yield_values(), except it takes the parameters as a C array instead of variadic argum...
VALUE rb_yield(VALUE val)
Yields the block.
void rb_fd_term(rb_fdset_t *f)
Destroys the rb_fdset_t, releasing any memory and resources it used.
#define MEMZERO(p, type, n)
Handy macro to erase a region of memory.
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
#define MEMMOVE(p1, p2, type, n)
Handy macro to call memmove.
#define NUM2MODET
Converts a C's mode_t into an instance of rb_cInteger.
void rb_define_hooked_variable(const char *q, VALUE *w, type *e, void_type *r)
Define a function-backended global variable.
void rb_define_virtual_variable(const char *q, type *w, void_type *e)
Define a function-backended global variable.
VALUE rb_rescue2(type *q, VALUE w, type *e, VALUE r,...)
An equivalent of rescue clause.
VALUE rb_ensure(type *q, VALUE w, type *e, VALUE r)
An equivalent of ensure clause.
#define PRI_OFFT_PREFIX
A rb_sprintf() format prefix to be used for an off_t parameter.
#define OFFT2NUM
Converts a C's off_t into an instance of rb_cInteger.
#define NUM2OFFT
Converts an instance of rb_cNumeric into C's off_t.
#define PIDT2NUM
Converts a C's pid_t into an instance of rb_cInteger.
#define rb_fd_isset
Queries if the given fd is in the rb_fdset_t.
#define rb_fd_select
Waits for multiple file descriptors at once.
#define rb_fd_init
Initialises the :given :rb_fdset_t.
#define rb_fd_set
Sets the given fd to the rb_fdset_t.
#define RARRAY_LEN
Just another name of rb_array_len.
static int RARRAY_LENINT(VALUE ary)
Identical to rb_array_len(), except it differs for the return type.
#define RARRAY_AREF(a, i)
#define RARRAY_CONST_PTR
Just another name of rb_array_const_ptr.
#define RFILE(obj)
Convenient casting macro.
#define StringValue(v)
Ensures that the parameter object is a String.
static char * RSTRING_END(VALUE str)
Queries the end of the contents pointer of the string.
#define RSTRING_GETMEM(str, ptrvar, lenvar)
Convenient macro to obtain the contents and length at once.
#define StringValueCStr(v)
Identical to StringValuePtr, except it additionally checks for the contents for viability as a C stri...
#define RUBY_TYPED_DEFAULT_FREE
This is a value you can set to rb_data_type_struct::dfree.
#define TypedData_Make_Struct(klass, type, data_type, sval)
Identical to TypedData_Wrap_Struct, except it allocates a new data region internally instead of takin...
VALUE rb_get_argv(void)
Queries the arguments passed to the current process that you can access from Ruby as ARGV.
void rb_p(VALUE obj)
Inspects an object.
#define FilePathValue(v)
Ensures that the parameter object is a path.
#define errno
Ractor-aware version of errno.
#define RB_SCAN_ARGS_LAST_HASH_KEYWORDS
Treat a final argument as keywords if it is a hash, and not as keywords otherwise.
#define RB_PASS_CALLED_KEYWORDS
Pass keywords if current method is called with keywords, useful for argument delegation.
VALUE rb_fiber_scheduler_current(void)
Identical to rb_fiber_scheduler_get(), except it also returns RUBY_Qnil in case of a blocking fiber.
VALUE rb_fiber_scheduler_make_timeout(struct timeval *timeout)
Converts the passed timeout to an expression that rb_fiber_scheduler_block() etc.
VALUE rb_fiber_scheduler_io_wait_readable(VALUE scheduler, VALUE io)
Non-blocking wait until the passed IO is ready for reading.
VALUE rb_fiber_scheduler_io_wait(VALUE scheduler, VALUE io, VALUE events, VALUE timeout)
Non-blocking version of rb_io_wait().
static ssize_t rb_fiber_scheduler_io_result_apply(VALUE result)
Apply an io result to the local thread, returning the value of the original system call that created ...
VALUE rb_fiber_scheduler_io_pread_memory(VALUE scheduler, VALUE io, rb_off_t from, void *base, size_t size)
Non-blocking pread from the passed IO using a native buffer.
VALUE rb_fiber_scheduler_io_selectv(VALUE scheduler, int argc, VALUE *argv)
Non-blocking version of IO.select, argv variant.
VALUE rb_fiber_scheduler_io_read_memory(VALUE scheduler, VALUE io, void *base, size_t size)
Non-blocking read from the passed IO using a native buffer.
VALUE rb_fiber_scheduler_current_for_thread(VALUE thread)
Identical to rb_fiber_scheduler_current(), except it queries for that of the passed thread value inst...
VALUE rb_fiber_scheduler_io_pwrite_memory(VALUE scheduler, VALUE io, rb_off_t from, const void *base, size_t size)
Non-blocking pwrite to the passed IO using a native buffer.
VALUE rb_fiber_scheduler_current_for_threadptr(struct rb_thread_struct *thread)
Identical to rb_fiber_scheduler_current_for_thread(), except it expects a threadptr instead of a thre...
VALUE rb_fiber_scheduler_io_wait_writable(VALUE scheduler, VALUE io)
Non-blocking wait until the passed IO is ready for writing.
VALUE rb_fiber_scheduler_io_close(VALUE scheduler, VALUE io)
Non-blocking close the given IO.
VALUE rb_fiber_scheduler_io_write_memory(VALUE scheduler, VALUE io, const void *base, size_t size)
Non-blocking write to the passed IO using a native buffer.
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.