14#include "ruby/internal/config.h"
25# if defined(__linux__)
28# if defined(__FreeBSD_version) && __FreeBSD_version >= 1100000
38#define free(x) xfree(x)
40#if defined(DOSISH) || defined(__CYGWIN__)
45#if defined HAVE_NET_SOCKET_H
46# include <net/socket.h>
47#elif defined HAVE_SYS_SOCKET_H
48# include <sys/socket.h>
51#if defined(__BOW__) || defined(__CYGWIN__) || defined(_WIN32)
52# define NO_SAFE_RENAME
55#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__sun) || defined(_nec_ews)
64#if defined(HAVE_SYS_IOCTL_H) && !defined(_WIN32)
67#if defined(HAVE_FCNTL_H) || defined(_WIN32)
69#elif defined(HAVE_SYS_FCNTL_H)
79#if defined(HAVE_SYS_PARAM_H) || defined(__HIUX_MPP__)
80# include <sys/param.h>
93#elif defined HAVE_SYS_SYSCALL_H
94#include <sys/syscall.h>
101#ifdef HAVE_SYS_WAIT_H
102# include <sys/wait.h>
105#ifdef HAVE_COPYFILE_H
106# include <copyfile.h>
108# ifndef COPYFILE_STATE_COPIED
114# undef HAVE_FCOPYFILE
120#include "ccan/list/list.h"
125#include "internal/class.h"
126#include "internal/encoding.h"
127#include "internal/error.h"
128#include "internal/inits.h"
129#include "internal/io.h"
130#include "internal/numeric.h"
131#include "internal/object.h"
132#include "internal/process.h"
133#include "internal/thread.h"
134#include "internal/transcode.h"
135#include "internal/variable.h"
138#include "ruby/missing.h"
141#include "ruby_atomic.h"
151#define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR)
155# ifdef _POSIX_PIPE_BUF
156# define PIPE_BUF _POSIX_PIPE_BUF
163# define EWOULDBLOCK EAGAIN
166#if defined(HAVE___SYSCALL) && (defined(__APPLE__) || defined(__OpenBSD__))
168off_t __syscall(quad_t number, ...);
171#define IO_RBUF_CAPA_MIN 8192
172#define IO_CBUF_CAPA_MIN (128*1024)
173#define IO_RBUF_CAPA_FOR(fptr) (NEED_READCONV(fptr) ? IO_CBUF_CAPA_MIN : IO_RBUF_CAPA_MIN)
174#define IO_WBUF_CAPA_MIN 8192
176#define IO_MAX_BUFFER_GROWTH 8 * 1024 * 1024
181#define open rb_w32_uopen
183#define rename(f, t) rb_w32_urename((f), (t))
184#include "win32/file.h"
194static VALUE rb_eEAGAINWaitReadable;
195static VALUE rb_eEAGAINWaitWritable;
196static VALUE rb_eEWOULDBLOCKWaitReadable;
197static VALUE rb_eEWOULDBLOCKWaitWritable;
198static VALUE rb_eEINPROGRESSWaitWritable;
199static VALUE rb_eEINPROGRESSWaitReadable;
202static VALUE orig_stdout, orig_stderr;
211static ID id_write, id_read, id_getc, id_flush, id_readpartial, id_set_encoding, id_fileno;
212static VALUE sym_mode, sym_perm, sym_flags, sym_extenc, sym_intenc, sym_encoding, sym_open_args;
213static VALUE sym_textmode, sym_binmode, sym_autoclose;
214static VALUE sym_SET, sym_CUR, sym_END;
215static VALUE sym_wait_readable, sym_wait_writable;
217static VALUE sym_DATA;
220static VALUE sym_HOLE;
223static VALUE prep_io(
int fd,
enum rb_io_mode fmode,
VALUE klass,
const char *path);
226rb_io_blocking_region_wait(
struct rb_io *io, rb_blocking_function_t *function,
void *argument,
enum rb_io_event events)
228 return rb_thread_io_blocking_call(io, function, argument, events);
231VALUE rb_io_blocking_region(
struct rb_io *io, rb_blocking_function_t *function,
void *argument)
233 return rb_io_blocking_region_wait(io, function, argument, 0);
237 VALUE filename, current_file;
243 int8_t init_p, next_p, binmode;
254 if (fd < 0 || afd <= max_fd)
257#if defined(HAVE_FCNTL) && defined(F_GETFL)
258 err = fcntl(fd, F_GETFL) == -1;
262 err = fstat(fd, &buf) != 0;
265 if (err &&
errno == EBADF) {
266 rb_bug(
"rb_update_max_fd: invalid fd (%d) given.", fd);
269 while (max_fd < afd) {
270 max_fd = ATOMIC_CAS(max_file_descriptor, max_fd, afd);
275rb_maygvl_fd_fix_cloexec(
int fd)
278#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
279 int flags, flags2, ret;
280 flags = fcntl(fd, F_GETFD);
282 rb_bug(
"rb_maygvl_fd_fix_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(
errno));
285 flags2 = flags & ~FD_CLOEXEC;
287 flags2 = flags | FD_CLOEXEC;
288 if (flags != flags2) {
289 ret = fcntl(fd, F_SETFD, flags2);
291 rb_bug(
"rb_maygvl_fd_fix_cloexec: fcntl(%d, F_SETFD, %d) failed: %s", fd, flags2, strerror(
errno));
300 rb_maygvl_fd_fix_cloexec(fd);
306rb_fix_detect_o_cloexec(
int fd)
308#if defined(O_CLOEXEC) && defined(F_GETFD)
309 int flags = fcntl(fd, F_GETFD);
312 rb_bug(
"rb_fix_detect_o_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(
errno));
314 if (flags & FD_CLOEXEC)
317 rb_maygvl_fd_fix_cloexec(fd);
324 return (e == EWOULDBLOCK) || (e == EAGAIN);
331 static int o_cloexec_state = -1;
333 static const int retry_interval = 0;
334 static const int retry_max_count = 10000;
341#elif defined O_NOINHERIT
342 flags |= O_NOINHERIT;
345 while ((ret = open(pathname, flags, mode)) == -1) {
347 if (!io_again_p(e))
break;
348 if (retry_count++ >= retry_max_count)
break;
350 sleep(retry_interval);
353 if (ret < 0)
return ret;
354 if (ret <= 2 || o_cloexec_state == 0) {
355 rb_maygvl_fd_fix_cloexec(ret);
357 else if (o_cloexec_state > 0) {
361 o_cloexec_state = rb_fix_detect_o_cloexec(ret);
380 if (oldfd == newfd) {
384#if defined(HAVE_DUP3) && defined(O_CLOEXEC)
385 static int try_dup3 = 1;
386 if (2 < newfd && try_dup3) {
387 ret = dup3(oldfd, newfd, O_CLOEXEC);
391 if (
errno == ENOSYS) {
393 ret = dup2(oldfd, newfd);
397 ret = dup2(oldfd, newfd);
400 ret = dup2(oldfd, newfd);
402 if (ret < 0)
return ret;
404 rb_maygvl_fd_fix_cloexec(ret);
409rb_fd_set_nonblock(
int fd)
412 return rb_w32_set_nonblock(fd);
413#elif defined(F_GETFL)
414 int oflags = fcntl(fd, F_GETFL);
418 if (oflags & O_NONBLOCK)
420 oflags |= O_NONBLOCK;
421 return fcntl(fd, F_SETFL, oflags);
430 int result = pipe2(descriptors, O_CLOEXEC | O_NONBLOCK);
432 int result = pipe(descriptors);
439 if (result == 0 && descriptors[1] == -1) {
440 close(descriptors[0]);
448 rb_maygvl_fd_fix_cloexec(descriptors[0]);
449 rb_maygvl_fd_fix_cloexec(descriptors[1]);
452 rb_fd_set_nonblock(descriptors[0]);
453 rb_fd_set_nonblock(descriptors[1]);
465#if defined(HAVE_FCNTL) && defined(F_DUPFD_CLOEXEC) && defined(F_DUPFD)
466 static int try_dupfd_cloexec = 1;
467 if (try_dupfd_cloexec) {
468 ret = fcntl(fd, F_DUPFD_CLOEXEC, minfd);
471 rb_maygvl_fd_fix_cloexec(ret);
475 if (
errno == EINVAL) {
476 ret = fcntl(fd, F_DUPFD, minfd);
478 try_dupfd_cloexec = 0;
483 ret = fcntl(fd, F_DUPFD, minfd);
485#elif defined(HAVE_FCNTL) && defined(F_DUPFD)
486 ret = fcntl(fd, F_DUPFD, minfd);
489 if (ret >= 0 && ret < minfd) {
490 const int prev_fd = ret;
496 if (ret < 0)
return ret;
497 rb_maygvl_fd_fix_cloexec(ret);
501#define argf_of(obj) (*(struct argf *)DATA_PTR(obj))
502#define ARGF argf_of(argf)
503#define ARGF_SET(field, value) RB_OBJ_WRITE(argf, &ARGF.field, value)
505#define GetWriteIO(io) rb_io_get_write_io(io)
507#define READ_DATA_PENDING(fptr) ((fptr)->rbuf.len)
508#define READ_DATA_PENDING_COUNT(fptr) ((fptr)->rbuf.len)
509#define READ_DATA_PENDING_PTR(fptr) ((fptr)->rbuf.ptr+(fptr)->rbuf.off)
510#define READ_DATA_BUFFERED(fptr) READ_DATA_PENDING(fptr)
512#define READ_CHAR_PENDING(fptr) ((fptr)->cbuf.len)
513#define READ_CHAR_PENDING_COUNT(fptr) ((fptr)->cbuf.len)
514#define READ_CHAR_PENDING_PTR(fptr) ((fptr)->cbuf.ptr+(fptr)->cbuf.off)
517#define WAIT_FD_IN_WIN32(fptr) \
518 (rb_w32_io_cancelable_p((fptr)->fd) ? Qnil : rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_READABLE), RUBY_IO_TIMEOUT_DEFAULT))
520#define WAIT_FD_IN_WIN32(fptr)
523#define READ_CHECK(fptr) do {\
524 if (!READ_DATA_PENDING(fptr)) {\
525 WAIT_FD_IN_WIN32(fptr);\
526 rb_io_check_closed(fptr);\
532# define S_ISSOCK(m) _S_ISSOCK(m)
535# define S_ISSOCK(m) (((m) & S_IFMT) == _S_IFSOCK)
538# define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
544static int io_fflush(
rb_io_t *);
545static rb_io_t *flush_before_seek(
rb_io_t *fptr,
bool discard_rbuf);
546static void clear_codeconv(
rb_io_t *fptr);
548#define FMODE_SIGNAL_ON_EPIPE (1<<17)
550#define fptr_signal_on_epipe(fptr) \
551 (((fptr)->mode & FMODE_SIGNAL_ON_EPIPE) != 0)
553#define fptr_set_signal_on_epipe(fptr, flag) \
555 (fptr)->mode |= FMODE_SIGNAL_ON_EPIPE : \
556 (fptr)->mode &= ~FMODE_SIGNAL_ON_EPIPE)
558extern ID ruby_static_id_signo;
560NORETURN(
static void rb_sys_fail_on_write(
rb_io_t *fptr));
562rb_sys_fail_on_write(
rb_io_t *fptr)
565 VALUE errinfo = rb_syserr_new_path(e, (fptr)->pathv);
567 if (fptr_signal_on_epipe(fptr) && (e == EPIPE)) {
579#define NEED_NEWLINE_DECORATOR_ON_READ(fptr) ((fptr)->mode & FMODE_TEXTMODE)
580#define NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) ((fptr)->mode & FMODE_TEXTMODE)
581#if defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32)
582# define RUBY_CRLF_ENVIRONMENT 1
584# define RUBY_CRLF_ENVIRONMENT 0
587#if RUBY_CRLF_ENVIRONMENT
589# define DEFAULT_TEXTMODE FMODE_TEXTMODE
590# define TEXTMODE_NEWLINE_DECORATOR_ON_WRITE ECONV_CRLF_NEWLINE_DECORATOR
598#define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || (fptr)->encs.ecflags & ~ECONV_CRLF_NEWLINE_DECORATOR)
599#define WRITECONV_MASK ( \
600 (ECONV_DECORATOR_MASK & ~ECONV_CRLF_NEWLINE_DECORATOR)|\
601 ECONV_STATEFUL_DECORATOR_MASK|\
603#define NEED_WRITECONV(fptr) ( \
604 ((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || \
605 ((fptr)->encs.ecflags & WRITECONV_MASK) || \
607#define SET_BINARY_MODE(fptr) setmode((fptr)->fd, O_BINARY)
609#define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) do {\
610 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {\
611 if (((fptr)->mode & FMODE_READABLE) &&\
612 !((fptr)->encs.ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {\
613 setmode((fptr)->fd, O_BINARY);\
616 setmode((fptr)->fd, O_TEXT);\
621#define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) do {\
622 if ((enc2) && ((ecflags) & ECONV_DEFAULT_NEWLINE_DECORATOR)) {\
623 (ecflags) |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;\
631io_unread(
rb_io_t *fptr,
bool discard_rbuf)
647 if (!rb_w32_fd_is_text(fptr->
fd)) {
648 r = lseek(fptr->
fd, -fptr->
rbuf.
len, SEEK_CUR);
649 if (r < 0 &&
errno) {
652 if (!discard_rbuf)
return;
658 pos = lseek(fptr->
fd, 0, SEEK_CUR);
659 if (pos < 0 &&
errno) {
662 if (!discard_rbuf)
goto end;
666 extra_max = (long)(pos - fptr->
rbuf.
len);
674 for (i = 0; i < fptr->
rbuf.
len; i++) {
675 if (*p ==
'\n') newlines++;
676 if (extra_max == newlines)
break;
681 while (newlines >= 0) {
682 r = lseek(fptr->
fd, pos - fptr->
rbuf.
len - newlines, SEEK_SET);
683 if (newlines == 0)
break;
688 read_size = _read(fptr->
fd, buf, fptr->
rbuf.
len + newlines);
692 rb_syserr_fail_path(e, fptr->
pathv);
694 if (read_size == fptr->
rbuf.
len) {
695 lseek(fptr->
fd, r, SEEK_SET);
706 clear_codeconv(fptr);
718set_binary_mode_with_seek_cur(
rb_io_t *fptr)
720 if (!rb_w32_fd_is_text(fptr->
fd))
return O_BINARY;
723 return setmode(fptr->
fd, O_BINARY);
725 flush_before_seek(fptr,
false);
726 return setmode(fptr->
fd, O_BINARY);
728#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) set_binary_mode_with_seek_cur(fptr)
732# define DEFAULT_TEXTMODE 0
733#define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || NEED_NEWLINE_DECORATOR_ON_READ(fptr))
734#define NEED_WRITECONV(fptr) ( \
735 ((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || \
736 NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) || \
737 ((fptr)->encs.ecflags & (ECONV_DECORATOR_MASK|ECONV_STATEFUL_DECORATOR_MASK)) || \
739#define SET_BINARY_MODE(fptr) (void)(fptr)
740#define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) (void)(fptr)
741#define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) ((void)(enc2), (void)(ecflags))
742#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) (void)(fptr)
745#if !defined HAVE_SHUTDOWN && !defined shutdown
746#define shutdown(a,b) 0
750#define is_socket(fd, path) rb_w32_is_socket(fd)
751#elif !defined(S_ISSOCK)
752#define is_socket(fd, path) 0
755is_socket(
int fd,
VALUE path)
758 if (fstat(fd, &sbuf) < 0)
759 rb_sys_fail_path(path);
760 return S_ISSOCK(sbuf.st_mode);
764static const char closed_stream[] =
"closed stream";
767io_fd_check_closed(
int fd)
800 io_fd_check_closed(fptr->
fd);
804rb_io_get_fptr(
VALUE io)
814 return rb_convert_type_with_id(io,
T_FILE,
"IO", idTo_io);
820 return rb_check_convert_type_with_id(io,
T_FILE,
"IO", idTo_io);
838 rb_io_t *fptr = rb_io_get_fptr(io);
847 return write_io ? write_io :
Qnil;
860 rb_io_t *fptr = rb_io_get_fptr(self);
890 if (
RTEST(timeout)) {
894 rb_io_t *fptr = rb_io_get_fptr(self);
919#if !RUBY_CRLF_ENVIRONMENT
921io_unread(
rb_io_t *fptr,
bool discard_rbuf)
929 r = lseek(fptr->
fd, -fptr->
rbuf.
len, SEEK_CUR);
930 if (r < 0 &&
errno) {
933 if (!discard_rbuf)
return;
937 clear_codeconv(fptr);
947 long len = RSTRING_LEN(str);
950 const int min_capa = IO_RBUF_CAPA_FOR(fptr);
953#if SIZEOF_LONG > SIZEOF_INT
978flush_before_seek(
rb_io_t *fptr,
bool discard_rbuf)
980 if (io_fflush(fptr) < 0)
981 rb_sys_fail_on_write(fptr);
982 io_unread(fptr, discard_rbuf);
987#define io_seek(fptr, ofs, whence) (errno = 0, lseek(flush_before_seek(fptr, true)->fd, (ofs), (whence)))
988#define io_tell(fptr) lseek(flush_before_seek(fptr, false)->fd, 0, SEEK_CUR)
1004 if (io_fflush(fptr) < 0)
1005 rb_sys_fail_on_write(fptr);
1010 if (io_fflush(wfptr) < 0)
1011 rb_sys_fail_on_write(wfptr);
1019 if (READ_CHAR_PENDING(fptr)) {
1020 rb_raise(
rb_eIOError,
"byte oriented read for character buffered IO");
1031io_read_encoding(
rb_io_t *fptr)
1036 return rb_default_external_encoding();
1040io_input_encoding(
rb_io_t *fptr)
1045 return io_read_encoding(fptr);
1056 io_unread(fptr,
true);
1061rb_io_read_pending(
rb_io_t *fptr)
1064 if (READ_CHAR_PENDING(fptr))
1066 return READ_DATA_PENDING(fptr);
1072 if (!READ_DATA_PENDING(fptr)) {
1079rb_gc_for_fd(
int err)
1081 if (err == EMFILE || err == ENFILE || err == ENOMEM) {
1091#define TRY_WITH_GC(expr) \
1092 for (int first_errno, retried_errno = 0, retried = 0; \
1095 (!rb_gc_for_fd(first_errno = errno) || !(expr)) && \
1096 (retried_errno = errno, 1)); \
1097 (void)retried_errno, retried = 1)
1112io_alloc(
VALUE klass)
1114 UNPROTECTED_NEWOBJ_OF(io,
struct RFile, klass,
T_FILE,
sizeof(
struct RFile));
1122# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
1148struct io_internal_writev_struct {
1155 const struct iovec *iov;
1168io_internal_wait(
VALUE thread,
rb_io_t *fptr,
int error,
int events,
struct timeval *timeout)
1170 if (!timeout && rb_thread_mn_schedulable(thread)) {
1175 int ready = nogvl_wait_for(thread, fptr, events, timeout);
1180 else if (ready == 0) {
1197internal_read_func(
void *ptr)
1202 if (iis->timeout && !iis->nonblock) {
1203 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_IN, iis->timeout) == -1) {
1209 result = read(iis->fd, iis->buf, iis->capa);
1211 if (result < 0 && !iis->nonblock) {
1212 if (io_again_p(
errno)) {
1213 if (io_internal_wait(iis->th, iis->fptr,
errno, RB_WAITFD_IN, iis->timeout) == -1) {
1225#if defined __APPLE__
1226# define do_write_retry(code) do {result = code;} while (result == -1 && errno == EPROTOTYPE)
1228# define do_write_retry(code) result = code
1232internal_write_func(
void *ptr)
1237 if (iis->timeout && !iis->nonblock) {
1238 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1244 do_write_retry(write(iis->fd, iis->buf, iis->capa));
1246 if (result < 0 && !iis->nonblock) {
1248 if (io_again_p(e)) {
1249 if (io_internal_wait(iis->th, iis->fptr,
errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1263internal_writev_func(
void *ptr)
1265 struct io_internal_writev_struct *iis = ptr;
1268 if (iis->timeout && !iis->nonblock) {
1269 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1275 do_write_retry(writev(iis->fd, iis->iov, iis->iovcnt));
1277 if (result < 0 && !iis->nonblock) {
1278 if (io_again_p(
errno)) {
1279 if (io_internal_wait(iis->th, iis->fptr,
errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1293rb_io_read_memory(
rb_io_t *fptr,
void *buf,
size_t count)
1297 if (scheduler !=
Qnil) {
1300 if (!UNDEF_P(result)) {
1316 struct timeval timeout_storage;
1320 iis.timeout = &timeout_storage;
1323 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_read_func, &iis,
RUBY_IO_READABLE);
1327rb_io_write_memory(
rb_io_t *fptr,
const void *buf,
size_t count)
1331 if (scheduler !=
Qnil) {
1334 if (!UNDEF_P(result)) {
1350 struct timeval timeout_storage;
1354 iis.timeout = &timeout_storage;
1357 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_write_func, &iis,
RUBY_IO_WRITABLE);
1362rb_writev_internal(
rb_io_t *fptr,
const struct iovec *iov,
int iovcnt)
1364 if (!iovcnt)
return 0;
1369 if (scheduler !=
Qnil) {
1373 if (!UNDEF_P(result)) {
1378 struct io_internal_writev_struct iis = {
1389 struct timeval timeout_storage;
1393 iis.timeout = &timeout_storage;
1396 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_writev_func, &iis,
RUBY_IO_WRITABLE);
1401io_flush_buffer_sync(
void *arg)
1423io_flush_buffer_fiber_scheduler(
VALUE scheduler,
rb_io_t *fptr)
1426 if (!UNDEF_P(ret)) {
1438io_flush_buffer_async(
VALUE arg)
1443 if (scheduler !=
Qnil) {
1444 VALUE result = io_flush_buffer_fiber_scheduler(scheduler, fptr);
1445 if (!UNDEF_P(result)) {
1450 return rb_io_blocking_region_wait(fptr, io_flush_buffer_sync, fptr,
RUBY_IO_WRITABLE);
1457 return (
int)io_flush_buffer_async((
VALUE)fptr);
1472 while (fptr->
wbuf.
len > 0 && io_flush_buffer(fptr) != 0) {
1488 if (scheduler !=
Qnil) {
1498 if (NIL_OR_UNDEF_P(timeout)) {
1502 if (timeout !=
Qnil) {
1507 int ready = rb_thread_io_wait(th, fptr,
RB_NUM2INT(events), tv);
1533 if (scheduler !=
Qnil) {
1539 return rb_thread_wait_for_single_fd(th, fd, events, timeout);
1545 io_fd_check_closed(f);
1552#if defined(ERESTART)
1559#if EWOULDBLOCK != EAGAIN
1562 if (scheduler !=
Qnil) {
1580 io_fd_check_closed(f);
1587#if defined(ERESTART)
1603#if EWOULDBLOCK != EAGAIN
1606 if (scheduler !=
Qnil) {
1626 return io_wait_for_single_fd(fd, events, timeout, th, scheduler);
1660#if defined(ERESTART)
1670#if EWOULDBLOCK != EAGAIN
1687 if (
RTEST(result)) {
1702 if (
RTEST(result)) {
1716 const char *senc, *denc;
1723 ecflags = fptr->
encs.
ecflags & ~ECONV_NEWLINE_DECORATOR_READ_MASK;
1750 denc = rb_enc_name(enc);
1782io_binwrite_string_internal(
rb_io_t *fptr,
const char *ptr,
long length)
1785 struct iovec iov[2];
1788 iov[0].iov_len = fptr->
wbuf.
len;
1789 iov[1].iov_base = (
void*)ptr;
1790 iov[1].iov_len = length;
1792 ssize_t result = rb_writev_internal(fptr, iov, 2);
1797 if (result >= fptr->
wbuf.
len) {
1805 fptr->
wbuf.
off += (int)result;
1806 fptr->
wbuf.
len -= (int)result;
1814 return rb_io_write_memory(fptr, ptr, length);
1819io_binwrite_string_internal(
rb_io_t *fptr,
const char *ptr,
long length)
1821 long remaining = length;
1824 if (fptr->
wbuf.
len+length <= fptr->wbuf.capa) {
1831 fptr->
wbuf.
len += (int)length;
1838 if (io_fflush(fptr) < 0) {
1843 if (remaining == 0) {
1849 return rb_io_write_memory(fptr, ptr, length);
1854io_binwrite_string(
VALUE arg)
1858 const char *ptr = p->ptr;
1859 size_t remaining = p->length;
1863 ssize_t result = io_binwrite_string_internal(p->fptr, ptr, remaining);
1869 else if (result > 0) {
1870 if ((
size_t)result == remaining)
break;
1872 remaining -= result;
1888io_allocate_write_buffer(
rb_io_t *fptr,
int sync)
1893 fptr->
wbuf.
capa = IO_WBUF_CAPA_MIN;
1904io_binwrite_requires_flush_write(
rb_io_t *fptr,
long len,
int nosync)
1919io_binwrite(
const char *ptr,
long len,
rb_io_t *fptr,
int nosync)
1921 if (
len <= 0)
return len;
1926 io_allocate_write_buffer(fptr, !nosync);
1928 if (io_binwrite_requires_flush_write(fptr,
len, nosync)) {
1939 return io_binwrite_string((
VALUE)&arg);
1956# define MODE_BTMODE(a,b,c) ((fmode & FMODE_BINMODE) ? (b) : \
1957 (fmode & FMODE_TEXTMODE) ? (c) : (a))
1959#define MODE_BTXMODE(a, b, c, d, e, f) ((fmode & FMODE_EXCL) ? \
1960 MODE_BTMODE(d, e, f) : \
1961 MODE_BTMODE(a, b, c))
1966 if (NEED_WRITECONV(fptr)) {
1968 SET_BINARY_MODE(fptr);
1970 make_writeconv(fptr);
1973#define fmode (fptr->mode)
1976 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1) && !rb_enc_asciicompat(rb_enc_get(str))) {
1977 rb_raise(rb_eArgError,
"ASCII incompatible string written for text mode IO without encoding conversion: %s",
1978 rb_enc_name(rb_enc_get(str)));
1984 common_encoding = rb_enc_from_encoding(fptr->
encs.
enc2);
1985 else if (fptr->
encs.
enc != rb_ascii8bit_encoding())
1986 common_encoding = rb_enc_from_encoding(fptr->
encs.
enc);
1989 if (!
NIL_P(common_encoding)) {
2000#if RUBY_CRLF_ENVIRONMENT
2001#define fmode (fptr->mode)
2002 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1)) {
2005 setmode(fptr->
fd, O_BINARY);
2008 setmode(fptr->
fd, O_TEXT);
2010 if (!rb_enc_asciicompat(rb_enc_get(str))) {
2011 rb_raise(rb_eArgError,
"ASCII incompatible string written for text mode IO without encoding conversion: %s",
2012 rb_enc_name(rb_enc_get(str)));
2030 long len = rb_w32_write_console(str, fptr->
fd);
2035 str = do_writeconv(str, fptr, &converted);
2039 tmp = rb_str_tmp_frozen_no_embed_acquire(str);
2041 n = io_binwrite(ptr,
len, fptr, nosync);
2042 rb_str_tmp_frozen_release(str, tmp);
2054 return (ssize_t)io_binwrite(buf, (
long)size, fptr, 0);
2064 io = GetWriteIO(io);
2074 if (RSTRING_LEN(str) == 0)
return INT2FIX(0);
2079 n = io_fwrite(str, fptr, nosync);
2080 if (n < 0L) rb_sys_fail_on_write(fptr);
2086struct binwritev_arg {
2094io_binwritev_internal(
VALUE arg)
2096 struct binwritev_arg *p = (
struct binwritev_arg *)arg;
2098 size_t remaining = p->total;
2102 struct iovec *iov = p->iov;
2103 int iovcnt = p->iovcnt;
2106 long result = rb_writev_internal(fptr, iov, iovcnt);
2111 if (offset < (
size_t)fptr->
wbuf.
len) {
2116 offset -= (size_t)fptr->
wbuf.
len;
2122 if (offset == p->total) {
2126 while (result >= (ssize_t)iov->iov_len) {
2128 result -= iov->iov_len;
2138 iov->iov_base = (
char *)iov->iov_base + result;
2139 iov->iov_len -= result;
2153io_binwritev(
struct iovec *iov,
int iovcnt,
rb_io_t *fptr)
2158 if (iovcnt == 0)
return 0;
2161 for (
int i = 1; i < iovcnt; i++) total += iov[i].iov_len;
2163 io_allocate_write_buffer(fptr, 1);
2169 if (offset + total <= (
size_t)fptr->
wbuf.
capa) {
2170 for (
int i = 1; i < iovcnt; i++) {
2171 memcpy(fptr->
wbuf.
ptr+offset, iov[i].iov_base, iov[i].iov_len);
2172 offset += iov[i].iov_len;
2181 iov[0].iov_len = fptr->
wbuf.
len;
2194 struct binwritev_arg arg;
2197 arg.iovcnt = iovcnt;
2204 return io_binwritev_internal((
VALUE)&arg);
2211 int i, converted, iovcnt = argc + 1;
2213 VALUE v1, v2, str, tmp, *tmp_array;
2219 for (i = 0; i < argc; i++) {
2222 str = do_writeconv(str, fptr, &converted);
2227 tmp = rb_str_tmp_frozen_acquire(str);
2231 iov[i+1].iov_base = RSTRING_PTR(tmp);
2232 iov[i+1].iov_len = RSTRING_LEN(tmp);
2235 n = io_binwritev(iov, iovcnt, fptr);
2238 for (i = 0; i < argc; i++) {
2239 rb_str_tmp_frozen_release(argv[i], tmp_array[i]);
2248iovcnt_ok(
int iovcnt)
2251 return iovcnt < IOV_MAX;
2259io_writev(
int argc,
const VALUE *argv,
VALUE io)
2266 io = GetWriteIO(io);
2271 return rb_funcallv(io, id_write, argc, argv);
2279 for (i = 0; i < argc; i += cnt) {
2282 n = io_fwritev(cnt, &argv[i], fptr);
2293 rb_sys_fail_on_write(fptr);
2295 total = rb_fix_plus(
LONG2FIX(n), total);
2326 return io_writev(argc, argv, io);
2329 VALUE str = argv[0];
2330 return io_write(io, str, 0);
2337 return rb_funcallv(io, id_write, 1, &str);
2341rb_io_writev(
VALUE io,
int argc,
const VALUE *argv)
2346 char sep = RCLASS_SINGLETON_P(klass) ? (klass = io,
'.') :
'#';
2349 " which accepts just one argument",
2354 do rb_io_write(io, *argv++);
while (--argc);
2359 return rb_funcallv(io, id_write, argc, argv);
2385 rb_io_write(io, str);
2391nogvl_fsync(
void *ptr)
2396 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->
fd)) != FILE_TYPE_DISK)
2399 return (
VALUE)fsync(fptr->
fd);
2404rb_io_flush_raw(
VALUE io,
int sync)
2412 io = GetWriteIO(io);
2416 if (io_fflush(fptr) < 0)
2417 rb_sys_fail_on_write(fptr);
2420 io_unread(fptr,
true);
2441 return rb_io_flush_raw(io, 1);
2467 pos = io_tell(fptr);
2468 if (pos < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
2474rb_io_seek(
VALUE io,
VALUE offset,
int whence)
2481 pos = io_seek(fptr, pos, whence);
2482 if (pos < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
2488interpret_seek_whence(
VALUE vwhence)
2490 if (vwhence == sym_SET)
2492 if (vwhence == sym_CUR)
2494 if (vwhence == sym_END)
2497 if (vwhence == sym_DATA)
2501 if (vwhence == sym_HOLE)
2557 VALUE offset, ptrname;
2558 int whence = SEEK_SET;
2560 if (
rb_scan_args(argc, argv,
"11", &offset, &ptrname) == 2) {
2561 whence = interpret_seek_whence(ptrname);
2564 return rb_io_seek(io, offset, whence);
2592 pos = io_seek(fptr, pos, SEEK_SET);
2593 if (pos < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
2598static void clear_readconv(
rb_io_t *fptr);
2625rb_io_rewind(
VALUE io)
2630 if (io_seek(fptr, 0L, 0) < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
2631 if (io == ARGF.current_file) {
2632 ARGF.lineno -= fptr->
lineno;
2636 clear_readconv(fptr);
2643fptr_wait_readable(
rb_io_t *fptr)
2661 fptr->
rbuf.
capa = IO_RBUF_CAPA_FOR(fptr);
2669 if (fptr_wait_readable(fptr))
2673 VALUE path = rb_sprintf(
"fd:%d ", fptr->
fd);
2678 rb_syserr_fail_path(e, path);
2732 if (READ_CHAR_PENDING(fptr))
return Qfalse;
2733 if (READ_DATA_PENDING(fptr))
return Qfalse;
2735#if RUBY_CRLF_ENVIRONMENT
2736 if (!NEED_READCONV(fptr) && NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
2737 return RBOOL(eof(fptr->
fd));
2740 return RBOOL(io_fillbuf(fptr) < 0);
2764 io = GetWriteIO(io);
2801 io = GetWriteIO(io);
2807 fptr->
mode &= ~FMODE_SYNC;
2831rb_io_fsync(
VALUE io)
2835 io = GetWriteIO(io);
2838 if (io_fflush(fptr) < 0)
2839 rb_sys_fail_on_write(fptr);
2841 if ((
int)rb_io_blocking_region(fptr, nogvl_fsync, fptr))
2842 rb_sys_fail_path(fptr->
pathv);
2847# define rb_io_fsync rb_f_notimplement
2848# define rb_io_sync rb_f_notimplement
2857#ifdef HAVE_FDATASYNC
2859nogvl_fdatasync(
void *ptr)
2864 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->
fd)) != FILE_TYPE_DISK)
2867 return (
VALUE)fdatasync(fptr->
fd);
2882rb_io_fdatasync(
VALUE io)
2886 io = GetWriteIO(io);
2889 if (io_fflush(fptr) < 0)
2890 rb_sys_fail_on_write(fptr);
2892 if ((
int)rb_io_blocking_region(fptr, nogvl_fdatasync, fptr) == 0)
2896 return rb_io_fsync(io);
2899#define rb_io_fdatasync rb_io_fsync
2917rb_io_fileno(
VALUE io)
2937 if (!UNDEF_P(fileno)) {
3025rb_io_inspect(
VALUE obj)
3029 static const char closed[] =
" (closed)";
3031 fptr =
RFILE(obj)->fptr;
3038 rb_str_cat(result, closed+1, strlen(closed)-1);
3041 rb_str_catf(result,
"fd %d", fptr->
fd);
3062rb_io_to_io(
VALUE io)
3069read_buffered_data(
char *ptr,
long len,
rb_io_t *fptr)
3073 n = READ_DATA_PENDING_COUNT(fptr);
3074 if (n <= 0)
return 0;
3075 if (n >
len) n = (int)
len;
3083io_bufread(
char *ptr,
long len,
rb_io_t *fptr)
3089 if (READ_DATA_PENDING(fptr) == 0) {
3093 c = rb_io_read_memory(fptr, ptr+offset, n);
3096 if (fptr_wait_readable(fptr))
3101 if ((n -= c) <= 0)
break;
3107 c = read_buffered_data(ptr+offset, n, fptr);
3110 if ((n -= c) <= 0)
break;
3113 if (io_fillbuf(fptr) < 0) {
3120static int io_setstrbuf(
VALUE *str,
long len);
3129bufread_call(
VALUE arg)
3132 p->len = io_bufread(p->str_ptr, p->len, p->fptr);
3137io_fread(
VALUE str,
long offset,
long size,
rb_io_t *fptr)
3142 io_setstrbuf(&str, offset + size);
3143 arg.str_ptr = RSTRING_PTR(str) + offset;
3146 rb_str_locktmp_ensure(str, bufread_call, (
VALUE)&arg);
3148 if (
len < 0) rb_sys_fail_path(fptr->
pathv);
3156 rb_off_t siz = READ_DATA_PENDING_COUNT(fptr);
3159 if (fstat(fptr->
fd, &st) == 0 && S_ISREG(st.st_mode)
3160#
if defined(__HAIKU__)
3165 if (io_fflush(fptr) < 0)
3166 rb_sys_fail_on_write(fptr);
3167 pos = lseek(fptr->
fd, 0, SEEK_CUR);
3168 if (st.st_size >= pos && pos >= 0) {
3169 siz += st.st_size - pos;
3170 if (siz > LONG_MAX) {
3171 rb_raise(
rb_eIOError,
"file too big for single read");
3184 rb_enc_associate(str, io_read_encoding(fptr));
3189make_readconv(
rb_io_t *fptr,
int size)
3194 const char *sname, *dname;
3195 ecflags = fptr->
encs.
ecflags & ~ECONV_NEWLINE_DECORATOR_WRITE_MASK;
3198 sname = rb_enc_name(fptr->
encs.
enc2);
3199 dname = rb_enc_name(io_read_encoding(fptr));
3209 if (size < IO_CBUF_CAPA_MIN) size = IO_CBUF_CAPA_MIN;
3215#define MORE_CHAR_SUSPENDED Qtrue
3216#define MORE_CHAR_FINISHED Qnil
3218fill_cbuf(
rb_io_t *fptr,
int ec_flags)
3220 const unsigned char *ss, *sp, *se;
3221 unsigned char *ds, *dp, *de;
3230 return MORE_CHAR_SUSPENDED;
3241 ss = sp = (
const unsigned char *)fptr->
rbuf.
ptr + fptr->
rbuf.
off;
3246 fptr->
rbuf.
off += (int)(sp - ss);
3247 fptr->
rbuf.
len -= (int)(sp - ss);
3248 fptr->
cbuf.
len += (int)(dp - ds);
3253 fptr->
rbuf.
off -= putbackable;
3254 fptr->
rbuf.
len += putbackable;
3261 if (cbuf_len0 != fptr->
cbuf.
len)
3262 return MORE_CHAR_SUSPENDED;
3265 return MORE_CHAR_FINISHED;
3271 if (io_fillbuf(fptr) < 0) {
3273 return MORE_CHAR_FINISHED;
3278 fptr->
cbuf.
len += (int)(dp - ds);
3285 if (cbuf_len0 != fptr->
cbuf.
len)
3286 return MORE_CHAR_SUSPENDED;
3288 return MORE_CHAR_FINISHED;
3296 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED)
3313 rb_enc_associate(str, fptr->
encs.
enc);
3338 long clen = RSTRING_LEN(s);
3350#define MAX_REALLOC_GAP 4096
3352io_shrink_read_string(
VALUE str,
long n)
3355 rb_str_resize(str, n);
3360io_set_read_length(
VALUE str,
long n,
int shrinkable)
3362 if (RSTRING_LEN(str) != n) {
3365 if (shrinkable) io_shrink_read_string(str, n);
3379 if (NEED_READCONV(fptr)) {
3380 int first = !
NIL_P(str);
3381 SET_BINARY_MODE(fptr);
3382 shrinkable = io_setstrbuf(&str,0);
3383 make_readconv(fptr, 0);
3388 io_shift_cbuf(fptr, fptr->
cbuf.
len, &str);
3390 v = fill_cbuf(fptr, 0);
3391 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED) {
3394 io_shift_cbuf(fptr, fptr->
cbuf.
len, &str);
3398 if (v == MORE_CHAR_FINISHED) {
3399 clear_readconv(fptr);
3401 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3402 return io_enc_str(str, fptr);
3407 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3411 enc = io_read_encoding(fptr);
3414 if (siz == 0) siz = BUFSIZ;
3415 shrinkable = io_setstrbuf(&str, siz);
3418 n = io_fread(str, bytes, siz - bytes, fptr);
3419 if (n == 0 && bytes == 0) {
3427 if (bytes < siz)
break;
3431 if (
capa < (
size_t)RSTRING_LEN(str) + BUFSIZ) {
3432 if (
capa < BUFSIZ) {
3435 else if (
capa > IO_MAX_BUFFER_GROWTH) {
3436 capa = IO_MAX_BUFFER_GROWTH;
3441 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3442 str = io_enc_str(str, fptr);
3450 if (rb_fd_set_nonblock(fptr->
fd) != 0) {
3451 rb_sys_fail_path(fptr->
pathv);
3456io_read_memory_call(
VALUE arg)
3461 if (scheduler !=
Qnil) {
3464 if (!UNDEF_P(result)) {
3470 if (iis->nonblock) {
3471 return rb_io_blocking_region(iis->fptr, internal_read_func, iis);
3474 return rb_io_blocking_region_wait(iis->fptr, internal_read_func, iis,
RUBY_IO_READABLE);
3481 return (
long)rb_str_locktmp_ensure(str, io_read_memory_call, (
VALUE)iis);
3484#define no_exception_p(opts) !rb_opts_exception_p((opts), TRUE)
3487io_getpartial(
int argc,
VALUE *argv,
VALUE io,
int no_exception,
int nonblock)
3498 rb_raise(rb_eArgError,
"negative length %ld given",
len);
3501 shrinkable = io_setstrbuf(&str,
len);
3507 io_set_read_length(str, 0, shrinkable);
3513 n = read_buffered_data(RSTRING_PTR(str),
len, fptr);
3519 io_setstrbuf(&str,
len);
3522 iis.nonblock = nonblock;
3524 iis.buf = RSTRING_PTR(str);
3527 n = io_read_memory_locktmp(str, &iis);
3530 if (!nonblock && fptr_wait_readable(fptr))
3532 if (nonblock && (io_again_p(e))) {
3534 return sym_wait_readable;
3537 e,
"read would block");
3539 rb_syserr_fail_path(e, fptr->
pathv);
3542 io_set_read_length(str, n, shrinkable);
3643io_readpartial(
int argc,
VALUE *argv,
VALUE io)
3647 ret = io_getpartial(argc, argv, io,
Qnil, 0);
3654io_nonblock_eof(
int no_exception)
3656 if (!no_exception) {
3672 rb_raise(rb_eArgError,
"negative length %ld given",
len);
3675 shrinkable = io_setstrbuf(&str,
len);
3676 rb_bool_expected(ex,
"exception", TRUE);
3682 io_set_read_length(str, 0, shrinkable);
3686 n = read_buffered_data(RSTRING_PTR(str),
len, fptr);
3688 rb_fd_set_nonblock(fptr->
fd);
3689 shrinkable |= io_setstrbuf(&str,
len);
3693 iis.buf = RSTRING_PTR(str);
3696 n = io_read_memory_locktmp(str, &iis);
3699 if (io_again_p(e)) {
3700 if (!ex)
return sym_wait_readable;
3702 e,
"read would block");
3704 rb_syserr_fail_path(e, fptr->
pathv);
3707 io_set_read_length(str, n, shrinkable);
3710 if (!ex)
return Qnil;
3726 rb_bool_expected(ex,
"exception", TRUE);
3728 io = GetWriteIO(io);
3732 if (io_fflush(fptr) < 0)
3733 rb_sys_fail_on_write(fptr);
3735 rb_fd_set_nonblock(fptr->
fd);
3736 n = write(fptr->
fd, RSTRING_PTR(str), RSTRING_LEN(str));
3741 if (io_again_p(e)) {
3743 return sym_wait_writable;
3749 rb_syserr_fail_path(e, fptr->
pathv);
3833#if RUBY_CRLF_ENVIRONMENT
3839 if (
NIL_P(length)) {
3842 return read_all(fptr, remain_size(fptr), str);
3846 rb_raise(rb_eArgError,
"negative length %ld given",
len);
3849 shrinkable = io_setstrbuf(&str,
len);
3854 io_set_read_length(str, 0, shrinkable);
3859#if RUBY_CRLF_ENVIRONMENT
3860 previous_mode = set_binary_mode_with_seek_cur(fptr);
3862 n = io_fread(str, 0,
len, fptr);
3863 io_set_read_length(str, n, shrinkable);
3864#if RUBY_CRLF_ENVIRONMENT
3865 if (previous_mode == O_TEXT) {
3866 setmode(fptr->
fd, O_TEXT);
3869 if (n == 0)
return Qnil;
3875rscheck(
const char *rsptr,
long rslen,
VALUE rs)
3878 if (RSTRING_PTR(rs) != rsptr && RSTRING_LEN(rs) != rslen)
3883search_delim(
const char *p,
long len,
int delim,
rb_encoding *enc)
3885 if (rb_enc_mbminlen(enc) == 1) {
3886 p = memchr(p, delim,
len);
3887 if (p)
return p + 1;
3890 const char *end = p +
len;
3892 int r = rb_enc_precise_mbclen(p, end, enc);
3894 p += rb_enc_mbminlen(enc);
3898 if (rb_enc_mbc_to_codepoint(p, end, enc) == (
unsigned int)delim) {
3913 if (NEED_READCONV(fptr)) {
3914 SET_BINARY_MODE(fptr);
3915 make_readconv(fptr, 0);
3918 int searchlen = READ_CHAR_PENDING_COUNT(fptr);
3920 p = READ_CHAR_PENDING_PTR(fptr);
3921 if (0 < limit && limit < searchlen)
3922 searchlen = (int)limit;
3923 e = search_delim(p, searchlen, delim, enc);
3925 int len = (int)(e-p);
3947 return (
unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
3950 }
while (more_char(fptr) != MORE_CHAR_FINISHED);
3951 clear_readconv(fptr);
3956 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3958 long pending = READ_DATA_PENDING_COUNT(fptr);
3960 const char *p = READ_DATA_PENDING_PTR(fptr);
3964 if (limit > 0 && pending > limit) pending = limit;
3965 e = search_delim(p, pending, delim, enc);
3966 if (e) pending = e - p;
3968 last = RSTRING_LEN(str);
3969 rb_str_resize(str, last + pending);
3976 read_buffered_data(RSTRING_PTR(str) + last, pending, fptr);
3979 if (e)
return delim;
3981 return (
unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
3984 }
while (io_fillbuf(fptr) >= 0);
3990swallow(
rb_io_t *fptr,
int term)
3992 if (NEED_READCONV(fptr)) {
3994 int needconv = rb_enc_mbminlen(enc) != 1;
3995 SET_BINARY_MODE(fptr);
3996 make_readconv(fptr, 0);
3999 while ((cnt = READ_CHAR_PENDING_COUNT(fptr)) > 0) {
4000 const char *p = READ_CHAR_PENDING_PTR(fptr);
4003 if (*p != term)
return TRUE;
4005 while (--i && *++p == term);
4008 const char *e = p + cnt;
4009 if (rb_enc_ascget(p, e, &i, enc) != term)
return TRUE;
4010 while ((p += i) < e && rb_enc_ascget(p, e, &i, enc) == term);
4013 io_shift_cbuf(fptr, (
int)cnt - i, NULL);
4015 }
while (more_char(fptr) != MORE_CHAR_FINISHED);
4019 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4022 while ((cnt = READ_DATA_PENDING_COUNT(fptr)) > 0) {
4024 const char *p = READ_DATA_PENDING_PTR(fptr);
4026 if (cnt >
sizeof buf) cnt =
sizeof buf;
4027 if (*p != term)
return TRUE;
4029 while (--i && *++p == term);
4030 if (!read_buffered_data(buf, cnt - i, fptr))
4031 rb_sys_fail_path(fptr->
pathv);
4034 }
while (io_fillbuf(fptr) == 0);
4047 int pending = READ_DATA_PENDING_COUNT(fptr);
4050 const char *p = READ_DATA_PENDING_PTR(fptr);
4054 e = memchr(p,
'\n', pending);
4056 pending = (int)(e - p + 1);
4058 chomplen = (pending > 1 && *(e-1) ==
'\r') + 1;
4067 rb_str_resize(str,
len + pending - chomplen);
4068 read_buffered_data(RSTRING_PTR(str)+
len, pending - chomplen, fptr);
4071 if (pending == 1 && chomplen == 1 &&
len > 0) {
4072 if (RSTRING_PTR(str)[
len-1] ==
'\r') {
4073 rb_str_resize(str, --
len);
4078 len += pending - chomplen;
4084 }
while (io_fillbuf(fptr) >= 0);
4087 str = io_enc_str(str, fptr);
4098 unsigned int chomp: 1;
4112 chomp = (!UNDEF_P(vchomp)) &&
RTEST(vchomp);
4114 args->chomp = chomp;
4132 else if (2 <= argc) {
4133 rs = argv[0], lim = argv[1];
4142check_getline_args(
VALUE *rsp,
long *limit,
VALUE io)
4151 enc_rs = rb_enc_get(rs);
4152 enc_io = io_read_encoding(fptr);
4153 if (enc_io != enc_rs &&
4154 (!is_ascii_string(rs) ||
4155 (RSTRING_LEN(rs) > 0 && !rb_enc_asciicompat(enc_io)))) {
4156 if (rs == rb_default_rs) {
4157 rs = rb_enc_str_new(0, 0, enc_io);
4162 rb_raise(rb_eArgError,
"encoding mismatch: %s IO with %s RS",
4163 rb_enc_name(enc_io),
4164 rb_enc_name(enc_rs));
4174 argc =
rb_scan_args(argc, argv,
"02:", NULL, NULL, &opts);
4175 extract_getline_args(argc, argv, args);
4176 extract_getline_opts(opts, args);
4177 check_getline_args(&args->rs, &args->limit, io);
4181rb_io_getline_0(
VALUE rs,
long limit,
int chomp,
rb_io_t *fptr)
4188 if (
NIL_P(rs) && limit < 0) {
4189 str = read_all(fptr, 0,
Qnil);
4190 if (RSTRING_LEN(str) == 0)
return Qnil;
4192 else if (limit == 0) {
4193 return rb_enc_str_new(0, 0, io_read_encoding(fptr));
4195 else if (rs == rb_default_rs && limit < 0 && !NEED_READCONV(fptr) &&
4196 rb_enc_asciicompat(enc = io_read_encoding(fptr))) {
4197 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4198 return rb_io_getline_fast(fptr, enc, chomp);
4201 int c, newline = -1;
4202 const char *rsptr = 0;
4205 int extra_limit = 16;
4206 int chomp_cr = chomp;
4208 SET_BINARY_MODE(fptr);
4209 enc = io_read_encoding(fptr);
4212 rslen = RSTRING_LEN(rs);
4217 swallow(fptr,
'\n');
4219 if (!rb_enc_asciicompat(enc)) {
4223 rsptr = RSTRING_PTR(rs);
4224 rslen = RSTRING_LEN(rs);
4228 else if (rb_enc_mbminlen(enc) == 1) {
4229 rsptr = RSTRING_PTR(rs);
4230 newline = (
unsigned char)rsptr[rslen - 1];
4234 rsptr = RSTRING_PTR(rs);
4235 const char *e = rsptr + rslen;
4236 const char *last = rb_enc_prev_char(rsptr, e, e, enc);
4238 newline = rb_enc_codepoint_len(last, e, &n, enc);
4239 if (last + n != e) rb_raise(rb_eArgError,
"broken separator");
4241 chomp_cr = chomp && newline ==
'\n' && rslen == rb_enc_mbminlen(enc);
4245 while ((c = appendline(fptr, newline, &str, &limit, enc)) != EOF) {
4246 const char *s, *p, *pp, *e;
4249 if (RSTRING_LEN(str) < rslen)
continue;
4250 s = RSTRING_PTR(str);
4253 if (!at_char_boundary(s, p, e, enc))
continue;
4254 if (!rspara) rscheck(rsptr, rslen, rs);
4255 if (memcmp(p, rsptr, rslen) == 0) {
4257 if (chomp_cr && p > s && *(p-1) ==
'\r') --p;
4264 s = RSTRING_PTR(str);
4266 pp = rb_enc_prev_char(s, p, p, enc);
4267 if (extra_limit && pp &&
4281 if (rspara && c != EOF)
4282 swallow(fptr,
'\n');
4284 str = io_enc_str(str, fptr);
4287 if (!
NIL_P(str) && !nolimit) {
4295rb_io_getline_1(
VALUE rs,
long limit,
int chomp,
VALUE io)
4298 int old_lineno, new_lineno;
4302 old_lineno = fptr->
lineno;
4303 str = rb_io_getline_0(rs, limit, chomp, fptr);
4304 if (!
NIL_P(str) && (new_lineno = fptr->
lineno) != old_lineno) {
4305 if (io == ARGF.current_file) {
4306 ARGF.lineno += new_lineno - old_lineno;
4307 ARGF.last_lineno = ARGF.lineno;
4310 ARGF.last_lineno = new_lineno;
4318rb_io_getline(
int argc,
VALUE *argv,
VALUE io)
4322 prepare_getline_args(argc, argv, &args, io);
4323 return rb_io_getline_1(args.rs, args.limit, args.chomp, io);
4333rb_io_gets_limit_internal(
VALUE io,
long limit)
4337 return rb_io_getline_0(rb_default_rs, limit, FALSE, fptr);
4341rb_io_gets_internal(
VALUE io)
4343 return rb_io_gets_limit_internal(io, -1);
4423 str = rb_io_getline(argc, argv, io);
4439rb_io_lineno(
VALUE io)
4494 check_getline_args(&sep, &limit, io);
4496 VALUE line = rb_io_getline_1(sep, limit,
RTEST(chomp), io);
4497 rb_lastline_set_up(line, 1);
4572rb_io_readlines(
int argc,
VALUE *argv,
VALUE io)
4576 prepare_getline_args(argc, argv, &args, io);
4577 return io_readlines(&args, io);
4585 if (arg->limit == 0)
4586 rb_raise(rb_eArgError,
"invalid limit: 0 for readlines");
4588 while (!
NIL_P(line = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, io))) {
4701rb_io_each_line(
int argc,
VALUE *argv,
VALUE io)
4707 prepare_getline_args(argc, argv, &args, io);
4708 if (args.limit == 0)
4709 rb_raise(rb_eArgError,
"invalid limit: 0 for each_line");
4710 while (!
NIL_P(str = rb_io_getline_1(args.rs, args.limit, args.chomp, io))) {
4738rb_io_each_byte(
VALUE io)
4754 }
while (io_fillbuf(fptr) >= 0);
4764 if (NEED_READCONV(fptr)) {
4768 SET_BINARY_MODE(fptr);
4769 make_readconv(fptr, 0);
4783 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4785 clear_readconv(fptr);
4789 str = rb_enc_str_new(fptr->
cbuf.
ptr+fptr->
cbuf.
off, 1, read_enc);
4792 if (fptr->
cbuf.
len == 0) clear_readconv(fptr);
4801 io_shift_cbuf(fptr, r, &str);
4808 ISASCII(RSTRING_PTR(str)[0])) {
4812 str = io_enc_str(str, fptr);
4817 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4818 if (io_fillbuf(fptr) < 0) {
4840 if (io_fillbuf(fptr) != -1) {
4844 r = rb_enc_precise_mbclen(RSTRING_PTR(str), RSTRING_PTR(str)+RSTRING_LEN(str), enc);
4860 str = io_enc_str(str, fptr);
4887rb_io_each_char(
VALUE io)
4897 enc = io_input_encoding(fptr);
4899 while (!
NIL_P(c = io_getc(fptr, enc))) {
4926rb_io_each_codepoint(
VALUE io)
4938 enc = io_read_encoding(fptr);
4939 if (NEED_READCONV(fptr)) {
4940 SET_BINARY_MODE(fptr);
4943 make_readconv(fptr, 0);
4955 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4956 clear_readconv(fptr);
4976 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4977 while (io_fillbuf(fptr) >= 0) {
4992 char cbuf[8], *p = cbuf;
4994 if (more > numberof(cbuf))
goto invalid;
4996 if (more > numberof(cbuf))
goto invalid;
4997 while ((n = (
int)read_buffered_data(p, more, fptr)) > 0 &&
4998 (p += n, (more -= n) > 0)) {
4999 if (io_fillbuf(fptr) < 0)
goto invalid;
5000 if ((n = fptr->
rbuf.
len) > more) n = more;
5002 r = rb_enc_precise_mbclen(cbuf, p, enc);
5015 rb_raise(rb_eArgError,
"invalid byte sequence in %s", rb_enc_name(enc));
5048 enc = io_input_encoding(fptr);
5050 return io_getc(fptr, enc);
5074rb_io_readchar(
VALUE io)
5076 VALUE c = rb_io_getc(io);
5112 VALUE r_stdout = rb_ractor_stdout();
5117 rb_io_flush(r_stdout);
5120 if (io_fillbuf(fptr) < 0) {
5150rb_io_readbyte(
VALUE io)
5211 unsigned char c =
NUM2INT(v) & 0xFF;
5217 io_ungetbyte(b, fptr);
5273 else if (RB_BIGNUM_TYPE_P(c)) {
5279 if (NEED_READCONV(fptr)) {
5280 SET_BINARY_MODE(fptr);
5281 len = RSTRING_LEN(c);
5282#if SIZEOF_LONG > SIZEOF_INT
5286 make_readconv(fptr, (
int)
len);
5300 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
5301 io_ungetbyte(c, fptr);
5321rb_io_isatty(
VALUE io)
5326 return RBOOL(isatty(fptr->
fd) != 0);
5329#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5345rb_io_close_on_exec_p(
VALUE io)
5351 write_io = GetWriteIO(io);
5352 if (io != write_io) {
5354 if (fptr && 0 <= (fd = fptr->
fd)) {
5355 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->
pathv);
5356 if (!(ret & FD_CLOEXEC))
return Qfalse;
5361 if (fptr && 0 <= (fd = fptr->
fd)) {
5362 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->
pathv);
5363 if (!(ret & FD_CLOEXEC))
return Qfalse;
5368#define rb_io_close_on_exec_p rb_f_notimplement
5371#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5395 int flag =
RTEST(arg) ? FD_CLOEXEC : 0;
5400 write_io = GetWriteIO(io);
5401 if (io != write_io) {
5403 if (fptr && 0 <= (fd = fptr->
fd)) {
5404 if ((ret = fcntl(fptr->
fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->
pathv);
5405 if ((ret & FD_CLOEXEC) != flag) {
5406 ret = (ret & ~FD_CLOEXEC) | flag;
5407 ret = fcntl(fd, F_SETFD, ret);
5408 if (ret != 0) rb_sys_fail_path(fptr->
pathv);
5415 if (fptr && 0 <= (fd = fptr->
fd)) {
5416 if ((ret = fcntl(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);
5426#define rb_io_set_close_on_exec rb_f_notimplement
5429#define RUBY_IO_EXTERNAL_P(f) ((f)->mode & FMODE_EXTERNAL)
5430#define PREP_STDIO_NAME(f) (RSTRING_PTR((f)->pathv))
5433finish_writeconv(
rb_io_t *fptr,
int noalloc)
5435 unsigned char *ds, *dp, *de;
5439 unsigned char buf[1024];
5444 de = buf +
sizeof(buf);
5447 size_t remaining = dp-ds;
5448 long result = rb_io_write_memory(fptr, ds, remaining);
5452 if ((
size_t)result == remaining)
break;
5475 if (io_fflush(fptr) < 0) {
5483 fptr->
wbuf.
len += (int)(dp - ds);
5499finish_writeconv_sync(
VALUE arg)
5502 return finish_writeconv(p->fptr, p->noalloc);
5506nogvl_close(
void *ptr)
5510 return (
void*)(intptr_t)close(*fd);
5514maygvl_close(
int fd,
int keepgvl)
5523 return IO_WITHOUT_GVL_INT(nogvl_close, &fd);
5527nogvl_fclose(
void *ptr)
5531 return (
void*)(intptr_t)fclose(file);
5535maygvl_fclose(
FILE *file,
int keepgvl)
5538 return fclose(file);
5540 return IO_WITHOUT_GVL_INT(nogvl_fclose, file);
5546fptr_finalize_flush(
rb_io_t *fptr,
int noraise,
int keepgvl)
5551 int mode = fptr->
mode;
5557 arg.noalloc = noraise;
5561 error = finish_writeconv(fptr, noraise);
5566 io_flush_buffer_sync(fptr);
5569 if (io_fflush(fptr) < 0 &&
NIL_P(error)) {
5577 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2) {
5587 rb_thread_io_close_wait(fptr);
5589 if (!done && stdio_file) {
5591 if ((maygvl_fclose(stdio_file, noraise) < 0) &&
NIL_P(error)) {
5601 if (!done && fd >= 0 && scheduler !=
Qnil) {
5604 if (!UNDEF_P(result)) {
5605 done =
RTEST(result);
5609 if (!done && fd >= 0) {
5615 if ((maygvl_close(fd, keepgvl) < 0) &&
NIL_P(error)) {
5624 if (!
NIL_P(error) && !noraise) {
5633fptr_finalize(
rb_io_t *fptr,
int noraise)
5635 fptr_finalize_flush(fptr, noraise, FALSE);
5636 free_io_buffer(&fptr->
rbuf);
5637 free_io_buffer(&fptr->
wbuf);
5638 clear_codeconv(fptr);
5642rb_io_fptr_cleanup(
rb_io_t *fptr,
int noraise)
5648 fptr_finalize(fptr, noraise);
5656 ruby_xfree_sized(buf->
ptr, (
size_t)buf->
capa);
5668 free_io_buffer(&fptr->
cbuf);
5684 clear_readconv(fptr);
5685 clear_writeconv(fptr);
5689rb_io_fptr_cleanup_all(
rb_io_t *fptr)
5693 rb_io_fptr_cleanup(fptr, TRUE);
5695 free_io_buffer(&fptr->
rbuf);
5696 free_io_buffer(&fptr->
wbuf);
5697 clear_codeconv(fptr);
5704 rb_io_fptr_cleanup_all(io);
5711rb_io_memsize(
const rb_io_t *io)
5713 size_t size =
sizeof(
rb_io_t);
5723 rb_serial_t fork_generation = GET_VM()->fork_gen;
5724 if (io->fork_generation == fork_generation) {
5735# define KEEPGVL TRUE
5737# define KEEPGVL FALSE
5741io_close_fptr(
VALUE io)
5747 write_io = GetWriteIO(io);
5748 if (io != write_io) {
5749 write_fptr =
RFILE(write_io)->fptr;
5750 if (write_fptr && 0 <= write_fptr->
fd) {
5751 rb_io_fptr_cleanup(write_fptr, TRUE);
5755 fptr =
RFILE(io)->fptr;
5756 if (!fptr)
return 0;
5757 if (fptr->
fd < 0)
return 0;
5760 if (rb_thread_io_close_interrupt(fptr)) {
5762 fptr_finalize_flush(fptr, FALSE, KEEPGVL);
5765 rb_io_fptr_cleanup(fptr, FALSE);
5770fptr_waitpid(
rb_io_t *fptr,
int nohang)
5774 rb_last_status_clear();
5783 rb_io_t *fptr = io_close_fptr(io);
5784 if (fptr) fptr_waitpid(fptr, 0);
5824rb_io_close_m(
VALUE io)
5826 rb_io_t *fptr = rb_io_get_fptr(io);
5835io_call_close(
VALUE io)
5844 enum {mesg_len =
sizeof(closed_stream)-1};
5845 VALUE mesg = rb_attr_get(exc, idMesg);
5847 RSTRING_LEN(mesg) != mesg_len ||
5848 memcmp(RSTRING_PTR(mesg), closed_stream, mesg_len)) {
5858 if (!UNDEF_P(closed) &&
RTEST(closed))
return io;
5859 rb_rescue2(io_call_close, io, ignore_closed_stream, io,
5895 write_io = GetWriteIO(io);
5896 if (io != write_io) {
5897 write_fptr =
RFILE(write_io)->fptr;
5898 if (write_fptr && 0 <= write_fptr->
fd) {
5903 fptr = rb_io_get_fptr(io);
5904 return RBOOL(0 > fptr->
fd);
5940rb_io_close_read(
VALUE io)
5946 if (fptr->
fd < 0)
return Qnil;
5947 if (is_socket(fptr->
fd, fptr->
pathv)) {
5951 if (shutdown(fptr->
fd, SHUT_RD) < 0)
5952 rb_sys_fail_path(fptr->
pathv);
5953 fptr->
mode &= ~FMODE_READABLE;
5959 write_io = GetWriteIO(io);
5960 if (io != write_io) {
5965 RFILE(io)->fptr = wfptr;
5968 RFILE(write_io)->fptr = fptr;
5969 rb_io_fptr_cleanup(fptr, FALSE);
5975 rb_raise(
rb_eIOError,
"closing non-duplex IO for reading");
6013rb_io_close_write(
VALUE io)
6018 write_io = GetWriteIO(io);
6020 if (fptr->
fd < 0)
return Qnil;
6021 if (is_socket(fptr->
fd, fptr->
pathv)) {
6025 if (shutdown(fptr->
fd, SHUT_WR) < 0)
6026 rb_sys_fail_path(fptr->
pathv);
6027 fptr->
mode &= ~FMODE_WRITABLE;
6034 rb_raise(
rb_eIOError,
"closing non-duplex IO for writing");
6037 if (io != write_io) {
6057rb_io_sysseek(
int argc,
VALUE *argv,
VALUE io)
6059 VALUE offset, ptrname;
6060 int whence = SEEK_SET;
6064 if (
rb_scan_args(argc, argv,
"11", &offset, &ptrname) == 2) {
6065 whence = interpret_seek_whence(ptrname);
6070 (READ_DATA_BUFFERED(fptr) || READ_CHAR_PENDING(fptr))) {
6074 rb_warn(
"sysseek for buffered IO");
6077 pos = lseek(fptr->
fd, pos, whence);
6078 if (pos < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
6112 io = GetWriteIO(io);
6117 rb_warn(
"syswrite for buffered IO");
6120 tmp = rb_str_tmp_frozen_acquire(str);
6122 n = rb_io_write_memory(fptr, ptr,
len);
6123 if (n < 0) rb_sys_fail_path(fptr->
pathv);
6124 rb_str_tmp_frozen_release(str, tmp);
6141rb_io_sysread(
int argc,
VALUE *argv,
VALUE io)
6152 shrinkable = io_setstrbuf(&str, ilen);
6153 if (ilen == 0)
return str;
6158 if (READ_DATA_BUFFERED(fptr)) {
6164 io_setstrbuf(&str, ilen);
6169 iis.buf = RSTRING_PTR(str);
6172 n = io_read_memory_locktmp(str, &iis);
6175 rb_sys_fail_path(fptr->
pathv);
6178 io_set_read_length(str, n, shrinkable);
6180 if (n == 0 && ilen > 0) {
6196internal_pread_func(
void *_arg)
6200 return (
VALUE)pread(arg->fd, arg->buf, arg->count, arg->offset);
6204pread_internal_call(
VALUE _arg)
6209 if (scheduler !=
Qnil) {
6212 if (!UNDEF_P(result)) {
6217 return rb_io_blocking_region_wait(arg->io, internal_pread_func, arg,
RUBY_IO_READABLE);
6261 shrinkable = io_setstrbuf(&str, (
long)arg.count);
6262 if (arg.count == 0)
return str;
6263 arg.buf = RSTRING_PTR(str);
6276 rb_sys_fail_path(fptr->
pathv);
6278 io_set_read_length(str, n, shrinkable);
6279 if (n == 0 && arg.count > 0) {
6287internal_pwrite_func(
void *_arg)
6291 return (
VALUE)pwrite(arg->fd, arg->buf, arg->count, arg->offset);
6295pwrite_internal_call(
VALUE _arg)
6300 if (scheduler !=
Qnil) {
6303 if (!UNDEF_P(result)) {
6308 return rb_io_blocking_region_wait(arg->io, internal_pwrite_func, arg,
RUBY_IO_WRITABLE);
6349 io = GetWriteIO(io);
6356 tmp = rb_str_tmp_frozen_acquire(str);
6357 arg.buf = RSTRING_PTR(tmp);
6358 arg.count = (size_t)RSTRING_LEN(tmp);
6360 n = (ssize_t)pwrite_internal_call((
VALUE)&arg);
6361 if (n < 0) rb_sys_fail_path(fptr->
pathv);
6362 rb_str_tmp_frozen_release(str, tmp);
6378 fptr->
mode &= ~FMODE_TEXTMODE;
6382 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6385 setmode(fptr->
fd, O_BINARY);
6392io_ascii8bit_binmode(
rb_io_t *fptr)
6403 fptr->
mode &= ~FMODE_TEXTMODE;
6404 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6406 fptr->
encs.
enc = rb_ascii8bit_encoding();
6410 clear_codeconv(fptr);
6419 io_ascii8bit_binmode(fptr);
6436rb_io_binmode_m(
VALUE io)
6442 write_io = GetWriteIO(io);
6457rb_io_binmode_p(
VALUE io)
6465rb_io_fmode_modestr(
enum rb_io_mode fmode)
6469 return MODE_BTMODE(
"a+",
"ab+",
"at+");
6471 return MODE_BTMODE(
"a",
"ab",
"at");
6475 rb_raise(rb_eArgError,
"invalid access fmode 0x%x", fmode);
6477 return MODE_BTMODE(
"r",
"rb",
"rt");
6479 return MODE_BTXMODE(
"w",
"wb",
"wt",
"wx",
"wbx",
"wtx");
6482 return MODE_BTXMODE(
"w+",
"wb+",
"wt+",
"w+x",
"wb+x",
"wt+x");
6484 return MODE_BTMODE(
"r+",
"rb+",
"rt+");
6488static const char bom_prefix[] =
"bom|";
6489static const char utf_prefix[] =
"utf-";
6490enum {bom_prefix_len = (int)
sizeof(bom_prefix) - 1};
6491enum {utf_prefix_len = (int)
sizeof(utf_prefix) - 1};
6494io_encname_bom_p(
const char *name,
long len)
6496 return len > bom_prefix_len &&
STRNCASECMP(name, bom_prefix, bom_prefix_len) == 0;
6502 enum rb_io_mode fmode = 0;
6503 const char *m = modestr, *p = NULL;
6531 if (modestr[0] !=
'w')
6539 if (io_encname_bom_p(m, p ? (
long)(p - m) : (long)strlen(m)))
6552 rb_raise(rb_eArgError,
"invalid access mode %s", modestr);
6557rb_io_oflags_fmode(
int oflags)
6559 enum rb_io_mode fmode = 0;
6561 switch (oflags & O_ACCMODE) {
6573 if (oflags & O_APPEND) {
6576 if (oflags & O_TRUNC) {
6579 if (oflags & O_CREAT) {
6582 if (oflags & O_EXCL) {
6586 if (oflags & O_BINARY) {
6595rb_io_fmode_oflags(
enum rb_io_mode fmode)
6639rb_io_oflags_modestr(
int oflags)
6642# define MODE_BINARY(a,b) ((oflags & O_BINARY) ? (b) : (a))
6644# define MODE_BINARY(a,b) (a)
6647 if (oflags & O_EXCL) {
6648 rb_raise(rb_eArgError,
"exclusive access mode is not supported");
6650 accmode = oflags & (O_RDONLY|O_WRONLY|O_RDWR);
6651 if (oflags & O_APPEND) {
6652 if (accmode == O_WRONLY) {
6653 return MODE_BINARY(
"a",
"ab");
6655 if (accmode == O_RDWR) {
6656 return MODE_BINARY(
"a+",
"ab+");
6661 rb_raise(rb_eArgError,
"invalid access oflags 0x%x", oflags);
6663 return MODE_BINARY(
"r",
"rb");
6665 return MODE_BINARY(
"w",
"wb");
6667 if (oflags & O_TRUNC) {
6668 return MODE_BINARY(
"w+",
"wb+");
6670 return MODE_BINARY(
"r+",
"rb+");
6682 int default_ext = 0;
6685 ext = rb_default_external_encoding();
6688 if (rb_is_ascii8bit_enc(ext)) {
6692 else if (intern == NULL) {
6693 intern = rb_default_internal_encoding();
6698 *enc = (default_ext && intern != ext) ? NULL : ext;
6708unsupported_encoding(
const char *name,
rb_encoding *enc)
6710 rb_enc_warn(enc,
"Unsupported encoding %s ignored", name);
6714parse_mode_enc(
const char *estr,
rb_encoding *estr_enc,
6720 enum rb_io_mode fmode = fmode_p ? *fmode_p : 0;
6726 p = strrchr(estr,
':');
6727 len = p ? (p++ - estr) : (long)strlen(estr);
6729 estr += bom_prefix_len;
6730 len -= bom_prefix_len;
6731 if (!
STRNCASECMP(estr, utf_prefix, utf_prefix_len)) {
6735 rb_enc_warn(estr_enc,
"BOM with non-UTF encoding %s is nonsense", estr);
6736 fmode &= ~FMODE_SETENC_BY_BOM;
6744 memcpy(encname, estr,
len);
6745 encname[
len] =
'\0';
6748 idx = rb_enc_find_index(estr);
6750 if (fmode_p) *fmode_p = fmode;
6753 ext_enc = rb_enc_from_index(idx);
6756 unsupported_encoding(estr, estr_enc);
6762 if (*p ==
'-' && *(p+1) ==
'\0') {
6767 idx2 = rb_enc_find_index(p);
6769 unsupported_encoding(p, estr_enc);
6774 int_enc = rb_enc_from_index(idx2);
6778 rb_io_ext_int_to_encs(ext_enc, int_enc, enc_p, enc2_p, fmode);
6791 v = rb_hash_lookup2(opt, sym_encoding,
Qnil);
6792 if (v !=
Qnil) encoding = v;
6793 v = rb_hash_lookup2(opt, sym_extenc,
Qundef);
6794 if (v !=
Qnil) extenc = v;
6795 v = rb_hash_lookup2(opt, sym_intenc,
Qundef);
6796 if (!UNDEF_P(v)) intenc = v;
6798 if ((!UNDEF_P(extenc) || !UNDEF_P(intenc)) && !
NIL_P(encoding)) {
6800 int idx = rb_to_encoding_index(encoding);
6801 if (idx >= 0) encoding = rb_enc_from_encoding(rb_enc_from_index(idx));
6802 rb_warn(
"Ignoring encoding parameter '%"PRIsVALUE
"': %s_encoding is used",
6803 encoding, UNDEF_P(extenc) ?
"internal" :
"external");
6807 if (!UNDEF_P(extenc) && !
NIL_P(extenc)) {
6808 extencoding = rb_to_encoding(extenc);
6810 if (!UNDEF_P(intenc)) {
6811 if (
NIL_P(intenc)) {
6818 if (*p ==
'-' && *(p+1) ==
'\0') {
6823 intencoding = rb_to_encoding(intenc);
6827 intencoding = rb_to_encoding(intenc);
6829 if (extencoding == intencoding) {
6833 if (!
NIL_P(encoding)) {
6837 enc_p, enc2_p, fmode_p);
6840 rb_io_ext_int_to_encs(rb_to_encoding(encoding), NULL, enc_p, enc2_p, 0);
6843 else if (!UNDEF_P(extenc) || !UNDEF_P(intenc)) {
6845 rb_io_ext_int_to_encs(extencoding, intencoding, enc_p, enc2_p, 0);
6853 enum rb_io_mode fmode = *fmode_p;
6858 !rb_enc_asciicompat(enc ? enc : rb_default_external_encoding()))
6859 rb_raise(rb_eArgError,
"ASCII incompatible encoding needs binmode");
6862 rb_raise(rb_eArgError,
"newline decorator with binary mode");
6869#if !DEFAULT_TEXTMODE
6871 fmode &= ~FMODE_TEXTMODE;
6878extract_binmode(
VALUE opthash,
enum rb_io_mode *fmode)
6880 if (!
NIL_P(opthash)) {
6882 v = rb_hash_aref(opthash, sym_textmode);
6885 rb_raise(rb_eArgError,
"textmode specified twice");
6887 rb_raise(rb_eArgError,
"both textmode and binmode specified");
6891 v = rb_hash_aref(opthash, sym_binmode);
6894 rb_raise(rb_eArgError,
"binmode specified twice");
6896 rb_raise(rb_eArgError,
"both textmode and binmode specified");
6902 rb_raise(rb_eArgError,
"both textmode and binmode specified");
6908 int *oflags_p,
enum rb_io_mode *fmode_p,
struct rb_io_encoding *convconfig_p)
6912 enum rb_io_mode fmode;
6916 int has_enc = 0, has_vmode = 0;
6922 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
6932 fmode = rb_io_oflags_fmode(oflags);
6940 oflags = rb_io_fmode_oflags(fmode);
6944 parse_mode_enc(p+1, rb_enc_get(vmode), &enc, &enc2, &fmode);
6949 e = (fmode &
FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
6950 rb_io_ext_int_to_encs(e, NULL, &enc, &enc2, fmode);
6954 if (
NIL_P(opthash)) {
6958#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
6960 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
6961 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
6963 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
6970 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
6973 else if (
NIL_P(vmode)) {
6974 fmode |= DEFAULT_TEXTMODE;
6981 v = rb_hash_aref(opthash, sym_mode);
6983 if (!
NIL_P(vmode)) {
6984 rb_raise(rb_eArgError,
"mode specified twice");
6991 v = rb_hash_aref(opthash, sym_flags);
6996 fmode = rb_io_oflags_fmode(oflags);
6998 extract_binmode(opthash, &fmode);
7004 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
7007 else if (
NIL_P(vmode)) {
7008 fmode |= DEFAULT_TEXTMODE;
7011 v = rb_hash_aref(opthash, sym_perm);
7014 if (!
NIL_P(*vperm_p)) {
7015 rb_raise(rb_eArgError,
"perm specified twice");
7026#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7028 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7029 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7034 rb_raise(rb_eArgError,
"encoding specified twice");
7037 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
7041 validate_enc_binmode(&fmode, ecflags, enc, enc2);
7047 convconfig_p->
enc = enc;
7048 convconfig_p->
enc2 = enc2;
7049 convconfig_p->
ecflags = ecflags;
7050 convconfig_p->
ecopts = ecopts;
7060sysopen_func(
void *ptr)
7063 const char *fname = RSTRING_PTR(data->fname);
7072 fd = IO_WITHOUT_GVL_INT(sysopen_func, data);
7073 }
while (fd < 0 &&
errno == EINTR);
7080rb_sysopen(
VALUE fname,
int oflags, mode_t perm)
7085 data.fname = rb_str_encode_ospath(fname);
7087 data.oflags = oflags;
7090 TRY_WITH_GC((fd = rb_sysopen_internal(&data)) >= 0) {
7091 rb_syserr_fail_path(first_errno, fname);
7097fdopen_internal(
int fd,
const char *modestr)
7104 file = fdopen(fd, modestr);
7120 TRY_WITH_GC((file = fdopen_internal(fd, modestr)) != 0) {
7126 if (setvbuf(file, NULL, _IOFBF, 0) != 0)
7127 rb_warn(
"setvbuf() can't be honoured (fd=%d)", fd);
7135 int t = isatty(fptr->
fd);
7145io_strip_bom(
VALUE io)
7147 VALUE b1, b2, b3, b4;
7158 return rb_utf8_encindex();
7168 return ENCINDEX_UTF_16BE;
7179 return ENCINDEX_UTF_32LE;
7184 return ENCINDEX_UTF_16LE;
7194 return ENCINDEX_UTF_32BE;
7208io_set_encoding_by_bom(
VALUE io)
7210 int idx = io_strip_bom(io);
7216 extenc = rb_enc_from_index(idx);
7217 io_encoding_set(fptr, rb_enc_from_encoding(extenc),
7218 rb_io_internal_encoding(io),
Qnil);
7227rb_file_open_generic(
VALUE io,
VALUE filename,
int oflags,
enum rb_io_mode fmode,
7235 rb_io_ext_int_to_encs(NULL, NULL, &cc.enc, &cc.enc2, fmode);
7240 validate_enc_binmode(&fmode, convconfig->
ecflags,
7241 convconfig->
enc, convconfig->
enc2);
7245 fptr->
encs = *convconfig;
7248 if (!(oflags & O_TMPFILE)) {
7249 fptr->
pathv = pathv;
7252 fptr->
pathv = pathv;
7254 fptr->
fd = rb_sysopen(pathv, oflags, perm);
7262rb_file_open_internal(
VALUE io,
VALUE filename,
const char *modestr)
7265 const char *p = strchr(modestr,
':');
7269 parse_mode_enc(p+1, rb_usascii_encoding(),
7270 &convconfig.
enc, &convconfig.
enc2, &fmode);
7276 e = (fmode &
FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
7277 rb_io_ext_int_to_encs(e, NULL, &convconfig.
enc, &convconfig.
enc2, fmode);
7283#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7285 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7286 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7288 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.
enc2, convconfig.
ecflags);
7291 return rb_file_open_generic(io, filename,
7292 rb_io_fmode_oflags(fmode),
7302 return rb_file_open_internal(io_alloc(
rb_cFile), fname, modestr);
7311#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7334 while ((tmp = *prev) != 0) {
7335 if (tmp->fptr == fptr) {
7344#if defined (_WIN32) || defined(__CYGWIN__)
7360pipe_finalize(
rb_io_t *fptr,
int noraise)
7362#if !defined(HAVE_WORKING_FORK) && !defined(_WIN32)
7371 fptr_finalize(fptr, noraise);
7373 pipe_del_fptr(fptr);
7380#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7381 void (*
const old_finalize)(
struct rb_io*,int) = fptr->
finalize;
7383 if (old_finalize == orig->finalize)
return;
7388#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7389 if (old_finalize != pipe_finalize) {
7391 for (list =
pipe_list; list; list = list->next) {
7392 if (list->fptr == fptr)
break;
7394 if (!list) pipe_add_fptr(fptr);
7397 pipe_del_fptr(fptr);
7410rb_io_unbuffered(
rb_io_t *fptr)
7428#define HAVE_SPAWNV 1
7429#define spawnv(mode, cmd, args) rb_w32_uaspawn((mode), (cmd), (args))
7430#define spawn(mode, cmd) rb_w32_uspawn((mode), (cmd), 0)
7433#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7443#ifdef HAVE_WORKING_FORK
7444# ifndef __EMSCRIPTEN__
7446popen_redirect(
struct popen_arg *p)
7449 close(p->write_pair[1]);
7450 if (p->write_pair[0] != 0) {
7451 dup2(p->write_pair[0], 0);
7452 close(p->write_pair[0]);
7455 if (p->pair[1] != 1) {
7456 dup2(p->pair[1], 1);
7462 if (p->pair[1] != 1) {
7463 dup2(p->pair[1], 1);
7469 if (p->pair[0] != 0) {
7470 dup2(p->pair[0], 0);
7477#if defined(__linux__)
7488linux_get_maxfd(
void)
7491 char buf[4096], *p, *np, *e;
7494 if (fd < 0)
return fd;
7495 ss = read(fd, buf,
sizeof(buf));
7496 if (ss < 0)
goto err;
7499 while ((
int)
sizeof(
"FDSize:\t0\n")-1 <= e-p &&
7500 (np = memchr(p,
'\n', e-p)) != NULL) {
7501 if (memcmp(p,
"FDSize:",
sizeof(
"FDSize:")-1) == 0) {
7503 p +=
sizeof(
"FDSize:")-1;
7523#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
7525 int max = (int)max_file_descriptor;
7528 ret = fcntl(0, F_MAXFD);
7530 maxhint = max = ret;
7531# elif defined(__linux__)
7532 ret = linux_get_maxfd();
7539 for (fd = lowfd; fd <= max; fd++) {
7540 if (!
NIL_P(noclose_fds) &&
7543 ret = fcntl(fd, F_GETFD);
7544 if (ret != -1 && !(ret & FD_CLOEXEC)) {
7545 fcntl(fd, F_SETFD, ret|FD_CLOEXEC);
7547# define CONTIGUOUS_CLOSED_FDS 20
7549 if (max < fd + CONTIGUOUS_CLOSED_FDS)
7550 max = fd + CONTIGUOUS_CLOSED_FDS;
7556# ifndef __EMSCRIPTEN__
7558popen_exec(
void *pp,
char *errmsg,
size_t errmsg_len)
7560 struct popen_arg *p = (
struct popen_arg*)pp;
7562 return rb_exec_async_signal_safe(p->eargp, errmsg, errmsg_len);
7567#if (defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)) && !defined __EMSCRIPTEN__
7569rb_execarg_fixup_v(
VALUE execarg_obj)
7571 rb_execarg_parent_start(execarg_obj);
7575char *rb_execarg_commandline(
const struct rb_execarg *eargp,
VALUE *prog);
7578#ifndef __EMSCRIPTEN__
7580pipe_open(
VALUE execarg_obj,
const char *modestr,
enum rb_io_mode fmode,
7583 struct rb_execarg *eargp =
NIL_P(execarg_obj) ? NULL : rb_execarg_get(execarg_obj);
7584 VALUE prog = eargp ? (eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name) :
Qfalse ;
7590#if defined(HAVE_WORKING_FORK)
7592 char errmsg[80] = {
'\0' };
7594#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7596 struct popen_arg arg;
7599#if defined(HAVE_SPAWNV)
7600# if defined(HAVE_SPAWNVE)
7601# define DO_SPAWN(cmd, args, envp) ((args) ? \
7602 spawnve(P_NOWAIT, (cmd), (args), (envp)) : \
7603 spawne(P_NOWAIT, (cmd), (envp)))
7605# define DO_SPAWN(cmd, args, envp) ((args) ? \
7606 spawnv(P_NOWAIT, (cmd), (args)) : \
7607 spawn(P_NOWAIT, (cmd)))
7609# if !defined(HAVE_WORKING_FORK)
7611# if defined(HAVE_SPAWNVE)
7616#if !defined(HAVE_WORKING_FORK)
7622#if !defined(HAVE_WORKING_FORK)
7623 const char *cmd = 0;
7629#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7630 arg.execarg_obj = execarg_obj;
7633 arg.pair[0] = arg.pair[1] = -1;
7634 arg.write_pair[0] = arg.write_pair[1] = -1;
7635# if !defined(HAVE_WORKING_FORK)
7636 if (eargp && !eargp->use_shell) {
7637 args = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
7642 if (
rb_pipe(arg.write_pair) < 0)
7643 rb_sys_fail_str(prog);
7646 close(arg.write_pair[0]);
7647 close(arg.write_pair[1]);
7651 rb_execarg_addopt(execarg_obj,
INT2FIX(0),
INT2FIX(arg.write_pair[0]));
7652 rb_execarg_addopt(execarg_obj,
INT2FIX(1),
INT2FIX(arg.pair[1]));
7657 rb_sys_fail_str(prog);
7659 rb_execarg_addopt(execarg_obj,
INT2FIX(1),
INT2FIX(arg.pair[1]));
7663 rb_sys_fail_str(prog);
7665 rb_execarg_addopt(execarg_obj,
INT2FIX(0),
INT2FIX(arg.pair[0]));
7668 rb_sys_fail_str(prog);
7670 if (!
NIL_P(execarg_obj)) {
7671 rb_protect(rb_execarg_fixup_v, execarg_obj, &state);
7673 if (0 <= arg.write_pair[0]) close(arg.write_pair[0]);
7674 if (0 <= arg.write_pair[1]) close(arg.write_pair[1]);
7675 if (0 <= arg.pair[0]) close(arg.pair[0]);
7676 if (0 <= arg.pair[1]) close(arg.pair[1]);
7677 rb_execarg_parent_end(execarg_obj);
7681# if defined(HAVE_WORKING_FORK)
7682 pid = rb_fork_async_signal_safe(&status, popen_exec, &arg, arg.eargp->redirect_fds, errmsg,
sizeof(errmsg));
7684 rb_execarg_run_options(eargp, sargp, NULL, 0);
7685# if defined(HAVE_SPAWNVE)
7686 if (eargp->envp_str) envp = (
char **)RSTRING_PTR(eargp->envp_str);
7688 while ((pid = DO_SPAWN(cmd, args, envp)) < 0) {
7690 switch (e =
errno) {
7692# if EWOULDBLOCK != EAGAIN
7701 rb_execarg_run_options(sargp, NULL, NULL, 0);
7703 rb_execarg_parent_end(execarg_obj);
7706# if defined(HAVE_WORKING_FORK)
7707 pid = rb_call_proc__fork();
7709 popen_redirect(&arg);
7721# if defined(HAVE_WORKING_FORK)
7727 close(arg.write_pair[0]);
7728 close(arg.write_pair[1]);
7730# if defined(HAVE_WORKING_FORK)
7739 close(arg.write_pair[0]);
7740 write_fd = arg.write_pair[1];
7751 cmd = rb_execarg_commandline(eargp, &prog);
7752 if (!
NIL_P(execarg_obj)) {
7753 rb_execarg_parent_start(execarg_obj);
7754 rb_execarg_run_options(eargp, sargp, NULL, 0);
7756 fp = popen(cmd, modestr);
7759 rb_execarg_parent_end(execarg_obj);
7760 rb_execarg_run_options(sargp, NULL, NULL, 0);
7762 if (!fp) rb_syserr_fail_path(e, prog);
7772 fptr->
encs = *convconfig;
7773#if RUBY_CRLF_ENVIRONMENT
7780 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
7783#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7784 if (NEED_NEWLINE_DECORATOR_ON_WRITE(fptr)) {
7785 fptr->
encs.
ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
7791 if (0 <= write_fd) {
7792 write_port = io_alloc(
rb_cIO);
7794 write_fptr->
fd = write_fd;
7796 fptr->
mode &= ~FMODE_WRITABLE;
7798 rb_ivar_set(port, rb_intern(
"@tied_io_for_writing"), write_port);
7801#if defined (__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7803 pipe_add_fptr(fptr);
7809pipe_open(
VALUE execarg_obj,
const char *modestr,
enum rb_io_mode fmode,
7817is_popen_fork(
VALUE prog)
7819 if (RSTRING_LEN(prog) == 1 && RSTRING_PTR(prog)[0] ==
'-') {
7820#if !defined(HAVE_WORKING_FORK)
7822 "fork() function is unimplemented on this machine");
7831pipe_open_s(
VALUE prog,
const char *modestr,
enum rb_io_mode fmode,
7835 VALUE *argv = &prog;
7838 if (!is_popen_fork(prog))
7839 execarg_obj = rb_execarg_new(argc, argv, TRUE, FALSE);
7840 return pipe_open(execarg_obj, modestr, fmode, convconfig);
7846 rb_io_t *fptr = io_close_fptr(io);
8015rb_io_s_popen(
int argc,
VALUE *argv,
VALUE klass)
8019 if (argc > 1 && !
NIL_P(opt = rb_check_hash_type(argv[argc-1]))) --argc;
8020 if (argc > 1 && !
NIL_P(env = rb_check_hash_type(argv[0]))) --argc, ++argv;
8029 int ex = !
NIL_P(opt);
8030 rb_error_arity(argc + ex, 1 + ex, 2 + ex);
8033 return popen_finish(rb_io_popen(pname, pmode, env, opt), klass);
8039 const char *modestr;
8042 enum rb_io_mode fmode;
8048#if SIZEOF_LONG > SIZEOF_INT
8049 if (
len > INT_MAX) {
8050 rb_raise(rb_eArgError,
"too many arguments");
8059 if (!is_popen_fork(pname))
8060 execarg_obj = rb_execarg_new(1, &pname, TRUE, FALSE);
8062 if (!
NIL_P(execarg_obj)) {
8064 opt = rb_execarg_extract_options(execarg_obj, opt);
8066 rb_execarg_setenv(execarg_obj, env);
8069 modestr = rb_io_oflags_modestr(oflags);
8071 return pipe_open(execarg_obj, modestr, fmode, &convconfig);
8081 rb_io_flush(rb_ractor_stdout());
8082 rb_io_flush(rb_ractor_stderr());
8083 _exit(EXIT_SUCCESS);
8087 RBASIC_SET_CLASS(port, klass);
8094#if defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)
8095struct popen_writer_arg {
8097 struct popen_arg popen;
8101exec_popen_writer(
void *arg,
char *errmsg,
size_t buflen)
8103 struct popen_writer_arg *pw = arg;
8105 popen_redirect(&pw->popen);
8106 execv(pw->argv[0], pw->argv);
8107 strlcpy(errmsg, strerror(
errno), buflen);
8113ruby_popen_writer(
char *
const *argv, rb_pid_t *pid)
8115#if (defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)) || defined(_WIN32)
8116# ifdef HAVE_WORKING_FORK
8117 struct popen_writer_arg pw;
8118 int *
const write_pair = pw.popen.pair;
8124 int result = pipe2(write_pair, O_CLOEXEC);
8126 int result = pipe(write_pair);
8131# ifdef HAVE_WORKING_FORK
8134 char errmsg[80] = {
'\0'};
8135 *pid = rb_fork_async_signal_safe(&status, exec_popen_writer, &pw,
Qnil, errmsg,
sizeof(errmsg));
8137 *pid = rb_w32_uspawn_process(P_NOWAIT, argv[0], argv, write_pair[0], -1, -1, 0);
8138 const char *errmsg = (*pid < 0) ? strerror(
errno) : NULL;
8140 close(write_pair[0]);
8142 close(write_pair[1]);
8143 fprintf(stderr,
"ruby_popen_writer(%s): %s\n", argv[0], errmsg);
8146 return fdopen(write_pair[1],
"w");
8157 enum rb_io_mode fmode;
8166 rb_file_open_generic(io, fname, oflags, fmode, &convconfig, perm);
8204rb_io_s_open(
int argc,
VALUE *argv,
VALUE klass)
8236 VALUE fname, vmode, vperm;
8241 rb_scan_args(argc, argv,
"12", &fname, &vmode, &vperm);
8252 if (
NIL_P(vperm)) perm = 0666;
8256 fd = rb_sysopen(fname, oflags, perm);
8288 int redirect = FALSE;
8296 VALUE tmp = argv[0];
8314 return rb_io_s_open(argc, argv,
rb_cFile);
8318rb_io_open_generic(
VALUE klass,
VALUE filename,
int oflags,
enum rb_io_mode fmode,
8321 return rb_file_open_generic(io_alloc(klass), filename,
8322 oflags, fmode, convconfig, perm);
8329 enum rb_io_mode fmode;
8335 return rb_io_open_generic(io, filename, oflags, fmode, &convconfig, perm);
8349 if (fptr == orig)
return io;
8350 if (RUBY_IO_EXTERNAL_P(fptr)) {
8354 rb_raise(rb_eArgError,
8355 "%s can't change access mode from \"%s\" to \"%s\"",
8356 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->
mode),
8357 rb_io_fmode_modestr(orig->
mode));
8361 if (io_fflush(fptr) < 0)
8362 rb_sys_fail_on_write(fptr);
8365 flush_before_seek(fptr,
true);
8368 pos = io_tell(orig);
8371 if (io_fflush(orig) < 0)
8372 rb_sys_fail_on_write(fptr);
8381 else if (!RUBY_IO_EXTERNAL_P(fptr)) fptr->
pathv =
Qnil;
8382 fptr_copy_finalizer(fptr, orig);
8388 rb_thread_io_close_interrupt(fptr);
8389 rb_thread_io_close_wait(fptr);
8391 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2 || !fptr->stdio_file) {
8394 rb_sys_fail_path(orig->
pathv);
8402 rb_sys_fail_path(orig->
pathv);
8408 if (io_seek(fptr, pos, SEEK_SET) < 0 &&
errno) {
8409 rb_sys_fail_path(fptr->
pathv);
8411 if (io_seek(orig, pos, SEEK_SET) < 0 &&
errno) {
8412 rb_sys_fail_path(orig->
pathv);
8426int rb_freopen(
VALUE fname,
const char *mode,
FILE *fp);
8429rb_freopen(
VALUE fname,
const char *mode,
FILE *fp)
8431 if (!freopen(RSTRING_PTR(fname), mode, fp)) {
8474rb_io_reopen(
int argc,
VALUE *argv,
VALUE file)
8476 VALUE fname, nmode, opt;
8480 if (
rb_scan_args(argc, argv,
"11:", &fname, &nmode, &opt) == 1) {
8483 return io_reopen(file, tmp);
8489 fptr =
RFILE(file)->fptr;
8495 enum rb_io_mode fmode;
8499 if (RUBY_IO_EXTERNAL_P(fptr) &&
8502 rb_raise(rb_eArgError,
8503 "%s can't change access mode from \"%s\" to \"%s\"",
8504 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->
mode),
8505 rb_io_fmode_modestr(fmode));
8508 fptr->
encs = convconfig;
8511 oflags = rb_io_fmode_oflags(fptr->
mode);
8514 fptr->
pathv = fname;
8516 fptr->
fd = rb_sysopen(fptr->
pathv, oflags, 0666);
8522 if (io_fflush(fptr) < 0)
8523 rb_sys_fail_on_write(fptr);
8528 int e = rb_freopen(rb_str_encode_ospath(fptr->
pathv),
8529 rb_io_oflags_modestr(oflags),
8531 if (e) rb_syserr_fail_path(e, fptr->
pathv);
8535 if (setvbuf(fptr->
stdio_file, NULL, _IOFBF, 0) != 0)
8536 rb_warn(
"setvbuf() can't be honoured for %"PRIsVALUE, fptr->
pathv);
8539 if (setvbuf(fptr->
stdio_file, NULL, _IONBF, BUFSIZ) != 0)
8540 rb_warn(
"setvbuf() can't be honoured for %"PRIsVALUE, fptr->
pathv);
8542 else if (fptr->
stdio_file == stdout && isatty(fptr->
fd)) {
8543 if (setvbuf(fptr->
stdio_file, NULL, _IOLBF, BUFSIZ) != 0)
8544 rb_warn(
"setvbuf() can't be honoured for %"PRIsVALUE, fptr->
pathv);
8548 int tmpfd = rb_sysopen(fptr->
pathv, oflags, 0666);
8554 rb_syserr_fail_path(err, fptr->
pathv);
8578 fptr->
mode = orig->
mode & ~FMODE_EXTERNAL;
8585 fptr->closing_ec = NULL;
8586 fptr->wakeup_mutex =
Qnil;
8587 fptr->fork_generation = GET_VM()->fork_gen;
8590 fptr_copy_finalizer(fptr, orig);
8592 fd = ruby_dup(orig->
fd);
8594 pos = io_tell(orig);
8596 io_seek(fptr, pos, SEEK_SET);
8601 write_io = GetWriteIO(io);
8602 if (io != write_io) {
8605 rb_ivar_set(dest, rb_intern(
"@tied_io_for_writing"), write_io);
8668 if (argc == 0)
return Qnil;
8670 out = rb_ractor_stdout();
8682extern void rb_deprecated_str_setter(
VALUE val,
ID id,
VALUE *var);
8687 rb_deprecated_str_setter(val,
id, &val);
8693 val = rb_str_frozen_bare_string(val);
8770 for (i=0; i<argc; i++) {
8774 rb_io_write(out, argv[i]);
8871 rb_io_write(io, str);
8875#define forward(obj, id, argc, argv) \
8876 rb_funcallv_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8877#define forward_public(obj, id, argc, argv) \
8878 rb_funcallv_public_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8879#define forward_current(id, argc, argv) \
8880 forward_public(ARGF.current_file, id, argc, argv)
8897 VALUE r_stdout = rb_ractor_stdout();
8898 if (recv == r_stdout) {
8899 return rb_io_putc(recv, ch);
8901 return forward(r_stdout, rb_intern(
"putc"), 1, &ch);
8906rb_str_end_with_asciichar(
VALUE str,
int c)
8908 long len = RSTRING_LEN(str);
8909 const char *
ptr = RSTRING_PTR(str);
8913 if (
len == 0)
return 0;
8914 if ((n = rb_enc_mbminlen(
enc)) == 1) {
8915 return ptr[
len - 1] == c;
8917 return rb_enc_ascget(
ptr + ((
len - 1) / n) * n,
ptr +
len, &n,
enc) == c;
8928 rb_io_puts(1, &tmp, out);
8935 rb_io_puts(1, &tmp, out);
8990 VALUE line, args[2];
8997 for (
int i = 0; i < argc; i++) {
9011 if (RSTRING_LEN(line) == 0) {
9016 if (!rb_str_end_with_asciichar(line,
'\n')) {
9021 rb_io_writev(out, n, args);
9039 VALUE r_stdout = rb_ractor_stdout();
9040 if (recv == r_stdout) {
9041 return rb_io_puts(argc, argv, recv);
9043 return forward(r_stdout, rb_intern(
"puts"), argc, argv);
9047rb_p_write(
VALUE str)
9052 VALUE r_stdout = rb_ractor_stdout();
9054 rb_method_basic_definition_p(
CLASS_OF(r_stdout), id_write)) {
9055 io_writev(2, args, r_stdout);
9058 rb_io_writev(r_stdout, 2, args);
9070rb_p_result(
int argc,
const VALUE *argv)
9077 else if (argc > 1) {
9080 VALUE r_stdout = rb_ractor_stdout();
9082 rb_uninterruptible(rb_io_flush, r_stdout);
9123 for (i=0; i<argc; i++) {
9125 rb_uninterruptible(rb_p_write, inspected);
9127 return rb_p_result(argc, argv);
9148rb_obj_display(
int argc,
VALUE *argv,
VALUE self)
9152 out = (!
rb_check_arity(argc, 0, 1) ? rb_ractor_stdout() : argv[0]);
9153 rb_io_write(out, self);
9159rb_stderr_to_original_p(
VALUE err)
9161 return (err == orig_stderr ||
RFILE(orig_stderr)->fptr->
fd < 0);
9167 VALUE out = rb_ractor_stderr();
9168 if (rb_stderr_to_original_p(out)) {
9170 if (isatty(fileno(stderr))) {
9171 if (rb_w32_write_console(
rb_str_new(mesg,
len), fileno(stderr)) > 0)
return;
9174 if (fwrite(mesg,
sizeof(
char), (
size_t)
len, stderr) < (
size_t)
len) {
9191rb_write_error_str(
VALUE mesg)
9193 VALUE out = rb_ractor_stderr();
9195 if (rb_stderr_to_original_p(out)) {
9196 size_t len = (size_t)RSTRING_LEN(mesg);
9198 if (isatty(fileno(stderr))) {
9199 if (rb_w32_write_console(mesg, fileno(stderr)) > 0)
return;
9202 if (fwrite(RSTRING_PTR(mesg),
sizeof(
char),
len, stderr) <
len) {
9209 rb_io_write(out, mesg);
9214rb_stderr_tty_p(
void)
9216 if (rb_stderr_to_original_p(rb_ractor_stderr()))
9217 return isatty(fileno(stderr));
9222must_respond_to(
ID mid,
VALUE val,
ID id)
9225 rb_raise(
rb_eTypeError,
"%"PRIsVALUE
" must have %"PRIsVALUE
" method, %"PRIsVALUE
" given",
9226 rb_id2str(
id), rb_id2str(mid),
9246 must_respond_to(id_write, val,
id);
9253 return rb_ractor_stdout();
9259 must_respond_to(id_write, val,
id);
9266 return rb_ractor_stderr();
9270allocate_and_open_new_file(
VALUE klass)
9272 VALUE self = io_alloc(klass);
9273 rb_io_make_open_file(self);
9281 VALUE self = rb_protect(allocate_and_open_new_file, klass, &state);
9289 maygvl_close(descriptor, 0);
9297 io->
fd = descriptor;
9315 io->closing_ec = NULL;
9316 io->wakeup_mutex =
Qnil;
9317 io->fork_generation = GET_VM()->fork_gen;
9320 io->
encs = *encoding;
9329prep_io(
int fd,
enum rb_io_mode fmode,
VALUE klass,
const char *path)
9339 e = (fmode &
FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
9340 rb_io_ext_int_to_encs(e, NULL, &convconfig.
enc, &convconfig.
enc2, fmode);
9344#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9346 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
9347 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
9349 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.
enc2, convconfig.
ecflags);
9355 if (!io_check_tty(io)) {
9358 setmode(fd, O_BINARY);
9370 if (path && strcmp(path,
"-")) klass =
rb_cFile;
9371 return prep_io(fd, rb_io_oflags_fmode(oflags), klass, path);
9375prep_stdio(
FILE *f,
enum rb_io_mode fmode,
VALUE klass,
const char *path)
9382#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9383 fptr->
encs.
ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
9394rb_io_prep_stdin(
void)
9400rb_io_prep_stdout(
void)
9406rb_io_prep_stderr(
void)
9415 int oflags = rb_io_fmode_oflags(fptr->
mode) & ~O_EXCL;
9442 rb_io_buffer_init(&fp->
wbuf);
9443 rb_io_buffer_init(&fp->
rbuf);
9444 rb_io_buffer_init(&fp->
cbuf);
9459 fp->closing_ec = NULL;
9460 fp->wakeup_mutex =
Qnil;
9461 fp->fork_generation = GET_VM()->fork_gen;
9466rb_io_make_open_file(
VALUE obj)
9471 if (
RFILE(obj)->fptr) {
9474 RFILE(obj)->fptr = 0;
9476 fp = rb_io_fptr_new();
9478 RFILE(obj)->fptr = fp;
9527rb_io_initialize(
int argc,
VALUE *argv,
VALUE io)
9533 return io_initialize(io, fnum, vmode, opt);
9540 int fd, oflags = O_RDONLY;
9541 enum rb_io_mode fmode;
9543#if defined(HAVE_FCNTL) && defined(F_GETFL)
9553 rb_raise(rb_eArgError,
"The given fd is not accessible because RubyVM reserves it");
9555#if defined(HAVE_FCNTL) && defined(F_GETFL)
9556 oflags = fcntl(fd, F_GETFL);
9557 if (oflags == -1) rb_sys_fail(0);
9559 if (fstat(fd, &st) < 0) rb_sys_fail(0);
9562#if defined(HAVE_FCNTL) && defined(F_GETFL)
9563 ofmode = rb_io_oflags_fmode(oflags);
9575 if (rb_hash_aref(opt, sym_autoclose) ==
Qfalse) {
9579 path = rb_hash_aref(opt,
RB_ID2SYM(idPath));
9590 fp->
encs = convconfig;
9594 fp->closing_ec = NULL;
9595 fp->wakeup_mutex =
Qnil;
9596 fp->fork_generation = GET_VM()->fork_gen;
9599 if (fileno(stdin) == fd)
9601 else if (fileno(stdout) == fd)
9603 else if (fileno(stderr) == fd)
9635rb_io_set_encoding_by_bom(
VALUE io)
9641 rb_raise(rb_eArgError,
"ASCII incompatible encoding needs binmode");
9644 rb_raise(rb_eArgError,
"encoding conversion is set");
9646 else if (fptr->
encs.
enc && fptr->
encs.
enc != rb_ascii8bit_encoding()) {
9647 rb_raise(rb_eArgError,
"encoding is set to %s already",
9650 if (!io_set_encoding_by_bom(io))
return Qnil;
9651 return rb_enc_from_encoding(fptr->
encs.
enc);
9696rb_file_initialize(
int argc,
VALUE *argv,
VALUE io)
9698 if (
RFILE(io)->fptr) {
9701 VALUE fname, vmode, vperm, opt;
9702 int posargc =
rb_scan_args(argc, argv,
"12:", &fname, &vmode, &vperm, &opt);
9707 return io_initialize(io, fd, vmode, opt);
9710 return rb_open_file(io, fname, vmode, vperm, opt);
9715rb_io_s_new(
int argc,
VALUE *argv,
VALUE klass)
9720 rb_warn(
"%"PRIsVALUE
"::new() does not take block; use %"PRIsVALUE
"::open() instead",
9736rb_io_s_for_fd(
int argc,
VALUE *argv,
VALUE klass)
9739 rb_io_initialize(argc, argv, io);
9752rb_io_autoclose_p(
VALUE io)
9777rb_io_set_autoclose(
VALUE io,
VALUE autoclose)
9781 if (!
RTEST(autoclose))
9784 fptr->
mode &= ~FMODE_EXTERNAL;
9789io_wait_event(
VALUE io,
int event,
VALUE timeout,
int return_io)
9821io_wait_readable(
int argc,
VALUE *argv,
VALUE io)
9828 if (rb_io_read_pending(fptr))
return Qtrue;
9831 VALUE timeout = (argc == 1 ? argv[0] :
Qnil);
9845io_wait_writable(
int argc,
VALUE *argv,
VALUE io)
9853 VALUE timeout = (argc == 1 ? argv[0] :
Qnil);
9868io_wait_priority(
int argc,
VALUE *argv,
VALUE io)
9875 if (rb_io_read_pending(fptr))
return Qtrue;
9878 VALUE timeout = argc == 1 ? argv[0] :
Qnil;
9884wait_mode_sym(
VALUE mode)
9886 if (mode ==
ID2SYM(rb_intern(
"r"))) {
9887 return RB_WAITFD_IN;
9889 if (mode ==
ID2SYM(rb_intern(
"read"))) {
9890 return RB_WAITFD_IN;
9892 if (mode ==
ID2SYM(rb_intern(
"readable"))) {
9893 return RB_WAITFD_IN;
9895 if (mode ==
ID2SYM(rb_intern(
"w"))) {
9896 return RB_WAITFD_OUT;
9898 if (mode ==
ID2SYM(rb_intern(
"write"))) {
9899 return RB_WAITFD_OUT;
9901 if (mode ==
ID2SYM(rb_intern(
"writable"))) {
9902 return RB_WAITFD_OUT;
9904 if (mode ==
ID2SYM(rb_intern(
"rw"))) {
9905 return RB_WAITFD_IN|RB_WAITFD_OUT;
9907 if (mode ==
ID2SYM(rb_intern(
"read_write"))) {
9908 return RB_WAITFD_IN|RB_WAITFD_OUT;
9910 if (mode ==
ID2SYM(rb_intern(
"readable_writable"))) {
9911 return RB_WAITFD_IN|RB_WAITFD_OUT;
9914 rb_raise(rb_eArgError,
"unsupported mode: %"PRIsVALUE, mode);
9918io_event_from_value(
VALUE value)
9922 if (events <= 0) rb_raise(rb_eArgError,
"Events must be positive integer!");
9960 for (
int i = 0; i < argc; i += 1) {
9962 events |= wait_mode_sym(argv[i]);
9964 else if (UNDEF_P(timeout)) {
9968 rb_raise(rb_eArgError,
"timeout given more than once");
9972 if (UNDEF_P(timeout)) timeout =
Qnil;
9980 events = io_event_from_value(argv[0]);
9988 if (rb_io_read_pending(fptr)) {
9990 if (return_io)
return Qtrue;
9996 return io_wait_event(io, events, timeout, return_io);
10000argf_mark_and_move(
void *ptr)
10002 struct argf *p = ptr;
10003 rb_gc_mark_and_move(&p->filename);
10004 rb_gc_mark_and_move(&p->current_file);
10005 rb_gc_mark_and_move(&p->argv);
10006 rb_gc_mark_and_move(&p->inplace);
10007 rb_gc_mark_and_move(&p->encs.
ecopts);
10011argf_memsize(
const void *ptr)
10013 const struct argf *p = ptr;
10014 size_t size =
sizeof(*p);
10027 p->filename =
Qnil;
10028 p->current_file =
Qnil;
10034argf_alloc(
VALUE klass)
10049 memset(&ARGF, 0,
sizeof(ARGF));
10050 argf_init(
argf, &ARGF, argv);
10060 ARGF = argf_of(orig);
10061 rb_gc_writebarrier_remember(
argf);
10088 ARGF.last_lineno = ARGF.lineno;
10114 return forward_current(rb_frame_this_func(), argc, argv);
10117#define next_argv() argf_next_argv(argf)
10118#define ARGF_GENERIC_INPUT_P() \
10119 (ARGF.current_file == rb_stdin && !RB_TYPE_P(ARGF.current_file, T_FILE))
10120#define ARGF_FORWARD(argc, argv) do {\
10121 if (ARGF_GENERIC_INPUT_P())\
10122 return argf_forward((argc), (argv), argf);\
10124#define NEXT_ARGF_FORWARD(argc, argv) do {\
10125 if (!next_argv()) return Qnil;\
10126 ARGF_FORWARD((argc), (argv));\
10132 VALUE file = ARGF.current_file;
10146 int stdout_binmode = 0;
10147 enum rb_io_mode fmode;
10149 VALUE r_stdout = rb_ractor_stdout();
10154 stdout_binmode = 1;
10157 if (ARGF.init_p == 0) {
10167 if (
NIL_P(ARGF.argv)) {
10170 else if (ARGF.next_p == -1 &&
RARRAY_LEN(ARGF.argv) > 0) {
10175 if (ARGF.next_p == 1) {
10176 if (ARGF.init_p == 1) argf_close(
argf);
10181 ARGF_SET(filename, filename);
10182 filename = rb_str_encode_ospath(filename);
10184 if (RSTRING_LEN(filename) == 1 && fn[0] ==
'-') {
10186 if (ARGF.inplace) {
10187 rb_warn(
"Can't do inplace edit for stdio; skipping");
10193 int fr = rb_sysopen(filename, O_RDONLY, 0);
10195 if (ARGF.inplace) {
10197#ifndef NO_SAFE_RENAME
10208 if (!
NIL_P(ARGF.inplace)) {
10209 VALUE suffix = ARGF.inplace;
10211 if (
NIL_P(rb_str_cat_conv_enc_opts(str, RSTRING_LEN(str),
10212 RSTRING_PTR(suffix), RSTRING_LEN(suffix),
10213 rb_enc_get(suffix), 0,
Qnil))) {
10216#ifdef NO_SAFE_RENAME
10218 (void)unlink(RSTRING_PTR(str));
10219 if (rename(fn, RSTRING_PTR(str)) < 0) {
10220 rb_warn(
"Can't rename %"PRIsVALUE
" to %"PRIsVALUE
": %s, skipping file",
10221 filename, str, strerror(
errno));
10224 fr = rb_sysopen(str, O_RDONLY, 0);
10226 if (rename(fn, RSTRING_PTR(str)) < 0) {
10227 rb_warn(
"Can't rename %"PRIsVALUE
" to %"PRIsVALUE
": %s, skipping file",
10228 filename, str, strerror(
errno));
10235#ifdef NO_SAFE_RENAME
10236 rb_fatal(
"Can't do inplace edit without backup");
10238 if (unlink(fn) < 0) {
10239 rb_warn(
"Can't remove %"PRIsVALUE
": %s, skipping file",
10240 filename, strerror(
errno));
10246 fw = rb_sysopen(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666);
10247#ifndef NO_SAFE_RENAME
10250 fchmod(fw, st.st_mode);
10252 chmod(fn, st.st_mode);
10254 if (st.st_uid!=st2.st_uid || st.st_gid!=st2.st_gid) {
10257 err = fchown(fw, st.st_uid, st.st_gid);
10259 err = chown(fn, st.st_uid, st.st_gid);
10261 if (err && getuid() == 0 && st2.st_uid == 0) {
10262 const char *wkfn = RSTRING_PTR(filename);
10263 rb_warn(
"Can't set owner/group of %"PRIsVALUE
" to same as %"PRIsVALUE
": %s, skipping file",
10264 filename, str, strerror(
errno));
10267 (void)unlink(wkfn);
10277 if (!ARGF.binmode) {
10278 fmode |= DEFAULT_TEXTMODE;
10280 ARGF_SET(current_file, prep_io(fr, fmode,
rb_cFile, fn));
10281 if (!
NIL_P(write_io)) {
10288 if (ARGF.encs.enc) {
10289 fptr->
encs = ARGF.encs;
10290 clear_codeconv(fptr);
10293 fptr->
encs.
ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
10294 if (!ARGF.binmode) {
10296#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
10297 fptr->
encs.
ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
10308 else if (ARGF.next_p == -1) {
10311 if (ARGF.inplace) {
10312 rb_warn(
"Can't do inplace edit for stdio");
10316 if (ARGF.init_p == -1) ARGF.init_p = 1;
10324 long lineno = ARGF.lineno;
10327 if (!next_argv())
return Qnil;
10328 if (ARGF_GENERIC_INPUT_P()) {
10329 line = forward_current(idGets, argc, argv);
10336 line = rb_io_getline(argc, argv, ARGF.current_file);
10338 if (
NIL_P(line) && ARGF.next_p != -1) {
10344 if (!
NIL_P(line)) {
10345 ARGF.lineno = ++lineno;
10346 ARGF.last_lineno = ARGF.lineno;
10352argf_lineno_getter(
ID id,
VALUE *var)
10355 return INT2FIX(ARGF.last_lineno);
10363 ARGF.last_lineno = ARGF.lineno = n;
10367rb_reset_argf_lineno(
long n)
10369 ARGF.last_lineno = ARGF.lineno = n;
10410 if (recv ==
argf) {
10411 return argf_gets(argc, argv,
argf);
10413 return forward(
argf, idGets, argc, argv);
10439 line = argf_getline(argc, argv,
argf);
10451 return rb_f_gets(0, 0,
argf);
10455 if (!next_argv())
return Qnil;
10457 if (
NIL_P(line) && ARGF.next_p != -1) {
10463 if (!
NIL_P(line)) {
10465 ARGF.last_lineno = ARGF.lineno;
10491rb_f_readline(
int argc,
VALUE *argv,
VALUE recv)
10493 if (recv ==
argf) {
10494 return argf_readline(argc, argv,
argf);
10496 return forward(
argf, rb_intern(
"readline"), argc, argv);
10522 if (!next_argv()) rb_eof_error();
10523 ARGF_FORWARD(argc, argv);
10524 line = argf_gets(argc, argv,
argf);
10594rb_f_readlines(
int argc,
VALUE *argv,
VALUE recv)
10596 if (recv ==
argf) {
10597 return argf_readlines(argc, argv,
argf);
10599 return forward(
argf, rb_intern(
"readlines"), argc, argv);
10623 long lineno = ARGF.lineno;
10627 while (next_argv()) {
10628 if (ARGF_GENERIC_INPUT_P()) {
10629 lines = forward_current(rb_intern(
"readlines"), argc, argv);
10632 lines = rb_io_readlines(argc, argv, ARGF.current_file);
10638 ARGF.last_lineno = ARGF.lineno;
10673 rb_last_status_clear();
10674 port = pipe_open_s(str,
"r",
FMODE_READABLE|DEFAULT_TEXTMODE, NULL);
10678 result = read_all(fptr, remain_size(fptr),
Qnil);
10680 rb_io_fptr_cleanup_all(fptr);
10686#ifdef HAVE_SYS_SELECT_H
10687#include <sys/select.h>
10701 if (!
NIL_P(read)) {
10706 if (READ_DATA_PENDING(fptr) || READ_CHAR_PENDING(fptr)) {
10710 if (max < fptr->fd) max = fptr->
fd;
10713 timerec.tv_sec = timerec.tv_usec = 0;
10721 if (!
NIL_P(write)) {
10727 if (max < fptr->fd) max = fptr->
fd;
10734 if (!
NIL_P(except)) {
10738 VALUE write_io = GetWriteIO(io);
10741 if (max < fptr->fd) max = fptr->
fd;
10742 if (io != write_io) {
10745 if (max < fptr->fd) max = fptr->
fd;
10760 if (!pending && n == 0)
return Qnil;
10785 VALUE write_io = GetWriteIO(io);
10798 VALUE write_io = GetWriteIO(io);
10803 else if (io != write_io) {
10816 VALUE read, write, except;
10822select_call(
VALUE arg)
10826 return select_internal(p->read, p->write, p->except, p->timeout, p->fdsets);
10830select_end(
VALUE arg)
10835 for (i = 0; i < numberof(p->fdsets); ++i)
10840static VALUE sym_normal, sym_sequential, sym_random,
10841 sym_willneed, sym_dontneed, sym_noreuse;
10843#ifdef HAVE_POSIX_FADVISE
10844struct io_advise_struct {
10852io_advise_internal(
void *arg)
10854 struct io_advise_struct *ptr = arg;
10855 return posix_fadvise(ptr->fd, ptr->offset, ptr->len, ptr->advice);
10859io_advise_sym_to_const(
VALUE sym)
10861#ifdef POSIX_FADV_NORMAL
10862 if (sym == sym_normal)
10863 return INT2NUM(POSIX_FADV_NORMAL);
10866#ifdef POSIX_FADV_RANDOM
10867 if (sym == sym_random)
10868 return INT2NUM(POSIX_FADV_RANDOM);
10871#ifdef POSIX_FADV_SEQUENTIAL
10872 if (sym == sym_sequential)
10873 return INT2NUM(POSIX_FADV_SEQUENTIAL);
10876#ifdef POSIX_FADV_WILLNEED
10877 if (sym == sym_willneed)
10878 return INT2NUM(POSIX_FADV_WILLNEED);
10881#ifdef POSIX_FADV_DONTNEED
10882 if (sym == sym_dontneed)
10883 return INT2NUM(POSIX_FADV_DONTNEED);
10886#ifdef POSIX_FADV_NOREUSE
10887 if (sym == sym_noreuse)
10888 return INT2NUM(POSIX_FADV_NOREUSE);
10895do_io_advise(
rb_io_t *fptr,
VALUE advice, rb_off_t offset, rb_off_t
len)
10898 struct io_advise_struct ias;
10901 num_adv = io_advise_sym_to_const(advice);
10907 if (
NIL_P(num_adv))
10911 ias.advice =
NUM2INT(num_adv);
10912 ias.offset = offset;
10915 rv = (int)rb_io_blocking_region(fptr, io_advise_internal, &ias);
10916 if (rv && rv != ENOSYS) {
10919 VALUE message = rb_sprintf(
"%"PRIsVALUE
" "
10923 fptr->
pathv, offset,
len, advice);
10933advice_arg_check(
VALUE advice)
10938 if (advice != sym_normal &&
10939 advice != sym_sequential &&
10940 advice != sym_random &&
10941 advice != sym_willneed &&
10942 advice != sym_dontneed &&
10943 advice != sym_noreuse) {
10944 rb_raise(
rb_eNotImpError,
"Unsupported advice: %+"PRIsVALUE, advice);
10982rb_io_advise(
int argc,
VALUE *argv,
VALUE io)
10989 advice_arg_check(advice);
10991 io = GetWriteIO(io);
10997#ifdef HAVE_POSIX_FADVISE
10998 return do_io_advise(fptr, advice,
off, l);
11000 ((void)
off, (
void)l);
11012 return isinf(f) && 0 < f;
11168rb_f_select(
int argc,
VALUE *argv,
VALUE obj)
11171 if (scheduler !=
Qnil) {
11174 if (!UNDEF_P(result))
return result;
11182 rb_scan_args(argc, argv,
"13", &args.read, &args.write, &args.except, &timeout);
11183 if (
NIL_P(timeout) || is_pos_inf(timeout)) {
11188 args.timeout = &timerec;
11191 for (i = 0; i < numberof(args.fdsets); ++i)
11197#ifdef IOCTL_REQ_TYPE
11198 typedef IOCTL_REQ_TYPE ioctl_req_t;
11200 typedef int ioctl_req_t;
11201# define NUM2IOCTLREQ(num) ((int)NUM2LONG(num))
11212nogvl_ioctl(
void *ptr)
11214 struct ioctl_arg *arg = ptr;
11216 return (
VALUE)ioctl(arg->fd, arg->cmd, arg->narg);
11220do_ioctl(
struct rb_io *io, ioctl_req_t cmd,
long narg)
11223 struct ioctl_arg arg;
11229 retval = (int)rb_io_blocking_region(io, nogvl_ioctl, &arg);
11235#define DEFAULT_IOCTL_NARG_LEN (256)
11237#if defined(__linux__) && defined(_IOC_SIZE)
11239linux_iocparm_len(ioctl_req_t cmd)
11243 if ((cmd & 0xFFFF0000) == 0) {
11245 return DEFAULT_IOCTL_NARG_LEN;
11248 len = _IOC_SIZE(cmd);
11251 if (
len < DEFAULT_IOCTL_NARG_LEN)
11252 len = DEFAULT_IOCTL_NARG_LEN;
11260ioctl_narg_len(ioctl_req_t cmd)
11266#define IOCPARM_LEN(x) (((x) >> 16) & IOCPARM_MASK)
11270 len = IOCPARM_LEN(cmd);
11271#elif defined(__linux__) && defined(_IOC_SIZE)
11272 len = linux_iocparm_len(cmd);
11275 len = DEFAULT_IOCTL_NARG_LEN;
11284typedef long fcntl_arg_t;
11287typedef int fcntl_arg_t;
11291fcntl_narg_len(ioctl_req_t cmd)
11298 len =
sizeof(fcntl_arg_t);
11306#ifdef F_DUPFD_CLOEXEC
11307 case F_DUPFD_CLOEXEC:
11308 len =
sizeof(fcntl_arg_t);
11318 len =
sizeof(fcntl_arg_t);
11328 len =
sizeof(fcntl_arg_t);
11338 len =
sizeof(fcntl_arg_t);
11343 len =
sizeof(
struct f_owner_ex);
11348 len =
sizeof(
struct f_owner_ex);
11353 len =
sizeof(
struct flock);
11358 len =
sizeof(
struct flock);
11363 len =
sizeof(
struct flock);
11383 len =
sizeof(fcntl_arg_t);
11393 len =
sizeof(fcntl_arg_t);
11398 len =
sizeof(fcntl_arg_t);
11411fcntl_narg_len(ioctl_req_t cmd)
11417#define NARG_SENTINEL 17
11420setup_narg(ioctl_req_t cmd,
VALUE *argp,
long (*narg_len)(ioctl_req_t))
11431 else if (arg ==
Qtrue) {
11445 len = narg_len(cmd);
11446 rb_str_modify(arg);
11448 slen = RSTRING_LEN(arg);
11450 if (slen <
len+1) {
11451 rb_str_resize(arg,
len+1);
11452 MEMZERO(RSTRING_PTR(arg)+slen,
char,
len-slen);
11456 ptr = RSTRING_PTR(arg);
11457 ptr[slen - 1] = NARG_SENTINEL;
11466finish_narg(
int retval,
VALUE arg,
const rb_io_t *fptr)
11468 if (retval < 0) rb_sys_fail_path(fptr->
pathv);
11473 if (ptr[slen-1] != NARG_SENTINEL)
11474 rb_raise(rb_eArgError,
"return value overflowed string");
11475 ptr[slen-1] =
'\0';
11485 ioctl_req_t cmd = NUM2IOCTLREQ(req);
11490 narg = setup_narg(cmd, &arg, ioctl_narg_len);
11492 retval = do_ioctl(fptr, cmd, narg);
11493 return finish_narg(retval, arg, fptr);
11520 return rb_ioctl(io, req, arg);
11523#define rb_io_ioctl rb_f_notimplement
11534nogvl_fcntl(
void *ptr)
11536 struct fcntl_arg *arg = ptr;
11538#if defined(F_DUPFD)
11539 if (arg->cmd == F_DUPFD)
11542 return (
VALUE)fcntl(arg->fd, arg->cmd, arg->narg);
11546do_fcntl(
struct rb_io *io,
int cmd,
long narg)
11549 struct fcntl_arg arg;
11555 retval = (int)rb_io_blocking_region(io, nogvl_fcntl, &arg);
11556 if (retval != -1) {
11558#if defined(F_DUPFD)
11561#if defined(F_DUPFD_CLOEXEC)
11562 case F_DUPFD_CLOEXEC:
11579 narg = setup_narg(cmd, &arg, fcntl_narg_len);
11581 retval = do_fcntl(fptr, cmd, narg);
11582 return finish_narg(retval, arg, fptr);
11608 return rb_fcntl(io, req, arg);
11611#define rb_io_fcntl rb_f_notimplement
11614#if defined(HAVE_SYSCALL) || defined(HAVE___SYSCALL)
11646#if SIZEOF_VOIDP == 8 && defined(HAVE___SYSCALL) && SIZEOF_INT != 8
11647# define SYSCALL __syscall
11648# define NUM2SYSCALLID(x) NUM2LONG(x)
11649# define RETVAL2NUM(x) LONG2NUM(x)
11650# if SIZEOF_LONG == 8
11651 long num, retval = -1;
11652# elif SIZEOF_LONG_LONG == 8
11653 long long num, retval = -1;
11655# error ---->> it is asserted that __syscall takes the first argument and returns retval in 64bit signed integer. <<----
11657#elif defined(__linux__)
11658# define SYSCALL syscall
11659# define NUM2SYSCALLID(x) NUM2LONG(x)
11660# define RETVAL2NUM(x) LONG2NUM(x)
11668 long num, retval = -1;
11670# define SYSCALL syscall
11671# define NUM2SYSCALLID(x) NUM2INT(x)
11672# define RETVAL2NUM(x) INT2NUM(x)
11673 int num, retval = -1;
11679 "We plan to remove a syscall function at future release. DL(Fiddle) provides safer alternative.");
11683 rb_raise(rb_eArgError,
"too few arguments for syscall");
11684 if (argc > numberof(arg))
11685 rb_raise(rb_eArgError,
"too many arguments for syscall");
11686 num = NUM2SYSCALLID(argv[0]); ++argv;
11687 for (i = argc - 1; i--; ) {
11702 retval = SYSCALL(num);
11705 retval = SYSCALL(num, arg[0]);
11708 retval = SYSCALL(num, arg[0],arg[1]);
11711 retval = SYSCALL(num, arg[0],arg[1],arg[2]);
11714 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3]);
11717 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4]);
11720 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5]);
11723 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6]);
11729 return RETVAL2NUM(retval);
11731#undef NUM2SYSCALLID
11735#define rb_f_syscall rb_f_notimplement
11739io_new_instance(
VALUE args)
11745find_encoding(
VALUE v)
11748 if (!enc)
rb_warn(
"Unsupported encoding %"PRIsVALUE
" ignored", v);
11760 enc2 = find_encoding(v1);
11763 if (RSTRING_LEN(tmp) == 1 && RSTRING_PTR(tmp)[0] ==
'-') {
11769 enc = find_encoding(v2);
11776 enc = find_encoding(v2);
11782 if (enc2 == rb_ascii8bit_encoding()) {
11787 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11793 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
11794 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11799 if (!
NIL_P(tmp) && rb_enc_asciicompat(enc = rb_enc_get(tmp))) {
11800 parse_mode_enc(RSTRING_PTR(tmp), enc, &enc, &enc2, NULL);
11801 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11805 rb_io_ext_int_to_encs(find_encoding(v1), NULL, &enc, &enc2, 0);
11806 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11811 validate_enc_binmode(&fptr->
mode, ecflags, enc, enc2);
11816 clear_codeconv(fptr);
11828io_encoding_set_v(
VALUE v)
11831 io_encoding_set(arg->fptr, arg->v1, arg->v2, arg->opt);
11836pipe_pair_close(
VALUE rw)
11839 return rb_ensure(io_close, rwp[0], io_close, rwp[1]);
11922rb_io_s_pipe(
int argc,
VALUE *argv,
VALUE klass)
11924 int pipes[2], state;
11925 VALUE r, w, args[3], v1, v2;
11929 enum rb_io_mode fmode = 0;
11932 argc =
rb_scan_args(argc, argv,
"02:", &v1, &v2, &opt);
11939 r = rb_protect(io_new_instance, (
VALUE)args, &state);
11943 rb_jump_tag(state);
11947 ies_args.fptr = fptr;
11950 ies_args.opt = opt;
11951 rb_protect(io_encoding_set_v, (
VALUE)&ies_args, &state);
11955 rb_jump_tag(state);
11960 w = rb_protect(io_new_instance, (
VALUE)args, &state);
11964 rb_jump_tag(state);
11969 extract_binmode(opt, &fmode);
11976#if DEFAULT_TEXTMODE
11978 fptr->
mode &= ~FMODE_TEXTMODE;
11979 setmode(fptr->
fd, O_BINARY);
11981#if RUBY_CRLF_ENVIRONMENT
11987 fptr->
mode |= fmode;
11988#if DEFAULT_TEXTMODE
11990 fptr2->
mode &= ~FMODE_TEXTMODE;
11991 setmode(fptr2->
fd, O_BINARY);
11994 fptr2->
mode |= fmode;
12028 else if (!
NIL_P(v = rb_hash_aref(opt, sym_open_args))) {
12031 v = rb_to_array_type(v);
12036 arg->io = rb_io_open(klass, path, vmode, vperm, opt);
12040io_s_foreach(
VALUE v)
12045 if (arg->limit == 0)
12046 rb_raise(rb_eArgError,
"invalid limit: 0 for foreach");
12047 while (!
NIL_P(str = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, arg->io))) {
12131rb_io_s_foreach(
int argc,
VALUE *argv,
VALUE self)
12134 int orig_argc = argc;
12138 argc =
rb_scan_args(argc, argv,
"12:", NULL, NULL, NULL, &opt);
12140 extract_getline_args(argc-1, argv+1, &garg);
12141 open_key_args(self, argc, argv, opt, &arg);
12143 extract_getline_opts(opt, &garg);
12144 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12145 return rb_ensure(io_s_foreach, (
VALUE)&garg, rb_io_close, arg.io);
12149io_s_readlines(
VALUE v)
12152 return io_readlines(arg, arg->io);
12205rb_io_s_readlines(
int argc,
VALUE *argv,
VALUE io)
12211 argc =
rb_scan_args(argc, argv,
"12:", NULL, NULL, NULL, &opt);
12212 extract_getline_args(argc-1, argv+1, &garg);
12213 open_key_args(io, argc, argv, opt, &arg);
12215 extract_getline_opts(opt, &garg);
12216 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12217 return rb_ensure(io_s_readlines, (
VALUE)&garg, rb_io_close, arg.io);
12224 return io_read(arg->argc, arg->argv, arg->io);
12234seek_before_access(
VALUE argp)
12238 return rb_io_seek(arg->io, arg->offset, arg->mode);
12305rb_io_s_read(
int argc,
VALUE *argv,
VALUE io)
12311 argc =
rb_scan_args(argc, argv,
"13:", NULL, NULL, &offset, NULL, &opt);
12313 rb_raise(rb_eArgError,
"negative offset %ld given",
off);
12315 open_key_args(io, argc, argv, opt, &arg);
12317 if (!
NIL_P(offset)) {
12321 sarg.offset = offset;
12322 sarg.mode = SEEK_SET;
12323 rb_protect(seek_before_access, (
VALUE)&sarg, &state);
12326 rb_jump_tag(state);
12328 if (arg.argc == 2) arg.argc = 1;
12343rb_io_s_binread(
int argc,
VALUE *argv,
VALUE io)
12358 convconfig.
enc = rb_ascii8bit_encoding();
12359 arg.io = rb_io_open_generic(io, argv[0], oflags, fmode, &convconfig, 0);
12362 arg.argc = (argc > 1) ? 1 : 0;
12363 if (!
NIL_P(offset)) {
12367 sarg.offset = offset;
12368 sarg.mode = SEEK_SET;
12369 rb_protect(seek_before_access, (
VALUE)&sarg, &state);
12372 rb_jump_tag(state);
12379io_s_write0(
VALUE v)
12382 return io_write(arg->io,arg->str,arg->nosync);
12386io_s_write(
int argc,
VALUE *argv,
VALUE klass,
int binary)
12388 VALUE string, offset, opt;
12392 rb_scan_args(argc, argv,
"21:", NULL, &
string, &offset, &opt);
12394 if (
NIL_P(opt)) opt = rb_hash_new();
12395 else opt = rb_hash_dup(opt);
12398 if (
NIL_P(rb_hash_aref(opt,sym_mode))) {
12399 int mode = O_WRONLY|O_CREAT;
12401 if (binary) mode |= O_BINARY;
12403 if (
NIL_P(offset)) mode |= O_TRUNC;
12404 rb_hash_aset(opt,sym_mode,
INT2NUM(mode));
12406 open_key_args(klass, argc, argv, opt, &arg);
12409 if (binary) rb_io_binmode_m(arg.io);
12413 if (!
NIL_P(offset)) {
12417 sarg.offset = offset;
12418 sarg.mode = SEEK_SET;
12419 rb_protect(seek_before_access, (
VALUE)&sarg, &state);
12422 rb_jump_tag(state);
12430 return rb_ensure(io_s_write0, (
VALUE)&warg, rb_io_close, arg.io);
12488rb_io_s_write(
int argc,
VALUE *argv,
VALUE io)
12490 return io_s_write(argc, argv, io, 0);
12503rb_io_s_binwrite(
int argc,
VALUE *argv,
VALUE io)
12505 return io_s_write(argc, argv, io, 1);
12511 rb_off_t copy_length;
12512 rb_off_t src_offset;
12516 unsigned close_src : 1;
12517 unsigned close_dst : 1;
12520 const char *syserr;
12521 const char *notimp;
12523 struct stat src_stat;
12524 struct stat dst_stat;
12525#ifdef HAVE_FCOPYFILE
12526 copyfile_state_t copyfile_state;
12531exec_interrupts(
void *arg)
12534 rb_thread_execute_interrupts(th);
12548#if defined(ERESTART)
12553 rb_thread_execute_interrupts(stp->th);
12572fiber_scheduler_wait_for(
void * _arguments)
12582# define IOWAIT_SYSCALL "poll"
12583STATIC_ASSERT(pollin_expected, POLLIN == RB_WAITFD_IN);
12584STATIC_ASSERT(pollout_expected, POLLOUT == RB_WAITFD_OUT);
12589 if (scheduler !=
Qnil) {
12592 return RTEST(args.result);
12596 if (fd == -1)
return 0;
12601 fds.events = events;
12603 int timeout_milliseconds = -1;
12606 timeout_milliseconds = (int)(timeout->tv_sec * 1000) + (int)(timeout->tv_usec / 1000);
12609 return poll(&fds, 1, timeout_milliseconds);
12612# define IOWAIT_SYSCALL "select"
12617 if (scheduler !=
Qnil) {
12620 return RTEST(args.result);
12640 case RB_WAITFD_OUT:
12644 VM_UNREACHABLE(nogvl_wait_for);
12664 ret = nogvl_wait_for(stp->th, stp->src_fptr, RB_WAITFD_IN, NULL);
12666 }
while (ret < 0 && maygvl_copy_stream_continue_p(has_gvl, stp));
12669 stp->syserr = IOWAIT_SYSCALL;
12670 stp->error_no =
errno;
12682 ret = nogvl_wait_for(stp->th, stp->dst_fptr, RB_WAITFD_OUT, NULL);
12683 }
while (ret < 0 && maygvl_copy_stream_continue_p(0, stp));
12686 stp->syserr = IOWAIT_SYSCALL;
12687 stp->error_no =
errno;
12693#ifdef USE_COPY_FILE_RANGE
12696simple_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)
12698#ifdef HAVE_COPY_FILE_RANGE
12699 return copy_file_range(in_fd, in_offset, out_fd, out_offset, count, flags);
12701 return syscall(__NR_copy_file_range, in_fd, in_offset, out_fd, out_offset, count, flags);
12710 rb_off_t copy_length, src_offset, *src_offset_ptr;
12712 if (!S_ISREG(stp->src_stat.st_mode))
12715 src_size = stp->src_stat.st_size;
12716 src_offset = stp->src_offset;
12717 if (src_offset >= (rb_off_t)0) {
12718 src_offset_ptr = &src_offset;
12721 src_offset_ptr = NULL;
12724 copy_length = stp->copy_length;
12725 if (copy_length < (rb_off_t)0) {
12726 if (src_offset < (rb_off_t)0) {
12727 rb_off_t current_offset;
12729 current_offset = lseek(stp->src_fptr->
fd, 0, SEEK_CUR);
12730 if (current_offset < (rb_off_t)0 &&
errno) {
12731 stp->syserr =
"lseek";
12732 stp->error_no =
errno;
12733 return (
int)current_offset;
12735 copy_length = src_size - current_offset;
12738 copy_length = src_size - src_offset;
12742 retry_copy_file_range:
12743# if SIZEOF_OFF_T > SIZEOF_SIZE_T
12745 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
12747 ss = (ssize_t)copy_length;
12749 ss = simple_copy_file_range(stp->src_fptr->
fd, src_offset_ptr, stp->dst_fptr->
fd, NULL, ss, 0);
12753 if (0 < copy_length) {
12754 goto retry_copy_file_range;
12758 if (maygvl_copy_stream_continue_p(0, stp)) {
12759 goto retry_copy_file_range;
12773#if EWOULDBLOCK != EAGAIN
12777 int ret = nogvl_copy_stream_wait_write(stp);
12778 if (ret < 0)
return ret;
12780 goto retry_copy_file_range;
12784 int flags = fcntl(stp->dst_fptr->
fd, F_GETFL);
12786 if (flags != -1 && flags & O_APPEND) {
12792 stp->syserr =
"copy_file_range";
12793 stp->error_no =
errno;
12800#ifdef HAVE_FCOPYFILE
12804 rb_off_t cur, ss = 0;
12805 const rb_off_t src_offset = stp->src_offset;
12808 if (stp->copy_length >= (rb_off_t)0) {
12813 if (!S_ISREG(stp->src_stat.st_mode))
12816 if (!S_ISREG(stp->dst_stat.st_mode))
12818 if (lseek(stp->dst_fptr->
fd, 0, SEEK_CUR) > (rb_off_t)0)
12820 if (fcntl(stp->dst_fptr->
fd, F_GETFL) & O_APPEND) {
12823 rb_off_t end = lseek(stp->dst_fptr->
fd, 0, SEEK_END);
12824 lseek(stp->dst_fptr->
fd, 0, SEEK_SET);
12825 if (end > (rb_off_t)0)
return 0;
12828 if (src_offset > (rb_off_t)0) {
12833 cur = lseek(stp->src_fptr->
fd, 0, SEEK_CUR);
12834 if (cur < (rb_off_t)0 &&
errno) {
12835 stp->error_no =
errno;
12840 r = lseek(stp->src_fptr->
fd, src_offset, SEEK_SET);
12841 if (r < (rb_off_t)0 &&
errno) {
12842 stp->error_no =
errno;
12847 stp->copyfile_state = copyfile_state_alloc();
12848 ret = fcopyfile(stp->src_fptr->
fd, stp->dst_fptr->
fd, stp->copyfile_state, COPYFILE_DATA);
12849 copyfile_state_get(stp->copyfile_state, COPYFILE_STATE_COPIED, &ss);
12853 if (src_offset > (rb_off_t)0) {
12857 r = lseek(stp->src_fptr->
fd, cur, SEEK_SET);
12858 if (r < (rb_off_t)0 &&
errno) {
12859 stp->error_no =
errno;
12871 stp->syserr =
"fcopyfile";
12872 stp->error_no =
errno;
12879#ifdef HAVE_SENDFILE
12882# define USE_SENDFILE
12884# ifdef HAVE_SYS_SENDFILE_H
12885# include <sys/sendfile.h>
12889simple_sendfile(
int out_fd,
int in_fd, rb_off_t *offset, rb_off_t count)
12891 return sendfile(out_fd, in_fd, offset, (
size_t)count);
12894# elif 0 || defined(__APPLE__)
12898# define USE_SENDFILE
12901simple_sendfile(
int out_fd,
int in_fd, rb_off_t *offset, rb_off_t count)
12904 rb_off_t pos = offset ? *offset : lseek(in_fd, 0, SEEK_CUR);
12907 r = sendfile(in_fd, out_fd, pos, &count, NULL, 0);
12910 r = sendfile(in_fd, out_fd, pos, (
size_t)count, NULL, &sbytes, 0);
12912 if (r != 0 && sbytes == 0)
return r;
12917 lseek(in_fd, sbytes, SEEK_CUR);
12919 return (ssize_t)sbytes;
12932 rb_off_t copy_length;
12933 rb_off_t src_offset;
12936 if (!S_ISREG(stp->src_stat.st_mode))
12939 src_size = stp->src_stat.st_size;
12941 if ((stp->dst_stat.st_mode & S_IFMT) != S_IFSOCK)
12945 src_offset = stp->src_offset;
12946 use_pread = src_offset >= (rb_off_t)0;
12948 copy_length = stp->copy_length;
12949 if (copy_length < (rb_off_t)0) {
12951 copy_length = src_size - src_offset;
12955 cur = lseek(stp->src_fptr->
fd, 0, SEEK_CUR);
12956 if (cur < (rb_off_t)0 &&
errno) {
12957 stp->syserr =
"lseek";
12958 stp->error_no =
errno;
12961 copy_length = src_size - cur;
12966# if SIZEOF_OFF_T > SIZEOF_SIZE_T
12968 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
12970 ss = (ssize_t)copy_length;
12973 ss = simple_sendfile(stp->dst_fptr->
fd, stp->src_fptr->
fd, &src_offset, ss);
12976 ss = simple_sendfile(stp->dst_fptr->
fd, stp->src_fptr->
fd, NULL, ss);
12981 if (0 < copy_length) {
12982 goto retry_sendfile;
12986 if (maygvl_copy_stream_continue_p(0, stp))
12987 goto retry_sendfile;
13000#if EWOULDBLOCK != EAGAIN
13013 ret = maygvl_copy_stream_wait_read(0, stp);
13014 if (ret < 0)
return ret;
13016 ret = nogvl_copy_stream_wait_write(stp);
13017 if (ret < 0)
return ret;
13019 goto retry_sendfile;
13021 stp->syserr =
"sendfile";
13022 stp->error_no =
errno;
13030maygvl_read(
int has_gvl,
rb_io_t *fptr,
void *buf,
size_t count)
13033 return rb_io_read_memory(fptr, buf, count);
13035 return read(fptr->
fd, buf, count);
13039maygvl_copy_stream_read(
int has_gvl,
struct copy_stream_struct *stp,
char *buf,
size_t len, rb_off_t offset)
13043 if (offset < (rb_off_t)0) {
13044 ss = maygvl_read(has_gvl, stp->src_fptr, buf,
len);
13047 ss = pread(stp->src_fptr->
fd, buf,
len, offset);
13053 if (maygvl_copy_stream_continue_p(has_gvl, stp))
13057#if EWOULDBLOCK != EAGAIN
13061 int ret = maygvl_copy_stream_wait_read(has_gvl, stp);
13062 if (ret < 0)
return ret;
13067 stp->notimp =
"pread";
13071 stp->syserr = offset < (rb_off_t)0 ?
"read" :
"pread";
13072 stp->error_no =
errno;
13083 ss = write(stp->dst_fptr->
fd, buf+
off,
len);
13085 if (maygvl_copy_stream_continue_p(0, stp))
13087 if (io_again_p(
errno)) {
13088 int ret = nogvl_copy_stream_wait_write(stp);
13089 if (ret < 0)
return ret;
13092 stp->syserr =
"write";
13093 stp->error_no =
errno;
13110 rb_off_t copy_length;
13111 rb_off_t src_offset;
13115 copy_length = stp->copy_length;
13116 use_eof = copy_length < (rb_off_t)0;
13117 src_offset = stp->src_offset;
13118 use_pread = src_offset >= (rb_off_t)0;
13120 if (use_pread && stp->close_src) {
13123 r = lseek(stp->src_fptr->
fd, src_offset, SEEK_SET);
13124 if (r < (rb_off_t)0 &&
errno) {
13125 stp->syserr =
"lseek";
13126 stp->error_no =
errno;
13129 src_offset = (rb_off_t)-1;
13133 while (use_eof || 0 < copy_length) {
13134 if (!use_eof && copy_length < (rb_off_t)
sizeof(buf)) {
13135 len = (size_t)copy_length;
13141 ss = maygvl_copy_stream_read(0, stp, buf,
len, src_offset);
13146 ss = maygvl_copy_stream_read(0, stp, buf,
len, (rb_off_t)-1);
13151 ret = nogvl_copy_stream_write(stp, buf, ss);
13161nogvl_copy_stream_func(
void *arg)
13164#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13168#ifdef USE_COPY_FILE_RANGE
13169 ret = nogvl_copy_file_range(stp);
13174#ifdef HAVE_FCOPYFILE
13175 ret = nogvl_fcopyfile(stp);
13181 ret = nogvl_copy_stream_sendfile(stp);
13186 nogvl_copy_stream_read_write(stp);
13188#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13195copy_stream_fallback_body(
VALUE arg)
13198 const int buflen = 16*1024;
13201 rb_off_t rest = stp->copy_length;
13202 rb_off_t
off = stp->src_offset;
13203 ID read_method = id_readpartial;
13205 if (!stp->src_fptr) {
13207 read_method = id_read;
13214 rb_str_make_independent(buf);
13215 if (stp->copy_length < (rb_off_t)0) {
13220 rb_str_resize(buf, 0);
13223 l = buflen < rest ? buflen : (long)rest;
13225 if (!stp->src_fptr) {
13228 if (read_method == id_read &&
NIL_P(rc))
13233 rb_str_resize(buf, buflen);
13234 ss = maygvl_copy_stream_read(1, stp, RSTRING_PTR(buf), l,
off);
13235 rb_str_resize(buf, ss > 0 ? ss : 0);
13240 if (
off >= (rb_off_t)0)
13243 n = rb_io_write(stp->dst, buf);
13245 stp->total += numwrote;
13247 if (read_method == id_read && RSTRING_LEN(buf) == 0) {
13258 if (!stp->src_fptr && stp->src_offset >= (rb_off_t)0) {
13259 rb_raise(rb_eArgError,
"cannot specify src_offset for non-IO");
13268copy_stream_body(
VALUE arg)
13271 VALUE src_io = stp->src, dst_io = stp->dst;
13272 const int common_oflags = 0
13282 if (src_io ==
argf ||
13286 stp->src_fptr = NULL;
13291 if (!
NIL_P(tmp_io)) {
13298 args[1] =
INT2NUM(O_RDONLY|common_oflags);
13301 stp->close_src = 1;
13306 stat_ret = fstat(stp->src_fptr->
fd, &stp->src_stat);
13307 if (stat_ret < 0) {
13308 stp->syserr =
"fstat";
13309 stp->error_no =
errno;
13314 if (dst_io ==
argf ||
13318 stp->dst_fptr = NULL;
13323 if (!
NIL_P(tmp_io)) {
13324 dst_io = GetWriteIO(tmp_io);
13330 args[1] =
INT2NUM(O_WRONLY|O_CREAT|O_TRUNC|common_oflags);
13334 stp->close_dst = 1;
13337 dst_io = GetWriteIO(dst_io);
13343 stat_ret = fstat(stp->dst_fptr->
fd, &stp->dst_stat);
13344 if (stat_ret < 0) {
13345 stp->syserr =
"fstat";
13346 stp->error_no =
errno;
13353 SET_BINARY_MODE_WITH_SEEK_CUR(stp->src_fptr);
13356 io_ascii8bit_binmode(stp->dst_fptr);
13358 if (stp->src_offset < (rb_off_t)0 && stp->src_fptr && stp->src_fptr->
rbuf.
len) {
13361 if (stp->copy_length >= (rb_off_t)0 && stp->copy_length < (rb_off_t)
len) {
13362 len = (size_t)stp->copy_length;
13365 rb_str_resize(str,
len);
13366 read_buffered_data(RSTRING_PTR(str),
len, stp->src_fptr);
13367 if (stp->dst_fptr) {
13368 if (io_binwrite(RSTRING_PTR(str), RSTRING_LEN(str), stp->dst_fptr, 0) < 0)
13369 rb_sys_fail_on_write(stp->dst_fptr);
13372 rb_io_write(dst_io, str);
13373 rb_str_resize(str, 0);
13375 if (stp->copy_length >= (rb_off_t)0)
13376 stp->copy_length -=
len;
13379 if (stp->dst_fptr && io_fflush(stp->dst_fptr) < 0) {
13383 if (stp->copy_length == 0)
13386 if (stp->src_fptr == NULL || stp->dst_fptr == NULL) {
13387 return copy_stream_fallback(stp);
13390 IO_WITHOUT_GVL(nogvl_copy_stream_func, stp);
13395copy_stream_finalize(
VALUE arg)
13399#ifdef HAVE_FCOPYFILE
13400 if (stp->copyfile_state) {
13401 copyfile_state_free(stp->copyfile_state);
13405 if (stp->close_src) {
13406 rb_io_close_m(stp->src);
13408 if (stp->close_dst) {
13409 rb_io_close_m(stp->dst);
13472rb_io_s_copy_stream(
int argc,
VALUE *argv,
VALUE io)
13474 VALUE src, dst, length, src_offset;
13479 rb_scan_args(argc, argv,
"22", &src, &dst, &length, &src_offset);
13484 st.src_fptr = NULL;
13485 st.dst_fptr = NULL;
13488 st.copy_length = (rb_off_t)-1;
13490 st.copy_length =
NUM2OFFT(length);
13492 if (
NIL_P(src_offset))
13493 st.src_offset = (rb_off_t)-1;
13495 st.src_offset =
NUM2OFFT(src_offset);
13514rb_io_external_encoding(
VALUE io)
13519 return rb_enc_from_encoding(fptr->
encs.
enc2);
13523 return rb_enc_from_encoding(fptr->
encs.
enc);
13526 return rb_enc_from_encoding(io_read_encoding(fptr));
13542rb_io_internal_encoding(
VALUE io)
13547 return rb_enc_from_encoding(io_read_encoding(fptr));
13581rb_io_set_encoding(
int argc,
VALUE *argv,
VALUE io)
13587 return forward(io, id_set_encoding, argc, argv);
13590 argc =
rb_scan_args(argc, argv,
"11:", &v1, &v2, &opt);
13592 io_encoding_set(fptr, v1, v2, opt);
13597rb_stdio_set_default_encoding(
void)
13602 if (isatty(fileno(stdin))) {
13604 rb_encoding *internal = rb_default_internal_encoding();
13605 if (!internal) internal = rb_default_external_encoding();
13607 rb_enc_from_encoding(external),
13608 rb_enc_from_encoding(internal),
13613 rb_io_set_encoding(1, &val,
rb_stdin);
13614 rb_io_set_encoding(1, &val,
rb_stdout);
13615 rb_io_set_encoding(1, &val,
rb_stderr);
13619global_argf_p(
VALUE arg)
13621 return arg ==
argf;
13624typedef VALUE (*argf_encoding_func)(
VALUE io);
13627argf_encoding(
VALUE argf, argf_encoding_func func)
13629 if (!
RTEST(ARGF.current_file)) {
13630 return rb_enc_default_external();
13654 return argf_encoding(
argf, rb_io_external_encoding);
13673 return argf_encoding(
argf, rb_io_internal_encoding);
13712 if (!next_argv()) {
13713 rb_raise(rb_eArgError,
"no stream to set encoding");
13715 rb_io_set_encoding(argc, argv, ARGF.current_file);
13717 ARGF.encs = fptr->
encs;
13737 if (!next_argv()) {
13738 rb_raise(rb_eArgError,
"no stream to tell");
13740 ARGF_FORWARD(0, 0);
13741 return rb_io_tell(ARGF.current_file);
13754 if (!next_argv()) {
13755 rb_raise(rb_eArgError,
"no stream to seek");
13757 ARGF_FORWARD(argc, argv);
13758 return rb_io_seek_m(argc, argv, ARGF.current_file);
13775 if (!next_argv()) {
13776 rb_raise(rb_eArgError,
"no stream to set position");
13778 ARGF_FORWARD(1, &offset);
13779 return rb_io_set_pos(ARGF.current_file, offset);
13800 if (!next_argv()) {
13801 rb_raise(rb_eArgError,
"no stream to rewind");
13803 ARGF_FORWARD(0, 0);
13804 old_lineno =
RFILE(ARGF.current_file)->fptr->lineno;
13805 ret = rb_io_rewind(ARGF.current_file);
13806 if (!global_argf_p(
argf)) {
13807 ARGF.last_lineno = ARGF.lineno -= old_lineno;
13825 if (!next_argv()) {
13826 rb_raise(rb_eArgError,
"no stream");
13828 ARGF_FORWARD(0, 0);
13829 return rb_io_fileno(ARGF.current_file);
13848 ARGF_FORWARD(0, 0);
13849 return ARGF.current_file;
13874 if (
RTEST(ARGF.current_file)) {
13875 if (ARGF.init_p == 0)
return Qtrue;
13877 ARGF_FORWARD(0, 0);
13936 VALUE tmp, str, length;
13940 if (!
NIL_P(length)) {
13945 rb_str_resize(str,0);
13950 if (!next_argv()) {
13953 if (ARGF_GENERIC_INPUT_P()) {
13954 tmp = argf_forward(argc, argv,
argf);
13957 tmp = io_read(argc, argv, ARGF.current_file);
13959 if (
NIL_P(str)) str = tmp;
13962 if (ARGF.next_p != -1) {
13968 else if (argc >= 1) {
13969 long slen = RSTRING_LEN(str);
13985argf_forward_call(
VALUE arg)
13988 argf_forward(p->argc, p->argv, p->argf);
14018 return argf_getpartial(argc, argv,
argf,
Qnil, 0);
14039 return argf_getpartial(argc, argv,
argf, opts, 1);
14045 VALUE tmp, str, length;
14053 no_exception = no_exception_p(opts);
14055 if (!next_argv()) {
14057 rb_str_resize(str, 0);
14061 if (ARGF_GENERIC_INPUT_P()) {
14071 tmp = io_getpartial(argc, argv, ARGF.current_file, no_exception, nonblock);
14074 if (ARGF.next_p == -1) {
14075 return io_nonblock_eof(no_exception);
14080 return io_nonblock_eof(no_exception);
14118 if (!next_argv())
return Qnil;
14119 if (ARGF_GENERIC_INPUT_P()) {
14120 ch = forward_current(rb_intern(
"getc"), 0, 0);
14123 ch = rb_io_getc(ARGF.current_file);
14125 if (
NIL_P(ch) && ARGF.next_p != -1) {
14158 if (!next_argv())
return Qnil;
14160 ch = forward_current(rb_intern(
"getbyte"), 0, 0);
14165 if (
NIL_P(ch) && ARGF.next_p != -1) {
14198 if (!next_argv()) rb_eof_error();
14200 ch = forward_current(rb_intern(
"getc"), 0, 0);
14203 ch = rb_io_getc(ARGF.current_file);
14205 if (
NIL_P(ch) && ARGF.next_p != -1) {
14237 NEXT_ARGF_FORWARD(0, 0);
14238 c = argf_getbyte(
argf);
14245#define FOREACH_ARGF() while (next_argv())
14250 const VALUE current = ARGF.current_file;
14252 if (ARGF.init_p == -1 || current != ARGF.current_file) {
14258#define ARGF_block_call(mid, argc, argv, func, argf) \
14259 rb_block_call_kw(ARGF.current_file, mid, argc, argv, \
14260 func, argf, rb_keyword_given_p())
14265 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_i,
argf);
14266 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14272 if (!global_argf_p(
argf)) {
14273 ARGF.last_lineno = ++ARGF.lineno;
14275 return argf_block_call_i(i,
argf, argc, argv, blockarg);
14281 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_line_i,
argf);
14282 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14330 argf_block_call_line(rb_intern(
"each_line"), argc, argv,
argf);
14361 argf_block_call(rb_intern(
"each_byte"), 0, 0,
argf);
14387 argf_block_call(rb_intern(
"each_char"), 0, 0,
argf);
14413 argf_block_call(rb_intern(
"each_codepoint"), 0, 0,
argf);
14444 return ARGF.filename;
14448argf_filename_getter(
ID id,
VALUE *var)
14450 return argf_filename(*var);
14475 return ARGF.current_file;
14494 ARGF_FORWARD(0, 0);
14515 return RBOOL(ARGF.binmode);
14535 if (ARGF.init_p && ARGF.next_p == 0) {
14564 if (ARGF.next_p != -1) {
14582 ARGF_FORWARD(0, 0);
14609 if (!ARGF.inplace)
return Qnil;
14617 return argf_inplace_mode_get(*var);
14648 ARGF.inplace =
Qnil;
14659 argf_inplace_mode_set(*var, val);
14663ruby_set_inplace_mode(
const char *suffix)
14689argf_argv_getter(
ID id,
VALUE *var)
14691 return argf_argv(*var);
14710 if (!
RTEST(ARGF.current_file)) {
14713 return GetWriteIO(ARGF.current_file);
14725 return rb_io_writev(argf_write_io(
argf), argc, argv);
14740 case RB_IO_WAIT_WRITABLE:
14743 c = rb_eEAGAINWaitWritable;
14745#if EAGAIN != EWOULDBLOCK
14747 c = rb_eEWOULDBLOCKWaitWritable;
14751 c = rb_eEINPROGRESSWaitWritable;
14757 case RB_IO_WAIT_READABLE:
14760 c = rb_eEAGAINWaitReadable;
14762#if EAGAIN != EWOULDBLOCK
14764 c = rb_eEWOULDBLOCKWaitReadable;
14768 c = rb_eEINPROGRESSWaitReadable;
14775 rb_bug(
"invalid read/write type passed to rb_readwrite_sys_fail: %d", waiting);
14781get_LAST_READ_LINE(
ID _x,
VALUE *_y)
15666#include <sys/cygwin.h>
15667 static struct __cygwin_perfile pf[] =
15669 {
"", O_RDONLY | O_BINARY},
15670 {
"", O_WRONLY | O_BINARY},
15671 {
"", O_RDWR | O_BINARY},
15672 {
"", O_APPEND | O_BINARY},
15675 cygwin_internal(CW_PERFILE, pf);
15730#if EAGAIN == EWOULDBLOCK
15731 rb_eEWOULDBLOCKWaitReadable = rb_eEAGAINWaitReadable;
15733 rb_define_const(
rb_cIO,
"EWOULDBLOCKWaitReadable", rb_eEAGAINWaitReadable);
15734 rb_eEWOULDBLOCKWaitWritable = rb_eEAGAINWaitWritable;
15736 rb_define_const(
rb_cIO,
"EWOULDBLOCKWaitWritable", rb_eEAGAINWaitWritable);
15784 rb_gvar_ractor_local(
"$/");
15786 rb_gvar_ractor_local(
"$-0");
15790 rb_gvar_ractor_local(
"$_");
15791 rb_gvar_box_dynamic(
"$_");
15907 rb_gvar_ractor_local(
"$stdin");
15908 rb_gvar_ractor_local(
"$stdout");
15909 rb_gvar_ractor_local(
"$>");
15910 rb_gvar_ractor_local(
"$stderr");
15996 rb_define_method(rb_cARGF,
"external_encoding", argf_external_encoding, 0);
15997 rb_define_method(rb_cARGF,
"internal_encoding", argf_internal_encoding, 0);
16016 rb_gvar_ractor_local(
"$-i");
16020#if defined (_WIN32) || defined(__CYGWIN__)
16021 atexit(pipe_atexit);
16033 sym_encoding =
ID2SYM(rb_id_encoding());
#define RUBY_ASSERT(...)
Asserts that the given expression is truthy if and only if RUBY_DEBUG is truthy.
std::atomic< unsigned > rb_atomic_t
Type that is eligible for atomic operations.
unsigned long ruby_strtoul(const char *str, char **endptr, int base)
Our own locale-insensitive version of strtoul(3).
#define rb_define_method(klass, mid, func, arity)
Defines klass#mid.
#define rb_define_singleton_method(klass, mid, func, arity)
Defines klass.mid.
#define rb_define_global_function(mid, func, arity)
Defines rb_mKernel #mid.
void rb_include_module(VALUE klass, VALUE module)
Includes a module to a class.
VALUE rb_define_class(const char *name, VALUE super)
Defines a top-level class.
VALUE rb_class_new(VALUE super)
Creates a new, anonymous class.
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
VALUE rb_define_module_under(VALUE outer, const char *name)
Defines a module under the namespace of outer.
void rb_define_alias(VALUE klass, const char *name1, const char *name2)
Defines an alias of a method.
int rb_scan_args_kw(int kw_flag, int argc, const VALUE *argv, const char *fmt,...)
Identical to rb_scan_args(), except it also accepts kw_splat.
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Retrieves argument from argc and argv to given VALUE references according to the format string.
int rb_block_given_p(void)
Determines if the current method is given a block.
int rb_get_kwargs(VALUE keyword_hash, const ID *table, int required, int optional, VALUE *values)
Keyword argument deconstructor.
#define ECONV_AFTER_OUTPUT
Old name of RUBY_ECONV_AFTER_OUTPUT.
#define rb_str_new2
Old name of rb_str_new_cstr.
#define TYPE(_)
Old name of rb_type.
#define RB_INTEGER_TYPE_P
Old name of rb_integer_type_p.
#define ENC_CODERANGE_7BIT
Old name of RUBY_ENC_CODERANGE_7BIT.
#define T_FILE
Old name of RUBY_T_FILE.
#define ENC_CODERANGE_VALID
Old name of RUBY_ENC_CODERANGE_VALID.
#define ECONV_UNIVERSAL_NEWLINE_DECORATOR
Old name of RUBY_ECONV_UNIVERSAL_NEWLINE_DECORATOR.
#define OBJ_INIT_COPY(obj, orig)
Old name of RB_OBJ_INIT_COPY.
#define ALLOC
Old name of RB_ALLOC.
#define RFLOAT_VALUE
Old name of rb_float_value.
#define T_STRING
Old name of RUBY_T_STRING.
#define Qundef
Old name of RUBY_Qundef.
#define INT2FIX
Old name of RB_INT2FIX.
#define rb_str_cat2
Old name of rb_str_cat_cstr.
#define T_NIL
Old name of RUBY_T_NIL.
#define UNREACHABLE
Old name of RBIMPL_UNREACHABLE.
#define ID2SYM
Old name of RB_ID2SYM.
#define T_BIGNUM
Old name of RUBY_T_BIGNUM.
#define OBJ_FREEZE
Old name of RB_OBJ_FREEZE.
#define T_FIXNUM
Old name of RUBY_T_FIXNUM.
#define UNREACHABLE_RETURN
Old name of RBIMPL_UNREACHABLE_RETURN.
#define FIX2UINT
Old name of RB_FIX2UINT.
#define SSIZET2NUM
Old name of RB_SSIZE2NUM.
#define ZALLOC
Old name of RB_ZALLOC.
#define CLASS_OF
Old name of rb_class_of.
#define rb_ary_new4
Old name of rb_ary_new_from_values.
#define ENCODING_MAXNAMELEN
Old name of RUBY_ENCODING_MAXNAMELEN.
#define MBCLEN_NEEDMORE_LEN(ret)
Old name of ONIGENC_MBCLEN_NEEDMORE_LEN.
#define ENCODING_GET(obj)
Old name of RB_ENCODING_GET.
#define LONG2FIX
Old name of RB_INT2FIX.
#define NUM2UINT
Old name of RB_NUM2UINT.
#define ALLOC_N
Old name of RB_ALLOC_N.
#define MBCLEN_CHARFOUND_LEN(ret)
Old name of ONIGENC_MBCLEN_CHARFOUND_LEN.
#define LONG2NUM
Old name of RB_LONG2NUM.
#define rb_exc_new3
Old name of rb_exc_new_str.
#define STRNCASECMP
Old name of st_locale_insensitive_strncasecmp.
#define MBCLEN_INVALID_P(ret)
Old name of ONIGENC_MBCLEN_INVALID_P.
#define ISASCII
Old name of rb_isascii.
#define ECONV_STATEFUL_DECORATOR_MASK
Old name of RUBY_ECONV_STATEFUL_DECORATOR_MASK.
#define Qtrue
Old name of RUBY_Qtrue.
#define MBCLEN_NEEDMORE_P(ret)
Old name of ONIGENC_MBCLEN_NEEDMORE_P.
#define ECONV_PARTIAL_INPUT
Old name of RUBY_ECONV_PARTIAL_INPUT.
#define NUM2INT
Old name of RB_NUM2INT.
#define ECONV_ERROR_HANDLER_MASK
Old name of RUBY_ECONV_ERROR_HANDLER_MASK.
#define INT2NUM
Old name of RB_INT2NUM.
#define Qnil
Old name of RUBY_Qnil.
#define Qfalse
Old name of RUBY_Qfalse.
#define FIX2LONG
Old name of RB_FIX2LONG.
#define ENC_CODERANGE_BROKEN
Old name of RUBY_ENC_CODERANGE_BROKEN.
#define T_ARRAY
Old name of RUBY_T_ARRAY.
#define NIL_P
Old name of RB_NIL_P.
#define ALLOCV_N
Old name of RB_ALLOCV_N.
#define MBCLEN_CHARFOUND_P(ret)
Old name of ONIGENC_MBCLEN_CHARFOUND_P.
#define NUM2CHR
Old name of RB_NUM2CHR.
#define NUM2LONG
Old name of RB_NUM2LONG.
#define UINT2NUM
Old name of RB_UINT2NUM.
#define FIXNUM_P
Old name of RB_FIXNUM_P.
#define ECONV_NEWLINE_DECORATOR_MASK
Old name of RUBY_ECONV_NEWLINE_DECORATOR_MASK.
#define CONST_ID
Old name of RUBY_CONST_ID.
#define rb_ary_new2
Old name of rb_ary_new_capa.
#define NUM2SIZET
Old name of RB_NUM2SIZE.
#define ENC_CODERANGE_SET(obj, cr)
Old name of RB_ENC_CODERANGE_SET.
#define rb_str_new4
Old name of rb_str_new_frozen.
#define ALLOCV_END
Old name of RB_ALLOCV_END.
#define SYMBOL_P
Old name of RB_SYMBOL_P.
#define ECONV_DEFAULT_NEWLINE_DECORATOR
Old name of RUBY_ECONV_DEFAULT_NEWLINE_DECORATOR.
void rb_notimplement(void)
void rb_category_warn(rb_warning_category_t category, const char *fmt,...)
Identical to rb_category_warning(), except it reports unless $VERBOSE is nil.
void rb_category_warning(rb_warning_category_t category, const char *fmt,...)
Identical to rb_warning(), except it takes additional "category" parameter.
VALUE rb_eNotImpError
NotImplementedError exception.
void rb_exc_raise(VALUE mesg)
Raises an exception in the current thread.
void rb_syserr_fail(int e, const char *mesg)
Raises appropriate exception that represents a C errno.
void rb_readwrite_syserr_fail(enum rb_io_wait_readwrite waiting, int n, const char *mesg)
Identical to rb_readwrite_sys_fail(), except it does not depend on C global variable errno.
VALUE rb_eIOError
IOError exception.
VALUE rb_eStandardError
StandardError exception.
void rb_mod_syserr_fail_str(VALUE mod, int e, VALUE mesg)
Identical to rb_mod_syserr_fail(), except it takes the message in Ruby's String instead of C's.
void rb_syserr_fail_str(int e, VALUE mesg)
Identical to rb_syserr_fail(), except it takes the message in Ruby's String instead of C's.
#define ruby_verbose
This variable controls whether the interpreter is in debug mode.
VALUE rb_eTypeError
TypeError exception.
VALUE rb_eEOFError
EOFError exception.
void rb_readwrite_sys_fail(enum rb_io_wait_readwrite waiting, const char *mesg)
Raises appropriate exception using the parameters.
void rb_iter_break_value(VALUE val)
Identical to rb_iter_break(), except it additionally takes the "value" of this breakage.
rb_io_wait_readwrite
for rb_readwrite_sys_fail first argument
VALUE rb_eRuntimeError
RuntimeError exception.
void rb_warn(const char *fmt,...)
Identical to rb_warning(), except it reports unless $VERBOSE is nil.
VALUE rb_eSystemCallError
SystemCallError exception.
@ RB_WARN_CATEGORY_DEPRECATED
Warning is for deprecated features.
VALUE rb_mKernel
Kernel module.
VALUE rb_check_to_int(VALUE val)
Identical to rb_check_to_integer(), except it uses #to_int for conversion.
VALUE rb_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.
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.
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 RUBY_TYPED_FREE_IMMEDIATELY
Macros to see if each corresponding flag is defined.
#define TypedData_Make_Struct(klass, type, data_type, sval)
Identical to TypedData_Wrap_Struct, except it allocates a new data region internally instead of takin...
VALUE rb_get_argv(void)
Queries the arguments passed to the current process that you can access from Ruby as ARGV.
void rb_p(VALUE obj)
Inspects an object.
#define FilePathValue(v)
Ensures that the parameter object is a path.
#define errno
Ractor-aware version of errno.
#define RB_SCAN_ARGS_LAST_HASH_KEYWORDS
Treat a final argument as keywords if it is a hash, and not as keywords otherwise.
#define RB_PASS_CALLED_KEYWORDS
Pass keywords if current method is called with keywords, useful for argument delegation.
VALUE rb_fiber_scheduler_current(void)
Identical to rb_fiber_scheduler_get(), except it also returns RUBY_Qnil in case of a blocking fiber.
VALUE rb_fiber_scheduler_io_pread_memory(VALUE scheduler, VALUE io, rb_off_t from, void *base, size_t size, size_t length)
Non-blocking pread from the passed IO using a native buffer.
VALUE rb_fiber_scheduler_make_timeout(struct timeval *timeout)
Converts the passed timeout to an expression that rb_fiber_scheduler_block() etc.
VALUE rb_fiber_scheduler_io_wait_readable(VALUE scheduler, VALUE io)
Non-blocking wait until the passed IO is ready for reading.
VALUE rb_fiber_scheduler_io_read_memory(VALUE scheduler, VALUE io, void *base, size_t size, size_t length)
Non-blocking read from the passed IO using a native buffer.
VALUE rb_fiber_scheduler_io_wait(VALUE scheduler, VALUE io, VALUE events, VALUE timeout)
Non-blocking version of rb_io_wait().
static ssize_t rb_fiber_scheduler_io_result_apply(VALUE result)
Apply an io result to the local thread, returning the value of the original system call that created ...
VALUE rb_fiber_scheduler_io_selectv(VALUE scheduler, int argc, VALUE *argv)
Non-blocking version of IO.select, argv variant.
VALUE rb_fiber_scheduler_io_pwrite_memory(VALUE scheduler, VALUE io, rb_off_t from, const void *base, size_t size, size_t length)
Non-blocking pwrite to the passed IO using a native buffer.
VALUE rb_fiber_scheduler_current_for_thread(VALUE thread)
Identical to rb_fiber_scheduler_current(), except it queries for that of the passed thread value inst...
VALUE rb_fiber_scheduler_io_write_memory(VALUE scheduler, VALUE io, const void *base, size_t size, size_t length)
Non-blocking write to the passed IO using a native buffer.
VALUE rb_fiber_scheduler_current_for_threadptr(struct rb_thread_struct *thread)
Identical to rb_fiber_scheduler_current_for_thread(), except it expects a threadptr instead of a thre...
VALUE rb_fiber_scheduler_io_wait_writable(VALUE scheduler, VALUE io)
Non-blocking wait until the passed IO is ready for writing.
VALUE rb_fiber_scheduler_io_close(VALUE scheduler, VALUE io)
Non-blocking close the given IO.
int rb_thread_fd_select(int nfds, rb_fdset_t *rfds, rb_fdset_t *wfds, rb_fdset_t *efds, struct timeval *timeout)
Waits for multiple file descriptors at once.
static bool RB_TEST(VALUE obj)
Emulates Ruby's "if" statement.
#define RTEST
This is an old name of RB_TEST.
#define _(args)
This was a transition path from K&R to ANSI.
This is the struct that holds necessary info for a struct.
The data structure which wraps the fd_set bitmap used by select(2).
Decomposed encoding flags (e.g.
VALUE ecopts
Flags as Ruby hash.
rb_encoding * enc2
External encoding.
rb_encoding * enc
Internal encoding.
char * ptr
Pointer to the underlying memory region, of at least capa bytes.
int off
Offset inside of ptr.
int len
Length of the buffer.
int capa
Designed capacity of the buffer.
Ruby's IO, metadata and buffers.
rb_io_buffer_t wbuf
Write buffer.
enum rb_io_mode mode
mode flags: FMODE_XXXs
void(* finalize)(struct rb_io *, int)
finalize proc
rb_econv_t * readconv
Encoding converter used when reading from this IO.
rb_econv_t * writeconv
Encoding converter used when writing to this IO.
struct rb_io_encoding encs
Decomposed encoding flags.
VALUE self
The IO's Ruby level counterpart.
VALUE write_lock
This is a Ruby level mutex.
VALUE timeout
The timeout associated with this IO when performing blocking operations.
FILE * stdio_file
stdio ptr for read/write, if available.
VALUE writeconv_pre_ecopts
Value of ::rb_io_t::rb_io_enc_t::ecopts stored right before initialising rb_io_t::writeconv.
VALUE tied_io_for_writing
Duplex IO object, if set.
int writeconv_initialized
Whether rb_io_t::writeconv is already set up.
rb_io_buffer_t rbuf
(Byte) read buffer.
int lineno
number of lines read
struct ccan_list_head blocking_operations
Threads that are performing a blocking operation without the GVL using this IO.
VALUE writeconv_asciicompat
This is, when set, an instance of rb_cString which holds the "common" encoding.
rb_io_buffer_t cbuf
rb_io_ungetc() destination.
rb_pid_t pid
child's pid (for pipes)
int writeconv_pre_ecflags
Value of ::rb_io_t::rb_io_enc_t::ecflags stored right before initialising rb_io_t::writeconv.
VALUE pathv
pathname for file
intptr_t SIGNED_VALUE
A signed integer type that has the same width with VALUE.
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
uintptr_t VALUE
Type that represents a Ruby object.
static bool RB_FLOAT_TYPE_P(VALUE obj)
Queries if the object is an instance of rb_cFloat.
static bool RB_SYMBOL_P(VALUE obj)
Queries if the object is an instance of rb_cSymbol.
static void Check_Type(VALUE v, enum ruby_value_type t)
Identical to RB_TYPE_P(), except it raises exceptions on predication failure.
static bool RB_TYPE_P(VALUE obj, enum ruby_value_type t)
Queries if the given object is of given type.