14#include "ruby/internal/config.h"
25# if defined(__linux__)
28# if defined(__FreeBSD_version) && __FreeBSD_version >= 1100000
38#define free(x) xfree(x)
40#if defined(DOSISH) || defined(__CYGWIN__)
45#if defined HAVE_NET_SOCKET_H
46# include <net/socket.h>
47#elif defined HAVE_SYS_SOCKET_H
48# include <sys/socket.h>
51#if defined(__BOW__) || defined(__CYGWIN__) || defined(_WIN32)
52# define NO_SAFE_RENAME
55#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__sun) || defined(_nec_ews)
64#if defined(HAVE_SYS_IOCTL_H) && !defined(_WIN32)
67#if defined(HAVE_FCNTL_H) || defined(_WIN32)
69#elif defined(HAVE_SYS_FCNTL_H)
79#if defined(HAVE_SYS_PARAM_H) || defined(__HIUX_MPP__)
80# include <sys/param.h>
93#elif defined HAVE_SYS_SYSCALL_H
94#include <sys/syscall.h>
101#ifdef HAVE_SYS_WAIT_H
102# include <sys/wait.h>
105#ifdef HAVE_COPYFILE_H
106# include <copyfile.h>
108# ifndef COPYFILE_STATE_COPIED
114# undef HAVE_FCOPYFILE
120# include <AvailabilityMacros.h>
124#include "ccan/list/list.h"
129#include "internal/class.h"
130#include "internal/encoding.h"
131#include "internal/error.h"
132#include "internal/inits.h"
133#include "internal/io.h"
134#include "internal/numeric.h"
135#include "internal/object.h"
136#include "internal/process.h"
137#include "internal/thread.h"
138#include "internal/transcode.h"
139#include "internal/variable.h"
142#include "ruby/missing.h"
145#include "ruby_atomic.h"
155#define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR)
159# ifdef _POSIX_PIPE_BUF
160# define PIPE_BUF _POSIX_PIPE_BUF
167# define EWOULDBLOCK EAGAIN
170#if defined(HAVE___SYSCALL) && (defined(__APPLE__) || defined(__OpenBSD__))
172off_t __syscall(quad_t number, ...);
175#define IO_RBUF_CAPA_MIN 8192
176#define IO_CBUF_CAPA_MIN (128*1024)
177#define IO_RBUF_CAPA_FOR(fptr) (NEED_READCONV(fptr) ? IO_CBUF_CAPA_MIN : IO_RBUF_CAPA_MIN)
178#define IO_WBUF_CAPA_MIN 8192
180#define IO_MAX_BUFFER_GROWTH 8 * 1024 * 1024
185#define open rb_w32_uopen
187#define rename(f, t) rb_w32_urename((f), (t))
188#include "win32/file.h"
198static VALUE rb_eEAGAINWaitReadable;
199static VALUE rb_eEAGAINWaitWritable;
200#if EAGAIN != EWOULDBLOCK
201static VALUE rb_eEWOULDBLOCKWaitReadable;
202static VALUE rb_eEWOULDBLOCKWaitWritable;
204static VALUE rb_eEINPROGRESSWaitWritable;
205static VALUE rb_eEINPROGRESSWaitReadable;
208static VALUE orig_stdout, orig_stderr;
217static ID id_write, id_read, id_flush, id_readpartial, id_set_encoding, id_fileno;
218static VALUE sym_mode, sym_perm, sym_flags, sym_extenc, sym_intenc, sym_encoding, sym_open_args;
219static VALUE sym_textmode, sym_binmode, sym_autoclose;
220static VALUE sym_SET, sym_CUR, sym_END;
221static VALUE sym_wait_readable, sym_wait_writable;
223static VALUE sym_DATA;
226static VALUE sym_HOLE;
229static VALUE prep_io(
int fd,
enum rb_io_mode fmode,
VALUE klass,
const char *path);
232rb_io_blocking_region_wait(
struct rb_io *io, rb_blocking_function_t *function,
void *argument,
enum rb_io_event events)
234 return rb_thread_io_blocking_call(io, function, argument, events);
237VALUE rb_io_blocking_region(
struct rb_io *io, rb_blocking_function_t *function,
void *argument)
239 return rb_io_blocking_region_wait(io, function, argument, 0);
243 VALUE filename, current_file;
249 int8_t init_p, next_p, binmode;
253#if defined(__APPLE__) && \
254 (!defined(MAC_OS_VERSION_27_0) || (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_VERSION_27_0))
256# if __has_attribute(availability) && __has_warning("-Wunguarded-availability-new")
262static inline int (*rb_dup3(
void))(int, int, int) {
return &dup3;}
263# define dup3 rb_dup3()
267static inline int (*rb_pipe2(
void))(
int [2], int) {
return &pipe2;}
268# define pipe2 rb_pipe2()
293 if (fd < 0 || afd <= max_fd)
296#if defined(HAVE_FCNTL) && defined(F_GETFL)
297 err = fcntl(fd, F_GETFL) == -1;
301 err = fstat(fd, &buf) != 0;
304 if (err &&
errno == EBADF) {
305 rb_bug(
"rb_update_max_fd: invalid fd (%d) given.", fd);
308 while (max_fd < afd) {
309 max_fd = ATOMIC_CAS(max_file_descriptor, max_fd, afd);
314rb_maygvl_fd_fix_cloexec(
int fd)
317#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
318 int flags, flags2, ret;
319 flags = fcntl(fd, F_GETFD);
321 rb_bug(
"rb_maygvl_fd_fix_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(
errno));
324 flags2 = flags & ~FD_CLOEXEC;
326 flags2 = flags | FD_CLOEXEC;
327 if (flags != flags2) {
328 ret = fcntl(fd, F_SETFD, flags2);
330 rb_bug(
"rb_maygvl_fd_fix_cloexec: fcntl(%d, F_SETFD, %d) failed: %s", fd, flags2, strerror(
errno));
339 rb_maygvl_fd_fix_cloexec(fd);
345rb_fix_detect_o_cloexec(
int fd)
347#if defined(O_CLOEXEC) && defined(F_GETFD)
348 int flags = fcntl(fd, F_GETFD);
351 rb_bug(
"rb_fix_detect_o_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(
errno));
353 if (flags & FD_CLOEXEC)
356 rb_maygvl_fd_fix_cloexec(fd);
363 return (e == EWOULDBLOCK) || (e == EAGAIN);
370 static int o_cloexec_state = -1;
372 static const int retry_interval = 0;
373 static const int retry_max_count = 10000;
380#elif defined O_NOINHERIT
381 flags |= O_NOINHERIT;
384 while ((ret = open(pathname, flags, mode)) == -1) {
386 if (!io_again_p(e))
break;
387 if (retry_count++ >= retry_max_count)
break;
389 sleep(retry_interval);
392 if (ret < 0)
return ret;
393 if (ret <= 2 || o_cloexec_state == 0) {
394 rb_maygvl_fd_fix_cloexec(ret);
396 else if (o_cloexec_state > 0) {
400 o_cloexec_state = rb_fix_detect_o_cloexec(ret);
419 if (oldfd == newfd) {
423#if defined(HAVE_DUP3) && defined(O_CLOEXEC)
424# if defined(__APPLE__)
425# define try_dup3 (dup3 != NULL)
426# define abandon_dup3() true
428 static bool try_dup3 =
true;
429# define abandon_dup3() (errno != ENOSYS || !!(try_dup3 = false))
435 ret = dup3(oldfd, newfd, O_CLOEXEC);
442 if (abandon_dup3())
return ret;
445 ret = dup2(oldfd, newfd);
446 if (ret < 0)
return ret;
448 rb_maygvl_fd_fix_cloexec(ret);
453rb_fd_set_nonblock(
int fd)
456 return rb_w32_set_nonblock(fd);
457#elif defined(F_GETFL)
458 int oflags = fcntl(fd, F_GETFL);
462 if (oflags & O_NONBLOCK)
464 oflags |= O_NONBLOCK;
465 return fcntl(fd, F_SETFL, oflags);
471cloexec_pipe(
int descriptors[2],
int flags,
bool force_cloexec)
475# if defined(__APPLE__)
476# define try_pipe2 (pipe2 != NULL)
477# define abandon_pipe2() true
479 static bool try_pipe2 =
true;
480# define abandon_pipe2() (errno != ENOSYS || !!(try_pipe2 = false))
483 result = pipe2(descriptors, O_CLOEXEC | flags);
484 if (result == 0)
return result;
485 if (abandon_pipe2())
return result;
488 if (result < 0 && (result = pipe(descriptors)) < 0)
492 if (result == 0 && descriptors[1] == -1) {
493 close(descriptors[0]);
500 if (!force_cloexec)
return result;
503 rb_maygvl_fd_fix_cloexec(descriptors[0]);
504 rb_maygvl_fd_fix_cloexec(descriptors[1]);
507 rb_fd_set_nonblock(descriptors[0]);
508 rb_fd_set_nonblock(descriptors[1]);
517 return cloexec_pipe(descriptors, O_NONBLOCK,
true);
525#if defined(HAVE_FCNTL) && defined(F_DUPFD_CLOEXEC) && defined(F_DUPFD)
526 static int try_dupfd_cloexec = 1;
527 if (try_dupfd_cloexec) {
528 ret = fcntl(fd, F_DUPFD_CLOEXEC, minfd);
531 rb_maygvl_fd_fix_cloexec(ret);
535 if (
errno == EINVAL) {
536 ret = fcntl(fd, F_DUPFD, minfd);
538 try_dupfd_cloexec = 0;
543 ret = fcntl(fd, F_DUPFD, minfd);
545#elif defined(HAVE_FCNTL) && defined(F_DUPFD)
546 ret = fcntl(fd, F_DUPFD, minfd);
549 if (ret >= 0 && ret < minfd) {
550 const int prev_fd = ret;
556 if (ret < 0)
return ret;
557 rb_maygvl_fd_fix_cloexec(ret);
561#define argf_of(obj) (*(struct argf *)DATA_PTR(obj))
562#define ARGF argf_of(argf)
563#define ARGF_SET(field, value) RB_OBJ_WRITE(argf, &ARGF.field, value)
565#define GetWriteIO(io) rb_io_get_write_io(io)
567#define READ_DATA_PENDING(fptr) ((fptr)->rbuf.len)
568#define READ_DATA_PENDING_COUNT(fptr) ((fptr)->rbuf.len)
569#define READ_DATA_PENDING_PTR(fptr) ((fptr)->rbuf.ptr+(fptr)->rbuf.off)
570#define READ_DATA_BUFFERED(fptr) READ_DATA_PENDING(fptr)
572#define READ_CHAR_PENDING(fptr) ((fptr)->cbuf.len)
573#define READ_CHAR_PENDING_COUNT(fptr) ((fptr)->cbuf.len)
574#define READ_CHAR_PENDING_PTR(fptr) ((fptr)->cbuf.ptr+(fptr)->cbuf.off)
577#define WAIT_FD_IN_WIN32(fptr) \
578 (rb_w32_io_cancelable_p((fptr)->fd) ? Qnil : rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_READABLE), RUBY_IO_TIMEOUT_DEFAULT))
580#define WAIT_FD_IN_WIN32(fptr)
583#define READ_CHECK(fptr) do {\
584 if (!READ_DATA_PENDING(fptr)) {\
585 WAIT_FD_IN_WIN32(fptr);\
586 rb_io_check_closed(fptr);\
592# define S_ISSOCK(m) _S_ISSOCK(m)
595# define S_ISSOCK(m) (((m) & S_IFMT) == _S_IFSOCK)
598# define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
604static int io_fflush(
rb_io_t *);
605static rb_io_t *flush_before_seek(
rb_io_t *fptr,
bool discard_rbuf);
606static void clear_readconv(
rb_io_t *fptr);
607static void clear_codeconv(
rb_io_t *fptr);
609#define FMODE_SIGNAL_ON_EPIPE (1<<17)
611#define fptr_signal_on_epipe(fptr) \
612 (((fptr)->mode & FMODE_SIGNAL_ON_EPIPE) != 0)
614#define fptr_set_signal_on_epipe(fptr, flag) \
616 (fptr)->mode |= FMODE_SIGNAL_ON_EPIPE : \
617 (fptr)->mode &= ~FMODE_SIGNAL_ON_EPIPE)
619extern ID ruby_static_id_signo;
621NORETURN(
static void rb_sys_fail_on_write(
rb_io_t *fptr));
623rb_sys_fail_on_write(
rb_io_t *fptr)
626 VALUE errinfo = rb_syserr_new_path(e, (fptr)->pathv);
628 if (fptr_signal_on_epipe(fptr) && (e == EPIPE)) {
640#define NEED_NEWLINE_DECORATOR_ON_READ(fptr) ((fptr)->mode & FMODE_TEXTMODE)
641#define NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) ((fptr)->mode & FMODE_TEXTMODE)
642#if defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32)
643# define RUBY_CRLF_ENVIRONMENT 1
645# define RUBY_CRLF_ENVIRONMENT 0
648#if RUBY_CRLF_ENVIRONMENT
650# define DEFAULT_TEXTMODE FMODE_TEXTMODE
651# define TEXTMODE_NEWLINE_DECORATOR_ON_WRITE ECONV_CRLF_NEWLINE_DECORATOR
659#define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || (fptr)->encs.ecflags & ~ECONV_CRLF_NEWLINE_DECORATOR)
660#define WRITECONV_MASK ( \
661 (ECONV_DECORATOR_MASK & ~ECONV_CRLF_NEWLINE_DECORATOR)|\
662 ECONV_STATEFUL_DECORATOR_MASK|\
664#define NEED_WRITECONV(fptr) ( \
665 ((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || \
666 ((fptr)->encs.ecflags & WRITECONV_MASK) || \
668#define SET_BINARY_MODE(fptr) setmode((fptr)->fd, O_BINARY)
670#define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) do {\
671 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {\
672 if (((fptr)->mode & FMODE_READABLE) &&\
673 !((fptr)->encs.ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {\
674 setmode((fptr)->fd, O_BINARY);\
677 setmode((fptr)->fd, O_TEXT);\
682#define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) do {\
683 if ((enc2) && ((ecflags) & ECONV_DEFAULT_NEWLINE_DECORATOR)) {\
684 (ecflags) |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;\
692io_unread(
rb_io_t *fptr,
bool discard_rbuf)
708 if (!rb_w32_fd_is_text(fptr->
fd)) {
709 r = lseek(fptr->
fd, -fptr->
rbuf.
len, SEEK_CUR);
710 if (r < 0 &&
errno) {
713 if (!discard_rbuf)
return;
719 pos = lseek(fptr->
fd, 0, SEEK_CUR);
720 if (pos < 0 &&
errno) {
723 if (!discard_rbuf)
goto end;
727 extra_max = (long)(pos - fptr->
rbuf.
len);
735 for (i = 0; i < fptr->
rbuf.
len; i++) {
736 if (*p ==
'\n') newlines++;
737 if (extra_max == newlines)
break;
742 while (newlines >= 0) {
743 r = lseek(fptr->
fd, pos - fptr->
rbuf.
len - newlines, SEEK_SET);
744 if (newlines == 0)
break;
749 read_size = _read(fptr->
fd, buf, fptr->
rbuf.
len + newlines);
753 rb_syserr_fail_path(e, fptr->
pathv);
755 if (read_size == fptr->
rbuf.
len) {
756 lseek(fptr->
fd, r, SEEK_SET);
767 clear_codeconv(fptr);
779set_binary_mode_with_seek_cur(
rb_io_t *fptr)
781 if (!rb_w32_fd_is_text(fptr->
fd))
return O_BINARY;
784 return setmode(fptr->
fd, O_BINARY);
786 flush_before_seek(fptr,
false);
787 return setmode(fptr->
fd, O_BINARY);
789#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) set_binary_mode_with_seek_cur(fptr)
793# define DEFAULT_TEXTMODE 0
794#define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || NEED_NEWLINE_DECORATOR_ON_READ(fptr))
795#define NEED_WRITECONV(fptr) ( \
796 ((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || \
797 NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) || \
798 ((fptr)->encs.ecflags & (ECONV_DECORATOR_MASK|ECONV_STATEFUL_DECORATOR_MASK)) || \
800#define SET_BINARY_MODE(fptr) (void)(fptr)
801#define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) (void)(fptr)
802#define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) ((void)(enc2), (void)(ecflags))
803#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) (void)(fptr)
806#if !defined HAVE_SHUTDOWN && !defined shutdown
807#define shutdown(a,b) 0
811#define is_socket(fd, path) rb_w32_is_socket(fd)
812#elif !defined(S_ISSOCK)
813#define is_socket(fd, path) 0
816is_socket(
int fd,
VALUE path)
819 if (fstat(fd, &sbuf) < 0)
820 rb_sys_fail_path(path);
821 return S_ISSOCK(sbuf.st_mode);
825static const char closed_stream[] =
"closed stream";
828io_fd_check_closed(
int fd)
861 io_fd_check_closed(fptr->
fd);
865rb_io_get_fptr(
VALUE io)
875 return rb_convert_type_with_id(io,
T_FILE,
"IO", idTo_io);
881 return rb_check_convert_type_with_id(io,
T_FILE,
"IO", idTo_io);
899 rb_io_t *fptr = rb_io_get_fptr(io);
908 return write_io ? write_io :
Qnil;
921 rb_io_t *fptr = rb_io_get_fptr(self);
951 if (
RTEST(timeout)) {
955 rb_io_t *fptr = rb_io_get_fptr(self);
980#if !RUBY_CRLF_ENVIRONMENT
982io_unread(
rb_io_t *fptr,
bool discard_rbuf)
990 r = lseek(fptr->
fd, -fptr->
rbuf.
len, SEEK_CUR);
991 if (r < 0 &&
errno) {
994 if (!discard_rbuf)
return;
998 clear_codeconv(fptr);
1008 long len = RSTRING_LEN(str);
1011 const int min_capa = IO_RBUF_CAPA_FOR(fptr);
1014#if SIZEOF_LONG > SIZEOF_INT
1039flush_before_seek(
rb_io_t *fptr,
bool discard_rbuf)
1041 if (io_fflush(fptr) < 0)
1042 rb_sys_fail_on_write(fptr);
1043 io_unread(fptr, discard_rbuf);
1048#define io_seek(fptr, ofs, whence) (errno = 0, lseek(flush_before_seek(fptr, true)->fd, (ofs), (whence)))
1049#define io_tell(fptr) lseek(flush_before_seek(fptr, false)->fd, 0, SEEK_CUR)
1065 if (io_fflush(fptr) < 0)
1066 rb_sys_fail_on_write(fptr);
1071 if (io_fflush(wfptr) < 0)
1072 rb_sys_fail_on_write(wfptr);
1080 if (READ_CHAR_PENDING(fptr)) {
1081 rb_raise(
rb_eIOError,
"byte oriented read for character buffered IO");
1092io_read_encoding(
rb_io_t *fptr)
1097 return rb_default_external_encoding();
1101io_input_encoding(
rb_io_t *fptr)
1106 return io_read_encoding(fptr);
1117 io_unread(fptr,
true);
1122rb_io_read_pending(
rb_io_t *fptr)
1125 if (READ_CHAR_PENDING(fptr))
1127 return READ_DATA_PENDING(fptr);
1133 if (!READ_DATA_PENDING(fptr)) {
1140rb_gc_for_fd(
int err)
1142 if (err == EMFILE || err == ENFILE || err == ENOMEM) {
1152#define TRY_WITH_GC(expr) \
1153 for (int first_errno, retried_errno = 0, retried = 0; \
1156 (!rb_gc_for_fd(first_errno = errno) || !(expr)) && \
1157 (retried_errno = errno, 1)); \
1158 (void)retried_errno, retried = 1)
1173io_alloc(
VALUE klass)
1175 UNPROTECTED_NEWOBJ_OF(io,
struct RFile, klass,
T_FILE,
sizeof(
struct RFile));
1183# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
1209struct io_internal_writev_struct {
1216 const struct iovec *iov;
1229io_internal_wait(
VALUE thread,
rb_io_t *fptr,
int error,
int events,
struct timeval *timeout)
1231 if (!timeout && rb_thread_mn_schedulable(thread)) {
1236 int ready = nogvl_wait_for(thread, fptr, events, timeout);
1241 else if (ready == 0) {
1258internal_read_func(
void *ptr)
1263 if (iis->timeout && !iis->nonblock) {
1264 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_IN, iis->timeout) == -1) {
1270 result = read(iis->fd, iis->buf, iis->capa);
1272 if (result < 0 && !iis->nonblock) {
1273 if (io_again_p(
errno)) {
1274 if (io_internal_wait(iis->th, iis->fptr,
errno, RB_WAITFD_IN, iis->timeout) == -1) {
1286#if defined __APPLE__
1287# define do_write_retry(code) do {result = code;} while (result == -1 && errno == EPROTOTYPE)
1289# define do_write_retry(code) result = code
1293internal_write_func(
void *ptr)
1298 if (iis->timeout && !iis->nonblock) {
1299 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1305 do_write_retry(write(iis->fd, iis->buf, iis->capa));
1307 if (result < 0 && !iis->nonblock) {
1309 if (io_again_p(e)) {
1310 if (io_internal_wait(iis->th, iis->fptr,
errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1324internal_writev_func(
void *ptr)
1326 struct io_internal_writev_struct *iis = ptr;
1329 if (iis->timeout && !iis->nonblock) {
1330 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1336 do_write_retry(writev(iis->fd, iis->iov, iis->iovcnt));
1338 if (result < 0 && !iis->nonblock) {
1339 if (io_again_p(
errno)) {
1340 if (io_internal_wait(iis->th, iis->fptr,
errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1354rb_io_read_memory(
rb_io_t *fptr,
void *buf,
size_t count)
1358 if (scheduler !=
Qnil) {
1361 if (!UNDEF_P(result)) {
1377 struct timeval timeout_storage;
1381 iis.timeout = &timeout_storage;
1384 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_read_func, &iis,
RUBY_IO_READABLE);
1388rb_io_write_memory(
rb_io_t *fptr,
const void *buf,
size_t count)
1392 if (scheduler !=
Qnil) {
1395 if (!UNDEF_P(result)) {
1411 struct timeval timeout_storage;
1415 iis.timeout = &timeout_storage;
1418 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_write_func, &iis,
RUBY_IO_WRITABLE);
1423rb_writev_internal(
rb_io_t *fptr,
const struct iovec *iov,
int iovcnt)
1425 if (!iovcnt)
return 0;
1430 if (scheduler !=
Qnil) {
1434 if (!UNDEF_P(result)) {
1439 struct io_internal_writev_struct iis = {
1450 struct timeval timeout_storage;
1454 iis.timeout = &timeout_storage;
1457 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_writev_func, &iis,
RUBY_IO_WRITABLE);
1462io_flush_buffer_sync(
void *arg)
1484io_flush_buffer_fiber_scheduler(
VALUE scheduler,
rb_io_t *fptr)
1487 if (!UNDEF_P(ret)) {
1499io_flush_buffer_async(
VALUE arg)
1504 if (scheduler !=
Qnil) {
1505 VALUE result = io_flush_buffer_fiber_scheduler(scheduler, fptr);
1506 if (!UNDEF_P(result)) {
1511 return rb_io_blocking_region_wait(fptr, io_flush_buffer_sync, fptr,
RUBY_IO_WRITABLE);
1518 return (
int)io_flush_buffer_async((
VALUE)fptr);
1533 while (fptr->
wbuf.
len > 0 && io_flush_buffer(fptr) != 0) {
1549 if (scheduler !=
Qnil) {
1559 if (NIL_OR_UNDEF_P(timeout)) {
1563 if (timeout !=
Qnil) {
1568 int ready = rb_thread_io_wait(th, fptr,
RB_NUM2INT(events), tv);
1594 if (scheduler !=
Qnil) {
1600 return rb_thread_wait_for_single_fd(th, fd, events, timeout);
1606 io_fd_check_closed(f);
1613#if defined(ERESTART)
1620#if EWOULDBLOCK != EAGAIN
1623 if (scheduler !=
Qnil) {
1641 io_fd_check_closed(f);
1648#if defined(ERESTART)
1664#if EWOULDBLOCK != EAGAIN
1667 if (scheduler !=
Qnil) {
1687 return io_wait_for_single_fd(fd, events, timeout, th, scheduler);
1721#if defined(ERESTART)
1731#if EWOULDBLOCK != EAGAIN
1748 if (
RTEST(result)) {
1763 if (
RTEST(result)) {
1777 const char *senc, *denc;
1784 ecflags = fptr->
encs.
ecflags & ~ECONV_NEWLINE_DECORATOR_READ_MASK;
1811 denc = rb_enc_name(enc);
1843io_binwrite_string_internal(
rb_io_t *fptr,
const char *ptr,
long length)
1846 struct iovec iov[2];
1849 iov[0].iov_len = fptr->
wbuf.
len;
1850 iov[1].iov_base = (
void*)ptr;
1851 iov[1].iov_len = length;
1853 ssize_t result = rb_writev_internal(fptr, iov, 2);
1858 if (result >= fptr->
wbuf.
len) {
1866 fptr->
wbuf.
off += (int)result;
1867 fptr->
wbuf.
len -= (int)result;
1875 return rb_io_write_memory(fptr, ptr, length);
1880io_binwrite_string_internal(
rb_io_t *fptr,
const char *ptr,
long length)
1882 long remaining = length;
1885 if (fptr->
wbuf.
len+length <= fptr->wbuf.capa) {
1892 fptr->
wbuf.
len += (int)length;
1899 if (io_fflush(fptr) < 0) {
1904 if (remaining == 0) {
1910 return rb_io_write_memory(fptr, ptr, length);
1915io_binwrite_string(
VALUE arg)
1919 const char *ptr = p->ptr;
1920 size_t remaining = p->length;
1924 ssize_t result = io_binwrite_string_internal(p->fptr, ptr, remaining);
1930 else if (result > 0) {
1931 if ((
size_t)result == remaining)
break;
1933 remaining -= result;
1949io_allocate_write_buffer(
rb_io_t *fptr,
int sync)
1954 fptr->
wbuf.
capa = IO_WBUF_CAPA_MIN;
1965io_binwrite_requires_flush_write(
rb_io_t *fptr,
long len,
int nosync)
1980io_binwrite(
const char *ptr,
long len,
rb_io_t *fptr,
int nosync)
1982 if (
len <= 0)
return len;
1987 io_allocate_write_buffer(fptr, !nosync);
1989 if (io_binwrite_requires_flush_write(fptr,
len, nosync)) {
2000 return io_binwrite_string((
VALUE)&arg);
2017# define MODE_BTMODE(a,b,c) ((fmode & FMODE_BINMODE) ? (b) : \
2018 (fmode & FMODE_TEXTMODE) ? (c) : (a))
2020#define MODE_BTXMODE(a, b, c, d, e, f) ((fmode & FMODE_EXCL) ? \
2021 MODE_BTMODE(d, e, f) : \
2022 MODE_BTMODE(a, b, c))
2027 if (NEED_WRITECONV(fptr)) {
2029 SET_BINARY_MODE(fptr);
2031 make_writeconv(fptr);
2034#define fmode (fptr->mode)
2037 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1) && !rb_enc_asciicompat(rb_enc_get(str))) {
2038 rb_raise(rb_eArgError,
"ASCII incompatible string written for text mode IO without encoding conversion: %s",
2039 rb_enc_name(rb_enc_get(str)));
2045 common_encoding = rb_enc_from_encoding(fptr->
encs.
enc2);
2046 else if (fptr->
encs.
enc != rb_ascii8bit_encoding())
2047 common_encoding = rb_enc_from_encoding(fptr->
encs.
enc);
2050 if (!
NIL_P(common_encoding)) {
2061#if RUBY_CRLF_ENVIRONMENT
2062#define fmode (fptr->mode)
2063 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1)) {
2066 setmode(fptr->
fd, O_BINARY);
2069 setmode(fptr->
fd, O_TEXT);
2071 if (!rb_enc_asciicompat(rb_enc_get(str))) {
2072 rb_raise(rb_eArgError,
"ASCII incompatible string written for text mode IO without encoding conversion: %s",
2073 rb_enc_name(rb_enc_get(str)));
2091 long len = rb_w32_write_console(str, fptr->
fd);
2096 str = do_writeconv(str, fptr, &converted);
2100 tmp = rb_str_tmp_frozen_no_embed_acquire(str);
2102 n = io_binwrite(ptr,
len, fptr, nosync);
2103 rb_str_tmp_frozen_release(str, tmp);
2115 return (ssize_t)io_binwrite(buf, (
long)size, fptr, 0);
2125 io = GetWriteIO(io);
2135 if (RSTRING_LEN(str) == 0)
return INT2FIX(0);
2140 n = io_fwrite(str, fptr, nosync);
2141 if (n < 0L) rb_sys_fail_on_write(fptr);
2147struct binwritev_arg {
2155io_binwritev_internal(
VALUE arg)
2157 struct binwritev_arg *p = (
struct binwritev_arg *)arg;
2159 size_t remaining = p->total;
2163 struct iovec *iov = p->iov;
2164 int iovcnt = p->iovcnt;
2167 long result = rb_writev_internal(fptr, iov, iovcnt);
2172 if (offset < (
size_t)fptr->
wbuf.
len) {
2177 offset -= (size_t)fptr->
wbuf.
len;
2183 if (offset == p->total) {
2187 while (result >= (ssize_t)iov->iov_len) {
2189 result -= iov->iov_len;
2199 iov->iov_base = (
char *)iov->iov_base + result;
2200 iov->iov_len -= result;
2214io_binwritev(
struct iovec *iov,
int iovcnt,
rb_io_t *fptr)
2219 if (iovcnt == 0)
return 0;
2222 for (
int i = 1; i < iovcnt; i++) total += iov[i].iov_len;
2224 io_allocate_write_buffer(fptr, 1);
2230 if (offset + total <= (
size_t)fptr->
wbuf.
capa) {
2231 for (
int i = 1; i < iovcnt; i++) {
2232 memcpy(fptr->
wbuf.
ptr+offset, iov[i].iov_base, iov[i].iov_len);
2233 offset += iov[i].iov_len;
2244 if (io_fflush(fptr) < 0)
return -1;
2250 iov[0].iov_len = fptr->
wbuf.
len;
2263 struct binwritev_arg arg;
2266 arg.iovcnt = iovcnt;
2273 return io_binwritev_internal((
VALUE)&arg);
2280 int i, converted, iovcnt = argc + 1;
2282 VALUE v1, v2, str, tmp, *tmp_array;
2288 for (i = 0; i < argc; i++) {
2291 str = do_writeconv(str, fptr, &converted);
2296 tmp = rb_str_tmp_frozen_acquire(str);
2300 iov[i+1].iov_base = RSTRING_PTR(tmp);
2301 iov[i+1].iov_len = RSTRING_LEN(tmp);
2304 n = io_binwritev(iov, iovcnt, fptr);
2307 for (i = 0; i < argc; i++) {
2308 rb_str_tmp_frozen_release(argv[i], tmp_array[i]);
2317iovcnt_ok(
int iovcnt)
2320 return iovcnt < IOV_MAX;
2328io_writev(
int argc,
const VALUE *argv,
VALUE io)
2335 io = GetWriteIO(io);
2348 for (i = 0; i < argc; i += cnt) {
2351 n = io_fwritev(cnt, &argv[i], fptr);
2362 rb_sys_fail_on_write(fptr);
2364 total = rb_fix_plus(
LONG2FIX(n), total);
2395 return io_writev(argc, argv, io);
2398 VALUE str = argv[0];
2399 return io_write(io, str, 0);
2410rb_io_writev(
VALUE io,
int argc,
const VALUE *argv)
2415 char sep = RCLASS_SINGLETON_P(klass) ? (klass = io,
'.') :
'#';
2418 " which accepts just one argument",
2423 do rb_io_write(io, *argv++);
while (--argc);
2454 rb_io_write(io, str);
2460nogvl_fsync(
void *ptr)
2465 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->
fd)) != FILE_TYPE_DISK)
2468 return (
VALUE)fsync(fptr->
fd);
2473rb_io_flush_raw(
VALUE io,
int sync)
2481 io = GetWriteIO(io);
2485 if (io_fflush(fptr) < 0)
2486 rb_sys_fail_on_write(fptr);
2489 io_unread(fptr,
true);
2510 return rb_io_flush_raw(io, 1);
2536 pos = io_tell(fptr);
2537 if (pos < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
2543rb_io_seek(
VALUE io,
VALUE offset,
int whence)
2550 pos = io_seek(fptr, pos, whence);
2551 if (pos < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
2552 if (fptr->
readconv) clear_readconv(fptr);
2558interpret_seek_whence(
VALUE vwhence)
2560 if (vwhence == sym_SET)
2562 if (vwhence == sym_CUR)
2564 if (vwhence == sym_END)
2567 if (vwhence == sym_DATA)
2571 if (vwhence == sym_HOLE)
2627 VALUE offset, ptrname;
2628 int whence = SEEK_SET;
2630 if (
rb_scan_args(argc, argv,
"11", &offset, &ptrname) == 2) {
2631 whence = interpret_seek_whence(ptrname);
2634 return rb_io_seek(io, offset, whence);
2662 pos = io_seek(fptr, pos, SEEK_SET);
2663 if (pos < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
2664 if (fptr->
readconv) clear_readconv(fptr);
2694rb_io_rewind(
VALUE io)
2699 if (io_seek(fptr, 0L, 0) < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
2700 if (io == ARGF.current_file) {
2701 ARGF.lineno -= fptr->
lineno;
2705 clear_readconv(fptr);
2712fptr_wait_readable(
rb_io_t *fptr)
2730 fptr->
rbuf.
capa = IO_RBUF_CAPA_FOR(fptr);
2738 if (fptr_wait_readable(fptr))
2742 VALUE path = rb_sprintf(
"fd:%d ", fptr->
fd);
2747 rb_syserr_fail_path(e, path);
2801 if (READ_CHAR_PENDING(fptr))
return Qfalse;
2802 if (READ_DATA_PENDING(fptr))
return Qfalse;
2804#if RUBY_CRLF_ENVIRONMENT
2805 if (!NEED_READCONV(fptr) && NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
2806 return RBOOL(eof(fptr->
fd));
2809 return RBOOL(io_fillbuf(fptr) < 0);
2833 io = GetWriteIO(io);
2870 io = GetWriteIO(io);
2876 fptr->
mode &= ~FMODE_SYNC;
2900rb_io_fsync(
VALUE io)
2904 io = GetWriteIO(io);
2907 if (io_fflush(fptr) < 0)
2908 rb_sys_fail_on_write(fptr);
2910 if ((
int)rb_io_blocking_region(fptr, nogvl_fsync, fptr))
2911 rb_sys_fail_path(fptr->
pathv);
2916# define rb_io_fsync rb_f_notimplement
2917# define rb_io_sync rb_f_notimplement
2926#ifdef HAVE_FDATASYNC
2928nogvl_fdatasync(
void *ptr)
2933 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->
fd)) != FILE_TYPE_DISK)
2936 return (
VALUE)fdatasync(fptr->
fd);
2951rb_io_fdatasync(
VALUE io)
2955 io = GetWriteIO(io);
2958 if (io_fflush(fptr) < 0)
2959 rb_sys_fail_on_write(fptr);
2961 if ((
int)rb_io_blocking_region(fptr, nogvl_fdatasync, fptr) == 0)
2965 return rb_io_fsync(io);
2968#define rb_io_fdatasync rb_io_fsync
2986rb_io_fileno(
VALUE io)
3006 if (!UNDEF_P(fileno)) {
3099rb_io_inspect(
VALUE obj)
3103 static const char closed[] =
" (closed)";
3105 fptr =
RFILE(obj)->fptr;
3112 rb_str_cat(result, closed+1, strlen(closed)-1);
3115 rb_str_catf(result,
"fd %d", fptr->
fd);
3136rb_io_to_io(
VALUE io)
3143read_buffered_data(
char *ptr,
long len,
rb_io_t *fptr)
3147 n = READ_DATA_PENDING_COUNT(fptr);
3148 if (n <= 0)
return 0;
3149 if (n >
len) n = (int)
len;
3157io_bufread(
char *ptr,
long len,
rb_io_t *fptr)
3163 if (READ_DATA_PENDING(fptr) == 0) {
3167 c = rb_io_read_memory(fptr, ptr+offset, n);
3170 if (fptr_wait_readable(fptr))
3175 if ((n -= c) <= 0)
break;
3181 c = read_buffered_data(ptr+offset, n, fptr);
3184 if ((n -= c) <= 0)
break;
3187 if (io_fillbuf(fptr) < 0) {
3194static int io_setstrbuf(
VALUE *str,
long len);
3203bufread_call(
VALUE arg)
3206 p->len = io_bufread(p->str_ptr, p->len, p->fptr);
3211io_fread(
VALUE str,
long offset,
long size,
rb_io_t *fptr)
3216 io_setstrbuf(&str, offset + size);
3217 arg.str_ptr = RSTRING_PTR(str) + offset;
3220 rb_str_locktmp_ensure(str, bufread_call, (
VALUE)&arg);
3222 if (
len < 0) rb_sys_fail_path(fptr->
pathv);
3230 rb_off_t siz = READ_DATA_PENDING_COUNT(fptr);
3233 if (fstat(fptr->
fd, &st) == 0 && S_ISREG(st.st_mode)
3234#
if defined(__HAIKU__)
3239 if (io_fflush(fptr) < 0)
3240 rb_sys_fail_on_write(fptr);
3241 pos = lseek(fptr->
fd, 0, SEEK_CUR);
3242 if (st.st_size >= pos && pos >= 0) {
3243 siz += st.st_size - pos;
3244 if (siz > LONG_MAX) {
3245 rb_raise(
rb_eIOError,
"file too big for single read");
3258 rb_enc_associate(str, io_read_encoding(fptr));
3263make_readconv(
rb_io_t *fptr,
int size)
3268 const char *sname, *dname;
3269 ecflags = fptr->
encs.
ecflags & ~ECONV_NEWLINE_DECORATOR_WRITE_MASK;
3272 sname = rb_enc_name(fptr->
encs.
enc2);
3273 dname = rb_enc_name(io_read_encoding(fptr));
3283 if (size < IO_CBUF_CAPA_MIN) size = IO_CBUF_CAPA_MIN;
3289#define MORE_CHAR_SUSPENDED Qtrue
3290#define MORE_CHAR_FINISHED Qnil
3292fill_cbuf(
rb_io_t *fptr,
int ec_flags)
3294 const unsigned char *ss, *sp, *se;
3295 unsigned char *ds, *dp, *de;
3304 return MORE_CHAR_SUSPENDED;
3315 ss = sp = (
const unsigned char *)fptr->
rbuf.
ptr + fptr->
rbuf.
off;
3320 fptr->
rbuf.
off += (int)(sp - ss);
3321 fptr->
rbuf.
len -= (int)(sp - ss);
3322 fptr->
cbuf.
len += (int)(dp - ds);
3327 fptr->
rbuf.
off -= putbackable;
3328 fptr->
rbuf.
len += putbackable;
3335 if (cbuf_len0 != fptr->
cbuf.
len)
3336 return MORE_CHAR_SUSPENDED;
3339 return MORE_CHAR_FINISHED;
3345 if (io_fillbuf(fptr) < 0) {
3347 return MORE_CHAR_FINISHED;
3352 fptr->
cbuf.
len += (int)(dp - ds);
3359 if (cbuf_len0 != fptr->
cbuf.
len)
3360 return MORE_CHAR_SUSPENDED;
3362 return MORE_CHAR_FINISHED;
3370 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED)
3387 rb_enc_associate(str, fptr->
encs.
enc);
3412 long clen = RSTRING_LEN(s);
3424#define MAX_REALLOC_GAP 4096
3426io_shrink_read_string(
VALUE str,
long n)
3429 rb_str_resize(str, n);
3434io_set_read_length(
VALUE str,
long n,
int shrinkable)
3436 if (RSTRING_LEN(str) != n) {
3439 if (shrinkable) io_shrink_read_string(str, n);
3453 if (NEED_READCONV(fptr)) {
3454 int first = !
NIL_P(str);
3455 SET_BINARY_MODE(fptr);
3456 shrinkable = io_setstrbuf(&str,0);
3457 make_readconv(fptr, 0);
3462 io_shift_cbuf(fptr, fptr->
cbuf.
len, &str);
3464 v = fill_cbuf(fptr, 0);
3465 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED) {
3468 io_shift_cbuf(fptr, fptr->
cbuf.
len, &str);
3472 if (v == MORE_CHAR_FINISHED) {
3473 clear_readconv(fptr);
3475 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3476 return io_enc_str(str, fptr);
3481 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3485 enc = io_read_encoding(fptr);
3498 shrinkable = io_setstrbuf(&str, siz);
3501 n = io_fread(str, bytes, siz - bytes, fptr);
3502 if (n == 0 && bytes == 0) {
3510 if (bytes < siz)
break;
3514 if (
capa < (
size_t)RSTRING_LEN(str) + BUFSIZ) {
3515 if (
capa < BUFSIZ) {
3518 else if (
capa > IO_MAX_BUFFER_GROWTH) {
3519 capa = IO_MAX_BUFFER_GROWTH;
3524 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3525 str = io_enc_str(str, fptr);
3533 if (rb_fd_set_nonblock(fptr->
fd) != 0) {
3534 rb_sys_fail_path(fptr->
pathv);
3539io_read_memory_call(
VALUE arg)
3544 if (scheduler !=
Qnil) {
3547 if (!UNDEF_P(result)) {
3553 if (iis->nonblock) {
3554 return rb_io_blocking_region(iis->fptr, internal_read_func, iis);
3557 return rb_io_blocking_region_wait(iis->fptr, internal_read_func, iis,
RUBY_IO_READABLE);
3564 return (
long)rb_str_locktmp_ensure(str, io_read_memory_call, (
VALUE)iis);
3567#define no_exception_p(opts) !rb_opts_exception_p((opts), TRUE)
3570io_getpartial(
int argc,
VALUE *argv,
VALUE io,
int no_exception,
int nonblock)
3581 rb_raise(rb_eArgError,
"negative length %ld given",
len);
3584 shrinkable = io_setstrbuf(&str,
len);
3590 io_set_read_length(str, 0, shrinkable);
3596 n = read_buffered_data(RSTRING_PTR(str),
len, fptr);
3602 io_setstrbuf(&str,
len);
3605 iis.nonblock = nonblock;
3607 iis.buf = RSTRING_PTR(str);
3610 n = io_read_memory_locktmp(str, &iis);
3613 if (!nonblock && fptr_wait_readable(fptr))
3615 if (nonblock && (io_again_p(e))) {
3617 return sym_wait_readable;
3620 e,
"read would block");
3622 rb_syserr_fail_path(e, fptr->
pathv);
3625 io_set_read_length(str, n, shrinkable);
3726io_readpartial(
int argc,
VALUE *argv,
VALUE io)
3730 ret = io_getpartial(argc, argv, io,
Qnil, 0);
3737io_nonblock_eof(
int no_exception)
3739 if (!no_exception) {
3755 rb_raise(rb_eArgError,
"negative length %ld given",
len);
3758 shrinkable = io_setstrbuf(&str,
len);
3759 rb_bool_expected(ex,
"exception", TRUE);
3765 io_set_read_length(str, 0, shrinkable);
3769 n = read_buffered_data(RSTRING_PTR(str),
len, fptr);
3771 rb_fd_set_nonblock(fptr->
fd);
3772 shrinkable |= io_setstrbuf(&str,
len);
3776 iis.buf = RSTRING_PTR(str);
3779 n = io_read_memory_locktmp(str, &iis);
3782 if (io_again_p(e)) {
3783 if (!ex)
return sym_wait_readable;
3785 e,
"read would block");
3787 rb_syserr_fail_path(e, fptr->
pathv);
3790 io_set_read_length(str, n, shrinkable);
3793 if (!ex)
return Qnil;
3809 rb_bool_expected(ex,
"exception", TRUE);
3811 io = GetWriteIO(io);
3815 if (io_fflush(fptr) < 0)
3816 rb_sys_fail_on_write(fptr);
3818 rb_fd_set_nonblock(fptr->
fd);
3819 n = write(fptr->
fd, RSTRING_PTR(str), RSTRING_LEN(str));
3824 if (io_again_p(e)) {
3826 return sym_wait_writable;
3832 rb_syserr_fail_path(e, fptr->
pathv);
3916#if RUBY_CRLF_ENVIRONMENT
3922 if (
NIL_P(length)) {
3925 return read_all(fptr, remain_size(fptr), str);
3929 rb_raise(rb_eArgError,
"negative length %ld given",
len);
3932 shrinkable = io_setstrbuf(&str,
len);
3937 io_set_read_length(str, 0, shrinkable);
3942#if RUBY_CRLF_ENVIRONMENT
3943 previous_mode = set_binary_mode_with_seek_cur(fptr);
3945 n = io_fread(str, 0,
len, fptr);
3946 io_set_read_length(str, n, shrinkable);
3947#if RUBY_CRLF_ENVIRONMENT
3948 if (previous_mode == O_TEXT) {
3949 setmode(fptr->
fd, O_TEXT);
3952 if (n == 0)
return Qnil;
3958rscheck(
const char *rsptr,
long rslen,
VALUE rs)
3961 if (RSTRING_PTR(rs) != rsptr && RSTRING_LEN(rs) != rslen)
3966search_delim(
const char *p,
long len,
int delim,
rb_encoding *enc)
3968 if (rb_enc_mbminlen(enc) == 1) {
3969 p = memchr(p, delim,
len);
3970 if (p)
return p + 1;
3973 const char *end = p +
len;
3975 int r = rb_enc_precise_mbclen(p, end, enc);
3977 p += rb_enc_mbminlen(enc);
3981 if (rb_enc_mbc_to_codepoint(p, end, enc) == (
unsigned int)delim) {
3996 if (NEED_READCONV(fptr)) {
3997 SET_BINARY_MODE(fptr);
3998 make_readconv(fptr, 0);
4001 int searchlen = READ_CHAR_PENDING_COUNT(fptr);
4003 p = READ_CHAR_PENDING_PTR(fptr);
4004 if (0 < limit && limit < searchlen)
4005 searchlen = (int)limit;
4006 e = search_delim(p, searchlen, delim, enc);
4008 int len = (int)(e-p);
4030 return (
unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
4033 }
while (more_char(fptr) != MORE_CHAR_FINISHED);
4034 clear_readconv(fptr);
4039 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4041 long pending = READ_DATA_PENDING_COUNT(fptr);
4043 const char *p = READ_DATA_PENDING_PTR(fptr);
4047 if (limit > 0 && pending > limit) pending = limit;
4048 e = search_delim(p, pending, delim, enc);
4049 if (e) pending = e - p;
4051 last = RSTRING_LEN(str);
4052 rb_str_resize(str, last + pending);
4059 read_buffered_data(RSTRING_PTR(str) + last, pending, fptr);
4062 if (e)
return delim;
4064 return (
unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
4067 }
while (io_fillbuf(fptr) >= 0);
4073swallow(
rb_io_t *fptr,
int term)
4075 if (NEED_READCONV(fptr)) {
4077 int needconv = rb_enc_mbminlen(enc) != 1;
4078 SET_BINARY_MODE(fptr);
4079 make_readconv(fptr, 0);
4082 while ((cnt = READ_CHAR_PENDING_COUNT(fptr)) > 0) {
4083 const char *p = READ_CHAR_PENDING_PTR(fptr);
4086 if (*p != term)
return TRUE;
4088 while (--i && *++p == term);
4091 const char *e = p + cnt;
4092 if (rb_enc_ascget(p, e, &i, enc) != term)
return TRUE;
4093 while ((p += i) < e && rb_enc_ascget(p, e, &i, enc) == term);
4096 io_shift_cbuf(fptr, (
int)cnt - i, NULL);
4098 }
while (more_char(fptr) != MORE_CHAR_FINISHED);
4102 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4105 while ((cnt = READ_DATA_PENDING_COUNT(fptr)) > 0) {
4107 const char *p = READ_DATA_PENDING_PTR(fptr);
4109 if (cnt >
sizeof buf) cnt =
sizeof buf;
4110 if (*p != term)
return TRUE;
4112 while (--i && *++p == term);
4113 if (!read_buffered_data(buf, cnt - i, fptr))
4114 rb_sys_fail_path(fptr->
pathv);
4117 }
while (io_fillbuf(fptr) == 0);
4130 int pending = READ_DATA_PENDING_COUNT(fptr);
4133 const char *p = READ_DATA_PENDING_PTR(fptr);
4137 e = memchr(p,
'\n', pending);
4139 pending = (int)(e - p + 1);
4141 chomplen = (pending > 1 && *(e-1) ==
'\r') + 1;
4150 rb_str_resize(str,
len + pending - chomplen);
4151 read_buffered_data(RSTRING_PTR(str)+
len, pending - chomplen, fptr);
4154 if (pending == 1 && chomplen == 1 &&
len > 0) {
4155 if (RSTRING_PTR(str)[
len-1] ==
'\r') {
4156 rb_str_resize(str, --
len);
4161 len += pending - chomplen;
4167 }
while (io_fillbuf(fptr) >= 0);
4170 str = io_enc_str(str, fptr);
4181 unsigned int chomp: 1;
4195 chomp = (!UNDEF_P(vchomp)) &&
RTEST(vchomp);
4197 args->chomp = chomp;
4215 else if (2 <= argc) {
4216 rs = argv[0], lim = argv[1];
4225check_getline_args(
VALUE *rsp,
long *limit,
VALUE io)
4234 enc_rs = rb_enc_get(rs);
4235 enc_io = io_read_encoding(fptr);
4236 if (enc_io != enc_rs &&
4237 (!is_ascii_string(rs) ||
4238 (RSTRING_LEN(rs) > 0 && !rb_enc_asciicompat(enc_io)))) {
4239 if (rs == rb_default_rs) {
4240 rs = rb_enc_str_new(0, 0, enc_io);
4245 rb_raise(rb_eArgError,
"encoding mismatch: %s IO with %s RS",
4246 rb_enc_name(enc_io),
4247 rb_enc_name(enc_rs));
4257 argc =
rb_scan_args(argc, argv,
"02:", NULL, NULL, &opts);
4258 extract_getline_args(argc, argv, args);
4259 extract_getline_opts(opts, args);
4260 check_getline_args(&args->rs, &args->limit, io);
4264rb_io_getline_0(
VALUE rs,
long limit,
int chomp,
rb_io_t *fptr)
4271 if (
NIL_P(rs) && limit < 0) {
4272 str = read_all(fptr, 0,
Qnil);
4273 if (RSTRING_LEN(str) == 0)
return Qnil;
4275 else if (limit == 0) {
4276 return rb_enc_str_new(0, 0, io_read_encoding(fptr));
4278 else if (rs == rb_default_rs && limit < 0 && !NEED_READCONV(fptr) &&
4279 rb_enc_asciicompat(enc = io_read_encoding(fptr))) {
4280 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4281 return rb_io_getline_fast(fptr, enc, chomp);
4284 int c, newline = -1;
4285 const char *rsptr = 0;
4288 int extra_limit = 16;
4289 int chomp_cr = chomp;
4291 SET_BINARY_MODE(fptr);
4292 enc = io_read_encoding(fptr);
4295 rslen = RSTRING_LEN(rs);
4300 swallow(fptr,
'\n');
4302 if (!rb_enc_asciicompat(enc)) {
4306 rsptr = RSTRING_PTR(rs);
4307 rslen = RSTRING_LEN(rs);
4311 else if (rb_enc_mbminlen(enc) == 1) {
4312 rsptr = RSTRING_PTR(rs);
4313 newline = (
unsigned char)rsptr[rslen - 1];
4317 rsptr = RSTRING_PTR(rs);
4318 const char *e = rsptr + rslen;
4319 const char *last = rb_enc_prev_char(rsptr, e, e, enc);
4321 newline = rb_enc_codepoint_len(last, e, &n, enc);
4322 if (last + n != e) rb_raise(rb_eArgError,
"broken separator");
4324 chomp_cr = chomp && newline ==
'\n' && rslen == rb_enc_mbminlen(enc);
4328 while ((c = appendline(fptr, newline, &str, &limit, enc)) != EOF) {
4329 const char *s, *p, *pp, *e;
4332 if (RSTRING_LEN(str) < rslen)
continue;
4333 s = RSTRING_PTR(str);
4336 if (!at_char_boundary(s, p, e, enc))
continue;
4337 if (!rspara) rscheck(rsptr, rslen, rs);
4338 if (memcmp(p, rsptr, rslen) == 0) {
4340 if (chomp_cr && p > s && *(p-1) ==
'\r') --p;
4347 s = RSTRING_PTR(str);
4349 pp = rb_enc_prev_char(s, p, p, enc);
4350 if (extra_limit && pp &&
4364 if (rspara && c != EOF)
4365 swallow(fptr,
'\n');
4367 str = io_enc_str(str, fptr);
4370 if (!
NIL_P(str) && !nolimit) {
4378rb_io_getline_1(
VALUE rs,
long limit,
int chomp,
VALUE io)
4381 int old_lineno, new_lineno;
4385 old_lineno = fptr->
lineno;
4386 str = rb_io_getline_0(rs, limit, chomp, fptr);
4387 if (!
NIL_P(str) && (new_lineno = fptr->
lineno) != old_lineno) {
4388 if (io == ARGF.current_file) {
4389 ARGF.lineno += new_lineno - old_lineno;
4390 ARGF.last_lineno = ARGF.lineno;
4393 ARGF.last_lineno = new_lineno;
4401rb_io_getline(
int argc,
VALUE *argv,
VALUE io)
4405 prepare_getline_args(argc, argv, &args, io);
4406 return rb_io_getline_1(args.rs, args.limit, args.chomp, io);
4416rb_io_gets_limit_internal(
VALUE io,
long limit)
4420 return rb_io_getline_0(rb_default_rs, limit, FALSE, fptr);
4424rb_io_gets_internal(
VALUE io)
4426 return rb_io_gets_limit_internal(io, -1);
4506 str = rb_io_getline(argc, argv, io);
4522rb_io_lineno(
VALUE io)
4577 check_getline_args(&sep, &limit, io);
4579 VALUE line = rb_io_getline_1(sep, limit,
RTEST(chomp), io);
4580 rb_lastline_set_up(line, 1);
4655rb_io_readlines(
int argc,
VALUE *argv,
VALUE io)
4659 prepare_getline_args(argc, argv, &args, io);
4660 return io_readlines(&args, io);
4668 if (arg->limit == 0)
4669 rb_raise(rb_eArgError,
"invalid limit: 0 for readlines");
4671 while (!
NIL_P(line = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, io))) {
4784rb_io_each_line(
int argc,
VALUE *argv,
VALUE io)
4790 prepare_getline_args(argc, argv, &args, io);
4791 if (args.limit == 0)
4792 rb_raise(rb_eArgError,
"invalid limit: 0 for each_line");
4793 while (!
NIL_P(str = rb_io_getline_1(args.rs, args.limit, args.chomp, io))) {
4821rb_io_each_byte(
VALUE io)
4837 }
while (io_fillbuf(fptr) >= 0);
4847 if (NEED_READCONV(fptr)) {
4851 SET_BINARY_MODE(fptr);
4852 make_readconv(fptr, 0);
4866 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4868 clear_readconv(fptr);
4872 str = rb_enc_str_new(fptr->
cbuf.
ptr+fptr->
cbuf.
off, 1, read_enc);
4875 if (fptr->
cbuf.
len == 0) clear_readconv(fptr);
4884 io_shift_cbuf(fptr, r, &str);
4891 ISASCII(RSTRING_PTR(str)[0])) {
4895 str = io_enc_str(str, fptr);
4900 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4901 if (io_fillbuf(fptr) < 0) {
4923 if (io_fillbuf(fptr) != -1) {
4927 r = rb_enc_precise_mbclen(RSTRING_PTR(str), RSTRING_PTR(str)+RSTRING_LEN(str), enc);
4943 str = io_enc_str(str, fptr);
4970rb_io_each_char(
VALUE io)
4980 enc = io_input_encoding(fptr);
4982 while (!
NIL_P(c = io_getc(fptr, enc))) {
5009rb_io_each_codepoint(
VALUE io)
5021 enc = io_read_encoding(fptr);
5022 if (NEED_READCONV(fptr)) {
5023 SET_BINARY_MODE(fptr);
5026 make_readconv(fptr, 0);
5038 if (more_char(fptr) == MORE_CHAR_FINISHED) {
5039 clear_readconv(fptr);
5059 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
5060 while (io_fillbuf(fptr) >= 0) {
5075 char cbuf[8], *p = cbuf;
5077 if (more > numberof(cbuf))
goto invalid;
5079 if (more > numberof(cbuf))
goto invalid;
5080 while ((n = (
int)read_buffered_data(p, more, fptr)) > 0 &&
5081 (p += n, (more -= n) > 0)) {
5082 if (io_fillbuf(fptr) < 0)
goto invalid;
5083 if ((n = fptr->
rbuf.
len) > more) n = more;
5085 r = rb_enc_precise_mbclen(cbuf, p, enc);
5098 rb_raise(rb_eArgError,
"invalid byte sequence in %s", rb_enc_name(enc));
5131 enc = io_input_encoding(fptr);
5133 return io_getc(fptr, enc);
5157rb_io_readchar(
VALUE io)
5159 VALUE c = rb_io_getc(io);
5195 VALUE r_stdout = rb_ractor_stdout();
5200 rb_io_flush(r_stdout);
5203 if (io_fillbuf(fptr) < 0) {
5233rb_io_readbyte(
VALUE io)
5294 unsigned char c =
NUM2INT(v) & 0xFF;
5300 io_ungetbyte(b, fptr);
5356 else if (RB_BIGNUM_TYPE_P(c)) {
5362 if (NEED_READCONV(fptr)) {
5363 SET_BINARY_MODE(fptr);
5364 len = RSTRING_LEN(c);
5365#if SIZEOF_LONG > SIZEOF_INT
5369 make_readconv(fptr, (
int)
len);
5383 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
5384 io_ungetbyte(c, fptr);
5404rb_io_isatty(
VALUE io)
5409 return RBOOL(isatty(fptr->
fd) != 0);
5412#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5428rb_io_close_on_exec_p(
VALUE io)
5434 write_io = GetWriteIO(io);
5435 if (io != write_io) {
5437 if (fptr && 0 <= (fd = fptr->
fd)) {
5438 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->
pathv);
5439 if (!(ret & FD_CLOEXEC))
return Qfalse;
5444 if (fptr && 0 <= (fd = fptr->
fd)) {
5445 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->
pathv);
5446 if (!(ret & FD_CLOEXEC))
return Qfalse;
5451#define rb_io_close_on_exec_p rb_f_notimplement
5454#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5478 int flag =
RTEST(arg) ? FD_CLOEXEC : 0;
5483 write_io = GetWriteIO(io);
5484 if (io != write_io) {
5486 if (fptr && 0 <= (fd = fptr->
fd)) {
5487 if ((ret = fcntl(fptr->
fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->
pathv);
5488 if ((ret & FD_CLOEXEC) != flag) {
5489 ret = (ret & ~FD_CLOEXEC) | flag;
5490 ret = fcntl(fd, F_SETFD, ret);
5491 if (ret != 0) rb_sys_fail_path(fptr->
pathv);
5498 if (fptr && 0 <= (fd = fptr->
fd)) {
5499 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->
pathv);
5500 if ((ret & FD_CLOEXEC) != flag) {
5501 ret = (ret & ~FD_CLOEXEC) | flag;
5502 ret = fcntl(fd, F_SETFD, ret);
5503 if (ret != 0) rb_sys_fail_path(fptr->
pathv);
5509#define rb_io_set_close_on_exec rb_f_notimplement
5512#define RUBY_IO_EXTERNAL_P(f) ((f)->mode & FMODE_EXTERNAL)
5513#define PREP_STDIO_NAME(f) (RSTRING_PTR((f)->pathv))
5516finish_writeconv(
rb_io_t *fptr,
int noalloc)
5518 unsigned char *ds, *dp, *de;
5522 unsigned char buf[1024];
5527 de = buf +
sizeof(buf);
5530 size_t remaining = dp-ds;
5531 long result = rb_io_write_memory(fptr, ds, remaining);
5535 if ((
size_t)result == remaining)
break;
5558 if (io_fflush(fptr) < 0) {
5566 fptr->
wbuf.
len += (int)(dp - ds);
5582finish_writeconv_sync(
VALUE arg)
5585 return finish_writeconv(p->fptr, p->noalloc);
5589nogvl_close(
void *ptr)
5593 return (
void*)(intptr_t)close(*fd);
5597maygvl_close(
int fd,
int keepgvl)
5606 return IO_WITHOUT_GVL_INT(nogvl_close, &fd);
5610nogvl_fclose(
void *ptr)
5614 return (
void*)(intptr_t)fclose(file);
5618maygvl_fclose(
FILE *file,
int keepgvl)
5621 return fclose(file);
5623 return IO_WITHOUT_GVL_INT(nogvl_fclose, file);
5629fptr_finalize_flush(
rb_io_t *fptr,
int noraise,
int keepgvl)
5634 int mode = fptr->
mode;
5640 arg.noalloc = noraise;
5644 error = finish_writeconv(fptr, noraise);
5657 io_flush_buffer_sync(fptr);
5660 if (io_fflush(fptr) < 0 &&
NIL_P(error)) {
5668 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2) {
5678 rb_thread_io_close_wait(fptr);
5680 if (!done && stdio_file) {
5682 if ((maygvl_fclose(stdio_file, noraise) < 0) &&
NIL_P(error)) {
5692 if (!done && fd >= 0 && scheduler !=
Qnil) {
5695 if (!UNDEF_P(result)) {
5696 done =
RTEST(result);
5700 if (!done && fd >= 0) {
5706 if ((maygvl_close(fd, keepgvl) < 0) &&
NIL_P(error)) {
5715 if (!
NIL_P(error) && !noraise) {
5724fptr_finalize(
rb_io_t *fptr,
int noraise)
5726 fptr_finalize_flush(fptr, noraise, FALSE);
5727 free_io_buffer(&fptr->
rbuf);
5728 free_io_buffer(&fptr->
wbuf);
5729 clear_codeconv(fptr);
5733rb_io_fptr_cleanup(
rb_io_t *fptr,
int noraise)
5739 fptr_finalize(fptr, noraise);
5747 ruby_xfree_sized(buf->
ptr, (
size_t)buf->
capa);
5760 free_io_buffer(&fptr->
cbuf);
5776 clear_readconv(fptr);
5777 clear_writeconv(fptr);
5781rb_io_fptr_cleanup_all(
rb_io_t *fptr)
5785 rb_io_fptr_cleanup(fptr, TRUE);
5787 free_io_buffer(&fptr->
rbuf);
5788 free_io_buffer(&fptr->
wbuf);
5789 clear_codeconv(fptr);
5796 rb_io_fptr_cleanup_all(io);
5803rb_io_fptr_finalize_closed(
struct rb_io *io)
5805 if (!io)
return true;
5806 if (io->
fd >= 0)
return false;
5812rb_io_memsize(
const rb_io_t *io)
5814 size_t size =
sizeof(
rb_io_t);
5824 rb_serial_t fork_generation = GET_VM()->fork_gen;
5825 if (io->fork_generation == fork_generation) {
5836# define KEEPGVL TRUE
5838# define KEEPGVL FALSE
5842io_close_fptr(
VALUE io)
5848 write_io = GetWriteIO(io);
5849 if (io != write_io) {
5850 write_fptr =
RFILE(write_io)->fptr;
5851 if (write_fptr && 0 <= write_fptr->
fd) {
5852 rb_io_fptr_cleanup(write_fptr, TRUE);
5856 fptr =
RFILE(io)->fptr;
5857 if (!fptr)
return 0;
5858 if (fptr->
fd < 0)
return 0;
5861 if (rb_thread_io_close_interrupt(fptr)) {
5863 fptr_finalize_flush(fptr, FALSE, KEEPGVL);
5866 rb_io_fptr_cleanup(fptr, FALSE);
5871fptr_waitpid(
rb_io_t *fptr,
int nohang)
5875 rb_last_status_clear();
5884 rb_io_t *fptr = io_close_fptr(io);
5885 if (fptr) fptr_waitpid(fptr, 0);
5925rb_io_close_m(
VALUE io)
5927 rb_io_t *fptr = rb_io_get_fptr(io);
5936io_call_close(
VALUE io)
5945 enum {mesg_len =
sizeof(closed_stream)-1};
5946 VALUE mesg = rb_attr_get(exc, idMesg);
5948 RSTRING_LEN(mesg) != mesg_len ||
5949 memcmp(RSTRING_PTR(mesg), closed_stream, mesg_len)) {
5959 if (!UNDEF_P(closed) &&
RTEST(closed))
return io;
5960 rb_rescue2(io_call_close, io, ignore_closed_stream, io,
5996 write_io = GetWriteIO(io);
5997 if (io != write_io) {
5998 write_fptr =
RFILE(write_io)->fptr;
5999 if (write_fptr && 0 <= write_fptr->
fd) {
6004 fptr = rb_io_get_fptr(io);
6005 return RBOOL(0 > fptr->
fd);
6041rb_io_close_read(
VALUE io)
6047 if (fptr->
fd < 0)
return Qnil;
6048 if (is_socket(fptr->
fd, fptr->
pathv)) {
6052 if (shutdown(fptr->
fd, SHUT_RD) < 0)
6053 rb_sys_fail_path(fptr->
pathv);
6054 fptr->
mode &= ~FMODE_READABLE;
6060 write_io = GetWriteIO(io);
6061 if (io != write_io) {
6066 RFILE(io)->fptr = wfptr;
6069 RFILE(write_io)->fptr = fptr;
6070 rb_io_fptr_cleanup(fptr, FALSE);
6076 rb_raise(
rb_eIOError,
"closing non-duplex IO for reading");
6114rb_io_close_write(
VALUE io)
6119 write_io = GetWriteIO(io);
6121 if (fptr->
fd < 0)
return Qnil;
6122 if (is_socket(fptr->
fd, fptr->
pathv)) {
6133 if (io_fflush(fptr) < 0)
6134 rb_sys_fail_on_write(fptr);
6136 if (shutdown(fptr->
fd, SHUT_WR) < 0)
6137 rb_sys_fail_path(fptr->
pathv);
6138 fptr->
mode &= ~FMODE_WRITABLE;
6145 rb_raise(
rb_eIOError,
"closing non-duplex IO for writing");
6148 if (io != write_io) {
6168rb_io_sysseek(
int argc,
VALUE *argv,
VALUE io)
6170 VALUE offset, ptrname;
6171 int whence = SEEK_SET;
6175 if (
rb_scan_args(argc, argv,
"11", &offset, &ptrname) == 2) {
6176 whence = interpret_seek_whence(ptrname);
6181 (READ_DATA_BUFFERED(fptr) || READ_CHAR_PENDING(fptr))) {
6185 rb_warn(
"sysseek for buffered IO");
6188 pos = lseek(fptr->
fd, pos, whence);
6189 if (pos < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
6223 io = GetWriteIO(io);
6228 rb_warn(
"syswrite for buffered IO");
6231 tmp = rb_str_tmp_frozen_acquire(str);
6233 n = rb_io_write_memory(fptr, ptr,
len);
6234 if (n < 0) rb_sys_fail_path(fptr->
pathv);
6235 rb_str_tmp_frozen_release(str, tmp);
6252rb_io_sysread(
int argc,
VALUE *argv,
VALUE io)
6263 shrinkable = io_setstrbuf(&str, ilen);
6264 if (ilen == 0)
return str;
6269 if (READ_DATA_BUFFERED(fptr)) {
6275 io_setstrbuf(&str, ilen);
6280 iis.buf = RSTRING_PTR(str);
6283 n = io_read_memory_locktmp(str, &iis);
6286 rb_sys_fail_path(fptr->
pathv);
6289 io_set_read_length(str, n, shrinkable);
6291 if (n == 0 && ilen > 0) {
6307internal_pread_func(
void *_arg)
6311 return (
VALUE)pread(arg->fd, arg->buf, arg->count, arg->offset);
6315pread_internal_call(
VALUE _arg)
6320 if (scheduler !=
Qnil) {
6323 if (!UNDEF_P(result)) {
6328 return rb_io_blocking_region_wait(arg->io, internal_pread_func, arg,
RUBY_IO_READABLE);
6372 shrinkable = io_setstrbuf(&str, (
long)arg.count);
6373 if (arg.count == 0)
return str;
6374 arg.buf = RSTRING_PTR(str);
6387 rb_sys_fail_path(fptr->
pathv);
6389 io_set_read_length(str, n, shrinkable);
6390 if (n == 0 && arg.count > 0) {
6398internal_pwrite_func(
void *_arg)
6402 return (
VALUE)pwrite(arg->fd, arg->buf, arg->count, arg->offset);
6406pwrite_internal_call(
VALUE _arg)
6411 if (scheduler !=
Qnil) {
6414 if (!UNDEF_P(result)) {
6419 return rb_io_blocking_region_wait(arg->io, internal_pwrite_func, arg,
RUBY_IO_WRITABLE);
6460 io = GetWriteIO(io);
6467 tmp = rb_str_tmp_frozen_acquire(str);
6468 arg.buf = RSTRING_PTR(tmp);
6469 arg.count = (size_t)RSTRING_LEN(tmp);
6471 n = (ssize_t)pwrite_internal_call((
VALUE)&arg);
6472 if (n < 0) rb_sys_fail_path(fptr->
pathv);
6473 rb_str_tmp_frozen_release(str, tmp);
6489 fptr->
mode &= ~FMODE_TEXTMODE;
6493 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6496 setmode(fptr->
fd, O_BINARY);
6503io_ascii8bit_binmode(
rb_io_t *fptr)
6514 fptr->
mode &= ~FMODE_TEXTMODE;
6515 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6517 fptr->
encs.
enc = rb_ascii8bit_encoding();
6521 clear_codeconv(fptr);
6530 io_ascii8bit_binmode(fptr);
6547rb_io_binmode_m(
VALUE io)
6553 write_io = GetWriteIO(io);
6568rb_io_binmode_p(
VALUE io)
6576rb_io_fmode_modestr(
enum rb_io_mode fmode)
6580 return MODE_BTMODE(
"a+",
"ab+",
"at+");
6582 return MODE_BTMODE(
"a",
"ab",
"at");
6586 rb_raise(rb_eArgError,
"invalid access fmode 0x%x", fmode);
6588 return MODE_BTMODE(
"r",
"rb",
"rt");
6590 return MODE_BTXMODE(
"w",
"wb",
"wt",
"wx",
"wbx",
"wtx");
6593 return MODE_BTXMODE(
"w+",
"wb+",
"wt+",
"w+x",
"wb+x",
"wt+x");
6595 return MODE_BTMODE(
"r+",
"rb+",
"rt+");
6599static const char bom_prefix[] =
"bom|";
6600static const char utf_prefix[] =
"utf-";
6601enum {bom_prefix_len = (int)
sizeof(bom_prefix) - 1};
6602enum {utf_prefix_len = (int)
sizeof(utf_prefix) - 1};
6605io_encname_bom_p(
const char *name,
long len)
6607 return len > bom_prefix_len &&
STRNCASECMP(name, bom_prefix, bom_prefix_len) == 0;
6613 enum rb_io_mode fmode = 0;
6614 const char *m = modestr, *p = NULL;
6642 if (modestr[0] !=
'w')
6650 if (io_encname_bom_p(m, p ? (
long)(p - m) : (long)strlen(m)))
6663 rb_raise(rb_eArgError,
"invalid access mode %s", modestr);
6668rb_io_oflags_fmode(
int oflags)
6670 enum rb_io_mode fmode = 0;
6672 switch (oflags & O_ACCMODE) {
6684 if (oflags & O_APPEND) {
6687 if (oflags & O_TRUNC) {
6690 if (oflags & O_CREAT) {
6693 if (oflags & O_EXCL) {
6697 if (oflags & O_BINARY) {
6706rb_io_fmode_oflags(
enum rb_io_mode fmode)
6750rb_io_oflags_modestr(
int oflags)
6753# define MODE_BINARY(a,b) ((oflags & O_BINARY) ? (b) : (a))
6755# define MODE_BINARY(a,b) (a)
6758 if (oflags & O_EXCL) {
6759 rb_raise(rb_eArgError,
"exclusive access mode is not supported");
6761 accmode = oflags & (O_RDONLY|O_WRONLY|O_RDWR);
6762 if (oflags & O_APPEND) {
6763 if (accmode == O_WRONLY) {
6764 return MODE_BINARY(
"a",
"ab");
6766 if (accmode == O_RDWR) {
6767 return MODE_BINARY(
"a+",
"ab+");
6772 rb_raise(rb_eArgError,
"invalid access oflags 0x%x", oflags);
6774 return MODE_BINARY(
"r",
"rb");
6776 return MODE_BINARY(
"w",
"wb");
6778 if (oflags & O_TRUNC) {
6779 return MODE_BINARY(
"w+",
"wb+");
6781 return MODE_BINARY(
"r+",
"rb+");
6793 int default_ext = 0;
6796 ext = rb_default_external_encoding();
6799 if (rb_is_ascii8bit_enc(ext)) {
6803 else if (intern == NULL) {
6804 intern = rb_default_internal_encoding();
6809 *enc = (default_ext && intern != ext) ? NULL : ext;
6819unsupported_encoding(
const char *name,
rb_encoding *enc)
6821 rb_enc_warn(enc,
"Unsupported encoding %s ignored", name);
6825parse_mode_enc(
const char *estr,
rb_encoding *estr_enc,
6831 enum rb_io_mode fmode = fmode_p ? *fmode_p : 0;
6837 p = strrchr(estr,
':');
6838 len = p ? (p++ - estr) : (long)strlen(estr);
6840 estr += bom_prefix_len;
6841 len -= bom_prefix_len;
6842 if (!
STRNCASECMP(estr, utf_prefix, utf_prefix_len)) {
6846 rb_enc_warn(estr_enc,
"BOM with non-UTF encoding %s is nonsense", estr);
6847 fmode &= ~FMODE_SETENC_BY_BOM;
6855 memcpy(encname, estr,
len);
6856 encname[
len] =
'\0';
6859 idx = rb_enc_find_index(estr);
6861 if (fmode_p) *fmode_p = fmode;
6864 ext_enc = rb_enc_from_index(idx);
6867 unsupported_encoding(estr, estr_enc);
6873 if (*p ==
'-' && *(p+1) ==
'\0') {
6878 idx2 = rb_enc_find_index(p);
6880 unsupported_encoding(p, estr_enc);
6885 int_enc = rb_enc_from_index(idx2);
6889 rb_io_ext_int_to_encs(ext_enc, int_enc, enc_p, enc2_p, fmode);
6902 v = rb_hash_lookup2(opt, sym_encoding,
Qnil);
6903 if (v !=
Qnil) encoding = v;
6904 v = rb_hash_lookup2(opt, sym_extenc,
Qundef);
6905 if (v !=
Qnil) extenc = v;
6906 v = rb_hash_lookup2(opt, sym_intenc,
Qundef);
6907 if (!UNDEF_P(v)) intenc = v;
6909 if ((!UNDEF_P(extenc) || !UNDEF_P(intenc)) && !
NIL_P(encoding)) {
6911 int idx = rb_to_encoding_index(encoding);
6912 if (idx >= 0) encoding = rb_enc_from_encoding(rb_enc_from_index(idx));
6913 rb_warn(
"Ignoring encoding parameter '%"PRIsVALUE
"': %s_encoding is used",
6914 encoding, UNDEF_P(extenc) ?
"internal" :
"external");
6918 if (!UNDEF_P(extenc) && !
NIL_P(extenc)) {
6919 extencoding = rb_to_encoding(extenc);
6921 if (!UNDEF_P(intenc)) {
6922 if (
NIL_P(intenc)) {
6929 if (*p ==
'-' && *(p+1) ==
'\0') {
6934 intencoding = rb_to_encoding(intenc);
6938 intencoding = rb_to_encoding(intenc);
6940 if (extencoding == intencoding) {
6944 if (!
NIL_P(encoding)) {
6948 enc_p, enc2_p, fmode_p);
6951 rb_io_ext_int_to_encs(rb_to_encoding(encoding), NULL, enc_p, enc2_p, 0);
6954 else if (!UNDEF_P(extenc) || !UNDEF_P(intenc)) {
6956 rb_io_ext_int_to_encs(extencoding, intencoding, enc_p, enc2_p, 0);
6964 enum rb_io_mode fmode = *fmode_p;
6969 !rb_enc_asciicompat(enc ? enc : rb_default_external_encoding()))
6970 rb_raise(rb_eArgError,
"ASCII incompatible encoding needs binmode");
6973 rb_raise(rb_eArgError,
"newline decorator with binary mode");
6980#if !DEFAULT_TEXTMODE
6982 fmode &= ~FMODE_TEXTMODE;
6989extract_binmode(
VALUE opthash,
enum rb_io_mode *fmode)
6991 if (!
NIL_P(opthash)) {
6993 v = rb_hash_aref(opthash, sym_textmode);
6996 rb_raise(rb_eArgError,
"textmode specified twice");
6998 rb_raise(rb_eArgError,
"both textmode and binmode specified");
7002 v = rb_hash_aref(opthash, sym_binmode);
7005 rb_raise(rb_eArgError,
"binmode specified twice");
7007 rb_raise(rb_eArgError,
"both textmode and binmode specified");
7013 rb_raise(rb_eArgError,
"both textmode and binmode specified");
7019 int *oflags_p,
enum rb_io_mode *fmode_p,
struct rb_io_encoding *convconfig_p)
7023 enum rb_io_mode fmode;
7027 int has_enc = 0, has_vmode = 0;
7033 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
7043 fmode = rb_io_oflags_fmode(oflags);
7051 oflags = rb_io_fmode_oflags(fmode);
7055 parse_mode_enc(p+1, rb_enc_get(vmode), &enc, &enc2, &fmode);
7060 e = (fmode &
FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
7061 rb_io_ext_int_to_encs(e, NULL, &enc, &enc2, fmode);
7065 if (
NIL_P(opthash)) {
7069#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7071 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7072 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7074 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
7081 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
7084 else if (
NIL_P(vmode)) {
7085 fmode |= DEFAULT_TEXTMODE;
7092 v = rb_hash_aref(opthash, sym_mode);
7094 if (!
NIL_P(vmode)) {
7095 rb_raise(rb_eArgError,
"mode specified twice");
7102 v = rb_hash_aref(opthash, sym_flags);
7107 fmode = rb_io_oflags_fmode(oflags);
7109 extract_binmode(opthash, &fmode);
7115 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
7118 else if (
NIL_P(vmode)) {
7119 fmode |= DEFAULT_TEXTMODE;
7122 v = rb_hash_aref(opthash, sym_perm);
7125 if (!
NIL_P(*vperm_p)) {
7126 rb_raise(rb_eArgError,
"perm specified twice");
7137#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7139 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7140 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7145 rb_raise(rb_eArgError,
"encoding specified twice");
7148 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
7152 validate_enc_binmode(&fmode, ecflags, enc, enc2);
7158 convconfig_p->
enc = enc;
7159 convconfig_p->
enc2 = enc2;
7160 convconfig_p->
ecflags = ecflags;
7161 convconfig_p->
ecopts = ecopts;
7171sysopen_func(
void *ptr)
7174 const char *fname = RSTRING_PTR(data->fname);
7183 fd = IO_WITHOUT_GVL_INT(sysopen_func, data);
7184 }
while (fd < 0 &&
errno == EINTR);
7191rb_sysopen(
VALUE fname,
int oflags, mode_t perm)
7196 data.fname = rb_str_encode_ospath(fname);
7198 data.oflags = oflags;
7201 TRY_WITH_GC((fd = rb_sysopen_internal(&data)) >= 0) {
7202 rb_syserr_fail_path(first_errno, fname);
7208fdopen_internal(
int fd,
const char *modestr)
7215 file = fdopen(fd, modestr);
7231 TRY_WITH_GC((file = fdopen_internal(fd, modestr)) != 0) {
7237 if (setvbuf(file, NULL, _IOFBF, 0) != 0)
7238 rb_warn(
"setvbuf() can't be honoured (fd=%d)", fd);
7246 int t = isatty(fptr->
fd);
7256io_strip_bom(
VALUE io)
7258 VALUE b1, b2, b3, b4;
7269 return rb_utf8_encindex();
7279 return ENCINDEX_UTF_16BE;
7290 return ENCINDEX_UTF_32LE;
7295 return ENCINDEX_UTF_16LE;
7305 return ENCINDEX_UTF_32BE;
7319io_set_encoding_by_bom(
VALUE io)
7321 int idx = io_strip_bom(io);
7327 extenc = rb_enc_from_index(idx);
7328 io_encoding_set(fptr, rb_enc_from_encoding(extenc),
7329 rb_io_internal_encoding(io),
Qnil);
7338rb_file_open_generic(
VALUE io,
VALUE filename,
int oflags,
enum rb_io_mode fmode,
7346 rb_io_ext_int_to_encs(NULL, NULL, &cc.enc, &cc.enc2, fmode);
7351 validate_enc_binmode(&fmode, convconfig->
ecflags,
7352 convconfig->
enc, convconfig->
enc2);
7356 fptr->
encs = *convconfig;
7359 if (!(oflags & O_TMPFILE)) {
7360 fptr->
pathv = pathv;
7363 fptr->
pathv = pathv;
7365 fptr->
fd = rb_sysopen(pathv, oflags, perm);
7373rb_file_open_internal(
VALUE io,
VALUE filename,
const char *modestr)
7376 const char *p = strchr(modestr,
':');
7380 parse_mode_enc(p+1, rb_usascii_encoding(),
7381 &convconfig.
enc, &convconfig.
enc2, &fmode);
7387 e = (fmode &
FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
7388 rb_io_ext_int_to_encs(e, NULL, &convconfig.
enc, &convconfig.
enc2, fmode);
7394#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7396 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7397 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7399 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.
enc2, convconfig.
ecflags);
7402 return rb_file_open_generic(io, filename,
7403 rb_io_fmode_oflags(fmode),
7413 return rb_file_open_internal(io_alloc(
rb_cFile), fname, modestr);
7422#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7445 while ((tmp = *prev) != 0) {
7446 if (tmp->fptr == fptr) {
7455#if defined (_WIN32) || defined(__CYGWIN__)
7471pipe_finalize(
rb_io_t *fptr,
int noraise)
7473#if !defined(HAVE_WORKING_FORK) && !defined(_WIN32)
7482 fptr_finalize(fptr, noraise);
7484 pipe_del_fptr(fptr);
7491#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7492 void (*
const old_finalize)(
struct rb_io*,int) = fptr->
finalize;
7494 if (old_finalize == orig->finalize)
return;
7499#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7500 if (old_finalize != pipe_finalize) {
7502 for (list =
pipe_list; list; list = list->next) {
7503 if (list->fptr == fptr)
break;
7505 if (!list) pipe_add_fptr(fptr);
7508 pipe_del_fptr(fptr);
7534#define HAVE_SPAWNV 1
7535#define spawnv(mode, cmd, args) rb_w32_uaspawn((mode), (cmd), (args))
7536#define spawn(mode, cmd) rb_w32_uspawn((mode), (cmd), 0)
7539#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7549#ifdef HAVE_WORKING_FORK
7550# ifndef __EMSCRIPTEN__
7552popen_redirect(
struct popen_arg *p)
7555 close(p->write_pair[1]);
7556 if (p->write_pair[0] != 0) {
7557 dup2(p->write_pair[0], 0);
7558 close(p->write_pair[0]);
7561 if (p->pair[1] != 1) {
7562 dup2(p->pair[1], 1);
7568 if (p->pair[1] != 1) {
7569 dup2(p->pair[1], 1);
7575 if (p->pair[0] != 0) {
7576 dup2(p->pair[0], 0);
7583#if defined(__linux__)
7594linux_get_maxfd(
void)
7597 char buf[4096], *p, *np, *e;
7600 if (fd < 0)
return fd;
7601 ss = read(fd, buf,
sizeof(buf));
7602 if (ss < 0)
goto err;
7605 while ((
int)
sizeof(
"FDSize:\t0\n")-1 <= e-p &&
7606 (np = memchr(p,
'\n', e-p)) != NULL) {
7607 if (memcmp(p,
"FDSize:",
sizeof(
"FDSize:")-1) == 0) {
7609 p +=
sizeof(
"FDSize:")-1;
7629#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
7631 int max = (int)max_file_descriptor;
7634 ret = fcntl(0, F_MAXFD);
7636 maxhint = max = ret;
7637# elif defined(__linux__)
7638 ret = linux_get_maxfd();
7645 for (fd = lowfd; fd <= max; fd++) {
7646 if (!
NIL_P(noclose_fds) &&
7649 ret = fcntl(fd, F_GETFD);
7650 if (ret != -1 && !(ret & FD_CLOEXEC)) {
7651 fcntl(fd, F_SETFD, ret|FD_CLOEXEC);
7653# define CONTIGUOUS_CLOSED_FDS 20
7655 if (max < fd + CONTIGUOUS_CLOSED_FDS)
7656 max = fd + CONTIGUOUS_CLOSED_FDS;
7662# ifndef __EMSCRIPTEN__
7664popen_exec(
void *pp,
char *errmsg,
size_t errmsg_len)
7666 struct popen_arg *p = (
struct popen_arg*)pp;
7668 return rb_exec_async_signal_safe(p->eargp, errmsg, errmsg_len);
7673#if (defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)) && !defined __EMSCRIPTEN__
7675rb_execarg_fixup_v(
VALUE execarg_obj)
7677 rb_execarg_parent_start(execarg_obj);
7681char *rb_execarg_commandline(
const struct rb_execarg *eargp,
VALUE *prog);
7684#ifndef __EMSCRIPTEN__
7686pipe_open(
VALUE execarg_obj,
const char *modestr,
enum rb_io_mode fmode,
7689 struct rb_execarg *eargp =
NIL_P(execarg_obj) ? NULL : rb_execarg_get(execarg_obj);
7690 VALUE prog = eargp ? (eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name) :
Qfalse ;
7696#if defined(HAVE_WORKING_FORK)
7698 char errmsg[80] = {
'\0' };
7700#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7702 struct popen_arg arg;
7705#if defined(HAVE_SPAWNV)
7706# if defined(HAVE_SPAWNVE)
7707# define DO_SPAWN(cmd, args, envp) ((args) ? \
7708 spawnve(P_NOWAIT, (cmd), (args), (envp)) : \
7709 spawne(P_NOWAIT, (cmd), (envp)))
7711# define DO_SPAWN(cmd, args, envp) ((args) ? \
7712 spawnv(P_NOWAIT, (cmd), (args)) : \
7713 spawn(P_NOWAIT, (cmd)))
7715# if !defined(HAVE_WORKING_FORK)
7717# if defined(HAVE_SPAWNVE)
7722#if !defined(HAVE_WORKING_FORK)
7728#if !defined(HAVE_WORKING_FORK)
7729 const char *cmd = 0;
7735#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7736 arg.execarg_obj = execarg_obj;
7739 arg.pair[0] = arg.pair[1] = -1;
7740 arg.write_pair[0] = arg.write_pair[1] = -1;
7741# if !defined(HAVE_WORKING_FORK)
7742 if (eargp && !eargp->use_shell) {
7743 args = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
7748 if (
rb_pipe(arg.write_pair) < 0)
7749 rb_sys_fail_str(prog);
7752 close(arg.write_pair[0]);
7753 close(arg.write_pair[1]);
7757 rb_execarg_addopt(execarg_obj,
INT2FIX(0),
INT2FIX(arg.write_pair[0]));
7758 rb_execarg_addopt(execarg_obj,
INT2FIX(1),
INT2FIX(arg.pair[1]));
7763 rb_sys_fail_str(prog);
7765 rb_execarg_addopt(execarg_obj,
INT2FIX(1),
INT2FIX(arg.pair[1]));
7769 rb_sys_fail_str(prog);
7771 rb_execarg_addopt(execarg_obj,
INT2FIX(0),
INT2FIX(arg.pair[0]));
7774 rb_sys_fail_str(prog);
7776 if (!
NIL_P(execarg_obj)) {
7777 rb_protect(rb_execarg_fixup_v, execarg_obj, &state);
7779 if (0 <= arg.write_pair[0]) close(arg.write_pair[0]);
7780 if (0 <= arg.write_pair[1]) close(arg.write_pair[1]);
7781 if (0 <= arg.pair[0]) close(arg.pair[0]);
7782 if (0 <= arg.pair[1]) close(arg.pair[1]);
7783 rb_execarg_parent_end(execarg_obj);
7787# if defined(HAVE_WORKING_FORK)
7788 pid = rb_fork_async_signal_safe(&status, popen_exec, &arg, arg.eargp->redirect_fds, errmsg,
sizeof(errmsg));
7790 rb_execarg_run_options(eargp, sargp, NULL, 0);
7791# if defined(HAVE_SPAWNVE)
7792 if (eargp->envp_str) envp = (
char **)RSTRING_PTR(eargp->envp_str);
7794 while ((pid = DO_SPAWN(cmd, args, envp)) < 0) {
7796 switch (e =
errno) {
7798# if EWOULDBLOCK != EAGAIN
7807 rb_execarg_run_options(sargp, NULL, NULL, 0);
7809 rb_execarg_parent_end(execarg_obj);
7812# if defined(HAVE_WORKING_FORK)
7813 pid = rb_call_proc__fork();
7815 popen_redirect(&arg);
7827# if defined(HAVE_WORKING_FORK)
7833 close(arg.write_pair[0]);
7834 close(arg.write_pair[1]);
7836# if defined(HAVE_WORKING_FORK)
7845 close(arg.write_pair[0]);
7846 write_fd = arg.write_pair[1];
7857 cmd = rb_execarg_commandline(eargp, &prog);
7858 if (!
NIL_P(execarg_obj)) {
7859 rb_execarg_parent_start(execarg_obj);
7860 rb_execarg_run_options(eargp, sargp, NULL, 0);
7862 fp = popen(cmd, modestr);
7865 rb_execarg_parent_end(execarg_obj);
7866 rb_execarg_run_options(sargp, NULL, NULL, 0);
7868 if (!fp) rb_syserr_fail_path(e, prog);
7878 fptr->
encs = *convconfig;
7879#if RUBY_CRLF_ENVIRONMENT
7886 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
7889#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7890 if (NEED_NEWLINE_DECORATOR_ON_WRITE(fptr)) {
7891 fptr->
encs.
ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
7897 if (0 <= write_fd) {
7898 write_port = io_alloc(
rb_cIO);
7900 write_fptr->
fd = write_fd;
7902 fptr->
mode &= ~FMODE_WRITABLE;
7904 rb_ivar_set(port, rb_intern(
"@tied_io_for_writing"), write_port);
7907#if defined (__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7909 pipe_add_fptr(fptr);
7915pipe_open(
VALUE execarg_obj,
const char *modestr,
enum rb_io_mode fmode,
7923is_popen_fork(
VALUE prog)
7925 if (RSTRING_LEN(prog) == 1 && RSTRING_PTR(prog)[0] ==
'-') {
7926#if !defined(HAVE_WORKING_FORK)
7928 "fork() function is unimplemented on this machine");
7937pipe_open_s(
VALUE prog,
const char *modestr,
enum rb_io_mode fmode,
7941 VALUE *argv = &prog;
7944 if (!is_popen_fork(prog))
7945 execarg_obj = rb_execarg_new(argc, argv, TRUE, FALSE);
7946 return pipe_open(execarg_obj, modestr, fmode, convconfig);
7952 rb_io_t *fptr = io_close_fptr(io);
8121rb_io_s_popen(
int argc,
VALUE *argv,
VALUE klass)
8125 if (argc > 1 && !
NIL_P(opt = rb_check_hash_type(argv[argc-1]))) --argc;
8126 if (argc > 1 && !
NIL_P(env = rb_check_hash_type(argv[0]))) --argc, ++argv;
8135 int ex = !
NIL_P(opt);
8136 rb_error_arity(argc + ex, 1 + ex, 2 + ex);
8139 return popen_finish(rb_io_popen(pname, pmode, env, opt), klass);
8145 const char *modestr;
8148 enum rb_io_mode fmode;
8154#if SIZEOF_LONG > SIZEOF_INT
8155 if (
len > INT_MAX) {
8156 rb_raise(rb_eArgError,
"too many arguments");
8165 if (!is_popen_fork(pname))
8166 execarg_obj = rb_execarg_new(1, &pname, TRUE, FALSE);
8168 if (!
NIL_P(execarg_obj)) {
8170 opt = rb_execarg_extract_options(execarg_obj, opt);
8172 rb_execarg_setenv(execarg_obj, env);
8175 modestr = rb_io_oflags_modestr(oflags);
8177 return pipe_open(execarg_obj, modestr, fmode, &convconfig);
8187 rb_io_flush(rb_ractor_stdout());
8188 rb_io_flush(rb_ractor_stderr());
8189 _exit(EXIT_SUCCESS);
8193 RBASIC_SET_CLASS(port, klass);
8200#if defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)
8201struct popen_writer_arg {
8203 struct popen_arg popen;
8207exec_popen_writer(
void *arg,
char *errmsg,
size_t buflen)
8209 struct popen_writer_arg *pw = arg;
8211 popen_redirect(&pw->popen);
8212 execv(pw->argv[0], pw->argv);
8213 strlcpy(errmsg, strerror(
errno), buflen);
8219ruby_popen_writer(
char *
const *argv, rb_pid_t *pid)
8221#if (defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)) || defined(_WIN32)
8222# ifdef HAVE_WORKING_FORK
8223 struct popen_writer_arg pw;
8224 int *
const write_pair = pw.popen.pair;
8230 if (cloexec_pipe(write_pair, 0,
false) == 0) {
8231# ifdef HAVE_WORKING_FORK
8234 char errmsg[80] = {
'\0'};
8235 *pid = rb_fork_async_signal_safe(&status, exec_popen_writer, &pw,
Qnil, errmsg,
sizeof(errmsg));
8237 *pid = rb_w32_uspawn_process(P_NOWAIT, argv[0], argv, write_pair[0], -1, -1, 0);
8238 const char *errmsg = (*pid < 0) ? strerror(
errno) : NULL;
8240 close(write_pair[0]);
8242 close(write_pair[1]);
8243 fprintf(stderr,
"ruby_popen_writer(%s): %s\n", argv[0], errmsg);
8246 return fdopen(write_pair[1],
"w");
8257 enum rb_io_mode fmode;
8266 rb_file_open_generic(io, fname, oflags, fmode, &convconfig, perm);
8318rb_io_s_open(
int argc,
VALUE *argv,
VALUE klass)
8350 VALUE fname, vmode, vperm;
8355 rb_scan_args(argc, argv,
"12", &fname, &vmode, &vperm);
8366 if (
NIL_P(vperm)) perm = 0666;
8370 fd = rb_sysopen(fname, oflags, perm);
8402 int redirect = FALSE;
8410 VALUE tmp = argv[0];
8428 return rb_io_s_open(argc, argv,
rb_cFile);
8432rb_io_open_generic(
VALUE klass,
VALUE filename,
int oflags,
enum rb_io_mode fmode,
8435 return rb_file_open_generic(io_alloc(klass), filename,
8436 oflags, fmode, convconfig, perm);
8443 enum rb_io_mode fmode;
8449 return rb_io_open_generic(io, filename, oflags, fmode, &convconfig, perm);
8463 if (fptr == orig)
return io;
8464 if (RUBY_IO_EXTERNAL_P(fptr)) {
8468 rb_raise(rb_eArgError,
8469 "%s can't change access mode from \"%s\" to \"%s\"",
8470 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->
mode),
8471 rb_io_fmode_modestr(orig->
mode));
8474 flush_before_seek(fptr,
true);
8476 clear_codeconv(fptr);
8478 pos = io_tell(orig);
8481 if (io_fflush(orig) < 0)
8482 rb_sys_fail_on_write(fptr);
8491 else if (!RUBY_IO_EXTERNAL_P(fptr)) fptr->
pathv =
Qnil;
8492 fptr_copy_finalizer(fptr, orig);
8498 rb_thread_io_close_interrupt(fptr);
8499 rb_thread_io_close_wait(fptr);
8501 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2 || !fptr->stdio_file) {
8504 rb_sys_fail_path(orig->
pathv);
8512 rb_sys_fail_path(orig->
pathv);
8518 if (io_seek(fptr, pos, SEEK_SET) < 0 &&
errno) {
8519 rb_sys_fail_path(fptr->
pathv);
8521 if (io_seek(orig, pos, SEEK_SET) < 0 &&
errno) {
8522 rb_sys_fail_path(orig->
pathv);
8536int rb_freopen(
VALUE fname,
const char *mode,
FILE *fp);
8539rb_freopen(
VALUE fname,
const char *mode,
FILE *fp)
8541 if (!freopen(RSTRING_PTR(fname), mode, fp)) {
8584rb_io_reopen(
int argc,
VALUE *argv,
VALUE file)
8586 VALUE fname, nmode, opt;
8590 if (
rb_scan_args(argc, argv,
"11:", &fname, &nmode, &opt) == 1) {
8593 return io_reopen(file, tmp);
8599 fptr =
RFILE(file)->fptr;
8605 enum rb_io_mode fmode;
8609 if (RUBY_IO_EXTERNAL_P(fptr) &&
8612 rb_raise(rb_eArgError,
8613 "%s can't change access mode from \"%s\" to \"%s\"",
8614 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->
mode),
8615 rb_io_fmode_modestr(fmode));
8618 fptr->
encs = convconfig;
8621 oflags = rb_io_fmode_oflags(fptr->
mode);
8624 fptr->
pathv = fname;
8626 fptr->
fd = rb_sysopen(fptr->
pathv, oflags, 0666);
8632 if (io_fflush(fptr) < 0)
8633 rb_sys_fail_on_write(fptr);
8636 clear_codeconv(fptr);
8639 int e = rb_freopen(rb_str_encode_ospath(fptr->
pathv),
8640 rb_io_oflags_modestr(oflags),
8642 if (e) rb_syserr_fail_path(e, fptr->
pathv);
8646 if (setvbuf(fptr->
stdio_file, NULL, _IOFBF, 0) != 0)
8647 rb_warn(
"setvbuf() can't be honoured for %"PRIsVALUE, fptr->
pathv);
8650 if (setvbuf(fptr->
stdio_file, NULL, _IONBF, BUFSIZ) != 0)
8651 rb_warn(
"setvbuf() can't be honoured for %"PRIsVALUE, fptr->
pathv);
8653 else if (fptr->
stdio_file == stdout && isatty(fptr->
fd)) {
8654 if (setvbuf(fptr->
stdio_file, NULL, _IOLBF, BUFSIZ) != 0)
8655 rb_warn(
"setvbuf() can't be honoured for %"PRIsVALUE, fptr->
pathv);
8659 int tmpfd = rb_sysopen(fptr->
pathv, oflags, 0666);
8665 rb_syserr_fail_path(err, fptr->
pathv);
8689 fptr->
mode = orig->
mode & ~FMODE_EXTERNAL;
8696 fptr->closing_ec = NULL;
8697 fptr->wakeup_mutex =
Qnil;
8698 fptr->fork_generation = GET_VM()->fork_gen;
8701 fptr_copy_finalizer(fptr, orig);
8703 fd = ruby_dup(orig->
fd);
8705 pos = io_tell(orig);
8707 io_seek(fptr, pos, SEEK_SET);
8712 write_io = GetWriteIO(io);
8713 if (io != write_io) {
8716 rb_ivar_set(dest, rb_intern(
"@tied_io_for_writing"), write_io);
8779 if (argc == 0)
return Qnil;
8781 out = rb_ractor_stdout();
8793extern void rb_deprecated_str_setter(
VALUE val,
ID id,
VALUE *var);
8798 rb_deprecated_str_setter(val,
id, &val);
8804 val = rb_str_frozen_bare_string(val);
8881 for (i=0; i<argc; i++) {
8885 rb_io_write(out, argv[i]);
8982 rb_io_write(io, str);
8986#define forward(obj, id, argc, argv) \
8987 rb_funcallv_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8988#define forward_public(obj, id, argc, argv) \
8989 rb_funcallv_public_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8990#define forward_current(id, argc, argv) \
8991 forward_public(ARGF.current_file, id, argc, argv)
9008 VALUE r_stdout = rb_ractor_stdout();
9009 if (recv == r_stdout) {
9010 return rb_io_putc(recv, ch);
9012 return forward(r_stdout, rb_intern(
"putc"), 1, &ch);
9017rb_str_end_with_asciichar(
VALUE str,
int c)
9019 long len = RSTRING_LEN(str);
9020 const char *
ptr = RSTRING_PTR(str);
9024 if (
len == 0)
return 0;
9025 if ((n = rb_enc_mbminlen(
enc)) == 1) {
9026 return ptr[
len - 1] == c;
9028 return rb_enc_ascget(
ptr + ((
len - 1) / n) * n,
ptr +
len, &n,
enc) == c;
9039 rb_io_puts(1, &tmp, out);
9046 rb_io_puts(1, &tmp, out);
9101 VALUE line, args[2];
9108 for (
int i = 0; i < argc; i++) {
9122 if (RSTRING_LEN(line) == 0) {
9127 if (!rb_str_end_with_asciichar(line,
'\n')) {
9132 rb_io_writev(out, n, args);
9150 VALUE r_stdout = rb_ractor_stdout();
9151 if (recv == r_stdout) {
9152 return rb_io_puts(argc, argv, recv);
9154 return forward(r_stdout, rb_intern(
"puts"), argc, argv);
9158rb_p_write(
VALUE str)
9163 VALUE r_stdout = rb_ractor_stdout();
9166 io_writev(2, args, r_stdout);
9169 rb_io_writev(r_stdout, 2, args);
9181rb_p_result(
int argc,
const VALUE *argv)
9188 else if (argc > 1) {
9191 VALUE r_stdout = rb_ractor_stdout();
9193 rb_uninterruptible(rb_io_flush, r_stdout);
9234 for (i=0; i<argc; i++) {
9236 rb_uninterruptible(rb_p_write, inspected);
9238 return rb_p_result(argc, argv);
9259rb_obj_display(
int argc,
VALUE *argv,
VALUE self)
9263 out = (!
rb_check_arity(argc, 0, 1) ? rb_ractor_stdout() : argv[0]);
9264 rb_io_write(out, self);
9270rb_stderr_to_original_p(
VALUE err)
9272 return (err == orig_stderr ||
RFILE(orig_stderr)->fptr->
fd < 0);
9278 VALUE out = rb_ractor_stderr();
9279 if (rb_stderr_to_original_p(out)) {
9281 if (isatty(fileno(stderr))) {
9282 if (rb_w32_write_console(
rb_str_new(mesg,
len), fileno(stderr)) > 0)
return;
9285 if (fwrite(mesg,
sizeof(
char), (
size_t)
len, stderr) < (
size_t)
len) {
9302rb_write_error_str(
VALUE mesg)
9304 VALUE out = rb_ractor_stderr();
9306 if (rb_stderr_to_original_p(out)) {
9307 size_t len = (size_t)RSTRING_LEN(mesg);
9309 if (isatty(fileno(stderr))) {
9310 if (rb_w32_write_console(mesg, fileno(stderr)) > 0)
return;
9313 if (fwrite(RSTRING_PTR(mesg),
sizeof(
char),
len, stderr) <
len) {
9320 rb_io_write(out, mesg);
9325rb_stderr_tty_p(
void)
9327 if (rb_stderr_to_original_p(rb_ractor_stderr()))
9328 return isatty(fileno(stderr));
9333must_respond_to(
ID mid,
VALUE val,
ID id)
9336 rb_raise(
rb_eTypeError,
"%"PRIsVALUE
" must have %"PRIsVALUE
" method, %"PRIsVALUE
" given",
9337 rb_id2str(
id), rb_id2str(mid),
9357 must_respond_to(id_write, val,
id);
9364 return rb_ractor_stdout();
9370 must_respond_to(id_write, val,
id);
9377 return rb_ractor_stderr();
9381allocate_and_open_new_file(
VALUE klass)
9383 VALUE self = io_alloc(klass);
9384 rb_io_make_open_file(self);
9392 VALUE self = rb_protect(allocate_and_open_new_file, klass, &state);
9400 maygvl_close(descriptor, 0);
9408 io->
fd = descriptor;
9426 io->closing_ec = NULL;
9427 io->wakeup_mutex =
Qnil;
9428 io->fork_generation = GET_VM()->fork_gen;
9431 io->
encs = *encoding;
9440prep_io(
int fd,
enum rb_io_mode fmode,
VALUE klass,
const char *path)
9450 e = (fmode &
FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
9451 rb_io_ext_int_to_encs(e, NULL, &convconfig.
enc, &convconfig.
enc2, fmode);
9455#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9457 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
9458 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
9460 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.
enc2, convconfig.
ecflags);
9466 if (!io_check_tty(io)) {
9469 setmode(fd, O_BINARY);
9481 if (path && strcmp(path,
"-")) klass =
rb_cFile;
9482 return prep_io(fd, rb_io_oflags_fmode(oflags), klass, path);
9486prep_stdio(
FILE *f,
enum rb_io_mode fmode,
VALUE klass,
const char *path)
9493#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9494 fptr->
encs.
ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
9505rb_io_prep_stdin(
void)
9511rb_io_prep_stdout(
void)
9517rb_io_prep_stderr(
void)
9526 int oflags = rb_io_fmode_oflags(fptr->
mode) & ~O_EXCL;
9553 rb_io_buffer_init(&fp->
wbuf);
9554 rb_io_buffer_init(&fp->
rbuf);
9555 rb_io_buffer_init(&fp->
cbuf);
9570 fp->closing_ec = NULL;
9571 fp->wakeup_mutex =
Qnil;
9572 fp->fork_generation = GET_VM()->fork_gen;
9577rb_io_make_open_file(
VALUE obj)
9582 if (
RFILE(obj)->fptr) {
9585 RFILE(obj)->fptr = 0;
9587 fp = rb_io_fptr_new();
9589 RFILE(obj)->fptr = fp;
9638rb_io_initialize(
int argc,
VALUE *argv,
VALUE io)
9644 return io_initialize(io, fnum, vmode, opt);
9651 int fd, oflags = O_RDONLY;
9652 enum rb_io_mode fmode;
9654#if defined(HAVE_FCNTL) && defined(F_GETFL)
9664 rb_raise(rb_eArgError,
"The given fd is not accessible because RubyVM reserves it");
9666#if defined(HAVE_FCNTL) && defined(F_GETFL)
9667 oflags = fcntl(fd, F_GETFL);
9668 if (oflags == -1) rb_sys_fail(0);
9670 if (fstat(fd, &st) < 0) rb_sys_fail(0);
9673#if defined(HAVE_FCNTL) && defined(F_GETFL)
9674 ofmode = rb_io_oflags_fmode(oflags);
9686 if (rb_hash_aref(opt, sym_autoclose) ==
Qfalse) {
9690 path = rb_hash_aref(opt,
RB_ID2SYM(idPath));
9701 fp->
encs = convconfig;
9705 fp->closing_ec = NULL;
9706 fp->wakeup_mutex =
Qnil;
9707 fp->fork_generation = GET_VM()->fork_gen;
9710 if (fileno(stdin) == fd)
9712 else if (fileno(stdout) == fd)
9714 else if (fileno(stderr) == fd)
9746rb_io_set_encoding_by_bom(
VALUE io)
9752 rb_raise(rb_eArgError,
"ASCII incompatible encoding needs binmode");
9755 rb_raise(rb_eArgError,
"encoding conversion is set");
9757 else if (fptr->
encs.
enc && fptr->
encs.
enc != rb_ascii8bit_encoding()) {
9758 rb_raise(rb_eArgError,
"encoding is set to %s already",
9761 if (!io_set_encoding_by_bom(io))
return Qnil;
9762 return rb_enc_from_encoding(fptr->
encs.
enc);
9815rb_file_initialize(
int argc,
VALUE *argv,
VALUE io)
9817 if (
RFILE(io)->fptr) {
9820 VALUE fname, vmode, vperm, opt;
9821 int posargc =
rb_scan_args(argc, argv,
"12:", &fname, &vmode, &vperm, &opt);
9826 return io_initialize(io, fd, vmode, opt);
9829 return rb_open_file(io, fname, vmode, vperm, opt);
9834rb_io_s_new(
int argc,
VALUE *argv,
VALUE klass)
9839 rb_warn(
"%"PRIsVALUE
"::new() does not take block; use %"PRIsVALUE
"::open() instead",
9855rb_io_s_for_fd(
int argc,
VALUE *argv,
VALUE klass)
9858 rb_io_initialize(argc, argv, io);
9871rb_io_autoclose_p(
VALUE io)
9896rb_io_set_autoclose(
VALUE io,
VALUE autoclose)
9900 if (!
RTEST(autoclose))
9903 fptr->
mode &= ~FMODE_EXTERNAL;
9908io_wait_event(
VALUE io,
int event,
VALUE timeout,
int return_io)
9940io_wait_readable(
int argc,
VALUE *argv,
VALUE io)
9947 if (rb_io_read_pending(fptr))
return Qtrue;
9950 VALUE timeout = (argc == 1 ? argv[0] :
Qnil);
9964io_wait_writable(
int argc,
VALUE *argv,
VALUE io)
9972 VALUE timeout = (argc == 1 ? argv[0] :
Qnil);
9987io_wait_priority(
int argc,
VALUE *argv,
VALUE io)
9994 if (rb_io_read_pending(fptr))
return Qtrue;
9997 VALUE timeout = argc == 1 ? argv[0] :
Qnil;
10003wait_mode_sym(
VALUE mode)
10005 if (mode ==
ID2SYM(rb_intern(
"r"))) {
10006 return RB_WAITFD_IN;
10008 if (mode ==
ID2SYM(rb_intern(
"read"))) {
10009 return RB_WAITFD_IN;
10011 if (mode ==
ID2SYM(rb_intern(
"readable"))) {
10012 return RB_WAITFD_IN;
10014 if (mode ==
ID2SYM(rb_intern(
"w"))) {
10015 return RB_WAITFD_OUT;
10017 if (mode ==
ID2SYM(rb_intern(
"write"))) {
10018 return RB_WAITFD_OUT;
10020 if (mode ==
ID2SYM(rb_intern(
"writable"))) {
10021 return RB_WAITFD_OUT;
10023 if (mode ==
ID2SYM(rb_intern(
"rw"))) {
10024 return RB_WAITFD_IN|RB_WAITFD_OUT;
10026 if (mode ==
ID2SYM(rb_intern(
"read_write"))) {
10027 return RB_WAITFD_IN|RB_WAITFD_OUT;
10029 if (mode ==
ID2SYM(rb_intern(
"readable_writable"))) {
10030 return RB_WAITFD_IN|RB_WAITFD_OUT;
10033 rb_raise(rb_eArgError,
"unsupported mode: %"PRIsVALUE, mode);
10037io_event_from_value(
VALUE value)
10041 if (events <= 0) rb_raise(rb_eArgError,
"Events must be positive integer!");
10079 for (
int i = 0; i < argc; i += 1) {
10081 events |= wait_mode_sym(argv[i]);
10083 else if (UNDEF_P(timeout)) {
10087 rb_raise(rb_eArgError,
"timeout given more than once");
10091 if (UNDEF_P(timeout)) timeout =
Qnil;
10099 events = io_event_from_value(argv[0]);
10107 if (rb_io_read_pending(fptr)) {
10109 if (return_io)
return Qtrue;
10115 return io_wait_event(io, events, timeout, return_io);
10119argf_mark_and_move(
void *ptr)
10121 struct argf *p = ptr;
10122 rb_gc_mark_and_move(&p->filename);
10123 rb_gc_mark_and_move(&p->current_file);
10124 rb_gc_mark_and_move(&p->argv);
10125 rb_gc_mark_and_move(&p->inplace);
10126 rb_gc_mark_and_move(&p->encs.
ecopts);
10130argf_memsize(
const void *ptr)
10132 const struct argf *p = ptr;
10133 size_t size =
sizeof(*p);
10140 0, 0, RUBY_TYPED_THREAD_SAFE_FREE | RUBY_TYPED_WB_PROTECTED
10146 p->filename =
Qnil;
10147 p->current_file =
Qnil;
10153argf_alloc(
VALUE klass)
10168 memset(&ARGF, 0,
sizeof(ARGF));
10169 argf_init(
argf, &ARGF, argv);
10179 ARGF = argf_of(orig);
10180 rb_gc_writebarrier_remember(
argf);
10207 ARGF.last_lineno = ARGF.lineno;
10233 return forward_current(rb_frame_this_func(), argc, argv);
10236#define next_argv() argf_next_argv(argf)
10237#define ARGF_GENERIC_INPUT_P() \
10238 (ARGF.current_file == rb_stdin && !RB_TYPE_P(ARGF.current_file, T_FILE))
10239#define ARGF_FORWARD(argc, argv) do {\
10240 if (ARGF_GENERIC_INPUT_P())\
10241 return argf_forward((argc), (argv), argf);\
10243#define NEXT_ARGF_FORWARD(argc, argv) do {\
10244 if (!next_argv()) return Qnil;\
10245 ARGF_FORWARD((argc), (argv));\
10251 VALUE file = ARGF.current_file;
10265 int stdout_binmode = 0;
10266 enum rb_io_mode fmode;
10268 VALUE r_stdout = rb_ractor_stdout();
10273 stdout_binmode = 1;
10276 if (ARGF.init_p == 0) {
10286 if (
NIL_P(ARGF.argv)) {
10289 else if (ARGF.next_p == -1 &&
RARRAY_LEN(ARGF.argv) > 0) {
10294 if (ARGF.next_p == 1) {
10295 if (ARGF.init_p == 1) argf_close(
argf);
10300 ARGF_SET(filename, filename);
10301 filename = rb_str_encode_ospath(filename);
10303 if (RSTRING_LEN(filename) == 1 && fn[0] ==
'-') {
10305 if (ARGF.inplace) {
10306 rb_warn(
"Can't do inplace edit for stdio; skipping");
10312 int fr = rb_sysopen(filename, O_RDONLY, 0);
10314 if (ARGF.inplace) {
10316#ifndef NO_SAFE_RENAME
10327 if (!
NIL_P(ARGF.inplace)) {
10328 VALUE suffix = ARGF.inplace;
10330 if (
NIL_P(rb_str_cat_conv_enc_opts(str, RSTRING_LEN(str),
10331 RSTRING_PTR(suffix), RSTRING_LEN(suffix),
10332 rb_enc_get(suffix), 0,
Qnil))) {
10335#ifdef NO_SAFE_RENAME
10337 (void)unlink(RSTRING_PTR(str));
10338 if (rename(fn, RSTRING_PTR(str)) < 0) {
10339 rb_warn(
"Can't rename %"PRIsVALUE
" to %"PRIsVALUE
": %s, skipping file",
10340 filename, str, strerror(
errno));
10343 fr = rb_sysopen(str, O_RDONLY, 0);
10345 if (rename(fn, RSTRING_PTR(str)) < 0) {
10346 rb_warn(
"Can't rename %"PRIsVALUE
" to %"PRIsVALUE
": %s, skipping file",
10347 filename, str, strerror(
errno));
10354#ifdef NO_SAFE_RENAME
10355 rb_fatal(
"Can't do inplace edit without backup");
10357 if (unlink(fn) < 0) {
10358 rb_warn(
"Can't remove %"PRIsVALUE
": %s, skipping file",
10359 filename, strerror(
errno));
10365 fw = rb_sysopen(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666);
10366#ifndef NO_SAFE_RENAME
10369 fchmod(fw, st.st_mode);
10371 chmod(fn, st.st_mode);
10373 if (st.st_uid!=st2.st_uid || st.st_gid!=st2.st_gid) {
10376 err = fchown(fw, st.st_uid, st.st_gid);
10378 err = chown(fn, st.st_uid, st.st_gid);
10380 if (err && getuid() == 0 && st2.st_uid == 0) {
10381 const char *wkfn = RSTRING_PTR(filename);
10382 rb_warn(
"Can't set owner/group of %"PRIsVALUE
" to same as %"PRIsVALUE
": %s, skipping file",
10383 filename, str, strerror(
errno));
10386 (void)unlink(wkfn);
10396 if (!ARGF.binmode) {
10397 fmode |= DEFAULT_TEXTMODE;
10399 ARGF_SET(current_file, prep_io(fr, fmode,
rb_cFile, fn));
10400 if (!
NIL_P(write_io)) {
10407 if (ARGF.encs.enc) {
10408 fptr->
encs = ARGF.encs;
10409 clear_codeconv(fptr);
10412 fptr->
encs.
ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
10413 if (!ARGF.binmode) {
10415#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
10416 fptr->
encs.
ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
10427 else if (ARGF.next_p == -1) {
10430 if (ARGF.inplace) {
10431 rb_warn(
"Can't do inplace edit for stdio");
10435 if (ARGF.init_p == -1) ARGF.init_p = 1;
10443 long lineno = ARGF.lineno;
10446 if (!next_argv())
return Qnil;
10447 if (ARGF_GENERIC_INPUT_P()) {
10448 line = forward_current(idGets, argc, argv);
10455 line = rb_io_getline(argc, argv, ARGF.current_file);
10457 if (
NIL_P(line) && ARGF.next_p != -1) {
10463 if (!
NIL_P(line)) {
10464 ARGF.lineno = ++lineno;
10465 ARGF.last_lineno = ARGF.lineno;
10471argf_lineno_getter(
ID id,
VALUE *var)
10474 return INT2FIX(ARGF.last_lineno);
10482 ARGF.last_lineno = ARGF.lineno = n;
10486rb_reset_argf_lineno(
long n)
10488 ARGF.last_lineno = ARGF.lineno = n;
10529 if (recv ==
argf) {
10530 return argf_gets(argc, argv,
argf);
10532 return forward(
argf, idGets, argc, argv);
10558 line = argf_getline(argc, argv,
argf);
10570 return rb_f_gets(0, 0,
argf);
10574 if (!next_argv())
return Qnil;
10576 if (
NIL_P(line) && ARGF.next_p != -1) {
10582 if (!
NIL_P(line)) {
10584 ARGF.last_lineno = ARGF.lineno;
10610rb_f_readline(
int argc,
VALUE *argv,
VALUE recv)
10612 if (recv ==
argf) {
10613 return argf_readline(argc, argv,
argf);
10615 return forward(
argf, rb_intern(
"readline"), argc, argv);
10641 if (!next_argv()) rb_eof_error();
10642 ARGF_FORWARD(argc, argv);
10643 line = argf_gets(argc, argv,
argf);
10713rb_f_readlines(
int argc,
VALUE *argv,
VALUE recv)
10715 if (recv ==
argf) {
10716 return argf_readlines(argc, argv,
argf);
10718 return forward(
argf, rb_intern(
"readlines"), argc, argv);
10742 long lineno = ARGF.lineno;
10746 while (next_argv()) {
10747 if (ARGF_GENERIC_INPUT_P()) {
10748 lines = forward_current(rb_intern(
"readlines"), argc, argv);
10751 lines = rb_io_readlines(argc, argv, ARGF.current_file);
10757 ARGF.last_lineno = ARGF.lineno;
10792 rb_last_status_clear();
10793 port = pipe_open_s(str,
"r",
FMODE_READABLE|DEFAULT_TEXTMODE, NULL);
10797 result = read_all(fptr, remain_size(fptr),
Qnil);
10799 rb_io_fptr_cleanup_all(fptr);
10805#ifdef HAVE_SYS_SELECT_H
10806#include <sys/select.h>
10820 if (!
NIL_P(read)) {
10825 if (READ_DATA_PENDING(fptr) || READ_CHAR_PENDING(fptr)) {
10829 if (max < fptr->fd) max = fptr->
fd;
10832 timerec.tv_sec = timerec.tv_usec = 0;
10840 if (!
NIL_P(write)) {
10846 if (max < fptr->fd) max = fptr->
fd;
10853 if (!
NIL_P(except)) {
10857 VALUE write_io = GetWriteIO(io);
10860 if (max < fptr->fd) max = fptr->
fd;
10861 if (io != write_io) {
10864 if (max < fptr->fd) max = fptr->
fd;
10879 if (!pending && n == 0)
return Qnil;
10904 VALUE write_io = GetWriteIO(io);
10917 VALUE write_io = GetWriteIO(io);
10922 else if (io != write_io) {
10935 VALUE read, write, except;
10941select_call(
VALUE arg)
10945 return select_internal(p->read, p->write, p->except, p->timeout, p->fdsets);
10949select_end(
VALUE arg)
10954 for (i = 0; i < numberof(p->fdsets); ++i)
10959static VALUE sym_normal, sym_sequential, sym_random,
10960 sym_willneed, sym_dontneed, sym_noreuse;
10962#ifdef HAVE_POSIX_FADVISE
10963struct io_advise_struct {
10971io_advise_internal(
void *arg)
10973 struct io_advise_struct *ptr = arg;
10974 return posix_fadvise(ptr->fd, ptr->offset, ptr->len, ptr->advice);
10978io_advise_sym_to_const(
VALUE sym)
10980#ifdef POSIX_FADV_NORMAL
10981 if (sym == sym_normal)
10982 return INT2NUM(POSIX_FADV_NORMAL);
10985#ifdef POSIX_FADV_RANDOM
10986 if (sym == sym_random)
10987 return INT2NUM(POSIX_FADV_RANDOM);
10990#ifdef POSIX_FADV_SEQUENTIAL
10991 if (sym == sym_sequential)
10992 return INT2NUM(POSIX_FADV_SEQUENTIAL);
10995#ifdef POSIX_FADV_WILLNEED
10996 if (sym == sym_willneed)
10997 return INT2NUM(POSIX_FADV_WILLNEED);
11000#ifdef POSIX_FADV_DONTNEED
11001 if (sym == sym_dontneed)
11002 return INT2NUM(POSIX_FADV_DONTNEED);
11005#ifdef POSIX_FADV_NOREUSE
11006 if (sym == sym_noreuse)
11007 return INT2NUM(POSIX_FADV_NOREUSE);
11014do_io_advise(
rb_io_t *fptr,
VALUE advice, rb_off_t offset, rb_off_t
len)
11017 struct io_advise_struct ias;
11020 num_adv = io_advise_sym_to_const(advice);
11026 if (
NIL_P(num_adv))
11030 ias.advice =
NUM2INT(num_adv);
11031 ias.offset = offset;
11034 rv = (int)rb_io_blocking_region(fptr, io_advise_internal, &ias);
11035 if (rv && rv != ENOSYS) {
11038 VALUE message = rb_sprintf(
"%"PRIsVALUE
" "
11042 fptr->
pathv, offset,
len, advice);
11052advice_arg_check(
VALUE advice)
11057 if (advice != sym_normal &&
11058 advice != sym_sequential &&
11059 advice != sym_random &&
11060 advice != sym_willneed &&
11061 advice != sym_dontneed &&
11062 advice != sym_noreuse) {
11063 rb_raise(
rb_eNotImpError,
"Unsupported advice: %+"PRIsVALUE, advice);
11101rb_io_advise(
int argc,
VALUE *argv,
VALUE io)
11108 advice_arg_check(advice);
11110 io = GetWriteIO(io);
11116#ifdef HAVE_POSIX_FADVISE
11117 return do_io_advise(fptr, advice,
off, l);
11119 ((void)
off, (
void)l);
11131 return isinf(f) && 0 < f;
11287rb_f_select(
int argc,
VALUE *argv,
VALUE obj)
11290 if (scheduler !=
Qnil) {
11293 if (!UNDEF_P(result))
return result;
11301 rb_scan_args(argc, argv,
"13", &args.read, &args.write, &args.except, &timeout);
11302 if (
NIL_P(timeout) || is_pos_inf(timeout)) {
11307 args.timeout = &timerec;
11310 for (i = 0; i < numberof(args.fdsets); ++i)
11316#ifdef IOCTL_REQ_TYPE
11317 typedef IOCTL_REQ_TYPE ioctl_req_t;
11319 typedef int ioctl_req_t;
11320# define NUM2IOCTLREQ(num) ((int)NUM2LONG(num))
11331nogvl_ioctl(
void *ptr)
11333 struct ioctl_arg *arg = ptr;
11335 return (
VALUE)ioctl(arg->fd, arg->cmd, arg->narg);
11339do_ioctl(
struct rb_io *io, ioctl_req_t cmd,
long narg)
11342 struct ioctl_arg arg;
11348 retval = (int)rb_io_blocking_region(io, nogvl_ioctl, &arg);
11354#define DEFAULT_IOCTL_NARG_LEN (256)
11356#if defined(__linux__) && defined(_IOC_SIZE)
11358linux_iocparm_len(ioctl_req_t cmd)
11362 if ((cmd & 0xFFFF0000) == 0) {
11364 return DEFAULT_IOCTL_NARG_LEN;
11367 len = _IOC_SIZE(cmd);
11370 if (
len < DEFAULT_IOCTL_NARG_LEN)
11371 len = DEFAULT_IOCTL_NARG_LEN;
11379ioctl_narg_len(ioctl_req_t cmd)
11385#define IOCPARM_LEN(x) (((x) >> 16) & IOCPARM_MASK)
11389 len = IOCPARM_LEN(cmd);
11390#elif defined(__linux__) && defined(_IOC_SIZE)
11391 len = linux_iocparm_len(cmd);
11394 len = DEFAULT_IOCTL_NARG_LEN;
11403typedef long fcntl_arg_t;
11406typedef int fcntl_arg_t;
11410fcntl_narg_len(ioctl_req_t cmd)
11417 len =
sizeof(fcntl_arg_t);
11425#ifdef F_DUPFD_CLOEXEC
11426 case F_DUPFD_CLOEXEC:
11427 len =
sizeof(fcntl_arg_t);
11437 len =
sizeof(fcntl_arg_t);
11447 len =
sizeof(fcntl_arg_t);
11457 len =
sizeof(fcntl_arg_t);
11462 len =
sizeof(
struct f_owner_ex);
11467 len =
sizeof(
struct f_owner_ex);
11472 len =
sizeof(
struct flock);
11477 len =
sizeof(
struct flock);
11482 len =
sizeof(
struct flock);
11502 len =
sizeof(fcntl_arg_t);
11512 len =
sizeof(fcntl_arg_t);
11517 len =
sizeof(fcntl_arg_t);
11530fcntl_narg_len(ioctl_req_t cmd)
11536#define NARG_SENTINEL 17
11539setup_narg(ioctl_req_t cmd,
VALUE *argp,
long (*narg_len)(ioctl_req_t))
11550 else if (arg ==
Qtrue) {
11564 len = narg_len(cmd);
11565 rb_str_modify(arg);
11567 slen = RSTRING_LEN(arg);
11569 if (slen <
len+1) {
11570 rb_str_resize(arg,
len+1);
11571 MEMZERO(RSTRING_PTR(arg)+slen,
char,
len-slen);
11575 ptr = RSTRING_PTR(arg);
11576 ptr[slen - 1] = NARG_SENTINEL;
11585finish_narg(
int retval,
VALUE arg,
const rb_io_t *fptr)
11587 if (retval < 0) rb_sys_fail_path(fptr->
pathv);
11592 if (ptr[slen-1] != NARG_SENTINEL)
11593 rb_raise(rb_eArgError,
"return value overflowed string");
11594 ptr[slen-1] =
'\0';
11604 ioctl_req_t cmd = NUM2IOCTLREQ(req);
11609 narg = setup_narg(cmd, &arg, ioctl_narg_len);
11611 retval = do_ioctl(fptr, cmd, narg);
11612 return finish_narg(retval, arg, fptr);
11639 return rb_ioctl(io, req, arg);
11642#define rb_io_ioctl rb_f_notimplement
11653nogvl_fcntl(
void *ptr)
11655 struct fcntl_arg *arg = ptr;
11657#if defined(F_DUPFD)
11658 if (arg->cmd == F_DUPFD)
11661 return (
VALUE)fcntl(arg->fd, arg->cmd, arg->narg);
11665do_fcntl(
struct rb_io *io,
int cmd,
long narg)
11668 struct fcntl_arg arg;
11674 retval = (int)rb_io_blocking_region(io, nogvl_fcntl, &arg);
11675 if (retval != -1) {
11677#if defined(F_DUPFD)
11680#if defined(F_DUPFD_CLOEXEC)
11681 case F_DUPFD_CLOEXEC:
11698 narg = setup_narg(cmd, &arg, fcntl_narg_len);
11700 retval = do_fcntl(fptr, cmd, narg);
11701 return finish_narg(retval, arg, fptr);
11727 return rb_fcntl(io, req, arg);
11730#define rb_io_fcntl rb_f_notimplement
11733#if defined(HAVE_SYSCALL) || defined(HAVE___SYSCALL)
11765#if SIZEOF_VOIDP == 8 && defined(HAVE___SYSCALL) && SIZEOF_INT != 8
11766# define SYSCALL __syscall
11767# define NUM2SYSCALLID(x) NUM2LONG(x)
11768# define RETVAL2NUM(x) LONG2NUM(x)
11769# if SIZEOF_LONG == 8
11770 long num, retval = -1;
11771# elif SIZEOF_LONG_LONG == 8
11772 long long num, retval = -1;
11774# error ---->> it is asserted that __syscall takes the first argument and returns retval in 64bit signed integer. <<----
11776#elif defined(__linux__)
11777# define SYSCALL syscall
11778# define NUM2SYSCALLID(x) NUM2LONG(x)
11779# define RETVAL2NUM(x) LONG2NUM(x)
11787 long num, retval = -1;
11789# define SYSCALL syscall
11790# define NUM2SYSCALLID(x) NUM2INT(x)
11791# define RETVAL2NUM(x) INT2NUM(x)
11792 int num, retval = -1;
11798 "We plan to remove a syscall function at future release. DL(Fiddle) provides safer alternative.");
11802 rb_raise(rb_eArgError,
"too few arguments for syscall");
11803 if (argc > numberof(arg))
11804 rb_raise(rb_eArgError,
"too many arguments for syscall");
11805 num = NUM2SYSCALLID(argv[0]); ++argv;
11806 for (i = argc - 1; i--; ) {
11821 retval = SYSCALL(num);
11824 retval = SYSCALL(num, arg[0]);
11827 retval = SYSCALL(num, arg[0],arg[1]);
11830 retval = SYSCALL(num, arg[0],arg[1],arg[2]);
11833 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3]);
11836 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4]);
11839 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5]);
11842 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6]);
11848 return RETVAL2NUM(retval);
11850#undef NUM2SYSCALLID
11854#define rb_f_syscall rb_f_notimplement
11858io_new_instance(
VALUE args)
11864find_encoding(
VALUE v)
11867 if (!enc)
rb_warn(
"Unsupported encoding %"PRIsVALUE
" ignored", v);
11879 enc2 = find_encoding(v1);
11882 if (RSTRING_LEN(tmp) == 1 && RSTRING_PTR(tmp)[0] ==
'-') {
11888 enc = find_encoding(v2);
11895 enc = find_encoding(v2);
11901 if (enc2 == rb_ascii8bit_encoding()) {
11906 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11912 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
11913 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11918 if (!
NIL_P(tmp) && rb_enc_asciicompat(enc = rb_enc_get(tmp))) {
11919 parse_mode_enc(RSTRING_PTR(tmp), enc, &enc, &enc2, NULL);
11920 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11924 rb_io_ext_int_to_encs(find_encoding(v1), NULL, &enc, &enc2, 0);
11925 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11930 validate_enc_binmode(&fptr->
mode, ecflags, enc, enc2);
11935 clear_codeconv(fptr);
11947io_encoding_set_v(
VALUE v)
11950 io_encoding_set(arg->fptr, arg->v1, arg->v2, arg->opt);
11955pipe_pair_close(
VALUE rw)
11958 return rb_ensure(io_close, rwp[0], io_close, rwp[1]);
12041rb_io_s_pipe(
int argc,
VALUE *argv,
VALUE klass)
12043 int pipes[2], state;
12044 VALUE r, w, args[3], v1, v2;
12048 enum rb_io_mode fmode = 0;
12051 argc =
rb_scan_args(argc, argv,
"02:", &v1, &v2, &opt);
12058 r = rb_protect(io_new_instance, (
VALUE)args, &state);
12062 rb_jump_tag(state);
12066 ies_args.fptr = fptr;
12069 ies_args.opt = opt;
12070 rb_protect(io_encoding_set_v, (
VALUE)&ies_args, &state);
12074 rb_jump_tag(state);
12079 w = rb_protect(io_new_instance, (
VALUE)args, &state);
12083 rb_jump_tag(state);
12088 extract_binmode(opt, &fmode);
12095#if DEFAULT_TEXTMODE
12097 fptr->
mode &= ~FMODE_TEXTMODE;
12098 setmode(fptr->
fd, O_BINARY);
12100#if RUBY_CRLF_ENVIRONMENT
12106 fptr->
mode |= fmode;
12107#if DEFAULT_TEXTMODE
12109 fptr2->
mode &= ~FMODE_TEXTMODE;
12110 setmode(fptr2->
fd, O_BINARY);
12113 fptr2->
mode |= fmode;
12147 else if (!
NIL_P(v = rb_hash_aref(opt, sym_open_args))) {
12150 v = rb_to_array_type(v);
12155 arg->io = rb_io_open(klass, path, vmode, vperm, opt);
12159io_s_foreach(
VALUE v)
12164 if (arg->limit == 0)
12165 rb_raise(rb_eArgError,
"invalid limit: 0 for foreach");
12166 while (!
NIL_P(str = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, arg->io))) {
12250rb_io_s_foreach(
int argc,
VALUE *argv,
VALUE self)
12253 int orig_argc = argc;
12257 argc =
rb_scan_args(argc, argv,
"12:", NULL, NULL, NULL, &opt);
12259 extract_getline_args(argc-1, argv+1, &garg);
12260 open_key_args(self, argc, argv, opt, &arg);
12262 extract_getline_opts(opt, &garg);
12263 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12264 return rb_ensure(io_s_foreach, (
VALUE)&garg, rb_io_close, arg.io);
12268io_s_readlines(
VALUE v)
12271 return io_readlines(arg, arg->io);
12324rb_io_s_readlines(
int argc,
VALUE *argv,
VALUE io)
12330 argc =
rb_scan_args(argc, argv,
"12:", NULL, NULL, NULL, &opt);
12331 extract_getline_args(argc-1, argv+1, &garg);
12332 open_key_args(io, argc, argv, opt, &arg);
12334 extract_getline_opts(opt, &garg);
12335 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12336 return rb_ensure(io_s_readlines, (
VALUE)&garg, rb_io_close, arg.io);
12343 return io_read(arg->argc, arg->argv, arg->io);
12353seek_before_access(
VALUE argp)
12357 return rb_io_seek(arg->io, arg->offset, arg->mode);
12424rb_io_s_read(
int argc,
VALUE *argv,
VALUE io)
12430 argc =
rb_scan_args(argc, argv,
"13:", NULL, NULL, &offset, NULL, &opt);
12432 rb_raise(rb_eArgError,
"negative offset %ld given",
off);
12434 open_key_args(io, argc, argv, opt, &arg);
12436 if (!
NIL_P(offset)) {
12440 sarg.offset = offset;
12441 sarg.mode = SEEK_SET;
12442 rb_protect(seek_before_access, (
VALUE)&sarg, &state);
12445 rb_jump_tag(state);
12447 if (arg.argc == 2) arg.argc = 1;
12462rb_io_s_binread(
int argc,
VALUE *argv,
VALUE io)
12477 convconfig.
enc = rb_ascii8bit_encoding();
12478 arg.io = rb_io_open_generic(io, argv[0], oflags, fmode, &convconfig, 0);
12481 arg.argc = (argc > 1) ? 1 : 0;
12482 if (!
NIL_P(offset)) {
12486 sarg.offset = offset;
12487 sarg.mode = SEEK_SET;
12488 rb_protect(seek_before_access, (
VALUE)&sarg, &state);
12491 rb_jump_tag(state);
12498io_s_write0(
VALUE v)
12501 return io_write(arg->io,arg->str,arg->nosync);
12505io_s_write(
int argc,
VALUE *argv,
VALUE klass,
int binary)
12507 VALUE string, offset, opt;
12511 rb_scan_args(argc, argv,
"21:", NULL, &
string, &offset, &opt);
12513 if (
NIL_P(opt)) opt = rb_hash_new();
12514 else opt = rb_hash_dup(opt);
12517 if (
NIL_P(rb_hash_aref(opt,sym_mode))) {
12518 int mode = O_WRONLY|O_CREAT;
12520 if (binary) mode |= O_BINARY;
12522 if (
NIL_P(offset)) mode |= O_TRUNC;
12523 rb_hash_aset(opt,sym_mode,
INT2NUM(mode));
12525 open_key_args(klass, argc, argv, opt, &arg);
12528 if (binary) rb_io_binmode_m(arg.io);
12532 if (!
NIL_P(offset)) {
12536 sarg.offset = offset;
12537 sarg.mode = SEEK_SET;
12538 rb_protect(seek_before_access, (
VALUE)&sarg, &state);
12541 rb_jump_tag(state);
12549 return rb_ensure(io_s_write0, (
VALUE)&warg, rb_io_close, arg.io);
12607rb_io_s_write(
int argc,
VALUE *argv,
VALUE io)
12609 return io_s_write(argc, argv, io, 0);
12622rb_io_s_binwrite(
int argc,
VALUE *argv,
VALUE io)
12624 return io_s_write(argc, argv, io, 1);
12630 rb_off_t copy_length;
12631 rb_off_t src_offset;
12635 unsigned close_src : 1;
12636 unsigned close_dst : 1;
12639 const char *syserr;
12640 const char *notimp;
12642 struct stat src_stat;
12643 struct stat dst_stat;
12644#ifdef HAVE_FCOPYFILE
12645 copyfile_state_t copyfile_state;
12650exec_interrupts(
void *arg)
12653 rb_thread_execute_interrupts(th);
12667#if defined(ERESTART)
12672 rb_thread_execute_interrupts(stp->th);
12691fiber_scheduler_wait_for(
void * _arguments)
12701# define IOWAIT_SYSCALL "poll"
12702STATIC_ASSERT(pollin_expected, POLLIN == RB_WAITFD_IN);
12703STATIC_ASSERT(pollout_expected, POLLOUT == RB_WAITFD_OUT);
12708 if (scheduler !=
Qnil) {
12711 return RTEST(args.result);
12715 if (fd == -1)
return 0;
12720 fds.events = events;
12722 int timeout_milliseconds = -1;
12725 timeout_milliseconds = (int)(timeout->tv_sec * 1000) + (int)(timeout->tv_usec / 1000);
12728 return poll(&fds, 1, timeout_milliseconds);
12731# define IOWAIT_SYSCALL "select"
12736 if (scheduler !=
Qnil) {
12739 return RTEST(args.result);
12759 case RB_WAITFD_OUT:
12763 VM_UNREACHABLE(nogvl_wait_for);
12783 ret = nogvl_wait_for(stp->th, stp->src_fptr, RB_WAITFD_IN, NULL);
12785 }
while (ret < 0 && maygvl_copy_stream_continue_p(has_gvl, stp));
12788 stp->syserr = IOWAIT_SYSCALL;
12789 stp->error_no =
errno;
12801 ret = nogvl_wait_for(stp->th, stp->dst_fptr, RB_WAITFD_OUT, NULL);
12802 }
while (ret < 0 && maygvl_copy_stream_continue_p(0, stp));
12805 stp->syserr = IOWAIT_SYSCALL;
12806 stp->error_no =
errno;
12812#ifdef USE_COPY_FILE_RANGE
12815simple_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)
12817#ifdef HAVE_COPY_FILE_RANGE
12818 return copy_file_range(in_fd, in_offset, out_fd, out_offset, count, flags);
12820 return syscall(__NR_copy_file_range, in_fd, in_offset, out_fd, out_offset, count, flags);
12829 rb_off_t copy_length, src_offset, *src_offset_ptr;
12831 if (!S_ISREG(stp->src_stat.st_mode))
12834 src_size = stp->src_stat.st_size;
12835 src_offset = stp->src_offset;
12836 if (src_offset >= (rb_off_t)0) {
12837 src_offset_ptr = &src_offset;
12840 src_offset_ptr = NULL;
12843 copy_length = stp->copy_length;
12844 if (copy_length < (rb_off_t)0) {
12845 if (src_offset < (rb_off_t)0) {
12846 rb_off_t current_offset;
12848 current_offset = lseek(stp->src_fptr->
fd, 0, SEEK_CUR);
12849 if (current_offset < (rb_off_t)0 &&
errno) {
12850 stp->syserr =
"lseek";
12851 stp->error_no =
errno;
12852 return (
int)current_offset;
12854 copy_length = src_size - current_offset;
12857 copy_length = src_size - src_offset;
12861 retry_copy_file_range:
12862# if SIZEOF_OFF_T > SIZEOF_SIZE_T
12864 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
12866 ss = (ssize_t)copy_length;
12868 ss = simple_copy_file_range(stp->src_fptr->
fd, src_offset_ptr, stp->dst_fptr->
fd, NULL, ss, 0);
12872 if (0 < copy_length) {
12873 goto retry_copy_file_range;
12877 if (maygvl_copy_stream_continue_p(0, stp)) {
12878 goto retry_copy_file_range;
12892#if EWOULDBLOCK != EAGAIN
12896 int ret = nogvl_copy_stream_wait_write(stp);
12897 if (ret < 0)
return ret;
12899 goto retry_copy_file_range;
12903 int flags = fcntl(stp->dst_fptr->
fd, F_GETFL);
12905 if (flags != -1 && flags & O_APPEND) {
12911 stp->syserr =
"copy_file_range";
12912 stp->error_no =
errno;
12919#ifdef HAVE_FCOPYFILE
12923 rb_off_t cur, ss = 0;
12924 const rb_off_t src_offset = stp->src_offset;
12927 if (stp->copy_length >= (rb_off_t)0) {
12932 if (!S_ISREG(stp->src_stat.st_mode))
12935 if (!S_ISREG(stp->dst_stat.st_mode))
12937 if (lseek(stp->dst_fptr->
fd, 0, SEEK_CUR) > (rb_off_t)0)
12939 if (fcntl(stp->dst_fptr->
fd, F_GETFL) & O_APPEND) {
12942 rb_off_t end = lseek(stp->dst_fptr->
fd, 0, SEEK_END);
12943 lseek(stp->dst_fptr->
fd, 0, SEEK_SET);
12944 if (end > (rb_off_t)0)
return 0;
12947 if (src_offset > (rb_off_t)0) {
12952 cur = lseek(stp->src_fptr->
fd, 0, SEEK_CUR);
12953 if (cur < (rb_off_t)0 &&
errno) {
12954 stp->error_no =
errno;
12959 r = lseek(stp->src_fptr->
fd, src_offset, SEEK_SET);
12960 if (r < (rb_off_t)0 &&
errno) {
12961 stp->error_no =
errno;
12966 stp->copyfile_state = copyfile_state_alloc();
12967 ret = fcopyfile(stp->src_fptr->
fd, stp->dst_fptr->
fd, stp->copyfile_state, COPYFILE_DATA);
12968 copyfile_state_get(stp->copyfile_state, COPYFILE_STATE_COPIED, &ss);
12972 if (src_offset > (rb_off_t)0) {
12976 r = lseek(stp->src_fptr->
fd, cur, SEEK_SET);
12977 if (r < (rb_off_t)0 &&
errno) {
12978 stp->error_no =
errno;
12990 stp->syserr =
"fcopyfile";
12991 stp->error_no =
errno;
12998#ifdef HAVE_SENDFILE
13001# define USE_SENDFILE
13003# ifdef HAVE_SYS_SENDFILE_H
13004# include <sys/sendfile.h>
13008simple_sendfile(
int out_fd,
int in_fd, rb_off_t *offset, rb_off_t count)
13010 return sendfile(out_fd, in_fd, offset, (
size_t)count);
13013# elif 0 || defined(__APPLE__)
13017# define USE_SENDFILE
13020simple_sendfile(
int out_fd,
int in_fd, rb_off_t *offset, rb_off_t count)
13023 rb_off_t pos = offset ? *offset : lseek(in_fd, 0, SEEK_CUR);
13026 r = sendfile(in_fd, out_fd, pos, &count, NULL, 0);
13029 r = sendfile(in_fd, out_fd, pos, (
size_t)count, NULL, &sbytes, 0);
13031 if (r != 0 && sbytes == 0)
return r;
13036 lseek(in_fd, sbytes, SEEK_CUR);
13038 return (ssize_t)sbytes;
13051 rb_off_t copy_length;
13052 rb_off_t src_offset;
13055 if (!S_ISREG(stp->src_stat.st_mode))
13058 src_size = stp->src_stat.st_size;
13060 if ((stp->dst_stat.st_mode & S_IFMT) != S_IFSOCK)
13064 src_offset = stp->src_offset;
13065 use_pread = src_offset >= (rb_off_t)0;
13067 copy_length = stp->copy_length;
13068 if (copy_length < (rb_off_t)0) {
13070 copy_length = src_size - src_offset;
13074 cur = lseek(stp->src_fptr->
fd, 0, SEEK_CUR);
13075 if (cur < (rb_off_t)0 &&
errno) {
13076 stp->syserr =
"lseek";
13077 stp->error_no =
errno;
13080 copy_length = src_size - cur;
13085# if SIZEOF_OFF_T > SIZEOF_SIZE_T
13087 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
13089 ss = (ssize_t)copy_length;
13092 ss = simple_sendfile(stp->dst_fptr->
fd, stp->src_fptr->
fd, &src_offset, ss);
13095 ss = simple_sendfile(stp->dst_fptr->
fd, stp->src_fptr->
fd, NULL, ss);
13100 if (0 < copy_length) {
13101 goto retry_sendfile;
13105 if (maygvl_copy_stream_continue_p(0, stp))
13106 goto retry_sendfile;
13119#if EWOULDBLOCK != EAGAIN
13132 ret = maygvl_copy_stream_wait_read(0, stp);
13133 if (ret < 0)
return ret;
13135 ret = nogvl_copy_stream_wait_write(stp);
13136 if (ret < 0)
return ret;
13138 goto retry_sendfile;
13140 stp->syserr =
"sendfile";
13141 stp->error_no =
errno;
13149maygvl_read(
int has_gvl,
rb_io_t *fptr,
void *buf,
size_t count)
13152 return rb_io_read_memory(fptr, buf, count);
13154 return read(fptr->
fd, buf, count);
13158maygvl_copy_stream_read(
int has_gvl,
struct copy_stream_struct *stp,
char *buf,
size_t len, rb_off_t offset)
13162 if (offset < (rb_off_t)0) {
13163 ss = maygvl_read(has_gvl, stp->src_fptr, buf,
len);
13166 ss = pread(stp->src_fptr->
fd, buf,
len, offset);
13172 if (maygvl_copy_stream_continue_p(has_gvl, stp))
13176#if EWOULDBLOCK != EAGAIN
13180 int ret = maygvl_copy_stream_wait_read(has_gvl, stp);
13181 if (ret < 0)
return ret;
13186 stp->notimp =
"pread";
13190 stp->syserr = offset < (rb_off_t)0 ?
"read" :
"pread";
13191 stp->error_no =
errno;
13202 ss = write(stp->dst_fptr->
fd, buf+
off,
len);
13204 if (maygvl_copy_stream_continue_p(0, stp))
13206 if (io_again_p(
errno)) {
13207 int ret = nogvl_copy_stream_wait_write(stp);
13208 if (ret < 0)
return ret;
13211 stp->syserr =
"write";
13212 stp->error_no =
errno;
13229 rb_off_t copy_length;
13230 rb_off_t src_offset;
13234 copy_length = stp->copy_length;
13235 use_eof = copy_length < (rb_off_t)0;
13236 src_offset = stp->src_offset;
13237 use_pread = src_offset >= (rb_off_t)0;
13239 if (use_pread && stp->close_src) {
13242 r = lseek(stp->src_fptr->
fd, src_offset, SEEK_SET);
13243 if (r < (rb_off_t)0 &&
errno) {
13244 stp->syserr =
"lseek";
13245 stp->error_no =
errno;
13248 src_offset = (rb_off_t)-1;
13252 while (use_eof || 0 < copy_length) {
13253 if (!use_eof && copy_length < (rb_off_t)
sizeof(buf)) {
13254 len = (size_t)copy_length;
13260 ss = maygvl_copy_stream_read(0, stp, buf,
len, src_offset);
13265 ss = maygvl_copy_stream_read(0, stp, buf,
len, (rb_off_t)-1);
13270 ret = nogvl_copy_stream_write(stp, buf, ss);
13280nogvl_copy_stream_func(
void *arg)
13283#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13287#ifdef USE_COPY_FILE_RANGE
13288 ret = nogvl_copy_file_range(stp);
13293#ifdef HAVE_FCOPYFILE
13294 ret = nogvl_fcopyfile(stp);
13300 ret = nogvl_copy_stream_sendfile(stp);
13305 nogvl_copy_stream_read_write(stp);
13307#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13314copy_stream_fallback_body(
VALUE arg)
13317 const int buflen = 16*1024;
13320 rb_off_t rest = stp->copy_length;
13321 rb_off_t
off = stp->src_offset;
13322 ID read_method = id_readpartial;
13324 if (!stp->src_fptr) {
13326 read_method = id_read;
13333 rb_str_make_independent(buf);
13334 if (stp->copy_length < (rb_off_t)0) {
13339 rb_str_resize(buf, 0);
13342 l = buflen < rest ? buflen : (long)rest;
13344 if (!stp->src_fptr) {
13347 if (read_method == id_read &&
NIL_P(rc))
13352 rb_str_resize(buf, buflen);
13353 ss = maygvl_copy_stream_read(1, stp, RSTRING_PTR(buf), l,
off);
13354 rb_str_resize(buf, ss > 0 ? ss : 0);
13359 if (
off >= (rb_off_t)0)
13362 n = rb_io_write(stp->dst, buf);
13364 stp->total += numwrote;
13366 if (read_method == id_read && RSTRING_LEN(buf) == 0) {
13377 if (!stp->src_fptr && stp->src_offset >= (rb_off_t)0) {
13378 rb_raise(rb_eArgError,
"cannot specify src_offset for non-IO");
13387copy_stream_body(
VALUE arg)
13390 VALUE src_io = stp->src, dst_io = stp->dst;
13391 const int common_oflags = 0
13401 if (src_io ==
argf ||
13405 stp->src_fptr = NULL;
13410 if (!
NIL_P(tmp_io)) {
13417 args[1] =
INT2NUM(O_RDONLY|common_oflags);
13420 stp->close_src = 1;
13425 stat_ret = fstat(stp->src_fptr->
fd, &stp->src_stat);
13426 if (stat_ret < 0) {
13427 stp->syserr =
"fstat";
13428 stp->error_no =
errno;
13433 if (dst_io ==
argf ||
13437 stp->dst_fptr = NULL;
13442 if (!
NIL_P(tmp_io)) {
13443 dst_io = GetWriteIO(tmp_io);
13449 args[1] =
INT2NUM(O_WRONLY|O_CREAT|O_TRUNC|common_oflags);
13453 stp->close_dst = 1;
13456 dst_io = GetWriteIO(dst_io);
13462 stat_ret = fstat(stp->dst_fptr->
fd, &stp->dst_stat);
13463 if (stat_ret < 0) {
13464 stp->syserr =
"fstat";
13465 stp->error_no =
errno;
13472 SET_BINARY_MODE_WITH_SEEK_CUR(stp->src_fptr);
13475 io_ascii8bit_binmode(stp->dst_fptr);
13477 if (stp->src_offset < (rb_off_t)0 && stp->src_fptr && stp->src_fptr->
rbuf.
len) {
13480 if (stp->copy_length >= (rb_off_t)0 && stp->copy_length < (rb_off_t)
len) {
13481 len = (size_t)stp->copy_length;
13484 rb_str_resize(str,
len);
13485 read_buffered_data(RSTRING_PTR(str),
len, stp->src_fptr);
13486 if (stp->dst_fptr) {
13487 if (io_binwrite(RSTRING_PTR(str), RSTRING_LEN(str), stp->dst_fptr, 0) < 0)
13488 rb_sys_fail_on_write(stp->dst_fptr);
13491 rb_io_write(dst_io, str);
13492 rb_str_resize(str, 0);
13494 if (stp->copy_length >= (rb_off_t)0)
13495 stp->copy_length -=
len;
13498 if (stp->dst_fptr && io_fflush(stp->dst_fptr) < 0) {
13502 if (stp->copy_length == 0)
13505 if (stp->src_fptr == NULL || stp->dst_fptr == NULL) {
13506 return copy_stream_fallback(stp);
13509 IO_WITHOUT_GVL(nogvl_copy_stream_func, stp);
13514copy_stream_finalize(
VALUE arg)
13518#ifdef HAVE_FCOPYFILE
13519 if (stp->copyfile_state) {
13520 copyfile_state_free(stp->copyfile_state);
13524 if (stp->close_src) {
13525 rb_io_close_m(stp->src);
13527 if (stp->close_dst) {
13528 rb_io_close_m(stp->dst);
13591rb_io_s_copy_stream(
int argc,
VALUE *argv,
VALUE io)
13593 VALUE src, dst, length, src_offset;
13598 rb_scan_args(argc, argv,
"22", &src, &dst, &length, &src_offset);
13603 st.src_fptr = NULL;
13604 st.dst_fptr = NULL;
13607 st.copy_length = (rb_off_t)-1;
13609 st.copy_length =
NUM2OFFT(length);
13611 if (
NIL_P(src_offset))
13612 st.src_offset = (rb_off_t)-1;
13614 st.src_offset =
NUM2OFFT(src_offset);
13633rb_io_external_encoding(
VALUE io)
13638 return rb_enc_from_encoding(fptr->
encs.
enc2);
13642 return rb_enc_from_encoding(fptr->
encs.
enc);
13645 return rb_enc_from_encoding(io_read_encoding(fptr));
13661rb_io_internal_encoding(
VALUE io)
13666 return rb_enc_from_encoding(io_read_encoding(fptr));
13700rb_io_set_encoding(
int argc,
VALUE *argv,
VALUE io)
13706 return forward(io, id_set_encoding, argc, argv);
13709 argc =
rb_scan_args(argc, argv,
"11:", &v1, &v2, &opt);
13711 io_encoding_set(fptr, v1, v2, opt);
13716rb_stdio_set_default_encoding(
void)
13721 if (isatty(fileno(stdin))) {
13723 rb_encoding *internal = rb_default_internal_encoding();
13724 if (!internal) internal = rb_default_external_encoding();
13726 rb_enc_from_encoding(external),
13727 rb_enc_from_encoding(internal),
13732 rb_io_set_encoding(1, &val,
rb_stdin);
13733 rb_io_set_encoding(1, &val,
rb_stdout);
13734 rb_io_set_encoding(1, &val,
rb_stderr);
13738global_argf_p(
VALUE arg)
13740 return arg ==
argf;
13743typedef VALUE (*argf_encoding_func)(
VALUE io);
13746argf_encoding(
VALUE argf, argf_encoding_func func)
13748 if (!
RTEST(ARGF.current_file)) {
13749 return rb_enc_default_external();
13773 return argf_encoding(
argf, rb_io_external_encoding);
13792 return argf_encoding(
argf, rb_io_internal_encoding);
13831 if (!next_argv()) {
13832 rb_raise(rb_eArgError,
"no stream to set encoding");
13834 rb_io_set_encoding(argc, argv, ARGF.current_file);
13836 ARGF.encs = fptr->
encs;
13856 if (!next_argv()) {
13857 rb_raise(rb_eArgError,
"no stream to tell");
13859 ARGF_FORWARD(0, 0);
13860 return rb_io_tell(ARGF.current_file);
13873 if (!next_argv()) {
13874 rb_raise(rb_eArgError,
"no stream to seek");
13876 ARGF_FORWARD(argc, argv);
13877 return rb_io_seek_m(argc, argv, ARGF.current_file);
13894 if (!next_argv()) {
13895 rb_raise(rb_eArgError,
"no stream to set position");
13897 ARGF_FORWARD(1, &offset);
13898 return rb_io_set_pos(ARGF.current_file, offset);
13919 if (!next_argv()) {
13920 rb_raise(rb_eArgError,
"no stream to rewind");
13922 ARGF_FORWARD(0, 0);
13923 old_lineno =
RFILE(ARGF.current_file)->fptr->lineno;
13924 ret = rb_io_rewind(ARGF.current_file);
13925 if (!global_argf_p(
argf)) {
13926 ARGF.last_lineno = ARGF.lineno -= old_lineno;
13944 if (!next_argv()) {
13945 rb_raise(rb_eArgError,
"no stream");
13947 ARGF_FORWARD(0, 0);
13948 return rb_io_fileno(ARGF.current_file);
13967 ARGF_FORWARD(0, 0);
13968 return ARGF.current_file;
13993 if (
RTEST(ARGF.current_file)) {
13994 if (ARGF.init_p == 0)
return Qtrue;
13996 ARGF_FORWARD(0, 0);
14055 VALUE tmp, str, length;
14059 if (!
NIL_P(length)) {
14064 rb_str_resize(str,0);
14069 if (!next_argv()) {
14072 if (ARGF_GENERIC_INPUT_P()) {
14073 tmp = argf_forward(argc, argv,
argf);
14076 tmp = io_read(argc, argv, ARGF.current_file);
14078 if (
NIL_P(str)) str = tmp;
14081 if (ARGF.next_p != -1) {
14087 else if (argc >= 1) {
14088 long slen = RSTRING_LEN(str);
14104argf_forward_call(
VALUE arg)
14107 argf_forward(p->argc, p->argv, p->argf);
14137 return argf_getpartial(argc, argv,
argf,
Qnil, 0);
14158 return argf_getpartial(argc, argv,
argf, opts, 1);
14164 VALUE tmp, str, length;
14172 no_exception = no_exception_p(opts);
14174 if (!next_argv()) {
14176 rb_str_resize(str, 0);
14180 if (ARGF_GENERIC_INPUT_P()) {
14190 tmp = io_getpartial(argc, argv, ARGF.current_file, no_exception, nonblock);
14193 if (ARGF.next_p == -1) {
14194 return io_nonblock_eof(no_exception);
14199 return io_nonblock_eof(no_exception);
14237 if (!next_argv())
return Qnil;
14238 if (ARGF_GENERIC_INPUT_P()) {
14239 ch = forward_current(rb_intern(
"getc"), 0, 0);
14242 ch = rb_io_getc(ARGF.current_file);
14244 if (
NIL_P(ch) && ARGF.next_p != -1) {
14277 if (!next_argv())
return Qnil;
14279 ch = forward_current(rb_intern(
"getbyte"), 0, 0);
14284 if (
NIL_P(ch) && ARGF.next_p != -1) {
14317 if (!next_argv()) rb_eof_error();
14319 ch = forward_current(rb_intern(
"getc"), 0, 0);
14322 ch = rb_io_getc(ARGF.current_file);
14324 if (
NIL_P(ch) && ARGF.next_p != -1) {
14356 NEXT_ARGF_FORWARD(0, 0);
14357 c = argf_getbyte(
argf);
14364#define FOREACH_ARGF() while (next_argv())
14369 const VALUE current = ARGF.current_file;
14371 if (ARGF.init_p == -1 || current != ARGF.current_file) {
14377#define ARGF_block_call(mid, argc, argv, func, argf) \
14378 rb_block_call_kw(ARGF.current_file, mid, argc, argv, \
14379 func, argf, rb_keyword_given_p())
14384 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_i,
argf);
14385 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14391 if (!global_argf_p(
argf)) {
14392 ARGF.last_lineno = ++ARGF.lineno;
14394 return argf_block_call_i(i,
argf, argc, argv, blockarg);
14400 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_line_i,
argf);
14401 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14449 argf_block_call_line(rb_intern(
"each_line"), argc, argv,
argf);
14480 argf_block_call(rb_intern(
"each_byte"), 0, 0,
argf);
14506 argf_block_call(rb_intern(
"each_char"), 0, 0,
argf);
14532 argf_block_call(rb_intern(
"each_codepoint"), 0, 0,
argf);
14563 return ARGF.filename;
14567argf_filename_getter(
ID id,
VALUE *var)
14569 return argf_filename(*var);
14594 return ARGF.current_file;
14613 ARGF_FORWARD(0, 0);
14634 return RBOOL(ARGF.binmode);
14654 if (ARGF.init_p && ARGF.next_p == 0) {
14683 if (ARGF.next_p != -1) {
14701 ARGF_FORWARD(0, 0);
14728 if (!ARGF.inplace)
return Qnil;
14736 return argf_inplace_mode_get(*var);
14767 ARGF.inplace =
Qnil;
14778 argf_inplace_mode_set(*var, val);
14782ruby_set_inplace_mode(
const char *suffix)
14808argf_argv_getter(
ID id,
VALUE *var)
14810 return argf_argv(*var);
14829 if (!
RTEST(ARGF.current_file)) {
14832 return GetWriteIO(ARGF.current_file);
14844 return rb_io_writev(argf_write_io(
argf), argc, argv);
14859 case RB_IO_WAIT_WRITABLE:
14862 c = rb_eEAGAINWaitWritable;
14864#if EAGAIN != EWOULDBLOCK
14866 c = rb_eEWOULDBLOCKWaitWritable;
14870 c = rb_eEINPROGRESSWaitWritable;
14876 case RB_IO_WAIT_READABLE:
14879 c = rb_eEAGAINWaitReadable;
14881#if EAGAIN != EWOULDBLOCK
14883 c = rb_eEWOULDBLOCKWaitReadable;
14887 c = rb_eEINPROGRESSWaitReadable;
14894 rb_bug(
"invalid read/write type passed to rb_readwrite_sys_fail: %d", waiting);
14900get_LAST_READ_LINE(
ID _x,
VALUE *_y)
15790#include <sys/cygwin.h>
15791 static struct __cygwin_perfile pf[] =
15793 {
"", O_RDONLY | O_BINARY},
15794 {
"", O_WRONLY | O_BINARY},
15795 {
"", O_RDWR | O_BINARY},
15796 {
"", O_APPEND | O_BINARY},
15799 cygwin_internal(CW_PERFILE, pf);
15848 rb_eEAGAINWaitReadable = rb_define_class_under(
rb_cIO,
"EAGAINWaitReadable", rb_eEAGAIN);
15851 rb_eEAGAINWaitWritable = rb_define_class_under(
rb_cIO,
"EAGAINWaitWritable", rb_eEAGAIN);
15853#if EAGAIN == EWOULDBLOCK
15855 rb_define_const(
rb_cIO,
"EWOULDBLOCKWaitReadable", rb_eEAGAINWaitReadable);
15857 rb_define_const(
rb_cIO,
"EWOULDBLOCKWaitWritable", rb_eEAGAINWaitWritable);
15860 rb_eEWOULDBLOCKWaitReadable = rb_define_class_under(
rb_cIO,
"EWOULDBLOCKWaitReadable", rb_eEWOULDBLOCK);
15863 rb_eEWOULDBLOCKWaitWritable = rb_define_class_under(
rb_cIO,
"EWOULDBLOCKWaitWritable", rb_eEWOULDBLOCK);
15867 rb_eEINPROGRESSWaitReadable = rb_define_class_under(
rb_cIO,
"EINPROGRESSWaitReadable", rb_eEINPROGRESS);
15870 rb_eEINPROGRESSWaitWritable = rb_define_class_under(
rb_cIO,
"EINPROGRESSWaitWritable", rb_eEINPROGRESS);
15905 rb_gvar_ractor_local(
"$/");
15907 rb_gvar_ractor_local(
"$-0");
15911 rb_gvar_ractor_local(
"$_");
15912 rb_gvar_box_dynamic(
"$_");
16028 rb_gvar_ractor_local(
"$stdin");
16029 rb_gvar_ractor_local(
"$stdout");
16030 rb_gvar_ractor_local(
"$>");
16031 rb_gvar_ractor_local(
"$stderr");
16033 rb_gvar_box_dynamic(
"$stdin");
16034 rb_gvar_box_dynamic(
"$stdout");
16035 rb_gvar_box_dynamic(
"$>");
16036 rb_gvar_box_dynamic(
"$stderr");
16057 rb_cARGF = rb_define_class(
"ARGF",
rb_cObject);
16122 rb_define_method(rb_cARGF,
"external_encoding", argf_external_encoding, 0);
16123 rb_define_method(rb_cARGF,
"internal_encoding", argf_internal_encoding, 0);
16142 rb_gvar_ractor_local(
"$-i");
16146#if defined (_WIN32) || defined(__CYGWIN__)
16147 atexit(pipe_atexit);
16159 sym_encoding =
ID2SYM(rb_id_encoding());
16183static void init_builtin_io(
void);
16184#define Init_builtin_io init_builtin_io
16186#undef Init_builtin_io
16189Init_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 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.
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.