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;
200static VALUE rb_eEWOULDBLOCKWaitReadable;
201static VALUE rb_eEWOULDBLOCKWaitWritable;
202static VALUE rb_eEINPROGRESSWaitWritable;
203static VALUE rb_eEINPROGRESSWaitReadable;
206static VALUE orig_stdout, orig_stderr;
215static ID id_write, id_read, id_getc, id_flush, id_readpartial, id_set_encoding, id_fileno;
216static VALUE sym_mode, sym_perm, sym_flags, sym_extenc, sym_intenc, sym_encoding, sym_open_args;
217static VALUE sym_textmode, sym_binmode, sym_autoclose;
218static VALUE sym_SET, sym_CUR, sym_END;
219static VALUE sym_wait_readable, sym_wait_writable;
221static VALUE sym_DATA;
224static VALUE sym_HOLE;
227static VALUE prep_io(
int fd,
enum rb_io_mode fmode,
VALUE klass,
const char *path);
230rb_io_blocking_region_wait(
struct rb_io *io, rb_blocking_function_t *function,
void *argument,
enum rb_io_event events)
232 return rb_thread_io_blocking_call(io, function, argument, events);
235VALUE rb_io_blocking_region(
struct rb_io *io, rb_blocking_function_t *function,
void *argument)
237 return rb_io_blocking_region_wait(io, function, argument, 0);
241 VALUE filename, current_file;
247 int8_t init_p, next_p, binmode;
251#if defined(__APPLE__) && \
252 (!defined(MAC_OS_VERSION_27_0) || (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_VERSION_27_0))
254# if __has_attribute(availability) && __has_warning("-Wunguarded-availability-new")
260static inline int (*rb_dup3(
void))(int, int, int) {
return &dup3;}
261# define dup3 rb_dup3()
265static inline int (*rb_pipe2(
void))(
int [2], int) {
return &pipe2;}
266# define pipe2 rb_pipe2()
291 if (fd < 0 || afd <= max_fd)
294#if defined(HAVE_FCNTL) && defined(F_GETFL)
295 err = fcntl(fd, F_GETFL) == -1;
299 err = fstat(fd, &buf) != 0;
302 if (err &&
errno == EBADF) {
303 rb_bug(
"rb_update_max_fd: invalid fd (%d) given.", fd);
306 while (max_fd < afd) {
307 max_fd = ATOMIC_CAS(max_file_descriptor, max_fd, afd);
312rb_maygvl_fd_fix_cloexec(
int fd)
315#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
316 int flags, flags2, ret;
317 flags = fcntl(fd, F_GETFD);
319 rb_bug(
"rb_maygvl_fd_fix_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(
errno));
322 flags2 = flags & ~FD_CLOEXEC;
324 flags2 = flags | FD_CLOEXEC;
325 if (flags != flags2) {
326 ret = fcntl(fd, F_SETFD, flags2);
328 rb_bug(
"rb_maygvl_fd_fix_cloexec: fcntl(%d, F_SETFD, %d) failed: %s", fd, flags2, strerror(
errno));
337 rb_maygvl_fd_fix_cloexec(fd);
343rb_fix_detect_o_cloexec(
int fd)
345#if defined(O_CLOEXEC) && defined(F_GETFD)
346 int flags = fcntl(fd, F_GETFD);
349 rb_bug(
"rb_fix_detect_o_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(
errno));
351 if (flags & FD_CLOEXEC)
354 rb_maygvl_fd_fix_cloexec(fd);
361 return (e == EWOULDBLOCK) || (e == EAGAIN);
368 static int o_cloexec_state = -1;
370 static const int retry_interval = 0;
371 static const int retry_max_count = 10000;
378#elif defined O_NOINHERIT
379 flags |= O_NOINHERIT;
382 while ((ret = open(pathname, flags, mode)) == -1) {
384 if (!io_again_p(e))
break;
385 if (retry_count++ >= retry_max_count)
break;
387 sleep(retry_interval);
390 if (ret < 0)
return ret;
391 if (ret <= 2 || o_cloexec_state == 0) {
392 rb_maygvl_fd_fix_cloexec(ret);
394 else if (o_cloexec_state > 0) {
398 o_cloexec_state = rb_fix_detect_o_cloexec(ret);
417 if (oldfd == newfd) {
421#if defined(HAVE_DUP3) && defined(O_CLOEXEC)
422# if defined(__APPLE__)
423# define try_dup3 (dup3 != NULL)
424# define abandon_dup3() true
426 static bool try_dup3 =
true;
427# define abandon_dup3() (errno != ENOSYS || !!(try_dup3 = false))
433 ret = dup3(oldfd, newfd, O_CLOEXEC);
440 if (abandon_dup3())
return ret;
443 ret = dup2(oldfd, newfd);
444 if (ret < 0)
return ret;
446 rb_maygvl_fd_fix_cloexec(ret);
451rb_fd_set_nonblock(
int fd)
454 return rb_w32_set_nonblock(fd);
455#elif defined(F_GETFL)
456 int oflags = fcntl(fd, F_GETFL);
460 if (oflags & O_NONBLOCK)
462 oflags |= O_NONBLOCK;
463 return fcntl(fd, F_SETFL, oflags);
469cloexec_pipe(
int descriptors[2],
int flags,
bool force_cloexec)
473# if defined(__APPLE__)
474# define try_pipe2 (pipe2 != NULL)
475# define abandon_pipe2() true
477 static bool try_pipe2 =
true;
478# define abandon_pipe2() (errno != ENOSYS || !!(try_pipe2 = false))
481 result = pipe2(descriptors, O_CLOEXEC | flags);
482 if (result == 0)
return result;
483 if (abandon_pipe2())
return result;
486 if (result < 0 && (result = pipe(descriptors)) < 0)
490 if (result == 0 && descriptors[1] == -1) {
491 close(descriptors[0]);
498 if (!force_cloexec)
return result;
501 rb_maygvl_fd_fix_cloexec(descriptors[0]);
502 rb_maygvl_fd_fix_cloexec(descriptors[1]);
505 rb_fd_set_nonblock(descriptors[0]);
506 rb_fd_set_nonblock(descriptors[1]);
515 return cloexec_pipe(descriptors, O_NONBLOCK,
true);
523#if defined(HAVE_FCNTL) && defined(F_DUPFD_CLOEXEC) && defined(F_DUPFD)
524 static int try_dupfd_cloexec = 1;
525 if (try_dupfd_cloexec) {
526 ret = fcntl(fd, F_DUPFD_CLOEXEC, minfd);
529 rb_maygvl_fd_fix_cloexec(ret);
533 if (
errno == EINVAL) {
534 ret = fcntl(fd, F_DUPFD, minfd);
536 try_dupfd_cloexec = 0;
541 ret = fcntl(fd, F_DUPFD, minfd);
543#elif defined(HAVE_FCNTL) && defined(F_DUPFD)
544 ret = fcntl(fd, F_DUPFD, minfd);
547 if (ret >= 0 && ret < minfd) {
548 const int prev_fd = ret;
554 if (ret < 0)
return ret;
555 rb_maygvl_fd_fix_cloexec(ret);
559#define argf_of(obj) (*(struct argf *)DATA_PTR(obj))
560#define ARGF argf_of(argf)
562#define GetWriteIO(io) rb_io_get_write_io(io)
564#define READ_DATA_PENDING(fptr) ((fptr)->rbuf.len)
565#define READ_DATA_PENDING_COUNT(fptr) ((fptr)->rbuf.len)
566#define READ_DATA_PENDING_PTR(fptr) ((fptr)->rbuf.ptr+(fptr)->rbuf.off)
567#define READ_DATA_BUFFERED(fptr) READ_DATA_PENDING(fptr)
569#define READ_CHAR_PENDING(fptr) ((fptr)->cbuf.len)
570#define READ_CHAR_PENDING_COUNT(fptr) ((fptr)->cbuf.len)
571#define READ_CHAR_PENDING_PTR(fptr) ((fptr)->cbuf.ptr+(fptr)->cbuf.off)
574#define WAIT_FD_IN_WIN32(fptr) \
575 (rb_w32_io_cancelable_p((fptr)->fd) ? Qnil : rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_READABLE), RUBY_IO_TIMEOUT_DEFAULT))
577#define WAIT_FD_IN_WIN32(fptr)
580#define READ_CHECK(fptr) do {\
581 if (!READ_DATA_PENDING(fptr)) {\
582 WAIT_FD_IN_WIN32(fptr);\
583 rb_io_check_closed(fptr);\
589# define S_ISSOCK(m) _S_ISSOCK(m)
592# define S_ISSOCK(m) (((m) & S_IFMT) == _S_IFSOCK)
595# define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
601static int io_fflush(rb_io_t *);
602static rb_io_t *flush_before_seek(rb_io_t *fptr,
bool discard_rbuf);
603static void clear_codeconv(rb_io_t *fptr);
605#define FMODE_SIGNAL_ON_EPIPE (1<<17)
607#define fptr_signal_on_epipe(fptr) \
608 (((fptr)->mode & FMODE_SIGNAL_ON_EPIPE) != 0)
610#define fptr_set_signal_on_epipe(fptr, flag) \
612 (fptr)->mode |= FMODE_SIGNAL_ON_EPIPE : \
613 (fptr)->mode &= ~FMODE_SIGNAL_ON_EPIPE)
615extern ID ruby_static_id_signo;
617NORETURN(
static void rb_sys_fail_on_write(rb_io_t *fptr));
619rb_sys_fail_on_write(rb_io_t *fptr)
622 VALUE errinfo = rb_syserr_new_path(e, (fptr)->pathv);
624 if (fptr_signal_on_epipe(fptr) && (e == EPIPE)) {
636#define NEED_NEWLINE_DECORATOR_ON_READ(fptr) ((fptr)->mode & FMODE_TEXTMODE)
637#define NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) ((fptr)->mode & FMODE_TEXTMODE)
638#if defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32)
639# define RUBY_CRLF_ENVIRONMENT 1
641# define RUBY_CRLF_ENVIRONMENT 0
644#if RUBY_CRLF_ENVIRONMENT
646# define DEFAULT_TEXTMODE FMODE_TEXTMODE
647# define TEXTMODE_NEWLINE_DECORATOR_ON_WRITE ECONV_CRLF_NEWLINE_DECORATOR
655#define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || (fptr)->encs.ecflags & ~ECONV_CRLF_NEWLINE_DECORATOR)
656#define WRITECONV_MASK ( \
657 (ECONV_DECORATOR_MASK & ~ECONV_CRLF_NEWLINE_DECORATOR)|\
658 ECONV_STATEFUL_DECORATOR_MASK|\
660#define NEED_WRITECONV(fptr) ( \
661 ((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || \
662 ((fptr)->encs.ecflags & WRITECONV_MASK) || \
664#define SET_BINARY_MODE(fptr) setmode((fptr)->fd, O_BINARY)
666#define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) do {\
667 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {\
668 if (((fptr)->mode & FMODE_READABLE) &&\
669 !((fptr)->encs.ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {\
670 setmode((fptr)->fd, O_BINARY);\
673 setmode((fptr)->fd, O_TEXT);\
678#define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) do {\
679 if ((enc2) && ((ecflags) & ECONV_DEFAULT_NEWLINE_DECORATOR)) {\
680 (ecflags) |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;\
688io_unread(rb_io_t *fptr,
bool discard_rbuf)
704 if (!rb_w32_fd_is_text(fptr->
fd)) {
705 r = lseek(fptr->
fd, -fptr->
rbuf.
len, SEEK_CUR);
706 if (r < 0 &&
errno) {
709 if (!discard_rbuf)
return;
715 pos = lseek(fptr->
fd, 0, SEEK_CUR);
716 if (pos < 0 &&
errno) {
719 if (!discard_rbuf)
goto end;
723 extra_max = (long)(pos - fptr->
rbuf.
len);
731 for (i = 0; i < fptr->
rbuf.
len; i++) {
732 if (*p ==
'\n') newlines++;
733 if (extra_max == newlines)
break;
738 while (newlines >= 0) {
739 r = lseek(fptr->
fd, pos - fptr->
rbuf.
len - newlines, SEEK_SET);
740 if (newlines == 0)
break;
745 read_size = _read(fptr->
fd, buf, fptr->
rbuf.
len + newlines);
749 rb_syserr_fail_path(e, fptr->
pathv);
751 if (read_size == fptr->
rbuf.
len) {
752 lseek(fptr->
fd, r, SEEK_SET);
763 clear_codeconv(fptr);
775set_binary_mode_with_seek_cur(rb_io_t *fptr)
777 if (!rb_w32_fd_is_text(fptr->
fd))
return O_BINARY;
780 return setmode(fptr->
fd, O_BINARY);
782 flush_before_seek(fptr,
false);
783 return setmode(fptr->
fd, O_BINARY);
785#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) set_binary_mode_with_seek_cur(fptr)
789# define DEFAULT_TEXTMODE 0
790#define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || NEED_NEWLINE_DECORATOR_ON_READ(fptr))
791#define NEED_WRITECONV(fptr) ( \
792 ((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || \
793 NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) || \
794 ((fptr)->encs.ecflags & (ECONV_DECORATOR_MASK|ECONV_STATEFUL_DECORATOR_MASK)) || \
796#define SET_BINARY_MODE(fptr) (void)(fptr)
797#define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) (void)(fptr)
798#define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) ((void)(enc2), (void)(ecflags))
799#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) (void)(fptr)
802#if !defined HAVE_SHUTDOWN && !defined shutdown
803#define shutdown(a,b) 0
807#define is_socket(fd, path) rb_w32_is_socket(fd)
808#elif !defined(S_ISSOCK)
809#define is_socket(fd, path) 0
812is_socket(
int fd,
VALUE path)
815 if (fstat(fd, &sbuf) < 0)
816 rb_sys_fail_path(path);
817 return S_ISSOCK(sbuf.st_mode);
821static const char closed_stream[] =
"closed stream";
824io_fd_check_closed(
int fd)
857 io_fd_check_closed(fptr->
fd);
861rb_io_get_fptr(
VALUE io)
863 rb_io_t *fptr =
RFILE(io)->fptr;
871 return rb_convert_type_with_id(io,
T_FILE,
"IO", idTo_io);
877 return rb_check_convert_type_with_id(io,
T_FILE,
"IO", idTo_io);
884 write_io = rb_io_get_fptr(io)->tied_io_for_writing;
895 rb_io_t *fptr = rb_io_get_fptr(io);
904 return write_io ? write_io :
Qnil;
917 rb_io_t *fptr = rb_io_get_fptr(self);
947 if (
RTEST(timeout)) {
951 rb_io_t *fptr = rb_io_get_fptr(self);
976#if !RUBY_CRLF_ENVIRONMENT
978io_unread(rb_io_t *fptr,
bool discard_rbuf)
986 r = lseek(fptr->
fd, -fptr->
rbuf.
len, SEEK_CUR);
987 if (r < 0 &&
errno) {
990 if (!discard_rbuf)
return;
994 clear_codeconv(fptr);
999static rb_encoding *io_input_encoding(rb_io_t *fptr);
1002io_ungetbyte(
VALUE str, rb_io_t *fptr)
1004 long len = RSTRING_LEN(str);
1007 const int min_capa = IO_RBUF_CAPA_FOR(fptr);
1010#if SIZEOF_LONG > SIZEOF_INT
1035flush_before_seek(rb_io_t *fptr,
bool discard_rbuf)
1037 if (io_fflush(fptr) < 0)
1038 rb_sys_fail_on_write(fptr);
1039 io_unread(fptr, discard_rbuf);
1044#define io_seek(fptr, ofs, whence) (errno = 0, lseek(flush_before_seek(fptr, true)->fd, (ofs), (whence)))
1045#define io_tell(fptr) lseek(flush_before_seek(fptr, false)->fd, 0, SEEK_CUR)
1061 if (io_fflush(fptr) < 0)
1062 rb_sys_fail_on_write(fptr);
1067 if (io_fflush(wfptr) < 0)
1068 rb_sys_fail_on_write(wfptr);
1076 if (READ_CHAR_PENDING(fptr)) {
1077 rb_raise(
rb_eIOError,
"byte oriented read for character buffered IO");
1088io_read_encoding(rb_io_t *fptr)
1093 return rb_default_external_encoding();
1097io_input_encoding(rb_io_t *fptr)
1102 return io_read_encoding(fptr);
1113 io_unread(fptr,
true);
1121 if (READ_CHAR_PENDING(fptr))
1123 return READ_DATA_PENDING(fptr);
1129 if (!READ_DATA_PENDING(fptr)) {
1136rb_gc_for_fd(
int err)
1138 if (err == EMFILE || err == ENFILE || err == ENOMEM) {
1148#define TRY_WITH_GC(expr) \
1149 for (int first_errno, retried_errno = 0, retried = 0; \
1152 (!rb_gc_for_fd(first_errno = errno) || !(expr)) && \
1153 (retried_errno = errno, 1)); \
1154 (void)retried_errno, retried = 1)
1169io_alloc(
VALUE klass)
1179# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
1205struct io_internal_writev_struct {
1212 const struct iovec *iov;
1217static int nogvl_wait_for(
VALUE th, rb_io_t *fptr,
short events,
struct timeval *timeout);
1225io_internal_wait(
VALUE thread, rb_io_t *fptr,
int error,
int events,
struct timeval *timeout)
1227 if (!timeout && rb_thread_mn_schedulable(thread)) {
1232 int ready = nogvl_wait_for(thread, fptr, events, timeout);
1237 else if (ready == 0) {
1254internal_read_func(
void *
ptr)
1259 if (iis->timeout && !iis->nonblock) {
1260 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_IN, iis->timeout) == -1) {
1266 result = read(iis->fd, iis->buf, iis->capa);
1268 if (result < 0 && !iis->nonblock) {
1269 if (io_again_p(
errno)) {
1270 if (io_internal_wait(iis->th, iis->fptr,
errno, RB_WAITFD_IN, iis->timeout) == -1) {
1282#if defined __APPLE__
1283# define do_write_retry(code) do {result = code;} while (result == -1 && errno == EPROTOTYPE)
1285# define do_write_retry(code) result = code
1289internal_write_func(
void *
ptr)
1294 if (iis->timeout && !iis->nonblock) {
1295 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1301 do_write_retry(write(iis->fd, iis->buf, iis->capa));
1303 if (result < 0 && !iis->nonblock) {
1305 if (io_again_p(e)) {
1306 if (io_internal_wait(iis->th, iis->fptr,
errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1320internal_writev_func(
void *
ptr)
1322 struct io_internal_writev_struct *iis =
ptr;
1325 if (iis->timeout && !iis->nonblock) {
1326 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1332 do_write_retry(writev(iis->fd, iis->iov, iis->iovcnt));
1334 if (result < 0 && !iis->nonblock) {
1335 if (io_again_p(
errno)) {
1336 if (io_internal_wait(iis->th, iis->fptr,
errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1350rb_io_read_memory(rb_io_t *fptr,
void *buf,
size_t count)
1352 rb_thread_t *th = GET_THREAD();
1354 if (scheduler !=
Qnil) {
1357 if (!UNDEF_P(result)) {
1358 return rb_fiber_scheduler_io_result_apply(result);
1373 struct timeval timeout_storage;
1377 iis.timeout = &timeout_storage;
1380 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_read_func, &iis,
RUBY_IO_READABLE);
1384rb_io_write_memory(rb_io_t *fptr,
const void *buf,
size_t count)
1386 rb_thread_t *th = GET_THREAD();
1388 if (scheduler !=
Qnil) {
1391 if (!UNDEF_P(result)) {
1392 return rb_fiber_scheduler_io_result_apply(result);
1407 struct timeval timeout_storage;
1411 iis.timeout = &timeout_storage;
1414 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_write_func, &iis,
RUBY_IO_WRITABLE);
1419rb_writev_internal(rb_io_t *fptr,
const struct iovec *iov,
int iovcnt)
1421 if (!iovcnt)
return 0;
1423 rb_thread_t *th = GET_THREAD();
1426 if (scheduler !=
Qnil) {
1430 if (!UNDEF_P(result)) {
1431 return rb_fiber_scheduler_io_result_apply(result);
1435 struct io_internal_writev_struct iis = {
1446 struct timeval timeout_storage;
1450 iis.timeout = &timeout_storage;
1453 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_writev_func, &iis,
RUBY_IO_WRITABLE);
1458io_flush_buffer_sync(
void *arg)
1460 rb_io_t *fptr = arg;
1480io_flush_buffer_fiber_scheduler(
VALUE scheduler, rb_io_t *fptr)
1483 if (!UNDEF_P(ret)) {
1484 ssize_t result = rb_fiber_scheduler_io_result_apply(ret);
1495io_flush_buffer_async(
VALUE arg)
1497 rb_io_t *fptr = (rb_io_t *)arg;
1500 if (scheduler !=
Qnil) {
1501 VALUE result = io_flush_buffer_fiber_scheduler(scheduler, fptr);
1502 if (!UNDEF_P(result)) {
1507 return rb_io_blocking_region_wait(fptr, io_flush_buffer_sync, fptr,
RUBY_IO_WRITABLE);
1511io_flush_buffer(rb_io_t *fptr)
1514 return (
int)io_flush_buffer_async((
VALUE)fptr);
1522io_fflush(rb_io_t *fptr)
1529 while (fptr->
wbuf.
len > 0 && io_flush_buffer(fptr) != 0) {
1542 rb_thread_t *th = GET_THREAD();
1545 if (scheduler !=
Qnil) {
1549 rb_io_t * fptr = NULL;
1555 if (NIL_OR_UNDEF_P(timeout)) {
1559 if (timeout !=
Qnil) {
1564 int ready = rb_thread_io_wait(th, fptr,
RB_NUM2INT(events), tv);
1588io_wait_for_single_fd(
int fd,
int events,
struct timeval *timeout, rb_thread_t *th,
VALUE scheduler)
1590 if (scheduler !=
Qnil) {
1596 return rb_thread_wait_for_single_fd(th, fd, events, timeout);
1602 io_fd_check_closed(f);
1604 rb_thread_t *th = GET_THREAD();
1609#if defined(ERESTART)
1616#if EWOULDBLOCK != EAGAIN
1619 if (scheduler !=
Qnil) {
1637 io_fd_check_closed(f);
1639 rb_thread_t *th = GET_THREAD();
1644#if defined(ERESTART)
1660#if EWOULDBLOCK != EAGAIN
1663 if (scheduler !=
Qnil) {
1681 rb_thread_t *th = GET_THREAD();
1683 return io_wait_for_single_fd(fd, events, timeout, th, scheduler);
1717#if defined(ERESTART)
1727#if EWOULDBLOCK != EAGAIN
1750 if (
RTEST(result)) {
1765 if (
RTEST(result)) {
1776make_writeconv(rb_io_t *fptr)
1779 const char *senc, *denc;
1813 denc = rb_enc_name(enc);
1845io_binwrite_string_internal(rb_io_t *fptr,
const char *
ptr,
long length)
1848 struct iovec iov[2];
1851 iov[0].iov_len = fptr->
wbuf.
len;
1852 iov[1].iov_base = (
void*)
ptr;
1853 iov[1].iov_len = length;
1855 ssize_t result = rb_writev_internal(fptr, iov, 2);
1860 if (result >= fptr->
wbuf.
len) {
1868 fptr->
wbuf.
off += (int)result;
1869 fptr->
wbuf.
len -= (int)result;
1877 return rb_io_write_memory(fptr,
ptr, length);
1882io_binwrite_string_internal(rb_io_t *fptr,
const char *
ptr,
long length)
1884 long remaining = length;
1887 if (fptr->
wbuf.
len+length <= fptr->wbuf.capa) {
1894 fptr->
wbuf.
len += (int)length;
1901 if (io_fflush(fptr) < 0) {
1906 if (remaining == 0) {
1912 return rb_io_write_memory(fptr,
ptr, length);
1917io_binwrite_string(
VALUE arg)
1921 const char *
ptr = p->ptr;
1922 size_t remaining = p->length;
1926 ssize_t result = io_binwrite_string_internal(p->fptr,
ptr, remaining);
1932 else if (result > 0) {
1933 if ((
size_t)result == remaining)
break;
1935 remaining -= result;
1951io_allocate_write_buffer(rb_io_t *fptr,
int sync)
1956 fptr->
wbuf.
capa = IO_WBUF_CAPA_MIN;
1967io_binwrite_requires_flush_write(rb_io_t *fptr,
long len,
int nosync)
1982io_binwrite(
const char *
ptr,
long len, rb_io_t *fptr,
int nosync)
1984 if (
len <= 0)
return len;
1989 io_allocate_write_buffer(fptr, !nosync);
1991 if (io_binwrite_requires_flush_write(fptr,
len, nosync)) {
2002 return io_binwrite_string((
VALUE)&arg);
2019# define MODE_BTMODE(a,b,c) ((fmode & FMODE_BINMODE) ? (b) : \
2020 (fmode & FMODE_TEXTMODE) ? (c) : (a))
2022#define MODE_BTXMODE(a, b, c, d, e, f) ((fmode & FMODE_EXCL) ? \
2023 MODE_BTMODE(d, e, f) : \
2024 MODE_BTMODE(a, b, c))
2027do_writeconv(
VALUE str, rb_io_t *fptr,
int *converted)
2029 if (NEED_WRITECONV(fptr)) {
2031 SET_BINARY_MODE(fptr);
2033 make_writeconv(fptr);
2036#define fmode (fptr->mode)
2039 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1) && !rb_enc_asciicompat(rb_enc_get(str))) {
2040 rb_raise(rb_eArgError,
"ASCII incompatible string written for text mode IO without encoding conversion: %s",
2041 rb_enc_name(rb_enc_get(str)));
2047 common_encoding = rb_enc_from_encoding(fptr->
encs.
enc2);
2048 else if (fptr->
encs.
enc != rb_ascii8bit_encoding())
2049 common_encoding = rb_enc_from_encoding(fptr->
encs.
enc);
2052 if (!
NIL_P(common_encoding)) {
2063#if RUBY_CRLF_ENVIRONMENT
2064#define fmode (fptr->mode)
2065 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1)) {
2068 setmode(fptr->
fd, O_BINARY);
2071 setmode(fptr->
fd, O_TEXT);
2073 if (!rb_enc_asciicompat(rb_enc_get(str))) {
2074 rb_raise(rb_eArgError,
"ASCII incompatible string written for text mode IO without encoding conversion: %s",
2075 rb_enc_name(rb_enc_get(str)));
2084io_fwrite(
VALUE str, rb_io_t *fptr,
int nosync)
2093 long len = rb_w32_write_console(str, fptr->
fd);
2098 str = do_writeconv(str, fptr, &converted);
2102 tmp = rb_str_tmp_frozen_no_embed_acquire(str);
2104 n = io_binwrite(
ptr,
len, fptr, nosync);
2105 rb_str_tmp_frozen_release(str, tmp);
2117 return (ssize_t)io_binwrite(buf, (
long)size, fptr, 0);
2127 io = GetWriteIO(io);
2137 if (RSTRING_LEN(str) == 0)
return INT2FIX(0);
2142 n = io_fwrite(str, fptr, nosync);
2143 if (n < 0L) rb_sys_fail_on_write(fptr);
2149struct binwritev_arg {
2157io_binwritev_internal(
VALUE arg)
2159 struct binwritev_arg *p = (
struct binwritev_arg *)arg;
2161 size_t remaining = p->total;
2164 rb_io_t *fptr = p->fptr;
2165 struct iovec *iov = p->iov;
2166 int iovcnt = p->iovcnt;
2169 long result = rb_writev_internal(fptr, iov, iovcnt);
2174 if (offset < (
size_t)fptr->
wbuf.
len) {
2179 offset -= (size_t)fptr->
wbuf.
len;
2185 if (offset == p->total) {
2189 while (result >= (ssize_t)iov->iov_len) {
2191 result -= iov->iov_len;
2201 iov->iov_base = (
char *)iov->iov_base + result;
2202 iov->iov_len -= result;
2216io_binwritev(
struct iovec *iov,
int iovcnt, rb_io_t *fptr)
2221 if (iovcnt == 0)
return 0;
2224 for (
int i = 1; i < iovcnt; i++) total += iov[i].iov_len;
2226 io_allocate_write_buffer(fptr, 1);
2232 if (offset + total <= (
size_t)fptr->
wbuf.
capa) {
2233 for (
int i = 1; i < iovcnt; i++) {
2234 memcpy(fptr->
wbuf.
ptr+offset, iov[i].iov_base, iov[i].iov_len);
2235 offset += iov[i].iov_len;
2244 iov[0].iov_len = fptr->
wbuf.
len;
2257 struct binwritev_arg arg;
2260 arg.iovcnt = iovcnt;
2267 return io_binwritev_internal((
VALUE)&arg);
2272io_fwritev(
int argc,
const VALUE *argv, rb_io_t *fptr)
2274 int i, converted, iovcnt = argc + 1;
2276 VALUE v1, v2, str, tmp, *tmp_array;
2282 for (i = 0; i < argc; i++) {
2285 str = do_writeconv(str, fptr, &converted);
2290 tmp = rb_str_tmp_frozen_acquire(str);
2294 iov[i+1].iov_base = RSTRING_PTR(tmp);
2295 iov[i+1].iov_len = RSTRING_LEN(tmp);
2298 n = io_binwritev(iov, iovcnt, fptr);
2301 for (i = 0; i < argc; i++) {
2302 rb_str_tmp_frozen_release(argv[i], tmp_array[i]);
2311iovcnt_ok(
int iovcnt)
2314 return iovcnt < IOV_MAX;
2322io_writev(
int argc,
const VALUE *argv,
VALUE io)
2329 io = GetWriteIO(io);
2334 return rb_funcallv(io, id_write, argc, argv);
2342 for (i = 0; i < argc; i += cnt) {
2345 n = io_fwritev(cnt, &argv[i], fptr);
2356 rb_sys_fail_on_write(fptr);
2358 total = rb_fix_plus(
LONG2FIX(n), total);
2389 return io_writev(argc, argv, io);
2392 VALUE str = argv[0];
2393 return io_write(io, str, 0);
2400 return rb_funcallv(io, id_write, 1, &str);
2404rb_io_writev(
VALUE io,
int argc,
const VALUE *argv)
2409 char sep = RCLASS_SINGLETON_P(klass) ? (klass = io,
'.') :
'#';
2412 " which accepts just one argument",
2417 do rb_io_write(io, *argv++);
while (--argc);
2422 return rb_funcallv(io, id_write, argc, argv);
2448 rb_io_write(io, str);
2454nogvl_fsync(
void *
ptr)
2456 rb_io_t *fptr =
ptr;
2459 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->
fd)) != FILE_TYPE_DISK)
2462 return (
VALUE)fsync(fptr->
fd);
2467rb_io_flush_raw(
VALUE io,
int sync)
2471 if (!RB_TYPE_P(io,
T_FILE)) {
2475 io = GetWriteIO(io);
2479 if (io_fflush(fptr) < 0)
2480 rb_sys_fail_on_write(fptr);
2483 io_unread(fptr,
true);
2504 return rb_io_flush_raw(io, 1);
2530 pos = io_tell(fptr);
2531 if (pos < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
2537rb_io_seek(
VALUE io,
VALUE offset,
int whence)
2544 pos = io_seek(fptr, pos, whence);
2545 if (pos < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
2551interpret_seek_whence(
VALUE vwhence)
2553 if (vwhence == sym_SET)
2555 if (vwhence == sym_CUR)
2557 if (vwhence == sym_END)
2560 if (vwhence == sym_DATA)
2564 if (vwhence == sym_HOLE)
2620 VALUE offset, ptrname;
2621 int whence = SEEK_SET;
2623 if (
rb_scan_args(argc, argv,
"11", &offset, &ptrname) == 2) {
2624 whence = interpret_seek_whence(ptrname);
2627 return rb_io_seek(io, offset, whence);
2655 pos = io_seek(fptr, pos, SEEK_SET);
2656 if (pos < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
2661static void clear_readconv(rb_io_t *fptr);
2688rb_io_rewind(
VALUE io)
2693 if (io_seek(fptr, 0L, 0) < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
2694 if (io == ARGF.current_file) {
2695 ARGF.lineno -= fptr->
lineno;
2699 clear_readconv(fptr);
2706fptr_wait_readable(rb_io_t *fptr)
2717io_fillbuf(rb_io_t *fptr)
2724 fptr->
rbuf.
capa = IO_RBUF_CAPA_FOR(fptr);
2732 if (fptr_wait_readable(fptr))
2736 VALUE path = rb_sprintf(
"fd:%d ", fptr->
fd);
2741 rb_syserr_fail_path(e, path);
2795 if (READ_CHAR_PENDING(fptr))
return Qfalse;
2796 if (READ_DATA_PENDING(fptr))
return Qfalse;
2798#if RUBY_CRLF_ENVIRONMENT
2799 if (!NEED_READCONV(fptr) && NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
2800 return RBOOL(eof(fptr->
fd));
2803 return RBOOL(io_fillbuf(fptr) < 0);
2827 io = GetWriteIO(io);
2864 io = GetWriteIO(io);
2894rb_io_fsync(
VALUE io)
2898 io = GetWriteIO(io);
2901 if (io_fflush(fptr) < 0)
2902 rb_sys_fail_on_write(fptr);
2904 if ((
int)rb_io_blocking_region(fptr, nogvl_fsync, fptr))
2905 rb_sys_fail_path(fptr->
pathv);
2910# define rb_io_fsync rb_f_notimplement
2911# define rb_io_sync rb_f_notimplement
2920#ifdef HAVE_FDATASYNC
2922nogvl_fdatasync(
void *
ptr)
2924 rb_io_t *fptr =
ptr;
2927 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->
fd)) != FILE_TYPE_DISK)
2930 return (
VALUE)fdatasync(fptr->
fd);
2945rb_io_fdatasync(
VALUE io)
2949 io = GetWriteIO(io);
2952 if (io_fflush(fptr) < 0)
2953 rb_sys_fail_on_write(fptr);
2955 if ((
int)rb_io_blocking_region(fptr, nogvl_fdatasync, fptr) == 0)
2959 return rb_io_fsync(io);
2962#define rb_io_fdatasync rb_io_fsync
2980rb_io_fileno(
VALUE io)
2982 rb_io_t *fptr =
RFILE(io)->fptr;
2993 if (RB_TYPE_P(io,
T_FILE)) {
2994 rb_io_t *fptr =
RFILE(io)->fptr;
3000 if (!UNDEF_P(fileno)) {
3067 rb_io_t *fptr =
RFILE(io)->fptr;
3088rb_io_inspect(
VALUE obj)
3092 static const char closed[] =
" (closed)";
3094 fptr =
RFILE(obj)->fptr;
3101 rb_str_cat(result, closed+1, strlen(closed)-1);
3104 rb_str_catf(result,
"fd %d", fptr->
fd);
3125rb_io_to_io(
VALUE io)
3132read_buffered_data(
char *
ptr,
long len, rb_io_t *fptr)
3136 n = READ_DATA_PENDING_COUNT(fptr);
3137 if (n <= 0)
return 0;
3138 if (n >
len) n = (int)
len;
3146io_bufread(
char *
ptr,
long len, rb_io_t *fptr)
3152 if (READ_DATA_PENDING(fptr) == 0) {
3156 c = rb_io_read_memory(fptr,
ptr+offset, n);
3159 if (fptr_wait_readable(fptr))
3164 if ((n -= c) <= 0)
break;
3170 c = read_buffered_data(
ptr+offset, n, fptr);
3173 if ((n -= c) <= 0)
break;
3176 if (io_fillbuf(fptr) < 0) {
3183static int io_setstrbuf(
VALUE *str,
long len);
3192bufread_call(
VALUE arg)
3195 p->len = io_bufread(p->str_ptr, p->len, p->fptr);
3200io_fread(
VALUE str,
long offset,
long size, rb_io_t *fptr)
3205 io_setstrbuf(&str, offset + size);
3206 arg.str_ptr = RSTRING_PTR(str) + offset;
3209 rb_str_locktmp_ensure(str, bufread_call, (
VALUE)&arg);
3211 if (
len < 0) rb_sys_fail_path(fptr->
pathv);
3216remain_size(rb_io_t *fptr)
3219 rb_off_t siz = READ_DATA_PENDING_COUNT(fptr);
3222 if (fstat(fptr->
fd, &st) == 0 && S_ISREG(st.st_mode)
3223#
if defined(__HAIKU__)
3228 if (io_fflush(fptr) < 0)
3229 rb_sys_fail_on_write(fptr);
3230 pos = lseek(fptr->
fd, 0, SEEK_CUR);
3231 if (st.st_size >= pos && pos >= 0) {
3232 siz += st.st_size - pos;
3233 if (siz > LONG_MAX) {
3234 rb_raise(
rb_eIOError,
"file too big for single read");
3245io_enc_str(
VALUE str, rb_io_t *fptr)
3247 rb_enc_associate(str, io_read_encoding(fptr));
3252make_readconv(rb_io_t *fptr,
int size)
3257 const char *sname, *dname;
3261 sname = rb_enc_name(fptr->
encs.
enc2);
3262 dname = rb_enc_name(io_read_encoding(fptr));
3272 if (size < IO_CBUF_CAPA_MIN) size = IO_CBUF_CAPA_MIN;
3278#define MORE_CHAR_SUSPENDED Qtrue
3279#define MORE_CHAR_FINISHED Qnil
3281fill_cbuf(rb_io_t *fptr,
int ec_flags)
3283 const unsigned char *ss, *sp, *se;
3284 unsigned char *ds, *dp, *de;
3293 return MORE_CHAR_SUSPENDED;
3304 ss = sp = (
const unsigned char *)fptr->
rbuf.
ptr + fptr->
rbuf.
off;
3309 fptr->
rbuf.
off += (int)(sp - ss);
3310 fptr->
rbuf.
len -= (int)(sp - ss);
3311 fptr->
cbuf.
len += (int)(dp - ds);
3316 fptr->
rbuf.
off -= putbackable;
3317 fptr->
rbuf.
len += putbackable;
3324 if (cbuf_len0 != fptr->
cbuf.
len)
3325 return MORE_CHAR_SUSPENDED;
3328 return MORE_CHAR_FINISHED;
3334 if (io_fillbuf(fptr) < 0) {
3336 return MORE_CHAR_FINISHED;
3341 fptr->
cbuf.
len += (int)(dp - ds);
3348 if (cbuf_len0 != fptr->
cbuf.
len)
3349 return MORE_CHAR_SUSPENDED;
3351 return MORE_CHAR_FINISHED;
3355more_char(rb_io_t *fptr)
3359 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED)
3365io_shift_cbuf(rb_io_t *fptr,
int len,
VALUE *strp)
3376 rb_enc_associate(str, fptr->
encs.
enc);
3401 long clen = RSTRING_LEN(s);
3413#define MAX_REALLOC_GAP 4096
3415io_shrink_read_string(
VALUE str,
long n)
3418 rb_str_resize(str, n);
3423io_set_read_length(
VALUE str,
long n,
int shrinkable)
3425 if (RSTRING_LEN(str) != n) {
3428 if (shrinkable) io_shrink_read_string(str, n);
3433read_all(rb_io_t *fptr,
long siz,
VALUE str)
3442 if (NEED_READCONV(fptr)) {
3443 int first = !
NIL_P(str);
3444 SET_BINARY_MODE(fptr);
3445 shrinkable = io_setstrbuf(&str,0);
3446 make_readconv(fptr, 0);
3451 io_shift_cbuf(fptr, fptr->
cbuf.
len, &str);
3453 v = fill_cbuf(fptr, 0);
3454 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED) {
3457 io_shift_cbuf(fptr, fptr->
cbuf.
len, &str);
3461 if (v == MORE_CHAR_FINISHED) {
3462 clear_readconv(fptr);
3464 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3465 return io_enc_str(str, fptr);
3470 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3474 enc = io_read_encoding(fptr);
3477 if (siz == 0) siz = BUFSIZ;
3478 shrinkable = io_setstrbuf(&str, siz);
3481 n = io_fread(str, bytes, siz - bytes, fptr);
3482 if (n == 0 && bytes == 0) {
3490 if (bytes < siz)
break;
3494 if (
capa < (
size_t)RSTRING_LEN(str) + BUFSIZ) {
3495 if (
capa < BUFSIZ) {
3498 else if (
capa > IO_MAX_BUFFER_GROWTH) {
3499 capa = IO_MAX_BUFFER_GROWTH;
3504 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3505 str = io_enc_str(str, fptr);
3513 if (rb_fd_set_nonblock(fptr->
fd) != 0) {
3514 rb_sys_fail_path(fptr->
pathv);
3519io_read_memory_call(
VALUE arg)
3524 if (scheduler !=
Qnil) {
3527 if (!UNDEF_P(result)) {
3529 return (
VALUE)rb_fiber_scheduler_io_result_apply(result);
3533 if (iis->nonblock) {
3534 return rb_io_blocking_region(iis->fptr, internal_read_func, iis);
3537 return rb_io_blocking_region_wait(iis->fptr, internal_read_func, iis,
RUBY_IO_READABLE);
3544 return (
long)rb_str_locktmp_ensure(str, io_read_memory_call, (
VALUE)iis);
3547#define no_exception_p(opts) !rb_opts_exception_p((opts), TRUE)
3550io_getpartial(
int argc,
VALUE *argv,
VALUE io,
int no_exception,
int nonblock)
3561 rb_raise(rb_eArgError,
"negative length %ld given",
len);
3564 shrinkable = io_setstrbuf(&str,
len);
3570 io_set_read_length(str, 0, shrinkable);
3576 n = read_buffered_data(RSTRING_PTR(str),
len, fptr);
3582 io_setstrbuf(&str,
len);
3585 iis.nonblock = nonblock;
3587 iis.buf = RSTRING_PTR(str);
3590 n = io_read_memory_locktmp(str, &iis);
3593 if (!nonblock && fptr_wait_readable(fptr))
3595 if (nonblock && (io_again_p(e))) {
3597 return sym_wait_readable;
3600 e,
"read would block");
3602 rb_syserr_fail_path(e, fptr->
pathv);
3605 io_set_read_length(str, n, shrinkable);
3706io_readpartial(
int argc,
VALUE *argv,
VALUE io)
3710 ret = io_getpartial(argc, argv, io,
Qnil, 0);
3717io_nonblock_eof(
int no_exception)
3719 if (!no_exception) {
3735 rb_raise(rb_eArgError,
"negative length %ld given",
len);
3738 shrinkable = io_setstrbuf(&str,
len);
3739 rb_bool_expected(ex,
"exception", TRUE);
3745 io_set_read_length(str, 0, shrinkable);
3749 n = read_buffered_data(RSTRING_PTR(str),
len, fptr);
3751 rb_fd_set_nonblock(fptr->
fd);
3752 shrinkable |= io_setstrbuf(&str,
len);
3756 iis.buf = RSTRING_PTR(str);
3759 n = io_read_memory_locktmp(str, &iis);
3762 if (io_again_p(e)) {
3763 if (!ex)
return sym_wait_readable;
3765 e,
"read would block");
3767 rb_syserr_fail_path(e, fptr->
pathv);
3770 io_set_read_length(str, n, shrinkable);
3773 if (!ex)
return Qnil;
3782io_write_nonblock(rb_execution_context_t *ec,
VALUE io,
VALUE str,
VALUE ex)
3789 rb_bool_expected(ex,
"exception", TRUE);
3791 io = GetWriteIO(io);
3795 if (io_fflush(fptr) < 0)
3796 rb_sys_fail_on_write(fptr);
3798 rb_fd_set_nonblock(fptr->
fd);
3799 n = write(fptr->
fd, RSTRING_PTR(str), RSTRING_LEN(str));
3804 if (io_again_p(e)) {
3806 return sym_wait_writable;
3812 rb_syserr_fail_path(e, fptr->
pathv);
3896#if RUBY_CRLF_ENVIRONMENT
3902 if (
NIL_P(length)) {
3905 return read_all(fptr, remain_size(fptr), str);
3909 rb_raise(rb_eArgError,
"negative length %ld given",
len);
3912 shrinkable = io_setstrbuf(&str,
len);
3917 io_set_read_length(str, 0, shrinkable);
3922#if RUBY_CRLF_ENVIRONMENT
3923 previous_mode = set_binary_mode_with_seek_cur(fptr);
3925 n = io_fread(str, 0,
len, fptr);
3926 io_set_read_length(str, n, shrinkable);
3927#if RUBY_CRLF_ENVIRONMENT
3928 if (previous_mode == O_TEXT) {
3929 setmode(fptr->
fd, O_TEXT);
3932 if (n == 0)
return Qnil;
3938rscheck(
const char *rsptr,
long rslen,
VALUE rs)
3941 if (RSTRING_PTR(rs) != rsptr && RSTRING_LEN(rs) != rslen)
3946search_delim(
const char *p,
long len,
int delim, rb_encoding *enc)
3948 if (rb_enc_mbminlen(enc) == 1) {
3949 p = memchr(p, delim,
len);
3950 if (p)
return p + 1;
3953 const char *end = p +
len;
3955 int r = rb_enc_precise_mbclen(p, end, enc);
3957 p += rb_enc_mbminlen(enc);
3961 if (rb_enc_mbc_to_codepoint(p, end, enc) == (
unsigned int)delim) {
3971appendline(rb_io_t *fptr,
int delim,
VALUE *strp,
long *lp, rb_encoding *enc)
3976 if (NEED_READCONV(fptr)) {
3977 SET_BINARY_MODE(fptr);
3978 make_readconv(fptr, 0);
3981 int searchlen = READ_CHAR_PENDING_COUNT(fptr);
3983 p = READ_CHAR_PENDING_PTR(fptr);
3984 if (0 < limit && limit < searchlen)
3985 searchlen = (int)limit;
3986 e = search_delim(p, searchlen, delim, enc);
3988 int len = (int)(e-p);
4010 return (
unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
4013 }
while (more_char(fptr) != MORE_CHAR_FINISHED);
4014 clear_readconv(fptr);
4019 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4021 long pending = READ_DATA_PENDING_COUNT(fptr);
4023 const char *p = READ_DATA_PENDING_PTR(fptr);
4027 if (limit > 0 && pending > limit) pending = limit;
4028 e = search_delim(p, pending, delim, enc);
4029 if (e) pending = e - p;
4031 last = RSTRING_LEN(str);
4032 rb_str_resize(str, last + pending);
4039 read_buffered_data(RSTRING_PTR(str) + last, pending, fptr);
4042 if (e)
return delim;
4044 return (
unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
4047 }
while (io_fillbuf(fptr) >= 0);
4053swallow(rb_io_t *fptr,
int term)
4055 if (NEED_READCONV(fptr)) {
4056 rb_encoding *enc = io_read_encoding(fptr);
4057 int needconv = rb_enc_mbminlen(enc) != 1;
4058 SET_BINARY_MODE(fptr);
4059 make_readconv(fptr, 0);
4062 while ((cnt = READ_CHAR_PENDING_COUNT(fptr)) > 0) {
4063 const char *p = READ_CHAR_PENDING_PTR(fptr);
4066 if (*p != term)
return TRUE;
4068 while (--i && *++p == term);
4071 const char *e = p + cnt;
4072 if (rb_enc_ascget(p, e, &i, enc) != term)
return TRUE;
4073 while ((p += i) < e && rb_enc_ascget(p, e, &i, enc) == term);
4076 io_shift_cbuf(fptr, (
int)cnt - i, NULL);
4078 }
while (more_char(fptr) != MORE_CHAR_FINISHED);
4082 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4085 while ((cnt = READ_DATA_PENDING_COUNT(fptr)) > 0) {
4087 const char *p = READ_DATA_PENDING_PTR(fptr);
4089 if (cnt >
sizeof buf) cnt =
sizeof buf;
4090 if (*p != term)
return TRUE;
4092 while (--i && *++p == term);
4093 if (!read_buffered_data(buf, cnt - i, fptr))
4094 rb_sys_fail_path(fptr->
pathv);
4097 }
while (io_fillbuf(fptr) == 0);
4102rb_io_getline_fast(rb_io_t *fptr, rb_encoding *enc,
int chomp)
4110 int pending = READ_DATA_PENDING_COUNT(fptr);
4113 const char *p = READ_DATA_PENDING_PTR(fptr);
4117 e = memchr(p,
'\n', pending);
4119 pending = (int)(e - p + 1);
4121 chomplen = (pending > 1 && *(e-1) ==
'\r') + 1;
4130 rb_str_resize(str,
len + pending - chomplen);
4131 read_buffered_data(RSTRING_PTR(str)+
len, pending - chomplen, fptr);
4134 if (pending == 1 && chomplen == 1 &&
len > 0) {
4135 if (RSTRING_PTR(str)[
len-1] ==
'\r') {
4136 rb_str_resize(str, --
len);
4141 len += pending - chomplen;
4147 }
while (io_fillbuf(fptr) >= 0);
4150 str = io_enc_str(str, fptr);
4161 unsigned int chomp: 1;
4172 kwds[0] = rb_intern_const(
"chomp");
4175 chomp = (!UNDEF_P(vchomp)) &&
RTEST(vchomp);
4177 args->chomp = chomp;
4195 else if (2 <= argc) {
4196 rs = argv[0], lim = argv[1];
4205check_getline_args(
VALUE *rsp,
long *limit,
VALUE io)
4211 rb_encoding *enc_rs, *enc_io;
4214 enc_rs = rb_enc_get(rs);
4215 enc_io = io_read_encoding(fptr);
4216 if (enc_io != enc_rs &&
4217 (!is_ascii_string(rs) ||
4218 (RSTRING_LEN(rs) > 0 && !rb_enc_asciicompat(enc_io)))) {
4220 rs = rb_enc_str_new(0, 0, enc_io);
4225 rb_raise(rb_eArgError,
"encoding mismatch: %s IO with %s RS",
4226 rb_enc_name(enc_io),
4227 rb_enc_name(enc_rs));
4237 argc =
rb_scan_args(argc, argv,
"02:", NULL, NULL, &opts);
4238 extract_getline_args(argc, argv, args);
4239 extract_getline_opts(opts, args);
4240 check_getline_args(&args->rs, &args->limit, io);
4244rb_io_getline_0(
VALUE rs,
long limit,
int chomp, rb_io_t *fptr)
4251 if (
NIL_P(rs) && limit < 0) {
4252 str = read_all(fptr, 0,
Qnil);
4253 if (RSTRING_LEN(str) == 0)
return Qnil;
4255 else if (limit == 0) {
4256 return rb_enc_str_new(0, 0, io_read_encoding(fptr));
4258 else if (rs ==
rb_default_rs && limit < 0 && !NEED_READCONV(fptr) &&
4259 rb_enc_asciicompat(enc = io_read_encoding(fptr))) {
4260 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4261 return rb_io_getline_fast(fptr, enc, chomp);
4264 int c, newline = -1;
4265 const char *rsptr = 0;
4268 int extra_limit = 16;
4269 int chomp_cr = chomp;
4271 SET_BINARY_MODE(fptr);
4272 enc = io_read_encoding(fptr);
4275 rslen = RSTRING_LEN(rs);
4280 swallow(fptr,
'\n');
4282 if (!rb_enc_asciicompat(enc)) {
4286 rsptr = RSTRING_PTR(rs);
4287 rslen = RSTRING_LEN(rs);
4291 else if (rb_enc_mbminlen(enc) == 1) {
4292 rsptr = RSTRING_PTR(rs);
4293 newline = (
unsigned char)rsptr[rslen - 1];
4297 rsptr = RSTRING_PTR(rs);
4298 const char *e = rsptr + rslen;
4299 const char *last = rb_enc_prev_char(rsptr, e, e, enc);
4301 newline = rb_enc_codepoint_len(last, e, &n, enc);
4302 if (last + n != e) rb_raise(rb_eArgError,
"broken separator");
4304 chomp_cr = chomp && newline ==
'\n' && rslen == rb_enc_mbminlen(enc);
4308 while ((c = appendline(fptr, newline, &str, &limit, enc)) != EOF) {
4309 const char *s, *p, *pp, *e;
4311 if (c == newline && RSTRING_LEN(str) >= rslen) {
4312 s = RSTRING_PTR(str);
4313 e = RSTRING_END(str);
4315 if (at_char_boundary(s, p, e, enc)) {
4316 if (!rspara) rscheck(rsptr, rslen, rs);
4317 if (memcmp(p, rsptr, rslen) == 0) {
4319 if (chomp_cr && p > s && *(p-1) ==
'\r') --p;
4327 s = RSTRING_PTR(str);
4328 p = RSTRING_END(str);
4329 pp = rb_enc_prev_char(s, p, p, enc);
4330 if (extra_limit && pp &&
4344 if (rspara && c != EOF)
4345 swallow(fptr,
'\n');
4347 str = io_enc_str(str, fptr);
4350 if (!
NIL_P(str) && !nolimit) {
4358rb_io_getline_1(
VALUE rs,
long limit,
int chomp,
VALUE io)
4361 int old_lineno, new_lineno;
4365 old_lineno = fptr->
lineno;
4366 str = rb_io_getline_0(rs, limit, chomp, fptr);
4367 if (!
NIL_P(str) && (new_lineno = fptr->
lineno) != old_lineno) {
4368 if (io == ARGF.current_file) {
4369 ARGF.lineno += new_lineno - old_lineno;
4370 ARGF.last_lineno = ARGF.lineno;
4373 ARGF.last_lineno = new_lineno;
4381rb_io_getline(
int argc,
VALUE *argv,
VALUE io)
4385 prepare_getline_args(argc, argv, &args, io);
4386 return rb_io_getline_1(args.rs, args.limit, args.chomp, io);
4396rb_io_gets_limit_internal(
VALUE io,
long limit)
4404rb_io_gets_internal(
VALUE io)
4406 return rb_io_gets_limit_internal(io, -1);
4486 str = rb_io_getline(argc, argv, io);
4502rb_io_lineno(
VALUE io)
4557 check_getline_args(&sep, &limit, io);
4559 VALUE line = rb_io_getline_1(sep, limit,
RTEST(chomp), io);
4560 rb_lastline_set_up(line, 1);
4635rb_io_readlines(
int argc,
VALUE *argv,
VALUE io)
4639 prepare_getline_args(argc, argv, &args, io);
4640 return io_readlines(&args, io);
4648 if (arg->limit == 0)
4649 rb_raise(rb_eArgError,
"invalid limit: 0 for readlines");
4651 while (!
NIL_P(line = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, io))) {
4764rb_io_each_line(
int argc,
VALUE *argv,
VALUE io)
4770 prepare_getline_args(argc, argv, &args, io);
4771 if (args.limit == 0)
4772 rb_raise(rb_eArgError,
"invalid limit: 0 for each_line");
4773 while (!
NIL_P(str = rb_io_getline_1(args.rs, args.limit, args.chomp, io))) {
4800rb_io_each_byte(
VALUE io)
4816 }
while (io_fillbuf(fptr) >= 0);
4821io_getc(rb_io_t *fptr, rb_encoding *enc)
4826 if (NEED_READCONV(fptr)) {
4827 rb_encoding *read_enc = io_read_encoding(fptr);
4830 SET_BINARY_MODE(fptr);
4831 make_readconv(fptr, 0);
4845 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4847 clear_readconv(fptr);
4851 str = rb_enc_str_new(fptr->
cbuf.
ptr+fptr->
cbuf.
off, 1, read_enc);
4854 if (fptr->
cbuf.
len == 0) clear_readconv(fptr);
4863 io_shift_cbuf(fptr, r, &str);
4870 ISASCII(RSTRING_PTR(str)[0])) {
4874 str = io_enc_str(str, fptr);
4879 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4880 if (io_fillbuf(fptr) < 0) {
4883 if (rb_enc_asciicompat(enc) && ISASCII(fptr->
rbuf.
ptr[fptr->
rbuf.
off])) {
4902 if (io_fillbuf(fptr) != -1) {
4906 r = rb_enc_precise_mbclen(RSTRING_PTR(str), RSTRING_PTR(str)+RSTRING_LEN(str), enc);
4922 str = io_enc_str(str, fptr);
4948rb_io_each_char(
VALUE io)
4958 enc = io_input_encoding(fptr);
4960 while (!
NIL_P(c = io_getc(fptr, enc))) {
4986rb_io_each_codepoint(
VALUE io)
4998 enc = io_read_encoding(fptr);
4999 if (NEED_READCONV(fptr)) {
5000 SET_BINARY_MODE(fptr);
5003 make_readconv(fptr, 0);
5015 if (more_char(fptr) == MORE_CHAR_FINISHED) {
5016 clear_readconv(fptr);
5036 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
5037 while (io_fillbuf(fptr) >= 0) {
5052 char cbuf[8], *p = cbuf;
5054 if (more > numberof(cbuf))
goto invalid;
5056 if (more > numberof(cbuf))
goto invalid;
5057 while ((n = (
int)read_buffered_data(p, more, fptr)) > 0 &&
5058 (p += n, (more -= n) > 0)) {
5059 if (io_fillbuf(fptr) < 0)
goto invalid;
5060 if ((n = fptr->
rbuf.
len) > more) n = more;
5062 r = rb_enc_precise_mbclen(cbuf, p, enc);
5064 c = rb_enc_codepoint(cbuf, p, enc);
5075 rb_raise(rb_eArgError,
"invalid byte sequence in %s", rb_enc_name(enc));
5107 enc = io_input_encoding(fptr);
5109 return io_getc(fptr, enc);
5132rb_io_readchar(
VALUE io)
5134 VALUE c = rb_io_getc(io);
5169 VALUE r_stdout = rb_ractor_stdout();
5174 rb_io_flush(r_stdout);
5177 if (io_fillbuf(fptr) < 0) {
5206rb_io_readbyte(
VALUE io)
5267 unsigned char c =
NUM2INT(v) & 0xFF;
5273 io_ungetbyte(b, fptr);
5329 else if (RB_BIGNUM_TYPE_P(c)) {
5335 if (NEED_READCONV(fptr)) {
5336 SET_BINARY_MODE(fptr);
5337 len = RSTRING_LEN(c);
5338#if SIZEOF_LONG > SIZEOF_INT
5342 make_readconv(fptr, (
int)
len);
5356 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
5357 io_ungetbyte(c, fptr);
5377rb_io_isatty(
VALUE io)
5382 return RBOOL(isatty(fptr->
fd) != 0);
5385#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5401rb_io_close_on_exec_p(
VALUE io)
5407 write_io = GetWriteIO(io);
5408 if (io != write_io) {
5410 if (fptr && 0 <= (fd = fptr->
fd)) {
5411 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->
pathv);
5412 if (!(ret & FD_CLOEXEC))
return Qfalse;
5417 if (fptr && 0 <= (fd = fptr->
fd)) {
5418 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->
pathv);
5419 if (!(ret & FD_CLOEXEC))
return Qfalse;
5424#define rb_io_close_on_exec_p rb_f_notimplement
5427#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5451 int flag =
RTEST(arg) ? FD_CLOEXEC : 0;
5456 write_io = GetWriteIO(io);
5457 if (io != write_io) {
5459 if (fptr && 0 <= (fd = fptr->
fd)) {
5460 if ((ret = fcntl(fptr->
fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->
pathv);
5461 if ((ret & FD_CLOEXEC) != flag) {
5462 ret = (ret & ~FD_CLOEXEC) | flag;
5463 ret = fcntl(fd, F_SETFD, ret);
5464 if (ret != 0) rb_sys_fail_path(fptr->
pathv);
5471 if (fptr && 0 <= (fd = fptr->
fd)) {
5472 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->
pathv);
5473 if ((ret & FD_CLOEXEC) != flag) {
5474 ret = (ret & ~FD_CLOEXEC) | flag;
5475 ret = fcntl(fd, F_SETFD, ret);
5476 if (ret != 0) rb_sys_fail_path(fptr->
pathv);
5482#define rb_io_set_close_on_exec rb_f_notimplement
5485#define RUBY_IO_EXTERNAL_P(f) ((f)->mode & FMODE_EXTERNAL)
5486#define PREP_STDIO_NAME(f) (RSTRING_PTR((f)->pathv))
5489finish_writeconv(rb_io_t *fptr,
int noalloc)
5491 unsigned char *ds, *dp, *de;
5495 unsigned char buf[1024];
5500 de = buf +
sizeof(buf);
5503 size_t remaining = dp-ds;
5504 long result = rb_io_write_memory(fptr, ds, remaining);
5508 if ((
size_t)result == remaining)
break;
5531 if (io_fflush(fptr) < 0) {
5539 fptr->
wbuf.
len += (int)(dp - ds);
5555finish_writeconv_sync(
VALUE arg)
5558 return finish_writeconv(p->fptr, p->noalloc);
5562nogvl_close(
void *
ptr)
5566 return (
void*)(intptr_t)close(*fd);
5570maygvl_close(
int fd,
int keepgvl)
5579 return IO_WITHOUT_GVL_INT(nogvl_close, &fd);
5583nogvl_fclose(
void *
ptr)
5587 return (
void*)(intptr_t)fclose(file);
5591maygvl_fclose(FILE *file,
int keepgvl)
5594 return fclose(file);
5596 return IO_WITHOUT_GVL_INT(nogvl_fclose, file);
5602fptr_finalize_flush(rb_io_t *fptr,
int noraise,
int keepgvl)
5607 int mode = fptr->
mode;
5613 arg.noalloc = noraise;
5617 error = finish_writeconv(fptr, noraise);
5622 io_flush_buffer_sync(fptr);
5625 if (io_fflush(fptr) < 0 &&
NIL_P(error)) {
5633 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2) {
5643 rb_thread_io_close_wait(fptr);
5645 if (!done && stdio_file) {
5647 if ((maygvl_fclose(stdio_file, noraise) < 0) &&
NIL_P(error)) {
5657 if (!done && fd >= 0 && scheduler !=
Qnil) {
5660 if (!UNDEF_P(result)) {
5661 done =
RTEST(result);
5665 if (!done && fd >= 0) {
5671 if ((maygvl_close(fd, keepgvl) < 0) &&
NIL_P(error)) {
5680 if (!
NIL_P(error) && !noraise) {
5689fptr_finalize(rb_io_t *fptr,
int noraise)
5691 fptr_finalize_flush(fptr, noraise, FALSE);
5692 free_io_buffer(&fptr->
rbuf);
5693 free_io_buffer(&fptr->
wbuf);
5694 clear_codeconv(fptr);
5698rb_io_fptr_cleanup(rb_io_t *fptr,
int noraise)
5704 fptr_finalize(fptr, noraise);
5712 ruby_sized_xfree(buf->
ptr, (
size_t)buf->
capa);
5718clear_readconv(rb_io_t *fptr)
5724 free_io_buffer(&fptr->
cbuf);
5728clear_writeconv(rb_io_t *fptr)
5738clear_codeconv(rb_io_t *fptr)
5740 clear_readconv(fptr);
5741 clear_writeconv(fptr);
5745rb_io_fptr_cleanup_all(rb_io_t *fptr)
5749 rb_io_fptr_cleanup(fptr, TRUE);
5751 free_io_buffer(&fptr->
rbuf);
5752 free_io_buffer(&fptr->
wbuf);
5753 clear_codeconv(fptr);
5760 rb_io_fptr_cleanup_all(io);
5767rb_io_memsize(
const rb_io_t *io)
5769 size_t size =
sizeof(rb_io_t);
5779 rb_serial_t fork_generation = GET_VM()->fork_gen;
5780 if (io->fork_generation == fork_generation) {
5791# define KEEPGVL TRUE
5793# define KEEPGVL FALSE
5797io_close_fptr(
VALUE io)
5801 rb_io_t *write_fptr;
5803 write_io = GetWriteIO(io);
5804 if (io != write_io) {
5805 write_fptr =
RFILE(write_io)->fptr;
5806 if (write_fptr && 0 <= write_fptr->
fd) {
5807 rb_io_fptr_cleanup(write_fptr, TRUE);
5811 fptr =
RFILE(io)->fptr;
5812 if (!fptr)
return 0;
5813 if (fptr->
fd < 0)
return 0;
5816 if (rb_thread_io_close_interrupt(fptr)) {
5818 fptr_finalize_flush(fptr, FALSE, KEEPGVL);
5821 rb_io_fptr_cleanup(fptr, FALSE);
5826fptr_waitpid(rb_io_t *fptr,
int nohang)
5830 rb_last_status_clear();
5839 rb_io_t *fptr = io_close_fptr(io);
5840 if (fptr) fptr_waitpid(fptr, 0);
5880rb_io_close_m(
VALUE io)
5882 rb_io_t *fptr = rb_io_get_fptr(io);
5891io_call_close(
VALUE io)
5900 enum {mesg_len =
sizeof(closed_stream)-1};
5901 VALUE mesg = rb_attr_get(exc, idMesg);
5903 RSTRING_LEN(mesg) != mesg_len ||
5904 memcmp(RSTRING_PTR(mesg), closed_stream, mesg_len)) {
5914 if (!UNDEF_P(closed) &&
RTEST(closed))
return io;
5915 rb_rescue2(io_call_close, io, ignore_closed_stream, io,
5949 rb_io_t *write_fptr;
5951 write_io = GetWriteIO(io);
5952 if (io != write_io) {
5953 write_fptr =
RFILE(write_io)->fptr;
5954 if (write_fptr && 0 <= write_fptr->
fd) {
5959 fptr = rb_io_get_fptr(io);
5960 return RBOOL(0 > fptr->
fd);
5996rb_io_close_read(
VALUE io)
6002 if (fptr->
fd < 0)
return Qnil;
6003 if (is_socket(fptr->
fd, fptr->
pathv)) {
6007 if (shutdown(fptr->
fd, SHUT_RD) < 0)
6008 rb_sys_fail_path(fptr->
pathv);
6015 write_io = GetWriteIO(io);
6016 if (io != write_io) {
6021 RFILE(io)->fptr = wfptr;
6024 RFILE(write_io)->fptr = fptr;
6025 rb_io_fptr_cleanup(fptr, FALSE);
6031 rb_raise(
rb_eIOError,
"closing non-duplex IO for reading");
6069rb_io_close_write(
VALUE io)
6074 write_io = GetWriteIO(io);
6076 if (fptr->
fd < 0)
return Qnil;
6077 if (is_socket(fptr->
fd, fptr->
pathv)) {
6081 if (shutdown(fptr->
fd, SHUT_WR) < 0)
6082 rb_sys_fail_path(fptr->
pathv);
6090 rb_raise(
rb_eIOError,
"closing non-duplex IO for writing");
6093 if (io != write_io) {
6113rb_io_sysseek(
int argc,
VALUE *argv,
VALUE io)
6115 VALUE offset, ptrname;
6116 int whence = SEEK_SET;
6120 if (
rb_scan_args(argc, argv,
"11", &offset, &ptrname) == 2) {
6121 whence = interpret_seek_whence(ptrname);
6126 (READ_DATA_BUFFERED(fptr) || READ_CHAR_PENDING(fptr))) {
6130 rb_warn(
"sysseek for buffered IO");
6133 pos = lseek(fptr->
fd, pos, whence);
6134 if (pos < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
6168 io = GetWriteIO(io);
6173 rb_warn(
"syswrite for buffered IO");
6176 tmp = rb_str_tmp_frozen_acquire(str);
6178 n = rb_io_write_memory(fptr,
ptr,
len);
6179 if (n < 0) rb_sys_fail_path(fptr->
pathv);
6180 rb_str_tmp_frozen_release(str, tmp);
6197rb_io_sysread(
int argc,
VALUE *argv,
VALUE io)
6208 shrinkable = io_setstrbuf(&str, ilen);
6209 if (ilen == 0)
return str;
6214 if (READ_DATA_BUFFERED(fptr)) {
6220 io_setstrbuf(&str, ilen);
6225 iis.buf = RSTRING_PTR(str);
6228 n = io_read_memory_locktmp(str, &iis);
6231 rb_sys_fail_path(fptr->
pathv);
6234 io_set_read_length(str, n, shrinkable);
6236 if (n == 0 && ilen > 0) {
6252internal_pread_func(
void *_arg)
6256 return (
VALUE)pread(arg->fd, arg->buf, arg->count, arg->offset);
6260pread_internal_call(
VALUE _arg)
6265 if (scheduler !=
Qnil) {
6268 if (!UNDEF_P(result)) {
6269 return rb_fiber_scheduler_io_result_apply(result);
6273 return rb_io_blocking_region_wait(arg->io, internal_pread_func, arg,
RUBY_IO_READABLE);
6317 shrinkable = io_setstrbuf(&str, (
long)arg.count);
6318 if (arg.count == 0)
return str;
6319 arg.buf = RSTRING_PTR(str);
6332 rb_sys_fail_path(fptr->
pathv);
6334 io_set_read_length(str, n, shrinkable);
6335 if (n == 0 && arg.count > 0) {
6343internal_pwrite_func(
void *_arg)
6347 return (
VALUE)pwrite(arg->fd, arg->buf, arg->count, arg->offset);
6351pwrite_internal_call(
VALUE _arg)
6356 if (scheduler !=
Qnil) {
6359 if (!UNDEF_P(result)) {
6360 return rb_fiber_scheduler_io_result_apply(result);
6364 return rb_io_blocking_region_wait(arg->io, internal_pwrite_func, arg,
RUBY_IO_WRITABLE);
6405 io = GetWriteIO(io);
6412 tmp = rb_str_tmp_frozen_acquire(str);
6413 arg.buf = RSTRING_PTR(tmp);
6414 arg.count = (size_t)RSTRING_LEN(tmp);
6416 n = (ssize_t)pwrite_internal_call((
VALUE)&arg);
6417 if (n < 0) rb_sys_fail_path(fptr->
pathv);
6418 rb_str_tmp_frozen_release(str, tmp);
6438 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6441 setmode(fptr->
fd, O_BINARY);
6448io_ascii8bit_binmode(rb_io_t *fptr)
6460 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6462 fptr->
encs.
enc = rb_ascii8bit_encoding();
6466 clear_codeconv(fptr);
6475 io_ascii8bit_binmode(fptr);
6492rb_io_binmode_m(
VALUE io)
6498 write_io = GetWriteIO(io);
6513rb_io_binmode_p(
VALUE io)
6521rb_io_fmode_modestr(
enum rb_io_mode fmode)
6525 return MODE_BTMODE(
"a+",
"ab+",
"at+");
6527 return MODE_BTMODE(
"a",
"ab",
"at");
6531 rb_raise(rb_eArgError,
"invalid access fmode 0x%x", fmode);
6533 return MODE_BTMODE(
"r",
"rb",
"rt");
6535 return MODE_BTXMODE(
"w",
"wb",
"wt",
"wx",
"wbx",
"wtx");
6538 return MODE_BTXMODE(
"w+",
"wb+",
"wt+",
"w+x",
"wb+x",
"wt+x");
6540 return MODE_BTMODE(
"r+",
"rb+",
"rt+");
6544static const char bom_prefix[] =
"bom|";
6545static const char utf_prefix[] =
"utf-";
6546enum {bom_prefix_len = (int)
sizeof(bom_prefix) - 1};
6547enum {utf_prefix_len = (int)
sizeof(utf_prefix) - 1};
6550io_encname_bom_p(
const char *name,
long len)
6552 return len > bom_prefix_len &&
STRNCASECMP(name, bom_prefix, bom_prefix_len) == 0;
6558 enum rb_io_mode fmode = 0;
6559 const char *m = modestr, *p = NULL;
6587 if (modestr[0] !=
'w')
6595 if (io_encname_bom_p(m, p ? (
long)(p - m) : (
long)strlen(m)))
6608 rb_raise(rb_eArgError,
"invalid access mode %s", modestr);
6615 enum rb_io_mode fmode = 0;
6617 switch (oflags & O_ACCMODE) {
6629 if (oflags & O_APPEND) {
6632 if (oflags & O_TRUNC) {
6635 if (oflags & O_CREAT) {
6638 if (oflags & O_EXCL) {
6642 if (oflags & O_BINARY) {
6651rb_io_fmode_oflags(
enum rb_io_mode fmode)
6695rb_io_oflags_modestr(
int oflags)
6698# define MODE_BINARY(a,b) ((oflags & O_BINARY) ? (b) : (a))
6700# define MODE_BINARY(a,b) (a)
6703 if (oflags & O_EXCL) {
6704 rb_raise(rb_eArgError,
"exclusive access mode is not supported");
6706 accmode = oflags & (O_RDONLY|O_WRONLY|O_RDWR);
6707 if (oflags & O_APPEND) {
6708 if (accmode == O_WRONLY) {
6709 return MODE_BINARY(
"a",
"ab");
6711 if (accmode == O_RDWR) {
6712 return MODE_BINARY(
"a+",
"ab+");
6717 rb_raise(rb_eArgError,
"invalid access oflags 0x%x", oflags);
6719 return MODE_BINARY(
"r",
"rb");
6721 return MODE_BINARY(
"w",
"wb");
6723 if (oflags & O_TRUNC) {
6724 return MODE_BINARY(
"w+",
"wb+");
6726 return MODE_BINARY(
"r+",
"rb+");
6736rb_io_ext_int_to_encs(rb_encoding *ext, rb_encoding *intern, rb_encoding **enc, rb_encoding **enc2,
enum rb_io_mode fmode)
6738 int default_ext = 0;
6741 ext = rb_default_external_encoding();
6744 if (rb_is_ascii8bit_enc(ext)) {
6748 else if (intern == NULL) {
6749 intern = rb_default_internal_encoding();
6751 if (intern == NULL || intern == (rb_encoding *)
Qnil ||
6754 *enc = (default_ext && intern != ext) ? NULL : ext;
6764unsupported_encoding(
const char *name, rb_encoding *enc)
6766 rb_enc_warn(enc,
"Unsupported encoding %s ignored", name);
6770parse_mode_enc(
const char *estr, rb_encoding *estr_enc,
6771 rb_encoding **enc_p, rb_encoding **enc2_p,
enum rb_io_mode *fmode_p)
6776 enum rb_io_mode fmode = fmode_p ? *fmode_p : 0;
6777 rb_encoding *ext_enc, *int_enc;
6782 p = strrchr(estr,
':');
6783 len = p ? (p++ - estr) : (long)strlen(estr);
6785 estr += bom_prefix_len;
6786 len -= bom_prefix_len;
6787 if (!
STRNCASECMP(estr, utf_prefix, utf_prefix_len)) {
6791 rb_enc_warn(estr_enc,
"BOM with non-UTF encoding %s is nonsense", estr);
6800 memcpy(encname, estr,
len);
6801 encname[
len] =
'\0';
6804 idx = rb_enc_find_index(estr);
6806 if (fmode_p) *fmode_p = fmode;
6809 ext_enc = rb_enc_from_index(idx);
6812 unsupported_encoding(estr, estr_enc);
6818 if (*p ==
'-' && *(p+1) ==
'\0') {
6820 int_enc = (rb_encoding *)
Qnil;
6823 idx2 = rb_enc_find_index(p);
6825 unsupported_encoding(p, estr_enc);
6827 int_enc = (rb_encoding *)
Qnil;
6830 int_enc = rb_enc_from_index(idx2);
6834 rb_io_ext_int_to_encs(ext_enc, int_enc, enc_p, enc2_p, fmode);
6842 rb_encoding *extencoding = NULL;
6843 rb_encoding *intencoding = NULL;
6847 v = rb_hash_lookup2(opt, sym_encoding,
Qnil);
6848 if (v !=
Qnil) encoding = v;
6849 v = rb_hash_lookup2(opt, sym_extenc,
Qundef);
6850 if (v !=
Qnil) extenc = v;
6851 v = rb_hash_lookup2(opt, sym_intenc,
Qundef);
6852 if (!UNDEF_P(v)) intenc = v;
6854 if ((!UNDEF_P(extenc) || !UNDEF_P(intenc)) && !
NIL_P(encoding)) {
6856 int idx = rb_to_encoding_index(encoding);
6857 if (idx >= 0) encoding = rb_enc_from_encoding(rb_enc_from_index(idx));
6858 rb_warn(
"Ignoring encoding parameter '%"PRIsVALUE
"': %s_encoding is used",
6859 encoding, UNDEF_P(extenc) ?
"internal" :
"external");
6863 if (!UNDEF_P(extenc) && !
NIL_P(extenc)) {
6864 extencoding = rb_to_encoding(extenc);
6866 if (!UNDEF_P(intenc)) {
6867 if (
NIL_P(intenc)) {
6869 intencoding = (rb_encoding *)
Qnil;
6874 if (*p ==
'-' && *(p+1) ==
'\0') {
6876 intencoding = (rb_encoding *)
Qnil;
6879 intencoding = rb_to_encoding(intenc);
6883 intencoding = rb_to_encoding(intenc);
6885 if (extencoding == intencoding) {
6886 intencoding = (rb_encoding *)
Qnil;
6889 if (!
NIL_P(encoding)) {
6893 enc_p, enc2_p, fmode_p);
6896 rb_io_ext_int_to_encs(rb_to_encoding(encoding), NULL, enc_p, enc2_p, 0);
6899 else if (!UNDEF_P(extenc) || !UNDEF_P(intenc)) {
6901 rb_io_ext_int_to_encs(extencoding, intencoding, enc_p, enc2_p, 0);
6907validate_enc_binmode(
enum rb_io_mode *fmode_p,
int ecflags, rb_encoding *enc, rb_encoding *enc2)
6909 enum rb_io_mode fmode = *fmode_p;
6914 !rb_enc_asciicompat(enc ? enc : rb_default_external_encoding()))
6915 rb_raise(rb_eArgError,
"ASCII incompatible encoding needs binmode");
6918 rb_raise(rb_eArgError,
"newline decorator with binary mode");
6925#if !DEFAULT_TEXTMODE
6934extract_binmode(
VALUE opthash,
enum rb_io_mode *fmode)
6936 if (!
NIL_P(opthash)) {
6938 v = rb_hash_aref(opthash, sym_textmode);
6941 rb_raise(rb_eArgError,
"textmode specified twice");
6943 rb_raise(rb_eArgError,
"both textmode and binmode specified");
6947 v = rb_hash_aref(opthash, sym_binmode);
6950 rb_raise(rb_eArgError,
"binmode specified twice");
6952 rb_raise(rb_eArgError,
"both textmode and binmode specified");
6958 rb_raise(rb_eArgError,
"both textmode and binmode specified");
6964 int *oflags_p,
enum rb_io_mode *fmode_p,
struct rb_io_encoding *convconfig_p)
6968 enum rb_io_mode fmode;
6969 rb_encoding *enc, *enc2;
6972 int has_enc = 0, has_vmode = 0;
6978 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
6996 oflags = rb_io_fmode_oflags(fmode);
7000 parse_mode_enc(p+1, rb_enc_get(vmode), &enc, &enc2, &fmode);
7005 e = (fmode &
FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
7006 rb_io_ext_int_to_encs(e, NULL, &enc, &enc2, fmode);
7010 if (
NIL_P(opthash)) {
7014#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7016 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7017 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7019 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
7026 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
7029 else if (
NIL_P(vmode)) {
7030 fmode |= DEFAULT_TEXTMODE;
7037 v = rb_hash_aref(opthash, sym_mode);
7039 if (!
NIL_P(vmode)) {
7040 rb_raise(rb_eArgError,
"mode specified twice");
7047 v = rb_hash_aref(opthash, sym_flags);
7054 extract_binmode(opthash, &fmode);
7060 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
7063 else if (
NIL_P(vmode)) {
7064 fmode |= DEFAULT_TEXTMODE;
7067 v = rb_hash_aref(opthash, sym_perm);
7070 if (!
NIL_P(*vperm_p)) {
7071 rb_raise(rb_eArgError,
"perm specified twice");
7082#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7084 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7085 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7090 rb_raise(rb_eArgError,
"encoding specified twice");
7093 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
7097 validate_enc_binmode(&fmode, ecflags, enc, enc2);
7103 convconfig_p->
enc = enc;
7104 convconfig_p->
enc2 = enc2;
7105 convconfig_p->
ecflags = ecflags;
7106 convconfig_p->
ecopts = ecopts;
7116sysopen_func(
void *
ptr)
7119 const char *fname = RSTRING_PTR(data->fname);
7128 fd = IO_WITHOUT_GVL_INT(sysopen_func, data);
7129 }
while (fd < 0 &&
errno == EINTR);
7136rb_sysopen(
VALUE fname,
int oflags, mode_t perm)
7141 data.fname = rb_str_encode_ospath(fname);
7143 data.oflags = oflags;
7146 TRY_WITH_GC((fd = rb_sysopen_internal(&data)) >= 0) {
7147 rb_syserr_fail_path(first_errno, fname);
7153fdopen_internal(
int fd,
const char *modestr)
7160 file = fdopen(fd, modestr);
7176 TRY_WITH_GC((file = fdopen_internal(fd, modestr)) != 0) {
7182 if (setvbuf(file, NULL, _IOFBF, 0) != 0)
7183 rb_warn(
"setvbuf() can't be honoured (fd=%d)", fd);
7189io_check_tty(rb_io_t *fptr)
7191 int t = isatty(fptr->
fd);
7201io_strip_bom(
VALUE io)
7203 VALUE b1, b2, b3, b4;
7214 return rb_utf8_encindex();
7224 return ENCINDEX_UTF_16BE;
7235 return ENCINDEX_UTF_32LE;
7240 return ENCINDEX_UTF_16LE;
7250 return ENCINDEX_UTF_32BE;
7264io_set_encoding_by_bom(
VALUE io)
7266 int idx = io_strip_bom(io);
7268 rb_encoding *extenc = NULL;
7272 extenc = rb_enc_from_index(idx);
7273 io_encoding_set(fptr, rb_enc_from_encoding(extenc),
7274 rb_io_internal_encoding(io),
Qnil);
7283rb_file_open_generic(
VALUE io,
VALUE filename,
int oflags,
enum rb_io_mode fmode,
7291 rb_io_ext_int_to_encs(NULL, NULL, &cc.enc, &cc.enc2, fmode);
7296 validate_enc_binmode(&fmode, convconfig->
ecflags,
7297 convconfig->
enc, convconfig->
enc2);
7301 fptr->
encs = *convconfig;
7304 if (!(oflags & O_TMPFILE)) {
7305 fptr->
pathv = pathv;
7308 fptr->
pathv = pathv;
7310 fptr->
fd = rb_sysopen(pathv, oflags, perm);
7318rb_file_open_internal(
VALUE io,
VALUE filename,
const char *modestr)
7321 const char *p = strchr(modestr,
':');
7325 parse_mode_enc(p+1, rb_usascii_encoding(),
7326 &convconfig.
enc, &convconfig.
enc2, &fmode);
7332 e = (fmode &
FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
7333 rb_io_ext_int_to_encs(e, NULL, &convconfig.
enc, &convconfig.
enc2, fmode);
7339#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7341 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7342 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7344 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.
enc2, convconfig.
ecflags);
7347 return rb_file_open_generic(io, filename,
7348 rb_io_fmode_oflags(fmode),
7358 return rb_file_open_internal(io_alloc(
rb_cFile), fname, modestr);
7367#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7374pipe_add_fptr(rb_io_t *fptr)
7385pipe_del_fptr(rb_io_t *fptr)
7390 while ((tmp = *prev) != 0) {
7391 if (tmp->fptr == fptr) {
7400#if defined (_WIN32) || defined(__CYGWIN__)
7416pipe_finalize(rb_io_t *fptr,
int noraise)
7418#if !defined(HAVE_WORKING_FORK) && !defined(_WIN32)
7427 fptr_finalize(fptr, noraise);
7429 pipe_del_fptr(fptr);
7434fptr_copy_finalizer(rb_io_t *fptr,
const rb_io_t *orig)
7436#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7437 void (*
const old_finalize)(
struct rb_io*,int) = fptr->
finalize;
7439 if (old_finalize == orig->finalize)
return;
7444#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7445 if (old_finalize != pipe_finalize) {
7447 for (list =
pipe_list; list; list = list->next) {
7448 if (list->fptr == fptr)
break;
7450 if (!list) pipe_add_fptr(fptr);
7453 pipe_del_fptr(fptr);
7466rb_io_unbuffered(rb_io_t *fptr)
7484#define HAVE_SPAWNV 1
7485#define spawnv(mode, cmd, args) rb_w32_uaspawn((mode), (cmd), (args))
7486#define spawn(mode, cmd) rb_w32_uspawn((mode), (cmd), 0)
7489#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7492 struct rb_execarg *eargp;
7499#ifdef HAVE_WORKING_FORK
7500# ifndef __EMSCRIPTEN__
7502popen_redirect(
struct popen_arg *p)
7505 close(p->write_pair[1]);
7506 if (p->write_pair[0] != 0) {
7507 dup2(p->write_pair[0], 0);
7508 close(p->write_pair[0]);
7511 if (p->pair[1] != 1) {
7512 dup2(p->pair[1], 1);
7518 if (p->pair[1] != 1) {
7519 dup2(p->pair[1], 1);
7525 if (p->pair[0] != 0) {
7526 dup2(p->pair[0], 0);
7533#if defined(__linux__)
7544linux_get_maxfd(
void)
7547 char buf[4096], *p, *np, *e;
7550 if (fd < 0)
return fd;
7551 ss = read(fd, buf,
sizeof(buf));
7552 if (ss < 0)
goto err;
7555 while ((
int)
sizeof(
"FDSize:\t0\n")-1 <= e-p &&
7556 (np = memchr(p,
'\n', e-p)) != NULL) {
7557 if (memcmp(p,
"FDSize:",
sizeof(
"FDSize:")-1) == 0) {
7559 p +=
sizeof(
"FDSize:")-1;
7579#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
7581 int max = (int)max_file_descriptor;
7584 ret = fcntl(0, F_MAXFD);
7586 maxhint = max = ret;
7587# elif defined(__linux__)
7588 ret = linux_get_maxfd();
7595 for (fd = lowfd; fd <= max; fd++) {
7596 if (!
NIL_P(noclose_fds) &&
7599 ret = fcntl(fd, F_GETFD);
7600 if (ret != -1 && !(ret & FD_CLOEXEC)) {
7601 fcntl(fd, F_SETFD, ret|FD_CLOEXEC);
7603# define CONTIGUOUS_CLOSED_FDS 20
7605 if (max < fd + CONTIGUOUS_CLOSED_FDS)
7606 max = fd + CONTIGUOUS_CLOSED_FDS;
7612# ifndef __EMSCRIPTEN__
7614popen_exec(
void *pp,
char *errmsg,
size_t errmsg_len)
7616 struct popen_arg *p = (
struct popen_arg*)pp;
7618 return rb_exec_async_signal_safe(p->eargp, errmsg, errmsg_len);
7623#if (defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)) && !defined __EMSCRIPTEN__
7625rb_execarg_fixup_v(
VALUE execarg_obj)
7627 rb_execarg_parent_start(execarg_obj);
7631char *rb_execarg_commandline(
const struct rb_execarg *eargp,
VALUE *prog);
7634#ifndef __EMSCRIPTEN__
7636pipe_open(
VALUE execarg_obj,
const char *modestr,
enum rb_io_mode fmode,
7639 struct rb_execarg *eargp =
NIL_P(execarg_obj) ? NULL : rb_execarg_get(execarg_obj);
7640 VALUE prog = eargp ? (eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name) :
Qfalse ;
7644 rb_io_t *write_fptr;
7646#if defined(HAVE_WORKING_FORK)
7648 char errmsg[80] = {
'\0' };
7650#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7652 struct popen_arg arg;
7655#if defined(HAVE_SPAWNV)
7656# if defined(HAVE_SPAWNVE)
7657# define DO_SPAWN(cmd, args, envp) ((args) ? \
7658 spawnve(P_NOWAIT, (cmd), (args), (envp)) : \
7659 spawne(P_NOWAIT, (cmd), (envp)))
7661# define DO_SPAWN(cmd, args, envp) ((args) ? \
7662 spawnv(P_NOWAIT, (cmd), (args)) : \
7663 spawn(P_NOWAIT, (cmd)))
7665# if !defined(HAVE_WORKING_FORK)
7667# if defined(HAVE_SPAWNVE)
7672#if !defined(HAVE_WORKING_FORK)
7678#if !defined(HAVE_WORKING_FORK)
7679 const char *cmd = 0;
7685#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7686 arg.execarg_obj = execarg_obj;
7689 arg.pair[0] = arg.pair[1] = -1;
7690 arg.write_pair[0] = arg.write_pair[1] = -1;
7691# if !defined(HAVE_WORKING_FORK)
7692 if (eargp && !eargp->use_shell) {
7693 args = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
7698 if (
rb_pipe(arg.write_pair) < 0)
7699 rb_sys_fail_str(prog);
7702 close(arg.write_pair[0]);
7703 close(arg.write_pair[1]);
7707 rb_execarg_addopt(execarg_obj,
INT2FIX(0),
INT2FIX(arg.write_pair[0]));
7708 rb_execarg_addopt(execarg_obj,
INT2FIX(1),
INT2FIX(arg.pair[1]));
7713 rb_sys_fail_str(prog);
7715 rb_execarg_addopt(execarg_obj,
INT2FIX(1),
INT2FIX(arg.pair[1]));
7719 rb_sys_fail_str(prog);
7721 rb_execarg_addopt(execarg_obj,
INT2FIX(0),
INT2FIX(arg.pair[0]));
7724 rb_sys_fail_str(prog);
7726 if (!
NIL_P(execarg_obj)) {
7727 rb_protect(rb_execarg_fixup_v, execarg_obj, &state);
7729 if (0 <= arg.write_pair[0]) close(arg.write_pair[0]);
7730 if (0 <= arg.write_pair[1]) close(arg.write_pair[1]);
7731 if (0 <= arg.pair[0]) close(arg.pair[0]);
7732 if (0 <= arg.pair[1]) close(arg.pair[1]);
7733 rb_execarg_parent_end(execarg_obj);
7737# if defined(HAVE_WORKING_FORK)
7738 pid = rb_fork_async_signal_safe(&status, popen_exec, &arg, arg.eargp->redirect_fds, errmsg,
sizeof(errmsg));
7740 rb_execarg_run_options(eargp, sargp, NULL, 0);
7741# if defined(HAVE_SPAWNVE)
7742 if (eargp->envp_str) envp = (
char **)RSTRING_PTR(eargp->envp_str);
7744 while ((pid = DO_SPAWN(cmd, args, envp)) < 0) {
7746 switch (e =
errno) {
7748# if EWOULDBLOCK != EAGAIN
7757 rb_execarg_run_options(sargp, NULL, NULL, 0);
7759 rb_execarg_parent_end(execarg_obj);
7762# if defined(HAVE_WORKING_FORK)
7763 pid = rb_call_proc__fork();
7765 popen_redirect(&arg);
7777# if defined(HAVE_WORKING_FORK)
7783 close(arg.write_pair[0]);
7784 close(arg.write_pair[1]);
7786# if defined(HAVE_WORKING_FORK)
7795 close(arg.write_pair[0]);
7796 write_fd = arg.write_pair[1];
7807 cmd = rb_execarg_commandline(eargp, &prog);
7808 if (!
NIL_P(execarg_obj)) {
7809 rb_execarg_parent_start(execarg_obj);
7810 rb_execarg_run_options(eargp, sargp, NULL, 0);
7812 fp = popen(cmd, modestr);
7815 rb_execarg_parent_end(execarg_obj);
7816 rb_execarg_run_options(sargp, NULL, NULL, 0);
7818 if (!fp) rb_syserr_fail_path(e, prog);
7828 fptr->
encs = *convconfig;
7829#if RUBY_CRLF_ENVIRONMENT
7836 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
7839#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7840 if (NEED_NEWLINE_DECORATOR_ON_WRITE(fptr)) {
7841 fptr->
encs.
ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
7847 if (0 <= write_fd) {
7848 write_port = io_alloc(
rb_cIO);
7850 write_fptr->
fd = write_fd;
7854 rb_ivar_set(port, rb_intern(
"@tied_io_for_writing"), write_port);
7857#if defined (__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7859 pipe_add_fptr(fptr);
7865pipe_open(
VALUE execarg_obj,
const char *modestr,
enum rb_io_mode fmode,
7873is_popen_fork(
VALUE prog)
7875 if (RSTRING_LEN(prog) == 1 && RSTRING_PTR(prog)[0] ==
'-') {
7876#if !defined(HAVE_WORKING_FORK)
7878 "fork() function is unimplemented on this machine");
7887pipe_open_s(
VALUE prog,
const char *modestr,
enum rb_io_mode fmode,
7891 VALUE *argv = &prog;
7894 if (!is_popen_fork(prog))
7895 execarg_obj = rb_execarg_new(argc, argv, TRUE, FALSE);
7896 return pipe_open(execarg_obj, modestr, fmode, convconfig);
7902 rb_io_t *fptr = io_close_fptr(io);
8071rb_io_s_popen(
int argc,
VALUE *argv,
VALUE klass)
8075 if (argc > 1 && !
NIL_P(opt = rb_check_hash_type(argv[argc-1]))) --argc;
8076 if (argc > 1 && !
NIL_P(env = rb_check_hash_type(argv[0]))) --argc, ++argv;
8085 int ex = !
NIL_P(opt);
8086 rb_error_arity(argc + ex, 1 + ex, 2 + ex);
8089 return popen_finish(rb_io_popen(pname, pmode, env, opt), klass);
8095 const char *modestr;
8098 enum rb_io_mode fmode;
8104#if SIZEOF_LONG > SIZEOF_INT
8105 if (
len > INT_MAX) {
8106 rb_raise(rb_eArgError,
"too many arguments");
8115 if (!is_popen_fork(pname))
8116 execarg_obj = rb_execarg_new(1, &pname, TRUE, FALSE);
8118 if (!
NIL_P(execarg_obj)) {
8120 opt = rb_execarg_extract_options(execarg_obj, opt);
8122 rb_execarg_setenv(execarg_obj, env);
8125 modestr = rb_io_oflags_modestr(oflags);
8127 return pipe_open(execarg_obj, modestr, fmode, &convconfig);
8137 rb_io_flush(rb_ractor_stdout());
8138 rb_io_flush(rb_ractor_stderr());
8143 RBASIC_SET_CLASS(port, klass);
8150#if defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)
8151struct popen_writer_arg {
8153 struct popen_arg popen;
8157exec_popen_writer(
void *arg,
char *errmsg,
size_t buflen)
8159 struct popen_writer_arg *pw = arg;
8161 popen_redirect(&pw->popen);
8162 execv(pw->argv[0], pw->argv);
8163 strlcpy(errmsg, strerror(
errno), buflen);
8169ruby_popen_writer(
char *
const *argv, rb_pid_t *pid)
8171#if (defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)) || defined(_WIN32)
8172# ifdef HAVE_WORKING_FORK
8173 struct popen_writer_arg pw;
8174 int *
const write_pair = pw.popen.pair;
8180 if (cloexec_pipe(write_pair, 0,
false) == 0) {
8181# ifdef HAVE_WORKING_FORK
8184 char errmsg[80] = {
'\0'};
8185 *pid = rb_fork_async_signal_safe(&status, exec_popen_writer, &pw,
Qnil, errmsg,
sizeof(errmsg));
8187 *pid = rb_w32_uspawn_process(P_NOWAIT, argv[0], argv, write_pair[0], -1, -1, 0);
8188 const char *errmsg = (*pid < 0) ? strerror(
errno) : NULL;
8190 close(write_pair[0]);
8192 close(write_pair[1]);
8193 fprintf(stderr,
"ruby_popen_writer(%s): %s\n", argv[0], errmsg);
8196 return fdopen(write_pair[1],
"w");
8207 enum rb_io_mode fmode;
8216 rb_file_open_generic(io, fname, oflags, fmode, &convconfig, perm);
8254rb_io_s_open(
int argc,
VALUE *argv,
VALUE klass)
8286 VALUE fname, vmode, vperm;
8291 rb_scan_args(argc, argv,
"12", &fname, &vmode, &vperm);
8302 if (
NIL_P(vperm)) perm = 0666;
8306 fd = rb_sysopen(fname, oflags, perm);
8338 int redirect = FALSE;
8346 VALUE tmp = argv[0];
8364 return rb_io_s_open(argc, argv,
rb_cFile);
8368rb_io_open_generic(
VALUE klass,
VALUE filename,
int oflags,
enum rb_io_mode fmode,
8371 return rb_file_open_generic(io_alloc(klass), filename,
8372 oflags, fmode, convconfig, perm);
8379 enum rb_io_mode fmode;
8385 return rb_io_open_generic(io, filename, oflags, fmode, &convconfig, perm);
8391 rb_io_t *fptr, *orig;
8399 if (fptr == orig)
return io;
8400 if (RUBY_IO_EXTERNAL_P(fptr)) {
8404 rb_raise(rb_eArgError,
8405 "%s can't change access mode from \"%s\" to \"%s\"",
8406 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->
mode),
8407 rb_io_fmode_modestr(orig->
mode));
8411 if (io_fflush(fptr) < 0)
8412 rb_sys_fail_on_write(fptr);
8415 flush_before_seek(fptr,
true);
8418 pos = io_tell(orig);
8421 if (io_fflush(orig) < 0)
8422 rb_sys_fail_on_write(fptr);
8431 else if (!RUBY_IO_EXTERNAL_P(fptr)) fptr->
pathv =
Qnil;
8432 fptr_copy_finalizer(fptr, orig);
8438 rb_thread_io_close_interrupt(fptr);
8439 rb_thread_io_close_wait(fptr);
8441 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2 || !fptr->stdio_file) {
8444 rb_sys_fail_path(orig->
pathv);
8452 rb_sys_fail_path(orig->
pathv);
8458 if (io_seek(fptr, pos, SEEK_SET) < 0 &&
errno) {
8459 rb_sys_fail_path(fptr->
pathv);
8461 if (io_seek(orig, pos, SEEK_SET) < 0 &&
errno) {
8462 rb_sys_fail_path(orig->
pathv);
8476int rb_freopen(
VALUE fname,
const char *mode, FILE *fp);
8479rb_freopen(
VALUE fname,
const char *mode, FILE *fp)
8481 if (!freopen(RSTRING_PTR(fname), mode, fp)) {
8524rb_io_reopen(
int argc,
VALUE *argv,
VALUE file)
8526 VALUE fname, nmode, opt;
8530 if (
rb_scan_args(argc, argv,
"11:", &fname, &nmode, &opt) == 1) {
8533 return io_reopen(file, tmp);
8539 fptr =
RFILE(file)->fptr;
8545 enum rb_io_mode fmode;
8549 if (RUBY_IO_EXTERNAL_P(fptr) &&
8552 rb_raise(rb_eArgError,
8553 "%s can't change access mode from \"%s\" to \"%s\"",
8554 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->
mode),
8555 rb_io_fmode_modestr(fmode));
8558 fptr->
encs = convconfig;
8561 oflags = rb_io_fmode_oflags(fptr->
mode);
8564 fptr->
pathv = fname;
8566 fptr->
fd = rb_sysopen(fptr->
pathv, oflags, 0666);
8572 if (io_fflush(fptr) < 0)
8573 rb_sys_fail_on_write(fptr);
8578 int e = rb_freopen(rb_str_encode_ospath(fptr->
pathv),
8579 rb_io_oflags_modestr(oflags),
8581 if (e) rb_syserr_fail_path(e, fptr->
pathv);
8585 if (setvbuf(fptr->
stdio_file, NULL, _IOFBF, 0) != 0)
8586 rb_warn(
"setvbuf() can't be honoured for %"PRIsVALUE, fptr->
pathv);
8589 if (setvbuf(fptr->
stdio_file, NULL, _IONBF, BUFSIZ) != 0)
8590 rb_warn(
"setvbuf() can't be honoured for %"PRIsVALUE, fptr->
pathv);
8592 else if (fptr->
stdio_file == stdout && isatty(fptr->
fd)) {
8593 if (setvbuf(fptr->
stdio_file, NULL, _IOLBF, BUFSIZ) != 0)
8594 rb_warn(
"setvbuf() can't be honoured for %"PRIsVALUE, fptr->
pathv);
8598 int tmpfd = rb_sysopen(fptr->
pathv, oflags, 0666);
8604 rb_syserr_fail_path(err, fptr->
pathv);
8615 rb_io_t *fptr, *orig;
8635 fptr->closing_ec = NULL;
8636 fptr->wakeup_mutex =
Qnil;
8637 fptr->fork_generation = GET_VM()->fork_gen;
8640 fptr_copy_finalizer(fptr, orig);
8642 fd = ruby_dup(orig->
fd);
8644 pos = io_tell(orig);
8646 io_seek(fptr, pos, SEEK_SET);
8651 write_io = GetWriteIO(io);
8652 if (io != write_io) {
8655 rb_ivar_set(dest, rb_intern(
"@tied_io_for_writing"), write_io);
8718 if (argc == 0)
return Qnil;
8719 if (RB_TYPE_P(argv[0],
T_STRING)) {
8720 out = rb_ractor_stdout();
8732extern void rb_deprecated_str_setter(
VALUE val,
ID id,
VALUE *var);
8737 rb_deprecated_str_setter(val,
id, &val);
8743 val = rb_str_frozen_bare_string(val);
8820 for (i=0; i<argc; i++) {
8824 rb_io_write(out, argv[i]);
8921 rb_io_write(io, str);
8925#define forward(obj, id, argc, argv) \
8926 rb_funcallv_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8927#define forward_public(obj, id, argc, argv) \
8928 rb_funcallv_public_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8929#define forward_current(id, argc, argv) \
8930 forward_public(ARGF.current_file, id, argc, argv)
8947 VALUE r_stdout = rb_ractor_stdout();
8948 if (recv == r_stdout) {
8949 return rb_io_putc(recv, ch);
8951 return forward(r_stdout, rb_intern(
"putc"), 1, &ch);
8956rb_str_end_with_asciichar(
VALUE str,
int c)
8958 long len = RSTRING_LEN(str);
8959 const char *
ptr = RSTRING_PTR(str);
8963 if (
len == 0)
return 0;
8964 if ((n = rb_enc_mbminlen(
enc)) == 1) {
8965 return ptr[
len - 1] == c;
8967 return rb_enc_ascget(
ptr + ((
len - 1) / n) * n,
ptr +
len, &n,
enc) == c;
8978 rb_io_puts(1, &tmp, out);
8985 rb_io_puts(1, &tmp, out);
9040 VALUE line, args[2];
9047 for (
int i = 0; i < argc; i++) {
9049 if (RB_TYPE_P(argv[i],
T_STRING)) {
9061 if (RSTRING_LEN(line) == 0) {
9066 if (!rb_str_end_with_asciichar(line,
'\n')) {
9071 rb_io_writev(out, n, args);
9089 VALUE r_stdout = rb_ractor_stdout();
9090 if (recv == r_stdout) {
9091 return rb_io_puts(argc, argv, recv);
9093 return forward(r_stdout, rb_intern(
"puts"), argc, argv);
9097rb_p_write(
VALUE str)
9102 VALUE r_stdout = rb_ractor_stdout();
9103 if (RB_TYPE_P(r_stdout,
T_FILE) &&
9104 rb_method_basic_definition_p(
CLASS_OF(r_stdout), id_write)) {
9105 io_writev(2, args, r_stdout);
9108 rb_io_writev(r_stdout, 2, args);
9120rb_p_result(
int argc,
const VALUE *argv)
9127 else if (argc > 1) {
9130 VALUE r_stdout = rb_ractor_stdout();
9131 if (RB_TYPE_P(r_stdout,
T_FILE)) {
9132 rb_uninterruptible(rb_io_flush, r_stdout);
9173 for (i=0; i<argc; i++) {
9175 rb_uninterruptible(rb_p_write, inspected);
9177 return rb_p_result(argc, argv);
9198rb_obj_display(
int argc,
VALUE *argv,
VALUE self)
9202 out = (!rb_check_arity(argc, 0, 1) ? rb_ractor_stdout() : argv[0]);
9203 rb_io_write(out, self);
9209rb_stderr_to_original_p(
VALUE err)
9211 return (err == orig_stderr ||
RFILE(orig_stderr)->fptr->
fd < 0);
9217 VALUE out = rb_ractor_stderr();
9218 if (rb_stderr_to_original_p(out)) {
9220 if (isatty(fileno(stderr))) {
9221 if (rb_w32_write_console(
rb_str_new(mesg,
len), fileno(stderr)) > 0)
return;
9224 if (fwrite(mesg,
sizeof(
char), (
size_t)
len, stderr) < (
size_t)
len) {
9241rb_write_error_str(
VALUE mesg)
9243 VALUE out = rb_ractor_stderr();
9245 if (rb_stderr_to_original_p(out)) {
9246 size_t len = (size_t)RSTRING_LEN(mesg);
9248 if (isatty(fileno(stderr))) {
9249 if (rb_w32_write_console(mesg, fileno(stderr)) > 0)
return;
9252 if (fwrite(RSTRING_PTR(mesg),
sizeof(
char),
len, stderr) <
len) {
9259 rb_io_write(out, mesg);
9264rb_stderr_tty_p(
void)
9266 if (rb_stderr_to_original_p(rb_ractor_stderr()))
9267 return isatty(fileno(stderr));
9272must_respond_to(
ID mid,
VALUE val,
ID id)
9275 rb_raise(
rb_eTypeError,
"%"PRIsVALUE
" must have %"PRIsVALUE
" method, %"PRIsVALUE
" given",
9276 rb_id2str(
id), rb_id2str(mid),
9296 must_respond_to(id_write, val,
id);
9303 return rb_ractor_stdout();
9309 must_respond_to(id_write, val,
id);
9316 return rb_ractor_stderr();
9320allocate_and_open_new_file(
VALUE klass)
9322 VALUE self = io_alloc(klass);
9323 rb_io_make_open_file(self);
9331 VALUE self = rb_protect(allocate_and_open_new_file, klass, &state);
9339 maygvl_close(descriptor, 0);
9345 rb_io_t *io =
RFILE(self)->fptr;
9347 io->
fd = descriptor;
9365 io->closing_ec = NULL;
9366 io->wakeup_mutex =
Qnil;
9367 io->fork_generation = GET_VM()->fork_gen;
9370 io->
encs = *encoding;
9379prep_io(
int fd,
enum rb_io_mode fmode,
VALUE klass,
const char *path)
9389 e = (fmode &
FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
9390 rb_io_ext_int_to_encs(e, NULL, &convconfig.
enc, &convconfig.
enc2, fmode);
9394#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9396 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
9397 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
9399 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.
enc2, convconfig.
ecflags);
9403 rb_io_t*io =
RFILE(self)->fptr;
9405 if (!io_check_tty(io)) {
9408 setmode(fd, O_BINARY);
9420 if (path && strcmp(path,
"-")) klass =
rb_cFile;
9425prep_stdio(FILE *f,
enum rb_io_mode fmode,
VALUE klass,
const char *path)
9432#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9433 fptr->
encs.
ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
9444rb_io_prep_stdin(
void)
9450rb_io_prep_stdout(
void)
9456rb_io_prep_stderr(
void)
9465 int oflags = rb_io_fmode_oflags(fptr->
mode) & ~O_EXCL;
9480static inline rb_io_t *
9483 rb_io_t *fp =
ALLOC(rb_io_t);
9492 rb_io_buffer_init(&fp->
wbuf);
9493 rb_io_buffer_init(&fp->
rbuf);
9494 rb_io_buffer_init(&fp->
cbuf);
9509 fp->closing_ec = NULL;
9510 fp->wakeup_mutex =
Qnil;
9511 fp->fork_generation = GET_VM()->fork_gen;
9516rb_io_make_open_file(
VALUE obj)
9521 if (
RFILE(obj)->fptr) {
9524 RFILE(obj)->fptr = 0;
9526 fp = rb_io_fptr_new();
9528 RFILE(obj)->fptr = fp;
9576rb_io_initialize(
int argc,
VALUE *argv,
VALUE io)
9582 return io_initialize(io, fnum, vmode, opt);
9589 int fd, oflags = O_RDONLY;
9590 enum rb_io_mode fmode;
9592#if defined(HAVE_FCNTL) && defined(F_GETFL)
9602 rb_raise(rb_eArgError,
"The given fd is not accessible because RubyVM reserves it");
9604#if defined(HAVE_FCNTL) && defined(F_GETFL)
9605 oflags = fcntl(fd, F_GETFL);
9606 if (oflags == -1) rb_sys_fail(0);
9608 if (fstat(fd, &st) < 0) rb_sys_fail(0);
9611#if defined(HAVE_FCNTL) && defined(F_GETFL)
9624 if (rb_hash_aref(opt, sym_autoclose) ==
Qfalse) {
9628 path = rb_hash_aref(opt,
RB_ID2SYM(idPath));
9639 fp->
encs = convconfig;
9643 fp->closing_ec = NULL;
9644 fp->wakeup_mutex =
Qnil;
9645 fp->fork_generation = GET_VM()->fork_gen;
9648 if (fileno(stdin) == fd)
9650 else if (fileno(stdout) == fd)
9652 else if (fileno(stderr) == fd)
9684rb_io_set_encoding_by_bom(
VALUE io)
9690 rb_raise(rb_eArgError,
"ASCII incompatible encoding needs binmode");
9693 rb_raise(rb_eArgError,
"encoding conversion is set");
9695 else if (fptr->
encs.
enc && fptr->
encs.
enc != rb_ascii8bit_encoding()) {
9696 rb_raise(rb_eArgError,
"encoding is set to %s already",
9699 if (!io_set_encoding_by_bom(io))
return Qnil;
9700 return rb_enc_from_encoding(fptr->
encs.
enc);
9745rb_file_initialize(
int argc,
VALUE *argv,
VALUE io)
9747 if (
RFILE(io)->fptr) {
9750 VALUE fname, vmode, vperm, opt;
9751 int posargc =
rb_scan_args(argc, argv,
"12:", &fname, &vmode, &vperm, &opt);
9756 return io_initialize(io, fd, vmode, opt);
9759 return rb_open_file(io, fname, vmode, vperm, opt);
9764rb_io_s_new(
int argc,
VALUE *argv,
VALUE klass)
9769 rb_warn(
"%"PRIsVALUE
"::new() does not take block; use %"PRIsVALUE
"::open() instead",
9785rb_io_s_for_fd(
int argc,
VALUE *argv,
VALUE klass)
9788 rb_io_initialize(argc, argv, io);
9801rb_io_autoclose_p(
VALUE io)
9803 rb_io_t *fptr =
RFILE(io)->fptr;
9826rb_io_set_autoclose(
VALUE io,
VALUE autoclose)
9830 if (!
RTEST(autoclose))
9838io_wait_event(
VALUE io,
int event,
VALUE timeout,
int return_io)
9842 if (!RB_TEST(result)) {
9870io_wait_readable(
int argc,
VALUE *argv,
VALUE io)
9879 rb_check_arity(argc, 0, 1);
9880 VALUE timeout = (argc == 1 ? argv[0] :
Qnil);
9894io_wait_writable(
int argc,
VALUE *argv,
VALUE io)
9901 rb_check_arity(argc, 0, 1);
9902 VALUE timeout = (argc == 1 ? argv[0] :
Qnil);
9917io_wait_priority(
int argc,
VALUE *argv,
VALUE io)
9919 rb_io_t *fptr = NULL;
9926 rb_check_arity(argc, 0, 1);
9927 VALUE timeout = argc == 1 ? argv[0] :
Qnil;
9933wait_mode_sym(
VALUE mode)
9935 if (mode ==
ID2SYM(rb_intern(
"r"))) {
9936 return RB_WAITFD_IN;
9938 if (mode ==
ID2SYM(rb_intern(
"read"))) {
9939 return RB_WAITFD_IN;
9941 if (mode ==
ID2SYM(rb_intern(
"readable"))) {
9942 return RB_WAITFD_IN;
9944 if (mode ==
ID2SYM(rb_intern(
"w"))) {
9945 return RB_WAITFD_OUT;
9947 if (mode ==
ID2SYM(rb_intern(
"write"))) {
9948 return RB_WAITFD_OUT;
9950 if (mode ==
ID2SYM(rb_intern(
"writable"))) {
9951 return RB_WAITFD_OUT;
9953 if (mode ==
ID2SYM(rb_intern(
"rw"))) {
9954 return RB_WAITFD_IN|RB_WAITFD_OUT;
9956 if (mode ==
ID2SYM(rb_intern(
"read_write"))) {
9957 return RB_WAITFD_IN|RB_WAITFD_OUT;
9959 if (mode ==
ID2SYM(rb_intern(
"readable_writable"))) {
9960 return RB_WAITFD_IN|RB_WAITFD_OUT;
9963 rb_raise(rb_eArgError,
"unsupported mode: %"PRIsVALUE, mode);
9967io_event_from_value(
VALUE value)
9971 if (events <= 0) rb_raise(rb_eArgError,
"Events must be positive integer!");
10004 if (argc != 2 || (RB_SYMBOL_P(argv[0]) || RB_SYMBOL_P(argv[1]))) {
10009 for (
int i = 0; i < argc; i += 1) {
10010 if (RB_SYMBOL_P(argv[i])) {
10011 events |= wait_mode_sym(argv[i]);
10013 else if (UNDEF_P(timeout)) {
10017 rb_raise(rb_eArgError,
"timeout given more than once");
10021 if (UNDEF_P(timeout)) timeout =
Qnil;
10029 events = io_event_from_value(argv[0]);
10034 rb_io_t *fptr = NULL;
10039 if (return_io)
return Qtrue;
10045 return io_wait_event(io, events, timeout, return_io);
10049argf_mark_and_move(
void *
ptr)
10052 rb_gc_mark_and_move(&p->filename);
10053 rb_gc_mark_and_move(&p->current_file);
10054 rb_gc_mark_and_move(&p->argv);
10055 rb_gc_mark_and_move(&p->inplace);
10056 rb_gc_mark_and_move(&p->encs.
ecopts);
10060argf_memsize(
const void *
ptr)
10063 size_t size =
sizeof(*p);
10070 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
10076 p->filename =
Qnil;
10077 p->current_file =
Qnil;
10083argf_alloc(
VALUE klass)
10088 argf_init(p,
Qnil);
10098 memset(&ARGF, 0,
sizeof(ARGF));
10099 argf_init(&ARGF, argv);
10109 ARGF = argf_of(orig);
10136 ARGF.last_lineno = ARGF.lineno;
10162 return forward_current(rb_frame_this_func(), argc, argv);
10165#define next_argv() argf_next_argv(argf)
10166#define ARGF_GENERIC_INPUT_P() \
10167 (ARGF.current_file == rb_stdin && !RB_TYPE_P(ARGF.current_file, T_FILE))
10168#define ARGF_FORWARD(argc, argv) do {\
10169 if (ARGF_GENERIC_INPUT_P())\
10170 return argf_forward((argc), (argv), argf);\
10172#define NEXT_ARGF_FORWARD(argc, argv) do {\
10173 if (!next_argv()) return Qnil;\
10174 ARGF_FORWARD((argc), (argv));\
10180 VALUE file = ARGF.current_file;
10182 if (RB_TYPE_P(file,
T_FILE)) {
10194 int stdout_binmode = 0;
10195 enum rb_io_mode fmode;
10197 VALUE r_stdout = rb_ractor_stdout();
10199 if (RB_TYPE_P(r_stdout,
T_FILE)) {
10202 stdout_binmode = 1;
10205 if (ARGF.init_p == 0) {
10215 if (
NIL_P(ARGF.argv)) {
10218 else if (ARGF.next_p == -1 &&
RARRAY_LEN(ARGF.argv) > 0) {
10223 if (ARGF.next_p == 1) {
10224 if (ARGF.init_p == 1) argf_close(
argf);
10229 ARGF.filename = filename;
10230 filename = rb_str_encode_ospath(filename);
10232 if (RSTRING_LEN(filename) == 1 && fn[0] ==
'-') {
10234 if (ARGF.inplace) {
10235 rb_warn(
"Can't do inplace edit for stdio; skipping");
10241 int fr = rb_sysopen(filename, O_RDONLY, 0);
10243 if (ARGF.inplace) {
10245#ifndef NO_SAFE_RENAME
10251 if (RB_TYPE_P(r_stdout,
T_FILE) && r_stdout != orig_stdout) {
10256 if (!
NIL_P(ARGF.inplace)) {
10257 VALUE suffix = ARGF.inplace;
10259 if (
NIL_P(rb_str_cat_conv_enc_opts(str, RSTRING_LEN(str),
10260 RSTRING_PTR(suffix), RSTRING_LEN(suffix),
10261 rb_enc_get(suffix), 0,
Qnil))) {
10264#ifdef NO_SAFE_RENAME
10266 (void)unlink(RSTRING_PTR(str));
10267 if (rename(fn, RSTRING_PTR(str)) < 0) {
10268 rb_warn(
"Can't rename %"PRIsVALUE
" to %"PRIsVALUE
": %s, skipping file",
10269 filename, str, strerror(
errno));
10272 fr = rb_sysopen(str, O_RDONLY, 0);
10274 if (rename(fn, RSTRING_PTR(str)) < 0) {
10275 rb_warn(
"Can't rename %"PRIsVALUE
" to %"PRIsVALUE
": %s, skipping file",
10276 filename, str, strerror(
errno));
10283#ifdef NO_SAFE_RENAME
10284 rb_fatal(
"Can't do inplace edit without backup");
10286 if (unlink(fn) < 0) {
10287 rb_warn(
"Can't remove %"PRIsVALUE
": %s, skipping file",
10288 filename, strerror(
errno));
10294 fw = rb_sysopen(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666);
10295#ifndef NO_SAFE_RENAME
10298 fchmod(fw, st.st_mode);
10300 chmod(fn, st.st_mode);
10302 if (st.st_uid!=st2.st_uid || st.st_gid!=st2.st_gid) {
10305 err = fchown(fw, st.st_uid, st.st_gid);
10307 err = chown(fn, st.st_uid, st.st_gid);
10309 if (err && getuid() == 0 && st2.st_uid == 0) {
10310 const char *wkfn = RSTRING_PTR(filename);
10311 rb_warn(
"Can't set owner/group of %"PRIsVALUE
" to same as %"PRIsVALUE
": %s, skipping file",
10312 filename, str, strerror(
errno));
10315 (void)unlink(wkfn);
10325 if (!ARGF.binmode) {
10326 fmode |= DEFAULT_TEXTMODE;
10328 ARGF.current_file = prep_io(fr, fmode,
rb_cFile, fn);
10329 if (!
NIL_P(write_io)) {
10336 if (ARGF.encs.enc) {
10337 fptr->
encs = ARGF.encs;
10338 clear_codeconv(fptr);
10342 if (!ARGF.binmode) {
10344#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
10345 fptr->
encs.
ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
10356 else if (ARGF.next_p == -1) {
10359 if (ARGF.inplace) {
10360 rb_warn(
"Can't do inplace edit for stdio");
10364 if (ARGF.init_p == -1) ARGF.init_p = 1;
10372 long lineno = ARGF.lineno;
10375 if (!next_argv())
return Qnil;
10376 if (ARGF_GENERIC_INPUT_P()) {
10377 line = forward_current(idGets, argc, argv);
10384 line = rb_io_getline(argc, argv, ARGF.current_file);
10386 if (
NIL_P(line) && ARGF.next_p != -1) {
10392 if (!
NIL_P(line)) {
10393 ARGF.lineno = ++lineno;
10394 ARGF.last_lineno = ARGF.lineno;
10400argf_lineno_getter(
ID id,
VALUE *var)
10403 return INT2FIX(ARGF.last_lineno);
10411 ARGF.last_lineno = ARGF.lineno = n;
10415rb_reset_argf_lineno(
long n)
10417 ARGF.last_lineno = ARGF.lineno = n;
10458 if (recv ==
argf) {
10459 return argf_gets(argc, argv,
argf);
10461 return forward(
argf, idGets, argc, argv);
10487 line = argf_getline(argc, argv,
argf);
10499 return rb_f_gets(0, 0,
argf);
10503 if (!next_argv())
return Qnil;
10505 if (
NIL_P(line) && ARGF.next_p != -1) {
10511 if (!
NIL_P(line)) {
10513 ARGF.last_lineno = ARGF.lineno;
10539rb_f_readline(
int argc,
VALUE *argv,
VALUE recv)
10541 if (recv ==
argf) {
10542 return argf_readline(argc, argv,
argf);
10544 return forward(
argf, rb_intern(
"readline"), argc, argv);
10571 ARGF_FORWARD(argc, argv);
10572 line = argf_gets(argc, argv,
argf);
10642rb_f_readlines(
int argc,
VALUE *argv,
VALUE recv)
10644 if (recv ==
argf) {
10645 return argf_readlines(argc, argv,
argf);
10647 return forward(
argf, rb_intern(
"readlines"), argc, argv);
10671 long lineno = ARGF.lineno;
10675 while (next_argv()) {
10676 if (ARGF_GENERIC_INPUT_P()) {
10677 lines = forward_current(rb_intern(
"readlines"), argc, argv);
10680 lines = rb_io_readlines(argc, argv, ARGF.current_file);
10686 ARGF.last_lineno = ARGF.lineno;
10721 rb_last_status_clear();
10722 port = pipe_open_s(str,
"r",
FMODE_READABLE|DEFAULT_TEXTMODE, NULL);
10726 result = read_all(fptr, remain_size(fptr),
Qnil);
10728 rb_io_fptr_cleanup_all(fptr);
10734#ifdef HAVE_SYS_SELECT_H
10735#include <sys/select.h>
10749 if (!
NIL_P(read)) {
10754 if (READ_DATA_PENDING(fptr) || READ_CHAR_PENDING(fptr)) {
10758 if (max < fptr->fd) max = fptr->
fd;
10761 timerec.tv_sec = timerec.tv_usec = 0;
10769 if (!
NIL_P(write)) {
10775 if (max < fptr->fd) max = fptr->
fd;
10782 if (!
NIL_P(except)) {
10786 VALUE write_io = GetWriteIO(io);
10789 if (max < fptr->fd) max = fptr->
fd;
10790 if (io != write_io) {
10793 if (max < fptr->fd) max = fptr->
fd;
10808 if (!pending && n == 0)
return Qnil;
10833 VALUE write_io = GetWriteIO(io);
10846 VALUE write_io = GetWriteIO(io);
10851 else if (io != write_io) {
10864 VALUE read, write, except;
10870select_call(
VALUE arg)
10874 return select_internal(p->read, p->write, p->except, p->timeout, p->fdsets);
10878select_end(
VALUE arg)
10883 for (i = 0; i < numberof(p->fdsets); ++i)
10888static VALUE sym_normal, sym_sequential, sym_random,
10889 sym_willneed, sym_dontneed, sym_noreuse;
10891#ifdef HAVE_POSIX_FADVISE
10892struct io_advise_struct {
10900io_advise_internal(
void *arg)
10902 struct io_advise_struct *
ptr = arg;
10903 return posix_fadvise(
ptr->fd,
ptr->offset,
ptr->len,
ptr->advice);
10907io_advise_sym_to_const(
VALUE sym)
10909#ifdef POSIX_FADV_NORMAL
10910 if (sym == sym_normal)
10911 return INT2NUM(POSIX_FADV_NORMAL);
10914#ifdef POSIX_FADV_RANDOM
10915 if (sym == sym_random)
10916 return INT2NUM(POSIX_FADV_RANDOM);
10919#ifdef POSIX_FADV_SEQUENTIAL
10920 if (sym == sym_sequential)
10921 return INT2NUM(POSIX_FADV_SEQUENTIAL);
10924#ifdef POSIX_FADV_WILLNEED
10925 if (sym == sym_willneed)
10926 return INT2NUM(POSIX_FADV_WILLNEED);
10929#ifdef POSIX_FADV_DONTNEED
10930 if (sym == sym_dontneed)
10931 return INT2NUM(POSIX_FADV_DONTNEED);
10934#ifdef POSIX_FADV_NOREUSE
10935 if (sym == sym_noreuse)
10936 return INT2NUM(POSIX_FADV_NOREUSE);
10943do_io_advise(rb_io_t *fptr,
VALUE advice, rb_off_t offset, rb_off_t
len)
10946 struct io_advise_struct ias;
10949 num_adv = io_advise_sym_to_const(advice);
10955 if (
NIL_P(num_adv))
10959 ias.advice =
NUM2INT(num_adv);
10960 ias.offset = offset;
10963 rv = (int)rb_io_blocking_region(fptr, io_advise_internal, &ias);
10964 if (rv && rv != ENOSYS) {
10967 VALUE message = rb_sprintf(
"%"PRIsVALUE
" "
10971 fptr->
pathv, offset,
len, advice);
10981advice_arg_check(
VALUE advice)
10986 if (advice != sym_normal &&
10987 advice != sym_sequential &&
10988 advice != sym_random &&
10989 advice != sym_willneed &&
10990 advice != sym_dontneed &&
10991 advice != sym_noreuse) {
10992 rb_raise(
rb_eNotImpError,
"Unsupported advice: %+"PRIsVALUE, advice);
11030rb_io_advise(
int argc,
VALUE *argv,
VALUE io)
11037 advice_arg_check(advice);
11039 io = GetWriteIO(io);
11045#ifdef HAVE_POSIX_FADVISE
11046 return do_io_advise(fptr, advice,
off, l);
11048 ((void)
off, (void)l);
11057 if (!RB_FLOAT_TYPE_P(x))
11060 return isinf(f) && 0 < f;
11216rb_f_select(
int argc,
VALUE *argv,
VALUE obj)
11219 if (scheduler !=
Qnil) {
11222 if (!UNDEF_P(result))
return result;
11230 rb_scan_args(argc, argv,
"13", &args.read, &args.write, &args.except, &timeout);
11231 if (
NIL_P(timeout) || is_pos_inf(timeout)) {
11236 args.timeout = &timerec;
11239 for (i = 0; i < numberof(args.fdsets); ++i)
11245#ifdef IOCTL_REQ_TYPE
11246 typedef IOCTL_REQ_TYPE ioctl_req_t;
11248 typedef int ioctl_req_t;
11249# define NUM2IOCTLREQ(num) ((int)NUM2LONG(num))
11260nogvl_ioctl(
void *
ptr)
11262 struct ioctl_arg *arg =
ptr;
11264 return (
VALUE)ioctl(arg->fd, arg->cmd, arg->narg);
11268do_ioctl(
struct rb_io *io, ioctl_req_t cmd,
long narg)
11271 struct ioctl_arg arg;
11277 retval = (int)rb_io_blocking_region(io, nogvl_ioctl, &arg);
11283#define DEFAULT_IOCTL_NARG_LEN (256)
11285#if defined(__linux__) && defined(_IOC_SIZE)
11287linux_iocparm_len(ioctl_req_t cmd)
11291 if ((cmd & 0xFFFF0000) == 0) {
11293 return DEFAULT_IOCTL_NARG_LEN;
11296 len = _IOC_SIZE(cmd);
11299 if (
len < DEFAULT_IOCTL_NARG_LEN)
11300 len = DEFAULT_IOCTL_NARG_LEN;
11308ioctl_narg_len(ioctl_req_t cmd)
11314#define IOCPARM_LEN(x) (((x) >> 16) & IOCPARM_MASK)
11318 len = IOCPARM_LEN(cmd);
11319#elif defined(__linux__) && defined(_IOC_SIZE)
11320 len = linux_iocparm_len(cmd);
11323 len = DEFAULT_IOCTL_NARG_LEN;
11332typedef long fcntl_arg_t;
11335typedef int fcntl_arg_t;
11339fcntl_narg_len(ioctl_req_t cmd)
11346 len =
sizeof(fcntl_arg_t);
11354#ifdef F_DUPFD_CLOEXEC
11355 case F_DUPFD_CLOEXEC:
11356 len =
sizeof(fcntl_arg_t);
11366 len =
sizeof(fcntl_arg_t);
11376 len =
sizeof(fcntl_arg_t);
11386 len =
sizeof(fcntl_arg_t);
11391 len =
sizeof(
struct f_owner_ex);
11396 len =
sizeof(
struct f_owner_ex);
11401 len =
sizeof(
struct flock);
11406 len =
sizeof(
struct flock);
11411 len =
sizeof(
struct flock);
11431 len =
sizeof(fcntl_arg_t);
11441 len =
sizeof(fcntl_arg_t);
11446 len =
sizeof(fcntl_arg_t);
11459fcntl_narg_len(ioctl_req_t cmd)
11465#define NARG_SENTINEL 17
11468setup_narg(ioctl_req_t cmd,
VALUE *argp,
long (*narg_len)(ioctl_req_t))
11479 else if (arg ==
Qtrue) {
11493 len = narg_len(cmd);
11494 rb_str_modify(arg);
11496 slen = RSTRING_LEN(arg);
11498 if (slen <
len+1) {
11499 rb_str_resize(arg,
len+1);
11500 MEMZERO(RSTRING_PTR(arg)+slen,
char,
len-slen);
11504 ptr = RSTRING_PTR(arg);
11505 ptr[slen - 1] = NARG_SENTINEL;
11514finish_narg(
int retval,
VALUE arg,
const rb_io_t *fptr)
11516 if (retval < 0) rb_sys_fail_path(fptr->
pathv);
11521 if (
ptr[slen-1] != NARG_SENTINEL)
11522 rb_raise(rb_eArgError,
"return value overflowed string");
11523 ptr[slen-1] =
'\0';
11533 ioctl_req_t cmd = NUM2IOCTLREQ(req);
11538 narg = setup_narg(cmd, &arg, ioctl_narg_len);
11540 retval = do_ioctl(fptr, cmd, narg);
11541 return finish_narg(retval, arg, fptr);
11568 return rb_ioctl(io, req, arg);
11571#define rb_io_ioctl rb_f_notimplement
11582nogvl_fcntl(
void *
ptr)
11584 struct fcntl_arg *arg =
ptr;
11586#if defined(F_DUPFD)
11587 if (arg->cmd == F_DUPFD)
11590 return (
VALUE)fcntl(arg->fd, arg->cmd, arg->narg);
11594do_fcntl(
struct rb_io *io,
int cmd,
long narg)
11597 struct fcntl_arg arg;
11603 retval = (int)rb_io_blocking_region(io, nogvl_fcntl, &arg);
11604 if (retval != -1) {
11606#if defined(F_DUPFD)
11609#if defined(F_DUPFD_CLOEXEC)
11610 case F_DUPFD_CLOEXEC:
11627 narg = setup_narg(cmd, &arg, fcntl_narg_len);
11629 retval = do_fcntl(fptr, cmd, narg);
11630 return finish_narg(retval, arg, fptr);
11656 return rb_fcntl(io, req, arg);
11659#define rb_io_fcntl rb_f_notimplement
11662#if defined(HAVE_SYSCALL) || defined(HAVE___SYSCALL)
11694#if SIZEOF_VOIDP == 8 && defined(HAVE___SYSCALL) && SIZEOF_INT != 8
11695# define SYSCALL __syscall
11696# define NUM2SYSCALLID(x) NUM2LONG(x)
11697# define RETVAL2NUM(x) LONG2NUM(x)
11698# if SIZEOF_LONG == 8
11699 long num, retval = -1;
11700# elif SIZEOF_LONG_LONG == 8
11701 long long num, retval = -1;
11703# error ---->> it is asserted that __syscall takes the first argument and returns retval in 64bit signed integer. <<----
11705#elif defined(__linux__)
11706# define SYSCALL syscall
11707# define NUM2SYSCALLID(x) NUM2LONG(x)
11708# define RETVAL2NUM(x) LONG2NUM(x)
11716 long num, retval = -1;
11718# define SYSCALL syscall
11719# define NUM2SYSCALLID(x) NUM2INT(x)
11720# define RETVAL2NUM(x) INT2NUM(x)
11721 int num, retval = -1;
11727 "We plan to remove a syscall function at future release. DL(Fiddle) provides safer alternative.");
11731 rb_raise(rb_eArgError,
"too few arguments for syscall");
11732 if (argc > numberof(arg))
11733 rb_raise(rb_eArgError,
"too many arguments for syscall");
11734 num = NUM2SYSCALLID(argv[0]); ++argv;
11735 for (i = argc - 1; i--; ) {
11750 retval = SYSCALL(num);
11753 retval = SYSCALL(num, arg[0]);
11756 retval = SYSCALL(num, arg[0],arg[1]);
11759 retval = SYSCALL(num, arg[0],arg[1],arg[2]);
11762 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3]);
11765 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4]);
11768 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5]);
11771 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6]);
11777 return RETVAL2NUM(retval);
11779#undef NUM2SYSCALLID
11783#define rb_f_syscall rb_f_notimplement
11787io_new_instance(
VALUE args)
11792static rb_encoding *
11793find_encoding(
VALUE v)
11795 rb_encoding *enc = rb_find_encoding(v);
11796 if (!enc)
rb_warn(
"Unsupported encoding %"PRIsVALUE
" ignored", v);
11803 rb_encoding *enc, *enc2;
11808 enc2 = find_encoding(v1);
11811 if (RSTRING_LEN(tmp) == 1 && RSTRING_PTR(tmp)[0] ==
'-') {
11817 enc = find_encoding(v2);
11824 enc = find_encoding(v2);
11830 if (enc2 == rb_ascii8bit_encoding()) {
11835 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11841 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
11842 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11847 if (!
NIL_P(tmp) && rb_enc_asciicompat(enc = rb_enc_get(tmp))) {
11848 parse_mode_enc(RSTRING_PTR(tmp), enc, &enc, &enc2, NULL);
11849 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11853 rb_io_ext_int_to_encs(find_encoding(v1), NULL, &enc, &enc2, 0);
11854 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11859 validate_enc_binmode(&fptr->
mode, ecflags, enc, enc2);
11864 clear_codeconv(fptr);
11876io_encoding_set_v(
VALUE v)
11879 io_encoding_set(arg->fptr, arg->v1, arg->v2, arg->opt);
11884pipe_pair_close(
VALUE rw)
11887 return rb_ensure(io_close, rwp[0], io_close, rwp[1]);
11970rb_io_s_pipe(
int argc,
VALUE *argv,
VALUE klass)
11972 int pipes[2], state;
11973 VALUE r, w, args[3], v1, v2;
11975 rb_io_t *fptr, *fptr2;
11977 enum rb_io_mode fmode = 0;
11980 argc =
rb_scan_args(argc, argv,
"02:", &v1, &v2, &opt);
11987 r = rb_protect(io_new_instance, (
VALUE)args, &state);
11991 rb_jump_tag(state);
11995 ies_args.fptr = fptr;
11998 ies_args.opt = opt;
11999 rb_protect(io_encoding_set_v, (
VALUE)&ies_args, &state);
12003 rb_jump_tag(state);
12008 w = rb_protect(io_new_instance, (
VALUE)args, &state);
12012 rb_jump_tag(state);
12017 extract_binmode(opt, &fmode);
12024#if DEFAULT_TEXTMODE
12027 setmode(fptr->
fd, O_BINARY);
12029#if RUBY_CRLF_ENVIRONMENT
12035 fptr->
mode |= fmode;
12036#if DEFAULT_TEXTMODE
12039 setmode(fptr2->
fd, O_BINARY);
12042 fptr2->
mode |= fmode;
12076 else if (!
NIL_P(v = rb_hash_aref(opt, sym_open_args))) {
12079 v = rb_to_array_type(v);
12080 n = RARRAY_LENINT(v);
12081 rb_check_arity(n, 0, 3);
12084 arg->io = rb_io_open(klass, path, vmode, vperm, opt);
12088io_s_foreach(
VALUE v)
12093 if (arg->limit == 0)
12094 rb_raise(rb_eArgError,
"invalid limit: 0 for foreach");
12095 while (!
NIL_P(str = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, arg->io))) {
12179rb_io_s_foreach(
int argc,
VALUE *argv,
VALUE self)
12182 int orig_argc = argc;
12186 argc =
rb_scan_args(argc, argv,
"12:", NULL, NULL, NULL, &opt);
12188 extract_getline_args(argc-1, argv+1, &garg);
12189 open_key_args(self, argc, argv, opt, &arg);
12191 extract_getline_opts(opt, &garg);
12192 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12197io_s_readlines(
VALUE v)
12200 return io_readlines(arg, arg->io);
12253rb_io_s_readlines(
int argc,
VALUE *argv,
VALUE io)
12259 argc =
rb_scan_args(argc, argv,
"12:", NULL, NULL, NULL, &opt);
12260 extract_getline_args(argc-1, argv+1, &garg);
12261 open_key_args(io, argc, argv, opt, &arg);
12263 extract_getline_opts(opt, &garg);
12264 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12272 return io_read(arg->argc, arg->argv, arg->io);
12282seek_before_access(
VALUE argp)
12286 return rb_io_seek(arg->io, arg->offset, arg->mode);
12328rb_io_s_read(
int argc,
VALUE *argv,
VALUE io)
12334 argc =
rb_scan_args(argc, argv,
"13:", NULL, NULL, &offset, NULL, &opt);
12336 rb_raise(rb_eArgError,
"negative offset %ld given",
off);
12338 open_key_args(io, argc, argv, opt, &arg);
12340 if (!
NIL_P(offset)) {
12344 sarg.offset = offset;
12345 sarg.mode = SEEK_SET;
12346 rb_protect(seek_before_access, (
VALUE)&sarg, &state);
12349 rb_jump_tag(state);
12351 if (arg.argc == 2) arg.argc = 1;
12366rb_io_s_binread(
int argc,
VALUE *argv,
VALUE io)
12381 convconfig.
enc = rb_ascii8bit_encoding();
12382 arg.io = rb_io_open_generic(io, argv[0], oflags, fmode, &convconfig, 0);
12385 arg.argc = (argc > 1) ? 1 : 0;
12386 if (!
NIL_P(offset)) {
12390 sarg.offset = offset;
12391 sarg.mode = SEEK_SET;
12392 rb_protect(seek_before_access, (
VALUE)&sarg, &state);
12395 rb_jump_tag(state);
12402io_s_write0(
VALUE v)
12405 return io_write(arg->io,arg->str,arg->nosync);
12409io_s_write(
int argc,
VALUE *argv,
VALUE klass,
int binary)
12411 VALUE string, offset, opt;
12415 rb_scan_args(argc, argv,
"21:", NULL, &
string, &offset, &opt);
12417 if (
NIL_P(opt)) opt = rb_hash_new();
12418 else opt = rb_hash_dup(opt);
12421 if (
NIL_P(rb_hash_aref(opt,sym_mode))) {
12422 int mode = O_WRONLY|O_CREAT;
12424 if (binary) mode |= O_BINARY;
12426 if (
NIL_P(offset)) mode |= O_TRUNC;
12427 rb_hash_aset(opt,sym_mode,
INT2NUM(mode));
12429 open_key_args(klass, argc, argv, opt, &arg);
12432 if (binary) rb_io_binmode_m(arg.io);
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);
12497rb_io_s_write(
int argc,
VALUE *argv,
VALUE io)
12499 return io_s_write(argc, argv, io, 0);
12512rb_io_s_binwrite(
int argc,
VALUE *argv,
VALUE io)
12514 return io_s_write(argc, argv, io, 1);
12520 rb_off_t copy_length;
12521 rb_off_t src_offset;
12525 unsigned close_src : 1;
12526 unsigned close_dst : 1;
12529 const char *syserr;
12530 const char *notimp;
12532 struct stat src_stat;
12533 struct stat dst_stat;
12534#ifdef HAVE_FCOPYFILE
12535 copyfile_state_t copyfile_state;
12540exec_interrupts(
void *arg)
12543 rb_thread_execute_interrupts(th);
12557#if defined(ERESTART)
12562 rb_thread_execute_interrupts(stp->th);
12581fiber_scheduler_wait_for(
void * _arguments)
12591# define IOWAIT_SYSCALL "poll"
12592STATIC_ASSERT(pollin_expected, POLLIN == RB_WAITFD_IN);
12593STATIC_ASSERT(pollout_expected, POLLOUT == RB_WAITFD_OUT);
12595nogvl_wait_for(
VALUE th, rb_io_t *fptr,
short events,
struct timeval *timeout)
12598 if (scheduler !=
Qnil) {
12601 return RTEST(args.result);
12605 if (fd == -1)
return 0;
12610 fds.events = events;
12612 int timeout_milliseconds = -1;
12615 timeout_milliseconds = (int)(timeout->tv_sec * 1000) + (int)(timeout->tv_usec / 1000);
12618 return poll(&fds, 1, timeout_milliseconds);
12621# define IOWAIT_SYSCALL "select"
12623nogvl_wait_for(
VALUE th, rb_io_t *fptr,
short events,
struct timeval *timeout)
12626 if (scheduler !=
Qnil) {
12629 return RTEST(args.result);
12649 case RB_WAITFD_OUT:
12653 VM_UNREACHABLE(nogvl_wait_for);
12673 ret = nogvl_wait_for(stp->th, stp->src_fptr, RB_WAITFD_IN, NULL);
12675 }
while (ret < 0 && maygvl_copy_stream_continue_p(has_gvl, stp));
12678 stp->syserr = IOWAIT_SYSCALL;
12679 stp->error_no =
errno;
12691 ret = nogvl_wait_for(stp->th, stp->dst_fptr, RB_WAITFD_OUT, NULL);
12692 }
while (ret < 0 && maygvl_copy_stream_continue_p(0, stp));
12695 stp->syserr = IOWAIT_SYSCALL;
12696 stp->error_no =
errno;
12702#ifdef USE_COPY_FILE_RANGE
12705simple_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)
12707#ifdef HAVE_COPY_FILE_RANGE
12708 return copy_file_range(in_fd, in_offset, out_fd, out_offset, count, flags);
12710 return syscall(__NR_copy_file_range, in_fd, in_offset, out_fd, out_offset, count, flags);
12719 rb_off_t copy_length, src_offset, *src_offset_ptr;
12721 if (!S_ISREG(stp->src_stat.st_mode))
12724 src_size = stp->src_stat.st_size;
12725 src_offset = stp->src_offset;
12726 if (src_offset >= (rb_off_t)0) {
12727 src_offset_ptr = &src_offset;
12730 src_offset_ptr = NULL;
12733 copy_length = stp->copy_length;
12734 if (copy_length < (rb_off_t)0) {
12735 if (src_offset < (rb_off_t)0) {
12736 rb_off_t current_offset;
12738 current_offset = lseek(stp->src_fptr->
fd, 0, SEEK_CUR);
12739 if (current_offset < (rb_off_t)0 &&
errno) {
12740 stp->syserr =
"lseek";
12741 stp->error_no =
errno;
12742 return (
int)current_offset;
12744 copy_length = src_size - current_offset;
12747 copy_length = src_size - src_offset;
12751 retry_copy_file_range:
12752# if SIZEOF_OFF_T > SIZEOF_SIZE_T
12754 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
12756 ss = (ssize_t)copy_length;
12758 ss = simple_copy_file_range(stp->src_fptr->
fd, src_offset_ptr, stp->dst_fptr->
fd, NULL, ss, 0);
12762 if (0 < copy_length) {
12763 goto retry_copy_file_range;
12767 if (maygvl_copy_stream_continue_p(0, stp)) {
12768 goto retry_copy_file_range;
12782#if EWOULDBLOCK != EAGAIN
12786 int ret = nogvl_copy_stream_wait_write(stp);
12787 if (ret < 0)
return ret;
12789 goto retry_copy_file_range;
12793 int flags = fcntl(stp->dst_fptr->
fd, F_GETFL);
12795 if (flags != -1 && flags & O_APPEND) {
12801 stp->syserr =
"copy_file_range";
12802 stp->error_no =
errno;
12809#ifdef HAVE_FCOPYFILE
12813 rb_off_t cur, ss = 0;
12814 const rb_off_t src_offset = stp->src_offset;
12817 if (stp->copy_length >= (rb_off_t)0) {
12822 if (!S_ISREG(stp->src_stat.st_mode))
12825 if (!S_ISREG(stp->dst_stat.st_mode))
12827 if (lseek(stp->dst_fptr->
fd, 0, SEEK_CUR) > (rb_off_t)0)
12829 if (fcntl(stp->dst_fptr->
fd, F_GETFL) & O_APPEND) {
12832 rb_off_t end = lseek(stp->dst_fptr->
fd, 0, SEEK_END);
12833 lseek(stp->dst_fptr->
fd, 0, SEEK_SET);
12834 if (end > (rb_off_t)0)
return 0;
12837 if (src_offset > (rb_off_t)0) {
12842 cur = lseek(stp->src_fptr->
fd, 0, SEEK_CUR);
12843 if (cur < (rb_off_t)0 &&
errno) {
12844 stp->error_no =
errno;
12849 r = lseek(stp->src_fptr->
fd, src_offset, SEEK_SET);
12850 if (r < (rb_off_t)0 &&
errno) {
12851 stp->error_no =
errno;
12856 stp->copyfile_state = copyfile_state_alloc();
12857 ret = fcopyfile(stp->src_fptr->
fd, stp->dst_fptr->
fd, stp->copyfile_state, COPYFILE_DATA);
12858 copyfile_state_get(stp->copyfile_state, COPYFILE_STATE_COPIED, &ss);
12862 if (src_offset > (rb_off_t)0) {
12866 r = lseek(stp->src_fptr->
fd, cur, SEEK_SET);
12867 if (r < (rb_off_t)0 &&
errno) {
12868 stp->error_no =
errno;
12880 stp->syserr =
"fcopyfile";
12881 stp->error_no =
errno;
12888#ifdef HAVE_SENDFILE
12891# define USE_SENDFILE
12893# ifdef HAVE_SYS_SENDFILE_H
12894# include <sys/sendfile.h>
12898simple_sendfile(
int out_fd,
int in_fd, rb_off_t *offset, rb_off_t count)
12900 return sendfile(out_fd, in_fd, offset, (
size_t)count);
12903# elif 0 || defined(__APPLE__)
12907# define USE_SENDFILE
12910simple_sendfile(
int out_fd,
int in_fd, rb_off_t *offset, rb_off_t count)
12913 rb_off_t pos = offset ? *offset : lseek(in_fd, 0, SEEK_CUR);
12916 r = sendfile(in_fd, out_fd, pos, &count, NULL, 0);
12919 r = sendfile(in_fd, out_fd, pos, (
size_t)count, NULL, &sbytes, 0);
12921 if (r != 0 && sbytes == 0)
return r;
12926 lseek(in_fd, sbytes, SEEK_CUR);
12928 return (ssize_t)sbytes;
12941 rb_off_t copy_length;
12942 rb_off_t src_offset;
12945 if (!S_ISREG(stp->src_stat.st_mode))
12948 src_size = stp->src_stat.st_size;
12950 if ((stp->dst_stat.st_mode & S_IFMT) != S_IFSOCK)
12954 src_offset = stp->src_offset;
12955 use_pread = src_offset >= (rb_off_t)0;
12957 copy_length = stp->copy_length;
12958 if (copy_length < (rb_off_t)0) {
12960 copy_length = src_size - src_offset;
12964 cur = lseek(stp->src_fptr->
fd, 0, SEEK_CUR);
12965 if (cur < (rb_off_t)0 &&
errno) {
12966 stp->syserr =
"lseek";
12967 stp->error_no =
errno;
12970 copy_length = src_size - cur;
12975# if SIZEOF_OFF_T > SIZEOF_SIZE_T
12977 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
12979 ss = (ssize_t)copy_length;
12982 ss = simple_sendfile(stp->dst_fptr->
fd, stp->src_fptr->
fd, &src_offset, ss);
12985 ss = simple_sendfile(stp->dst_fptr->
fd, stp->src_fptr->
fd, NULL, ss);
12990 if (0 < copy_length) {
12991 goto retry_sendfile;
12995 if (maygvl_copy_stream_continue_p(0, stp))
12996 goto retry_sendfile;
13009#if EWOULDBLOCK != EAGAIN
13022 ret = maygvl_copy_stream_wait_read(0, stp);
13023 if (ret < 0)
return ret;
13025 ret = nogvl_copy_stream_wait_write(stp);
13026 if (ret < 0)
return ret;
13028 goto retry_sendfile;
13030 stp->syserr =
"sendfile";
13031 stp->error_no =
errno;
13039maygvl_read(
int has_gvl, rb_io_t *fptr,
void *buf,
size_t count)
13042 return rb_io_read_memory(fptr, buf, count);
13044 return read(fptr->
fd, buf, count);
13048maygvl_copy_stream_read(
int has_gvl,
struct copy_stream_struct *stp,
char *buf,
size_t len, rb_off_t offset)
13052 if (offset < (rb_off_t)0) {
13053 ss = maygvl_read(has_gvl, stp->src_fptr, buf,
len);
13056 ss = pread(stp->src_fptr->
fd, buf,
len, offset);
13062 if (maygvl_copy_stream_continue_p(has_gvl, stp))
13066#if EWOULDBLOCK != EAGAIN
13070 int ret = maygvl_copy_stream_wait_read(has_gvl, stp);
13071 if (ret < 0)
return ret;
13076 stp->notimp =
"pread";
13080 stp->syserr = offset < (rb_off_t)0 ?
"read" :
"pread";
13081 stp->error_no =
errno;
13092 ss = write(stp->dst_fptr->
fd, buf+
off,
len);
13094 if (maygvl_copy_stream_continue_p(0, stp))
13096 if (io_again_p(
errno)) {
13097 int ret = nogvl_copy_stream_wait_write(stp);
13098 if (ret < 0)
return ret;
13101 stp->syserr =
"write";
13102 stp->error_no =
errno;
13119 rb_off_t copy_length;
13120 rb_off_t src_offset;
13124 copy_length = stp->copy_length;
13125 use_eof = copy_length < (rb_off_t)0;
13126 src_offset = stp->src_offset;
13127 use_pread = src_offset >= (rb_off_t)0;
13129 if (use_pread && stp->close_src) {
13132 r = lseek(stp->src_fptr->
fd, src_offset, SEEK_SET);
13133 if (r < (rb_off_t)0 &&
errno) {
13134 stp->syserr =
"lseek";
13135 stp->error_no =
errno;
13138 src_offset = (rb_off_t)-1;
13142 while (use_eof || 0 < copy_length) {
13143 if (!use_eof && copy_length < (rb_off_t)
sizeof(buf)) {
13144 len = (size_t)copy_length;
13150 ss = maygvl_copy_stream_read(0, stp, buf,
len, src_offset);
13155 ss = maygvl_copy_stream_read(0, stp, buf,
len, (rb_off_t)-1);
13160 ret = nogvl_copy_stream_write(stp, buf, ss);
13170nogvl_copy_stream_func(
void *arg)
13173#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13177#ifdef USE_COPY_FILE_RANGE
13178 ret = nogvl_copy_file_range(stp);
13183#ifdef HAVE_FCOPYFILE
13184 ret = nogvl_fcopyfile(stp);
13190 ret = nogvl_copy_stream_sendfile(stp);
13195 nogvl_copy_stream_read_write(stp);
13197#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13204copy_stream_fallback_body(
VALUE arg)
13207 const int buflen = 16*1024;
13210 rb_off_t rest = stp->copy_length;
13211 rb_off_t
off = stp->src_offset;
13212 ID read_method = id_readpartial;
13214 if (!stp->src_fptr) {
13216 read_method = id_read;
13223 rb_str_make_independent(buf);
13224 if (stp->copy_length < (rb_off_t)0) {
13229 rb_str_resize(buf, 0);
13232 l = buflen < rest ? buflen : (long)rest;
13234 if (!stp->src_fptr) {
13237 if (read_method == id_read &&
NIL_P(rc))
13242 rb_str_resize(buf, buflen);
13243 ss = maygvl_copy_stream_read(1, stp, RSTRING_PTR(buf), l,
off);
13244 rb_str_resize(buf, ss > 0 ? ss : 0);
13249 if (
off >= (rb_off_t)0)
13252 n = rb_io_write(stp->dst, buf);
13254 stp->total += numwrote;
13256 if (read_method == id_read && RSTRING_LEN(buf) == 0) {
13267 if (!stp->src_fptr && stp->src_offset >= (rb_off_t)0) {
13268 rb_raise(rb_eArgError,
"cannot specify src_offset for non-IO");
13277copy_stream_body(
VALUE arg)
13280 VALUE src_io = stp->src, dst_io = stp->dst;
13281 const int common_oflags = 0
13291 if (src_io ==
argf ||
13292 !(RB_TYPE_P(src_io,
T_FILE) ||
13295 stp->src_fptr = NULL;
13300 if (!
NIL_P(tmp_io)) {
13303 else if (!RB_TYPE_P(src_io,
T_FILE)) {
13307 args[1] =
INT2NUM(O_RDONLY|common_oflags);
13310 stp->close_src = 1;
13315 stat_ret = fstat(stp->src_fptr->
fd, &stp->src_stat);
13316 if (stat_ret < 0) {
13317 stp->syserr =
"fstat";
13318 stp->error_no =
errno;
13323 if (dst_io ==
argf ||
13324 !(RB_TYPE_P(dst_io,
T_FILE) ||
13327 stp->dst_fptr = NULL;
13332 if (!
NIL_P(tmp_io)) {
13333 dst_io = GetWriteIO(tmp_io);
13335 else if (!RB_TYPE_P(dst_io,
T_FILE)) {
13339 args[1] =
INT2NUM(O_WRONLY|O_CREAT|O_TRUNC|common_oflags);
13343 stp->close_dst = 1;
13346 dst_io = GetWriteIO(dst_io);
13352 stat_ret = fstat(stp->dst_fptr->
fd, &stp->dst_stat);
13353 if (stat_ret < 0) {
13354 stp->syserr =
"fstat";
13355 stp->error_no =
errno;
13362 SET_BINARY_MODE_WITH_SEEK_CUR(stp->src_fptr);
13365 io_ascii8bit_binmode(stp->dst_fptr);
13367 if (stp->src_offset < (rb_off_t)0 && stp->src_fptr && stp->src_fptr->
rbuf.
len) {
13370 if (stp->copy_length >= (rb_off_t)0 && stp->copy_length < (rb_off_t)
len) {
13371 len = (size_t)stp->copy_length;
13374 rb_str_resize(str,
len);
13375 read_buffered_data(RSTRING_PTR(str),
len, stp->src_fptr);
13376 if (stp->dst_fptr) {
13377 if (io_binwrite(RSTRING_PTR(str), RSTRING_LEN(str), stp->dst_fptr, 0) < 0)
13378 rb_sys_fail_on_write(stp->dst_fptr);
13381 rb_io_write(dst_io, str);
13382 rb_str_resize(str, 0);
13384 if (stp->copy_length >= (rb_off_t)0)
13385 stp->copy_length -=
len;
13388 if (stp->dst_fptr && io_fflush(stp->dst_fptr) < 0) {
13392 if (stp->copy_length == 0)
13395 if (stp->src_fptr == NULL || stp->dst_fptr == NULL) {
13396 return copy_stream_fallback(stp);
13399 IO_WITHOUT_GVL(nogvl_copy_stream_func, stp);
13404copy_stream_finalize(
VALUE arg)
13408#ifdef HAVE_FCOPYFILE
13409 if (stp->copyfile_state) {
13410 copyfile_state_free(stp->copyfile_state);
13414 if (stp->close_src) {
13415 rb_io_close_m(stp->src);
13417 if (stp->close_dst) {
13418 rb_io_close_m(stp->dst);
13481rb_io_s_copy_stream(
int argc,
VALUE *argv,
VALUE io)
13483 VALUE src, dst, length, src_offset;
13488 rb_scan_args(argc, argv,
"22", &src, &dst, &length, &src_offset);
13493 st.src_fptr = NULL;
13494 st.dst_fptr = NULL;
13497 st.copy_length = (rb_off_t)-1;
13499 st.copy_length =
NUM2OFFT(length);
13501 if (
NIL_P(src_offset))
13502 st.src_offset = (rb_off_t)-1;
13504 st.src_offset =
NUM2OFFT(src_offset);
13523rb_io_external_encoding(
VALUE io)
13528 return rb_enc_from_encoding(fptr->
encs.
enc2);
13532 return rb_enc_from_encoding(fptr->
encs.
enc);
13535 return rb_enc_from_encoding(io_read_encoding(fptr));
13551rb_io_internal_encoding(
VALUE io)
13556 return rb_enc_from_encoding(io_read_encoding(fptr));
13590rb_io_set_encoding(
int argc,
VALUE *argv,
VALUE io)
13595 if (!RB_TYPE_P(io,
T_FILE)) {
13596 return forward(io, id_set_encoding, argc, argv);
13599 argc =
rb_scan_args(argc, argv,
"11:", &v1, &v2, &opt);
13601 io_encoding_set(fptr, v1, v2, opt);
13606rb_stdio_set_default_encoding(
void)
13611 if (isatty(fileno(stdin))) {
13612 rb_encoding *external = rb_locale_encoding();
13613 rb_encoding *internal = rb_default_internal_encoding();
13614 if (!internal) internal = rb_default_external_encoding();
13616 rb_enc_from_encoding(external),
13617 rb_enc_from_encoding(internal),
13622 rb_io_set_encoding(1, &val,
rb_stdin);
13623 rb_io_set_encoding(1, &val,
rb_stdout);
13624 rb_io_set_encoding(1, &val,
rb_stderr);
13628global_argf_p(
VALUE arg)
13630 return arg ==
argf;
13633typedef VALUE (*argf_encoding_func)(
VALUE io);
13636argf_encoding(
VALUE argf, argf_encoding_func func)
13638 if (!
RTEST(ARGF.current_file)) {
13639 return rb_enc_default_external();
13663 return argf_encoding(
argf, rb_io_external_encoding);
13682 return argf_encoding(
argf, rb_io_internal_encoding);
13721 if (!next_argv()) {
13722 rb_raise(rb_eArgError,
"no stream to set encoding");
13724 rb_io_set_encoding(argc, argv, ARGF.current_file);
13726 ARGF.encs = fptr->
encs;
13745 if (!next_argv()) {
13746 rb_raise(rb_eArgError,
"no stream to tell");
13748 ARGF_FORWARD(0, 0);
13749 return rb_io_tell(ARGF.current_file);
13762 if (!next_argv()) {
13763 rb_raise(rb_eArgError,
"no stream to seek");
13765 ARGF_FORWARD(argc, argv);
13766 return rb_io_seek_m(argc, argv, ARGF.current_file);
13783 if (!next_argv()) {
13784 rb_raise(rb_eArgError,
"no stream to set position");
13786 ARGF_FORWARD(1, &offset);
13787 return rb_io_set_pos(ARGF.current_file, offset);
13808 if (!next_argv()) {
13809 rb_raise(rb_eArgError,
"no stream to rewind");
13811 ARGF_FORWARD(0, 0);
13812 old_lineno =
RFILE(ARGF.current_file)->fptr->lineno;
13813 ret = rb_io_rewind(ARGF.current_file);
13814 if (!global_argf_p(
argf)) {
13815 ARGF.last_lineno = ARGF.lineno -= old_lineno;
13833 if (!next_argv()) {
13834 rb_raise(rb_eArgError,
"no stream");
13836 ARGF_FORWARD(0, 0);
13837 return rb_io_fileno(ARGF.current_file);
13856 ARGF_FORWARD(0, 0);
13857 return ARGF.current_file;
13882 if (
RTEST(ARGF.current_file)) {
13883 if (ARGF.init_p == 0)
return Qtrue;
13885 ARGF_FORWARD(0, 0);
13944 VALUE tmp, str, length;
13948 if (!
NIL_P(length)) {
13953 rb_str_resize(str,0);
13958 if (!next_argv()) {
13961 if (ARGF_GENERIC_INPUT_P()) {
13962 tmp = argf_forward(argc, argv,
argf);
13965 tmp = io_read(argc, argv, ARGF.current_file);
13967 if (
NIL_P(str)) str = tmp;
13970 if (ARGF.next_p != -1) {
13976 else if (argc >= 1) {
13977 long slen = RSTRING_LEN(str);
13993argf_forward_call(
VALUE arg)
13996 argf_forward(p->argc, p->argv, p->argf);
14026 return argf_getpartial(argc, argv,
argf,
Qnil, 0);
14047 return argf_getpartial(argc, argv,
argf, opts, 1);
14053 VALUE tmp, str, length;
14061 no_exception = no_exception_p(opts);
14063 if (!next_argv()) {
14065 rb_str_resize(str, 0);
14069 if (ARGF_GENERIC_INPUT_P()) {
14079 tmp = io_getpartial(argc, argv, ARGF.current_file, no_exception, nonblock);
14082 if (ARGF.next_p == -1) {
14083 return io_nonblock_eof(no_exception);
14088 return io_nonblock_eof(no_exception);
14126 if (!next_argv())
return Qnil;
14127 if (ARGF_GENERIC_INPUT_P()) {
14128 ch = forward_current(rb_intern(
"getc"), 0, 0);
14131 ch = rb_io_getc(ARGF.current_file);
14133 if (
NIL_P(ch) && ARGF.next_p != -1) {
14166 if (!next_argv())
return Qnil;
14167 if (!RB_TYPE_P(ARGF.current_file,
T_FILE)) {
14168 ch = forward_current(rb_intern(
"getbyte"), 0, 0);
14173 if (
NIL_P(ch) && ARGF.next_p != -1) {
14207 if (!RB_TYPE_P(ARGF.current_file,
T_FILE)) {
14208 ch = forward_current(rb_intern(
"getc"), 0, 0);
14211 ch = rb_io_getc(ARGF.current_file);
14213 if (
NIL_P(ch) && ARGF.next_p != -1) {
14245 NEXT_ARGF_FORWARD(0, 0);
14246 c = argf_getbyte(
argf);
14253#define FOREACH_ARGF() while (next_argv())
14258 const VALUE current = ARGF.current_file;
14260 if (ARGF.init_p == -1 || current != ARGF.current_file) {
14266#define ARGF_block_call(mid, argc, argv, func, argf) \
14267 rb_block_call_kw(ARGF.current_file, mid, argc, argv, \
14268 func, argf, rb_keyword_given_p())
14273 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_i,
argf);
14274 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14280 if (!global_argf_p(
argf)) {
14281 ARGF.last_lineno = ++ARGF.lineno;
14283 return argf_block_call_i(i,
argf, argc, argv, blockarg);
14289 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_line_i,
argf);
14290 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14338 argf_block_call_line(rb_intern(
"each_line"), argc, argv,
argf);
14369 argf_block_call(rb_intern(
"each_byte"), 0, 0,
argf);
14395 argf_block_call(rb_intern(
"each_char"), 0, 0,
argf);
14421 argf_block_call(rb_intern(
"each_codepoint"), 0, 0,
argf);
14452 return ARGF.filename;
14456argf_filename_getter(
ID id,
VALUE *var)
14458 return argf_filename(*var);
14483 return ARGF.current_file;
14502 ARGF_FORWARD(0, 0);
14523 return RBOOL(ARGF.binmode);
14543 if (ARGF.init_p && ARGF.next_p == 0) {
14572 if (ARGF.next_p != -1) {
14590 ARGF_FORWARD(0, 0);
14617 if (!ARGF.inplace)
return Qnil;
14625 return argf_inplace_mode_get(*var);
14656 ARGF.inplace =
Qnil;
14667 argf_inplace_mode_set(*var, val);
14671ruby_set_inplace_mode(
const char *suffix)
14697argf_argv_getter(
ID id,
VALUE *var)
14699 return argf_argv(*var);
14718 if (!
RTEST(ARGF.current_file)) {
14721 return GetWriteIO(ARGF.current_file);
14733 return rb_io_writev(argf_write_io(
argf), argc, argv);
14748 case RB_IO_WAIT_WRITABLE:
14751 c = rb_eEAGAINWaitWritable;
14753#if EAGAIN != EWOULDBLOCK
14755 c = rb_eEWOULDBLOCKWaitWritable;
14759 c = rb_eEINPROGRESSWaitWritable;
14765 case RB_IO_WAIT_READABLE:
14768 c = rb_eEAGAINWaitReadable;
14770#if EAGAIN != EWOULDBLOCK
14772 c = rb_eEWOULDBLOCKWaitReadable;
14776 c = rb_eEINPROGRESSWaitReadable;
14783 rb_bug(
"invalid read/write type passed to rb_readwrite_sys_fail: %d", waiting);
14789get_LAST_READ_LINE(
ID _x,
VALUE *_y)
15674#include <sys/cygwin.h>
15675 static struct __cygwin_perfile pf[] =
15677 {
"", O_RDONLY | O_BINARY},
15678 {
"", O_WRONLY | O_BINARY},
15679 {
"", O_RDWR | O_BINARY},
15680 {
"", O_APPEND | O_BINARY},
15683 cygwin_internal(CW_PERFILE, pf);
15689 id_write = rb_intern_const(
"write");
15690 id_read = rb_intern_const(
"read");
15691 id_getc = rb_intern_const(
"getc");
15692 id_flush = rb_intern_const(
"flush");
15693 id_readpartial = rb_intern_const(
"readpartial");
15694 id_set_encoding = rb_intern_const(
"set_encoding");
15695 id_fileno = rb_intern_const(
"fileno");
15738#if EAGAIN == EWOULDBLOCK
15739 rb_eEWOULDBLOCKWaitReadable = rb_eEAGAINWaitReadable;
15741 rb_define_const(
rb_cIO,
"EWOULDBLOCKWaitReadable", rb_eEAGAINWaitReadable);
15742 rb_eEWOULDBLOCKWaitWritable = rb_eEAGAINWaitWritable;
15744 rb_define_const(
rb_cIO,
"EWOULDBLOCKWaitWritable", rb_eEAGAINWaitWritable);
15792 rb_gvar_ractor_local(
"$/");
15794 rb_gvar_ractor_local(
"$-0");
15798 rb_gvar_ractor_local(
"$_");
15799 rb_gvar_box_dynamic(
"$_");
15915 rb_gvar_ractor_local(
"$stdin");
15916 rb_gvar_ractor_local(
"$stdout");
15917 rb_gvar_ractor_local(
"$>");
15918 rb_gvar_ractor_local(
"$stderr");
16004 rb_define_method(rb_cARGF,
"external_encoding", argf_external_encoding, 0);
16005 rb_define_method(rb_cARGF,
"internal_encoding", argf_internal_encoding, 0);
16024 rb_gvar_ractor_local(
"$-i");
16028#if defined (_WIN32) || defined(__CYGWIN__)
16029 atexit(pipe_atexit);
16036 sym_mode =
ID2SYM(rb_intern_const(
"mode"));
16037 sym_perm =
ID2SYM(rb_intern_const(
"perm"));
16038 sym_flags =
ID2SYM(rb_intern_const(
"flags"));
16039 sym_extenc =
ID2SYM(rb_intern_const(
"external_encoding"));
16040 sym_intenc =
ID2SYM(rb_intern_const(
"internal_encoding"));
16041 sym_encoding =
ID2SYM(rb_id_encoding());
16042 sym_open_args =
ID2SYM(rb_intern_const(
"open_args"));
16043 sym_textmode =
ID2SYM(rb_intern_const(
"textmode"));
16044 sym_binmode =
ID2SYM(rb_intern_const(
"binmode"));
16045 sym_autoclose =
ID2SYM(rb_intern_const(
"autoclose"));
16046 sym_normal =
ID2SYM(rb_intern_const(
"normal"));
16047 sym_sequential =
ID2SYM(rb_intern_const(
"sequential"));
16048 sym_random =
ID2SYM(rb_intern_const(
"random"));
16049 sym_willneed =
ID2SYM(rb_intern_const(
"willneed"));
16050 sym_dontneed =
ID2SYM(rb_intern_const(
"dontneed"));
16051 sym_noreuse =
ID2SYM(rb_intern_const(
"noreuse"));
16052 sym_SET =
ID2SYM(rb_intern_const(
"SET"));
16053 sym_CUR =
ID2SYM(rb_intern_const(
"CUR"));
16054 sym_END =
ID2SYM(rb_intern_const(
"END"));
16056 sym_DATA =
ID2SYM(rb_intern_const(
"DATA"));
16059 sym_HOLE =
ID2SYM(rb_intern_const(
"HOLE"));
16061 sym_wait_readable =
ID2SYM(rb_intern_const(
"wait_readable"));
16062 sym_wait_writable =
ID2SYM(rb_intern_const(
"wait_writable"));
#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.
#define STRNCASECMP
@old{st_locale_insensitive_strncasecmp}
unsigned long ruby_strtoul(const char *str, char **endptr, int base)
Our own locale-insensitive version of strtoul(3).
#define rb_define_method(klass, mid, func, arity)
Defines klass#mid.
#define rb_define_singleton_method(klass, mid, func, arity)
Defines klass.mid.
#define rb_define_global_function(mid, func, arity)
Defines rb_mKernel #mid.
void rb_include_module(VALUE klass, VALUE module)
Includes a module to a class.
VALUE rb_define_class(const char *name, VALUE super)
Defines a top-level class.
VALUE rb_class_new(VALUE super)
Creates a new, anonymous class.
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
VALUE rb_define_module_under(VALUE outer, const char *name)
Defines a module under the namespace of outer.
void rb_define_alias(VALUE klass, const char *name1, const char *name2)
Defines an alias of a method.
int rb_scan_args_kw(int kw_flag, int argc, const VALUE *argv, const char *fmt,...)
Identical to rb_scan_args(), except it also accepts kw_splat.
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Retrieves argument from argc and argv to given VALUE references according to the format string.
int rb_block_given_p(void)
Determines if the current method is given a block.
int rb_get_kwargs(VALUE keyword_hash, const ID *table, int required, int optional, VALUE *values)
Keyword argument deconstructor.
#define ECONV_AFTER_OUTPUT
Old name of RUBY_ECONV_AFTER_OUTPUT.
#define rb_str_new2
Old name of rb_str_new_cstr.
#define TYPE(_)
Old name of rb_type.
#define RB_INTEGER_TYPE_P
Old name of rb_integer_type_p.
#define ENC_CODERANGE_7BIT
Old name of RUBY_ENC_CODERANGE_7BIT.
#define T_FILE
Old name of RUBY_T_FILE.
#define ENC_CODERANGE_VALID
Old name of RUBY_ENC_CODERANGE_VALID.
#define ECONV_UNIVERSAL_NEWLINE_DECORATOR
Old name of RUBY_ECONV_UNIVERSAL_NEWLINE_DECORATOR.
#define OBJ_INIT_COPY(obj, orig)
Old name of RB_OBJ_INIT_COPY.
#define ALLOC
Old name of RB_ALLOC.
#define 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 ECONV_NEWLINE_DECORATOR_WRITE_MASK
Old name of RUBY_ECONV_NEWLINE_DECORATOR_WRITE_MASK.
#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 MBCLEN_INVALID_P(ret)
Old name of ONIGENC_MBCLEN_INVALID_P.
#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 ECONV_NEWLINE_DECORATOR_READ_MASK
Old name of RUBY_ECONV_NEWLINE_DECORATOR_READ_MASK.
#define NUM2CHR
Old name of RB_NUM2CHR.
#define NUM2LONG
Old name of RB_NUM2LONG.
#define UINT2NUM
Old name of RB_UINT2NUM.
#define FIXNUM_P
Old name of RB_FIXNUM_P.
#define ECONV_NEWLINE_DECORATOR_MASK
Old name of RUBY_ECONV_NEWLINE_DECORATOR_MASK.
#define CONST_ID
Old name of RUBY_CONST_ID.
#define rb_ary_new2
Old name of rb_ary_new_capa.
#define NUM2SIZET
Old name of RB_NUM2SIZE.
#define ENC_CODERANGE_SET(obj, cr)
Old name of RB_ENC_CODERANGE_SET.
#define rb_str_new4
Old name of rb_str_new_frozen.
#define ALLOCV_END
Old name of RB_ALLOCV_END.
#define SYMBOL_P
Old name of RB_SYMBOL_P.
#define ECONV_DEFAULT_NEWLINE_DECORATOR
Old name of RUBY_ECONV_DEFAULT_NEWLINE_DECORATOR.
void rb_notimplement(void)
void rb_category_warn(rb_warning_category_t category, const char *fmt,...)
Identical to rb_category_warning(), except it reports unless $VERBOSE is nil.
void rb_category_warning(rb_warning_category_t category, const char *fmt,...)
Identical to rb_warning(), except it takes additional "category" parameter.
VALUE rb_rescue2(VALUE(*b_proc)(VALUE), VALUE data1, VALUE(*r_proc)(VALUE, VALUE), VALUE data2,...)
An equivalent of rescue clause.
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 err, const char *msg)
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 *msg)
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_ensure(VALUE(*b_proc)(VALUE), VALUE data1, VALUE(*e_proc)(VALUE), VALUE data2)
An equivalent to ensure clause.
VALUE rb_eSystemCallError
SystemCallError exception.
@ RB_WARN_CATEGORY_DEPRECATED
Warning is for deprecated features.
VALUE rb_mKernel
Kernel module.
VALUE rb_check_to_int(VALUE val)
Identical to rb_check_to_integer(), except it uses #to_int for conversion.
VALUE rb_any_to_s(VALUE obj)
Generates a textual representation of the given object.
VALUE rb_obj_alloc(VALUE klass)
Allocates an instance of the given class.
VALUE rb_class_new_instance(int argc, const VALUE *argv, VALUE klass)
Allocates, then initialises an instance of the given class.
VALUE rb_class_new_instance_kw(int argc, const VALUE *argv, VALUE klass, int kw_splat)
Identical to rb_class_new_instance(), except you can specify how to handle the last element of the gi...
VALUE rb_mEnumerable
Enumerable module.
VALUE rb_stdin
STDIN constant.
VALUE rb_stderr
STDERR constant.
VALUE rb_obj_class(VALUE obj)
Queries the class of an object.
VALUE rb_obj_dup(VALUE obj)
Duplicates the given object.
VALUE rb_inspect(VALUE obj)
Generates a human-readable textual representation of the given object.
VALUE rb_mWaitReadable
IO::WaitReadable module.
VALUE rb_mWaitWritable
IO::WaitReadable module.
VALUE rb_obj_freeze(VALUE obj)
Just calls rb_obj_freeze_inline() inside.
VALUE rb_check_to_integer(VALUE val, const char *mid)
Identical to rb_check_convert_type(), except the return value type is fixed to rb_cInteger.
VALUE rb_cFile
File class.
VALUE rb_stdout
STDOUT constant.
VALUE rb_to_int(VALUE val)
Identical to rb_check_to_int(), except it raises in case of conversion mismatch.
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_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_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.
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 $\\endiskip.
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_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.
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.
#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_io_oflags_fmode(int oflags)
Converts an oflags (that rb_io_modestr_oflags() returns) to a fmode (that rb_io_mode_flags() returns)...
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.
struct rb_io_internal_buffer rb_io_buffer_t
Just another name of rb_io_buffer_t.
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 ...
int rb_io_read_pending(rb_io_t *fptr)
Queries if the passed IO has any pending reads.
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.
void rb_eof_error(void)
Utility function to raise rb_eEOFError.
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.
#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.
#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.
#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.
struct rb_data_type_struct rb_data_type_t
This is the struct that holds necessary info for a struct.
#define TypedData_Make_Struct(klass, type, data_type, sval)
Identical to TypedData_Wrap_Struct, except it allocates a new data region internally instead of takin...
VALUE rb_get_argv(void)
Queries the arguments passed to the current process that you can access from Ruby as ARGV.
void rb_p(VALUE obj)
Inspects an object.
#define FilePathValue(v)
Ensures that the parameter object is a path.
#define errno
Ractor-aware version of errno.
#define RB_SCAN_ARGS_LAST_HASH_KEYWORDS
Treat a final argument as keywords if it is a hash, and not as keywords otherwise.
#define RB_PASS_CALLED_KEYWORDS
Pass keywords if current method is called with keywords, useful for argument delegation.
VALUE rb_fiber_scheduler_current(void)
Identical to rb_fiber_scheduler_get(), except it also returns RUBY_Qnil in case of a blocking fiber.
VALUE rb_fiber_scheduler_io_pread_memory(VALUE scheduler, VALUE io, rb_off_t from, void *base, size_t size, size_t length)
Non-blocking pread from the passed IO using a native buffer.
VALUE rb_fiber_scheduler_make_timeout(struct timeval *timeout)
Converts the passed timeout to an expression that rb_fiber_scheduler_block() etc.
VALUE rb_fiber_scheduler_io_wait_readable(VALUE scheduler, VALUE io)
Non-blocking wait until the passed IO is ready for reading.
VALUE rb_fiber_scheduler_io_read_memory(VALUE scheduler, VALUE io, void *base, size_t size, size_t length)
Non-blocking read from the passed IO using a native buffer.
VALUE rb_fiber_scheduler_io_wait(VALUE scheduler, VALUE io, VALUE events, VALUE timeout)
Non-blocking version of rb_io_wait().
VALUE rb_fiber_scheduler_io_selectv(VALUE scheduler, int argc, VALUE *argv)
Non-blocking version of IO.select, argv variant.
VALUE rb_fiber_scheduler_io_pwrite_memory(VALUE scheduler, VALUE io, rb_off_t from, const void *base, size_t size, size_t length)
Non-blocking pwrite to the passed IO using a native buffer.
VALUE rb_fiber_scheduler_current_for_thread(VALUE thread)
Identical to rb_fiber_scheduler_current(), except it queries for that of the passed thread value inst...
VALUE rb_fiber_scheduler_io_write_memory(VALUE scheduler, VALUE io, const void *base, size_t size, size_t length)
Non-blocking write to the passed IO using a native buffer.
VALUE rb_fiber_scheduler_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.
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.
#define RTEST
This is an old name of RB_TEST.
#define _(args)
This was a transition path from K&R to ANSI.
C99 shim for <stdbool.h>.
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
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.
void(*) finalize(struct rb_io *, int)
finalize proc
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.
#define RBIMPL_WARNING_IGNORED(flag)
Suppresses a warning.
#define RBIMPL_WARNING_PUSH()
Pushes compiler warning state.
#define RBIMPL_WARNING_POP()
Pops compiler warning state.