14#include "ruby/internal/config.h"
25# if defined(__linux__)
28# if defined(__FreeBSD_version) && __FreeBSD_version >= 1100000
38#define free(x) xfree(x)
40#if defined(DOSISH) || defined(__CYGWIN__)
45#if defined HAVE_NET_SOCKET_H
46# include <net/socket.h>
47#elif defined HAVE_SYS_SOCKET_H
48# include <sys/socket.h>
51#if defined(__BOW__) || defined(__CYGWIN__) || defined(_WIN32)
52# define NO_SAFE_RENAME
55#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__sun) || defined(_nec_ews)
64#if defined(HAVE_SYS_IOCTL_H) && !defined(_WIN32)
67#if defined(HAVE_FCNTL_H) || defined(_WIN32)
69#elif defined(HAVE_SYS_FCNTL_H)
79#if defined(HAVE_SYS_PARAM_H) || defined(__HIUX_MPP__)
80# include <sys/param.h>
93#elif defined HAVE_SYS_SYSCALL_H
94#include <sys/syscall.h>
101#ifdef HAVE_SYS_WAIT_H
102# include <sys/wait.h>
105#ifdef HAVE_COPYFILE_H
106# include <copyfile.h>
108# ifndef COPYFILE_STATE_COPIED
114# undef HAVE_FCOPYFILE
120#include "ccan/list/list.h"
125#include "internal/class.h"
126#include "internal/encoding.h"
127#include "internal/error.h"
128#include "internal/inits.h"
129#include "internal/io.h"
130#include "internal/numeric.h"
131#include "internal/object.h"
132#include "internal/process.h"
133#include "internal/thread.h"
134#include "internal/transcode.h"
135#include "internal/variable.h"
138#include "ruby/missing.h"
141#include "ruby_atomic.h"
151#define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR)
155# ifdef _POSIX_PIPE_BUF
156# define PIPE_BUF _POSIX_PIPE_BUF
163# define EWOULDBLOCK EAGAIN
166#if defined(HAVE___SYSCALL) && (defined(__APPLE__) || defined(__OpenBSD__))
168off_t __syscall(quad_t number, ...);
171#define IO_RBUF_CAPA_MIN 8192
172#define IO_CBUF_CAPA_MIN (128*1024)
173#define IO_RBUF_CAPA_FOR(fptr) (NEED_READCONV(fptr) ? IO_CBUF_CAPA_MIN : IO_RBUF_CAPA_MIN)
174#define IO_WBUF_CAPA_MIN 8192
176#define IO_MAX_BUFFER_GROWTH 8 * 1024 * 1024
181#define open rb_w32_uopen
183#define rename(f, t) rb_w32_urename((f), (t))
184#include "win32/file.h"
194static VALUE rb_eEAGAINWaitReadable;
195static VALUE rb_eEAGAINWaitWritable;
196static VALUE rb_eEWOULDBLOCKWaitReadable;
197static VALUE rb_eEWOULDBLOCKWaitWritable;
198static VALUE rb_eEINPROGRESSWaitWritable;
199static VALUE rb_eEINPROGRESSWaitReadable;
202static VALUE orig_stdout, orig_stderr;
211static ID id_write, id_read, id_getc, id_flush, id_readpartial, id_set_encoding, id_fileno;
212static VALUE sym_mode, sym_perm, sym_flags, sym_extenc, sym_intenc, sym_encoding, sym_open_args;
213static VALUE sym_textmode, sym_binmode, sym_autoclose;
214static VALUE sym_SET, sym_CUR, sym_END;
215static VALUE sym_wait_readable, sym_wait_writable;
217static VALUE sym_DATA;
220static VALUE sym_HOLE;
223static VALUE prep_io(
int fd,
enum rb_io_mode fmode,
VALUE klass,
const char *path);
226rb_io_blocking_region_wait(
struct rb_io *io, rb_blocking_function_t *function,
void *argument,
enum rb_io_event events)
228 return rb_thread_io_blocking_call(io, function, argument, events);
231VALUE rb_io_blocking_region(
struct rb_io *io, rb_blocking_function_t *function,
void *argument)
233 return rb_io_blocking_region_wait(io, function, argument, 0);
237 VALUE filename, current_file;
243 int8_t init_p, next_p, binmode;
254 if (fd < 0 || afd <= max_fd)
257#if defined(HAVE_FCNTL) && defined(F_GETFL)
258 err = fcntl(fd, F_GETFL) == -1;
262 err = fstat(fd, &buf) != 0;
265 if (err &&
errno == EBADF) {
266 rb_bug(
"rb_update_max_fd: invalid fd (%d) given.", fd);
269 while (max_fd < afd) {
270 max_fd = ATOMIC_CAS(max_file_descriptor, max_fd, afd);
275rb_maygvl_fd_fix_cloexec(
int fd)
278#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
279 int flags, flags2, ret;
280 flags = fcntl(fd, F_GETFD);
282 rb_bug(
"rb_maygvl_fd_fix_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(
errno));
285 flags2 = flags & ~FD_CLOEXEC;
287 flags2 = flags | FD_CLOEXEC;
288 if (flags != flags2) {
289 ret = fcntl(fd, F_SETFD, flags2);
291 rb_bug(
"rb_maygvl_fd_fix_cloexec: fcntl(%d, F_SETFD, %d) failed: %s", fd, flags2, strerror(
errno));
300 rb_maygvl_fd_fix_cloexec(fd);
306rb_fix_detect_o_cloexec(
int fd)
308#if defined(O_CLOEXEC) && defined(F_GETFD)
309 int flags = fcntl(fd, F_GETFD);
312 rb_bug(
"rb_fix_detect_o_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(
errno));
314 if (flags & FD_CLOEXEC)
317 rb_maygvl_fd_fix_cloexec(fd);
324 return (e == EWOULDBLOCK) || (e == EAGAIN);
331 static int o_cloexec_state = -1;
333 static const int retry_interval = 0;
334 static const int retry_max_count = 10000;
341#elif defined O_NOINHERIT
342 flags |= O_NOINHERIT;
345 while ((ret = open(pathname, flags, mode)) == -1) {
347 if (!io_again_p(e))
break;
348 if (retry_count++ >= retry_max_count)
break;
350 sleep(retry_interval);
353 if (ret < 0)
return ret;
354 if (ret <= 2 || o_cloexec_state == 0) {
355 rb_maygvl_fd_fix_cloexec(ret);
357 else if (o_cloexec_state > 0) {
361 o_cloexec_state = rb_fix_detect_o_cloexec(ret);
380 if (oldfd == newfd) {
384#if defined(HAVE_DUP3) && defined(O_CLOEXEC)
385 static int try_dup3 = 1;
386 if (2 < newfd && try_dup3) {
387 ret = dup3(oldfd, newfd, O_CLOEXEC);
391 if (
errno == ENOSYS) {
393 ret = dup2(oldfd, newfd);
397 ret = dup2(oldfd, newfd);
400 ret = dup2(oldfd, newfd);
402 if (ret < 0)
return ret;
404 rb_maygvl_fd_fix_cloexec(ret);
409rb_fd_set_nonblock(
int fd)
412 return rb_w32_set_nonblock(fd);
413#elif defined(F_GETFL)
414 int oflags = fcntl(fd, F_GETFL);
418 if (oflags & O_NONBLOCK)
420 oflags |= O_NONBLOCK;
421 return fcntl(fd, F_SETFL, oflags);
430 int result = pipe2(descriptors, O_CLOEXEC | O_NONBLOCK);
432 int result = pipe(descriptors);
439 if (result == 0 && descriptors[1] == -1) {
440 close(descriptors[0]);
448 rb_maygvl_fd_fix_cloexec(descriptors[0]);
449 rb_maygvl_fd_fix_cloexec(descriptors[1]);
452 rb_fd_set_nonblock(descriptors[0]);
453 rb_fd_set_nonblock(descriptors[1]);
465#if defined(HAVE_FCNTL) && defined(F_DUPFD_CLOEXEC) && defined(F_DUPFD)
466 static int try_dupfd_cloexec = 1;
467 if (try_dupfd_cloexec) {
468 ret = fcntl(fd, F_DUPFD_CLOEXEC, minfd);
471 rb_maygvl_fd_fix_cloexec(ret);
475 if (
errno == EINVAL) {
476 ret = fcntl(fd, F_DUPFD, minfd);
478 try_dupfd_cloexec = 0;
483 ret = fcntl(fd, F_DUPFD, minfd);
485#elif defined(HAVE_FCNTL) && defined(F_DUPFD)
486 ret = fcntl(fd, F_DUPFD, minfd);
489 if (ret >= 0 && ret < minfd) {
490 const int prev_fd = ret;
496 if (ret < 0)
return ret;
497 rb_maygvl_fd_fix_cloexec(ret);
501#define argf_of(obj) (*(struct argf *)DATA_PTR(obj))
502#define ARGF argf_of(argf)
504#define GetWriteIO(io) rb_io_get_write_io(io)
506#define READ_DATA_PENDING(fptr) ((fptr)->rbuf.len)
507#define READ_DATA_PENDING_COUNT(fptr) ((fptr)->rbuf.len)
508#define READ_DATA_PENDING_PTR(fptr) ((fptr)->rbuf.ptr+(fptr)->rbuf.off)
509#define READ_DATA_BUFFERED(fptr) READ_DATA_PENDING(fptr)
511#define READ_CHAR_PENDING(fptr) ((fptr)->cbuf.len)
512#define READ_CHAR_PENDING_COUNT(fptr) ((fptr)->cbuf.len)
513#define READ_CHAR_PENDING_PTR(fptr) ((fptr)->cbuf.ptr+(fptr)->cbuf.off)
516#define WAIT_FD_IN_WIN32(fptr) \
517 (rb_w32_io_cancelable_p((fptr)->fd) ? Qnil : rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_READABLE), RUBY_IO_TIMEOUT_DEFAULT))
519#define WAIT_FD_IN_WIN32(fptr)
522#define READ_CHECK(fptr) do {\
523 if (!READ_DATA_PENDING(fptr)) {\
524 WAIT_FD_IN_WIN32(fptr);\
525 rb_io_check_closed(fptr);\
531# define S_ISSOCK(m) _S_ISSOCK(m)
534# define S_ISSOCK(m) (((m) & S_IFMT) == _S_IFSOCK)
537# define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
543static int io_fflush(
rb_io_t *);
544static rb_io_t *flush_before_seek(
rb_io_t *fptr,
bool discard_rbuf);
545static void clear_codeconv(
rb_io_t *fptr);
547#define FMODE_SIGNAL_ON_EPIPE (1<<17)
549#define fptr_signal_on_epipe(fptr) \
550 (((fptr)->mode & FMODE_SIGNAL_ON_EPIPE) != 0)
552#define fptr_set_signal_on_epipe(fptr, flag) \
554 (fptr)->mode |= FMODE_SIGNAL_ON_EPIPE : \
555 (fptr)->mode &= ~FMODE_SIGNAL_ON_EPIPE)
557extern ID ruby_static_id_signo;
559NORETURN(
static void rb_sys_fail_on_write(
rb_io_t *fptr));
561rb_sys_fail_on_write(
rb_io_t *fptr)
564 VALUE errinfo = rb_syserr_new_path(e, (fptr)->pathv);
566 if (fptr_signal_on_epipe(fptr) && (e == EPIPE)) {
578#define NEED_NEWLINE_DECORATOR_ON_READ(fptr) ((fptr)->mode & FMODE_TEXTMODE)
579#define NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) ((fptr)->mode & FMODE_TEXTMODE)
580#if defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32)
581# define RUBY_CRLF_ENVIRONMENT 1
583# define RUBY_CRLF_ENVIRONMENT 0
586#if RUBY_CRLF_ENVIRONMENT
588# define DEFAULT_TEXTMODE FMODE_TEXTMODE
589# define TEXTMODE_NEWLINE_DECORATOR_ON_WRITE ECONV_CRLF_NEWLINE_DECORATOR
597#define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || (fptr)->encs.ecflags & ~ECONV_CRLF_NEWLINE_DECORATOR)
598#define WRITECONV_MASK ( \
599 (ECONV_DECORATOR_MASK & ~ECONV_CRLF_NEWLINE_DECORATOR)|\
600 ECONV_STATEFUL_DECORATOR_MASK|\
602#define NEED_WRITECONV(fptr) ( \
603 ((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || \
604 ((fptr)->encs.ecflags & WRITECONV_MASK) || \
606#define SET_BINARY_MODE(fptr) setmode((fptr)->fd, O_BINARY)
608#define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) do {\
609 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {\
610 if (((fptr)->mode & FMODE_READABLE) &&\
611 !((fptr)->encs.ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {\
612 setmode((fptr)->fd, O_BINARY);\
615 setmode((fptr)->fd, O_TEXT);\
620#define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) do {\
621 if ((enc2) && ((ecflags) & ECONV_DEFAULT_NEWLINE_DECORATOR)) {\
622 (ecflags) |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;\
630io_unread(
rb_io_t *fptr,
bool discard_rbuf)
646 if (!rb_w32_fd_is_text(fptr->
fd)) {
647 r = lseek(fptr->
fd, -fptr->
rbuf.
len, SEEK_CUR);
648 if (r < 0 &&
errno) {
651 if (!discard_rbuf)
return;
657 pos = lseek(fptr->
fd, 0, SEEK_CUR);
658 if (pos < 0 &&
errno) {
661 if (!discard_rbuf)
goto end;
665 extra_max = (long)(pos - fptr->
rbuf.
len);
673 for (i = 0; i < fptr->
rbuf.
len; i++) {
674 if (*p ==
'\n') newlines++;
675 if (extra_max == newlines)
break;
680 while (newlines >= 0) {
681 r = lseek(fptr->
fd, pos - fptr->
rbuf.
len - newlines, SEEK_SET);
682 if (newlines == 0)
break;
687 read_size = _read(fptr->
fd, buf, fptr->
rbuf.
len + newlines);
691 rb_syserr_fail_path(e, fptr->
pathv);
693 if (read_size == fptr->
rbuf.
len) {
694 lseek(fptr->
fd, r, SEEK_SET);
705 clear_codeconv(fptr);
717set_binary_mode_with_seek_cur(
rb_io_t *fptr)
719 if (!rb_w32_fd_is_text(fptr->
fd))
return O_BINARY;
722 return setmode(fptr->
fd, O_BINARY);
724 flush_before_seek(fptr,
false);
725 return setmode(fptr->
fd, O_BINARY);
727#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) set_binary_mode_with_seek_cur(fptr)
731# define DEFAULT_TEXTMODE 0
732#define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || NEED_NEWLINE_DECORATOR_ON_READ(fptr))
733#define NEED_WRITECONV(fptr) ( \
734 ((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || \
735 NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) || \
736 ((fptr)->encs.ecflags & (ECONV_DECORATOR_MASK|ECONV_STATEFUL_DECORATOR_MASK)) || \
738#define SET_BINARY_MODE(fptr) (void)(fptr)
739#define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) (void)(fptr)
740#define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) ((void)(enc2), (void)(ecflags))
741#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) (void)(fptr)
744#if !defined HAVE_SHUTDOWN && !defined shutdown
745#define shutdown(a,b) 0
749#define is_socket(fd, path) rb_w32_is_socket(fd)
750#elif !defined(S_ISSOCK)
751#define is_socket(fd, path) 0
754is_socket(
int fd,
VALUE path)
757 if (fstat(fd, &sbuf) < 0)
758 rb_sys_fail_path(path);
759 return S_ISSOCK(sbuf.st_mode);
763static const char closed_stream[] =
"closed stream";
766io_fd_check_closed(
int fd)
799 io_fd_check_closed(fptr->
fd);
803rb_io_get_fptr(
VALUE io)
813 return rb_convert_type_with_id(io,
T_FILE,
"IO", idTo_io);
819 return rb_check_convert_type_with_id(io,
T_FILE,
"IO", idTo_io);
837 rb_io_t *fptr = rb_io_get_fptr(io);
846 return write_io ? write_io :
Qnil;
859 rb_io_t *fptr = rb_io_get_fptr(self);
889 if (
RTEST(timeout)) {
893 rb_io_t *fptr = rb_io_get_fptr(self);
918#if !RUBY_CRLF_ENVIRONMENT
920io_unread(
rb_io_t *fptr,
bool discard_rbuf)
928 r = lseek(fptr->
fd, -fptr->
rbuf.
len, SEEK_CUR);
929 if (r < 0 &&
errno) {
932 if (!discard_rbuf)
return;
936 clear_codeconv(fptr);
946 long len = RSTRING_LEN(str);
949 const int min_capa = IO_RBUF_CAPA_FOR(fptr);
952#if SIZEOF_LONG > SIZEOF_INT
977flush_before_seek(
rb_io_t *fptr,
bool discard_rbuf)
979 if (io_fflush(fptr) < 0)
980 rb_sys_fail_on_write(fptr);
981 io_unread(fptr, discard_rbuf);
986#define io_seek(fptr, ofs, whence) (errno = 0, lseek(flush_before_seek(fptr, true)->fd, (ofs), (whence)))
987#define io_tell(fptr) lseek(flush_before_seek(fptr, false)->fd, 0, SEEK_CUR)
1003 if (io_fflush(fptr) < 0)
1004 rb_sys_fail_on_write(fptr);
1009 if (io_fflush(wfptr) < 0)
1010 rb_sys_fail_on_write(wfptr);
1018 if (READ_CHAR_PENDING(fptr)) {
1019 rb_raise(
rb_eIOError,
"byte oriented read for character buffered IO");
1030io_read_encoding(
rb_io_t *fptr)
1035 return rb_default_external_encoding();
1039io_input_encoding(
rb_io_t *fptr)
1044 return io_read_encoding(fptr);
1055 io_unread(fptr,
true);
1060rb_io_read_pending(
rb_io_t *fptr)
1063 if (READ_CHAR_PENDING(fptr))
1065 return READ_DATA_PENDING(fptr);
1071 if (!READ_DATA_PENDING(fptr)) {
1078rb_gc_for_fd(
int err)
1080 if (err == EMFILE || err == ENFILE || err == ENOMEM) {
1090#define TRY_WITH_GC(expr) \
1091 for (int first_errno, retried_errno = 0, retried = 0; \
1094 (!rb_gc_for_fd(first_errno = errno) || !(expr)) && \
1095 (retried_errno = errno, 1)); \
1096 (void)retried_errno, retried = 1)
1111io_alloc(
VALUE klass)
1121# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
1147struct io_internal_writev_struct {
1154 const struct iovec *iov;
1167io_internal_wait(
VALUE thread,
rb_io_t *fptr,
int error,
int events,
struct timeval *timeout)
1169 if (!timeout && rb_thread_mn_schedulable(thread)) {
1174 int ready = nogvl_wait_for(thread, fptr, events, timeout);
1179 else if (ready == 0) {
1196internal_read_func(
void *ptr)
1201 if (iis->timeout && !iis->nonblock) {
1202 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_IN, iis->timeout) == -1) {
1208 result = read(iis->fd, iis->buf, iis->capa);
1210 if (result < 0 && !iis->nonblock) {
1211 if (io_again_p(
errno)) {
1212 if (io_internal_wait(iis->th, iis->fptr,
errno, RB_WAITFD_IN, iis->timeout) == -1) {
1224#if defined __APPLE__
1225# define do_write_retry(code) do {result = code;} while (result == -1 && errno == EPROTOTYPE)
1227# define do_write_retry(code) result = code
1231internal_write_func(
void *ptr)
1236 if (iis->timeout && !iis->nonblock) {
1237 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1243 do_write_retry(write(iis->fd, iis->buf, iis->capa));
1245 if (result < 0 && !iis->nonblock) {
1247 if (io_again_p(e)) {
1248 if (io_internal_wait(iis->th, iis->fptr,
errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1262internal_writev_func(
void *ptr)
1264 struct io_internal_writev_struct *iis = ptr;
1267 if (iis->timeout && !iis->nonblock) {
1268 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1274 do_write_retry(writev(iis->fd, iis->iov, iis->iovcnt));
1276 if (result < 0 && !iis->nonblock) {
1277 if (io_again_p(
errno)) {
1278 if (io_internal_wait(iis->th, iis->fptr,
errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1292rb_io_read_memory(
rb_io_t *fptr,
void *buf,
size_t count)
1296 if (scheduler !=
Qnil) {
1299 if (!UNDEF_P(result)) {
1315 struct timeval timeout_storage;
1319 iis.timeout = &timeout_storage;
1322 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_read_func, &iis,
RUBY_IO_READABLE);
1326rb_io_write_memory(
rb_io_t *fptr,
const void *buf,
size_t count)
1330 if (scheduler !=
Qnil) {
1333 if (!UNDEF_P(result)) {
1349 struct timeval timeout_storage;
1353 iis.timeout = &timeout_storage;
1356 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_write_func, &iis,
RUBY_IO_WRITABLE);
1361rb_writev_internal(
rb_io_t *fptr,
const struct iovec *iov,
int iovcnt)
1363 if (!iovcnt)
return 0;
1368 if (scheduler !=
Qnil) {
1372 if (!UNDEF_P(result)) {
1377 struct io_internal_writev_struct iis = {
1388 struct timeval timeout_storage;
1392 iis.timeout = &timeout_storage;
1395 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_writev_func, &iis,
RUBY_IO_WRITABLE);
1400io_flush_buffer_sync(
void *arg)
1422io_flush_buffer_async(
VALUE arg)
1425 return rb_io_blocking_region_wait(fptr, io_flush_buffer_sync, fptr,
RUBY_IO_WRITABLE);
1432 return (
int)io_flush_buffer_async((
VALUE)fptr);
1447 while (fptr->
wbuf.
len > 0 && io_flush_buffer(fptr) != 0) {
1463 if (scheduler !=
Qnil) {
1473 if (NIL_OR_UNDEF_P(timeout)) {
1477 if (timeout !=
Qnil) {
1482 int ready = rb_thread_io_wait(th, fptr,
RB_NUM2INT(events), tv);
1508 if (scheduler !=
Qnil) {
1514 return rb_thread_wait_for_single_fd(th, fd, events, timeout);
1520 io_fd_check_closed(f);
1527#if defined(ERESTART)
1534#if EWOULDBLOCK != EAGAIN
1537 if (scheduler !=
Qnil) {
1555 io_fd_check_closed(f);
1562#if defined(ERESTART)
1578#if EWOULDBLOCK != EAGAIN
1581 if (scheduler !=
Qnil) {
1601 return io_wait_for_single_fd(fd, events, timeout, th, scheduler);
1635#if defined(ERESTART)
1645#if EWOULDBLOCK != EAGAIN
1662 if (
RTEST(result)) {
1677 if (
RTEST(result)) {
1691 const char *senc, *denc;
1698 ecflags = fptr->
encs.
ecflags & ~ECONV_NEWLINE_DECORATOR_READ_MASK;
1725 denc = rb_enc_name(enc);
1757io_binwrite_string_internal(
rb_io_t *fptr,
const char *ptr,
long length)
1760 struct iovec iov[2];
1763 iov[0].iov_len = fptr->
wbuf.
len;
1764 iov[1].iov_base = (
void*)ptr;
1765 iov[1].iov_len = length;
1767 ssize_t result = rb_writev_internal(fptr, iov, 2);
1772 if (result >= fptr->
wbuf.
len) {
1780 fptr->
wbuf.
off += (int)result;
1781 fptr->
wbuf.
len -= (int)result;
1789 return rb_io_write_memory(fptr, ptr, length);
1794io_binwrite_string_internal(
rb_io_t *fptr,
const char *ptr,
long length)
1796 long remaining = length;
1799 if (fptr->
wbuf.
len+length <= fptr->wbuf.capa) {
1806 fptr->
wbuf.
len += (int)length;
1813 if (io_fflush(fptr) < 0) {
1818 if (remaining == 0) {
1824 return rb_io_write_memory(fptr, ptr, length);
1829io_binwrite_string(
VALUE arg)
1833 const char *ptr = p->ptr;
1834 size_t remaining = p->length;
1838 ssize_t result = io_binwrite_string_internal(p->fptr, ptr, remaining);
1844 else if (result > 0) {
1845 if ((
size_t)result == remaining)
break;
1847 remaining -= result;
1863io_allocate_write_buffer(
rb_io_t *fptr,
int sync)
1868 fptr->
wbuf.
capa = IO_WBUF_CAPA_MIN;
1879io_binwrite_requires_flush_write(
rb_io_t *fptr,
long len,
int nosync)
1894io_binwrite(
const char *ptr,
long len,
rb_io_t *fptr,
int nosync)
1896 if (
len <= 0)
return len;
1901 io_allocate_write_buffer(fptr, !nosync);
1903 if (io_binwrite_requires_flush_write(fptr,
len, nosync)) {
1914 return io_binwrite_string((
VALUE)&arg);
1931# define MODE_BTMODE(a,b,c) ((fmode & FMODE_BINMODE) ? (b) : \
1932 (fmode & FMODE_TEXTMODE) ? (c) : (a))
1934#define MODE_BTXMODE(a, b, c, d, e, f) ((fmode & FMODE_EXCL) ? \
1935 MODE_BTMODE(d, e, f) : \
1936 MODE_BTMODE(a, b, c))
1941 if (NEED_WRITECONV(fptr)) {
1943 SET_BINARY_MODE(fptr);
1945 make_writeconv(fptr);
1948#define fmode (fptr->mode)
1951 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1) && !rb_enc_asciicompat(rb_enc_get(str))) {
1952 rb_raise(rb_eArgError,
"ASCII incompatible string written for text mode IO without encoding conversion: %s",
1953 rb_enc_name(rb_enc_get(str)));
1959 common_encoding = rb_enc_from_encoding(fptr->
encs.
enc2);
1960 else if (fptr->
encs.
enc != rb_ascii8bit_encoding())
1961 common_encoding = rb_enc_from_encoding(fptr->
encs.
enc);
1964 if (!
NIL_P(common_encoding)) {
1975#if RUBY_CRLF_ENVIRONMENT
1976#define fmode (fptr->mode)
1977 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1)) {
1980 setmode(fptr->
fd, O_BINARY);
1983 setmode(fptr->
fd, O_TEXT);
1985 if (!rb_enc_asciicompat(rb_enc_get(str))) {
1986 rb_raise(rb_eArgError,
"ASCII incompatible string written for text mode IO without encoding conversion: %s",
1987 rb_enc_name(rb_enc_get(str)));
2005 long len = rb_w32_write_console(str, fptr->
fd);
2010 str = do_writeconv(str, fptr, &converted);
2014 tmp = rb_str_tmp_frozen_no_embed_acquire(str);
2016 n = io_binwrite(ptr,
len, fptr, nosync);
2017 rb_str_tmp_frozen_release(str, tmp);
2029 return (ssize_t)io_binwrite(buf, (
long)size, fptr, 0);
2039 io = GetWriteIO(io);
2049 if (RSTRING_LEN(str) == 0)
return INT2FIX(0);
2054 n = io_fwrite(str, fptr, nosync);
2055 if (n < 0L) rb_sys_fail_on_write(fptr);
2061struct binwritev_arg {
2069io_binwritev_internal(
VALUE arg)
2071 struct binwritev_arg *p = (
struct binwritev_arg *)arg;
2073 size_t remaining = p->total;
2077 struct iovec *iov = p->iov;
2078 int iovcnt = p->iovcnt;
2081 long result = rb_writev_internal(fptr, iov, iovcnt);
2086 if (offset < (
size_t)fptr->
wbuf.
len) {
2091 offset -= (size_t)fptr->
wbuf.
len;
2097 if (offset == p->total) {
2101 while (result >= (ssize_t)iov->iov_len) {
2103 result -= iov->iov_len;
2113 iov->iov_base = (
char *)iov->iov_base + result;
2114 iov->iov_len -= result;
2128io_binwritev(
struct iovec *iov,
int iovcnt,
rb_io_t *fptr)
2133 if (iovcnt == 0)
return 0;
2136 for (
int i = 1; i < iovcnt; i++) total += iov[i].iov_len;
2138 io_allocate_write_buffer(fptr, 1);
2144 if (offset + total <= (
size_t)fptr->
wbuf.
capa) {
2145 for (
int i = 1; i < iovcnt; i++) {
2146 memcpy(fptr->
wbuf.
ptr+offset, iov[i].iov_base, iov[i].iov_len);
2147 offset += iov[i].iov_len;
2156 iov[0].iov_len = fptr->
wbuf.
len;
2169 struct binwritev_arg arg;
2172 arg.iovcnt = iovcnt;
2179 return io_binwritev_internal((
VALUE)&arg);
2186 int i, converted, iovcnt = argc + 1;
2188 VALUE v1, v2, str, tmp, *tmp_array;
2194 for (i = 0; i < argc; i++) {
2197 str = do_writeconv(str, fptr, &converted);
2202 tmp = rb_str_tmp_frozen_acquire(str);
2206 iov[i+1].iov_base = RSTRING_PTR(tmp);
2207 iov[i+1].iov_len = RSTRING_LEN(tmp);
2210 n = io_binwritev(iov, iovcnt, fptr);
2213 for (i = 0; i < argc; i++) {
2214 rb_str_tmp_frozen_release(argv[i], tmp_array[i]);
2223iovcnt_ok(
int iovcnt)
2226 return iovcnt < IOV_MAX;
2234io_writev(
int argc,
const VALUE *argv,
VALUE io)
2241 io = GetWriteIO(io);
2246 return rb_funcallv(io, id_write, argc, argv);
2254 for (i = 0; i < argc; i += cnt) {
2257 n = io_fwritev(cnt, &argv[i], fptr);
2268 rb_sys_fail_on_write(fptr);
2270 total = rb_fix_plus(
LONG2FIX(n), total);
2301 return io_writev(argc, argv, io);
2304 VALUE str = argv[0];
2305 return io_write(io, str, 0);
2312 return rb_funcallv(io, id_write, 1, &str);
2316rb_io_writev(
VALUE io,
int argc,
const VALUE *argv)
2321 char sep = RCLASS_SINGLETON_P(klass) ? (klass = io,
'.') :
'#';
2324 " which accepts just one argument",
2329 do rb_io_write(io, *argv++);
while (--argc);
2334 return rb_funcallv(io, id_write, argc, argv);
2360 rb_io_write(io, str);
2366nogvl_fsync(
void *ptr)
2371 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->
fd)) != FILE_TYPE_DISK)
2374 return (
VALUE)fsync(fptr->
fd);
2379rb_io_flush_raw(
VALUE io,
int sync)
2387 io = GetWriteIO(io);
2391 if (io_fflush(fptr) < 0)
2392 rb_sys_fail_on_write(fptr);
2395 io_unread(fptr,
true);
2416 return rb_io_flush_raw(io, 1);
2442 pos = io_tell(fptr);
2443 if (pos < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
2449rb_io_seek(
VALUE io,
VALUE offset,
int whence)
2456 pos = io_seek(fptr, pos, whence);
2457 if (pos < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
2463interpret_seek_whence(
VALUE vwhence)
2465 if (vwhence == sym_SET)
2467 if (vwhence == sym_CUR)
2469 if (vwhence == sym_END)
2472 if (vwhence == sym_DATA)
2476 if (vwhence == sym_HOLE)
2532 VALUE offset, ptrname;
2533 int whence = SEEK_SET;
2535 if (
rb_scan_args(argc, argv,
"11", &offset, &ptrname) == 2) {
2536 whence = interpret_seek_whence(ptrname);
2539 return rb_io_seek(io, offset, whence);
2567 pos = io_seek(fptr, pos, SEEK_SET);
2568 if (pos < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
2573static void clear_readconv(
rb_io_t *fptr);
2600rb_io_rewind(
VALUE io)
2605 if (io_seek(fptr, 0L, 0) < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
2606 if (io == ARGF.current_file) {
2607 ARGF.lineno -= fptr->
lineno;
2611 clear_readconv(fptr);
2618fptr_wait_readable(
rb_io_t *fptr)
2636 fptr->
rbuf.
capa = IO_RBUF_CAPA_FOR(fptr);
2647 if (fptr_wait_readable(fptr))
2651 VALUE path = rb_sprintf(
"fd:%d ", fptr->
fd);
2656 rb_syserr_fail_path(e, path);
2710 if (READ_CHAR_PENDING(fptr))
return Qfalse;
2711 if (READ_DATA_PENDING(fptr))
return Qfalse;
2713#if RUBY_CRLF_ENVIRONMENT
2714 if (!NEED_READCONV(fptr) && NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
2715 return RBOOL(eof(fptr->
fd));
2718 return RBOOL(io_fillbuf(fptr) < 0);
2742 io = GetWriteIO(io);
2779 io = GetWriteIO(io);
2785 fptr->
mode &= ~FMODE_SYNC;
2809rb_io_fsync(
VALUE io)
2813 io = GetWriteIO(io);
2816 if (io_fflush(fptr) < 0)
2817 rb_sys_fail_on_write(fptr);
2819 if ((
int)rb_io_blocking_region(fptr, nogvl_fsync, fptr))
2820 rb_sys_fail_path(fptr->
pathv);
2825# define rb_io_fsync rb_f_notimplement
2826# define rb_io_sync rb_f_notimplement
2835#ifdef HAVE_FDATASYNC
2837nogvl_fdatasync(
void *ptr)
2842 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->
fd)) != FILE_TYPE_DISK)
2845 return (
VALUE)fdatasync(fptr->
fd);
2860rb_io_fdatasync(
VALUE io)
2864 io = GetWriteIO(io);
2867 if (io_fflush(fptr) < 0)
2868 rb_sys_fail_on_write(fptr);
2870 if ((
int)rb_io_blocking_region(fptr, nogvl_fdatasync, fptr) == 0)
2874 return rb_io_fsync(io);
2877#define rb_io_fdatasync rb_io_fsync
2895rb_io_fileno(
VALUE io)
2915 if (!UNDEF_P(fileno)) {
3003rb_io_inspect(
VALUE obj)
3007 static const char closed[] =
" (closed)";
3009 fptr =
RFILE(obj)->fptr;
3016 rb_str_cat(result, closed+1, strlen(closed)-1);
3019 rb_str_catf(result,
"fd %d", fptr->
fd);
3040rb_io_to_io(
VALUE io)
3047read_buffered_data(
char *ptr,
long len,
rb_io_t *fptr)
3051 n = READ_DATA_PENDING_COUNT(fptr);
3052 if (n <= 0)
return 0;
3053 if (n >
len) n = (int)
len;
3061io_bufread(
char *ptr,
long len,
rb_io_t *fptr)
3067 if (READ_DATA_PENDING(fptr) == 0) {
3071 c = rb_io_read_memory(fptr, ptr+offset, n);
3074 if (fptr_wait_readable(fptr))
3079 if ((n -= c) <= 0)
break;
3085 c = read_buffered_data(ptr+offset, n, fptr);
3088 if ((n -= c) <= 0)
break;
3091 if (io_fillbuf(fptr) < 0) {
3098static int io_setstrbuf(
VALUE *str,
long len);
3107bufread_call(
VALUE arg)
3110 p->len = io_bufread(p->str_ptr, p->len, p->fptr);
3115io_fread(
VALUE str,
long offset,
long size,
rb_io_t *fptr)
3120 io_setstrbuf(&str, offset + size);
3121 arg.str_ptr = RSTRING_PTR(str) + offset;
3124 rb_str_locktmp_ensure(str, bufread_call, (
VALUE)&arg);
3126 if (
len < 0) rb_sys_fail_path(fptr->
pathv);
3134 rb_off_t siz = READ_DATA_PENDING_COUNT(fptr);
3137 if (fstat(fptr->
fd, &st) == 0 && S_ISREG(st.st_mode)
3138#
if defined(__HAIKU__)
3143 if (io_fflush(fptr) < 0)
3144 rb_sys_fail_on_write(fptr);
3145 pos = lseek(fptr->
fd, 0, SEEK_CUR);
3146 if (st.st_size >= pos && pos >= 0) {
3147 siz += st.st_size - pos;
3148 if (siz > LONG_MAX) {
3149 rb_raise(
rb_eIOError,
"file too big for single read");
3162 rb_enc_associate(str, io_read_encoding(fptr));
3167make_readconv(
rb_io_t *fptr,
int size)
3172 const char *sname, *dname;
3173 ecflags = fptr->
encs.
ecflags & ~ECONV_NEWLINE_DECORATOR_WRITE_MASK;
3176 sname = rb_enc_name(fptr->
encs.
enc2);
3177 dname = rb_enc_name(io_read_encoding(fptr));
3187 if (size < IO_CBUF_CAPA_MIN) size = IO_CBUF_CAPA_MIN;
3193#define MORE_CHAR_SUSPENDED Qtrue
3194#define MORE_CHAR_FINISHED Qnil
3196fill_cbuf(
rb_io_t *fptr,
int ec_flags)
3198 const unsigned char *ss, *sp, *se;
3199 unsigned char *ds, *dp, *de;
3208 return MORE_CHAR_SUSPENDED;
3219 ss = sp = (
const unsigned char *)fptr->
rbuf.
ptr + fptr->
rbuf.
off;
3224 fptr->
rbuf.
off += (int)(sp - ss);
3225 fptr->
rbuf.
len -= (int)(sp - ss);
3226 fptr->
cbuf.
len += (int)(dp - ds);
3231 fptr->
rbuf.
off -= putbackable;
3232 fptr->
rbuf.
len += putbackable;
3239 if (cbuf_len0 != fptr->
cbuf.
len)
3240 return MORE_CHAR_SUSPENDED;
3243 return MORE_CHAR_FINISHED;
3249 if (io_fillbuf(fptr) < 0) {
3251 return MORE_CHAR_FINISHED;
3256 fptr->
cbuf.
len += (int)(dp - ds);
3263 if (cbuf_len0 != fptr->
cbuf.
len)
3264 return MORE_CHAR_SUSPENDED;
3266 return MORE_CHAR_FINISHED;
3274 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED)
3291 rb_enc_associate(str, fptr->
encs.
enc);
3320 long clen = RSTRING_LEN(s);
3332#define MAX_REALLOC_GAP 4096
3334io_shrink_read_string(
VALUE str,
long n)
3337 rb_str_resize(str, n);
3342io_set_read_length(
VALUE str,
long n,
int shrinkable)
3344 if (RSTRING_LEN(str) != n) {
3347 if (shrinkable) io_shrink_read_string(str, n);
3361 if (NEED_READCONV(fptr)) {
3362 int first = !
NIL_P(str);
3363 SET_BINARY_MODE(fptr);
3364 shrinkable = io_setstrbuf(&str,0);
3365 make_readconv(fptr, 0);
3370 io_shift_cbuf(fptr, fptr->
cbuf.
len, &str);
3372 v = fill_cbuf(fptr, 0);
3373 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED) {
3376 io_shift_cbuf(fptr, fptr->
cbuf.
len, &str);
3380 if (v == MORE_CHAR_FINISHED) {
3381 clear_readconv(fptr);
3383 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3384 return io_enc_str(str, fptr);
3389 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3393 enc = io_read_encoding(fptr);
3396 if (siz == 0) siz = BUFSIZ;
3397 shrinkable = io_setstrbuf(&str, siz);
3400 n = io_fread(str, bytes, siz - bytes, fptr);
3401 if (n == 0 && bytes == 0) {
3409 if (bytes < siz)
break;
3413 if (
capa < (
size_t)RSTRING_LEN(str) + BUFSIZ) {
3414 if (
capa < BUFSIZ) {
3417 else if (
capa > IO_MAX_BUFFER_GROWTH) {
3418 capa = IO_MAX_BUFFER_GROWTH;
3423 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3424 str = io_enc_str(str, fptr);
3432 if (rb_fd_set_nonblock(fptr->
fd) != 0) {
3433 rb_sys_fail_path(fptr->
pathv);
3438io_read_memory_call(
VALUE arg)
3443 if (scheduler !=
Qnil) {
3446 if (!UNDEF_P(result)) {
3452 if (iis->nonblock) {
3453 return rb_io_blocking_region(iis->fptr, internal_read_func, iis);
3456 return rb_io_blocking_region_wait(iis->fptr, internal_read_func, iis,
RUBY_IO_READABLE);
3463 return (
long)rb_str_locktmp_ensure(str, io_read_memory_call, (
VALUE)iis);
3466#define no_exception_p(opts) !rb_opts_exception_p((opts), TRUE)
3469io_getpartial(
int argc,
VALUE *argv,
VALUE io,
int no_exception,
int nonblock)
3480 rb_raise(rb_eArgError,
"negative length %ld given",
len);
3483 shrinkable = io_setstrbuf(&str,
len);
3489 io_set_read_length(str, 0, shrinkable);
3495 n = read_buffered_data(RSTRING_PTR(str),
len, fptr);
3501 io_setstrbuf(&str,
len);
3504 iis.nonblock = nonblock;
3506 iis.buf = RSTRING_PTR(str);
3509 n = io_read_memory_locktmp(str, &iis);
3512 if (!nonblock && fptr_wait_readable(fptr))
3514 if (nonblock && (io_again_p(e))) {
3516 return sym_wait_readable;
3519 e,
"read would block");
3521 rb_syserr_fail_path(e, fptr->
pathv);
3524 io_set_read_length(str, n, shrinkable);
3625io_readpartial(
int argc,
VALUE *argv,
VALUE io)
3629 ret = io_getpartial(argc, argv, io,
Qnil, 0);
3636io_nonblock_eof(
int no_exception)
3638 if (!no_exception) {
3654 rb_raise(rb_eArgError,
"negative length %ld given",
len);
3657 shrinkable = io_setstrbuf(&str,
len);
3658 rb_bool_expected(ex,
"exception", TRUE);
3664 io_set_read_length(str, 0, shrinkable);
3668 n = read_buffered_data(RSTRING_PTR(str),
len, fptr);
3670 rb_fd_set_nonblock(fptr->
fd);
3671 shrinkable |= io_setstrbuf(&str,
len);
3675 iis.buf = RSTRING_PTR(str);
3678 n = io_read_memory_locktmp(str, &iis);
3681 if (io_again_p(e)) {
3682 if (!ex)
return sym_wait_readable;
3684 e,
"read would block");
3686 rb_syserr_fail_path(e, fptr->
pathv);
3689 io_set_read_length(str, n, shrinkable);
3692 if (!ex)
return Qnil;
3708 rb_bool_expected(ex,
"exception", TRUE);
3710 io = GetWriteIO(io);
3714 if (io_fflush(fptr) < 0)
3715 rb_sys_fail_on_write(fptr);
3717 rb_fd_set_nonblock(fptr->
fd);
3718 n = write(fptr->
fd, RSTRING_PTR(str), RSTRING_LEN(str));
3723 if (io_again_p(e)) {
3725 return sym_wait_writable;
3731 rb_syserr_fail_path(e, fptr->
pathv);
3815#if RUBY_CRLF_ENVIRONMENT
3821 if (
NIL_P(length)) {
3824 return read_all(fptr, remain_size(fptr), str);
3828 rb_raise(rb_eArgError,
"negative length %ld given",
len);
3831 shrinkable = io_setstrbuf(&str,
len);
3836 io_set_read_length(str, 0, shrinkable);
3841#if RUBY_CRLF_ENVIRONMENT
3842 previous_mode = set_binary_mode_with_seek_cur(fptr);
3844 n = io_fread(str, 0,
len, fptr);
3845 io_set_read_length(str, n, shrinkable);
3846#if RUBY_CRLF_ENVIRONMENT
3847 if (previous_mode == O_TEXT) {
3848 setmode(fptr->
fd, O_TEXT);
3851 if (n == 0)
return Qnil;
3857rscheck(
const char *rsptr,
long rslen,
VALUE rs)
3860 if (RSTRING_PTR(rs) != rsptr && RSTRING_LEN(rs) != rslen)
3865search_delim(
const char *p,
long len,
int delim,
rb_encoding *enc)
3867 if (rb_enc_mbminlen(enc) == 1) {
3868 p = memchr(p, delim,
len);
3869 if (p)
return p + 1;
3872 const char *end = p +
len;
3874 int r = rb_enc_precise_mbclen(p, end, enc);
3876 p += rb_enc_mbminlen(enc);
3880 if (rb_enc_mbc_to_codepoint(p, end, enc) == (
unsigned int)delim) {
3895 if (NEED_READCONV(fptr)) {
3896 SET_BINARY_MODE(fptr);
3897 make_readconv(fptr, 0);
3900 int searchlen = READ_CHAR_PENDING_COUNT(fptr);
3902 p = READ_CHAR_PENDING_PTR(fptr);
3903 if (0 < limit && limit < searchlen)
3904 searchlen = (int)limit;
3905 e = search_delim(p, searchlen, delim, enc);
3907 int len = (int)(e-p);
3929 return (
unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
3932 }
while (more_char(fptr) != MORE_CHAR_FINISHED);
3933 clear_readconv(fptr);
3938 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3940 long pending = READ_DATA_PENDING_COUNT(fptr);
3942 const char *p = READ_DATA_PENDING_PTR(fptr);
3946 if (limit > 0 && pending > limit) pending = limit;
3947 e = search_delim(p, pending, delim, enc);
3948 if (e) pending = e - p;
3950 last = RSTRING_LEN(str);
3951 rb_str_resize(str, last + pending);
3958 read_buffered_data(RSTRING_PTR(str) + last, pending, fptr);
3961 if (e)
return delim;
3963 return (
unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
3966 }
while (io_fillbuf(fptr) >= 0);
3972swallow(
rb_io_t *fptr,
int term)
3974 if (NEED_READCONV(fptr)) {
3976 int needconv = rb_enc_mbminlen(enc) != 1;
3977 SET_BINARY_MODE(fptr);
3978 make_readconv(fptr, 0);
3981 while ((cnt = READ_CHAR_PENDING_COUNT(fptr)) > 0) {
3982 const char *p = READ_CHAR_PENDING_PTR(fptr);
3985 if (*p != term)
return TRUE;
3987 while (--i && *++p == term);
3990 const char *e = p + cnt;
3991 if (rb_enc_ascget(p, e, &i, enc) != term)
return TRUE;
3992 while ((p += i) < e && rb_enc_ascget(p, e, &i, enc) == term);
3995 io_shift_cbuf(fptr, (
int)cnt - i, NULL);
3997 }
while (more_char(fptr) != MORE_CHAR_FINISHED);
4001 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4004 while ((cnt = READ_DATA_PENDING_COUNT(fptr)) > 0) {
4006 const char *p = READ_DATA_PENDING_PTR(fptr);
4008 if (cnt >
sizeof buf) cnt =
sizeof buf;
4009 if (*p != term)
return TRUE;
4011 while (--i && *++p == term);
4012 if (!read_buffered_data(buf, cnt - i, fptr))
4013 rb_sys_fail_path(fptr->
pathv);
4016 }
while (io_fillbuf(fptr) == 0);
4029 int pending = READ_DATA_PENDING_COUNT(fptr);
4032 const char *p = READ_DATA_PENDING_PTR(fptr);
4036 e = memchr(p,
'\n', pending);
4038 pending = (int)(e - p + 1);
4040 chomplen = (pending > 1 && *(e-1) ==
'\r') + 1;
4049 rb_str_resize(str,
len + pending - chomplen);
4050 read_buffered_data(RSTRING_PTR(str)+
len, pending - chomplen, fptr);
4053 if (pending == 1 && chomplen == 1 &&
len > 0) {
4054 if (RSTRING_PTR(str)[
len-1] ==
'\r') {
4055 rb_str_resize(str, --
len);
4060 len += pending - chomplen;
4066 }
while (io_fillbuf(fptr) >= 0);
4069 str = io_enc_str(str, fptr);
4080 unsigned int chomp: 1;
4094 chomp = (!UNDEF_P(vchomp)) &&
RTEST(vchomp);
4096 args->chomp = chomp;
4114 else if (2 <= argc) {
4115 rs = argv[0], lim = argv[1];
4124check_getline_args(
VALUE *rsp,
long *limit,
VALUE io)
4133 enc_rs = rb_enc_get(rs);
4134 enc_io = io_read_encoding(fptr);
4135 if (enc_io != enc_rs &&
4136 (!is_ascii_string(rs) ||
4137 (RSTRING_LEN(rs) > 0 && !rb_enc_asciicompat(enc_io)))) {
4138 if (rs == rb_default_rs) {
4139 rs = rb_enc_str_new(0, 0, enc_io);
4144 rb_raise(rb_eArgError,
"encoding mismatch: %s IO with %s RS",
4145 rb_enc_name(enc_io),
4146 rb_enc_name(enc_rs));
4156 argc =
rb_scan_args(argc, argv,
"02:", NULL, NULL, &opts);
4157 extract_getline_args(argc, argv, args);
4158 extract_getline_opts(opts, args);
4159 check_getline_args(&args->rs, &args->limit, io);
4163rb_io_getline_0(
VALUE rs,
long limit,
int chomp,
rb_io_t *fptr)
4170 if (
NIL_P(rs) && limit < 0) {
4171 str = read_all(fptr, 0,
Qnil);
4172 if (RSTRING_LEN(str) == 0)
return Qnil;
4174 else if (limit == 0) {
4175 return rb_enc_str_new(0, 0, io_read_encoding(fptr));
4177 else if (rs == rb_default_rs && limit < 0 && !NEED_READCONV(fptr) &&
4178 rb_enc_asciicompat(enc = io_read_encoding(fptr))) {
4179 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4180 return rb_io_getline_fast(fptr, enc, chomp);
4183 int c, newline = -1;
4184 const char *rsptr = 0;
4187 int extra_limit = 16;
4188 int chomp_cr = chomp;
4190 SET_BINARY_MODE(fptr);
4191 enc = io_read_encoding(fptr);
4194 rslen = RSTRING_LEN(rs);
4199 swallow(fptr,
'\n');
4201 if (!rb_enc_asciicompat(enc)) {
4205 rsptr = RSTRING_PTR(rs);
4206 rslen = RSTRING_LEN(rs);
4210 else if (rb_enc_mbminlen(enc) == 1) {
4211 rsptr = RSTRING_PTR(rs);
4212 newline = (
unsigned char)rsptr[rslen - 1];
4216 rsptr = RSTRING_PTR(rs);
4217 const char *e = rsptr + rslen;
4218 const char *last = rb_enc_prev_char(rsptr, e, e, enc);
4220 newline = rb_enc_codepoint_len(last, e, &n, enc);
4221 if (last + n != e) rb_raise(rb_eArgError,
"broken separator");
4223 chomp_cr = chomp && newline ==
'\n' && rslen == rb_enc_mbminlen(enc);
4227 while ((c = appendline(fptr, newline, &str, &limit, enc)) != EOF) {
4228 const char *s, *p, *pp, *e;
4231 if (RSTRING_LEN(str) < rslen)
continue;
4232 s = RSTRING_PTR(str);
4235 if (!at_char_boundary(s, p, e, enc))
continue;
4236 if (!rspara) rscheck(rsptr, rslen, rs);
4237 if (memcmp(p, rsptr, rslen) == 0) {
4239 if (chomp_cr && p > s && *(p-1) ==
'\r') --p;
4246 s = RSTRING_PTR(str);
4248 pp = rb_enc_prev_char(s, p, p, enc);
4249 if (extra_limit && pp &&
4263 if (rspara && c != EOF)
4264 swallow(fptr,
'\n');
4266 str = io_enc_str(str, fptr);
4269 if (!
NIL_P(str) && !nolimit) {
4277rb_io_getline_1(
VALUE rs,
long limit,
int chomp,
VALUE io)
4280 int old_lineno, new_lineno;
4284 old_lineno = fptr->
lineno;
4285 str = rb_io_getline_0(rs, limit, chomp, fptr);
4286 if (!
NIL_P(str) && (new_lineno = fptr->
lineno) != old_lineno) {
4287 if (io == ARGF.current_file) {
4288 ARGF.lineno += new_lineno - old_lineno;
4289 ARGF.last_lineno = ARGF.lineno;
4292 ARGF.last_lineno = new_lineno;
4300rb_io_getline(
int argc,
VALUE *argv,
VALUE io)
4304 prepare_getline_args(argc, argv, &args, io);
4305 return rb_io_getline_1(args.rs, args.limit, args.chomp, io);
4315rb_io_gets_limit_internal(
VALUE io,
long limit)
4319 return rb_io_getline_0(rb_default_rs, limit, FALSE, fptr);
4323rb_io_gets_internal(
VALUE io)
4325 return rb_io_gets_limit_internal(io, -1);
4405 str = rb_io_getline(argc, argv, io);
4421rb_io_lineno(
VALUE io)
4476 check_getline_args(&sep, &limit, io);
4478 VALUE line = rb_io_getline_1(sep, limit,
RTEST(chomp), io);
4479 rb_lastline_set_up(line, 1);
4554rb_io_readlines(
int argc,
VALUE *argv,
VALUE io)
4558 prepare_getline_args(argc, argv, &args, io);
4559 return io_readlines(&args, io);
4567 if (arg->limit == 0)
4568 rb_raise(rb_eArgError,
"invalid limit: 0 for readlines");
4570 while (!
NIL_P(line = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, io))) {
4683rb_io_each_line(
int argc,
VALUE *argv,
VALUE io)
4689 prepare_getline_args(argc, argv, &args, io);
4690 if (args.limit == 0)
4691 rb_raise(rb_eArgError,
"invalid limit: 0 for each_line");
4692 while (!
NIL_P(str = rb_io_getline_1(args.rs, args.limit, args.chomp, io))) {
4719rb_io_each_byte(
VALUE io)
4735 }
while (io_fillbuf(fptr) >= 0);
4745 if (NEED_READCONV(fptr)) {
4749 SET_BINARY_MODE(fptr);
4750 make_readconv(fptr, 0);
4764 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4766 clear_readconv(fptr);
4770 str = rb_enc_str_new(fptr->
cbuf.
ptr+fptr->
cbuf.
off, 1, read_enc);
4773 if (fptr->
cbuf.
len == 0) clear_readconv(fptr);
4782 io_shift_cbuf(fptr, r, &str);
4789 ISASCII(RSTRING_PTR(str)[0])) {
4793 str = io_enc_str(str, fptr);
4798 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4799 if (io_fillbuf(fptr) < 0) {
4821 if (io_fillbuf(fptr) != -1) {
4825 r = rb_enc_precise_mbclen(RSTRING_PTR(str), RSTRING_PTR(str)+RSTRING_LEN(str), enc);
4841 str = io_enc_str(str, fptr);
4867rb_io_each_char(
VALUE io)
4877 enc = io_input_encoding(fptr);
4879 while (!
NIL_P(c = io_getc(fptr, enc))) {
4905rb_io_each_codepoint(
VALUE io)
4917 enc = io_read_encoding(fptr);
4918 if (NEED_READCONV(fptr)) {
4919 SET_BINARY_MODE(fptr);
4922 make_readconv(fptr, 0);
4934 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4935 clear_readconv(fptr);
4955 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4956 while (io_fillbuf(fptr) >= 0) {
4971 char cbuf[8], *p = cbuf;
4973 if (more > numberof(cbuf))
goto invalid;
4975 if (more > numberof(cbuf))
goto invalid;
4976 while ((n = (
int)read_buffered_data(p, more, fptr)) > 0 &&
4977 (p += n, (more -= n) > 0)) {
4978 if (io_fillbuf(fptr) < 0)
goto invalid;
4979 if ((n = fptr->
rbuf.
len) > more) n = more;
4981 r = rb_enc_precise_mbclen(cbuf, p, enc);
4994 rb_raise(rb_eArgError,
"invalid byte sequence in %s", rb_enc_name(enc));
5026 enc = io_input_encoding(fptr);
5028 return io_getc(fptr, enc);
5051rb_io_readchar(
VALUE io)
5053 VALUE c = rb_io_getc(io);
5088 VALUE r_stdout = rb_ractor_stdout();
5093 rb_io_flush(r_stdout);
5096 if (io_fillbuf(fptr) < 0) {
5125rb_io_readbyte(
VALUE io)
5186 unsigned char c =
NUM2INT(v) & 0xFF;
5192 io_ungetbyte(b, fptr);
5248 else if (RB_BIGNUM_TYPE_P(c)) {
5254 if (NEED_READCONV(fptr)) {
5255 SET_BINARY_MODE(fptr);
5256 len = RSTRING_LEN(c);
5257#if SIZEOF_LONG > SIZEOF_INT
5261 make_readconv(fptr, (
int)
len);
5275 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
5276 io_ungetbyte(c, fptr);
5296rb_io_isatty(
VALUE io)
5301 return RBOOL(isatty(fptr->
fd) != 0);
5304#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5320rb_io_close_on_exec_p(
VALUE io)
5326 write_io = GetWriteIO(io);
5327 if (io != write_io) {
5329 if (fptr && 0 <= (fd = fptr->
fd)) {
5330 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->
pathv);
5331 if (!(ret & FD_CLOEXEC))
return Qfalse;
5336 if (fptr && 0 <= (fd = fptr->
fd)) {
5337 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->
pathv);
5338 if (!(ret & FD_CLOEXEC))
return Qfalse;
5343#define rb_io_close_on_exec_p rb_f_notimplement
5346#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5370 int flag =
RTEST(arg) ? FD_CLOEXEC : 0;
5375 write_io = GetWriteIO(io);
5376 if (io != write_io) {
5378 if (fptr && 0 <= (fd = fptr->
fd)) {
5379 if ((ret = fcntl(fptr->
fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->
pathv);
5380 if ((ret & FD_CLOEXEC) != flag) {
5381 ret = (ret & ~FD_CLOEXEC) | flag;
5382 ret = fcntl(fd, F_SETFD, ret);
5383 if (ret != 0) rb_sys_fail_path(fptr->
pathv);
5390 if (fptr && 0 <= (fd = fptr->
fd)) {
5391 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->
pathv);
5392 if ((ret & FD_CLOEXEC) != flag) {
5393 ret = (ret & ~FD_CLOEXEC) | flag;
5394 ret = fcntl(fd, F_SETFD, ret);
5395 if (ret != 0) rb_sys_fail_path(fptr->
pathv);
5401#define rb_io_set_close_on_exec rb_f_notimplement
5404#define RUBY_IO_EXTERNAL_P(f) ((f)->mode & FMODE_EXTERNAL)
5405#define PREP_STDIO_NAME(f) (RSTRING_PTR((f)->pathv))
5408finish_writeconv(
rb_io_t *fptr,
int noalloc)
5410 unsigned char *ds, *dp, *de;
5414 unsigned char buf[1024];
5419 de = buf +
sizeof(buf);
5422 size_t remaining = dp-ds;
5423 long result = rb_io_write_memory(fptr, ds, remaining);
5427 if ((
size_t)result == remaining)
break;
5450 if (io_fflush(fptr) < 0) {
5458 fptr->
wbuf.
len += (int)(dp - ds);
5474finish_writeconv_sync(
VALUE arg)
5477 return finish_writeconv(p->fptr, p->noalloc);
5481nogvl_close(
void *ptr)
5485 return (
void*)(intptr_t)close(*fd);
5489maygvl_close(
int fd,
int keepgvl)
5498 return IO_WITHOUT_GVL_INT(nogvl_close, &fd);
5502nogvl_fclose(
void *ptr)
5506 return (
void*)(intptr_t)fclose(file);
5510maygvl_fclose(
FILE *file,
int keepgvl)
5513 return fclose(file);
5515 return IO_WITHOUT_GVL_INT(nogvl_fclose, file);
5521fptr_finalize_flush(
rb_io_t *fptr,
int noraise,
int keepgvl)
5526 int mode = fptr->
mode;
5532 arg.noalloc = noraise;
5536 error = finish_writeconv(fptr, noraise);
5541 io_flush_buffer_sync(fptr);
5544 if (io_fflush(fptr) < 0 &&
NIL_P(error)) {
5552 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2) {
5562 rb_thread_io_close_wait(fptr);
5564 if (!done && stdio_file) {
5566 if ((maygvl_fclose(stdio_file, noraise) < 0) &&
NIL_P(error)) {
5576 if (!done && fd >= 0 && scheduler !=
Qnil) {
5579 if (!UNDEF_P(result)) {
5580 done =
RTEST(result);
5584 if (!done && fd >= 0) {
5590 if ((maygvl_close(fd, keepgvl) < 0) &&
NIL_P(error)) {
5599 if (!
NIL_P(error) && !noraise) {
5608fptr_finalize(
rb_io_t *fptr,
int noraise)
5610 fptr_finalize_flush(fptr, noraise, FALSE);
5611 free_io_buffer(&fptr->
rbuf);
5612 free_io_buffer(&fptr->
wbuf);
5613 clear_codeconv(fptr);
5617rb_io_fptr_cleanup(
rb_io_t *fptr,
int noraise)
5623 fptr_finalize(fptr, noraise);
5631 ruby_sized_xfree(buf->
ptr, (
size_t)buf->
capa);
5643 free_io_buffer(&fptr->
cbuf);
5659 clear_readconv(fptr);
5660 clear_writeconv(fptr);
5664rb_io_fptr_cleanup_all(
rb_io_t *fptr)
5668 rb_io_fptr_cleanup(fptr, TRUE);
5670 free_io_buffer(&fptr->
rbuf);
5671 free_io_buffer(&fptr->
wbuf);
5672 clear_codeconv(fptr);
5679 rb_io_fptr_cleanup_all(io);
5686rb_io_memsize(
const rb_io_t *io)
5688 size_t size =
sizeof(
rb_io_t);
5698 rb_serial_t fork_generation = GET_VM()->fork_gen;
5699 if (io->fork_generation == fork_generation) {
5710# define KEEPGVL TRUE
5712# define KEEPGVL FALSE
5716io_close_fptr(
VALUE io)
5722 write_io = GetWriteIO(io);
5723 if (io != write_io) {
5724 write_fptr =
RFILE(write_io)->fptr;
5725 if (write_fptr && 0 <= write_fptr->
fd) {
5726 rb_io_fptr_cleanup(write_fptr, TRUE);
5730 fptr =
RFILE(io)->fptr;
5731 if (!fptr)
return 0;
5732 if (fptr->
fd < 0)
return 0;
5735 if (rb_thread_io_close_interrupt(fptr)) {
5737 fptr_finalize_flush(fptr, FALSE, KEEPGVL);
5740 rb_io_fptr_cleanup(fptr, FALSE);
5745fptr_waitpid(
rb_io_t *fptr,
int nohang)
5749 rb_last_status_clear();
5758 rb_io_t *fptr = io_close_fptr(io);
5759 if (fptr) fptr_waitpid(fptr, 0);
5799rb_io_close_m(
VALUE io)
5801 rb_io_t *fptr = rb_io_get_fptr(io);
5810io_call_close(
VALUE io)
5819 enum {mesg_len =
sizeof(closed_stream)-1};
5820 VALUE mesg = rb_attr_get(exc, idMesg);
5822 RSTRING_LEN(mesg) != mesg_len ||
5823 memcmp(RSTRING_PTR(mesg), closed_stream, mesg_len)) {
5833 if (!UNDEF_P(closed) &&
RTEST(closed))
return io;
5834 rb_rescue2(io_call_close, io, ignore_closed_stream, io,
5870 write_io = GetWriteIO(io);
5871 if (io != write_io) {
5872 write_fptr =
RFILE(write_io)->fptr;
5873 if (write_fptr && 0 <= write_fptr->
fd) {
5878 fptr = rb_io_get_fptr(io);
5879 return RBOOL(0 > fptr->
fd);
5915rb_io_close_read(
VALUE io)
5921 if (fptr->
fd < 0)
return Qnil;
5922 if (is_socket(fptr->
fd, fptr->
pathv)) {
5926 if (shutdown(fptr->
fd, SHUT_RD) < 0)
5927 rb_sys_fail_path(fptr->
pathv);
5928 fptr->
mode &= ~FMODE_READABLE;
5934 write_io = GetWriteIO(io);
5935 if (io != write_io) {
5940 RFILE(io)->fptr = wfptr;
5943 RFILE(write_io)->fptr = fptr;
5944 rb_io_fptr_cleanup(fptr, FALSE);
5950 rb_raise(
rb_eIOError,
"closing non-duplex IO for reading");
5988rb_io_close_write(
VALUE io)
5993 write_io = GetWriteIO(io);
5995 if (fptr->
fd < 0)
return Qnil;
5996 if (is_socket(fptr->
fd, fptr->
pathv)) {
6000 if (shutdown(fptr->
fd, SHUT_WR) < 0)
6001 rb_sys_fail_path(fptr->
pathv);
6002 fptr->
mode &= ~FMODE_WRITABLE;
6009 rb_raise(
rb_eIOError,
"closing non-duplex IO for writing");
6012 if (io != write_io) {
6032rb_io_sysseek(
int argc,
VALUE *argv,
VALUE io)
6034 VALUE offset, ptrname;
6035 int whence = SEEK_SET;
6039 if (
rb_scan_args(argc, argv,
"11", &offset, &ptrname) == 2) {
6040 whence = interpret_seek_whence(ptrname);
6045 (READ_DATA_BUFFERED(fptr) || READ_CHAR_PENDING(fptr))) {
6049 rb_warn(
"sysseek for buffered IO");
6052 pos = lseek(fptr->
fd, pos, whence);
6053 if (pos < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
6087 io = GetWriteIO(io);
6092 rb_warn(
"syswrite for buffered IO");
6095 tmp = rb_str_tmp_frozen_acquire(str);
6097 n = rb_io_write_memory(fptr, ptr,
len);
6098 if (n < 0) rb_sys_fail_path(fptr->
pathv);
6099 rb_str_tmp_frozen_release(str, tmp);
6116rb_io_sysread(
int argc,
VALUE *argv,
VALUE io)
6127 shrinkable = io_setstrbuf(&str, ilen);
6128 if (ilen == 0)
return str;
6133 if (READ_DATA_BUFFERED(fptr)) {
6139 io_setstrbuf(&str, ilen);
6144 iis.buf = RSTRING_PTR(str);
6147 n = io_read_memory_locktmp(str, &iis);
6150 rb_sys_fail_path(fptr->
pathv);
6153 io_set_read_length(str, n, shrinkable);
6155 if (n == 0 && ilen > 0) {
6171internal_pread_func(
void *_arg)
6175 return (
VALUE)pread(arg->fd, arg->buf, arg->count, arg->offset);
6179pread_internal_call(
VALUE _arg)
6184 if (scheduler !=
Qnil) {
6187 if (!UNDEF_P(result)) {
6192 return rb_io_blocking_region_wait(arg->io, internal_pread_func, arg,
RUBY_IO_READABLE);
6236 shrinkable = io_setstrbuf(&str, (
long)arg.count);
6237 if (arg.count == 0)
return str;
6238 arg.buf = RSTRING_PTR(str);
6251 rb_sys_fail_path(fptr->
pathv);
6253 io_set_read_length(str, n, shrinkable);
6254 if (n == 0 && arg.count > 0) {
6262internal_pwrite_func(
void *_arg)
6266 return (
VALUE)pwrite(arg->fd, arg->buf, arg->count, arg->offset);
6270pwrite_internal_call(
VALUE _arg)
6275 if (scheduler !=
Qnil) {
6278 if (!UNDEF_P(result)) {
6283 return rb_io_blocking_region_wait(arg->io, internal_pwrite_func, arg,
RUBY_IO_WRITABLE);
6324 io = GetWriteIO(io);
6331 tmp = rb_str_tmp_frozen_acquire(str);
6332 arg.buf = RSTRING_PTR(tmp);
6333 arg.count = (size_t)RSTRING_LEN(tmp);
6335 n = (ssize_t)pwrite_internal_call((
VALUE)&arg);
6336 if (n < 0) rb_sys_fail_path(fptr->
pathv);
6337 rb_str_tmp_frozen_release(str, tmp);
6353 fptr->
mode &= ~FMODE_TEXTMODE;
6357 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6360 setmode(fptr->
fd, O_BINARY);
6367io_ascii8bit_binmode(
rb_io_t *fptr)
6378 fptr->
mode &= ~FMODE_TEXTMODE;
6379 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6381 fptr->
encs.
enc = rb_ascii8bit_encoding();
6385 clear_codeconv(fptr);
6394 io_ascii8bit_binmode(fptr);
6411rb_io_binmode_m(
VALUE io)
6417 write_io = GetWriteIO(io);
6432rb_io_binmode_p(
VALUE io)
6440rb_io_fmode_modestr(
enum rb_io_mode fmode)
6444 return MODE_BTMODE(
"a+",
"ab+",
"at+");
6446 return MODE_BTMODE(
"a",
"ab",
"at");
6450 rb_raise(rb_eArgError,
"invalid access fmode 0x%x", fmode);
6452 return MODE_BTMODE(
"r",
"rb",
"rt");
6454 return MODE_BTXMODE(
"w",
"wb",
"wt",
"wx",
"wbx",
"wtx");
6457 return MODE_BTXMODE(
"w+",
"wb+",
"wt+",
"w+x",
"wb+x",
"wt+x");
6459 return MODE_BTMODE(
"r+",
"rb+",
"rt+");
6463static const char bom_prefix[] =
"bom|";
6464static const char utf_prefix[] =
"utf-";
6465enum {bom_prefix_len = (int)
sizeof(bom_prefix) - 1};
6466enum {utf_prefix_len = (int)
sizeof(utf_prefix) - 1};
6469io_encname_bom_p(
const char *name,
long len)
6471 return len > bom_prefix_len &&
STRNCASECMP(name, bom_prefix, bom_prefix_len) == 0;
6477 enum rb_io_mode fmode = 0;
6478 const char *m = modestr, *p = NULL;
6506 if (modestr[0] !=
'w')
6514 if (io_encname_bom_p(m, p ? (
long)(p - m) : (long)strlen(m)))
6527 rb_raise(rb_eArgError,
"invalid access mode %s", modestr);
6532rb_io_oflags_fmode(
int oflags)
6534 enum rb_io_mode fmode = 0;
6536 switch (oflags & O_ACCMODE) {
6548 if (oflags & O_APPEND) {
6551 if (oflags & O_TRUNC) {
6554 if (oflags & O_CREAT) {
6557 if (oflags & O_EXCL) {
6561 if (oflags & O_BINARY) {
6570rb_io_fmode_oflags(
enum rb_io_mode fmode)
6614rb_io_oflags_modestr(
int oflags)
6617# define MODE_BINARY(a,b) ((oflags & O_BINARY) ? (b) : (a))
6619# define MODE_BINARY(a,b) (a)
6622 if (oflags & O_EXCL) {
6623 rb_raise(rb_eArgError,
"exclusive access mode is not supported");
6625 accmode = oflags & (O_RDONLY|O_WRONLY|O_RDWR);
6626 if (oflags & O_APPEND) {
6627 if (accmode == O_WRONLY) {
6628 return MODE_BINARY(
"a",
"ab");
6630 if (accmode == O_RDWR) {
6631 return MODE_BINARY(
"a+",
"ab+");
6636 rb_raise(rb_eArgError,
"invalid access oflags 0x%x", oflags);
6638 return MODE_BINARY(
"r",
"rb");
6640 return MODE_BINARY(
"w",
"wb");
6642 if (oflags & O_TRUNC) {
6643 return MODE_BINARY(
"w+",
"wb+");
6645 return MODE_BINARY(
"r+",
"rb+");
6657 int default_ext = 0;
6660 ext = rb_default_external_encoding();
6663 if (rb_is_ascii8bit_enc(ext)) {
6667 else if (intern == NULL) {
6668 intern = rb_default_internal_encoding();
6673 *enc = (default_ext && intern != ext) ? NULL : ext;
6683unsupported_encoding(
const char *name,
rb_encoding *enc)
6685 rb_enc_warn(enc,
"Unsupported encoding %s ignored", name);
6689parse_mode_enc(
const char *estr,
rb_encoding *estr_enc,
6695 enum rb_io_mode fmode = fmode_p ? *fmode_p : 0;
6701 p = strrchr(estr,
':');
6702 len = p ? (p++ - estr) : (long)strlen(estr);
6704 estr += bom_prefix_len;
6705 len -= bom_prefix_len;
6706 if (!
STRNCASECMP(estr, utf_prefix, utf_prefix_len)) {
6710 rb_enc_warn(estr_enc,
"BOM with non-UTF encoding %s is nonsense", estr);
6711 fmode &= ~FMODE_SETENC_BY_BOM;
6719 memcpy(encname, estr,
len);
6720 encname[
len] =
'\0';
6723 idx = rb_enc_find_index(estr);
6725 if (fmode_p) *fmode_p = fmode;
6728 ext_enc = rb_enc_from_index(idx);
6731 unsupported_encoding(estr, estr_enc);
6737 if (*p ==
'-' && *(p+1) ==
'\0') {
6742 idx2 = rb_enc_find_index(p);
6744 unsupported_encoding(p, estr_enc);
6749 int_enc = rb_enc_from_index(idx2);
6753 rb_io_ext_int_to_encs(ext_enc, int_enc, enc_p, enc2_p, fmode);
6766 v = rb_hash_lookup2(opt, sym_encoding,
Qnil);
6767 if (v !=
Qnil) encoding = v;
6768 v = rb_hash_lookup2(opt, sym_extenc,
Qundef);
6769 if (v !=
Qnil) extenc = v;
6770 v = rb_hash_lookup2(opt, sym_intenc,
Qundef);
6771 if (!UNDEF_P(v)) intenc = v;
6773 if ((!UNDEF_P(extenc) || !UNDEF_P(intenc)) && !
NIL_P(encoding)) {
6775 int idx = rb_to_encoding_index(encoding);
6776 if (idx >= 0) encoding = rb_enc_from_encoding(rb_enc_from_index(idx));
6777 rb_warn(
"Ignoring encoding parameter '%"PRIsVALUE
"': %s_encoding is used",
6778 encoding, UNDEF_P(extenc) ?
"internal" :
"external");
6782 if (!UNDEF_P(extenc) && !
NIL_P(extenc)) {
6783 extencoding = rb_to_encoding(extenc);
6785 if (!UNDEF_P(intenc)) {
6786 if (
NIL_P(intenc)) {
6793 if (*p ==
'-' && *(p+1) ==
'\0') {
6798 intencoding = rb_to_encoding(intenc);
6802 intencoding = rb_to_encoding(intenc);
6804 if (extencoding == intencoding) {
6808 if (!
NIL_P(encoding)) {
6812 enc_p, enc2_p, fmode_p);
6815 rb_io_ext_int_to_encs(rb_to_encoding(encoding), NULL, enc_p, enc2_p, 0);
6818 else if (!UNDEF_P(extenc) || !UNDEF_P(intenc)) {
6820 rb_io_ext_int_to_encs(extencoding, intencoding, enc_p, enc2_p, 0);
6828 enum rb_io_mode fmode = *fmode_p;
6833 !rb_enc_asciicompat(enc ? enc : rb_default_external_encoding()))
6834 rb_raise(rb_eArgError,
"ASCII incompatible encoding needs binmode");
6837 rb_raise(rb_eArgError,
"newline decorator with binary mode");
6844#if !DEFAULT_TEXTMODE
6846 fmode &= ~FMODE_TEXTMODE;
6853extract_binmode(
VALUE opthash,
enum rb_io_mode *fmode)
6855 if (!
NIL_P(opthash)) {
6857 v = rb_hash_aref(opthash, sym_textmode);
6860 rb_raise(rb_eArgError,
"textmode specified twice");
6862 rb_raise(rb_eArgError,
"both textmode and binmode specified");
6866 v = rb_hash_aref(opthash, sym_binmode);
6869 rb_raise(rb_eArgError,
"binmode specified twice");
6871 rb_raise(rb_eArgError,
"both textmode and binmode specified");
6877 rb_raise(rb_eArgError,
"both textmode and binmode specified");
6883 int *oflags_p,
enum rb_io_mode *fmode_p,
struct rb_io_encoding *convconfig_p)
6887 enum rb_io_mode fmode;
6891 int has_enc = 0, has_vmode = 0;
6897 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
6907 fmode = rb_io_oflags_fmode(oflags);
6915 oflags = rb_io_fmode_oflags(fmode);
6919 parse_mode_enc(p+1, rb_enc_get(vmode), &enc, &enc2, &fmode);
6924 e = (fmode &
FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
6925 rb_io_ext_int_to_encs(e, NULL, &enc, &enc2, fmode);
6929 if (
NIL_P(opthash)) {
6933#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
6935 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
6936 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
6938 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
6945 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
6948 else if (
NIL_P(vmode)) {
6949 fmode |= DEFAULT_TEXTMODE;
6956 v = rb_hash_aref(opthash, sym_mode);
6958 if (!
NIL_P(vmode)) {
6959 rb_raise(rb_eArgError,
"mode specified twice");
6966 v = rb_hash_aref(opthash, sym_flags);
6971 fmode = rb_io_oflags_fmode(oflags);
6973 extract_binmode(opthash, &fmode);
6979 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
6982 else if (
NIL_P(vmode)) {
6983 fmode |= DEFAULT_TEXTMODE;
6986 v = rb_hash_aref(opthash, sym_perm);
6989 if (!
NIL_P(*vperm_p)) {
6990 rb_raise(rb_eArgError,
"perm specified twice");
7001#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7003 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7004 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7009 rb_raise(rb_eArgError,
"encoding specified twice");
7012 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
7016 validate_enc_binmode(&fmode, ecflags, enc, enc2);
7022 convconfig_p->
enc = enc;
7023 convconfig_p->
enc2 = enc2;
7024 convconfig_p->
ecflags = ecflags;
7025 convconfig_p->
ecopts = ecopts;
7035sysopen_func(
void *ptr)
7038 const char *fname = RSTRING_PTR(data->fname);
7047 fd = IO_WITHOUT_GVL_INT(sysopen_func, data);
7048 }
while (fd < 0 &&
errno == EINTR);
7055rb_sysopen(
VALUE fname,
int oflags, mode_t perm)
7060 data.fname = rb_str_encode_ospath(fname);
7062 data.oflags = oflags;
7065 TRY_WITH_GC((fd = rb_sysopen_internal(&data)) >= 0) {
7066 rb_syserr_fail_path(first_errno, fname);
7072fdopen_internal(
int fd,
const char *modestr)
7079 file = fdopen(fd, modestr);
7095 TRY_WITH_GC((file = fdopen_internal(fd, modestr)) != 0) {
7101 if (setvbuf(file, NULL, _IOFBF, 0) != 0)
7102 rb_warn(
"setvbuf() can't be honoured (fd=%d)", fd);
7110 int t = isatty(fptr->
fd);
7120io_strip_bom(
VALUE io)
7122 VALUE b1, b2, b3, b4;
7133 return rb_utf8_encindex();
7143 return ENCINDEX_UTF_16BE;
7154 return ENCINDEX_UTF_32LE;
7159 return ENCINDEX_UTF_16LE;
7169 return ENCINDEX_UTF_32BE;
7183io_set_encoding_by_bom(
VALUE io)
7185 int idx = io_strip_bom(io);
7191 extenc = rb_enc_from_index(idx);
7192 io_encoding_set(fptr, rb_enc_from_encoding(extenc),
7193 rb_io_internal_encoding(io),
Qnil);
7202rb_file_open_generic(
VALUE io,
VALUE filename,
int oflags,
enum rb_io_mode fmode,
7210 rb_io_ext_int_to_encs(NULL, NULL, &cc.enc, &cc.enc2, fmode);
7215 validate_enc_binmode(&fmode, convconfig->
ecflags,
7216 convconfig->
enc, convconfig->
enc2);
7220 fptr->
encs = *convconfig;
7223 if (!(oflags & O_TMPFILE)) {
7224 fptr->
pathv = pathv;
7227 fptr->
pathv = pathv;
7229 fptr->
fd = rb_sysopen(pathv, oflags, perm);
7237rb_file_open_internal(
VALUE io,
VALUE filename,
const char *modestr)
7240 const char *p = strchr(modestr,
':');
7244 parse_mode_enc(p+1, rb_usascii_encoding(),
7245 &convconfig.
enc, &convconfig.
enc2, &fmode);
7251 e = (fmode &
FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
7252 rb_io_ext_int_to_encs(e, NULL, &convconfig.
enc, &convconfig.
enc2, fmode);
7258#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7260 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7261 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7263 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.
enc2, convconfig.
ecflags);
7266 return rb_file_open_generic(io, filename,
7267 rb_io_fmode_oflags(fmode),
7277 return rb_file_open_internal(io_alloc(
rb_cFile), fname, modestr);
7286#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7309 while ((tmp = *prev) != 0) {
7310 if (tmp->fptr == fptr) {
7319#if defined (_WIN32) || defined(__CYGWIN__)
7335pipe_finalize(
rb_io_t *fptr,
int noraise)
7337#if !defined(HAVE_WORKING_FORK) && !defined(_WIN32)
7346 fptr_finalize(fptr, noraise);
7348 pipe_del_fptr(fptr);
7355#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7356 void (*
const old_finalize)(
struct rb_io*,int) = fptr->
finalize;
7358 if (old_finalize == orig->finalize)
return;
7363#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7364 if (old_finalize != pipe_finalize) {
7366 for (list =
pipe_list; list; list = list->next) {
7367 if (list->fptr == fptr)
break;
7369 if (!list) pipe_add_fptr(fptr);
7372 pipe_del_fptr(fptr);
7385rb_io_unbuffered(
rb_io_t *fptr)
7403#define HAVE_SPAWNV 1
7404#define spawnv(mode, cmd, args) rb_w32_uaspawn((mode), (cmd), (args))
7405#define spawn(mode, cmd) rb_w32_uspawn((mode), (cmd), 0)
7408#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7418#ifdef HAVE_WORKING_FORK
7419# ifndef __EMSCRIPTEN__
7421popen_redirect(
struct popen_arg *p)
7424 close(p->write_pair[1]);
7425 if (p->write_pair[0] != 0) {
7426 dup2(p->write_pair[0], 0);
7427 close(p->write_pair[0]);
7430 if (p->pair[1] != 1) {
7431 dup2(p->pair[1], 1);
7437 if (p->pair[1] != 1) {
7438 dup2(p->pair[1], 1);
7444 if (p->pair[0] != 0) {
7445 dup2(p->pair[0], 0);
7452#if defined(__linux__)
7463linux_get_maxfd(
void)
7466 char buf[4096], *p, *np, *e;
7469 if (fd < 0)
return fd;
7470 ss = read(fd, buf,
sizeof(buf));
7471 if (ss < 0)
goto err;
7474 while ((
int)
sizeof(
"FDSize:\t0\n")-1 <= e-p &&
7475 (np = memchr(p,
'\n', e-p)) != NULL) {
7476 if (memcmp(p,
"FDSize:",
sizeof(
"FDSize:")-1) == 0) {
7478 p +=
sizeof(
"FDSize:")-1;
7498#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
7500 int max = (int)max_file_descriptor;
7503 ret = fcntl(0, F_MAXFD);
7505 maxhint = max = ret;
7506# elif defined(__linux__)
7507 ret = linux_get_maxfd();
7514 for (fd = lowfd; fd <= max; fd++) {
7515 if (!
NIL_P(noclose_fds) &&
7518 ret = fcntl(fd, F_GETFD);
7519 if (ret != -1 && !(ret & FD_CLOEXEC)) {
7520 fcntl(fd, F_SETFD, ret|FD_CLOEXEC);
7522# define CONTIGUOUS_CLOSED_FDS 20
7524 if (max < fd + CONTIGUOUS_CLOSED_FDS)
7525 max = fd + CONTIGUOUS_CLOSED_FDS;
7531# ifndef __EMSCRIPTEN__
7533popen_exec(
void *pp,
char *errmsg,
size_t errmsg_len)
7535 struct popen_arg *p = (
struct popen_arg*)pp;
7537 return rb_exec_async_signal_safe(p->eargp, errmsg, errmsg_len);
7542#if (defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)) && !defined __EMSCRIPTEN__
7544rb_execarg_fixup_v(
VALUE execarg_obj)
7546 rb_execarg_parent_start(execarg_obj);
7550char *rb_execarg_commandline(
const struct rb_execarg *eargp,
VALUE *prog);
7553#ifndef __EMSCRIPTEN__
7555pipe_open(
VALUE execarg_obj,
const char *modestr,
enum rb_io_mode fmode,
7558 struct rb_execarg *eargp =
NIL_P(execarg_obj) ? NULL : rb_execarg_get(execarg_obj);
7559 VALUE prog = eargp ? (eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name) :
Qfalse ;
7565#if defined(HAVE_WORKING_FORK)
7567 char errmsg[80] = {
'\0' };
7569#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7571 struct popen_arg arg;
7574#if defined(HAVE_SPAWNV)
7575# if defined(HAVE_SPAWNVE)
7576# define DO_SPAWN(cmd, args, envp) ((args) ? \
7577 spawnve(P_NOWAIT, (cmd), (args), (envp)) : \
7578 spawne(P_NOWAIT, (cmd), (envp)))
7580# define DO_SPAWN(cmd, args, envp) ((args) ? \
7581 spawnv(P_NOWAIT, (cmd), (args)) : \
7582 spawn(P_NOWAIT, (cmd)))
7584# if !defined(HAVE_WORKING_FORK)
7586# if defined(HAVE_SPAWNVE)
7591#if !defined(HAVE_WORKING_FORK)
7597#if !defined(HAVE_WORKING_FORK)
7598 const char *cmd = 0;
7604#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7605 arg.execarg_obj = execarg_obj;
7608 arg.pair[0] = arg.pair[1] = -1;
7609 arg.write_pair[0] = arg.write_pair[1] = -1;
7610# if !defined(HAVE_WORKING_FORK)
7611 if (eargp && !eargp->use_shell) {
7612 args = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
7617 if (
rb_pipe(arg.write_pair) < 0)
7618 rb_sys_fail_str(prog);
7621 close(arg.write_pair[0]);
7622 close(arg.write_pair[1]);
7626 rb_execarg_addopt(execarg_obj,
INT2FIX(0),
INT2FIX(arg.write_pair[0]));
7627 rb_execarg_addopt(execarg_obj,
INT2FIX(1),
INT2FIX(arg.pair[1]));
7632 rb_sys_fail_str(prog);
7634 rb_execarg_addopt(execarg_obj,
INT2FIX(1),
INT2FIX(arg.pair[1]));
7638 rb_sys_fail_str(prog);
7640 rb_execarg_addopt(execarg_obj,
INT2FIX(0),
INT2FIX(arg.pair[0]));
7643 rb_sys_fail_str(prog);
7645 if (!
NIL_P(execarg_obj)) {
7646 rb_protect(rb_execarg_fixup_v, execarg_obj, &state);
7648 if (0 <= arg.write_pair[0]) close(arg.write_pair[0]);
7649 if (0 <= arg.write_pair[1]) close(arg.write_pair[1]);
7650 if (0 <= arg.pair[0]) close(arg.pair[0]);
7651 if (0 <= arg.pair[1]) close(arg.pair[1]);
7652 rb_execarg_parent_end(execarg_obj);
7656# if defined(HAVE_WORKING_FORK)
7657 pid = rb_fork_async_signal_safe(&status, popen_exec, &arg, arg.eargp->redirect_fds, errmsg,
sizeof(errmsg));
7659 rb_execarg_run_options(eargp, sargp, NULL, 0);
7660# if defined(HAVE_SPAWNVE)
7661 if (eargp->envp_str) envp = (
char **)RSTRING_PTR(eargp->envp_str);
7663 while ((pid = DO_SPAWN(cmd, args, envp)) < 0) {
7665 switch (e =
errno) {
7667# if EWOULDBLOCK != EAGAIN
7676 rb_execarg_run_options(sargp, NULL, NULL, 0);
7678 rb_execarg_parent_end(execarg_obj);
7681# if defined(HAVE_WORKING_FORK)
7682 pid = rb_call_proc__fork();
7684 popen_redirect(&arg);
7696# if defined(HAVE_WORKING_FORK)
7702 close(arg.write_pair[0]);
7703 close(arg.write_pair[1]);
7705# if defined(HAVE_WORKING_FORK)
7714 close(arg.write_pair[0]);
7715 write_fd = arg.write_pair[1];
7726 cmd = rb_execarg_commandline(eargp, &prog);
7727 if (!
NIL_P(execarg_obj)) {
7728 rb_execarg_parent_start(execarg_obj);
7729 rb_execarg_run_options(eargp, sargp, NULL, 0);
7731 fp = popen(cmd, modestr);
7734 rb_execarg_parent_end(execarg_obj);
7735 rb_execarg_run_options(sargp, NULL, NULL, 0);
7737 if (!fp) rb_syserr_fail_path(e, prog);
7747 fptr->
encs = *convconfig;
7748#if RUBY_CRLF_ENVIRONMENT
7755 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
7758#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7759 if (NEED_NEWLINE_DECORATOR_ON_WRITE(fptr)) {
7760 fptr->
encs.
ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
7766 if (0 <= write_fd) {
7767 write_port = io_alloc(
rb_cIO);
7769 write_fptr->
fd = write_fd;
7771 fptr->
mode &= ~FMODE_WRITABLE;
7773 rb_ivar_set(port, rb_intern(
"@tied_io_for_writing"), write_port);
7776#if defined (__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7778 pipe_add_fptr(fptr);
7784pipe_open(
VALUE execarg_obj,
const char *modestr,
enum rb_io_mode fmode,
7792is_popen_fork(
VALUE prog)
7794 if (RSTRING_LEN(prog) == 1 && RSTRING_PTR(prog)[0] ==
'-') {
7795#if !defined(HAVE_WORKING_FORK)
7797 "fork() function is unimplemented on this machine");
7806pipe_open_s(
VALUE prog,
const char *modestr,
enum rb_io_mode fmode,
7810 VALUE *argv = &prog;
7813 if (!is_popen_fork(prog))
7814 execarg_obj = rb_execarg_new(argc, argv, TRUE, FALSE);
7815 return pipe_open(execarg_obj, modestr, fmode, convconfig);
7821 rb_io_t *fptr = io_close_fptr(io);
7990rb_io_s_popen(
int argc,
VALUE *argv,
VALUE klass)
7994 if (argc > 1 && !
NIL_P(opt = rb_check_hash_type(argv[argc-1]))) --argc;
7995 if (argc > 1 && !
NIL_P(env = rb_check_hash_type(argv[0]))) --argc, ++argv;
8004 int ex = !
NIL_P(opt);
8005 rb_error_arity(argc + ex, 1 + ex, 2 + ex);
8008 return popen_finish(rb_io_popen(pname, pmode, env, opt), klass);
8014 const char *modestr;
8017 enum rb_io_mode fmode;
8023#if SIZEOF_LONG > SIZEOF_INT
8024 if (
len > INT_MAX) {
8025 rb_raise(rb_eArgError,
"too many arguments");
8034 if (!is_popen_fork(pname))
8035 execarg_obj = rb_execarg_new(1, &pname, TRUE, FALSE);
8037 if (!
NIL_P(execarg_obj)) {
8039 opt = rb_execarg_extract_options(execarg_obj, opt);
8041 rb_execarg_setenv(execarg_obj, env);
8044 modestr = rb_io_oflags_modestr(oflags);
8046 return pipe_open(execarg_obj, modestr, fmode, &convconfig);
8056 rb_io_flush(rb_ractor_stdout());
8057 rb_io_flush(rb_ractor_stderr());
8062 RBASIC_SET_CLASS(port, klass);
8069#if defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)
8070struct popen_writer_arg {
8072 struct popen_arg popen;
8076exec_popen_writer(
void *arg,
char *errmsg,
size_t buflen)
8078 struct popen_writer_arg *pw = arg;
8080 popen_redirect(&pw->popen);
8081 execv(pw->argv[0], pw->argv);
8082 strlcpy(errmsg, strerror(
errno), buflen);
8088ruby_popen_writer(
char *
const *argv, rb_pid_t *pid)
8090#if (defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)) || defined(_WIN32)
8091# ifdef HAVE_WORKING_FORK
8092 struct popen_writer_arg pw;
8093 int *
const write_pair = pw.popen.pair;
8099 int result = pipe2(write_pair, O_CLOEXEC);
8101 int result = pipe(write_pair);
8106# ifdef HAVE_WORKING_FORK
8109 char errmsg[80] = {
'\0'};
8110 *pid = rb_fork_async_signal_safe(&status, exec_popen_writer, &pw,
Qnil, errmsg,
sizeof(errmsg));
8112 *pid = rb_w32_uspawn_process(P_NOWAIT, argv[0], argv, write_pair[0], -1, -1, 0);
8113 const char *errmsg = (*pid < 0) ? strerror(
errno) : NULL;
8115 close(write_pair[0]);
8117 close(write_pair[1]);
8118 fprintf(stderr,
"ruby_popen_writer(%s): %s\n", argv[0], errmsg);
8121 return fdopen(write_pair[1],
"w");
8132 enum rb_io_mode fmode;
8141 rb_file_open_generic(io, fname, oflags, fmode, &convconfig, perm);
8179rb_io_s_open(
int argc,
VALUE *argv,
VALUE klass)
8211 VALUE fname, vmode, vperm;
8216 rb_scan_args(argc, argv,
"12", &fname, &vmode, &vperm);
8227 if (
NIL_P(vperm)) perm = 0666;
8231 fd = rb_sysopen(fname, oflags, perm);
8266 int redirect = FALSE;
8274 VALUE tmp = argv[0];
8292 return rb_io_s_open(argc, argv,
rb_cFile);
8296rb_io_open_generic(
VALUE klass,
VALUE filename,
int oflags,
enum rb_io_mode fmode,
8299 return rb_file_open_generic(io_alloc(klass), filename,
8300 oflags, fmode, convconfig, perm);
8307 enum rb_io_mode fmode;
8313 return rb_io_open_generic(io, filename, oflags, fmode, &convconfig, perm);
8327 if (fptr == orig)
return io;
8328 if (RUBY_IO_EXTERNAL_P(fptr)) {
8332 rb_raise(rb_eArgError,
8333 "%s can't change access mode from \"%s\" to \"%s\"",
8334 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->
mode),
8335 rb_io_fmode_modestr(orig->
mode));
8339 if (io_fflush(fptr) < 0)
8340 rb_sys_fail_on_write(fptr);
8343 flush_before_seek(fptr,
true);
8346 pos = io_tell(orig);
8349 if (io_fflush(orig) < 0)
8350 rb_sys_fail_on_write(fptr);
8359 else if (!RUBY_IO_EXTERNAL_P(fptr)) fptr->
pathv =
Qnil;
8360 fptr_copy_finalizer(fptr, orig);
8366 rb_thread_io_close_interrupt(fptr);
8367 rb_thread_io_close_wait(fptr);
8369 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2 || !fptr->stdio_file) {
8372 rb_sys_fail_path(orig->
pathv);
8380 rb_sys_fail_path(orig->
pathv);
8386 if (io_seek(fptr, pos, SEEK_SET) < 0 &&
errno) {
8387 rb_sys_fail_path(fptr->
pathv);
8389 if (io_seek(orig, pos, SEEK_SET) < 0 &&
errno) {
8390 rb_sys_fail_path(orig->
pathv);
8404int rb_freopen(
VALUE fname,
const char *mode,
FILE *fp);
8407rb_freopen(
VALUE fname,
const char *mode,
FILE *fp)
8409 if (!freopen(RSTRING_PTR(fname), mode, fp)) {
8452rb_io_reopen(
int argc,
VALUE *argv,
VALUE file)
8454 VALUE fname, nmode, opt;
8458 if (
rb_scan_args(argc, argv,
"11:", &fname, &nmode, &opt) == 1) {
8461 return io_reopen(file, tmp);
8467 fptr =
RFILE(file)->fptr;
8473 enum rb_io_mode fmode;
8477 if (RUBY_IO_EXTERNAL_P(fptr) &&
8480 rb_raise(rb_eArgError,
8481 "%s can't change access mode from \"%s\" to \"%s\"",
8482 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->
mode),
8483 rb_io_fmode_modestr(fmode));
8486 fptr->
encs = convconfig;
8489 oflags = rb_io_fmode_oflags(fptr->
mode);
8492 fptr->
pathv = fname;
8494 fptr->
fd = rb_sysopen(fptr->
pathv, oflags, 0666);
8500 if (io_fflush(fptr) < 0)
8501 rb_sys_fail_on_write(fptr);
8506 int e = rb_freopen(rb_str_encode_ospath(fptr->
pathv),
8507 rb_io_oflags_modestr(oflags),
8509 if (e) rb_syserr_fail_path(e, fptr->
pathv);
8513 if (setvbuf(fptr->
stdio_file, NULL, _IOFBF, 0) != 0)
8514 rb_warn(
"setvbuf() can't be honoured for %"PRIsVALUE, fptr->
pathv);
8517 if (setvbuf(fptr->
stdio_file, NULL, _IONBF, BUFSIZ) != 0)
8518 rb_warn(
"setvbuf() can't be honoured for %"PRIsVALUE, fptr->
pathv);
8520 else if (fptr->
stdio_file == stdout && isatty(fptr->
fd)) {
8521 if (setvbuf(fptr->
stdio_file, NULL, _IOLBF, BUFSIZ) != 0)
8522 rb_warn(
"setvbuf() can't be honoured for %"PRIsVALUE, fptr->
pathv);
8526 int tmpfd = rb_sysopen(fptr->
pathv, oflags, 0666);
8532 rb_syserr_fail_path(err, fptr->
pathv);
8556 fptr->
mode = orig->
mode & ~FMODE_EXTERNAL;
8563 fptr->closing_ec = NULL;
8564 fptr->wakeup_mutex =
Qnil;
8565 fptr->fork_generation = GET_VM()->fork_gen;
8568 fptr_copy_finalizer(fptr, orig);
8570 fd = ruby_dup(orig->
fd);
8572 pos = io_tell(orig);
8574 io_seek(fptr, pos, SEEK_SET);
8579 write_io = GetWriteIO(io);
8580 if (io != write_io) {
8583 rb_ivar_set(dest, rb_intern(
"@tied_io_for_writing"), write_io);
8646 if (argc == 0)
return Qnil;
8648 out = rb_ractor_stdout();
8660extern void rb_deprecated_str_setter(
VALUE val,
ID id,
VALUE *var);
8665 rb_deprecated_str_setter(val,
id, &val);
8671 val = rb_str_frozen_bare_string(val);
8748 for (i=0; i<argc; i++) {
8752 rb_io_write(out, argv[i]);
8849 rb_io_write(io, str);
8853#define forward(obj, id, argc, argv) \
8854 rb_funcallv_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8855#define forward_public(obj, id, argc, argv) \
8856 rb_funcallv_public_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8857#define forward_current(id, argc, argv) \
8858 forward_public(ARGF.current_file, id, argc, argv)
8875 VALUE r_stdout = rb_ractor_stdout();
8876 if (recv == r_stdout) {
8877 return rb_io_putc(recv, ch);
8879 return forward(r_stdout, rb_intern(
"putc"), 1, &ch);
8884rb_str_end_with_asciichar(
VALUE str,
int c)
8886 long len = RSTRING_LEN(str);
8887 const char *
ptr = RSTRING_PTR(str);
8891 if (
len == 0)
return 0;
8892 if ((n = rb_enc_mbminlen(
enc)) == 1) {
8893 return ptr[
len - 1] == c;
8895 return rb_enc_ascget(
ptr + ((
len - 1) / n) * n,
ptr +
len, &n,
enc) == c;
8906 rb_io_puts(1, &tmp, out);
8913 rb_io_puts(1, &tmp, out);
8968 VALUE line, args[2];
8975 for (
int i = 0; i < argc; i++) {
8989 if (RSTRING_LEN(line) == 0) {
8994 if (!rb_str_end_with_asciichar(line,
'\n')) {
8999 rb_io_writev(out, n, args);
9017 VALUE r_stdout = rb_ractor_stdout();
9018 if (recv == r_stdout) {
9019 return rb_io_puts(argc, argv, recv);
9021 return forward(r_stdout, rb_intern(
"puts"), argc, argv);
9025rb_p_write(
VALUE str)
9030 VALUE r_stdout = rb_ractor_stdout();
9032 rb_method_basic_definition_p(
CLASS_OF(r_stdout), id_write)) {
9033 io_writev(2, args, r_stdout);
9036 rb_io_writev(r_stdout, 2, args);
9048rb_p_result(
int argc,
const VALUE *argv)
9055 else if (argc > 1) {
9058 VALUE r_stdout = rb_ractor_stdout();
9060 rb_uninterruptible(rb_io_flush, r_stdout);
9101 for (i=0; i<argc; i++) {
9103 rb_uninterruptible(rb_p_write, inspected);
9105 return rb_p_result(argc, argv);
9126rb_obj_display(
int argc,
VALUE *argv,
VALUE self)
9130 out = (!
rb_check_arity(argc, 0, 1) ? rb_ractor_stdout() : argv[0]);
9131 rb_io_write(out, self);
9137rb_stderr_to_original_p(
VALUE err)
9139 return (err == orig_stderr ||
RFILE(orig_stderr)->fptr->
fd < 0);
9145 VALUE out = rb_ractor_stderr();
9146 if (rb_stderr_to_original_p(out)) {
9148 if (isatty(fileno(stderr))) {
9149 if (rb_w32_write_console(
rb_str_new(mesg,
len), fileno(stderr)) > 0)
return;
9152 if (fwrite(mesg,
sizeof(
char), (
size_t)
len, stderr) < (
size_t)
len) {
9169rb_write_error_str(
VALUE mesg)
9171 VALUE out = rb_ractor_stderr();
9173 if (rb_stderr_to_original_p(out)) {
9174 size_t len = (size_t)RSTRING_LEN(mesg);
9176 if (isatty(fileno(stderr))) {
9177 if (rb_w32_write_console(mesg, fileno(stderr)) > 0)
return;
9180 if (fwrite(RSTRING_PTR(mesg),
sizeof(
char),
len, stderr) <
len) {
9187 rb_io_write(out, mesg);
9192rb_stderr_tty_p(
void)
9194 if (rb_stderr_to_original_p(rb_ractor_stderr()))
9195 return isatty(fileno(stderr));
9200must_respond_to(
ID mid,
VALUE val,
ID id)
9203 rb_raise(
rb_eTypeError,
"%"PRIsVALUE
" must have %"PRIsVALUE
" method, %"PRIsVALUE
" given",
9204 rb_id2str(
id), rb_id2str(mid),
9224 must_respond_to(id_write, val,
id);
9231 return rb_ractor_stdout();
9237 must_respond_to(id_write, val,
id);
9244 return rb_ractor_stderr();
9248allocate_and_open_new_file(
VALUE klass)
9250 VALUE self = io_alloc(klass);
9251 rb_io_make_open_file(self);
9259 VALUE self = rb_protect(allocate_and_open_new_file, klass, &state);
9267 maygvl_close(descriptor, 0);
9275 io->
fd = descriptor;
9293 io->closing_ec = NULL;
9294 io->wakeup_mutex =
Qnil;
9295 io->fork_generation = GET_VM()->fork_gen;
9298 io->
encs = *encoding;
9307prep_io(
int fd,
enum rb_io_mode fmode,
VALUE klass,
const char *path)
9317 e = (fmode &
FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
9318 rb_io_ext_int_to_encs(e, NULL, &convconfig.
enc, &convconfig.
enc2, fmode);
9322#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9324 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
9325 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
9327 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.
enc2, convconfig.
ecflags);
9333 if (!io_check_tty(io)) {
9336 setmode(fd, O_BINARY);
9348 if (path && strcmp(path,
"-")) klass =
rb_cFile;
9349 return prep_io(fd, rb_io_oflags_fmode(oflags), klass, path);
9353prep_stdio(
FILE *f,
enum rb_io_mode fmode,
VALUE klass,
const char *path)
9360#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9361 fptr->
encs.
ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
9372rb_io_prep_stdin(
void)
9378rb_io_prep_stdout(
void)
9384rb_io_prep_stderr(
void)
9393 int oflags = rb_io_fmode_oflags(fptr->
mode) & ~O_EXCL;
9420 rb_io_buffer_init(&fp->
wbuf);
9421 rb_io_buffer_init(&fp->
rbuf);
9422 rb_io_buffer_init(&fp->
cbuf);
9437 fp->closing_ec = NULL;
9438 fp->wakeup_mutex =
Qnil;
9439 fp->fork_generation = GET_VM()->fork_gen;
9444rb_io_make_open_file(
VALUE obj)
9449 if (
RFILE(obj)->fptr) {
9452 RFILE(obj)->fptr = 0;
9454 fp = rb_io_fptr_new();
9456 RFILE(obj)->fptr = fp;
9504rb_io_initialize(
int argc,
VALUE *argv,
VALUE io)
9510 return io_initialize(io, fnum, vmode, opt);
9517 int fd, oflags = O_RDONLY;
9518 enum rb_io_mode fmode;
9520#if defined(HAVE_FCNTL) && defined(F_GETFL)
9530 rb_raise(rb_eArgError,
"The given fd is not accessible because RubyVM reserves it");
9532#if defined(HAVE_FCNTL) && defined(F_GETFL)
9533 oflags = fcntl(fd, F_GETFL);
9534 if (oflags == -1) rb_sys_fail(0);
9536 if (fstat(fd, &st) < 0) rb_sys_fail(0);
9539#if defined(HAVE_FCNTL) && defined(F_GETFL)
9540 ofmode = rb_io_oflags_fmode(oflags);
9552 if (rb_hash_aref(opt, sym_autoclose) ==
Qfalse) {
9556 path = rb_hash_aref(opt,
RB_ID2SYM(idPath));
9567 fp->
encs = convconfig;
9571 fp->closing_ec = NULL;
9572 fp->wakeup_mutex =
Qnil;
9573 fp->fork_generation = GET_VM()->fork_gen;
9576 if (fileno(stdin) == fd)
9578 else if (fileno(stdout) == fd)
9580 else if (fileno(stderr) == fd)
9612rb_io_set_encoding_by_bom(
VALUE io)
9618 rb_raise(rb_eArgError,
"ASCII incompatible encoding needs binmode");
9621 rb_raise(rb_eArgError,
"encoding conversion is set");
9623 else if (fptr->
encs.
enc && fptr->
encs.
enc != rb_ascii8bit_encoding()) {
9624 rb_raise(rb_eArgError,
"encoding is set to %s already",
9627 if (!io_set_encoding_by_bom(io))
return Qnil;
9628 return rb_enc_from_encoding(fptr->
encs.
enc);
9673rb_file_initialize(
int argc,
VALUE *argv,
VALUE io)
9675 if (
RFILE(io)->fptr) {
9678 VALUE fname, vmode, vperm, opt;
9679 int posargc =
rb_scan_args(argc, argv,
"12:", &fname, &vmode, &vperm, &opt);
9684 return io_initialize(io, fd, vmode, opt);
9687 return rb_open_file(io, fname, vmode, vperm, opt);
9692rb_io_s_new(
int argc,
VALUE *argv,
VALUE klass)
9697 rb_warn(
"%"PRIsVALUE
"::new() does not take block; use %"PRIsVALUE
"::open() instead",
9713rb_io_s_for_fd(
int argc,
VALUE *argv,
VALUE klass)
9716 rb_io_initialize(argc, argv, io);
9729rb_io_autoclose_p(
VALUE io)
9754rb_io_set_autoclose(
VALUE io,
VALUE autoclose)
9758 if (!
RTEST(autoclose))
9761 fptr->
mode &= ~FMODE_EXTERNAL;
9766io_wait_event(
VALUE io,
int event,
VALUE timeout,
int return_io)
9798io_wait_readable(
int argc,
VALUE *argv,
VALUE io)
9805 if (rb_io_read_pending(fptr))
return Qtrue;
9808 VALUE timeout = (argc == 1 ? argv[0] :
Qnil);
9822io_wait_writable(
int argc,
VALUE *argv,
VALUE io)
9830 VALUE timeout = (argc == 1 ? argv[0] :
Qnil);
9845io_wait_priority(
int argc,
VALUE *argv,
VALUE io)
9852 if (rb_io_read_pending(fptr))
return Qtrue;
9855 VALUE timeout = argc == 1 ? argv[0] :
Qnil;
9861wait_mode_sym(
VALUE mode)
9863 if (mode ==
ID2SYM(rb_intern(
"r"))) {
9864 return RB_WAITFD_IN;
9866 if (mode ==
ID2SYM(rb_intern(
"read"))) {
9867 return RB_WAITFD_IN;
9869 if (mode ==
ID2SYM(rb_intern(
"readable"))) {
9870 return RB_WAITFD_IN;
9872 if (mode ==
ID2SYM(rb_intern(
"w"))) {
9873 return RB_WAITFD_OUT;
9875 if (mode ==
ID2SYM(rb_intern(
"write"))) {
9876 return RB_WAITFD_OUT;
9878 if (mode ==
ID2SYM(rb_intern(
"writable"))) {
9879 return RB_WAITFD_OUT;
9881 if (mode ==
ID2SYM(rb_intern(
"rw"))) {
9882 return RB_WAITFD_IN|RB_WAITFD_OUT;
9884 if (mode ==
ID2SYM(rb_intern(
"read_write"))) {
9885 return RB_WAITFD_IN|RB_WAITFD_OUT;
9887 if (mode ==
ID2SYM(rb_intern(
"readable_writable"))) {
9888 return RB_WAITFD_IN|RB_WAITFD_OUT;
9891 rb_raise(rb_eArgError,
"unsupported mode: %"PRIsVALUE, mode);
9895io_event_from_value(
VALUE value)
9899 if (events <= 0) rb_raise(rb_eArgError,
"Events must be positive integer!");
9937 for (
int i = 0; i < argc; i += 1) {
9939 events |= wait_mode_sym(argv[i]);
9941 else if (UNDEF_P(timeout)) {
9945 rb_raise(rb_eArgError,
"timeout given more than once");
9949 if (UNDEF_P(timeout)) timeout =
Qnil;
9957 events = io_event_from_value(argv[0]);
9965 if (rb_io_read_pending(fptr)) {
9967 if (return_io)
return Qtrue;
9973 return io_wait_event(io, events, timeout, return_io);
9977argf_mark_and_move(
void *ptr)
9979 struct argf *p = ptr;
9980 rb_gc_mark_and_move(&p->filename);
9981 rb_gc_mark_and_move(&p->current_file);
9982 rb_gc_mark_and_move(&p->argv);
9983 rb_gc_mark_and_move(&p->inplace);
9984 rb_gc_mark_and_move(&p->encs.
ecopts);
9988argf_memsize(
const void *ptr)
9990 const struct argf *p = ptr;
9991 size_t size =
sizeof(*p);
9998 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
10004 p->filename =
Qnil;
10005 p->current_file =
Qnil;
10011argf_alloc(
VALUE klass)
10016 argf_init(p,
Qnil);
10026 memset(&ARGF, 0,
sizeof(ARGF));
10027 argf_init(&ARGF, argv);
10037 ARGF = argf_of(orig);
10064 ARGF.last_lineno = ARGF.lineno;
10090 return forward_current(rb_frame_this_func(), argc, argv);
10093#define next_argv() argf_next_argv(argf)
10094#define ARGF_GENERIC_INPUT_P() \
10095 (ARGF.current_file == rb_stdin && !RB_TYPE_P(ARGF.current_file, T_FILE))
10096#define ARGF_FORWARD(argc, argv) do {\
10097 if (ARGF_GENERIC_INPUT_P())\
10098 return argf_forward((argc), (argv), argf);\
10100#define NEXT_ARGF_FORWARD(argc, argv) do {\
10101 if (!next_argv()) return Qnil;\
10102 ARGF_FORWARD((argc), (argv));\
10108 VALUE file = ARGF.current_file;
10122 int stdout_binmode = 0;
10123 enum rb_io_mode fmode;
10125 VALUE r_stdout = rb_ractor_stdout();
10130 stdout_binmode = 1;
10133 if (ARGF.init_p == 0) {
10143 if (
NIL_P(ARGF.argv)) {
10146 else if (ARGF.next_p == -1 &&
RARRAY_LEN(ARGF.argv) > 0) {
10151 if (ARGF.next_p == 1) {
10152 if (ARGF.init_p == 1) argf_close(
argf);
10157 ARGF.filename = filename;
10158 filename = rb_str_encode_ospath(filename);
10160 if (RSTRING_LEN(filename) == 1 && fn[0] ==
'-') {
10162 if (ARGF.inplace) {
10163 rb_warn(
"Can't do inplace edit for stdio; skipping");
10169 int fr = rb_sysopen(filename, O_RDONLY, 0);
10171 if (ARGF.inplace) {
10173#ifndef NO_SAFE_RENAME
10184 if (!
NIL_P(ARGF.inplace)) {
10185 VALUE suffix = ARGF.inplace;
10187 if (
NIL_P(rb_str_cat_conv_enc_opts(str, RSTRING_LEN(str),
10188 RSTRING_PTR(suffix), RSTRING_LEN(suffix),
10189 rb_enc_get(suffix), 0,
Qnil))) {
10192#ifdef NO_SAFE_RENAME
10194 (void)unlink(RSTRING_PTR(str));
10195 if (rename(fn, RSTRING_PTR(str)) < 0) {
10196 rb_warn(
"Can't rename %"PRIsVALUE
" to %"PRIsVALUE
": %s, skipping file",
10197 filename, str, strerror(
errno));
10200 fr = rb_sysopen(str, O_RDONLY, 0);
10202 if (rename(fn, RSTRING_PTR(str)) < 0) {
10203 rb_warn(
"Can't rename %"PRIsVALUE
" to %"PRIsVALUE
": %s, skipping file",
10204 filename, str, strerror(
errno));
10211#ifdef NO_SAFE_RENAME
10212 rb_fatal(
"Can't do inplace edit without backup");
10214 if (unlink(fn) < 0) {
10215 rb_warn(
"Can't remove %"PRIsVALUE
": %s, skipping file",
10216 filename, strerror(
errno));
10222 fw = rb_sysopen(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666);
10223#ifndef NO_SAFE_RENAME
10226 fchmod(fw, st.st_mode);
10228 chmod(fn, st.st_mode);
10230 if (st.st_uid!=st2.st_uid || st.st_gid!=st2.st_gid) {
10233 err = fchown(fw, st.st_uid, st.st_gid);
10235 err = chown(fn, st.st_uid, st.st_gid);
10237 if (err && getuid() == 0 && st2.st_uid == 0) {
10238 const char *wkfn = RSTRING_PTR(filename);
10239 rb_warn(
"Can't set owner/group of %"PRIsVALUE
" to same as %"PRIsVALUE
": %s, skipping file",
10240 filename, str, strerror(
errno));
10243 (void)unlink(wkfn);
10253 if (!ARGF.binmode) {
10254 fmode |= DEFAULT_TEXTMODE;
10256 ARGF.current_file = prep_io(fr, fmode,
rb_cFile, fn);
10257 if (!
NIL_P(write_io)) {
10264 if (ARGF.encs.enc) {
10265 fptr->
encs = ARGF.encs;
10266 clear_codeconv(fptr);
10269 fptr->
encs.
ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
10270 if (!ARGF.binmode) {
10272#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
10273 fptr->
encs.
ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
10284 else if (ARGF.next_p == -1) {
10287 if (ARGF.inplace) {
10288 rb_warn(
"Can't do inplace edit for stdio");
10292 if (ARGF.init_p == -1) ARGF.init_p = 1;
10300 long lineno = ARGF.lineno;
10303 if (!next_argv())
return Qnil;
10304 if (ARGF_GENERIC_INPUT_P()) {
10305 line = forward_current(idGets, argc, argv);
10312 line = rb_io_getline(argc, argv, ARGF.current_file);
10314 if (
NIL_P(line) && ARGF.next_p != -1) {
10320 if (!
NIL_P(line)) {
10321 ARGF.lineno = ++lineno;
10322 ARGF.last_lineno = ARGF.lineno;
10328argf_lineno_getter(
ID id,
VALUE *var)
10331 return INT2FIX(ARGF.last_lineno);
10339 ARGF.last_lineno = ARGF.lineno = n;
10343rb_reset_argf_lineno(
long n)
10345 ARGF.last_lineno = ARGF.lineno = n;
10386 if (recv ==
argf) {
10387 return argf_gets(argc, argv,
argf);
10389 return forward(
argf, idGets, argc, argv);
10415 line = argf_getline(argc, argv,
argf);
10427 return rb_f_gets(0, 0,
argf);
10431 if (!next_argv())
return Qnil;
10433 if (
NIL_P(line) && ARGF.next_p != -1) {
10439 if (!
NIL_P(line)) {
10441 ARGF.last_lineno = ARGF.lineno;
10467rb_f_readline(
int argc,
VALUE *argv,
VALUE recv)
10469 if (recv ==
argf) {
10470 return argf_readline(argc, argv,
argf);
10472 return forward(
argf, rb_intern(
"readline"), argc, argv);
10498 if (!next_argv()) rb_eof_error();
10499 ARGF_FORWARD(argc, argv);
10500 line = argf_gets(argc, argv,
argf);
10570rb_f_readlines(
int argc,
VALUE *argv,
VALUE recv)
10572 if (recv ==
argf) {
10573 return argf_readlines(argc, argv,
argf);
10575 return forward(
argf, rb_intern(
"readlines"), argc, argv);
10599 long lineno = ARGF.lineno;
10603 while (next_argv()) {
10604 if (ARGF_GENERIC_INPUT_P()) {
10605 lines = forward_current(rb_intern(
"readlines"), argc, argv);
10608 lines = rb_io_readlines(argc, argv, ARGF.current_file);
10614 ARGF.last_lineno = ARGF.lineno;
10649 rb_last_status_clear();
10650 port = pipe_open_s(str,
"r",
FMODE_READABLE|DEFAULT_TEXTMODE, NULL);
10654 result = read_all(fptr, remain_size(fptr),
Qnil);
10656 rb_io_fptr_cleanup_all(fptr);
10662#ifdef HAVE_SYS_SELECT_H
10663#include <sys/select.h>
10677 if (!
NIL_P(read)) {
10682 if (READ_DATA_PENDING(fptr) || READ_CHAR_PENDING(fptr)) {
10686 if (max < fptr->fd) max = fptr->
fd;
10689 timerec.tv_sec = timerec.tv_usec = 0;
10697 if (!
NIL_P(write)) {
10703 if (max < fptr->fd) max = fptr->
fd;
10710 if (!
NIL_P(except)) {
10714 VALUE write_io = GetWriteIO(io);
10717 if (max < fptr->fd) max = fptr->
fd;
10718 if (io != write_io) {
10721 if (max < fptr->fd) max = fptr->
fd;
10736 if (!pending && n == 0)
return Qnil;
10761 VALUE write_io = GetWriteIO(io);
10774 VALUE write_io = GetWriteIO(io);
10779 else if (io != write_io) {
10792 VALUE read, write, except;
10798select_call(
VALUE arg)
10802 return select_internal(p->read, p->write, p->except, p->timeout, p->fdsets);
10806select_end(
VALUE arg)
10811 for (i = 0; i < numberof(p->fdsets); ++i)
10816static VALUE sym_normal, sym_sequential, sym_random,
10817 sym_willneed, sym_dontneed, sym_noreuse;
10819#ifdef HAVE_POSIX_FADVISE
10820struct io_advise_struct {
10828io_advise_internal(
void *arg)
10830 struct io_advise_struct *ptr = arg;
10831 return posix_fadvise(ptr->fd, ptr->offset, ptr->len, ptr->advice);
10835io_advise_sym_to_const(
VALUE sym)
10837#ifdef POSIX_FADV_NORMAL
10838 if (sym == sym_normal)
10839 return INT2NUM(POSIX_FADV_NORMAL);
10842#ifdef POSIX_FADV_RANDOM
10843 if (sym == sym_random)
10844 return INT2NUM(POSIX_FADV_RANDOM);
10847#ifdef POSIX_FADV_SEQUENTIAL
10848 if (sym == sym_sequential)
10849 return INT2NUM(POSIX_FADV_SEQUENTIAL);
10852#ifdef POSIX_FADV_WILLNEED
10853 if (sym == sym_willneed)
10854 return INT2NUM(POSIX_FADV_WILLNEED);
10857#ifdef POSIX_FADV_DONTNEED
10858 if (sym == sym_dontneed)
10859 return INT2NUM(POSIX_FADV_DONTNEED);
10862#ifdef POSIX_FADV_NOREUSE
10863 if (sym == sym_noreuse)
10864 return INT2NUM(POSIX_FADV_NOREUSE);
10871do_io_advise(
rb_io_t *fptr,
VALUE advice, rb_off_t offset, rb_off_t
len)
10874 struct io_advise_struct ias;
10877 num_adv = io_advise_sym_to_const(advice);
10883 if (
NIL_P(num_adv))
10887 ias.advice =
NUM2INT(num_adv);
10888 ias.offset = offset;
10891 rv = (int)rb_io_blocking_region(fptr, io_advise_internal, &ias);
10892 if (rv && rv != ENOSYS) {
10895 VALUE message = rb_sprintf(
"%"PRIsVALUE
" "
10899 fptr->
pathv, offset,
len, advice);
10909advice_arg_check(
VALUE advice)
10914 if (advice != sym_normal &&
10915 advice != sym_sequential &&
10916 advice != sym_random &&
10917 advice != sym_willneed &&
10918 advice != sym_dontneed &&
10919 advice != sym_noreuse) {
10920 rb_raise(
rb_eNotImpError,
"Unsupported advice: %+"PRIsVALUE, advice);
10958rb_io_advise(
int argc,
VALUE *argv,
VALUE io)
10965 advice_arg_check(advice);
10967 io = GetWriteIO(io);
10973#ifdef HAVE_POSIX_FADVISE
10974 return do_io_advise(fptr, advice,
off, l);
10976 ((void)
off, (
void)l);
10988 return isinf(f) && 0 < f;
11144rb_f_select(
int argc,
VALUE *argv,
VALUE obj)
11147 if (scheduler !=
Qnil) {
11150 if (!UNDEF_P(result))
return result;
11158 rb_scan_args(argc, argv,
"13", &args.read, &args.write, &args.except, &timeout);
11159 if (
NIL_P(timeout) || is_pos_inf(timeout)) {
11164 args.timeout = &timerec;
11167 for (i = 0; i < numberof(args.fdsets); ++i)
11173#ifdef IOCTL_REQ_TYPE
11174 typedef IOCTL_REQ_TYPE ioctl_req_t;
11176 typedef int ioctl_req_t;
11177# define NUM2IOCTLREQ(num) ((int)NUM2LONG(num))
11188nogvl_ioctl(
void *ptr)
11190 struct ioctl_arg *arg = ptr;
11192 return (
VALUE)ioctl(arg->fd, arg->cmd, arg->narg);
11196do_ioctl(
struct rb_io *io, ioctl_req_t cmd,
long narg)
11199 struct ioctl_arg arg;
11205 retval = (int)rb_io_blocking_region(io, nogvl_ioctl, &arg);
11211#define DEFAULT_IOCTL_NARG_LEN (256)
11213#if defined(__linux__) && defined(_IOC_SIZE)
11215linux_iocparm_len(ioctl_req_t cmd)
11219 if ((cmd & 0xFFFF0000) == 0) {
11221 return DEFAULT_IOCTL_NARG_LEN;
11224 len = _IOC_SIZE(cmd);
11227 if (
len < DEFAULT_IOCTL_NARG_LEN)
11228 len = DEFAULT_IOCTL_NARG_LEN;
11236ioctl_narg_len(ioctl_req_t cmd)
11242#define IOCPARM_LEN(x) (((x) >> 16) & IOCPARM_MASK)
11246 len = IOCPARM_LEN(cmd);
11247#elif defined(__linux__) && defined(_IOC_SIZE)
11248 len = linux_iocparm_len(cmd);
11251 len = DEFAULT_IOCTL_NARG_LEN;
11260typedef long fcntl_arg_t;
11263typedef int fcntl_arg_t;
11267fcntl_narg_len(ioctl_req_t cmd)
11274 len =
sizeof(fcntl_arg_t);
11282#ifdef F_DUPFD_CLOEXEC
11283 case F_DUPFD_CLOEXEC:
11284 len =
sizeof(fcntl_arg_t);
11294 len =
sizeof(fcntl_arg_t);
11304 len =
sizeof(fcntl_arg_t);
11314 len =
sizeof(fcntl_arg_t);
11319 len =
sizeof(
struct f_owner_ex);
11324 len =
sizeof(
struct f_owner_ex);
11329 len =
sizeof(
struct flock);
11334 len =
sizeof(
struct flock);
11339 len =
sizeof(
struct flock);
11359 len =
sizeof(fcntl_arg_t);
11369 len =
sizeof(fcntl_arg_t);
11374 len =
sizeof(fcntl_arg_t);
11387fcntl_narg_len(ioctl_req_t cmd)
11393#define NARG_SENTINEL 17
11396setup_narg(ioctl_req_t cmd,
VALUE *argp,
long (*narg_len)(ioctl_req_t))
11407 else if (arg ==
Qtrue) {
11421 len = narg_len(cmd);
11422 rb_str_modify(arg);
11424 slen = RSTRING_LEN(arg);
11426 if (slen <
len+1) {
11427 rb_str_resize(arg,
len+1);
11428 MEMZERO(RSTRING_PTR(arg)+slen,
char,
len-slen);
11432 ptr = RSTRING_PTR(arg);
11433 ptr[slen - 1] = NARG_SENTINEL;
11442finish_narg(
int retval,
VALUE arg,
const rb_io_t *fptr)
11444 if (retval < 0) rb_sys_fail_path(fptr->
pathv);
11449 if (ptr[slen-1] != NARG_SENTINEL)
11450 rb_raise(rb_eArgError,
"return value overflowed string");
11451 ptr[slen-1] =
'\0';
11461 ioctl_req_t cmd = NUM2IOCTLREQ(req);
11466 narg = setup_narg(cmd, &arg, ioctl_narg_len);
11468 retval = do_ioctl(fptr, cmd, narg);
11469 return finish_narg(retval, arg, fptr);
11496 return rb_ioctl(io, req, arg);
11499#define rb_io_ioctl rb_f_notimplement
11510nogvl_fcntl(
void *ptr)
11512 struct fcntl_arg *arg = ptr;
11514#if defined(F_DUPFD)
11515 if (arg->cmd == F_DUPFD)
11518 return (
VALUE)fcntl(arg->fd, arg->cmd, arg->narg);
11522do_fcntl(
struct rb_io *io,
int cmd,
long narg)
11525 struct fcntl_arg arg;
11531 retval = (int)rb_io_blocking_region(io, nogvl_fcntl, &arg);
11532 if (retval != -1) {
11534#if defined(F_DUPFD)
11537#if defined(F_DUPFD_CLOEXEC)
11538 case F_DUPFD_CLOEXEC:
11555 narg = setup_narg(cmd, &arg, fcntl_narg_len);
11557 retval = do_fcntl(fptr, cmd, narg);
11558 return finish_narg(retval, arg, fptr);
11584 return rb_fcntl(io, req, arg);
11587#define rb_io_fcntl rb_f_notimplement
11590#if defined(HAVE_SYSCALL) || defined(HAVE___SYSCALL)
11622#if SIZEOF_VOIDP == 8 && defined(HAVE___SYSCALL) && SIZEOF_INT != 8
11623# define SYSCALL __syscall
11624# define NUM2SYSCALLID(x) NUM2LONG(x)
11625# define RETVAL2NUM(x) LONG2NUM(x)
11626# if SIZEOF_LONG == 8
11627 long num, retval = -1;
11628# elif SIZEOF_LONG_LONG == 8
11629 long long num, retval = -1;
11631# error ---->> it is asserted that __syscall takes the first argument and returns retval in 64bit signed integer. <<----
11633#elif defined(__linux__)
11634# define SYSCALL syscall
11635# define NUM2SYSCALLID(x) NUM2LONG(x)
11636# define RETVAL2NUM(x) LONG2NUM(x)
11644 long num, retval = -1;
11646# define SYSCALL syscall
11647# define NUM2SYSCALLID(x) NUM2INT(x)
11648# define RETVAL2NUM(x) INT2NUM(x)
11649 int num, retval = -1;
11655 "We plan to remove a syscall function at future release. DL(Fiddle) provides safer alternative.");
11659 rb_raise(rb_eArgError,
"too few arguments for syscall");
11660 if (argc > numberof(arg))
11661 rb_raise(rb_eArgError,
"too many arguments for syscall");
11662 num = NUM2SYSCALLID(argv[0]); ++argv;
11663 for (i = argc - 1; i--; ) {
11678 retval = SYSCALL(num);
11681 retval = SYSCALL(num, arg[0]);
11684 retval = SYSCALL(num, arg[0],arg[1]);
11687 retval = SYSCALL(num, arg[0],arg[1],arg[2]);
11690 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3]);
11693 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4]);
11696 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5]);
11699 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6]);
11705 return RETVAL2NUM(retval);
11707#undef NUM2SYSCALLID
11711#define rb_f_syscall rb_f_notimplement
11715io_new_instance(
VALUE args)
11721find_encoding(
VALUE v)
11724 if (!enc)
rb_warn(
"Unsupported encoding %"PRIsVALUE
" ignored", v);
11736 enc2 = find_encoding(v1);
11739 if (RSTRING_LEN(tmp) == 1 && RSTRING_PTR(tmp)[0] ==
'-') {
11745 enc = find_encoding(v2);
11752 enc = find_encoding(v2);
11758 if (enc2 == rb_ascii8bit_encoding()) {
11763 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11769 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
11770 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11775 if (!
NIL_P(tmp) && rb_enc_asciicompat(enc = rb_enc_get(tmp))) {
11776 parse_mode_enc(RSTRING_PTR(tmp), enc, &enc, &enc2, NULL);
11777 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11781 rb_io_ext_int_to_encs(find_encoding(v1), NULL, &enc, &enc2, 0);
11782 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11787 validate_enc_binmode(&fptr->
mode, ecflags, enc, enc2);
11792 clear_codeconv(fptr);
11804io_encoding_set_v(
VALUE v)
11807 io_encoding_set(arg->fptr, arg->v1, arg->v2, arg->opt);
11812pipe_pair_close(
VALUE rw)
11815 return rb_ensure(io_close, rwp[0], io_close, rwp[1]);
11898rb_io_s_pipe(
int argc,
VALUE *argv,
VALUE klass)
11900 int pipes[2], state;
11901 VALUE r, w, args[3], v1, v2;
11905 enum rb_io_mode fmode = 0;
11908 argc =
rb_scan_args(argc, argv,
"02:", &v1, &v2, &opt);
11915 r = rb_protect(io_new_instance, (
VALUE)args, &state);
11919 rb_jump_tag(state);
11923 ies_args.fptr = fptr;
11926 ies_args.opt = opt;
11927 rb_protect(io_encoding_set_v, (
VALUE)&ies_args, &state);
11931 rb_jump_tag(state);
11936 w = rb_protect(io_new_instance, (
VALUE)args, &state);
11940 rb_jump_tag(state);
11945 extract_binmode(opt, &fmode);
11952#if DEFAULT_TEXTMODE
11954 fptr->
mode &= ~FMODE_TEXTMODE;
11955 setmode(fptr->
fd, O_BINARY);
11957#if RUBY_CRLF_ENVIRONMENT
11963 fptr->
mode |= fmode;
11964#if DEFAULT_TEXTMODE
11966 fptr2->
mode &= ~FMODE_TEXTMODE;
11967 setmode(fptr2->
fd, O_BINARY);
11970 fptr2->
mode |= fmode;
12004 else if (!
NIL_P(v = rb_hash_aref(opt, sym_open_args))) {
12007 v = rb_to_array_type(v);
12012 arg->io = rb_io_open(klass, path, vmode, vperm, opt);
12016io_s_foreach(
VALUE v)
12021 if (arg->limit == 0)
12022 rb_raise(rb_eArgError,
"invalid limit: 0 for foreach");
12023 while (!
NIL_P(str = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, arg->io))) {
12111rb_io_s_foreach(
int argc,
VALUE *argv,
VALUE self)
12114 int orig_argc = argc;
12118 argc =
rb_scan_args(argc, argv,
"12:", NULL, NULL, NULL, &opt);
12120 extract_getline_args(argc-1, argv+1, &garg);
12121 open_key_args(self, argc, argv, opt, &arg);
12123 extract_getline_opts(opt, &garg);
12124 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12125 return rb_ensure(io_s_foreach, (
VALUE)&garg, rb_io_close, arg.io);
12129io_s_readlines(
VALUE v)
12132 return io_readlines(arg, arg->io);
12189rb_io_s_readlines(
int argc,
VALUE *argv,
VALUE io)
12195 argc =
rb_scan_args(argc, argv,
"12:", NULL, NULL, NULL, &opt);
12196 extract_getline_args(argc-1, argv+1, &garg);
12197 open_key_args(io, argc, argv, opt, &arg);
12199 extract_getline_opts(opt, &garg);
12200 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12201 return rb_ensure(io_s_readlines, (
VALUE)&garg, rb_io_close, arg.io);
12208 return io_read(arg->argc, arg->argv, arg->io);
12218seek_before_access(
VALUE argp)
12222 return rb_io_seek(arg->io, arg->offset, arg->mode);
12268rb_io_s_read(
int argc,
VALUE *argv,
VALUE io)
12274 argc =
rb_scan_args(argc, argv,
"13:", NULL, NULL, &offset, NULL, &opt);
12276 rb_raise(rb_eArgError,
"negative offset %ld given",
off);
12278 open_key_args(io, argc, argv, opt, &arg);
12280 if (!
NIL_P(offset)) {
12284 sarg.offset = offset;
12285 sarg.mode = SEEK_SET;
12286 rb_protect(seek_before_access, (
VALUE)&sarg, &state);
12289 rb_jump_tag(state);
12291 if (arg.argc == 2) arg.argc = 1;
12310rb_io_s_binread(
int argc,
VALUE *argv,
VALUE io)
12325 convconfig.
enc = rb_ascii8bit_encoding();
12326 arg.io = rb_io_open_generic(io, argv[0], oflags, fmode, &convconfig, 0);
12329 arg.argc = (argc > 1) ? 1 : 0;
12330 if (!
NIL_P(offset)) {
12334 sarg.offset = offset;
12335 sarg.mode = SEEK_SET;
12336 rb_protect(seek_before_access, (
VALUE)&sarg, &state);
12339 rb_jump_tag(state);
12346io_s_write0(
VALUE v)
12349 return io_write(arg->io,arg->str,arg->nosync);
12353io_s_write(
int argc,
VALUE *argv,
VALUE klass,
int binary)
12355 VALUE string, offset, opt;
12359 rb_scan_args(argc, argv,
"21:", NULL, &
string, &offset, &opt);
12361 if (
NIL_P(opt)) opt = rb_hash_new();
12362 else opt = rb_hash_dup(opt);
12365 if (
NIL_P(rb_hash_aref(opt,sym_mode))) {
12366 int mode = O_WRONLY|O_CREAT;
12368 if (binary) mode |= O_BINARY;
12370 if (
NIL_P(offset)) mode |= O_TRUNC;
12371 rb_hash_aset(opt,sym_mode,
INT2NUM(mode));
12373 open_key_args(klass, argc, argv, opt, &arg);
12376 if (binary) rb_io_binmode_m(arg.io);
12380 if (!
NIL_P(offset)) {
12384 sarg.offset = offset;
12385 sarg.mode = SEEK_SET;
12386 rb_protect(seek_before_access, (
VALUE)&sarg, &state);
12389 rb_jump_tag(state);
12397 return rb_ensure(io_s_write0, (
VALUE)&warg, rb_io_close, arg.io);
12445rb_io_s_write(
int argc,
VALUE *argv,
VALUE io)
12447 return io_s_write(argc, argv, io, 0);
12464rb_io_s_binwrite(
int argc,
VALUE *argv,
VALUE io)
12466 return io_s_write(argc, argv, io, 1);
12472 rb_off_t copy_length;
12473 rb_off_t src_offset;
12477 unsigned close_src : 1;
12478 unsigned close_dst : 1;
12481 const char *syserr;
12482 const char *notimp;
12484 struct stat src_stat;
12485 struct stat dst_stat;
12486#ifdef HAVE_FCOPYFILE
12487 copyfile_state_t copyfile_state;
12492exec_interrupts(
void *arg)
12495 rb_thread_execute_interrupts(th);
12509#if defined(ERESTART)
12514 rb_thread_execute_interrupts(stp->th);
12533fiber_scheduler_wait_for(
void * _arguments)
12543# define IOWAIT_SYSCALL "poll"
12544STATIC_ASSERT(pollin_expected, POLLIN == RB_WAITFD_IN);
12545STATIC_ASSERT(pollout_expected, POLLOUT == RB_WAITFD_OUT);
12550 if (scheduler !=
Qnil) {
12553 return RTEST(args.result);
12557 if (fd == -1)
return 0;
12562 fds.events = events;
12564 int timeout_milliseconds = -1;
12567 timeout_milliseconds = (int)(timeout->tv_sec * 1000) + (int)(timeout->tv_usec / 1000);
12570 return poll(&fds, 1, timeout_milliseconds);
12573# define IOWAIT_SYSCALL "select"
12578 if (scheduler !=
Qnil) {
12581 return RTEST(args.result);
12601 case RB_WAITFD_OUT:
12605 VM_UNREACHABLE(nogvl_wait_for);
12625 ret = nogvl_wait_for(stp->th, stp->src_fptr, RB_WAITFD_IN, NULL);
12627 }
while (ret < 0 && maygvl_copy_stream_continue_p(has_gvl, stp));
12630 stp->syserr = IOWAIT_SYSCALL;
12631 stp->error_no =
errno;
12643 ret = nogvl_wait_for(stp->th, stp->dst_fptr, RB_WAITFD_OUT, NULL);
12644 }
while (ret < 0 && maygvl_copy_stream_continue_p(0, stp));
12647 stp->syserr = IOWAIT_SYSCALL;
12648 stp->error_no =
errno;
12654#ifdef USE_COPY_FILE_RANGE
12657simple_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)
12659#ifdef HAVE_COPY_FILE_RANGE
12660 return copy_file_range(in_fd, in_offset, out_fd, out_offset, count, flags);
12662 return syscall(__NR_copy_file_range, in_fd, in_offset, out_fd, out_offset, count, flags);
12671 rb_off_t copy_length, src_offset, *src_offset_ptr;
12673 if (!S_ISREG(stp->src_stat.st_mode))
12676 src_size = stp->src_stat.st_size;
12677 src_offset = stp->src_offset;
12678 if (src_offset >= (rb_off_t)0) {
12679 src_offset_ptr = &src_offset;
12682 src_offset_ptr = NULL;
12685 copy_length = stp->copy_length;
12686 if (copy_length < (rb_off_t)0) {
12687 if (src_offset < (rb_off_t)0) {
12688 rb_off_t current_offset;
12690 current_offset = lseek(stp->src_fptr->
fd, 0, SEEK_CUR);
12691 if (current_offset < (rb_off_t)0 &&
errno) {
12692 stp->syserr =
"lseek";
12693 stp->error_no =
errno;
12694 return (
int)current_offset;
12696 copy_length = src_size - current_offset;
12699 copy_length = src_size - src_offset;
12703 retry_copy_file_range:
12704# if SIZEOF_OFF_T > SIZEOF_SIZE_T
12706 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
12708 ss = (ssize_t)copy_length;
12710 ss = simple_copy_file_range(stp->src_fptr->
fd, src_offset_ptr, stp->dst_fptr->
fd, NULL, ss, 0);
12714 if (0 < copy_length) {
12715 goto retry_copy_file_range;
12719 if (maygvl_copy_stream_continue_p(0, stp)) {
12720 goto retry_copy_file_range;
12734#if EWOULDBLOCK != EAGAIN
12738 int ret = nogvl_copy_stream_wait_write(stp);
12739 if (ret < 0)
return ret;
12741 goto retry_copy_file_range;
12745 int flags = fcntl(stp->dst_fptr->
fd, F_GETFL);
12747 if (flags != -1 && flags & O_APPEND) {
12753 stp->syserr =
"copy_file_range";
12754 stp->error_no =
errno;
12761#ifdef HAVE_FCOPYFILE
12765 rb_off_t cur, ss = 0;
12766 const rb_off_t src_offset = stp->src_offset;
12769 if (stp->copy_length >= (rb_off_t)0) {
12774 if (!S_ISREG(stp->src_stat.st_mode))
12777 if (!S_ISREG(stp->dst_stat.st_mode))
12779 if (lseek(stp->dst_fptr->
fd, 0, SEEK_CUR) > (rb_off_t)0)
12781 if (fcntl(stp->dst_fptr->
fd, F_GETFL) & O_APPEND) {
12784 rb_off_t end = lseek(stp->dst_fptr->
fd, 0, SEEK_END);
12785 lseek(stp->dst_fptr->
fd, 0, SEEK_SET);
12786 if (end > (rb_off_t)0)
return 0;
12789 if (src_offset > (rb_off_t)0) {
12794 cur = lseek(stp->src_fptr->
fd, 0, SEEK_CUR);
12795 if (cur < (rb_off_t)0 &&
errno) {
12796 stp->error_no =
errno;
12801 r = lseek(stp->src_fptr->
fd, src_offset, SEEK_SET);
12802 if (r < (rb_off_t)0 &&
errno) {
12803 stp->error_no =
errno;
12808 stp->copyfile_state = copyfile_state_alloc();
12809 ret = fcopyfile(stp->src_fptr->
fd, stp->dst_fptr->
fd, stp->copyfile_state, COPYFILE_DATA);
12810 copyfile_state_get(stp->copyfile_state, COPYFILE_STATE_COPIED, &ss);
12814 if (src_offset > (rb_off_t)0) {
12818 r = lseek(stp->src_fptr->
fd, cur, SEEK_SET);
12819 if (r < (rb_off_t)0 &&
errno) {
12820 stp->error_no =
errno;
12832 stp->syserr =
"fcopyfile";
12833 stp->error_no =
errno;
12840#ifdef HAVE_SENDFILE
12843# define USE_SENDFILE
12845# ifdef HAVE_SYS_SENDFILE_H
12846# include <sys/sendfile.h>
12850simple_sendfile(
int out_fd,
int in_fd, rb_off_t *offset, rb_off_t count)
12852 return sendfile(out_fd, in_fd, offset, (
size_t)count);
12855# elif 0 || defined(__APPLE__)
12859# define USE_SENDFILE
12862simple_sendfile(
int out_fd,
int in_fd, rb_off_t *offset, rb_off_t count)
12865 rb_off_t pos = offset ? *offset : lseek(in_fd, 0, SEEK_CUR);
12868 r = sendfile(in_fd, out_fd, pos, &count, NULL, 0);
12871 r = sendfile(in_fd, out_fd, pos, (
size_t)count, NULL, &sbytes, 0);
12873 if (r != 0 && sbytes == 0)
return r;
12878 lseek(in_fd, sbytes, SEEK_CUR);
12880 return (ssize_t)sbytes;
12893 rb_off_t copy_length;
12894 rb_off_t src_offset;
12897 if (!S_ISREG(stp->src_stat.st_mode))
12900 src_size = stp->src_stat.st_size;
12902 if ((stp->dst_stat.st_mode & S_IFMT) != S_IFSOCK)
12906 src_offset = stp->src_offset;
12907 use_pread = src_offset >= (rb_off_t)0;
12909 copy_length = stp->copy_length;
12910 if (copy_length < (rb_off_t)0) {
12912 copy_length = src_size - src_offset;
12916 cur = lseek(stp->src_fptr->
fd, 0, SEEK_CUR);
12917 if (cur < (rb_off_t)0 &&
errno) {
12918 stp->syserr =
"lseek";
12919 stp->error_no =
errno;
12922 copy_length = src_size - cur;
12927# if SIZEOF_OFF_T > SIZEOF_SIZE_T
12929 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
12931 ss = (ssize_t)copy_length;
12934 ss = simple_sendfile(stp->dst_fptr->
fd, stp->src_fptr->
fd, &src_offset, ss);
12937 ss = simple_sendfile(stp->dst_fptr->
fd, stp->src_fptr->
fd, NULL, ss);
12942 if (0 < copy_length) {
12943 goto retry_sendfile;
12947 if (maygvl_copy_stream_continue_p(0, stp))
12948 goto retry_sendfile;
12961#if EWOULDBLOCK != EAGAIN
12974 ret = maygvl_copy_stream_wait_read(0, stp);
12975 if (ret < 0)
return ret;
12977 ret = nogvl_copy_stream_wait_write(stp);
12978 if (ret < 0)
return ret;
12980 goto retry_sendfile;
12982 stp->syserr =
"sendfile";
12983 stp->error_no =
errno;
12991maygvl_read(
int has_gvl,
rb_io_t *fptr,
void *buf,
size_t count)
12994 return rb_io_read_memory(fptr, buf, count);
12996 return read(fptr->
fd, buf, count);
13000maygvl_copy_stream_read(
int has_gvl,
struct copy_stream_struct *stp,
char *buf,
size_t len, rb_off_t offset)
13004 if (offset < (rb_off_t)0) {
13005 ss = maygvl_read(has_gvl, stp->src_fptr, buf,
len);
13008 ss = pread(stp->src_fptr->
fd, buf,
len, offset);
13014 if (maygvl_copy_stream_continue_p(has_gvl, stp))
13018#if EWOULDBLOCK != EAGAIN
13022 int ret = maygvl_copy_stream_wait_read(has_gvl, stp);
13023 if (ret < 0)
return ret;
13028 stp->notimp =
"pread";
13032 stp->syserr = offset < (rb_off_t)0 ?
"read" :
"pread";
13033 stp->error_no =
errno;
13044 ss = write(stp->dst_fptr->
fd, buf+
off,
len);
13046 if (maygvl_copy_stream_continue_p(0, stp))
13048 if (io_again_p(
errno)) {
13049 int ret = nogvl_copy_stream_wait_write(stp);
13050 if (ret < 0)
return ret;
13053 stp->syserr =
"write";
13054 stp->error_no =
errno;
13071 rb_off_t copy_length;
13072 rb_off_t src_offset;
13076 copy_length = stp->copy_length;
13077 use_eof = copy_length < (rb_off_t)0;
13078 src_offset = stp->src_offset;
13079 use_pread = src_offset >= (rb_off_t)0;
13081 if (use_pread && stp->close_src) {
13084 r = lseek(stp->src_fptr->
fd, src_offset, SEEK_SET);
13085 if (r < (rb_off_t)0 &&
errno) {
13086 stp->syserr =
"lseek";
13087 stp->error_no =
errno;
13090 src_offset = (rb_off_t)-1;
13094 while (use_eof || 0 < copy_length) {
13095 if (!use_eof && copy_length < (rb_off_t)
sizeof(buf)) {
13096 len = (size_t)copy_length;
13102 ss = maygvl_copy_stream_read(0, stp, buf,
len, src_offset);
13107 ss = maygvl_copy_stream_read(0, stp, buf,
len, (rb_off_t)-1);
13112 ret = nogvl_copy_stream_write(stp, buf, ss);
13122nogvl_copy_stream_func(
void *arg)
13125#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13129#ifdef USE_COPY_FILE_RANGE
13130 ret = nogvl_copy_file_range(stp);
13135#ifdef HAVE_FCOPYFILE
13136 ret = nogvl_fcopyfile(stp);
13142 ret = nogvl_copy_stream_sendfile(stp);
13147 nogvl_copy_stream_read_write(stp);
13149#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13156copy_stream_fallback_body(
VALUE arg)
13159 const int buflen = 16*1024;
13162 rb_off_t rest = stp->copy_length;
13163 rb_off_t
off = stp->src_offset;
13164 ID read_method = id_readpartial;
13166 if (!stp->src_fptr) {
13168 read_method = id_read;
13175 rb_str_make_independent(buf);
13176 if (stp->copy_length < (rb_off_t)0) {
13181 rb_str_resize(buf, 0);
13184 l = buflen < rest ? buflen : (long)rest;
13186 if (!stp->src_fptr) {
13189 if (read_method == id_read &&
NIL_P(rc))
13194 rb_str_resize(buf, buflen);
13195 ss = maygvl_copy_stream_read(1, stp, RSTRING_PTR(buf), l,
off);
13196 rb_str_resize(buf, ss > 0 ? ss : 0);
13201 if (
off >= (rb_off_t)0)
13204 n = rb_io_write(stp->dst, buf);
13206 stp->total += numwrote;
13208 if (read_method == id_read && RSTRING_LEN(buf) == 0) {
13219 if (!stp->src_fptr && stp->src_offset >= (rb_off_t)0) {
13220 rb_raise(rb_eArgError,
"cannot specify src_offset for non-IO");
13229copy_stream_body(
VALUE arg)
13232 VALUE src_io = stp->src, dst_io = stp->dst;
13233 const int common_oflags = 0
13243 if (src_io ==
argf ||
13247 stp->src_fptr = NULL;
13252 if (!
NIL_P(tmp_io)) {
13259 args[1] =
INT2NUM(O_RDONLY|common_oflags);
13262 stp->close_src = 1;
13267 stat_ret = fstat(stp->src_fptr->
fd, &stp->src_stat);
13268 if (stat_ret < 0) {
13269 stp->syserr =
"fstat";
13270 stp->error_no =
errno;
13275 if (dst_io ==
argf ||
13279 stp->dst_fptr = NULL;
13284 if (!
NIL_P(tmp_io)) {
13285 dst_io = GetWriteIO(tmp_io);
13291 args[1] =
INT2NUM(O_WRONLY|O_CREAT|O_TRUNC|common_oflags);
13295 stp->close_dst = 1;
13298 dst_io = GetWriteIO(dst_io);
13304 stat_ret = fstat(stp->dst_fptr->
fd, &stp->dst_stat);
13305 if (stat_ret < 0) {
13306 stp->syserr =
"fstat";
13307 stp->error_no =
errno;
13314 SET_BINARY_MODE_WITH_SEEK_CUR(stp->src_fptr);
13317 io_ascii8bit_binmode(stp->dst_fptr);
13319 if (stp->src_offset < (rb_off_t)0 && stp->src_fptr && stp->src_fptr->
rbuf.
len) {
13322 if (stp->copy_length >= (rb_off_t)0 && stp->copy_length < (rb_off_t)
len) {
13323 len = (size_t)stp->copy_length;
13326 rb_str_resize(str,
len);
13327 read_buffered_data(RSTRING_PTR(str),
len, stp->src_fptr);
13328 if (stp->dst_fptr) {
13329 if (io_binwrite(RSTRING_PTR(str), RSTRING_LEN(str), stp->dst_fptr, 0) < 0)
13330 rb_sys_fail_on_write(stp->dst_fptr);
13333 rb_io_write(dst_io, str);
13334 rb_str_resize(str, 0);
13336 if (stp->copy_length >= (rb_off_t)0)
13337 stp->copy_length -=
len;
13340 if (stp->dst_fptr && io_fflush(stp->dst_fptr) < 0) {
13344 if (stp->copy_length == 0)
13347 if (stp->src_fptr == NULL || stp->dst_fptr == NULL) {
13348 return copy_stream_fallback(stp);
13351 IO_WITHOUT_GVL(nogvl_copy_stream_func, stp);
13356copy_stream_finalize(
VALUE arg)
13360#ifdef HAVE_FCOPYFILE
13361 if (stp->copyfile_state) {
13362 copyfile_state_free(stp->copyfile_state);
13366 if (stp->close_src) {
13367 rb_io_close_m(stp->src);
13369 if (stp->close_dst) {
13370 rb_io_close_m(stp->dst);
13433rb_io_s_copy_stream(
int argc,
VALUE *argv,
VALUE io)
13435 VALUE src, dst, length, src_offset;
13440 rb_scan_args(argc, argv,
"22", &src, &dst, &length, &src_offset);
13445 st.src_fptr = NULL;
13446 st.dst_fptr = NULL;
13449 st.copy_length = (rb_off_t)-1;
13451 st.copy_length =
NUM2OFFT(length);
13453 if (
NIL_P(src_offset))
13454 st.src_offset = (rb_off_t)-1;
13456 st.src_offset =
NUM2OFFT(src_offset);
13475rb_io_external_encoding(
VALUE io)
13480 return rb_enc_from_encoding(fptr->
encs.
enc2);
13484 return rb_enc_from_encoding(fptr->
encs.
enc);
13487 return rb_enc_from_encoding(io_read_encoding(fptr));
13503rb_io_internal_encoding(
VALUE io)
13508 return rb_enc_from_encoding(io_read_encoding(fptr));
13542rb_io_set_encoding(
int argc,
VALUE *argv,
VALUE io)
13548 return forward(io, id_set_encoding, argc, argv);
13551 argc =
rb_scan_args(argc, argv,
"11:", &v1, &v2, &opt);
13553 io_encoding_set(fptr, v1, v2, opt);
13558rb_stdio_set_default_encoding(
void)
13563 if (isatty(fileno(stdin))) {
13565 rb_encoding *internal = rb_default_internal_encoding();
13566 if (!internal) internal = rb_default_external_encoding();
13568 rb_enc_from_encoding(external),
13569 rb_enc_from_encoding(internal),
13574 rb_io_set_encoding(1, &val,
rb_stdin);
13575 rb_io_set_encoding(1, &val,
rb_stdout);
13576 rb_io_set_encoding(1, &val,
rb_stderr);
13580global_argf_p(
VALUE arg)
13582 return arg ==
argf;
13585typedef VALUE (*argf_encoding_func)(
VALUE io);
13588argf_encoding(
VALUE argf, argf_encoding_func func)
13590 if (!
RTEST(ARGF.current_file)) {
13591 return rb_enc_default_external();
13615 return argf_encoding(
argf, rb_io_external_encoding);
13634 return argf_encoding(
argf, rb_io_internal_encoding);
13673 if (!next_argv()) {
13674 rb_raise(rb_eArgError,
"no stream to set encoding");
13676 rb_io_set_encoding(argc, argv, ARGF.current_file);
13678 ARGF.encs = fptr->
encs;
13697 if (!next_argv()) {
13698 rb_raise(rb_eArgError,
"no stream to tell");
13700 ARGF_FORWARD(0, 0);
13701 return rb_io_tell(ARGF.current_file);
13714 if (!next_argv()) {
13715 rb_raise(rb_eArgError,
"no stream to seek");
13717 ARGF_FORWARD(argc, argv);
13718 return rb_io_seek_m(argc, argv, ARGF.current_file);
13735 if (!next_argv()) {
13736 rb_raise(rb_eArgError,
"no stream to set position");
13738 ARGF_FORWARD(1, &offset);
13739 return rb_io_set_pos(ARGF.current_file, offset);
13760 if (!next_argv()) {
13761 rb_raise(rb_eArgError,
"no stream to rewind");
13763 ARGF_FORWARD(0, 0);
13764 old_lineno =
RFILE(ARGF.current_file)->fptr->lineno;
13765 ret = rb_io_rewind(ARGF.current_file);
13766 if (!global_argf_p(
argf)) {
13767 ARGF.last_lineno = ARGF.lineno -= old_lineno;
13785 if (!next_argv()) {
13786 rb_raise(rb_eArgError,
"no stream");
13788 ARGF_FORWARD(0, 0);
13789 return rb_io_fileno(ARGF.current_file);
13808 ARGF_FORWARD(0, 0);
13809 return ARGF.current_file;
13834 if (
RTEST(ARGF.current_file)) {
13835 if (ARGF.init_p == 0)
return Qtrue;
13837 ARGF_FORWARD(0, 0);
13896 VALUE tmp, str, length;
13900 if (!
NIL_P(length)) {
13905 rb_str_resize(str,0);
13910 if (!next_argv()) {
13913 if (ARGF_GENERIC_INPUT_P()) {
13914 tmp = argf_forward(argc, argv,
argf);
13917 tmp = io_read(argc, argv, ARGF.current_file);
13919 if (
NIL_P(str)) str = tmp;
13922 if (ARGF.next_p != -1) {
13928 else if (argc >= 1) {
13929 long slen = RSTRING_LEN(str);
13945argf_forward_call(
VALUE arg)
13948 argf_forward(p->argc, p->argv, p->argf);
13978 return argf_getpartial(argc, argv,
argf,
Qnil, 0);
13999 return argf_getpartial(argc, argv,
argf, opts, 1);
14005 VALUE tmp, str, length;
14013 no_exception = no_exception_p(opts);
14015 if (!next_argv()) {
14017 rb_str_resize(str, 0);
14021 if (ARGF_GENERIC_INPUT_P()) {
14031 tmp = io_getpartial(argc, argv, ARGF.current_file, no_exception, nonblock);
14034 if (ARGF.next_p == -1) {
14035 return io_nonblock_eof(no_exception);
14040 return io_nonblock_eof(no_exception);
14078 if (!next_argv())
return Qnil;
14079 if (ARGF_GENERIC_INPUT_P()) {
14080 ch = forward_current(rb_intern(
"getc"), 0, 0);
14083 ch = rb_io_getc(ARGF.current_file);
14085 if (
NIL_P(ch) && ARGF.next_p != -1) {
14118 if (!next_argv())
return Qnil;
14120 ch = forward_current(rb_intern(
"getbyte"), 0, 0);
14125 if (
NIL_P(ch) && ARGF.next_p != -1) {
14158 if (!next_argv()) rb_eof_error();
14160 ch = forward_current(rb_intern(
"getc"), 0, 0);
14163 ch = rb_io_getc(ARGF.current_file);
14165 if (
NIL_P(ch) && ARGF.next_p != -1) {
14197 NEXT_ARGF_FORWARD(0, 0);
14198 c = argf_getbyte(
argf);
14205#define FOREACH_ARGF() while (next_argv())
14210 const VALUE current = ARGF.current_file;
14212 if (ARGF.init_p == -1 || current != ARGF.current_file) {
14218#define ARGF_block_call(mid, argc, argv, func, argf) \
14219 rb_block_call_kw(ARGF.current_file, mid, argc, argv, \
14220 func, argf, rb_keyword_given_p())
14225 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_i,
argf);
14226 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14232 if (!global_argf_p(
argf)) {
14233 ARGF.last_lineno = ++ARGF.lineno;
14235 return argf_block_call_i(i,
argf, argc, argv, blockarg);
14241 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_line_i,
argf);
14242 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14290 argf_block_call_line(rb_intern(
"each_line"), argc, argv,
argf);
14321 argf_block_call(rb_intern(
"each_byte"), 0, 0,
argf);
14347 argf_block_call(rb_intern(
"each_char"), 0, 0,
argf);
14373 argf_block_call(rb_intern(
"each_codepoint"), 0, 0,
argf);
14404 return ARGF.filename;
14408argf_filename_getter(
ID id,
VALUE *var)
14410 return argf_filename(*var);
14435 return ARGF.current_file;
14454 ARGF_FORWARD(0, 0);
14475 return RBOOL(ARGF.binmode);
14495 if (ARGF.init_p && ARGF.next_p == 0) {
14524 if (ARGF.next_p != -1) {
14542 ARGF_FORWARD(0, 0);
14569 if (!ARGF.inplace)
return Qnil;
14577 return argf_inplace_mode_get(*var);
14608 ARGF.inplace =
Qnil;
14619 argf_inplace_mode_set(*var, val);
14623ruby_set_inplace_mode(
const char *suffix)
14649argf_argv_getter(
ID id,
VALUE *var)
14651 return argf_argv(*var);
14670 if (!
RTEST(ARGF.current_file)) {
14673 return GetWriteIO(ARGF.current_file);
14685 return rb_io_writev(argf_write_io(
argf), argc, argv);
14700 case RB_IO_WAIT_WRITABLE:
14703 c = rb_eEAGAINWaitWritable;
14705#if EAGAIN != EWOULDBLOCK
14707 c = rb_eEWOULDBLOCKWaitWritable;
14711 c = rb_eEINPROGRESSWaitWritable;
14717 case RB_IO_WAIT_READABLE:
14720 c = rb_eEAGAINWaitReadable;
14722#if EAGAIN != EWOULDBLOCK
14724 c = rb_eEWOULDBLOCKWaitReadable;
14728 c = rb_eEINPROGRESSWaitReadable;
14735 rb_bug(
"invalid read/write type passed to rb_readwrite_sys_fail: %d", waiting);
14741get_LAST_READ_LINE(
ID _x,
VALUE *_y)
15626#include <sys/cygwin.h>
15627 static struct __cygwin_perfile pf[] =
15629 {
"", O_RDONLY | O_BINARY},
15630 {
"", O_WRONLY | O_BINARY},
15631 {
"", O_RDWR | O_BINARY},
15632 {
"", O_APPEND | O_BINARY},
15635 cygwin_internal(CW_PERFILE, pf);
15690#if EAGAIN == EWOULDBLOCK
15691 rb_eEWOULDBLOCKWaitReadable = rb_eEAGAINWaitReadable;
15693 rb_define_const(
rb_cIO,
"EWOULDBLOCKWaitReadable", rb_eEAGAINWaitReadable);
15694 rb_eEWOULDBLOCKWaitWritable = rb_eEAGAINWaitWritable;
15696 rb_define_const(
rb_cIO,
"EWOULDBLOCKWaitWritable", rb_eEAGAINWaitWritable);
15744 rb_gvar_ractor_local(
"$/");
15746 rb_gvar_ractor_local(
"$-0");
15750 rb_gvar_ractor_local(
"$_");
15866 rb_gvar_ractor_local(
"$stdin");
15867 rb_gvar_ractor_local(
"$stdout");
15868 rb_gvar_ractor_local(
"$>");
15869 rb_gvar_ractor_local(
"$stderr");
15955 rb_define_method(rb_cARGF,
"external_encoding", argf_external_encoding, 0);
15956 rb_define_method(rb_cARGF,
"internal_encoding", argf_internal_encoding, 0);
15975 rb_gvar_ractor_local(
"$-i");
15979#if defined (_WIN32) || defined(__CYGWIN__)
15980 atexit(pipe_atexit);
15992 sym_encoding =
ID2SYM(rb_id_encoding());
#define RUBY_ASSERT(...)
Asserts that the given expression is truthy if and only if RUBY_DEBUG is truthy.
std::atomic< unsigned > rb_atomic_t
Type that is eligible for atomic operations.
unsigned long ruby_strtoul(const char *str, char **endptr, int base)
Our own locale-insensitive version of strtoul(3).
#define rb_define_method(klass, mid, func, arity)
Defines klass#mid.
#define rb_define_singleton_method(klass, mid, func, arity)
Defines klass.mid.
#define rb_define_global_function(mid, func, arity)
Defines rb_mKernel #mid.
void rb_include_module(VALUE klass, VALUE module)
Includes a module to a class.
VALUE rb_define_class(const char *name, VALUE super)
Defines a top-level class.
VALUE rb_class_new(VALUE super)
Creates a new, anonymous class.
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
VALUE rb_define_module_under(VALUE outer, const char *name)
Defines a module under the namespace of outer.
void rb_define_alias(VALUE klass, const char *name1, const char *name2)
Defines an alias of a method.
int rb_scan_args_kw(int kw_flag, int argc, const VALUE *argv, const char *fmt,...)
Identical to rb_scan_args(), except it also accepts kw_splat.
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Retrieves argument from argc and argv to given VALUE references according to the format string.
int rb_block_given_p(void)
Determines if the current method is given a block.
int rb_get_kwargs(VALUE keyword_hash, const ID *table, int required, int optional, VALUE *values)
Keyword argument deconstructor.
#define ECONV_AFTER_OUTPUT
Old name of RUBY_ECONV_AFTER_OUTPUT.
#define rb_str_new2
Old name of rb_str_new_cstr.
#define TYPE(_)
Old name of rb_type.
#define RB_INTEGER_TYPE_P
Old name of rb_integer_type_p.
#define ENC_CODERANGE_7BIT
Old name of RUBY_ENC_CODERANGE_7BIT.
#define T_FILE
Old name of RUBY_T_FILE.
#define ENC_CODERANGE_VALID
Old name of RUBY_ENC_CODERANGE_VALID.
#define ECONV_UNIVERSAL_NEWLINE_DECORATOR
Old name of RUBY_ECONV_UNIVERSAL_NEWLINE_DECORATOR.
#define OBJ_INIT_COPY(obj, orig)
Old name of RB_OBJ_INIT_COPY.
#define ALLOC
Old name of RB_ALLOC.
#define RFLOAT_VALUE
Old name of rb_float_value.
#define T_STRING
Old name of RUBY_T_STRING.
#define Qundef
Old name of RUBY_Qundef.
#define INT2FIX
Old name of RB_INT2FIX.
#define rb_str_cat2
Old name of rb_str_cat_cstr.
#define T_NIL
Old name of RUBY_T_NIL.
#define UNREACHABLE
Old name of RBIMPL_UNREACHABLE.
#define ID2SYM
Old name of RB_ID2SYM.
#define T_BIGNUM
Old name of RUBY_T_BIGNUM.
#define OBJ_FREEZE
Old name of RB_OBJ_FREEZE.
#define T_FIXNUM
Old name of RUBY_T_FIXNUM.
#define UNREACHABLE_RETURN
Old name of RBIMPL_UNREACHABLE_RETURN.
#define FIX2UINT
Old name of RB_FIX2UINT.
#define SSIZET2NUM
Old name of RB_SSIZE2NUM.
#define ZALLOC
Old name of RB_ZALLOC.
#define CLASS_OF
Old name of rb_class_of.
#define rb_ary_new4
Old name of rb_ary_new_from_values.
#define ENCODING_MAXNAMELEN
Old name of RUBY_ENCODING_MAXNAMELEN.
#define MBCLEN_NEEDMORE_LEN(ret)
Old name of ONIGENC_MBCLEN_NEEDMORE_LEN.
#define ENCODING_GET(obj)
Old name of RB_ENCODING_GET.
#define LONG2FIX
Old name of RB_INT2FIX.
#define NUM2UINT
Old name of RB_NUM2UINT.
#define ALLOC_N
Old name of RB_ALLOC_N.
#define MBCLEN_CHARFOUND_LEN(ret)
Old name of ONIGENC_MBCLEN_CHARFOUND_LEN.
#define LONG2NUM
Old name of RB_LONG2NUM.
#define rb_exc_new3
Old name of rb_exc_new_str.
#define STRNCASECMP
Old name of st_locale_insensitive_strncasecmp.
#define MBCLEN_INVALID_P(ret)
Old name of ONIGENC_MBCLEN_INVALID_P.
#define ISASCII
Old name of rb_isascii.
#define ECONV_STATEFUL_DECORATOR_MASK
Old name of RUBY_ECONV_STATEFUL_DECORATOR_MASK.
#define Qtrue
Old name of RUBY_Qtrue.
#define MBCLEN_NEEDMORE_P(ret)
Old name of ONIGENC_MBCLEN_NEEDMORE_P.
#define ECONV_PARTIAL_INPUT
Old name of RUBY_ECONV_PARTIAL_INPUT.
#define NUM2INT
Old name of RB_NUM2INT.
#define ECONV_ERROR_HANDLER_MASK
Old name of RUBY_ECONV_ERROR_HANDLER_MASK.
#define INT2NUM
Old name of RB_INT2NUM.
#define Qnil
Old name of RUBY_Qnil.
#define Qfalse
Old name of RUBY_Qfalse.
#define FIX2LONG
Old name of RB_FIX2LONG.
#define ENC_CODERANGE_BROKEN
Old name of RUBY_ENC_CODERANGE_BROKEN.
#define T_ARRAY
Old name of RUBY_T_ARRAY.
#define NIL_P
Old name of RB_NIL_P.
#define ALLOCV_N
Old name of RB_ALLOCV_N.
#define MBCLEN_CHARFOUND_P(ret)
Old name of ONIGENC_MBCLEN_CHARFOUND_P.
#define NUM2CHR
Old name of RB_NUM2CHR.
#define NUM2LONG
Old name of RB_NUM2LONG.
#define UINT2NUM
Old name of RB_UINT2NUM.
#define FIXNUM_P
Old name of RB_FIXNUM_P.
#define ECONV_NEWLINE_DECORATOR_MASK
Old name of RUBY_ECONV_NEWLINE_DECORATOR_MASK.
#define CONST_ID
Old name of RUBY_CONST_ID.
#define rb_ary_new2
Old name of rb_ary_new_capa.
#define NUM2SIZET
Old name of RB_NUM2SIZE.
#define ENC_CODERANGE_SET(obj, cr)
Old name of RB_ENC_CODERANGE_SET.
#define rb_str_new4
Old name of rb_str_new_frozen.
#define ALLOCV_END
Old name of RB_ALLOCV_END.
#define SYMBOL_P
Old name of RB_SYMBOL_P.
#define ECONV_DEFAULT_NEWLINE_DECORATOR
Old name of RUBY_ECONV_DEFAULT_NEWLINE_DECORATOR.
void rb_notimplement(void)
void rb_category_warn(rb_warning_category_t category, const char *fmt,...)
Identical to rb_category_warning(), except it reports unless $VERBOSE is nil.
void rb_category_warning(rb_warning_category_t category, const char *fmt,...)
Identical to rb_warning(), except it takes additional "category" parameter.
VALUE rb_eNotImpError
NotImplementedError exception.
void rb_exc_raise(VALUE mesg)
Raises an exception in the current thread.
void rb_syserr_fail(int e, const char *mesg)
Raises appropriate exception that represents a C errno.
void rb_readwrite_syserr_fail(enum rb_io_wait_readwrite waiting, int n, const char *mesg)
Identical to rb_readwrite_sys_fail(), except it does not depend on C global variable errno.
VALUE rb_eIOError
IOError exception.
VALUE rb_eStandardError
StandardError exception.
void rb_mod_syserr_fail_str(VALUE mod, int e, VALUE mesg)
Identical to rb_mod_syserr_fail(), except it takes the message in Ruby's String instead of C's.
void rb_syserr_fail_str(int e, VALUE mesg)
Identical to rb_syserr_fail(), except it takes the message in Ruby's String instead of C's.
#define ruby_verbose
This variable controls whether the interpreter is in debug mode.
VALUE rb_eTypeError
TypeError exception.
VALUE rb_eEOFError
EOFError exception.
void rb_readwrite_sys_fail(enum rb_io_wait_readwrite waiting, const char *mesg)
Raises appropriate exception using the parameters.
void rb_iter_break_value(VALUE val)
Identical to rb_iter_break(), except it additionally takes the "value" of this breakage.
rb_io_wait_readwrite
for rb_readwrite_sys_fail first argument
VALUE rb_eRuntimeError
RuntimeError exception.
void rb_warn(const char *fmt,...)
Identical to rb_warning(), except it reports unless $VERBOSE is nil.
VALUE rb_eSystemCallError
SystemCallError exception.
@ RB_WARN_CATEGORY_DEPRECATED
Warning is for deprecated features.
VALUE rb_mKernel
Kernel module.
VALUE rb_check_to_int(VALUE val)
Identical to rb_check_to_integer(), except it uses #to_int for conversion.
VALUE rb_any_to_s(VALUE obj)
Generates a textual representation of the given object.
VALUE rb_obj_alloc(VALUE klass)
Allocates an instance of the given class.
VALUE rb_class_new_instance(int argc, const VALUE *argv, VALUE klass)
Allocates, then initialises an instance of the given class.
VALUE rb_class_new_instance_kw(int argc, const VALUE *argv, VALUE klass, int kw_splat)
Identical to rb_class_new_instance(), except you can specify how to handle the last element of the gi...
VALUE rb_mEnumerable
Enumerable module.
VALUE rb_stdin
STDIN constant.
VALUE rb_stderr
STDERR constant.
VALUE rb_obj_class(VALUE obj)
Queries the class of an object.
VALUE rb_obj_dup(VALUE obj)
Duplicates the given object.
VALUE rb_inspect(VALUE obj)
Generates a human-readable textual representation of the given object.
VALUE rb_mWaitReadable
IO::WaitReadable module.
VALUE rb_mWaitWritable
IO::WaitReadable module.
VALUE rb_obj_freeze(VALUE obj)
Just calls rb_obj_freeze_inline() inside.
VALUE rb_check_to_integer(VALUE val, const char *mid)
Identical to rb_check_convert_type(), except the return value type is fixed to rb_cInteger.
VALUE rb_cFile
File class.
VALUE rb_stdout
STDOUT constant.
VALUE rb_to_int(VALUE val)
Identical to rb_check_to_int(), except it raises in case of conversion mismatch.
static unsigned int rb_enc_codepoint(const char *p, const char *e, rb_encoding *enc)
Queries the code point of character pointed by the passed pointer.
VALUE rb_str_conv_enc(VALUE str, rb_encoding *from, rb_encoding *to)
Encoding conversion main routine.
VALUE rb_enc_uint_chr(unsigned int code, rb_encoding *enc)
Encodes the passed code point into a series of bytes.
long rb_str_coderange_scan_restartable(const char *str, const char *end, rb_encoding *enc, int *cr)
Scans the passed string until it finds something odd.
int rb_econv_prepare_options(VALUE opthash, VALUE *ecopts, int ecflags)
Identical to rb_econv_prepare_opts(), except it additionally takes the initial value of flags.
VALUE rb_econv_open_exc(const char *senc, const char *denc, int ecflags)
Creates a rb_eConverterNotFoundError exception object (but does not raise).
rb_econv_result_t rb_econv_convert(rb_econv_t *ec, const unsigned char **source_buffer_ptr, const unsigned char *source_buffer_end, unsigned char **destination_buffer_ptr, unsigned char *destination_buffer_end, int flags)
Converts a string from an encoding to another.
rb_econv_result_t
return value of rb_econv_convert()
@ econv_incomplete_input
The conversion stopped in middle of reading a character, possibly due to a partial read of a socket e...
@ econv_finished
The conversion stopped after converting everything.
@ econv_undefined_conversion
The conversion stopped when it found a character in the input which cannot be representable in the ou...
@ econv_source_buffer_empty
The conversion stopped because there is no input.
@ econv_destination_buffer_full
The conversion stopped because there is no destination.
@ econv_invalid_byte_sequence
The conversion stopped when it found an invalid sequence.
int rb_econv_putbackable(rb_econv_t *ec)
Queries if rb_econv_putback() makes sense, i.e.
const char * rb_econv_asciicompat_encoding(const char *encname)
Queries the passed encoding's corresponding ASCII compatible encoding.
VALUE rb_econv_str_convert(rb_econv_t *ec, VALUE src, int flags)
Identical to rb_econv_convert(), except it takes Ruby's string instead of C's pointer.
rb_econv_t * rb_econv_open_opts(const char *source_encoding, const char *destination_encoding, int ecflags, VALUE ecopts)
Identical to rb_econv_open(), except it additionally takes a hash of optional strings.
void rb_econv_binmode(rb_econv_t *ec)
This badly named function does not set the destination encoding to binary, but instead just nullifies...
VALUE rb_str_encode(VALUE str, VALUE to, int ecflags, VALUE ecopts)
Converts the contents of the passed string from its encoding to the passed one.
VALUE rb_econv_make_exception(rb_econv_t *ec)
This function makes sense right after rb_econv_convert() returns.
void rb_econv_check_error(rb_econv_t *ec)
This is a rb_econv_make_exception() + rb_exc_raise() combo.
void rb_econv_close(rb_econv_t *ec)
Destructs a converter.
void rb_econv_putback(rb_econv_t *ec, unsigned char *p, int n)
Puts back the bytes.
VALUE rb_funcall(VALUE recv, ID mid, int n,...)
Calls a method.
VALUE rb_funcallv_kw(VALUE recv, ID mid, int argc, const VALUE *argv, int kw_splat)
Identical to rb_funcallv(), except you can specify how to handle the last element of the given array.
Defines RBIMPL_HAS_BUILTIN.
VALUE rb_ary_concat(VALUE lhs, VALUE rhs)
Destructively appends the contents of latter into the end of former.
VALUE rb_ary_shift(VALUE ary)
Destructively deletes an element from the beginning of the passed array and returns what was deleted.
VALUE rb_check_array_type(VALUE obj)
Try converting an object to its array representation using its to_ary method, if any.
VALUE rb_ary_new(void)
Allocates a new, empty array.
VALUE rb_ary_push(VALUE ary, VALUE elem)
Special case of rb_ary_cat() that it adds only one element.
VALUE rb_ary_entry(VALUE ary, long off)
Queries an element of an array.
VALUE rb_assoc_new(VALUE car, VALUE cdr)
Identical to rb_ary_new_from_values(), except it expects exactly two parameters.
#define RETURN_ENUMERATOR(obj, argc, argv)
Identical to RETURN_SIZED_ENUMERATOR(), except its size is unknown.
static int rb_check_arity(int argc, int min, int max)
Ensures that the passed integer is in the passed range.
VALUE rb_io_printf(int argc, const VALUE *argv, VALUE io)
This is a rb_f_sprintf() + rb_io_write() combo.
VALUE rb_io_gets(VALUE io)
Reads a "line" from the given IO.
int rb_cloexec_pipe(int fildes[2])
Opens a pipe with closing on exec.
VALUE rb_io_print(int argc, const VALUE *argv, VALUE io)
Iterates over the passed array to apply rb_io_write() individually.
VALUE rb_io_addstr(VALUE io, VALUE str)
Identical to rb_io_write(), except it always returns the passed IO.
void rb_write_error(const char *str)
Writes the given error message to somewhere applicable.
VALUE rb_io_ungetbyte(VALUE io, VALUE b)
Identical to rb_io_ungetc(), except it doesn't take the encoding of the passed IO into account.
VALUE rb_io_getbyte(VALUE io)
Reads a byte from the given IO.
int rb_cloexec_dup2(int oldfd, int newfd)
Identical to rb_cloexec_dup(), except you can specify the destination file descriptor.
VALUE rb_io_fdopen(int fd, int flags, const char *path)
Creates an IO instance whose backend is the given file descriptor.
void rb_update_max_fd(int fd)
Informs the interpreter that the passed fd can be the max.
int rb_cloexec_open(const char *pathname, int flags, mode_t mode)
Opens a file that closes on exec.
VALUE rb_output_rs
The record separator character for outputs, or the $\.
VALUE rb_io_eof(VALUE io)
Queries if the passed IO is at the end of file.
void rb_write_error2(const char *str, long len)
Identical to rb_write_error(), except it additionally takes the message's length.
void rb_close_before_exec(int lowfd, int maxhint, VALUE noclose_fds)
Closes everything.
int rb_reserved_fd_p(int fd)
Queries if the given FD is reserved or not.
void rb_fd_fix_cloexec(int fd)
Sets or clears the close-on-exec flag of the passed file descriptor to the desired state.
VALUE rb_io_ascii8bit_binmode(VALUE io)
Forces no conversions be applied to the passed IO.
VALUE rb_io_binmode(VALUE io)
Sets the binmode.
VALUE rb_io_ungetc(VALUE io, VALUE c)
"Unget"s a string.
int rb_pipe(int *pipes)
This is an rb_cloexec_pipe() + rb_update_max_fd() combo.
VALUE rb_gets(void)
Much like rb_io_gets(), but it reads from the mysterious ARGF object.
int rb_cloexec_fcntl_dupfd(int fd, int minfd)
Duplicates a file descriptor with closing on exec.
VALUE rb_output_fs
The field separator character for outputs, or the $,.
VALUE rb_file_open_str(VALUE fname, const char *fmode)
Identical to rb_file_open(), except it takes the pathname as a Ruby's string instead of C's.
int rb_cloexec_dup(int oldfd)
Identical to rb_cloexec_fcntl_dupfd(), except it implies minfd is 3.
VALUE rb_file_open(const char *fname, const char *fmode)
Opens a file located at the given path.
VALUE rb_io_close(VALUE io)
Closes the IO.
VALUE rb_default_rs
This is the default value of rb_rs, i.e.
void rb_lastline_set(VALUE str)
Updates $_.
VALUE rb_lastline_get(void)
Queries the last line, or the $_.
int rb_obj_method_arity(VALUE obj, ID mid)
Identical to rb_mod_method_arity(), except it searches for singleton methods rather than instance met...
rb_pid_t rb_waitpid(rb_pid_t pid, int *status, int flags)
Waits for a process, with releasing GVL.
void rb_last_status_set(int status, rb_pid_t pid)
Sets the "last status", or the $?.
VALUE rb_str_append(VALUE dst, VALUE src)
Identical to rb_str_buf_append(), except it converts the right hand side before concatenating.
#define rb_str_new(str, len)
Allocates an instance of rb_cString.
#define rb_str_buf_cat
Just another name of rb_str_cat.
#define rb_usascii_str_new(str, len)
Identical to rb_str_new, except it generates a string of "US ASCII" encoding.
size_t rb_str_capacity(VALUE str)
Queries the capacity of the given string.
VALUE rb_str_new_frozen(VALUE str)
Creates a frozen copy of the string, if necessary.
VALUE rb_str_dup(VALUE str)
Duplicates a string.
VALUE rb_str_cat(VALUE dst, const char *src, long srclen)
Destructively appends the passed contents to the string.
VALUE rb_str_locktmp(VALUE str)
Obtains a "temporary lock" of the string.
VALUE rb_str_equal(VALUE str1, VALUE str2)
Equality of two strings.
void rb_str_set_len(VALUE str, long len)
Overwrites the length of the string.
VALUE rb_str_buf_cat_ascii(VALUE dst, const char *src)
Identical to rb_str_cat_cstr(), except it additionally assumes the source string be a NUL terminated ...
VALUE rb_check_string_type(VALUE obj)
Try converting an object to its stringised representation using its to_str method,...
VALUE rb_str_substr(VALUE str, long beg, long len)
This is the implementation of two-argumented String#slice.
VALUE rb_str_unlocktmp(VALUE str)
Releases a lock formerly obtained by rb_str_locktmp().
void rb_str_modify_expand(VALUE str, long capa)
Identical to rb_str_modify(), except it additionally expands the capacity of the receiver.
VALUE rb_str_buf_new(long capa)
Allocates a "string buffer".
#define rb_str_new_cstr(str)
Identical to rb_str_new, except it assumes the passed pointer is a pointer to a C string.
VALUE rb_obj_as_string(VALUE obj)
Try converting an object to its stringised representation using its to_s method, if any.
int rb_thread_interrupted(VALUE thval)
Checks if the thread's execution was recently interrupted.
VALUE rb_mutex_new(void)
Creates a mutex.
int rb_thread_fd_writable(int fd)
Identical to rb_thread_wait_fd(), except it blocks the current thread until the given file descriptor...
VALUE rb_exec_recursive(VALUE(*f)(VALUE g, VALUE h, int r), VALUE g, VALUE h)
"Recursion" API entry point.
VALUE rb_mutex_synchronize(VALUE mutex, VALUE(*func)(VALUE arg), VALUE arg)
Obtains the lock, runs the passed function, and releases the lock when it completes.
void rb_thread_check_ints(void)
Checks for interrupts.
VALUE rb_thread_current(void)
Obtains the "current" thread.
int rb_thread_wait_fd(int fd)
Blocks the current thread until the given file descriptor is ready to be read.
void rb_thread_sleep(int sec)
Blocks for the given period of time.
struct timeval rb_time_interval(VALUE num)
Creates a "time interval".
void rb_set_class_path(VALUE klass, VALUE space, const char *name)
Names a class.
VALUE rb_ivar_set(VALUE obj, ID name, VALUE val)
Identical to rb_iv_set(), except it accepts the name as an ID instead of a C string.
VALUE rb_class_name(VALUE obj)
Queries the name of the given object's class.
int rb_respond_to(VALUE obj, ID mid)
Queries if the object responds to the method.
VALUE rb_check_funcall(VALUE recv, ID mid, int argc, const VALUE *argv)
Identical to rb_funcallv(), except it returns RUBY_Qundef instead of raising rb_eNoMethodError.
void rb_define_alloc_func(VALUE klass, rb_alloc_func_t func)
Sets the allocator function of a class.
static ID rb_intern_const(const char *str)
This is a "tiny optimisation" over rb_intern().
#define RB_ID2SYM
Just another name of rb_id2sym.
void rb_define_global_const(const char *name, VALUE val)
Identical to rb_define_const(), except it defines that of "global", i.e.
void rb_define_readonly_variable(const char *name, const VALUE *var)
Identical to rb_define_variable(), except it does not allow Ruby programs to assign values to such gl...
rb_gvar_setter_t rb_gvar_readonly_setter
This function just raises rb_eNameError.
#define FMODE_READABLE
The IO is opened for reading.
enum rb_io_mode rb_io_modestr_fmode(const char *modestr)
Maps a file mode string (that rb_file_open() takes) into a mixture of FMODE_ flags.
VALUE rb_io_get_io(VALUE io)
Identical to rb_io_check_io(), except it raises exceptions on conversion failures.
VALUE rb_io_timeout(VALUE io)
Get the timeout associated with the specified io object.
VALUE rb_io_taint_check(VALUE obj)
void rb_io_read_check(rb_io_t *fptr)
Blocks until there is a pending read in the passed IO.
int rb_io_modestr_oflags(const char *modestr)
Identical to rb_io_modestr_fmode(), except it returns a mixture of O_ flags.
#define FMODE_SETENC_BY_BOM
This flag amends the encoding of the IO so that the BOM of the contents of the IO takes effect.
rb_io_event
Type of events that an IO can wait.
@ RUBY_IO_READABLE
IO::READABLE
@ RUBY_IO_PRIORITY
IO::PRIORITY
@ RUBY_IO_WRITABLE
IO::WRITABLE
#define FMODE_READWRITE
The IO is opened for both read/write.
#define FMODE_EXTERNAL
This flag means that an IO object is wrapping an "external" file descriptor, which is owned by someth...
#define GetOpenFile
This is an old name of RB_IO_POINTER.
void rb_io_check_byte_readable(rb_io_t *fptr)
Asserts that an IO is opened for byte-based reading.
#define FMODE_TTY
The IO is a TTY.
#define FMODE_CREATE
The IO is opened for creating.
void rb_io_check_readable(rb_io_t *fptr)
Just another name of rb_io_check_byte_readable.
int rb_wait_for_single_fd(int fd, int events, struct timeval *tv)
Blocks until the passed file descriptor is ready for the passed events.
FILE * rb_fdopen(int fd, const char *modestr)
Identical to rb_io_stdio_file(), except it takes file descriptors instead of Ruby's IO.
int rb_io_extract_encoding_option(VALUE opt, rb_encoding **enc_p, rb_encoding **enc2_p, enum rb_io_mode *fmode_p)
This function breaks down the option hash that IO#initialize takes into components.
int rb_io_descriptor(VALUE io)
Returns an integer representing the numeric file descriptor for io.
#define FMODE_WRITABLE
The IO is opened for writing.
FILE * rb_io_stdio_file(rb_io_t *fptr)
Finds or creates a stdio's file structure from a Ruby's one.
#define FMODE_APPEND
The IO is opened for appending.
#define MakeOpenFile
This is an old name of RB_IO_OPEN.
#define FMODE_DUPLEX
Ruby eventually detects that the IO is bidirectional.
#define FMODE_BINMODE
The IO is in "binary mode".
int rb_io_maybe_wait_readable(int error, VALUE io, VALUE timeout)
Blocks until the passed IO is ready for reading, if that makes sense for the passed errno.
int capa
Designed capacity of the buffer.
#define RB_IO_POINTER(obj, fp)
Queries the underlying IO pointer.
VALUE rb_io_maybe_wait(int error, VALUE io, VALUE events, VALUE timeout)
Identical to rb_io_wait() except it additionally takes previous errno.
VALUE rb_eIOTimeoutError
Indicates that a timeout has occurred while performing an IO operation.
char * ptr
Pointer to the underlying memory region, of at least capa bytes.
#define FMODE_SYNC
The IO is in "sync mode".
int off
Offset inside of ptr.
VALUE rb_io_path(VALUE io)
Returns the path for the given IO.
void rb_io_extract_modeenc(VALUE *vmode_p, VALUE *vperm_p, VALUE opthash, int *oflags_p, enum rb_io_mode *fmode_p, rb_io_enc_t *convconfig_p)
This function can be seen as an extended version of rb_io_extract_encoding_option() that not only con...
void rb_io_check_initialized(rb_io_t *fptr)
Asserts that the passed IO is initialised.
#define FMODE_EXCL
This flag amends the effect of FMODE_CREATE, so that if there already is a file at the given path the...
#define FMODE_TEXTMODE
The IO is in "text mode".
int rb_io_fptr_finalize(rb_io_t *fptr)
Destroys the given IO.
VALUE rb_io_check_io(VALUE io)
Try converting an object to its IO representation using its to_io method, if any.
VALUE rb_io_closed_p(VALUE io)
Returns whether or not the underlying IO is closed.
VALUE rb_io_set_timeout(VALUE io, VALUE timeout)
Set the timeout associated with the specified io object.
ssize_t rb_io_bufwrite(VALUE io, const void *buf, size_t size)
Buffered write to the passed IO.
void rb_io_check_char_readable(rb_io_t *fptr)
Asserts that an IO is opened for character-based reading.
#define FMODE_TRUNC
This flag amends the effect of FMODE_CREATE, so that if there already is a file at the given path it ...
VALUE rb_io_get_write_io(VALUE io)
Queries the tied IO for writing.
void rb_io_set_nonblock(rb_io_t *fptr)
Instructs the OS to put its internal file structure into "nonblocking mode".
int rb_io_wait_writable(int fd)
Blocks until the passed file descriptor gets writable.
VALUE rb_io_open_descriptor(VALUE klass, int descriptor, int mode, VALUE path, VALUE timeout, struct rb_io_encoding *encoding)
Allocate a new IO object, with the given file descriptor.
VALUE rb_io_set_write_io(VALUE io, VALUE w)
Assigns the tied IO for writing.
void rb_io_check_writable(rb_io_t *fptr)
Asserts that an IO is opened for writing.
int rb_io_maybe_wait_writable(int error, VALUE io, VALUE timeout)
Blocks until the passed IO is ready for writing, if that makes sense for the passed errno.
void rb_io_check_closed(rb_io_t *fptr)
This badly named function asserts that the passed IO is open.
int rb_io_wait_readable(int fd)
Blocks until the passed file descriptor gets readable.
void rb_io_synchronized(rb_io_t *fptr)
Sets FMODE_SYNC.
VALUE rb_io_wait(VALUE io, VALUE events, VALUE timeout)
Blocks until the passed IO is ready for the passed events.
int len
Length of the buffer.
VALUE rb_ractor_stdin(void)
Queries the standard input of the current Ractor that is calling this function.
void rb_ractor_stderr_set(VALUE io)
Assigns an IO to the standard error of the Ractor that is calling this function.
void rb_ractor_stdout_set(VALUE io)
Assigns an IO to the standard output of the Ractor that is calling this function.
void rb_ractor_stdin_set(VALUE io)
Assigns an IO to the standard input of the Ractor that is calling this function.
void * rb_thread_call_with_gvl(void *(*func)(void *), void *data1)
(Re-)acquires the GVL.
#define RB_NUM2INT
Just another name of rb_num2int_inline.
#define RB_INT2NUM
Just another name of rb_int2num_inline.
VALUE rb_f_sprintf(int argc, const VALUE *argv)
Identical to rb_str_format(), except how the arguments are arranged.
#define RB_BLOCK_CALL_FUNC_ARGLIST(yielded_arg, callback_arg)
Shim for block function parameters.
VALUE rb_yield_values2(int n, const VALUE *argv)
Identical to rb_yield_values(), except it takes the parameters as a C array instead of variadic argum...
VALUE rb_yield(VALUE val)
Yields the block.
void rb_fd_term(rb_fdset_t *f)
Destroys the rb_fdset_t, releasing any memory and resources it used.
#define MEMZERO(p, type, n)
Handy macro to erase a region of memory.
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
#define MEMMOVE(p1, p2, type, n)
Handy macro to call memmove.
#define NUM2MODET
Converts a C's mode_t into an instance of rb_cInteger.
void rb_define_hooked_variable(const char *q, VALUE *w, type *e, void_type *r)
Define a function-backended global variable.
void rb_define_virtual_variable(const char *q, type *w, void_type *e)
Define a function-backended global variable.
VALUE rb_rescue2(type *q, VALUE w, type *e, VALUE r,...)
An equivalent of rescue clause.
VALUE rb_ensure(type *q, VALUE w, type *e, VALUE r)
An equivalent of ensure clause.
#define PRI_OFFT_PREFIX
A rb_sprintf() format prefix to be used for an off_t parameter.
#define OFFT2NUM
Converts a C's off_t into an instance of rb_cInteger.
#define NUM2OFFT
Converts an instance of rb_cNumeric into C's off_t.
#define PIDT2NUM
Converts a C's pid_t into an instance of rb_cInteger.
#define rb_fd_isset
Queries if the given fd is in the rb_fdset_t.
#define rb_fd_select
Waits for multiple file descriptors at once.
#define rb_fd_init
Initialises the :given :rb_fdset_t.
#define rb_fd_set
Sets the given fd to the rb_fdset_t.
#define RARRAY_LEN
Just another name of rb_array_len.
static int RARRAY_LENINT(VALUE ary)
Identical to rb_array_len(), except it differs for the return type.
#define RARRAY_AREF(a, i)
#define RARRAY_CONST_PTR
Just another name of rb_array_const_ptr.
#define RFILE(obj)
Convenient casting macro.
#define StringValue(v)
Ensures that the parameter object is a String.
static char * RSTRING_END(VALUE str)
Queries the end of the contents pointer of the string.
#define RSTRING_GETMEM(str, ptrvar, lenvar)
Convenient macro to obtain the contents and length at once.
#define StringValueCStr(v)
Identical to StringValuePtr, except it additionally checks for the contents for viability as a C stri...
#define RUBY_TYPED_DEFAULT_FREE
This is a value you can set to rb_data_type_struct::dfree.
#define TypedData_Make_Struct(klass, type, data_type, sval)
Identical to TypedData_Wrap_Struct, except it allocates a new data region internally instead of takin...
VALUE rb_get_argv(void)
Queries the arguments passed to the current process that you can access from Ruby as ARGV.
void rb_p(VALUE obj)
Inspects an object.
#define FilePathValue(v)
Ensures that the parameter object is a path.
#define errno
Ractor-aware version of errno.
#define RB_SCAN_ARGS_LAST_HASH_KEYWORDS
Treat a final argument as keywords if it is a hash, and not as keywords otherwise.
#define RB_PASS_CALLED_KEYWORDS
Pass keywords if current method is called with keywords, useful for argument delegation.
VALUE rb_fiber_scheduler_current(void)
Identical to rb_fiber_scheduler_get(), except it also returns RUBY_Qnil in case of a blocking fiber.
VALUE rb_fiber_scheduler_io_pread_memory(VALUE scheduler, VALUE io, rb_off_t from, void *base, size_t size, size_t length)
Non-blocking pread from the passed IO using a native buffer.
VALUE rb_fiber_scheduler_make_timeout(struct timeval *timeout)
Converts the passed timeout to an expression that rb_fiber_scheduler_block() etc.
VALUE rb_fiber_scheduler_io_wait_readable(VALUE scheduler, VALUE io)
Non-blocking wait until the passed IO is ready for reading.
VALUE rb_fiber_scheduler_io_read_memory(VALUE scheduler, VALUE io, void *base, size_t size, size_t length)
Non-blocking read from the passed IO using a native buffer.
VALUE rb_fiber_scheduler_io_wait(VALUE scheduler, VALUE io, VALUE events, VALUE timeout)
Non-blocking version of rb_io_wait().
static ssize_t rb_fiber_scheduler_io_result_apply(VALUE result)
Apply an io result to the local thread, returning the value of the original system call that created ...
VALUE rb_fiber_scheduler_io_selectv(VALUE scheduler, int argc, VALUE *argv)
Non-blocking version of IO.select, argv variant.
VALUE rb_fiber_scheduler_io_pwrite_memory(VALUE scheduler, VALUE io, rb_off_t from, const void *base, size_t size, size_t length)
Non-blocking pwrite to the passed IO using a native buffer.
VALUE rb_fiber_scheduler_current_for_thread(VALUE thread)
Identical to rb_fiber_scheduler_current(), except it queries for that of the passed thread value inst...
VALUE rb_fiber_scheduler_io_write_memory(VALUE scheduler, VALUE io, const void *base, size_t size, size_t length)
Non-blocking write to the passed IO using a native buffer.
VALUE rb_fiber_scheduler_current_for_threadptr(struct rb_thread_struct *thread)
Identical to rb_fiber_scheduler_current_for_thread(), except it expects a threadptr instead of a thre...
VALUE rb_fiber_scheduler_io_wait_writable(VALUE scheduler, VALUE io)
Non-blocking wait until the passed IO is ready for writing.
VALUE rb_fiber_scheduler_io_close(VALUE scheduler, VALUE io)
Non-blocking close the given IO.
int rb_thread_fd_select(int nfds, rb_fdset_t *rfds, rb_fdset_t *wfds, rb_fdset_t *efds, struct timeval *timeout)
Waits for multiple file descriptors at once.
static bool RB_TEST(VALUE obj)
Emulates Ruby's "if" statement.
#define RTEST
This is an old name of RB_TEST.
#define _(args)
This was a transition path from K&R to ANSI.
This is the struct that holds necessary info for a struct.
The data structure which wraps the fd_set bitmap used by select(2).
Decomposed encoding flags (e.g.
VALUE ecopts
Flags as Ruby hash.
rb_encoding * enc2
External encoding.
rb_encoding * enc
Internal encoding.
char * ptr
Pointer to the underlying memory region, of at least capa bytes.
int off
Offset inside of ptr.
int len
Length of the buffer.
int capa
Designed capacity of the buffer.
Ruby's IO, metadata and buffers.
rb_io_buffer_t wbuf
Write buffer.
enum rb_io_mode mode
mode flags: FMODE_XXXs
void(* finalize)(struct rb_io *, int)
finalize proc
rb_econv_t * readconv
Encoding converter used when reading from this IO.
rb_econv_t * writeconv
Encoding converter used when writing to this IO.
struct rb_io_encoding encs
Decomposed encoding flags.
VALUE self
The IO's Ruby level counterpart.
VALUE write_lock
This is a Ruby level mutex.
VALUE timeout
The timeout associated with this IO when performing blocking operations.
FILE * stdio_file
stdio ptr for read/write, if available.
VALUE writeconv_pre_ecopts
Value of ::rb_io_t::rb_io_enc_t::ecopts stored right before initialising rb_io_t::writeconv.
VALUE tied_io_for_writing
Duplex IO object, if set.
int writeconv_initialized
Whether rb_io_t::writeconv is already set up.
rb_io_buffer_t rbuf
(Byte) read buffer.
int lineno
number of lines read
struct ccan_list_head blocking_operations
Threads that are performing a blocking operation without the GVL using this IO.
VALUE writeconv_asciicompat
This is, when set, an instance of rb_cString which holds the "common" encoding.
rb_io_buffer_t cbuf
rb_io_ungetc() destination.
rb_pid_t pid
child's pid (for pipes)
int writeconv_pre_ecflags
Value of ::rb_io_t::rb_io_enc_t::ecflags stored right before initialising rb_io_t::writeconv.
VALUE pathv
pathname for file
intptr_t SIGNED_VALUE
A signed integer type that has the same width with VALUE.
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
uintptr_t VALUE
Type that represents a Ruby object.
static bool RB_FLOAT_TYPE_P(VALUE obj)
Queries if the object is an instance of rb_cFloat.
static bool RB_SYMBOL_P(VALUE obj)
Queries if the object is an instance of rb_cSymbol.
static void Check_Type(VALUE v, enum ruby_value_type t)
Identical to RB_TYPE_P(), except it raises exceptions on predication failure.
static bool RB_TYPE_P(VALUE obj, enum ruby_value_type t)
Queries if the given object is of given type.