14#include "ruby/internal/config.h"
25# if defined(__linux__)
28# if defined(__FreeBSD_version) && __FreeBSD_version >= 1100000
38#define free(x) xfree(x)
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(__CYGWIN__) || defined(_WIN32)
52# define NO_SAFE_RENAME
55#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__sun)
60#ifdef HAVE_SYS_IOCTL_H
63#if defined(HAVE_FCNTL_H)
65#elif defined(HAVE_SYS_FCNTL_H)
75#if defined(HAVE_SYS_PARAM_H)
76# include <sys/param.h>
89#elif defined HAVE_SYS_SYSCALL_H
90#include <sys/syscall.h>
101#ifdef HAVE_COPYFILE_H
102# include <copyfile.h>
106# include <AvailabilityMacros.h>
110#include "ccan/list/list.h"
115#include "internal/class.h"
116#include "internal/encoding.h"
117#include "internal/error.h"
118#include "internal/inits.h"
119#include "internal/io.h"
120#include "internal/numeric.h"
121#include "internal/object.h"
122#include "internal/process.h"
123#include "internal/thread.h"
124#include "internal/transcode.h"
125#include "internal/variable.h"
128#include "ruby/missing.h"
131#include "ruby_atomic.h"
141#define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR)
145# ifdef _POSIX_PIPE_BUF
146# define PIPE_BUF _POSIX_PIPE_BUF
153# define EWOULDBLOCK EAGAIN
156#if defined(HAVE___SYSCALL) && (defined(__APPLE__) || defined(__OpenBSD__))
158off_t __syscall(quad_t number, ...);
161#define IO_RBUF_CAPA_MIN 8192
162#define IO_CBUF_CAPA_MIN (128*1024)
163#define IO_RBUF_CAPA_FOR(fptr) (NEED_READCONV(fptr) ? IO_CBUF_CAPA_MIN : IO_RBUF_CAPA_MIN)
164#define IO_WBUF_CAPA_MIN 8192
166#define IO_MAX_BUFFER_GROWTH 8 * 1024 * 1024
171#define open rb_w32_uopen
173#define rename(f, t) rb_w32_urename((f), (t))
174#include "win32/file.h"
184static VALUE rb_eEAGAINWaitReadable;
185static VALUE rb_eEAGAINWaitWritable;
186#if EAGAIN != EWOULDBLOCK
187static VALUE rb_eEWOULDBLOCKWaitReadable;
188static VALUE rb_eEWOULDBLOCKWaitWritable;
190static VALUE rb_eEINPROGRESSWaitWritable;
191static VALUE rb_eEINPROGRESSWaitReadable;
194static VALUE orig_stdout, orig_stderr;
203static ID id_write, id_read, id_flush, id_readpartial, id_set_encoding, id_fileno;
204static VALUE sym_mode, sym_perm, sym_flags, sym_extenc, sym_intenc, sym_encoding, sym_open_args;
205static VALUE sym_textmode, sym_binmode, sym_autoclose;
206static VALUE sym_SET, sym_CUR, sym_END;
207static VALUE sym_wait_readable, sym_wait_writable;
209static VALUE sym_DATA;
212static VALUE sym_HOLE;
215static VALUE prep_io(
int fd,
enum rb_io_mode fmode,
VALUE klass,
const char *path);
218rb_io_blocking_region_wait(
struct rb_io *io, rb_blocking_function_t *function,
void *argument,
enum rb_io_event events)
220 return rb_thread_io_blocking_call(io, function, argument, events);
223VALUE rb_io_blocking_region(
struct rb_io *io, rb_blocking_function_t *function,
void *argument)
225 return rb_io_blocking_region_wait(io, function, argument, 0);
229 VALUE filename, current_file;
235 int8_t init_p, next_p, binmode;
239#if defined(__APPLE__) && \
240 (!defined(MAC_OS_VERSION_27_0) || (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_VERSION_27_0))
242# if __has_attribute(availability) && __has_warning("-Wunguarded-availability-new")
248static inline int (*rb_dup3(
void))(int, int, int) {
return &dup3;}
249# define dup3 rb_dup3()
253static inline int (*rb_pipe2(
void))(
int [2], int) {
return &pipe2;}
254# define pipe2 rb_pipe2()
279 if (fd < 0 || afd <= max_fd)
282#if defined(HAVE_FCNTL) && defined(F_GETFL)
283 err = fcntl(fd, F_GETFL) == -1;
287 err = fstat(fd, &buf) != 0;
290 if (err &&
errno == EBADF) {
291 rb_bug(
"rb_update_max_fd: invalid fd (%d) given.", fd);
294 while (max_fd < afd) {
295 max_fd = ATOMIC_CAS(max_file_descriptor, max_fd, afd);
300rb_maygvl_fd_fix_cloexec(
int fd)
303#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
304 int flags, flags2, ret;
305 flags = fcntl(fd, F_GETFD);
307 rb_bug(
"rb_maygvl_fd_fix_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(
errno));
310 flags2 = flags & ~FD_CLOEXEC;
312 flags2 = flags | FD_CLOEXEC;
313 if (flags != flags2) {
314 ret = fcntl(fd, F_SETFD, flags2);
316 rb_bug(
"rb_maygvl_fd_fix_cloexec: fcntl(%d, F_SETFD, %d) failed: %s", fd, flags2, strerror(
errno));
325 rb_maygvl_fd_fix_cloexec(fd);
332 return (e == EWOULDBLOCK) || (e == EAGAIN);
340 static const int retry_interval = 0;
341 static const int retry_max_count = 10000;
347#elif defined O_NOINHERIT
348 flags |= O_NOINHERIT;
351 while ((ret = open(pathname, flags, mode)) == -1) {
353 if (!io_again_p(e))
break;
354 if (retry_count++ >= retry_max_count)
break;
356 sleep(retry_interval);
359 if (ret < 0)
return ret;
361 if (ret > 2)
return ret;
363 rb_maygvl_fd_fix_cloexec(ret);
381 if (oldfd == newfd) {
385#if defined(HAVE_DUP3) && defined(O_CLOEXEC)
386# if defined(__APPLE__)
387# define try_dup3 (dup3 != NULL)
388# define abandon_dup3() true
390 static bool try_dup3 =
true;
391# define abandon_dup3() (errno != ENOSYS || !!(try_dup3 = false))
397 ret = dup3(oldfd, newfd, O_CLOEXEC);
404 if (abandon_dup3())
return ret;
407 ret = dup2(oldfd, newfd);
408 if (ret < 0)
return ret;
410 rb_maygvl_fd_fix_cloexec(ret);
415rb_fd_set_nonblock(
int fd)
418 return rb_w32_set_nonblock(fd);
419#elif defined(F_GETFL)
420 int oflags = fcntl(fd, F_GETFL);
424 if (oflags & O_NONBLOCK)
426 oflags |= O_NONBLOCK;
427 return fcntl(fd, F_SETFL, oflags);
433cloexec_pipe(
int descriptors[2],
int flags,
bool force_cloexec)
437# if defined(__APPLE__)
438# define try_pipe2 (pipe2 != NULL)
439# define abandon_pipe2() true
441 static bool try_pipe2 =
true;
442# define abandon_pipe2() (errno != ENOSYS || !!(try_pipe2 = false))
445 result = pipe2(descriptors, O_CLOEXEC | flags);
446 if (result == 0)
return result;
447 if (abandon_pipe2())
return result;
450 if (result < 0 && (result = pipe(descriptors)) < 0)
454 if (result == 0 && descriptors[1] == -1) {
455 close(descriptors[0]);
462 if (!force_cloexec)
return result;
465 rb_maygvl_fd_fix_cloexec(descriptors[0]);
466 rb_maygvl_fd_fix_cloexec(descriptors[1]);
469 rb_fd_set_nonblock(descriptors[0]);
470 rb_fd_set_nonblock(descriptors[1]);
479 return cloexec_pipe(descriptors, O_NONBLOCK,
true);
487#if defined(HAVE_FCNTL) && defined(F_DUPFD_CLOEXEC)
488 ret = fcntl(fd, F_DUPFD_CLOEXEC, minfd);
489 if (ret > 2)
return ret;
490#elif defined(HAVE_FCNTL) && defined(F_DUPFD)
491 ret = fcntl(fd, F_DUPFD, minfd);
494 if (ret >= 0 && ret < minfd) {
495 const int prev_fd = ret;
501 if (ret < 0)
return ret;
502 rb_maygvl_fd_fix_cloexec(ret);
506#define argf_of(obj) (*(struct argf *)DATA_PTR(obj))
507#define ARGF argf_of(argf)
508#define ARGF_SET(field, value) RB_OBJ_WRITE(argf, &ARGF.field, value)
510#define GetWriteIO(io) rb_io_get_write_io(io)
512#define READ_DATA_PENDING(fptr) ((fptr)->rbuf.len)
513#define READ_DATA_PENDING_COUNT(fptr) ((fptr)->rbuf.len)
514#define READ_DATA_PENDING_PTR(fptr) ((fptr)->rbuf.ptr+(fptr)->rbuf.off)
515#define READ_DATA_BUFFERED(fptr) READ_DATA_PENDING(fptr)
517#define READ_CHAR_PENDING(fptr) ((fptr)->cbuf.len)
518#define READ_CHAR_PENDING_COUNT(fptr) ((fptr)->cbuf.len)
519#define READ_CHAR_PENDING_PTR(fptr) ((fptr)->cbuf.ptr+(fptr)->cbuf.off)
522#define WAIT_FD_IN_WIN32(fptr) \
523 (rb_w32_io_cancelable_p((fptr)->fd) ? Qnil : rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_READABLE), RUBY_IO_TIMEOUT_DEFAULT))
525#define WAIT_FD_IN_WIN32(fptr)
528#define READ_CHECK(fptr) do {\
529 if (!READ_DATA_PENDING(fptr)) {\
530 WAIT_FD_IN_WIN32(fptr);\
531 rb_io_check_closed(fptr);\
537# define S_ISSOCK(m) _S_ISSOCK(m)
540# define S_ISSOCK(m) (((m) & S_IFMT) == _S_IFSOCK)
543# define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
549static int io_fflush(
rb_io_t *);
550static rb_io_t *flush_before_seek(
rb_io_t *fptr,
bool discard_rbuf);
551static void clear_readconv(
rb_io_t *fptr);
552static void clear_codeconv(
rb_io_t *fptr);
554#define FMODE_SIGNAL_ON_EPIPE (1<<17)
556#define fptr_signal_on_epipe(fptr) \
557 (((fptr)->mode & FMODE_SIGNAL_ON_EPIPE) != 0)
559#define fptr_set_signal_on_epipe(fptr, flag) \
561 (fptr)->mode |= FMODE_SIGNAL_ON_EPIPE : \
562 (fptr)->mode &= ~FMODE_SIGNAL_ON_EPIPE)
564extern ID ruby_static_id_signo;
566NORETURN(
static void rb_sys_fail_on_write(
rb_io_t *fptr));
568rb_sys_fail_on_write(
rb_io_t *fptr)
571 VALUE errinfo = rb_syserr_new_path(e, (fptr)->pathv);
573 if (fptr_signal_on_epipe(fptr) && (e == EPIPE)) {
585#define NEED_NEWLINE_DECORATOR_ON_READ(fptr) ((fptr)->mode & FMODE_TEXTMODE)
586#define NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) ((fptr)->mode & FMODE_TEXTMODE)
587#if defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32)
588# define RUBY_CRLF_ENVIRONMENT 1
590# define RUBY_CRLF_ENVIRONMENT 0
593#if RUBY_CRLF_ENVIRONMENT
595# define DEFAULT_TEXTMODE FMODE_TEXTMODE
596# define TEXTMODE_NEWLINE_DECORATOR_ON_WRITE ECONV_CRLF_NEWLINE_DECORATOR
604#define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || (fptr)->encs.ecflags & ~ECONV_CRLF_NEWLINE_DECORATOR)
605#define WRITECONV_MASK ( \
606 (ECONV_DECORATOR_MASK & ~ECONV_CRLF_NEWLINE_DECORATOR)|\
607 ECONV_STATEFUL_DECORATOR_MASK|\
609#define NEED_WRITECONV(fptr) ( \
610 ((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || \
611 ((fptr)->encs.ecflags & WRITECONV_MASK) || \
613#define SET_BINARY_MODE(fptr) setmode((fptr)->fd, O_BINARY)
615#define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) do {\
616 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {\
617 if (((fptr)->mode & FMODE_READABLE) &&\
618 !((fptr)->encs.ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {\
619 setmode((fptr)->fd, O_BINARY);\
622 setmode((fptr)->fd, O_TEXT);\
627#define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) do {\
628 if ((enc2) && ((ecflags) & ECONV_DEFAULT_NEWLINE_DECORATOR)) {\
629 (ecflags) |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;\
637io_unread(
rb_io_t *fptr,
bool discard_rbuf)
653 if (!rb_w32_fd_is_text(fptr->
fd)) {
654 r = lseek(fptr->
fd, -fptr->
rbuf.
len, SEEK_CUR);
655 if (r < 0 &&
errno) {
658 if (!discard_rbuf)
return;
664 pos = lseek(fptr->
fd, 0, SEEK_CUR);
665 if (pos < 0 &&
errno) {
668 if (!discard_rbuf)
goto end;
672 extra_max = (long)(pos - fptr->
rbuf.
len);
680 for (i = 0; i < fptr->
rbuf.
len; i++) {
681 if (*p ==
'\n') newlines++;
682 if (extra_max == newlines)
break;
687 while (newlines >= 0) {
688 r = lseek(fptr->
fd, pos - fptr->
rbuf.
len - newlines, SEEK_SET);
689 if (newlines == 0)
break;
694 read_size = _read(fptr->
fd, buf, fptr->
rbuf.
len + newlines);
698 rb_syserr_fail_path(e, fptr->
pathv);
700 if (read_size == fptr->
rbuf.
len) {
701 lseek(fptr->
fd, r, SEEK_SET);
712 clear_codeconv(fptr);
724set_binary_mode_with_seek_cur(
rb_io_t *fptr)
726 if (!rb_w32_fd_is_text(fptr->
fd))
return O_BINARY;
729 return setmode(fptr->
fd, O_BINARY);
731 flush_before_seek(fptr,
false);
732 return setmode(fptr->
fd, O_BINARY);
734#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) set_binary_mode_with_seek_cur(fptr)
738# define DEFAULT_TEXTMODE 0
739#define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || NEED_NEWLINE_DECORATOR_ON_READ(fptr))
740#define NEED_WRITECONV(fptr) ( \
741 ((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || \
742 NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) || \
743 ((fptr)->encs.ecflags & (ECONV_DECORATOR_MASK|ECONV_STATEFUL_DECORATOR_MASK)) || \
745#define SET_BINARY_MODE(fptr) (void)(fptr)
746#define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) (void)(fptr)
747#define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) ((void)(enc2), (void)(ecflags))
748#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) (void)(fptr)
751#if !defined HAVE_SHUTDOWN && !defined shutdown
752#define shutdown(a,b) 0
756#define is_socket(fd, path) rb_w32_is_socket(fd)
757#elif !defined(S_ISSOCK)
758#define is_socket(fd, path) 0
761is_socket(
int fd,
VALUE path)
764 if (fstat(fd, &sbuf) < 0)
765 rb_sys_fail_path(path);
766 return S_ISSOCK(sbuf.st_mode);
770static const char closed_stream[] =
"closed stream";
773io_fd_check_closed(
int fd)
806 io_fd_check_closed(fptr->
fd);
810rb_io_get_fptr(
VALUE io)
820 return rb_convert_type_with_id(io,
T_FILE,
"IO", idTo_io);
826 return rb_check_convert_type_with_id(io,
T_FILE,
"IO", idTo_io);
844 rb_io_t *fptr = rb_io_get_fptr(io);
853 return write_io ? write_io :
Qnil;
866 rb_io_t *fptr = rb_io_get_fptr(self);
896 if (
RTEST(timeout)) {
900 rb_io_t *fptr = rb_io_get_fptr(self);
925#if !RUBY_CRLF_ENVIRONMENT
927io_unread(
rb_io_t *fptr,
bool discard_rbuf)
935 r = lseek(fptr->
fd, -fptr->
rbuf.
len, SEEK_CUR);
936 if (r < 0 &&
errno) {
939 if (!discard_rbuf)
return;
943 clear_codeconv(fptr);
956 const int min_capa = IO_RBUF_CAPA_FOR(fptr);
959#if SIZEOF_RB_LEN_T > SIZEOF_INT
992 io_ungetbyte(str, fptr);
1010flush_before_seek(
rb_io_t *fptr,
bool discard_rbuf)
1012 if (io_fflush(fptr) < 0)
1013 rb_sys_fail_on_write(fptr);
1014 io_unread(fptr, discard_rbuf);
1019#define io_seek(fptr, ofs, whence) (errno = 0, lseek(flush_before_seek(fptr, true)->fd, (ofs), (whence)))
1020#define io_tell(fptr) lseek(flush_before_seek(fptr, false)->fd, 0, SEEK_CUR)
1036 if (io_fflush(fptr) < 0)
1037 rb_sys_fail_on_write(fptr);
1042 if (io_fflush(wfptr) < 0)
1043 rb_sys_fail_on_write(wfptr);
1051 if (READ_CHAR_PENDING(fptr)) {
1052 rb_raise(
rb_eIOError,
"byte oriented read for character buffered IO");
1063io_read_encoding(
rb_io_t *fptr)
1068 return rb_default_external_encoding();
1072io_input_encoding(
rb_io_t *fptr)
1077 return io_read_encoding(fptr);
1088 io_unread(fptr,
true);
1093rb_io_read_pending(
rb_io_t *fptr)
1096 if (READ_CHAR_PENDING(fptr))
1098 return READ_DATA_PENDING(fptr);
1104 if (!READ_DATA_PENDING(fptr)) {
1111rb_gc_for_fd(
int err)
1113 if (err == EMFILE || err == ENFILE || err == ENOMEM) {
1123#define TRY_WITH_GC(expr) \
1124 for (int first_errno, retried_errno = 0, retried = 0; \
1127 (!rb_gc_for_fd(first_errno = errno) || !(expr)) && \
1128 (retried_errno = errno, 1)); \
1129 (void)retried_errno, retried = 1)
1144io_alloc(
VALUE klass)
1146 UNPROTECTED_NEWOBJ_OF(io,
struct RFile, klass,
T_FILE,
sizeof(
struct RFile));
1154# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
1180struct io_internal_writev_struct {
1187 const struct iovec *iov;
1200io_internal_wait(
VALUE thread,
rb_io_t *fptr,
int error,
int events,
struct timeval *timeout)
1202 if (!timeout && rb_thread_mn_schedulable(thread)) {
1207 int ready = nogvl_wait_for(thread, fptr, events, timeout);
1212 else if (ready == 0) {
1229internal_read_func(
void *ptr)
1234 if (iis->timeout && !iis->nonblock) {
1235 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_IN, iis->timeout) == -1) {
1241 result = read(iis->fd, iis->buf, iis->capa);
1243 if (result < 0 && !iis->nonblock) {
1244 if (io_again_p(
errno)) {
1245 if (io_internal_wait(iis->th, iis->fptr,
errno, RB_WAITFD_IN, iis->timeout) == -1) {
1257#if defined __APPLE__
1258# define do_write_retry(code) do {result = code;} while (result == -1 && errno == EPROTOTYPE)
1260# define do_write_retry(code) result = code
1264internal_write_func(
void *ptr)
1269 if (iis->timeout && !iis->nonblock) {
1270 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1276 do_write_retry(write(iis->fd, iis->buf, iis->capa));
1278 if (result < 0 && !iis->nonblock) {
1280 if (io_again_p(e)) {
1281 if (io_internal_wait(iis->th, iis->fptr,
errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1295internal_writev_func(
void *ptr)
1297 struct io_internal_writev_struct *iis = ptr;
1300 if (iis->timeout && !iis->nonblock) {
1301 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1307 do_write_retry(writev(iis->fd, iis->iov, iis->iovcnt));
1309 if (result < 0 && !iis->nonblock) {
1310 if (io_again_p(
errno)) {
1311 if (io_internal_wait(iis->th, iis->fptr,
errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1325rb_io_read_memory(
rb_io_t *fptr,
void *buf,
size_t count)
1329 if (scheduler !=
Qnil) {
1332 if (!UNDEF_P(result)) {
1348 struct timeval timeout_storage;
1352 iis.timeout = &timeout_storage;
1355 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_read_func, &iis,
RUBY_IO_READABLE);
1359rb_io_write_memory(
rb_io_t *fptr,
const void *buf,
size_t count)
1363 if (scheduler !=
Qnil) {
1366 if (!UNDEF_P(result)) {
1382 struct timeval timeout_storage;
1386 iis.timeout = &timeout_storage;
1389 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_write_func, &iis,
RUBY_IO_WRITABLE);
1394rb_writev_internal(
rb_io_t *fptr,
const struct iovec *iov,
int iovcnt)
1396 if (!iovcnt)
return 0;
1401 if (scheduler !=
Qnil) {
1405 if (!UNDEF_P(result)) {
1410 struct io_internal_writev_struct iis = {
1421 struct timeval timeout_storage;
1425 iis.timeout = &timeout_storage;
1428 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_writev_func, &iis,
RUBY_IO_WRITABLE);
1433io_flush_buffer_sync(
void *arg)
1455io_flush_buffer_fiber_scheduler(
VALUE scheduler,
rb_io_t *fptr)
1458 if (!UNDEF_P(ret)) {
1470io_flush_buffer_async(
VALUE arg)
1475 if (scheduler !=
Qnil) {
1476 VALUE result = io_flush_buffer_fiber_scheduler(scheduler, fptr);
1477 if (!UNDEF_P(result)) {
1482 return rb_io_blocking_region_wait(fptr, io_flush_buffer_sync, fptr,
RUBY_IO_WRITABLE);
1489 return (
int)io_flush_buffer_async((
VALUE)fptr);
1504 while (fptr->
wbuf.
len > 0 && io_flush_buffer(fptr) != 0) {
1520 if (scheduler !=
Qnil) {
1530 if (NIL_OR_UNDEF_P(timeout)) {
1534 if (timeout !=
Qnil) {
1539 int ready = rb_thread_io_wait(th, fptr,
RB_NUM2INT(events), tv);
1565 if (scheduler !=
Qnil) {
1571 return rb_thread_wait_for_single_fd(th, fd, events, timeout);
1577 io_fd_check_closed(f);
1584#if defined(ERESTART)
1591#if EWOULDBLOCK != EAGAIN
1594 if (scheduler !=
Qnil) {
1612 io_fd_check_closed(f);
1619#if defined(ERESTART)
1635#if EWOULDBLOCK != EAGAIN
1638 if (scheduler !=
Qnil) {
1658 return io_wait_for_single_fd(fd, events, timeout, th, scheduler);
1692#if defined(ERESTART)
1702#if EWOULDBLOCK != EAGAIN
1725 if (
RTEST(result)) {
1740 if (
RTEST(result)) {
1754 const char *senc, *denc;
1761 ecflags = fptr->
encs.
ecflags & ~ECONV_NEWLINE_DECORATOR_READ_MASK;
1788 denc = rb_enc_name(enc);
1820io_binwrite_string_internal(
rb_io_t *fptr,
const char *ptr,
rb_len_t length)
1823 struct iovec iov[2];
1826 iov[0].iov_len = fptr->
wbuf.
len;
1827 iov[1].iov_base = (
void*)ptr;
1828 iov[1].iov_len = length;
1830 ssize_t result = rb_writev_internal(fptr, iov, 2);
1835 if (result >= fptr->
wbuf.
len) {
1843 fptr->
wbuf.
off += (int)result;
1844 fptr->
wbuf.
len -= (int)result;
1852 return rb_io_write_memory(fptr, ptr, length);
1857io_binwrite_string_internal(
rb_io_t *fptr,
const char *ptr,
rb_len_t length)
1862 if (fptr->
wbuf.
len+length <= fptr->wbuf.capa) {
1869 fptr->
wbuf.
len += (int)length;
1876 if (io_fflush(fptr) < 0) {
1881 if (remaining == 0) {
1887 return rb_io_write_memory(fptr, ptr, length);
1892io_binwrite_string(
VALUE arg)
1896 const char *ptr = p->ptr;
1897 size_t remaining = p->length;
1901 ssize_t result = io_binwrite_string_internal(p->fptr, ptr, remaining);
1907 else if (result > 0) {
1908 if ((
size_t)result == remaining)
break;
1910 remaining -= result;
1926io_allocate_write_buffer(
rb_io_t *fptr,
int sync)
1931 fptr->
wbuf.
capa = IO_WBUF_CAPA_MIN;
1959 if (
len <= 0)
return len;
1964 io_allocate_write_buffer(fptr, !nosync);
1966 if (io_binwrite_requires_flush_write(fptr,
len, nosync)) {
1977 return io_binwrite_string((
VALUE)&arg);
1994# define MODE_BTMODE(a,b,c) ((fmode & FMODE_BINMODE) ? (b) : \
1995 (fmode & FMODE_TEXTMODE) ? (c) : (a))
1997#define MODE_BTXMODE(a, b, c, d, e, f) ((fmode & FMODE_EXCL) ? \
1998 MODE_BTMODE(d, e, f) : \
1999 MODE_BTMODE(a, b, c))
2004 if (NEED_WRITECONV(fptr)) {
2006 SET_BINARY_MODE(fptr);
2008 make_writeconv(fptr);
2011#define fmode (fptr->mode)
2014 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1) && !rb_enc_asciicompat(rb_enc_get(str))) {
2015 rb_raise(rb_eArgError,
"ASCII incompatible string written for text mode IO without encoding conversion: %s",
2016 rb_enc_name(rb_enc_get(str)));
2022 common_encoding = rb_enc_from_encoding(fptr->
encs.
enc2);
2023 else if (fptr->
encs.
enc != rb_ascii8bit_encoding())
2024 common_encoding = rb_enc_from_encoding(fptr->
encs.
enc);
2027 if (!
NIL_P(common_encoding)) {
2038#if RUBY_CRLF_ENVIRONMENT
2039#define fmode (fptr->mode)
2040 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1)) {
2043 setmode(fptr->
fd, O_BINARY);
2046 setmode(fptr->
fd, O_TEXT);
2048 if (!rb_enc_asciicompat(rb_enc_get(str))) {
2049 rb_raise(rb_eArgError,
"ASCII incompatible string written for text mode IO without encoding conversion: %s",
2050 rb_enc_name(rb_enc_get(str)));
2068 if (rb_w32_write_console(str, fptr->
fd) > 0)
return RSTRING_LEN(str);
2072 str = do_writeconv(str, fptr, &converted);
2078 n = io_binwrite(ptr,
len, fptr, nosync);
2091 return (ssize_t)io_binwrite(buf, (
rb_len_t)size, fptr, 0);
2101 io = GetWriteIO(io);
2111 if (RSTRING_LEN(str) == 0)
return INT2FIX(0);
2116 n = io_fwrite(str, fptr, nosync);
2117 if (n < 0L) rb_sys_fail_on_write(fptr);
2123struct binwritev_arg {
2131io_binwritev_internal(
VALUE arg)
2133 struct binwritev_arg *p = (
struct binwritev_arg *)arg;
2135 size_t remaining = p->total;
2139 struct iovec *iov = p->iov;
2140 int iovcnt = p->iovcnt;
2143 rb_len_t result = rb_writev_internal(fptr, iov, iovcnt);
2148 if (offset < (
size_t)fptr->
wbuf.
len) {
2153 offset -= (size_t)fptr->
wbuf.
len;
2159 if (offset == p->total) {
2163 while (result >= (ssize_t)iov->iov_len) {
2165 result -= iov->iov_len;
2175 iov->iov_base = (
char *)iov->iov_base + result;
2176 iov->iov_len -= result;
2190io_binwritev(
struct iovec *iov,
int iovcnt,
rb_io_t *fptr)
2195 if (iovcnt == 0)
return 0;
2198 for (
int i = 1; i < iovcnt; i++) total += iov[i].iov_len;
2200 io_allocate_write_buffer(fptr, 1);
2206 if (offset + total <= (
size_t)fptr->
wbuf.
capa) {
2207 for (
int i = 1; i < iovcnt; i++) {
2208 memcpy(fptr->
wbuf.
ptr+offset, iov[i].iov_base, iov[i].iov_len);
2209 offset += iov[i].iov_len;
2220 if (io_fflush(fptr) < 0)
return -1;
2226 iov[0].iov_len = fptr->
wbuf.
len;
2239 struct binwritev_arg arg;
2242 arg.iovcnt = iovcnt;
2249 return io_binwritev_internal((
VALUE)&arg);
2256 int i, converted, iovcnt = argc + 1;
2258 VALUE v1, v2, str, tmp, *tmp_array;
2264 for (i = 0; i < argc; i++) {
2267 str = do_writeconv(str, fptr, &converted);
2272 tmp = rb_str_tmp_frozen_acquire(str);
2276 iov[i+1].iov_base = RSTRING_PTR(tmp);
2277 iov[i+1].iov_len = RSTRING_LEN(tmp);
2280 n = io_binwritev(iov, iovcnt, fptr);
2283 for (i = 0; i < argc; i++) {
2284 rb_str_tmp_frozen_release(argv[i], tmp_array[i]);
2293iovcnt_ok(
int iovcnt)
2296 return iovcnt < IOV_MAX;
2304io_writev(
int argc,
const VALUE *argv,
VALUE io)
2311 io = GetWriteIO(io);
2324 for (i = 0; i < argc; i += cnt) {
2327 n = io_fwritev(cnt, &argv[i], fptr);
2338 rb_sys_fail_on_write(fptr);
2340 total = rb_int_plus(
LEN2NUM(n), total);
2371 return io_writev(argc, argv, io);
2374 VALUE str = argv[0];
2375 return io_write(io, str, 0);
2386rb_io_writev(
VALUE io,
int argc,
const VALUE *argv)
2391 char sep = RCLASS_SINGLETON_P(klass) ? (klass = io,
'.') :
'#';
2394 " which accepts just one argument",
2399 do rb_io_write(io, *argv++);
while (--argc);
2430 rb_io_write(io, str);
2436nogvl_fsync(
void *ptr)
2441 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->
fd)) != FILE_TYPE_DISK)
2444 return (
VALUE)fsync(fptr->
fd);
2449rb_io_flush_raw(
VALUE io,
int sync)
2457 io = GetWriteIO(io);
2461 if (io_fflush(fptr) < 0)
2462 rb_sys_fail_on_write(fptr);
2465 io_unread(fptr,
true);
2486 return rb_io_flush_raw(io, 1);
2512 pos = io_tell(fptr);
2513 if (pos < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
2519rb_io_seek(
VALUE io,
VALUE offset,
int whence)
2526 pos = io_seek(fptr, pos, whence);
2527 if (pos < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
2528 if (fptr->
readconv) clear_readconv(fptr);
2534interpret_seek_whence(
VALUE vwhence)
2536 if (vwhence == sym_SET)
2538 if (vwhence == sym_CUR)
2540 if (vwhence == sym_END)
2543 if (vwhence == sym_DATA)
2547 if (vwhence == sym_HOLE)
2603 VALUE offset, ptrname;
2604 int whence = SEEK_SET;
2606 if (
rb_scan_args(argc, argv,
"11", &offset, &ptrname) == 2) {
2607 whence = interpret_seek_whence(ptrname);
2610 return rb_io_seek(io, offset, whence);
2638 pos = io_seek(fptr, pos, SEEK_SET);
2639 if (pos < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
2640 if (fptr->
readconv) clear_readconv(fptr);
2670rb_io_rewind(
VALUE io)
2675 if (io_seek(fptr, 0L, 0) < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
2676 if (io == ARGF.current_file) {
2677 ARGF.lineno -= fptr->
lineno;
2681 clear_readconv(fptr);
2688fptr_wait_readable(
rb_io_t *fptr)
2706 fptr->
rbuf.
capa = IO_RBUF_CAPA_FOR(fptr);
2714 if (fptr_wait_readable(fptr))
2718 VALUE path = rb_sprintf(
"fd:%d ", fptr->
fd);
2723 rb_syserr_fail_path(e, path);
2777 if (READ_CHAR_PENDING(fptr))
return Qfalse;
2778 if (READ_DATA_PENDING(fptr))
return Qfalse;
2780#if RUBY_CRLF_ENVIRONMENT
2781 if (!NEED_READCONV(fptr) && NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
2782 return RBOOL(eof(fptr->
fd));
2785 return RBOOL(io_fillbuf(fptr) < 0);
2809 io = GetWriteIO(io);
2846 io = GetWriteIO(io);
2852 fptr->
mode &= ~FMODE_SYNC;
2876rb_io_fsync(
VALUE io)
2880 io = GetWriteIO(io);
2883 if (io_fflush(fptr) < 0)
2884 rb_sys_fail_on_write(fptr);
2886 if ((
int)rb_io_blocking_region(fptr, nogvl_fsync, fptr))
2887 rb_sys_fail_path(fptr->
pathv);
2892# define rb_io_fsync rb_f_notimplement
2893# define rb_io_sync rb_f_notimplement
2902#ifdef HAVE_FDATASYNC
2904nogvl_fdatasync(
void *ptr)
2908 return (
VALUE)fdatasync(fptr->
fd);
2923rb_io_fdatasync(
VALUE io)
2927 io = GetWriteIO(io);
2930 if (io_fflush(fptr) < 0)
2931 rb_sys_fail_on_write(fptr);
2933 if ((
int)rb_io_blocking_region(fptr, nogvl_fdatasync, fptr) == 0)
2937 return rb_io_fsync(io);
2940#define rb_io_fdatasync rb_io_fsync
2958rb_io_fileno(
VALUE io)
2978 if (!UNDEF_P(fileno)) {
3071rb_io_inspect(
VALUE obj)
3075 static const char closed[] =
" (closed)";
3077 fptr =
RFILE(obj)->fptr;
3084 rb_str_cat(result, closed+1, strlen(closed)-1);
3087 rb_str_catf(result,
"fd %d", fptr->
fd);
3108rb_io_to_io(
VALUE io)
3119 n = READ_DATA_PENDING_COUNT(fptr);
3120 if (n <= 0)
return 0;
3121 if (n >
len) n = (int)
len;
3136 if (READ_DATA_PENDING(fptr) == 0) {
3140 c = rb_io_read_memory(fptr, ptr+offset, n);
3143 if (fptr_wait_readable(fptr))
3149 if ((n -= c) <= 0)
break;
3155 c = read_buffered_data(ptr+offset, n, fptr);
3159 if ((n -= c) <= 0)
break;
3162 if (io_fillbuf(fptr) < 0) {
3180bufread_body(
VALUE arg)
3183 p->len = io_bufread(p->str_ptr + p->offset, p->len, p->fptr, &p->read_len);
3192 if (p->offset + p->read_len > 0) {
3194 io_restore_read_buffer(str, p->fptr);
3201bufread_call(
VALUE arg)
3206 return bufread_body(arg);
3208 return rb_rescue2(bufread_body, arg, bufread_timeout, arg,
3209 rb_eIOTimeoutError, (
VALUE)0);
3218 io_setstrbuf(&str, offset + size);
3219 arg.str_ptr = RSTRING_PTR(str);
3220 arg.offset = offset;
3224 rb_str_locktmp_ensure(str, bufread_call, (
VALUE)&arg);
3226 if (
len < 0) rb_sys_fail_path(fptr->
pathv);
3234 rb_off_t siz = READ_DATA_PENDING_COUNT(fptr);
3237 if (fstat(fptr->
fd, &st) == 0 && S_ISREG(st.st_mode)
3238#
if defined(__HAIKU__)
3243 if (io_fflush(fptr) < 0)
3244 rb_sys_fail_on_write(fptr);
3245 pos = lseek(fptr->
fd, 0, SEEK_CUR);
3246 if (st.st_size >= pos && pos >= 0) {
3247 siz += st.st_size - pos;
3249 rb_raise(
rb_eIOError,
"file too big for single read");
3262 rb_enc_associate(str, io_read_encoding(fptr));
3267make_readconv(
rb_io_t *fptr,
int size)
3272 const char *sname, *dname;
3273 ecflags = fptr->
encs.
ecflags & ~ECONV_NEWLINE_DECORATOR_WRITE_MASK;
3276 sname = rb_enc_name(fptr->
encs.
enc2);
3277 dname = rb_enc_name(io_read_encoding(fptr));
3287 if (size < IO_CBUF_CAPA_MIN) size = IO_CBUF_CAPA_MIN;
3293#define MORE_CHAR_SUSPENDED Qtrue
3294#define MORE_CHAR_FINISHED Qnil
3296fill_cbuf(
rb_io_t *fptr,
int ec_flags)
3298 const unsigned char *ss, *sp, *se;
3299 unsigned char *ds, *dp, *de;
3308 return MORE_CHAR_SUSPENDED;
3319 ss = sp = (
const unsigned char *)fptr->
rbuf.
ptr + fptr->
rbuf.
off;
3324 fptr->
rbuf.
off += (int)(sp - ss);
3325 fptr->
rbuf.
len -= (int)(sp - ss);
3326 fptr->
cbuf.
len += (int)(dp - ds);
3331 fptr->
rbuf.
off -= putbackable;
3332 fptr->
rbuf.
len += putbackable;
3339 if (cbuf_len0 != fptr->
cbuf.
len)
3340 return MORE_CHAR_SUSPENDED;
3343 return MORE_CHAR_FINISHED;
3349 if (io_fillbuf(fptr) < 0) {
3351 return MORE_CHAR_FINISHED;
3356 fptr->
cbuf.
len += (int)(dp - ds);
3363 if (cbuf_len0 != fptr->
cbuf.
len)
3364 return MORE_CHAR_SUSPENDED;
3366 return MORE_CHAR_FINISHED;
3374 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED)
3391 rb_enc_associate(str, fptr->
encs.
enc);
3428#define MAX_REALLOC_GAP 4096
3433 rb_str_resize(str, n);
3440 if (RSTRING_LEN(str) != n) {
3443 if (shrinkable) io_shrink_read_string(str, n);
3457 if (NEED_READCONV(fptr)) {
3458 int first = !
NIL_P(str);
3459 SET_BINARY_MODE(fptr);
3460 shrinkable = io_setstrbuf(&str,0);
3461 make_readconv(fptr, 0);
3466 io_shift_cbuf(fptr, fptr->
cbuf.
len, &str);
3468 v = fill_cbuf(fptr, 0);
3469 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED) {
3472 io_shift_cbuf(fptr, fptr->
cbuf.
len, &str);
3476 if (v == MORE_CHAR_FINISHED) {
3477 clear_readconv(fptr);
3479 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3480 return io_enc_str(str, fptr);
3485 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3489 enc = io_read_encoding(fptr);
3502 shrinkable = io_setstrbuf(&str, siz);
3505 n = io_fread(str, bytes, siz - bytes, fptr);
3506 if (n == 0 && bytes == 0) {
3514 if (bytes < siz)
break;
3518 if (
capa < (
size_t)RSTRING_LEN(str) + BUFSIZ) {
3519 if (
capa < BUFSIZ) {
3522 else if (
capa > IO_MAX_BUFFER_GROWTH) {
3523 capa = IO_MAX_BUFFER_GROWTH;
3528 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3529 str = io_enc_str(str, fptr);
3537 if (rb_fd_set_nonblock(fptr->
fd) != 0) {
3538 rb_sys_fail_path(fptr->
pathv);
3543io_read_memory_call(
VALUE arg)
3548 if (scheduler !=
Qnil) {
3551 if (!UNDEF_P(result)) {
3557 if (iis->nonblock) {
3558 return rb_io_blocking_region(iis->fptr, internal_read_func, iis);
3561 return rb_io_blocking_region_wait(iis->fptr, internal_read_func, iis,
RUBY_IO_READABLE);
3568 return (
rb_len_t)rb_str_locktmp_ensure(str, io_read_memory_call, (
VALUE)iis);
3571#define no_exception_p(opts) !rb_opts_exception_p((opts), TRUE)
3574io_getpartial(
VALUE io,
VALUE length,
VALUE str,
int no_exception,
int nonblock)
3582 rb_raise(rb_eArgError,
"negative length %"PRIdLEN
" given",
len);
3585 shrinkable = io_setstrbuf(&str,
len);
3591 io_set_read_length(str, 0, shrinkable);
3597 n = read_buffered_data(RSTRING_PTR(str),
len, fptr);
3602 rb_fd_set_nonblock(fptr->
fd);
3604 io_setstrbuf(&str,
len);
3607 iis.nonblock = nonblock;
3609 iis.buf = RSTRING_PTR(str);
3612 n = io_read_memory_locktmp(str, &iis);
3615 if (!nonblock && fptr_wait_readable(fptr))
3617 if (nonblock && (io_again_p(e))) {
3619 return sym_wait_readable;
3622 e,
"read would block");
3624 rb_syserr_fail_path(e, fptr->
pathv);
3627 io_set_read_length(str, n, shrinkable);
3728io_readpartial(
int argc,
VALUE *argv,
VALUE io)
3730 VALUE ret, length, str;
3733 ret = io_getpartial(io, length, str, 0, 0);
3740io_nonblock_eof(
int no_exception)
3742 if (!no_exception) {
3752 int no_exception = !rb_bool_expected(ex,
"exception", TRUE);
3753 VALUE ret = io_getpartial(io, length, str, no_exception, 1);
3755 io_nonblock_eof(no_exception);
3769 rb_bool_expected(ex,
"exception", TRUE);
3771 io = GetWriteIO(io);
3775 if (io_fflush(fptr) < 0)
3776 rb_sys_fail_on_write(fptr);
3778 rb_fd_set_nonblock(fptr->
fd);
3779 n = write(fptr->
fd, RSTRING_PTR(str), RSTRING_LEN(str));
3784 if (io_again_p(e)) {
3786 return sym_wait_writable;
3792 rb_syserr_fail_path(e, fptr->
pathv);
3876#if RUBY_CRLF_ENVIRONMENT
3882 if (
NIL_P(length)) {
3885 return read_all(fptr, remain_size(fptr), str);
3889 rb_raise(rb_eArgError,
"negative length %"PRIdLEN
" given",
len);
3892 shrinkable = io_setstrbuf(&str,
len);
3897 io_set_read_length(str, 0, shrinkable);
3902#if RUBY_CRLF_ENVIRONMENT
3903 previous_mode = set_binary_mode_with_seek_cur(fptr);
3905 n = io_fread(str, 0,
len, fptr);
3906 io_set_read_length(str, n, shrinkable);
3907#if RUBY_CRLF_ENVIRONMENT
3908 if (previous_mode == O_TEXT) {
3909 setmode(fptr->
fd, O_TEXT);
3912 if (n == 0)
return Qnil;
3921 if (RSTRING_PTR(rs) != rsptr && RSTRING_LEN(rs) != rslen)
3928 if (rb_enc_mbminlen(enc) == 1) {
3929 p = memchr(p, delim,
len);
3930 if (p)
return p + 1;
3933 const char *end = p +
len;
3935 int r = rb_enc_precise_mbclen(p, end, enc);
3937 p += rb_enc_mbminlen(enc);
3941 if (rb_enc_mbc_to_codepoint(p, end, enc) == (
unsigned int)delim) {
3957 if (!READ_DATA_PENDING(fptr)) {
3959 if (io_fillbuf(fptr) < 0)
break;
3961 buf[n++] = *READ_DATA_PENDING_PTR(fptr);
3964 r = rb_enc_precise_mbclen(buf, buf + n, enc);
3971unread_raw_character(
rb_io_t *fptr,
const char *buf,
int len)
3983search_wide_delim(
const char *p,
long len,
const char *delim,
int width)
3985 const char *e = p +
len;
3988 while (index < width && delim[index] == 0) index++;
3989 if (index == width) index = 0;
3991 const char *candidate = p + index;
3992 while (candidate < e) {
3993 candidate = memchr(candidate, (
unsigned char)delim[index], e - candidate);
3994 if (candidate == NULL)
break;
3995 const char *start = candidate - index;
3996 if ((start - p) % width == 0 && start + width <= e &&
3997 memcmp(start, delim, width) == 0) {
4011 if (NEED_READCONV(fptr)) {
4012 SET_BINARY_MODE(fptr);
4013 make_readconv(fptr, 0);
4016 int searchlen = READ_CHAR_PENDING_COUNT(fptr);
4018 p = READ_CHAR_PENDING_PTR(fptr);
4019 if (0 < limit && limit < searchlen)
4020 searchlen = (int)limit;
4021 e = search_delim(p, searchlen, delim, enc);
4023 int len = (int)(e-p);
4045 return (
unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
4048 }
while (more_char(fptr) != MORE_CHAR_FINISHED);
4049 clear_readconv(fptr);
4054 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4055 if (rb_enc_mbminlen(enc) != 1) {
4056 char buf[ONIGENC_CODE_TO_MBC_MAXLEN];
4060 int width = rb_enc_mbminlen(enc);
4061 int delim_len = rb_enc_codelen(delim, enc);
4063 if (delim_len == width) {
4064 rb_enc_mbcput(delim, buf, enc);
4066 if (!READ_DATA_PENDING(fptr)) {
4068 if (io_fillbuf(fptr) < 0)
return EOF;
4070 long pending = READ_DATA_PENDING_COUNT(fptr);
4071 long complete = pending - pending % width;
4072 const char *p = READ_DATA_PENDING_PTR(fptr);
4073 const char *q = complete ? search_wide_delim(p, complete, buf, width) : NULL;
4074 long take = q ? q - p + width : complete;
4083 if (q)
return delim;
4084 if (complete == pending)
continue;
4086 len = read_raw_character(fptr, enc, buf);
4087 if (
len == 0)
return EOF;
4091 int r = rb_enc_precise_mbclen(buf, buf +
len, enc);
4093 rb_enc_mbc_to_codepoint(buf, buf +
len, enc) == (
unsigned int)delim)
4099 while ((
len = read_raw_character(fptr, enc, buf)) > 0) {
4106 return (
unsigned char)buf[
len - 1];
4110 int r = rb_enc_precise_mbclen(buf, buf +
len, enc);
4112 rb_enc_mbc_to_codepoint(buf, buf +
len, enc) == (
unsigned int)delim)
4115 return (
unsigned char)buf[
len - 1];
4121 rb_len_t pending = READ_DATA_PENDING_COUNT(fptr);
4123 const char *p = READ_DATA_PENDING_PTR(fptr);
4127 if (limit > 0 && pending > limit) pending = limit;
4128 e = search_delim(p, pending, delim, enc);
4129 if (e) pending = e - p;
4131 last = RSTRING_LEN(str);
4132 rb_str_resize(str, last + pending);
4139 read_buffered_data(RSTRING_PTR(str) + last, pending, fptr);
4142 if (e)
return delim;
4144 return (
unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
4147 }
while (io_fillbuf(fptr) >= 0);
4153swallow(
rb_io_t *fptr,
int term)
4155 if (NEED_READCONV(fptr)) {
4157 int needconv = rb_enc_mbminlen(enc) != 1;
4158 SET_BINARY_MODE(fptr);
4159 make_readconv(fptr, 0);
4162 while ((cnt = READ_CHAR_PENDING_COUNT(fptr)) > 0) {
4163 const char *p = READ_CHAR_PENDING_PTR(fptr);
4166 if (*p != term)
return TRUE;
4168 while (--i && *++p == term);
4171 const char *e = p + cnt;
4172 if (rb_enc_ascget(p, e, &i, enc) != term)
return TRUE;
4173 while ((p += i) < e && rb_enc_ascget(p, e, &i, enc) == term);
4176 io_shift_cbuf(fptr, (
int)cnt - i, NULL);
4178 }
while (more_char(fptr) != MORE_CHAR_FINISHED);
4182 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4184 int widechar = rb_enc_mbminlen(enc) != 1;
4186 char buf[ONIGENC_CODE_TO_MBC_MAXLEN];
4189 while ((
len = read_raw_character(fptr, enc, buf)) > 0) {
4190 if (rb_enc_ascget(buf, buf +
len, NULL, enc) != term) {
4191 unread_raw_character(fptr, buf,
len);
4199 while ((cnt = READ_DATA_PENDING_COUNT(fptr)) > 0) {
4201 const char *p = READ_DATA_PENDING_PTR(fptr);
4203 if (cnt >
sizeof buf) cnt =
sizeof buf;
4204 if (*p != term)
return TRUE;
4206 while (--i && *++p == term);
4207 if (!read_buffered_data(buf, cnt - i, fptr))
4208 rb_sys_fail_path(fptr->
pathv);
4211 }
while (io_fillbuf(fptr) == 0);
4224 int pending = READ_DATA_PENDING_COUNT(fptr);
4227 const char *p = READ_DATA_PENDING_PTR(fptr);
4231 e = memchr(p,
'\n', pending);
4233 pending = (int)(e - p + 1);
4235 chomplen = (pending > 1 && *(e-1) ==
'\r') + 1;
4244 rb_str_resize(str,
len + pending - chomplen);
4245 read_buffered_data(RSTRING_PTR(str)+
len, pending - chomplen, fptr);
4248 if (pending == 1 && chomplen == 1 &&
len > 0) {
4249 if (RSTRING_PTR(str)[
len-1] ==
'\r') {
4250 rb_str_resize(str, --
len);
4255 len += pending - chomplen;
4261 }
while (io_fillbuf(fptr) >= 0);
4264 str = io_enc_str(str, fptr);
4275 unsigned int chomp: 1;
4289 chomp = (!UNDEF_P(vchomp)) &&
RTEST(vchomp);
4291 args->chomp = chomp;
4309 else if (2 <= argc) {
4310 rs = argv[0], lim = argv[1];
4328 enc_rs = rb_enc_get(rs);
4329 enc_io = io_read_encoding(fptr);
4330 if (enc_io != enc_rs &&
4331 (!is_ascii_string(rs) ||
4332 (RSTRING_LEN(rs) > 0 && !rb_enc_asciicompat(enc_io)))) {
4333 if (rs == rb_default_rs) {
4334 rs = rb_enc_str_new(0, 0, enc_io);
4339 rb_raise(rb_eArgError,
"encoding mismatch: %s IO with %s RS",
4340 rb_enc_name(enc_io),
4341 rb_enc_name(enc_rs));
4351 argc =
rb_scan_args(argc, argv,
"02:", NULL, NULL, &opts);
4352 extract_getline_args(argc, argv, args);
4353 extract_getline_opts(opts, args);
4354 check_getline_args(&args->rs, &args->limit, io);
4365 if (
NIL_P(rs) && limit < 0) {
4366 str = read_all(fptr, 0,
Qnil);
4367 if (RSTRING_LEN(str) == 0)
return Qnil;
4369 else if (limit == 0) {
4370 return rb_enc_str_new(0, 0, io_read_encoding(fptr));
4372 else if (rs == rb_default_rs && limit < 0 && !NEED_READCONV(fptr) &&
4373 rb_enc_asciicompat(enc = io_read_encoding(fptr))) {
4374 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4375 return rb_io_getline_fast(fptr, enc, chomp);
4378 int c, newline = -1;
4379 const char *rsptr = 0;
4382 int extra_limit = 16;
4383 int chomp_cr = chomp;
4385 SET_BINARY_MODE(fptr);
4386 enc = io_read_encoding(fptr);
4389 rslen = RSTRING_LEN(rs);
4394 swallow(fptr,
'\n');
4396 if (!rb_enc_asciicompat(enc)) {
4400 rsptr = RSTRING_PTR(rs);
4401 rslen = RSTRING_LEN(rs);
4405 else if (rb_enc_mbminlen(enc) == 1) {
4406 rsptr = RSTRING_PTR(rs);
4407 newline = (
unsigned char)rsptr[rslen - 1];
4411 rsptr = RSTRING_PTR(rs);
4412 const char *e = rsptr + rslen;
4413 const char *last = rb_enc_prev_char(rsptr, e, e, enc);
4415 newline = rb_enc_codepoint_len(last, e, &n, enc);
4416 if (last + n != e) rb_raise(rb_eArgError,
"broken separator");
4418 chomp_cr = chomp && newline ==
'\n' && rslen == rb_enc_mbminlen(enc);
4422 while ((c = appendline(fptr, newline, &str, &limit, enc)) != EOF) {
4423 const char *s, *p, *pp, *e;
4425 if (c == newline && RSTRING_LEN(str) >= rslen) {
4426 s = RSTRING_PTR(str);
4429 if (at_char_boundary(s, p, e, enc)) {
4430 if (!rspara) rscheck(rsptr, rslen, rs);
4431 if (memcmp(p, rsptr, rslen) == 0) {
4433 if (chomp_cr && p > s && *(p-1) ==
'\r') --p;
4441 s = RSTRING_PTR(str);
4443 pp = rb_enc_prev_char(s, p, p, enc);
4444 if (extra_limit && pp &&
4458 if (rspara && c != EOF)
4459 swallow(fptr,
'\n');
4461 str = io_enc_str(str, fptr);
4464 if (!
NIL_P(str) && !nolimit) {
4475 int old_lineno, new_lineno;
4479 old_lineno = fptr->
lineno;
4480 str = rb_io_getline_0(rs, limit, chomp, fptr);
4481 if (!
NIL_P(str) && (new_lineno = fptr->
lineno) != old_lineno) {
4482 if (io == ARGF.current_file) {
4483 ARGF.lineno += new_lineno - old_lineno;
4484 ARGF.last_lineno = ARGF.lineno;
4487 ARGF.last_lineno = new_lineno;
4495rb_io_getline(
int argc,
VALUE *argv,
VALUE io)
4499 prepare_getline_args(argc, argv, &args, io);
4500 return rb_io_getline_1(args.rs, args.limit, args.chomp, io);
4514 return rb_io_getline_0(rb_default_rs, limit, FALSE, fptr);
4518rb_io_gets_internal(
VALUE io)
4520 return rb_io_gets_limit_internal(io, -1);
4600 str = rb_io_getline(argc, argv, io);
4616rb_io_lineno(
VALUE io)
4671 check_getline_args(&sep, &limit, io);
4673 VALUE line = rb_io_getline_1(sep, limit,
RTEST(chomp), io);
4674 rb_lastline_set_up(line, 1);
4749rb_io_readlines(
int argc,
VALUE *argv,
VALUE io)
4753 prepare_getline_args(argc, argv, &args, io);
4754 return io_readlines(&args, io);
4762 if (arg->limit == 0)
4763 rb_raise(rb_eArgError,
"invalid limit: 0 for readlines");
4765 while (!
NIL_P(line = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, io))) {
4878rb_io_each_line(
int argc,
VALUE *argv,
VALUE io)
4884 prepare_getline_args(argc, argv, &args, io);
4885 if (args.limit == 0)
4886 rb_raise(rb_eArgError,
"invalid limit: 0 for each_line");
4887 while (!
NIL_P(str = rb_io_getline_1(args.rs, args.limit, args.chomp, io))) {
4915rb_io_each_byte(
VALUE io)
4931 }
while (io_fillbuf(fptr) >= 0);
4941 if (NEED_READCONV(fptr)) {
4945 SET_BINARY_MODE(fptr);
4946 make_readconv(fptr, 0);
4960 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4962 clear_readconv(fptr);
4966 str = rb_enc_str_new(fptr->
cbuf.
ptr+fptr->
cbuf.
off, 1, read_enc);
4969 if (fptr->
cbuf.
len == 0) clear_readconv(fptr);
4978 io_shift_cbuf(fptr, r, &str);
4985 ISASCII(RSTRING_PTR(str)[0])) {
4989 str = io_enc_str(str, fptr);
4994 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4995 if (io_fillbuf(fptr) < 0) {
5017 if (io_fillbuf(fptr) != -1) {
5021 r = rb_enc_precise_mbclen(RSTRING_PTR(str), RSTRING_PTR(str)+RSTRING_LEN(str), enc);
5037 str = io_enc_str(str, fptr);
5064rb_io_each_char(
VALUE io)
5074 enc = io_input_encoding(fptr);
5076 while (!
NIL_P(c = io_getc(fptr, enc))) {
5103rb_io_each_codepoint(
VALUE io)
5115 enc = io_read_encoding(fptr);
5116 if (NEED_READCONV(fptr)) {
5117 SET_BINARY_MODE(fptr);
5120 make_readconv(fptr, 0);
5132 if (more_char(fptr) == MORE_CHAR_FINISHED) {
5133 clear_readconv(fptr);
5153 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
5154 while (io_fillbuf(fptr) >= 0) {
5169 char cbuf[8], *p = cbuf;
5171 if (more > numberof(cbuf))
goto invalid;
5173 if (more > numberof(cbuf))
goto invalid;
5174 while ((n = (
int)read_buffered_data(p, more, fptr)) > 0 &&
5175 (p += n, (more -= n) > 0)) {
5176 if (io_fillbuf(fptr) < 0)
goto invalid;
5177 if ((n = fptr->
rbuf.
len) > more) n = more;
5179 r = rb_enc_precise_mbclen(cbuf, p, enc);
5192 rb_raise(rb_eArgError,
"invalid byte sequence in %s", rb_enc_name(enc));
5225 enc = io_input_encoding(fptr);
5227 return io_getc(fptr, enc);
5251rb_io_readchar(
VALUE io)
5253 VALUE c = rb_io_getc(io);
5289 VALUE r_stdout = rb_ractor_stdout();
5294 rb_io_flush(r_stdout);
5297 if (io_fillbuf(fptr) < 0) {
5327rb_io_readbyte(
VALUE io)
5388 unsigned char c =
NUM2INT(v) & 0xFF;
5394 io_ungetbyte(b, fptr);
5450 else if (RB_BIGNUM_TYPE_P(c)) {
5456 if (NEED_READCONV(fptr)) {
5457 SET_BINARY_MODE(fptr);
5458 len = RSTRING_LEN(c);
5459#if SIZEOF_RB_LEN_T > SIZEOF_INT
5463 make_readconv(fptr, (
int)
len);
5477 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
5478 io_ungetbyte(c, fptr);
5498rb_io_isatty(
VALUE io)
5503 return RBOOL(isatty(fptr->
fd) != 0);
5506#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5522rb_io_close_on_exec_p(
VALUE io)
5528 write_io = GetWriteIO(io);
5529 if (io != write_io) {
5531 if (fptr && 0 <= (fd = fptr->
fd)) {
5532 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->
pathv);
5533 if (!(ret & FD_CLOEXEC))
return Qfalse;
5538 if (fptr && 0 <= (fd = fptr->
fd)) {
5539 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->
pathv);
5540 if (!(ret & FD_CLOEXEC))
return Qfalse;
5545#define rb_io_close_on_exec_p rb_f_notimplement
5548#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5572 int flag =
RTEST(arg) ? FD_CLOEXEC : 0;
5577 write_io = GetWriteIO(io);
5578 if (io != write_io) {
5580 if (fptr && 0 <= (fd = fptr->
fd)) {
5581 if ((ret = fcntl(fptr->
fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->
pathv);
5582 if ((ret & FD_CLOEXEC) != flag) {
5583 ret = (ret & ~FD_CLOEXEC) | flag;
5584 ret = fcntl(fd, F_SETFD, ret);
5585 if (ret != 0) rb_sys_fail_path(fptr->
pathv);
5592 if (fptr && 0 <= (fd = fptr->
fd)) {
5593 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->
pathv);
5594 if ((ret & FD_CLOEXEC) != flag) {
5595 ret = (ret & ~FD_CLOEXEC) | flag;
5596 ret = fcntl(fd, F_SETFD, ret);
5597 if (ret != 0) rb_sys_fail_path(fptr->
pathv);
5603#define rb_io_set_close_on_exec rb_f_notimplement
5606#define RUBY_IO_EXTERNAL_P(f) ((f)->mode & FMODE_EXTERNAL)
5607#define PREP_STDIO_NAME(f) (RSTRING_PTR((f)->pathv))
5610finish_writeconv(
rb_io_t *fptr,
int noalloc)
5612 unsigned char *ds, *dp, *de;
5616 unsigned char buf[1024];
5621 de = buf +
sizeof(buf);
5624 size_t remaining = dp-ds;
5625 rb_len_t result = rb_io_write_memory(fptr, ds, remaining);
5629 if ((
size_t)result == remaining)
break;
5652 if (io_fflush(fptr) < 0) {
5660 fptr->
wbuf.
len += (int)(dp - ds);
5676finish_writeconv_sync(
VALUE arg)
5679 return finish_writeconv(p->fptr, p->noalloc);
5683nogvl_close(
void *ptr)
5687 return (
void*)(intptr_t)close(*fd);
5691maygvl_close(
int fd,
int keepgvl)
5700 return IO_WITHOUT_GVL_INT(nogvl_close, &fd);
5704nogvl_fclose(
void *ptr)
5708 return (
void*)(intptr_t)fclose(file);
5712maygvl_fclose(
FILE *file,
int keepgvl)
5715 return fclose(file);
5717 return IO_WITHOUT_GVL_INT(nogvl_fclose, file);
5723fptr_finalize_flush(
rb_io_t *fptr,
int noraise,
int keepgvl)
5728 int mode = fptr->
mode;
5734 arg.noalloc = noraise;
5738 error = finish_writeconv(fptr, noraise);
5751 io_flush_buffer_sync(fptr);
5754 if (io_fflush(fptr) < 0 &&
NIL_P(error)) {
5762 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2) {
5772 rb_thread_io_close_wait(fptr);
5774 if (!done && stdio_file) {
5776 if ((maygvl_fclose(stdio_file, noraise) < 0) &&
NIL_P(error)) {
5786 if (!done && fd >= 0 && scheduler !=
Qnil) {
5789 if (!UNDEF_P(result)) {
5790 done =
RTEST(result);
5794 if (!done && fd >= 0) {
5800 if ((maygvl_close(fd, keepgvl) < 0) &&
NIL_P(error)) {
5809 if (!
NIL_P(error) && !noraise) {
5818fptr_finalize(
rb_io_t *fptr,
int noraise)
5820 fptr_finalize_flush(fptr, noraise, FALSE);
5821 free_io_buffer(&fptr->
rbuf);
5822 free_io_buffer(&fptr->
wbuf);
5823 clear_codeconv(fptr);
5827rb_io_fptr_cleanup(
rb_io_t *fptr,
int noraise)
5833 fptr_finalize(fptr, noraise);
5841 ruby_xfree_sized(buf->
ptr, (
size_t)buf->
capa);
5854 free_io_buffer(&fptr->
cbuf);
5870 clear_readconv(fptr);
5871 clear_writeconv(fptr);
5875rb_io_fptr_cleanup_all(
rb_io_t *fptr)
5879 rb_io_fptr_cleanup(fptr, TRUE);
5881 free_io_buffer(&fptr->
rbuf);
5882 free_io_buffer(&fptr->
wbuf);
5883 clear_codeconv(fptr);
5890 rb_io_fptr_cleanup_all(io);
5897rb_io_fptr_finalize_closed(
struct rb_io *io)
5899 if (!io)
return true;
5900 if (io->
fd >= 0)
return false;
5906rb_io_memsize(
const rb_io_t *io)
5908 size_t size =
sizeof(
rb_io_t);
5918 rb_serial_t fork_generation = GET_VM()->fork_gen;
5919 if (io->fork_generation == fork_generation) {
5930# define KEEPGVL TRUE
5932# define KEEPGVL FALSE
5936io_close_fptr(
VALUE io)
5942 write_io = GetWriteIO(io);
5943 if (io != write_io) {
5944 write_fptr =
RFILE(write_io)->fptr;
5945 if (write_fptr && 0 <= write_fptr->
fd) {
5946 rb_io_fptr_cleanup(write_fptr, TRUE);
5950 fptr =
RFILE(io)->fptr;
5951 if (!fptr)
return 0;
5952 if (fptr->
fd < 0)
return 0;
5955 if (rb_thread_io_close_interrupt(fptr)) {
5957 fptr_finalize_flush(fptr, FALSE, KEEPGVL);
5960 rb_io_fptr_cleanup(fptr, FALSE);
5965fptr_waitpid(
rb_io_t *fptr,
int nohang)
5969 rb_last_status_clear();
5978 rb_io_t *fptr = io_close_fptr(io);
5979 if (fptr) fptr_waitpid(fptr, 0);
6019rb_io_close_m(
VALUE io)
6021 rb_io_t *fptr = rb_io_get_fptr(io);
6030io_call_close(
VALUE io)
6039 enum {mesg_len =
sizeof(closed_stream)-1};
6040 VALUE mesg = rb_attr_get(exc, idMesg);
6042 RSTRING_LEN(mesg) != mesg_len ||
6043 memcmp(RSTRING_PTR(mesg), closed_stream, mesg_len)) {
6053 if (!UNDEF_P(closed) &&
RTEST(closed))
return io;
6054 rb_rescue2(io_call_close, io, ignore_closed_stream, io,
6090 write_io = GetWriteIO(io);
6091 if (io != write_io) {
6092 write_fptr =
RFILE(write_io)->fptr;
6093 if (write_fptr && 0 <= write_fptr->
fd) {
6098 fptr = rb_io_get_fptr(io);
6099 return RBOOL(0 > fptr->
fd);
6135rb_io_close_read(
VALUE io)
6141 if (fptr->
fd < 0)
return Qnil;
6142 if (is_socket(fptr->
fd, fptr->
pathv)) {
6146 if (shutdown(fptr->
fd, SHUT_RD) < 0)
6147 rb_sys_fail_path(fptr->
pathv);
6148 fptr->
mode &= ~FMODE_READABLE;
6154 write_io = GetWriteIO(io);
6155 if (io != write_io) {
6160 RFILE(io)->fptr = wfptr;
6163 RFILE(write_io)->fptr = fptr;
6164 rb_io_fptr_cleanup(fptr, FALSE);
6170 rb_raise(
rb_eIOError,
"closing non-duplex IO for reading");
6208rb_io_close_write(
VALUE io)
6213 write_io = GetWriteIO(io);
6215 if (fptr->
fd < 0)
return Qnil;
6216 if (is_socket(fptr->
fd, fptr->
pathv)) {
6227 if (io_fflush(fptr) < 0)
6228 rb_sys_fail_on_write(fptr);
6230 if (shutdown(fptr->
fd, SHUT_WR) < 0)
6231 rb_sys_fail_path(fptr->
pathv);
6232 fptr->
mode &= ~FMODE_WRITABLE;
6239 rb_raise(
rb_eIOError,
"closing non-duplex IO for writing");
6242 if (io != write_io) {
6262rb_io_sysseek(
int argc,
VALUE *argv,
VALUE io)
6264 VALUE offset, ptrname;
6265 int whence = SEEK_SET;
6269 if (
rb_scan_args(argc, argv,
"11", &offset, &ptrname) == 2) {
6270 whence = interpret_seek_whence(ptrname);
6275 (READ_DATA_BUFFERED(fptr) || READ_CHAR_PENDING(fptr))) {
6279 rb_warn(
"sysseek for buffered IO");
6282 pos = lseek(fptr->
fd, pos, whence);
6283 if (pos < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
6317 io = GetWriteIO(io);
6322 rb_warn(
"syswrite for buffered IO");
6325 tmp = rb_str_tmp_frozen_acquire(str);
6327 n = rb_io_write_memory(fptr, ptr,
len);
6328 if (n < 0) rb_sys_fail_path(fptr->
pathv);
6329 rb_str_tmp_frozen_release(str, tmp);
6346rb_io_sysread(
int argc,
VALUE *argv,
VALUE io)
6357 shrinkable = io_setstrbuf(&str, ilen);
6358 if (ilen == 0)
return str;
6363 if (READ_DATA_BUFFERED(fptr)) {
6369 io_setstrbuf(&str, ilen);
6374 iis.buf = RSTRING_PTR(str);
6377 n = io_read_memory_locktmp(str, &iis);
6380 rb_sys_fail_path(fptr->
pathv);
6383 io_set_read_length(str, n, shrinkable);
6385 if (n == 0 && ilen > 0) {
6401internal_pread_func(
void *_arg)
6405 return (
VALUE)pread(arg->fd, arg->buf, arg->count, arg->offset);
6409pread_internal_call(
VALUE _arg)
6414 if (scheduler !=
Qnil) {
6417 if (!UNDEF_P(result)) {
6422 return rb_io_blocking_region_wait(arg->io, internal_pread_func, arg,
RUBY_IO_READABLE);
6466 shrinkable = io_setstrbuf(&str, (
rb_len_t)arg.count);
6467 if (arg.count == 0)
return str;
6468 arg.buf = RSTRING_PTR(str);
6481 rb_sys_fail_path(fptr->
pathv);
6483 io_set_read_length(str, n, shrinkable);
6484 if (n == 0 && arg.count > 0) {
6492internal_pwrite_func(
void *_arg)
6496 return (
VALUE)pwrite(arg->fd, arg->buf, arg->count, arg->offset);
6500pwrite_internal_call(
VALUE _arg)
6505 if (scheduler !=
Qnil) {
6508 if (!UNDEF_P(result)) {
6513 return rb_io_blocking_region_wait(arg->io, internal_pwrite_func, arg,
RUBY_IO_WRITABLE);
6554 io = GetWriteIO(io);
6561 tmp = rb_str_tmp_frozen_acquire(str);
6562 arg.buf = RSTRING_PTR(tmp);
6563 arg.count = (size_t)RSTRING_LEN(tmp);
6565 n = (ssize_t)pwrite_internal_call((
VALUE)&arg);
6566 if (n < 0) rb_sys_fail_path(fptr->
pathv);
6567 rb_str_tmp_frozen_release(str, tmp);
6583 fptr->
mode &= ~FMODE_TEXTMODE;
6587 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6590 setmode(fptr->
fd, O_BINARY);
6597io_ascii8bit_binmode(
rb_io_t *fptr)
6608 fptr->
mode &= ~FMODE_TEXTMODE;
6609 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6611 fptr->
encs.
enc = rb_ascii8bit_encoding();
6615 clear_codeconv(fptr);
6624 io_ascii8bit_binmode(fptr);
6641rb_io_binmode_m(
VALUE io)
6647 write_io = GetWriteIO(io);
6662rb_io_binmode_p(
VALUE io)
6670rb_io_fmode_modestr(
enum rb_io_mode fmode)
6674 return MODE_BTMODE(
"a+",
"ab+",
"at+");
6676 return MODE_BTMODE(
"a",
"ab",
"at");
6680 rb_raise(rb_eArgError,
"invalid access fmode 0x%x", fmode);
6682 return MODE_BTMODE(
"r",
"rb",
"rt");
6684 return MODE_BTXMODE(
"w",
"wb",
"wt",
"wx",
"wbx",
"wtx");
6687 return MODE_BTXMODE(
"w+",
"wb+",
"wt+",
"w+x",
"wb+x",
"wt+x");
6689 return MODE_BTMODE(
"r+",
"rb+",
"rt+");
6693static const char bom_prefix[] =
"bom|";
6694static const char utf_prefix[] =
"utf-";
6695enum {bom_prefix_len = (int)
sizeof(bom_prefix) - 1};
6696enum {utf_prefix_len = (int)
sizeof(utf_prefix) - 1};
6701 return len > bom_prefix_len &&
STRNCASECMP(name, bom_prefix, bom_prefix_len) == 0;
6707 enum rb_io_mode fmode = 0;
6708 const char *m = modestr, *p = NULL;
6736 if (modestr[0] !=
'w')
6757 rb_raise(rb_eArgError,
"invalid access mode %s", modestr);
6762rb_io_oflags_fmode(
int oflags)
6764 enum rb_io_mode fmode = 0;
6766 switch (oflags & O_ACCMODE) {
6778 if (oflags & O_APPEND) {
6781 if (oflags & O_TRUNC) {
6784 if (oflags & O_CREAT) {
6787 if (oflags & O_EXCL) {
6791 if (oflags & O_BINARY) {
6800rb_io_fmode_oflags(
enum rb_io_mode fmode)
6844rb_io_oflags_modestr(
int oflags)
6847# define MODE_BINARY(a,b) ((oflags & O_BINARY) ? (b) : (a))
6849# define MODE_BINARY(a,b) (a)
6852 if (oflags & O_EXCL) {
6853 rb_raise(rb_eArgError,
"exclusive access mode is not supported");
6855 accmode = oflags & (O_RDONLY|O_WRONLY|O_RDWR);
6856 if (oflags & O_APPEND) {
6857 if (accmode == O_WRONLY) {
6858 return MODE_BINARY(
"a",
"ab");
6860 if (accmode == O_RDWR) {
6861 return MODE_BINARY(
"a+",
"ab+");
6866 rb_raise(rb_eArgError,
"invalid access oflags 0x%x", oflags);
6868 return MODE_BINARY(
"r",
"rb");
6870 return MODE_BINARY(
"w",
"wb");
6872 if (oflags & O_TRUNC) {
6873 return MODE_BINARY(
"w+",
"wb+");
6875 return MODE_BINARY(
"r+",
"rb+");
6887 int default_ext = 0;
6890 ext = rb_default_external_encoding();
6893 if (rb_is_ascii8bit_enc(ext)) {
6897 else if (intern == NULL) {
6898 intern = rb_default_internal_encoding();
6903 *enc = (default_ext && intern != ext) ? NULL : ext;
6913unsupported_encoding(
const char *name,
rb_encoding *enc)
6915 rb_enc_warn(enc,
"Unsupported encoding %s ignored", name);
6919parse_mode_enc(
const char *estr,
rb_encoding *estr_enc,
6925 enum rb_io_mode fmode = fmode_p ? *fmode_p : 0;
6931 p = strrchr(estr,
':');
6934 estr += bom_prefix_len;
6935 len -= bom_prefix_len;
6936 if (!
STRNCASECMP(estr, utf_prefix, utf_prefix_len)) {
6940 rb_enc_warn(estr_enc,
"BOM with non-UTF encoding %s is nonsense", estr);
6941 fmode &= ~FMODE_SETENC_BY_BOM;
6949 memcpy(encname, estr,
len);
6950 encname[
len] =
'\0';
6953 idx = rb_enc_find_index(estr);
6955 if (fmode_p) *fmode_p = fmode;
6958 ext_enc = rb_enc_from_index(idx);
6961 unsupported_encoding(estr, estr_enc);
6967 if (*p ==
'-' && *(p+1) ==
'\0') {
6972 idx2 = rb_enc_find_index(p);
6974 unsupported_encoding(p, estr_enc);
6979 int_enc = rb_enc_from_index(idx2);
6983 rb_io_ext_int_to_encs(ext_enc, int_enc, enc_p, enc2_p, fmode);
6996 v = rb_hash_lookup2(opt, sym_encoding,
Qnil);
6997 if (v !=
Qnil) encoding = v;
6998 v = rb_hash_lookup2(opt, sym_extenc,
Qundef);
6999 if (v !=
Qnil) extenc = v;
7000 v = rb_hash_lookup2(opt, sym_intenc,
Qundef);
7001 if (!UNDEF_P(v)) intenc = v;
7003 if ((!UNDEF_P(extenc) || !UNDEF_P(intenc)) && !
NIL_P(encoding)) {
7005 int idx = rb_to_encoding_index(encoding);
7006 if (idx >= 0) encoding = rb_enc_from_encoding(rb_enc_from_index(idx));
7007 rb_warn(
"Ignoring encoding parameter '%"PRIsVALUE
"': %s_encoding is used",
7008 encoding, UNDEF_P(extenc) ?
"internal" :
"external");
7012 if (!NIL_OR_UNDEF_P(extenc)) {
7013 extencoding = rb_to_encoding(extenc);
7015 if (!UNDEF_P(intenc)) {
7016 if (
NIL_P(intenc)) {
7023 if (*p ==
'-' && *(p+1) ==
'\0') {
7028 intencoding = rb_to_encoding(intenc);
7032 intencoding = rb_to_encoding(intenc);
7034 if (extencoding == intencoding) {
7038 if (!
NIL_P(encoding)) {
7042 enc_p, enc2_p, fmode_p);
7045 rb_io_ext_int_to_encs(rb_to_encoding(encoding), NULL, enc_p, enc2_p, 0);
7048 else if (!UNDEF_P(extenc) || !UNDEF_P(intenc)) {
7050 rb_io_ext_int_to_encs(extencoding, intencoding, enc_p, enc2_p, 0);
7058 enum rb_io_mode fmode = *fmode_p;
7063 !rb_enc_asciicompat(enc ? enc : rb_default_external_encoding()))
7064 rb_raise(rb_eArgError,
"ASCII incompatible encoding needs binmode");
7067 rb_raise(rb_eArgError,
"newline decorator with binary mode");
7074#if !DEFAULT_TEXTMODE
7076 fmode &= ~FMODE_TEXTMODE;
7083extract_binmode(
VALUE opthash,
enum rb_io_mode *fmode)
7085 if (!
NIL_P(opthash)) {
7087 v = rb_hash_aref(opthash, sym_textmode);
7090 rb_raise(rb_eArgError,
"textmode specified twice");
7092 rb_raise(rb_eArgError,
"both textmode and binmode specified");
7096 v = rb_hash_aref(opthash, sym_binmode);
7099 rb_raise(rb_eArgError,
"binmode specified twice");
7101 rb_raise(rb_eArgError,
"both textmode and binmode specified");
7107 rb_raise(rb_eArgError,
"both textmode and binmode specified");
7113 int *oflags_p,
enum rb_io_mode *fmode_p,
struct rb_io_encoding *convconfig_p)
7117 enum rb_io_mode fmode;
7121 int has_enc = 0, has_vmode = 0;
7127 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
7137 fmode = rb_io_oflags_fmode(oflags);
7145 oflags = rb_io_fmode_oflags(fmode);
7149 parse_mode_enc(p+1, rb_enc_get(vmode), &enc, &enc2, &fmode);
7154 e = (fmode &
FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
7155 rb_io_ext_int_to_encs(e, NULL, &enc, &enc2, fmode);
7159 if (
NIL_P(opthash)) {
7163#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7165 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7166 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7168 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
7175 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
7178 else if (
NIL_P(vmode)) {
7179 fmode |= DEFAULT_TEXTMODE;
7186 v = rb_hash_aref(opthash, sym_mode);
7188 if (!
NIL_P(vmode)) {
7189 rb_raise(rb_eArgError,
"mode specified twice");
7196 v = rb_hash_aref(opthash, sym_flags);
7201 fmode = rb_io_oflags_fmode(oflags);
7203 extract_binmode(opthash, &fmode);
7209 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
7212 else if (
NIL_P(vmode)) {
7213 fmode |= DEFAULT_TEXTMODE;
7216 v = rb_hash_aref(opthash, sym_perm);
7219 if (!
NIL_P(*vperm_p)) {
7220 rb_raise(rb_eArgError,
"perm specified twice");
7231#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7233 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7234 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7239 rb_raise(rb_eArgError,
"encoding specified twice");
7242 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
7246 validate_enc_binmode(&fmode, ecflags, enc, enc2);
7252 convconfig_p->
enc = enc;
7253 convconfig_p->
enc2 = enc2;
7254 convconfig_p->
ecflags = ecflags;
7255 convconfig_p->
ecopts = ecopts;
7265sysopen_func(
void *ptr)
7268 const char *fname = RSTRING_PTR(data->fname);
7277 fd = IO_WITHOUT_GVL_INT(sysopen_func, data);
7278 }
while (fd < 0 &&
errno == EINTR);
7285rb_sysopen(
VALUE fname,
int oflags, mode_t perm)
7290 data.fname = rb_str_encode_ospath(fname);
7292 data.oflags = oflags;
7295 TRY_WITH_GC((fd = rb_sysopen_internal(&data)) >= 0) {
7296 rb_syserr_fail_path(first_errno, fname);
7302fdopen_internal(
int fd,
const char *modestr)
7309 file = fdopen(fd, modestr);
7325 TRY_WITH_GC((file = fdopen_internal(fd, modestr)) != 0) {
7331 if (setvbuf(file, NULL, _IOFBF, 0) != 0)
7332 rb_warn(
"setvbuf() can't be honoured (fd=%d)", fd);
7340 int t = isatty(fptr->
fd);
7350io_strip_bom(
VALUE io)
7352 VALUE b1, b2, b3, b4;
7363 return rb_utf8_encindex();
7373 return ENCINDEX_UTF_16BE;
7384 return ENCINDEX_UTF_32LE;
7389 return ENCINDEX_UTF_16LE;
7399 return ENCINDEX_UTF_32BE;
7413io_set_encoding_by_bom(
VALUE io)
7415 int idx = io_strip_bom(io);
7421 extenc = rb_enc_from_index(idx);
7422 io_encoding_set(fptr, rb_enc_from_encoding(extenc),
7423 rb_io_internal_encoding(io),
Qnil);
7432rb_file_open_generic(
VALUE io,
VALUE filename,
int oflags,
enum rb_io_mode fmode,
7440 rb_io_ext_int_to_encs(NULL, NULL, &cc.enc, &cc.enc2, fmode);
7445 validate_enc_binmode(&fmode, convconfig->
ecflags,
7446 convconfig->
enc, convconfig->
enc2);
7450 fptr->
encs = *convconfig;
7453 if (!(oflags & O_TMPFILE)) {
7454 fptr->
pathv = pathv;
7457 fptr->
pathv = pathv;
7459 fptr->
fd = rb_sysopen(pathv, oflags, perm);
7467rb_file_open_internal(
VALUE io,
VALUE filename,
const char *modestr)
7470 const char *p = strchr(modestr,
':');
7474 parse_mode_enc(p+1, rb_usascii_encoding(),
7475 &convconfig.
enc, &convconfig.
enc2, &fmode);
7481 e = (fmode &
FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
7482 rb_io_ext_int_to_encs(e, NULL, &convconfig.
enc, &convconfig.
enc2, fmode);
7488#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7490 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7491 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7493 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.
enc2, convconfig.
ecflags);
7496 return rb_file_open_generic(io, filename,
7497 rb_io_fmode_oflags(fmode),
7507 return rb_file_open_internal(io_alloc(
rb_cFile), fname, modestr);
7516#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7539 while ((tmp = *prev) != 0) {
7540 if (tmp->fptr == fptr) {
7549#if defined (_WIN32) || defined(__CYGWIN__)
7558 if (!rb_current_execution_context(
false))
return;
7569pipe_finalize(
rb_io_t *fptr,
int noraise)
7571#if !defined(HAVE_WORKING_FORK) && !defined(_WIN32)
7580 fptr_finalize(fptr, noraise);
7582 pipe_del_fptr(fptr);
7589#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7590 void (*
const old_finalize)(
struct rb_io*,int) = fptr->
finalize;
7592 if (old_finalize == orig->finalize)
return;
7597#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7598 if (old_finalize != pipe_finalize) {
7600 for (list =
pipe_list; list; list = list->next) {
7601 if (list->fptr == fptr)
break;
7603 if (!list) pipe_add_fptr(fptr);
7606 pipe_del_fptr(fptr);
7632#define spawnv(mode, cmd, args) rb_w32_uaspawn((mode), (cmd), (args))
7633#define spawn(mode, cmd) rb_w32_uspawn((mode), (cmd), 0)
7636#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7646#ifdef HAVE_WORKING_FORK
7647# ifndef __EMSCRIPTEN__
7649popen_redirect(
struct popen_arg *p)
7652 close(p->write_pair[1]);
7653 if (p->write_pair[0] != 0) {
7654 dup2(p->write_pair[0], 0);
7655 close(p->write_pair[0]);
7658 if (p->pair[1] != 1) {
7659 dup2(p->pair[1], 1);
7665 if (p->pair[1] != 1) {
7666 dup2(p->pair[1], 1);
7672 if (p->pair[0] != 0) {
7673 dup2(p->pair[0], 0);
7680#if defined(__linux__)
7691linux_get_maxfd(
void)
7694 char buf[4096], *p, *np, *e;
7697 if (fd < 0)
return fd;
7698 ss = read(fd, buf,
sizeof(buf));
7699 if (ss < 0)
goto err;
7702 while ((
int)
sizeof(
"FDSize:\t0\n")-1 <= e-p &&
7703 (np = memchr(p,
'\n', e-p)) != NULL) {
7704 if (memcmp(p,
"FDSize:",
sizeof(
"FDSize:")-1) == 0) {
7706 p +=
sizeof(
"FDSize:")-1;
7726#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
7728 int max = (int)max_file_descriptor;
7731 ret = fcntl(0, F_MAXFD);
7733 maxhint = max = ret;
7734# elif defined(__linux__)
7735 ret = linux_get_maxfd();
7742 for (fd = lowfd; fd <= max; fd++) {
7743 if (!
NIL_P(noclose_fds) &&
7746 ret = fcntl(fd, F_GETFD);
7747 if (ret != -1 && !(ret & FD_CLOEXEC)) {
7748 fcntl(fd, F_SETFD, ret|FD_CLOEXEC);
7750# define CONTIGUOUS_CLOSED_FDS 20
7752 if (max < fd + CONTIGUOUS_CLOSED_FDS)
7753 max = fd + CONTIGUOUS_CLOSED_FDS;
7759# ifndef __EMSCRIPTEN__
7761popen_exec(
void *pp,
char *errmsg,
size_t errmsg_len)
7763 struct popen_arg *p = (
struct popen_arg*)pp;
7765 return rb_exec_async_signal_safe(p->eargp, errmsg, errmsg_len);
7770#if (defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)) && !defined __EMSCRIPTEN__
7772rb_execarg_fixup_v(
VALUE execarg_obj)
7774 rb_execarg_parent_start(execarg_obj);
7778char *rb_execarg_commandline(
const struct rb_execarg *eargp,
VALUE *prog);
7781#ifndef __EMSCRIPTEN__
7783pipe_open(
VALUE execarg_obj,
const char *modestr,
enum rb_io_mode fmode,
7786 struct rb_execarg *eargp =
NIL_P(execarg_obj) ? NULL : rb_execarg_get(execarg_obj);
7787 VALUE prog = eargp ? (eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name) :
Qfalse ;
7793#if defined(HAVE_WORKING_FORK)
7795 char errmsg[80] = {
'\0' };
7797#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7799 struct popen_arg arg;
7802#if defined(HAVE_SPAWNV)
7803# define DO_SPAWN(cmd, args) ((args) ? \
7804 spawnv(P_NOWAIT, (cmd), (args)) : \
7805 spawn(P_NOWAIT, (cmd)))
7806# if !defined(HAVE_WORKING_FORK)
7810#if !defined(HAVE_WORKING_FORK)
7816#if !defined(HAVE_WORKING_FORK)
7817 const char *cmd = 0;
7823#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7824 arg.execarg_obj = execarg_obj;
7827 arg.pair[0] = arg.pair[1] = -1;
7828 arg.write_pair[0] = arg.write_pair[1] = -1;
7829# if !defined(HAVE_WORKING_FORK)
7830 if (eargp && !eargp->use_shell) {
7831 args = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
7836 if (
rb_pipe(arg.write_pair) < 0)
7837 rb_sys_fail_str(prog);
7840 close(arg.write_pair[0]);
7841 close(arg.write_pair[1]);
7845 rb_execarg_addopt(execarg_obj,
INT2FIX(0),
INT2FIX(arg.write_pair[0]));
7846 rb_execarg_addopt(execarg_obj,
INT2FIX(1),
INT2FIX(arg.pair[1]));
7851 rb_sys_fail_str(prog);
7853 rb_execarg_addopt(execarg_obj,
INT2FIX(1),
INT2FIX(arg.pair[1]));
7857 rb_sys_fail_str(prog);
7859 rb_execarg_addopt(execarg_obj,
INT2FIX(0),
INT2FIX(arg.pair[0]));
7862 rb_sys_fail_str(prog);
7864 if (!
NIL_P(execarg_obj)) {
7865 rb_protect(rb_execarg_fixup_v, execarg_obj, &state);
7867 if (0 <= arg.write_pair[0]) close(arg.write_pair[0]);
7868 if (0 <= arg.write_pair[1]) close(arg.write_pair[1]);
7869 if (0 <= arg.pair[0]) close(arg.pair[0]);
7870 if (0 <= arg.pair[1]) close(arg.pair[1]);
7871 rb_execarg_parent_end(execarg_obj);
7875# if defined(HAVE_WORKING_FORK)
7876 pid = rb_fork_async_signal_safe(&status, popen_exec, &arg, arg.eargp->redirect_fds, errmsg,
sizeof(errmsg));
7878 rb_execarg_run_options(eargp, sargp, NULL, 0);
7879 while ((pid = DO_SPAWN(cmd, args)) < 0) {
7881 switch (e =
errno) {
7883# if EWOULDBLOCK != EAGAIN
7892 rb_execarg_run_options(sargp, NULL, NULL, 0);
7894 rb_execarg_parent_end(execarg_obj);
7897# if defined(HAVE_WORKING_FORK)
7898 pid = rb_call_proc__fork();
7900 popen_redirect(&arg);
7912# if defined(HAVE_WORKING_FORK)
7918 close(arg.write_pair[0]);
7919 close(arg.write_pair[1]);
7921# if defined(HAVE_WORKING_FORK)
7930 close(arg.write_pair[0]);
7931 write_fd = arg.write_pair[1];
7942 cmd = rb_execarg_commandline(eargp, &prog);
7943 if (!
NIL_P(execarg_obj)) {
7944 rb_execarg_parent_start(execarg_obj);
7945 rb_execarg_run_options(eargp, sargp, NULL, 0);
7947 fp = popen(cmd, modestr);
7950 rb_execarg_parent_end(execarg_obj);
7951 rb_execarg_run_options(sargp, NULL, NULL, 0);
7953 if (!fp) rb_syserr_fail_path(e, prog);
7963 fptr->
encs = *convconfig;
7964#if RUBY_CRLF_ENVIRONMENT
7971 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
7974#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7975 if (NEED_NEWLINE_DECORATOR_ON_WRITE(fptr)) {
7976 fptr->
encs.
ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
7982 if (0 <= write_fd) {
7983 write_port = io_alloc(
rb_cIO);
7985 write_fptr->
fd = write_fd;
7987 fptr->
mode &= ~FMODE_WRITABLE;
7989 rb_ivar_set(port, rb_intern(
"@tied_io_for_writing"), write_port);
7992#if defined (__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7994 pipe_add_fptr(fptr);
8000pipe_open(
VALUE execarg_obj,
const char *modestr,
enum rb_io_mode fmode,
8008is_popen_fork(
VALUE prog)
8010 if (RSTRING_LEN(prog) == 1 && RSTRING_PTR(prog)[0] ==
'-') {
8011#if !defined(HAVE_WORKING_FORK)
8013 "fork() function is unimplemented on this machine");
8022pipe_open_s(
VALUE prog,
const char *modestr,
enum rb_io_mode fmode,
8026 VALUE *argv = &prog;
8029 if (!is_popen_fork(prog))
8030 execarg_obj = rb_execarg_new(argc, argv, TRUE, FALSE);
8031 return pipe_open(execarg_obj, modestr, fmode, convconfig);
8037 rb_io_t *fptr = io_close_fptr(io);
8206rb_io_s_popen(
int argc,
VALUE *argv,
VALUE klass)
8210 if (argc > 1 && !
NIL_P(opt = rb_check_hash_type(argv[argc-1]))) --argc;
8211 if (argc > 1 && !
NIL_P(env = rb_check_hash_type(argv[0]))) --argc, ++argv;
8220 int ex = !
NIL_P(opt);
8221 rb_error_arity(argc + ex, 1 + ex, 2 + ex);
8224 return popen_finish(rb_io_popen(pname, pmode, env, opt), klass);
8230 const char *modestr;
8233 enum rb_io_mode fmode;
8239#if SIZEOF_RB_LEN_T > SIZEOF_INT
8240 if (
len > INT_MAX) {
8241 rb_raise(rb_eArgError,
"too many arguments");
8250 if (!is_popen_fork(pname))
8251 execarg_obj = rb_execarg_new(1, &pname, TRUE, FALSE);
8253 if (!
NIL_P(execarg_obj)) {
8255 opt = rb_execarg_extract_options(execarg_obj, opt);
8257 rb_execarg_setenv(execarg_obj, env);
8260 modestr = rb_io_oflags_modestr(oflags);
8262 return pipe_open(execarg_obj, modestr, fmode, &convconfig);
8272 rb_io_flush(rb_ractor_stdout());
8273 rb_io_flush(rb_ractor_stderr());
8274 _exit(EXIT_SUCCESS);
8278 RBASIC_SET_CLASS(port, klass);
8285#if defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)
8286struct popen_writer_arg {
8288 struct popen_arg popen;
8292exec_popen_writer(
void *arg,
char *errmsg,
size_t buflen)
8294 struct popen_writer_arg *pw = arg;
8296 popen_redirect(&pw->popen);
8297 execv(pw->argv[0], pw->argv);
8298 strlcpy(errmsg, strerror(
errno), buflen);
8304ruby_popen_writer(
char *
const *argv, rb_pid_t *pid)
8306#if (defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)) || defined(_WIN32)
8307# ifdef HAVE_WORKING_FORK
8308 struct popen_writer_arg pw;
8309 int *
const write_pair = pw.popen.pair;
8315 if (cloexec_pipe(write_pair, 0,
false) == 0) {
8316# ifdef HAVE_WORKING_FORK
8319 char errmsg[80] = {
'\0'};
8320 *pid = rb_fork_async_signal_safe(&status, exec_popen_writer, &pw,
Qnil, errmsg,
sizeof(errmsg));
8322 *pid = rb_w32_uspawn_process(P_NOWAIT, argv[0], argv, write_pair[0], -1, -1, 0);
8323 const char *errmsg = (*pid < 0) ? strerror(
errno) : NULL;
8325 close(write_pair[0]);
8327 close(write_pair[1]);
8328 fprintf(stderr,
"ruby_popen_writer(%s): %s\n", argv[0], errmsg);
8331 return fdopen(write_pair[1],
"w");
8342 enum rb_io_mode fmode;
8351 rb_file_open_generic(io, fname, oflags, fmode, &convconfig, perm);
8403rb_io_s_open(
int argc,
VALUE *argv,
VALUE klass)
8435 VALUE fname, vmode, vperm;
8440 rb_scan_args(argc, argv,
"12", &fname, &vmode, &vperm);
8451 if (
NIL_P(vperm)) perm = 0666;
8455 fd = rb_sysopen(fname, oflags, perm);
8487 int redirect = FALSE;
8495 VALUE tmp = argv[0];
8513 return rb_io_s_open(argc, argv,
rb_cFile);
8517rb_io_open_generic(
VALUE klass,
VALUE filename,
int oflags,
enum rb_io_mode fmode,
8520 return rb_file_open_generic(io_alloc(klass), filename,
8521 oflags, fmode, convconfig, perm);
8528 enum rb_io_mode fmode;
8534 return rb_io_open_generic(io, filename, oflags, fmode, &convconfig, perm);
8548 if (fptr == orig)
return io;
8549 if (RUBY_IO_EXTERNAL_P(fptr)) {
8553 rb_raise(rb_eArgError,
8554 "%s can't change access mode from \"%s\" to \"%s\"",
8555 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->
mode),
8556 rb_io_fmode_modestr(orig->
mode));
8559 flush_before_seek(fptr,
true);
8561 clear_codeconv(fptr);
8563 pos = io_tell(orig);
8566 if (io_fflush(orig) < 0)
8567 rb_sys_fail_on_write(fptr);
8576 else if (!RUBY_IO_EXTERNAL_P(fptr)) fptr->
pathv =
Qnil;
8577 fptr_copy_finalizer(fptr, orig);
8583 rb_thread_io_close_interrupt(fptr);
8584 rb_thread_io_close_wait(fptr);
8586 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2 || !fptr->stdio_file) {
8589 rb_sys_fail_path(orig->
pathv);
8597 rb_sys_fail_path(orig->
pathv);
8603 if (io_seek(fptr, pos, SEEK_SET) < 0 &&
errno) {
8604 rb_sys_fail_path(fptr->
pathv);
8606 if (io_seek(orig, pos, SEEK_SET) < 0 &&
errno) {
8607 rb_sys_fail_path(orig->
pathv);
8621int rb_freopen(
VALUE fname,
const char *mode,
FILE *fp);
8624rb_freopen(
VALUE fname,
const char *mode,
FILE *fp)
8626 if (!freopen(RSTRING_PTR(fname), mode, fp)) {
8669rb_io_reopen(
int argc,
VALUE *argv,
VALUE file)
8671 VALUE fname, nmode, opt;
8675 if (
rb_scan_args(argc, argv,
"11:", &fname, &nmode, &opt) == 1) {
8678 return io_reopen(file, tmp);
8684 fptr =
RFILE(file)->fptr;
8688 enum rb_io_mode fmode;
8692 if (RUBY_IO_EXTERNAL_P(fptr) &&
8695 rb_raise(rb_eArgError,
8696 "%s can't change access mode from \"%s\" to \"%s\"",
8697 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->
mode),
8698 rb_io_fmode_modestr(fmode));
8701 fptr->
encs = convconfig;
8704 oflags = rb_io_fmode_oflags(fptr->
mode);
8707 fptr->
pathv = fname;
8709 fptr->
fd = rb_sysopen(fptr->
pathv, oflags, 0666);
8715 if (io_fflush(fptr) < 0)
8716 rb_sys_fail_on_write(fptr);
8719 clear_codeconv(fptr);
8722 int e = rb_freopen(rb_str_encode_ospath(fptr->
pathv),
8723 rb_io_oflags_modestr(oflags),
8725 if (e) rb_syserr_fail_path(e, fptr->
pathv);
8729 if (setvbuf(fptr->
stdio_file, NULL, _IOFBF, 0) != 0)
8730 rb_warn(
"setvbuf() can't be honoured for %"PRIsVALUE, fptr->
pathv);
8733 if (setvbuf(fptr->
stdio_file, NULL, _IONBF, BUFSIZ) != 0)
8734 rb_warn(
"setvbuf() can't be honoured for %"PRIsVALUE, fptr->
pathv);
8736 else if (fptr->
stdio_file == stdout && isatty(fptr->
fd)) {
8737 if (setvbuf(fptr->
stdio_file, NULL, _IOLBF, BUFSIZ) != 0)
8738 rb_warn(
"setvbuf() can't be honoured for %"PRIsVALUE, fptr->
pathv);
8742 int tmpfd = rb_sysopen(fptr->
pathv, oflags, 0666);
8748 rb_syserr_fail_path(err, fptr->
pathv);
8772 fptr->
mode = orig->
mode & ~FMODE_EXTERNAL;
8779 fptr->closing_ec = NULL;
8780 fptr->wakeup_mutex =
Qnil;
8781 fptr->fork_generation = GET_VM()->fork_gen;
8784 fptr_copy_finalizer(fptr, orig);
8786 fd = ruby_dup(orig->
fd);
8788 pos = io_tell(orig);
8790 io_seek(fptr, pos, SEEK_SET);
8795 write_io = GetWriteIO(io);
8796 if (io != write_io) {
8799 rb_ivar_set(dest, rb_intern(
"@tied_io_for_writing"), write_io);
8862 if (argc == 0)
return Qnil;
8864 out = rb_ractor_stdout();
8876extern void rb_deprecated_str_setter(
VALUE val,
ID id,
VALUE *var);
8881 rb_deprecated_str_setter(val,
id, &val);
8887 val = rb_str_frozen_bare_string(val);
8964 for (i=0; i<argc; i++) {
8968 rb_io_write(out, argv[i]);
9065 rb_io_write(io, str);
9069#define forward(obj, id, argc, argv) \
9070 rb_funcallv_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
9071#define forward_public(obj, id, argc, argv) \
9072 rb_funcallv_public_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
9073#define forward_current(id, argc, argv) \
9074 forward_public(ARGF.current_file, id, argc, argv)
9091 VALUE r_stdout = rb_ractor_stdout();
9092 if (recv == r_stdout) {
9093 return rb_io_putc(recv, ch);
9095 return forward(r_stdout, rb_intern(
"putc"), 1, &ch);
9100rb_str_end_with_asciichar(
VALUE str,
int c)
9103 const char *
ptr = RSTRING_PTR(str);
9107 if (
len == 0)
return 0;
9108 if ((n = rb_enc_mbminlen(
enc)) == 1) {
9109 return ptr[
len - 1] == c;
9111 return rb_enc_ascget(
ptr + ((
len - 1) / n) * n,
ptr +
len, &n,
enc) == c;
9122 rb_io_puts(1, &tmp, out);
9129 rb_io_puts(1, &tmp, out);
9184 VALUE line, args[2];
9191 for (
int i = 0; i < argc; i++) {
9205 if (RSTRING_LEN(line) == 0) {
9210 if (!rb_str_end_with_asciichar(line,
'\n')) {
9215 rb_io_writev(out, n, args);
9233 VALUE r_stdout = rb_ractor_stdout();
9234 if (recv == r_stdout) {
9235 return rb_io_puts(argc, argv, recv);
9237 return forward(r_stdout, rb_intern(
"puts"), argc, argv);
9241rb_p_write(
VALUE str)
9246 VALUE r_stdout = rb_ractor_stdout();
9249 io_writev(2, args, r_stdout);
9252 rb_io_writev(r_stdout, 2, args);
9264rb_p_result(
int argc,
const VALUE *argv)
9271 else if (argc > 1) {
9274 VALUE r_stdout = rb_ractor_stdout();
9276 rb_uninterruptible(rb_io_flush, r_stdout);
9317 for (i=0; i<argc; i++) {
9319 rb_uninterruptible(rb_p_write, inspected);
9321 return rb_p_result(argc, argv);
9342rb_obj_display(
int argc,
VALUE *argv,
VALUE self)
9346 out = (!
rb_check_arity(argc, 0, 1) ? rb_ractor_stdout() : argv[0]);
9347 rb_io_write(out, self);
9353rb_stderr_to_original_p(
VALUE err)
9355 return (err == orig_stderr ||
RFILE(orig_stderr)->fptr->
fd < 0);
9361 VALUE out = rb_ractor_stderr();
9362 if (rb_stderr_to_original_p(out)) {
9364 if (isatty(fileno(stderr))) {
9365 if (rb_w32_write_console(
rb_str_new(mesg,
len), fileno(stderr)) > 0)
return;
9368 if (fwrite(mesg,
sizeof(
char), (
size_t)
len, stderr) < (
size_t)
len) {
9385rb_write_error_str(
VALUE mesg)
9387 VALUE out = rb_ractor_stderr();
9389 if (rb_stderr_to_original_p(out)) {
9390 size_t len = (size_t)RSTRING_LEN(mesg);
9392 if (isatty(fileno(stderr))) {
9393 if (rb_w32_write_console(mesg, fileno(stderr)) > 0)
return;
9396 if (fwrite(RSTRING_PTR(mesg),
sizeof(
char),
len, stderr) <
len) {
9403 rb_io_write(out, mesg);
9408rb_stderr_tty_p(
void)
9410 if (rb_stderr_to_original_p(rb_ractor_stderr()))
9411 return isatty(fileno(stderr));
9416must_respond_to(
ID mid,
VALUE val,
ID id)
9419 rb_raise(
rb_eTypeError,
"%"PRIsVALUE
" must have %"PRIsVALUE
" method, %"PRIsVALUE
" given",
9420 rb_id2str(
id), rb_id2str(mid),
9440 must_respond_to(id_write, val,
id);
9447 return rb_ractor_stdout();
9453 must_respond_to(id_write, val,
id);
9460 return rb_ractor_stderr();
9464allocate_and_open_new_file(
VALUE klass)
9466 VALUE self = io_alloc(klass);
9467 rb_io_make_open_file(self);
9475 VALUE self = rb_protect(allocate_and_open_new_file, klass, &state);
9483 maygvl_close(descriptor, 0);
9491 io->
fd = descriptor;
9509 io->closing_ec = NULL;
9510 io->wakeup_mutex =
Qnil;
9511 io->fork_generation = GET_VM()->fork_gen;
9514 io->
encs = *encoding;
9523prep_io(
int fd,
enum rb_io_mode fmode,
VALUE klass,
const char *path)
9533 e = (fmode &
FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
9534 rb_io_ext_int_to_encs(e, NULL, &convconfig.
enc, &convconfig.
enc2, fmode);
9538#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9540 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
9541 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
9543 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.
enc2, convconfig.
ecflags);
9549 if (!io_check_tty(io)) {
9552 setmode(fd, O_BINARY);
9564 if (path && strcmp(path,
"-")) klass =
rb_cFile;
9565 return prep_io(fd, rb_io_oflags_fmode(oflags), klass, path);
9569prep_stdio(
FILE *f,
enum rb_io_mode fmode,
VALUE klass,
const char *path)
9576#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9577 fptr->
encs.
ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
9588rb_io_prep_stdin(
void)
9594rb_io_prep_stdout(
void)
9600rb_io_prep_stderr(
void)
9609 int oflags = rb_io_fmode_oflags(fptr->
mode) & ~O_EXCL;
9636 rb_io_buffer_init(&fp->
wbuf);
9637 rb_io_buffer_init(&fp->
rbuf);
9638 rb_io_buffer_init(&fp->
cbuf);
9653 fp->closing_ec = NULL;
9654 fp->wakeup_mutex =
Qnil;
9655 fp->fork_generation = GET_VM()->fork_gen;
9660rb_io_make_open_file(
VALUE obj)
9665 if (
RFILE(obj)->fptr) {
9668 RFILE(obj)->fptr = 0;
9670 fp = rb_io_fptr_new();
9672 RFILE(obj)->fptr = fp;
9721rb_io_initialize(
int argc,
VALUE *argv,
VALUE io)
9727 return io_initialize(io, fnum, vmode, opt);
9734 int fd, oflags = O_RDONLY;
9735 enum rb_io_mode fmode;
9737#if defined(HAVE_FCNTL) && defined(F_GETFL)
9747 rb_raise(rb_eArgError,
"The given fd is not accessible because RubyVM reserves it");
9749#if defined(HAVE_FCNTL) && defined(F_GETFL)
9750 oflags = fcntl(fd, F_GETFL);
9751 if (oflags == -1) rb_sys_fail(0);
9753 if (fstat(fd, &st) < 0) rb_sys_fail(0);
9756#if defined(HAVE_FCNTL) && defined(F_GETFL)
9757 ofmode = rb_io_oflags_fmode(oflags);
9769 if (rb_hash_aref(opt, sym_autoclose) ==
Qfalse) {
9773 path = rb_hash_aref(opt,
RB_ID2SYM(idPath));
9784 fp->
encs = convconfig;
9788 fp->closing_ec = NULL;
9789 fp->wakeup_mutex =
Qnil;
9790 fp->fork_generation = GET_VM()->fork_gen;
9793 if (fileno(stdin) == fd)
9795 else if (fileno(stdout) == fd)
9797 else if (fileno(stderr) == fd)
9829rb_io_set_encoding_by_bom(
VALUE io)
9835 rb_raise(rb_eArgError,
"ASCII incompatible encoding needs binmode");
9838 rb_raise(rb_eArgError,
"encoding conversion is set");
9840 else if (fptr->
encs.
enc && fptr->
encs.
enc != rb_ascii8bit_encoding()) {
9841 rb_raise(rb_eArgError,
"encoding is set to %s already",
9844 if (!io_set_encoding_by_bom(io))
return Qnil;
9845 return rb_enc_from_encoding(fptr->
encs.
enc);
9898rb_file_initialize(
int argc,
VALUE *argv,
VALUE io)
9900 if (
RFILE(io)->fptr) {
9903 VALUE fname, vmode, vperm, opt;
9904 int posargc =
rb_scan_args(argc, argv,
"12:", &fname, &vmode, &vperm, &opt);
9909 return io_initialize(io, fd, vmode, opt);
9912 return rb_open_file(io, fname, vmode, vperm, opt);
9917rb_io_s_new(
int argc,
VALUE *argv,
VALUE klass)
9922 rb_warn(
"%"PRIsVALUE
"::new() does not take block; use %"PRIsVALUE
"::open() instead",
9938rb_io_s_for_fd(
int argc,
VALUE *argv,
VALUE klass)
9941 rb_io_initialize(argc, argv, io);
9954rb_io_autoclose_p(
VALUE io)
9979rb_io_set_autoclose(
VALUE io,
VALUE autoclose)
9983 if (!
RTEST(autoclose))
9986 fptr->
mode &= ~FMODE_EXTERNAL;
9991io_wait_event(
VALUE io,
int event,
VALUE timeout,
int return_io)
10001 if (mask & event) {
10023io_wait_readable(
int argc,
VALUE *argv,
VALUE io)
10030 if (rb_io_read_pending(fptr))
return Qtrue;
10033 VALUE timeout = (argc == 1 ? argv[0] :
Qnil);
10047io_wait_writable(
int argc,
VALUE *argv,
VALUE io)
10055 VALUE timeout = (argc == 1 ? argv[0] :
Qnil);
10070io_wait_priority(
int argc,
VALUE *argv,
VALUE io)
10077 if (rb_io_read_pending(fptr))
return Qtrue;
10080 VALUE timeout = argc == 1 ? argv[0] :
Qnil;
10086wait_mode_sym(
VALUE mode)
10088 if (mode ==
ID2SYM(rb_intern(
"r"))) {
10089 return RB_WAITFD_IN;
10091 if (mode ==
ID2SYM(rb_intern(
"read"))) {
10092 return RB_WAITFD_IN;
10094 if (mode ==
ID2SYM(rb_intern(
"readable"))) {
10095 return RB_WAITFD_IN;
10097 if (mode ==
ID2SYM(rb_intern(
"w"))) {
10098 return RB_WAITFD_OUT;
10100 if (mode ==
ID2SYM(rb_intern(
"write"))) {
10101 return RB_WAITFD_OUT;
10103 if (mode ==
ID2SYM(rb_intern(
"writable"))) {
10104 return RB_WAITFD_OUT;
10106 if (mode ==
ID2SYM(rb_intern(
"rw"))) {
10107 return RB_WAITFD_IN|RB_WAITFD_OUT;
10109 if (mode ==
ID2SYM(rb_intern(
"read_write"))) {
10110 return RB_WAITFD_IN|RB_WAITFD_OUT;
10112 if (mode ==
ID2SYM(rb_intern(
"readable_writable"))) {
10113 return RB_WAITFD_IN|RB_WAITFD_OUT;
10116 rb_raise(rb_eArgError,
"unsupported mode: %"PRIsVALUE, mode);
10120io_event_from_value(
VALUE value)
10124 if (events <= 0) rb_raise(rb_eArgError,
"Events must be positive integer!");
10162 for (
int i = 0; i < argc; i += 1) {
10164 events |= wait_mode_sym(argv[i]);
10166 else if (UNDEF_P(timeout)) {
10170 rb_raise(rb_eArgError,
"timeout given more than once");
10174 if (UNDEF_P(timeout)) timeout =
Qnil;
10182 events = io_event_from_value(argv[0]);
10190 if (rb_io_read_pending(fptr)) {
10192 if (return_io)
return Qtrue;
10198 return io_wait_event(io, events, timeout, return_io);
10202argf_mark_and_move(
void *ptr)
10204 struct argf *p = ptr;
10205 rb_gc_mark_and_move(&p->filename);
10206 rb_gc_mark_and_move(&p->current_file);
10207 rb_gc_mark_and_move(&p->argv);
10208 rb_gc_mark_and_move(&p->inplace);
10209 rb_gc_mark_and_move(&p->encs.
ecopts);
10213argf_memsize(
const void *ptr)
10215 const struct argf *p = ptr;
10216 size_t size =
sizeof(*p);
10223 0, 0, RUBY_TYPED_THREAD_SAFE_FREE | RUBY_TYPED_WB_PROTECTED
10229 p->filename =
Qnil;
10230 p->current_file =
Qnil;
10236argf_alloc(
VALUE klass)
10251 memset(&ARGF, 0,
sizeof(ARGF));
10252 argf_init(
argf, &ARGF, argv);
10262 ARGF = argf_of(orig);
10263 rb_gc_writebarrier_remember(
argf);
10290 ARGF.last_lineno = ARGF.lineno;
10316 return forward_current(rb_frame_this_func(), argc, argv);
10319#define next_argv() argf_next_argv(argf)
10320#define ARGF_GENERIC_INPUT_P() \
10321 (ARGF.current_file == rb_stdin && !RB_TYPE_P(ARGF.current_file, T_FILE))
10322#define ARGF_FORWARD(argc, argv) do {\
10323 if (ARGF_GENERIC_INPUT_P())\
10324 return argf_forward((argc), (argv), argf);\
10326#define NEXT_ARGF_FORWARD(argc, argv) do {\
10327 if (!next_argv()) return Qnil;\
10328 ARGF_FORWARD((argc), (argv));\
10334 VALUE file = ARGF.current_file;
10348 int stdout_binmode = 0;
10349 enum rb_io_mode fmode;
10351 VALUE r_stdout = rb_ractor_stdout();
10356 stdout_binmode = 1;
10359 if (ARGF.init_p == 0) {
10369 if (
NIL_P(ARGF.argv)) {
10372 else if (ARGF.next_p == -1 &&
RARRAY_LEN(ARGF.argv) > 0) {
10377 if (ARGF.next_p == 1) {
10378 if (ARGF.init_p == 1) argf_close(
argf);
10383 ARGF_SET(filename, filename);
10384 filename = rb_str_encode_ospath(filename);
10386 if (RSTRING_LEN(filename) == 1 && fn[0] ==
'-') {
10388 if (ARGF.inplace) {
10389 rb_warn(
"Can't do inplace edit for stdio; skipping");
10395 int fr = rb_sysopen(filename, O_RDONLY, 0);
10397 if (ARGF.inplace) {
10399#ifndef NO_SAFE_RENAME
10410 if (!
NIL_P(ARGF.inplace)) {
10411 VALUE suffix = ARGF.inplace;
10413 if (
NIL_P(rb_str_cat_conv_enc_opts(str, RSTRING_LEN(str),
10414 RSTRING_PTR(suffix), RSTRING_LEN(suffix),
10415 rb_enc_get(suffix), 0,
Qnil))) {
10418#ifdef NO_SAFE_RENAME
10420 (void)unlink(RSTRING_PTR(str));
10421 if (rename(fn, RSTRING_PTR(str)) < 0) {
10422 rb_warn(
"Can't rename %"PRIsVALUE
" to %"PRIsVALUE
": %s, skipping file",
10423 filename, str, strerror(
errno));
10426 fr = rb_sysopen(str, O_RDONLY, 0);
10428 if (rename(fn, RSTRING_PTR(str)) < 0) {
10429 rb_warn(
"Can't rename %"PRIsVALUE
" to %"PRIsVALUE
": %s, skipping file",
10430 filename, str, strerror(
errno));
10437#ifdef NO_SAFE_RENAME
10438 rb_fatal(
"Can't do inplace edit without backup");
10440 if (unlink(fn) < 0) {
10441 rb_warn(
"Can't remove %"PRIsVALUE
": %s, skipping file",
10442 filename, strerror(
errno));
10448 fw = rb_sysopen(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666);
10449#ifndef NO_SAFE_RENAME
10452 fchmod(fw, st.st_mode);
10454 chmod(fn, st.st_mode);
10456 if (st.st_uid!=st2.st_uid || st.st_gid!=st2.st_gid) {
10459 err = fchown(fw, st.st_uid, st.st_gid);
10461 err = chown(fn, st.st_uid, st.st_gid);
10463 if (err && getuid() == 0 && st2.st_uid == 0) {
10464 const char *wkfn = RSTRING_PTR(filename);
10465 rb_warn(
"Can't set owner/group of %"PRIsVALUE
" to same as %"PRIsVALUE
": %s, skipping file",
10466 filename, str, strerror(
errno));
10469 (void)unlink(wkfn);
10479 if (!ARGF.binmode) {
10480 fmode |= DEFAULT_TEXTMODE;
10482 ARGF_SET(current_file, prep_io(fr, fmode,
rb_cFile, fn));
10483 if (!
NIL_P(write_io)) {
10490 if (ARGF.encs.enc) {
10491 fptr->
encs = ARGF.encs;
10492 clear_codeconv(fptr);
10495 fptr->
encs.
ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
10496 if (!ARGF.binmode) {
10498#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
10499 fptr->
encs.
ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
10510 else if (ARGF.next_p == -1) {
10513 if (ARGF.inplace) {
10514 rb_warn(
"Can't do inplace edit for stdio");
10518 if (ARGF.init_p == -1) ARGF.init_p = 1;
10526 long lineno = ARGF.lineno;
10529 if (!next_argv())
return Qnil;
10530 if (ARGF_GENERIC_INPUT_P()) {
10531 line = forward_current(idGets, argc, argv);
10538 line = rb_io_getline(argc, argv, ARGF.current_file);
10540 if (
NIL_P(line) && ARGF.next_p != -1) {
10546 if (!
NIL_P(line)) {
10547 ARGF.lineno = ++lineno;
10548 ARGF.last_lineno = ARGF.lineno;
10554argf_lineno_getter(
ID id,
VALUE *var)
10557 return INT2FIX(ARGF.last_lineno);
10565 ARGF.last_lineno = ARGF.lineno = n;
10569rb_reset_argf_lineno(
long n)
10571 ARGF.last_lineno = ARGF.lineno = n;
10612 if (recv ==
argf) {
10613 return argf_gets(argc, argv,
argf);
10615 return forward(
argf, idGets, argc, argv);
10641 line = argf_getline(argc, argv,
argf);
10653 return rb_f_gets(0, 0,
argf);
10657 if (!next_argv())
return Qnil;
10659 if (
NIL_P(line) && ARGF.next_p != -1) {
10665 if (!
NIL_P(line)) {
10667 ARGF.last_lineno = ARGF.lineno;
10693rb_f_readline(
int argc,
VALUE *argv,
VALUE recv)
10695 if (recv ==
argf) {
10696 return argf_readline(argc, argv,
argf);
10698 return forward(
argf, rb_intern(
"readline"), argc, argv);
10724 if (!next_argv()) rb_eof_error();
10725 ARGF_FORWARD(argc, argv);
10726 line = argf_gets(argc, argv,
argf);
10796rb_f_readlines(
int argc,
VALUE *argv,
VALUE recv)
10798 if (recv ==
argf) {
10799 return argf_readlines(argc, argv,
argf);
10801 return forward(
argf, rb_intern(
"readlines"), argc, argv);
10825 long lineno = ARGF.lineno;
10829 while (next_argv()) {
10830 if (ARGF_GENERIC_INPUT_P()) {
10831 lines = forward_current(rb_intern(
"readlines"), argc, argv);
10834 lines = rb_io_readlines(argc, argv, ARGF.current_file);
10840 ARGF.last_lineno = ARGF.lineno;
10875 rb_last_status_clear();
10876 port = pipe_open_s(str,
"r",
FMODE_READABLE|DEFAULT_TEXTMODE, NULL);
10880 result = read_all(fptr, remain_size(fptr),
Qnil);
10882 rb_io_fptr_cleanup_all(fptr);
10888#ifdef HAVE_SYS_SELECT_H
10889#include <sys/select.h>
10903 if (!
NIL_P(read)) {
10908 if (READ_DATA_PENDING(fptr) || READ_CHAR_PENDING(fptr)) {
10912 if (max < fptr->fd) max = fptr->
fd;
10915 timerec.tv_sec = timerec.tv_usec = 0;
10923 if (!
NIL_P(write)) {
10929 if (max < fptr->fd) max = fptr->
fd;
10936 if (!
NIL_P(except)) {
10940 VALUE write_io = GetWriteIO(io);
10943 if (max < fptr->fd) max = fptr->
fd;
10944 if (io != write_io) {
10947 if (max < fptr->fd) max = fptr->
fd;
10962 if (!pending && n == 0)
return Qnil;
10987 VALUE write_io = GetWriteIO(io);
11000 VALUE write_io = GetWriteIO(io);
11005 else if (io != write_io) {
11018 VALUE read, write, except;
11024select_call(
VALUE arg)
11028 return select_internal(p->read, p->write, p->except, p->timeout, p->fdsets);
11032select_end(
VALUE arg)
11037 for (i = 0; i < numberof(p->fdsets); ++i)
11042static VALUE sym_normal, sym_sequential, sym_random,
11043 sym_willneed, sym_dontneed, sym_noreuse;
11045#ifdef HAVE_POSIX_FADVISE
11046struct io_advise_struct {
11054io_advise_internal(
void *arg)
11056 struct io_advise_struct *ptr = arg;
11057 return posix_fadvise(ptr->fd, ptr->offset, ptr->len, ptr->advice);
11061io_advise_sym_to_const(
VALUE sym)
11063#ifdef POSIX_FADV_NORMAL
11064 if (sym == sym_normal)
11065 return INT2NUM(POSIX_FADV_NORMAL);
11068#ifdef POSIX_FADV_RANDOM
11069 if (sym == sym_random)
11070 return INT2NUM(POSIX_FADV_RANDOM);
11073#ifdef POSIX_FADV_SEQUENTIAL
11074 if (sym == sym_sequential)
11075 return INT2NUM(POSIX_FADV_SEQUENTIAL);
11078#ifdef POSIX_FADV_WILLNEED
11079 if (sym == sym_willneed)
11080 return INT2NUM(POSIX_FADV_WILLNEED);
11083#ifdef POSIX_FADV_DONTNEED
11084 if (sym == sym_dontneed)
11085 return INT2NUM(POSIX_FADV_DONTNEED);
11088#ifdef POSIX_FADV_NOREUSE
11089 if (sym == sym_noreuse)
11090 return INT2NUM(POSIX_FADV_NOREUSE);
11097do_io_advise(
rb_io_t *fptr,
VALUE advice, rb_off_t offset, rb_off_t
len)
11100 struct io_advise_struct ias;
11103 num_adv = io_advise_sym_to_const(advice);
11109 if (
NIL_P(num_adv))
11113 ias.advice =
NUM2INT(num_adv);
11114 ias.offset = offset;
11117 rv = (int)rb_io_blocking_region(fptr, io_advise_internal, &ias);
11118 if (rv && rv != ENOSYS) {
11121 VALUE message = rb_sprintf(
"%"PRIsVALUE
" "
11125 fptr->
pathv, offset,
len, advice);
11135advice_arg_check(
VALUE advice)
11140 if (advice != sym_normal &&
11141 advice != sym_sequential &&
11142 advice != sym_random &&
11143 advice != sym_willneed &&
11144 advice != sym_dontneed &&
11145 advice != sym_noreuse) {
11146 rb_raise(
rb_eNotImpError,
"Unsupported advice: %+"PRIsVALUE, advice);
11184rb_io_advise(
int argc,
VALUE *argv,
VALUE io)
11191 advice_arg_check(advice);
11193 io = GetWriteIO(io);
11199#ifdef HAVE_POSIX_FADVISE
11200 return do_io_advise(fptr, advice,
off, l);
11202 ((void)
off, (
void)l);
11214 return isinf(f) && 0 < f;
11370rb_f_select(
int argc,
VALUE *argv,
VALUE obj)
11373 if (scheduler !=
Qnil) {
11376 if (!UNDEF_P(result))
return result;
11384 rb_scan_args(argc, argv,
"13", &args.read, &args.write, &args.except, &timeout);
11385 if (
NIL_P(timeout) || is_pos_inf(timeout)) {
11390 args.timeout = &timerec;
11393 for (i = 0; i < numberof(args.fdsets); ++i)
11399#ifdef IOCTL_REQ_TYPE
11400 typedef IOCTL_REQ_TYPE ioctl_req_t;
11402 typedef int ioctl_req_t;
11403# define NUM2IOCTLREQ(num) ((int)NUM2LONG(num))
11414nogvl_ioctl(
void *ptr)
11416 struct ioctl_arg *arg = ptr;
11418 return (
VALUE)ioctl(arg->fd, arg->cmd, arg->narg);
11422do_ioctl(
struct rb_io *io, ioctl_req_t cmd,
long narg)
11425 struct ioctl_arg arg;
11431 retval = (int)rb_io_blocking_region(io, nogvl_ioctl, &arg);
11437#define DEFAULT_IOCTL_NARG_LEN (256)
11439#if defined(__linux__) && defined(_IOC_SIZE)
11441linux_iocparm_len(ioctl_req_t cmd)
11445 if ((cmd & 0xFFFF0000) == 0) {
11447 return DEFAULT_IOCTL_NARG_LEN;
11450 len = _IOC_SIZE(cmd);
11453 if (
len < DEFAULT_IOCTL_NARG_LEN)
11454 len = DEFAULT_IOCTL_NARG_LEN;
11462ioctl_narg_len(ioctl_req_t cmd)
11468#define IOCPARM_LEN(x) (((x) >> 16) & IOCPARM_MASK)
11472 len = IOCPARM_LEN(cmd);
11473#elif defined(__linux__) && defined(_IOC_SIZE)
11474 len = linux_iocparm_len(cmd);
11477 len = DEFAULT_IOCTL_NARG_LEN;
11486typedef long fcntl_arg_t;
11489typedef int fcntl_arg_t;
11493fcntl_narg_len(ioctl_req_t cmd)
11500 len =
sizeof(fcntl_arg_t);
11508#ifdef F_DUPFD_CLOEXEC
11509 case F_DUPFD_CLOEXEC:
11510 len =
sizeof(fcntl_arg_t);
11520 len =
sizeof(fcntl_arg_t);
11530 len =
sizeof(fcntl_arg_t);
11540 len =
sizeof(fcntl_arg_t);
11545 len =
sizeof(
struct f_owner_ex);
11550 len =
sizeof(
struct f_owner_ex);
11555 len =
sizeof(
struct flock);
11560 len =
sizeof(
struct flock);
11565 len =
sizeof(
struct flock);
11585 len =
sizeof(fcntl_arg_t);
11595 len =
sizeof(fcntl_arg_t);
11600 len =
sizeof(fcntl_arg_t);
11613fcntl_narg_len(ioctl_req_t cmd)
11619#define NARG_SENTINEL 17
11622setup_narg(ioctl_req_t cmd,
VALUE *argp,
long (*narg_len)(ioctl_req_t))
11633 else if (arg ==
Qtrue) {
11648 req_len = narg_len(cmd);
11649 rb_str_modify(arg);
11651 slen = RSTRING_LEN(arg);
11653 if (slen < req_len+1) {
11654 rb_str_resize(arg, req_len+1);
11655 MEMZERO(RSTRING_PTR(arg)+slen,
char, req_len-slen);
11659 ptr = RSTRING_PTR(arg);
11660 ptr[slen - 1] = NARG_SENTINEL;
11669finish_narg(
int retval,
VALUE arg,
const rb_io_t *fptr)
11671 if (retval < 0) rb_sys_fail_path(fptr->
pathv);
11676 if (ptr[slen-1] != NARG_SENTINEL)
11677 rb_raise(rb_eArgError,
"return value overflowed string");
11678 ptr[slen-1] =
'\0';
11688 ioctl_req_t cmd = NUM2IOCTLREQ(req);
11693 narg = setup_narg(cmd, &arg, ioctl_narg_len);
11695 retval = do_ioctl(fptr, cmd, narg);
11696 return finish_narg(retval, arg, fptr);
11723 return rb_ioctl(io, req, arg);
11726#define rb_io_ioctl rb_f_notimplement
11737nogvl_fcntl(
void *ptr)
11739 struct fcntl_arg *arg = ptr;
11741#if defined(F_DUPFD)
11742 if (arg->cmd == F_DUPFD)
11745 return (
VALUE)fcntl(arg->fd, arg->cmd, arg->narg);
11749do_fcntl(
struct rb_io *io,
int cmd,
long narg)
11752 struct fcntl_arg arg;
11758 retval = (int)rb_io_blocking_region(io, nogvl_fcntl, &arg);
11759 if (retval != -1) {
11761#if defined(F_DUPFD)
11764#if defined(F_DUPFD_CLOEXEC)
11765 case F_DUPFD_CLOEXEC:
11782 narg = setup_narg(cmd, &arg, fcntl_narg_len);
11784 retval = do_fcntl(fptr, cmd, narg);
11785 return finish_narg(retval, arg, fptr);
11811 return rb_fcntl(io, req, arg);
11814#define rb_io_fcntl rb_f_notimplement
11817#if defined(HAVE_SYSCALL) || defined(HAVE___SYSCALL)
11849#if SIZEOF_VOIDP == 8 && defined(HAVE___SYSCALL) && SIZEOF_INT != 8
11850# define SYSCALL __syscall
11851# define NUM2SYSCALLID(x) NUM2LONG(x)
11852# define RETVAL2NUM(x) LONG2NUM(x)
11853# if SIZEOF_LONG == 8
11854 long num, retval = -1;
11855# elif SIZEOF_LONG_LONG == 8
11856 long long num, retval = -1;
11858# error ---->> it is asserted that __syscall takes the first argument and returns retval in 64bit signed integer. <<----
11860#elif defined(__linux__)
11861# define SYSCALL syscall
11862# define NUM2SYSCALLID(x) NUM2LONG(x)
11863# define RETVAL2NUM(x) LONG2NUM(x)
11871 long num, retval = -1;
11873# define SYSCALL syscall
11874# define NUM2SYSCALLID(x) NUM2INT(x)
11875# define RETVAL2NUM(x) INT2NUM(x)
11876 int num, retval = -1;
11882 "We plan to remove a syscall function at future release. DL(Fiddle) provides safer alternative.");
11886 rb_raise(rb_eArgError,
"too few arguments for syscall");
11887 if (argc > numberof(arg))
11888 rb_raise(rb_eArgError,
"too many arguments for syscall");
11889 num = NUM2SYSCALLID(argv[0]); ++argv;
11890 for (i = argc - 1; i--; ) {
11905 retval = SYSCALL(num);
11908 retval = SYSCALL(num, arg[0]);
11911 retval = SYSCALL(num, arg[0],arg[1]);
11914 retval = SYSCALL(num, arg[0],arg[1],arg[2]);
11917 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3]);
11920 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4]);
11923 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5]);
11926 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6]);
11932 return RETVAL2NUM(retval);
11934#undef NUM2SYSCALLID
11938#define rb_f_syscall rb_f_notimplement
11942io_new_instance(
VALUE args)
11948find_encoding(
VALUE v)
11951 if (!enc)
rb_warn(
"Unsupported encoding %"PRIsVALUE
" ignored", v);
11963 enc2 = find_encoding(v1);
11966 if (RSTRING_LEN(tmp) == 1 && RSTRING_PTR(tmp)[0] ==
'-') {
11972 enc = find_encoding(v2);
11979 enc = find_encoding(v2);
11985 if (enc2 == rb_ascii8bit_encoding()) {
11990 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11996 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
11997 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
12002 if (!
NIL_P(tmp) && rb_enc_asciicompat(enc = rb_enc_get(tmp))) {
12003 parse_mode_enc(RSTRING_PTR(tmp), enc, &enc, &enc2, NULL);
12004 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
12007 rb_io_ext_int_to_encs(find_encoding(v1), NULL, &enc, &enc2, 0);
12008 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
12013 validate_enc_binmode(&fptr->
mode, ecflags, enc, enc2);
12018 clear_codeconv(fptr);
12030io_encoding_set_v(
VALUE v)
12033 io_encoding_set(arg->fptr, arg->v1, arg->v2, arg->opt);
12038pipe_pair_close(
VALUE rw)
12041 return rb_ensure(io_close, rwp[0], io_close, rwp[1]);
12124rb_io_s_pipe(
int argc,
VALUE *argv,
VALUE klass)
12126 int pipes[2], state;
12127 VALUE r, w, args[3], v1, v2;
12131 enum rb_io_mode fmode = 0;
12134 argc =
rb_scan_args(argc, argv,
"02:", &v1, &v2, &opt);
12141 r = rb_protect(io_new_instance, (
VALUE)args, &state);
12145 rb_jump_tag(state);
12149 ies_args.fptr = fptr;
12152 ies_args.opt = opt;
12153 rb_protect(io_encoding_set_v, (
VALUE)&ies_args, &state);
12157 rb_jump_tag(state);
12162 w = rb_protect(io_new_instance, (
VALUE)args, &state);
12166 rb_jump_tag(state);
12171 extract_binmode(opt, &fmode);
12178#if DEFAULT_TEXTMODE
12180 fptr->
mode &= ~FMODE_TEXTMODE;
12181 setmode(fptr->
fd, O_BINARY);
12183#if RUBY_CRLF_ENVIRONMENT
12189 fptr->
mode |= fmode;
12190#if DEFAULT_TEXTMODE
12192 fptr2->
mode &= ~FMODE_TEXTMODE;
12193 setmode(fptr2->
fd, O_BINARY);
12196 fptr2->
mode |= fmode;
12230 else if (!
NIL_P(v = rb_hash_aref(opt, sym_open_args))) {
12233 v = rb_to_array_type(v);
12238 arg->io = rb_io_open(klass, path, vmode, vperm, opt);
12242io_s_foreach(
VALUE v)
12247 if (arg->limit == 0)
12248 rb_raise(rb_eArgError,
"invalid limit: 0 for foreach");
12249 while (!
NIL_P(str = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, arg->io))) {
12333rb_io_s_foreach(
int argc,
VALUE *argv,
VALUE self)
12336 int orig_argc = argc;
12340 argc =
rb_scan_args(argc, argv,
"12:", NULL, NULL, NULL, &opt);
12342 extract_getline_args(argc-1, argv+1, &garg);
12343 open_key_args(self, argc, argv, opt, &arg);
12345 extract_getline_opts(opt, &garg);
12346 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12347 return rb_ensure(io_s_foreach, (
VALUE)&garg, rb_io_close, arg.io);
12351io_s_readlines(
VALUE v)
12354 return io_readlines(arg, arg->io);
12407rb_io_s_readlines(
int argc,
VALUE *argv,
VALUE io)
12413 argc =
rb_scan_args(argc, argv,
"12:", NULL, NULL, NULL, &opt);
12414 extract_getline_args(argc-1, argv+1, &garg);
12415 open_key_args(io, argc, argv, opt, &arg);
12417 extract_getline_opts(opt, &garg);
12418 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12419 return rb_ensure(io_s_readlines, (
VALUE)&garg, rb_io_close, arg.io);
12426 return io_read(arg->argc, arg->argv, arg->io);
12436seek_before_access(
VALUE argp)
12440 return rb_io_seek(arg->io, arg->offset, arg->mode);
12507rb_io_s_read(
int argc,
VALUE *argv,
VALUE io)
12513 argc =
rb_scan_args(argc, argv,
"13:", NULL, NULL, &offset, NULL, &opt);
12515 rb_raise(rb_eArgError,
"negative offset %"PRIdLEN
" given",
off);
12517 open_key_args(io, argc, argv, opt, &arg);
12519 if (!
NIL_P(offset)) {
12523 sarg.offset = offset;
12524 sarg.mode = SEEK_SET;
12525 rb_protect(seek_before_access, (
VALUE)&sarg, &state);
12528 rb_jump_tag(state);
12530 if (arg.argc == 2) arg.argc = 1;
12545rb_io_s_binread(
int argc,
VALUE *argv,
VALUE io)
12560 convconfig.
enc = rb_ascii8bit_encoding();
12561 arg.io = rb_io_open_generic(io, argv[0], oflags, fmode, &convconfig, 0);
12564 arg.argc = (argc > 1) ? 1 : 0;
12565 if (!
NIL_P(offset)) {
12569 sarg.offset = offset;
12570 sarg.mode = SEEK_SET;
12571 rb_protect(seek_before_access, (
VALUE)&sarg, &state);
12574 rb_jump_tag(state);
12581io_s_write0(
VALUE v)
12584 return io_write(arg->io,arg->str,arg->nosync);
12588io_s_write(
int argc,
VALUE *argv,
VALUE klass,
int binary)
12590 VALUE string, offset, opt;
12594 rb_scan_args(argc, argv,
"21:", NULL, &
string, &offset, &opt);
12596 if (
NIL_P(opt)) opt = rb_hash_new();
12597 else opt = rb_hash_dup(opt);
12600 if (
NIL_P(rb_hash_aref(opt,sym_mode))) {
12601 int mode = O_WRONLY|O_CREAT;
12603 if (binary) mode |= O_BINARY;
12605 if (
NIL_P(offset)) mode |= O_TRUNC;
12606 rb_hash_aset(opt,sym_mode,
INT2NUM(mode));
12608 open_key_args(klass, argc, argv, opt, &arg);
12611 if (binary) rb_io_binmode_m(arg.io);
12615 if (!
NIL_P(offset)) {
12619 sarg.offset = offset;
12620 sarg.mode = SEEK_SET;
12621 rb_protect(seek_before_access, (
VALUE)&sarg, &state);
12624 rb_jump_tag(state);
12632 return rb_ensure(io_s_write0, (
VALUE)&warg, rb_io_close, arg.io);
12690rb_io_s_write(
int argc,
VALUE *argv,
VALUE io)
12692 return io_s_write(argc, argv, io, 0);
12705rb_io_s_binwrite(
int argc,
VALUE *argv,
VALUE io)
12707 return io_s_write(argc, argv, io, 1);
12713 rb_off_t copy_length;
12714 rb_off_t src_offset;
12718 unsigned close_src : 1;
12719 unsigned close_dst : 1;
12722 const char *syserr;
12723 const char *notimp;
12725 struct stat src_stat;
12726 struct stat dst_stat;
12727#ifdef HAVE_FCOPYFILE
12728 copyfile_state_t copyfile_state;
12733exec_interrupts(
void *arg)
12736 rb_thread_execute_interrupts(th);
12750#if defined(ERESTART)
12755 rb_thread_execute_interrupts(stp->th);
12774fiber_scheduler_wait_for(
void * _arguments)
12784# define IOWAIT_SYSCALL "poll"
12785STATIC_ASSERT(pollin_expected, POLLIN == RB_WAITFD_IN);
12786STATIC_ASSERT(pollout_expected, POLLOUT == RB_WAITFD_OUT);
12791 if (scheduler !=
Qnil) {
12794 return RTEST(args.result);
12798 if (fd == -1)
return 0;
12803 fds.events = events;
12805 int timeout_milliseconds = -1;
12808 timeout_milliseconds = (int)(timeout->tv_sec * 1000) + (int)(timeout->tv_usec / 1000);
12811 return poll(&fds, 1, timeout_milliseconds);
12814# define IOWAIT_SYSCALL "select"
12819 if (scheduler !=
Qnil) {
12822 return RTEST(args.result);
12842 case RB_WAITFD_OUT:
12846 VM_UNREACHABLE(nogvl_wait_for);
12866 ret = nogvl_wait_for(stp->th, stp->src_fptr, RB_WAITFD_IN, NULL);
12868 }
while (ret < 0 && maygvl_copy_stream_continue_p(has_gvl, stp));
12871 stp->syserr = IOWAIT_SYSCALL;
12872 stp->error_no =
errno;
12884 ret = nogvl_wait_for(stp->th, stp->dst_fptr, RB_WAITFD_OUT, NULL);
12885 }
while (ret < 0 && maygvl_copy_stream_continue_p(0, stp));
12888 stp->syserr = IOWAIT_SYSCALL;
12889 stp->error_no =
errno;
12895#ifdef USE_COPY_FILE_RANGE
12898simple_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)
12900#ifdef HAVE_COPY_FILE_RANGE
12901 return copy_file_range(in_fd, in_offset, out_fd, out_offset, count, flags);
12903 return syscall(__NR_copy_file_range, in_fd, in_offset, out_fd, out_offset, count, flags);
12912 rb_off_t copy_length, src_offset, *src_offset_ptr;
12914 if (!S_ISREG(stp->src_stat.st_mode))
12917 src_size = stp->src_stat.st_size;
12918 src_offset = stp->src_offset;
12919 if (src_offset >= (rb_off_t)0) {
12920 src_offset_ptr = &src_offset;
12923 src_offset_ptr = NULL;
12926 copy_length = stp->copy_length;
12927 if (copy_length < (rb_off_t)0) {
12928 if (src_offset < (rb_off_t)0) {
12929 rb_off_t current_offset;
12931 current_offset = lseek(stp->src_fptr->
fd, 0, SEEK_CUR);
12932 if (current_offset < (rb_off_t)0 &&
errno) {
12933 stp->syserr =
"lseek";
12934 stp->error_no =
errno;
12935 return (
int)current_offset;
12937 copy_length = src_size - current_offset;
12940 copy_length = src_size - src_offset;
12944 retry_copy_file_range:
12945# if SIZEOF_OFF_T > SIZEOF_SIZE_T
12947 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
12949 ss = (ssize_t)copy_length;
12951 ss = simple_copy_file_range(stp->src_fptr->
fd, src_offset_ptr, stp->dst_fptr->
fd, NULL, ss, 0);
12955 if (0 < copy_length) {
12956 goto retry_copy_file_range;
12960 if (maygvl_copy_stream_continue_p(0, stp)) {
12961 goto retry_copy_file_range;
12975#if EWOULDBLOCK != EAGAIN
12979 int ret = nogvl_copy_stream_wait_write(stp);
12980 if (ret < 0)
return ret;
12982 goto retry_copy_file_range;
12986 int flags = fcntl(stp->dst_fptr->
fd, F_GETFL);
12988 if (flags != -1 && flags & O_APPEND) {
12994 stp->syserr =
"copy_file_range";
12995 stp->error_no =
errno;
13002#ifdef HAVE_FCOPYFILE
13006 rb_off_t cur, ss = 0;
13007 const rb_off_t src_offset = stp->src_offset;
13010 if (stp->copy_length >= (rb_off_t)0) {
13015 if (!S_ISREG(stp->src_stat.st_mode))
13018 if (!S_ISREG(stp->dst_stat.st_mode))
13020 if (lseek(stp->dst_fptr->
fd, 0, SEEK_CUR) > (rb_off_t)0)
13022 if (fcntl(stp->dst_fptr->
fd, F_GETFL) & O_APPEND) {
13025 rb_off_t end = lseek(stp->dst_fptr->
fd, 0, SEEK_END);
13026 lseek(stp->dst_fptr->
fd, 0, SEEK_SET);
13027 if (end > (rb_off_t)0)
return 0;
13030 if (src_offset > (rb_off_t)0) {
13035 cur = lseek(stp->src_fptr->
fd, 0, SEEK_CUR);
13036 if (cur < (rb_off_t)0 &&
errno) {
13037 stp->error_no =
errno;
13042 r = lseek(stp->src_fptr->
fd, src_offset, SEEK_SET);
13043 if (r < (rb_off_t)0 &&
errno) {
13044 stp->error_no =
errno;
13049 stp->copyfile_state = copyfile_state_alloc();
13050 ret = fcopyfile(stp->src_fptr->
fd, stp->dst_fptr->
fd, stp->copyfile_state, COPYFILE_DATA);
13051 copyfile_state_get(stp->copyfile_state, COPYFILE_STATE_COPIED, &ss);
13055 if (src_offset > (rb_off_t)0) {
13059 r = lseek(stp->src_fptr->
fd, cur, SEEK_SET);
13060 if (r < (rb_off_t)0 &&
errno) {
13061 stp->error_no =
errno;
13073 stp->syserr =
"fcopyfile";
13074 stp->error_no =
errno;
13081#ifdef HAVE_SENDFILE
13084# define USE_SENDFILE
13086# ifdef HAVE_SYS_SENDFILE_H
13087# include <sys/sendfile.h>
13091simple_sendfile(
int out_fd,
int in_fd, rb_off_t *offset, rb_off_t count)
13093 return sendfile(out_fd, in_fd, offset, (
size_t)count);
13096# elif 0 || defined(__APPLE__)
13100# define USE_SENDFILE
13103simple_sendfile(
int out_fd,
int in_fd, rb_off_t *offset, rb_off_t count)
13106 rb_off_t pos = offset ? *offset : lseek(in_fd, 0, SEEK_CUR);
13109 r = sendfile(in_fd, out_fd, pos, &count, NULL, 0);
13112 r = sendfile(in_fd, out_fd, pos, (
size_t)count, NULL, &sbytes, 0);
13114 if (r != 0 && sbytes == 0)
return r;
13119 lseek(in_fd, sbytes, SEEK_CUR);
13121 return (ssize_t)sbytes;
13134 rb_off_t copy_length;
13135 rb_off_t src_offset;
13138 if (!S_ISREG(stp->src_stat.st_mode))
13141 src_size = stp->src_stat.st_size;
13143 if ((stp->dst_stat.st_mode & S_IFMT) != S_IFSOCK)
13147 src_offset = stp->src_offset;
13148 use_pread = src_offset >= (rb_off_t)0;
13150 copy_length = stp->copy_length;
13151 if (copy_length < (rb_off_t)0) {
13153 copy_length = src_size - src_offset;
13157 cur = lseek(stp->src_fptr->
fd, 0, SEEK_CUR);
13158 if (cur < (rb_off_t)0 &&
errno) {
13159 stp->syserr =
"lseek";
13160 stp->error_no =
errno;
13163 copy_length = src_size - cur;
13168# if SIZEOF_OFF_T > SIZEOF_SIZE_T
13170 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
13172 ss = (ssize_t)copy_length;
13175 ss = simple_sendfile(stp->dst_fptr->
fd, stp->src_fptr->
fd, &src_offset, ss);
13178 ss = simple_sendfile(stp->dst_fptr->
fd, stp->src_fptr->
fd, NULL, ss);
13183 if (0 < copy_length) {
13184 goto retry_sendfile;
13188 if (maygvl_copy_stream_continue_p(0, stp))
13189 goto retry_sendfile;
13202#if EWOULDBLOCK != EAGAIN
13215 ret = maygvl_copy_stream_wait_read(0, stp);
13216 if (ret < 0)
return ret;
13218 ret = nogvl_copy_stream_wait_write(stp);
13219 if (ret < 0)
return ret;
13221 goto retry_sendfile;
13223 stp->syserr =
"sendfile";
13224 stp->error_no =
errno;
13232maygvl_read(
int has_gvl,
rb_io_t *fptr,
void *buf,
size_t count)
13235 return rb_io_read_memory(fptr, buf, count);
13237 return read(fptr->
fd, buf, count);
13241maygvl_copy_stream_read(
int has_gvl,
struct copy_stream_struct *stp,
char *buf,
size_t len, rb_off_t offset)
13245 if (offset < (rb_off_t)0) {
13246 ss = maygvl_read(has_gvl, stp->src_fptr, buf,
len);
13249 ss = pread(stp->src_fptr->
fd, buf,
len, offset);
13255 if (maygvl_copy_stream_continue_p(has_gvl, stp))
13259#if EWOULDBLOCK != EAGAIN
13263 int ret = maygvl_copy_stream_wait_read(has_gvl, stp);
13264 if (ret < 0)
return ret;
13269 stp->notimp =
"pread";
13273 stp->syserr = offset < (rb_off_t)0 ?
"read" :
"pread";
13274 stp->error_no =
errno;
13285 ss = write(stp->dst_fptr->
fd, buf+
off,
len);
13287 if (maygvl_copy_stream_continue_p(0, stp))
13289 if (io_again_p(
errno)) {
13290 int ret = nogvl_copy_stream_wait_write(stp);
13291 if (ret < 0)
return ret;
13294 stp->syserr =
"write";
13295 stp->error_no =
errno;
13312 rb_off_t copy_length;
13313 rb_off_t src_offset;
13317 copy_length = stp->copy_length;
13318 use_eof = copy_length < (rb_off_t)0;
13319 src_offset = stp->src_offset;
13320 use_pread = src_offset >= (rb_off_t)0;
13322 if (use_pread && stp->close_src) {
13325 r = lseek(stp->src_fptr->
fd, src_offset, SEEK_SET);
13326 if (r < (rb_off_t)0 &&
errno) {
13327 stp->syserr =
"lseek";
13328 stp->error_no =
errno;
13331 src_offset = (rb_off_t)-1;
13335 while (use_eof || 0 < copy_length) {
13336 if (!use_eof && copy_length < (rb_off_t)
sizeof(buf)) {
13337 len = (size_t)copy_length;
13343 ss = maygvl_copy_stream_read(0, stp, buf,
len, src_offset);
13348 ss = maygvl_copy_stream_read(0, stp, buf,
len, (rb_off_t)-1);
13353 ret = nogvl_copy_stream_write(stp, buf, ss);
13363nogvl_copy_stream_func(
void *arg)
13366#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13370#ifdef USE_COPY_FILE_RANGE
13371 ret = nogvl_copy_file_range(stp);
13376#ifdef HAVE_FCOPYFILE
13377 ret = nogvl_fcopyfile(stp);
13383 ret = nogvl_copy_stream_sendfile(stp);
13388 nogvl_copy_stream_read_write(stp);
13390#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13397copy_stream_fallback_body(
VALUE arg)
13400 const int buflen = 16*1024;
13403 rb_off_t rest = stp->copy_length;
13404 rb_off_t
off = stp->src_offset;
13405 ID read_method = id_readpartial;
13407 if (!stp->src_fptr) {
13409 read_method = id_read;
13416 rb_str_make_independent(buf);
13417 if (stp->copy_length < (rb_off_t)0) {
13422 rb_str_resize(buf, 0);
13425 l = buflen < rest ? buflen : (
rb_len_t)rest;
13427 if (!stp->src_fptr) {
13430 if (read_method == id_read &&
NIL_P(rc))
13435 rb_str_resize(buf, buflen);
13436 ss = maygvl_copy_stream_read(1, stp, RSTRING_PTR(buf), l,
off);
13437 rb_str_resize(buf, ss > 0 ? ss : 0);
13442 if (
off >= (rb_off_t)0)
13445 n = rb_io_write(stp->dst, buf);
13447 stp->total += numwrote;
13449 if (read_method == id_read && RSTRING_LEN(buf) == 0) {
13460 if (!stp->src_fptr && stp->src_offset >= (rb_off_t)0) {
13461 rb_raise(rb_eArgError,
"cannot specify src_offset for non-IO");
13470copy_stream_body(
VALUE arg)
13473 VALUE src_io = stp->src, dst_io = stp->dst;
13474 const int common_oflags = 0
13484 if (src_io ==
argf ||
13488 stp->src_fptr = NULL;
13493 if (!
NIL_P(tmp_io)) {
13500 args[1] =
INT2NUM(O_RDONLY|common_oflags);
13503 stp->close_src = 1;
13508 stat_ret = fstat(stp->src_fptr->
fd, &stp->src_stat);
13509 if (stat_ret < 0) {
13510 stp->syserr =
"fstat";
13511 stp->error_no =
errno;
13516 if (dst_io ==
argf ||
13520 stp->dst_fptr = NULL;
13525 if (!
NIL_P(tmp_io)) {
13526 dst_io = GetWriteIO(tmp_io);
13532 args[1] =
INT2NUM(O_WRONLY|O_CREAT|O_TRUNC|common_oflags);
13536 stp->close_dst = 1;
13539 dst_io = GetWriteIO(dst_io);
13545 stat_ret = fstat(stp->dst_fptr->
fd, &stp->dst_stat);
13546 if (stat_ret < 0) {
13547 stp->syserr =
"fstat";
13548 stp->error_no =
errno;
13555 SET_BINARY_MODE_WITH_SEEK_CUR(stp->src_fptr);
13558 io_ascii8bit_binmode(stp->dst_fptr);
13560 if (stp->src_offset < (rb_off_t)0 && stp->src_fptr && stp->src_fptr->
rbuf.
len) {
13563 if (stp->copy_length >= (rb_off_t)0 && stp->copy_length < (rb_off_t)
len) {
13564 len = (size_t)stp->copy_length;
13567 rb_str_resize(str,
len);
13568 read_buffered_data(RSTRING_PTR(str),
len, stp->src_fptr);
13569 if (stp->dst_fptr) {
13570 if (io_binwrite(RSTRING_PTR(str), RSTRING_LEN(str), stp->dst_fptr, 0) < 0)
13571 rb_sys_fail_on_write(stp->dst_fptr);
13574 rb_io_write(dst_io, str);
13575 rb_str_resize(str, 0);
13577 if (stp->copy_length >= (rb_off_t)0)
13578 stp->copy_length -=
len;
13581 if (stp->dst_fptr && io_fflush(stp->dst_fptr) < 0) {
13585 if (stp->copy_length == 0)
13588 if (stp->src_fptr == NULL || stp->dst_fptr == NULL) {
13589 return copy_stream_fallback(stp);
13592 IO_WITHOUT_GVL(nogvl_copy_stream_func, stp);
13597copy_stream_finalize(
VALUE arg)
13601#ifdef HAVE_FCOPYFILE
13602 if (stp->copyfile_state) {
13603 copyfile_state_free(stp->copyfile_state);
13607 if (stp->close_src) {
13608 rb_io_close_m(stp->src);
13610 if (stp->close_dst) {
13611 rb_io_close_m(stp->dst);
13674rb_io_s_copy_stream(
int argc,
VALUE *argv,
VALUE io)
13676 VALUE src, dst, length, src_offset;
13681 rb_scan_args(argc, argv,
"22", &src, &dst, &length, &src_offset);
13686 st.src_fptr = NULL;
13687 st.dst_fptr = NULL;
13690 st.copy_length = (rb_off_t)-1;
13692 st.copy_length =
NUM2OFFT(length);
13694 if (
NIL_P(src_offset))
13695 st.src_offset = (rb_off_t)-1;
13697 st.src_offset =
NUM2OFFT(src_offset);
13716rb_io_external_encoding(
VALUE io)
13721 return rb_enc_from_encoding(fptr->
encs.
enc2);
13725 return rb_enc_from_encoding(fptr->
encs.
enc);
13728 return rb_enc_from_encoding(io_read_encoding(fptr));
13744rb_io_internal_encoding(
VALUE io)
13749 return rb_enc_from_encoding(io_read_encoding(fptr));
13783rb_io_set_encoding(
int argc,
VALUE *argv,
VALUE io)
13789 return forward(io, id_set_encoding, argc, argv);
13792 argc =
rb_scan_args(argc, argv,
"11:", &v1, &v2, &opt);
13794 io_encoding_set(fptr, v1, v2, opt);
13799rb_stdio_set_default_encoding(
void)
13804 if (isatty(fileno(stdin))) {
13806 rb_encoding *internal = rb_default_internal_encoding();
13807 if (!internal) internal = rb_default_external_encoding();
13809 rb_enc_from_encoding(external),
13810 rb_enc_from_encoding(internal),
13815 rb_io_set_encoding(1, &val,
rb_stdin);
13816 rb_io_set_encoding(1, &val,
rb_stdout);
13817 rb_io_set_encoding(1, &val,
rb_stderr);
13821global_argf_p(
VALUE arg)
13823 return arg ==
argf;
13826typedef VALUE (*argf_encoding_func)(
VALUE io);
13829argf_encoding(
VALUE argf, argf_encoding_func func)
13831 if (!
RTEST(ARGF.current_file)) {
13832 return rb_enc_default_external();
13856 return argf_encoding(
argf, rb_io_external_encoding);
13875 return argf_encoding(
argf, rb_io_internal_encoding);
13914 if (!next_argv()) {
13915 rb_raise(rb_eArgError,
"no stream to set encoding");
13917 rb_io_set_encoding(argc, argv, ARGF.current_file);
13919 ARGF.encs = fptr->
encs;
13939 if (!next_argv()) {
13940 rb_raise(rb_eArgError,
"no stream to tell");
13942 ARGF_FORWARD(0, 0);
13943 return rb_io_tell(ARGF.current_file);
13956 if (!next_argv()) {
13957 rb_raise(rb_eArgError,
"no stream to seek");
13959 ARGF_FORWARD(argc, argv);
13960 return rb_io_seek_m(argc, argv, ARGF.current_file);
13977 if (!next_argv()) {
13978 rb_raise(rb_eArgError,
"no stream to set position");
13980 ARGF_FORWARD(1, &offset);
13981 return rb_io_set_pos(ARGF.current_file, offset);
14002 if (!next_argv()) {
14003 rb_raise(rb_eArgError,
"no stream to rewind");
14005 ARGF_FORWARD(0, 0);
14006 old_lineno =
RFILE(ARGF.current_file)->fptr->lineno;
14007 ret = rb_io_rewind(ARGF.current_file);
14008 if (!global_argf_p(
argf)) {
14009 ARGF.last_lineno = ARGF.lineno -= old_lineno;
14027 if (!next_argv()) {
14028 rb_raise(rb_eArgError,
"no stream");
14030 ARGF_FORWARD(0, 0);
14031 return rb_io_fileno(ARGF.current_file);
14050 ARGF_FORWARD(0, 0);
14051 return ARGF.current_file;
14076 if (
RTEST(ARGF.current_file)) {
14077 if (ARGF.init_p == 0)
return Qtrue;
14079 ARGF_FORWARD(0, 0);
14138 VALUE tmp, str, length;
14142 if (!
NIL_P(length)) {
14147 rb_str_resize(str,0);
14152 if (!next_argv()) {
14155 if (ARGF_GENERIC_INPUT_P()) {
14156 tmp = argf_forward(argc, argv,
argf);
14159 tmp = io_read(argc, argv, ARGF.current_file);
14161 if (
NIL_P(str)) str = tmp;
14164 if (ARGF.next_p != -1) {
14170 else if (argc >= 1) {
14187argf_forward_call(
VALUE arg)
14190 argf_forward(p->argc, p->argv, p->argf);
14220 return argf_getpartial(argc, argv,
argf,
Qnil, 0);
14241 return argf_getpartial(argc, argv,
argf, opts, 1);
14247 VALUE tmp, str, length;
14255 no_exception = no_exception_p(opts);
14257 if (!next_argv()) {
14259 rb_str_resize(str, 0);
14263 if (ARGF_GENERIC_INPUT_P()) {
14273 tmp = io_getpartial(ARGF.current_file, length, str, no_exception, nonblock);
14276 if (ARGF.next_p == -1) {
14277 return io_nonblock_eof(no_exception);
14282 return io_nonblock_eof(no_exception);
14320 if (!next_argv())
return Qnil;
14321 if (ARGF_GENERIC_INPUT_P()) {
14322 ch = forward_current(rb_intern(
"getc"), 0, 0);
14325 ch = rb_io_getc(ARGF.current_file);
14327 if (
NIL_P(ch) && ARGF.next_p != -1) {
14360 if (!next_argv())
return Qnil;
14362 ch = forward_current(rb_intern(
"getbyte"), 0, 0);
14367 if (
NIL_P(ch) && ARGF.next_p != -1) {
14400 if (!next_argv()) rb_eof_error();
14402 ch = forward_current(rb_intern(
"getc"), 0, 0);
14405 ch = rb_io_getc(ARGF.current_file);
14407 if (
NIL_P(ch) && ARGF.next_p != -1) {
14439 NEXT_ARGF_FORWARD(0, 0);
14440 c = argf_getbyte(
argf);
14447#define FOREACH_ARGF() while (next_argv())
14452 const VALUE current = ARGF.current_file;
14454 if (ARGF.init_p == -1 || current != ARGF.current_file) {
14460#define ARGF_block_call(mid, argc, argv, func, argf) \
14461 rb_block_call_kw(ARGF.current_file, mid, argc, argv, \
14462 func, argf, rb_keyword_given_p())
14467 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_i,
argf);
14468 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14474 if (!global_argf_p(
argf)) {
14475 ARGF.last_lineno = ++ARGF.lineno;
14477 return argf_block_call_i(i,
argf, argc, argv, blockarg);
14483 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_line_i,
argf);
14484 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14532 argf_block_call_line(rb_intern(
"each_line"), argc, argv,
argf);
14563 argf_block_call(rb_intern(
"each_byte"), 0, 0,
argf);
14589 argf_block_call(rb_intern(
"each_char"), 0, 0,
argf);
14615 argf_block_call(rb_intern(
"each_codepoint"), 0, 0,
argf);
14646 return ARGF.filename;
14650argf_filename_getter(
ID id,
VALUE *var)
14652 return argf_filename(*var);
14677 return ARGF.current_file;
14696 ARGF_FORWARD(0, 0);
14717 return RBOOL(ARGF.binmode);
14737 if (ARGF.init_p && ARGF.next_p == 0) {
14766 if (ARGF.next_p != -1) {
14784 ARGF_FORWARD(0, 0);
14811 if (!ARGF.inplace)
return Qnil;
14819 return argf_inplace_mode_get(*var);
14850 ARGF.inplace =
Qnil;
14861 argf_inplace_mode_set(*var, val);
14865ruby_set_inplace_mode(
const char *suffix)
14891argf_argv_getter(
ID id,
VALUE *var)
14893 return argf_argv(*var);
14912 if (!
RTEST(ARGF.current_file)) {
14915 return GetWriteIO(ARGF.current_file);
14927 return rb_io_writev(argf_write_io(
argf), argc, argv);
14942 case RB_IO_WAIT_WRITABLE:
14945 c = rb_eEAGAINWaitWritable;
14947#if EAGAIN != EWOULDBLOCK
14949 c = rb_eEWOULDBLOCKWaitWritable;
14953 c = rb_eEINPROGRESSWaitWritable;
14959 case RB_IO_WAIT_READABLE:
14962 c = rb_eEAGAINWaitReadable;
14964#if EAGAIN != EWOULDBLOCK
14966 c = rb_eEWOULDBLOCKWaitReadable;
14970 c = rb_eEINPROGRESSWaitReadable;
14977 rb_bug(
"invalid read/write type passed to rb_readwrite_sys_fail: %d", waiting);
14983get_LAST_READ_LINE(
ID _x,
VALUE *_y)
15873#include <sys/cygwin.h>
15874 static struct __cygwin_perfile pf[] =
15876 {
"", O_RDONLY | O_BINARY},
15877 {
"", O_WRONLY | O_BINARY},
15878 {
"", O_RDWR | O_BINARY},
15879 {
"", O_APPEND | O_BINARY},
15882 cygwin_internal(CW_PERFILE, pf);
15931 rb_eEAGAINWaitReadable = rb_define_class_under(
rb_cIO,
"EAGAINWaitReadable", rb_eEAGAIN);
15934 rb_eEAGAINWaitWritable = rb_define_class_under(
rb_cIO,
"EAGAINWaitWritable", rb_eEAGAIN);
15936#if EAGAIN == EWOULDBLOCK
15938 rb_define_const(
rb_cIO,
"EWOULDBLOCKWaitReadable", rb_eEAGAINWaitReadable);
15940 rb_define_const(
rb_cIO,
"EWOULDBLOCKWaitWritable", rb_eEAGAINWaitWritable);
15943 rb_eEWOULDBLOCKWaitReadable = rb_define_class_under(
rb_cIO,
"EWOULDBLOCKWaitReadable", rb_eEWOULDBLOCK);
15946 rb_eEWOULDBLOCKWaitWritable = rb_define_class_under(
rb_cIO,
"EWOULDBLOCKWaitWritable", rb_eEWOULDBLOCK);
15950 rb_eEINPROGRESSWaitReadable = rb_define_class_under(
rb_cIO,
"EINPROGRESSWaitReadable", rb_eEINPROGRESS);
15953 rb_eEINPROGRESSWaitWritable = rb_define_class_under(
rb_cIO,
"EINPROGRESSWaitWritable", rb_eEINPROGRESS);
15988 rb_gvar_ractor_local(
"$/");
15990 rb_gvar_ractor_local(
"$-0");
15994 rb_gvar_ractor_local(
"$_");
15995 rb_gvar_box_dynamic(
"$_");
16111 rb_gvar_ractor_local(
"$stdin");
16112 rb_gvar_ractor_local(
"$stdout");
16113 rb_gvar_ractor_local(
"$>");
16114 rb_gvar_ractor_local(
"$stderr");
16116 rb_gvar_box_dynamic(
"$stdin");
16117 rb_gvar_box_dynamic(
"$stdout");
16118 rb_gvar_box_dynamic(
"$>");
16119 rb_gvar_box_dynamic(
"$stderr");
16140 rb_cARGF = rb_define_class(
"ARGF",
rb_cObject);
16205 rb_define_method(rb_cARGF,
"external_encoding", argf_external_encoding, 0);
16206 rb_define_method(rb_cARGF,
"internal_encoding", argf_internal_encoding, 0);
16225 rb_gvar_ractor_local(
"$-i");
16229#if defined (_WIN32) || defined(__CYGWIN__)
16230 atexit(pipe_atexit);
16242 sym_encoding =
ID2SYM(rb_id_encoding());
16266static void init_builtin_io(
void);
16267#define Init_builtin_io init_builtin_io
16269#undef Init_builtin_io
16272Init_builtin_io(
void)
#define RUBY_ASSERT(...)
Asserts that the given expression is truthy if and only if RUBY_DEBUG is truthy.
std::atomic< unsigned > rb_atomic_t
Type that is eligible for atomic operations.
unsigned long ruby_strtoul(const char *str, char **endptr, int base)
Our own locale-insensitive version of strtoul(3).
#define rb_define_method(klass, mid, func, arity)
Defines klass#mid.
#define rb_define_singleton_method(klass, mid, func, arity)
Defines klass.mid.
#define rb_define_global_function(mid, func, arity)
Defines rb_mKernel #mid.
void rb_include_module(VALUE klass, VALUE module)
Includes a module to a class.
VALUE rb_class_new(VALUE super)
Creates a new, anonymous class.
void rb_define_alias(VALUE klass, const char *name1, const char *name2)
Defines an alias of a method.
int rb_scan_args_kw(int kw_flag, int argc, const VALUE *argv, const char *fmt,...)
Identical to rb_scan_args(), except it also accepts kw_splat.
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Retrieves argument from argc and argv to given VALUE references according to the format string.
int rb_block_given_p(void)
Determines if the current method is given a block.
int rb_get_kwargs(VALUE keyword_hash, const ID *table, int required, int optional, VALUE *values)
Keyword argument deconstructor.
#define ECONV_AFTER_OUTPUT
Old name of RUBY_ECONV_AFTER_OUTPUT.
#define rb_str_new2
Old name of rb_str_new_cstr.
#define TYPE(_)
Old name of rb_type.
#define RB_INTEGER_TYPE_P
Old name of rb_integer_type_p.
#define ENC_CODERANGE_7BIT
Old name of RUBY_ENC_CODERANGE_7BIT.
#define T_FILE
Old name of RUBY_T_FILE.
#define ENC_CODERANGE_VALID
Old name of RUBY_ENC_CODERANGE_VALID.
#define ECONV_UNIVERSAL_NEWLINE_DECORATOR
Old name of RUBY_ECONV_UNIVERSAL_NEWLINE_DECORATOR.
#define REALLOC_N
Old name of RB_REALLOC_N.
#define OBJ_INIT_COPY(obj, orig)
Old name of RB_OBJ_INIT_COPY.
#define ALLOC
Old name of RB_ALLOC.
#define RFLOAT_VALUE
Old name of rb_float_value.
#define T_STRING
Old name of RUBY_T_STRING.
#define Qundef
Old name of RUBY_Qundef.
#define INT2FIX
Old name of RB_INT2FIX.
#define LEN2NUM
Old name of RB_LEN2NUM.
#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 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 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 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 NUM2LEN
Old name of RB_NUM2LEN.
#define ECONV_NEWLINE_DECORATOR_MASK
Old name of RUBY_ECONV_NEWLINE_DECORATOR_MASK.
#define CONST_ID
Old name of RUBY_CONST_ID.
#define rb_ary_new2
Old name of rb_ary_new_capa.
#define NUM2SIZET
Old name of RB_NUM2SIZE.
#define ENC_CODERANGE_SET(obj, cr)
Old name of RB_ENC_CODERANGE_SET.
#define rb_str_new4
Old name of rb_str_new_frozen.
#define ALLOCV_END
Old name of RB_ALLOCV_END.
#define SYMBOL_P
Old name of RB_SYMBOL_P.
#define ECONV_DEFAULT_NEWLINE_DECORATOR
Old name of RUBY_ECONV_DEFAULT_NEWLINE_DECORATOR.
void rb_category_warn(rb_warning_category_t category, const char *fmt,...)
Identical to rb_category_warning(), except it reports unless $VERBOSE is nil.
void rb_category_warning(rb_warning_category_t category, const char *fmt,...)
Identical to rb_warning(), except it takes additional "category" parameter.
VALUE rb_eNotImpError
NotImplementedError exception.
void rb_exc_raise(VALUE mesg)
Raises an exception in the current thread.
void rb_syserr_fail(int e, const char *mesg)
Raises appropriate exception that represents a C errno.
void rb_readwrite_syserr_fail(enum rb_io_wait_readwrite waiting, int n, const char *mesg)
Identical to rb_readwrite_sys_fail(), except it does not depend on C global variable errno.
VALUE rb_eIOError
IOError exception.
VALUE rb_eStandardError
StandardError exception.
void rb_mod_syserr_fail_str(VALUE mod, int e, VALUE mesg)
Identical to rb_mod_syserr_fail(), except it takes the message in Ruby's String instead of C's.
void rb_syserr_fail_str(int e, VALUE mesg)
Identical to rb_syserr_fail(), except it takes the message in Ruby's String instead of C's.
#define ruby_verbose
This variable controls whether the interpreter is in debug mode.
VALUE rb_eTypeError
TypeError exception.
VALUE rb_eEOFError
EOFError exception.
void rb_readwrite_sys_fail(enum rb_io_wait_readwrite waiting, const char *mesg)
Raises appropriate exception using the parameters.
void rb_iter_break_value(VALUE val)
Identical to rb_iter_break(), except it additionally takes the "value" of this breakage.
rb_io_wait_readwrite
for rb_readwrite_sys_fail first argument
VALUE rb_eRuntimeError
RuntimeError exception.
void rb_warn(const char *fmt,...)
Identical to rb_warning(), except it reports unless $VERBOSE is nil.
VALUE rb_eSystemCallError
SystemCallError exception.
@ RB_WARN_CATEGORY_DEPRECATED
Warning is for deprecated features.
VALUE rb_mKernel
Kernel module.
VALUE rb_check_to_int(VALUE val)
Identical to rb_check_to_integer(), except it uses #to_int for conversion.
VALUE rb_cObject
Object class.
VALUE rb_any_to_s(VALUE obj)
Generates a textual representation of the given object.
VALUE rb_obj_alloc(VALUE klass)
Allocates an instance of the given class.
VALUE rb_class_new_instance(int argc, const VALUE *argv, VALUE klass)
Allocates, then initialises an instance of the given class.
VALUE rb_class_new_instance_kw(int argc, const VALUE *argv, VALUE klass, int kw_splat)
Identical to rb_class_new_instance(), except you can specify how to handle the last element of the gi...
VALUE rb_mEnumerable
Enumerable module.
VALUE rb_stdin
STDIN constant.
VALUE rb_stderr
STDERR constant.
VALUE rb_obj_class(VALUE obj)
Queries the class of an object.
VALUE rb_obj_dup(VALUE obj)
Duplicates the given object.
VALUE rb_inspect(VALUE obj)
Generates a human-readable textual representation of the given object.
VALUE rb_mWaitReadable
IO::WaitReadable module.
VALUE rb_mWaitWritable
IO::WaitReadable module.
VALUE rb_obj_freeze(VALUE obj)
Same as RB_OBJ_FREEZE(), but returns the given object.
VALUE rb_check_to_integer(VALUE val, const char *mid)
Identical to rb_check_convert_type(), except the return value type is fixed to rb_cInteger.
VALUE rb_cFile
File class.
VALUE rb_stdout
STDOUT constant.
VALUE rb_to_int(VALUE val)
Identical to rb_check_to_int(), except it raises in case of conversion mismatch.
#define RB_OBJ_WRITTEN(old, oldv, young)
Identical to RB_OBJ_WRITE(), except it doesn't write any values, but only a WB declaration.
#define RB_OBJ_WRITE(old, slot, young)
Declaration of a "back" pointer.
VALUE rb_fiber_scheduler_current(void)
Identical to rb_fiber_scheduler_get(), except it also returns RUBY_Qnil in case of a blocking fiber.
VALUE rb_fiber_scheduler_make_timeout(struct timeval *timeout)
Converts the passed timeout to an expression that rb_fiber_scheduler_block() etc.
VALUE rb_fiber_scheduler_io_wait_readable(VALUE scheduler, VALUE io)
Non-blocking wait until the passed IO is ready for reading.
VALUE rb_fiber_scheduler_io_wait(VALUE scheduler, VALUE io, VALUE events, VALUE timeout)
Non-blocking version of rb_io_wait().
static ssize_t rb_fiber_scheduler_io_result_apply(VALUE result)
Apply an io result to the local thread, returning the value of the original system call that created ...
VALUE rb_fiber_scheduler_io_pread_memory(VALUE scheduler, VALUE io, rb_off_t from, void *base, size_t size)
Non-blocking pread from the passed IO using a native buffer.
VALUE rb_fiber_scheduler_io_selectv(VALUE scheduler, int argc, VALUE *argv)
Non-blocking version of IO.select, argv variant.
VALUE rb_fiber_scheduler_io_read_memory(VALUE scheduler, VALUE io, void *base, size_t size)
Non-blocking read from the passed IO using a native buffer.
VALUE rb_fiber_scheduler_current_for_thread(VALUE thread)
Identical to rb_fiber_scheduler_current(), except it queries for that of the passed thread value inst...
VALUE rb_fiber_scheduler_io_pwrite_memory(VALUE scheduler, VALUE io, rb_off_t from, const void *base, size_t size)
Non-blocking pwrite to the passed IO using a native buffer.
VALUE rb_fiber_scheduler_current_for_threadptr(struct rb_thread_struct *thread)
Identical to rb_fiber_scheduler_current_for_thread(), except it expects a threadptr instead of a thre...
VALUE rb_fiber_scheduler_io_wait_writable(VALUE scheduler, VALUE io)
Non-blocking wait until the passed IO is ready for writing.
VALUE rb_fiber_scheduler_io_close(VALUE scheduler, VALUE io)
Non-blocking close the given IO.
VALUE rb_fiber_scheduler_io_write_memory(VALUE scheduler, VALUE io, const void *base, size_t size)
Non-blocking write to the passed IO using a native buffer.
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.
static int rb_enc_mbmaxlen(rb_encoding *enc)
Queries the maximum number of bytes that the passed encoding needs to represent a character.
VALUE rb_str_conv_enc(VALUE str, rb_encoding *from, rb_encoding *to)
Encoding conversion main routine.
rb_len_t 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.
VALUE rb_enc_uint_chr(unsigned int code, rb_encoding *enc)
Encodes the passed code point into a series of bytes.
int rb_econv_prepare_options(VALUE opthash, VALUE *ecopts, int ecflags)
Identical to rb_econv_prepare_opts(), except it additionally takes the initial value of flags.
VALUE rb_econv_open_exc(const char *senc, const char *denc, int ecflags)
Creates a rb_eConverterNotFoundError exception object (but does not raise).
rb_econv_result_t rb_econv_convert(rb_econv_t *ec, const unsigned char **source_buffer_ptr, const unsigned char *source_buffer_end, unsigned char **destination_buffer_ptr, unsigned char *destination_buffer_end, int flags)
Converts a string from an encoding to another.
rb_econv_result_t
return value of rb_econv_convert()
@ econv_incomplete_input
The conversion stopped in middle of reading a character, possibly due to a partial read of a socket e...
@ econv_finished
The conversion stopped after converting everything.
@ econv_undefined_conversion
The conversion stopped when it found a character in the input which cannot be representable in the ou...
@ econv_source_buffer_empty
The conversion stopped because there is no input.
@ econv_destination_buffer_full
The conversion stopped because there is no destination.
@ econv_invalid_byte_sequence
The conversion stopped when it found an invalid sequence.
int rb_econv_putbackable(rb_econv_t *ec)
Queries if rb_econv_putback() makes sense, i.e.
const char * rb_econv_asciicompat_encoding(const char *encname)
Queries the passed encoding's corresponding ASCII compatible encoding.
VALUE rb_econv_str_convert(rb_econv_t *ec, VALUE src, int flags)
Identical to rb_econv_convert(), except it takes Ruby's string instead of C's pointer.
rb_econv_t * rb_econv_open_opts(const char *source_encoding, const char *destination_encoding, int ecflags, VALUE ecopts)
Identical to rb_econv_open(), except it additionally takes a hash of optional strings.
void rb_econv_binmode(rb_econv_t *ec)
This badly named function does not set the destination encoding to binary, but instead just nullifies...
VALUE rb_str_encode(VALUE str, VALUE to, int ecflags, VALUE ecopts)
Converts the contents of the passed string from its encoding to the passed one.
VALUE rb_econv_make_exception(rb_econv_t *ec)
This function makes sense right after rb_econv_convert() returns.
void rb_econv_check_error(rb_econv_t *ec)
This is a rb_econv_make_exception() + rb_exc_raise() combo.
void rb_econv_close(rb_econv_t *ec)
Destructs a converter.
void rb_econv_putback(rb_econv_t *ec, unsigned char *p, int n)
Puts back the bytes.
VALUE rb_funcall(VALUE recv, ID mid, int n,...)
Calls a method.
VALUE rb_funcallv_kw(VALUE recv, ID mid, int argc, const VALUE *argv, int kw_splat)
Identical to rb_funcallv(), except you can specify how to handle the last element of the given array.
VALUE rb_funcallv(VALUE recv, ID mid, int argc, const VALUE *argv)
Identical to rb_funcall(), except it takes the method arguments as a C array.
Defines RBIMPL_HAS_BUILTIN.
VALUE rb_ary_concat(VALUE lhs, VALUE rhs)
Destructively appends the contents of latter into the end of former.
VALUE rb_ary_shift(VALUE ary)
Destructively deletes an element from the beginning of the passed array and returns what was deleted.
VALUE rb_ary_entry(VALUE ary, rb_len_t off)
Queries an element of an array.
VALUE rb_ary_new_capa(rb_len_t capa)
Identical to rb_ary_new(), except it additionally specifies how many rooms of objects it should alloc...
VALUE rb_check_array_type(VALUE obj)
Try converting an object to its array representation using its to_ary method, if any.
VALUE rb_ary_new(void)
Allocates a new, empty array.
VALUE rb_ary_push(VALUE ary, VALUE elem)
Special case of rb_ary_cat() that it adds only one element.
VALUE rb_assoc_new(VALUE car, VALUE cdr)
Identical to rb_ary_new_from_values(), except it expects exactly two parameters.
#define RETURN_ENUMERATOR(obj, argc, argv)
Identical to RETURN_SIZED_ENUMERATOR(), except its size is unknown.
static int rb_check_arity(int argc, int min, int max)
Ensures that the passed integer is in the passed range.
VALUE rb_io_printf(int argc, const VALUE *argv, VALUE io)
This is a rb_f_sprintf() + rb_io_write() combo.
VALUE rb_io_gets(VALUE io)
Reads a "line" from the given IO.
int rb_cloexec_pipe(int fildes[2])
Opens a pipe with closing on exec.
VALUE rb_io_print(int argc, const VALUE *argv, VALUE io)
Iterates over the passed array to apply rb_io_write() individually.
VALUE rb_io_addstr(VALUE io, VALUE str)
Identical to rb_io_write(), except it always returns the passed IO.
void rb_write_error2(const char *str, rb_len_t len)
Identical to rb_write_error(), except it additionally takes the message's length.
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_close_before_exec(int lowfd, int maxhint, VALUE noclose_fds)
Closes everything.
int rb_reserved_fd_p(int fd)
Queries if the given FD is reserved or not.
void rb_fd_fix_cloexec(int fd)
Sets or clears the close-on-exec flag of the passed file descriptor to the desired state.
VALUE rb_io_ascii8bit_binmode(VALUE io)
Forces no conversions be applied to the passed IO.
VALUE rb_io_binmode(VALUE io)
Sets the binmode.
VALUE rb_io_ungetc(VALUE io, VALUE c)
"Unget"s a string.
int rb_pipe(int *pipes)
This is an rb_cloexec_pipe() + rb_update_max_fd() combo.
VALUE rb_gets(void)
Much like rb_io_gets(), but it reads from the mysterious ARGF object.
int rb_cloexec_fcntl_dupfd(int fd, int minfd)
Duplicates a file descriptor with closing on exec.
VALUE rb_output_fs
The field separator character for outputs, or the $,.
VALUE rb_file_open_str(VALUE fname, const char *fmode)
Identical to rb_file_open(), except it takes the pathname as a Ruby's string instead of C's.
int rb_cloexec_dup(int oldfd)
Identical to rb_cloexec_fcntl_dupfd(), except it implies minfd is 3.
VALUE rb_file_open(const char *fname, const char *fmode)
Opens a file located at the given path.
VALUE rb_io_close(VALUE io)
Closes the IO.
VALUE rb_default_rs
This is the default value of rb_rs, i.e.
void rb_provide(const char *feature)
Declares that the given feature is already provided by someone else.
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 $?.
void rb_str_modify_expand(VALUE str, rb_len_t capa)
Identical to rb_str_modify(), except it additionally expands the capacity of the receiver.
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.
void rb_str_set_len(VALUE str, rb_len_t len)
Overwrites the length of the string.
VALUE rb_str_dup(VALUE str)
Duplicates a string.
VALUE rb_str_cat(VALUE dst, const char *src, rb_len_t srclen)
Destructively appends the passed contents to the string.
VALUE rb_str_locktmp(VALUE str)
Obtains a "temporary lock" of the string.
VALUE rb_str_no_gvl_safe_acquire(VALUE orig)
Creates a frozen copy of orig that guarantees the RSTRING_PTR is safe to use in operations that relea...
VALUE rb_str_equal(VALUE str1, VALUE str2)
Equality of two strings.
void rb_str_no_gvl_safe_release(VALUE orig, VALUE tmp)
Releases a string created from rb_str_no_gvl_safe_acquire.
VALUE rb_str_substr(VALUE str, rb_len_t beg, rb_len_t len)
This is the implementation of two-argumented String#slice.
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_str_buf_new(rb_len_t capa)
Allocates a "string buffer".
VALUE rb_check_string_type(VALUE obj)
Try converting an object to its stringised representation using its to_str method,...
VALUE rb_str_unlocktmp(VALUE str)
Releases a lock formerly obtained by rb_str_locktmp().
#define rb_str_new_cstr(str)
Identical to rb_str_new, except it assumes the passed pointer is a pointer to a C string.
VALUE rb_obj_as_string(VALUE obj)
Try converting an object to its stringised representation using its to_s method, if any.
int rb_thread_interrupted(VALUE thval)
Checks if the thread's execution was recently interrupted.
VALUE rb_mutex_new(void)
Creates a mutex.
int rb_thread_fd_writable(int fd)
Identical to rb_thread_wait_fd(), except it blocks the current thread until the given file descriptor...
VALUE rb_exec_recursive(VALUE(*f)(VALUE g, VALUE h, int r), VALUE g, VALUE h)
"Recursion" API entry point.
VALUE rb_mutex_synchronize(VALUE mutex, VALUE(*func)(VALUE arg), VALUE arg)
Obtains the lock, runs the passed function, and releases the lock when it completes.
void rb_thread_check_ints(void)
Checks for interrupts.
VALUE rb_thread_current(void)
Obtains the "current" thread.
int rb_thread_wait_fd(int fd)
Blocks the current thread until the given file descriptor is ready to be read.
void rb_thread_sleep(int sec)
Blocks for the given period of time.
struct timeval rb_time_interval(VALUE num)
Creates a "time interval".
void rb_set_class_path(VALUE klass, VALUE space, const char *name)
Names a class.
VALUE rb_ivar_set(VALUE obj, ID name, VALUE val)
Identical to rb_iv_set(), except it accepts the name as an ID instead of a C string.
VALUE rb_class_name(VALUE obj)
Queries the name of the given object's class.
int rb_respond_to(VALUE obj, ID mid)
Queries if the object responds to the method.
int rb_method_basic_definition_p(VALUE klass, ID mid)
Well... Let us hesitate from describing what a "basic definition" is.
VALUE rb_check_funcall(VALUE recv, ID mid, int argc, const VALUE *argv)
Identical to rb_funcallv(), except it returns RUBY_Qundef instead of raising rb_eNoMethodError.
void rb_define_alloc_func(VALUE klass, rb_alloc_func_t func)
Sets the allocator function of a class.
static ID rb_intern_const(const char *str)
This is a "tiny optimisation" over rb_intern().
#define RB_ID2SYM
Just another name of rb_id2sym.
void rb_define_global_const(const char *name, VALUE val)
Identical to rb_define_const(), except it defines that of "global", i.e.
void rb_define_readonly_variable(const char *name, const VALUE *var)
Identical to rb_define_variable(), except it does not allow Ruby programs to assign values to such gl...
rb_gvar_setter_t rb_gvar_readonly_setter
This function just raises rb_eNameError.
#define FMODE_READABLE
The IO is opened for reading.
enum rb_io_mode rb_io_modestr_fmode(const char *modestr)
Maps a file mode string (that rb_file_open() takes) into a mixture of FMODE_ flags.
VALUE rb_io_get_io(VALUE io)
Identical to rb_io_check_io(), except it raises exceptions on conversion failures.
VALUE rb_io_timeout(VALUE io)
Get the timeout associated with the specified io object.
VALUE rb_io_taint_check(VALUE obj)
void rb_io_read_check(rb_io_t *fptr)
Blocks until there is a pending read in the passed IO.
int rb_io_modestr_oflags(const char *modestr)
Identical to rb_io_modestr_fmode(), except it returns a mixture of O_ flags.
#define FMODE_SETENC_BY_BOM
This flag amends the encoding of the IO so that the BOM of the contents of the IO takes effect.
rb_io_event
Type of events that an IO can wait.
@ RUBY_IO_READABLE
IO::READABLE
@ RUBY_IO_PRIORITY
IO::PRIORITY
@ RUBY_IO_WRITABLE
IO::WRITABLE
#define FMODE_READWRITE
The IO is opened for both read/write.
#define FMODE_EXTERNAL
This flag means that an IO object is wrapping an "external" file descriptor, which is owned by someth...
#define GetOpenFile
This is an old name of RB_IO_POINTER.
void rb_io_check_byte_readable(rb_io_t *fptr)
Asserts that an IO is opened for byte-based reading.
#define FMODE_TTY
The IO is a TTY.
#define FMODE_CREATE
The IO is opened for creating.
void rb_io_check_readable(rb_io_t *fptr)
Just another name of rb_io_check_byte_readable.
int rb_wait_for_single_fd(int fd, int events, struct timeval *tv)
Blocks until the passed file descriptor is ready for the passed events.
FILE * rb_fdopen(int fd, const char *modestr)
Identical to rb_io_stdio_file(), except it takes file descriptors instead of Ruby's IO.
int rb_io_extract_encoding_option(VALUE opt, rb_encoding **enc_p, rb_encoding **enc2_p, enum rb_io_mode *fmode_p)
This function breaks down the option hash that IO#initialize takes into components.
int rb_io_descriptor(VALUE io)
Returns an integer representing the numeric file descriptor for io.
#define FMODE_WRITABLE
The IO is opened for writing.
FILE * rb_io_stdio_file(rb_io_t *fptr)
Finds or creates a stdio's file structure from a Ruby's one.
#define FMODE_APPEND
The IO is opened for appending.
#define MakeOpenFile
This is an old name of RB_IO_OPEN.
#define FMODE_DUPLEX
Ruby eventually detects that the IO is bidirectional.
#define FMODE_BINMODE
The IO is in "binary mode".
int rb_io_maybe_wait_readable(int error, VALUE io, VALUE timeout)
Blocks until the passed IO is ready for reading, if that makes sense for the passed errno.
int capa
Designed capacity of the buffer.
#define RB_IO_POINTER(obj, fp)
Queries the underlying IO pointer.
VALUE rb_io_maybe_wait(int error, VALUE io, VALUE events, VALUE timeout)
Identical to rb_io_wait() except it additionally takes previous errno.
VALUE rb_eIOTimeoutError
Indicates that a timeout has occurred while performing an IO operation.
char * ptr
Pointer to the underlying memory region, of at least capa bytes.
#define FMODE_SYNC
The IO is in "sync mode".
int off
Offset inside of ptr.
VALUE rb_io_path(VALUE io)
Returns the path for the given IO.
void rb_io_extract_modeenc(VALUE *vmode_p, VALUE *vperm_p, VALUE opthash, int *oflags_p, enum rb_io_mode *fmode_p, rb_io_enc_t *convconfig_p)
This function can be seen as an extended version of rb_io_extract_encoding_option() that not only con...
void rb_io_check_initialized(rb_io_t *fptr)
Asserts that the passed IO is initialised.
#define FMODE_EXCL
This flag amends the effect of FMODE_CREATE, so that if there already is a file at the given path the...
#define FMODE_TEXTMODE
The IO is in "text mode".
int rb_io_fptr_finalize(rb_io_t *fptr)
Destroys the given IO.
VALUE rb_io_check_io(VALUE io)
Try converting an object to its IO representation using its to_io method, if any.
VALUE rb_io_closed_p(VALUE io)
Returns whether or not the underlying IO is closed.
VALUE rb_io_set_timeout(VALUE io, VALUE timeout)
Set the timeout associated with the specified io object.
ssize_t rb_io_bufwrite(VALUE io, const void *buf, size_t size)
Buffered write to the passed IO.
void rb_io_check_char_readable(rb_io_t *fptr)
Asserts that an IO is opened for character-based reading.
#define FMODE_TRUNC
This flag amends the effect of FMODE_CREATE, so that if there already is a file at the given path it ...
VALUE rb_io_get_write_io(VALUE io)
Queries the tied IO for writing.
void rb_io_set_nonblock(rb_io_t *fptr)
Instructs the OS to put its internal file structure into "nonblocking mode".
int rb_io_wait_writable(int fd)
Blocks until the passed file descriptor gets writable.
VALUE rb_io_open_descriptor(VALUE klass, int descriptor, int mode, VALUE path, VALUE timeout, struct rb_io_encoding *encoding)
Allocate a new IO object, with the given file descriptor.
VALUE rb_io_set_write_io(VALUE io, VALUE w)
Assigns the tied IO for writing.
void rb_io_check_writable(rb_io_t *fptr)
Asserts that an IO is opened for writing.
int rb_io_maybe_wait_writable(int error, VALUE io, VALUE timeout)
Blocks until the passed IO is ready for writing, if that makes sense for the passed errno.
void rb_io_check_closed(rb_io_t *fptr)
This badly named function asserts that the passed IO is open.
int rb_io_wait_readable(int fd)
Blocks until the passed file descriptor gets readable.
void rb_io_synchronized(rb_io_t *fptr)
Sets FMODE_SYNC.
VALUE rb_io_wait(VALUE io, VALUE events, VALUE timeout)
Blocks until the passed IO is ready for the passed events.
int len
Length of the buffer.
VALUE rb_ractor_stdin(void)
Queries the standard input of the current Ractor that is calling this function.
void rb_ractor_stderr_set(VALUE io)
Assigns an IO to the standard error of the Ractor that is calling this function.
void rb_ractor_stdout_set(VALUE io)
Assigns an IO to the standard output of the Ractor that is calling this function.
void rb_ractor_stdin_set(VALUE io)
Assigns an IO to the standard input of the Ractor that is calling this function.
void * rb_thread_call_with_gvl(void *(*func)(void *), void *data1)
(Re-)acquires the GVL.
#define RB_NUM2INT
Just another name of rb_num2int_inline.
#define RB_INT2NUM
Just another name of rb_int2num_inline.
VALUE rb_f_sprintf(int argc, const VALUE *argv)
Identical to rb_str_format(), except how the arguments are arranged.
#define RB_BLOCK_CALL_FUNC_ARGLIST(yielded_arg, callback_arg)
Shim for block function parameters.
VALUE rb_yield_values2(int n, const VALUE *argv)
Identical to rb_yield_values(), except it takes the parameters as a C array instead of variadic argum...
VALUE rb_yield(VALUE val)
Yields the block.
void rb_fd_term(rb_fdset_t *f)
Destroys the rb_fdset_t, releasing any memory and resources it used.
#define MEMZERO(p, type, n)
Handy macro to erase a region of memory.
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
#define MEMMOVE(p1, p2, type, n)
Handy macro to call memmove.
#define NUM2MODET
Converts a C's mode_t into an instance of rb_cInteger.
void rb_define_hooked_variable(const char *q, VALUE *w, type *e, void_type *r)
Define a function-backended global variable.
void rb_define_virtual_variable(const char *q, type *w, void_type *e)
Define a function-backended global variable.
VALUE rb_rescue2(type *q, VALUE w, type *e, VALUE r,...)
An equivalent of rescue clause.
VALUE rb_ensure(type *q, VALUE w, type *e, VALUE r)
An equivalent of ensure clause.
#define PRI_OFFT_PREFIX
A rb_sprintf() format prefix to be used for an off_t parameter.
#define OFFT2NUM
Converts a C's off_t into an instance of rb_cInteger.
#define NUM2OFFT
Converts an instance of rb_cNumeric into C's off_t.
#define PIDT2NUM
Converts a C's pid_t into an instance of rb_cInteger.
#define rb_fd_isset
Queries if the given fd is in the rb_fdset_t.
#define rb_fd_select
Waits for multiple file descriptors at once.
#define rb_fd_init
Initialises the :given :rb_fdset_t.
#define rb_fd_set
Sets the given fd to the rb_fdset_t.
#define RARRAY_LEN
Just another name of rb_array_len.
static int RARRAY_LENINT(VALUE ary)
Identical to rb_array_len(), except it differs for the return type.
#define RARRAY_AREF(a, i)
#define RARRAY_CONST_PTR
Just another name of rb_array_const_ptr.
#define RFILE(obj)
Convenient casting macro.
#define StringValue(v)
Ensures that the parameter object is a String.
static char * RSTRING_END(VALUE str)
Queries the end of the contents pointer of the string.
#define RSTRING_GETMEM(str, ptrvar, lenvar)
Convenient macro to obtain the contents and length at once.
#define StringValueCStr(v)
Identical to StringValuePtr, except it additionally checks for the contents for viability as a C stri...
#define RUBY_TYPED_DEFAULT_FREE
This is a value you can set to rb_data_type_struct::dfree.
#define TypedData_Make_Struct(klass, type, data_type, sval)
Identical to TypedData_Wrap_Struct, except it allocates a new data region internally instead of takin...
VALUE rb_get_argv(void)
Queries the arguments passed to the current process that you can access from Ruby as ARGV.
void rb_p(VALUE obj)
Inspects an object.
#define FilePathValue(v)
Ensures that the parameter object is a path.
#define errno
Ractor-aware version of errno.
#define RB_SCAN_ARGS_LAST_HASH_KEYWORDS
Treat a final argument as keywords if it is a hash, and not as keywords otherwise.
#define RB_PASS_CALLED_KEYWORDS
Pass keywords if current method is called with keywords, useful for argument delegation.
int rb_thread_fd_select(int nfds, rb_fdset_t *rfds, rb_fdset_t *wfds, rb_fdset_t *efds, struct timeval *timeout)
Waits for multiple file descriptors at once.
static bool RB_TEST(VALUE obj)
Emulates Ruby's "if" statement.
#define RTEST
This is an old name of RB_TEST.
#define _(args)
This was a transition path from K&R to ANSI.
This is the struct that holds necessary info for a struct.
The data structure which wraps the fd_set bitmap used by select(2).
Decomposed encoding flags (e.g.
VALUE ecopts
Flags as Ruby hash.
rb_encoding * enc2
External encoding.
rb_encoding * enc
Internal encoding.
char * ptr
Pointer to the underlying memory region, of at least capa bytes.
int off
Offset inside of ptr.
int len
Length of the buffer.
int capa
Designed capacity of the buffer.
Ruby's IO, metadata and buffers.
rb_io_buffer_t wbuf
Write buffer.
enum rb_io_mode mode
mode flags: FMODE_XXXs
void(* finalize)(struct rb_io *, int)
finalize proc
rb_econv_t * readconv
Encoding converter used when reading from this IO.
rb_econv_t * writeconv
Encoding converter used when writing to this IO.
struct rb_io_encoding encs
Decomposed encoding flags.
VALUE self
The IO's Ruby level counterpart.
VALUE write_lock
This is a Ruby level mutex.
VALUE timeout
The timeout associated with this IO when performing blocking operations.
FILE * stdio_file
stdio ptr for read/write, if available.
VALUE writeconv_pre_ecopts
Value of ::rb_io_t::rb_io_enc_t::ecopts stored right before initialising rb_io_t::writeconv.
VALUE tied_io_for_writing
Duplex IO object, if set.
int writeconv_initialized
Whether rb_io_t::writeconv is already set up.
rb_io_buffer_t rbuf
(Byte) read buffer.
int lineno
number of lines read
struct ccan_list_head blocking_operations
Threads that are performing a blocking operation without the GVL using this IO.
VALUE writeconv_asciicompat
This is, when set, an instance of rb_cString which holds the "common" encoding.
rb_io_buffer_t cbuf
rb_io_ungetc() destination.
rb_pid_t pid
child's pid (for pipes)
int writeconv_pre_ecflags
Value of ::rb_io_t::rb_io_enc_t::ecflags stored right before initialising rb_io_t::writeconv.
VALUE pathv
pathname for file
long rb_len_t
A signed integer type for lengths and indices of objects such as String and Array.
#define RB_LEN_MAX
Maximum possible value that a rb_len_t can take.
intptr_t SIGNED_VALUE
A signed integer type that has the same width with VALUE.
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
uintptr_t VALUE
Type that represents a Ruby object.
static bool RB_FLOAT_TYPE_P(VALUE obj)
Queries if the object is an instance of rb_cFloat.
static bool RB_SYMBOL_P(VALUE obj)
Queries if the object is an instance of rb_cSymbol.
static void Check_Type(VALUE v, enum ruby_value_type t)
Identical to RB_TYPE_P(), except it raises exceptions on predication failure.
static bool RB_TYPE_P(VALUE obj, enum ruby_value_type t)
Queries if the given object is of given type.
#define RBIMPL_WARNING_IGNORED(flag)
Suppresses a warning.
#define RBIMPL_WARNING_PUSH()
Pushes compiler warning state.
#define RBIMPL_WARNING_POP()
Pops compiler warning state.