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) || defined(_nec_ews)
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>
104# ifndef COPYFILE_STATE_COPIED
110# undef HAVE_FCOPYFILE
116# include <AvailabilityMacros.h>
120#include "ccan/list/list.h"
125#include "internal/class.h"
126#include "internal/encoding.h"
127#include "internal/error.h"
128#include "internal/inits.h"
129#include "internal/io.h"
130#include "internal/numeric.h"
131#include "internal/object.h"
132#include "internal/process.h"
133#include "internal/thread.h"
134#include "internal/transcode.h"
135#include "internal/variable.h"
138#include "ruby/missing.h"
141#include "ruby_atomic.h"
151#define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR)
155# ifdef _POSIX_PIPE_BUF
156# define PIPE_BUF _POSIX_PIPE_BUF
163# define EWOULDBLOCK EAGAIN
166#if defined(HAVE___SYSCALL) && (defined(__APPLE__) || defined(__OpenBSD__))
168off_t __syscall(quad_t number, ...);
171#define IO_RBUF_CAPA_MIN 8192
172#define IO_CBUF_CAPA_MIN (128*1024)
173#define IO_RBUF_CAPA_FOR(fptr) (NEED_READCONV(fptr) ? IO_CBUF_CAPA_MIN : IO_RBUF_CAPA_MIN)
174#define IO_WBUF_CAPA_MIN 8192
176#define IO_MAX_BUFFER_GROWTH 8 * 1024 * 1024
181#define open rb_w32_uopen
183#define rename(f, t) rb_w32_urename((f), (t))
184#include "win32/file.h"
194static VALUE rb_eEAGAINWaitReadable;
195static VALUE rb_eEAGAINWaitWritable;
196#if EAGAIN != EWOULDBLOCK
197static VALUE rb_eEWOULDBLOCKWaitReadable;
198static VALUE rb_eEWOULDBLOCKWaitWritable;
200static VALUE rb_eEINPROGRESSWaitWritable;
201static VALUE rb_eEINPROGRESSWaitReadable;
204static VALUE orig_stdout, orig_stderr;
213static ID id_write, id_read, id_flush, id_readpartial, id_set_encoding, id_fileno;
214static VALUE sym_mode, sym_perm, sym_flags, sym_extenc, sym_intenc, sym_encoding, sym_open_args;
215static VALUE sym_textmode, sym_binmode, sym_autoclose;
216static VALUE sym_SET, sym_CUR, sym_END;
217static VALUE sym_wait_readable, sym_wait_writable;
219static VALUE sym_DATA;
222static VALUE sym_HOLE;
225static VALUE prep_io(
int fd,
enum rb_io_mode fmode,
VALUE klass,
const char *path);
228rb_io_blocking_region_wait(
struct rb_io *io, rb_blocking_function_t *function,
void *argument,
enum rb_io_event events)
230 return rb_thread_io_blocking_call(io, function, argument, events);
233VALUE rb_io_blocking_region(
struct rb_io *io, rb_blocking_function_t *function,
void *argument)
235 return rb_io_blocking_region_wait(io, function, argument, 0);
239 VALUE filename, current_file;
245 int8_t init_p, next_p, binmode;
249#if defined(__APPLE__) && \
250 (!defined(MAC_OS_VERSION_27_0) || (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_VERSION_27_0))
252# if __has_attribute(availability) && __has_warning("-Wunguarded-availability-new")
258static inline int (*rb_dup3(
void))(int, int, int) {
return &dup3;}
259# define dup3 rb_dup3()
263static inline int (*rb_pipe2(
void))(
int [2], int) {
return &pipe2;}
264# define pipe2 rb_pipe2()
289 if (fd < 0 || afd <= max_fd)
292#if defined(HAVE_FCNTL) && defined(F_GETFL)
293 err = fcntl(fd, F_GETFL) == -1;
297 err = fstat(fd, &buf) != 0;
300 if (err &&
errno == EBADF) {
301 rb_bug(
"rb_update_max_fd: invalid fd (%d) given.", fd);
304 while (max_fd < afd) {
305 max_fd = ATOMIC_CAS(max_file_descriptor, max_fd, afd);
310rb_maygvl_fd_fix_cloexec(
int fd)
313#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
314 int flags, flags2, ret;
315 flags = fcntl(fd, F_GETFD);
317 rb_bug(
"rb_maygvl_fd_fix_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(
errno));
320 flags2 = flags & ~FD_CLOEXEC;
322 flags2 = flags | FD_CLOEXEC;
323 if (flags != flags2) {
324 ret = fcntl(fd, F_SETFD, flags2);
326 rb_bug(
"rb_maygvl_fd_fix_cloexec: fcntl(%d, F_SETFD, %d) failed: %s", fd, flags2, strerror(
errno));
335 rb_maygvl_fd_fix_cloexec(fd);
341rb_fix_detect_o_cloexec(
int fd)
343#if defined(O_CLOEXEC) && defined(F_GETFD)
344 int flags = fcntl(fd, F_GETFD);
347 rb_bug(
"rb_fix_detect_o_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(
errno));
349 if (flags & FD_CLOEXEC)
352 rb_maygvl_fd_fix_cloexec(fd);
359 return (e == EWOULDBLOCK) || (e == EAGAIN);
366 static int o_cloexec_state = -1;
368 static const int retry_interval = 0;
369 static const int retry_max_count = 10000;
376#elif defined O_NOINHERIT
377 flags |= O_NOINHERIT;
380 while ((ret = open(pathname, flags, mode)) == -1) {
382 if (!io_again_p(e))
break;
383 if (retry_count++ >= retry_max_count)
break;
385 sleep(retry_interval);
388 if (ret < 0)
return ret;
389 if (ret <= 2 || o_cloexec_state == 0) {
390 rb_maygvl_fd_fix_cloexec(ret);
392 else if (o_cloexec_state > 0) {
396 o_cloexec_state = rb_fix_detect_o_cloexec(ret);
415 if (oldfd == newfd) {
419#if defined(HAVE_DUP3) && defined(O_CLOEXEC)
420# if defined(__APPLE__)
421# define try_dup3 (dup3 != NULL)
422# define abandon_dup3() true
424 static bool try_dup3 =
true;
425# define abandon_dup3() (errno != ENOSYS || !!(try_dup3 = false))
431 ret = dup3(oldfd, newfd, O_CLOEXEC);
438 if (abandon_dup3())
return ret;
441 ret = dup2(oldfd, newfd);
442 if (ret < 0)
return ret;
444 rb_maygvl_fd_fix_cloexec(ret);
449rb_fd_set_nonblock(
int fd)
452 return rb_w32_set_nonblock(fd);
453#elif defined(F_GETFL)
454 int oflags = fcntl(fd, F_GETFL);
458 if (oflags & O_NONBLOCK)
460 oflags |= O_NONBLOCK;
461 return fcntl(fd, F_SETFL, oflags);
467cloexec_pipe(
int descriptors[2],
int flags,
bool force_cloexec)
471# if defined(__APPLE__)
472# define try_pipe2 (pipe2 != NULL)
473# define abandon_pipe2() true
475 static bool try_pipe2 =
true;
476# define abandon_pipe2() (errno != ENOSYS || !!(try_pipe2 = false))
479 result = pipe2(descriptors, O_CLOEXEC | flags);
480 if (result == 0)
return result;
481 if (abandon_pipe2())
return result;
484 if (result < 0 && (result = pipe(descriptors)) < 0)
488 if (result == 0 && descriptors[1] == -1) {
489 close(descriptors[0]);
496 if (!force_cloexec)
return result;
499 rb_maygvl_fd_fix_cloexec(descriptors[0]);
500 rb_maygvl_fd_fix_cloexec(descriptors[1]);
503 rb_fd_set_nonblock(descriptors[0]);
504 rb_fd_set_nonblock(descriptors[1]);
513 return cloexec_pipe(descriptors, O_NONBLOCK,
true);
521#if defined(HAVE_FCNTL) && defined(F_DUPFD_CLOEXEC) && defined(F_DUPFD)
522 static int try_dupfd_cloexec = 1;
523 if (try_dupfd_cloexec) {
524 ret = fcntl(fd, F_DUPFD_CLOEXEC, minfd);
527 rb_maygvl_fd_fix_cloexec(ret);
531 if (
errno == EINVAL) {
532 ret = fcntl(fd, F_DUPFD, minfd);
534 try_dupfd_cloexec = 0;
539 ret = fcntl(fd, F_DUPFD, minfd);
541#elif defined(HAVE_FCNTL) && defined(F_DUPFD)
542 ret = fcntl(fd, F_DUPFD, minfd);
545 if (ret >= 0 && ret < minfd) {
546 const int prev_fd = ret;
552 if (ret < 0)
return ret;
553 rb_maygvl_fd_fix_cloexec(ret);
557#define argf_of(obj) (*(struct argf *)DATA_PTR(obj))
558#define ARGF argf_of(argf)
559#define ARGF_SET(field, value) RB_OBJ_WRITE(argf, &ARGF.field, value)
561#define GetWriteIO(io) rb_io_get_write_io(io)
563#define READ_DATA_PENDING(fptr) ((fptr)->rbuf.len)
564#define READ_DATA_PENDING_COUNT(fptr) ((fptr)->rbuf.len)
565#define READ_DATA_PENDING_PTR(fptr) ((fptr)->rbuf.ptr+(fptr)->rbuf.off)
566#define READ_DATA_BUFFERED(fptr) READ_DATA_PENDING(fptr)
568#define READ_CHAR_PENDING(fptr) ((fptr)->cbuf.len)
569#define READ_CHAR_PENDING_COUNT(fptr) ((fptr)->cbuf.len)
570#define READ_CHAR_PENDING_PTR(fptr) ((fptr)->cbuf.ptr+(fptr)->cbuf.off)
573#define WAIT_FD_IN_WIN32(fptr) \
574 (rb_w32_io_cancelable_p((fptr)->fd) ? Qnil : rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_READABLE), RUBY_IO_TIMEOUT_DEFAULT))
576#define WAIT_FD_IN_WIN32(fptr)
579#define READ_CHECK(fptr) do {\
580 if (!READ_DATA_PENDING(fptr)) {\
581 WAIT_FD_IN_WIN32(fptr);\
582 rb_io_check_closed(fptr);\
588# define S_ISSOCK(m) _S_ISSOCK(m)
591# define S_ISSOCK(m) (((m) & S_IFMT) == _S_IFSOCK)
594# define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
600static int io_fflush(
rb_io_t *);
601static rb_io_t *flush_before_seek(
rb_io_t *fptr,
bool discard_rbuf);
602static void clear_readconv(
rb_io_t *fptr);
603static void clear_codeconv(
rb_io_t *fptr);
605#define FMODE_SIGNAL_ON_EPIPE (1<<17)
607#define fptr_signal_on_epipe(fptr) \
608 (((fptr)->mode & FMODE_SIGNAL_ON_EPIPE) != 0)
610#define fptr_set_signal_on_epipe(fptr, flag) \
612 (fptr)->mode |= FMODE_SIGNAL_ON_EPIPE : \
613 (fptr)->mode &= ~FMODE_SIGNAL_ON_EPIPE)
615extern ID ruby_static_id_signo;
617NORETURN(
static void rb_sys_fail_on_write(
rb_io_t *fptr));
619rb_sys_fail_on_write(
rb_io_t *fptr)
622 VALUE errinfo = rb_syserr_new_path(e, (fptr)->pathv);
624 if (fptr_signal_on_epipe(fptr) && (e == EPIPE)) {
636#define NEED_NEWLINE_DECORATOR_ON_READ(fptr) ((fptr)->mode & FMODE_TEXTMODE)
637#define NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) ((fptr)->mode & FMODE_TEXTMODE)
638#if defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32)
639# define RUBY_CRLF_ENVIRONMENT 1
641# define RUBY_CRLF_ENVIRONMENT 0
644#if RUBY_CRLF_ENVIRONMENT
646# define DEFAULT_TEXTMODE FMODE_TEXTMODE
647# define TEXTMODE_NEWLINE_DECORATOR_ON_WRITE ECONV_CRLF_NEWLINE_DECORATOR
655#define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || (fptr)->encs.ecflags & ~ECONV_CRLF_NEWLINE_DECORATOR)
656#define WRITECONV_MASK ( \
657 (ECONV_DECORATOR_MASK & ~ECONV_CRLF_NEWLINE_DECORATOR)|\
658 ECONV_STATEFUL_DECORATOR_MASK|\
660#define NEED_WRITECONV(fptr) ( \
661 ((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || \
662 ((fptr)->encs.ecflags & WRITECONV_MASK) || \
664#define SET_BINARY_MODE(fptr) setmode((fptr)->fd, O_BINARY)
666#define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) do {\
667 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {\
668 if (((fptr)->mode & FMODE_READABLE) &&\
669 !((fptr)->encs.ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {\
670 setmode((fptr)->fd, O_BINARY);\
673 setmode((fptr)->fd, O_TEXT);\
678#define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) do {\
679 if ((enc2) && ((ecflags) & ECONV_DEFAULT_NEWLINE_DECORATOR)) {\
680 (ecflags) |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;\
688io_unread(
rb_io_t *fptr,
bool discard_rbuf)
704 if (!rb_w32_fd_is_text(fptr->
fd)) {
705 r = lseek(fptr->
fd, -fptr->
rbuf.
len, SEEK_CUR);
706 if (r < 0 &&
errno) {
709 if (!discard_rbuf)
return;
715 pos = lseek(fptr->
fd, 0, SEEK_CUR);
716 if (pos < 0 &&
errno) {
719 if (!discard_rbuf)
goto end;
723 extra_max = (long)(pos - fptr->
rbuf.
len);
731 for (i = 0; i < fptr->
rbuf.
len; i++) {
732 if (*p ==
'\n') newlines++;
733 if (extra_max == newlines)
break;
738 while (newlines >= 0) {
739 r = lseek(fptr->
fd, pos - fptr->
rbuf.
len - newlines, SEEK_SET);
740 if (newlines == 0)
break;
745 read_size = _read(fptr->
fd, buf, fptr->
rbuf.
len + newlines);
749 rb_syserr_fail_path(e, fptr->
pathv);
751 if (read_size == fptr->
rbuf.
len) {
752 lseek(fptr->
fd, r, SEEK_SET);
763 clear_codeconv(fptr);
775set_binary_mode_with_seek_cur(
rb_io_t *fptr)
777 if (!rb_w32_fd_is_text(fptr->
fd))
return O_BINARY;
780 return setmode(fptr->
fd, O_BINARY);
782 flush_before_seek(fptr,
false);
783 return setmode(fptr->
fd, O_BINARY);
785#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) set_binary_mode_with_seek_cur(fptr)
789# define DEFAULT_TEXTMODE 0
790#define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || NEED_NEWLINE_DECORATOR_ON_READ(fptr))
791#define NEED_WRITECONV(fptr) ( \
792 ((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || \
793 NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) || \
794 ((fptr)->encs.ecflags & (ECONV_DECORATOR_MASK|ECONV_STATEFUL_DECORATOR_MASK)) || \
796#define SET_BINARY_MODE(fptr) (void)(fptr)
797#define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) (void)(fptr)
798#define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) ((void)(enc2), (void)(ecflags))
799#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) (void)(fptr)
802#if !defined HAVE_SHUTDOWN && !defined shutdown
803#define shutdown(a,b) 0
807#define is_socket(fd, path) rb_w32_is_socket(fd)
808#elif !defined(S_ISSOCK)
809#define is_socket(fd, path) 0
812is_socket(
int fd,
VALUE path)
815 if (fstat(fd, &sbuf) < 0)
816 rb_sys_fail_path(path);
817 return S_ISSOCK(sbuf.st_mode);
821static const char closed_stream[] =
"closed stream";
824io_fd_check_closed(
int fd)
857 io_fd_check_closed(fptr->
fd);
861rb_io_get_fptr(
VALUE io)
871 return rb_convert_type_with_id(io,
T_FILE,
"IO", idTo_io);
877 return rb_check_convert_type_with_id(io,
T_FILE,
"IO", idTo_io);
895 rb_io_t *fptr = rb_io_get_fptr(io);
904 return write_io ? write_io :
Qnil;
917 rb_io_t *fptr = rb_io_get_fptr(self);
947 if (
RTEST(timeout)) {
951 rb_io_t *fptr = rb_io_get_fptr(self);
976#if !RUBY_CRLF_ENVIRONMENT
978io_unread(
rb_io_t *fptr,
bool discard_rbuf)
986 r = lseek(fptr->
fd, -fptr->
rbuf.
len, SEEK_CUR);
987 if (r < 0 &&
errno) {
990 if (!discard_rbuf)
return;
994 clear_codeconv(fptr);
1004 long len = RSTRING_LEN(str);
1007 const int min_capa = IO_RBUF_CAPA_FOR(fptr);
1010#if SIZEOF_LONG > SIZEOF_INT
1037 long len = RSTRING_LEN(str);
1043 io_ungetbyte(str, fptr);
1047 int capa = (int)
len + pending;
1061flush_before_seek(
rb_io_t *fptr,
bool discard_rbuf)
1063 if (io_fflush(fptr) < 0)
1064 rb_sys_fail_on_write(fptr);
1065 io_unread(fptr, discard_rbuf);
1070#define io_seek(fptr, ofs, whence) (errno = 0, lseek(flush_before_seek(fptr, true)->fd, (ofs), (whence)))
1071#define io_tell(fptr) lseek(flush_before_seek(fptr, false)->fd, 0, SEEK_CUR)
1087 if (io_fflush(fptr) < 0)
1088 rb_sys_fail_on_write(fptr);
1093 if (io_fflush(wfptr) < 0)
1094 rb_sys_fail_on_write(wfptr);
1102 if (READ_CHAR_PENDING(fptr)) {
1103 rb_raise(
rb_eIOError,
"byte oriented read for character buffered IO");
1114io_read_encoding(
rb_io_t *fptr)
1119 return rb_default_external_encoding();
1123io_input_encoding(
rb_io_t *fptr)
1128 return io_read_encoding(fptr);
1139 io_unread(fptr,
true);
1144rb_io_read_pending(
rb_io_t *fptr)
1147 if (READ_CHAR_PENDING(fptr))
1149 return READ_DATA_PENDING(fptr);
1155 if (!READ_DATA_PENDING(fptr)) {
1162rb_gc_for_fd(
int err)
1164 if (err == EMFILE || err == ENFILE || err == ENOMEM) {
1174#define TRY_WITH_GC(expr) \
1175 for (int first_errno, retried_errno = 0, retried = 0; \
1178 (!rb_gc_for_fd(first_errno = errno) || !(expr)) && \
1179 (retried_errno = errno, 1)); \
1180 (void)retried_errno, retried = 1)
1195io_alloc(
VALUE klass)
1197 UNPROTECTED_NEWOBJ_OF(io,
struct RFile, klass,
T_FILE,
sizeof(
struct RFile));
1205# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
1231struct io_internal_writev_struct {
1238 const struct iovec *iov;
1251io_internal_wait(
VALUE thread,
rb_io_t *fptr,
int error,
int events,
struct timeval *timeout)
1253 if (!timeout && rb_thread_mn_schedulable(thread)) {
1258 int ready = nogvl_wait_for(thread, fptr, events, timeout);
1263 else if (ready == 0) {
1280internal_read_func(
void *ptr)
1285 if (iis->timeout && !iis->nonblock) {
1286 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_IN, iis->timeout) == -1) {
1292 result = read(iis->fd, iis->buf, iis->capa);
1294 if (result < 0 && !iis->nonblock) {
1295 if (io_again_p(
errno)) {
1296 if (io_internal_wait(iis->th, iis->fptr,
errno, RB_WAITFD_IN, iis->timeout) == -1) {
1308#if defined __APPLE__
1309# define do_write_retry(code) do {result = code;} while (result == -1 && errno == EPROTOTYPE)
1311# define do_write_retry(code) result = code
1315internal_write_func(
void *ptr)
1320 if (iis->timeout && !iis->nonblock) {
1321 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1327 do_write_retry(write(iis->fd, iis->buf, iis->capa));
1329 if (result < 0 && !iis->nonblock) {
1331 if (io_again_p(e)) {
1332 if (io_internal_wait(iis->th, iis->fptr,
errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1346internal_writev_func(
void *ptr)
1348 struct io_internal_writev_struct *iis = ptr;
1351 if (iis->timeout && !iis->nonblock) {
1352 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1358 do_write_retry(writev(iis->fd, iis->iov, iis->iovcnt));
1360 if (result < 0 && !iis->nonblock) {
1361 if (io_again_p(
errno)) {
1362 if (io_internal_wait(iis->th, iis->fptr,
errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1376rb_io_read_memory(
rb_io_t *fptr,
void *buf,
size_t count)
1380 if (scheduler !=
Qnil) {
1383 if (!UNDEF_P(result)) {
1399 struct timeval timeout_storage;
1403 iis.timeout = &timeout_storage;
1406 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_read_func, &iis,
RUBY_IO_READABLE);
1410rb_io_write_memory(
rb_io_t *fptr,
const void *buf,
size_t count)
1414 if (scheduler !=
Qnil) {
1417 if (!UNDEF_P(result)) {
1433 struct timeval timeout_storage;
1437 iis.timeout = &timeout_storage;
1440 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_write_func, &iis,
RUBY_IO_WRITABLE);
1445rb_writev_internal(
rb_io_t *fptr,
const struct iovec *iov,
int iovcnt)
1447 if (!iovcnt)
return 0;
1452 if (scheduler !=
Qnil) {
1456 if (!UNDEF_P(result)) {
1461 struct io_internal_writev_struct iis = {
1472 struct timeval timeout_storage;
1476 iis.timeout = &timeout_storage;
1479 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_writev_func, &iis,
RUBY_IO_WRITABLE);
1484io_flush_buffer_sync(
void *arg)
1506io_flush_buffer_fiber_scheduler(
VALUE scheduler,
rb_io_t *fptr)
1509 if (!UNDEF_P(ret)) {
1521io_flush_buffer_async(
VALUE arg)
1526 if (scheduler !=
Qnil) {
1527 VALUE result = io_flush_buffer_fiber_scheduler(scheduler, fptr);
1528 if (!UNDEF_P(result)) {
1533 return rb_io_blocking_region_wait(fptr, io_flush_buffer_sync, fptr,
RUBY_IO_WRITABLE);
1540 return (
int)io_flush_buffer_async((
VALUE)fptr);
1555 while (fptr->
wbuf.
len > 0 && io_flush_buffer(fptr) != 0) {
1571 if (scheduler !=
Qnil) {
1581 if (NIL_OR_UNDEF_P(timeout)) {
1585 if (timeout !=
Qnil) {
1590 int ready = rb_thread_io_wait(th, fptr,
RB_NUM2INT(events), tv);
1616 if (scheduler !=
Qnil) {
1622 return rb_thread_wait_for_single_fd(th, fd, events, timeout);
1628 io_fd_check_closed(f);
1635#if defined(ERESTART)
1642#if EWOULDBLOCK != EAGAIN
1645 if (scheduler !=
Qnil) {
1663 io_fd_check_closed(f);
1670#if defined(ERESTART)
1686#if EWOULDBLOCK != EAGAIN
1689 if (scheduler !=
Qnil) {
1709 return io_wait_for_single_fd(fd, events, timeout, th, scheduler);
1743#if defined(ERESTART)
1753#if EWOULDBLOCK != EAGAIN
1776 if (
RTEST(result)) {
1791 if (
RTEST(result)) {
1805 const char *senc, *denc;
1812 ecflags = fptr->
encs.
ecflags & ~ECONV_NEWLINE_DECORATOR_READ_MASK;
1839 denc = rb_enc_name(enc);
1871io_binwrite_string_internal(
rb_io_t *fptr,
const char *ptr,
long length)
1874 struct iovec iov[2];
1877 iov[0].iov_len = fptr->
wbuf.
len;
1878 iov[1].iov_base = (
void*)ptr;
1879 iov[1].iov_len = length;
1881 ssize_t result = rb_writev_internal(fptr, iov, 2);
1886 if (result >= fptr->
wbuf.
len) {
1894 fptr->
wbuf.
off += (int)result;
1895 fptr->
wbuf.
len -= (int)result;
1903 return rb_io_write_memory(fptr, ptr, length);
1908io_binwrite_string_internal(
rb_io_t *fptr,
const char *ptr,
long length)
1910 long remaining = length;
1913 if (fptr->
wbuf.
len+length <= fptr->wbuf.capa) {
1920 fptr->
wbuf.
len += (int)length;
1927 if (io_fflush(fptr) < 0) {
1932 if (remaining == 0) {
1938 return rb_io_write_memory(fptr, ptr, length);
1943io_binwrite_string(
VALUE arg)
1947 const char *ptr = p->ptr;
1948 size_t remaining = p->length;
1952 ssize_t result = io_binwrite_string_internal(p->fptr, ptr, remaining);
1958 else if (result > 0) {
1959 if ((
size_t)result == remaining)
break;
1961 remaining -= result;
1977io_allocate_write_buffer(
rb_io_t *fptr,
int sync)
1982 fptr->
wbuf.
capa = IO_WBUF_CAPA_MIN;
1993io_binwrite_requires_flush_write(
rb_io_t *fptr,
long len,
int nosync)
2008io_binwrite(
const char *ptr,
long len,
rb_io_t *fptr,
int nosync)
2010 if (
len <= 0)
return len;
2015 io_allocate_write_buffer(fptr, !nosync);
2017 if (io_binwrite_requires_flush_write(fptr,
len, nosync)) {
2028 return io_binwrite_string((
VALUE)&arg);
2045# define MODE_BTMODE(a,b,c) ((fmode & FMODE_BINMODE) ? (b) : \
2046 (fmode & FMODE_TEXTMODE) ? (c) : (a))
2048#define MODE_BTXMODE(a, b, c, d, e, f) ((fmode & FMODE_EXCL) ? \
2049 MODE_BTMODE(d, e, f) : \
2050 MODE_BTMODE(a, b, c))
2055 if (NEED_WRITECONV(fptr)) {
2057 SET_BINARY_MODE(fptr);
2059 make_writeconv(fptr);
2062#define fmode (fptr->mode)
2065 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1) && !rb_enc_asciicompat(rb_enc_get(str))) {
2066 rb_raise(rb_eArgError,
"ASCII incompatible string written for text mode IO without encoding conversion: %s",
2067 rb_enc_name(rb_enc_get(str)));
2073 common_encoding = rb_enc_from_encoding(fptr->
encs.
enc2);
2074 else if (fptr->
encs.
enc != rb_ascii8bit_encoding())
2075 common_encoding = rb_enc_from_encoding(fptr->
encs.
enc);
2078 if (!
NIL_P(common_encoding)) {
2089#if RUBY_CRLF_ENVIRONMENT
2090#define fmode (fptr->mode)
2091 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1)) {
2094 setmode(fptr->
fd, O_BINARY);
2097 setmode(fptr->
fd, O_TEXT);
2099 if (!rb_enc_asciicompat(rb_enc_get(str))) {
2100 rb_raise(rb_eArgError,
"ASCII incompatible string written for text mode IO without encoding conversion: %s",
2101 rb_enc_name(rb_enc_get(str)));
2119 if (rb_w32_write_console(str, fptr->
fd) > 0)
return RSTRING_LEN(str);
2123 str = do_writeconv(str, fptr, &converted);
2129 n = io_binwrite(ptr,
len, fptr, nosync);
2142 return (ssize_t)io_binwrite(buf, (
long)size, fptr, 0);
2152 io = GetWriteIO(io);
2162 if (RSTRING_LEN(str) == 0)
return INT2FIX(0);
2167 n = io_fwrite(str, fptr, nosync);
2168 if (n < 0L) rb_sys_fail_on_write(fptr);
2174struct binwritev_arg {
2182io_binwritev_internal(
VALUE arg)
2184 struct binwritev_arg *p = (
struct binwritev_arg *)arg;
2186 size_t remaining = p->total;
2190 struct iovec *iov = p->iov;
2191 int iovcnt = p->iovcnt;
2194 long result = rb_writev_internal(fptr, iov, iovcnt);
2199 if (offset < (
size_t)fptr->
wbuf.
len) {
2204 offset -= (size_t)fptr->
wbuf.
len;
2210 if (offset == p->total) {
2214 while (result >= (ssize_t)iov->iov_len) {
2216 result -= iov->iov_len;
2226 iov->iov_base = (
char *)iov->iov_base + result;
2227 iov->iov_len -= result;
2241io_binwritev(
struct iovec *iov,
int iovcnt,
rb_io_t *fptr)
2246 if (iovcnt == 0)
return 0;
2249 for (
int i = 1; i < iovcnt; i++) total += iov[i].iov_len;
2251 io_allocate_write_buffer(fptr, 1);
2257 if (offset + total <= (
size_t)fptr->
wbuf.
capa) {
2258 for (
int i = 1; i < iovcnt; i++) {
2259 memcpy(fptr->
wbuf.
ptr+offset, iov[i].iov_base, iov[i].iov_len);
2260 offset += iov[i].iov_len;
2271 if (io_fflush(fptr) < 0)
return -1;
2277 iov[0].iov_len = fptr->
wbuf.
len;
2290 struct binwritev_arg arg;
2293 arg.iovcnt = iovcnt;
2300 return io_binwritev_internal((
VALUE)&arg);
2307 int i, converted, iovcnt = argc + 1;
2309 VALUE v1, v2, str, tmp, *tmp_array;
2315 for (i = 0; i < argc; i++) {
2318 str = do_writeconv(str, fptr, &converted);
2323 tmp = rb_str_tmp_frozen_acquire(str);
2327 iov[i+1].iov_base = RSTRING_PTR(tmp);
2328 iov[i+1].iov_len = RSTRING_LEN(tmp);
2331 n = io_binwritev(iov, iovcnt, fptr);
2334 for (i = 0; i < argc; i++) {
2335 rb_str_tmp_frozen_release(argv[i], tmp_array[i]);
2344iovcnt_ok(
int iovcnt)
2347 return iovcnt < IOV_MAX;
2355io_writev(
int argc,
const VALUE *argv,
VALUE io)
2362 io = GetWriteIO(io);
2375 for (i = 0; i < argc; i += cnt) {
2378 n = io_fwritev(cnt, &argv[i], fptr);
2389 rb_sys_fail_on_write(fptr);
2391 total = rb_fix_plus(
LONG2FIX(n), total);
2422 return io_writev(argc, argv, io);
2425 VALUE str = argv[0];
2426 return io_write(io, str, 0);
2437rb_io_writev(
VALUE io,
int argc,
const VALUE *argv)
2442 char sep = RCLASS_SINGLETON_P(klass) ? (klass = io,
'.') :
'#';
2445 " which accepts just one argument",
2450 do rb_io_write(io, *argv++);
while (--argc);
2481 rb_io_write(io, str);
2487nogvl_fsync(
void *ptr)
2492 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->
fd)) != FILE_TYPE_DISK)
2495 return (
VALUE)fsync(fptr->
fd);
2500rb_io_flush_raw(
VALUE io,
int sync)
2508 io = GetWriteIO(io);
2512 if (io_fflush(fptr) < 0)
2513 rb_sys_fail_on_write(fptr);
2516 io_unread(fptr,
true);
2537 return rb_io_flush_raw(io, 1);
2563 pos = io_tell(fptr);
2564 if (pos < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
2570rb_io_seek(
VALUE io,
VALUE offset,
int whence)
2577 pos = io_seek(fptr, pos, whence);
2578 if (pos < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
2579 if (fptr->
readconv) clear_readconv(fptr);
2585interpret_seek_whence(
VALUE vwhence)
2587 if (vwhence == sym_SET)
2589 if (vwhence == sym_CUR)
2591 if (vwhence == sym_END)
2594 if (vwhence == sym_DATA)
2598 if (vwhence == sym_HOLE)
2654 VALUE offset, ptrname;
2655 int whence = SEEK_SET;
2657 if (
rb_scan_args(argc, argv,
"11", &offset, &ptrname) == 2) {
2658 whence = interpret_seek_whence(ptrname);
2661 return rb_io_seek(io, offset, whence);
2689 pos = io_seek(fptr, pos, SEEK_SET);
2690 if (pos < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
2691 if (fptr->
readconv) clear_readconv(fptr);
2721rb_io_rewind(
VALUE io)
2726 if (io_seek(fptr, 0L, 0) < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
2727 if (io == ARGF.current_file) {
2728 ARGF.lineno -= fptr->
lineno;
2732 clear_readconv(fptr);
2739fptr_wait_readable(
rb_io_t *fptr)
2757 fptr->
rbuf.
capa = IO_RBUF_CAPA_FOR(fptr);
2765 if (fptr_wait_readable(fptr))
2769 VALUE path = rb_sprintf(
"fd:%d ", fptr->
fd);
2774 rb_syserr_fail_path(e, path);
2828 if (READ_CHAR_PENDING(fptr))
return Qfalse;
2829 if (READ_DATA_PENDING(fptr))
return Qfalse;
2831#if RUBY_CRLF_ENVIRONMENT
2832 if (!NEED_READCONV(fptr) && NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
2833 return RBOOL(eof(fptr->
fd));
2836 return RBOOL(io_fillbuf(fptr) < 0);
2860 io = GetWriteIO(io);
2897 io = GetWriteIO(io);
2903 fptr->
mode &= ~FMODE_SYNC;
2927rb_io_fsync(
VALUE io)
2931 io = GetWriteIO(io);
2934 if (io_fflush(fptr) < 0)
2935 rb_sys_fail_on_write(fptr);
2937 if ((
int)rb_io_blocking_region(fptr, nogvl_fsync, fptr))
2938 rb_sys_fail_path(fptr->
pathv);
2943# define rb_io_fsync rb_f_notimplement
2944# define rb_io_sync rb_f_notimplement
2953#ifdef HAVE_FDATASYNC
2955nogvl_fdatasync(
void *ptr)
2959 return (
VALUE)fdatasync(fptr->
fd);
2974rb_io_fdatasync(
VALUE io)
2978 io = GetWriteIO(io);
2981 if (io_fflush(fptr) < 0)
2982 rb_sys_fail_on_write(fptr);
2984 if ((
int)rb_io_blocking_region(fptr, nogvl_fdatasync, fptr) == 0)
2988 return rb_io_fsync(io);
2991#define rb_io_fdatasync rb_io_fsync
3009rb_io_fileno(
VALUE io)
3029 if (!UNDEF_P(fileno)) {
3122rb_io_inspect(
VALUE obj)
3126 static const char closed[] =
" (closed)";
3128 fptr =
RFILE(obj)->fptr;
3135 rb_str_cat(result, closed+1, strlen(closed)-1);
3138 rb_str_catf(result,
"fd %d", fptr->
fd);
3159rb_io_to_io(
VALUE io)
3166read_buffered_data(
char *ptr,
long len,
rb_io_t *fptr)
3170 n = READ_DATA_PENDING_COUNT(fptr);
3171 if (n <= 0)
return 0;
3172 if (n >
len) n = (int)
len;
3180io_bufread(
char *ptr,
long len,
rb_io_t *fptr,
long *read_len)
3187 if (READ_DATA_PENDING(fptr) == 0) {
3191 c = rb_io_read_memory(fptr, ptr+offset, n);
3194 if (fptr_wait_readable(fptr))
3200 if ((n -= c) <= 0)
break;
3206 c = read_buffered_data(ptr+offset, n, fptr);
3210 if ((n -= c) <= 0)
break;
3213 if (io_fillbuf(fptr) < 0) {
3220static int io_setstrbuf(
VALUE *str,
long len);
3231bufread_body(
VALUE arg)
3234 p->len = io_bufread(p->str_ptr + p->offset, p->len, p->fptr, &p->read_len);
3243 if (p->offset + p->read_len > 0) {
3245 io_restore_read_buffer(str, p->fptr);
3252bufread_call(
VALUE arg)
3257 return bufread_body(arg);
3259 return rb_rescue2(bufread_body, arg, bufread_timeout, arg,
3260 rb_eIOTimeoutError, (
VALUE)0);
3264io_fread(
VALUE str,
long offset,
long size,
rb_io_t *fptr)
3269 io_setstrbuf(&str, offset + size);
3270 arg.str_ptr = RSTRING_PTR(str);
3271 arg.offset = offset;
3275 rb_str_locktmp_ensure(str, bufread_call, (
VALUE)&arg);
3277 if (
len < 0) rb_sys_fail_path(fptr->
pathv);
3285 rb_off_t siz = READ_DATA_PENDING_COUNT(fptr);
3288 if (fstat(fptr->
fd, &st) == 0 && S_ISREG(st.st_mode)
3289#
if defined(__HAIKU__)
3294 if (io_fflush(fptr) < 0)
3295 rb_sys_fail_on_write(fptr);
3296 pos = lseek(fptr->
fd, 0, SEEK_CUR);
3297 if (st.st_size >= pos && pos >= 0) {
3298 siz += st.st_size - pos;
3299 if (siz > LONG_MAX) {
3300 rb_raise(
rb_eIOError,
"file too big for single read");
3313 rb_enc_associate(str, io_read_encoding(fptr));
3318make_readconv(
rb_io_t *fptr,
int size)
3323 const char *sname, *dname;
3324 ecflags = fptr->
encs.
ecflags & ~ECONV_NEWLINE_DECORATOR_WRITE_MASK;
3327 sname = rb_enc_name(fptr->
encs.
enc2);
3328 dname = rb_enc_name(io_read_encoding(fptr));
3338 if (size < IO_CBUF_CAPA_MIN) size = IO_CBUF_CAPA_MIN;
3344#define MORE_CHAR_SUSPENDED Qtrue
3345#define MORE_CHAR_FINISHED Qnil
3347fill_cbuf(
rb_io_t *fptr,
int ec_flags)
3349 const unsigned char *ss, *sp, *se;
3350 unsigned char *ds, *dp, *de;
3359 return MORE_CHAR_SUSPENDED;
3370 ss = sp = (
const unsigned char *)fptr->
rbuf.
ptr + fptr->
rbuf.
off;
3375 fptr->
rbuf.
off += (int)(sp - ss);
3376 fptr->
rbuf.
len -= (int)(sp - ss);
3377 fptr->
cbuf.
len += (int)(dp - ds);
3382 fptr->
rbuf.
off -= putbackable;
3383 fptr->
rbuf.
len += putbackable;
3390 if (cbuf_len0 != fptr->
cbuf.
len)
3391 return MORE_CHAR_SUSPENDED;
3394 return MORE_CHAR_FINISHED;
3400 if (io_fillbuf(fptr) < 0) {
3402 return MORE_CHAR_FINISHED;
3407 fptr->
cbuf.
len += (int)(dp - ds);
3414 if (cbuf_len0 != fptr->
cbuf.
len)
3415 return MORE_CHAR_SUSPENDED;
3417 return MORE_CHAR_FINISHED;
3425 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED)
3442 rb_enc_associate(str, fptr->
encs.
enc);
3467 long clen = RSTRING_LEN(s);
3479#define MAX_REALLOC_GAP 4096
3481io_shrink_read_string(
VALUE str,
long n)
3484 rb_str_resize(str, n);
3489io_set_read_length(
VALUE str,
long n,
int shrinkable)
3491 if (RSTRING_LEN(str) != n) {
3494 if (shrinkable) io_shrink_read_string(str, n);
3508 if (NEED_READCONV(fptr)) {
3509 int first = !
NIL_P(str);
3510 SET_BINARY_MODE(fptr);
3511 shrinkable = io_setstrbuf(&str,0);
3512 make_readconv(fptr, 0);
3517 io_shift_cbuf(fptr, fptr->
cbuf.
len, &str);
3519 v = fill_cbuf(fptr, 0);
3520 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED) {
3523 io_shift_cbuf(fptr, fptr->
cbuf.
len, &str);
3527 if (v == MORE_CHAR_FINISHED) {
3528 clear_readconv(fptr);
3530 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3531 return io_enc_str(str, fptr);
3536 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3540 enc = io_read_encoding(fptr);
3553 shrinkable = io_setstrbuf(&str, siz);
3556 n = io_fread(str, bytes, siz - bytes, fptr);
3557 if (n == 0 && bytes == 0) {
3565 if (bytes < siz)
break;
3569 if (
capa < (
size_t)RSTRING_LEN(str) + BUFSIZ) {
3570 if (
capa < BUFSIZ) {
3573 else if (
capa > IO_MAX_BUFFER_GROWTH) {
3574 capa = IO_MAX_BUFFER_GROWTH;
3579 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3580 str = io_enc_str(str, fptr);
3588 if (rb_fd_set_nonblock(fptr->
fd) != 0) {
3589 rb_sys_fail_path(fptr->
pathv);
3594io_read_memory_call(
VALUE arg)
3599 if (scheduler !=
Qnil) {
3602 if (!UNDEF_P(result)) {
3608 if (iis->nonblock) {
3609 return rb_io_blocking_region(iis->fptr, internal_read_func, iis);
3612 return rb_io_blocking_region_wait(iis->fptr, internal_read_func, iis,
RUBY_IO_READABLE);
3619 return (
long)rb_str_locktmp_ensure(str, io_read_memory_call, (
VALUE)iis);
3622#define no_exception_p(opts) !rb_opts_exception_p((opts), TRUE)
3625io_getpartial(
int argc,
VALUE *argv,
VALUE io,
int no_exception,
int nonblock)
3636 rb_raise(rb_eArgError,
"negative length %ld given",
len);
3639 shrinkable = io_setstrbuf(&str,
len);
3645 io_set_read_length(str, 0, shrinkable);
3651 n = read_buffered_data(RSTRING_PTR(str),
len, fptr);
3657 io_setstrbuf(&str,
len);
3660 iis.nonblock = nonblock;
3662 iis.buf = RSTRING_PTR(str);
3665 n = io_read_memory_locktmp(str, &iis);
3668 if (!nonblock && fptr_wait_readable(fptr))
3670 if (nonblock && (io_again_p(e))) {
3672 return sym_wait_readable;
3675 e,
"read would block");
3677 rb_syserr_fail_path(e, fptr->
pathv);
3680 io_set_read_length(str, n, shrinkable);
3781io_readpartial(
int argc,
VALUE *argv,
VALUE io)
3785 ret = io_getpartial(argc, argv, io,
Qnil, 0);
3792io_nonblock_eof(
int no_exception)
3794 if (!no_exception) {
3810 rb_raise(rb_eArgError,
"negative length %ld given",
len);
3813 shrinkable = io_setstrbuf(&str,
len);
3814 rb_bool_expected(ex,
"exception", TRUE);
3820 io_set_read_length(str, 0, shrinkable);
3824 n = read_buffered_data(RSTRING_PTR(str),
len, fptr);
3826 rb_fd_set_nonblock(fptr->
fd);
3827 shrinkable |= io_setstrbuf(&str,
len);
3831 iis.buf = RSTRING_PTR(str);
3834 n = io_read_memory_locktmp(str, &iis);
3837 if (io_again_p(e)) {
3838 if (!ex)
return sym_wait_readable;
3840 e,
"read would block");
3842 rb_syserr_fail_path(e, fptr->
pathv);
3845 io_set_read_length(str, n, shrinkable);
3848 if (!ex)
return Qnil;
3864 rb_bool_expected(ex,
"exception", TRUE);
3866 io = GetWriteIO(io);
3870 if (io_fflush(fptr) < 0)
3871 rb_sys_fail_on_write(fptr);
3873 rb_fd_set_nonblock(fptr->
fd);
3874 n = write(fptr->
fd, RSTRING_PTR(str), RSTRING_LEN(str));
3879 if (io_again_p(e)) {
3881 return sym_wait_writable;
3887 rb_syserr_fail_path(e, fptr->
pathv);
3971#if RUBY_CRLF_ENVIRONMENT
3977 if (
NIL_P(length)) {
3980 return read_all(fptr, remain_size(fptr), str);
3984 rb_raise(rb_eArgError,
"negative length %ld given",
len);
3987 shrinkable = io_setstrbuf(&str,
len);
3992 io_set_read_length(str, 0, shrinkable);
3997#if RUBY_CRLF_ENVIRONMENT
3998 previous_mode = set_binary_mode_with_seek_cur(fptr);
4000 n = io_fread(str, 0,
len, fptr);
4001 io_set_read_length(str, n, shrinkable);
4002#if RUBY_CRLF_ENVIRONMENT
4003 if (previous_mode == O_TEXT) {
4004 setmode(fptr->
fd, O_TEXT);
4007 if (n == 0)
return Qnil;
4013rscheck(
const char *rsptr,
long rslen,
VALUE rs)
4016 if (RSTRING_PTR(rs) != rsptr && RSTRING_LEN(rs) != rslen)
4021search_delim(
const char *p,
long len,
int delim,
rb_encoding *enc)
4023 if (rb_enc_mbminlen(enc) == 1) {
4024 p = memchr(p, delim,
len);
4025 if (p)
return p + 1;
4028 const char *end = p +
len;
4030 int r = rb_enc_precise_mbclen(p, end, enc);
4032 p += rb_enc_mbminlen(enc);
4036 if (rb_enc_mbc_to_codepoint(p, end, enc) == (
unsigned int)delim) {
4052 if (!READ_DATA_PENDING(fptr)) {
4054 if (io_fillbuf(fptr) < 0)
break;
4056 buf[n++] = *READ_DATA_PENDING_PTR(fptr);
4059 r = rb_enc_precise_mbclen(buf, buf + n, enc);
4066unread_raw_character(
rb_io_t *fptr,
const char *buf,
int len)
4078search_wide_delim(
const char *p,
long len,
const char *delim,
int width)
4080 const char *e = p +
len;
4083 while (index < width && delim[index] == 0) index++;
4084 if (index == width) index = 0;
4086 const char *candidate = p + index;
4087 while (candidate < e) {
4088 candidate = memchr(candidate, (
unsigned char)delim[index], e - candidate);
4089 if (candidate == NULL)
break;
4090 const char *start = candidate - index;
4091 if ((start - p) % width == 0 && start + width <= e &&
4092 memcmp(start, delim, width) == 0) {
4106 if (NEED_READCONV(fptr)) {
4107 SET_BINARY_MODE(fptr);
4108 make_readconv(fptr, 0);
4111 int searchlen = READ_CHAR_PENDING_COUNT(fptr);
4113 p = READ_CHAR_PENDING_PTR(fptr);
4114 if (0 < limit && limit < searchlen)
4115 searchlen = (int)limit;
4116 e = search_delim(p, searchlen, delim, enc);
4118 int len = (int)(e-p);
4140 return (
unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
4143 }
while (more_char(fptr) != MORE_CHAR_FINISHED);
4144 clear_readconv(fptr);
4149 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4150 if (rb_enc_mbminlen(enc) != 1) {
4151 char buf[ONIGENC_CODE_TO_MBC_MAXLEN];
4155 int width = rb_enc_mbminlen(enc);
4156 int delim_len = rb_enc_codelen(delim, enc);
4158 if (delim_len == width) {
4159 rb_enc_mbcput(delim, buf, enc);
4161 if (!READ_DATA_PENDING(fptr)) {
4163 if (io_fillbuf(fptr) < 0)
return EOF;
4165 long pending = READ_DATA_PENDING_COUNT(fptr);
4166 long complete = pending - pending % width;
4167 const char *p = READ_DATA_PENDING_PTR(fptr);
4168 const char *q = complete ? search_wide_delim(p, complete, buf, width) : NULL;
4169 long take = q ? q - p + width : complete;
4178 if (q)
return delim;
4179 if (complete == pending)
continue;
4181 len = read_raw_character(fptr, enc, buf);
4182 if (
len == 0)
return EOF;
4186 int r = rb_enc_precise_mbclen(buf, buf +
len, enc);
4188 rb_enc_mbc_to_codepoint(buf, buf +
len, enc) == (
unsigned int)delim)
4194 while ((
len = read_raw_character(fptr, enc, buf)) > 0) {
4201 return (
unsigned char)buf[
len - 1];
4205 int r = rb_enc_precise_mbclen(buf, buf +
len, enc);
4207 rb_enc_mbc_to_codepoint(buf, buf +
len, enc) == (
unsigned int)delim)
4210 return (
unsigned char)buf[
len - 1];
4216 long pending = READ_DATA_PENDING_COUNT(fptr);
4218 const char *p = READ_DATA_PENDING_PTR(fptr);
4222 if (limit > 0 && pending > limit) pending = limit;
4223 e = search_delim(p, pending, delim, enc);
4224 if (e) pending = e - p;
4226 last = RSTRING_LEN(str);
4227 rb_str_resize(str, last + pending);
4234 read_buffered_data(RSTRING_PTR(str) + last, pending, fptr);
4237 if (e)
return delim;
4239 return (
unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
4242 }
while (io_fillbuf(fptr) >= 0);
4248swallow(
rb_io_t *fptr,
int term)
4250 if (NEED_READCONV(fptr)) {
4252 int needconv = rb_enc_mbminlen(enc) != 1;
4253 SET_BINARY_MODE(fptr);
4254 make_readconv(fptr, 0);
4257 while ((cnt = READ_CHAR_PENDING_COUNT(fptr)) > 0) {
4258 const char *p = READ_CHAR_PENDING_PTR(fptr);
4261 if (*p != term)
return TRUE;
4263 while (--i && *++p == term);
4266 const char *e = p + cnt;
4267 if (rb_enc_ascget(p, e, &i, enc) != term)
return TRUE;
4268 while ((p += i) < e && rb_enc_ascget(p, e, &i, enc) == term);
4271 io_shift_cbuf(fptr, (
int)cnt - i, NULL);
4273 }
while (more_char(fptr) != MORE_CHAR_FINISHED);
4277 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4279 int widechar = rb_enc_mbminlen(enc) != 1;
4281 char buf[ONIGENC_CODE_TO_MBC_MAXLEN];
4284 while ((
len = read_raw_character(fptr, enc, buf)) > 0) {
4285 if (rb_enc_ascget(buf, buf +
len, NULL, enc) != term) {
4286 unread_raw_character(fptr, buf,
len);
4294 while ((cnt = READ_DATA_PENDING_COUNT(fptr)) > 0) {
4296 const char *p = READ_DATA_PENDING_PTR(fptr);
4298 if (cnt >
sizeof buf) cnt =
sizeof buf;
4299 if (*p != term)
return TRUE;
4301 while (--i && *++p == term);
4302 if (!read_buffered_data(buf, cnt - i, fptr))
4303 rb_sys_fail_path(fptr->
pathv);
4306 }
while (io_fillbuf(fptr) == 0);
4319 int pending = READ_DATA_PENDING_COUNT(fptr);
4322 const char *p = READ_DATA_PENDING_PTR(fptr);
4326 e = memchr(p,
'\n', pending);
4328 pending = (int)(e - p + 1);
4330 chomplen = (pending > 1 && *(e-1) ==
'\r') + 1;
4339 rb_str_resize(str,
len + pending - chomplen);
4340 read_buffered_data(RSTRING_PTR(str)+
len, pending - chomplen, fptr);
4343 if (pending == 1 && chomplen == 1 &&
len > 0) {
4344 if (RSTRING_PTR(str)[
len-1] ==
'\r') {
4345 rb_str_resize(str, --
len);
4350 len += pending - chomplen;
4356 }
while (io_fillbuf(fptr) >= 0);
4359 str = io_enc_str(str, fptr);
4370 unsigned int chomp: 1;
4384 chomp = (!UNDEF_P(vchomp)) &&
RTEST(vchomp);
4386 args->chomp = chomp;
4404 else if (2 <= argc) {
4405 rs = argv[0], lim = argv[1];
4414check_getline_args(
VALUE *rsp,
long *limit,
VALUE io)
4423 enc_rs = rb_enc_get(rs);
4424 enc_io = io_read_encoding(fptr);
4425 if (enc_io != enc_rs &&
4426 (!is_ascii_string(rs) ||
4427 (RSTRING_LEN(rs) > 0 && !rb_enc_asciicompat(enc_io)))) {
4428 if (rs == rb_default_rs) {
4429 rs = rb_enc_str_new(0, 0, enc_io);
4434 rb_raise(rb_eArgError,
"encoding mismatch: %s IO with %s RS",
4435 rb_enc_name(enc_io),
4436 rb_enc_name(enc_rs));
4446 argc =
rb_scan_args(argc, argv,
"02:", NULL, NULL, &opts);
4447 extract_getline_args(argc, argv, args);
4448 extract_getline_opts(opts, args);
4449 check_getline_args(&args->rs, &args->limit, io);
4453rb_io_getline_0(
VALUE rs,
long limit,
int chomp,
rb_io_t *fptr)
4460 if (
NIL_P(rs) && limit < 0) {
4461 str = read_all(fptr, 0,
Qnil);
4462 if (RSTRING_LEN(str) == 0)
return Qnil;
4464 else if (limit == 0) {
4465 return rb_enc_str_new(0, 0, io_read_encoding(fptr));
4467 else if (rs == rb_default_rs && limit < 0 && !NEED_READCONV(fptr) &&
4468 rb_enc_asciicompat(enc = io_read_encoding(fptr))) {
4469 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4470 return rb_io_getline_fast(fptr, enc, chomp);
4473 int c, newline = -1;
4474 const char *rsptr = 0;
4477 int extra_limit = 16;
4478 int chomp_cr = chomp;
4480 SET_BINARY_MODE(fptr);
4481 enc = io_read_encoding(fptr);
4484 rslen = RSTRING_LEN(rs);
4489 swallow(fptr,
'\n');
4491 if (!rb_enc_asciicompat(enc)) {
4495 rsptr = RSTRING_PTR(rs);
4496 rslen = RSTRING_LEN(rs);
4500 else if (rb_enc_mbminlen(enc) == 1) {
4501 rsptr = RSTRING_PTR(rs);
4502 newline = (
unsigned char)rsptr[rslen - 1];
4506 rsptr = RSTRING_PTR(rs);
4507 const char *e = rsptr + rslen;
4508 const char *last = rb_enc_prev_char(rsptr, e, e, enc);
4510 newline = rb_enc_codepoint_len(last, e, &n, enc);
4511 if (last + n != e) rb_raise(rb_eArgError,
"broken separator");
4513 chomp_cr = chomp && newline ==
'\n' && rslen == rb_enc_mbminlen(enc);
4517 while ((c = appendline(fptr, newline, &str, &limit, enc)) != EOF) {
4518 const char *s, *p, *pp, *e;
4520 if (c == newline && RSTRING_LEN(str) >= rslen) {
4521 s = RSTRING_PTR(str);
4524 if (at_char_boundary(s, p, e, enc)) {
4525 if (!rspara) rscheck(rsptr, rslen, rs);
4526 if (memcmp(p, rsptr, rslen) == 0) {
4528 if (chomp_cr && p > s && *(p-1) ==
'\r') --p;
4536 s = RSTRING_PTR(str);
4538 pp = rb_enc_prev_char(s, p, p, enc);
4539 if (extra_limit && pp &&
4553 if (rspara && c != EOF)
4554 swallow(fptr,
'\n');
4556 str = io_enc_str(str, fptr);
4559 if (!
NIL_P(str) && !nolimit) {
4567rb_io_getline_1(
VALUE rs,
long limit,
int chomp,
VALUE io)
4570 int old_lineno, new_lineno;
4574 old_lineno = fptr->
lineno;
4575 str = rb_io_getline_0(rs, limit, chomp, fptr);
4576 if (!
NIL_P(str) && (new_lineno = fptr->
lineno) != old_lineno) {
4577 if (io == ARGF.current_file) {
4578 ARGF.lineno += new_lineno - old_lineno;
4579 ARGF.last_lineno = ARGF.lineno;
4582 ARGF.last_lineno = new_lineno;
4590rb_io_getline(
int argc,
VALUE *argv,
VALUE io)
4594 prepare_getline_args(argc, argv, &args, io);
4595 return rb_io_getline_1(args.rs, args.limit, args.chomp, io);
4605rb_io_gets_limit_internal(
VALUE io,
long limit)
4609 return rb_io_getline_0(rb_default_rs, limit, FALSE, fptr);
4613rb_io_gets_internal(
VALUE io)
4615 return rb_io_gets_limit_internal(io, -1);
4695 str = rb_io_getline(argc, argv, io);
4711rb_io_lineno(
VALUE io)
4766 check_getline_args(&sep, &limit, io);
4768 VALUE line = rb_io_getline_1(sep, limit,
RTEST(chomp), io);
4769 rb_lastline_set_up(line, 1);
4844rb_io_readlines(
int argc,
VALUE *argv,
VALUE io)
4848 prepare_getline_args(argc, argv, &args, io);
4849 return io_readlines(&args, io);
4857 if (arg->limit == 0)
4858 rb_raise(rb_eArgError,
"invalid limit: 0 for readlines");
4860 while (!
NIL_P(line = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, io))) {
4973rb_io_each_line(
int argc,
VALUE *argv,
VALUE io)
4979 prepare_getline_args(argc, argv, &args, io);
4980 if (args.limit == 0)
4981 rb_raise(rb_eArgError,
"invalid limit: 0 for each_line");
4982 while (!
NIL_P(str = rb_io_getline_1(args.rs, args.limit, args.chomp, io))) {
5010rb_io_each_byte(
VALUE io)
5026 }
while (io_fillbuf(fptr) >= 0);
5036 if (NEED_READCONV(fptr)) {
5040 SET_BINARY_MODE(fptr);
5041 make_readconv(fptr, 0);
5055 if (more_char(fptr) == MORE_CHAR_FINISHED) {
5057 clear_readconv(fptr);
5061 str = rb_enc_str_new(fptr->
cbuf.
ptr+fptr->
cbuf.
off, 1, read_enc);
5064 if (fptr->
cbuf.
len == 0) clear_readconv(fptr);
5073 io_shift_cbuf(fptr, r, &str);
5080 ISASCII(RSTRING_PTR(str)[0])) {
5084 str = io_enc_str(str, fptr);
5089 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
5090 if (io_fillbuf(fptr) < 0) {
5112 if (io_fillbuf(fptr) != -1) {
5116 r = rb_enc_precise_mbclen(RSTRING_PTR(str), RSTRING_PTR(str)+RSTRING_LEN(str), enc);
5132 str = io_enc_str(str, fptr);
5159rb_io_each_char(
VALUE io)
5169 enc = io_input_encoding(fptr);
5171 while (!
NIL_P(c = io_getc(fptr, enc))) {
5198rb_io_each_codepoint(
VALUE io)
5210 enc = io_read_encoding(fptr);
5211 if (NEED_READCONV(fptr)) {
5212 SET_BINARY_MODE(fptr);
5215 make_readconv(fptr, 0);
5227 if (more_char(fptr) == MORE_CHAR_FINISHED) {
5228 clear_readconv(fptr);
5248 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
5249 while (io_fillbuf(fptr) >= 0) {
5264 char cbuf[8], *p = cbuf;
5266 if (more > numberof(cbuf))
goto invalid;
5268 if (more > numberof(cbuf))
goto invalid;
5269 while ((n = (
int)read_buffered_data(p, more, fptr)) > 0 &&
5270 (p += n, (more -= n) > 0)) {
5271 if (io_fillbuf(fptr) < 0)
goto invalid;
5272 if ((n = fptr->
rbuf.
len) > more) n = more;
5274 r = rb_enc_precise_mbclen(cbuf, p, enc);
5287 rb_raise(rb_eArgError,
"invalid byte sequence in %s", rb_enc_name(enc));
5320 enc = io_input_encoding(fptr);
5322 return io_getc(fptr, enc);
5346rb_io_readchar(
VALUE io)
5348 VALUE c = rb_io_getc(io);
5384 VALUE r_stdout = rb_ractor_stdout();
5389 rb_io_flush(r_stdout);
5392 if (io_fillbuf(fptr) < 0) {
5422rb_io_readbyte(
VALUE io)
5483 unsigned char c =
NUM2INT(v) & 0xFF;
5489 io_ungetbyte(b, fptr);
5545 else if (RB_BIGNUM_TYPE_P(c)) {
5551 if (NEED_READCONV(fptr)) {
5552 SET_BINARY_MODE(fptr);
5553 len = RSTRING_LEN(c);
5554#if SIZEOF_LONG > SIZEOF_INT
5558 make_readconv(fptr, (
int)
len);
5572 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
5573 io_ungetbyte(c, fptr);
5593rb_io_isatty(
VALUE io)
5598 return RBOOL(isatty(fptr->
fd) != 0);
5601#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5617rb_io_close_on_exec_p(
VALUE io)
5623 write_io = GetWriteIO(io);
5624 if (io != write_io) {
5626 if (fptr && 0 <= (fd = fptr->
fd)) {
5627 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->
pathv);
5628 if (!(ret & FD_CLOEXEC))
return Qfalse;
5633 if (fptr && 0 <= (fd = fptr->
fd)) {
5634 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->
pathv);
5635 if (!(ret & FD_CLOEXEC))
return Qfalse;
5640#define rb_io_close_on_exec_p rb_f_notimplement
5643#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5667 int flag =
RTEST(arg) ? FD_CLOEXEC : 0;
5672 write_io = GetWriteIO(io);
5673 if (io != write_io) {
5675 if (fptr && 0 <= (fd = fptr->
fd)) {
5676 if ((ret = fcntl(fptr->
fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->
pathv);
5677 if ((ret & FD_CLOEXEC) != flag) {
5678 ret = (ret & ~FD_CLOEXEC) | flag;
5679 ret = fcntl(fd, F_SETFD, ret);
5680 if (ret != 0) rb_sys_fail_path(fptr->
pathv);
5687 if (fptr && 0 <= (fd = fptr->
fd)) {
5688 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->
pathv);
5689 if ((ret & FD_CLOEXEC) != flag) {
5690 ret = (ret & ~FD_CLOEXEC) | flag;
5691 ret = fcntl(fd, F_SETFD, ret);
5692 if (ret != 0) rb_sys_fail_path(fptr->
pathv);
5698#define rb_io_set_close_on_exec rb_f_notimplement
5701#define RUBY_IO_EXTERNAL_P(f) ((f)->mode & FMODE_EXTERNAL)
5702#define PREP_STDIO_NAME(f) (RSTRING_PTR((f)->pathv))
5705finish_writeconv(
rb_io_t *fptr,
int noalloc)
5707 unsigned char *ds, *dp, *de;
5711 unsigned char buf[1024];
5716 de = buf +
sizeof(buf);
5719 size_t remaining = dp-ds;
5720 long result = rb_io_write_memory(fptr, ds, remaining);
5724 if ((
size_t)result == remaining)
break;
5747 if (io_fflush(fptr) < 0) {
5755 fptr->
wbuf.
len += (int)(dp - ds);
5771finish_writeconv_sync(
VALUE arg)
5774 return finish_writeconv(p->fptr, p->noalloc);
5778nogvl_close(
void *ptr)
5782 return (
void*)(intptr_t)close(*fd);
5786maygvl_close(
int fd,
int keepgvl)
5795 return IO_WITHOUT_GVL_INT(nogvl_close, &fd);
5799nogvl_fclose(
void *ptr)
5803 return (
void*)(intptr_t)fclose(file);
5807maygvl_fclose(
FILE *file,
int keepgvl)
5810 return fclose(file);
5812 return IO_WITHOUT_GVL_INT(nogvl_fclose, file);
5818fptr_finalize_flush(
rb_io_t *fptr,
int noraise,
int keepgvl)
5823 int mode = fptr->
mode;
5829 arg.noalloc = noraise;
5833 error = finish_writeconv(fptr, noraise);
5846 io_flush_buffer_sync(fptr);
5849 if (io_fflush(fptr) < 0 &&
NIL_P(error)) {
5857 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2) {
5867 rb_thread_io_close_wait(fptr);
5869 if (!done && stdio_file) {
5871 if ((maygvl_fclose(stdio_file, noraise) < 0) &&
NIL_P(error)) {
5881 if (!done && fd >= 0 && scheduler !=
Qnil) {
5884 if (!UNDEF_P(result)) {
5885 done =
RTEST(result);
5889 if (!done && fd >= 0) {
5895 if ((maygvl_close(fd, keepgvl) < 0) &&
NIL_P(error)) {
5904 if (!
NIL_P(error) && !noraise) {
5913fptr_finalize(
rb_io_t *fptr,
int noraise)
5915 fptr_finalize_flush(fptr, noraise, FALSE);
5916 free_io_buffer(&fptr->
rbuf);
5917 free_io_buffer(&fptr->
wbuf);
5918 clear_codeconv(fptr);
5922rb_io_fptr_cleanup(
rb_io_t *fptr,
int noraise)
5928 fptr_finalize(fptr, noraise);
5936 ruby_xfree_sized(buf->
ptr, (
size_t)buf->
capa);
5949 free_io_buffer(&fptr->
cbuf);
5965 clear_readconv(fptr);
5966 clear_writeconv(fptr);
5970rb_io_fptr_cleanup_all(
rb_io_t *fptr)
5974 rb_io_fptr_cleanup(fptr, TRUE);
5976 free_io_buffer(&fptr->
rbuf);
5977 free_io_buffer(&fptr->
wbuf);
5978 clear_codeconv(fptr);
5985 rb_io_fptr_cleanup_all(io);
5992rb_io_fptr_finalize_closed(
struct rb_io *io)
5994 if (!io)
return true;
5995 if (io->
fd >= 0)
return false;
6001rb_io_memsize(
const rb_io_t *io)
6003 size_t size =
sizeof(
rb_io_t);
6013 rb_serial_t fork_generation = GET_VM()->fork_gen;
6014 if (io->fork_generation == fork_generation) {
6025# define KEEPGVL TRUE
6027# define KEEPGVL FALSE
6031io_close_fptr(
VALUE io)
6037 write_io = GetWriteIO(io);
6038 if (io != write_io) {
6039 write_fptr =
RFILE(write_io)->fptr;
6040 if (write_fptr && 0 <= write_fptr->
fd) {
6041 rb_io_fptr_cleanup(write_fptr, TRUE);
6045 fptr =
RFILE(io)->fptr;
6046 if (!fptr)
return 0;
6047 if (fptr->
fd < 0)
return 0;
6050 if (rb_thread_io_close_interrupt(fptr)) {
6052 fptr_finalize_flush(fptr, FALSE, KEEPGVL);
6055 rb_io_fptr_cleanup(fptr, FALSE);
6060fptr_waitpid(
rb_io_t *fptr,
int nohang)
6064 rb_last_status_clear();
6073 rb_io_t *fptr = io_close_fptr(io);
6074 if (fptr) fptr_waitpid(fptr, 0);
6114rb_io_close_m(
VALUE io)
6116 rb_io_t *fptr = rb_io_get_fptr(io);
6125io_call_close(
VALUE io)
6134 enum {mesg_len =
sizeof(closed_stream)-1};
6135 VALUE mesg = rb_attr_get(exc, idMesg);
6137 RSTRING_LEN(mesg) != mesg_len ||
6138 memcmp(RSTRING_PTR(mesg), closed_stream, mesg_len)) {
6148 if (!UNDEF_P(closed) &&
RTEST(closed))
return io;
6149 rb_rescue2(io_call_close, io, ignore_closed_stream, io,
6185 write_io = GetWriteIO(io);
6186 if (io != write_io) {
6187 write_fptr =
RFILE(write_io)->fptr;
6188 if (write_fptr && 0 <= write_fptr->
fd) {
6193 fptr = rb_io_get_fptr(io);
6194 return RBOOL(0 > fptr->
fd);
6230rb_io_close_read(
VALUE io)
6236 if (fptr->
fd < 0)
return Qnil;
6237 if (is_socket(fptr->
fd, fptr->
pathv)) {
6241 if (shutdown(fptr->
fd, SHUT_RD) < 0)
6242 rb_sys_fail_path(fptr->
pathv);
6243 fptr->
mode &= ~FMODE_READABLE;
6249 write_io = GetWriteIO(io);
6250 if (io != write_io) {
6255 RFILE(io)->fptr = wfptr;
6258 RFILE(write_io)->fptr = fptr;
6259 rb_io_fptr_cleanup(fptr, FALSE);
6265 rb_raise(
rb_eIOError,
"closing non-duplex IO for reading");
6303rb_io_close_write(
VALUE io)
6308 write_io = GetWriteIO(io);
6310 if (fptr->
fd < 0)
return Qnil;
6311 if (is_socket(fptr->
fd, fptr->
pathv)) {
6322 if (io_fflush(fptr) < 0)
6323 rb_sys_fail_on_write(fptr);
6325 if (shutdown(fptr->
fd, SHUT_WR) < 0)
6326 rb_sys_fail_path(fptr->
pathv);
6327 fptr->
mode &= ~FMODE_WRITABLE;
6334 rb_raise(
rb_eIOError,
"closing non-duplex IO for writing");
6337 if (io != write_io) {
6357rb_io_sysseek(
int argc,
VALUE *argv,
VALUE io)
6359 VALUE offset, ptrname;
6360 int whence = SEEK_SET;
6364 if (
rb_scan_args(argc, argv,
"11", &offset, &ptrname) == 2) {
6365 whence = interpret_seek_whence(ptrname);
6370 (READ_DATA_BUFFERED(fptr) || READ_CHAR_PENDING(fptr))) {
6374 rb_warn(
"sysseek for buffered IO");
6377 pos = lseek(fptr->
fd, pos, whence);
6378 if (pos < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
6412 io = GetWriteIO(io);
6417 rb_warn(
"syswrite for buffered IO");
6420 tmp = rb_str_tmp_frozen_acquire(str);
6422 n = rb_io_write_memory(fptr, ptr,
len);
6423 if (n < 0) rb_sys_fail_path(fptr->
pathv);
6424 rb_str_tmp_frozen_release(str, tmp);
6441rb_io_sysread(
int argc,
VALUE *argv,
VALUE io)
6452 shrinkable = io_setstrbuf(&str, ilen);
6453 if (ilen == 0)
return str;
6458 if (READ_DATA_BUFFERED(fptr)) {
6464 io_setstrbuf(&str, ilen);
6469 iis.buf = RSTRING_PTR(str);
6472 n = io_read_memory_locktmp(str, &iis);
6475 rb_sys_fail_path(fptr->
pathv);
6478 io_set_read_length(str, n, shrinkable);
6480 if (n == 0 && ilen > 0) {
6496internal_pread_func(
void *_arg)
6500 return (
VALUE)pread(arg->fd, arg->buf, arg->count, arg->offset);
6504pread_internal_call(
VALUE _arg)
6509 if (scheduler !=
Qnil) {
6512 if (!UNDEF_P(result)) {
6517 return rb_io_blocking_region_wait(arg->io, internal_pread_func, arg,
RUBY_IO_READABLE);
6561 shrinkable = io_setstrbuf(&str, (
long)arg.count);
6562 if (arg.count == 0)
return str;
6563 arg.buf = RSTRING_PTR(str);
6576 rb_sys_fail_path(fptr->
pathv);
6578 io_set_read_length(str, n, shrinkable);
6579 if (n == 0 && arg.count > 0) {
6587internal_pwrite_func(
void *_arg)
6591 return (
VALUE)pwrite(arg->fd, arg->buf, arg->count, arg->offset);
6595pwrite_internal_call(
VALUE _arg)
6600 if (scheduler !=
Qnil) {
6603 if (!UNDEF_P(result)) {
6608 return rb_io_blocking_region_wait(arg->io, internal_pwrite_func, arg,
RUBY_IO_WRITABLE);
6649 io = GetWriteIO(io);
6656 tmp = rb_str_tmp_frozen_acquire(str);
6657 arg.buf = RSTRING_PTR(tmp);
6658 arg.count = (size_t)RSTRING_LEN(tmp);
6660 n = (ssize_t)pwrite_internal_call((
VALUE)&arg);
6661 if (n < 0) rb_sys_fail_path(fptr->
pathv);
6662 rb_str_tmp_frozen_release(str, tmp);
6678 fptr->
mode &= ~FMODE_TEXTMODE;
6682 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6685 setmode(fptr->
fd, O_BINARY);
6692io_ascii8bit_binmode(
rb_io_t *fptr)
6703 fptr->
mode &= ~FMODE_TEXTMODE;
6704 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6706 fptr->
encs.
enc = rb_ascii8bit_encoding();
6710 clear_codeconv(fptr);
6719 io_ascii8bit_binmode(fptr);
6736rb_io_binmode_m(
VALUE io)
6742 write_io = GetWriteIO(io);
6757rb_io_binmode_p(
VALUE io)
6765rb_io_fmode_modestr(
enum rb_io_mode fmode)
6769 return MODE_BTMODE(
"a+",
"ab+",
"at+");
6771 return MODE_BTMODE(
"a",
"ab",
"at");
6775 rb_raise(rb_eArgError,
"invalid access fmode 0x%x", fmode);
6777 return MODE_BTMODE(
"r",
"rb",
"rt");
6779 return MODE_BTXMODE(
"w",
"wb",
"wt",
"wx",
"wbx",
"wtx");
6782 return MODE_BTXMODE(
"w+",
"wb+",
"wt+",
"w+x",
"wb+x",
"wt+x");
6784 return MODE_BTMODE(
"r+",
"rb+",
"rt+");
6788static const char bom_prefix[] =
"bom|";
6789static const char utf_prefix[] =
"utf-";
6790enum {bom_prefix_len = (int)
sizeof(bom_prefix) - 1};
6791enum {utf_prefix_len = (int)
sizeof(utf_prefix) - 1};
6794io_encname_bom_p(
const char *name,
long len)
6796 return len > bom_prefix_len &&
STRNCASECMP(name, bom_prefix, bom_prefix_len) == 0;
6802 enum rb_io_mode fmode = 0;
6803 const char *m = modestr, *p = NULL;
6831 if (modestr[0] !=
'w')
6839 if (io_encname_bom_p(m, p ? (
long)(p - m) : (long)strlen(m)))
6852 rb_raise(rb_eArgError,
"invalid access mode %s", modestr);
6857rb_io_oflags_fmode(
int oflags)
6859 enum rb_io_mode fmode = 0;
6861 switch (oflags & O_ACCMODE) {
6873 if (oflags & O_APPEND) {
6876 if (oflags & O_TRUNC) {
6879 if (oflags & O_CREAT) {
6882 if (oflags & O_EXCL) {
6886 if (oflags & O_BINARY) {
6895rb_io_fmode_oflags(
enum rb_io_mode fmode)
6939rb_io_oflags_modestr(
int oflags)
6942# define MODE_BINARY(a,b) ((oflags & O_BINARY) ? (b) : (a))
6944# define MODE_BINARY(a,b) (a)
6947 if (oflags & O_EXCL) {
6948 rb_raise(rb_eArgError,
"exclusive access mode is not supported");
6950 accmode = oflags & (O_RDONLY|O_WRONLY|O_RDWR);
6951 if (oflags & O_APPEND) {
6952 if (accmode == O_WRONLY) {
6953 return MODE_BINARY(
"a",
"ab");
6955 if (accmode == O_RDWR) {
6956 return MODE_BINARY(
"a+",
"ab+");
6961 rb_raise(rb_eArgError,
"invalid access oflags 0x%x", oflags);
6963 return MODE_BINARY(
"r",
"rb");
6965 return MODE_BINARY(
"w",
"wb");
6967 if (oflags & O_TRUNC) {
6968 return MODE_BINARY(
"w+",
"wb+");
6970 return MODE_BINARY(
"r+",
"rb+");
6982 int default_ext = 0;
6985 ext = rb_default_external_encoding();
6988 if (rb_is_ascii8bit_enc(ext)) {
6992 else if (intern == NULL) {
6993 intern = rb_default_internal_encoding();
6998 *enc = (default_ext && intern != ext) ? NULL : ext;
7008unsupported_encoding(
const char *name,
rb_encoding *enc)
7010 rb_enc_warn(enc,
"Unsupported encoding %s ignored", name);
7014parse_mode_enc(
const char *estr,
rb_encoding *estr_enc,
7020 enum rb_io_mode fmode = fmode_p ? *fmode_p : 0;
7026 p = strrchr(estr,
':');
7027 len = p ? (p++ - estr) : (long)strlen(estr);
7029 estr += bom_prefix_len;
7030 len -= bom_prefix_len;
7031 if (!
STRNCASECMP(estr, utf_prefix, utf_prefix_len)) {
7035 rb_enc_warn(estr_enc,
"BOM with non-UTF encoding %s is nonsense", estr);
7036 fmode &= ~FMODE_SETENC_BY_BOM;
7044 memcpy(encname, estr,
len);
7045 encname[
len] =
'\0';
7048 idx = rb_enc_find_index(estr);
7050 if (fmode_p) *fmode_p = fmode;
7053 ext_enc = rb_enc_from_index(idx);
7056 unsupported_encoding(estr, estr_enc);
7062 if (*p ==
'-' && *(p+1) ==
'\0') {
7067 idx2 = rb_enc_find_index(p);
7069 unsupported_encoding(p, estr_enc);
7074 int_enc = rb_enc_from_index(idx2);
7078 rb_io_ext_int_to_encs(ext_enc, int_enc, enc_p, enc2_p, fmode);
7091 v = rb_hash_lookup2(opt, sym_encoding,
Qnil);
7092 if (v !=
Qnil) encoding = v;
7093 v = rb_hash_lookup2(opt, sym_extenc,
Qundef);
7094 if (v !=
Qnil) extenc = v;
7095 v = rb_hash_lookup2(opt, sym_intenc,
Qundef);
7096 if (!UNDEF_P(v)) intenc = v;
7098 if ((!UNDEF_P(extenc) || !UNDEF_P(intenc)) && !
NIL_P(encoding)) {
7100 int idx = rb_to_encoding_index(encoding);
7101 if (idx >= 0) encoding = rb_enc_from_encoding(rb_enc_from_index(idx));
7102 rb_warn(
"Ignoring encoding parameter '%"PRIsVALUE
"': %s_encoding is used",
7103 encoding, UNDEF_P(extenc) ?
"internal" :
"external");
7107 if (!UNDEF_P(extenc) && !
NIL_P(extenc)) {
7108 extencoding = rb_to_encoding(extenc);
7110 if (!UNDEF_P(intenc)) {
7111 if (
NIL_P(intenc)) {
7118 if (*p ==
'-' && *(p+1) ==
'\0') {
7123 intencoding = rb_to_encoding(intenc);
7127 intencoding = rb_to_encoding(intenc);
7129 if (extencoding == intencoding) {
7133 if (!
NIL_P(encoding)) {
7137 enc_p, enc2_p, fmode_p);
7140 rb_io_ext_int_to_encs(rb_to_encoding(encoding), NULL, enc_p, enc2_p, 0);
7143 else if (!UNDEF_P(extenc) || !UNDEF_P(intenc)) {
7145 rb_io_ext_int_to_encs(extencoding, intencoding, enc_p, enc2_p, 0);
7153 enum rb_io_mode fmode = *fmode_p;
7158 !rb_enc_asciicompat(enc ? enc : rb_default_external_encoding()))
7159 rb_raise(rb_eArgError,
"ASCII incompatible encoding needs binmode");
7162 rb_raise(rb_eArgError,
"newline decorator with binary mode");
7169#if !DEFAULT_TEXTMODE
7171 fmode &= ~FMODE_TEXTMODE;
7178extract_binmode(
VALUE opthash,
enum rb_io_mode *fmode)
7180 if (!
NIL_P(opthash)) {
7182 v = rb_hash_aref(opthash, sym_textmode);
7185 rb_raise(rb_eArgError,
"textmode specified twice");
7187 rb_raise(rb_eArgError,
"both textmode and binmode specified");
7191 v = rb_hash_aref(opthash, sym_binmode);
7194 rb_raise(rb_eArgError,
"binmode specified twice");
7196 rb_raise(rb_eArgError,
"both textmode and binmode specified");
7202 rb_raise(rb_eArgError,
"both textmode and binmode specified");
7208 int *oflags_p,
enum rb_io_mode *fmode_p,
struct rb_io_encoding *convconfig_p)
7212 enum rb_io_mode fmode;
7216 int has_enc = 0, has_vmode = 0;
7222 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
7232 fmode = rb_io_oflags_fmode(oflags);
7240 oflags = rb_io_fmode_oflags(fmode);
7244 parse_mode_enc(p+1, rb_enc_get(vmode), &enc, &enc2, &fmode);
7249 e = (fmode &
FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
7250 rb_io_ext_int_to_encs(e, NULL, &enc, &enc2, fmode);
7254 if (
NIL_P(opthash)) {
7258#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7260 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7261 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7263 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
7270 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
7273 else if (
NIL_P(vmode)) {
7274 fmode |= DEFAULT_TEXTMODE;
7281 v = rb_hash_aref(opthash, sym_mode);
7283 if (!
NIL_P(vmode)) {
7284 rb_raise(rb_eArgError,
"mode specified twice");
7291 v = rb_hash_aref(opthash, sym_flags);
7296 fmode = rb_io_oflags_fmode(oflags);
7298 extract_binmode(opthash, &fmode);
7304 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
7307 else if (
NIL_P(vmode)) {
7308 fmode |= DEFAULT_TEXTMODE;
7311 v = rb_hash_aref(opthash, sym_perm);
7314 if (!
NIL_P(*vperm_p)) {
7315 rb_raise(rb_eArgError,
"perm specified twice");
7326#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7328 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7329 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7334 rb_raise(rb_eArgError,
"encoding specified twice");
7337 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
7341 validate_enc_binmode(&fmode, ecflags, enc, enc2);
7347 convconfig_p->
enc = enc;
7348 convconfig_p->
enc2 = enc2;
7349 convconfig_p->
ecflags = ecflags;
7350 convconfig_p->
ecopts = ecopts;
7360sysopen_func(
void *ptr)
7363 const char *fname = RSTRING_PTR(data->fname);
7372 fd = IO_WITHOUT_GVL_INT(sysopen_func, data);
7373 }
while (fd < 0 &&
errno == EINTR);
7380rb_sysopen(
VALUE fname,
int oflags, mode_t perm)
7385 data.fname = rb_str_encode_ospath(fname);
7387 data.oflags = oflags;
7390 TRY_WITH_GC((fd = rb_sysopen_internal(&data)) >= 0) {
7391 rb_syserr_fail_path(first_errno, fname);
7397fdopen_internal(
int fd,
const char *modestr)
7404 file = fdopen(fd, modestr);
7420 TRY_WITH_GC((file = fdopen_internal(fd, modestr)) != 0) {
7426 if (setvbuf(file, NULL, _IOFBF, 0) != 0)
7427 rb_warn(
"setvbuf() can't be honoured (fd=%d)", fd);
7435 int t = isatty(fptr->
fd);
7445io_strip_bom(
VALUE io)
7447 VALUE b1, b2, b3, b4;
7458 return rb_utf8_encindex();
7468 return ENCINDEX_UTF_16BE;
7479 return ENCINDEX_UTF_32LE;
7484 return ENCINDEX_UTF_16LE;
7494 return ENCINDEX_UTF_32BE;
7508io_set_encoding_by_bom(
VALUE io)
7510 int idx = io_strip_bom(io);
7516 extenc = rb_enc_from_index(idx);
7517 io_encoding_set(fptr, rb_enc_from_encoding(extenc),
7518 rb_io_internal_encoding(io),
Qnil);
7527rb_file_open_generic(
VALUE io,
VALUE filename,
int oflags,
enum rb_io_mode fmode,
7535 rb_io_ext_int_to_encs(NULL, NULL, &cc.enc, &cc.enc2, fmode);
7540 validate_enc_binmode(&fmode, convconfig->
ecflags,
7541 convconfig->
enc, convconfig->
enc2);
7545 fptr->
encs = *convconfig;
7548 if (!(oflags & O_TMPFILE)) {
7549 fptr->
pathv = pathv;
7552 fptr->
pathv = pathv;
7554 fptr->
fd = rb_sysopen(pathv, oflags, perm);
7562rb_file_open_internal(
VALUE io,
VALUE filename,
const char *modestr)
7565 const char *p = strchr(modestr,
':');
7569 parse_mode_enc(p+1, rb_usascii_encoding(),
7570 &convconfig.
enc, &convconfig.
enc2, &fmode);
7576 e = (fmode &
FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
7577 rb_io_ext_int_to_encs(e, NULL, &convconfig.
enc, &convconfig.
enc2, fmode);
7583#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7585 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7586 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7588 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.
enc2, convconfig.
ecflags);
7591 return rb_file_open_generic(io, filename,
7592 rb_io_fmode_oflags(fmode),
7602 return rb_file_open_internal(io_alloc(
rb_cFile), fname, modestr);
7611#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7634 while ((tmp = *prev) != 0) {
7635 if (tmp->fptr == fptr) {
7644#if defined (_WIN32) || defined(__CYGWIN__)
7653 if (!rb_current_execution_context(
false))
return;
7664pipe_finalize(
rb_io_t *fptr,
int noraise)
7666#if !defined(HAVE_WORKING_FORK) && !defined(_WIN32)
7675 fptr_finalize(fptr, noraise);
7677 pipe_del_fptr(fptr);
7684#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7685 void (*
const old_finalize)(
struct rb_io*,int) = fptr->
finalize;
7687 if (old_finalize == orig->finalize)
return;
7692#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7693 if (old_finalize != pipe_finalize) {
7695 for (list =
pipe_list; list; list = list->next) {
7696 if (list->fptr == fptr)
break;
7698 if (!list) pipe_add_fptr(fptr);
7701 pipe_del_fptr(fptr);
7727#define spawnv(mode, cmd, args) rb_w32_uaspawn((mode), (cmd), (args))
7728#define spawn(mode, cmd) rb_w32_uspawn((mode), (cmd), 0)
7731#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7741#ifdef HAVE_WORKING_FORK
7742# ifndef __EMSCRIPTEN__
7744popen_redirect(
struct popen_arg *p)
7747 close(p->write_pair[1]);
7748 if (p->write_pair[0] != 0) {
7749 dup2(p->write_pair[0], 0);
7750 close(p->write_pair[0]);
7753 if (p->pair[1] != 1) {
7754 dup2(p->pair[1], 1);
7760 if (p->pair[1] != 1) {
7761 dup2(p->pair[1], 1);
7767 if (p->pair[0] != 0) {
7768 dup2(p->pair[0], 0);
7775#if defined(__linux__)
7786linux_get_maxfd(
void)
7789 char buf[4096], *p, *np, *e;
7792 if (fd < 0)
return fd;
7793 ss = read(fd, buf,
sizeof(buf));
7794 if (ss < 0)
goto err;
7797 while ((
int)
sizeof(
"FDSize:\t0\n")-1 <= e-p &&
7798 (np = memchr(p,
'\n', e-p)) != NULL) {
7799 if (memcmp(p,
"FDSize:",
sizeof(
"FDSize:")-1) == 0) {
7801 p +=
sizeof(
"FDSize:")-1;
7821#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
7823 int max = (int)max_file_descriptor;
7826 ret = fcntl(0, F_MAXFD);
7828 maxhint = max = ret;
7829# elif defined(__linux__)
7830 ret = linux_get_maxfd();
7837 for (fd = lowfd; fd <= max; fd++) {
7838 if (!
NIL_P(noclose_fds) &&
7841 ret = fcntl(fd, F_GETFD);
7842 if (ret != -1 && !(ret & FD_CLOEXEC)) {
7843 fcntl(fd, F_SETFD, ret|FD_CLOEXEC);
7845# define CONTIGUOUS_CLOSED_FDS 20
7847 if (max < fd + CONTIGUOUS_CLOSED_FDS)
7848 max = fd + CONTIGUOUS_CLOSED_FDS;
7854# ifndef __EMSCRIPTEN__
7856popen_exec(
void *pp,
char *errmsg,
size_t errmsg_len)
7858 struct popen_arg *p = (
struct popen_arg*)pp;
7860 return rb_exec_async_signal_safe(p->eargp, errmsg, errmsg_len);
7865#if (defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)) && !defined __EMSCRIPTEN__
7867rb_execarg_fixup_v(
VALUE execarg_obj)
7869 rb_execarg_parent_start(execarg_obj);
7873char *rb_execarg_commandline(
const struct rb_execarg *eargp,
VALUE *prog);
7876#ifndef __EMSCRIPTEN__
7878pipe_open(
VALUE execarg_obj,
const char *modestr,
enum rb_io_mode fmode,
7881 struct rb_execarg *eargp =
NIL_P(execarg_obj) ? NULL : rb_execarg_get(execarg_obj);
7882 VALUE prog = eargp ? (eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name) :
Qfalse ;
7888#if defined(HAVE_WORKING_FORK)
7890 char errmsg[80] = {
'\0' };
7892#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7894 struct popen_arg arg;
7897#if defined(HAVE_SPAWNV)
7898# define DO_SPAWN(cmd, args) ((args) ? \
7899 spawnv(P_NOWAIT, (cmd), (args)) : \
7900 spawn(P_NOWAIT, (cmd)))
7901# if !defined(HAVE_WORKING_FORK)
7905#if !defined(HAVE_WORKING_FORK)
7911#if !defined(HAVE_WORKING_FORK)
7912 const char *cmd = 0;
7918#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7919 arg.execarg_obj = execarg_obj;
7922 arg.pair[0] = arg.pair[1] = -1;
7923 arg.write_pair[0] = arg.write_pair[1] = -1;
7924# if !defined(HAVE_WORKING_FORK)
7925 if (eargp && !eargp->use_shell) {
7926 args = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
7931 if (
rb_pipe(arg.write_pair) < 0)
7932 rb_sys_fail_str(prog);
7935 close(arg.write_pair[0]);
7936 close(arg.write_pair[1]);
7940 rb_execarg_addopt(execarg_obj,
INT2FIX(0),
INT2FIX(arg.write_pair[0]));
7941 rb_execarg_addopt(execarg_obj,
INT2FIX(1),
INT2FIX(arg.pair[1]));
7946 rb_sys_fail_str(prog);
7948 rb_execarg_addopt(execarg_obj,
INT2FIX(1),
INT2FIX(arg.pair[1]));
7952 rb_sys_fail_str(prog);
7954 rb_execarg_addopt(execarg_obj,
INT2FIX(0),
INT2FIX(arg.pair[0]));
7957 rb_sys_fail_str(prog);
7959 if (!
NIL_P(execarg_obj)) {
7960 rb_protect(rb_execarg_fixup_v, execarg_obj, &state);
7962 if (0 <= arg.write_pair[0]) close(arg.write_pair[0]);
7963 if (0 <= arg.write_pair[1]) close(arg.write_pair[1]);
7964 if (0 <= arg.pair[0]) close(arg.pair[0]);
7965 if (0 <= arg.pair[1]) close(arg.pair[1]);
7966 rb_execarg_parent_end(execarg_obj);
7970# if defined(HAVE_WORKING_FORK)
7971 pid = rb_fork_async_signal_safe(&status, popen_exec, &arg, arg.eargp->redirect_fds, errmsg,
sizeof(errmsg));
7973 rb_execarg_run_options(eargp, sargp, NULL, 0);
7974 while ((pid = DO_SPAWN(cmd, args)) < 0) {
7976 switch (e =
errno) {
7978# if EWOULDBLOCK != EAGAIN
7987 rb_execarg_run_options(sargp, NULL, NULL, 0);
7989 rb_execarg_parent_end(execarg_obj);
7992# if defined(HAVE_WORKING_FORK)
7993 pid = rb_call_proc__fork();
7995 popen_redirect(&arg);
8007# if defined(HAVE_WORKING_FORK)
8013 close(arg.write_pair[0]);
8014 close(arg.write_pair[1]);
8016# if defined(HAVE_WORKING_FORK)
8025 close(arg.write_pair[0]);
8026 write_fd = arg.write_pair[1];
8037 cmd = rb_execarg_commandline(eargp, &prog);
8038 if (!
NIL_P(execarg_obj)) {
8039 rb_execarg_parent_start(execarg_obj);
8040 rb_execarg_run_options(eargp, sargp, NULL, 0);
8042 fp = popen(cmd, modestr);
8045 rb_execarg_parent_end(execarg_obj);
8046 rb_execarg_run_options(sargp, NULL, NULL, 0);
8048 if (!fp) rb_syserr_fail_path(e, prog);
8058 fptr->
encs = *convconfig;
8059#if RUBY_CRLF_ENVIRONMENT
8066 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
8069#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
8070 if (NEED_NEWLINE_DECORATOR_ON_WRITE(fptr)) {
8071 fptr->
encs.
ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
8077 if (0 <= write_fd) {
8078 write_port = io_alloc(
rb_cIO);
8080 write_fptr->
fd = write_fd;
8082 fptr->
mode &= ~FMODE_WRITABLE;
8084 rb_ivar_set(port, rb_intern(
"@tied_io_for_writing"), write_port);
8087#if defined (__CYGWIN__) || !defined(HAVE_WORKING_FORK)
8089 pipe_add_fptr(fptr);
8095pipe_open(
VALUE execarg_obj,
const char *modestr,
enum rb_io_mode fmode,
8103is_popen_fork(
VALUE prog)
8105 if (RSTRING_LEN(prog) == 1 && RSTRING_PTR(prog)[0] ==
'-') {
8106#if !defined(HAVE_WORKING_FORK)
8108 "fork() function is unimplemented on this machine");
8117pipe_open_s(
VALUE prog,
const char *modestr,
enum rb_io_mode fmode,
8121 VALUE *argv = &prog;
8124 if (!is_popen_fork(prog))
8125 execarg_obj = rb_execarg_new(argc, argv, TRUE, FALSE);
8126 return pipe_open(execarg_obj, modestr, fmode, convconfig);
8132 rb_io_t *fptr = io_close_fptr(io);
8301rb_io_s_popen(
int argc,
VALUE *argv,
VALUE klass)
8305 if (argc > 1 && !
NIL_P(opt = rb_check_hash_type(argv[argc-1]))) --argc;
8306 if (argc > 1 && !
NIL_P(env = rb_check_hash_type(argv[0]))) --argc, ++argv;
8315 int ex = !
NIL_P(opt);
8316 rb_error_arity(argc + ex, 1 + ex, 2 + ex);
8319 return popen_finish(rb_io_popen(pname, pmode, env, opt), klass);
8325 const char *modestr;
8328 enum rb_io_mode fmode;
8334#if SIZEOF_LONG > SIZEOF_INT
8335 if (
len > INT_MAX) {
8336 rb_raise(rb_eArgError,
"too many arguments");
8345 if (!is_popen_fork(pname))
8346 execarg_obj = rb_execarg_new(1, &pname, TRUE, FALSE);
8348 if (!
NIL_P(execarg_obj)) {
8350 opt = rb_execarg_extract_options(execarg_obj, opt);
8352 rb_execarg_setenv(execarg_obj, env);
8355 modestr = rb_io_oflags_modestr(oflags);
8357 return pipe_open(execarg_obj, modestr, fmode, &convconfig);
8367 rb_io_flush(rb_ractor_stdout());
8368 rb_io_flush(rb_ractor_stderr());
8369 _exit(EXIT_SUCCESS);
8373 RBASIC_SET_CLASS(port, klass);
8380#if defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)
8381struct popen_writer_arg {
8383 struct popen_arg popen;
8387exec_popen_writer(
void *arg,
char *errmsg,
size_t buflen)
8389 struct popen_writer_arg *pw = arg;
8391 popen_redirect(&pw->popen);
8392 execv(pw->argv[0], pw->argv);
8393 strlcpy(errmsg, strerror(
errno), buflen);
8399ruby_popen_writer(
char *
const *argv, rb_pid_t *pid)
8401#if (defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)) || defined(_WIN32)
8402# ifdef HAVE_WORKING_FORK
8403 struct popen_writer_arg pw;
8404 int *
const write_pair = pw.popen.pair;
8410 if (cloexec_pipe(write_pair, 0,
false) == 0) {
8411# ifdef HAVE_WORKING_FORK
8414 char errmsg[80] = {
'\0'};
8415 *pid = rb_fork_async_signal_safe(&status, exec_popen_writer, &pw,
Qnil, errmsg,
sizeof(errmsg));
8417 *pid = rb_w32_uspawn_process(P_NOWAIT, argv[0], argv, write_pair[0], -1, -1, 0);
8418 const char *errmsg = (*pid < 0) ? strerror(
errno) : NULL;
8420 close(write_pair[0]);
8422 close(write_pair[1]);
8423 fprintf(stderr,
"ruby_popen_writer(%s): %s\n", argv[0], errmsg);
8426 return fdopen(write_pair[1],
"w");
8437 enum rb_io_mode fmode;
8446 rb_file_open_generic(io, fname, oflags, fmode, &convconfig, perm);
8498rb_io_s_open(
int argc,
VALUE *argv,
VALUE klass)
8530 VALUE fname, vmode, vperm;
8535 rb_scan_args(argc, argv,
"12", &fname, &vmode, &vperm);
8546 if (
NIL_P(vperm)) perm = 0666;
8550 fd = rb_sysopen(fname, oflags, perm);
8582 int redirect = FALSE;
8590 VALUE tmp = argv[0];
8608 return rb_io_s_open(argc, argv,
rb_cFile);
8612rb_io_open_generic(
VALUE klass,
VALUE filename,
int oflags,
enum rb_io_mode fmode,
8615 return rb_file_open_generic(io_alloc(klass), filename,
8616 oflags, fmode, convconfig, perm);
8623 enum rb_io_mode fmode;
8629 return rb_io_open_generic(io, filename, oflags, fmode, &convconfig, perm);
8643 if (fptr == orig)
return io;
8644 if (RUBY_IO_EXTERNAL_P(fptr)) {
8648 rb_raise(rb_eArgError,
8649 "%s can't change access mode from \"%s\" to \"%s\"",
8650 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->
mode),
8651 rb_io_fmode_modestr(orig->
mode));
8654 flush_before_seek(fptr,
true);
8656 clear_codeconv(fptr);
8658 pos = io_tell(orig);
8661 if (io_fflush(orig) < 0)
8662 rb_sys_fail_on_write(fptr);
8671 else if (!RUBY_IO_EXTERNAL_P(fptr)) fptr->
pathv =
Qnil;
8672 fptr_copy_finalizer(fptr, orig);
8678 rb_thread_io_close_interrupt(fptr);
8679 rb_thread_io_close_wait(fptr);
8681 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2 || !fptr->stdio_file) {
8684 rb_sys_fail_path(orig->
pathv);
8692 rb_sys_fail_path(orig->
pathv);
8698 if (io_seek(fptr, pos, SEEK_SET) < 0 &&
errno) {
8699 rb_sys_fail_path(fptr->
pathv);
8701 if (io_seek(orig, pos, SEEK_SET) < 0 &&
errno) {
8702 rb_sys_fail_path(orig->
pathv);
8716int rb_freopen(
VALUE fname,
const char *mode,
FILE *fp);
8719rb_freopen(
VALUE fname,
const char *mode,
FILE *fp)
8721 if (!freopen(RSTRING_PTR(fname), mode, fp)) {
8764rb_io_reopen(
int argc,
VALUE *argv,
VALUE file)
8766 VALUE fname, nmode, opt;
8770 if (
rb_scan_args(argc, argv,
"11:", &fname, &nmode, &opt) == 1) {
8773 return io_reopen(file, tmp);
8779 fptr =
RFILE(file)->fptr;
8785 enum rb_io_mode fmode;
8789 if (RUBY_IO_EXTERNAL_P(fptr) &&
8792 rb_raise(rb_eArgError,
8793 "%s can't change access mode from \"%s\" to \"%s\"",
8794 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->
mode),
8795 rb_io_fmode_modestr(fmode));
8798 fptr->
encs = convconfig;
8801 oflags = rb_io_fmode_oflags(fptr->
mode);
8804 fptr->
pathv = fname;
8806 fptr->
fd = rb_sysopen(fptr->
pathv, oflags, 0666);
8812 if (io_fflush(fptr) < 0)
8813 rb_sys_fail_on_write(fptr);
8816 clear_codeconv(fptr);
8819 int e = rb_freopen(rb_str_encode_ospath(fptr->
pathv),
8820 rb_io_oflags_modestr(oflags),
8822 if (e) rb_syserr_fail_path(e, fptr->
pathv);
8826 if (setvbuf(fptr->
stdio_file, NULL, _IOFBF, 0) != 0)
8827 rb_warn(
"setvbuf() can't be honoured for %"PRIsVALUE, fptr->
pathv);
8830 if (setvbuf(fptr->
stdio_file, NULL, _IONBF, BUFSIZ) != 0)
8831 rb_warn(
"setvbuf() can't be honoured for %"PRIsVALUE, fptr->
pathv);
8833 else if (fptr->
stdio_file == stdout && isatty(fptr->
fd)) {
8834 if (setvbuf(fptr->
stdio_file, NULL, _IOLBF, BUFSIZ) != 0)
8835 rb_warn(
"setvbuf() can't be honoured for %"PRIsVALUE, fptr->
pathv);
8839 int tmpfd = rb_sysopen(fptr->
pathv, oflags, 0666);
8845 rb_syserr_fail_path(err, fptr->
pathv);
8869 fptr->
mode = orig->
mode & ~FMODE_EXTERNAL;
8876 fptr->closing_ec = NULL;
8877 fptr->wakeup_mutex =
Qnil;
8878 fptr->fork_generation = GET_VM()->fork_gen;
8881 fptr_copy_finalizer(fptr, orig);
8883 fd = ruby_dup(orig->
fd);
8885 pos = io_tell(orig);
8887 io_seek(fptr, pos, SEEK_SET);
8892 write_io = GetWriteIO(io);
8893 if (io != write_io) {
8896 rb_ivar_set(dest, rb_intern(
"@tied_io_for_writing"), write_io);
8959 if (argc == 0)
return Qnil;
8961 out = rb_ractor_stdout();
8973extern void rb_deprecated_str_setter(
VALUE val,
ID id,
VALUE *var);
8978 rb_deprecated_str_setter(val,
id, &val);
8984 val = rb_str_frozen_bare_string(val);
9061 for (i=0; i<argc; i++) {
9065 rb_io_write(out, argv[i]);
9162 rb_io_write(io, str);
9166#define forward(obj, id, argc, argv) \
9167 rb_funcallv_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
9168#define forward_public(obj, id, argc, argv) \
9169 rb_funcallv_public_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
9170#define forward_current(id, argc, argv) \
9171 forward_public(ARGF.current_file, id, argc, argv)
9188 VALUE r_stdout = rb_ractor_stdout();
9189 if (recv == r_stdout) {
9190 return rb_io_putc(recv, ch);
9192 return forward(r_stdout, rb_intern(
"putc"), 1, &ch);
9197rb_str_end_with_asciichar(
VALUE str,
int c)
9199 long len = RSTRING_LEN(str);
9200 const char *
ptr = RSTRING_PTR(str);
9204 if (
len == 0)
return 0;
9205 if ((n = rb_enc_mbminlen(
enc)) == 1) {
9206 return ptr[
len - 1] == c;
9208 return rb_enc_ascget(
ptr + ((
len - 1) / n) * n,
ptr +
len, &n,
enc) == c;
9219 rb_io_puts(1, &tmp, out);
9226 rb_io_puts(1, &tmp, out);
9281 VALUE line, args[2];
9288 for (
int i = 0; i < argc; i++) {
9302 if (RSTRING_LEN(line) == 0) {
9307 if (!rb_str_end_with_asciichar(line,
'\n')) {
9312 rb_io_writev(out, n, args);
9330 VALUE r_stdout = rb_ractor_stdout();
9331 if (recv == r_stdout) {
9332 return rb_io_puts(argc, argv, recv);
9334 return forward(r_stdout, rb_intern(
"puts"), argc, argv);
9338rb_p_write(
VALUE str)
9343 VALUE r_stdout = rb_ractor_stdout();
9346 io_writev(2, args, r_stdout);
9349 rb_io_writev(r_stdout, 2, args);
9361rb_p_result(
int argc,
const VALUE *argv)
9368 else if (argc > 1) {
9371 VALUE r_stdout = rb_ractor_stdout();
9373 rb_uninterruptible(rb_io_flush, r_stdout);
9414 for (i=0; i<argc; i++) {
9416 rb_uninterruptible(rb_p_write, inspected);
9418 return rb_p_result(argc, argv);
9439rb_obj_display(
int argc,
VALUE *argv,
VALUE self)
9443 out = (!
rb_check_arity(argc, 0, 1) ? rb_ractor_stdout() : argv[0]);
9444 rb_io_write(out, self);
9450rb_stderr_to_original_p(
VALUE err)
9452 return (err == orig_stderr ||
RFILE(orig_stderr)->fptr->
fd < 0);
9458 VALUE out = rb_ractor_stderr();
9459 if (rb_stderr_to_original_p(out)) {
9461 if (isatty(fileno(stderr))) {
9462 if (rb_w32_write_console(
rb_str_new(mesg,
len), fileno(stderr)) > 0)
return;
9465 if (fwrite(mesg,
sizeof(
char), (
size_t)
len, stderr) < (
size_t)
len) {
9482rb_write_error_str(
VALUE mesg)
9484 VALUE out = rb_ractor_stderr();
9486 if (rb_stderr_to_original_p(out)) {
9487 size_t len = (size_t)RSTRING_LEN(mesg);
9489 if (isatty(fileno(stderr))) {
9490 if (rb_w32_write_console(mesg, fileno(stderr)) > 0)
return;
9493 if (fwrite(RSTRING_PTR(mesg),
sizeof(
char),
len, stderr) <
len) {
9500 rb_io_write(out, mesg);
9505rb_stderr_tty_p(
void)
9507 if (rb_stderr_to_original_p(rb_ractor_stderr()))
9508 return isatty(fileno(stderr));
9513must_respond_to(
ID mid,
VALUE val,
ID id)
9516 rb_raise(
rb_eTypeError,
"%"PRIsVALUE
" must have %"PRIsVALUE
" method, %"PRIsVALUE
" given",
9517 rb_id2str(
id), rb_id2str(mid),
9537 must_respond_to(id_write, val,
id);
9544 return rb_ractor_stdout();
9550 must_respond_to(id_write, val,
id);
9557 return rb_ractor_stderr();
9561allocate_and_open_new_file(
VALUE klass)
9563 VALUE self = io_alloc(klass);
9564 rb_io_make_open_file(self);
9572 VALUE self = rb_protect(allocate_and_open_new_file, klass, &state);
9580 maygvl_close(descriptor, 0);
9588 io->
fd = descriptor;
9606 io->closing_ec = NULL;
9607 io->wakeup_mutex =
Qnil;
9608 io->fork_generation = GET_VM()->fork_gen;
9611 io->
encs = *encoding;
9620prep_io(
int fd,
enum rb_io_mode fmode,
VALUE klass,
const char *path)
9630 e = (fmode &
FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
9631 rb_io_ext_int_to_encs(e, NULL, &convconfig.
enc, &convconfig.
enc2, fmode);
9635#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9637 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
9638 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
9640 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.
enc2, convconfig.
ecflags);
9646 if (!io_check_tty(io)) {
9649 setmode(fd, O_BINARY);
9661 if (path && strcmp(path,
"-")) klass =
rb_cFile;
9662 return prep_io(fd, rb_io_oflags_fmode(oflags), klass, path);
9666prep_stdio(
FILE *f,
enum rb_io_mode fmode,
VALUE klass,
const char *path)
9673#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9674 fptr->
encs.
ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
9685rb_io_prep_stdin(
void)
9691rb_io_prep_stdout(
void)
9697rb_io_prep_stderr(
void)
9706 int oflags = rb_io_fmode_oflags(fptr->
mode) & ~O_EXCL;
9733 rb_io_buffer_init(&fp->
wbuf);
9734 rb_io_buffer_init(&fp->
rbuf);
9735 rb_io_buffer_init(&fp->
cbuf);
9750 fp->closing_ec = NULL;
9751 fp->wakeup_mutex =
Qnil;
9752 fp->fork_generation = GET_VM()->fork_gen;
9757rb_io_make_open_file(
VALUE obj)
9762 if (
RFILE(obj)->fptr) {
9765 RFILE(obj)->fptr = 0;
9767 fp = rb_io_fptr_new();
9769 RFILE(obj)->fptr = fp;
9818rb_io_initialize(
int argc,
VALUE *argv,
VALUE io)
9824 return io_initialize(io, fnum, vmode, opt);
9831 int fd, oflags = O_RDONLY;
9832 enum rb_io_mode fmode;
9834#if defined(HAVE_FCNTL) && defined(F_GETFL)
9844 rb_raise(rb_eArgError,
"The given fd is not accessible because RubyVM reserves it");
9846#if defined(HAVE_FCNTL) && defined(F_GETFL)
9847 oflags = fcntl(fd, F_GETFL);
9848 if (oflags == -1) rb_sys_fail(0);
9850 if (fstat(fd, &st) < 0) rb_sys_fail(0);
9853#if defined(HAVE_FCNTL) && defined(F_GETFL)
9854 ofmode = rb_io_oflags_fmode(oflags);
9866 if (rb_hash_aref(opt, sym_autoclose) ==
Qfalse) {
9870 path = rb_hash_aref(opt,
RB_ID2SYM(idPath));
9881 fp->
encs = convconfig;
9885 fp->closing_ec = NULL;
9886 fp->wakeup_mutex =
Qnil;
9887 fp->fork_generation = GET_VM()->fork_gen;
9890 if (fileno(stdin) == fd)
9892 else if (fileno(stdout) == fd)
9894 else if (fileno(stderr) == fd)
9926rb_io_set_encoding_by_bom(
VALUE io)
9932 rb_raise(rb_eArgError,
"ASCII incompatible encoding needs binmode");
9935 rb_raise(rb_eArgError,
"encoding conversion is set");
9937 else if (fptr->
encs.
enc && fptr->
encs.
enc != rb_ascii8bit_encoding()) {
9938 rb_raise(rb_eArgError,
"encoding is set to %s already",
9941 if (!io_set_encoding_by_bom(io))
return Qnil;
9942 return rb_enc_from_encoding(fptr->
encs.
enc);
9995rb_file_initialize(
int argc,
VALUE *argv,
VALUE io)
9997 if (
RFILE(io)->fptr) {
10000 VALUE fname, vmode, vperm, opt;
10001 int posargc =
rb_scan_args(argc, argv,
"12:", &fname, &vmode, &vperm, &opt);
10006 return io_initialize(io, fd, vmode, opt);
10009 return rb_open_file(io, fname, vmode, vperm, opt);
10014rb_io_s_new(
int argc,
VALUE *argv,
VALUE klass)
10019 rb_warn(
"%"PRIsVALUE
"::new() does not take block; use %"PRIsVALUE
"::open() instead",
10035rb_io_s_for_fd(
int argc,
VALUE *argv,
VALUE klass)
10038 rb_io_initialize(argc, argv, io);
10051rb_io_autoclose_p(
VALUE io)
10076rb_io_set_autoclose(
VALUE io,
VALUE autoclose)
10080 if (!
RTEST(autoclose))
10083 fptr->
mode &= ~FMODE_EXTERNAL;
10088io_wait_event(
VALUE io,
int event,
VALUE timeout,
int return_io)
10098 if (mask & event) {
10120io_wait_readable(
int argc,
VALUE *argv,
VALUE io)
10127 if (rb_io_read_pending(fptr))
return Qtrue;
10130 VALUE timeout = (argc == 1 ? argv[0] :
Qnil);
10144io_wait_writable(
int argc,
VALUE *argv,
VALUE io)
10152 VALUE timeout = (argc == 1 ? argv[0] :
Qnil);
10167io_wait_priority(
int argc,
VALUE *argv,
VALUE io)
10174 if (rb_io_read_pending(fptr))
return Qtrue;
10177 VALUE timeout = argc == 1 ? argv[0] :
Qnil;
10183wait_mode_sym(
VALUE mode)
10185 if (mode ==
ID2SYM(rb_intern(
"r"))) {
10186 return RB_WAITFD_IN;
10188 if (mode ==
ID2SYM(rb_intern(
"read"))) {
10189 return RB_WAITFD_IN;
10191 if (mode ==
ID2SYM(rb_intern(
"readable"))) {
10192 return RB_WAITFD_IN;
10194 if (mode ==
ID2SYM(rb_intern(
"w"))) {
10195 return RB_WAITFD_OUT;
10197 if (mode ==
ID2SYM(rb_intern(
"write"))) {
10198 return RB_WAITFD_OUT;
10200 if (mode ==
ID2SYM(rb_intern(
"writable"))) {
10201 return RB_WAITFD_OUT;
10203 if (mode ==
ID2SYM(rb_intern(
"rw"))) {
10204 return RB_WAITFD_IN|RB_WAITFD_OUT;
10206 if (mode ==
ID2SYM(rb_intern(
"read_write"))) {
10207 return RB_WAITFD_IN|RB_WAITFD_OUT;
10209 if (mode ==
ID2SYM(rb_intern(
"readable_writable"))) {
10210 return RB_WAITFD_IN|RB_WAITFD_OUT;
10213 rb_raise(rb_eArgError,
"unsupported mode: %"PRIsVALUE, mode);
10217io_event_from_value(
VALUE value)
10221 if (events <= 0) rb_raise(rb_eArgError,
"Events must be positive integer!");
10259 for (
int i = 0; i < argc; i += 1) {
10261 events |= wait_mode_sym(argv[i]);
10263 else if (UNDEF_P(timeout)) {
10267 rb_raise(rb_eArgError,
"timeout given more than once");
10271 if (UNDEF_P(timeout)) timeout =
Qnil;
10279 events = io_event_from_value(argv[0]);
10287 if (rb_io_read_pending(fptr)) {
10289 if (return_io)
return Qtrue;
10295 return io_wait_event(io, events, timeout, return_io);
10299argf_mark_and_move(
void *ptr)
10301 struct argf *p = ptr;
10302 rb_gc_mark_and_move(&p->filename);
10303 rb_gc_mark_and_move(&p->current_file);
10304 rb_gc_mark_and_move(&p->argv);
10305 rb_gc_mark_and_move(&p->inplace);
10306 rb_gc_mark_and_move(&p->encs.
ecopts);
10310argf_memsize(
const void *ptr)
10312 const struct argf *p = ptr;
10313 size_t size =
sizeof(*p);
10320 0, 0, RUBY_TYPED_THREAD_SAFE_FREE | RUBY_TYPED_WB_PROTECTED
10326 p->filename =
Qnil;
10327 p->current_file =
Qnil;
10333argf_alloc(
VALUE klass)
10348 memset(&ARGF, 0,
sizeof(ARGF));
10349 argf_init(
argf, &ARGF, argv);
10359 ARGF = argf_of(orig);
10360 rb_gc_writebarrier_remember(
argf);
10387 ARGF.last_lineno = ARGF.lineno;
10413 return forward_current(rb_frame_this_func(), argc, argv);
10416#define next_argv() argf_next_argv(argf)
10417#define ARGF_GENERIC_INPUT_P() \
10418 (ARGF.current_file == rb_stdin && !RB_TYPE_P(ARGF.current_file, T_FILE))
10419#define ARGF_FORWARD(argc, argv) do {\
10420 if (ARGF_GENERIC_INPUT_P())\
10421 return argf_forward((argc), (argv), argf);\
10423#define NEXT_ARGF_FORWARD(argc, argv) do {\
10424 if (!next_argv()) return Qnil;\
10425 ARGF_FORWARD((argc), (argv));\
10431 VALUE file = ARGF.current_file;
10445 int stdout_binmode = 0;
10446 enum rb_io_mode fmode;
10448 VALUE r_stdout = rb_ractor_stdout();
10453 stdout_binmode = 1;
10456 if (ARGF.init_p == 0) {
10466 if (
NIL_P(ARGF.argv)) {
10469 else if (ARGF.next_p == -1 &&
RARRAY_LEN(ARGF.argv) > 0) {
10474 if (ARGF.next_p == 1) {
10475 if (ARGF.init_p == 1) argf_close(
argf);
10480 ARGF_SET(filename, filename);
10481 filename = rb_str_encode_ospath(filename);
10483 if (RSTRING_LEN(filename) == 1 && fn[0] ==
'-') {
10485 if (ARGF.inplace) {
10486 rb_warn(
"Can't do inplace edit for stdio; skipping");
10492 int fr = rb_sysopen(filename, O_RDONLY, 0);
10494 if (ARGF.inplace) {
10496#ifndef NO_SAFE_RENAME
10507 if (!
NIL_P(ARGF.inplace)) {
10508 VALUE suffix = ARGF.inplace;
10510 if (
NIL_P(rb_str_cat_conv_enc_opts(str, RSTRING_LEN(str),
10511 RSTRING_PTR(suffix), RSTRING_LEN(suffix),
10512 rb_enc_get(suffix), 0,
Qnil))) {
10515#ifdef NO_SAFE_RENAME
10517 (void)unlink(RSTRING_PTR(str));
10518 if (rename(fn, RSTRING_PTR(str)) < 0) {
10519 rb_warn(
"Can't rename %"PRIsVALUE
" to %"PRIsVALUE
": %s, skipping file",
10520 filename, str, strerror(
errno));
10523 fr = rb_sysopen(str, O_RDONLY, 0);
10525 if (rename(fn, RSTRING_PTR(str)) < 0) {
10526 rb_warn(
"Can't rename %"PRIsVALUE
" to %"PRIsVALUE
": %s, skipping file",
10527 filename, str, strerror(
errno));
10534#ifdef NO_SAFE_RENAME
10535 rb_fatal(
"Can't do inplace edit without backup");
10537 if (unlink(fn) < 0) {
10538 rb_warn(
"Can't remove %"PRIsVALUE
": %s, skipping file",
10539 filename, strerror(
errno));
10545 fw = rb_sysopen(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666);
10546#ifndef NO_SAFE_RENAME
10549 fchmod(fw, st.st_mode);
10551 chmod(fn, st.st_mode);
10553 if (st.st_uid!=st2.st_uid || st.st_gid!=st2.st_gid) {
10556 err = fchown(fw, st.st_uid, st.st_gid);
10558 err = chown(fn, st.st_uid, st.st_gid);
10560 if (err && getuid() == 0 && st2.st_uid == 0) {
10561 const char *wkfn = RSTRING_PTR(filename);
10562 rb_warn(
"Can't set owner/group of %"PRIsVALUE
" to same as %"PRIsVALUE
": %s, skipping file",
10563 filename, str, strerror(
errno));
10566 (void)unlink(wkfn);
10576 if (!ARGF.binmode) {
10577 fmode |= DEFAULT_TEXTMODE;
10579 ARGF_SET(current_file, prep_io(fr, fmode,
rb_cFile, fn));
10580 if (!
NIL_P(write_io)) {
10587 if (ARGF.encs.enc) {
10588 fptr->
encs = ARGF.encs;
10589 clear_codeconv(fptr);
10592 fptr->
encs.
ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
10593 if (!ARGF.binmode) {
10595#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
10596 fptr->
encs.
ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
10607 else if (ARGF.next_p == -1) {
10610 if (ARGF.inplace) {
10611 rb_warn(
"Can't do inplace edit for stdio");
10615 if (ARGF.init_p == -1) ARGF.init_p = 1;
10623 long lineno = ARGF.lineno;
10626 if (!next_argv())
return Qnil;
10627 if (ARGF_GENERIC_INPUT_P()) {
10628 line = forward_current(idGets, argc, argv);
10635 line = rb_io_getline(argc, argv, ARGF.current_file);
10637 if (
NIL_P(line) && ARGF.next_p != -1) {
10643 if (!
NIL_P(line)) {
10644 ARGF.lineno = ++lineno;
10645 ARGF.last_lineno = ARGF.lineno;
10651argf_lineno_getter(
ID id,
VALUE *var)
10654 return INT2FIX(ARGF.last_lineno);
10662 ARGF.last_lineno = ARGF.lineno = n;
10666rb_reset_argf_lineno(
long n)
10668 ARGF.last_lineno = ARGF.lineno = n;
10709 if (recv ==
argf) {
10710 return argf_gets(argc, argv,
argf);
10712 return forward(
argf, idGets, argc, argv);
10738 line = argf_getline(argc, argv,
argf);
10750 return rb_f_gets(0, 0,
argf);
10754 if (!next_argv())
return Qnil;
10756 if (
NIL_P(line) && ARGF.next_p != -1) {
10762 if (!
NIL_P(line)) {
10764 ARGF.last_lineno = ARGF.lineno;
10790rb_f_readline(
int argc,
VALUE *argv,
VALUE recv)
10792 if (recv ==
argf) {
10793 return argf_readline(argc, argv,
argf);
10795 return forward(
argf, rb_intern(
"readline"), argc, argv);
10821 if (!next_argv()) rb_eof_error();
10822 ARGF_FORWARD(argc, argv);
10823 line = argf_gets(argc, argv,
argf);
10893rb_f_readlines(
int argc,
VALUE *argv,
VALUE recv)
10895 if (recv ==
argf) {
10896 return argf_readlines(argc, argv,
argf);
10898 return forward(
argf, rb_intern(
"readlines"), argc, argv);
10922 long lineno = ARGF.lineno;
10926 while (next_argv()) {
10927 if (ARGF_GENERIC_INPUT_P()) {
10928 lines = forward_current(rb_intern(
"readlines"), argc, argv);
10931 lines = rb_io_readlines(argc, argv, ARGF.current_file);
10937 ARGF.last_lineno = ARGF.lineno;
10972 rb_last_status_clear();
10973 port = pipe_open_s(str,
"r",
FMODE_READABLE|DEFAULT_TEXTMODE, NULL);
10977 result = read_all(fptr, remain_size(fptr),
Qnil);
10979 rb_io_fptr_cleanup_all(fptr);
10985#ifdef HAVE_SYS_SELECT_H
10986#include <sys/select.h>
11000 if (!
NIL_P(read)) {
11005 if (READ_DATA_PENDING(fptr) || READ_CHAR_PENDING(fptr)) {
11009 if (max < fptr->fd) max = fptr->
fd;
11012 timerec.tv_sec = timerec.tv_usec = 0;
11020 if (!
NIL_P(write)) {
11026 if (max < fptr->fd) max = fptr->
fd;
11033 if (!
NIL_P(except)) {
11037 VALUE write_io = GetWriteIO(io);
11040 if (max < fptr->fd) max = fptr->
fd;
11041 if (io != write_io) {
11044 if (max < fptr->fd) max = fptr->
fd;
11059 if (!pending && n == 0)
return Qnil;
11084 VALUE write_io = GetWriteIO(io);
11097 VALUE write_io = GetWriteIO(io);
11102 else if (io != write_io) {
11115 VALUE read, write, except;
11121select_call(
VALUE arg)
11125 return select_internal(p->read, p->write, p->except, p->timeout, p->fdsets);
11129select_end(
VALUE arg)
11134 for (i = 0; i < numberof(p->fdsets); ++i)
11139static VALUE sym_normal, sym_sequential, sym_random,
11140 sym_willneed, sym_dontneed, sym_noreuse;
11142#ifdef HAVE_POSIX_FADVISE
11143struct io_advise_struct {
11151io_advise_internal(
void *arg)
11153 struct io_advise_struct *ptr = arg;
11154 return posix_fadvise(ptr->fd, ptr->offset, ptr->len, ptr->advice);
11158io_advise_sym_to_const(
VALUE sym)
11160#ifdef POSIX_FADV_NORMAL
11161 if (sym == sym_normal)
11162 return INT2NUM(POSIX_FADV_NORMAL);
11165#ifdef POSIX_FADV_RANDOM
11166 if (sym == sym_random)
11167 return INT2NUM(POSIX_FADV_RANDOM);
11170#ifdef POSIX_FADV_SEQUENTIAL
11171 if (sym == sym_sequential)
11172 return INT2NUM(POSIX_FADV_SEQUENTIAL);
11175#ifdef POSIX_FADV_WILLNEED
11176 if (sym == sym_willneed)
11177 return INT2NUM(POSIX_FADV_WILLNEED);
11180#ifdef POSIX_FADV_DONTNEED
11181 if (sym == sym_dontneed)
11182 return INT2NUM(POSIX_FADV_DONTNEED);
11185#ifdef POSIX_FADV_NOREUSE
11186 if (sym == sym_noreuse)
11187 return INT2NUM(POSIX_FADV_NOREUSE);
11194do_io_advise(
rb_io_t *fptr,
VALUE advice, rb_off_t offset, rb_off_t
len)
11197 struct io_advise_struct ias;
11200 num_adv = io_advise_sym_to_const(advice);
11206 if (
NIL_P(num_adv))
11210 ias.advice =
NUM2INT(num_adv);
11211 ias.offset = offset;
11214 rv = (int)rb_io_blocking_region(fptr, io_advise_internal, &ias);
11215 if (rv && rv != ENOSYS) {
11218 VALUE message = rb_sprintf(
"%"PRIsVALUE
" "
11222 fptr->
pathv, offset,
len, advice);
11232advice_arg_check(
VALUE advice)
11237 if (advice != sym_normal &&
11238 advice != sym_sequential &&
11239 advice != sym_random &&
11240 advice != sym_willneed &&
11241 advice != sym_dontneed &&
11242 advice != sym_noreuse) {
11243 rb_raise(
rb_eNotImpError,
"Unsupported advice: %+"PRIsVALUE, advice);
11281rb_io_advise(
int argc,
VALUE *argv,
VALUE io)
11288 advice_arg_check(advice);
11290 io = GetWriteIO(io);
11296#ifdef HAVE_POSIX_FADVISE
11297 return do_io_advise(fptr, advice,
off, l);
11299 ((void)
off, (
void)l);
11311 return isinf(f) && 0 < f;
11467rb_f_select(
int argc,
VALUE *argv,
VALUE obj)
11470 if (scheduler !=
Qnil) {
11473 if (!UNDEF_P(result))
return result;
11481 rb_scan_args(argc, argv,
"13", &args.read, &args.write, &args.except, &timeout);
11482 if (
NIL_P(timeout) || is_pos_inf(timeout)) {
11487 args.timeout = &timerec;
11490 for (i = 0; i < numberof(args.fdsets); ++i)
11496#ifdef IOCTL_REQ_TYPE
11497 typedef IOCTL_REQ_TYPE ioctl_req_t;
11499 typedef int ioctl_req_t;
11500# define NUM2IOCTLREQ(num) ((int)NUM2LONG(num))
11511nogvl_ioctl(
void *ptr)
11513 struct ioctl_arg *arg = ptr;
11515 return (
VALUE)ioctl(arg->fd, arg->cmd, arg->narg);
11519do_ioctl(
struct rb_io *io, ioctl_req_t cmd,
long narg)
11522 struct ioctl_arg arg;
11528 retval = (int)rb_io_blocking_region(io, nogvl_ioctl, &arg);
11534#define DEFAULT_IOCTL_NARG_LEN (256)
11536#if defined(__linux__) && defined(_IOC_SIZE)
11538linux_iocparm_len(ioctl_req_t cmd)
11542 if ((cmd & 0xFFFF0000) == 0) {
11544 return DEFAULT_IOCTL_NARG_LEN;
11547 len = _IOC_SIZE(cmd);
11550 if (
len < DEFAULT_IOCTL_NARG_LEN)
11551 len = DEFAULT_IOCTL_NARG_LEN;
11559ioctl_narg_len(ioctl_req_t cmd)
11565#define IOCPARM_LEN(x) (((x) >> 16) & IOCPARM_MASK)
11569 len = IOCPARM_LEN(cmd);
11570#elif defined(__linux__) && defined(_IOC_SIZE)
11571 len = linux_iocparm_len(cmd);
11574 len = DEFAULT_IOCTL_NARG_LEN;
11583typedef long fcntl_arg_t;
11586typedef int fcntl_arg_t;
11590fcntl_narg_len(ioctl_req_t cmd)
11597 len =
sizeof(fcntl_arg_t);
11605#ifdef F_DUPFD_CLOEXEC
11606 case F_DUPFD_CLOEXEC:
11607 len =
sizeof(fcntl_arg_t);
11617 len =
sizeof(fcntl_arg_t);
11627 len =
sizeof(fcntl_arg_t);
11637 len =
sizeof(fcntl_arg_t);
11642 len =
sizeof(
struct f_owner_ex);
11647 len =
sizeof(
struct f_owner_ex);
11652 len =
sizeof(
struct flock);
11657 len =
sizeof(
struct flock);
11662 len =
sizeof(
struct flock);
11682 len =
sizeof(fcntl_arg_t);
11692 len =
sizeof(fcntl_arg_t);
11697 len =
sizeof(fcntl_arg_t);
11710fcntl_narg_len(ioctl_req_t cmd)
11716#define NARG_SENTINEL 17
11719setup_narg(ioctl_req_t cmd,
VALUE *argp,
long (*narg_len)(ioctl_req_t))
11730 else if (arg ==
Qtrue) {
11744 len = narg_len(cmd);
11745 rb_str_modify(arg);
11747 slen = RSTRING_LEN(arg);
11749 if (slen <
len+1) {
11750 rb_str_resize(arg,
len+1);
11751 MEMZERO(RSTRING_PTR(arg)+slen,
char,
len-slen);
11755 ptr = RSTRING_PTR(arg);
11756 ptr[slen - 1] = NARG_SENTINEL;
11765finish_narg(
int retval,
VALUE arg,
const rb_io_t *fptr)
11767 if (retval < 0) rb_sys_fail_path(fptr->
pathv);
11772 if (ptr[slen-1] != NARG_SENTINEL)
11773 rb_raise(rb_eArgError,
"return value overflowed string");
11774 ptr[slen-1] =
'\0';
11784 ioctl_req_t cmd = NUM2IOCTLREQ(req);
11789 narg = setup_narg(cmd, &arg, ioctl_narg_len);
11791 retval = do_ioctl(fptr, cmd, narg);
11792 return finish_narg(retval, arg, fptr);
11819 return rb_ioctl(io, req, arg);
11822#define rb_io_ioctl rb_f_notimplement
11833nogvl_fcntl(
void *ptr)
11835 struct fcntl_arg *arg = ptr;
11837#if defined(F_DUPFD)
11838 if (arg->cmd == F_DUPFD)
11841 return (
VALUE)fcntl(arg->fd, arg->cmd, arg->narg);
11845do_fcntl(
struct rb_io *io,
int cmd,
long narg)
11848 struct fcntl_arg arg;
11854 retval = (int)rb_io_blocking_region(io, nogvl_fcntl, &arg);
11855 if (retval != -1) {
11857#if defined(F_DUPFD)
11860#if defined(F_DUPFD_CLOEXEC)
11861 case F_DUPFD_CLOEXEC:
11878 narg = setup_narg(cmd, &arg, fcntl_narg_len);
11880 retval = do_fcntl(fptr, cmd, narg);
11881 return finish_narg(retval, arg, fptr);
11907 return rb_fcntl(io, req, arg);
11910#define rb_io_fcntl rb_f_notimplement
11913#if defined(HAVE_SYSCALL) || defined(HAVE___SYSCALL)
11945#if SIZEOF_VOIDP == 8 && defined(HAVE___SYSCALL) && SIZEOF_INT != 8
11946# define SYSCALL __syscall
11947# define NUM2SYSCALLID(x) NUM2LONG(x)
11948# define RETVAL2NUM(x) LONG2NUM(x)
11949# if SIZEOF_LONG == 8
11950 long num, retval = -1;
11951# elif SIZEOF_LONG_LONG == 8
11952 long long num, retval = -1;
11954# error ---->> it is asserted that __syscall takes the first argument and returns retval in 64bit signed integer. <<----
11956#elif defined(__linux__)
11957# define SYSCALL syscall
11958# define NUM2SYSCALLID(x) NUM2LONG(x)
11959# define RETVAL2NUM(x) LONG2NUM(x)
11967 long num, retval = -1;
11969# define SYSCALL syscall
11970# define NUM2SYSCALLID(x) NUM2INT(x)
11971# define RETVAL2NUM(x) INT2NUM(x)
11972 int num, retval = -1;
11978 "We plan to remove a syscall function at future release. DL(Fiddle) provides safer alternative.");
11982 rb_raise(rb_eArgError,
"too few arguments for syscall");
11983 if (argc > numberof(arg))
11984 rb_raise(rb_eArgError,
"too many arguments for syscall");
11985 num = NUM2SYSCALLID(argv[0]); ++argv;
11986 for (i = argc - 1; i--; ) {
12001 retval = SYSCALL(num);
12004 retval = SYSCALL(num, arg[0]);
12007 retval = SYSCALL(num, arg[0],arg[1]);
12010 retval = SYSCALL(num, arg[0],arg[1],arg[2]);
12013 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3]);
12016 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4]);
12019 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5]);
12022 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6]);
12028 return RETVAL2NUM(retval);
12030#undef NUM2SYSCALLID
12034#define rb_f_syscall rb_f_notimplement
12038io_new_instance(
VALUE args)
12044find_encoding(
VALUE v)
12047 if (!enc)
rb_warn(
"Unsupported encoding %"PRIsVALUE
" ignored", v);
12059 enc2 = find_encoding(v1);
12062 if (RSTRING_LEN(tmp) == 1 && RSTRING_PTR(tmp)[0] ==
'-') {
12068 enc = find_encoding(v2);
12075 enc = find_encoding(v2);
12081 if (enc2 == rb_ascii8bit_encoding()) {
12086 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
12092 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
12093 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
12098 if (!
NIL_P(tmp) && rb_enc_asciicompat(enc = rb_enc_get(tmp))) {
12099 parse_mode_enc(RSTRING_PTR(tmp), enc, &enc, &enc2, NULL);
12100 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
12104 rb_io_ext_int_to_encs(find_encoding(v1), NULL, &enc, &enc2, 0);
12105 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
12110 validate_enc_binmode(&fptr->
mode, ecflags, enc, enc2);
12115 clear_codeconv(fptr);
12127io_encoding_set_v(
VALUE v)
12130 io_encoding_set(arg->fptr, arg->v1, arg->v2, arg->opt);
12135pipe_pair_close(
VALUE rw)
12138 return rb_ensure(io_close, rwp[0], io_close, rwp[1]);
12221rb_io_s_pipe(
int argc,
VALUE *argv,
VALUE klass)
12223 int pipes[2], state;
12224 VALUE r, w, args[3], v1, v2;
12228 enum rb_io_mode fmode = 0;
12231 argc =
rb_scan_args(argc, argv,
"02:", &v1, &v2, &opt);
12238 r = rb_protect(io_new_instance, (
VALUE)args, &state);
12242 rb_jump_tag(state);
12246 ies_args.fptr = fptr;
12249 ies_args.opt = opt;
12250 rb_protect(io_encoding_set_v, (
VALUE)&ies_args, &state);
12254 rb_jump_tag(state);
12259 w = rb_protect(io_new_instance, (
VALUE)args, &state);
12263 rb_jump_tag(state);
12268 extract_binmode(opt, &fmode);
12275#if DEFAULT_TEXTMODE
12277 fptr->
mode &= ~FMODE_TEXTMODE;
12278 setmode(fptr->
fd, O_BINARY);
12280#if RUBY_CRLF_ENVIRONMENT
12286 fptr->
mode |= fmode;
12287#if DEFAULT_TEXTMODE
12289 fptr2->
mode &= ~FMODE_TEXTMODE;
12290 setmode(fptr2->
fd, O_BINARY);
12293 fptr2->
mode |= fmode;
12327 else if (!
NIL_P(v = rb_hash_aref(opt, sym_open_args))) {
12330 v = rb_to_array_type(v);
12335 arg->io = rb_io_open(klass, path, vmode, vperm, opt);
12339io_s_foreach(
VALUE v)
12344 if (arg->limit == 0)
12345 rb_raise(rb_eArgError,
"invalid limit: 0 for foreach");
12346 while (!
NIL_P(str = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, arg->io))) {
12430rb_io_s_foreach(
int argc,
VALUE *argv,
VALUE self)
12433 int orig_argc = argc;
12437 argc =
rb_scan_args(argc, argv,
"12:", NULL, NULL, NULL, &opt);
12439 extract_getline_args(argc-1, argv+1, &garg);
12440 open_key_args(self, argc, argv, opt, &arg);
12442 extract_getline_opts(opt, &garg);
12443 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12444 return rb_ensure(io_s_foreach, (
VALUE)&garg, rb_io_close, arg.io);
12448io_s_readlines(
VALUE v)
12451 return io_readlines(arg, arg->io);
12504rb_io_s_readlines(
int argc,
VALUE *argv,
VALUE io)
12510 argc =
rb_scan_args(argc, argv,
"12:", NULL, NULL, NULL, &opt);
12511 extract_getline_args(argc-1, argv+1, &garg);
12512 open_key_args(io, argc, argv, opt, &arg);
12514 extract_getline_opts(opt, &garg);
12515 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12516 return rb_ensure(io_s_readlines, (
VALUE)&garg, rb_io_close, arg.io);
12523 return io_read(arg->argc, arg->argv, arg->io);
12533seek_before_access(
VALUE argp)
12537 return rb_io_seek(arg->io, arg->offset, arg->mode);
12604rb_io_s_read(
int argc,
VALUE *argv,
VALUE io)
12610 argc =
rb_scan_args(argc, argv,
"13:", NULL, NULL, &offset, NULL, &opt);
12612 rb_raise(rb_eArgError,
"negative offset %ld given",
off);
12614 open_key_args(io, argc, argv, opt, &arg);
12616 if (!
NIL_P(offset)) {
12620 sarg.offset = offset;
12621 sarg.mode = SEEK_SET;
12622 rb_protect(seek_before_access, (
VALUE)&sarg, &state);
12625 rb_jump_tag(state);
12627 if (arg.argc == 2) arg.argc = 1;
12642rb_io_s_binread(
int argc,
VALUE *argv,
VALUE io)
12657 convconfig.
enc = rb_ascii8bit_encoding();
12658 arg.io = rb_io_open_generic(io, argv[0], oflags, fmode, &convconfig, 0);
12661 arg.argc = (argc > 1) ? 1 : 0;
12662 if (!
NIL_P(offset)) {
12666 sarg.offset = offset;
12667 sarg.mode = SEEK_SET;
12668 rb_protect(seek_before_access, (
VALUE)&sarg, &state);
12671 rb_jump_tag(state);
12678io_s_write0(
VALUE v)
12681 return io_write(arg->io,arg->str,arg->nosync);
12685io_s_write(
int argc,
VALUE *argv,
VALUE klass,
int binary)
12687 VALUE string, offset, opt;
12691 rb_scan_args(argc, argv,
"21:", NULL, &
string, &offset, &opt);
12693 if (
NIL_P(opt)) opt = rb_hash_new();
12694 else opt = rb_hash_dup(opt);
12697 if (
NIL_P(rb_hash_aref(opt,sym_mode))) {
12698 int mode = O_WRONLY|O_CREAT;
12700 if (binary) mode |= O_BINARY;
12702 if (
NIL_P(offset)) mode |= O_TRUNC;
12703 rb_hash_aset(opt,sym_mode,
INT2NUM(mode));
12705 open_key_args(klass, argc, argv, opt, &arg);
12708 if (binary) rb_io_binmode_m(arg.io);
12712 if (!
NIL_P(offset)) {
12716 sarg.offset = offset;
12717 sarg.mode = SEEK_SET;
12718 rb_protect(seek_before_access, (
VALUE)&sarg, &state);
12721 rb_jump_tag(state);
12729 return rb_ensure(io_s_write0, (
VALUE)&warg, rb_io_close, arg.io);
12787rb_io_s_write(
int argc,
VALUE *argv,
VALUE io)
12789 return io_s_write(argc, argv, io, 0);
12802rb_io_s_binwrite(
int argc,
VALUE *argv,
VALUE io)
12804 return io_s_write(argc, argv, io, 1);
12810 rb_off_t copy_length;
12811 rb_off_t src_offset;
12815 unsigned close_src : 1;
12816 unsigned close_dst : 1;
12819 const char *syserr;
12820 const char *notimp;
12822 struct stat src_stat;
12823 struct stat dst_stat;
12824#ifdef HAVE_FCOPYFILE
12825 copyfile_state_t copyfile_state;
12830exec_interrupts(
void *arg)
12833 rb_thread_execute_interrupts(th);
12847#if defined(ERESTART)
12852 rb_thread_execute_interrupts(stp->th);
12871fiber_scheduler_wait_for(
void * _arguments)
12881# define IOWAIT_SYSCALL "poll"
12882STATIC_ASSERT(pollin_expected, POLLIN == RB_WAITFD_IN);
12883STATIC_ASSERT(pollout_expected, POLLOUT == RB_WAITFD_OUT);
12888 if (scheduler !=
Qnil) {
12891 return RTEST(args.result);
12895 if (fd == -1)
return 0;
12900 fds.events = events;
12902 int timeout_milliseconds = -1;
12905 timeout_milliseconds = (int)(timeout->tv_sec * 1000) + (int)(timeout->tv_usec / 1000);
12908 return poll(&fds, 1, timeout_milliseconds);
12911# define IOWAIT_SYSCALL "select"
12916 if (scheduler !=
Qnil) {
12919 return RTEST(args.result);
12939 case RB_WAITFD_OUT:
12943 VM_UNREACHABLE(nogvl_wait_for);
12963 ret = nogvl_wait_for(stp->th, stp->src_fptr, RB_WAITFD_IN, NULL);
12965 }
while (ret < 0 && maygvl_copy_stream_continue_p(has_gvl, stp));
12968 stp->syserr = IOWAIT_SYSCALL;
12969 stp->error_no =
errno;
12981 ret = nogvl_wait_for(stp->th, stp->dst_fptr, RB_WAITFD_OUT, NULL);
12982 }
while (ret < 0 && maygvl_copy_stream_continue_p(0, stp));
12985 stp->syserr = IOWAIT_SYSCALL;
12986 stp->error_no =
errno;
12992#ifdef USE_COPY_FILE_RANGE
12995simple_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)
12997#ifdef HAVE_COPY_FILE_RANGE
12998 return copy_file_range(in_fd, in_offset, out_fd, out_offset, count, flags);
13000 return syscall(__NR_copy_file_range, in_fd, in_offset, out_fd, out_offset, count, flags);
13009 rb_off_t copy_length, src_offset, *src_offset_ptr;
13011 if (!S_ISREG(stp->src_stat.st_mode))
13014 src_size = stp->src_stat.st_size;
13015 src_offset = stp->src_offset;
13016 if (src_offset >= (rb_off_t)0) {
13017 src_offset_ptr = &src_offset;
13020 src_offset_ptr = NULL;
13023 copy_length = stp->copy_length;
13024 if (copy_length < (rb_off_t)0) {
13025 if (src_offset < (rb_off_t)0) {
13026 rb_off_t current_offset;
13028 current_offset = lseek(stp->src_fptr->
fd, 0, SEEK_CUR);
13029 if (current_offset < (rb_off_t)0 &&
errno) {
13030 stp->syserr =
"lseek";
13031 stp->error_no =
errno;
13032 return (
int)current_offset;
13034 copy_length = src_size - current_offset;
13037 copy_length = src_size - src_offset;
13041 retry_copy_file_range:
13042# if SIZEOF_OFF_T > SIZEOF_SIZE_T
13044 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
13046 ss = (ssize_t)copy_length;
13048 ss = simple_copy_file_range(stp->src_fptr->
fd, src_offset_ptr, stp->dst_fptr->
fd, NULL, ss, 0);
13052 if (0 < copy_length) {
13053 goto retry_copy_file_range;
13057 if (maygvl_copy_stream_continue_p(0, stp)) {
13058 goto retry_copy_file_range;
13072#if EWOULDBLOCK != EAGAIN
13076 int ret = nogvl_copy_stream_wait_write(stp);
13077 if (ret < 0)
return ret;
13079 goto retry_copy_file_range;
13083 int flags = fcntl(stp->dst_fptr->
fd, F_GETFL);
13085 if (flags != -1 && flags & O_APPEND) {
13091 stp->syserr =
"copy_file_range";
13092 stp->error_no =
errno;
13099#ifdef HAVE_FCOPYFILE
13103 rb_off_t cur, ss = 0;
13104 const rb_off_t src_offset = stp->src_offset;
13107 if (stp->copy_length >= (rb_off_t)0) {
13112 if (!S_ISREG(stp->src_stat.st_mode))
13115 if (!S_ISREG(stp->dst_stat.st_mode))
13117 if (lseek(stp->dst_fptr->
fd, 0, SEEK_CUR) > (rb_off_t)0)
13119 if (fcntl(stp->dst_fptr->
fd, F_GETFL) & O_APPEND) {
13122 rb_off_t end = lseek(stp->dst_fptr->
fd, 0, SEEK_END);
13123 lseek(stp->dst_fptr->
fd, 0, SEEK_SET);
13124 if (end > (rb_off_t)0)
return 0;
13127 if (src_offset > (rb_off_t)0) {
13132 cur = lseek(stp->src_fptr->
fd, 0, SEEK_CUR);
13133 if (cur < (rb_off_t)0 &&
errno) {
13134 stp->error_no =
errno;
13139 r = lseek(stp->src_fptr->
fd, src_offset, SEEK_SET);
13140 if (r < (rb_off_t)0 &&
errno) {
13141 stp->error_no =
errno;
13146 stp->copyfile_state = copyfile_state_alloc();
13147 ret = fcopyfile(stp->src_fptr->
fd, stp->dst_fptr->
fd, stp->copyfile_state, COPYFILE_DATA);
13148 copyfile_state_get(stp->copyfile_state, COPYFILE_STATE_COPIED, &ss);
13152 if (src_offset > (rb_off_t)0) {
13156 r = lseek(stp->src_fptr->
fd, cur, SEEK_SET);
13157 if (r < (rb_off_t)0 &&
errno) {
13158 stp->error_no =
errno;
13170 stp->syserr =
"fcopyfile";
13171 stp->error_no =
errno;
13178#ifdef HAVE_SENDFILE
13181# define USE_SENDFILE
13183# ifdef HAVE_SYS_SENDFILE_H
13184# include <sys/sendfile.h>
13188simple_sendfile(
int out_fd,
int in_fd, rb_off_t *offset, rb_off_t count)
13190 return sendfile(out_fd, in_fd, offset, (
size_t)count);
13193# elif 0 || defined(__APPLE__)
13197# define USE_SENDFILE
13200simple_sendfile(
int out_fd,
int in_fd, rb_off_t *offset, rb_off_t count)
13203 rb_off_t pos = offset ? *offset : lseek(in_fd, 0, SEEK_CUR);
13206 r = sendfile(in_fd, out_fd, pos, &count, NULL, 0);
13209 r = sendfile(in_fd, out_fd, pos, (
size_t)count, NULL, &sbytes, 0);
13211 if (r != 0 && sbytes == 0)
return r;
13216 lseek(in_fd, sbytes, SEEK_CUR);
13218 return (ssize_t)sbytes;
13231 rb_off_t copy_length;
13232 rb_off_t src_offset;
13235 if (!S_ISREG(stp->src_stat.st_mode))
13238 src_size = stp->src_stat.st_size;
13240 if ((stp->dst_stat.st_mode & S_IFMT) != S_IFSOCK)
13244 src_offset = stp->src_offset;
13245 use_pread = src_offset >= (rb_off_t)0;
13247 copy_length = stp->copy_length;
13248 if (copy_length < (rb_off_t)0) {
13250 copy_length = src_size - src_offset;
13254 cur = lseek(stp->src_fptr->
fd, 0, SEEK_CUR);
13255 if (cur < (rb_off_t)0 &&
errno) {
13256 stp->syserr =
"lseek";
13257 stp->error_no =
errno;
13260 copy_length = src_size - cur;
13265# if SIZEOF_OFF_T > SIZEOF_SIZE_T
13267 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
13269 ss = (ssize_t)copy_length;
13272 ss = simple_sendfile(stp->dst_fptr->
fd, stp->src_fptr->
fd, &src_offset, ss);
13275 ss = simple_sendfile(stp->dst_fptr->
fd, stp->src_fptr->
fd, NULL, ss);
13280 if (0 < copy_length) {
13281 goto retry_sendfile;
13285 if (maygvl_copy_stream_continue_p(0, stp))
13286 goto retry_sendfile;
13299#if EWOULDBLOCK != EAGAIN
13312 ret = maygvl_copy_stream_wait_read(0, stp);
13313 if (ret < 0)
return ret;
13315 ret = nogvl_copy_stream_wait_write(stp);
13316 if (ret < 0)
return ret;
13318 goto retry_sendfile;
13320 stp->syserr =
"sendfile";
13321 stp->error_no =
errno;
13329maygvl_read(
int has_gvl,
rb_io_t *fptr,
void *buf,
size_t count)
13332 return rb_io_read_memory(fptr, buf, count);
13334 return read(fptr->
fd, buf, count);
13338maygvl_copy_stream_read(
int has_gvl,
struct copy_stream_struct *stp,
char *buf,
size_t len, rb_off_t offset)
13342 if (offset < (rb_off_t)0) {
13343 ss = maygvl_read(has_gvl, stp->src_fptr, buf,
len);
13346 ss = pread(stp->src_fptr->
fd, buf,
len, offset);
13352 if (maygvl_copy_stream_continue_p(has_gvl, stp))
13356#if EWOULDBLOCK != EAGAIN
13360 int ret = maygvl_copy_stream_wait_read(has_gvl, stp);
13361 if (ret < 0)
return ret;
13366 stp->notimp =
"pread";
13370 stp->syserr = offset < (rb_off_t)0 ?
"read" :
"pread";
13371 stp->error_no =
errno;
13382 ss = write(stp->dst_fptr->
fd, buf+
off,
len);
13384 if (maygvl_copy_stream_continue_p(0, stp))
13386 if (io_again_p(
errno)) {
13387 int ret = nogvl_copy_stream_wait_write(stp);
13388 if (ret < 0)
return ret;
13391 stp->syserr =
"write";
13392 stp->error_no =
errno;
13409 rb_off_t copy_length;
13410 rb_off_t src_offset;
13414 copy_length = stp->copy_length;
13415 use_eof = copy_length < (rb_off_t)0;
13416 src_offset = stp->src_offset;
13417 use_pread = src_offset >= (rb_off_t)0;
13419 if (use_pread && stp->close_src) {
13422 r = lseek(stp->src_fptr->
fd, src_offset, SEEK_SET);
13423 if (r < (rb_off_t)0 &&
errno) {
13424 stp->syserr =
"lseek";
13425 stp->error_no =
errno;
13428 src_offset = (rb_off_t)-1;
13432 while (use_eof || 0 < copy_length) {
13433 if (!use_eof && copy_length < (rb_off_t)
sizeof(buf)) {
13434 len = (size_t)copy_length;
13440 ss = maygvl_copy_stream_read(0, stp, buf,
len, src_offset);
13445 ss = maygvl_copy_stream_read(0, stp, buf,
len, (rb_off_t)-1);
13450 ret = nogvl_copy_stream_write(stp, buf, ss);
13460nogvl_copy_stream_func(
void *arg)
13463#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13467#ifdef USE_COPY_FILE_RANGE
13468 ret = nogvl_copy_file_range(stp);
13473#ifdef HAVE_FCOPYFILE
13474 ret = nogvl_fcopyfile(stp);
13480 ret = nogvl_copy_stream_sendfile(stp);
13485 nogvl_copy_stream_read_write(stp);
13487#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13494copy_stream_fallback_body(
VALUE arg)
13497 const int buflen = 16*1024;
13500 rb_off_t rest = stp->copy_length;
13501 rb_off_t
off = stp->src_offset;
13502 ID read_method = id_readpartial;
13504 if (!stp->src_fptr) {
13506 read_method = id_read;
13513 rb_str_make_independent(buf);
13514 if (stp->copy_length < (rb_off_t)0) {
13519 rb_str_resize(buf, 0);
13522 l = buflen < rest ? buflen : (long)rest;
13524 if (!stp->src_fptr) {
13527 if (read_method == id_read &&
NIL_P(rc))
13532 rb_str_resize(buf, buflen);
13533 ss = maygvl_copy_stream_read(1, stp, RSTRING_PTR(buf), l,
off);
13534 rb_str_resize(buf, ss > 0 ? ss : 0);
13539 if (
off >= (rb_off_t)0)
13542 n = rb_io_write(stp->dst, buf);
13544 stp->total += numwrote;
13546 if (read_method == id_read && RSTRING_LEN(buf) == 0) {
13557 if (!stp->src_fptr && stp->src_offset >= (rb_off_t)0) {
13558 rb_raise(rb_eArgError,
"cannot specify src_offset for non-IO");
13567copy_stream_body(
VALUE arg)
13570 VALUE src_io = stp->src, dst_io = stp->dst;
13571 const int common_oflags = 0
13581 if (src_io ==
argf ||
13585 stp->src_fptr = NULL;
13590 if (!
NIL_P(tmp_io)) {
13597 args[1] =
INT2NUM(O_RDONLY|common_oflags);
13600 stp->close_src = 1;
13605 stat_ret = fstat(stp->src_fptr->
fd, &stp->src_stat);
13606 if (stat_ret < 0) {
13607 stp->syserr =
"fstat";
13608 stp->error_no =
errno;
13613 if (dst_io ==
argf ||
13617 stp->dst_fptr = NULL;
13622 if (!
NIL_P(tmp_io)) {
13623 dst_io = GetWriteIO(tmp_io);
13629 args[1] =
INT2NUM(O_WRONLY|O_CREAT|O_TRUNC|common_oflags);
13633 stp->close_dst = 1;
13636 dst_io = GetWriteIO(dst_io);
13642 stat_ret = fstat(stp->dst_fptr->
fd, &stp->dst_stat);
13643 if (stat_ret < 0) {
13644 stp->syserr =
"fstat";
13645 stp->error_no =
errno;
13652 SET_BINARY_MODE_WITH_SEEK_CUR(stp->src_fptr);
13655 io_ascii8bit_binmode(stp->dst_fptr);
13657 if (stp->src_offset < (rb_off_t)0 && stp->src_fptr && stp->src_fptr->
rbuf.
len) {
13660 if (stp->copy_length >= (rb_off_t)0 && stp->copy_length < (rb_off_t)
len) {
13661 len = (size_t)stp->copy_length;
13664 rb_str_resize(str,
len);
13665 read_buffered_data(RSTRING_PTR(str),
len, stp->src_fptr);
13666 if (stp->dst_fptr) {
13667 if (io_binwrite(RSTRING_PTR(str), RSTRING_LEN(str), stp->dst_fptr, 0) < 0)
13668 rb_sys_fail_on_write(stp->dst_fptr);
13671 rb_io_write(dst_io, str);
13672 rb_str_resize(str, 0);
13674 if (stp->copy_length >= (rb_off_t)0)
13675 stp->copy_length -=
len;
13678 if (stp->dst_fptr && io_fflush(stp->dst_fptr) < 0) {
13682 if (stp->copy_length == 0)
13685 if (stp->src_fptr == NULL || stp->dst_fptr == NULL) {
13686 return copy_stream_fallback(stp);
13689 IO_WITHOUT_GVL(nogvl_copy_stream_func, stp);
13694copy_stream_finalize(
VALUE arg)
13698#ifdef HAVE_FCOPYFILE
13699 if (stp->copyfile_state) {
13700 copyfile_state_free(stp->copyfile_state);
13704 if (stp->close_src) {
13705 rb_io_close_m(stp->src);
13707 if (stp->close_dst) {
13708 rb_io_close_m(stp->dst);
13771rb_io_s_copy_stream(
int argc,
VALUE *argv,
VALUE io)
13773 VALUE src, dst, length, src_offset;
13778 rb_scan_args(argc, argv,
"22", &src, &dst, &length, &src_offset);
13783 st.src_fptr = NULL;
13784 st.dst_fptr = NULL;
13787 st.copy_length = (rb_off_t)-1;
13789 st.copy_length =
NUM2OFFT(length);
13791 if (
NIL_P(src_offset))
13792 st.src_offset = (rb_off_t)-1;
13794 st.src_offset =
NUM2OFFT(src_offset);
13813rb_io_external_encoding(
VALUE io)
13818 return rb_enc_from_encoding(fptr->
encs.
enc2);
13822 return rb_enc_from_encoding(fptr->
encs.
enc);
13825 return rb_enc_from_encoding(io_read_encoding(fptr));
13841rb_io_internal_encoding(
VALUE io)
13846 return rb_enc_from_encoding(io_read_encoding(fptr));
13880rb_io_set_encoding(
int argc,
VALUE *argv,
VALUE io)
13886 return forward(io, id_set_encoding, argc, argv);
13889 argc =
rb_scan_args(argc, argv,
"11:", &v1, &v2, &opt);
13891 io_encoding_set(fptr, v1, v2, opt);
13896rb_stdio_set_default_encoding(
void)
13901 if (isatty(fileno(stdin))) {
13903 rb_encoding *internal = rb_default_internal_encoding();
13904 if (!internal) internal = rb_default_external_encoding();
13906 rb_enc_from_encoding(external),
13907 rb_enc_from_encoding(internal),
13912 rb_io_set_encoding(1, &val,
rb_stdin);
13913 rb_io_set_encoding(1, &val,
rb_stdout);
13914 rb_io_set_encoding(1, &val,
rb_stderr);
13918global_argf_p(
VALUE arg)
13920 return arg ==
argf;
13923typedef VALUE (*argf_encoding_func)(
VALUE io);
13926argf_encoding(
VALUE argf, argf_encoding_func func)
13928 if (!
RTEST(ARGF.current_file)) {
13929 return rb_enc_default_external();
13953 return argf_encoding(
argf, rb_io_external_encoding);
13972 return argf_encoding(
argf, rb_io_internal_encoding);
14011 if (!next_argv()) {
14012 rb_raise(rb_eArgError,
"no stream to set encoding");
14014 rb_io_set_encoding(argc, argv, ARGF.current_file);
14016 ARGF.encs = fptr->
encs;
14036 if (!next_argv()) {
14037 rb_raise(rb_eArgError,
"no stream to tell");
14039 ARGF_FORWARD(0, 0);
14040 return rb_io_tell(ARGF.current_file);
14053 if (!next_argv()) {
14054 rb_raise(rb_eArgError,
"no stream to seek");
14056 ARGF_FORWARD(argc, argv);
14057 return rb_io_seek_m(argc, argv, ARGF.current_file);
14074 if (!next_argv()) {
14075 rb_raise(rb_eArgError,
"no stream to set position");
14077 ARGF_FORWARD(1, &offset);
14078 return rb_io_set_pos(ARGF.current_file, offset);
14099 if (!next_argv()) {
14100 rb_raise(rb_eArgError,
"no stream to rewind");
14102 ARGF_FORWARD(0, 0);
14103 old_lineno =
RFILE(ARGF.current_file)->fptr->lineno;
14104 ret = rb_io_rewind(ARGF.current_file);
14105 if (!global_argf_p(
argf)) {
14106 ARGF.last_lineno = ARGF.lineno -= old_lineno;
14124 if (!next_argv()) {
14125 rb_raise(rb_eArgError,
"no stream");
14127 ARGF_FORWARD(0, 0);
14128 return rb_io_fileno(ARGF.current_file);
14147 ARGF_FORWARD(0, 0);
14148 return ARGF.current_file;
14173 if (
RTEST(ARGF.current_file)) {
14174 if (ARGF.init_p == 0)
return Qtrue;
14176 ARGF_FORWARD(0, 0);
14235 VALUE tmp, str, length;
14239 if (!
NIL_P(length)) {
14244 rb_str_resize(str,0);
14249 if (!next_argv()) {
14252 if (ARGF_GENERIC_INPUT_P()) {
14253 tmp = argf_forward(argc, argv,
argf);
14256 tmp = io_read(argc, argv, ARGF.current_file);
14258 if (
NIL_P(str)) str = tmp;
14261 if (ARGF.next_p != -1) {
14267 else if (argc >= 1) {
14268 long slen = RSTRING_LEN(str);
14284argf_forward_call(
VALUE arg)
14287 argf_forward(p->argc, p->argv, p->argf);
14317 return argf_getpartial(argc, argv,
argf,
Qnil, 0);
14338 return argf_getpartial(argc, argv,
argf, opts, 1);
14344 VALUE tmp, str, length;
14352 no_exception = no_exception_p(opts);
14354 if (!next_argv()) {
14356 rb_str_resize(str, 0);
14360 if (ARGF_GENERIC_INPUT_P()) {
14370 tmp = io_getpartial(argc, argv, ARGF.current_file, no_exception, nonblock);
14373 if (ARGF.next_p == -1) {
14374 return io_nonblock_eof(no_exception);
14379 return io_nonblock_eof(no_exception);
14417 if (!next_argv())
return Qnil;
14418 if (ARGF_GENERIC_INPUT_P()) {
14419 ch = forward_current(rb_intern(
"getc"), 0, 0);
14422 ch = rb_io_getc(ARGF.current_file);
14424 if (
NIL_P(ch) && ARGF.next_p != -1) {
14457 if (!next_argv())
return Qnil;
14459 ch = forward_current(rb_intern(
"getbyte"), 0, 0);
14464 if (
NIL_P(ch) && ARGF.next_p != -1) {
14497 if (!next_argv()) rb_eof_error();
14499 ch = forward_current(rb_intern(
"getc"), 0, 0);
14502 ch = rb_io_getc(ARGF.current_file);
14504 if (
NIL_P(ch) && ARGF.next_p != -1) {
14536 NEXT_ARGF_FORWARD(0, 0);
14537 c = argf_getbyte(
argf);
14544#define FOREACH_ARGF() while (next_argv())
14549 const VALUE current = ARGF.current_file;
14551 if (ARGF.init_p == -1 || current != ARGF.current_file) {
14557#define ARGF_block_call(mid, argc, argv, func, argf) \
14558 rb_block_call_kw(ARGF.current_file, mid, argc, argv, \
14559 func, argf, rb_keyword_given_p())
14564 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_i,
argf);
14565 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14571 if (!global_argf_p(
argf)) {
14572 ARGF.last_lineno = ++ARGF.lineno;
14574 return argf_block_call_i(i,
argf, argc, argv, blockarg);
14580 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_line_i,
argf);
14581 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14629 argf_block_call_line(rb_intern(
"each_line"), argc, argv,
argf);
14660 argf_block_call(rb_intern(
"each_byte"), 0, 0,
argf);
14686 argf_block_call(rb_intern(
"each_char"), 0, 0,
argf);
14712 argf_block_call(rb_intern(
"each_codepoint"), 0, 0,
argf);
14743 return ARGF.filename;
14747argf_filename_getter(
ID id,
VALUE *var)
14749 return argf_filename(*var);
14774 return ARGF.current_file;
14793 ARGF_FORWARD(0, 0);
14814 return RBOOL(ARGF.binmode);
14834 if (ARGF.init_p && ARGF.next_p == 0) {
14863 if (ARGF.next_p != -1) {
14881 ARGF_FORWARD(0, 0);
14908 if (!ARGF.inplace)
return Qnil;
14916 return argf_inplace_mode_get(*var);
14947 ARGF.inplace =
Qnil;
14958 argf_inplace_mode_set(*var, val);
14962ruby_set_inplace_mode(
const char *suffix)
14988argf_argv_getter(
ID id,
VALUE *var)
14990 return argf_argv(*var);
15009 if (!
RTEST(ARGF.current_file)) {
15012 return GetWriteIO(ARGF.current_file);
15024 return rb_io_writev(argf_write_io(
argf), argc, argv);
15039 case RB_IO_WAIT_WRITABLE:
15042 c = rb_eEAGAINWaitWritable;
15044#if EAGAIN != EWOULDBLOCK
15046 c = rb_eEWOULDBLOCKWaitWritable;
15050 c = rb_eEINPROGRESSWaitWritable;
15056 case RB_IO_WAIT_READABLE:
15059 c = rb_eEAGAINWaitReadable;
15061#if EAGAIN != EWOULDBLOCK
15063 c = rb_eEWOULDBLOCKWaitReadable;
15067 c = rb_eEINPROGRESSWaitReadable;
15074 rb_bug(
"invalid read/write type passed to rb_readwrite_sys_fail: %d", waiting);
15080get_LAST_READ_LINE(
ID _x,
VALUE *_y)
15970#include <sys/cygwin.h>
15971 static struct __cygwin_perfile pf[] =
15973 {
"", O_RDONLY | O_BINARY},
15974 {
"", O_WRONLY | O_BINARY},
15975 {
"", O_RDWR | O_BINARY},
15976 {
"", O_APPEND | O_BINARY},
15979 cygwin_internal(CW_PERFILE, pf);
16028 rb_eEAGAINWaitReadable = rb_define_class_under(
rb_cIO,
"EAGAINWaitReadable", rb_eEAGAIN);
16031 rb_eEAGAINWaitWritable = rb_define_class_under(
rb_cIO,
"EAGAINWaitWritable", rb_eEAGAIN);
16033#if EAGAIN == EWOULDBLOCK
16035 rb_define_const(
rb_cIO,
"EWOULDBLOCKWaitReadable", rb_eEAGAINWaitReadable);
16037 rb_define_const(
rb_cIO,
"EWOULDBLOCKWaitWritable", rb_eEAGAINWaitWritable);
16040 rb_eEWOULDBLOCKWaitReadable = rb_define_class_under(
rb_cIO,
"EWOULDBLOCKWaitReadable", rb_eEWOULDBLOCK);
16043 rb_eEWOULDBLOCKWaitWritable = rb_define_class_under(
rb_cIO,
"EWOULDBLOCKWaitWritable", rb_eEWOULDBLOCK);
16047 rb_eEINPROGRESSWaitReadable = rb_define_class_under(
rb_cIO,
"EINPROGRESSWaitReadable", rb_eEINPROGRESS);
16050 rb_eEINPROGRESSWaitWritable = rb_define_class_under(
rb_cIO,
"EINPROGRESSWaitWritable", rb_eEINPROGRESS);
16085 rb_gvar_ractor_local(
"$/");
16087 rb_gvar_ractor_local(
"$-0");
16091 rb_gvar_ractor_local(
"$_");
16092 rb_gvar_box_dynamic(
"$_");
16208 rb_gvar_ractor_local(
"$stdin");
16209 rb_gvar_ractor_local(
"$stdout");
16210 rb_gvar_ractor_local(
"$>");
16211 rb_gvar_ractor_local(
"$stderr");
16213 rb_gvar_box_dynamic(
"$stdin");
16214 rb_gvar_box_dynamic(
"$stdout");
16215 rb_gvar_box_dynamic(
"$>");
16216 rb_gvar_box_dynamic(
"$stderr");
16237 rb_cARGF = rb_define_class(
"ARGF",
rb_cObject);
16302 rb_define_method(rb_cARGF,
"external_encoding", argf_external_encoding, 0);
16303 rb_define_method(rb_cARGF,
"internal_encoding", argf_internal_encoding, 0);
16322 rb_gvar_ractor_local(
"$-i");
16326#if defined (_WIN32) || defined(__CYGWIN__)
16327 atexit(pipe_atexit);
16339 sym_encoding =
ID2SYM(rb_id_encoding());
16363static void init_builtin_io(
void);
16364#define Init_builtin_io init_builtin_io
16366#undef Init_builtin_io
16369Init_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 rb_str_cat2
Old name of rb_str_cat_cstr.
#define T_NIL
Old name of RUBY_T_NIL.
#define UNREACHABLE
Old name of RBIMPL_UNREACHABLE.
#define ID2SYM
Old name of RB_ID2SYM.
#define T_BIGNUM
Old name of RUBY_T_BIGNUM.
#define OBJ_FREEZE
Old name of RB_OBJ_FREEZE.
#define T_FIXNUM
Old name of RUBY_T_FIXNUM.
#define UNREACHABLE_RETURN
Old name of RBIMPL_UNREACHABLE_RETURN.
#define FIX2UINT
Old name of RB_FIX2UINT.
#define SSIZET2NUM
Old name of RB_SSIZE2NUM.
#define ZALLOC
Old name of RB_ZALLOC.
#define CLASS_OF
Old name of rb_class_of.
#define rb_ary_new4
Old name of rb_ary_new_from_values.
#define ENCODING_MAXNAMELEN
Old name of RUBY_ENCODING_MAXNAMELEN.
#define MBCLEN_NEEDMORE_LEN(ret)
Old name of ONIGENC_MBCLEN_NEEDMORE_LEN.
#define ENCODING_GET(obj)
Old name of RB_ENCODING_GET.
#define LONG2FIX
Old name of RB_INT2FIX.
#define NUM2UINT
Old name of RB_NUM2UINT.
#define ALLOC_N
Old name of RB_ALLOC_N.
#define MBCLEN_CHARFOUND_LEN(ret)
Old name of ONIGENC_MBCLEN_CHARFOUND_LEN.
#define LONG2NUM
Old name of RB_LONG2NUM.
#define rb_exc_new3
Old name of rb_exc_new_str.
#define STRNCASECMP
Old name of st_locale_insensitive_strncasecmp.
#define MBCLEN_INVALID_P(ret)
Old name of ONIGENC_MBCLEN_INVALID_P.
#define ISASCII
Old name of rb_isascii.
#define ECONV_STATEFUL_DECORATOR_MASK
Old name of RUBY_ECONV_STATEFUL_DECORATOR_MASK.
#define Qtrue
Old name of RUBY_Qtrue.
#define MBCLEN_NEEDMORE_P(ret)
Old name of ONIGENC_MBCLEN_NEEDMORE_P.
#define ECONV_PARTIAL_INPUT
Old name of RUBY_ECONV_PARTIAL_INPUT.
#define NUM2INT
Old name of RB_NUM2INT.
#define ECONV_ERROR_HANDLER_MASK
Old name of RUBY_ECONV_ERROR_HANDLER_MASK.
#define INT2NUM
Old name of RB_INT2NUM.
#define Qnil
Old name of RUBY_Qnil.
#define Qfalse
Old name of RUBY_Qfalse.
#define FIX2LONG
Old name of RB_FIX2LONG.
#define ENC_CODERANGE_BROKEN
Old name of RUBY_ENC_CODERANGE_BROKEN.
#define T_ARRAY
Old name of RUBY_T_ARRAY.
#define NIL_P
Old name of RB_NIL_P.
#define ALLOCV_N
Old name of RB_ALLOCV_N.
#define MBCLEN_CHARFOUND_P(ret)
Old name of ONIGENC_MBCLEN_CHARFOUND_P.
#define NUM2CHR
Old name of RB_NUM2CHR.
#define NUM2LONG
Old name of RB_NUM2LONG.
#define UINT2NUM
Old name of RB_UINT2NUM.
#define FIXNUM_P
Old name of RB_FIXNUM_P.
#define ECONV_NEWLINE_DECORATOR_MASK
Old name of RUBY_ECONV_NEWLINE_DECORATOR_MASK.
#define CONST_ID
Old name of RUBY_CONST_ID.
#define rb_ary_new2
Old name of rb_ary_new_capa.
#define NUM2SIZET
Old name of RB_NUM2SIZE.
#define ENC_CODERANGE_SET(obj, cr)
Old name of RB_ENC_CODERANGE_SET.
#define rb_str_new4
Old name of rb_str_new_frozen.
#define ALLOCV_END
Old name of RB_ALLOCV_END.
#define SYMBOL_P
Old name of RB_SYMBOL_P.
#define ECONV_DEFAULT_NEWLINE_DECORATOR
Old name of RUBY_ECONV_DEFAULT_NEWLINE_DECORATOR.
void rb_category_warn(rb_warning_category_t category, const char *fmt,...)
Identical to rb_category_warning(), except it reports unless $VERBOSE is nil.
void rb_category_warning(rb_warning_category_t category, const char *fmt,...)
Identical to rb_warning(), except it takes additional "category" parameter.
VALUE rb_eNotImpError
NotImplementedError exception.
void rb_exc_raise(VALUE mesg)
Raises an exception in the current thread.
void rb_syserr_fail(int e, const char *mesg)
Raises appropriate exception that represents a C errno.
void rb_readwrite_syserr_fail(enum rb_io_wait_readwrite waiting, int n, const char *mesg)
Identical to rb_readwrite_sys_fail(), except it does not depend on C global variable errno.
VALUE rb_eIOError
IOError exception.
VALUE rb_eStandardError
StandardError exception.
void rb_mod_syserr_fail_str(VALUE mod, int e, VALUE mesg)
Identical to rb_mod_syserr_fail(), except it takes the message in Ruby's String instead of C's.
void rb_syserr_fail_str(int e, VALUE mesg)
Identical to rb_syserr_fail(), except it takes the message in Ruby's String instead of C's.
#define ruby_verbose
This variable controls whether the interpreter is in debug mode.
VALUE rb_eTypeError
TypeError exception.
VALUE rb_eEOFError
EOFError exception.
void rb_readwrite_sys_fail(enum rb_io_wait_readwrite waiting, const char *mesg)
Raises appropriate exception using the parameters.
void rb_iter_break_value(VALUE val)
Identical to rb_iter_break(), except it additionally takes the "value" of this breakage.
rb_io_wait_readwrite
for rb_readwrite_sys_fail first argument
VALUE rb_eRuntimeError
RuntimeError exception.
void rb_warn(const char *fmt,...)
Identical to rb_warning(), except it reports unless $VERBOSE is nil.
VALUE rb_eSystemCallError
SystemCallError exception.
@ RB_WARN_CATEGORY_DEPRECATED
Warning is for deprecated features.
VALUE rb_mKernel
Kernel module.
VALUE rb_check_to_int(VALUE val)
Identical to rb_check_to_integer(), except it uses #to_int for conversion.
VALUE rb_cObject
Object class.
VALUE rb_any_to_s(VALUE obj)
Generates a textual representation of the given object.
VALUE rb_obj_alloc(VALUE klass)
Allocates an instance of the given class.
VALUE rb_class_new_instance(int argc, const VALUE *argv, VALUE klass)
Allocates, then initialises an instance of the given class.
VALUE rb_class_new_instance_kw(int argc, const VALUE *argv, VALUE klass, int kw_splat)
Identical to rb_class_new_instance(), except you can specify how to handle the last element of the gi...
VALUE rb_mEnumerable
Enumerable module.
VALUE rb_stdin
STDIN constant.
VALUE rb_stderr
STDERR constant.
VALUE rb_obj_class(VALUE obj)
Queries the class of an object.
VALUE rb_obj_dup(VALUE obj)
Duplicates the given object.
VALUE rb_inspect(VALUE obj)
Generates a human-readable textual representation of the given object.
VALUE rb_mWaitReadable
IO::WaitReadable module.
VALUE rb_mWaitWritable
IO::WaitReadable module.
VALUE rb_obj_freeze(VALUE obj)
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.
VALUE rb_enc_uint_chr(unsigned int code, rb_encoding *enc)
Encodes the passed code point into a series of bytes.
long rb_str_coderange_scan_restartable(const char *str, const char *end, rb_encoding *enc, int *cr)
Scans the passed string until it finds something odd.
int rb_econv_prepare_options(VALUE opthash, VALUE *ecopts, int ecflags)
Identical to rb_econv_prepare_opts(), except it additionally takes the initial value of flags.
VALUE rb_econv_open_exc(const char *senc, const char *denc, int ecflags)
Creates a rb_eConverterNotFoundError exception object (but does not raise).
rb_econv_result_t rb_econv_convert(rb_econv_t *ec, const unsigned char **source_buffer_ptr, const unsigned char *source_buffer_end, unsigned char **destination_buffer_ptr, unsigned char *destination_buffer_end, int flags)
Converts a string from an encoding to another.
rb_econv_result_t
return value of rb_econv_convert()
@ econv_incomplete_input
The conversion stopped in middle of reading a character, possibly due to a partial read of a socket e...
@ econv_finished
The conversion stopped after converting everything.
@ econv_undefined_conversion
The conversion stopped when it found a character in the input which cannot be representable in the ou...
@ econv_source_buffer_empty
The conversion stopped because there is no input.
@ econv_destination_buffer_full
The conversion stopped because there is no destination.
@ econv_invalid_byte_sequence
The conversion stopped when it found an invalid sequence.
int rb_econv_putbackable(rb_econv_t *ec)
Queries if rb_econv_putback() makes sense, i.e.
const char * rb_econv_asciicompat_encoding(const char *encname)
Queries the passed encoding's corresponding ASCII compatible encoding.
VALUE rb_econv_str_convert(rb_econv_t *ec, VALUE src, int flags)
Identical to rb_econv_convert(), except it takes Ruby's string instead of C's pointer.
rb_econv_t * rb_econv_open_opts(const char *source_encoding, const char *destination_encoding, int ecflags, VALUE ecopts)
Identical to rb_econv_open(), except it additionally takes a hash of optional strings.
void rb_econv_binmode(rb_econv_t *ec)
This badly named function does not set the destination encoding to binary, but instead just nullifies...
VALUE rb_str_encode(VALUE str, VALUE to, int ecflags, VALUE ecopts)
Converts the contents of the passed string from its encoding to the passed one.
VALUE rb_econv_make_exception(rb_econv_t *ec)
This function makes sense right after rb_econv_convert() returns.
void rb_econv_check_error(rb_econv_t *ec)
This is a rb_econv_make_exception() + rb_exc_raise() combo.
void rb_econv_close(rb_econv_t *ec)
Destructs a converter.
void rb_econv_putback(rb_econv_t *ec, unsigned char *p, int n)
Puts back the bytes.
VALUE rb_funcall(VALUE recv, ID mid, int n,...)
Calls a method.
VALUE rb_funcallv_kw(VALUE recv, ID mid, int argc, const VALUE *argv, int kw_splat)
Identical to rb_funcallv(), except you can specify how to handle the last element of the given array.
VALUE rb_funcallv(VALUE recv, ID mid, int argc, const VALUE *argv)
Identical to rb_funcall(), except it takes the method arguments as a C array.
Defines RBIMPL_HAS_BUILTIN.
VALUE rb_ary_concat(VALUE lhs, VALUE rhs)
Destructively appends the contents of latter into the end of former.
VALUE rb_ary_shift(VALUE ary)
Destructively deletes an element from the beginning of the passed array and returns what was deleted.
VALUE rb_check_array_type(VALUE obj)
Try converting an object to its array representation using its to_ary method, if any.
VALUE rb_ary_new(void)
Allocates a new, empty array.
VALUE rb_ary_new_capa(long capa)
Identical to rb_ary_new(), except it additionally specifies how many rooms of objects it should alloc...
VALUE rb_ary_push(VALUE ary, VALUE elem)
Special case of rb_ary_cat() that it adds only one element.
VALUE rb_ary_entry(VALUE ary, long off)
Queries an element of an array.
VALUE rb_assoc_new(VALUE car, VALUE cdr)
Identical to rb_ary_new_from_values(), except it expects exactly two parameters.
#define RETURN_ENUMERATOR(obj, argc, argv)
Identical to RETURN_SIZED_ENUMERATOR(), except its size is unknown.
static int rb_check_arity(int argc, int min, int max)
Ensures that the passed integer is in the passed range.
VALUE rb_io_printf(int argc, const VALUE *argv, VALUE io)
This is a rb_f_sprintf() + rb_io_write() combo.
VALUE rb_io_gets(VALUE io)
Reads a "line" from the given IO.
int rb_cloexec_pipe(int fildes[2])
Opens a pipe with closing on exec.
VALUE rb_io_print(int argc, const VALUE *argv, VALUE io)
Iterates over the passed array to apply rb_io_write() individually.
VALUE rb_io_addstr(VALUE io, VALUE str)
Identical to rb_io_write(), except it always returns the passed IO.
void rb_write_error(const char *str)
Writes the given error message to somewhere applicable.
VALUE rb_io_ungetbyte(VALUE io, VALUE b)
Identical to rb_io_ungetc(), except it doesn't take the encoding of the passed IO into account.
VALUE rb_io_getbyte(VALUE io)
Reads a byte from the given IO.
int rb_cloexec_dup2(int oldfd, int newfd)
Identical to rb_cloexec_dup(), except you can specify the destination file descriptor.
VALUE rb_io_fdopen(int fd, int flags, const char *path)
Creates an IO instance whose backend is the given file descriptor.
void rb_update_max_fd(int fd)
Informs the interpreter that the passed fd can be the max.
int rb_cloexec_open(const char *pathname, int flags, mode_t mode)
Opens a file that closes on exec.
VALUE rb_output_rs
The record separator character for outputs, or the $\.
VALUE rb_io_eof(VALUE io)
Queries if the passed IO is at the end of file.
void rb_write_error2(const char *str, long len)
Identical to rb_write_error(), except it additionally takes the message's length.
void rb_close_before_exec(int lowfd, int maxhint, VALUE noclose_fds)
Closes everything.
int rb_reserved_fd_p(int fd)
Queries if the given FD is reserved or not.
void rb_fd_fix_cloexec(int fd)
Sets or clears the close-on-exec flag of the passed file descriptor to the desired state.
VALUE rb_io_ascii8bit_binmode(VALUE io)
Forces no conversions be applied to the passed IO.
VALUE rb_io_binmode(VALUE io)
Sets the binmode.
VALUE rb_io_ungetc(VALUE io, VALUE c)
"Unget"s a string.
int rb_pipe(int *pipes)
This is an rb_cloexec_pipe() + rb_update_max_fd() combo.
VALUE rb_gets(void)
Much like rb_io_gets(), but it reads from the mysterious ARGF object.
int rb_cloexec_fcntl_dupfd(int fd, int minfd)
Duplicates a file descriptor with closing on exec.
VALUE rb_output_fs
The field separator character for outputs, or the $,.
VALUE rb_file_open_str(VALUE fname, const char *fmode)
Identical to rb_file_open(), except it takes the pathname as a Ruby's string instead of C's.
int rb_cloexec_dup(int oldfd)
Identical to rb_cloexec_fcntl_dupfd(), except it implies minfd is 3.
VALUE rb_file_open(const char *fname, const char *fmode)
Opens a file located at the given path.
VALUE rb_io_close(VALUE io)
Closes the IO.
VALUE rb_default_rs
This is the default value of rb_rs, i.e.
void rb_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 $?.
VALUE rb_str_append(VALUE dst, VALUE src)
Identical to rb_str_buf_append(), except it converts the right hand side before concatenating.
#define rb_str_new(str, len)
Allocates an instance of rb_cString.
#define rb_str_buf_cat
Just another name of rb_str_cat.
#define rb_usascii_str_new(str, len)
Identical to rb_str_new, except it generates a string of "US ASCII" encoding.
size_t rb_str_capacity(VALUE str)
Queries the capacity of the given string.
VALUE rb_str_new_frozen(VALUE str)
Creates a frozen copy of the string, if necessary.
VALUE rb_str_dup(VALUE str)
Duplicates a string.
VALUE rb_str_cat(VALUE dst, const char *src, long srclen)
Destructively appends the passed contents to the string.
VALUE rb_str_locktmp(VALUE str)
Obtains a "temporary lock" of the string.
VALUE rb_str_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.
void rb_str_set_len(VALUE str, long len)
Overwrites the length of the string.
VALUE rb_str_buf_cat_ascii(VALUE dst, const char *src)
Identical to rb_str_cat_cstr(), except it additionally assumes the source string be a NUL terminated ...
VALUE rb_check_string_type(VALUE obj)
Try converting an object to its stringised representation using its to_str method,...
VALUE rb_str_substr(VALUE str, long beg, long len)
This is the implementation of two-argumented String#slice.
VALUE rb_str_unlocktmp(VALUE str)
Releases a lock formerly obtained by rb_str_locktmp().
void rb_str_modify_expand(VALUE str, long capa)
Identical to rb_str_modify(), except it additionally expands the capacity of the receiver.
VALUE rb_str_buf_new(long capa)
Allocates a "string buffer".
#define rb_str_new_cstr(str)
Identical to rb_str_new, except it assumes the passed pointer is a pointer to a C string.
VALUE rb_obj_as_string(VALUE obj)
Try converting an object to its stringised representation using its to_s method, if any.
int rb_thread_interrupted(VALUE thval)
Checks if the thread's execution was recently interrupted.
VALUE rb_mutex_new(void)
Creates a mutex.
int rb_thread_fd_writable(int fd)
Identical to rb_thread_wait_fd(), except it blocks the current thread until the given file descriptor...
VALUE rb_exec_recursive(VALUE(*f)(VALUE g, VALUE h, int r), VALUE g, VALUE h)
"Recursion" API entry point.
VALUE rb_mutex_synchronize(VALUE mutex, VALUE(*func)(VALUE arg), VALUE arg)
Obtains the lock, runs the passed function, and releases the lock when it completes.
void rb_thread_check_ints(void)
Checks for interrupts.
VALUE rb_thread_current(void)
Obtains the "current" thread.
int rb_thread_wait_fd(int fd)
Blocks the current thread until the given file descriptor is ready to be read.
void rb_thread_sleep(int sec)
Blocks for the given period of time.
struct timeval rb_time_interval(VALUE num)
Creates a "time interval".
void rb_set_class_path(VALUE klass, VALUE space, const char *name)
Names a class.
VALUE rb_ivar_set(VALUE obj, ID name, VALUE val)
Identical to rb_iv_set(), except it accepts the name as an ID instead of a C string.
VALUE rb_class_name(VALUE obj)
Queries the name of the given object's class.
int rb_respond_to(VALUE obj, ID mid)
Queries if the object responds to the method.
int rb_method_basic_definition_p(VALUE klass, ID mid)
Well... Let us hesitate from describing what a "basic definition" is.
VALUE rb_check_funcall(VALUE recv, ID mid, int argc, const VALUE *argv)
Identical to rb_funcallv(), except it returns RUBY_Qundef instead of raising rb_eNoMethodError.
void rb_define_alloc_func(VALUE klass, rb_alloc_func_t func)
Sets the allocator function of a class.
static ID rb_intern_const(const char *str)
This is a "tiny optimisation" over rb_intern().
#define RB_ID2SYM
Just another name of rb_id2sym.
void rb_define_global_const(const char *name, VALUE val)
Identical to rb_define_const(), except it defines that of "global", i.e.
void rb_define_readonly_variable(const char *name, const VALUE *var)
Identical to rb_define_variable(), except it does not allow Ruby programs to assign values to such gl...
rb_gvar_setter_t rb_gvar_readonly_setter
This function just raises rb_eNameError.
#define FMODE_READABLE
The IO is opened for reading.
enum rb_io_mode rb_io_modestr_fmode(const char *modestr)
Maps a file mode string (that rb_file_open() takes) into a mixture of FMODE_ flags.
VALUE rb_io_get_io(VALUE io)
Identical to rb_io_check_io(), except it raises exceptions on conversion failures.
VALUE rb_io_timeout(VALUE io)
Get the timeout associated with the specified io object.
VALUE rb_io_taint_check(VALUE obj)
void rb_io_read_check(rb_io_t *fptr)
Blocks until there is a pending read in the passed IO.
int rb_io_modestr_oflags(const char *modestr)
Identical to rb_io_modestr_fmode(), except it returns a mixture of O_ flags.
#define FMODE_SETENC_BY_BOM
This flag amends the encoding of the IO so that the BOM of the contents of the IO takes effect.
rb_io_event
Type of events that an IO can wait.
@ RUBY_IO_READABLE
IO::READABLE
@ RUBY_IO_PRIORITY
IO::PRIORITY
@ RUBY_IO_WRITABLE
IO::WRITABLE
#define FMODE_READWRITE
The IO is opened for both read/write.
#define FMODE_EXTERNAL
This flag means that an IO object is wrapping an "external" file descriptor, which is owned by someth...
#define GetOpenFile
This is an old name of RB_IO_POINTER.
void rb_io_check_byte_readable(rb_io_t *fptr)
Asserts that an IO is opened for byte-based reading.
#define FMODE_TTY
The IO is a TTY.
#define FMODE_CREATE
The IO is opened for creating.
void rb_io_check_readable(rb_io_t *fptr)
Just another name of rb_io_check_byte_readable.
int rb_wait_for_single_fd(int fd, int events, struct timeval *tv)
Blocks until the passed file descriptor is ready for the passed events.
FILE * rb_fdopen(int fd, const char *modestr)
Identical to rb_io_stdio_file(), except it takes file descriptors instead of Ruby's IO.
int rb_io_extract_encoding_option(VALUE opt, rb_encoding **enc_p, rb_encoding **enc2_p, enum rb_io_mode *fmode_p)
This function breaks down the option hash that IO#initialize takes into components.
int rb_io_descriptor(VALUE io)
Returns an integer representing the numeric file descriptor for io.
#define FMODE_WRITABLE
The IO is opened for writing.
FILE * rb_io_stdio_file(rb_io_t *fptr)
Finds or creates a stdio's file structure from a Ruby's one.
#define FMODE_APPEND
The IO is opened for appending.
#define MakeOpenFile
This is an old name of RB_IO_OPEN.
#define FMODE_DUPLEX
Ruby eventually detects that the IO is bidirectional.
#define FMODE_BINMODE
The IO is in "binary mode".
int rb_io_maybe_wait_readable(int error, VALUE io, VALUE timeout)
Blocks until the passed IO is ready for reading, if that makes sense for the passed errno.
int capa
Designed capacity of the buffer.
#define RB_IO_POINTER(obj, fp)
Queries the underlying IO pointer.
VALUE rb_io_maybe_wait(int error, VALUE io, VALUE events, VALUE timeout)
Identical to rb_io_wait() except it additionally takes previous errno.
VALUE rb_eIOTimeoutError
Indicates that a timeout has occurred while performing an IO operation.
char * ptr
Pointer to the underlying memory region, of at least capa bytes.
#define FMODE_SYNC
The IO is in "sync mode".
int off
Offset inside of ptr.
VALUE rb_io_path(VALUE io)
Returns the path for the given IO.
void rb_io_extract_modeenc(VALUE *vmode_p, VALUE *vperm_p, VALUE opthash, int *oflags_p, enum rb_io_mode *fmode_p, rb_io_enc_t *convconfig_p)
This function can be seen as an extended version of rb_io_extract_encoding_option() that not only con...
void rb_io_check_initialized(rb_io_t *fptr)
Asserts that the passed IO is initialised.
#define FMODE_EXCL
This flag amends the effect of FMODE_CREATE, so that if there already is a file at the given path the...
#define FMODE_TEXTMODE
The IO is in "text mode".
int rb_io_fptr_finalize(rb_io_t *fptr)
Destroys the given IO.
VALUE rb_io_check_io(VALUE io)
Try converting an object to its IO representation using its to_io method, if any.
VALUE rb_io_closed_p(VALUE io)
Returns whether or not the underlying IO is closed.
VALUE rb_io_set_timeout(VALUE io, VALUE timeout)
Set the timeout associated with the specified io object.
ssize_t rb_io_bufwrite(VALUE io, const void *buf, size_t size)
Buffered write to the passed IO.
void rb_io_check_char_readable(rb_io_t *fptr)
Asserts that an IO is opened for character-based reading.
#define FMODE_TRUNC
This flag amends the effect of FMODE_CREATE, so that if there already is a file at the given path it ...
VALUE rb_io_get_write_io(VALUE io)
Queries the tied IO for writing.
void rb_io_set_nonblock(rb_io_t *fptr)
Instructs the OS to put its internal file structure into "nonblocking mode".
int rb_io_wait_writable(int fd)
Blocks until the passed file descriptor gets writable.
VALUE rb_io_open_descriptor(VALUE klass, int descriptor, int mode, VALUE path, VALUE timeout, struct rb_io_encoding *encoding)
Allocate a new IO object, with the given file descriptor.
VALUE rb_io_set_write_io(VALUE io, VALUE w)
Assigns the tied IO for writing.
void rb_io_check_writable(rb_io_t *fptr)
Asserts that an IO is opened for writing.
int rb_io_maybe_wait_writable(int error, VALUE io, VALUE timeout)
Blocks until the passed IO is ready for writing, if that makes sense for the passed errno.
void rb_io_check_closed(rb_io_t *fptr)
This badly named function asserts that the passed IO is open.
int rb_io_wait_readable(int fd)
Blocks until the passed file descriptor gets readable.
void rb_io_synchronized(rb_io_t *fptr)
Sets FMODE_SYNC.
VALUE rb_io_wait(VALUE io, VALUE events, VALUE timeout)
Blocks until the passed IO is ready for the passed events.
int len
Length of the buffer.
VALUE rb_ractor_stdin(void)
Queries the standard input of the current Ractor that is calling this function.
void rb_ractor_stderr_set(VALUE io)
Assigns an IO to the standard error of the Ractor that is calling this function.
void rb_ractor_stdout_set(VALUE io)
Assigns an IO to the standard output of the Ractor that is calling this function.
void rb_ractor_stdin_set(VALUE io)
Assigns an IO to the standard input of the Ractor that is calling this function.
void * rb_thread_call_with_gvl(void *(*func)(void *), void *data1)
(Re-)acquires the GVL.
#define RB_NUM2INT
Just another name of rb_num2int_inline.
#define RB_INT2NUM
Just another name of rb_int2num_inline.
VALUE rb_f_sprintf(int argc, const VALUE *argv)
Identical to rb_str_format(), except how the arguments are arranged.
#define RB_BLOCK_CALL_FUNC_ARGLIST(yielded_arg, callback_arg)
Shim for block function parameters.
VALUE rb_yield_values2(int n, const VALUE *argv)
Identical to rb_yield_values(), except it takes the parameters as a C array instead of variadic argum...
VALUE rb_yield(VALUE val)
Yields the block.
void rb_fd_term(rb_fdset_t *f)
Destroys the rb_fdset_t, releasing any memory and resources it used.
#define MEMZERO(p, type, n)
Handy macro to erase a region of memory.
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
#define MEMMOVE(p1, p2, type, n)
Handy macro to call memmove.
#define NUM2MODET
Converts a C's mode_t into an instance of rb_cInteger.
void rb_define_hooked_variable(const char *q, VALUE *w, type *e, void_type *r)
Define a function-backended global variable.
void rb_define_virtual_variable(const char *q, type *w, void_type *e)
Define a function-backended global variable.
VALUE rb_rescue2(type *q, VALUE w, type *e, VALUE r,...)
An equivalent of rescue clause.
VALUE rb_ensure(type *q, VALUE w, type *e, VALUE r)
An equivalent of ensure clause.
#define PRI_OFFT_PREFIX
A rb_sprintf() format prefix to be used for an off_t parameter.
#define OFFT2NUM
Converts a C's off_t into an instance of rb_cInteger.
#define NUM2OFFT
Converts an instance of rb_cNumeric into C's off_t.
#define PIDT2NUM
Converts a C's pid_t into an instance of rb_cInteger.
#define rb_fd_isset
Queries if the given fd is in the rb_fdset_t.
#define rb_fd_select
Waits for multiple file descriptors at once.
#define rb_fd_init
Initialises the :given :rb_fdset_t.
#define rb_fd_set
Sets the given fd to the rb_fdset_t.
#define RARRAY_LEN
Just another name of rb_array_len.
static int RARRAY_LENINT(VALUE ary)
Identical to rb_array_len(), except it differs for the return type.
#define RARRAY_AREF(a, i)
#define RARRAY_CONST_PTR
Just another name of rb_array_const_ptr.
#define RFILE(obj)
Convenient casting macro.
#define StringValue(v)
Ensures that the parameter object is a String.
static char * RSTRING_END(VALUE str)
Queries the end of the contents pointer of the string.
#define RSTRING_GETMEM(str, ptrvar, lenvar)
Convenient macro to obtain the contents and length at once.
#define StringValueCStr(v)
Identical to StringValuePtr, except it additionally checks for the contents for viability as a C stri...
#define RUBY_TYPED_DEFAULT_FREE
This is a value you can set to rb_data_type_struct::dfree.
#define TypedData_Make_Struct(klass, type, data_type, sval)
Identical to TypedData_Wrap_Struct, except it allocates a new data region internally instead of takin...
VALUE rb_get_argv(void)
Queries the arguments passed to the current process that you can access from Ruby as ARGV.
void rb_p(VALUE obj)
Inspects an object.
#define FilePathValue(v)
Ensures that the parameter object is a path.
#define errno
Ractor-aware version of errno.
#define RB_SCAN_ARGS_LAST_HASH_KEYWORDS
Treat a final argument as keywords if it is a hash, and not as keywords otherwise.
#define RB_PASS_CALLED_KEYWORDS
Pass keywords if current method is called with keywords, useful for argument delegation.
int rb_thread_fd_select(int nfds, rb_fdset_t *rfds, rb_fdset_t *wfds, rb_fdset_t *efds, struct timeval *timeout)
Waits for multiple file descriptors at once.
static bool RB_TEST(VALUE obj)
Emulates Ruby's "if" statement.
#define RTEST
This is an old name of RB_TEST.
#define _(args)
This was a transition path from K&R to ANSI.
This is the struct that holds necessary info for a struct.
The data structure which wraps the fd_set bitmap used by select(2).
Decomposed encoding flags (e.g.
VALUE ecopts
Flags as Ruby hash.
rb_encoding * enc2
External encoding.
rb_encoding * enc
Internal encoding.
char * ptr
Pointer to the underlying memory region, of at least capa bytes.
int off
Offset inside of ptr.
int len
Length of the buffer.
int capa
Designed capacity of the buffer.
Ruby's IO, metadata and buffers.
rb_io_buffer_t wbuf
Write buffer.
enum rb_io_mode mode
mode flags: FMODE_XXXs
void(* finalize)(struct rb_io *, int)
finalize proc
rb_econv_t * readconv
Encoding converter used when reading from this IO.
rb_econv_t * writeconv
Encoding converter used when writing to this IO.
struct rb_io_encoding encs
Decomposed encoding flags.
VALUE self
The IO's Ruby level counterpart.
VALUE write_lock
This is a Ruby level mutex.
VALUE timeout
The timeout associated with this IO when performing blocking operations.
FILE * stdio_file
stdio ptr for read/write, if available.
VALUE writeconv_pre_ecopts
Value of ::rb_io_t::rb_io_enc_t::ecopts stored right before initialising rb_io_t::writeconv.
VALUE tied_io_for_writing
Duplex IO object, if set.
int writeconv_initialized
Whether rb_io_t::writeconv is already set up.
rb_io_buffer_t rbuf
(Byte) read buffer.
int lineno
number of lines read
struct ccan_list_head blocking_operations
Threads that are performing a blocking operation without the GVL using this IO.
VALUE writeconv_asciicompat
This is, when set, an instance of rb_cString which holds the "common" encoding.
rb_io_buffer_t cbuf
rb_io_ungetc() destination.
rb_pid_t pid
child's pid (for pipes)
int writeconv_pre_ecflags
Value of ::rb_io_t::rb_io_enc_t::ecflags stored right before initialising rb_io_t::writeconv.
VALUE pathv
pathname for file
intptr_t SIGNED_VALUE
A signed integer type that has the same width with VALUE.
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
uintptr_t VALUE
Type that represents a Ruby object.
static bool RB_FLOAT_TYPE_P(VALUE obj)
Queries if the object is an instance of rb_cFloat.
static bool RB_SYMBOL_P(VALUE obj)
Queries if the object is an instance of rb_cSymbol.
static void Check_Type(VALUE v, enum ruby_value_type t)
Identical to RB_TYPE_P(), except it raises exceptions on predication failure.
static bool RB_TYPE_P(VALUE obj, enum ruby_value_type t)
Queries if the given object is of given type.
#define RBIMPL_WARNING_IGNORED(flag)
Suppresses a warning.
#define RBIMPL_WARNING_PUSH()
Pushes compiler warning state.
#define RBIMPL_WARNING_POP()
Pops compiler warning state.