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,
int 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(function, argument, io->
fd, 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) {
1189internal_read_func(
void *ptr)
1194 if (iis->timeout && !iis->nonblock) {
1195 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_IN, iis->timeout) == -1) {
1201 result = read(iis->fd, iis->buf, iis->capa);
1203 if (result < 0 && !iis->nonblock) {
1204 if (io_again_p(
errno)) {
1205 if (io_internal_wait(iis->th, iis->fptr,
errno, RB_WAITFD_IN, iis->timeout) == -1) {
1217#if defined __APPLE__
1218# define do_write_retry(code) do {result = code;} while (result == -1 && errno == EPROTOTYPE)
1220# define do_write_retry(code) result = code
1224internal_write_func(
void *ptr)
1229 if (iis->timeout && !iis->nonblock) {
1230 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1236 do_write_retry(write(iis->fd, iis->buf, iis->capa));
1238 if (result < 0 && !iis->nonblock) {
1240 if (io_again_p(e)) {
1241 if (io_internal_wait(iis->th, iis->fptr,
errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1255internal_writev_func(
void *ptr)
1257 struct io_internal_writev_struct *iis = ptr;
1260 if (iis->timeout && !iis->nonblock) {
1261 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1267 do_write_retry(writev(iis->fd, iis->iov, iis->iovcnt));
1269 if (result < 0 && !iis->nonblock) {
1270 if (io_again_p(
errno)) {
1271 if (io_internal_wait(iis->th, iis->fptr,
errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1285rb_io_read_memory(
rb_io_t *fptr,
void *buf,
size_t count)
1288 if (scheduler !=
Qnil) {
1291 if (!UNDEF_P(result)) {
1307 struct timeval timeout_storage;
1311 iis.timeout = &timeout_storage;
1314 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_read_func, &iis,
RUBY_IO_READABLE);
1318rb_io_write_memory(
rb_io_t *fptr,
const void *buf,
size_t count)
1321 if (scheduler !=
Qnil) {
1324 if (!UNDEF_P(result)) {
1340 struct timeval timeout_storage;
1344 iis.timeout = &timeout_storage;
1347 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_write_func, &iis,
RUBY_IO_WRITABLE);
1352rb_writev_internal(
rb_io_t *fptr,
const struct iovec *iov,
int iovcnt)
1354 if (!iovcnt)
return 0;
1357 if (scheduler !=
Qnil) {
1361 if (!UNDEF_P(result)) {
1366 struct io_internal_writev_struct iis = {
1377 struct timeval timeout_storage;
1381 iis.timeout = &timeout_storage;
1384 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_writev_func, &iis,
RUBY_IO_WRITABLE);
1389io_flush_buffer_sync(
void *arg)
1411io_flush_buffer_async(
VALUE arg)
1414 return rb_io_blocking_region_wait(fptr, io_flush_buffer_sync, fptr,
RUBY_IO_WRITABLE);
1421 return (
int)io_flush_buffer_async((
VALUE)fptr);
1436 while (fptr->
wbuf.
len > 0 && io_flush_buffer(fptr) != 0) {
1451 if (scheduler !=
Qnil) {
1461 if (NIL_OR_UNDEF_P(timeout)) {
1465 if (timeout !=
Qnil) {
1470 int ready = rb_thread_wait_for_single_fd(fptr->
fd,
RB_NUM2INT(events), tv);
1494io_wait_for_single_fd(
int fd,
int events,
struct timeval *timeout)
1498 if (scheduler !=
Qnil) {
1504 return rb_thread_wait_for_single_fd(fd, events, timeout);
1510 io_fd_check_closed(f);
1516#if defined(ERESTART)
1523#if EWOULDBLOCK != EAGAIN
1526 if (scheduler !=
Qnil) {
1544 io_fd_check_closed(f);
1550#if defined(ERESTART)
1566#if EWOULDBLOCK != EAGAIN
1569 if (scheduler !=
Qnil) {
1587 return io_wait_for_single_fd(fd, events, timeout);
1621#if defined(ERESTART)
1631#if EWOULDBLOCK != EAGAIN
1648 if (
RTEST(result)) {
1663 if (
RTEST(result)) {
1677 const char *senc, *denc;
1684 ecflags = fptr->
encs.
ecflags & ~ECONV_NEWLINE_DECORATOR_READ_MASK;
1711 denc = rb_enc_name(enc);
1743io_binwrite_string_internal(
rb_io_t *fptr,
const char *ptr,
long length)
1746 struct iovec iov[2];
1749 iov[0].iov_len = fptr->
wbuf.
len;
1750 iov[1].iov_base = (
void*)ptr;
1751 iov[1].iov_len = length;
1753 ssize_t result = rb_writev_internal(fptr, iov, 2);
1758 if (result >= fptr->
wbuf.
len) {
1766 fptr->
wbuf.
off += (int)result;
1767 fptr->
wbuf.
len -= (int)result;
1775 return rb_io_write_memory(fptr, ptr, length);
1780io_binwrite_string_internal(
rb_io_t *fptr,
const char *ptr,
long length)
1782 long remaining = length;
1785 if (fptr->
wbuf.
len+length <= fptr->wbuf.capa) {
1792 fptr->
wbuf.
len += (int)length;
1799 if (io_fflush(fptr) < 0) {
1804 if (remaining == 0) {
1810 return rb_io_write_memory(fptr, ptr, length);
1815io_binwrite_string(
VALUE arg)
1819 const char *ptr = p->ptr;
1820 size_t remaining = p->length;
1824 ssize_t result = io_binwrite_string_internal(p->fptr, ptr, remaining);
1830 else if (result > 0) {
1831 if ((
size_t)result == remaining)
break;
1833 remaining -= result;
1849io_allocate_write_buffer(
rb_io_t *fptr,
int sync)
1854 fptr->
wbuf.
capa = IO_WBUF_CAPA_MIN;
1865io_binwrite_requires_flush_write(
rb_io_t *fptr,
long len,
int nosync)
1880io_binwrite(
const char *ptr,
long len,
rb_io_t *fptr,
int nosync)
1882 if (
len <= 0)
return len;
1887 io_allocate_write_buffer(fptr, !nosync);
1889 if (io_binwrite_requires_flush_write(fptr,
len, nosync)) {
1900 return io_binwrite_string((
VALUE)&arg);
1917# define MODE_BTMODE(a,b,c) ((fmode & FMODE_BINMODE) ? (b) : \
1918 (fmode & FMODE_TEXTMODE) ? (c) : (a))
1920#define MODE_BTXMODE(a, b, c, d, e, f) ((fmode & FMODE_EXCL) ? \
1921 MODE_BTMODE(d, e, f) : \
1922 MODE_BTMODE(a, b, c))
1927 if (NEED_WRITECONV(fptr)) {
1929 SET_BINARY_MODE(fptr);
1931 make_writeconv(fptr);
1934#define fmode (fptr->mode)
1937 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1) && !rb_enc_asciicompat(rb_enc_get(str))) {
1938 rb_raise(rb_eArgError,
"ASCII incompatible string written for text mode IO without encoding conversion: %s",
1939 rb_enc_name(rb_enc_get(str)));
1945 common_encoding = rb_enc_from_encoding(fptr->
encs.
enc2);
1946 else if (fptr->
encs.
enc != rb_ascii8bit_encoding())
1947 common_encoding = rb_enc_from_encoding(fptr->
encs.
enc);
1950 if (!
NIL_P(common_encoding)) {
1961#if RUBY_CRLF_ENVIRONMENT
1962#define fmode (fptr->mode)
1963 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1)) {
1966 setmode(fptr->
fd, O_BINARY);
1969 setmode(fptr->
fd, O_TEXT);
1971 if (!rb_enc_asciicompat(rb_enc_get(str))) {
1972 rb_raise(rb_eArgError,
"ASCII incompatible string written for text mode IO without encoding conversion: %s",
1973 rb_enc_name(rb_enc_get(str)));
1991 long len = rb_w32_write_console(str, fptr->
fd);
1996 str = do_writeconv(str, fptr, &converted);
2000 tmp = rb_str_tmp_frozen_no_embed_acquire(str);
2002 n = io_binwrite(ptr,
len, fptr, nosync);
2003 rb_str_tmp_frozen_release(str, tmp);
2015 return (ssize_t)io_binwrite(buf, (
long)size, fptr, 0);
2025 io = GetWriteIO(io);
2035 if (RSTRING_LEN(str) == 0)
return INT2FIX(0);
2040 n = io_fwrite(str, fptr, nosync);
2041 if (n < 0L) rb_sys_fail_on_write(fptr);
2047struct binwritev_arg {
2055io_binwritev_internal(
VALUE arg)
2057 struct binwritev_arg *p = (
struct binwritev_arg *)arg;
2059 size_t remaining = p->total;
2063 struct iovec *iov = p->iov;
2064 int iovcnt = p->iovcnt;
2067 long result = rb_writev_internal(fptr, iov, iovcnt);
2072 if (offset < (
size_t)fptr->
wbuf.
len) {
2077 offset -= (size_t)fptr->
wbuf.
len;
2083 if (offset == p->total) {
2087 while (result >= (ssize_t)iov->iov_len) {
2089 result -= iov->iov_len;
2099 iov->iov_base = (
char *)iov->iov_base + result;
2100 iov->iov_len -= result;
2114io_binwritev(
struct iovec *iov,
int iovcnt,
rb_io_t *fptr)
2119 if (iovcnt == 0)
return 0;
2122 for (
int i = 1; i < iovcnt; i++) total += iov[i].iov_len;
2124 io_allocate_write_buffer(fptr, 1);
2130 if (offset + total <= (
size_t)fptr->
wbuf.
capa) {
2131 for (
int i = 1; i < iovcnt; i++) {
2132 memcpy(fptr->
wbuf.
ptr+offset, iov[i].iov_base, iov[i].iov_len);
2133 offset += iov[i].iov_len;
2142 iov[0].iov_len = fptr->
wbuf.
len;
2155 struct binwritev_arg arg;
2158 arg.iovcnt = iovcnt;
2165 return io_binwritev_internal((
VALUE)&arg);
2172 int i, converted, iovcnt = argc + 1;
2174 VALUE v1, v2, str, tmp, *tmp_array;
2180 for (i = 0; i < argc; i++) {
2183 str = do_writeconv(str, fptr, &converted);
2188 tmp = rb_str_tmp_frozen_acquire(str);
2192 iov[i+1].iov_base = RSTRING_PTR(tmp);
2193 iov[i+1].iov_len = RSTRING_LEN(tmp);
2196 n = io_binwritev(iov, iovcnt, fptr);
2199 for (i = 0; i < argc; i++) {
2200 rb_str_tmp_frozen_release(argv[i], tmp_array[i]);
2209iovcnt_ok(
int iovcnt)
2212 return iovcnt < IOV_MAX;
2220io_writev(
int argc,
const VALUE *argv,
VALUE io)
2227 io = GetWriteIO(io);
2232 return rb_funcallv(io, id_write, argc, argv);
2240 for (i = 0; i < argc; i += cnt) {
2243 n = io_fwritev(cnt, &argv[i], fptr);
2254 rb_sys_fail_on_write(fptr);
2256 total = rb_fix_plus(
LONG2FIX(n), total);
2287 return io_writev(argc, argv, io);
2290 VALUE str = argv[0];
2291 return io_write(io, str, 0);
2298 return rb_funcallv(io, id_write, 1, &str);
2302rb_io_writev(
VALUE io,
int argc,
const VALUE *argv)
2307 char sep = RCLASS_SINGLETON_P(klass) ? (klass = io,
'.') :
'#';
2310 " which accepts just one argument",
2315 do rb_io_write(io, *argv++);
while (--argc);
2320 return rb_funcallv(io, id_write, argc, argv);
2346 rb_io_write(io, str);
2352nogvl_fsync(
void *ptr)
2357 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->
fd)) != FILE_TYPE_DISK)
2360 return (
VALUE)fsync(fptr->
fd);
2365rb_io_flush_raw(
VALUE io,
int sync)
2373 io = GetWriteIO(io);
2377 if (io_fflush(fptr) < 0)
2378 rb_sys_fail_on_write(fptr);
2381 io_unread(fptr,
true);
2402 return rb_io_flush_raw(io, 1);
2428 pos = io_tell(fptr);
2429 if (pos < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
2435rb_io_seek(
VALUE io,
VALUE offset,
int whence)
2442 pos = io_seek(fptr, pos, whence);
2443 if (pos < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
2449interpret_seek_whence(
VALUE vwhence)
2451 if (vwhence == sym_SET)
2453 if (vwhence == sym_CUR)
2455 if (vwhence == sym_END)
2458 if (vwhence == sym_DATA)
2462 if (vwhence == sym_HOLE)
2518 VALUE offset, ptrname;
2519 int whence = SEEK_SET;
2521 if (
rb_scan_args(argc, argv,
"11", &offset, &ptrname) == 2) {
2522 whence = interpret_seek_whence(ptrname);
2525 return rb_io_seek(io, offset, whence);
2553 pos = io_seek(fptr, pos, SEEK_SET);
2554 if (pos < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
2559static void clear_readconv(
rb_io_t *fptr);
2586rb_io_rewind(
VALUE io)
2591 if (io_seek(fptr, 0L, 0) < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
2592 if (io == ARGF.current_file) {
2593 ARGF.lineno -= fptr->
lineno;
2597 clear_readconv(fptr);
2604fptr_wait_readable(
rb_io_t *fptr)
2622 fptr->
rbuf.
capa = IO_RBUF_CAPA_FOR(fptr);
2633 if (fptr_wait_readable(fptr))
2637 VALUE path = rb_sprintf(
"fd:%d ", fptr->
fd);
2642 rb_syserr_fail_path(e, path);
2696 if (READ_CHAR_PENDING(fptr))
return Qfalse;
2697 if (READ_DATA_PENDING(fptr))
return Qfalse;
2699#if RUBY_CRLF_ENVIRONMENT
2700 if (!NEED_READCONV(fptr) && NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
2701 return RBOOL(eof(fptr->
fd));
2704 return RBOOL(io_fillbuf(fptr) < 0);
2728 io = GetWriteIO(io);
2765 io = GetWriteIO(io);
2771 fptr->
mode &= ~FMODE_SYNC;
2795rb_io_fsync(
VALUE io)
2799 io = GetWriteIO(io);
2802 if (io_fflush(fptr) < 0)
2803 rb_sys_fail_on_write(fptr);
2805 if ((
int)rb_io_blocking_region(fptr, nogvl_fsync, fptr))
2806 rb_sys_fail_path(fptr->
pathv);
2811# define rb_io_fsync rb_f_notimplement
2812# define rb_io_sync rb_f_notimplement
2821#ifdef HAVE_FDATASYNC
2823nogvl_fdatasync(
void *ptr)
2828 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->
fd)) != FILE_TYPE_DISK)
2831 return (
VALUE)fdatasync(fptr->
fd);
2846rb_io_fdatasync(
VALUE io)
2850 io = GetWriteIO(io);
2853 if (io_fflush(fptr) < 0)
2854 rb_sys_fail_on_write(fptr);
2856 if ((
int)rb_io_blocking_region(fptr, nogvl_fdatasync, fptr) == 0)
2860 return rb_io_fsync(io);
2863#define rb_io_fdatasync rb_io_fsync
2881rb_io_fileno(
VALUE io)
2901 if (!UNDEF_P(fileno)) {
2989rb_io_inspect(
VALUE obj)
2993 static const char closed[] =
" (closed)";
2995 fptr =
RFILE(obj)->fptr;
3002 rb_str_cat(result, closed+1, strlen(closed)-1);
3005 rb_str_catf(result,
"fd %d", fptr->
fd);
3026rb_io_to_io(
VALUE io)
3033read_buffered_data(
char *ptr,
long len,
rb_io_t *fptr)
3037 n = READ_DATA_PENDING_COUNT(fptr);
3038 if (n <= 0)
return 0;
3039 if (n >
len) n = (int)
len;
3047io_bufread(
char *ptr,
long len,
rb_io_t *fptr)
3053 if (READ_DATA_PENDING(fptr) == 0) {
3057 c = rb_io_read_memory(fptr, ptr+offset, n);
3060 if (fptr_wait_readable(fptr))
3065 if ((n -= c) <= 0)
break;
3071 c = read_buffered_data(ptr+offset, n, fptr);
3074 if ((n -= c) <= 0)
break;
3077 if (io_fillbuf(fptr) < 0) {
3084static int io_setstrbuf(
VALUE *str,
long len);
3093bufread_call(
VALUE arg)
3096 p->len = io_bufread(p->str_ptr, p->len, p->fptr);
3101io_fread(
VALUE str,
long offset,
long size,
rb_io_t *fptr)
3106 io_setstrbuf(&str, offset + size);
3107 arg.str_ptr = RSTRING_PTR(str) + offset;
3110 rb_str_locktmp_ensure(str, bufread_call, (
VALUE)&arg);
3112 if (
len < 0) rb_sys_fail_path(fptr->
pathv);
3120 rb_off_t siz = READ_DATA_PENDING_COUNT(fptr);
3123 if (fstat(fptr->
fd, &st) == 0 && S_ISREG(st.st_mode)
3124#
if defined(__HAIKU__)
3129 if (io_fflush(fptr) < 0)
3130 rb_sys_fail_on_write(fptr);
3131 pos = lseek(fptr->
fd, 0, SEEK_CUR);
3132 if (st.st_size >= pos && pos >= 0) {
3133 siz += st.st_size - pos;
3134 if (siz > LONG_MAX) {
3135 rb_raise(
rb_eIOError,
"file too big for single read");
3148 rb_enc_associate(str, io_read_encoding(fptr));
3155make_readconv(
rb_io_t *fptr,
int size)
3160 const char *sname, *dname;
3161 ecflags = fptr->
encs.
ecflags & ~ECONV_NEWLINE_DECORATOR_WRITE_MASK;
3164 sname = rb_enc_name(fptr->
encs.
enc2);
3165 dname = rb_enc_name(io_read_encoding(fptr));
3175 if (size < IO_CBUF_CAPA_MIN) size = IO_CBUF_CAPA_MIN;
3181#define MORE_CHAR_SUSPENDED Qtrue
3182#define MORE_CHAR_FINISHED Qnil
3184fill_cbuf(
rb_io_t *fptr,
int ec_flags)
3186 const unsigned char *ss, *sp, *se;
3187 unsigned char *ds, *dp, *de;
3196 return MORE_CHAR_SUSPENDED;
3207 ss = sp = (
const unsigned char *)fptr->
rbuf.
ptr + fptr->
rbuf.
off;
3212 fptr->
rbuf.
off += (int)(sp - ss);
3213 fptr->
rbuf.
len -= (int)(sp - ss);
3214 fptr->
cbuf.
len += (int)(dp - ds);
3219 fptr->
rbuf.
off -= putbackable;
3220 fptr->
rbuf.
len += putbackable;
3227 if (cbuf_len0 != fptr->
cbuf.
len)
3228 return MORE_CHAR_SUSPENDED;
3231 return MORE_CHAR_FINISHED;
3237 if (io_fillbuf(fptr) < 0) {
3239 return MORE_CHAR_FINISHED;
3244 fptr->
cbuf.
len += (int)(dp - ds);
3251 if (cbuf_len0 != fptr->
cbuf.
len)
3252 return MORE_CHAR_SUSPENDED;
3254 return MORE_CHAR_FINISHED;
3262 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED)
3279 rb_enc_associate(str, fptr->
encs.
enc);
3308 long clen = RSTRING_LEN(s);
3320#define MAX_REALLOC_GAP 4096
3322io_shrink_read_string(
VALUE str,
long n)
3325 rb_str_resize(str, n);
3330io_set_read_length(
VALUE str,
long n,
int shrinkable)
3332 if (RSTRING_LEN(str) != n) {
3335 if (shrinkable) io_shrink_read_string(str, n);
3349 if (NEED_READCONV(fptr)) {
3350 int first = !
NIL_P(str);
3351 SET_BINARY_MODE(fptr);
3352 shrinkable = io_setstrbuf(&str,0);
3353 make_readconv(fptr, 0);
3358 io_shift_cbuf(fptr, fptr->
cbuf.
len, &str);
3360 v = fill_cbuf(fptr, 0);
3361 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED) {
3364 io_shift_cbuf(fptr, fptr->
cbuf.
len, &str);
3368 if (v == MORE_CHAR_FINISHED) {
3369 clear_readconv(fptr);
3371 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3372 return io_enc_str(str, fptr);
3377 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3381 enc = io_read_encoding(fptr);
3384 if (siz == 0) siz = BUFSIZ;
3385 shrinkable = io_setstrbuf(&str, siz);
3388 n = io_fread(str, bytes, siz - bytes, fptr);
3389 if (n == 0 && bytes == 0) {
3397 if (bytes < siz)
break;
3401 if (
capa < (
size_t)RSTRING_LEN(str) + BUFSIZ) {
3402 if (
capa < BUFSIZ) {
3405 else if (
capa > IO_MAX_BUFFER_GROWTH) {
3406 capa = IO_MAX_BUFFER_GROWTH;
3411 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3412 str = io_enc_str(str, fptr);
3420 if (rb_fd_set_nonblock(fptr->
fd) != 0) {
3421 rb_sys_fail_path(fptr->
pathv);
3426io_read_memory_call(
VALUE arg)
3431 if (scheduler !=
Qnil) {
3434 if (!UNDEF_P(result)) {
3440 if (iis->nonblock) {
3441 return rb_io_blocking_region(iis->fptr, internal_read_func, iis);
3444 return rb_io_blocking_region_wait(iis->fptr, internal_read_func, iis,
RUBY_IO_READABLE);
3451 return (
long)rb_str_locktmp_ensure(str, io_read_memory_call, (
VALUE)iis);
3454#define no_exception_p(opts) !rb_opts_exception_p((opts), TRUE)
3457io_getpartial(
int argc,
VALUE *argv,
VALUE io,
int no_exception,
int nonblock)
3468 rb_raise(rb_eArgError,
"negative length %ld given",
len);
3471 shrinkable = io_setstrbuf(&str,
len);
3477 io_set_read_length(str, 0, shrinkable);
3483 n = read_buffered_data(RSTRING_PTR(str),
len, fptr);
3489 io_setstrbuf(&str,
len);
3492 iis.nonblock = nonblock;
3494 iis.buf = RSTRING_PTR(str);
3497 n = io_read_memory_locktmp(str, &iis);
3500 if (!nonblock && fptr_wait_readable(fptr))
3502 if (nonblock && (io_again_p(e))) {
3504 return sym_wait_readable;
3507 e,
"read would block");
3509 rb_syserr_fail_path(e, fptr->
pathv);
3512 io_set_read_length(str, n, shrinkable);
3613io_readpartial(
int argc,
VALUE *argv,
VALUE io)
3617 ret = io_getpartial(argc, argv, io,
Qnil, 0);
3624io_nonblock_eof(
int no_exception)
3626 if (!no_exception) {
3642 rb_raise(rb_eArgError,
"negative length %ld given",
len);
3645 shrinkable = io_setstrbuf(&str,
len);
3646 rb_bool_expected(ex,
"exception", TRUE);
3652 io_set_read_length(str, 0, shrinkable);
3656 n = read_buffered_data(RSTRING_PTR(str),
len, fptr);
3658 rb_fd_set_nonblock(fptr->
fd);
3659 shrinkable |= io_setstrbuf(&str,
len);
3663 iis.buf = RSTRING_PTR(str);
3666 n = io_read_memory_locktmp(str, &iis);
3669 if (io_again_p(e)) {
3670 if (!ex)
return sym_wait_readable;
3672 e,
"read would block");
3674 rb_syserr_fail_path(e, fptr->
pathv);
3677 io_set_read_length(str, n, shrinkable);
3680 if (!ex)
return Qnil;
3696 rb_bool_expected(ex,
"exception", TRUE);
3698 io = GetWriteIO(io);
3702 if (io_fflush(fptr) < 0)
3703 rb_sys_fail_on_write(fptr);
3705 rb_fd_set_nonblock(fptr->
fd);
3706 n = write(fptr->
fd, RSTRING_PTR(str), RSTRING_LEN(str));
3711 if (io_again_p(e)) {
3713 return sym_wait_writable;
3719 rb_syserr_fail_path(e, fptr->
pathv);
3803#if RUBY_CRLF_ENVIRONMENT
3809 if (
NIL_P(length)) {
3812 return read_all(fptr, remain_size(fptr), str);
3816 rb_raise(rb_eArgError,
"negative length %ld given",
len);
3819 shrinkable = io_setstrbuf(&str,
len);
3824 io_set_read_length(str, 0, shrinkable);
3829#if RUBY_CRLF_ENVIRONMENT
3830 previous_mode = set_binary_mode_with_seek_cur(fptr);
3832 n = io_fread(str, 0,
len, fptr);
3833 io_set_read_length(str, n, shrinkable);
3834#if RUBY_CRLF_ENVIRONMENT
3835 if (previous_mode == O_TEXT) {
3836 setmode(fptr->
fd, O_TEXT);
3839 if (n == 0)
return Qnil;
3845rscheck(
const char *rsptr,
long rslen,
VALUE rs)
3848 if (RSTRING_PTR(rs) != rsptr && RSTRING_LEN(rs) != rslen)
3853search_delim(
const char *p,
long len,
int delim,
rb_encoding *enc)
3855 if (rb_enc_mbminlen(enc) == 1) {
3856 p = memchr(p, delim,
len);
3857 if (p)
return p + 1;
3860 const char *end = p +
len;
3862 int r = rb_enc_precise_mbclen(p, end, enc);
3864 p += rb_enc_mbminlen(enc);
3868 if (rb_enc_mbc_to_codepoint(p, end, enc) == (
unsigned int)delim) {
3883 if (NEED_READCONV(fptr)) {
3884 SET_BINARY_MODE(fptr);
3885 make_readconv(fptr, 0);
3888 int searchlen = READ_CHAR_PENDING_COUNT(fptr);
3890 p = READ_CHAR_PENDING_PTR(fptr);
3891 if (0 < limit && limit < searchlen)
3892 searchlen = (int)limit;
3893 e = search_delim(p, searchlen, delim, enc);
3895 int len = (int)(e-p);
3917 return (
unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
3920 }
while (more_char(fptr) != MORE_CHAR_FINISHED);
3921 clear_readconv(fptr);
3926 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3928 long pending = READ_DATA_PENDING_COUNT(fptr);
3930 const char *p = READ_DATA_PENDING_PTR(fptr);
3934 if (limit > 0 && pending > limit) pending = limit;
3935 e = search_delim(p, pending, delim, enc);
3936 if (e) pending = e - p;
3938 last = RSTRING_LEN(str);
3939 rb_str_resize(str, last + pending);
3946 read_buffered_data(RSTRING_PTR(str) + last, pending, fptr);
3949 if (e)
return delim;
3951 return (
unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
3954 }
while (io_fillbuf(fptr) >= 0);
3960swallow(
rb_io_t *fptr,
int term)
3962 if (NEED_READCONV(fptr)) {
3964 int needconv = rb_enc_mbminlen(enc) != 1;
3965 SET_BINARY_MODE(fptr);
3966 make_readconv(fptr, 0);
3969 while ((cnt = READ_CHAR_PENDING_COUNT(fptr)) > 0) {
3970 const char *p = READ_CHAR_PENDING_PTR(fptr);
3973 if (*p != term)
return TRUE;
3975 while (--i && *++p == term);
3978 const char *e = p + cnt;
3979 if (rb_enc_ascget(p, e, &i, enc) != term)
return TRUE;
3980 while ((p += i) < e && rb_enc_ascget(p, e, &i, enc) == term);
3983 io_shift_cbuf(fptr, (
int)cnt - i, NULL);
3985 }
while (more_char(fptr) != MORE_CHAR_FINISHED);
3989 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3992 while ((cnt = READ_DATA_PENDING_COUNT(fptr)) > 0) {
3994 const char *p = READ_DATA_PENDING_PTR(fptr);
3996 if (cnt >
sizeof buf) cnt =
sizeof buf;
3997 if (*p != term)
return TRUE;
3999 while (--i && *++p == term);
4000 if (!read_buffered_data(buf, cnt - i, fptr))
4001 rb_sys_fail_path(fptr->
pathv);
4004 }
while (io_fillbuf(fptr) == 0);
4017 int pending = READ_DATA_PENDING_COUNT(fptr);
4020 const char *p = READ_DATA_PENDING_PTR(fptr);
4024 e = memchr(p,
'\n', pending);
4026 pending = (int)(e - p + 1);
4028 chomplen = (pending > 1 && *(e-1) ==
'\r') + 1;
4037 rb_str_resize(str,
len + pending - chomplen);
4038 read_buffered_data(RSTRING_PTR(str)+
len, pending - chomplen, fptr);
4041 if (pending == 1 && chomplen == 1 &&
len > 0) {
4042 if (RSTRING_PTR(str)[
len-1] ==
'\r') {
4043 rb_str_resize(str, --
len);
4048 len += pending - chomplen;
4054 }
while (io_fillbuf(fptr) >= 0);
4057 str = io_enc_str(str, fptr);
4068 unsigned int chomp: 1;
4082 chomp = (!UNDEF_P(vchomp)) &&
RTEST(vchomp);
4084 args->chomp = chomp;
4102 else if (2 <= argc) {
4103 rs = argv[0], lim = argv[1];
4112check_getline_args(
VALUE *rsp,
long *limit,
VALUE io)
4121 enc_rs = rb_enc_get(rs);
4122 enc_io = io_read_encoding(fptr);
4123 if (enc_io != enc_rs &&
4124 (!is_ascii_string(rs) ||
4125 (RSTRING_LEN(rs) > 0 && !rb_enc_asciicompat(enc_io)))) {
4126 if (rs == rb_default_rs) {
4127 rs = rb_enc_str_new(0, 0, enc_io);
4132 rb_raise(rb_eArgError,
"encoding mismatch: %s IO with %s RS",
4133 rb_enc_name(enc_io),
4134 rb_enc_name(enc_rs));
4144 argc =
rb_scan_args(argc, argv,
"02:", NULL, NULL, &opts);
4145 extract_getline_args(argc, argv, args);
4146 extract_getline_opts(opts, args);
4147 check_getline_args(&args->rs, &args->limit, io);
4151rb_io_getline_0(
VALUE rs,
long limit,
int chomp,
rb_io_t *fptr)
4158 if (
NIL_P(rs) && limit < 0) {
4159 str = read_all(fptr, 0,
Qnil);
4160 if (RSTRING_LEN(str) == 0)
return Qnil;
4162 else if (limit == 0) {
4163 return rb_enc_str_new(0, 0, io_read_encoding(fptr));
4165 else if (rs == rb_default_rs && limit < 0 && !NEED_READCONV(fptr) &&
4166 rb_enc_asciicompat(enc = io_read_encoding(fptr))) {
4167 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4168 return rb_io_getline_fast(fptr, enc, chomp);
4171 int c, newline = -1;
4172 const char *rsptr = 0;
4175 int extra_limit = 16;
4176 int chomp_cr = chomp;
4178 SET_BINARY_MODE(fptr);
4179 enc = io_read_encoding(fptr);
4182 rslen = RSTRING_LEN(rs);
4187 swallow(fptr,
'\n');
4189 if (!rb_enc_asciicompat(enc)) {
4193 rsptr = RSTRING_PTR(rs);
4194 rslen = RSTRING_LEN(rs);
4198 else if (rb_enc_mbminlen(enc) == 1) {
4199 rsptr = RSTRING_PTR(rs);
4200 newline = (
unsigned char)rsptr[rslen - 1];
4204 rsptr = RSTRING_PTR(rs);
4205 const char *e = rsptr + rslen;
4206 const char *last = rb_enc_prev_char(rsptr, e, e, enc);
4208 newline = rb_enc_codepoint_len(last, e, &n, enc);
4209 if (last + n != e) rb_raise(rb_eArgError,
"broken separator");
4211 chomp_cr = chomp && newline ==
'\n' && rslen == rb_enc_mbminlen(enc);
4215 while ((c = appendline(fptr, newline, &str, &limit, enc)) != EOF) {
4216 const char *s, *p, *pp, *e;
4219 if (RSTRING_LEN(str) < rslen)
continue;
4220 s = RSTRING_PTR(str);
4223 if (!at_char_boundary(s, p, e, enc))
continue;
4224 if (!rspara) rscheck(rsptr, rslen, rs);
4225 if (memcmp(p, rsptr, rslen) == 0) {
4227 if (chomp_cr && p > s && *(p-1) ==
'\r') --p;
4234 s = RSTRING_PTR(str);
4236 pp = rb_enc_prev_char(s, p, p, enc);
4237 if (extra_limit && pp &&
4251 if (rspara && c != EOF)
4252 swallow(fptr,
'\n');
4254 str = io_enc_str(str, fptr);
4257 if (!
NIL_P(str) && !nolimit) {
4265rb_io_getline_1(
VALUE rs,
long limit,
int chomp,
VALUE io)
4268 int old_lineno, new_lineno;
4272 old_lineno = fptr->
lineno;
4273 str = rb_io_getline_0(rs, limit, chomp, fptr);
4274 if (!
NIL_P(str) && (new_lineno = fptr->
lineno) != old_lineno) {
4275 if (io == ARGF.current_file) {
4276 ARGF.lineno += new_lineno - old_lineno;
4277 ARGF.last_lineno = ARGF.lineno;
4280 ARGF.last_lineno = new_lineno;
4288rb_io_getline(
int argc,
VALUE *argv,
VALUE io)
4292 prepare_getline_args(argc, argv, &args, io);
4293 return rb_io_getline_1(args.rs, args.limit, args.chomp, io);
4303rb_io_gets_internal(
VALUE io)
4307 return rb_io_getline_0(rb_default_rs, -1, FALSE, fptr);
4387 str = rb_io_getline(argc, argv, io);
4403rb_io_lineno(
VALUE io)
4458 check_getline_args(&sep, &limit, io);
4460 VALUE line = rb_io_getline_1(sep, limit,
RTEST(chomp), io);
4461 rb_lastline_set_up(line, 1);
4536rb_io_readlines(
int argc,
VALUE *argv,
VALUE io)
4540 prepare_getline_args(argc, argv, &args, io);
4541 return io_readlines(&args, io);
4549 if (arg->limit == 0)
4550 rb_raise(rb_eArgError,
"invalid limit: 0 for readlines");
4552 while (!
NIL_P(line = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, io))) {
4553 rb_ary_push(ary, line);
4665rb_io_each_line(
int argc,
VALUE *argv,
VALUE io)
4671 prepare_getline_args(argc, argv, &args, io);
4672 if (args.limit == 0)
4673 rb_raise(rb_eArgError,
"invalid limit: 0 for each_line");
4674 while (!
NIL_P(str = rb_io_getline_1(args.rs, args.limit, args.chomp, io))) {
4701rb_io_each_byte(
VALUE io)
4717 }
while (io_fillbuf(fptr) >= 0);
4727 if (NEED_READCONV(fptr)) {
4731 SET_BINARY_MODE(fptr);
4732 make_readconv(fptr, 0);
4746 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4748 clear_readconv(fptr);
4752 str = rb_enc_str_new(fptr->
cbuf.
ptr+fptr->
cbuf.
off, 1, read_enc);
4755 if (fptr->
cbuf.
len == 0) clear_readconv(fptr);
4764 io_shift_cbuf(fptr, r, &str);
4771 ISASCII(RSTRING_PTR(str)[0])) {
4775 str = io_enc_str(str, fptr);
4780 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4781 if (io_fillbuf(fptr) < 0) {
4803 if (io_fillbuf(fptr) != -1) {
4807 r = rb_enc_precise_mbclen(RSTRING_PTR(str), RSTRING_PTR(str)+RSTRING_LEN(str), enc);
4823 str = io_enc_str(str, fptr);
4849rb_io_each_char(
VALUE io)
4859 enc = io_input_encoding(fptr);
4861 while (!
NIL_P(c = io_getc(fptr, enc))) {
4887rb_io_each_codepoint(
VALUE io)
4899 if (NEED_READCONV(fptr)) {
4900 SET_BINARY_MODE(fptr);
4903 make_readconv(fptr, 0);
4911 r = ONIGENC_CONSTRUCT_MBCLEN_CHARFOUND(1);
4918 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4919 clear_readconv(fptr);
4946 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4947 enc = io_input_encoding(fptr);
4948 while (io_fillbuf(fptr) >= 0) {
4963 char cbuf[8], *p = cbuf;
4965 if (more > numberof(cbuf))
goto invalid;
4967 if (more > numberof(cbuf))
goto invalid;
4968 while ((n = (
int)read_buffered_data(p, more, fptr)) > 0 &&
4969 (p += n, (more -= n) > 0)) {
4970 if (io_fillbuf(fptr) < 0)
goto invalid;
4971 if ((n = fptr->
rbuf.
len) > more) n = more;
4973 r = rb_enc_precise_mbclen(cbuf, p, enc);
4986 rb_raise(rb_eArgError,
"invalid byte sequence in %s", rb_enc_name(enc));
5018 enc = io_input_encoding(fptr);
5020 return io_getc(fptr, enc);
5043rb_io_readchar(
VALUE io)
5045 VALUE c = rb_io_getc(io);
5080 VALUE r_stdout = rb_ractor_stdout();
5085 rb_io_flush(r_stdout);
5088 if (io_fillbuf(fptr) < 0) {
5117rb_io_readbyte(
VALUE io)
5178 unsigned char c =
NUM2INT(v) & 0xFF;
5184 io_ungetbyte(b, fptr);
5240 else if (RB_BIGNUM_TYPE_P(c)) {
5246 if (NEED_READCONV(fptr)) {
5247 SET_BINARY_MODE(fptr);
5248 len = RSTRING_LEN(c);
5249#if SIZEOF_LONG > SIZEOF_INT
5253 make_readconv(fptr, (
int)
len);
5267 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
5268 io_ungetbyte(c, fptr);
5288rb_io_isatty(
VALUE io)
5293 return RBOOL(isatty(fptr->
fd) != 0);
5296#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5312rb_io_close_on_exec_p(
VALUE io)
5318 write_io = GetWriteIO(io);
5319 if (io != write_io) {
5321 if (fptr && 0 <= (fd = fptr->
fd)) {
5322 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->
pathv);
5323 if (!(ret & FD_CLOEXEC))
return Qfalse;
5328 if (fptr && 0 <= (fd = fptr->
fd)) {
5329 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->
pathv);
5330 if (!(ret & FD_CLOEXEC))
return Qfalse;
5335#define rb_io_close_on_exec_p rb_f_notimplement
5338#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5362 int flag =
RTEST(arg) ? FD_CLOEXEC : 0;
5367 write_io = GetWriteIO(io);
5368 if (io != write_io) {
5370 if (fptr && 0 <= (fd = fptr->
fd)) {
5371 if ((ret = fcntl(fptr->
fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->
pathv);
5372 if ((ret & FD_CLOEXEC) != flag) {
5373 ret = (ret & ~FD_CLOEXEC) | flag;
5374 ret = fcntl(fd, F_SETFD, ret);
5375 if (ret != 0) rb_sys_fail_path(fptr->
pathv);
5382 if (fptr && 0 <= (fd = fptr->
fd)) {
5383 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->
pathv);
5384 if ((ret & FD_CLOEXEC) != flag) {
5385 ret = (ret & ~FD_CLOEXEC) | flag;
5386 ret = fcntl(fd, F_SETFD, ret);
5387 if (ret != 0) rb_sys_fail_path(fptr->
pathv);
5393#define rb_io_set_close_on_exec rb_f_notimplement
5396#define RUBY_IO_EXTERNAL_P(f) ((f)->mode & FMODE_EXTERNAL)
5397#define PREP_STDIO_NAME(f) (RSTRING_PTR((f)->pathv))
5400finish_writeconv(
rb_io_t *fptr,
int noalloc)
5402 unsigned char *ds, *dp, *de;
5406 unsigned char buf[1024];
5411 de = buf +
sizeof(buf);
5414 size_t remaining = dp-ds;
5415 long result = rb_io_write_memory(fptr, ds, remaining);
5419 if ((
size_t)result == remaining)
break;
5442 if (io_fflush(fptr) < 0) {
5450 fptr->
wbuf.
len += (int)(dp - ds);
5466finish_writeconv_sync(
VALUE arg)
5469 return finish_writeconv(p->fptr, p->noalloc);
5473nogvl_close(
void *ptr)
5477 return (
void*)(intptr_t)close(*fd);
5481maygvl_close(
int fd,
int keepgvl)
5490 return IO_WITHOUT_GVL_INT(nogvl_close, &fd);
5494nogvl_fclose(
void *ptr)
5498 return (
void*)(intptr_t)fclose(file);
5502maygvl_fclose(
FILE *file,
int keepgvl)
5505 return fclose(file);
5507 return IO_WITHOUT_GVL_INT(nogvl_fclose, file);
5513fptr_finalize_flush(
rb_io_t *fptr,
int noraise,
int keepgvl,
5519 int mode = fptr->
mode;
5525 arg.noalloc = noraise;
5529 error = finish_writeconv(fptr, noraise);
5534 io_flush_buffer_sync(fptr);
5537 if (io_fflush(fptr) < 0 &&
NIL_P(error)) {
5545 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2) {
5557 rb_notify_fd_close_wait(busy);
5569 if (!done && stdio_file) {
5571 if ((maygvl_fclose(stdio_file, noraise) < 0) &&
NIL_P(error)) {
5580 if (!done && fd >= 0) {
5586 if ((maygvl_close(fd, keepgvl) < 0) &&
NIL_P(error)) {
5595 if (!
NIL_P(error) && !noraise) {
5604fptr_finalize(
rb_io_t *fptr,
int noraise)
5606 fptr_finalize_flush(fptr, noraise, FALSE, 0);
5607 free_io_buffer(&fptr->
rbuf);
5608 free_io_buffer(&fptr->
wbuf);
5609 clear_codeconv(fptr);
5613rb_io_fptr_cleanup(
rb_io_t *fptr,
int noraise)
5619 fptr_finalize(fptr, noraise);
5627 ruby_sized_xfree(buf->
ptr, (
size_t)buf->
capa);
5639 free_io_buffer(&fptr->
cbuf);
5655 clear_readconv(fptr);
5656 clear_writeconv(fptr);
5660rb_io_fptr_cleanup_all(
rb_io_t *fptr)
5664 rb_io_fptr_cleanup(fptr, TRUE);
5666 free_io_buffer(&fptr->
rbuf);
5667 free_io_buffer(&fptr->
wbuf);
5668 clear_codeconv(fptr);
5672rb_io_fptr_finalize_internal(
void *ptr)
5675 rb_io_fptr_cleanup_all(ptr);
5679#undef rb_io_fptr_finalize
5687 rb_io_fptr_finalize_internal(fptr);
5691#define rb_io_fptr_finalize(fptr) rb_io_fptr_finalize_internal(fptr)
5694rb_io_memsize(
const rb_io_t *fptr)
5696 size_t size =
sizeof(
rb_io_t);
5707# define KEEPGVL TRUE
5709# define KEEPGVL FALSE
5713io_close_fptr(
VALUE io)
5720 write_io = GetWriteIO(io);
5721 if (io != write_io) {
5722 write_fptr =
RFILE(write_io)->fptr;
5723 if (write_fptr && 0 <= write_fptr->
fd) {
5724 rb_io_fptr_cleanup(write_fptr, TRUE);
5728 fptr =
RFILE(io)->fptr;
5729 if (!fptr)
return 0;
5730 if (fptr->
fd < 0)
return 0;
5732 if (rb_notify_fd_close(fptr->
fd, &busy)) {
5734 fptr_finalize_flush(fptr, FALSE, KEEPGVL, &busy);
5736 rb_io_fptr_cleanup(fptr, FALSE);
5741fptr_waitpid(
rb_io_t *fptr,
int nohang)
5745 rb_last_status_clear();
5754 rb_io_t *fptr = io_close_fptr(io);
5755 if (fptr) fptr_waitpid(fptr, 0);
5795rb_io_close_m(
VALUE io)
5797 rb_io_t *fptr = rb_io_get_fptr(io);
5806io_call_close(
VALUE io)
5815 enum {mesg_len =
sizeof(closed_stream)-1};
5816 VALUE mesg = rb_attr_get(exc, idMesg);
5818 RSTRING_LEN(mesg) != mesg_len ||
5819 memcmp(RSTRING_PTR(mesg), closed_stream, mesg_len)) {
5829 if (!UNDEF_P(closed) &&
RTEST(closed))
return io;
5830 rb_rescue2(io_call_close, io, ignore_closed_stream, io,
5866 write_io = GetWriteIO(io);
5867 if (io != write_io) {
5868 write_fptr =
RFILE(write_io)->fptr;
5869 if (write_fptr && 0 <= write_fptr->
fd) {
5874 fptr = rb_io_get_fptr(io);
5875 return RBOOL(0 > fptr->
fd);
5911rb_io_close_read(
VALUE io)
5917 if (fptr->
fd < 0)
return Qnil;
5918 if (is_socket(fptr->
fd, fptr->
pathv)) {
5922 if (shutdown(fptr->
fd, SHUT_RD) < 0)
5923 rb_sys_fail_path(fptr->
pathv);
5924 fptr->
mode &= ~FMODE_READABLE;
5930 write_io = GetWriteIO(io);
5931 if (io != write_io) {
5936 RFILE(io)->fptr = wfptr;
5939 RFILE(write_io)->fptr = fptr;
5940 rb_io_fptr_cleanup(fptr, FALSE);
5946 rb_raise(
rb_eIOError,
"closing non-duplex IO for reading");
5984rb_io_close_write(
VALUE io)
5989 write_io = GetWriteIO(io);
5991 if (fptr->
fd < 0)
return Qnil;
5992 if (is_socket(fptr->
fd, fptr->
pathv)) {
5996 if (shutdown(fptr->
fd, SHUT_WR) < 0)
5997 rb_sys_fail_path(fptr->
pathv);
5998 fptr->
mode &= ~FMODE_WRITABLE;
6005 rb_raise(
rb_eIOError,
"closing non-duplex IO for writing");
6008 if (io != write_io) {
6028rb_io_sysseek(
int argc,
VALUE *argv,
VALUE io)
6030 VALUE offset, ptrname;
6031 int whence = SEEK_SET;
6035 if (
rb_scan_args(argc, argv,
"11", &offset, &ptrname) == 2) {
6036 whence = interpret_seek_whence(ptrname);
6041 (READ_DATA_BUFFERED(fptr) || READ_CHAR_PENDING(fptr))) {
6045 rb_warn(
"sysseek for buffered IO");
6048 pos = lseek(fptr->
fd, pos, whence);
6049 if (pos < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
6083 io = GetWriteIO(io);
6088 rb_warn(
"syswrite for buffered IO");
6091 tmp = rb_str_tmp_frozen_acquire(str);
6093 n = rb_io_write_memory(fptr, ptr,
len);
6094 if (n < 0) rb_sys_fail_path(fptr->
pathv);
6095 rb_str_tmp_frozen_release(str, tmp);
6112rb_io_sysread(
int argc,
VALUE *argv,
VALUE io)
6123 shrinkable = io_setstrbuf(&str, ilen);
6124 if (ilen == 0)
return str;
6129 if (READ_DATA_BUFFERED(fptr)) {
6135 io_setstrbuf(&str, ilen);
6140 iis.buf = RSTRING_PTR(str);
6143 n = io_read_memory_locktmp(str, &iis);
6146 rb_sys_fail_path(fptr->
pathv);
6149 io_set_read_length(str, n, shrinkable);
6151 if (n == 0 && ilen > 0) {
6167internal_pread_func(
void *_arg)
6171 return (
VALUE)pread(arg->fd, arg->buf, arg->count, arg->offset);
6175pread_internal_call(
VALUE _arg)
6180 if (scheduler !=
Qnil) {
6183 if (!UNDEF_P(result)) {
6188 return rb_io_blocking_region_wait(arg->io, internal_pread_func, arg,
RUBY_IO_READABLE);
6232 shrinkable = io_setstrbuf(&str, (
long)arg.count);
6233 if (arg.count == 0)
return str;
6234 arg.buf = RSTRING_PTR(str);
6247 rb_sys_fail_path(fptr->
pathv);
6249 io_set_read_length(str, n, shrinkable);
6250 if (n == 0 && arg.count > 0) {
6258internal_pwrite_func(
void *_arg)
6263 if (scheduler !=
Qnil) {
6266 if (!UNDEF_P(result)) {
6272 return (
VALUE)pwrite(arg->fd, arg->buf, arg->count, arg->offset);
6313 io = GetWriteIO(io);
6320 tmp = rb_str_tmp_frozen_acquire(str);
6321 arg.buf = RSTRING_PTR(tmp);
6322 arg.count = (size_t)RSTRING_LEN(tmp);
6324 n = (ssize_t)rb_io_blocking_region_wait(fptr, internal_pwrite_func, &arg,
RUBY_IO_WRITABLE);
6325 if (n < 0) rb_sys_fail_path(fptr->
pathv);
6326 rb_str_tmp_frozen_release(str, tmp);
6342 fptr->
mode &= ~FMODE_TEXTMODE;
6346 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6349 setmode(fptr->
fd, O_BINARY);
6356io_ascii8bit_binmode(
rb_io_t *fptr)
6367 fptr->
mode &= ~FMODE_TEXTMODE;
6368 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6370 fptr->
encs.
enc = rb_ascii8bit_encoding();
6374 clear_codeconv(fptr);
6383 io_ascii8bit_binmode(fptr);
6400rb_io_binmode_m(
VALUE io)
6406 write_io = GetWriteIO(io);
6421rb_io_binmode_p(
VALUE io)
6429rb_io_fmode_modestr(
int fmode)
6433 return MODE_BTMODE(
"a+",
"ab+",
"at+");
6435 return MODE_BTMODE(
"a",
"ab",
"at");
6439 rb_raise(rb_eArgError,
"invalid access fmode 0x%x", fmode);
6441 return MODE_BTMODE(
"r",
"rb",
"rt");
6443 return MODE_BTXMODE(
"w",
"wb",
"wt",
"wx",
"wbx",
"wtx");
6446 return MODE_BTXMODE(
"w+",
"wb+",
"wt+",
"w+x",
"wb+x",
"wt+x");
6448 return MODE_BTMODE(
"r+",
"rb+",
"rt+");
6452static const char bom_prefix[] =
"bom|";
6453static const char utf_prefix[] =
"utf-";
6454enum {bom_prefix_len = (int)
sizeof(bom_prefix) - 1};
6455enum {utf_prefix_len = (int)
sizeof(utf_prefix) - 1};
6458io_encname_bom_p(
const char *name,
long len)
6460 return len > bom_prefix_len &&
STRNCASECMP(name, bom_prefix, bom_prefix_len) == 0;
6467 const char *m = modestr, *p = NULL;
6495 if (modestr[0] !=
'w')
6503 if (io_encname_bom_p(m, p ? (
long)(p - m) : (long)strlen(m)))
6516 rb_raise(rb_eArgError,
"invalid access mode %s", modestr);
6521rb_io_oflags_fmode(
int oflags)
6525 switch (oflags & O_ACCMODE) {
6537 if (oflags & O_APPEND) {
6540 if (oflags & O_TRUNC) {
6543 if (oflags & O_CREAT) {
6546 if (oflags & O_EXCL) {
6550 if (oflags & O_BINARY) {
6559rb_io_fmode_oflags(
int fmode)
6603rb_io_oflags_modestr(
int oflags)
6606# define MODE_BINARY(a,b) ((oflags & O_BINARY) ? (b) : (a))
6608# define MODE_BINARY(a,b) (a)
6611 if (oflags & O_EXCL) {
6612 rb_raise(rb_eArgError,
"exclusive access mode is not supported");
6614 accmode = oflags & (O_RDONLY|O_WRONLY|O_RDWR);
6615 if (oflags & O_APPEND) {
6616 if (accmode == O_WRONLY) {
6617 return MODE_BINARY(
"a",
"ab");
6619 if (accmode == O_RDWR) {
6620 return MODE_BINARY(
"a+",
"ab+");
6625 rb_raise(rb_eArgError,
"invalid access oflags 0x%x", oflags);
6627 return MODE_BINARY(
"r",
"rb");
6629 return MODE_BINARY(
"w",
"wb");
6631 if (oflags & O_TRUNC) {
6632 return MODE_BINARY(
"w+",
"wb+");
6634 return MODE_BINARY(
"r+",
"rb+");
6646 int default_ext = 0;
6649 ext = rb_default_external_encoding();
6652 if (rb_is_ascii8bit_enc(ext)) {
6656 else if (intern == NULL) {
6657 intern = rb_default_internal_encoding();
6662 *enc = (default_ext && intern != ext) ? NULL : ext;
6672unsupported_encoding(
const char *name,
rb_encoding *enc)
6674 rb_enc_warn(enc,
"Unsupported encoding %s ignored", name);
6678parse_mode_enc(
const char *estr,
rb_encoding *estr_enc,
6684 int fmode = fmode_p ? *fmode_p : 0;
6690 p = strrchr(estr,
':');
6691 len = p ? (p++ - estr) : (long)strlen(estr);
6693 estr += bom_prefix_len;
6694 len -= bom_prefix_len;
6695 if (!
STRNCASECMP(estr, utf_prefix, utf_prefix_len)) {
6699 rb_enc_warn(estr_enc,
"BOM with non-UTF encoding %s is nonsense", estr);
6700 fmode &= ~FMODE_SETENC_BY_BOM;
6708 memcpy(encname, estr,
len);
6709 encname[
len] =
'\0';
6712 idx = rb_enc_find_index(estr);
6714 if (fmode_p) *fmode_p = fmode;
6717 ext_enc = rb_enc_from_index(idx);
6720 unsupported_encoding(estr, estr_enc);
6726 if (*p ==
'-' && *(p+1) ==
'\0') {
6731 idx2 = rb_enc_find_index(p);
6733 unsupported_encoding(p, estr_enc);
6738 int_enc = rb_enc_from_index(idx2);
6742 rb_io_ext_int_to_encs(ext_enc, int_enc, enc_p, enc2_p, fmode);
6755 v = rb_hash_lookup2(opt, sym_encoding,
Qnil);
6756 if (v !=
Qnil) encoding = v;
6757 v = rb_hash_lookup2(opt, sym_extenc,
Qundef);
6758 if (v !=
Qnil) extenc = v;
6759 v = rb_hash_lookup2(opt, sym_intenc,
Qundef);
6760 if (!UNDEF_P(v)) intenc = v;
6762 if ((!UNDEF_P(extenc) || !UNDEF_P(intenc)) && !
NIL_P(encoding)) {
6764 int idx = rb_to_encoding_index(encoding);
6765 if (idx >= 0) encoding = rb_enc_from_encoding(rb_enc_from_index(idx));
6766 rb_warn(
"Ignoring encoding parameter '%"PRIsVALUE
"': %s_encoding is used",
6767 encoding, UNDEF_P(extenc) ?
"internal" :
"external");
6771 if (!UNDEF_P(extenc) && !
NIL_P(extenc)) {
6772 extencoding = rb_to_encoding(extenc);
6774 if (!UNDEF_P(intenc)) {
6775 if (
NIL_P(intenc)) {
6782 if (*p ==
'-' && *(p+1) ==
'\0') {
6787 intencoding = rb_to_encoding(intenc);
6791 intencoding = rb_to_encoding(intenc);
6793 if (extencoding == intencoding) {
6797 if (!
NIL_P(encoding)) {
6801 enc_p, enc2_p, fmode_p);
6804 rb_io_ext_int_to_encs(rb_to_encoding(encoding), NULL, enc_p, enc2_p, 0);
6807 else if (!UNDEF_P(extenc) || !UNDEF_P(intenc)) {
6809 rb_io_ext_int_to_encs(extencoding, intencoding, enc_p, enc2_p, 0);
6817 int fmode = *fmode_p;
6822 !rb_enc_asciicompat(enc ? enc : rb_default_external_encoding()))
6823 rb_raise(rb_eArgError,
"ASCII incompatible encoding needs binmode");
6826 rb_raise(rb_eArgError,
"newline decorator with binary mode");
6833#if !DEFAULT_TEXTMODE
6835 fmode &= ~FMODE_TEXTMODE;
6842extract_binmode(
VALUE opthash,
int *fmode)
6844 if (!
NIL_P(opthash)) {
6846 v = rb_hash_aref(opthash, sym_textmode);
6849 rb_raise(rb_eArgError,
"textmode specified twice");
6851 rb_raise(rb_eArgError,
"both textmode and binmode specified");
6855 v = rb_hash_aref(opthash, sym_binmode);
6858 rb_raise(rb_eArgError,
"binmode specified twice");
6860 rb_raise(rb_eArgError,
"both textmode and binmode specified");
6866 rb_raise(rb_eArgError,
"both textmode and binmode specified");
6872 int *oflags_p,
int *fmode_p,
struct rb_io_encoding *convconfig_p)
6879 int has_enc = 0, has_vmode = 0;
6885 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
6895 fmode = rb_io_oflags_fmode(oflags);
6903 oflags = rb_io_fmode_oflags(fmode);
6907 parse_mode_enc(p+1, rb_enc_get(vmode), &enc, &enc2, &fmode);
6912 e = (fmode &
FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
6913 rb_io_ext_int_to_encs(e, NULL, &enc, &enc2, fmode);
6917 if (
NIL_P(opthash)) {
6921#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
6923 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
6924 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
6926 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
6933 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
6936 else if (
NIL_P(vmode)) {
6937 fmode |= DEFAULT_TEXTMODE;
6944 v = rb_hash_aref(opthash, sym_mode);
6946 if (!
NIL_P(vmode)) {
6947 rb_raise(rb_eArgError,
"mode specified twice");
6954 v = rb_hash_aref(opthash, sym_flags);
6959 fmode = rb_io_oflags_fmode(oflags);
6961 extract_binmode(opthash, &fmode);
6967 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
6970 else if (
NIL_P(vmode)) {
6971 fmode |= DEFAULT_TEXTMODE;
6974 v = rb_hash_aref(opthash, sym_perm);
6977 if (!
NIL_P(*vperm_p)) {
6978 rb_raise(rb_eArgError,
"perm specified twice");
6989#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
6991 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
6992 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
6997 rb_raise(rb_eArgError,
"encoding specified twice");
7000 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
7004 validate_enc_binmode(&fmode, ecflags, enc, enc2);
7010 convconfig_p->
enc = enc;
7011 convconfig_p->
enc2 = enc2;
7012 convconfig_p->
ecflags = ecflags;
7013 convconfig_p->
ecopts = ecopts;
7023sysopen_func(
void *ptr)
7026 const char *fname = RSTRING_PTR(data->fname);
7035 fd = IO_WITHOUT_GVL_INT(sysopen_func, data);
7036 }
while (fd < 0 &&
errno == EINTR);
7043rb_sysopen(
VALUE fname,
int oflags, mode_t perm)
7048 data.fname = rb_str_encode_ospath(fname);
7050 data.oflags = oflags;
7053 TRY_WITH_GC((fd = rb_sysopen_internal(&data)) >= 0) {
7054 rb_syserr_fail_path(first_errno, fname);
7060fdopen_internal(
int fd,
const char *modestr)
7067 file = fdopen(fd, modestr);
7083 TRY_WITH_GC((file = fdopen_internal(fd, modestr)) != 0) {
7089 if (setvbuf(file, NULL, _IOFBF, 0) != 0)
7090 rb_warn(
"setvbuf() can't be honoured (fd=%d)", fd);
7098 int t = isatty(fptr->
fd);
7108io_strip_bom(
VALUE io)
7110 VALUE b1, b2, b3, b4;
7121 return rb_utf8_encindex();
7131 return ENCINDEX_UTF_16BE;
7142 return ENCINDEX_UTF_32LE;
7147 return ENCINDEX_UTF_16LE;
7157 return ENCINDEX_UTF_32BE;
7171io_set_encoding_by_bom(
VALUE io)
7173 int idx = io_strip_bom(io);
7179 extenc = rb_enc_from_index(idx);
7180 io_encoding_set(fptr, rb_enc_from_encoding(extenc),
7181 rb_io_internal_encoding(io),
Qnil);
7190rb_file_open_generic(
VALUE io,
VALUE filename,
int oflags,
int fmode,
7198 rb_io_ext_int_to_encs(NULL, NULL, &cc.enc, &cc.enc2, fmode);
7203 validate_enc_binmode(&fmode, convconfig->
ecflags,
7204 convconfig->
enc, convconfig->
enc2);
7208 fptr->
encs = *convconfig;
7211 if (!(oflags & O_TMPFILE)) {
7212 fptr->
pathv = pathv;
7215 fptr->
pathv = pathv;
7217 fptr->
fd = rb_sysopen(pathv, oflags, perm);
7225rb_file_open_internal(
VALUE io,
VALUE filename,
const char *modestr)
7228 const char *p = strchr(modestr,
':');
7232 parse_mode_enc(p+1, rb_usascii_encoding(),
7233 &convconfig.
enc, &convconfig.
enc2, &fmode);
7239 e = (fmode &
FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
7240 rb_io_ext_int_to_encs(e, NULL, &convconfig.
enc, &convconfig.
enc2, fmode);
7246#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7248 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7249 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7251 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.
enc2, convconfig.
ecflags);
7254 return rb_file_open_generic(io, filename,
7255 rb_io_fmode_oflags(fmode),
7265 return rb_file_open_internal(io_alloc(
rb_cFile), fname, modestr);
7274#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7297 while ((tmp = *prev) != 0) {
7298 if (tmp->fptr == fptr) {
7307#if defined (_WIN32) || defined(__CYGWIN__)
7316 rb_io_fptr_finalize(list->fptr);
7323pipe_finalize(
rb_io_t *fptr,
int noraise)
7325#if !defined(HAVE_WORKING_FORK) && !defined(_WIN32)
7334 fptr_finalize(fptr, noraise);
7336 pipe_del_fptr(fptr);
7343#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7344 void (*
const old_finalize)(
struct rb_io*,int) = fptr->
finalize;
7346 if (old_finalize == orig->finalize)
return;
7351#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7352 if (old_finalize != pipe_finalize) {
7354 for (list =
pipe_list; list; list = list->next) {
7355 if (list->fptr == fptr)
break;
7357 if (!list) pipe_add_fptr(fptr);
7360 pipe_del_fptr(fptr);
7373rb_io_unbuffered(
rb_io_t *fptr)
7391#define HAVE_SPAWNV 1
7392#define spawnv(mode, cmd, args) rb_w32_uaspawn((mode), (cmd), (args))
7393#define spawn(mode, cmd) rb_w32_uspawn((mode), (cmd), 0)
7396#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7406#ifdef HAVE_WORKING_FORK
7407# ifndef __EMSCRIPTEN__
7409popen_redirect(
struct popen_arg *p)
7412 close(p->write_pair[1]);
7413 if (p->write_pair[0] != 0) {
7414 dup2(p->write_pair[0], 0);
7415 close(p->write_pair[0]);
7418 if (p->pair[1] != 1) {
7419 dup2(p->pair[1], 1);
7425 if (p->pair[1] != 1) {
7426 dup2(p->pair[1], 1);
7432 if (p->pair[0] != 0) {
7433 dup2(p->pair[0], 0);
7440#if defined(__linux__)
7451linux_get_maxfd(
void)
7454 char buf[4096], *p, *np, *e;
7457 if (fd < 0)
return fd;
7458 ss = read(fd, buf,
sizeof(buf));
7459 if (ss < 0)
goto err;
7462 while ((
int)
sizeof(
"FDSize:\t0\n")-1 <= e-p &&
7463 (np = memchr(p,
'\n', e-p)) != NULL) {
7464 if (memcmp(p,
"FDSize:",
sizeof(
"FDSize:")-1) == 0) {
7466 p +=
sizeof(
"FDSize:")-1;
7486#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
7488 int max = (int)max_file_descriptor;
7491 ret = fcntl(0, F_MAXFD);
7493 maxhint = max = ret;
7494# elif defined(__linux__)
7495 ret = linux_get_maxfd();
7502 for (fd = lowfd; fd <= max; fd++) {
7503 if (!
NIL_P(noclose_fds) &&
7506 ret = fcntl(fd, F_GETFD);
7507 if (ret != -1 && !(ret & FD_CLOEXEC)) {
7508 fcntl(fd, F_SETFD, ret|FD_CLOEXEC);
7510# define CONTIGUOUS_CLOSED_FDS 20
7512 if (max < fd + CONTIGUOUS_CLOSED_FDS)
7513 max = fd + CONTIGUOUS_CLOSED_FDS;
7519# ifndef __EMSCRIPTEN__
7521popen_exec(
void *pp,
char *errmsg,
size_t errmsg_len)
7523 struct popen_arg *p = (
struct popen_arg*)pp;
7525 return rb_exec_async_signal_safe(p->eargp, errmsg, errmsg_len);
7530#if (defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)) && !defined __EMSCRIPTEN__
7532rb_execarg_fixup_v(
VALUE execarg_obj)
7534 rb_execarg_parent_start(execarg_obj);
7538char *rb_execarg_commandline(
const struct rb_execarg *eargp,
VALUE *prog);
7541#ifndef __EMSCRIPTEN__
7543pipe_open(
VALUE execarg_obj,
const char *modestr,
int fmode,
7546 struct rb_execarg *eargp =
NIL_P(execarg_obj) ? NULL : rb_execarg_get(execarg_obj);
7547 VALUE prog = eargp ? (eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name) :
Qfalse ;
7553#if defined(HAVE_WORKING_FORK)
7555 char errmsg[80] = {
'\0' };
7557#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7559 struct popen_arg arg;
7562#if defined(HAVE_SPAWNV)
7563# if defined(HAVE_SPAWNVE)
7564# define DO_SPAWN(cmd, args, envp) ((args) ? \
7565 spawnve(P_NOWAIT, (cmd), (args), (envp)) : \
7566 spawne(P_NOWAIT, (cmd), (envp)))
7568# define DO_SPAWN(cmd, args, envp) ((args) ? \
7569 spawnv(P_NOWAIT, (cmd), (args)) : \
7570 spawn(P_NOWAIT, (cmd)))
7572# if !defined(HAVE_WORKING_FORK)
7574# if defined(HAVE_SPAWNVE)
7579#if !defined(HAVE_WORKING_FORK)
7585#if !defined(HAVE_WORKING_FORK)
7586 const char *cmd = 0;
7592#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7593 arg.execarg_obj = execarg_obj;
7596 arg.pair[0] = arg.pair[1] = -1;
7597 arg.write_pair[0] = arg.write_pair[1] = -1;
7598# if !defined(HAVE_WORKING_FORK)
7599 if (eargp && !eargp->use_shell) {
7600 args = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
7605 if (
rb_pipe(arg.write_pair) < 0)
7606 rb_sys_fail_str(prog);
7609 close(arg.write_pair[0]);
7610 close(arg.write_pair[1]);
7614 rb_execarg_addopt(execarg_obj,
INT2FIX(0),
INT2FIX(arg.write_pair[0]));
7615 rb_execarg_addopt(execarg_obj,
INT2FIX(1),
INT2FIX(arg.pair[1]));
7620 rb_sys_fail_str(prog);
7622 rb_execarg_addopt(execarg_obj,
INT2FIX(1),
INT2FIX(arg.pair[1]));
7626 rb_sys_fail_str(prog);
7628 rb_execarg_addopt(execarg_obj,
INT2FIX(0),
INT2FIX(arg.pair[0]));
7631 rb_sys_fail_str(prog);
7633 if (!
NIL_P(execarg_obj)) {
7634 rb_protect(rb_execarg_fixup_v, execarg_obj, &state);
7636 if (0 <= arg.write_pair[0]) close(arg.write_pair[0]);
7637 if (0 <= arg.write_pair[1]) close(arg.write_pair[1]);
7638 if (0 <= arg.pair[0]) close(arg.pair[0]);
7639 if (0 <= arg.pair[1]) close(arg.pair[1]);
7640 rb_execarg_parent_end(execarg_obj);
7644# if defined(HAVE_WORKING_FORK)
7645 pid = rb_fork_async_signal_safe(&status, popen_exec, &arg, arg.eargp->redirect_fds, errmsg,
sizeof(errmsg));
7647 rb_execarg_run_options(eargp, sargp, NULL, 0);
7648# if defined(HAVE_SPAWNVE)
7649 if (eargp->envp_str) envp = (
char **)RSTRING_PTR(eargp->envp_str);
7651 while ((pid = DO_SPAWN(cmd, args, envp)) < 0) {
7653 switch (e =
errno) {
7655# if EWOULDBLOCK != EAGAIN
7664 rb_execarg_run_options(sargp, NULL, NULL, 0);
7666 rb_execarg_parent_end(execarg_obj);
7669# if defined(HAVE_WORKING_FORK)
7670 pid = rb_call_proc__fork();
7672 popen_redirect(&arg);
7684# if defined(HAVE_WORKING_FORK)
7690 close(arg.write_pair[0]);
7691 close(arg.write_pair[1]);
7693# if defined(HAVE_WORKING_FORK)
7702 close(arg.write_pair[0]);
7703 write_fd = arg.write_pair[1];
7714 cmd = rb_execarg_commandline(eargp, &prog);
7715 if (!
NIL_P(execarg_obj)) {
7716 rb_execarg_parent_start(execarg_obj);
7717 rb_execarg_run_options(eargp, sargp, NULL, 0);
7719 fp = popen(cmd, modestr);
7722 rb_execarg_parent_end(execarg_obj);
7723 rb_execarg_run_options(sargp, NULL, NULL, 0);
7725 if (!fp) rb_syserr_fail_path(e, prog);
7735 fptr->
encs = *convconfig;
7736#if RUBY_CRLF_ENVIRONMENT
7743 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
7746#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7747 if (NEED_NEWLINE_DECORATOR_ON_WRITE(fptr)) {
7748 fptr->
encs.
ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
7754 if (0 <= write_fd) {
7755 write_port = io_alloc(
rb_cIO);
7757 write_fptr->
fd = write_fd;
7759 fptr->
mode &= ~FMODE_WRITABLE;
7761 rb_ivar_set(port, rb_intern(
"@tied_io_for_writing"), write_port);
7764#if defined (__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7766 pipe_add_fptr(fptr);
7772pipe_open(
VALUE execarg_obj,
const char *modestr,
int fmode,
7780is_popen_fork(
VALUE prog)
7782 if (RSTRING_LEN(prog) == 1 && RSTRING_PTR(prog)[0] ==
'-') {
7783#if !defined(HAVE_WORKING_FORK)
7785 "fork() function is unimplemented on this machine");
7794pipe_open_s(
VALUE prog,
const char *modestr,
int fmode,
7798 VALUE *argv = &prog;
7801 if (!is_popen_fork(prog))
7802 execarg_obj = rb_execarg_new(argc, argv, TRUE, FALSE);
7803 return pipe_open(execarg_obj, modestr, fmode, convconfig);
7809 rb_io_t *fptr = io_close_fptr(io);
7977rb_io_s_popen(
int argc,
VALUE *argv,
VALUE klass)
7981 if (argc > 1 && !
NIL_P(opt = rb_check_hash_type(argv[argc-1]))) --argc;
7982 if (argc > 1 && !
NIL_P(env = rb_check_hash_type(argv[0]))) --argc, ++argv;
7991 int ex = !
NIL_P(opt);
7992 rb_error_arity(argc + ex, 1 + ex, 2 + ex);
7995 return popen_finish(rb_io_popen(pname, pmode, env, opt), klass);
8001 const char *modestr;
8006 tmp = rb_check_array_type(pname);
8009#if SIZEOF_LONG > SIZEOF_INT
8010 if (
len > INT_MAX) {
8011 rb_raise(rb_eArgError,
"too many arguments");
8020 if (!is_popen_fork(pname))
8021 execarg_obj = rb_execarg_new(1, &pname, TRUE, FALSE);
8023 if (!
NIL_P(execarg_obj)) {
8025 opt = rb_execarg_extract_options(execarg_obj, opt);
8027 rb_execarg_setenv(execarg_obj, env);
8030 modestr = rb_io_oflags_modestr(oflags);
8032 return pipe_open(execarg_obj, modestr, fmode, &convconfig);
8042 rb_io_flush(rb_ractor_stdout());
8043 rb_io_flush(rb_ractor_stderr());
8048 RBASIC_SET_CLASS(port, klass);
8055#if defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)
8056struct popen_writer_arg {
8058 struct popen_arg popen;
8062exec_popen_writer(
void *arg,
char *errmsg,
size_t buflen)
8064 struct popen_writer_arg *pw = arg;
8066 popen_redirect(&pw->popen);
8067 execv(pw->argv[0], pw->argv);
8068 strlcpy(errmsg, strerror(
errno), buflen);
8074ruby_popen_writer(
char *
const *argv, rb_pid_t *pid)
8076#if (defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)) || defined(_WIN32)
8077# ifdef HAVE_WORKING_FORK
8078 struct popen_writer_arg pw;
8079 int *
const write_pair = pw.popen.pair;
8087# ifdef HAVE_WORKING_FORK
8090 char errmsg[80] = {
'\0'};
8091 *pid = rb_fork_async_signal_safe(&status, exec_popen_writer, &pw,
Qnil, errmsg,
sizeof(errmsg));
8093 *pid = rb_w32_uspawn_process(P_NOWAIT, argv[0], argv, write_pair[0], -1, -1, 0);
8094 const char *errmsg = (*pid < 0) ? strerror(
errno) : NULL;
8096 close(write_pair[0]);
8098 close(write_pair[1]);
8099 fprintf(stderr,
"ruby_popen_writer(%s): %s\n", argv[0], errmsg);
8102 return fdopen(write_pair[1],
"w");
8121 rb_file_open_generic(io, fname, oflags, fmode, &convconfig, perm);
8159rb_io_s_open(
int argc,
VALUE *argv,
VALUE klass)
8191 VALUE fname, vmode, vperm;
8196 rb_scan_args(argc, argv,
"12", &fname, &vmode, &vperm);
8207 if (
NIL_P(vperm)) perm = 0666;
8211 fd = rb_sysopen(fname, oflags, perm);
8216check_pipe_command(
VALUE filename_or_command)
8218 char *s = RSTRING_PTR(filename_or_command);
8219 long l = RSTRING_LEN(filename_or_command);
8223 if (rb_enc_ascget(s, e, &chlen, rb_enc_get(filename_or_command)) ==
'|') {
8261 int redirect = FALSE;
8269 VALUE tmp = argv[0];
8275 VALUE cmd = check_pipe_command(tmp);
8278 rb_warn_deprecated_to_remove_at(4.0,
"Calling Kernel#open with a leading '|'",
"IO.popen");
8280 return rb_io_s_popen(argc, argv,
rb_cIO);
8293 return rb_io_s_open(argc, argv,
rb_cFile);
8307 return rb_io_open_generic(io, filename, oflags, fmode, &convconfig, perm);
8311rb_io_open_generic(
VALUE klass,
VALUE filename,
int oflags,
int fmode,
8315 if (klass ==
rb_cIO && !
NIL_P(cmd = check_pipe_command(filename))) {
8317 rb_warn_deprecated_to_remove_at(4.0,
"IO process creation with a leading '|'",
"IO.popen");
8318 return pipe_open_s(cmd, rb_io_oflags_modestr(oflags), fmode, convconfig);
8321 return rb_file_open_generic(io_alloc(klass), filename,
8322 oflags, fmode, convconfig, perm);
8337 if (fptr == orig)
return io;
8338 if (RUBY_IO_EXTERNAL_P(fptr)) {
8342 rb_raise(rb_eArgError,
8343 "%s can't change access mode from \"%s\" to \"%s\"",
8344 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->
mode),
8345 rb_io_fmode_modestr(orig->
mode));
8349 if (io_fflush(fptr) < 0)
8350 rb_sys_fail_on_write(fptr);
8353 flush_before_seek(fptr,
true);
8356 pos = io_tell(orig);
8359 if (io_fflush(orig) < 0)
8360 rb_sys_fail_on_write(fptr);
8369 else if (!RUBY_IO_EXTERNAL_P(fptr)) fptr->
pathv =
Qnil;
8370 fptr_copy_finalizer(fptr, orig);
8375 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2 || !fptr->stdio_file) {
8378 rb_sys_fail_path(orig->
pathv);
8386 rb_sys_fail_path(orig->
pathv);
8392 if (io_seek(fptr, pos, SEEK_SET) < 0 &&
errno) {
8393 rb_sys_fail_path(fptr->
pathv);
8395 if (io_seek(orig, pos, SEEK_SET) < 0 &&
errno) {
8396 rb_sys_fail_path(orig->
pathv);
8410int rb_freopen(
VALUE fname,
const char *mode,
FILE *fp);
8413rb_freopen(
VALUE fname,
const char *mode,
FILE *fp)
8415 if (!freopen(RSTRING_PTR(fname), mode, fp)) {
8458rb_io_reopen(
int argc,
VALUE *argv,
VALUE file)
8460 VALUE fname, nmode, opt;
8464 if (
rb_scan_args(argc, argv,
"11:", &fname, &nmode, &opt) == 1) {
8467 return io_reopen(file, tmp);
8473 fptr =
RFILE(file)->fptr;
8483 if (RUBY_IO_EXTERNAL_P(fptr) &&
8486 rb_raise(rb_eArgError,
8487 "%s can't change access mode from \"%s\" to \"%s\"",
8488 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->
mode),
8489 rb_io_fmode_modestr(fmode));
8492 fptr->
encs = convconfig;
8495 oflags = rb_io_fmode_oflags(fptr->
mode);
8498 fptr->
pathv = fname;
8500 fptr->
fd = rb_sysopen(fptr->
pathv, oflags, 0666);
8506 if (io_fflush(fptr) < 0)
8507 rb_sys_fail_on_write(fptr);
8512 int e = rb_freopen(rb_str_encode_ospath(fptr->
pathv),
8513 rb_io_oflags_modestr(oflags),
8515 if (e) rb_syserr_fail_path(e, fptr->
pathv);
8519 if (setvbuf(fptr->
stdio_file, NULL, _IOFBF, 0) != 0)
8520 rb_warn(
"setvbuf() can't be honoured for %"PRIsVALUE, fptr->
pathv);
8523 if (setvbuf(fptr->
stdio_file, NULL, _IONBF, BUFSIZ) != 0)
8524 rb_warn(
"setvbuf() can't be honoured for %"PRIsVALUE, fptr->
pathv);
8526 else if (fptr->
stdio_file == stdout && isatty(fptr->
fd)) {
8527 if (setvbuf(fptr->
stdio_file, NULL, _IOLBF, BUFSIZ) != 0)
8528 rb_warn(
"setvbuf() can't be honoured for %"PRIsVALUE, fptr->
pathv);
8532 int tmpfd = rb_sysopen(fptr->
pathv, oflags, 0666);
8538 rb_syserr_fail_path(err, fptr->
pathv);
8562 fptr->
mode = orig->
mode & ~FMODE_EXTERNAL;
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();
8665 rb_warn_deprecated(
"'%s'", NULL, rb_id2name(
id));
8738 if (argc > 1 && !
NIL_P(rb_output_fs)) {
8741 for (i=0; i<argc; i++) {
8742 if (!
NIL_P(rb_output_fs) && i>0) {
8743 rb_io_write(out, rb_output_fs);
8745 rb_io_write(out, argv[i]);
8842 rb_io_write(io, str);
8846#define forward(obj, id, argc, argv) \
8847 rb_funcallv_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8848#define forward_public(obj, id, argc, argv) \
8849 rb_funcallv_public_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8850#define forward_current(id, argc, argv) \
8851 forward_public(ARGF.current_file, id, argc, argv)
8868 VALUE r_stdout = rb_ractor_stdout();
8869 if (recv == r_stdout) {
8870 return rb_io_putc(recv, ch);
8872 return forward(r_stdout, rb_intern(
"putc"), 1, &ch);
8877rb_str_end_with_asciichar(
VALUE str,
int c)
8879 long len = RSTRING_LEN(str);
8880 const char *
ptr = RSTRING_PTR(str);
8884 if (
len == 0)
return 0;
8885 if ((n = rb_enc_mbminlen(
enc)) == 1) {
8886 return ptr[
len - 1] == c;
8888 return rb_enc_ascget(
ptr + ((
len - 1) / n) * n,
ptr +
len, &n,
enc) == c;
8899 rb_io_puts(1, &tmp, out);
8902 ary = rb_check_array_type(ary);
8906 rb_io_puts(1, &tmp, out);
8961 VALUE line, args[2];
8968 for (
int i = 0; i < argc; i++) {
8982 if (RSTRING_LEN(line) == 0) {
8987 if (!rb_str_end_with_asciichar(line,
'\n')) {
8992 rb_io_writev(out, n, args);
9010 VALUE r_stdout = rb_ractor_stdout();
9011 if (recv == r_stdout) {
9012 return rb_io_puts(argc, argv, recv);
9014 return forward(r_stdout, rb_intern(
"puts"), argc, argv);
9018rb_p_write(
VALUE str)
9023 VALUE r_stdout = rb_ractor_stdout();
9025 rb_method_basic_definition_p(
CLASS_OF(r_stdout), id_write)) {
9026 io_writev(2, args, r_stdout);
9029 rb_io_writev(r_stdout, 2, args);
9041rb_p_result(
int argc,
const VALUE *argv)
9048 else if (argc > 1) {
9051 VALUE r_stdout = rb_ractor_stdout();
9053 rb_uninterruptible(rb_io_flush, r_stdout);
9094 for (i=0; i<argc; i++) {
9096 rb_uninterruptible(rb_p_write, inspected);
9098 return rb_p_result(argc, argv);
9119rb_obj_display(
int argc,
VALUE *argv,
VALUE self)
9123 out = (!
rb_check_arity(argc, 0, 1) ? rb_ractor_stdout() : argv[0]);
9124 rb_io_write(out, self);
9130rb_stderr_to_original_p(
VALUE err)
9132 return (err == orig_stderr ||
RFILE(orig_stderr)->fptr->
fd < 0);
9138 VALUE out = rb_ractor_stderr();
9139 if (rb_stderr_to_original_p(out)) {
9141 if (isatty(fileno(stderr))) {
9142 if (rb_w32_write_console(
rb_str_new(mesg,
len), fileno(stderr)) > 0)
return;
9145 if (fwrite(mesg,
sizeof(
char), (
size_t)
len, stderr) < (
size_t)
len) {
9162rb_write_error_str(
VALUE mesg)
9164 VALUE out = rb_ractor_stderr();
9166 if (rb_stderr_to_original_p(out)) {
9167 size_t len = (size_t)RSTRING_LEN(mesg);
9169 if (isatty(fileno(stderr))) {
9170 if (rb_w32_write_console(mesg, fileno(stderr)) > 0)
return;
9173 if (fwrite(RSTRING_PTR(mesg),
sizeof(
char),
len, stderr) <
len) {
9180 rb_io_write(out, mesg);
9185rb_stderr_tty_p(
void)
9187 if (rb_stderr_to_original_p(rb_ractor_stderr()))
9188 return isatty(fileno(stderr));
9193must_respond_to(
ID mid,
VALUE val,
ID id)
9196 rb_raise(
rb_eTypeError,
"%"PRIsVALUE
" must have %"PRIsVALUE
" method, %"PRIsVALUE
" given",
9197 rb_id2str(
id), rb_id2str(mid),
9217 must_respond_to(id_write, val,
id);
9224 return rb_ractor_stdout();
9230 must_respond_to(id_write, val,
id);
9237 return rb_ractor_stderr();
9241allocate_and_open_new_file(
VALUE klass)
9243 VALUE self = io_alloc(klass);
9244 rb_io_make_open_file(self);
9252 VALUE self = rb_protect(allocate_and_open_new_file, klass, &state);
9260 maygvl_close(descriptor, 0);
9268 io->
fd = descriptor;
9286 io->
encs = *encoding;
9295prep_io(
int fd,
int fmode,
VALUE klass,
const char *path)
9305 e = (fmode &
FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
9306 rb_io_ext_int_to_encs(e, NULL, &convconfig.
enc, &convconfig.
enc2, fmode);
9310#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9312 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
9313 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
9315 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.
enc2, convconfig.
ecflags);
9321 if (!io_check_tty(io)) {
9324 setmode(fd, O_BINARY);
9336 if (path && strcmp(path,
"-")) klass =
rb_cFile;
9337 return prep_io(fd, rb_io_oflags_fmode(oflags), klass, path);
9341prep_stdio(
FILE *f,
int fmode,
VALUE klass,
const char *path)
9348#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9349 fptr->
encs.
ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
9360rb_io_prep_stdin(
void)
9366rb_io_prep_stdout(
void)
9372rb_io_prep_stderr(
void)
9381 int oflags = rb_io_fmode_oflags(fptr->
mode) & ~O_EXCL;
9408 rb_io_buffer_init(&fp->
wbuf);
9409 rb_io_buffer_init(&fp->
rbuf);
9410 rb_io_buffer_init(&fp->
cbuf);
9428rb_io_make_open_file(
VALUE obj)
9433 if (
RFILE(obj)->fptr) {
9435 rb_io_fptr_finalize(
RFILE(obj)->fptr);
9436 RFILE(obj)->fptr = 0;
9438 fp = rb_io_fptr_new();
9440 RFILE(obj)->fptr = fp;
9488rb_io_initialize(
int argc,
VALUE *argv,
VALUE io)
9494 return io_initialize(io, fnum, vmode, opt);
9501 int fd, fmode, oflags = O_RDONLY;
9503#if defined(HAVE_FCNTL) && defined(F_GETFL)
9513 rb_raise(rb_eArgError,
"The given fd is not accessible because RubyVM reserves it");
9515#if defined(HAVE_FCNTL) && defined(F_GETFL)
9516 oflags = fcntl(fd, F_GETFL);
9517 if (oflags == -1) rb_sys_fail(0);
9519 if (fstat(fd, &st) < 0) rb_sys_fail(0);
9522#if defined(HAVE_FCNTL) && defined(F_GETFL)
9523 ofmode = rb_io_oflags_fmode(oflags);
9535 if (rb_hash_aref(opt, sym_autoclose) ==
Qfalse) {
9539 path = rb_hash_aref(opt,
RB_ID2SYM(idPath));
9550 fp->
encs = convconfig;
9555 if (fileno(stdin) == fd)
9557 else if (fileno(stdout) == fd)
9559 else if (fileno(stderr) == fd)
9591rb_io_set_encoding_by_bom(
VALUE io)
9597 rb_raise(rb_eArgError,
"ASCII incompatible encoding needs binmode");
9600 rb_raise(rb_eArgError,
"encoding conversion is set");
9602 else if (fptr->
encs.
enc && fptr->
encs.
enc != rb_ascii8bit_encoding()) {
9603 rb_raise(rb_eArgError,
"encoding is set to %s already",
9606 if (!io_set_encoding_by_bom(io))
return Qnil;
9607 return rb_enc_from_encoding(fptr->
encs.
enc);
9652rb_file_initialize(
int argc,
VALUE *argv,
VALUE io)
9654 if (
RFILE(io)->fptr) {
9657 VALUE fname, vmode, vperm, opt;
9658 int posargc =
rb_scan_args(argc, argv,
"12:", &fname, &vmode, &vperm, &opt);
9663 return io_initialize(io, fd, vmode, opt);
9666 return rb_open_file(io, fname, vmode, vperm, opt);
9671rb_io_s_new(
int argc,
VALUE *argv,
VALUE klass)
9676 rb_warn(
"%"PRIsVALUE
"::new() does not take block; use %"PRIsVALUE
"::open() instead",
9692rb_io_s_for_fd(
int argc,
VALUE *argv,
VALUE klass)
9695 rb_io_initialize(argc, argv, io);
9708rb_io_autoclose_p(
VALUE io)
9733rb_io_set_autoclose(
VALUE io,
VALUE autoclose)
9737 if (!
RTEST(autoclose))
9740 fptr->
mode &= ~FMODE_EXTERNAL;
9745io_wait_event(
VALUE io,
int event,
VALUE timeout,
int return_io)
9777io_wait_readable(
int argc,
VALUE *argv,
VALUE io)
9784 if (rb_io_read_pending(fptr))
return Qtrue;
9787 VALUE timeout = (argc == 1 ? argv[0] :
Qnil);
9801io_wait_writable(
int argc,
VALUE *argv,
VALUE io)
9809 VALUE timeout = (argc == 1 ? argv[0] :
Qnil);
9824io_wait_priority(
int argc,
VALUE *argv,
VALUE io)
9831 if (rb_io_read_pending(fptr))
return Qtrue;
9834 VALUE timeout = argc == 1 ? argv[0] :
Qnil;
9840wait_mode_sym(
VALUE mode)
9842 if (mode ==
ID2SYM(rb_intern(
"r"))) {
9843 return RB_WAITFD_IN;
9845 if (mode ==
ID2SYM(rb_intern(
"read"))) {
9846 return RB_WAITFD_IN;
9848 if (mode ==
ID2SYM(rb_intern(
"readable"))) {
9849 return RB_WAITFD_IN;
9851 if (mode ==
ID2SYM(rb_intern(
"w"))) {
9852 return RB_WAITFD_OUT;
9854 if (mode ==
ID2SYM(rb_intern(
"write"))) {
9855 return RB_WAITFD_OUT;
9857 if (mode ==
ID2SYM(rb_intern(
"writable"))) {
9858 return RB_WAITFD_OUT;
9860 if (mode ==
ID2SYM(rb_intern(
"rw"))) {
9861 return RB_WAITFD_IN|RB_WAITFD_OUT;
9863 if (mode ==
ID2SYM(rb_intern(
"read_write"))) {
9864 return RB_WAITFD_IN|RB_WAITFD_OUT;
9866 if (mode ==
ID2SYM(rb_intern(
"readable_writable"))) {
9867 return RB_WAITFD_IN|RB_WAITFD_OUT;
9870 rb_raise(rb_eArgError,
"unsupported mode: %"PRIsVALUE, mode);
9874io_event_from_value(
VALUE value)
9878 if (events <= 0) rb_raise(rb_eArgError,
"Events must be positive integer!");
9916 for (
int i = 0; i < argc; i += 1) {
9918 events |= wait_mode_sym(argv[i]);
9920 else if (UNDEF_P(timeout)) {
9924 rb_raise(rb_eArgError,
"timeout given more than once");
9928 if (UNDEF_P(timeout)) timeout =
Qnil;
9936 events = io_event_from_value(argv[0]);
9944 if (rb_io_read_pending(fptr)) {
9946 if (return_io)
return Qtrue;
9952 return io_wait_event(io, events, timeout, return_io);
9958 struct argf *p = ptr;
9959 rb_gc_mark(p->filename);
9960 rb_gc_mark(p->current_file);
9961 rb_gc_mark(p->argv);
9962 rb_gc_mark(p->inplace);
9963 rb_gc_mark(p->encs.
ecopts);
9967argf_memsize(
const void *ptr)
9969 const struct argf *p = ptr;
9970 size_t size =
sizeof(*p);
9977 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
9984 p->current_file =
Qnil;
9990argf_alloc(
VALUE klass)
10005 memset(&ARGF, 0,
sizeof(ARGF));
10006 argf_init(&ARGF, argv);
10016 ARGF = argf_of(orig);
10043 ARGF.last_lineno = ARGF.lineno;
10069 return forward_current(rb_frame_this_func(), argc, argv);
10072#define next_argv() argf_next_argv(argf)
10073#define ARGF_GENERIC_INPUT_P() \
10074 (ARGF.current_file == rb_stdin && !RB_TYPE_P(ARGF.current_file, T_FILE))
10075#define ARGF_FORWARD(argc, argv) do {\
10076 if (ARGF_GENERIC_INPUT_P())\
10077 return argf_forward((argc), (argv), argf);\
10079#define NEXT_ARGF_FORWARD(argc, argv) do {\
10080 if (!next_argv()) return Qnil;\
10081 ARGF_FORWARD((argc), (argv));\
10087 VALUE file = ARGF.current_file;
10101 int stdout_binmode = 0;
10104 VALUE r_stdout = rb_ractor_stdout();
10109 stdout_binmode = 1;
10112 if (ARGF.init_p == 0) {
10122 if (
NIL_P(ARGF.argv)) {
10125 else if (ARGF.next_p == -1 &&
RARRAY_LEN(ARGF.argv) > 0) {
10130 if (ARGF.next_p == 1) {
10131 if (ARGF.init_p == 1) argf_close(
argf);
10134 VALUE filename = rb_ary_shift(ARGF.argv);
10136 ARGF.filename = filename;
10137 filename = rb_str_encode_ospath(filename);
10139 if (RSTRING_LEN(filename) == 1 && fn[0] ==
'-') {
10141 if (ARGF.inplace) {
10142 rb_warn(
"Can't do inplace edit for stdio; skipping");
10148 int fr = rb_sysopen(filename, O_RDONLY, 0);
10150 if (ARGF.inplace) {
10152#ifndef NO_SAFE_RENAME
10163 if (!
NIL_P(ARGF.inplace)) {
10164 VALUE suffix = ARGF.inplace;
10166 if (
NIL_P(rb_str_cat_conv_enc_opts(str, RSTRING_LEN(str),
10167 RSTRING_PTR(suffix), RSTRING_LEN(suffix),
10168 rb_enc_get(suffix), 0,
Qnil))) {
10171#ifdef NO_SAFE_RENAME
10173 (void)unlink(RSTRING_PTR(str));
10174 if (rename(fn, RSTRING_PTR(str)) < 0) {
10175 rb_warn(
"Can't rename %"PRIsVALUE
" to %"PRIsVALUE
": %s, skipping file",
10176 filename, str, strerror(
errno));
10179 fr = rb_sysopen(str, O_RDONLY, 0);
10181 if (rename(fn, RSTRING_PTR(str)) < 0) {
10182 rb_warn(
"Can't rename %"PRIsVALUE
" to %"PRIsVALUE
": %s, skipping file",
10183 filename, str, strerror(
errno));
10190#ifdef NO_SAFE_RENAME
10191 rb_fatal(
"Can't do inplace edit without backup");
10193 if (unlink(fn) < 0) {
10194 rb_warn(
"Can't remove %"PRIsVALUE
": %s, skipping file",
10195 filename, strerror(
errno));
10201 fw = rb_sysopen(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666);
10202#ifndef NO_SAFE_RENAME
10205 fchmod(fw, st.st_mode);
10207 chmod(fn, st.st_mode);
10209 if (st.st_uid!=st2.st_uid || st.st_gid!=st2.st_gid) {
10212 err = fchown(fw, st.st_uid, st.st_gid);
10214 err = chown(fn, st.st_uid, st.st_gid);
10216 if (err && getuid() == 0 && st2.st_uid == 0) {
10217 const char *wkfn = RSTRING_PTR(filename);
10218 rb_warn(
"Can't set owner/group of %"PRIsVALUE
" to same as %"PRIsVALUE
": %s, skipping file",
10219 filename, str, strerror(
errno));
10222 (void)unlink(wkfn);
10232 if (!ARGF.binmode) {
10233 fmode |= DEFAULT_TEXTMODE;
10235 ARGF.current_file = prep_io(fr, fmode,
rb_cFile, fn);
10236 if (!
NIL_P(write_io)) {
10243 if (ARGF.encs.enc) {
10244 fptr->
encs = ARGF.encs;
10245 clear_codeconv(fptr);
10248 fptr->
encs.
ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
10249 if (!ARGF.binmode) {
10251#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
10252 fptr->
encs.
ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
10263 else if (ARGF.next_p == -1) {
10266 if (ARGF.inplace) {
10267 rb_warn(
"Can't do inplace edit for stdio");
10271 if (ARGF.init_p == -1) ARGF.init_p = 1;
10279 long lineno = ARGF.lineno;
10282 if (!next_argv())
return Qnil;
10283 if (ARGF_GENERIC_INPUT_P()) {
10284 line = forward_current(idGets, argc, argv);
10291 line = rb_io_getline(argc, argv, ARGF.current_file);
10293 if (
NIL_P(line) && ARGF.next_p != -1) {
10299 if (!
NIL_P(line)) {
10300 ARGF.lineno = ++lineno;
10301 ARGF.last_lineno = ARGF.lineno;
10307argf_lineno_getter(
ID id,
VALUE *var)
10310 return INT2FIX(ARGF.last_lineno);
10318 ARGF.last_lineno = ARGF.lineno = n;
10322rb_reset_argf_lineno(
long n)
10324 ARGF.last_lineno = ARGF.lineno = n;
10365 if (recv ==
argf) {
10366 return argf_gets(argc, argv,
argf);
10368 return forward(
argf, idGets, argc, argv);
10394 line = argf_getline(argc, argv,
argf);
10406 return rb_f_gets(0, 0,
argf);
10410 if (!next_argv())
return Qnil;
10412 if (
NIL_P(line) && ARGF.next_p != -1) {
10418 if (!
NIL_P(line)) {
10420 ARGF.last_lineno = ARGF.lineno;
10446rb_f_readline(
int argc,
VALUE *argv,
VALUE recv)
10448 if (recv ==
argf) {
10449 return argf_readline(argc, argv,
argf);
10451 return forward(
argf, rb_intern(
"readline"), argc, argv);
10477 if (!next_argv()) rb_eof_error();
10478 ARGF_FORWARD(argc, argv);
10479 line = argf_gets(argc, argv,
argf);
10549rb_f_readlines(
int argc,
VALUE *argv,
VALUE recv)
10551 if (recv ==
argf) {
10552 return argf_readlines(argc, argv,
argf);
10554 return forward(
argf, rb_intern(
"readlines"), argc, argv);
10578 long lineno = ARGF.lineno;
10581 ary = rb_ary_new();
10582 while (next_argv()) {
10583 if (ARGF_GENERIC_INPUT_P()) {
10584 lines = forward_current(rb_intern(
"readlines"), argc, argv);
10587 lines = rb_io_readlines(argc, argv, ARGF.current_file);
10591 rb_ary_concat(ary, lines);
10593 ARGF.last_lineno = ARGF.lineno;
10628 rb_last_status_clear();
10629 port = pipe_open_s(str,
"r",
FMODE_READABLE|DEFAULT_TEXTMODE, NULL);
10633 result = read_all(fptr, remain_size(fptr),
Qnil);
10635 rb_io_fptr_cleanup_all(fptr);
10641#ifdef HAVE_SYS_SELECT_H
10642#include <sys/select.h>
10656 if (!
NIL_P(read)) {
10661 if (READ_DATA_PENDING(fptr) || READ_CHAR_PENDING(fptr)) {
10665 if (max < fptr->fd) max = fptr->
fd;
10668 timerec.tv_sec = timerec.tv_usec = 0;
10676 if (!
NIL_P(write)) {
10682 if (max < fptr->fd) max = fptr->
fd;
10689 if (!
NIL_P(except)) {
10693 VALUE write_io = GetWriteIO(io);
10696 if (max < fptr->fd) max = fptr->
fd;
10697 if (io != write_io) {
10700 if (max < fptr->fd) max = fptr->
fd;
10715 if (!pending && n == 0)
return Qnil;
10718 rb_ary_push(res, rp?rb_ary_new():
rb_ary_new2(0));
10719 rb_ary_push(res, wp?rb_ary_new():
rb_ary_new2(0));
10720 rb_ary_push(res, ep?rb_ary_new():
rb_ary_new2(0));
10725 VALUE obj = rb_ary_entry(read, i);
10730 rb_ary_push(list, obj);
10738 VALUE obj = rb_ary_entry(write, i);
10740 VALUE write_io = GetWriteIO(io);
10743 rb_ary_push(list, obj);
10751 VALUE obj = rb_ary_entry(except, i);
10753 VALUE write_io = GetWriteIO(io);
10756 rb_ary_push(list, obj);
10758 else if (io != write_io) {
10761 rb_ary_push(list, obj);
10771 VALUE read, write, except;
10777select_call(
VALUE arg)
10781 return select_internal(p->read, p->write, p->except, p->timeout, p->fdsets);
10785select_end(
VALUE arg)
10790 for (i = 0; i < numberof(p->fdsets); ++i)
10795static VALUE sym_normal, sym_sequential, sym_random,
10796 sym_willneed, sym_dontneed, sym_noreuse;
10798#ifdef HAVE_POSIX_FADVISE
10799struct io_advise_struct {
10807io_advise_internal(
void *arg)
10809 struct io_advise_struct *ptr = arg;
10810 return posix_fadvise(ptr->fd, ptr->offset, ptr->len, ptr->advice);
10814io_advise_sym_to_const(
VALUE sym)
10816#ifdef POSIX_FADV_NORMAL
10817 if (sym == sym_normal)
10818 return INT2NUM(POSIX_FADV_NORMAL);
10821#ifdef POSIX_FADV_RANDOM
10822 if (sym == sym_random)
10823 return INT2NUM(POSIX_FADV_RANDOM);
10826#ifdef POSIX_FADV_SEQUENTIAL
10827 if (sym == sym_sequential)
10828 return INT2NUM(POSIX_FADV_SEQUENTIAL);
10831#ifdef POSIX_FADV_WILLNEED
10832 if (sym == sym_willneed)
10833 return INT2NUM(POSIX_FADV_WILLNEED);
10836#ifdef POSIX_FADV_DONTNEED
10837 if (sym == sym_dontneed)
10838 return INT2NUM(POSIX_FADV_DONTNEED);
10841#ifdef POSIX_FADV_NOREUSE
10842 if (sym == sym_noreuse)
10843 return INT2NUM(POSIX_FADV_NOREUSE);
10850do_io_advise(
rb_io_t *fptr,
VALUE advice, rb_off_t offset, rb_off_t
len)
10853 struct io_advise_struct ias;
10856 num_adv = io_advise_sym_to_const(advice);
10862 if (
NIL_P(num_adv))
10866 ias.advice =
NUM2INT(num_adv);
10867 ias.offset = offset;
10870 rv = (int)rb_io_blocking_region(fptr, io_advise_internal, &ias);
10871 if (rv && rv != ENOSYS) {
10874 VALUE message = rb_sprintf(
"%"PRIsVALUE
" "
10878 fptr->
pathv, offset,
len, advice);
10888advice_arg_check(
VALUE advice)
10893 if (advice != sym_normal &&
10894 advice != sym_sequential &&
10895 advice != sym_random &&
10896 advice != sym_willneed &&
10897 advice != sym_dontneed &&
10898 advice != sym_noreuse) {
10899 rb_raise(
rb_eNotImpError,
"Unsupported advice: %+"PRIsVALUE, advice);
10937rb_io_advise(
int argc,
VALUE *argv,
VALUE io)
10944 advice_arg_check(advice);
10946 io = GetWriteIO(io);
10952#ifdef HAVE_POSIX_FADVISE
10953 return do_io_advise(fptr, advice,
off, l);
10955 ((void)
off, (
void)l);
11111rb_f_select(
int argc,
VALUE *argv,
VALUE obj)
11114 if (scheduler !=
Qnil) {
11117 if (!UNDEF_P(result))
return result;
11125 rb_scan_args(argc, argv,
"13", &args.read, &args.write, &args.except, &timeout);
11126 if (
NIL_P(timeout)) {
11131 args.timeout = &timerec;
11134 for (i = 0; i < numberof(args.fdsets); ++i)
11140#ifdef IOCTL_REQ_TYPE
11141 typedef IOCTL_REQ_TYPE ioctl_req_t;
11143 typedef int ioctl_req_t;
11144# define NUM2IOCTLREQ(num) ((int)NUM2LONG(num))
11155nogvl_ioctl(
void *ptr)
11157 struct ioctl_arg *arg = ptr;
11159 return (
VALUE)ioctl(arg->fd, arg->cmd, arg->narg);
11163do_ioctl(
struct rb_io *io, ioctl_req_t cmd,
long narg)
11166 struct ioctl_arg arg;
11172 retval = (int)rb_io_blocking_region(io, nogvl_ioctl, &arg);
11178#define DEFAULT_IOCTL_NARG_LEN (256)
11180#if defined(__linux__) && defined(_IOC_SIZE)
11182linux_iocparm_len(ioctl_req_t cmd)
11186 if ((cmd & 0xFFFF0000) == 0) {
11188 return DEFAULT_IOCTL_NARG_LEN;
11191 len = _IOC_SIZE(cmd);
11194 if (
len < DEFAULT_IOCTL_NARG_LEN)
11195 len = DEFAULT_IOCTL_NARG_LEN;
11203ioctl_narg_len(ioctl_req_t cmd)
11209#define IOCPARM_LEN(x) (((x) >> 16) & IOCPARM_MASK)
11213 len = IOCPARM_LEN(cmd);
11214#elif defined(__linux__) && defined(_IOC_SIZE)
11215 len = linux_iocparm_len(cmd);
11218 len = DEFAULT_IOCTL_NARG_LEN;
11227typedef long fcntl_arg_t;
11230typedef int fcntl_arg_t;
11234fcntl_narg_len(ioctl_req_t cmd)
11241 len =
sizeof(fcntl_arg_t);
11249#ifdef F_DUPFD_CLOEXEC
11250 case F_DUPFD_CLOEXEC:
11251 len =
sizeof(fcntl_arg_t);
11261 len =
sizeof(fcntl_arg_t);
11271 len =
sizeof(fcntl_arg_t);
11281 len =
sizeof(fcntl_arg_t);
11286 len =
sizeof(
struct f_owner_ex);
11291 len =
sizeof(
struct f_owner_ex);
11296 len =
sizeof(
struct flock);
11301 len =
sizeof(
struct flock);
11306 len =
sizeof(
struct flock);
11326 len =
sizeof(fcntl_arg_t);
11336 len =
sizeof(fcntl_arg_t);
11341 len =
sizeof(fcntl_arg_t);
11354fcntl_narg_len(ioctl_req_t cmd)
11360#define NARG_SENTINEL 17
11363setup_narg(ioctl_req_t cmd,
VALUE *argp,
long (*narg_len)(ioctl_req_t))
11374 else if (arg ==
Qtrue) {
11388 len = narg_len(cmd);
11389 rb_str_modify(arg);
11391 slen = RSTRING_LEN(arg);
11393 if (slen <
len+1) {
11394 rb_str_resize(arg,
len+1);
11395 MEMZERO(RSTRING_PTR(arg)+slen,
char,
len-slen);
11399 ptr = RSTRING_PTR(arg);
11400 ptr[slen - 1] = NARG_SENTINEL;
11409finish_narg(
int retval,
VALUE arg,
const rb_io_t *fptr)
11411 if (retval < 0) rb_sys_fail_path(fptr->
pathv);
11416 if (ptr[slen-1] != NARG_SENTINEL)
11417 rb_raise(rb_eArgError,
"return value overflowed string");
11418 ptr[slen-1] =
'\0';
11428 ioctl_req_t cmd = NUM2IOCTLREQ(req);
11433 narg = setup_narg(cmd, &arg, ioctl_narg_len);
11435 retval = do_ioctl(fptr, cmd, narg);
11436 return finish_narg(retval, arg, fptr);
11463 return rb_ioctl(io, req, arg);
11466#define rb_io_ioctl rb_f_notimplement
11477nogvl_fcntl(
void *ptr)
11479 struct fcntl_arg *arg = ptr;
11481#if defined(F_DUPFD)
11482 if (arg->cmd == F_DUPFD)
11485 return (
VALUE)fcntl(arg->fd, arg->cmd, arg->narg);
11489do_fcntl(
struct rb_io *io,
int cmd,
long narg)
11492 struct fcntl_arg arg;
11498 retval = (int)rb_io_blocking_region(io, nogvl_fcntl, &arg);
11499 if (retval != -1) {
11501#if defined(F_DUPFD)
11504#if defined(F_DUPFD_CLOEXEC)
11505 case F_DUPFD_CLOEXEC:
11522 narg = setup_narg(cmd, &arg, fcntl_narg_len);
11524 retval = do_fcntl(fptr, cmd, narg);
11525 return finish_narg(retval, arg, fptr);
11551 return rb_fcntl(io, req, arg);
11554#define rb_io_fcntl rb_f_notimplement
11557#if defined(HAVE_SYSCALL) || defined(HAVE___SYSCALL)
11589#if SIZEOF_VOIDP == 8 && defined(HAVE___SYSCALL) && SIZEOF_INT != 8
11590# define SYSCALL __syscall
11591# define NUM2SYSCALLID(x) NUM2LONG(x)
11592# define RETVAL2NUM(x) LONG2NUM(x)
11593# if SIZEOF_LONG == 8
11594 long num, retval = -1;
11595# elif SIZEOF_LONG_LONG == 8
11596 long long num, retval = -1;
11598# error ---->> it is asserted that __syscall takes the first argument and returns retval in 64bit signed integer. <<----
11600#elif defined(__linux__)
11601# define SYSCALL syscall
11602# define NUM2SYSCALLID(x) NUM2LONG(x)
11603# define RETVAL2NUM(x) LONG2NUM(x)
11611 long num, retval = -1;
11613# define SYSCALL syscall
11614# define NUM2SYSCALLID(x) NUM2INT(x)
11615# define RETVAL2NUM(x) INT2NUM(x)
11616 int num, retval = -1;
11622 "We plan to remove a syscall function at future release. DL(Fiddle) provides safer alternative.");
11626 rb_raise(rb_eArgError,
"too few arguments for syscall");
11627 if (argc > numberof(arg))
11628 rb_raise(rb_eArgError,
"too many arguments for syscall");
11629 num = NUM2SYSCALLID(argv[0]); ++argv;
11630 for (i = argc - 1; i--; ) {
11645 retval = SYSCALL(num);
11648 retval = SYSCALL(num, arg[0]);
11651 retval = SYSCALL(num, arg[0],arg[1]);
11654 retval = SYSCALL(num, arg[0],arg[1],arg[2]);
11657 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3]);
11660 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4]);
11663 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5]);
11666 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6]);
11672 return RETVAL2NUM(retval);
11674#undef NUM2SYSCALLID
11678#define rb_f_syscall rb_f_notimplement
11682io_new_instance(
VALUE args)
11688find_encoding(
VALUE v)
11691 if (!enc)
rb_warn(
"Unsupported encoding %"PRIsVALUE
" ignored", v);
11703 enc2 = find_encoding(v1);
11706 if (RSTRING_LEN(tmp) == 1 && RSTRING_PTR(tmp)[0] ==
'-') {
11712 enc = find_encoding(v2);
11719 enc = find_encoding(v2);
11725 if (enc2 == rb_ascii8bit_encoding()) {
11730 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11736 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
11737 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11742 if (!
NIL_P(tmp) && rb_enc_asciicompat(enc = rb_enc_get(tmp))) {
11743 parse_mode_enc(RSTRING_PTR(tmp), enc, &enc, &enc2, NULL);
11744 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11748 rb_io_ext_int_to_encs(find_encoding(v1), NULL, &enc, &enc2, 0);
11749 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11754 validate_enc_binmode(&fptr->
mode, ecflags, enc, enc2);
11759 clear_codeconv(fptr);
11771io_encoding_set_v(
VALUE v)
11774 io_encoding_set(arg->fptr, arg->v1, arg->v2, arg->opt);
11779pipe_pair_close(
VALUE rw)
11782 return rb_ensure(io_close, rwp[0], io_close, rwp[1]);
11865rb_io_s_pipe(
int argc,
VALUE *argv,
VALUE klass)
11867 int pipes[2], state;
11868 VALUE r, w, args[3], v1, v2;
11875 argc =
rb_scan_args(argc, argv,
"02:", &v1, &v2, &opt);
11882 r = rb_protect(io_new_instance, (
VALUE)args, &state);
11886 rb_jump_tag(state);
11890 ies_args.fptr = fptr;
11893 ies_args.opt = opt;
11894 rb_protect(io_encoding_set_v, (
VALUE)&ies_args, &state);
11898 rb_jump_tag(state);
11903 w = rb_protect(io_new_instance, (
VALUE)args, &state);
11907 rb_jump_tag(state);
11912 extract_binmode(opt, &fmode);
11919#if DEFAULT_TEXTMODE
11921 fptr->
mode &= ~FMODE_TEXTMODE;
11922 setmode(fptr->
fd, O_BINARY);
11924#if RUBY_CRLF_ENVIRONMENT
11930 fptr->
mode |= fmode;
11931#if DEFAULT_TEXTMODE
11933 fptr2->
mode &= ~FMODE_TEXTMODE;
11934 setmode(fptr2->
fd, O_BINARY);
11937 fptr2->
mode |= fmode;
11939 ret = rb_assoc_new(r, w);
11971 else if (!
NIL_P(v = rb_hash_aref(opt, sym_open_args))) {
11974 v = rb_to_array_type(v);
11979 arg->io = rb_io_open(klass, path, vmode, vperm, opt);
11983io_s_foreach(
VALUE v)
11988 if (arg->limit == 0)
11989 rb_raise(rb_eArgError,
"invalid limit: 0 for foreach");
11990 while (!
NIL_P(str = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, arg->io))) {
12078rb_io_s_foreach(
int argc,
VALUE *argv,
VALUE self)
12081 int orig_argc = argc;
12085 argc =
rb_scan_args(argc, argv,
"12:", NULL, NULL, NULL, &opt);
12087 extract_getline_args(argc-1, argv+1, &garg);
12088 open_key_args(self, argc, argv, opt, &arg);
12090 extract_getline_opts(opt, &garg);
12091 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12092 return rb_ensure(io_s_foreach, (
VALUE)&garg, rb_io_close, arg.io);
12096io_s_readlines(
VALUE v)
12099 return io_readlines(arg, arg->io);
12156rb_io_s_readlines(
int argc,
VALUE *argv,
VALUE io)
12162 argc =
rb_scan_args(argc, argv,
"12:", NULL, NULL, NULL, &opt);
12163 extract_getline_args(argc-1, argv+1, &garg);
12164 open_key_args(io, argc, argv, opt, &arg);
12166 extract_getline_opts(opt, &garg);
12167 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12168 return rb_ensure(io_s_readlines, (
VALUE)&garg, rb_io_close, arg.io);
12175 return io_read(arg->argc, arg->argv, arg->io);
12185seek_before_access(
VALUE argp)
12189 return rb_io_seek(arg->io, arg->offset, arg->mode);
12235rb_io_s_read(
int argc,
VALUE *argv,
VALUE io)
12241 argc =
rb_scan_args(argc, argv,
"13:", NULL, NULL, &offset, NULL, &opt);
12243 rb_raise(rb_eArgError,
"negative offset %ld given",
off);
12245 open_key_args(io, argc, argv, opt, &arg);
12247 if (!
NIL_P(offset)) {
12251 sarg.offset = offset;
12252 sarg.mode = SEEK_SET;
12253 rb_protect(seek_before_access, (
VALUE)&sarg, &state);
12256 rb_jump_tag(state);
12258 if (arg.argc == 2) arg.argc = 1;
12277rb_io_s_binread(
int argc,
VALUE *argv,
VALUE io)
12292 convconfig.
enc = rb_ascii8bit_encoding();
12293 arg.io = rb_io_open_generic(io, argv[0], oflags, fmode, &convconfig, 0);
12296 arg.argc = (argc > 1) ? 1 : 0;
12297 if (!
NIL_P(offset)) {
12301 sarg.offset = offset;
12302 sarg.mode = SEEK_SET;
12303 rb_protect(seek_before_access, (
VALUE)&sarg, &state);
12306 rb_jump_tag(state);
12313io_s_write0(
VALUE v)
12316 return io_write(arg->io,arg->str,arg->nosync);
12320io_s_write(
int argc,
VALUE *argv,
VALUE klass,
int binary)
12322 VALUE string, offset, opt;
12326 rb_scan_args(argc, argv,
"21:", NULL, &
string, &offset, &opt);
12328 if (
NIL_P(opt)) opt = rb_hash_new();
12329 else opt = rb_hash_dup(opt);
12332 if (
NIL_P(rb_hash_aref(opt,sym_mode))) {
12333 int mode = O_WRONLY|O_CREAT;
12335 if (binary) mode |= O_BINARY;
12337 if (
NIL_P(offset)) mode |= O_TRUNC;
12338 rb_hash_aset(opt,sym_mode,
INT2NUM(mode));
12340 open_key_args(klass, argc, argv, opt, &arg);
12343 if (binary) rb_io_binmode_m(arg.io);
12347 if (!
NIL_P(offset)) {
12351 sarg.offset = offset;
12352 sarg.mode = SEEK_SET;
12353 rb_protect(seek_before_access, (
VALUE)&sarg, &state);
12356 rb_jump_tag(state);
12364 return rb_ensure(io_s_write0, (
VALUE)&warg, rb_io_close, arg.io);
12412rb_io_s_write(
int argc,
VALUE *argv,
VALUE io)
12414 return io_s_write(argc, argv, io, 0);
12431rb_io_s_binwrite(
int argc,
VALUE *argv,
VALUE io)
12433 return io_s_write(argc, argv, io, 1);
12439 rb_off_t copy_length;
12440 rb_off_t src_offset;
12444 unsigned close_src : 1;
12445 unsigned close_dst : 1;
12448 const char *syserr;
12449 const char *notimp;
12451 struct stat src_stat;
12452 struct stat dst_stat;
12453#ifdef HAVE_FCOPYFILE
12454 copyfile_state_t copyfile_state;
12459exec_interrupts(
void *arg)
12462 rb_thread_execute_interrupts(th);
12476#if defined(ERESTART)
12481 rb_thread_execute_interrupts(stp->th);
12500fiber_scheduler_wait_for(
void * _arguments)
12510# define IOWAIT_SYSCALL "poll"
12511STATIC_ASSERT(pollin_expected, POLLIN == RB_WAITFD_IN);
12512STATIC_ASSERT(pollout_expected, POLLOUT == RB_WAITFD_OUT);
12517 if (scheduler !=
Qnil) {
12520 return RTEST(args.result);
12524 if (fd == -1)
return 0;
12529 fds.events = events;
12531 int timeout_milliseconds = -1;
12534 timeout_milliseconds = (int)(timeout->tv_sec * 1000) + (int)(timeout->tv_usec / 1000);
12537 return poll(&fds, 1, timeout_milliseconds);
12540# define IOWAIT_SYSCALL "select"
12545 if (scheduler !=
Qnil) {
12548 return RTEST(args.result);
12568 case RB_WAITFD_OUT:
12572 VM_UNREACHABLE(nogvl_wait_for);
12592 ret = nogvl_wait_for(stp->th, stp->src_fptr, RB_WAITFD_IN, NULL);
12594 }
while (ret < 0 && maygvl_copy_stream_continue_p(has_gvl, stp));
12597 stp->syserr = IOWAIT_SYSCALL;
12598 stp->error_no =
errno;
12610 ret = nogvl_wait_for(stp->th, stp->dst_fptr, RB_WAITFD_OUT, NULL);
12611 }
while (ret < 0 && maygvl_copy_stream_continue_p(0, stp));
12614 stp->syserr = IOWAIT_SYSCALL;
12615 stp->error_no =
errno;
12621#ifdef USE_COPY_FILE_RANGE
12624simple_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)
12626#ifdef HAVE_COPY_FILE_RANGE
12627 return copy_file_range(in_fd, in_offset, out_fd, out_offset, count, flags);
12629 return syscall(__NR_copy_file_range, in_fd, in_offset, out_fd, out_offset, count, flags);
12638 rb_off_t copy_length, src_offset, *src_offset_ptr;
12640 if (!S_ISREG(stp->src_stat.st_mode))
12643 src_size = stp->src_stat.st_size;
12644 src_offset = stp->src_offset;
12645 if (src_offset >= (rb_off_t)0) {
12646 src_offset_ptr = &src_offset;
12649 src_offset_ptr = NULL;
12652 copy_length = stp->copy_length;
12653 if (copy_length < (rb_off_t)0) {
12654 if (src_offset < (rb_off_t)0) {
12655 rb_off_t current_offset;
12657 current_offset = lseek(stp->src_fptr->
fd, 0, SEEK_CUR);
12658 if (current_offset < (rb_off_t)0 &&
errno) {
12659 stp->syserr =
"lseek";
12660 stp->error_no =
errno;
12661 return (
int)current_offset;
12663 copy_length = src_size - current_offset;
12666 copy_length = src_size - src_offset;
12670 retry_copy_file_range:
12671# if SIZEOF_OFF_T > SIZEOF_SIZE_T
12673 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
12675 ss = (ssize_t)copy_length;
12677 ss = simple_copy_file_range(stp->src_fptr->
fd, src_offset_ptr, stp->dst_fptr->
fd, NULL, ss, 0);
12681 if (0 < copy_length) {
12682 goto retry_copy_file_range;
12686 if (maygvl_copy_stream_continue_p(0, stp)) {
12687 goto retry_copy_file_range;
12701#if EWOULDBLOCK != EAGAIN
12705 int ret = nogvl_copy_stream_wait_write(stp);
12706 if (ret < 0)
return ret;
12708 goto retry_copy_file_range;
12712 int flags = fcntl(stp->dst_fptr->
fd, F_GETFL);
12714 if (flags != -1 && flags & O_APPEND) {
12720 stp->syserr =
"copy_file_range";
12721 stp->error_no =
errno;
12728#ifdef HAVE_FCOPYFILE
12732 rb_off_t cur, ss = 0;
12733 const rb_off_t src_offset = stp->src_offset;
12736 if (stp->copy_length >= (rb_off_t)0) {
12741 if (!S_ISREG(stp->src_stat.st_mode))
12744 if (!S_ISREG(stp->dst_stat.st_mode))
12746 if (lseek(stp->dst_fptr->
fd, 0, SEEK_CUR) > (rb_off_t)0)
12748 if (fcntl(stp->dst_fptr->
fd, F_GETFL) & O_APPEND) {
12751 rb_off_t end = lseek(stp->dst_fptr->
fd, 0, SEEK_END);
12752 lseek(stp->dst_fptr->
fd, 0, SEEK_SET);
12753 if (end > (rb_off_t)0)
return 0;
12756 if (src_offset > (rb_off_t)0) {
12761 cur = lseek(stp->src_fptr->
fd, 0, SEEK_CUR);
12762 if (cur < (rb_off_t)0 &&
errno) {
12763 stp->error_no =
errno;
12768 r = lseek(stp->src_fptr->
fd, src_offset, SEEK_SET);
12769 if (r < (rb_off_t)0 &&
errno) {
12770 stp->error_no =
errno;
12775 stp->copyfile_state = copyfile_state_alloc();
12776 ret = fcopyfile(stp->src_fptr->
fd, stp->dst_fptr->
fd, stp->copyfile_state, COPYFILE_DATA);
12777 copyfile_state_get(stp->copyfile_state, COPYFILE_STATE_COPIED, &ss);
12781 if (src_offset > (rb_off_t)0) {
12785 r = lseek(stp->src_fptr->
fd, cur, SEEK_SET);
12786 if (r < (rb_off_t)0 &&
errno) {
12787 stp->error_no =
errno;
12799 stp->syserr =
"fcopyfile";
12800 stp->error_no =
errno;
12807#ifdef HAVE_SENDFILE
12810# define USE_SENDFILE
12812# ifdef HAVE_SYS_SENDFILE_H
12813# include <sys/sendfile.h>
12817simple_sendfile(
int out_fd,
int in_fd, rb_off_t *offset, rb_off_t count)
12819 return sendfile(out_fd, in_fd, offset, (
size_t)count);
12822# elif 0 || defined(__APPLE__)
12826# define USE_SENDFILE
12829simple_sendfile(
int out_fd,
int in_fd, rb_off_t *offset, rb_off_t count)
12832 rb_off_t pos = offset ? *offset : lseek(in_fd, 0, SEEK_CUR);
12835 r = sendfile(in_fd, out_fd, pos, &count, NULL, 0);
12838 r = sendfile(in_fd, out_fd, pos, (
size_t)count, NULL, &sbytes, 0);
12840 if (r != 0 && sbytes == 0)
return r;
12845 lseek(in_fd, sbytes, SEEK_CUR);
12847 return (ssize_t)sbytes;
12860 rb_off_t copy_length;
12861 rb_off_t src_offset;
12864 if (!S_ISREG(stp->src_stat.st_mode))
12867 src_size = stp->src_stat.st_size;
12869 if ((stp->dst_stat.st_mode & S_IFMT) != S_IFSOCK)
12873 src_offset = stp->src_offset;
12874 use_pread = src_offset >= (rb_off_t)0;
12876 copy_length = stp->copy_length;
12877 if (copy_length < (rb_off_t)0) {
12879 copy_length = src_size - src_offset;
12883 cur = lseek(stp->src_fptr->
fd, 0, SEEK_CUR);
12884 if (cur < (rb_off_t)0 &&
errno) {
12885 stp->syserr =
"lseek";
12886 stp->error_no =
errno;
12889 copy_length = src_size - cur;
12894# if SIZEOF_OFF_T > SIZEOF_SIZE_T
12896 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
12898 ss = (ssize_t)copy_length;
12901 ss = simple_sendfile(stp->dst_fptr->
fd, stp->src_fptr->
fd, &src_offset, ss);
12904 ss = simple_sendfile(stp->dst_fptr->
fd, stp->src_fptr->
fd, NULL, ss);
12909 if (0 < copy_length) {
12910 goto retry_sendfile;
12914 if (maygvl_copy_stream_continue_p(0, stp))
12915 goto retry_sendfile;
12928#if EWOULDBLOCK != EAGAIN
12941 ret = maygvl_copy_stream_wait_read(0, stp);
12942 if (ret < 0)
return ret;
12944 ret = nogvl_copy_stream_wait_write(stp);
12945 if (ret < 0)
return ret;
12947 goto retry_sendfile;
12949 stp->syserr =
"sendfile";
12950 stp->error_no =
errno;
12958maygvl_read(
int has_gvl,
rb_io_t *fptr,
void *buf,
size_t count)
12961 return rb_io_read_memory(fptr, buf, count);
12963 return read(fptr->
fd, buf, count);
12967maygvl_copy_stream_read(
int has_gvl,
struct copy_stream_struct *stp,
char *buf,
size_t len, rb_off_t offset)
12971 if (offset < (rb_off_t)0) {
12972 ss = maygvl_read(has_gvl, stp->src_fptr, buf,
len);
12975 ss = pread(stp->src_fptr->
fd, buf,
len, offset);
12981 if (maygvl_copy_stream_continue_p(has_gvl, stp))
12985#if EWOULDBLOCK != EAGAIN
12989 int ret = maygvl_copy_stream_wait_read(has_gvl, stp);
12990 if (ret < 0)
return ret;
12995 stp->notimp =
"pread";
12999 stp->syserr = offset < (rb_off_t)0 ?
"read" :
"pread";
13000 stp->error_no =
errno;
13011 ss = write(stp->dst_fptr->
fd, buf+
off,
len);
13013 if (maygvl_copy_stream_continue_p(0, stp))
13015 if (io_again_p(
errno)) {
13016 int ret = nogvl_copy_stream_wait_write(stp);
13017 if (ret < 0)
return ret;
13020 stp->syserr =
"write";
13021 stp->error_no =
errno;
13038 rb_off_t copy_length;
13039 rb_off_t src_offset;
13043 copy_length = stp->copy_length;
13044 use_eof = copy_length < (rb_off_t)0;
13045 src_offset = stp->src_offset;
13046 use_pread = src_offset >= (rb_off_t)0;
13048 if (use_pread && stp->close_src) {
13051 r = lseek(stp->src_fptr->
fd, src_offset, SEEK_SET);
13052 if (r < (rb_off_t)0 &&
errno) {
13053 stp->syserr =
"lseek";
13054 stp->error_no =
errno;
13057 src_offset = (rb_off_t)-1;
13061 while (use_eof || 0 < copy_length) {
13062 if (!use_eof && copy_length < (rb_off_t)
sizeof(buf)) {
13063 len = (size_t)copy_length;
13069 ss = maygvl_copy_stream_read(0, stp, buf,
len, src_offset);
13074 ss = maygvl_copy_stream_read(0, stp, buf,
len, (rb_off_t)-1);
13079 ret = nogvl_copy_stream_write(stp, buf, ss);
13089nogvl_copy_stream_func(
void *arg)
13092#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13096#ifdef USE_COPY_FILE_RANGE
13097 ret = nogvl_copy_file_range(stp);
13102#ifdef HAVE_FCOPYFILE
13103 ret = nogvl_fcopyfile(stp);
13109 ret = nogvl_copy_stream_sendfile(stp);
13114 nogvl_copy_stream_read_write(stp);
13116#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13123copy_stream_fallback_body(
VALUE arg)
13126 const int buflen = 16*1024;
13129 rb_off_t rest = stp->copy_length;
13130 rb_off_t
off = stp->src_offset;
13131 ID read_method = id_readpartial;
13133 if (!stp->src_fptr) {
13135 read_method = id_read;
13142 rb_str_make_independent(buf);
13143 if (stp->copy_length < (rb_off_t)0) {
13148 rb_str_resize(buf, 0);
13151 l = buflen < rest ? buflen : (long)rest;
13153 if (!stp->src_fptr) {
13156 if (read_method == id_read &&
NIL_P(rc))
13161 rb_str_resize(buf, buflen);
13162 ss = maygvl_copy_stream_read(1, stp, RSTRING_PTR(buf), l,
off);
13163 rb_str_resize(buf, ss > 0 ? ss : 0);
13168 if (
off >= (rb_off_t)0)
13171 n = rb_io_write(stp->dst, buf);
13173 stp->total += numwrote;
13175 if (read_method == id_read && RSTRING_LEN(buf) == 0) {
13186 if (!stp->src_fptr && stp->src_offset >= (rb_off_t)0) {
13187 rb_raise(rb_eArgError,
"cannot specify src_offset for non-IO");
13196copy_stream_body(
VALUE arg)
13199 VALUE src_io = stp->src, dst_io = stp->dst;
13200 const int common_oflags = 0
13210 if (src_io ==
argf ||
13214 stp->src_fptr = NULL;
13219 if (!
NIL_P(tmp_io)) {
13226 args[1] =
INT2NUM(O_RDONLY|common_oflags);
13229 stp->close_src = 1;
13234 stat_ret = fstat(stp->src_fptr->
fd, &stp->src_stat);
13235 if (stat_ret < 0) {
13236 stp->syserr =
"fstat";
13237 stp->error_no =
errno;
13242 if (dst_io ==
argf ||
13246 stp->dst_fptr = NULL;
13251 if (!
NIL_P(tmp_io)) {
13252 dst_io = GetWriteIO(tmp_io);
13258 args[1] =
INT2NUM(O_WRONLY|O_CREAT|O_TRUNC|common_oflags);
13262 stp->close_dst = 1;
13265 dst_io = GetWriteIO(dst_io);
13271 stat_ret = fstat(stp->dst_fptr->
fd, &stp->dst_stat);
13272 if (stat_ret < 0) {
13273 stp->syserr =
"fstat";
13274 stp->error_no =
errno;
13281 SET_BINARY_MODE_WITH_SEEK_CUR(stp->src_fptr);
13284 io_ascii8bit_binmode(stp->dst_fptr);
13286 if (stp->src_offset < (rb_off_t)0 && stp->src_fptr && stp->src_fptr->
rbuf.
len) {
13289 if (stp->copy_length >= (rb_off_t)0 && stp->copy_length < (rb_off_t)
len) {
13290 len = (size_t)stp->copy_length;
13293 rb_str_resize(str,
len);
13294 read_buffered_data(RSTRING_PTR(str),
len, stp->src_fptr);
13295 if (stp->dst_fptr) {
13296 if (io_binwrite(RSTRING_PTR(str), RSTRING_LEN(str), stp->dst_fptr, 0) < 0)
13297 rb_sys_fail_on_write(stp->dst_fptr);
13300 rb_io_write(dst_io, str);
13301 rb_str_resize(str, 0);
13303 if (stp->copy_length >= (rb_off_t)0)
13304 stp->copy_length -=
len;
13307 if (stp->dst_fptr && io_fflush(stp->dst_fptr) < 0) {
13311 if (stp->copy_length == 0)
13314 if (stp->src_fptr == NULL || stp->dst_fptr == NULL) {
13315 return copy_stream_fallback(stp);
13318 IO_WITHOUT_GVL(nogvl_copy_stream_func, stp);
13323copy_stream_finalize(
VALUE arg)
13327#ifdef HAVE_FCOPYFILE
13328 if (stp->copyfile_state) {
13329 copyfile_state_free(stp->copyfile_state);
13333 if (stp->close_src) {
13334 rb_io_close_m(stp->src);
13336 if (stp->close_dst) {
13337 rb_io_close_m(stp->dst);
13400rb_io_s_copy_stream(
int argc,
VALUE *argv,
VALUE io)
13402 VALUE src, dst, length, src_offset;
13407 rb_scan_args(argc, argv,
"22", &src, &dst, &length, &src_offset);
13412 st.src_fptr = NULL;
13413 st.dst_fptr = NULL;
13416 st.copy_length = (rb_off_t)-1;
13418 st.copy_length =
NUM2OFFT(length);
13420 if (
NIL_P(src_offset))
13421 st.src_offset = (rb_off_t)-1;
13423 st.src_offset =
NUM2OFFT(src_offset);
13442rb_io_external_encoding(
VALUE io)
13447 return rb_enc_from_encoding(fptr->
encs.
enc2);
13451 return rb_enc_from_encoding(fptr->
encs.
enc);
13454 return rb_enc_from_encoding(io_read_encoding(fptr));
13470rb_io_internal_encoding(
VALUE io)
13475 return rb_enc_from_encoding(io_read_encoding(fptr));
13509rb_io_set_encoding(
int argc,
VALUE *argv,
VALUE io)
13515 return forward(io, id_set_encoding, argc, argv);
13518 argc =
rb_scan_args(argc, argv,
"11:", &v1, &v2, &opt);
13520 io_encoding_set(fptr, v1, v2, opt);
13525rb_stdio_set_default_encoding(
void)
13530 if (isatty(fileno(stdin))) {
13532 rb_encoding *internal = rb_default_internal_encoding();
13533 if (!internal) internal = rb_default_external_encoding();
13535 rb_enc_from_encoding(external),
13536 rb_enc_from_encoding(internal),
13541 rb_io_set_encoding(1, &val,
rb_stdin);
13542 rb_io_set_encoding(1, &val,
rb_stdout);
13543 rb_io_set_encoding(1, &val,
rb_stderr);
13547global_argf_p(
VALUE arg)
13549 return arg ==
argf;
13552typedef VALUE (*argf_encoding_func)(
VALUE io);
13555argf_encoding(
VALUE argf, argf_encoding_func func)
13557 if (!
RTEST(ARGF.current_file)) {
13558 return rb_enc_default_external();
13582 return argf_encoding(
argf, rb_io_external_encoding);
13601 return argf_encoding(
argf, rb_io_internal_encoding);
13640 if (!next_argv()) {
13641 rb_raise(rb_eArgError,
"no stream to set encoding");
13643 rb_io_set_encoding(argc, argv, ARGF.current_file);
13645 ARGF.encs = fptr->
encs;
13664 if (!next_argv()) {
13665 rb_raise(rb_eArgError,
"no stream to tell");
13667 ARGF_FORWARD(0, 0);
13668 return rb_io_tell(ARGF.current_file);
13681 if (!next_argv()) {
13682 rb_raise(rb_eArgError,
"no stream to seek");
13684 ARGF_FORWARD(argc, argv);
13685 return rb_io_seek_m(argc, argv, ARGF.current_file);
13702 if (!next_argv()) {
13703 rb_raise(rb_eArgError,
"no stream to set position");
13705 ARGF_FORWARD(1, &offset);
13706 return rb_io_set_pos(ARGF.current_file, offset);
13727 if (!next_argv()) {
13728 rb_raise(rb_eArgError,
"no stream to rewind");
13730 ARGF_FORWARD(0, 0);
13731 old_lineno =
RFILE(ARGF.current_file)->fptr->lineno;
13732 ret = rb_io_rewind(ARGF.current_file);
13733 if (!global_argf_p(
argf)) {
13734 ARGF.last_lineno = ARGF.lineno -= old_lineno;
13752 if (!next_argv()) {
13753 rb_raise(rb_eArgError,
"no stream");
13755 ARGF_FORWARD(0, 0);
13756 return rb_io_fileno(ARGF.current_file);
13775 ARGF_FORWARD(0, 0);
13776 return ARGF.current_file;
13801 if (
RTEST(ARGF.current_file)) {
13802 if (ARGF.init_p == 0)
return Qtrue;
13804 ARGF_FORWARD(0, 0);
13863 VALUE tmp, str, length;
13867 if (!
NIL_P(length)) {
13872 rb_str_resize(str,0);
13877 if (!next_argv()) {
13880 if (ARGF_GENERIC_INPUT_P()) {
13881 tmp = argf_forward(argc, argv,
argf);
13884 tmp = io_read(argc, argv, ARGF.current_file);
13886 if (
NIL_P(str)) str = tmp;
13889 if (ARGF.next_p != -1) {
13895 else if (argc >= 1) {
13896 long slen = RSTRING_LEN(str);
13912argf_forward_call(
VALUE arg)
13915 argf_forward(p->argc, p->argv, p->argf);
13945 return argf_getpartial(argc, argv,
argf,
Qnil, 0);
13966 return argf_getpartial(argc, argv,
argf, opts, 1);
13972 VALUE tmp, str, length;
13980 no_exception = no_exception_p(opts);
13982 if (!next_argv()) {
13984 rb_str_resize(str, 0);
13988 if (ARGF_GENERIC_INPUT_P()) {
13998 tmp = io_getpartial(argc, argv, ARGF.current_file, no_exception, nonblock);
14001 if (ARGF.next_p == -1) {
14002 return io_nonblock_eof(no_exception);
14007 return io_nonblock_eof(no_exception);
14045 if (!next_argv())
return Qnil;
14046 if (ARGF_GENERIC_INPUT_P()) {
14047 ch = forward_current(rb_intern(
"getc"), 0, 0);
14050 ch = rb_io_getc(ARGF.current_file);
14052 if (
NIL_P(ch) && ARGF.next_p != -1) {
14085 if (!next_argv())
return Qnil;
14087 ch = forward_current(rb_intern(
"getbyte"), 0, 0);
14092 if (
NIL_P(ch) && ARGF.next_p != -1) {
14125 if (!next_argv()) rb_eof_error();
14127 ch = forward_current(rb_intern(
"getc"), 0, 0);
14130 ch = rb_io_getc(ARGF.current_file);
14132 if (
NIL_P(ch) && ARGF.next_p != -1) {
14164 NEXT_ARGF_FORWARD(0, 0);
14165 c = argf_getbyte(
argf);
14172#define FOREACH_ARGF() while (next_argv())
14177 const VALUE current = ARGF.current_file;
14179 if (ARGF.init_p == -1 || current != ARGF.current_file) {
14185#define ARGF_block_call(mid, argc, argv, func, argf) \
14186 rb_block_call_kw(ARGF.current_file, mid, argc, argv, \
14187 func, argf, rb_keyword_given_p())
14192 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_i,
argf);
14193 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14199 if (!global_argf_p(
argf)) {
14200 ARGF.last_lineno = ++ARGF.lineno;
14202 return argf_block_call_i(i,
argf, argc, argv, blockarg);
14208 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_line_i,
argf);
14209 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14257 argf_block_call_line(rb_intern(
"each_line"), argc, argv,
argf);
14288 argf_block_call(rb_intern(
"each_byte"), 0, 0,
argf);
14314 argf_block_call(rb_intern(
"each_char"), 0, 0,
argf);
14340 argf_block_call(rb_intern(
"each_codepoint"), 0, 0,
argf);
14371 return ARGF.filename;
14375argf_filename_getter(
ID id,
VALUE *var)
14377 return argf_filename(*var);
14402 return ARGF.current_file;
14421 ARGF_FORWARD(0, 0);
14442 return RBOOL(ARGF.binmode);
14462 if (ARGF.init_p && ARGF.next_p == 0) {
14491 if (ARGF.next_p != -1) {
14509 ARGF_FORWARD(0, 0);
14536 if (!ARGF.inplace)
return Qnil;
14544 return argf_inplace_mode_get(*var);
14575 ARGF.inplace =
Qnil;
14586 argf_inplace_mode_set(*var, val);
14590ruby_set_inplace_mode(
const char *suffix)
14616argf_argv_getter(
ID id,
VALUE *var)
14618 return argf_argv(*var);
14637 if (!
RTEST(ARGF.current_file)) {
14640 return GetWriteIO(ARGF.current_file);
14652 return rb_io_writev(argf_write_io(
argf), argc, argv);
14667 case RB_IO_WAIT_WRITABLE:
14670 c = rb_eEAGAINWaitWritable;
14672#if EAGAIN != EWOULDBLOCK
14674 c = rb_eEWOULDBLOCKWaitWritable;
14678 c = rb_eEINPROGRESSWaitWritable;
14684 case RB_IO_WAIT_READABLE:
14687 c = rb_eEAGAINWaitReadable;
14689#if EAGAIN != EWOULDBLOCK
14691 c = rb_eEWOULDBLOCKWaitReadable;
14695 c = rb_eEINPROGRESSWaitReadable;
14702 rb_bug(
"invalid read/write type passed to rb_readwrite_sys_fail: %d", waiting);
14708get_LAST_READ_LINE(
ID _x,
VALUE *_y)
15593#include <sys/cygwin.h>
15594 static struct __cygwin_perfile pf[] =
15596 {
"", O_RDONLY | O_BINARY},
15597 {
"", O_WRONLY | O_BINARY},
15598 {
"", O_RDWR | O_BINARY},
15599 {
"", O_APPEND | O_BINARY},
15602 cygwin_internal(CW_PERFILE, pf);
15657#if EAGAIN == EWOULDBLOCK
15658 rb_eEWOULDBLOCKWaitReadable = rb_eEAGAINWaitReadable;
15660 rb_define_const(
rb_cIO,
"EWOULDBLOCKWaitReadable", rb_eEAGAINWaitReadable);
15661 rb_eEWOULDBLOCKWaitWritable = rb_eEAGAINWaitWritable;
15663 rb_define_const(
rb_cIO,
"EWOULDBLOCKWaitWritable", rb_eEAGAINWaitWritable);
15703 rb_output_fs =
Qnil;
15715 rb_gvar_ractor_local(
"$_");
15831 rb_gvar_ractor_local(
"$stdin");
15832 rb_gvar_ractor_local(
"$stdout");
15833 rb_gvar_ractor_local(
"$>");
15834 rb_gvar_ractor_local(
"$stderr");
15920 rb_define_method(rb_cARGF,
"external_encoding", argf_external_encoding, 0);
15921 rb_define_method(rb_cARGF,
"internal_encoding", argf_internal_encoding, 0);
15940 rb_gvar_ractor_local(
"$-i");
15944#if defined (_WIN32) || defined(__CYGWIN__)
15945 atexit(pipe_atexit);
15957 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 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.
#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_file_open_str(VALUE fname, const char *fmode)
Identical to rb_file_open(), except it takes the pathname as a Ruby's string instead of C's.
int rb_cloexec_dup(int oldfd)
Identical to rb_cloexec_fcntl_dupfd(), except it implies minfd is 3.
VALUE rb_file_open(const char *fname, const char *fmode)
Opens a file located at the given path.
VALUE rb_io_close(VALUE io)
Closes the IO.
VALUE rb_default_rs
This is the default value of rb_rs, i.e.
void rb_lastline_set(VALUE str)
Updates $_.
VALUE rb_lastline_get(void)
Queries the last line, or the $_.
int rb_obj_method_arity(VALUE obj, ID mid)
Identical to rb_mod_method_arity(), except it searches for singleton methods rather than instance met...
rb_pid_t rb_waitpid(rb_pid_t pid, int *status, int flags)
Waits for a process, with releasing GVL.
void rb_last_status_set(int status, rb_pid_t pid)
Sets the "last status", or the $?.
VALUE rb_str_append(VALUE dst, VALUE src)
Identical to rb_str_buf_append(), except it converts the right hand side before concatenating.
#define rb_str_new(str, len)
Allocates an instance of rb_cString.
#define rb_str_buf_cat
Just another name of rb_str_cat.
#define rb_usascii_str_new(str, len)
Identical to rb_str_new, except it generates a string of "US ASCII" encoding.
size_t rb_str_capacity(VALUE str)
Queries the capacity of the given string.
VALUE rb_str_new_frozen(VALUE str)
Creates a frozen copy of the string, if necessary.
VALUE rb_str_dup(VALUE str)
Duplicates a string.
VALUE rb_str_cat(VALUE dst, const char *src, long srclen)
Destructively appends the passed contents to the string.
VALUE rb_str_locktmp(VALUE str)
Obtains a "temporary lock" of the string.
rb_gvar_setter_t rb_str_setter
This is a rb_gvar_setter_t that refutes non-string assignments.
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.
void rb_thread_fd_close(int fd)
Notifies a closing of a file descriptor to other threads.
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.
int 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.
int rb_io_mode(VALUE io)
Get the mode of the IO.
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_io_extract_encoding_option(VALUE opt, rb_encoding **enc_p, rb_encoding **enc2_p, int *fmode_p)
This function breaks down the option hash that IO#initialize takes into components.
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_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_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".
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".
void rb_io_extract_modeenc(VALUE *vmode_p, VALUE *vperm_p, VALUE opthash, int *oflags_p, int *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...
int rb_io_wait_writable(int fd)
Blocks until the passed file descriptor gets writable.
VALUE rb_io_open_descriptor(VALUE klass, int descriptor, int mode, VALUE path, VALUE timeout, struct rb_io_encoding *encoding)
Allocate a new IO object, with the given file descriptor.
VALUE rb_io_set_write_io(VALUE io, VALUE w)
Assigns the tied IO for writing.
void rb_io_check_writable(rb_io_t *fptr)
Asserts that an IO is opened for writing.
int rb_io_maybe_wait_writable(int error, VALUE io, VALUE timeout)
Blocks until the passed IO is ready for writing, if that makes sense for the passed errno.
void rb_io_check_closed(rb_io_t *fptr)
This badly named function asserts that the passed IO is open.
int rb_io_wait_readable(int fd)
Blocks until the passed file descriptor gets readable.
void rb_io_synchronized(rb_io_t *fptr)
Sets FMODE_SYNC.
VALUE rb_io_wait(VALUE io, VALUE events, VALUE timeout)
Blocks until the passed IO is ready for the passed events.
int len
Length of the buffer.
VALUE rb_ractor_stdin(void)
Queries the standard input of the current Ractor that is calling this function.
void rb_ractor_stderr_set(VALUE io)
Assigns an IO to the standard error of the Ractor that is calling this function.
void rb_ractor_stdout_set(VALUE io)
Assigns an IO to the standard output of the Ractor that is calling this function.
void rb_ractor_stdin_set(VALUE io)
Assigns an IO to the standard input of the Ractor that is calling this function.
void * rb_thread_call_with_gvl(void *(*func)(void *), void *data1)
(Re-)acquires the GVL.
#define RB_NUM2INT
Just another name of rb_num2int_inline.
#define RB_INT2NUM
Just another name of rb_int2num_inline.
VALUE rb_f_sprintf(int argc, const VALUE *argv)
Identical to rb_str_format(), except how the arguments are arranged.
#define RB_BLOCK_CALL_FUNC_ARGLIST(yielded_arg, callback_arg)
Shim for block function parameters.
VALUE rb_yield_values2(int n, const VALUE *argv)
Identical to rb_yield_values(), except it takes the parameters as a C array instead of variadic argum...
VALUE rb_yield(VALUE val)
Yields the block.
void rb_fd_term(rb_fdset_t *f)
Destroys the rb_fdset_t, releasing any memory and resources it used.
#define MEMZERO(p, type, n)
Handy macro to erase a region of memory.
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
#define MEMMOVE(p1, p2, type, n)
Handy macro to call memmove.
#define NUM2MODET
Converts a C's mode_t into an instance of rb_cInteger.
void rb_define_hooked_variable(const char *q, VALUE *w, type *e, void_type *r)
Define a function-backended global variable.
void rb_define_virtual_variable(const char *q, type *w, void_type *e)
Define a function-backended global variable.
VALUE rb_rescue2(type *q, VALUE w, type *e, VALUE r,...)
An equivalent of rescue clause.
VALUE rb_ensure(type *q, VALUE w, type *e, VALUE r)
An equivalent of ensure clause.
#define PRI_OFFT_PREFIX
A rb_sprintf() format prefix to be used for an off_t parameter.
#define OFFT2NUM
Converts a C's off_t into an instance of rb_cInteger.
#define NUM2OFFT
Converts an instance of rb_cNumeric into C's off_t.
#define PIDT2NUM
Converts a C's pid_t into an instance of rb_cInteger.
#define rb_fd_isset
Queries if the given fd is in the rb_fdset_t.
#define rb_fd_select
Waits for multiple file descriptors at once.
#define rb_fd_init
Initialises the :given :rb_fdset_t.
#define rb_fd_set
Sets the given fd to the rb_fdset_t.
#define RARRAY_LEN
Just another name of rb_array_len.
static int RARRAY_LENINT(VALUE ary)
Identical to rb_array_len(), except it differs for the return type.
#define RARRAY_AREF(a, i)
#define RARRAY_CONST_PTR
Just another name of rb_array_const_ptr.
#define RFILE(obj)
Convenient casting macro.
#define StringValue(v)
Ensures that the parameter object is a String.
static char * RSTRING_END(VALUE str)
Queries the end of the contents pointer of the string.
#define RSTRING_GETMEM(str, ptrvar, lenvar)
Convenient macro to obtain the contents and length at once.
#define StringValueCStr(v)
Identical to StringValuePtr, except it additionally checks for the contents for viability as a C stri...
#define RUBY_TYPED_DEFAULT_FREE
This is a value you can set to rb_data_type_struct::dfree.
#define TypedData_Make_Struct(klass, type, data_type, sval)
Identical to TypedData_Wrap_Struct, except it allocates a new data region internally instead of takin...
VALUE rb_get_argv(void)
Queries the arguments passed to the current process that you can access from Ruby as ARGV.
void rb_p(VALUE obj)
Inspects an object.
#define FilePathValue(v)
Ensures that the parameter object is a path.
#define errno
Ractor-aware version of errno.
#define RB_SCAN_ARGS_LAST_HASH_KEYWORDS
Treat a final argument as keywords if it is a hash, and not as keywords otherwise.
#define RB_PASS_CALLED_KEYWORDS
Pass keywords if current method is called with keywords, useful for argument delegation.
VALUE rb_fiber_scheduler_current(void)
Identical to rb_fiber_scheduler_get(), except it also returns RUBY_Qnil in case of a blocking fiber.
VALUE rb_fiber_scheduler_io_pread_memory(VALUE scheduler, VALUE io, rb_off_t from, void *base, size_t size, size_t length)
Non-blocking pread from the passed IO using a native buffer.
VALUE rb_fiber_scheduler_make_timeout(struct timeval *timeout)
Converts the passed timeout to an expression that rb_fiber_scheduler_block() etc.
VALUE rb_fiber_scheduler_io_wait_readable(VALUE scheduler, VALUE io)
Non-blocking wait until the passed IO is ready for reading.
VALUE rb_fiber_scheduler_io_read_memory(VALUE scheduler, VALUE io, void *base, size_t size, size_t length)
Non-blocking read from the passed IO using a native buffer.
VALUE rb_fiber_scheduler_io_wait(VALUE scheduler, VALUE io, VALUE events, VALUE timeout)
Non-blocking version of rb_io_wait().
static ssize_t rb_fiber_scheduler_io_result_apply(VALUE result)
Apply an io result to the local thread, returning the value of the original system call that created ...
VALUE rb_fiber_scheduler_io_selectv(VALUE scheduler, int argc, VALUE *argv)
Non-blocking version of IO.select, argv variant.
VALUE rb_fiber_scheduler_io_pwrite_memory(VALUE scheduler, VALUE io, rb_off_t from, const void *base, size_t size, size_t length)
Non-blocking pwrite to the passed IO using a native buffer.
VALUE rb_fiber_scheduler_current_for_thread(VALUE thread)
Identical to rb_fiber_scheduler_current(), except it queries for that of the passed thread instead of...
VALUE rb_fiber_scheduler_io_write_memory(VALUE scheduler, VALUE io, const void *base, size_t size, size_t length)
Non-blocking write to the passed IO using a native buffer.
VALUE rb_fiber_scheduler_io_wait_writable(VALUE scheduler, VALUE io)
Non-blocking wait until the passed IO is ready for writing.
int rb_thread_fd_select(int nfds, rb_fdset_t *rfds, rb_fdset_t *wfds, rb_fdset_t *efds, struct timeval *timeout)
Waits for multiple file descriptors at once.
static bool RB_TEST(VALUE obj)
Emulates Ruby's "if" statement.
#define RTEST
This is an old name of RB_TEST.
#define _(args)
This was a transition path from K&R to ANSI.
This is the struct that holds necessary info for a struct.
The data structure which wraps the fd_set bitmap used by select(2).
Decomposed encoding flags (e.g.
VALUE ecopts
Flags as Ruby hash.
rb_encoding * enc2
External encoding.
rb_encoding * enc
Internal encoding.
char * ptr
Pointer to the underlying memory region, of at least capa bytes.
int off
Offset inside of ptr.
int len
Length of the buffer.
int capa
Designed capacity of the buffer.
Ruby's IO, metadata and buffers.
int mode
mode flags: FMODE_XXXs
rb_io_buffer_t wbuf
Write buffer.
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
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_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.