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);
2127 tmp = rb_str_tmp_frozen_no_embed_acquire(str);
2129 n = io_binwrite(ptr,
len, fptr, nosync);
2130 rb_str_tmp_frozen_release(str, tmp);
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__)
7660pipe_finalize(
rb_io_t *fptr,
int noraise)
7662#if !defined(HAVE_WORKING_FORK) && !defined(_WIN32)
7671 fptr_finalize(fptr, noraise);
7673 pipe_del_fptr(fptr);
7680#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7681 void (*
const old_finalize)(
struct rb_io*,int) = fptr->
finalize;
7683 if (old_finalize == orig->finalize)
return;
7688#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7689 if (old_finalize != pipe_finalize) {
7691 for (list =
pipe_list; list; list = list->next) {
7692 if (list->fptr == fptr)
break;
7694 if (!list) pipe_add_fptr(fptr);
7697 pipe_del_fptr(fptr);
7723#define spawnv(mode, cmd, args) rb_w32_uaspawn((mode), (cmd), (args))
7724#define spawn(mode, cmd) rb_w32_uspawn((mode), (cmd), 0)
7727#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7737#ifdef HAVE_WORKING_FORK
7738# ifndef __EMSCRIPTEN__
7740popen_redirect(
struct popen_arg *p)
7743 close(p->write_pair[1]);
7744 if (p->write_pair[0] != 0) {
7745 dup2(p->write_pair[0], 0);
7746 close(p->write_pair[0]);
7749 if (p->pair[1] != 1) {
7750 dup2(p->pair[1], 1);
7756 if (p->pair[1] != 1) {
7757 dup2(p->pair[1], 1);
7763 if (p->pair[0] != 0) {
7764 dup2(p->pair[0], 0);
7771#if defined(__linux__)
7782linux_get_maxfd(
void)
7785 char buf[4096], *p, *np, *e;
7788 if (fd < 0)
return fd;
7789 ss = read(fd, buf,
sizeof(buf));
7790 if (ss < 0)
goto err;
7793 while ((
int)
sizeof(
"FDSize:\t0\n")-1 <= e-p &&
7794 (np = memchr(p,
'\n', e-p)) != NULL) {
7795 if (memcmp(p,
"FDSize:",
sizeof(
"FDSize:")-1) == 0) {
7797 p +=
sizeof(
"FDSize:")-1;
7817#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
7819 int max = (int)max_file_descriptor;
7822 ret = fcntl(0, F_MAXFD);
7824 maxhint = max = ret;
7825# elif defined(__linux__)
7826 ret = linux_get_maxfd();
7833 for (fd = lowfd; fd <= max; fd++) {
7834 if (!
NIL_P(noclose_fds) &&
7837 ret = fcntl(fd, F_GETFD);
7838 if (ret != -1 && !(ret & FD_CLOEXEC)) {
7839 fcntl(fd, F_SETFD, ret|FD_CLOEXEC);
7841# define CONTIGUOUS_CLOSED_FDS 20
7843 if (max < fd + CONTIGUOUS_CLOSED_FDS)
7844 max = fd + CONTIGUOUS_CLOSED_FDS;
7850# ifndef __EMSCRIPTEN__
7852popen_exec(
void *pp,
char *errmsg,
size_t errmsg_len)
7854 struct popen_arg *p = (
struct popen_arg*)pp;
7856 return rb_exec_async_signal_safe(p->eargp, errmsg, errmsg_len);
7861#if (defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)) && !defined __EMSCRIPTEN__
7863rb_execarg_fixup_v(
VALUE execarg_obj)
7865 rb_execarg_parent_start(execarg_obj);
7869char *rb_execarg_commandline(
const struct rb_execarg *eargp,
VALUE *prog);
7872#ifndef __EMSCRIPTEN__
7874pipe_open(
VALUE execarg_obj,
const char *modestr,
enum rb_io_mode fmode,
7877 struct rb_execarg *eargp =
NIL_P(execarg_obj) ? NULL : rb_execarg_get(execarg_obj);
7878 VALUE prog = eargp ? (eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name) :
Qfalse ;
7884#if defined(HAVE_WORKING_FORK)
7886 char errmsg[80] = {
'\0' };
7888#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7890 struct popen_arg arg;
7893#if defined(HAVE_SPAWNV)
7894# define DO_SPAWN(cmd, args) ((args) ? \
7895 spawnv(P_NOWAIT, (cmd), (args)) : \
7896 spawn(P_NOWAIT, (cmd)))
7897# if !defined(HAVE_WORKING_FORK)
7901#if !defined(HAVE_WORKING_FORK)
7907#if !defined(HAVE_WORKING_FORK)
7908 const char *cmd = 0;
7914#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7915 arg.execarg_obj = execarg_obj;
7918 arg.pair[0] = arg.pair[1] = -1;
7919 arg.write_pair[0] = arg.write_pair[1] = -1;
7920# if !defined(HAVE_WORKING_FORK)
7921 if (eargp && !eargp->use_shell) {
7922 args = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
7927 if (
rb_pipe(arg.write_pair) < 0)
7928 rb_sys_fail_str(prog);
7931 close(arg.write_pair[0]);
7932 close(arg.write_pair[1]);
7936 rb_execarg_addopt(execarg_obj,
INT2FIX(0),
INT2FIX(arg.write_pair[0]));
7937 rb_execarg_addopt(execarg_obj,
INT2FIX(1),
INT2FIX(arg.pair[1]));
7942 rb_sys_fail_str(prog);
7944 rb_execarg_addopt(execarg_obj,
INT2FIX(1),
INT2FIX(arg.pair[1]));
7948 rb_sys_fail_str(prog);
7950 rb_execarg_addopt(execarg_obj,
INT2FIX(0),
INT2FIX(arg.pair[0]));
7953 rb_sys_fail_str(prog);
7955 if (!
NIL_P(execarg_obj)) {
7956 rb_protect(rb_execarg_fixup_v, execarg_obj, &state);
7958 if (0 <= arg.write_pair[0]) close(arg.write_pair[0]);
7959 if (0 <= arg.write_pair[1]) close(arg.write_pair[1]);
7960 if (0 <= arg.pair[0]) close(arg.pair[0]);
7961 if (0 <= arg.pair[1]) close(arg.pair[1]);
7962 rb_execarg_parent_end(execarg_obj);
7966# if defined(HAVE_WORKING_FORK)
7967 pid = rb_fork_async_signal_safe(&status, popen_exec, &arg, arg.eargp->redirect_fds, errmsg,
sizeof(errmsg));
7969 rb_execarg_run_options(eargp, sargp, NULL, 0);
7970 while ((pid = DO_SPAWN(cmd, args)) < 0) {
7972 switch (e =
errno) {
7974# if EWOULDBLOCK != EAGAIN
7983 rb_execarg_run_options(sargp, NULL, NULL, 0);
7985 rb_execarg_parent_end(execarg_obj);
7988# if defined(HAVE_WORKING_FORK)
7989 pid = rb_call_proc__fork();
7991 popen_redirect(&arg);
8003# if defined(HAVE_WORKING_FORK)
8009 close(arg.write_pair[0]);
8010 close(arg.write_pair[1]);
8012# if defined(HAVE_WORKING_FORK)
8021 close(arg.write_pair[0]);
8022 write_fd = arg.write_pair[1];
8033 cmd = rb_execarg_commandline(eargp, &prog);
8034 if (!
NIL_P(execarg_obj)) {
8035 rb_execarg_parent_start(execarg_obj);
8036 rb_execarg_run_options(eargp, sargp, NULL, 0);
8038 fp = popen(cmd, modestr);
8041 rb_execarg_parent_end(execarg_obj);
8042 rb_execarg_run_options(sargp, NULL, NULL, 0);
8044 if (!fp) rb_syserr_fail_path(e, prog);
8054 fptr->
encs = *convconfig;
8055#if RUBY_CRLF_ENVIRONMENT
8062 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
8065#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
8066 if (NEED_NEWLINE_DECORATOR_ON_WRITE(fptr)) {
8067 fptr->
encs.
ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
8073 if (0 <= write_fd) {
8074 write_port = io_alloc(
rb_cIO);
8076 write_fptr->
fd = write_fd;
8078 fptr->
mode &= ~FMODE_WRITABLE;
8080 rb_ivar_set(port, rb_intern(
"@tied_io_for_writing"), write_port);
8083#if defined (__CYGWIN__) || !defined(HAVE_WORKING_FORK)
8085 pipe_add_fptr(fptr);
8091pipe_open(
VALUE execarg_obj,
const char *modestr,
enum rb_io_mode fmode,
8099is_popen_fork(
VALUE prog)
8101 if (RSTRING_LEN(prog) == 1 && RSTRING_PTR(prog)[0] ==
'-') {
8102#if !defined(HAVE_WORKING_FORK)
8104 "fork() function is unimplemented on this machine");
8113pipe_open_s(
VALUE prog,
const char *modestr,
enum rb_io_mode fmode,
8117 VALUE *argv = &prog;
8120 if (!is_popen_fork(prog))
8121 execarg_obj = rb_execarg_new(argc, argv, TRUE, FALSE);
8122 return pipe_open(execarg_obj, modestr, fmode, convconfig);
8128 rb_io_t *fptr = io_close_fptr(io);
8297rb_io_s_popen(
int argc,
VALUE *argv,
VALUE klass)
8301 if (argc > 1 && !
NIL_P(opt = rb_check_hash_type(argv[argc-1]))) --argc;
8302 if (argc > 1 && !
NIL_P(env = rb_check_hash_type(argv[0]))) --argc, ++argv;
8311 int ex = !
NIL_P(opt);
8312 rb_error_arity(argc + ex, 1 + ex, 2 + ex);
8315 return popen_finish(rb_io_popen(pname, pmode, env, opt), klass);
8321 const char *modestr;
8324 enum rb_io_mode fmode;
8330#if SIZEOF_LONG > SIZEOF_INT
8331 if (
len > INT_MAX) {
8332 rb_raise(rb_eArgError,
"too many arguments");
8341 if (!is_popen_fork(pname))
8342 execarg_obj = rb_execarg_new(1, &pname, TRUE, FALSE);
8344 if (!
NIL_P(execarg_obj)) {
8346 opt = rb_execarg_extract_options(execarg_obj, opt);
8348 rb_execarg_setenv(execarg_obj, env);
8351 modestr = rb_io_oflags_modestr(oflags);
8353 return pipe_open(execarg_obj, modestr, fmode, &convconfig);
8363 rb_io_flush(rb_ractor_stdout());
8364 rb_io_flush(rb_ractor_stderr());
8365 _exit(EXIT_SUCCESS);
8369 RBASIC_SET_CLASS(port, klass);
8376#if defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)
8377struct popen_writer_arg {
8379 struct popen_arg popen;
8383exec_popen_writer(
void *arg,
char *errmsg,
size_t buflen)
8385 struct popen_writer_arg *pw = arg;
8387 popen_redirect(&pw->popen);
8388 execv(pw->argv[0], pw->argv);
8389 strlcpy(errmsg, strerror(
errno), buflen);
8395ruby_popen_writer(
char *
const *argv, rb_pid_t *pid)
8397#if (defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)) || defined(_WIN32)
8398# ifdef HAVE_WORKING_FORK
8399 struct popen_writer_arg pw;
8400 int *
const write_pair = pw.popen.pair;
8406 if (cloexec_pipe(write_pair, 0,
false) == 0) {
8407# ifdef HAVE_WORKING_FORK
8410 char errmsg[80] = {
'\0'};
8411 *pid = rb_fork_async_signal_safe(&status, exec_popen_writer, &pw,
Qnil, errmsg,
sizeof(errmsg));
8413 *pid = rb_w32_uspawn_process(P_NOWAIT, argv[0], argv, write_pair[0], -1, -1, 0);
8414 const char *errmsg = (*pid < 0) ? strerror(
errno) : NULL;
8416 close(write_pair[0]);
8418 close(write_pair[1]);
8419 fprintf(stderr,
"ruby_popen_writer(%s): %s\n", argv[0], errmsg);
8422 return fdopen(write_pair[1],
"w");
8433 enum rb_io_mode fmode;
8442 rb_file_open_generic(io, fname, oflags, fmode, &convconfig, perm);
8494rb_io_s_open(
int argc,
VALUE *argv,
VALUE klass)
8526 VALUE fname, vmode, vperm;
8531 rb_scan_args(argc, argv,
"12", &fname, &vmode, &vperm);
8542 if (
NIL_P(vperm)) perm = 0666;
8546 fd = rb_sysopen(fname, oflags, perm);
8578 int redirect = FALSE;
8586 VALUE tmp = argv[0];
8604 return rb_io_s_open(argc, argv,
rb_cFile);
8608rb_io_open_generic(
VALUE klass,
VALUE filename,
int oflags,
enum rb_io_mode fmode,
8611 return rb_file_open_generic(io_alloc(klass), filename,
8612 oflags, fmode, convconfig, perm);
8619 enum rb_io_mode fmode;
8625 return rb_io_open_generic(io, filename, oflags, fmode, &convconfig, perm);
8639 if (fptr == orig)
return io;
8640 if (RUBY_IO_EXTERNAL_P(fptr)) {
8644 rb_raise(rb_eArgError,
8645 "%s can't change access mode from \"%s\" to \"%s\"",
8646 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->
mode),
8647 rb_io_fmode_modestr(orig->
mode));
8650 flush_before_seek(fptr,
true);
8652 clear_codeconv(fptr);
8654 pos = io_tell(orig);
8657 if (io_fflush(orig) < 0)
8658 rb_sys_fail_on_write(fptr);
8667 else if (!RUBY_IO_EXTERNAL_P(fptr)) fptr->
pathv =
Qnil;
8668 fptr_copy_finalizer(fptr, orig);
8674 rb_thread_io_close_interrupt(fptr);
8675 rb_thread_io_close_wait(fptr);
8677 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2 || !fptr->stdio_file) {
8680 rb_sys_fail_path(orig->
pathv);
8688 rb_sys_fail_path(orig->
pathv);
8694 if (io_seek(fptr, pos, SEEK_SET) < 0 &&
errno) {
8695 rb_sys_fail_path(fptr->
pathv);
8697 if (io_seek(orig, pos, SEEK_SET) < 0 &&
errno) {
8698 rb_sys_fail_path(orig->
pathv);
8712int rb_freopen(
VALUE fname,
const char *mode,
FILE *fp);
8715rb_freopen(
VALUE fname,
const char *mode,
FILE *fp)
8717 if (!freopen(RSTRING_PTR(fname), mode, fp)) {
8760rb_io_reopen(
int argc,
VALUE *argv,
VALUE file)
8762 VALUE fname, nmode, opt;
8766 if (
rb_scan_args(argc, argv,
"11:", &fname, &nmode, &opt) == 1) {
8769 return io_reopen(file, tmp);
8775 fptr =
RFILE(file)->fptr;
8781 enum rb_io_mode fmode;
8785 if (RUBY_IO_EXTERNAL_P(fptr) &&
8788 rb_raise(rb_eArgError,
8789 "%s can't change access mode from \"%s\" to \"%s\"",
8790 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->
mode),
8791 rb_io_fmode_modestr(fmode));
8794 fptr->
encs = convconfig;
8797 oflags = rb_io_fmode_oflags(fptr->
mode);
8800 fptr->
pathv = fname;
8802 fptr->
fd = rb_sysopen(fptr->
pathv, oflags, 0666);
8808 if (io_fflush(fptr) < 0)
8809 rb_sys_fail_on_write(fptr);
8812 clear_codeconv(fptr);
8815 int e = rb_freopen(rb_str_encode_ospath(fptr->
pathv),
8816 rb_io_oflags_modestr(oflags),
8818 if (e) rb_syserr_fail_path(e, fptr->
pathv);
8822 if (setvbuf(fptr->
stdio_file, NULL, _IOFBF, 0) != 0)
8823 rb_warn(
"setvbuf() can't be honoured for %"PRIsVALUE, fptr->
pathv);
8826 if (setvbuf(fptr->
stdio_file, NULL, _IONBF, BUFSIZ) != 0)
8827 rb_warn(
"setvbuf() can't be honoured for %"PRIsVALUE, fptr->
pathv);
8829 else if (fptr->
stdio_file == stdout && isatty(fptr->
fd)) {
8830 if (setvbuf(fptr->
stdio_file, NULL, _IOLBF, BUFSIZ) != 0)
8831 rb_warn(
"setvbuf() can't be honoured for %"PRIsVALUE, fptr->
pathv);
8835 int tmpfd = rb_sysopen(fptr->
pathv, oflags, 0666);
8841 rb_syserr_fail_path(err, fptr->
pathv);
8865 fptr->
mode = orig->
mode & ~FMODE_EXTERNAL;
8872 fptr->closing_ec = NULL;
8873 fptr->wakeup_mutex =
Qnil;
8874 fptr->fork_generation = GET_VM()->fork_gen;
8877 fptr_copy_finalizer(fptr, orig);
8879 fd = ruby_dup(orig->
fd);
8881 pos = io_tell(orig);
8883 io_seek(fptr, pos, SEEK_SET);
8888 write_io = GetWriteIO(io);
8889 if (io != write_io) {
8892 rb_ivar_set(dest, rb_intern(
"@tied_io_for_writing"), write_io);
8955 if (argc == 0)
return Qnil;
8957 out = rb_ractor_stdout();
8969extern void rb_deprecated_str_setter(
VALUE val,
ID id,
VALUE *var);
8974 rb_deprecated_str_setter(val,
id, &val);
8980 val = rb_str_frozen_bare_string(val);
9057 for (i=0; i<argc; i++) {
9061 rb_io_write(out, argv[i]);
9158 rb_io_write(io, str);
9162#define forward(obj, id, argc, argv) \
9163 rb_funcallv_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
9164#define forward_public(obj, id, argc, argv) \
9165 rb_funcallv_public_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
9166#define forward_current(id, argc, argv) \
9167 forward_public(ARGF.current_file, id, argc, argv)
9184 VALUE r_stdout = rb_ractor_stdout();
9185 if (recv == r_stdout) {
9186 return rb_io_putc(recv, ch);
9188 return forward(r_stdout, rb_intern(
"putc"), 1, &ch);
9193rb_str_end_with_asciichar(
VALUE str,
int c)
9195 long len = RSTRING_LEN(str);
9196 const char *
ptr = RSTRING_PTR(str);
9200 if (
len == 0)
return 0;
9201 if ((n = rb_enc_mbminlen(
enc)) == 1) {
9202 return ptr[
len - 1] == c;
9204 return rb_enc_ascget(
ptr + ((
len - 1) / n) * n,
ptr +
len, &n,
enc) == c;
9215 rb_io_puts(1, &tmp, out);
9222 rb_io_puts(1, &tmp, out);
9277 VALUE line, args[2];
9284 for (
int i = 0; i < argc; i++) {
9298 if (RSTRING_LEN(line) == 0) {
9303 if (!rb_str_end_with_asciichar(line,
'\n')) {
9308 rb_io_writev(out, n, args);
9326 VALUE r_stdout = rb_ractor_stdout();
9327 if (recv == r_stdout) {
9328 return rb_io_puts(argc, argv, recv);
9330 return forward(r_stdout, rb_intern(
"puts"), argc, argv);
9334rb_p_write(
VALUE str)
9339 VALUE r_stdout = rb_ractor_stdout();
9342 io_writev(2, args, r_stdout);
9345 rb_io_writev(r_stdout, 2, args);
9357rb_p_result(
int argc,
const VALUE *argv)
9364 else if (argc > 1) {
9367 VALUE r_stdout = rb_ractor_stdout();
9369 rb_uninterruptible(rb_io_flush, r_stdout);
9410 for (i=0; i<argc; i++) {
9412 rb_uninterruptible(rb_p_write, inspected);
9414 return rb_p_result(argc, argv);
9435rb_obj_display(
int argc,
VALUE *argv,
VALUE self)
9439 out = (!
rb_check_arity(argc, 0, 1) ? rb_ractor_stdout() : argv[0]);
9440 rb_io_write(out, self);
9446rb_stderr_to_original_p(
VALUE err)
9448 return (err == orig_stderr ||
RFILE(orig_stderr)->fptr->
fd < 0);
9454 VALUE out = rb_ractor_stderr();
9455 if (rb_stderr_to_original_p(out)) {
9457 if (isatty(fileno(stderr))) {
9458 if (rb_w32_write_console(
rb_str_new(mesg,
len), fileno(stderr)) > 0)
return;
9461 if (fwrite(mesg,
sizeof(
char), (
size_t)
len, stderr) < (
size_t)
len) {
9478rb_write_error_str(
VALUE mesg)
9480 VALUE out = rb_ractor_stderr();
9482 if (rb_stderr_to_original_p(out)) {
9483 size_t len = (size_t)RSTRING_LEN(mesg);
9485 if (isatty(fileno(stderr))) {
9486 if (rb_w32_write_console(mesg, fileno(stderr)) > 0)
return;
9489 if (fwrite(RSTRING_PTR(mesg),
sizeof(
char),
len, stderr) <
len) {
9496 rb_io_write(out, mesg);
9501rb_stderr_tty_p(
void)
9503 if (rb_stderr_to_original_p(rb_ractor_stderr()))
9504 return isatty(fileno(stderr));
9509must_respond_to(
ID mid,
VALUE val,
ID id)
9512 rb_raise(
rb_eTypeError,
"%"PRIsVALUE
" must have %"PRIsVALUE
" method, %"PRIsVALUE
" given",
9513 rb_id2str(
id), rb_id2str(mid),
9533 must_respond_to(id_write, val,
id);
9540 return rb_ractor_stdout();
9546 must_respond_to(id_write, val,
id);
9553 return rb_ractor_stderr();
9557allocate_and_open_new_file(
VALUE klass)
9559 VALUE self = io_alloc(klass);
9560 rb_io_make_open_file(self);
9568 VALUE self = rb_protect(allocate_and_open_new_file, klass, &state);
9576 maygvl_close(descriptor, 0);
9584 io->
fd = descriptor;
9602 io->closing_ec = NULL;
9603 io->wakeup_mutex =
Qnil;
9604 io->fork_generation = GET_VM()->fork_gen;
9607 io->
encs = *encoding;
9616prep_io(
int fd,
enum rb_io_mode fmode,
VALUE klass,
const char *path)
9626 e = (fmode &
FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
9627 rb_io_ext_int_to_encs(e, NULL, &convconfig.
enc, &convconfig.
enc2, fmode);
9631#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9633 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
9634 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
9636 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.
enc2, convconfig.
ecflags);
9642 if (!io_check_tty(io)) {
9645 setmode(fd, O_BINARY);
9657 if (path && strcmp(path,
"-")) klass =
rb_cFile;
9658 return prep_io(fd, rb_io_oflags_fmode(oflags), klass, path);
9662prep_stdio(
FILE *f,
enum rb_io_mode fmode,
VALUE klass,
const char *path)
9669#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9670 fptr->
encs.
ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
9681rb_io_prep_stdin(
void)
9687rb_io_prep_stdout(
void)
9693rb_io_prep_stderr(
void)
9702 int oflags = rb_io_fmode_oflags(fptr->
mode) & ~O_EXCL;
9729 rb_io_buffer_init(&fp->
wbuf);
9730 rb_io_buffer_init(&fp->
rbuf);
9731 rb_io_buffer_init(&fp->
cbuf);
9746 fp->closing_ec = NULL;
9747 fp->wakeup_mutex =
Qnil;
9748 fp->fork_generation = GET_VM()->fork_gen;
9753rb_io_make_open_file(
VALUE obj)
9758 if (
RFILE(obj)->fptr) {
9761 RFILE(obj)->fptr = 0;
9763 fp = rb_io_fptr_new();
9765 RFILE(obj)->fptr = fp;
9814rb_io_initialize(
int argc,
VALUE *argv,
VALUE io)
9820 return io_initialize(io, fnum, vmode, opt);
9827 int fd, oflags = O_RDONLY;
9828 enum rb_io_mode fmode;
9830#if defined(HAVE_FCNTL) && defined(F_GETFL)
9840 rb_raise(rb_eArgError,
"The given fd is not accessible because RubyVM reserves it");
9842#if defined(HAVE_FCNTL) && defined(F_GETFL)
9843 oflags = fcntl(fd, F_GETFL);
9844 if (oflags == -1) rb_sys_fail(0);
9846 if (fstat(fd, &st) < 0) rb_sys_fail(0);
9849#if defined(HAVE_FCNTL) && defined(F_GETFL)
9850 ofmode = rb_io_oflags_fmode(oflags);
9862 if (rb_hash_aref(opt, sym_autoclose) ==
Qfalse) {
9866 path = rb_hash_aref(opt,
RB_ID2SYM(idPath));
9877 fp->
encs = convconfig;
9881 fp->closing_ec = NULL;
9882 fp->wakeup_mutex =
Qnil;
9883 fp->fork_generation = GET_VM()->fork_gen;
9886 if (fileno(stdin) == fd)
9888 else if (fileno(stdout) == fd)
9890 else if (fileno(stderr) == fd)
9922rb_io_set_encoding_by_bom(
VALUE io)
9928 rb_raise(rb_eArgError,
"ASCII incompatible encoding needs binmode");
9931 rb_raise(rb_eArgError,
"encoding conversion is set");
9933 else if (fptr->
encs.
enc && fptr->
encs.
enc != rb_ascii8bit_encoding()) {
9934 rb_raise(rb_eArgError,
"encoding is set to %s already",
9937 if (!io_set_encoding_by_bom(io))
return Qnil;
9938 return rb_enc_from_encoding(fptr->
encs.
enc);
9991rb_file_initialize(
int argc,
VALUE *argv,
VALUE io)
9993 if (
RFILE(io)->fptr) {
9996 VALUE fname, vmode, vperm, opt;
9997 int posargc =
rb_scan_args(argc, argv,
"12:", &fname, &vmode, &vperm, &opt);
10002 return io_initialize(io, fd, vmode, opt);
10005 return rb_open_file(io, fname, vmode, vperm, opt);
10010rb_io_s_new(
int argc,
VALUE *argv,
VALUE klass)
10015 rb_warn(
"%"PRIsVALUE
"::new() does not take block; use %"PRIsVALUE
"::open() instead",
10031rb_io_s_for_fd(
int argc,
VALUE *argv,
VALUE klass)
10034 rb_io_initialize(argc, argv, io);
10047rb_io_autoclose_p(
VALUE io)
10072rb_io_set_autoclose(
VALUE io,
VALUE autoclose)
10076 if (!
RTEST(autoclose))
10079 fptr->
mode &= ~FMODE_EXTERNAL;
10084io_wait_event(
VALUE io,
int event,
VALUE timeout,
int return_io)
10094 if (mask & event) {
10116io_wait_readable(
int argc,
VALUE *argv,
VALUE io)
10123 if (rb_io_read_pending(fptr))
return Qtrue;
10126 VALUE timeout = (argc == 1 ? argv[0] :
Qnil);
10140io_wait_writable(
int argc,
VALUE *argv,
VALUE io)
10148 VALUE timeout = (argc == 1 ? argv[0] :
Qnil);
10163io_wait_priority(
int argc,
VALUE *argv,
VALUE io)
10170 if (rb_io_read_pending(fptr))
return Qtrue;
10173 VALUE timeout = argc == 1 ? argv[0] :
Qnil;
10179wait_mode_sym(
VALUE mode)
10181 if (mode ==
ID2SYM(rb_intern(
"r"))) {
10182 return RB_WAITFD_IN;
10184 if (mode ==
ID2SYM(rb_intern(
"read"))) {
10185 return RB_WAITFD_IN;
10187 if (mode ==
ID2SYM(rb_intern(
"readable"))) {
10188 return RB_WAITFD_IN;
10190 if (mode ==
ID2SYM(rb_intern(
"w"))) {
10191 return RB_WAITFD_OUT;
10193 if (mode ==
ID2SYM(rb_intern(
"write"))) {
10194 return RB_WAITFD_OUT;
10196 if (mode ==
ID2SYM(rb_intern(
"writable"))) {
10197 return RB_WAITFD_OUT;
10199 if (mode ==
ID2SYM(rb_intern(
"rw"))) {
10200 return RB_WAITFD_IN|RB_WAITFD_OUT;
10202 if (mode ==
ID2SYM(rb_intern(
"read_write"))) {
10203 return RB_WAITFD_IN|RB_WAITFD_OUT;
10205 if (mode ==
ID2SYM(rb_intern(
"readable_writable"))) {
10206 return RB_WAITFD_IN|RB_WAITFD_OUT;
10209 rb_raise(rb_eArgError,
"unsupported mode: %"PRIsVALUE, mode);
10213io_event_from_value(
VALUE value)
10217 if (events <= 0) rb_raise(rb_eArgError,
"Events must be positive integer!");
10255 for (
int i = 0; i < argc; i += 1) {
10257 events |= wait_mode_sym(argv[i]);
10259 else if (UNDEF_P(timeout)) {
10263 rb_raise(rb_eArgError,
"timeout given more than once");
10267 if (UNDEF_P(timeout)) timeout =
Qnil;
10275 events = io_event_from_value(argv[0]);
10283 if (rb_io_read_pending(fptr)) {
10285 if (return_io)
return Qtrue;
10291 return io_wait_event(io, events, timeout, return_io);
10295argf_mark_and_move(
void *ptr)
10297 struct argf *p = ptr;
10298 rb_gc_mark_and_move(&p->filename);
10299 rb_gc_mark_and_move(&p->current_file);
10300 rb_gc_mark_and_move(&p->argv);
10301 rb_gc_mark_and_move(&p->inplace);
10302 rb_gc_mark_and_move(&p->encs.
ecopts);
10306argf_memsize(
const void *ptr)
10308 const struct argf *p = ptr;
10309 size_t size =
sizeof(*p);
10316 0, 0, RUBY_TYPED_THREAD_SAFE_FREE | RUBY_TYPED_WB_PROTECTED
10322 p->filename =
Qnil;
10323 p->current_file =
Qnil;
10329argf_alloc(
VALUE klass)
10344 memset(&ARGF, 0,
sizeof(ARGF));
10345 argf_init(
argf, &ARGF, argv);
10355 ARGF = argf_of(orig);
10356 rb_gc_writebarrier_remember(
argf);
10383 ARGF.last_lineno = ARGF.lineno;
10409 return forward_current(rb_frame_this_func(), argc, argv);
10412#define next_argv() argf_next_argv(argf)
10413#define ARGF_GENERIC_INPUT_P() \
10414 (ARGF.current_file == rb_stdin && !RB_TYPE_P(ARGF.current_file, T_FILE))
10415#define ARGF_FORWARD(argc, argv) do {\
10416 if (ARGF_GENERIC_INPUT_P())\
10417 return argf_forward((argc), (argv), argf);\
10419#define NEXT_ARGF_FORWARD(argc, argv) do {\
10420 if (!next_argv()) return Qnil;\
10421 ARGF_FORWARD((argc), (argv));\
10427 VALUE file = ARGF.current_file;
10441 int stdout_binmode = 0;
10442 enum rb_io_mode fmode;
10444 VALUE r_stdout = rb_ractor_stdout();
10449 stdout_binmode = 1;
10452 if (ARGF.init_p == 0) {
10462 if (
NIL_P(ARGF.argv)) {
10465 else if (ARGF.next_p == -1 &&
RARRAY_LEN(ARGF.argv) > 0) {
10470 if (ARGF.next_p == 1) {
10471 if (ARGF.init_p == 1) argf_close(
argf);
10476 ARGF_SET(filename, filename);
10477 filename = rb_str_encode_ospath(filename);
10479 if (RSTRING_LEN(filename) == 1 && fn[0] ==
'-') {
10481 if (ARGF.inplace) {
10482 rb_warn(
"Can't do inplace edit for stdio; skipping");
10488 int fr = rb_sysopen(filename, O_RDONLY, 0);
10490 if (ARGF.inplace) {
10492#ifndef NO_SAFE_RENAME
10503 if (!
NIL_P(ARGF.inplace)) {
10504 VALUE suffix = ARGF.inplace;
10506 if (
NIL_P(rb_str_cat_conv_enc_opts(str, RSTRING_LEN(str),
10507 RSTRING_PTR(suffix), RSTRING_LEN(suffix),
10508 rb_enc_get(suffix), 0,
Qnil))) {
10511#ifdef NO_SAFE_RENAME
10513 (void)unlink(RSTRING_PTR(str));
10514 if (rename(fn, RSTRING_PTR(str)) < 0) {
10515 rb_warn(
"Can't rename %"PRIsVALUE
" to %"PRIsVALUE
": %s, skipping file",
10516 filename, str, strerror(
errno));
10519 fr = rb_sysopen(str, O_RDONLY, 0);
10521 if (rename(fn, RSTRING_PTR(str)) < 0) {
10522 rb_warn(
"Can't rename %"PRIsVALUE
" to %"PRIsVALUE
": %s, skipping file",
10523 filename, str, strerror(
errno));
10530#ifdef NO_SAFE_RENAME
10531 rb_fatal(
"Can't do inplace edit without backup");
10533 if (unlink(fn) < 0) {
10534 rb_warn(
"Can't remove %"PRIsVALUE
": %s, skipping file",
10535 filename, strerror(
errno));
10541 fw = rb_sysopen(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666);
10542#ifndef NO_SAFE_RENAME
10545 fchmod(fw, st.st_mode);
10547 chmod(fn, st.st_mode);
10549 if (st.st_uid!=st2.st_uid || st.st_gid!=st2.st_gid) {
10552 err = fchown(fw, st.st_uid, st.st_gid);
10554 err = chown(fn, st.st_uid, st.st_gid);
10556 if (err && getuid() == 0 && st2.st_uid == 0) {
10557 const char *wkfn = RSTRING_PTR(filename);
10558 rb_warn(
"Can't set owner/group of %"PRIsVALUE
" to same as %"PRIsVALUE
": %s, skipping file",
10559 filename, str, strerror(
errno));
10562 (void)unlink(wkfn);
10572 if (!ARGF.binmode) {
10573 fmode |= DEFAULT_TEXTMODE;
10575 ARGF_SET(current_file, prep_io(fr, fmode,
rb_cFile, fn));
10576 if (!
NIL_P(write_io)) {
10583 if (ARGF.encs.enc) {
10584 fptr->
encs = ARGF.encs;
10585 clear_codeconv(fptr);
10588 fptr->
encs.
ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
10589 if (!ARGF.binmode) {
10591#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
10592 fptr->
encs.
ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
10603 else if (ARGF.next_p == -1) {
10606 if (ARGF.inplace) {
10607 rb_warn(
"Can't do inplace edit for stdio");
10611 if (ARGF.init_p == -1) ARGF.init_p = 1;
10619 long lineno = ARGF.lineno;
10622 if (!next_argv())
return Qnil;
10623 if (ARGF_GENERIC_INPUT_P()) {
10624 line = forward_current(idGets, argc, argv);
10631 line = rb_io_getline(argc, argv, ARGF.current_file);
10633 if (
NIL_P(line) && ARGF.next_p != -1) {
10639 if (!
NIL_P(line)) {
10640 ARGF.lineno = ++lineno;
10641 ARGF.last_lineno = ARGF.lineno;
10647argf_lineno_getter(
ID id,
VALUE *var)
10650 return INT2FIX(ARGF.last_lineno);
10658 ARGF.last_lineno = ARGF.lineno = n;
10662rb_reset_argf_lineno(
long n)
10664 ARGF.last_lineno = ARGF.lineno = n;
10705 if (recv ==
argf) {
10706 return argf_gets(argc, argv,
argf);
10708 return forward(
argf, idGets, argc, argv);
10734 line = argf_getline(argc, argv,
argf);
10746 return rb_f_gets(0, 0,
argf);
10750 if (!next_argv())
return Qnil;
10752 if (
NIL_P(line) && ARGF.next_p != -1) {
10758 if (!
NIL_P(line)) {
10760 ARGF.last_lineno = ARGF.lineno;
10786rb_f_readline(
int argc,
VALUE *argv,
VALUE recv)
10788 if (recv ==
argf) {
10789 return argf_readline(argc, argv,
argf);
10791 return forward(
argf, rb_intern(
"readline"), argc, argv);
10817 if (!next_argv()) rb_eof_error();
10818 ARGF_FORWARD(argc, argv);
10819 line = argf_gets(argc, argv,
argf);
10889rb_f_readlines(
int argc,
VALUE *argv,
VALUE recv)
10891 if (recv ==
argf) {
10892 return argf_readlines(argc, argv,
argf);
10894 return forward(
argf, rb_intern(
"readlines"), argc, argv);
10918 long lineno = ARGF.lineno;
10922 while (next_argv()) {
10923 if (ARGF_GENERIC_INPUT_P()) {
10924 lines = forward_current(rb_intern(
"readlines"), argc, argv);
10927 lines = rb_io_readlines(argc, argv, ARGF.current_file);
10933 ARGF.last_lineno = ARGF.lineno;
10968 rb_last_status_clear();
10969 port = pipe_open_s(str,
"r",
FMODE_READABLE|DEFAULT_TEXTMODE, NULL);
10973 result = read_all(fptr, remain_size(fptr),
Qnil);
10975 rb_io_fptr_cleanup_all(fptr);
10981#ifdef HAVE_SYS_SELECT_H
10982#include <sys/select.h>
10996 if (!
NIL_P(read)) {
11001 if (READ_DATA_PENDING(fptr) || READ_CHAR_PENDING(fptr)) {
11005 if (max < fptr->fd) max = fptr->
fd;
11008 timerec.tv_sec = timerec.tv_usec = 0;
11016 if (!
NIL_P(write)) {
11022 if (max < fptr->fd) max = fptr->
fd;
11029 if (!
NIL_P(except)) {
11033 VALUE write_io = GetWriteIO(io);
11036 if (max < fptr->fd) max = fptr->
fd;
11037 if (io != write_io) {
11040 if (max < fptr->fd) max = fptr->
fd;
11055 if (!pending && n == 0)
return Qnil;
11080 VALUE write_io = GetWriteIO(io);
11093 VALUE write_io = GetWriteIO(io);
11098 else if (io != write_io) {
11111 VALUE read, write, except;
11117select_call(
VALUE arg)
11121 return select_internal(p->read, p->write, p->except, p->timeout, p->fdsets);
11125select_end(
VALUE arg)
11130 for (i = 0; i < numberof(p->fdsets); ++i)
11135static VALUE sym_normal, sym_sequential, sym_random,
11136 sym_willneed, sym_dontneed, sym_noreuse;
11138#ifdef HAVE_POSIX_FADVISE
11139struct io_advise_struct {
11147io_advise_internal(
void *arg)
11149 struct io_advise_struct *ptr = arg;
11150 return posix_fadvise(ptr->fd, ptr->offset, ptr->len, ptr->advice);
11154io_advise_sym_to_const(
VALUE sym)
11156#ifdef POSIX_FADV_NORMAL
11157 if (sym == sym_normal)
11158 return INT2NUM(POSIX_FADV_NORMAL);
11161#ifdef POSIX_FADV_RANDOM
11162 if (sym == sym_random)
11163 return INT2NUM(POSIX_FADV_RANDOM);
11166#ifdef POSIX_FADV_SEQUENTIAL
11167 if (sym == sym_sequential)
11168 return INT2NUM(POSIX_FADV_SEQUENTIAL);
11171#ifdef POSIX_FADV_WILLNEED
11172 if (sym == sym_willneed)
11173 return INT2NUM(POSIX_FADV_WILLNEED);
11176#ifdef POSIX_FADV_DONTNEED
11177 if (sym == sym_dontneed)
11178 return INT2NUM(POSIX_FADV_DONTNEED);
11181#ifdef POSIX_FADV_NOREUSE
11182 if (sym == sym_noreuse)
11183 return INT2NUM(POSIX_FADV_NOREUSE);
11190do_io_advise(
rb_io_t *fptr,
VALUE advice, rb_off_t offset, rb_off_t
len)
11193 struct io_advise_struct ias;
11196 num_adv = io_advise_sym_to_const(advice);
11202 if (
NIL_P(num_adv))
11206 ias.advice =
NUM2INT(num_adv);
11207 ias.offset = offset;
11210 rv = (int)rb_io_blocking_region(fptr, io_advise_internal, &ias);
11211 if (rv && rv != ENOSYS) {
11214 VALUE message = rb_sprintf(
"%"PRIsVALUE
" "
11218 fptr->
pathv, offset,
len, advice);
11228advice_arg_check(
VALUE advice)
11233 if (advice != sym_normal &&
11234 advice != sym_sequential &&
11235 advice != sym_random &&
11236 advice != sym_willneed &&
11237 advice != sym_dontneed &&
11238 advice != sym_noreuse) {
11239 rb_raise(
rb_eNotImpError,
"Unsupported advice: %+"PRIsVALUE, advice);
11277rb_io_advise(
int argc,
VALUE *argv,
VALUE io)
11284 advice_arg_check(advice);
11286 io = GetWriteIO(io);
11292#ifdef HAVE_POSIX_FADVISE
11293 return do_io_advise(fptr, advice,
off, l);
11295 ((void)
off, (
void)l);
11307 return isinf(f) && 0 < f;
11463rb_f_select(
int argc,
VALUE *argv,
VALUE obj)
11466 if (scheduler !=
Qnil) {
11469 if (!UNDEF_P(result))
return result;
11477 rb_scan_args(argc, argv,
"13", &args.read, &args.write, &args.except, &timeout);
11478 if (
NIL_P(timeout) || is_pos_inf(timeout)) {
11483 args.timeout = &timerec;
11486 for (i = 0; i < numberof(args.fdsets); ++i)
11492#ifdef IOCTL_REQ_TYPE
11493 typedef IOCTL_REQ_TYPE ioctl_req_t;
11495 typedef int ioctl_req_t;
11496# define NUM2IOCTLREQ(num) ((int)NUM2LONG(num))
11507nogvl_ioctl(
void *ptr)
11509 struct ioctl_arg *arg = ptr;
11511 return (
VALUE)ioctl(arg->fd, arg->cmd, arg->narg);
11515do_ioctl(
struct rb_io *io, ioctl_req_t cmd,
long narg)
11518 struct ioctl_arg arg;
11524 retval = (int)rb_io_blocking_region(io, nogvl_ioctl, &arg);
11530#define DEFAULT_IOCTL_NARG_LEN (256)
11532#if defined(__linux__) && defined(_IOC_SIZE)
11534linux_iocparm_len(ioctl_req_t cmd)
11538 if ((cmd & 0xFFFF0000) == 0) {
11540 return DEFAULT_IOCTL_NARG_LEN;
11543 len = _IOC_SIZE(cmd);
11546 if (
len < DEFAULT_IOCTL_NARG_LEN)
11547 len = DEFAULT_IOCTL_NARG_LEN;
11555ioctl_narg_len(ioctl_req_t cmd)
11561#define IOCPARM_LEN(x) (((x) >> 16) & IOCPARM_MASK)
11565 len = IOCPARM_LEN(cmd);
11566#elif defined(__linux__) && defined(_IOC_SIZE)
11567 len = linux_iocparm_len(cmd);
11570 len = DEFAULT_IOCTL_NARG_LEN;
11579typedef long fcntl_arg_t;
11582typedef int fcntl_arg_t;
11586fcntl_narg_len(ioctl_req_t cmd)
11593 len =
sizeof(fcntl_arg_t);
11601#ifdef F_DUPFD_CLOEXEC
11602 case F_DUPFD_CLOEXEC:
11603 len =
sizeof(fcntl_arg_t);
11613 len =
sizeof(fcntl_arg_t);
11623 len =
sizeof(fcntl_arg_t);
11633 len =
sizeof(fcntl_arg_t);
11638 len =
sizeof(
struct f_owner_ex);
11643 len =
sizeof(
struct f_owner_ex);
11648 len =
sizeof(
struct flock);
11653 len =
sizeof(
struct flock);
11658 len =
sizeof(
struct flock);
11678 len =
sizeof(fcntl_arg_t);
11688 len =
sizeof(fcntl_arg_t);
11693 len =
sizeof(fcntl_arg_t);
11706fcntl_narg_len(ioctl_req_t cmd)
11712#define NARG_SENTINEL 17
11715setup_narg(ioctl_req_t cmd,
VALUE *argp,
long (*narg_len)(ioctl_req_t))
11726 else if (arg ==
Qtrue) {
11740 len = narg_len(cmd);
11741 rb_str_modify(arg);
11743 slen = RSTRING_LEN(arg);
11745 if (slen <
len+1) {
11746 rb_str_resize(arg,
len+1);
11747 MEMZERO(RSTRING_PTR(arg)+slen,
char,
len-slen);
11751 ptr = RSTRING_PTR(arg);
11752 ptr[slen - 1] = NARG_SENTINEL;
11761finish_narg(
int retval,
VALUE arg,
const rb_io_t *fptr)
11763 if (retval < 0) rb_sys_fail_path(fptr->
pathv);
11768 if (ptr[slen-1] != NARG_SENTINEL)
11769 rb_raise(rb_eArgError,
"return value overflowed string");
11770 ptr[slen-1] =
'\0';
11780 ioctl_req_t cmd = NUM2IOCTLREQ(req);
11785 narg = setup_narg(cmd, &arg, ioctl_narg_len);
11787 retval = do_ioctl(fptr, cmd, narg);
11788 return finish_narg(retval, arg, fptr);
11815 return rb_ioctl(io, req, arg);
11818#define rb_io_ioctl rb_f_notimplement
11829nogvl_fcntl(
void *ptr)
11831 struct fcntl_arg *arg = ptr;
11833#if defined(F_DUPFD)
11834 if (arg->cmd == F_DUPFD)
11837 return (
VALUE)fcntl(arg->fd, arg->cmd, arg->narg);
11841do_fcntl(
struct rb_io *io,
int cmd,
long narg)
11844 struct fcntl_arg arg;
11850 retval = (int)rb_io_blocking_region(io, nogvl_fcntl, &arg);
11851 if (retval != -1) {
11853#if defined(F_DUPFD)
11856#if defined(F_DUPFD_CLOEXEC)
11857 case F_DUPFD_CLOEXEC:
11874 narg = setup_narg(cmd, &arg, fcntl_narg_len);
11876 retval = do_fcntl(fptr, cmd, narg);
11877 return finish_narg(retval, arg, fptr);
11903 return rb_fcntl(io, req, arg);
11906#define rb_io_fcntl rb_f_notimplement
11909#if defined(HAVE_SYSCALL) || defined(HAVE___SYSCALL)
11941#if SIZEOF_VOIDP == 8 && defined(HAVE___SYSCALL) && SIZEOF_INT != 8
11942# define SYSCALL __syscall
11943# define NUM2SYSCALLID(x) NUM2LONG(x)
11944# define RETVAL2NUM(x) LONG2NUM(x)
11945# if SIZEOF_LONG == 8
11946 long num, retval = -1;
11947# elif SIZEOF_LONG_LONG == 8
11948 long long num, retval = -1;
11950# error ---->> it is asserted that __syscall takes the first argument and returns retval in 64bit signed integer. <<----
11952#elif defined(__linux__)
11953# define SYSCALL syscall
11954# define NUM2SYSCALLID(x) NUM2LONG(x)
11955# define RETVAL2NUM(x) LONG2NUM(x)
11963 long num, retval = -1;
11965# define SYSCALL syscall
11966# define NUM2SYSCALLID(x) NUM2INT(x)
11967# define RETVAL2NUM(x) INT2NUM(x)
11968 int num, retval = -1;
11974 "We plan to remove a syscall function at future release. DL(Fiddle) provides safer alternative.");
11978 rb_raise(rb_eArgError,
"too few arguments for syscall");
11979 if (argc > numberof(arg))
11980 rb_raise(rb_eArgError,
"too many arguments for syscall");
11981 num = NUM2SYSCALLID(argv[0]); ++argv;
11982 for (i = argc - 1; i--; ) {
11997 retval = SYSCALL(num);
12000 retval = SYSCALL(num, arg[0]);
12003 retval = SYSCALL(num, arg[0],arg[1]);
12006 retval = SYSCALL(num, arg[0],arg[1],arg[2]);
12009 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3]);
12012 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4]);
12015 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5]);
12018 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6]);
12024 return RETVAL2NUM(retval);
12026#undef NUM2SYSCALLID
12030#define rb_f_syscall rb_f_notimplement
12034io_new_instance(
VALUE args)
12040find_encoding(
VALUE v)
12043 if (!enc)
rb_warn(
"Unsupported encoding %"PRIsVALUE
" ignored", v);
12055 enc2 = find_encoding(v1);
12058 if (RSTRING_LEN(tmp) == 1 && RSTRING_PTR(tmp)[0] ==
'-') {
12064 enc = find_encoding(v2);
12071 enc = find_encoding(v2);
12077 if (enc2 == rb_ascii8bit_encoding()) {
12082 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
12088 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
12089 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
12094 if (!
NIL_P(tmp) && rb_enc_asciicompat(enc = rb_enc_get(tmp))) {
12095 parse_mode_enc(RSTRING_PTR(tmp), enc, &enc, &enc2, NULL);
12096 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
12100 rb_io_ext_int_to_encs(find_encoding(v1), NULL, &enc, &enc2, 0);
12101 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
12106 validate_enc_binmode(&fptr->
mode, ecflags, enc, enc2);
12111 clear_codeconv(fptr);
12123io_encoding_set_v(
VALUE v)
12126 io_encoding_set(arg->fptr, arg->v1, arg->v2, arg->opt);
12131pipe_pair_close(
VALUE rw)
12134 return rb_ensure(io_close, rwp[0], io_close, rwp[1]);
12217rb_io_s_pipe(
int argc,
VALUE *argv,
VALUE klass)
12219 int pipes[2], state;
12220 VALUE r, w, args[3], v1, v2;
12224 enum rb_io_mode fmode = 0;
12227 argc =
rb_scan_args(argc, argv,
"02:", &v1, &v2, &opt);
12234 r = rb_protect(io_new_instance, (
VALUE)args, &state);
12238 rb_jump_tag(state);
12242 ies_args.fptr = fptr;
12245 ies_args.opt = opt;
12246 rb_protect(io_encoding_set_v, (
VALUE)&ies_args, &state);
12250 rb_jump_tag(state);
12255 w = rb_protect(io_new_instance, (
VALUE)args, &state);
12259 rb_jump_tag(state);
12264 extract_binmode(opt, &fmode);
12271#if DEFAULT_TEXTMODE
12273 fptr->
mode &= ~FMODE_TEXTMODE;
12274 setmode(fptr->
fd, O_BINARY);
12276#if RUBY_CRLF_ENVIRONMENT
12282 fptr->
mode |= fmode;
12283#if DEFAULT_TEXTMODE
12285 fptr2->
mode &= ~FMODE_TEXTMODE;
12286 setmode(fptr2->
fd, O_BINARY);
12289 fptr2->
mode |= fmode;
12323 else if (!
NIL_P(v = rb_hash_aref(opt, sym_open_args))) {
12326 v = rb_to_array_type(v);
12331 arg->io = rb_io_open(klass, path, vmode, vperm, opt);
12335io_s_foreach(
VALUE v)
12340 if (arg->limit == 0)
12341 rb_raise(rb_eArgError,
"invalid limit: 0 for foreach");
12342 while (!
NIL_P(str = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, arg->io))) {
12426rb_io_s_foreach(
int argc,
VALUE *argv,
VALUE self)
12429 int orig_argc = argc;
12433 argc =
rb_scan_args(argc, argv,
"12:", NULL, NULL, NULL, &opt);
12435 extract_getline_args(argc-1, argv+1, &garg);
12436 open_key_args(self, argc, argv, opt, &arg);
12438 extract_getline_opts(opt, &garg);
12439 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12440 return rb_ensure(io_s_foreach, (
VALUE)&garg, rb_io_close, arg.io);
12444io_s_readlines(
VALUE v)
12447 return io_readlines(arg, arg->io);
12500rb_io_s_readlines(
int argc,
VALUE *argv,
VALUE io)
12506 argc =
rb_scan_args(argc, argv,
"12:", NULL, NULL, NULL, &opt);
12507 extract_getline_args(argc-1, argv+1, &garg);
12508 open_key_args(io, argc, argv, opt, &arg);
12510 extract_getline_opts(opt, &garg);
12511 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12512 return rb_ensure(io_s_readlines, (
VALUE)&garg, rb_io_close, arg.io);
12519 return io_read(arg->argc, arg->argv, arg->io);
12529seek_before_access(
VALUE argp)
12533 return rb_io_seek(arg->io, arg->offset, arg->mode);
12600rb_io_s_read(
int argc,
VALUE *argv,
VALUE io)
12606 argc =
rb_scan_args(argc, argv,
"13:", NULL, NULL, &offset, NULL, &opt);
12608 rb_raise(rb_eArgError,
"negative offset %ld given",
off);
12610 open_key_args(io, argc, argv, opt, &arg);
12612 if (!
NIL_P(offset)) {
12616 sarg.offset = offset;
12617 sarg.mode = SEEK_SET;
12618 rb_protect(seek_before_access, (
VALUE)&sarg, &state);
12621 rb_jump_tag(state);
12623 if (arg.argc == 2) arg.argc = 1;
12638rb_io_s_binread(
int argc,
VALUE *argv,
VALUE io)
12653 convconfig.
enc = rb_ascii8bit_encoding();
12654 arg.io = rb_io_open_generic(io, argv[0], oflags, fmode, &convconfig, 0);
12657 arg.argc = (argc > 1) ? 1 : 0;
12658 if (!
NIL_P(offset)) {
12662 sarg.offset = offset;
12663 sarg.mode = SEEK_SET;
12664 rb_protect(seek_before_access, (
VALUE)&sarg, &state);
12667 rb_jump_tag(state);
12674io_s_write0(
VALUE v)
12677 return io_write(arg->io,arg->str,arg->nosync);
12681io_s_write(
int argc,
VALUE *argv,
VALUE klass,
int binary)
12683 VALUE string, offset, opt;
12687 rb_scan_args(argc, argv,
"21:", NULL, &
string, &offset, &opt);
12689 if (
NIL_P(opt)) opt = rb_hash_new();
12690 else opt = rb_hash_dup(opt);
12693 if (
NIL_P(rb_hash_aref(opt,sym_mode))) {
12694 int mode = O_WRONLY|O_CREAT;
12696 if (binary) mode |= O_BINARY;
12698 if (
NIL_P(offset)) mode |= O_TRUNC;
12699 rb_hash_aset(opt,sym_mode,
INT2NUM(mode));
12701 open_key_args(klass, argc, argv, opt, &arg);
12704 if (binary) rb_io_binmode_m(arg.io);
12708 if (!
NIL_P(offset)) {
12712 sarg.offset = offset;
12713 sarg.mode = SEEK_SET;
12714 rb_protect(seek_before_access, (
VALUE)&sarg, &state);
12717 rb_jump_tag(state);
12725 return rb_ensure(io_s_write0, (
VALUE)&warg, rb_io_close, arg.io);
12783rb_io_s_write(
int argc,
VALUE *argv,
VALUE io)
12785 return io_s_write(argc, argv, io, 0);
12798rb_io_s_binwrite(
int argc,
VALUE *argv,
VALUE io)
12800 return io_s_write(argc, argv, io, 1);
12806 rb_off_t copy_length;
12807 rb_off_t src_offset;
12811 unsigned close_src : 1;
12812 unsigned close_dst : 1;
12815 const char *syserr;
12816 const char *notimp;
12818 struct stat src_stat;
12819 struct stat dst_stat;
12820#ifdef HAVE_FCOPYFILE
12821 copyfile_state_t copyfile_state;
12826exec_interrupts(
void *arg)
12829 rb_thread_execute_interrupts(th);
12843#if defined(ERESTART)
12848 rb_thread_execute_interrupts(stp->th);
12867fiber_scheduler_wait_for(
void * _arguments)
12877# define IOWAIT_SYSCALL "poll"
12878STATIC_ASSERT(pollin_expected, POLLIN == RB_WAITFD_IN);
12879STATIC_ASSERT(pollout_expected, POLLOUT == RB_WAITFD_OUT);
12884 if (scheduler !=
Qnil) {
12887 return RTEST(args.result);
12891 if (fd == -1)
return 0;
12896 fds.events = events;
12898 int timeout_milliseconds = -1;
12901 timeout_milliseconds = (int)(timeout->tv_sec * 1000) + (int)(timeout->tv_usec / 1000);
12904 return poll(&fds, 1, timeout_milliseconds);
12907# define IOWAIT_SYSCALL "select"
12912 if (scheduler !=
Qnil) {
12915 return RTEST(args.result);
12935 case RB_WAITFD_OUT:
12939 VM_UNREACHABLE(nogvl_wait_for);
12959 ret = nogvl_wait_for(stp->th, stp->src_fptr, RB_WAITFD_IN, NULL);
12961 }
while (ret < 0 && maygvl_copy_stream_continue_p(has_gvl, stp));
12964 stp->syserr = IOWAIT_SYSCALL;
12965 stp->error_no =
errno;
12977 ret = nogvl_wait_for(stp->th, stp->dst_fptr, RB_WAITFD_OUT, NULL);
12978 }
while (ret < 0 && maygvl_copy_stream_continue_p(0, stp));
12981 stp->syserr = IOWAIT_SYSCALL;
12982 stp->error_no =
errno;
12988#ifdef USE_COPY_FILE_RANGE
12991simple_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)
12993#ifdef HAVE_COPY_FILE_RANGE
12994 return copy_file_range(in_fd, in_offset, out_fd, out_offset, count, flags);
12996 return syscall(__NR_copy_file_range, in_fd, in_offset, out_fd, out_offset, count, flags);
13005 rb_off_t copy_length, src_offset, *src_offset_ptr;
13007 if (!S_ISREG(stp->src_stat.st_mode))
13010 src_size = stp->src_stat.st_size;
13011 src_offset = stp->src_offset;
13012 if (src_offset >= (rb_off_t)0) {
13013 src_offset_ptr = &src_offset;
13016 src_offset_ptr = NULL;
13019 copy_length = stp->copy_length;
13020 if (copy_length < (rb_off_t)0) {
13021 if (src_offset < (rb_off_t)0) {
13022 rb_off_t current_offset;
13024 current_offset = lseek(stp->src_fptr->
fd, 0, SEEK_CUR);
13025 if (current_offset < (rb_off_t)0 &&
errno) {
13026 stp->syserr =
"lseek";
13027 stp->error_no =
errno;
13028 return (
int)current_offset;
13030 copy_length = src_size - current_offset;
13033 copy_length = src_size - src_offset;
13037 retry_copy_file_range:
13038# if SIZEOF_OFF_T > SIZEOF_SIZE_T
13040 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
13042 ss = (ssize_t)copy_length;
13044 ss = simple_copy_file_range(stp->src_fptr->
fd, src_offset_ptr, stp->dst_fptr->
fd, NULL, ss, 0);
13048 if (0 < copy_length) {
13049 goto retry_copy_file_range;
13053 if (maygvl_copy_stream_continue_p(0, stp)) {
13054 goto retry_copy_file_range;
13068#if EWOULDBLOCK != EAGAIN
13072 int ret = nogvl_copy_stream_wait_write(stp);
13073 if (ret < 0)
return ret;
13075 goto retry_copy_file_range;
13079 int flags = fcntl(stp->dst_fptr->
fd, F_GETFL);
13081 if (flags != -1 && flags & O_APPEND) {
13087 stp->syserr =
"copy_file_range";
13088 stp->error_no =
errno;
13095#ifdef HAVE_FCOPYFILE
13099 rb_off_t cur, ss = 0;
13100 const rb_off_t src_offset = stp->src_offset;
13103 if (stp->copy_length >= (rb_off_t)0) {
13108 if (!S_ISREG(stp->src_stat.st_mode))
13111 if (!S_ISREG(stp->dst_stat.st_mode))
13113 if (lseek(stp->dst_fptr->
fd, 0, SEEK_CUR) > (rb_off_t)0)
13115 if (fcntl(stp->dst_fptr->
fd, F_GETFL) & O_APPEND) {
13118 rb_off_t end = lseek(stp->dst_fptr->
fd, 0, SEEK_END);
13119 lseek(stp->dst_fptr->
fd, 0, SEEK_SET);
13120 if (end > (rb_off_t)0)
return 0;
13123 if (src_offset > (rb_off_t)0) {
13128 cur = lseek(stp->src_fptr->
fd, 0, SEEK_CUR);
13129 if (cur < (rb_off_t)0 &&
errno) {
13130 stp->error_no =
errno;
13135 r = lseek(stp->src_fptr->
fd, src_offset, SEEK_SET);
13136 if (r < (rb_off_t)0 &&
errno) {
13137 stp->error_no =
errno;
13142 stp->copyfile_state = copyfile_state_alloc();
13143 ret = fcopyfile(stp->src_fptr->
fd, stp->dst_fptr->
fd, stp->copyfile_state, COPYFILE_DATA);
13144 copyfile_state_get(stp->copyfile_state, COPYFILE_STATE_COPIED, &ss);
13148 if (src_offset > (rb_off_t)0) {
13152 r = lseek(stp->src_fptr->
fd, cur, SEEK_SET);
13153 if (r < (rb_off_t)0 &&
errno) {
13154 stp->error_no =
errno;
13166 stp->syserr =
"fcopyfile";
13167 stp->error_no =
errno;
13174#ifdef HAVE_SENDFILE
13177# define USE_SENDFILE
13179# ifdef HAVE_SYS_SENDFILE_H
13180# include <sys/sendfile.h>
13184simple_sendfile(
int out_fd,
int in_fd, rb_off_t *offset, rb_off_t count)
13186 return sendfile(out_fd, in_fd, offset, (
size_t)count);
13189# elif 0 || defined(__APPLE__)
13193# define USE_SENDFILE
13196simple_sendfile(
int out_fd,
int in_fd, rb_off_t *offset, rb_off_t count)
13199 rb_off_t pos = offset ? *offset : lseek(in_fd, 0, SEEK_CUR);
13202 r = sendfile(in_fd, out_fd, pos, &count, NULL, 0);
13205 r = sendfile(in_fd, out_fd, pos, (
size_t)count, NULL, &sbytes, 0);
13207 if (r != 0 && sbytes == 0)
return r;
13212 lseek(in_fd, sbytes, SEEK_CUR);
13214 return (ssize_t)sbytes;
13227 rb_off_t copy_length;
13228 rb_off_t src_offset;
13231 if (!S_ISREG(stp->src_stat.st_mode))
13234 src_size = stp->src_stat.st_size;
13236 if ((stp->dst_stat.st_mode & S_IFMT) != S_IFSOCK)
13240 src_offset = stp->src_offset;
13241 use_pread = src_offset >= (rb_off_t)0;
13243 copy_length = stp->copy_length;
13244 if (copy_length < (rb_off_t)0) {
13246 copy_length = src_size - src_offset;
13250 cur = lseek(stp->src_fptr->
fd, 0, SEEK_CUR);
13251 if (cur < (rb_off_t)0 &&
errno) {
13252 stp->syserr =
"lseek";
13253 stp->error_no =
errno;
13256 copy_length = src_size - cur;
13261# if SIZEOF_OFF_T > SIZEOF_SIZE_T
13263 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
13265 ss = (ssize_t)copy_length;
13268 ss = simple_sendfile(stp->dst_fptr->
fd, stp->src_fptr->
fd, &src_offset, ss);
13271 ss = simple_sendfile(stp->dst_fptr->
fd, stp->src_fptr->
fd, NULL, ss);
13276 if (0 < copy_length) {
13277 goto retry_sendfile;
13281 if (maygvl_copy_stream_continue_p(0, stp))
13282 goto retry_sendfile;
13295#if EWOULDBLOCK != EAGAIN
13308 ret = maygvl_copy_stream_wait_read(0, stp);
13309 if (ret < 0)
return ret;
13311 ret = nogvl_copy_stream_wait_write(stp);
13312 if (ret < 0)
return ret;
13314 goto retry_sendfile;
13316 stp->syserr =
"sendfile";
13317 stp->error_no =
errno;
13325maygvl_read(
int has_gvl,
rb_io_t *fptr,
void *buf,
size_t count)
13328 return rb_io_read_memory(fptr, buf, count);
13330 return read(fptr->
fd, buf, count);
13334maygvl_copy_stream_read(
int has_gvl,
struct copy_stream_struct *stp,
char *buf,
size_t len, rb_off_t offset)
13338 if (offset < (rb_off_t)0) {
13339 ss = maygvl_read(has_gvl, stp->src_fptr, buf,
len);
13342 ss = pread(stp->src_fptr->
fd, buf,
len, offset);
13348 if (maygvl_copy_stream_continue_p(has_gvl, stp))
13352#if EWOULDBLOCK != EAGAIN
13356 int ret = maygvl_copy_stream_wait_read(has_gvl, stp);
13357 if (ret < 0)
return ret;
13362 stp->notimp =
"pread";
13366 stp->syserr = offset < (rb_off_t)0 ?
"read" :
"pread";
13367 stp->error_no =
errno;
13378 ss = write(stp->dst_fptr->
fd, buf+
off,
len);
13380 if (maygvl_copy_stream_continue_p(0, stp))
13382 if (io_again_p(
errno)) {
13383 int ret = nogvl_copy_stream_wait_write(stp);
13384 if (ret < 0)
return ret;
13387 stp->syserr =
"write";
13388 stp->error_no =
errno;
13405 rb_off_t copy_length;
13406 rb_off_t src_offset;
13410 copy_length = stp->copy_length;
13411 use_eof = copy_length < (rb_off_t)0;
13412 src_offset = stp->src_offset;
13413 use_pread = src_offset >= (rb_off_t)0;
13415 if (use_pread && stp->close_src) {
13418 r = lseek(stp->src_fptr->
fd, src_offset, SEEK_SET);
13419 if (r < (rb_off_t)0 &&
errno) {
13420 stp->syserr =
"lseek";
13421 stp->error_no =
errno;
13424 src_offset = (rb_off_t)-1;
13428 while (use_eof || 0 < copy_length) {
13429 if (!use_eof && copy_length < (rb_off_t)
sizeof(buf)) {
13430 len = (size_t)copy_length;
13436 ss = maygvl_copy_stream_read(0, stp, buf,
len, src_offset);
13441 ss = maygvl_copy_stream_read(0, stp, buf,
len, (rb_off_t)-1);
13446 ret = nogvl_copy_stream_write(stp, buf, ss);
13456nogvl_copy_stream_func(
void *arg)
13459#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13463#ifdef USE_COPY_FILE_RANGE
13464 ret = nogvl_copy_file_range(stp);
13469#ifdef HAVE_FCOPYFILE
13470 ret = nogvl_fcopyfile(stp);
13476 ret = nogvl_copy_stream_sendfile(stp);
13481 nogvl_copy_stream_read_write(stp);
13483#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13490copy_stream_fallback_body(
VALUE arg)
13493 const int buflen = 16*1024;
13496 rb_off_t rest = stp->copy_length;
13497 rb_off_t
off = stp->src_offset;
13498 ID read_method = id_readpartial;
13500 if (!stp->src_fptr) {
13502 read_method = id_read;
13509 rb_str_make_independent(buf);
13510 if (stp->copy_length < (rb_off_t)0) {
13515 rb_str_resize(buf, 0);
13518 l = buflen < rest ? buflen : (long)rest;
13520 if (!stp->src_fptr) {
13523 if (read_method == id_read &&
NIL_P(rc))
13528 rb_str_resize(buf, buflen);
13529 ss = maygvl_copy_stream_read(1, stp, RSTRING_PTR(buf), l,
off);
13530 rb_str_resize(buf, ss > 0 ? ss : 0);
13535 if (
off >= (rb_off_t)0)
13538 n = rb_io_write(stp->dst, buf);
13540 stp->total += numwrote;
13542 if (read_method == id_read && RSTRING_LEN(buf) == 0) {
13553 if (!stp->src_fptr && stp->src_offset >= (rb_off_t)0) {
13554 rb_raise(rb_eArgError,
"cannot specify src_offset for non-IO");
13563copy_stream_body(
VALUE arg)
13566 VALUE src_io = stp->src, dst_io = stp->dst;
13567 const int common_oflags = 0
13577 if (src_io ==
argf ||
13581 stp->src_fptr = NULL;
13586 if (!
NIL_P(tmp_io)) {
13593 args[1] =
INT2NUM(O_RDONLY|common_oflags);
13596 stp->close_src = 1;
13601 stat_ret = fstat(stp->src_fptr->
fd, &stp->src_stat);
13602 if (stat_ret < 0) {
13603 stp->syserr =
"fstat";
13604 stp->error_no =
errno;
13609 if (dst_io ==
argf ||
13613 stp->dst_fptr = NULL;
13618 if (!
NIL_P(tmp_io)) {
13619 dst_io = GetWriteIO(tmp_io);
13625 args[1] =
INT2NUM(O_WRONLY|O_CREAT|O_TRUNC|common_oflags);
13629 stp->close_dst = 1;
13632 dst_io = GetWriteIO(dst_io);
13638 stat_ret = fstat(stp->dst_fptr->
fd, &stp->dst_stat);
13639 if (stat_ret < 0) {
13640 stp->syserr =
"fstat";
13641 stp->error_no =
errno;
13648 SET_BINARY_MODE_WITH_SEEK_CUR(stp->src_fptr);
13651 io_ascii8bit_binmode(stp->dst_fptr);
13653 if (stp->src_offset < (rb_off_t)0 && stp->src_fptr && stp->src_fptr->
rbuf.
len) {
13656 if (stp->copy_length >= (rb_off_t)0 && stp->copy_length < (rb_off_t)
len) {
13657 len = (size_t)stp->copy_length;
13660 rb_str_resize(str,
len);
13661 read_buffered_data(RSTRING_PTR(str),
len, stp->src_fptr);
13662 if (stp->dst_fptr) {
13663 if (io_binwrite(RSTRING_PTR(str), RSTRING_LEN(str), stp->dst_fptr, 0) < 0)
13664 rb_sys_fail_on_write(stp->dst_fptr);
13667 rb_io_write(dst_io, str);
13668 rb_str_resize(str, 0);
13670 if (stp->copy_length >= (rb_off_t)0)
13671 stp->copy_length -=
len;
13674 if (stp->dst_fptr && io_fflush(stp->dst_fptr) < 0) {
13678 if (stp->copy_length == 0)
13681 if (stp->src_fptr == NULL || stp->dst_fptr == NULL) {
13682 return copy_stream_fallback(stp);
13685 IO_WITHOUT_GVL(nogvl_copy_stream_func, stp);
13690copy_stream_finalize(
VALUE arg)
13694#ifdef HAVE_FCOPYFILE
13695 if (stp->copyfile_state) {
13696 copyfile_state_free(stp->copyfile_state);
13700 if (stp->close_src) {
13701 rb_io_close_m(stp->src);
13703 if (stp->close_dst) {
13704 rb_io_close_m(stp->dst);
13767rb_io_s_copy_stream(
int argc,
VALUE *argv,
VALUE io)
13769 VALUE src, dst, length, src_offset;
13774 rb_scan_args(argc, argv,
"22", &src, &dst, &length, &src_offset);
13779 st.src_fptr = NULL;
13780 st.dst_fptr = NULL;
13783 st.copy_length = (rb_off_t)-1;
13785 st.copy_length =
NUM2OFFT(length);
13787 if (
NIL_P(src_offset))
13788 st.src_offset = (rb_off_t)-1;
13790 st.src_offset =
NUM2OFFT(src_offset);
13809rb_io_external_encoding(
VALUE io)
13814 return rb_enc_from_encoding(fptr->
encs.
enc2);
13818 return rb_enc_from_encoding(fptr->
encs.
enc);
13821 return rb_enc_from_encoding(io_read_encoding(fptr));
13837rb_io_internal_encoding(
VALUE io)
13842 return rb_enc_from_encoding(io_read_encoding(fptr));
13876rb_io_set_encoding(
int argc,
VALUE *argv,
VALUE io)
13882 return forward(io, id_set_encoding, argc, argv);
13885 argc =
rb_scan_args(argc, argv,
"11:", &v1, &v2, &opt);
13887 io_encoding_set(fptr, v1, v2, opt);
13892rb_stdio_set_default_encoding(
void)
13897 if (isatty(fileno(stdin))) {
13899 rb_encoding *internal = rb_default_internal_encoding();
13900 if (!internal) internal = rb_default_external_encoding();
13902 rb_enc_from_encoding(external),
13903 rb_enc_from_encoding(internal),
13908 rb_io_set_encoding(1, &val,
rb_stdin);
13909 rb_io_set_encoding(1, &val,
rb_stdout);
13910 rb_io_set_encoding(1, &val,
rb_stderr);
13914global_argf_p(
VALUE arg)
13916 return arg ==
argf;
13919typedef VALUE (*argf_encoding_func)(
VALUE io);
13922argf_encoding(
VALUE argf, argf_encoding_func func)
13924 if (!
RTEST(ARGF.current_file)) {
13925 return rb_enc_default_external();
13949 return argf_encoding(
argf, rb_io_external_encoding);
13968 return argf_encoding(
argf, rb_io_internal_encoding);
14007 if (!next_argv()) {
14008 rb_raise(rb_eArgError,
"no stream to set encoding");
14010 rb_io_set_encoding(argc, argv, ARGF.current_file);
14012 ARGF.encs = fptr->
encs;
14032 if (!next_argv()) {
14033 rb_raise(rb_eArgError,
"no stream to tell");
14035 ARGF_FORWARD(0, 0);
14036 return rb_io_tell(ARGF.current_file);
14049 if (!next_argv()) {
14050 rb_raise(rb_eArgError,
"no stream to seek");
14052 ARGF_FORWARD(argc, argv);
14053 return rb_io_seek_m(argc, argv, ARGF.current_file);
14070 if (!next_argv()) {
14071 rb_raise(rb_eArgError,
"no stream to set position");
14073 ARGF_FORWARD(1, &offset);
14074 return rb_io_set_pos(ARGF.current_file, offset);
14095 if (!next_argv()) {
14096 rb_raise(rb_eArgError,
"no stream to rewind");
14098 ARGF_FORWARD(0, 0);
14099 old_lineno =
RFILE(ARGF.current_file)->fptr->lineno;
14100 ret = rb_io_rewind(ARGF.current_file);
14101 if (!global_argf_p(
argf)) {
14102 ARGF.last_lineno = ARGF.lineno -= old_lineno;
14120 if (!next_argv()) {
14121 rb_raise(rb_eArgError,
"no stream");
14123 ARGF_FORWARD(0, 0);
14124 return rb_io_fileno(ARGF.current_file);
14143 ARGF_FORWARD(0, 0);
14144 return ARGF.current_file;
14169 if (
RTEST(ARGF.current_file)) {
14170 if (ARGF.init_p == 0)
return Qtrue;
14172 ARGF_FORWARD(0, 0);
14231 VALUE tmp, str, length;
14235 if (!
NIL_P(length)) {
14240 rb_str_resize(str,0);
14245 if (!next_argv()) {
14248 if (ARGF_GENERIC_INPUT_P()) {
14249 tmp = argf_forward(argc, argv,
argf);
14252 tmp = io_read(argc, argv, ARGF.current_file);
14254 if (
NIL_P(str)) str = tmp;
14257 if (ARGF.next_p != -1) {
14263 else if (argc >= 1) {
14264 long slen = RSTRING_LEN(str);
14280argf_forward_call(
VALUE arg)
14283 argf_forward(p->argc, p->argv, p->argf);
14313 return argf_getpartial(argc, argv,
argf,
Qnil, 0);
14334 return argf_getpartial(argc, argv,
argf, opts, 1);
14340 VALUE tmp, str, length;
14348 no_exception = no_exception_p(opts);
14350 if (!next_argv()) {
14352 rb_str_resize(str, 0);
14356 if (ARGF_GENERIC_INPUT_P()) {
14366 tmp = io_getpartial(argc, argv, ARGF.current_file, no_exception, nonblock);
14369 if (ARGF.next_p == -1) {
14370 return io_nonblock_eof(no_exception);
14375 return io_nonblock_eof(no_exception);
14413 if (!next_argv())
return Qnil;
14414 if (ARGF_GENERIC_INPUT_P()) {
14415 ch = forward_current(rb_intern(
"getc"), 0, 0);
14418 ch = rb_io_getc(ARGF.current_file);
14420 if (
NIL_P(ch) && ARGF.next_p != -1) {
14453 if (!next_argv())
return Qnil;
14455 ch = forward_current(rb_intern(
"getbyte"), 0, 0);
14460 if (
NIL_P(ch) && ARGF.next_p != -1) {
14493 if (!next_argv()) rb_eof_error();
14495 ch = forward_current(rb_intern(
"getc"), 0, 0);
14498 ch = rb_io_getc(ARGF.current_file);
14500 if (
NIL_P(ch) && ARGF.next_p != -1) {
14532 NEXT_ARGF_FORWARD(0, 0);
14533 c = argf_getbyte(
argf);
14540#define FOREACH_ARGF() while (next_argv())
14545 const VALUE current = ARGF.current_file;
14547 if (ARGF.init_p == -1 || current != ARGF.current_file) {
14553#define ARGF_block_call(mid, argc, argv, func, argf) \
14554 rb_block_call_kw(ARGF.current_file, mid, argc, argv, \
14555 func, argf, rb_keyword_given_p())
14560 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_i,
argf);
14561 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14567 if (!global_argf_p(
argf)) {
14568 ARGF.last_lineno = ++ARGF.lineno;
14570 return argf_block_call_i(i,
argf, argc, argv, blockarg);
14576 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_line_i,
argf);
14577 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14625 argf_block_call_line(rb_intern(
"each_line"), argc, argv,
argf);
14656 argf_block_call(rb_intern(
"each_byte"), 0, 0,
argf);
14682 argf_block_call(rb_intern(
"each_char"), 0, 0,
argf);
14708 argf_block_call(rb_intern(
"each_codepoint"), 0, 0,
argf);
14739 return ARGF.filename;
14743argf_filename_getter(
ID id,
VALUE *var)
14745 return argf_filename(*var);
14770 return ARGF.current_file;
14789 ARGF_FORWARD(0, 0);
14810 return RBOOL(ARGF.binmode);
14830 if (ARGF.init_p && ARGF.next_p == 0) {
14859 if (ARGF.next_p != -1) {
14877 ARGF_FORWARD(0, 0);
14904 if (!ARGF.inplace)
return Qnil;
14912 return argf_inplace_mode_get(*var);
14943 ARGF.inplace =
Qnil;
14954 argf_inplace_mode_set(*var, val);
14958ruby_set_inplace_mode(
const char *suffix)
14984argf_argv_getter(
ID id,
VALUE *var)
14986 return argf_argv(*var);
15005 if (!
RTEST(ARGF.current_file)) {
15008 return GetWriteIO(ARGF.current_file);
15020 return rb_io_writev(argf_write_io(
argf), argc, argv);
15035 case RB_IO_WAIT_WRITABLE:
15038 c = rb_eEAGAINWaitWritable;
15040#if EAGAIN != EWOULDBLOCK
15042 c = rb_eEWOULDBLOCKWaitWritable;
15046 c = rb_eEINPROGRESSWaitWritable;
15052 case RB_IO_WAIT_READABLE:
15055 c = rb_eEAGAINWaitReadable;
15057#if EAGAIN != EWOULDBLOCK
15059 c = rb_eEWOULDBLOCKWaitReadable;
15063 c = rb_eEINPROGRESSWaitReadable;
15070 rb_bug(
"invalid read/write type passed to rb_readwrite_sys_fail: %d", waiting);
15076get_LAST_READ_LINE(
ID _x,
VALUE *_y)
15966#include <sys/cygwin.h>
15967 static struct __cygwin_perfile pf[] =
15969 {
"", O_RDONLY | O_BINARY},
15970 {
"", O_WRONLY | O_BINARY},
15971 {
"", O_RDWR | O_BINARY},
15972 {
"", O_APPEND | O_BINARY},
15975 cygwin_internal(CW_PERFILE, pf);
16024 rb_eEAGAINWaitReadable = rb_define_class_under(
rb_cIO,
"EAGAINWaitReadable", rb_eEAGAIN);
16027 rb_eEAGAINWaitWritable = rb_define_class_under(
rb_cIO,
"EAGAINWaitWritable", rb_eEAGAIN);
16029#if EAGAIN == EWOULDBLOCK
16031 rb_define_const(
rb_cIO,
"EWOULDBLOCKWaitReadable", rb_eEAGAINWaitReadable);
16033 rb_define_const(
rb_cIO,
"EWOULDBLOCKWaitWritable", rb_eEAGAINWaitWritable);
16036 rb_eEWOULDBLOCKWaitReadable = rb_define_class_under(
rb_cIO,
"EWOULDBLOCKWaitReadable", rb_eEWOULDBLOCK);
16039 rb_eEWOULDBLOCKWaitWritable = rb_define_class_under(
rb_cIO,
"EWOULDBLOCKWaitWritable", rb_eEWOULDBLOCK);
16043 rb_eEINPROGRESSWaitReadable = rb_define_class_under(
rb_cIO,
"EINPROGRESSWaitReadable", rb_eEINPROGRESS);
16046 rb_eEINPROGRESSWaitWritable = rb_define_class_under(
rb_cIO,
"EINPROGRESSWaitWritable", rb_eEINPROGRESS);
16081 rb_gvar_ractor_local(
"$/");
16083 rb_gvar_ractor_local(
"$-0");
16087 rb_gvar_ractor_local(
"$_");
16088 rb_gvar_box_dynamic(
"$_");
16204 rb_gvar_ractor_local(
"$stdin");
16205 rb_gvar_ractor_local(
"$stdout");
16206 rb_gvar_ractor_local(
"$>");
16207 rb_gvar_ractor_local(
"$stderr");
16209 rb_gvar_box_dynamic(
"$stdin");
16210 rb_gvar_box_dynamic(
"$stdout");
16211 rb_gvar_box_dynamic(
"$>");
16212 rb_gvar_box_dynamic(
"$stderr");
16233 rb_cARGF = rb_define_class(
"ARGF",
rb_cObject);
16298 rb_define_method(rb_cARGF,
"external_encoding", argf_external_encoding, 0);
16299 rb_define_method(rb_cARGF,
"internal_encoding", argf_internal_encoding, 0);
16318 rb_gvar_ractor_local(
"$-i");
16322#if defined (_WIN32) || defined(__CYGWIN__)
16323 atexit(pipe_atexit);
16335 sym_encoding =
ID2SYM(rb_id_encoding());
16359static void init_builtin_io(
void);
16360#define Init_builtin_io init_builtin_io
16362#undef Init_builtin_io
16365Init_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_equal(VALUE str1, VALUE str2)
Equality of two strings.
void rb_str_set_len(VALUE str, long len)
Overwrites the length of the string.
VALUE rb_str_buf_cat_ascii(VALUE dst, const char *src)
Identical to rb_str_cat_cstr(), except it additionally assumes the source string be a NUL terminated ...
VALUE rb_check_string_type(VALUE obj)
Try converting an object to its stringised representation using its to_str method,...
VALUE rb_str_substr(VALUE str, long beg, long len)
This is the implementation of two-argumented String#slice.
VALUE rb_str_unlocktmp(VALUE str)
Releases a lock formerly obtained by rb_str_locktmp().
void rb_str_modify_expand(VALUE str, long capa)
Identical to rb_str_modify(), except it additionally expands the capacity of the receiver.
VALUE rb_str_buf_new(long capa)
Allocates a "string buffer".
#define rb_str_new_cstr(str)
Identical to rb_str_new, except it assumes the passed pointer is a pointer to a C string.
VALUE rb_obj_as_string(VALUE obj)
Try converting an object to its stringised representation using its to_s method, if any.
int rb_thread_interrupted(VALUE thval)
Checks if the thread's execution was recently interrupted.
VALUE rb_mutex_new(void)
Creates a mutex.
int rb_thread_fd_writable(int fd)
Identical to rb_thread_wait_fd(), except it blocks the current thread until the given file descriptor...
VALUE rb_exec_recursive(VALUE(*f)(VALUE g, VALUE h, int r), VALUE g, VALUE h)
"Recursion" API entry point.
VALUE rb_mutex_synchronize(VALUE mutex, VALUE(*func)(VALUE arg), VALUE arg)
Obtains the lock, runs the passed function, and releases the lock when it completes.
void rb_thread_check_ints(void)
Checks for interrupts.
VALUE rb_thread_current(void)
Obtains the "current" thread.
int rb_thread_wait_fd(int fd)
Blocks the current thread until the given file descriptor is ready to be read.
void rb_thread_sleep(int sec)
Blocks for the given period of time.
struct timeval rb_time_interval(VALUE num)
Creates a "time interval".
void rb_set_class_path(VALUE klass, VALUE space, const char *name)
Names a class.
VALUE rb_ivar_set(VALUE obj, ID name, VALUE val)
Identical to rb_iv_set(), except it accepts the name as an ID instead of a C string.
VALUE rb_class_name(VALUE obj)
Queries the name of the given object's class.
int rb_respond_to(VALUE obj, ID mid)
Queries if the object responds to the method.
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.