14#include "ruby/internal/config.h"
25# if defined(__linux__)
28# if defined(__FreeBSD_version) && __FreeBSD_version >= 1100000
38#define free(x) xfree(x)
45#if defined HAVE_NET_SOCKET_H
46# include <net/socket.h>
47#elif defined HAVE_SYS_SOCKET_H
48# include <sys/socket.h>
51#if defined(__CYGWIN__) || defined(_WIN32)
52# define NO_SAFE_RENAME
55#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__sun)
60#ifdef HAVE_SYS_IOCTL_H
63#if defined(HAVE_FCNTL_H)
65#elif defined(HAVE_SYS_FCNTL_H)
75#if defined(HAVE_SYS_PARAM_H)
76# include <sys/param.h>
89#elif defined HAVE_SYS_SYSCALL_H
90#include <sys/syscall.h>
101#ifdef HAVE_COPYFILE_H
102# include <copyfile.h>
104# ifndef COPYFILE_STATE_COPIED
110# undef HAVE_FCOPYFILE
116# include <AvailabilityMacros.h>
120#include "ccan/list/list.h"
125#include "internal/class.h"
126#include "internal/encoding.h"
127#include "internal/error.h"
128#include "internal/inits.h"
129#include "internal/io.h"
130#include "internal/numeric.h"
131#include "internal/object.h"
132#include "internal/process.h"
133#include "internal/thread.h"
134#include "internal/transcode.h"
135#include "internal/variable.h"
138#include "ruby/missing.h"
141#include "ruby_atomic.h"
151#define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR)
155# ifdef _POSIX_PIPE_BUF
156# define PIPE_BUF _POSIX_PIPE_BUF
163# define EWOULDBLOCK EAGAIN
166#if defined(HAVE___SYSCALL) && (defined(__APPLE__) || defined(__OpenBSD__))
168off_t __syscall(quad_t number, ...);
171#define IO_RBUF_CAPA_MIN 8192
172#define IO_CBUF_CAPA_MIN (128*1024)
173#define IO_RBUF_CAPA_FOR(fptr) (NEED_READCONV(fptr) ? IO_CBUF_CAPA_MIN : IO_RBUF_CAPA_MIN)
174#define IO_WBUF_CAPA_MIN 8192
176#define IO_MAX_BUFFER_GROWTH 8 * 1024 * 1024
181#define open rb_w32_uopen
183#define rename(f, t) rb_w32_urename((f), (t))
184#include "win32/file.h"
194static VALUE rb_eEAGAINWaitReadable;
195static VALUE rb_eEAGAINWaitWritable;
196#if EAGAIN != EWOULDBLOCK
197static VALUE rb_eEWOULDBLOCKWaitReadable;
198static VALUE rb_eEWOULDBLOCKWaitWritable;
200static VALUE rb_eEINPROGRESSWaitWritable;
201static VALUE rb_eEINPROGRESSWaitReadable;
204static VALUE orig_stdout, orig_stderr;
213static ID id_write, id_read, id_flush, id_readpartial, id_set_encoding, id_fileno;
214static VALUE sym_mode, sym_perm, sym_flags, sym_extenc, sym_intenc, sym_encoding, sym_open_args;
215static VALUE sym_textmode, sym_binmode, sym_autoclose;
216static VALUE sym_SET, sym_CUR, sym_END;
217static VALUE sym_wait_readable, sym_wait_writable;
219static VALUE sym_DATA;
222static VALUE sym_HOLE;
225static VALUE prep_io(
int fd,
enum rb_io_mode fmode,
VALUE klass,
const char *path);
228rb_io_blocking_region_wait(
struct rb_io *io, rb_blocking_function_t *function,
void *argument,
enum rb_io_event events)
230 return rb_thread_io_blocking_call(io, function, argument, events);
233VALUE rb_io_blocking_region(
struct rb_io *io, rb_blocking_function_t *function,
void *argument)
235 return rb_io_blocking_region_wait(io, function, argument, 0);
239 VALUE filename, current_file;
245 int8_t init_p, next_p, binmode;
249#if defined(__APPLE__) && \
250 (!defined(MAC_OS_VERSION_27_0) || (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_VERSION_27_0))
252# if __has_attribute(availability) && __has_warning("-Wunguarded-availability-new")
258static inline int (*rb_dup3(
void))(int, int, int) {
return &dup3;}
259# define dup3 rb_dup3()
263static inline int (*rb_pipe2(
void))(
int [2], int) {
return &pipe2;}
264# define pipe2 rb_pipe2()
289 if (fd < 0 || afd <= max_fd)
292#if defined(HAVE_FCNTL) && defined(F_GETFL)
293 err = fcntl(fd, F_GETFL) == -1;
297 err = fstat(fd, &buf) != 0;
300 if (err &&
errno == EBADF) {
301 rb_bug(
"rb_update_max_fd: invalid fd (%d) given.", fd);
304 while (max_fd < afd) {
305 max_fd = ATOMIC_CAS(max_file_descriptor, max_fd, afd);
310rb_maygvl_fd_fix_cloexec(
int fd)
313#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
314 int flags, flags2, ret;
315 flags = fcntl(fd, F_GETFD);
317 rb_bug(
"rb_maygvl_fd_fix_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(
errno));
320 flags2 = flags & ~FD_CLOEXEC;
322 flags2 = flags | FD_CLOEXEC;
323 if (flags != flags2) {
324 ret = fcntl(fd, F_SETFD, flags2);
326 rb_bug(
"rb_maygvl_fd_fix_cloexec: fcntl(%d, F_SETFD, %d) failed: %s", fd, flags2, strerror(
errno));
335 rb_maygvl_fd_fix_cloexec(fd);
342 return (e == EWOULDBLOCK) || (e == EAGAIN);
350 static const int retry_interval = 0;
351 static const int retry_max_count = 10000;
357#elif defined O_NOINHERIT
358 flags |= O_NOINHERIT;
361 while ((ret = open(pathname, flags, mode)) == -1) {
363 if (!io_again_p(e))
break;
364 if (retry_count++ >= retry_max_count)
break;
366 sleep(retry_interval);
369 if (ret < 0)
return ret;
371 if (ret > 2)
return ret;
373 rb_maygvl_fd_fix_cloexec(ret);
391 if (oldfd == newfd) {
395#if defined(HAVE_DUP3) && defined(O_CLOEXEC)
396# if defined(__APPLE__)
397# define try_dup3 (dup3 != NULL)
398# define abandon_dup3() true
400 static bool try_dup3 =
true;
401# define abandon_dup3() (errno != ENOSYS || !!(try_dup3 = false))
407 ret = dup3(oldfd, newfd, O_CLOEXEC);
414 if (abandon_dup3())
return ret;
417 ret = dup2(oldfd, newfd);
418 if (ret < 0)
return ret;
420 rb_maygvl_fd_fix_cloexec(ret);
425rb_fd_set_nonblock(
int fd)
428 return rb_w32_set_nonblock(fd);
429#elif defined(F_GETFL)
430 int oflags = fcntl(fd, F_GETFL);
434 if (oflags & O_NONBLOCK)
436 oflags |= O_NONBLOCK;
437 return fcntl(fd, F_SETFL, oflags);
443cloexec_pipe(
int descriptors[2],
int flags,
bool force_cloexec)
447# if defined(__APPLE__)
448# define try_pipe2 (pipe2 != NULL)
449# define abandon_pipe2() true
451 static bool try_pipe2 =
true;
452# define abandon_pipe2() (errno != ENOSYS || !!(try_pipe2 = false))
455 result = pipe2(descriptors, O_CLOEXEC | flags);
456 if (result == 0)
return result;
457 if (abandon_pipe2())
return result;
460 if (result < 0 && (result = pipe(descriptors)) < 0)
464 if (result == 0 && descriptors[1] == -1) {
465 close(descriptors[0]);
472 if (!force_cloexec)
return result;
475 rb_maygvl_fd_fix_cloexec(descriptors[0]);
476 rb_maygvl_fd_fix_cloexec(descriptors[1]);
479 rb_fd_set_nonblock(descriptors[0]);
480 rb_fd_set_nonblock(descriptors[1]);
489 return cloexec_pipe(descriptors, O_NONBLOCK,
true);
497#if defined(HAVE_FCNTL) && defined(F_DUPFD_CLOEXEC)
498 ret = fcntl(fd, F_DUPFD_CLOEXEC, minfd);
499 if (ret > 2)
return ret;
500#elif defined(HAVE_FCNTL) && defined(F_DUPFD)
501 ret = fcntl(fd, F_DUPFD, minfd);
504 if (ret >= 0 && ret < minfd) {
505 const int prev_fd = ret;
511 if (ret < 0)
return ret;
512 rb_maygvl_fd_fix_cloexec(ret);
516#define argf_of(obj) (*(struct argf *)DATA_PTR(obj))
517#define ARGF argf_of(argf)
518#define ARGF_SET(field, value) RB_OBJ_WRITE(argf, &ARGF.field, value)
520#define GetWriteIO(io) rb_io_get_write_io(io)
522#define READ_DATA_PENDING(fptr) ((fptr)->rbuf.len)
523#define READ_DATA_PENDING_COUNT(fptr) ((fptr)->rbuf.len)
524#define READ_DATA_PENDING_PTR(fptr) ((fptr)->rbuf.ptr+(fptr)->rbuf.off)
525#define READ_DATA_BUFFERED(fptr) READ_DATA_PENDING(fptr)
527#define READ_CHAR_PENDING(fptr) ((fptr)->cbuf.len)
528#define READ_CHAR_PENDING_COUNT(fptr) ((fptr)->cbuf.len)
529#define READ_CHAR_PENDING_PTR(fptr) ((fptr)->cbuf.ptr+(fptr)->cbuf.off)
532#define WAIT_FD_IN_WIN32(fptr) \
533 (rb_w32_io_cancelable_p((fptr)->fd) ? Qnil : rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_READABLE), RUBY_IO_TIMEOUT_DEFAULT))
535#define WAIT_FD_IN_WIN32(fptr)
538#define READ_CHECK(fptr) do {\
539 if (!READ_DATA_PENDING(fptr)) {\
540 WAIT_FD_IN_WIN32(fptr);\
541 rb_io_check_closed(fptr);\
547# define S_ISSOCK(m) _S_ISSOCK(m)
550# define S_ISSOCK(m) (((m) & S_IFMT) == _S_IFSOCK)
553# define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
559static int io_fflush(
rb_io_t *);
560static rb_io_t *flush_before_seek(
rb_io_t *fptr,
bool discard_rbuf);
561static void clear_readconv(
rb_io_t *fptr);
562static void clear_codeconv(
rb_io_t *fptr);
564#define FMODE_SIGNAL_ON_EPIPE (1<<17)
566#define fptr_signal_on_epipe(fptr) \
567 (((fptr)->mode & FMODE_SIGNAL_ON_EPIPE) != 0)
569#define fptr_set_signal_on_epipe(fptr, flag) \
571 (fptr)->mode |= FMODE_SIGNAL_ON_EPIPE : \
572 (fptr)->mode &= ~FMODE_SIGNAL_ON_EPIPE)
574extern ID ruby_static_id_signo;
576NORETURN(
static void rb_sys_fail_on_write(
rb_io_t *fptr));
578rb_sys_fail_on_write(
rb_io_t *fptr)
581 VALUE errinfo = rb_syserr_new_path(e, (fptr)->pathv);
583 if (fptr_signal_on_epipe(fptr) && (e == EPIPE)) {
595#define NEED_NEWLINE_DECORATOR_ON_READ(fptr) ((fptr)->mode & FMODE_TEXTMODE)
596#define NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) ((fptr)->mode & FMODE_TEXTMODE)
597#if defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32)
598# define RUBY_CRLF_ENVIRONMENT 1
600# define RUBY_CRLF_ENVIRONMENT 0
603#if RUBY_CRLF_ENVIRONMENT
605# define DEFAULT_TEXTMODE FMODE_TEXTMODE
606# define TEXTMODE_NEWLINE_DECORATOR_ON_WRITE ECONV_CRLF_NEWLINE_DECORATOR
614#define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || (fptr)->encs.ecflags & ~ECONV_CRLF_NEWLINE_DECORATOR)
615#define WRITECONV_MASK ( \
616 (ECONV_DECORATOR_MASK & ~ECONV_CRLF_NEWLINE_DECORATOR)|\
617 ECONV_STATEFUL_DECORATOR_MASK|\
619#define NEED_WRITECONV(fptr) ( \
620 ((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || \
621 ((fptr)->encs.ecflags & WRITECONV_MASK) || \
623#define SET_BINARY_MODE(fptr) setmode((fptr)->fd, O_BINARY)
625#define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) do {\
626 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {\
627 if (((fptr)->mode & FMODE_READABLE) &&\
628 !((fptr)->encs.ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {\
629 setmode((fptr)->fd, O_BINARY);\
632 setmode((fptr)->fd, O_TEXT);\
637#define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) do {\
638 if ((enc2) && ((ecflags) & ECONV_DEFAULT_NEWLINE_DECORATOR)) {\
639 (ecflags) |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;\
647io_unread(
rb_io_t *fptr,
bool discard_rbuf)
663 if (!rb_w32_fd_is_text(fptr->
fd)) {
664 r = lseek(fptr->
fd, -fptr->
rbuf.
len, SEEK_CUR);
665 if (r < 0 &&
errno) {
668 if (!discard_rbuf)
return;
674 pos = lseek(fptr->
fd, 0, SEEK_CUR);
675 if (pos < 0 &&
errno) {
678 if (!discard_rbuf)
goto end;
682 extra_max = (long)(pos - fptr->
rbuf.
len);
690 for (i = 0; i < fptr->
rbuf.
len; i++) {
691 if (*p ==
'\n') newlines++;
692 if (extra_max == newlines)
break;
697 while (newlines >= 0) {
698 r = lseek(fptr->
fd, pos - fptr->
rbuf.
len - newlines, SEEK_SET);
699 if (newlines == 0)
break;
704 read_size = _read(fptr->
fd, buf, fptr->
rbuf.
len + newlines);
708 rb_syserr_fail_path(e, fptr->
pathv);
710 if (read_size == fptr->
rbuf.
len) {
711 lseek(fptr->
fd, r, SEEK_SET);
722 clear_codeconv(fptr);
734set_binary_mode_with_seek_cur(
rb_io_t *fptr)
736 if (!rb_w32_fd_is_text(fptr->
fd))
return O_BINARY;
739 return setmode(fptr->
fd, O_BINARY);
741 flush_before_seek(fptr,
false);
742 return setmode(fptr->
fd, O_BINARY);
744#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) set_binary_mode_with_seek_cur(fptr)
748# define DEFAULT_TEXTMODE 0
749#define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || NEED_NEWLINE_DECORATOR_ON_READ(fptr))
750#define NEED_WRITECONV(fptr) ( \
751 ((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || \
752 NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) || \
753 ((fptr)->encs.ecflags & (ECONV_DECORATOR_MASK|ECONV_STATEFUL_DECORATOR_MASK)) || \
755#define SET_BINARY_MODE(fptr) (void)(fptr)
756#define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) (void)(fptr)
757#define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) ((void)(enc2), (void)(ecflags))
758#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) (void)(fptr)
761#if !defined HAVE_SHUTDOWN && !defined shutdown
762#define shutdown(a,b) 0
766#define is_socket(fd, path) rb_w32_is_socket(fd)
767#elif !defined(S_ISSOCK)
768#define is_socket(fd, path) 0
771is_socket(
int fd,
VALUE path)
774 if (fstat(fd, &sbuf) < 0)
775 rb_sys_fail_path(path);
776 return S_ISSOCK(sbuf.st_mode);
780static const char closed_stream[] =
"closed stream";
783io_fd_check_closed(
int fd)
816 io_fd_check_closed(fptr->
fd);
820rb_io_get_fptr(
VALUE io)
830 return rb_convert_type_with_id(io,
T_FILE,
"IO", idTo_io);
836 return rb_check_convert_type_with_id(io,
T_FILE,
"IO", idTo_io);
854 rb_io_t *fptr = rb_io_get_fptr(io);
863 return write_io ? write_io :
Qnil;
876 rb_io_t *fptr = rb_io_get_fptr(self);
906 if (
RTEST(timeout)) {
910 rb_io_t *fptr = rb_io_get_fptr(self);
935#if !RUBY_CRLF_ENVIRONMENT
937io_unread(
rb_io_t *fptr,
bool discard_rbuf)
945 r = lseek(fptr->
fd, -fptr->
rbuf.
len, SEEK_CUR);
946 if (r < 0 &&
errno) {
949 if (!discard_rbuf)
return;
953 clear_codeconv(fptr);
963 long len = RSTRING_LEN(str);
966 const int min_capa = IO_RBUF_CAPA_FOR(fptr);
969#if SIZEOF_LONG > SIZEOF_INT
996 long len = RSTRING_LEN(str);
1002 io_ungetbyte(str, fptr);
1006 int capa = (int)
len + pending;
1020flush_before_seek(
rb_io_t *fptr,
bool discard_rbuf)
1022 if (io_fflush(fptr) < 0)
1023 rb_sys_fail_on_write(fptr);
1024 io_unread(fptr, discard_rbuf);
1029#define io_seek(fptr, ofs, whence) (errno = 0, lseek(flush_before_seek(fptr, true)->fd, (ofs), (whence)))
1030#define io_tell(fptr) lseek(flush_before_seek(fptr, false)->fd, 0, SEEK_CUR)
1046 if (io_fflush(fptr) < 0)
1047 rb_sys_fail_on_write(fptr);
1052 if (io_fflush(wfptr) < 0)
1053 rb_sys_fail_on_write(wfptr);
1061 if (READ_CHAR_PENDING(fptr)) {
1062 rb_raise(
rb_eIOError,
"byte oriented read for character buffered IO");
1073io_read_encoding(
rb_io_t *fptr)
1078 return rb_default_external_encoding();
1082io_input_encoding(
rb_io_t *fptr)
1087 return io_read_encoding(fptr);
1098 io_unread(fptr,
true);
1103rb_io_read_pending(
rb_io_t *fptr)
1106 if (READ_CHAR_PENDING(fptr))
1108 return READ_DATA_PENDING(fptr);
1114 if (!READ_DATA_PENDING(fptr)) {
1121rb_gc_for_fd(
int err)
1123 if (err == EMFILE || err == ENFILE || err == ENOMEM) {
1133#define TRY_WITH_GC(expr) \
1134 for (int first_errno, retried_errno = 0, retried = 0; \
1137 (!rb_gc_for_fd(first_errno = errno) || !(expr)) && \
1138 (retried_errno = errno, 1)); \
1139 (void)retried_errno, retried = 1)
1154io_alloc(
VALUE klass)
1156 UNPROTECTED_NEWOBJ_OF(io,
struct RFile, klass,
T_FILE,
sizeof(
struct RFile));
1164# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
1190struct io_internal_writev_struct {
1197 const struct iovec *iov;
1210io_internal_wait(
VALUE thread,
rb_io_t *fptr,
int error,
int events,
struct timeval *timeout)
1212 if (!timeout && rb_thread_mn_schedulable(thread)) {
1217 int ready = nogvl_wait_for(thread, fptr, events, timeout);
1222 else if (ready == 0) {
1239internal_read_func(
void *ptr)
1244 if (iis->timeout && !iis->nonblock) {
1245 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_IN, iis->timeout) == -1) {
1251 result = read(iis->fd, iis->buf, iis->capa);
1253 if (result < 0 && !iis->nonblock) {
1254 if (io_again_p(
errno)) {
1255 if (io_internal_wait(iis->th, iis->fptr,
errno, RB_WAITFD_IN, iis->timeout) == -1) {
1267#if defined __APPLE__
1268# define do_write_retry(code) do {result = code;} while (result == -1 && errno == EPROTOTYPE)
1270# define do_write_retry(code) result = code
1274internal_write_func(
void *ptr)
1279 if (iis->timeout && !iis->nonblock) {
1280 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1286 do_write_retry(write(iis->fd, iis->buf, iis->capa));
1288 if (result < 0 && !iis->nonblock) {
1290 if (io_again_p(e)) {
1291 if (io_internal_wait(iis->th, iis->fptr,
errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1305internal_writev_func(
void *ptr)
1307 struct io_internal_writev_struct *iis = ptr;
1310 if (iis->timeout && !iis->nonblock) {
1311 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1317 do_write_retry(writev(iis->fd, iis->iov, iis->iovcnt));
1319 if (result < 0 && !iis->nonblock) {
1320 if (io_again_p(
errno)) {
1321 if (io_internal_wait(iis->th, iis->fptr,
errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1335rb_io_read_memory(
rb_io_t *fptr,
void *buf,
size_t count)
1339 if (scheduler !=
Qnil) {
1342 if (!UNDEF_P(result)) {
1358 struct timeval timeout_storage;
1362 iis.timeout = &timeout_storage;
1365 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_read_func, &iis,
RUBY_IO_READABLE);
1369rb_io_write_memory(
rb_io_t *fptr,
const void *buf,
size_t count)
1373 if (scheduler !=
Qnil) {
1376 if (!UNDEF_P(result)) {
1392 struct timeval timeout_storage;
1396 iis.timeout = &timeout_storage;
1399 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_write_func, &iis,
RUBY_IO_WRITABLE);
1404rb_writev_internal(
rb_io_t *fptr,
const struct iovec *iov,
int iovcnt)
1406 if (!iovcnt)
return 0;
1411 if (scheduler !=
Qnil) {
1415 if (!UNDEF_P(result)) {
1420 struct io_internal_writev_struct iis = {
1431 struct timeval timeout_storage;
1435 iis.timeout = &timeout_storage;
1438 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_writev_func, &iis,
RUBY_IO_WRITABLE);
1443io_flush_buffer_sync(
void *arg)
1465io_flush_buffer_fiber_scheduler(
VALUE scheduler,
rb_io_t *fptr)
1468 if (!UNDEF_P(ret)) {
1480io_flush_buffer_async(
VALUE arg)
1485 if (scheduler !=
Qnil) {
1486 VALUE result = io_flush_buffer_fiber_scheduler(scheduler, fptr);
1487 if (!UNDEF_P(result)) {
1492 return rb_io_blocking_region_wait(fptr, io_flush_buffer_sync, fptr,
RUBY_IO_WRITABLE);
1499 return (
int)io_flush_buffer_async((
VALUE)fptr);
1514 while (fptr->
wbuf.
len > 0 && io_flush_buffer(fptr) != 0) {
1530 if (scheduler !=
Qnil) {
1540 if (NIL_OR_UNDEF_P(timeout)) {
1544 if (timeout !=
Qnil) {
1549 int ready = rb_thread_io_wait(th, fptr,
RB_NUM2INT(events), tv);
1575 if (scheduler !=
Qnil) {
1581 return rb_thread_wait_for_single_fd(th, fd, events, timeout);
1587 io_fd_check_closed(f);
1594#if defined(ERESTART)
1601#if EWOULDBLOCK != EAGAIN
1604 if (scheduler !=
Qnil) {
1622 io_fd_check_closed(f);
1629#if defined(ERESTART)
1645#if EWOULDBLOCK != EAGAIN
1648 if (scheduler !=
Qnil) {
1668 return io_wait_for_single_fd(fd, events, timeout, th, scheduler);
1702#if defined(ERESTART)
1712#if EWOULDBLOCK != EAGAIN
1735 if (
RTEST(result)) {
1750 if (
RTEST(result)) {
1764 const char *senc, *denc;
1771 ecflags = fptr->
encs.
ecflags & ~ECONV_NEWLINE_DECORATOR_READ_MASK;
1798 denc = rb_enc_name(enc);
1830io_binwrite_string_internal(
rb_io_t *fptr,
const char *ptr,
long length)
1833 struct iovec iov[2];
1836 iov[0].iov_len = fptr->
wbuf.
len;
1837 iov[1].iov_base = (
void*)ptr;
1838 iov[1].iov_len = length;
1840 ssize_t result = rb_writev_internal(fptr, iov, 2);
1845 if (result >= fptr->
wbuf.
len) {
1853 fptr->
wbuf.
off += (int)result;
1854 fptr->
wbuf.
len -= (int)result;
1862 return rb_io_write_memory(fptr, ptr, length);
1867io_binwrite_string_internal(
rb_io_t *fptr,
const char *ptr,
long length)
1869 long remaining = length;
1872 if (fptr->
wbuf.
len+length <= fptr->wbuf.capa) {
1879 fptr->
wbuf.
len += (int)length;
1886 if (io_fflush(fptr) < 0) {
1891 if (remaining == 0) {
1897 return rb_io_write_memory(fptr, ptr, length);
1902io_binwrite_string(
VALUE arg)
1906 const char *ptr = p->ptr;
1907 size_t remaining = p->length;
1911 ssize_t result = io_binwrite_string_internal(p->fptr, ptr, remaining);
1917 else if (result > 0) {
1918 if ((
size_t)result == remaining)
break;
1920 remaining -= result;
1936io_allocate_write_buffer(
rb_io_t *fptr,
int sync)
1941 fptr->
wbuf.
capa = IO_WBUF_CAPA_MIN;
1952io_binwrite_requires_flush_write(
rb_io_t *fptr,
long len,
int nosync)
1967io_binwrite(
const char *ptr,
long len,
rb_io_t *fptr,
int nosync)
1969 if (
len <= 0)
return len;
1974 io_allocate_write_buffer(fptr, !nosync);
1976 if (io_binwrite_requires_flush_write(fptr,
len, nosync)) {
1987 return io_binwrite_string((
VALUE)&arg);
2004# define MODE_BTMODE(a,b,c) ((fmode & FMODE_BINMODE) ? (b) : \
2005 (fmode & FMODE_TEXTMODE) ? (c) : (a))
2007#define MODE_BTXMODE(a, b, c, d, e, f) ((fmode & FMODE_EXCL) ? \
2008 MODE_BTMODE(d, e, f) : \
2009 MODE_BTMODE(a, b, c))
2014 if (NEED_WRITECONV(fptr)) {
2016 SET_BINARY_MODE(fptr);
2018 make_writeconv(fptr);
2021#define fmode (fptr->mode)
2024 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1) && !rb_enc_asciicompat(rb_enc_get(str))) {
2025 rb_raise(rb_eArgError,
"ASCII incompatible string written for text mode IO without encoding conversion: %s",
2026 rb_enc_name(rb_enc_get(str)));
2032 common_encoding = rb_enc_from_encoding(fptr->
encs.
enc2);
2033 else if (fptr->
encs.
enc != rb_ascii8bit_encoding())
2034 common_encoding = rb_enc_from_encoding(fptr->
encs.
enc);
2037 if (!
NIL_P(common_encoding)) {
2048#if RUBY_CRLF_ENVIRONMENT
2049#define fmode (fptr->mode)
2050 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1)) {
2053 setmode(fptr->
fd, O_BINARY);
2056 setmode(fptr->
fd, O_TEXT);
2058 if (!rb_enc_asciicompat(rb_enc_get(str))) {
2059 rb_raise(rb_eArgError,
"ASCII incompatible string written for text mode IO without encoding conversion: %s",
2060 rb_enc_name(rb_enc_get(str)));
2078 if (rb_w32_write_console(str, fptr->
fd) > 0)
return RSTRING_LEN(str);
2082 str = do_writeconv(str, fptr, &converted);
2088 n = io_binwrite(ptr,
len, fptr, nosync);
2101 return (ssize_t)io_binwrite(buf, (
long)size, fptr, 0);
2111 io = GetWriteIO(io);
2121 if (RSTRING_LEN(str) == 0)
return INT2FIX(0);
2126 n = io_fwrite(str, fptr, nosync);
2127 if (n < 0L) rb_sys_fail_on_write(fptr);
2133struct binwritev_arg {
2141io_binwritev_internal(
VALUE arg)
2143 struct binwritev_arg *p = (
struct binwritev_arg *)arg;
2145 size_t remaining = p->total;
2149 struct iovec *iov = p->iov;
2150 int iovcnt = p->iovcnt;
2153 long result = rb_writev_internal(fptr, iov, iovcnt);
2158 if (offset < (
size_t)fptr->
wbuf.
len) {
2163 offset -= (size_t)fptr->
wbuf.
len;
2169 if (offset == p->total) {
2173 while (result >= (ssize_t)iov->iov_len) {
2175 result -= iov->iov_len;
2185 iov->iov_base = (
char *)iov->iov_base + result;
2186 iov->iov_len -= result;
2200io_binwritev(
struct iovec *iov,
int iovcnt,
rb_io_t *fptr)
2205 if (iovcnt == 0)
return 0;
2208 for (
int i = 1; i < iovcnt; i++) total += iov[i].iov_len;
2210 io_allocate_write_buffer(fptr, 1);
2216 if (offset + total <= (
size_t)fptr->
wbuf.
capa) {
2217 for (
int i = 1; i < iovcnt; i++) {
2218 memcpy(fptr->
wbuf.
ptr+offset, iov[i].iov_base, iov[i].iov_len);
2219 offset += iov[i].iov_len;
2230 if (io_fflush(fptr) < 0)
return -1;
2236 iov[0].iov_len = fptr->
wbuf.
len;
2249 struct binwritev_arg arg;
2252 arg.iovcnt = iovcnt;
2259 return io_binwritev_internal((
VALUE)&arg);
2266 int i, converted, iovcnt = argc + 1;
2268 VALUE v1, v2, str, tmp, *tmp_array;
2274 for (i = 0; i < argc; i++) {
2277 str = do_writeconv(str, fptr, &converted);
2282 tmp = rb_str_tmp_frozen_acquire(str);
2286 iov[i+1].iov_base = RSTRING_PTR(tmp);
2287 iov[i+1].iov_len = RSTRING_LEN(tmp);
2290 n = io_binwritev(iov, iovcnt, fptr);
2293 for (i = 0; i < argc; i++) {
2294 rb_str_tmp_frozen_release(argv[i], tmp_array[i]);
2303iovcnt_ok(
int iovcnt)
2306 return iovcnt < IOV_MAX;
2314io_writev(
int argc,
const VALUE *argv,
VALUE io)
2321 io = GetWriteIO(io);
2334 for (i = 0; i < argc; i += cnt) {
2337 n = io_fwritev(cnt, &argv[i], fptr);
2348 rb_sys_fail_on_write(fptr);
2350 total = rb_fix_plus(
LONG2FIX(n), total);
2381 return io_writev(argc, argv, io);
2384 VALUE str = argv[0];
2385 return io_write(io, str, 0);
2396rb_io_writev(
VALUE io,
int argc,
const VALUE *argv)
2401 char sep = RCLASS_SINGLETON_P(klass) ? (klass = io,
'.') :
'#';
2404 " which accepts just one argument",
2409 do rb_io_write(io, *argv++);
while (--argc);
2440 rb_io_write(io, str);
2446nogvl_fsync(
void *ptr)
2451 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->
fd)) != FILE_TYPE_DISK)
2454 return (
VALUE)fsync(fptr->
fd);
2459rb_io_flush_raw(
VALUE io,
int sync)
2467 io = GetWriteIO(io);
2471 if (io_fflush(fptr) < 0)
2472 rb_sys_fail_on_write(fptr);
2475 io_unread(fptr,
true);
2496 return rb_io_flush_raw(io, 1);
2522 pos = io_tell(fptr);
2523 if (pos < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
2529rb_io_seek(
VALUE io,
VALUE offset,
int whence)
2536 pos = io_seek(fptr, pos, whence);
2537 if (pos < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
2538 if (fptr->
readconv) clear_readconv(fptr);
2544interpret_seek_whence(
VALUE vwhence)
2546 if (vwhence == sym_SET)
2548 if (vwhence == sym_CUR)
2550 if (vwhence == sym_END)
2553 if (vwhence == sym_DATA)
2557 if (vwhence == sym_HOLE)
2613 VALUE offset, ptrname;
2614 int whence = SEEK_SET;
2616 if (
rb_scan_args(argc, argv,
"11", &offset, &ptrname) == 2) {
2617 whence = interpret_seek_whence(ptrname);
2620 return rb_io_seek(io, offset, whence);
2648 pos = io_seek(fptr, pos, SEEK_SET);
2649 if (pos < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
2650 if (fptr->
readconv) clear_readconv(fptr);
2680rb_io_rewind(
VALUE io)
2685 if (io_seek(fptr, 0L, 0) < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
2686 if (io == ARGF.current_file) {
2687 ARGF.lineno -= fptr->
lineno;
2691 clear_readconv(fptr);
2698fptr_wait_readable(
rb_io_t *fptr)
2716 fptr->
rbuf.
capa = IO_RBUF_CAPA_FOR(fptr);
2724 if (fptr_wait_readable(fptr))
2728 VALUE path = rb_sprintf(
"fd:%d ", fptr->
fd);
2733 rb_syserr_fail_path(e, path);
2787 if (READ_CHAR_PENDING(fptr))
return Qfalse;
2788 if (READ_DATA_PENDING(fptr))
return Qfalse;
2790#if RUBY_CRLF_ENVIRONMENT
2791 if (!NEED_READCONV(fptr) && NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
2792 return RBOOL(eof(fptr->
fd));
2795 return RBOOL(io_fillbuf(fptr) < 0);
2819 io = GetWriteIO(io);
2856 io = GetWriteIO(io);
2862 fptr->
mode &= ~FMODE_SYNC;
2886rb_io_fsync(
VALUE io)
2890 io = GetWriteIO(io);
2893 if (io_fflush(fptr) < 0)
2894 rb_sys_fail_on_write(fptr);
2896 if ((
int)rb_io_blocking_region(fptr, nogvl_fsync, fptr))
2897 rb_sys_fail_path(fptr->
pathv);
2902# define rb_io_fsync rb_f_notimplement
2903# define rb_io_sync rb_f_notimplement
2912#ifdef HAVE_FDATASYNC
2914nogvl_fdatasync(
void *ptr)
2918 return (
VALUE)fdatasync(fptr->
fd);
2933rb_io_fdatasync(
VALUE io)
2937 io = GetWriteIO(io);
2940 if (io_fflush(fptr) < 0)
2941 rb_sys_fail_on_write(fptr);
2943 if ((
int)rb_io_blocking_region(fptr, nogvl_fdatasync, fptr) == 0)
2947 return rb_io_fsync(io);
2950#define rb_io_fdatasync rb_io_fsync
2968rb_io_fileno(
VALUE io)
2988 if (!UNDEF_P(fileno)) {
3081rb_io_inspect(
VALUE obj)
3085 static const char closed[] =
" (closed)";
3087 fptr =
RFILE(obj)->fptr;
3094 rb_str_cat(result, closed+1, strlen(closed)-1);
3097 rb_str_catf(result,
"fd %d", fptr->
fd);
3118rb_io_to_io(
VALUE io)
3125read_buffered_data(
char *ptr,
long len,
rb_io_t *fptr)
3129 n = READ_DATA_PENDING_COUNT(fptr);
3130 if (n <= 0)
return 0;
3131 if (n >
len) n = (int)
len;
3139io_bufread(
char *ptr,
long len,
rb_io_t *fptr,
long *read_len)
3146 if (READ_DATA_PENDING(fptr) == 0) {
3150 c = rb_io_read_memory(fptr, ptr+offset, n);
3153 if (fptr_wait_readable(fptr))
3159 if ((n -= c) <= 0)
break;
3165 c = read_buffered_data(ptr+offset, n, fptr);
3169 if ((n -= c) <= 0)
break;
3172 if (io_fillbuf(fptr) < 0) {
3179static int io_setstrbuf(
VALUE *str,
long len);
3190bufread_body(
VALUE arg)
3193 p->len = io_bufread(p->str_ptr + p->offset, p->len, p->fptr, &p->read_len);
3202 if (p->offset + p->read_len > 0) {
3204 io_restore_read_buffer(str, p->fptr);
3211bufread_call(
VALUE arg)
3216 return bufread_body(arg);
3218 return rb_rescue2(bufread_body, arg, bufread_timeout, arg,
3219 rb_eIOTimeoutError, (
VALUE)0);
3223io_fread(
VALUE str,
long offset,
long size,
rb_io_t *fptr)
3228 io_setstrbuf(&str, offset + size);
3229 arg.str_ptr = RSTRING_PTR(str);
3230 arg.offset = offset;
3234 rb_str_locktmp_ensure(str, bufread_call, (
VALUE)&arg);
3236 if (
len < 0) rb_sys_fail_path(fptr->
pathv);
3244 rb_off_t siz = READ_DATA_PENDING_COUNT(fptr);
3247 if (fstat(fptr->
fd, &st) == 0 && S_ISREG(st.st_mode)
3248#
if defined(__HAIKU__)
3253 if (io_fflush(fptr) < 0)
3254 rb_sys_fail_on_write(fptr);
3255 pos = lseek(fptr->
fd, 0, SEEK_CUR);
3256 if (st.st_size >= pos && pos >= 0) {
3257 siz += st.st_size - pos;
3258 if (siz > LONG_MAX) {
3259 rb_raise(
rb_eIOError,
"file too big for single read");
3272 rb_enc_associate(str, io_read_encoding(fptr));
3277make_readconv(
rb_io_t *fptr,
int size)
3282 const char *sname, *dname;
3283 ecflags = fptr->
encs.
ecflags & ~ECONV_NEWLINE_DECORATOR_WRITE_MASK;
3286 sname = rb_enc_name(fptr->
encs.
enc2);
3287 dname = rb_enc_name(io_read_encoding(fptr));
3297 if (size < IO_CBUF_CAPA_MIN) size = IO_CBUF_CAPA_MIN;
3303#define MORE_CHAR_SUSPENDED Qtrue
3304#define MORE_CHAR_FINISHED Qnil
3306fill_cbuf(
rb_io_t *fptr,
int ec_flags)
3308 const unsigned char *ss, *sp, *se;
3309 unsigned char *ds, *dp, *de;
3318 return MORE_CHAR_SUSPENDED;
3329 ss = sp = (
const unsigned char *)fptr->
rbuf.
ptr + fptr->
rbuf.
off;
3334 fptr->
rbuf.
off += (int)(sp - ss);
3335 fptr->
rbuf.
len -= (int)(sp - ss);
3336 fptr->
cbuf.
len += (int)(dp - ds);
3341 fptr->
rbuf.
off -= putbackable;
3342 fptr->
rbuf.
len += putbackable;
3349 if (cbuf_len0 != fptr->
cbuf.
len)
3350 return MORE_CHAR_SUSPENDED;
3353 return MORE_CHAR_FINISHED;
3359 if (io_fillbuf(fptr) < 0) {
3361 return MORE_CHAR_FINISHED;
3366 fptr->
cbuf.
len += (int)(dp - ds);
3373 if (cbuf_len0 != fptr->
cbuf.
len)
3374 return MORE_CHAR_SUSPENDED;
3376 return MORE_CHAR_FINISHED;
3384 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED)
3401 rb_enc_associate(str, fptr->
encs.
enc);
3426 long clen = RSTRING_LEN(s);
3438#define MAX_REALLOC_GAP 4096
3440io_shrink_read_string(
VALUE str,
long n)
3443 rb_str_resize(str, n);
3448io_set_read_length(
VALUE str,
long n,
int shrinkable)
3450 if (RSTRING_LEN(str) != n) {
3453 if (shrinkable) io_shrink_read_string(str, n);
3467 if (NEED_READCONV(fptr)) {
3468 int first = !
NIL_P(str);
3469 SET_BINARY_MODE(fptr);
3470 shrinkable = io_setstrbuf(&str,0);
3471 make_readconv(fptr, 0);
3476 io_shift_cbuf(fptr, fptr->
cbuf.
len, &str);
3478 v = fill_cbuf(fptr, 0);
3479 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED) {
3482 io_shift_cbuf(fptr, fptr->
cbuf.
len, &str);
3486 if (v == MORE_CHAR_FINISHED) {
3487 clear_readconv(fptr);
3489 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3490 return io_enc_str(str, fptr);
3495 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3499 enc = io_read_encoding(fptr);
3512 shrinkable = io_setstrbuf(&str, siz);
3515 n = io_fread(str, bytes, siz - bytes, fptr);
3516 if (n == 0 && bytes == 0) {
3524 if (bytes < siz)
break;
3528 if (
capa < (
size_t)RSTRING_LEN(str) + BUFSIZ) {
3529 if (
capa < BUFSIZ) {
3532 else if (
capa > IO_MAX_BUFFER_GROWTH) {
3533 capa = IO_MAX_BUFFER_GROWTH;
3538 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3539 str = io_enc_str(str, fptr);
3547 if (rb_fd_set_nonblock(fptr->
fd) != 0) {
3548 rb_sys_fail_path(fptr->
pathv);
3553io_read_memory_call(
VALUE arg)
3558 if (scheduler !=
Qnil) {
3561 if (!UNDEF_P(result)) {
3567 if (iis->nonblock) {
3568 return rb_io_blocking_region(iis->fptr, internal_read_func, iis);
3571 return rb_io_blocking_region_wait(iis->fptr, internal_read_func, iis,
RUBY_IO_READABLE);
3578 return (
long)rb_str_locktmp_ensure(str, io_read_memory_call, (
VALUE)iis);
3581#define no_exception_p(opts) !rb_opts_exception_p((opts), TRUE)
3584io_getpartial(
int argc,
VALUE *argv,
VALUE io,
int no_exception,
int nonblock)
3595 rb_raise(rb_eArgError,
"negative length %ld given",
len);
3598 shrinkable = io_setstrbuf(&str,
len);
3604 io_set_read_length(str, 0, shrinkable);
3610 n = read_buffered_data(RSTRING_PTR(str),
len, fptr);
3616 io_setstrbuf(&str,
len);
3619 iis.nonblock = nonblock;
3621 iis.buf = RSTRING_PTR(str);
3624 n = io_read_memory_locktmp(str, &iis);
3627 if (!nonblock && fptr_wait_readable(fptr))
3629 if (nonblock && (io_again_p(e))) {
3631 return sym_wait_readable;
3634 e,
"read would block");
3636 rb_syserr_fail_path(e, fptr->
pathv);
3639 io_set_read_length(str, n, shrinkable);
3740io_readpartial(
int argc,
VALUE *argv,
VALUE io)
3744 ret = io_getpartial(argc, argv, io,
Qnil, 0);
3751io_nonblock_eof(
int no_exception)
3753 if (!no_exception) {
3769 rb_raise(rb_eArgError,
"negative length %ld given",
len);
3772 shrinkable = io_setstrbuf(&str,
len);
3773 rb_bool_expected(ex,
"exception", TRUE);
3779 io_set_read_length(str, 0, shrinkable);
3783 n = read_buffered_data(RSTRING_PTR(str),
len, fptr);
3785 rb_fd_set_nonblock(fptr->
fd);
3786 shrinkable |= io_setstrbuf(&str,
len);
3790 iis.buf = RSTRING_PTR(str);
3793 n = io_read_memory_locktmp(str, &iis);
3796 if (io_again_p(e)) {
3797 if (!ex)
return sym_wait_readable;
3799 e,
"read would block");
3801 rb_syserr_fail_path(e, fptr->
pathv);
3804 io_set_read_length(str, n, shrinkable);
3807 if (!ex)
return Qnil;
3823 rb_bool_expected(ex,
"exception", TRUE);
3825 io = GetWriteIO(io);
3829 if (io_fflush(fptr) < 0)
3830 rb_sys_fail_on_write(fptr);
3832 rb_fd_set_nonblock(fptr->
fd);
3833 n = write(fptr->
fd, RSTRING_PTR(str), RSTRING_LEN(str));
3838 if (io_again_p(e)) {
3840 return sym_wait_writable;
3846 rb_syserr_fail_path(e, fptr->
pathv);
3930#if RUBY_CRLF_ENVIRONMENT
3936 if (
NIL_P(length)) {
3939 return read_all(fptr, remain_size(fptr), str);
3943 rb_raise(rb_eArgError,
"negative length %ld given",
len);
3946 shrinkable = io_setstrbuf(&str,
len);
3951 io_set_read_length(str, 0, shrinkable);
3956#if RUBY_CRLF_ENVIRONMENT
3957 previous_mode = set_binary_mode_with_seek_cur(fptr);
3959 n = io_fread(str, 0,
len, fptr);
3960 io_set_read_length(str, n, shrinkable);
3961#if RUBY_CRLF_ENVIRONMENT
3962 if (previous_mode == O_TEXT) {
3963 setmode(fptr->
fd, O_TEXT);
3966 if (n == 0)
return Qnil;
3972rscheck(
const char *rsptr,
long rslen,
VALUE rs)
3975 if (RSTRING_PTR(rs) != rsptr && RSTRING_LEN(rs) != rslen)
3980search_delim(
const char *p,
long len,
int delim,
rb_encoding *enc)
3982 if (rb_enc_mbminlen(enc) == 1) {
3983 p = memchr(p, delim,
len);
3984 if (p)
return p + 1;
3987 const char *end = p +
len;
3989 int r = rb_enc_precise_mbclen(p, end, enc);
3991 p += rb_enc_mbminlen(enc);
3995 if (rb_enc_mbc_to_codepoint(p, end, enc) == (
unsigned int)delim) {
4011 if (!READ_DATA_PENDING(fptr)) {
4013 if (io_fillbuf(fptr) < 0)
break;
4015 buf[n++] = *READ_DATA_PENDING_PTR(fptr);
4018 r = rb_enc_precise_mbclen(buf, buf + n, enc);
4025unread_raw_character(
rb_io_t *fptr,
const char *buf,
int len)
4037search_wide_delim(
const char *p,
long len,
const char *delim,
int width)
4039 const char *e = p +
len;
4042 while (index < width && delim[index] == 0) index++;
4043 if (index == width) index = 0;
4045 const char *candidate = p + index;
4046 while (candidate < e) {
4047 candidate = memchr(candidate, (
unsigned char)delim[index], e - candidate);
4048 if (candidate == NULL)
break;
4049 const char *start = candidate - index;
4050 if ((start - p) % width == 0 && start + width <= e &&
4051 memcmp(start, delim, width) == 0) {
4065 if (NEED_READCONV(fptr)) {
4066 SET_BINARY_MODE(fptr);
4067 make_readconv(fptr, 0);
4070 int searchlen = READ_CHAR_PENDING_COUNT(fptr);
4072 p = READ_CHAR_PENDING_PTR(fptr);
4073 if (0 < limit && limit < searchlen)
4074 searchlen = (int)limit;
4075 e = search_delim(p, searchlen, delim, enc);
4077 int len = (int)(e-p);
4099 return (
unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
4102 }
while (more_char(fptr) != MORE_CHAR_FINISHED);
4103 clear_readconv(fptr);
4108 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4109 if (rb_enc_mbminlen(enc) != 1) {
4110 char buf[ONIGENC_CODE_TO_MBC_MAXLEN];
4114 int width = rb_enc_mbminlen(enc);
4115 int delim_len = rb_enc_codelen(delim, enc);
4117 if (delim_len == width) {
4118 rb_enc_mbcput(delim, buf, enc);
4120 if (!READ_DATA_PENDING(fptr)) {
4122 if (io_fillbuf(fptr) < 0)
return EOF;
4124 long pending = READ_DATA_PENDING_COUNT(fptr);
4125 long complete = pending - pending % width;
4126 const char *p = READ_DATA_PENDING_PTR(fptr);
4127 const char *q = complete ? search_wide_delim(p, complete, buf, width) : NULL;
4128 long take = q ? q - p + width : complete;
4137 if (q)
return delim;
4138 if (complete == pending)
continue;
4140 len = read_raw_character(fptr, enc, buf);
4141 if (
len == 0)
return EOF;
4145 int r = rb_enc_precise_mbclen(buf, buf +
len, enc);
4147 rb_enc_mbc_to_codepoint(buf, buf +
len, enc) == (
unsigned int)delim)
4153 while ((
len = read_raw_character(fptr, enc, buf)) > 0) {
4160 return (
unsigned char)buf[
len - 1];
4164 int r = rb_enc_precise_mbclen(buf, buf +
len, enc);
4166 rb_enc_mbc_to_codepoint(buf, buf +
len, enc) == (
unsigned int)delim)
4169 return (
unsigned char)buf[
len - 1];
4175 long pending = READ_DATA_PENDING_COUNT(fptr);
4177 const char *p = READ_DATA_PENDING_PTR(fptr);
4181 if (limit > 0 && pending > limit) pending = limit;
4182 e = search_delim(p, pending, delim, enc);
4183 if (e) pending = e - p;
4185 last = RSTRING_LEN(str);
4186 rb_str_resize(str, last + pending);
4193 read_buffered_data(RSTRING_PTR(str) + last, pending, fptr);
4196 if (e)
return delim;
4198 return (
unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
4201 }
while (io_fillbuf(fptr) >= 0);
4207swallow(
rb_io_t *fptr,
int term)
4209 if (NEED_READCONV(fptr)) {
4211 int needconv = rb_enc_mbminlen(enc) != 1;
4212 SET_BINARY_MODE(fptr);
4213 make_readconv(fptr, 0);
4216 while ((cnt = READ_CHAR_PENDING_COUNT(fptr)) > 0) {
4217 const char *p = READ_CHAR_PENDING_PTR(fptr);
4220 if (*p != term)
return TRUE;
4222 while (--i && *++p == term);
4225 const char *e = p + cnt;
4226 if (rb_enc_ascget(p, e, &i, enc) != term)
return TRUE;
4227 while ((p += i) < e && rb_enc_ascget(p, e, &i, enc) == term);
4230 io_shift_cbuf(fptr, (
int)cnt - i, NULL);
4232 }
while (more_char(fptr) != MORE_CHAR_FINISHED);
4236 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4238 int widechar = rb_enc_mbminlen(enc) != 1;
4240 char buf[ONIGENC_CODE_TO_MBC_MAXLEN];
4243 while ((
len = read_raw_character(fptr, enc, buf)) > 0) {
4244 if (rb_enc_ascget(buf, buf +
len, NULL, enc) != term) {
4245 unread_raw_character(fptr, buf,
len);
4253 while ((cnt = READ_DATA_PENDING_COUNT(fptr)) > 0) {
4255 const char *p = READ_DATA_PENDING_PTR(fptr);
4257 if (cnt >
sizeof buf) cnt =
sizeof buf;
4258 if (*p != term)
return TRUE;
4260 while (--i && *++p == term);
4261 if (!read_buffered_data(buf, cnt - i, fptr))
4262 rb_sys_fail_path(fptr->
pathv);
4265 }
while (io_fillbuf(fptr) == 0);
4278 int pending = READ_DATA_PENDING_COUNT(fptr);
4281 const char *p = READ_DATA_PENDING_PTR(fptr);
4285 e = memchr(p,
'\n', pending);
4287 pending = (int)(e - p + 1);
4289 chomplen = (pending > 1 && *(e-1) ==
'\r') + 1;
4298 rb_str_resize(str,
len + pending - chomplen);
4299 read_buffered_data(RSTRING_PTR(str)+
len, pending - chomplen, fptr);
4302 if (pending == 1 && chomplen == 1 &&
len > 0) {
4303 if (RSTRING_PTR(str)[
len-1] ==
'\r') {
4304 rb_str_resize(str, --
len);
4309 len += pending - chomplen;
4315 }
while (io_fillbuf(fptr) >= 0);
4318 str = io_enc_str(str, fptr);
4329 unsigned int chomp: 1;
4343 chomp = (!UNDEF_P(vchomp)) &&
RTEST(vchomp);
4345 args->chomp = chomp;
4363 else if (2 <= argc) {
4364 rs = argv[0], lim = argv[1];
4373check_getline_args(
VALUE *rsp,
long *limit,
VALUE io)
4382 enc_rs = rb_enc_get(rs);
4383 enc_io = io_read_encoding(fptr);
4384 if (enc_io != enc_rs &&
4385 (!is_ascii_string(rs) ||
4386 (RSTRING_LEN(rs) > 0 && !rb_enc_asciicompat(enc_io)))) {
4387 if (rs == rb_default_rs) {
4388 rs = rb_enc_str_new(0, 0, enc_io);
4393 rb_raise(rb_eArgError,
"encoding mismatch: %s IO with %s RS",
4394 rb_enc_name(enc_io),
4395 rb_enc_name(enc_rs));
4405 argc =
rb_scan_args(argc, argv,
"02:", NULL, NULL, &opts);
4406 extract_getline_args(argc, argv, args);
4407 extract_getline_opts(opts, args);
4408 check_getline_args(&args->rs, &args->limit, io);
4412rb_io_getline_0(
VALUE rs,
long limit,
int chomp,
rb_io_t *fptr)
4419 if (
NIL_P(rs) && limit < 0) {
4420 str = read_all(fptr, 0,
Qnil);
4421 if (RSTRING_LEN(str) == 0)
return Qnil;
4423 else if (limit == 0) {
4424 return rb_enc_str_new(0, 0, io_read_encoding(fptr));
4426 else if (rs == rb_default_rs && limit < 0 && !NEED_READCONV(fptr) &&
4427 rb_enc_asciicompat(enc = io_read_encoding(fptr))) {
4428 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4429 return rb_io_getline_fast(fptr, enc, chomp);
4432 int c, newline = -1;
4433 const char *rsptr = 0;
4436 int extra_limit = 16;
4437 int chomp_cr = chomp;
4439 SET_BINARY_MODE(fptr);
4440 enc = io_read_encoding(fptr);
4443 rslen = RSTRING_LEN(rs);
4448 swallow(fptr,
'\n');
4450 if (!rb_enc_asciicompat(enc)) {
4454 rsptr = RSTRING_PTR(rs);
4455 rslen = RSTRING_LEN(rs);
4459 else if (rb_enc_mbminlen(enc) == 1) {
4460 rsptr = RSTRING_PTR(rs);
4461 newline = (
unsigned char)rsptr[rslen - 1];
4465 rsptr = RSTRING_PTR(rs);
4466 const char *e = rsptr + rslen;
4467 const char *last = rb_enc_prev_char(rsptr, e, e, enc);
4469 newline = rb_enc_codepoint_len(last, e, &n, enc);
4470 if (last + n != e) rb_raise(rb_eArgError,
"broken separator");
4472 chomp_cr = chomp && newline ==
'\n' && rslen == rb_enc_mbminlen(enc);
4476 while ((c = appendline(fptr, newline, &str, &limit, enc)) != EOF) {
4477 const char *s, *p, *pp, *e;
4479 if (c == newline && RSTRING_LEN(str) >= rslen) {
4480 s = RSTRING_PTR(str);
4483 if (at_char_boundary(s, p, e, enc)) {
4484 if (!rspara) rscheck(rsptr, rslen, rs);
4485 if (memcmp(p, rsptr, rslen) == 0) {
4487 if (chomp_cr && p > s && *(p-1) ==
'\r') --p;
4495 s = RSTRING_PTR(str);
4497 pp = rb_enc_prev_char(s, p, p, enc);
4498 if (extra_limit && pp &&
4512 if (rspara && c != EOF)
4513 swallow(fptr,
'\n');
4515 str = io_enc_str(str, fptr);
4518 if (!
NIL_P(str) && !nolimit) {
4526rb_io_getline_1(
VALUE rs,
long limit,
int chomp,
VALUE io)
4529 int old_lineno, new_lineno;
4533 old_lineno = fptr->
lineno;
4534 str = rb_io_getline_0(rs, limit, chomp, fptr);
4535 if (!
NIL_P(str) && (new_lineno = fptr->
lineno) != old_lineno) {
4536 if (io == ARGF.current_file) {
4537 ARGF.lineno += new_lineno - old_lineno;
4538 ARGF.last_lineno = ARGF.lineno;
4541 ARGF.last_lineno = new_lineno;
4549rb_io_getline(
int argc,
VALUE *argv,
VALUE io)
4553 prepare_getline_args(argc, argv, &args, io);
4554 return rb_io_getline_1(args.rs, args.limit, args.chomp, io);
4564rb_io_gets_limit_internal(
VALUE io,
long limit)
4568 return rb_io_getline_0(rb_default_rs, limit, FALSE, fptr);
4572rb_io_gets_internal(
VALUE io)
4574 return rb_io_gets_limit_internal(io, -1);
4654 str = rb_io_getline(argc, argv, io);
4670rb_io_lineno(
VALUE io)
4725 check_getline_args(&sep, &limit, io);
4727 VALUE line = rb_io_getline_1(sep, limit,
RTEST(chomp), io);
4728 rb_lastline_set_up(line, 1);
4803rb_io_readlines(
int argc,
VALUE *argv,
VALUE io)
4807 prepare_getline_args(argc, argv, &args, io);
4808 return io_readlines(&args, io);
4816 if (arg->limit == 0)
4817 rb_raise(rb_eArgError,
"invalid limit: 0 for readlines");
4819 while (!
NIL_P(line = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, io))) {
4932rb_io_each_line(
int argc,
VALUE *argv,
VALUE io)
4938 prepare_getline_args(argc, argv, &args, io);
4939 if (args.limit == 0)
4940 rb_raise(rb_eArgError,
"invalid limit: 0 for each_line");
4941 while (!
NIL_P(str = rb_io_getline_1(args.rs, args.limit, args.chomp, io))) {
4969rb_io_each_byte(
VALUE io)
4985 }
while (io_fillbuf(fptr) >= 0);
4995 if (NEED_READCONV(fptr)) {
4999 SET_BINARY_MODE(fptr);
5000 make_readconv(fptr, 0);
5014 if (more_char(fptr) == MORE_CHAR_FINISHED) {
5016 clear_readconv(fptr);
5020 str = rb_enc_str_new(fptr->
cbuf.
ptr+fptr->
cbuf.
off, 1, read_enc);
5023 if (fptr->
cbuf.
len == 0) clear_readconv(fptr);
5032 io_shift_cbuf(fptr, r, &str);
5039 ISASCII(RSTRING_PTR(str)[0])) {
5043 str = io_enc_str(str, fptr);
5048 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
5049 if (io_fillbuf(fptr) < 0) {
5071 if (io_fillbuf(fptr) != -1) {
5075 r = rb_enc_precise_mbclen(RSTRING_PTR(str), RSTRING_PTR(str)+RSTRING_LEN(str), enc);
5091 str = io_enc_str(str, fptr);
5118rb_io_each_char(
VALUE io)
5128 enc = io_input_encoding(fptr);
5130 while (!
NIL_P(c = io_getc(fptr, enc))) {
5157rb_io_each_codepoint(
VALUE io)
5169 enc = io_read_encoding(fptr);
5170 if (NEED_READCONV(fptr)) {
5171 SET_BINARY_MODE(fptr);
5174 make_readconv(fptr, 0);
5186 if (more_char(fptr) == MORE_CHAR_FINISHED) {
5187 clear_readconv(fptr);
5207 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
5208 while (io_fillbuf(fptr) >= 0) {
5223 char cbuf[8], *p = cbuf;
5225 if (more > numberof(cbuf))
goto invalid;
5227 if (more > numberof(cbuf))
goto invalid;
5228 while ((n = (
int)read_buffered_data(p, more, fptr)) > 0 &&
5229 (p += n, (more -= n) > 0)) {
5230 if (io_fillbuf(fptr) < 0)
goto invalid;
5231 if ((n = fptr->
rbuf.
len) > more) n = more;
5233 r = rb_enc_precise_mbclen(cbuf, p, enc);
5246 rb_raise(rb_eArgError,
"invalid byte sequence in %s", rb_enc_name(enc));
5279 enc = io_input_encoding(fptr);
5281 return io_getc(fptr, enc);
5305rb_io_readchar(
VALUE io)
5307 VALUE c = rb_io_getc(io);
5343 VALUE r_stdout = rb_ractor_stdout();
5348 rb_io_flush(r_stdout);
5351 if (io_fillbuf(fptr) < 0) {
5381rb_io_readbyte(
VALUE io)
5442 unsigned char c =
NUM2INT(v) & 0xFF;
5448 io_ungetbyte(b, fptr);
5504 else if (RB_BIGNUM_TYPE_P(c)) {
5510 if (NEED_READCONV(fptr)) {
5511 SET_BINARY_MODE(fptr);
5512 len = RSTRING_LEN(c);
5513#if SIZEOF_LONG > SIZEOF_INT
5517 make_readconv(fptr, (
int)
len);
5531 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
5532 io_ungetbyte(c, fptr);
5552rb_io_isatty(
VALUE io)
5557 return RBOOL(isatty(fptr->
fd) != 0);
5560#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5576rb_io_close_on_exec_p(
VALUE io)
5582 write_io = GetWriteIO(io);
5583 if (io != write_io) {
5585 if (fptr && 0 <= (fd = fptr->
fd)) {
5586 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->
pathv);
5587 if (!(ret & FD_CLOEXEC))
return Qfalse;
5592 if (fptr && 0 <= (fd = fptr->
fd)) {
5593 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->
pathv);
5594 if (!(ret & FD_CLOEXEC))
return Qfalse;
5599#define rb_io_close_on_exec_p rb_f_notimplement
5602#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5626 int flag =
RTEST(arg) ? FD_CLOEXEC : 0;
5631 write_io = GetWriteIO(io);
5632 if (io != write_io) {
5634 if (fptr && 0 <= (fd = fptr->
fd)) {
5635 if ((ret = fcntl(fptr->
fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->
pathv);
5636 if ((ret & FD_CLOEXEC) != flag) {
5637 ret = (ret & ~FD_CLOEXEC) | flag;
5638 ret = fcntl(fd, F_SETFD, ret);
5639 if (ret != 0) rb_sys_fail_path(fptr->
pathv);
5646 if (fptr && 0 <= (fd = fptr->
fd)) {
5647 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->
pathv);
5648 if ((ret & FD_CLOEXEC) != flag) {
5649 ret = (ret & ~FD_CLOEXEC) | flag;
5650 ret = fcntl(fd, F_SETFD, ret);
5651 if (ret != 0) rb_sys_fail_path(fptr->
pathv);
5657#define rb_io_set_close_on_exec rb_f_notimplement
5660#define RUBY_IO_EXTERNAL_P(f) ((f)->mode & FMODE_EXTERNAL)
5661#define PREP_STDIO_NAME(f) (RSTRING_PTR((f)->pathv))
5664finish_writeconv(
rb_io_t *fptr,
int noalloc)
5666 unsigned char *ds, *dp, *de;
5670 unsigned char buf[1024];
5675 de = buf +
sizeof(buf);
5678 size_t remaining = dp-ds;
5679 long result = rb_io_write_memory(fptr, ds, remaining);
5683 if ((
size_t)result == remaining)
break;
5706 if (io_fflush(fptr) < 0) {
5714 fptr->
wbuf.
len += (int)(dp - ds);
5730finish_writeconv_sync(
VALUE arg)
5733 return finish_writeconv(p->fptr, p->noalloc);
5737nogvl_close(
void *ptr)
5741 return (
void*)(intptr_t)close(*fd);
5745maygvl_close(
int fd,
int keepgvl)
5754 return IO_WITHOUT_GVL_INT(nogvl_close, &fd);
5758nogvl_fclose(
void *ptr)
5762 return (
void*)(intptr_t)fclose(file);
5766maygvl_fclose(
FILE *file,
int keepgvl)
5769 return fclose(file);
5771 return IO_WITHOUT_GVL_INT(nogvl_fclose, file);
5777fptr_finalize_flush(
rb_io_t *fptr,
int noraise,
int keepgvl)
5782 int mode = fptr->
mode;
5788 arg.noalloc = noraise;
5792 error = finish_writeconv(fptr, noraise);
5805 io_flush_buffer_sync(fptr);
5808 if (io_fflush(fptr) < 0 &&
NIL_P(error)) {
5816 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2) {
5826 rb_thread_io_close_wait(fptr);
5828 if (!done && stdio_file) {
5830 if ((maygvl_fclose(stdio_file, noraise) < 0) &&
NIL_P(error)) {
5840 if (!done && fd >= 0 && scheduler !=
Qnil) {
5843 if (!UNDEF_P(result)) {
5844 done =
RTEST(result);
5848 if (!done && fd >= 0) {
5854 if ((maygvl_close(fd, keepgvl) < 0) &&
NIL_P(error)) {
5863 if (!
NIL_P(error) && !noraise) {
5872fptr_finalize(
rb_io_t *fptr,
int noraise)
5874 fptr_finalize_flush(fptr, noraise, FALSE);
5875 free_io_buffer(&fptr->
rbuf);
5876 free_io_buffer(&fptr->
wbuf);
5877 clear_codeconv(fptr);
5881rb_io_fptr_cleanup(
rb_io_t *fptr,
int noraise)
5887 fptr_finalize(fptr, noraise);
5895 ruby_xfree_sized(buf->
ptr, (
size_t)buf->
capa);
5908 free_io_buffer(&fptr->
cbuf);
5924 clear_readconv(fptr);
5925 clear_writeconv(fptr);
5929rb_io_fptr_cleanup_all(
rb_io_t *fptr)
5933 rb_io_fptr_cleanup(fptr, TRUE);
5935 free_io_buffer(&fptr->
rbuf);
5936 free_io_buffer(&fptr->
wbuf);
5937 clear_codeconv(fptr);
5944 rb_io_fptr_cleanup_all(io);
5951rb_io_fptr_finalize_closed(
struct rb_io *io)
5953 if (!io)
return true;
5954 if (io->
fd >= 0)
return false;
5960rb_io_memsize(
const rb_io_t *io)
5962 size_t size =
sizeof(
rb_io_t);
5972 rb_serial_t fork_generation = GET_VM()->fork_gen;
5973 if (io->fork_generation == fork_generation) {
5984# define KEEPGVL TRUE
5986# define KEEPGVL FALSE
5990io_close_fptr(
VALUE io)
5996 write_io = GetWriteIO(io);
5997 if (io != write_io) {
5998 write_fptr =
RFILE(write_io)->fptr;
5999 if (write_fptr && 0 <= write_fptr->
fd) {
6000 rb_io_fptr_cleanup(write_fptr, TRUE);
6004 fptr =
RFILE(io)->fptr;
6005 if (!fptr)
return 0;
6006 if (fptr->
fd < 0)
return 0;
6009 if (rb_thread_io_close_interrupt(fptr)) {
6011 fptr_finalize_flush(fptr, FALSE, KEEPGVL);
6014 rb_io_fptr_cleanup(fptr, FALSE);
6019fptr_waitpid(
rb_io_t *fptr,
int nohang)
6023 rb_last_status_clear();
6032 rb_io_t *fptr = io_close_fptr(io);
6033 if (fptr) fptr_waitpid(fptr, 0);
6073rb_io_close_m(
VALUE io)
6075 rb_io_t *fptr = rb_io_get_fptr(io);
6084io_call_close(
VALUE io)
6093 enum {mesg_len =
sizeof(closed_stream)-1};
6094 VALUE mesg = rb_attr_get(exc, idMesg);
6096 RSTRING_LEN(mesg) != mesg_len ||
6097 memcmp(RSTRING_PTR(mesg), closed_stream, mesg_len)) {
6107 if (!UNDEF_P(closed) &&
RTEST(closed))
return io;
6108 rb_rescue2(io_call_close, io, ignore_closed_stream, io,
6144 write_io = GetWriteIO(io);
6145 if (io != write_io) {
6146 write_fptr =
RFILE(write_io)->fptr;
6147 if (write_fptr && 0 <= write_fptr->
fd) {
6152 fptr = rb_io_get_fptr(io);
6153 return RBOOL(0 > fptr->
fd);
6189rb_io_close_read(
VALUE io)
6195 if (fptr->
fd < 0)
return Qnil;
6196 if (is_socket(fptr->
fd, fptr->
pathv)) {
6200 if (shutdown(fptr->
fd, SHUT_RD) < 0)
6201 rb_sys_fail_path(fptr->
pathv);
6202 fptr->
mode &= ~FMODE_READABLE;
6208 write_io = GetWriteIO(io);
6209 if (io != write_io) {
6214 RFILE(io)->fptr = wfptr;
6217 RFILE(write_io)->fptr = fptr;
6218 rb_io_fptr_cleanup(fptr, FALSE);
6224 rb_raise(
rb_eIOError,
"closing non-duplex IO for reading");
6262rb_io_close_write(
VALUE io)
6267 write_io = GetWriteIO(io);
6269 if (fptr->
fd < 0)
return Qnil;
6270 if (is_socket(fptr->
fd, fptr->
pathv)) {
6281 if (io_fflush(fptr) < 0)
6282 rb_sys_fail_on_write(fptr);
6284 if (shutdown(fptr->
fd, SHUT_WR) < 0)
6285 rb_sys_fail_path(fptr->
pathv);
6286 fptr->
mode &= ~FMODE_WRITABLE;
6293 rb_raise(
rb_eIOError,
"closing non-duplex IO for writing");
6296 if (io != write_io) {
6316rb_io_sysseek(
int argc,
VALUE *argv,
VALUE io)
6318 VALUE offset, ptrname;
6319 int whence = SEEK_SET;
6323 if (
rb_scan_args(argc, argv,
"11", &offset, &ptrname) == 2) {
6324 whence = interpret_seek_whence(ptrname);
6329 (READ_DATA_BUFFERED(fptr) || READ_CHAR_PENDING(fptr))) {
6333 rb_warn(
"sysseek for buffered IO");
6336 pos = lseek(fptr->
fd, pos, whence);
6337 if (pos < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
6371 io = GetWriteIO(io);
6376 rb_warn(
"syswrite for buffered IO");
6379 tmp = rb_str_tmp_frozen_acquire(str);
6381 n = rb_io_write_memory(fptr, ptr,
len);
6382 if (n < 0) rb_sys_fail_path(fptr->
pathv);
6383 rb_str_tmp_frozen_release(str, tmp);
6400rb_io_sysread(
int argc,
VALUE *argv,
VALUE io)
6411 shrinkable = io_setstrbuf(&str, ilen);
6412 if (ilen == 0)
return str;
6417 if (READ_DATA_BUFFERED(fptr)) {
6423 io_setstrbuf(&str, ilen);
6428 iis.buf = RSTRING_PTR(str);
6431 n = io_read_memory_locktmp(str, &iis);
6434 rb_sys_fail_path(fptr->
pathv);
6437 io_set_read_length(str, n, shrinkable);
6439 if (n == 0 && ilen > 0) {
6455internal_pread_func(
void *_arg)
6459 return (
VALUE)pread(arg->fd, arg->buf, arg->count, arg->offset);
6463pread_internal_call(
VALUE _arg)
6468 if (scheduler !=
Qnil) {
6471 if (!UNDEF_P(result)) {
6476 return rb_io_blocking_region_wait(arg->io, internal_pread_func, arg,
RUBY_IO_READABLE);
6520 shrinkable = io_setstrbuf(&str, (
long)arg.count);
6521 if (arg.count == 0)
return str;
6522 arg.buf = RSTRING_PTR(str);
6535 rb_sys_fail_path(fptr->
pathv);
6537 io_set_read_length(str, n, shrinkable);
6538 if (n == 0 && arg.count > 0) {
6546internal_pwrite_func(
void *_arg)
6550 return (
VALUE)pwrite(arg->fd, arg->buf, arg->count, arg->offset);
6554pwrite_internal_call(
VALUE _arg)
6559 if (scheduler !=
Qnil) {
6562 if (!UNDEF_P(result)) {
6567 return rb_io_blocking_region_wait(arg->io, internal_pwrite_func, arg,
RUBY_IO_WRITABLE);
6608 io = GetWriteIO(io);
6615 tmp = rb_str_tmp_frozen_acquire(str);
6616 arg.buf = RSTRING_PTR(tmp);
6617 arg.count = (size_t)RSTRING_LEN(tmp);
6619 n = (ssize_t)pwrite_internal_call((
VALUE)&arg);
6620 if (n < 0) rb_sys_fail_path(fptr->
pathv);
6621 rb_str_tmp_frozen_release(str, tmp);
6637 fptr->
mode &= ~FMODE_TEXTMODE;
6641 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6644 setmode(fptr->
fd, O_BINARY);
6651io_ascii8bit_binmode(
rb_io_t *fptr)
6662 fptr->
mode &= ~FMODE_TEXTMODE;
6663 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6665 fptr->
encs.
enc = rb_ascii8bit_encoding();
6669 clear_codeconv(fptr);
6678 io_ascii8bit_binmode(fptr);
6695rb_io_binmode_m(
VALUE io)
6701 write_io = GetWriteIO(io);
6716rb_io_binmode_p(
VALUE io)
6724rb_io_fmode_modestr(
enum rb_io_mode fmode)
6728 return MODE_BTMODE(
"a+",
"ab+",
"at+");
6730 return MODE_BTMODE(
"a",
"ab",
"at");
6734 rb_raise(rb_eArgError,
"invalid access fmode 0x%x", fmode);
6736 return MODE_BTMODE(
"r",
"rb",
"rt");
6738 return MODE_BTXMODE(
"w",
"wb",
"wt",
"wx",
"wbx",
"wtx");
6741 return MODE_BTXMODE(
"w+",
"wb+",
"wt+",
"w+x",
"wb+x",
"wt+x");
6743 return MODE_BTMODE(
"r+",
"rb+",
"rt+");
6747static const char bom_prefix[] =
"bom|";
6748static const char utf_prefix[] =
"utf-";
6749enum {bom_prefix_len = (int)
sizeof(bom_prefix) - 1};
6750enum {utf_prefix_len = (int)
sizeof(utf_prefix) - 1};
6753io_encname_bom_p(
const char *name,
long len)
6755 return len > bom_prefix_len &&
STRNCASECMP(name, bom_prefix, bom_prefix_len) == 0;
6761 enum rb_io_mode fmode = 0;
6762 const char *m = modestr, *p = NULL;
6790 if (modestr[0] !=
'w')
6798 if (io_encname_bom_p(m, p ? (
long)(p - m) : (long)strlen(m)))
6811 rb_raise(rb_eArgError,
"invalid access mode %s", modestr);
6816rb_io_oflags_fmode(
int oflags)
6818 enum rb_io_mode fmode = 0;
6820 switch (oflags & O_ACCMODE) {
6832 if (oflags & O_APPEND) {
6835 if (oflags & O_TRUNC) {
6838 if (oflags & O_CREAT) {
6841 if (oflags & O_EXCL) {
6845 if (oflags & O_BINARY) {
6854rb_io_fmode_oflags(
enum rb_io_mode fmode)
6898rb_io_oflags_modestr(
int oflags)
6901# define MODE_BINARY(a,b) ((oflags & O_BINARY) ? (b) : (a))
6903# define MODE_BINARY(a,b) (a)
6906 if (oflags & O_EXCL) {
6907 rb_raise(rb_eArgError,
"exclusive access mode is not supported");
6909 accmode = oflags & (O_RDONLY|O_WRONLY|O_RDWR);
6910 if (oflags & O_APPEND) {
6911 if (accmode == O_WRONLY) {
6912 return MODE_BINARY(
"a",
"ab");
6914 if (accmode == O_RDWR) {
6915 return MODE_BINARY(
"a+",
"ab+");
6920 rb_raise(rb_eArgError,
"invalid access oflags 0x%x", oflags);
6922 return MODE_BINARY(
"r",
"rb");
6924 return MODE_BINARY(
"w",
"wb");
6926 if (oflags & O_TRUNC) {
6927 return MODE_BINARY(
"w+",
"wb+");
6929 return MODE_BINARY(
"r+",
"rb+");
6941 int default_ext = 0;
6944 ext = rb_default_external_encoding();
6947 if (rb_is_ascii8bit_enc(ext)) {
6951 else if (intern == NULL) {
6952 intern = rb_default_internal_encoding();
6957 *enc = (default_ext && intern != ext) ? NULL : ext;
6967unsupported_encoding(
const char *name,
rb_encoding *enc)
6969 rb_enc_warn(enc,
"Unsupported encoding %s ignored", name);
6973parse_mode_enc(
const char *estr,
rb_encoding *estr_enc,
6979 enum rb_io_mode fmode = fmode_p ? *fmode_p : 0;
6985 p = strrchr(estr,
':');
6986 len = p ? (p++ - estr) : (long)strlen(estr);
6988 estr += bom_prefix_len;
6989 len -= bom_prefix_len;
6990 if (!
STRNCASECMP(estr, utf_prefix, utf_prefix_len)) {
6994 rb_enc_warn(estr_enc,
"BOM with non-UTF encoding %s is nonsense", estr);
6995 fmode &= ~FMODE_SETENC_BY_BOM;
7003 memcpy(encname, estr,
len);
7004 encname[
len] =
'\0';
7007 idx = rb_enc_find_index(estr);
7009 if (fmode_p) *fmode_p = fmode;
7012 ext_enc = rb_enc_from_index(idx);
7015 unsupported_encoding(estr, estr_enc);
7021 if (*p ==
'-' && *(p+1) ==
'\0') {
7026 idx2 = rb_enc_find_index(p);
7028 unsupported_encoding(p, estr_enc);
7033 int_enc = rb_enc_from_index(idx2);
7037 rb_io_ext_int_to_encs(ext_enc, int_enc, enc_p, enc2_p, fmode);
7050 v = rb_hash_lookup2(opt, sym_encoding,
Qnil);
7051 if (v !=
Qnil) encoding = v;
7052 v = rb_hash_lookup2(opt, sym_extenc,
Qundef);
7053 if (v !=
Qnil) extenc = v;
7054 v = rb_hash_lookup2(opt, sym_intenc,
Qundef);
7055 if (!UNDEF_P(v)) intenc = v;
7057 if ((!UNDEF_P(extenc) || !UNDEF_P(intenc)) && !
NIL_P(encoding)) {
7059 int idx = rb_to_encoding_index(encoding);
7060 if (idx >= 0) encoding = rb_enc_from_encoding(rb_enc_from_index(idx));
7061 rb_warn(
"Ignoring encoding parameter '%"PRIsVALUE
"': %s_encoding is used",
7062 encoding, UNDEF_P(extenc) ?
"internal" :
"external");
7066 if (!UNDEF_P(extenc) && !
NIL_P(extenc)) {
7067 extencoding = rb_to_encoding(extenc);
7069 if (!UNDEF_P(intenc)) {
7070 if (
NIL_P(intenc)) {
7077 if (*p ==
'-' && *(p+1) ==
'\0') {
7082 intencoding = rb_to_encoding(intenc);
7086 intencoding = rb_to_encoding(intenc);
7088 if (extencoding == intencoding) {
7092 if (!
NIL_P(encoding)) {
7096 enc_p, enc2_p, fmode_p);
7099 rb_io_ext_int_to_encs(rb_to_encoding(encoding), NULL, enc_p, enc2_p, 0);
7102 else if (!UNDEF_P(extenc) || !UNDEF_P(intenc)) {
7104 rb_io_ext_int_to_encs(extencoding, intencoding, enc_p, enc2_p, 0);
7112 enum rb_io_mode fmode = *fmode_p;
7117 !rb_enc_asciicompat(enc ? enc : rb_default_external_encoding()))
7118 rb_raise(rb_eArgError,
"ASCII incompatible encoding needs binmode");
7121 rb_raise(rb_eArgError,
"newline decorator with binary mode");
7128#if !DEFAULT_TEXTMODE
7130 fmode &= ~FMODE_TEXTMODE;
7137extract_binmode(
VALUE opthash,
enum rb_io_mode *fmode)
7139 if (!
NIL_P(opthash)) {
7141 v = rb_hash_aref(opthash, sym_textmode);
7144 rb_raise(rb_eArgError,
"textmode specified twice");
7146 rb_raise(rb_eArgError,
"both textmode and binmode specified");
7150 v = rb_hash_aref(opthash, sym_binmode);
7153 rb_raise(rb_eArgError,
"binmode specified twice");
7155 rb_raise(rb_eArgError,
"both textmode and binmode specified");
7161 rb_raise(rb_eArgError,
"both textmode and binmode specified");
7167 int *oflags_p,
enum rb_io_mode *fmode_p,
struct rb_io_encoding *convconfig_p)
7171 enum rb_io_mode fmode;
7175 int has_enc = 0, has_vmode = 0;
7181 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
7191 fmode = rb_io_oflags_fmode(oflags);
7199 oflags = rb_io_fmode_oflags(fmode);
7203 parse_mode_enc(p+1, rb_enc_get(vmode), &enc, &enc2, &fmode);
7208 e = (fmode &
FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
7209 rb_io_ext_int_to_encs(e, NULL, &enc, &enc2, fmode);
7213 if (
NIL_P(opthash)) {
7217#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7219 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7220 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7222 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
7229 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
7232 else if (
NIL_P(vmode)) {
7233 fmode |= DEFAULT_TEXTMODE;
7240 v = rb_hash_aref(opthash, sym_mode);
7242 if (!
NIL_P(vmode)) {
7243 rb_raise(rb_eArgError,
"mode specified twice");
7250 v = rb_hash_aref(opthash, sym_flags);
7255 fmode = rb_io_oflags_fmode(oflags);
7257 extract_binmode(opthash, &fmode);
7263 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
7266 else if (
NIL_P(vmode)) {
7267 fmode |= DEFAULT_TEXTMODE;
7270 v = rb_hash_aref(opthash, sym_perm);
7273 if (!
NIL_P(*vperm_p)) {
7274 rb_raise(rb_eArgError,
"perm specified twice");
7285#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7287 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7288 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7293 rb_raise(rb_eArgError,
"encoding specified twice");
7296 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
7300 validate_enc_binmode(&fmode, ecflags, enc, enc2);
7306 convconfig_p->
enc = enc;
7307 convconfig_p->
enc2 = enc2;
7308 convconfig_p->
ecflags = ecflags;
7309 convconfig_p->
ecopts = ecopts;
7319sysopen_func(
void *ptr)
7322 const char *fname = RSTRING_PTR(data->fname);
7331 fd = IO_WITHOUT_GVL_INT(sysopen_func, data);
7332 }
while (fd < 0 &&
errno == EINTR);
7339rb_sysopen(
VALUE fname,
int oflags, mode_t perm)
7344 data.fname = rb_str_encode_ospath(fname);
7346 data.oflags = oflags;
7349 TRY_WITH_GC((fd = rb_sysopen_internal(&data)) >= 0) {
7350 rb_syserr_fail_path(first_errno, fname);
7356fdopen_internal(
int fd,
const char *modestr)
7363 file = fdopen(fd, modestr);
7379 TRY_WITH_GC((file = fdopen_internal(fd, modestr)) != 0) {
7385 if (setvbuf(file, NULL, _IOFBF, 0) != 0)
7386 rb_warn(
"setvbuf() can't be honoured (fd=%d)", fd);
7394 int t = isatty(fptr->
fd);
7404io_strip_bom(
VALUE io)
7406 VALUE b1, b2, b3, b4;
7417 return rb_utf8_encindex();
7427 return ENCINDEX_UTF_16BE;
7438 return ENCINDEX_UTF_32LE;
7443 return ENCINDEX_UTF_16LE;
7453 return ENCINDEX_UTF_32BE;
7467io_set_encoding_by_bom(
VALUE io)
7469 int idx = io_strip_bom(io);
7475 extenc = rb_enc_from_index(idx);
7476 io_encoding_set(fptr, rb_enc_from_encoding(extenc),
7477 rb_io_internal_encoding(io),
Qnil);
7486rb_file_open_generic(
VALUE io,
VALUE filename,
int oflags,
enum rb_io_mode fmode,
7494 rb_io_ext_int_to_encs(NULL, NULL, &cc.enc, &cc.enc2, fmode);
7499 validate_enc_binmode(&fmode, convconfig->
ecflags,
7500 convconfig->
enc, convconfig->
enc2);
7504 fptr->
encs = *convconfig;
7507 if (!(oflags & O_TMPFILE)) {
7508 fptr->
pathv = pathv;
7511 fptr->
pathv = pathv;
7513 fptr->
fd = rb_sysopen(pathv, oflags, perm);
7521rb_file_open_internal(
VALUE io,
VALUE filename,
const char *modestr)
7524 const char *p = strchr(modestr,
':');
7528 parse_mode_enc(p+1, rb_usascii_encoding(),
7529 &convconfig.
enc, &convconfig.
enc2, &fmode);
7535 e = (fmode &
FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
7536 rb_io_ext_int_to_encs(e, NULL, &convconfig.
enc, &convconfig.
enc2, fmode);
7542#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7544 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7545 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7547 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.
enc2, convconfig.
ecflags);
7550 return rb_file_open_generic(io, filename,
7551 rb_io_fmode_oflags(fmode),
7561 return rb_file_open_internal(io_alloc(
rb_cFile), fname, modestr);
7570#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7593 while ((tmp = *prev) != 0) {
7594 if (tmp->fptr == fptr) {
7603#if defined (_WIN32) || defined(__CYGWIN__)
7612 if (!rb_current_execution_context(
false))
return;
7623pipe_finalize(
rb_io_t *fptr,
int noraise)
7625#if !defined(HAVE_WORKING_FORK) && !defined(_WIN32)
7634 fptr_finalize(fptr, noraise);
7636 pipe_del_fptr(fptr);
7643#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7644 void (*
const old_finalize)(
struct rb_io*,int) = fptr->
finalize;
7646 if (old_finalize == orig->finalize)
return;
7651#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7652 if (old_finalize != pipe_finalize) {
7654 for (list =
pipe_list; list; list = list->next) {
7655 if (list->fptr == fptr)
break;
7657 if (!list) pipe_add_fptr(fptr);
7660 pipe_del_fptr(fptr);
7686#define spawnv(mode, cmd, args) rb_w32_uaspawn((mode), (cmd), (args))
7687#define spawn(mode, cmd) rb_w32_uspawn((mode), (cmd), 0)
7690#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7700#ifdef HAVE_WORKING_FORK
7701# ifndef __EMSCRIPTEN__
7703popen_redirect(
struct popen_arg *p)
7706 close(p->write_pair[1]);
7707 if (p->write_pair[0] != 0) {
7708 dup2(p->write_pair[0], 0);
7709 close(p->write_pair[0]);
7712 if (p->pair[1] != 1) {
7713 dup2(p->pair[1], 1);
7719 if (p->pair[1] != 1) {
7720 dup2(p->pair[1], 1);
7726 if (p->pair[0] != 0) {
7727 dup2(p->pair[0], 0);
7734#if defined(__linux__)
7745linux_get_maxfd(
void)
7748 char buf[4096], *p, *np, *e;
7751 if (fd < 0)
return fd;
7752 ss = read(fd, buf,
sizeof(buf));
7753 if (ss < 0)
goto err;
7756 while ((
int)
sizeof(
"FDSize:\t0\n")-1 <= e-p &&
7757 (np = memchr(p,
'\n', e-p)) != NULL) {
7758 if (memcmp(p,
"FDSize:",
sizeof(
"FDSize:")-1) == 0) {
7760 p +=
sizeof(
"FDSize:")-1;
7780#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
7782 int max = (int)max_file_descriptor;
7785 ret = fcntl(0, F_MAXFD);
7787 maxhint = max = ret;
7788# elif defined(__linux__)
7789 ret = linux_get_maxfd();
7796 for (fd = lowfd; fd <= max; fd++) {
7797 if (!
NIL_P(noclose_fds) &&
7800 ret = fcntl(fd, F_GETFD);
7801 if (ret != -1 && !(ret & FD_CLOEXEC)) {
7802 fcntl(fd, F_SETFD, ret|FD_CLOEXEC);
7804# define CONTIGUOUS_CLOSED_FDS 20
7806 if (max < fd + CONTIGUOUS_CLOSED_FDS)
7807 max = fd + CONTIGUOUS_CLOSED_FDS;
7813# ifndef __EMSCRIPTEN__
7815popen_exec(
void *pp,
char *errmsg,
size_t errmsg_len)
7817 struct popen_arg *p = (
struct popen_arg*)pp;
7819 return rb_exec_async_signal_safe(p->eargp, errmsg, errmsg_len);
7824#if (defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)) && !defined __EMSCRIPTEN__
7826rb_execarg_fixup_v(
VALUE execarg_obj)
7828 rb_execarg_parent_start(execarg_obj);
7832char *rb_execarg_commandline(
const struct rb_execarg *eargp,
VALUE *prog);
7835#ifndef __EMSCRIPTEN__
7837pipe_open(
VALUE execarg_obj,
const char *modestr,
enum rb_io_mode fmode,
7840 struct rb_execarg *eargp =
NIL_P(execarg_obj) ? NULL : rb_execarg_get(execarg_obj);
7841 VALUE prog = eargp ? (eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name) :
Qfalse ;
7847#if defined(HAVE_WORKING_FORK)
7849 char errmsg[80] = {
'\0' };
7851#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7853 struct popen_arg arg;
7856#if defined(HAVE_SPAWNV)
7857# define DO_SPAWN(cmd, args) ((args) ? \
7858 spawnv(P_NOWAIT, (cmd), (args)) : \
7859 spawn(P_NOWAIT, (cmd)))
7860# if !defined(HAVE_WORKING_FORK)
7864#if !defined(HAVE_WORKING_FORK)
7870#if !defined(HAVE_WORKING_FORK)
7871 const char *cmd = 0;
7877#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7878 arg.execarg_obj = execarg_obj;
7881 arg.pair[0] = arg.pair[1] = -1;
7882 arg.write_pair[0] = arg.write_pair[1] = -1;
7883# if !defined(HAVE_WORKING_FORK)
7884 if (eargp && !eargp->use_shell) {
7885 args = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
7890 if (
rb_pipe(arg.write_pair) < 0)
7891 rb_sys_fail_str(prog);
7894 close(arg.write_pair[0]);
7895 close(arg.write_pair[1]);
7899 rb_execarg_addopt(execarg_obj,
INT2FIX(0),
INT2FIX(arg.write_pair[0]));
7900 rb_execarg_addopt(execarg_obj,
INT2FIX(1),
INT2FIX(arg.pair[1]));
7905 rb_sys_fail_str(prog);
7907 rb_execarg_addopt(execarg_obj,
INT2FIX(1),
INT2FIX(arg.pair[1]));
7911 rb_sys_fail_str(prog);
7913 rb_execarg_addopt(execarg_obj,
INT2FIX(0),
INT2FIX(arg.pair[0]));
7916 rb_sys_fail_str(prog);
7918 if (!
NIL_P(execarg_obj)) {
7919 rb_protect(rb_execarg_fixup_v, execarg_obj, &state);
7921 if (0 <= arg.write_pair[0]) close(arg.write_pair[0]);
7922 if (0 <= arg.write_pair[1]) close(arg.write_pair[1]);
7923 if (0 <= arg.pair[0]) close(arg.pair[0]);
7924 if (0 <= arg.pair[1]) close(arg.pair[1]);
7925 rb_execarg_parent_end(execarg_obj);
7929# if defined(HAVE_WORKING_FORK)
7930 pid = rb_fork_async_signal_safe(&status, popen_exec, &arg, arg.eargp->redirect_fds, errmsg,
sizeof(errmsg));
7932 rb_execarg_run_options(eargp, sargp, NULL, 0);
7933 while ((pid = DO_SPAWN(cmd, args)) < 0) {
7935 switch (e =
errno) {
7937# if EWOULDBLOCK != EAGAIN
7946 rb_execarg_run_options(sargp, NULL, NULL, 0);
7948 rb_execarg_parent_end(execarg_obj);
7951# if defined(HAVE_WORKING_FORK)
7952 pid = rb_call_proc__fork();
7954 popen_redirect(&arg);
7966# if defined(HAVE_WORKING_FORK)
7972 close(arg.write_pair[0]);
7973 close(arg.write_pair[1]);
7975# if defined(HAVE_WORKING_FORK)
7984 close(arg.write_pair[0]);
7985 write_fd = arg.write_pair[1];
7996 cmd = rb_execarg_commandline(eargp, &prog);
7997 if (!
NIL_P(execarg_obj)) {
7998 rb_execarg_parent_start(execarg_obj);
7999 rb_execarg_run_options(eargp, sargp, NULL, 0);
8001 fp = popen(cmd, modestr);
8004 rb_execarg_parent_end(execarg_obj);
8005 rb_execarg_run_options(sargp, NULL, NULL, 0);
8007 if (!fp) rb_syserr_fail_path(e, prog);
8017 fptr->
encs = *convconfig;
8018#if RUBY_CRLF_ENVIRONMENT
8025 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
8028#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
8029 if (NEED_NEWLINE_DECORATOR_ON_WRITE(fptr)) {
8030 fptr->
encs.
ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
8036 if (0 <= write_fd) {
8037 write_port = io_alloc(
rb_cIO);
8039 write_fptr->
fd = write_fd;
8041 fptr->
mode &= ~FMODE_WRITABLE;
8043 rb_ivar_set(port, rb_intern(
"@tied_io_for_writing"), write_port);
8046#if defined (__CYGWIN__) || !defined(HAVE_WORKING_FORK)
8048 pipe_add_fptr(fptr);
8054pipe_open(
VALUE execarg_obj,
const char *modestr,
enum rb_io_mode fmode,
8062is_popen_fork(
VALUE prog)
8064 if (RSTRING_LEN(prog) == 1 && RSTRING_PTR(prog)[0] ==
'-') {
8065#if !defined(HAVE_WORKING_FORK)
8067 "fork() function is unimplemented on this machine");
8076pipe_open_s(
VALUE prog,
const char *modestr,
enum rb_io_mode fmode,
8080 VALUE *argv = &prog;
8083 if (!is_popen_fork(prog))
8084 execarg_obj = rb_execarg_new(argc, argv, TRUE, FALSE);
8085 return pipe_open(execarg_obj, modestr, fmode, convconfig);
8091 rb_io_t *fptr = io_close_fptr(io);
8260rb_io_s_popen(
int argc,
VALUE *argv,
VALUE klass)
8264 if (argc > 1 && !
NIL_P(opt = rb_check_hash_type(argv[argc-1]))) --argc;
8265 if (argc > 1 && !
NIL_P(env = rb_check_hash_type(argv[0]))) --argc, ++argv;
8274 int ex = !
NIL_P(opt);
8275 rb_error_arity(argc + ex, 1 + ex, 2 + ex);
8278 return popen_finish(rb_io_popen(pname, pmode, env, opt), klass);
8284 const char *modestr;
8287 enum rb_io_mode fmode;
8293#if SIZEOF_LONG > SIZEOF_INT
8294 if (
len > INT_MAX) {
8295 rb_raise(rb_eArgError,
"too many arguments");
8304 if (!is_popen_fork(pname))
8305 execarg_obj = rb_execarg_new(1, &pname, TRUE, FALSE);
8307 if (!
NIL_P(execarg_obj)) {
8309 opt = rb_execarg_extract_options(execarg_obj, opt);
8311 rb_execarg_setenv(execarg_obj, env);
8314 modestr = rb_io_oflags_modestr(oflags);
8316 return pipe_open(execarg_obj, modestr, fmode, &convconfig);
8326 rb_io_flush(rb_ractor_stdout());
8327 rb_io_flush(rb_ractor_stderr());
8328 _exit(EXIT_SUCCESS);
8332 RBASIC_SET_CLASS(port, klass);
8339#if defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)
8340struct popen_writer_arg {
8342 struct popen_arg popen;
8346exec_popen_writer(
void *arg,
char *errmsg,
size_t buflen)
8348 struct popen_writer_arg *pw = arg;
8350 popen_redirect(&pw->popen);
8351 execv(pw->argv[0], pw->argv);
8352 strlcpy(errmsg, strerror(
errno), buflen);
8358ruby_popen_writer(
char *
const *argv, rb_pid_t *pid)
8360#if (defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)) || defined(_WIN32)
8361# ifdef HAVE_WORKING_FORK
8362 struct popen_writer_arg pw;
8363 int *
const write_pair = pw.popen.pair;
8369 if (cloexec_pipe(write_pair, 0,
false) == 0) {
8370# ifdef HAVE_WORKING_FORK
8373 char errmsg[80] = {
'\0'};
8374 *pid = rb_fork_async_signal_safe(&status, exec_popen_writer, &pw,
Qnil, errmsg,
sizeof(errmsg));
8376 *pid = rb_w32_uspawn_process(P_NOWAIT, argv[0], argv, write_pair[0], -1, -1, 0);
8377 const char *errmsg = (*pid < 0) ? strerror(
errno) : NULL;
8379 close(write_pair[0]);
8381 close(write_pair[1]);
8382 fprintf(stderr,
"ruby_popen_writer(%s): %s\n", argv[0], errmsg);
8385 return fdopen(write_pair[1],
"w");
8396 enum rb_io_mode fmode;
8405 rb_file_open_generic(io, fname, oflags, fmode, &convconfig, perm);
8457rb_io_s_open(
int argc,
VALUE *argv,
VALUE klass)
8489 VALUE fname, vmode, vperm;
8494 rb_scan_args(argc, argv,
"12", &fname, &vmode, &vperm);
8505 if (
NIL_P(vperm)) perm = 0666;
8509 fd = rb_sysopen(fname, oflags, perm);
8541 int redirect = FALSE;
8549 VALUE tmp = argv[0];
8567 return rb_io_s_open(argc, argv,
rb_cFile);
8571rb_io_open_generic(
VALUE klass,
VALUE filename,
int oflags,
enum rb_io_mode fmode,
8574 return rb_file_open_generic(io_alloc(klass), filename,
8575 oflags, fmode, convconfig, perm);
8582 enum rb_io_mode fmode;
8588 return rb_io_open_generic(io, filename, oflags, fmode, &convconfig, perm);
8602 if (fptr == orig)
return io;
8603 if (RUBY_IO_EXTERNAL_P(fptr)) {
8607 rb_raise(rb_eArgError,
8608 "%s can't change access mode from \"%s\" to \"%s\"",
8609 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->
mode),
8610 rb_io_fmode_modestr(orig->
mode));
8613 flush_before_seek(fptr,
true);
8615 clear_codeconv(fptr);
8617 pos = io_tell(orig);
8620 if (io_fflush(orig) < 0)
8621 rb_sys_fail_on_write(fptr);
8630 else if (!RUBY_IO_EXTERNAL_P(fptr)) fptr->
pathv =
Qnil;
8631 fptr_copy_finalizer(fptr, orig);
8637 rb_thread_io_close_interrupt(fptr);
8638 rb_thread_io_close_wait(fptr);
8640 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2 || !fptr->stdio_file) {
8643 rb_sys_fail_path(orig->
pathv);
8651 rb_sys_fail_path(orig->
pathv);
8657 if (io_seek(fptr, pos, SEEK_SET) < 0 &&
errno) {
8658 rb_sys_fail_path(fptr->
pathv);
8660 if (io_seek(orig, pos, SEEK_SET) < 0 &&
errno) {
8661 rb_sys_fail_path(orig->
pathv);
8675int rb_freopen(
VALUE fname,
const char *mode,
FILE *fp);
8678rb_freopen(
VALUE fname,
const char *mode,
FILE *fp)
8680 if (!freopen(RSTRING_PTR(fname), mode, fp)) {
8723rb_io_reopen(
int argc,
VALUE *argv,
VALUE file)
8725 VALUE fname, nmode, opt;
8729 if (
rb_scan_args(argc, argv,
"11:", &fname, &nmode, &opt) == 1) {
8732 return io_reopen(file, tmp);
8738 fptr =
RFILE(file)->fptr;
8744 enum rb_io_mode fmode;
8748 if (RUBY_IO_EXTERNAL_P(fptr) &&
8751 rb_raise(rb_eArgError,
8752 "%s can't change access mode from \"%s\" to \"%s\"",
8753 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->
mode),
8754 rb_io_fmode_modestr(fmode));
8757 fptr->
encs = convconfig;
8760 oflags = rb_io_fmode_oflags(fptr->
mode);
8763 fptr->
pathv = fname;
8765 fptr->
fd = rb_sysopen(fptr->
pathv, oflags, 0666);
8771 if (io_fflush(fptr) < 0)
8772 rb_sys_fail_on_write(fptr);
8775 clear_codeconv(fptr);
8778 int e = rb_freopen(rb_str_encode_ospath(fptr->
pathv),
8779 rb_io_oflags_modestr(oflags),
8781 if (e) rb_syserr_fail_path(e, fptr->
pathv);
8785 if (setvbuf(fptr->
stdio_file, NULL, _IOFBF, 0) != 0)
8786 rb_warn(
"setvbuf() can't be honoured for %"PRIsVALUE, fptr->
pathv);
8789 if (setvbuf(fptr->
stdio_file, NULL, _IONBF, BUFSIZ) != 0)
8790 rb_warn(
"setvbuf() can't be honoured for %"PRIsVALUE, fptr->
pathv);
8792 else if (fptr->
stdio_file == stdout && isatty(fptr->
fd)) {
8793 if (setvbuf(fptr->
stdio_file, NULL, _IOLBF, BUFSIZ) != 0)
8794 rb_warn(
"setvbuf() can't be honoured for %"PRIsVALUE, fptr->
pathv);
8798 int tmpfd = rb_sysopen(fptr->
pathv, oflags, 0666);
8804 rb_syserr_fail_path(err, fptr->
pathv);
8828 fptr->
mode = orig->
mode & ~FMODE_EXTERNAL;
8835 fptr->closing_ec = NULL;
8836 fptr->wakeup_mutex =
Qnil;
8837 fptr->fork_generation = GET_VM()->fork_gen;
8840 fptr_copy_finalizer(fptr, orig);
8842 fd = ruby_dup(orig->
fd);
8844 pos = io_tell(orig);
8846 io_seek(fptr, pos, SEEK_SET);
8851 write_io = GetWriteIO(io);
8852 if (io != write_io) {
8855 rb_ivar_set(dest, rb_intern(
"@tied_io_for_writing"), write_io);
8918 if (argc == 0)
return Qnil;
8920 out = rb_ractor_stdout();
8932extern void rb_deprecated_str_setter(
VALUE val,
ID id,
VALUE *var);
8937 rb_deprecated_str_setter(val,
id, &val);
8943 val = rb_str_frozen_bare_string(val);
9020 for (i=0; i<argc; i++) {
9024 rb_io_write(out, argv[i]);
9121 rb_io_write(io, str);
9125#define forward(obj, id, argc, argv) \
9126 rb_funcallv_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
9127#define forward_public(obj, id, argc, argv) \
9128 rb_funcallv_public_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
9129#define forward_current(id, argc, argv) \
9130 forward_public(ARGF.current_file, id, argc, argv)
9147 VALUE r_stdout = rb_ractor_stdout();
9148 if (recv == r_stdout) {
9149 return rb_io_putc(recv, ch);
9151 return forward(r_stdout, rb_intern(
"putc"), 1, &ch);
9156rb_str_end_with_asciichar(
VALUE str,
int c)
9158 long len = RSTRING_LEN(str);
9159 const char *
ptr = RSTRING_PTR(str);
9163 if (
len == 0)
return 0;
9164 if ((n = rb_enc_mbminlen(
enc)) == 1) {
9165 return ptr[
len - 1] == c;
9167 return rb_enc_ascget(
ptr + ((
len - 1) / n) * n,
ptr +
len, &n,
enc) == c;
9178 rb_io_puts(1, &tmp, out);
9185 rb_io_puts(1, &tmp, out);
9240 VALUE line, args[2];
9247 for (
int i = 0; i < argc; i++) {
9261 if (RSTRING_LEN(line) == 0) {
9266 if (!rb_str_end_with_asciichar(line,
'\n')) {
9271 rb_io_writev(out, n, args);
9289 VALUE r_stdout = rb_ractor_stdout();
9290 if (recv == r_stdout) {
9291 return rb_io_puts(argc, argv, recv);
9293 return forward(r_stdout, rb_intern(
"puts"), argc, argv);
9297rb_p_write(
VALUE str)
9302 VALUE r_stdout = rb_ractor_stdout();
9305 io_writev(2, args, r_stdout);
9308 rb_io_writev(r_stdout, 2, args);
9320rb_p_result(
int argc,
const VALUE *argv)
9327 else if (argc > 1) {
9330 VALUE r_stdout = rb_ractor_stdout();
9332 rb_uninterruptible(rb_io_flush, r_stdout);
9373 for (i=0; i<argc; i++) {
9375 rb_uninterruptible(rb_p_write, inspected);
9377 return rb_p_result(argc, argv);
9398rb_obj_display(
int argc,
VALUE *argv,
VALUE self)
9402 out = (!
rb_check_arity(argc, 0, 1) ? rb_ractor_stdout() : argv[0]);
9403 rb_io_write(out, self);
9409rb_stderr_to_original_p(
VALUE err)
9411 return (err == orig_stderr ||
RFILE(orig_stderr)->fptr->
fd < 0);
9417 VALUE out = rb_ractor_stderr();
9418 if (rb_stderr_to_original_p(out)) {
9420 if (isatty(fileno(stderr))) {
9421 if (rb_w32_write_console(
rb_str_new(mesg,
len), fileno(stderr)) > 0)
return;
9424 if (fwrite(mesg,
sizeof(
char), (
size_t)
len, stderr) < (
size_t)
len) {
9441rb_write_error_str(
VALUE mesg)
9443 VALUE out = rb_ractor_stderr();
9445 if (rb_stderr_to_original_p(out)) {
9446 size_t len = (size_t)RSTRING_LEN(mesg);
9448 if (isatty(fileno(stderr))) {
9449 if (rb_w32_write_console(mesg, fileno(stderr)) > 0)
return;
9452 if (fwrite(RSTRING_PTR(mesg),
sizeof(
char),
len, stderr) <
len) {
9459 rb_io_write(out, mesg);
9464rb_stderr_tty_p(
void)
9466 if (rb_stderr_to_original_p(rb_ractor_stderr()))
9467 return isatty(fileno(stderr));
9472must_respond_to(
ID mid,
VALUE val,
ID id)
9475 rb_raise(
rb_eTypeError,
"%"PRIsVALUE
" must have %"PRIsVALUE
" method, %"PRIsVALUE
" given",
9476 rb_id2str(
id), rb_id2str(mid),
9496 must_respond_to(id_write, val,
id);
9503 return rb_ractor_stdout();
9509 must_respond_to(id_write, val,
id);
9516 return rb_ractor_stderr();
9520allocate_and_open_new_file(
VALUE klass)
9522 VALUE self = io_alloc(klass);
9523 rb_io_make_open_file(self);
9531 VALUE self = rb_protect(allocate_and_open_new_file, klass, &state);
9539 maygvl_close(descriptor, 0);
9547 io->
fd = descriptor;
9565 io->closing_ec = NULL;
9566 io->wakeup_mutex =
Qnil;
9567 io->fork_generation = GET_VM()->fork_gen;
9570 io->
encs = *encoding;
9579prep_io(
int fd,
enum rb_io_mode fmode,
VALUE klass,
const char *path)
9589 e = (fmode &
FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
9590 rb_io_ext_int_to_encs(e, NULL, &convconfig.
enc, &convconfig.
enc2, fmode);
9594#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9596 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
9597 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
9599 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.
enc2, convconfig.
ecflags);
9605 if (!io_check_tty(io)) {
9608 setmode(fd, O_BINARY);
9620 if (path && strcmp(path,
"-")) klass =
rb_cFile;
9621 return prep_io(fd, rb_io_oflags_fmode(oflags), klass, path);
9625prep_stdio(
FILE *f,
enum rb_io_mode fmode,
VALUE klass,
const char *path)
9632#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9633 fptr->
encs.
ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
9644rb_io_prep_stdin(
void)
9650rb_io_prep_stdout(
void)
9656rb_io_prep_stderr(
void)
9665 int oflags = rb_io_fmode_oflags(fptr->
mode) & ~O_EXCL;
9692 rb_io_buffer_init(&fp->
wbuf);
9693 rb_io_buffer_init(&fp->
rbuf);
9694 rb_io_buffer_init(&fp->
cbuf);
9709 fp->closing_ec = NULL;
9710 fp->wakeup_mutex =
Qnil;
9711 fp->fork_generation = GET_VM()->fork_gen;
9716rb_io_make_open_file(
VALUE obj)
9721 if (
RFILE(obj)->fptr) {
9724 RFILE(obj)->fptr = 0;
9726 fp = rb_io_fptr_new();
9728 RFILE(obj)->fptr = fp;
9777rb_io_initialize(
int argc,
VALUE *argv,
VALUE io)
9783 return io_initialize(io, fnum, vmode, opt);
9790 int fd, oflags = O_RDONLY;
9791 enum rb_io_mode fmode;
9793#if defined(HAVE_FCNTL) && defined(F_GETFL)
9803 rb_raise(rb_eArgError,
"The given fd is not accessible because RubyVM reserves it");
9805#if defined(HAVE_FCNTL) && defined(F_GETFL)
9806 oflags = fcntl(fd, F_GETFL);
9807 if (oflags == -1) rb_sys_fail(0);
9809 if (fstat(fd, &st) < 0) rb_sys_fail(0);
9812#if defined(HAVE_FCNTL) && defined(F_GETFL)
9813 ofmode = rb_io_oflags_fmode(oflags);
9825 if (rb_hash_aref(opt, sym_autoclose) ==
Qfalse) {
9829 path = rb_hash_aref(opt,
RB_ID2SYM(idPath));
9840 fp->
encs = convconfig;
9844 fp->closing_ec = NULL;
9845 fp->wakeup_mutex =
Qnil;
9846 fp->fork_generation = GET_VM()->fork_gen;
9849 if (fileno(stdin) == fd)
9851 else if (fileno(stdout) == fd)
9853 else if (fileno(stderr) == fd)
9885rb_io_set_encoding_by_bom(
VALUE io)
9891 rb_raise(rb_eArgError,
"ASCII incompatible encoding needs binmode");
9894 rb_raise(rb_eArgError,
"encoding conversion is set");
9896 else if (fptr->
encs.
enc && fptr->
encs.
enc != rb_ascii8bit_encoding()) {
9897 rb_raise(rb_eArgError,
"encoding is set to %s already",
9900 if (!io_set_encoding_by_bom(io))
return Qnil;
9901 return rb_enc_from_encoding(fptr->
encs.
enc);
9954rb_file_initialize(
int argc,
VALUE *argv,
VALUE io)
9956 if (
RFILE(io)->fptr) {
9959 VALUE fname, vmode, vperm, opt;
9960 int posargc =
rb_scan_args(argc, argv,
"12:", &fname, &vmode, &vperm, &opt);
9965 return io_initialize(io, fd, vmode, opt);
9968 return rb_open_file(io, fname, vmode, vperm, opt);
9973rb_io_s_new(
int argc,
VALUE *argv,
VALUE klass)
9978 rb_warn(
"%"PRIsVALUE
"::new() does not take block; use %"PRIsVALUE
"::open() instead",
9994rb_io_s_for_fd(
int argc,
VALUE *argv,
VALUE klass)
9997 rb_io_initialize(argc, argv, io);
10010rb_io_autoclose_p(
VALUE io)
10035rb_io_set_autoclose(
VALUE io,
VALUE autoclose)
10039 if (!
RTEST(autoclose))
10042 fptr->
mode &= ~FMODE_EXTERNAL;
10047io_wait_event(
VALUE io,
int event,
VALUE timeout,
int return_io)
10057 if (mask & event) {
10079io_wait_readable(
int argc,
VALUE *argv,
VALUE io)
10086 if (rb_io_read_pending(fptr))
return Qtrue;
10089 VALUE timeout = (argc == 1 ? argv[0] :
Qnil);
10103io_wait_writable(
int argc,
VALUE *argv,
VALUE io)
10111 VALUE timeout = (argc == 1 ? argv[0] :
Qnil);
10126io_wait_priority(
int argc,
VALUE *argv,
VALUE io)
10133 if (rb_io_read_pending(fptr))
return Qtrue;
10136 VALUE timeout = argc == 1 ? argv[0] :
Qnil;
10142wait_mode_sym(
VALUE mode)
10144 if (mode ==
ID2SYM(rb_intern(
"r"))) {
10145 return RB_WAITFD_IN;
10147 if (mode ==
ID2SYM(rb_intern(
"read"))) {
10148 return RB_WAITFD_IN;
10150 if (mode ==
ID2SYM(rb_intern(
"readable"))) {
10151 return RB_WAITFD_IN;
10153 if (mode ==
ID2SYM(rb_intern(
"w"))) {
10154 return RB_WAITFD_OUT;
10156 if (mode ==
ID2SYM(rb_intern(
"write"))) {
10157 return RB_WAITFD_OUT;
10159 if (mode ==
ID2SYM(rb_intern(
"writable"))) {
10160 return RB_WAITFD_OUT;
10162 if (mode ==
ID2SYM(rb_intern(
"rw"))) {
10163 return RB_WAITFD_IN|RB_WAITFD_OUT;
10165 if (mode ==
ID2SYM(rb_intern(
"read_write"))) {
10166 return RB_WAITFD_IN|RB_WAITFD_OUT;
10168 if (mode ==
ID2SYM(rb_intern(
"readable_writable"))) {
10169 return RB_WAITFD_IN|RB_WAITFD_OUT;
10172 rb_raise(rb_eArgError,
"unsupported mode: %"PRIsVALUE, mode);
10176io_event_from_value(
VALUE value)
10180 if (events <= 0) rb_raise(rb_eArgError,
"Events must be positive integer!");
10218 for (
int i = 0; i < argc; i += 1) {
10220 events |= wait_mode_sym(argv[i]);
10222 else if (UNDEF_P(timeout)) {
10226 rb_raise(rb_eArgError,
"timeout given more than once");
10230 if (UNDEF_P(timeout)) timeout =
Qnil;
10238 events = io_event_from_value(argv[0]);
10246 if (rb_io_read_pending(fptr)) {
10248 if (return_io)
return Qtrue;
10254 return io_wait_event(io, events, timeout, return_io);
10258argf_mark_and_move(
void *ptr)
10260 struct argf *p = ptr;
10261 rb_gc_mark_and_move(&p->filename);
10262 rb_gc_mark_and_move(&p->current_file);
10263 rb_gc_mark_and_move(&p->argv);
10264 rb_gc_mark_and_move(&p->inplace);
10265 rb_gc_mark_and_move(&p->encs.
ecopts);
10269argf_memsize(
const void *ptr)
10271 const struct argf *p = ptr;
10272 size_t size =
sizeof(*p);
10279 0, 0, RUBY_TYPED_THREAD_SAFE_FREE | RUBY_TYPED_WB_PROTECTED
10285 p->filename =
Qnil;
10286 p->current_file =
Qnil;
10292argf_alloc(
VALUE klass)
10307 memset(&ARGF, 0,
sizeof(ARGF));
10308 argf_init(
argf, &ARGF, argv);
10318 ARGF = argf_of(orig);
10319 rb_gc_writebarrier_remember(
argf);
10346 ARGF.last_lineno = ARGF.lineno;
10372 return forward_current(rb_frame_this_func(), argc, argv);
10375#define next_argv() argf_next_argv(argf)
10376#define ARGF_GENERIC_INPUT_P() \
10377 (ARGF.current_file == rb_stdin && !RB_TYPE_P(ARGF.current_file, T_FILE))
10378#define ARGF_FORWARD(argc, argv) do {\
10379 if (ARGF_GENERIC_INPUT_P())\
10380 return argf_forward((argc), (argv), argf);\
10382#define NEXT_ARGF_FORWARD(argc, argv) do {\
10383 if (!next_argv()) return Qnil;\
10384 ARGF_FORWARD((argc), (argv));\
10390 VALUE file = ARGF.current_file;
10404 int stdout_binmode = 0;
10405 enum rb_io_mode fmode;
10407 VALUE r_stdout = rb_ractor_stdout();
10412 stdout_binmode = 1;
10415 if (ARGF.init_p == 0) {
10425 if (
NIL_P(ARGF.argv)) {
10428 else if (ARGF.next_p == -1 &&
RARRAY_LEN(ARGF.argv) > 0) {
10433 if (ARGF.next_p == 1) {
10434 if (ARGF.init_p == 1) argf_close(
argf);
10439 ARGF_SET(filename, filename);
10440 filename = rb_str_encode_ospath(filename);
10442 if (RSTRING_LEN(filename) == 1 && fn[0] ==
'-') {
10444 if (ARGF.inplace) {
10445 rb_warn(
"Can't do inplace edit for stdio; skipping");
10451 int fr = rb_sysopen(filename, O_RDONLY, 0);
10453 if (ARGF.inplace) {
10455#ifndef NO_SAFE_RENAME
10466 if (!
NIL_P(ARGF.inplace)) {
10467 VALUE suffix = ARGF.inplace;
10469 if (
NIL_P(rb_str_cat_conv_enc_opts(str, RSTRING_LEN(str),
10470 RSTRING_PTR(suffix), RSTRING_LEN(suffix),
10471 rb_enc_get(suffix), 0,
Qnil))) {
10474#ifdef NO_SAFE_RENAME
10476 (void)unlink(RSTRING_PTR(str));
10477 if (rename(fn, RSTRING_PTR(str)) < 0) {
10478 rb_warn(
"Can't rename %"PRIsVALUE
" to %"PRIsVALUE
": %s, skipping file",
10479 filename, str, strerror(
errno));
10482 fr = rb_sysopen(str, O_RDONLY, 0);
10484 if (rename(fn, RSTRING_PTR(str)) < 0) {
10485 rb_warn(
"Can't rename %"PRIsVALUE
" to %"PRIsVALUE
": %s, skipping file",
10486 filename, str, strerror(
errno));
10493#ifdef NO_SAFE_RENAME
10494 rb_fatal(
"Can't do inplace edit without backup");
10496 if (unlink(fn) < 0) {
10497 rb_warn(
"Can't remove %"PRIsVALUE
": %s, skipping file",
10498 filename, strerror(
errno));
10504 fw = rb_sysopen(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666);
10505#ifndef NO_SAFE_RENAME
10508 fchmod(fw, st.st_mode);
10510 chmod(fn, st.st_mode);
10512 if (st.st_uid!=st2.st_uid || st.st_gid!=st2.st_gid) {
10515 err = fchown(fw, st.st_uid, st.st_gid);
10517 err = chown(fn, st.st_uid, st.st_gid);
10519 if (err && getuid() == 0 && st2.st_uid == 0) {
10520 const char *wkfn = RSTRING_PTR(filename);
10521 rb_warn(
"Can't set owner/group of %"PRIsVALUE
" to same as %"PRIsVALUE
": %s, skipping file",
10522 filename, str, strerror(
errno));
10525 (void)unlink(wkfn);
10535 if (!ARGF.binmode) {
10536 fmode |= DEFAULT_TEXTMODE;
10538 ARGF_SET(current_file, prep_io(fr, fmode,
rb_cFile, fn));
10539 if (!
NIL_P(write_io)) {
10546 if (ARGF.encs.enc) {
10547 fptr->
encs = ARGF.encs;
10548 clear_codeconv(fptr);
10551 fptr->
encs.
ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
10552 if (!ARGF.binmode) {
10554#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
10555 fptr->
encs.
ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
10566 else if (ARGF.next_p == -1) {
10569 if (ARGF.inplace) {
10570 rb_warn(
"Can't do inplace edit for stdio");
10574 if (ARGF.init_p == -1) ARGF.init_p = 1;
10582 long lineno = ARGF.lineno;
10585 if (!next_argv())
return Qnil;
10586 if (ARGF_GENERIC_INPUT_P()) {
10587 line = forward_current(idGets, argc, argv);
10594 line = rb_io_getline(argc, argv, ARGF.current_file);
10596 if (
NIL_P(line) && ARGF.next_p != -1) {
10602 if (!
NIL_P(line)) {
10603 ARGF.lineno = ++lineno;
10604 ARGF.last_lineno = ARGF.lineno;
10610argf_lineno_getter(
ID id,
VALUE *var)
10613 return INT2FIX(ARGF.last_lineno);
10621 ARGF.last_lineno = ARGF.lineno = n;
10625rb_reset_argf_lineno(
long n)
10627 ARGF.last_lineno = ARGF.lineno = n;
10668 if (recv ==
argf) {
10669 return argf_gets(argc, argv,
argf);
10671 return forward(
argf, idGets, argc, argv);
10697 line = argf_getline(argc, argv,
argf);
10709 return rb_f_gets(0, 0,
argf);
10713 if (!next_argv())
return Qnil;
10715 if (
NIL_P(line) && ARGF.next_p != -1) {
10721 if (!
NIL_P(line)) {
10723 ARGF.last_lineno = ARGF.lineno;
10749rb_f_readline(
int argc,
VALUE *argv,
VALUE recv)
10751 if (recv ==
argf) {
10752 return argf_readline(argc, argv,
argf);
10754 return forward(
argf, rb_intern(
"readline"), argc, argv);
10780 if (!next_argv()) rb_eof_error();
10781 ARGF_FORWARD(argc, argv);
10782 line = argf_gets(argc, argv,
argf);
10852rb_f_readlines(
int argc,
VALUE *argv,
VALUE recv)
10854 if (recv ==
argf) {
10855 return argf_readlines(argc, argv,
argf);
10857 return forward(
argf, rb_intern(
"readlines"), argc, argv);
10881 long lineno = ARGF.lineno;
10885 while (next_argv()) {
10886 if (ARGF_GENERIC_INPUT_P()) {
10887 lines = forward_current(rb_intern(
"readlines"), argc, argv);
10890 lines = rb_io_readlines(argc, argv, ARGF.current_file);
10896 ARGF.last_lineno = ARGF.lineno;
10931 rb_last_status_clear();
10932 port = pipe_open_s(str,
"r",
FMODE_READABLE|DEFAULT_TEXTMODE, NULL);
10936 result = read_all(fptr, remain_size(fptr),
Qnil);
10938 rb_io_fptr_cleanup_all(fptr);
10944#ifdef HAVE_SYS_SELECT_H
10945#include <sys/select.h>
10959 if (!
NIL_P(read)) {
10964 if (READ_DATA_PENDING(fptr) || READ_CHAR_PENDING(fptr)) {
10968 if (max < fptr->fd) max = fptr->
fd;
10971 timerec.tv_sec = timerec.tv_usec = 0;
10979 if (!
NIL_P(write)) {
10985 if (max < fptr->fd) max = fptr->
fd;
10992 if (!
NIL_P(except)) {
10996 VALUE write_io = GetWriteIO(io);
10999 if (max < fptr->fd) max = fptr->
fd;
11000 if (io != write_io) {
11003 if (max < fptr->fd) max = fptr->
fd;
11018 if (!pending && n == 0)
return Qnil;
11043 VALUE write_io = GetWriteIO(io);
11056 VALUE write_io = GetWriteIO(io);
11061 else if (io != write_io) {
11074 VALUE read, write, except;
11080select_call(
VALUE arg)
11084 return select_internal(p->read, p->write, p->except, p->timeout, p->fdsets);
11088select_end(
VALUE arg)
11093 for (i = 0; i < numberof(p->fdsets); ++i)
11098static VALUE sym_normal, sym_sequential, sym_random,
11099 sym_willneed, sym_dontneed, sym_noreuse;
11101#ifdef HAVE_POSIX_FADVISE
11102struct io_advise_struct {
11110io_advise_internal(
void *arg)
11112 struct io_advise_struct *ptr = arg;
11113 return posix_fadvise(ptr->fd, ptr->offset, ptr->len, ptr->advice);
11117io_advise_sym_to_const(
VALUE sym)
11119#ifdef POSIX_FADV_NORMAL
11120 if (sym == sym_normal)
11121 return INT2NUM(POSIX_FADV_NORMAL);
11124#ifdef POSIX_FADV_RANDOM
11125 if (sym == sym_random)
11126 return INT2NUM(POSIX_FADV_RANDOM);
11129#ifdef POSIX_FADV_SEQUENTIAL
11130 if (sym == sym_sequential)
11131 return INT2NUM(POSIX_FADV_SEQUENTIAL);
11134#ifdef POSIX_FADV_WILLNEED
11135 if (sym == sym_willneed)
11136 return INT2NUM(POSIX_FADV_WILLNEED);
11139#ifdef POSIX_FADV_DONTNEED
11140 if (sym == sym_dontneed)
11141 return INT2NUM(POSIX_FADV_DONTNEED);
11144#ifdef POSIX_FADV_NOREUSE
11145 if (sym == sym_noreuse)
11146 return INT2NUM(POSIX_FADV_NOREUSE);
11153do_io_advise(
rb_io_t *fptr,
VALUE advice, rb_off_t offset, rb_off_t
len)
11156 struct io_advise_struct ias;
11159 num_adv = io_advise_sym_to_const(advice);
11165 if (
NIL_P(num_adv))
11169 ias.advice =
NUM2INT(num_adv);
11170 ias.offset = offset;
11173 rv = (int)rb_io_blocking_region(fptr, io_advise_internal, &ias);
11174 if (rv && rv != ENOSYS) {
11177 VALUE message = rb_sprintf(
"%"PRIsVALUE
" "
11181 fptr->
pathv, offset,
len, advice);
11191advice_arg_check(
VALUE advice)
11196 if (advice != sym_normal &&
11197 advice != sym_sequential &&
11198 advice != sym_random &&
11199 advice != sym_willneed &&
11200 advice != sym_dontneed &&
11201 advice != sym_noreuse) {
11202 rb_raise(
rb_eNotImpError,
"Unsupported advice: %+"PRIsVALUE, advice);
11240rb_io_advise(
int argc,
VALUE *argv,
VALUE io)
11247 advice_arg_check(advice);
11249 io = GetWriteIO(io);
11255#ifdef HAVE_POSIX_FADVISE
11256 return do_io_advise(fptr, advice,
off, l);
11258 ((void)
off, (
void)l);
11270 return isinf(f) && 0 < f;
11426rb_f_select(
int argc,
VALUE *argv,
VALUE obj)
11429 if (scheduler !=
Qnil) {
11432 if (!UNDEF_P(result))
return result;
11440 rb_scan_args(argc, argv,
"13", &args.read, &args.write, &args.except, &timeout);
11441 if (
NIL_P(timeout) || is_pos_inf(timeout)) {
11446 args.timeout = &timerec;
11449 for (i = 0; i < numberof(args.fdsets); ++i)
11455#ifdef IOCTL_REQ_TYPE
11456 typedef IOCTL_REQ_TYPE ioctl_req_t;
11458 typedef int ioctl_req_t;
11459# define NUM2IOCTLREQ(num) ((int)NUM2LONG(num))
11470nogvl_ioctl(
void *ptr)
11472 struct ioctl_arg *arg = ptr;
11474 return (
VALUE)ioctl(arg->fd, arg->cmd, arg->narg);
11478do_ioctl(
struct rb_io *io, ioctl_req_t cmd,
long narg)
11481 struct ioctl_arg arg;
11487 retval = (int)rb_io_blocking_region(io, nogvl_ioctl, &arg);
11493#define DEFAULT_IOCTL_NARG_LEN (256)
11495#if defined(__linux__) && defined(_IOC_SIZE)
11497linux_iocparm_len(ioctl_req_t cmd)
11501 if ((cmd & 0xFFFF0000) == 0) {
11503 return DEFAULT_IOCTL_NARG_LEN;
11506 len = _IOC_SIZE(cmd);
11509 if (
len < DEFAULT_IOCTL_NARG_LEN)
11510 len = DEFAULT_IOCTL_NARG_LEN;
11518ioctl_narg_len(ioctl_req_t cmd)
11524#define IOCPARM_LEN(x) (((x) >> 16) & IOCPARM_MASK)
11528 len = IOCPARM_LEN(cmd);
11529#elif defined(__linux__) && defined(_IOC_SIZE)
11530 len = linux_iocparm_len(cmd);
11533 len = DEFAULT_IOCTL_NARG_LEN;
11542typedef long fcntl_arg_t;
11545typedef int fcntl_arg_t;
11549fcntl_narg_len(ioctl_req_t cmd)
11556 len =
sizeof(fcntl_arg_t);
11564#ifdef F_DUPFD_CLOEXEC
11565 case F_DUPFD_CLOEXEC:
11566 len =
sizeof(fcntl_arg_t);
11576 len =
sizeof(fcntl_arg_t);
11586 len =
sizeof(fcntl_arg_t);
11596 len =
sizeof(fcntl_arg_t);
11601 len =
sizeof(
struct f_owner_ex);
11606 len =
sizeof(
struct f_owner_ex);
11611 len =
sizeof(
struct flock);
11616 len =
sizeof(
struct flock);
11621 len =
sizeof(
struct flock);
11641 len =
sizeof(fcntl_arg_t);
11651 len =
sizeof(fcntl_arg_t);
11656 len =
sizeof(fcntl_arg_t);
11669fcntl_narg_len(ioctl_req_t cmd)
11675#define NARG_SENTINEL 17
11678setup_narg(ioctl_req_t cmd,
VALUE *argp,
long (*narg_len)(ioctl_req_t))
11689 else if (arg ==
Qtrue) {
11703 len = narg_len(cmd);
11704 rb_str_modify(arg);
11706 slen = RSTRING_LEN(arg);
11708 if (slen <
len+1) {
11709 rb_str_resize(arg,
len+1);
11710 MEMZERO(RSTRING_PTR(arg)+slen,
char,
len-slen);
11714 ptr = RSTRING_PTR(arg);
11715 ptr[slen - 1] = NARG_SENTINEL;
11724finish_narg(
int retval,
VALUE arg,
const rb_io_t *fptr)
11726 if (retval < 0) rb_sys_fail_path(fptr->
pathv);
11731 if (ptr[slen-1] != NARG_SENTINEL)
11732 rb_raise(rb_eArgError,
"return value overflowed string");
11733 ptr[slen-1] =
'\0';
11743 ioctl_req_t cmd = NUM2IOCTLREQ(req);
11748 narg = setup_narg(cmd, &arg, ioctl_narg_len);
11750 retval = do_ioctl(fptr, cmd, narg);
11751 return finish_narg(retval, arg, fptr);
11778 return rb_ioctl(io, req, arg);
11781#define rb_io_ioctl rb_f_notimplement
11792nogvl_fcntl(
void *ptr)
11794 struct fcntl_arg *arg = ptr;
11796#if defined(F_DUPFD)
11797 if (arg->cmd == F_DUPFD)
11800 return (
VALUE)fcntl(arg->fd, arg->cmd, arg->narg);
11804do_fcntl(
struct rb_io *io,
int cmd,
long narg)
11807 struct fcntl_arg arg;
11813 retval = (int)rb_io_blocking_region(io, nogvl_fcntl, &arg);
11814 if (retval != -1) {
11816#if defined(F_DUPFD)
11819#if defined(F_DUPFD_CLOEXEC)
11820 case F_DUPFD_CLOEXEC:
11837 narg = setup_narg(cmd, &arg, fcntl_narg_len);
11839 retval = do_fcntl(fptr, cmd, narg);
11840 return finish_narg(retval, arg, fptr);
11866 return rb_fcntl(io, req, arg);
11869#define rb_io_fcntl rb_f_notimplement
11872#if defined(HAVE_SYSCALL) || defined(HAVE___SYSCALL)
11904#if SIZEOF_VOIDP == 8 && defined(HAVE___SYSCALL) && SIZEOF_INT != 8
11905# define SYSCALL __syscall
11906# define NUM2SYSCALLID(x) NUM2LONG(x)
11907# define RETVAL2NUM(x) LONG2NUM(x)
11908# if SIZEOF_LONG == 8
11909 long num, retval = -1;
11910# elif SIZEOF_LONG_LONG == 8
11911 long long num, retval = -1;
11913# error ---->> it is asserted that __syscall takes the first argument and returns retval in 64bit signed integer. <<----
11915#elif defined(__linux__)
11916# define SYSCALL syscall
11917# define NUM2SYSCALLID(x) NUM2LONG(x)
11918# define RETVAL2NUM(x) LONG2NUM(x)
11926 long num, retval = -1;
11928# define SYSCALL syscall
11929# define NUM2SYSCALLID(x) NUM2INT(x)
11930# define RETVAL2NUM(x) INT2NUM(x)
11931 int num, retval = -1;
11937 "We plan to remove a syscall function at future release. DL(Fiddle) provides safer alternative.");
11941 rb_raise(rb_eArgError,
"too few arguments for syscall");
11942 if (argc > numberof(arg))
11943 rb_raise(rb_eArgError,
"too many arguments for syscall");
11944 num = NUM2SYSCALLID(argv[0]); ++argv;
11945 for (i = argc - 1; i--; ) {
11960 retval = SYSCALL(num);
11963 retval = SYSCALL(num, arg[0]);
11966 retval = SYSCALL(num, arg[0],arg[1]);
11969 retval = SYSCALL(num, arg[0],arg[1],arg[2]);
11972 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3]);
11975 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4]);
11978 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5]);
11981 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6]);
11987 return RETVAL2NUM(retval);
11989#undef NUM2SYSCALLID
11993#define rb_f_syscall rb_f_notimplement
11997io_new_instance(
VALUE args)
12003find_encoding(
VALUE v)
12006 if (!enc)
rb_warn(
"Unsupported encoding %"PRIsVALUE
" ignored", v);
12018 enc2 = find_encoding(v1);
12021 if (RSTRING_LEN(tmp) == 1 && RSTRING_PTR(tmp)[0] ==
'-') {
12027 enc = find_encoding(v2);
12034 enc = find_encoding(v2);
12040 if (enc2 == rb_ascii8bit_encoding()) {
12045 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
12051 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
12052 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
12057 if (!
NIL_P(tmp) && rb_enc_asciicompat(enc = rb_enc_get(tmp))) {
12058 parse_mode_enc(RSTRING_PTR(tmp), enc, &enc, &enc2, NULL);
12059 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
12063 rb_io_ext_int_to_encs(find_encoding(v1), NULL, &enc, &enc2, 0);
12064 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
12069 validate_enc_binmode(&fptr->
mode, ecflags, enc, enc2);
12074 clear_codeconv(fptr);
12086io_encoding_set_v(
VALUE v)
12089 io_encoding_set(arg->fptr, arg->v1, arg->v2, arg->opt);
12094pipe_pair_close(
VALUE rw)
12097 return rb_ensure(io_close, rwp[0], io_close, rwp[1]);
12180rb_io_s_pipe(
int argc,
VALUE *argv,
VALUE klass)
12182 int pipes[2], state;
12183 VALUE r, w, args[3], v1, v2;
12187 enum rb_io_mode fmode = 0;
12190 argc =
rb_scan_args(argc, argv,
"02:", &v1, &v2, &opt);
12197 r = rb_protect(io_new_instance, (
VALUE)args, &state);
12201 rb_jump_tag(state);
12205 ies_args.fptr = fptr;
12208 ies_args.opt = opt;
12209 rb_protect(io_encoding_set_v, (
VALUE)&ies_args, &state);
12213 rb_jump_tag(state);
12218 w = rb_protect(io_new_instance, (
VALUE)args, &state);
12222 rb_jump_tag(state);
12227 extract_binmode(opt, &fmode);
12234#if DEFAULT_TEXTMODE
12236 fptr->
mode &= ~FMODE_TEXTMODE;
12237 setmode(fptr->
fd, O_BINARY);
12239#if RUBY_CRLF_ENVIRONMENT
12245 fptr->
mode |= fmode;
12246#if DEFAULT_TEXTMODE
12248 fptr2->
mode &= ~FMODE_TEXTMODE;
12249 setmode(fptr2->
fd, O_BINARY);
12252 fptr2->
mode |= fmode;
12286 else if (!
NIL_P(v = rb_hash_aref(opt, sym_open_args))) {
12289 v = rb_to_array_type(v);
12294 arg->io = rb_io_open(klass, path, vmode, vperm, opt);
12298io_s_foreach(
VALUE v)
12303 if (arg->limit == 0)
12304 rb_raise(rb_eArgError,
"invalid limit: 0 for foreach");
12305 while (!
NIL_P(str = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, arg->io))) {
12389rb_io_s_foreach(
int argc,
VALUE *argv,
VALUE self)
12392 int orig_argc = argc;
12396 argc =
rb_scan_args(argc, argv,
"12:", NULL, NULL, NULL, &opt);
12398 extract_getline_args(argc-1, argv+1, &garg);
12399 open_key_args(self, argc, argv, opt, &arg);
12401 extract_getline_opts(opt, &garg);
12402 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12403 return rb_ensure(io_s_foreach, (
VALUE)&garg, rb_io_close, arg.io);
12407io_s_readlines(
VALUE v)
12410 return io_readlines(arg, arg->io);
12463rb_io_s_readlines(
int argc,
VALUE *argv,
VALUE io)
12469 argc =
rb_scan_args(argc, argv,
"12:", NULL, NULL, NULL, &opt);
12470 extract_getline_args(argc-1, argv+1, &garg);
12471 open_key_args(io, argc, argv, opt, &arg);
12473 extract_getline_opts(opt, &garg);
12474 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12475 return rb_ensure(io_s_readlines, (
VALUE)&garg, rb_io_close, arg.io);
12482 return io_read(arg->argc, arg->argv, arg->io);
12492seek_before_access(
VALUE argp)
12496 return rb_io_seek(arg->io, arg->offset, arg->mode);
12563rb_io_s_read(
int argc,
VALUE *argv,
VALUE io)
12569 argc =
rb_scan_args(argc, argv,
"13:", NULL, NULL, &offset, NULL, &opt);
12571 rb_raise(rb_eArgError,
"negative offset %ld given",
off);
12573 open_key_args(io, argc, argv, opt, &arg);
12575 if (!
NIL_P(offset)) {
12579 sarg.offset = offset;
12580 sarg.mode = SEEK_SET;
12581 rb_protect(seek_before_access, (
VALUE)&sarg, &state);
12584 rb_jump_tag(state);
12586 if (arg.argc == 2) arg.argc = 1;
12601rb_io_s_binread(
int argc,
VALUE *argv,
VALUE io)
12616 convconfig.
enc = rb_ascii8bit_encoding();
12617 arg.io = rb_io_open_generic(io, argv[0], oflags, fmode, &convconfig, 0);
12620 arg.argc = (argc > 1) ? 1 : 0;
12621 if (!
NIL_P(offset)) {
12625 sarg.offset = offset;
12626 sarg.mode = SEEK_SET;
12627 rb_protect(seek_before_access, (
VALUE)&sarg, &state);
12630 rb_jump_tag(state);
12637io_s_write0(
VALUE v)
12640 return io_write(arg->io,arg->str,arg->nosync);
12644io_s_write(
int argc,
VALUE *argv,
VALUE klass,
int binary)
12646 VALUE string, offset, opt;
12650 rb_scan_args(argc, argv,
"21:", NULL, &
string, &offset, &opt);
12652 if (
NIL_P(opt)) opt = rb_hash_new();
12653 else opt = rb_hash_dup(opt);
12656 if (
NIL_P(rb_hash_aref(opt,sym_mode))) {
12657 int mode = O_WRONLY|O_CREAT;
12659 if (binary) mode |= O_BINARY;
12661 if (
NIL_P(offset)) mode |= O_TRUNC;
12662 rb_hash_aset(opt,sym_mode,
INT2NUM(mode));
12664 open_key_args(klass, argc, argv, opt, &arg);
12667 if (binary) rb_io_binmode_m(arg.io);
12671 if (!
NIL_P(offset)) {
12675 sarg.offset = offset;
12676 sarg.mode = SEEK_SET;
12677 rb_protect(seek_before_access, (
VALUE)&sarg, &state);
12680 rb_jump_tag(state);
12688 return rb_ensure(io_s_write0, (
VALUE)&warg, rb_io_close, arg.io);
12746rb_io_s_write(
int argc,
VALUE *argv,
VALUE io)
12748 return io_s_write(argc, argv, io, 0);
12761rb_io_s_binwrite(
int argc,
VALUE *argv,
VALUE io)
12763 return io_s_write(argc, argv, io, 1);
12769 rb_off_t copy_length;
12770 rb_off_t src_offset;
12774 unsigned close_src : 1;
12775 unsigned close_dst : 1;
12778 const char *syserr;
12779 const char *notimp;
12781 struct stat src_stat;
12782 struct stat dst_stat;
12783#ifdef HAVE_FCOPYFILE
12784 copyfile_state_t copyfile_state;
12789exec_interrupts(
void *arg)
12792 rb_thread_execute_interrupts(th);
12806#if defined(ERESTART)
12811 rb_thread_execute_interrupts(stp->th);
12830fiber_scheduler_wait_for(
void * _arguments)
12840# define IOWAIT_SYSCALL "poll"
12841STATIC_ASSERT(pollin_expected, POLLIN == RB_WAITFD_IN);
12842STATIC_ASSERT(pollout_expected, POLLOUT == RB_WAITFD_OUT);
12847 if (scheduler !=
Qnil) {
12850 return RTEST(args.result);
12854 if (fd == -1)
return 0;
12859 fds.events = events;
12861 int timeout_milliseconds = -1;
12864 timeout_milliseconds = (int)(timeout->tv_sec * 1000) + (int)(timeout->tv_usec / 1000);
12867 return poll(&fds, 1, timeout_milliseconds);
12870# define IOWAIT_SYSCALL "select"
12875 if (scheduler !=
Qnil) {
12878 return RTEST(args.result);
12898 case RB_WAITFD_OUT:
12902 VM_UNREACHABLE(nogvl_wait_for);
12922 ret = nogvl_wait_for(stp->th, stp->src_fptr, RB_WAITFD_IN, NULL);
12924 }
while (ret < 0 && maygvl_copy_stream_continue_p(has_gvl, stp));
12927 stp->syserr = IOWAIT_SYSCALL;
12928 stp->error_no =
errno;
12940 ret = nogvl_wait_for(stp->th, stp->dst_fptr, RB_WAITFD_OUT, NULL);
12941 }
while (ret < 0 && maygvl_copy_stream_continue_p(0, stp));
12944 stp->syserr = IOWAIT_SYSCALL;
12945 stp->error_no =
errno;
12951#ifdef USE_COPY_FILE_RANGE
12954simple_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)
12956#ifdef HAVE_COPY_FILE_RANGE
12957 return copy_file_range(in_fd, in_offset, out_fd, out_offset, count, flags);
12959 return syscall(__NR_copy_file_range, in_fd, in_offset, out_fd, out_offset, count, flags);
12968 rb_off_t copy_length, src_offset, *src_offset_ptr;
12970 if (!S_ISREG(stp->src_stat.st_mode))
12973 src_size = stp->src_stat.st_size;
12974 src_offset = stp->src_offset;
12975 if (src_offset >= (rb_off_t)0) {
12976 src_offset_ptr = &src_offset;
12979 src_offset_ptr = NULL;
12982 copy_length = stp->copy_length;
12983 if (copy_length < (rb_off_t)0) {
12984 if (src_offset < (rb_off_t)0) {
12985 rb_off_t current_offset;
12987 current_offset = lseek(stp->src_fptr->
fd, 0, SEEK_CUR);
12988 if (current_offset < (rb_off_t)0 &&
errno) {
12989 stp->syserr =
"lseek";
12990 stp->error_no =
errno;
12991 return (
int)current_offset;
12993 copy_length = src_size - current_offset;
12996 copy_length = src_size - src_offset;
13000 retry_copy_file_range:
13001# if SIZEOF_OFF_T > SIZEOF_SIZE_T
13003 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
13005 ss = (ssize_t)copy_length;
13007 ss = simple_copy_file_range(stp->src_fptr->
fd, src_offset_ptr, stp->dst_fptr->
fd, NULL, ss, 0);
13011 if (0 < copy_length) {
13012 goto retry_copy_file_range;
13016 if (maygvl_copy_stream_continue_p(0, stp)) {
13017 goto retry_copy_file_range;
13031#if EWOULDBLOCK != EAGAIN
13035 int ret = nogvl_copy_stream_wait_write(stp);
13036 if (ret < 0)
return ret;
13038 goto retry_copy_file_range;
13042 int flags = fcntl(stp->dst_fptr->
fd, F_GETFL);
13044 if (flags != -1 && flags & O_APPEND) {
13050 stp->syserr =
"copy_file_range";
13051 stp->error_no =
errno;
13058#ifdef HAVE_FCOPYFILE
13062 rb_off_t cur, ss = 0;
13063 const rb_off_t src_offset = stp->src_offset;
13066 if (stp->copy_length >= (rb_off_t)0) {
13071 if (!S_ISREG(stp->src_stat.st_mode))
13074 if (!S_ISREG(stp->dst_stat.st_mode))
13076 if (lseek(stp->dst_fptr->
fd, 0, SEEK_CUR) > (rb_off_t)0)
13078 if (fcntl(stp->dst_fptr->
fd, F_GETFL) & O_APPEND) {
13081 rb_off_t end = lseek(stp->dst_fptr->
fd, 0, SEEK_END);
13082 lseek(stp->dst_fptr->
fd, 0, SEEK_SET);
13083 if (end > (rb_off_t)0)
return 0;
13086 if (src_offset > (rb_off_t)0) {
13091 cur = lseek(stp->src_fptr->
fd, 0, SEEK_CUR);
13092 if (cur < (rb_off_t)0 &&
errno) {
13093 stp->error_no =
errno;
13098 r = lseek(stp->src_fptr->
fd, src_offset, SEEK_SET);
13099 if (r < (rb_off_t)0 &&
errno) {
13100 stp->error_no =
errno;
13105 stp->copyfile_state = copyfile_state_alloc();
13106 ret = fcopyfile(stp->src_fptr->
fd, stp->dst_fptr->
fd, stp->copyfile_state, COPYFILE_DATA);
13107 copyfile_state_get(stp->copyfile_state, COPYFILE_STATE_COPIED, &ss);
13111 if (src_offset > (rb_off_t)0) {
13115 r = lseek(stp->src_fptr->
fd, cur, SEEK_SET);
13116 if (r < (rb_off_t)0 &&
errno) {
13117 stp->error_no =
errno;
13129 stp->syserr =
"fcopyfile";
13130 stp->error_no =
errno;
13137#ifdef HAVE_SENDFILE
13140# define USE_SENDFILE
13142# ifdef HAVE_SYS_SENDFILE_H
13143# include <sys/sendfile.h>
13147simple_sendfile(
int out_fd,
int in_fd, rb_off_t *offset, rb_off_t count)
13149 return sendfile(out_fd, in_fd, offset, (
size_t)count);
13152# elif 0 || defined(__APPLE__)
13156# define USE_SENDFILE
13159simple_sendfile(
int out_fd,
int in_fd, rb_off_t *offset, rb_off_t count)
13162 rb_off_t pos = offset ? *offset : lseek(in_fd, 0, SEEK_CUR);
13165 r = sendfile(in_fd, out_fd, pos, &count, NULL, 0);
13168 r = sendfile(in_fd, out_fd, pos, (
size_t)count, NULL, &sbytes, 0);
13170 if (r != 0 && sbytes == 0)
return r;
13175 lseek(in_fd, sbytes, SEEK_CUR);
13177 return (ssize_t)sbytes;
13190 rb_off_t copy_length;
13191 rb_off_t src_offset;
13194 if (!S_ISREG(stp->src_stat.st_mode))
13197 src_size = stp->src_stat.st_size;
13199 if ((stp->dst_stat.st_mode & S_IFMT) != S_IFSOCK)
13203 src_offset = stp->src_offset;
13204 use_pread = src_offset >= (rb_off_t)0;
13206 copy_length = stp->copy_length;
13207 if (copy_length < (rb_off_t)0) {
13209 copy_length = src_size - src_offset;
13213 cur = lseek(stp->src_fptr->
fd, 0, SEEK_CUR);
13214 if (cur < (rb_off_t)0 &&
errno) {
13215 stp->syserr =
"lseek";
13216 stp->error_no =
errno;
13219 copy_length = src_size - cur;
13224# if SIZEOF_OFF_T > SIZEOF_SIZE_T
13226 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
13228 ss = (ssize_t)copy_length;
13231 ss = simple_sendfile(stp->dst_fptr->
fd, stp->src_fptr->
fd, &src_offset, ss);
13234 ss = simple_sendfile(stp->dst_fptr->
fd, stp->src_fptr->
fd, NULL, ss);
13239 if (0 < copy_length) {
13240 goto retry_sendfile;
13244 if (maygvl_copy_stream_continue_p(0, stp))
13245 goto retry_sendfile;
13258#if EWOULDBLOCK != EAGAIN
13271 ret = maygvl_copy_stream_wait_read(0, stp);
13272 if (ret < 0)
return ret;
13274 ret = nogvl_copy_stream_wait_write(stp);
13275 if (ret < 0)
return ret;
13277 goto retry_sendfile;
13279 stp->syserr =
"sendfile";
13280 stp->error_no =
errno;
13288maygvl_read(
int has_gvl,
rb_io_t *fptr,
void *buf,
size_t count)
13291 return rb_io_read_memory(fptr, buf, count);
13293 return read(fptr->
fd, buf, count);
13297maygvl_copy_stream_read(
int has_gvl,
struct copy_stream_struct *stp,
char *buf,
size_t len, rb_off_t offset)
13301 if (offset < (rb_off_t)0) {
13302 ss = maygvl_read(has_gvl, stp->src_fptr, buf,
len);
13305 ss = pread(stp->src_fptr->
fd, buf,
len, offset);
13311 if (maygvl_copy_stream_continue_p(has_gvl, stp))
13315#if EWOULDBLOCK != EAGAIN
13319 int ret = maygvl_copy_stream_wait_read(has_gvl, stp);
13320 if (ret < 0)
return ret;
13325 stp->notimp =
"pread";
13329 stp->syserr = offset < (rb_off_t)0 ?
"read" :
"pread";
13330 stp->error_no =
errno;
13341 ss = write(stp->dst_fptr->
fd, buf+
off,
len);
13343 if (maygvl_copy_stream_continue_p(0, stp))
13345 if (io_again_p(
errno)) {
13346 int ret = nogvl_copy_stream_wait_write(stp);
13347 if (ret < 0)
return ret;
13350 stp->syserr =
"write";
13351 stp->error_no =
errno;
13368 rb_off_t copy_length;
13369 rb_off_t src_offset;
13373 copy_length = stp->copy_length;
13374 use_eof = copy_length < (rb_off_t)0;
13375 src_offset = stp->src_offset;
13376 use_pread = src_offset >= (rb_off_t)0;
13378 if (use_pread && stp->close_src) {
13381 r = lseek(stp->src_fptr->
fd, src_offset, SEEK_SET);
13382 if (r < (rb_off_t)0 &&
errno) {
13383 stp->syserr =
"lseek";
13384 stp->error_no =
errno;
13387 src_offset = (rb_off_t)-1;
13391 while (use_eof || 0 < copy_length) {
13392 if (!use_eof && copy_length < (rb_off_t)
sizeof(buf)) {
13393 len = (size_t)copy_length;
13399 ss = maygvl_copy_stream_read(0, stp, buf,
len, src_offset);
13404 ss = maygvl_copy_stream_read(0, stp, buf,
len, (rb_off_t)-1);
13409 ret = nogvl_copy_stream_write(stp, buf, ss);
13419nogvl_copy_stream_func(
void *arg)
13422#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13426#ifdef USE_COPY_FILE_RANGE
13427 ret = nogvl_copy_file_range(stp);
13432#ifdef HAVE_FCOPYFILE
13433 ret = nogvl_fcopyfile(stp);
13439 ret = nogvl_copy_stream_sendfile(stp);
13444 nogvl_copy_stream_read_write(stp);
13446#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13453copy_stream_fallback_body(
VALUE arg)
13456 const int buflen = 16*1024;
13459 rb_off_t rest = stp->copy_length;
13460 rb_off_t
off = stp->src_offset;
13461 ID read_method = id_readpartial;
13463 if (!stp->src_fptr) {
13465 read_method = id_read;
13472 rb_str_make_independent(buf);
13473 if (stp->copy_length < (rb_off_t)0) {
13478 rb_str_resize(buf, 0);
13481 l = buflen < rest ? buflen : (long)rest;
13483 if (!stp->src_fptr) {
13486 if (read_method == id_read &&
NIL_P(rc))
13491 rb_str_resize(buf, buflen);
13492 ss = maygvl_copy_stream_read(1, stp, RSTRING_PTR(buf), l,
off);
13493 rb_str_resize(buf, ss > 0 ? ss : 0);
13498 if (
off >= (rb_off_t)0)
13501 n = rb_io_write(stp->dst, buf);
13503 stp->total += numwrote;
13505 if (read_method == id_read && RSTRING_LEN(buf) == 0) {
13516 if (!stp->src_fptr && stp->src_offset >= (rb_off_t)0) {
13517 rb_raise(rb_eArgError,
"cannot specify src_offset for non-IO");
13526copy_stream_body(
VALUE arg)
13529 VALUE src_io = stp->src, dst_io = stp->dst;
13530 const int common_oflags = 0
13540 if (src_io ==
argf ||
13544 stp->src_fptr = NULL;
13549 if (!
NIL_P(tmp_io)) {
13556 args[1] =
INT2NUM(O_RDONLY|common_oflags);
13559 stp->close_src = 1;
13564 stat_ret = fstat(stp->src_fptr->
fd, &stp->src_stat);
13565 if (stat_ret < 0) {
13566 stp->syserr =
"fstat";
13567 stp->error_no =
errno;
13572 if (dst_io ==
argf ||
13576 stp->dst_fptr = NULL;
13581 if (!
NIL_P(tmp_io)) {
13582 dst_io = GetWriteIO(tmp_io);
13588 args[1] =
INT2NUM(O_WRONLY|O_CREAT|O_TRUNC|common_oflags);
13592 stp->close_dst = 1;
13595 dst_io = GetWriteIO(dst_io);
13601 stat_ret = fstat(stp->dst_fptr->
fd, &stp->dst_stat);
13602 if (stat_ret < 0) {
13603 stp->syserr =
"fstat";
13604 stp->error_no =
errno;
13611 SET_BINARY_MODE_WITH_SEEK_CUR(stp->src_fptr);
13614 io_ascii8bit_binmode(stp->dst_fptr);
13616 if (stp->src_offset < (rb_off_t)0 && stp->src_fptr && stp->src_fptr->
rbuf.
len) {
13619 if (stp->copy_length >= (rb_off_t)0 && stp->copy_length < (rb_off_t)
len) {
13620 len = (size_t)stp->copy_length;
13623 rb_str_resize(str,
len);
13624 read_buffered_data(RSTRING_PTR(str),
len, stp->src_fptr);
13625 if (stp->dst_fptr) {
13626 if (io_binwrite(RSTRING_PTR(str), RSTRING_LEN(str), stp->dst_fptr, 0) < 0)
13627 rb_sys_fail_on_write(stp->dst_fptr);
13630 rb_io_write(dst_io, str);
13631 rb_str_resize(str, 0);
13633 if (stp->copy_length >= (rb_off_t)0)
13634 stp->copy_length -=
len;
13637 if (stp->dst_fptr && io_fflush(stp->dst_fptr) < 0) {
13641 if (stp->copy_length == 0)
13644 if (stp->src_fptr == NULL || stp->dst_fptr == NULL) {
13645 return copy_stream_fallback(stp);
13648 IO_WITHOUT_GVL(nogvl_copy_stream_func, stp);
13653copy_stream_finalize(
VALUE arg)
13657#ifdef HAVE_FCOPYFILE
13658 if (stp->copyfile_state) {
13659 copyfile_state_free(stp->copyfile_state);
13663 if (stp->close_src) {
13664 rb_io_close_m(stp->src);
13666 if (stp->close_dst) {
13667 rb_io_close_m(stp->dst);
13730rb_io_s_copy_stream(
int argc,
VALUE *argv,
VALUE io)
13732 VALUE src, dst, length, src_offset;
13737 rb_scan_args(argc, argv,
"22", &src, &dst, &length, &src_offset);
13742 st.src_fptr = NULL;
13743 st.dst_fptr = NULL;
13746 st.copy_length = (rb_off_t)-1;
13748 st.copy_length =
NUM2OFFT(length);
13750 if (
NIL_P(src_offset))
13751 st.src_offset = (rb_off_t)-1;
13753 st.src_offset =
NUM2OFFT(src_offset);
13772rb_io_external_encoding(
VALUE io)
13777 return rb_enc_from_encoding(fptr->
encs.
enc2);
13781 return rb_enc_from_encoding(fptr->
encs.
enc);
13784 return rb_enc_from_encoding(io_read_encoding(fptr));
13800rb_io_internal_encoding(
VALUE io)
13805 return rb_enc_from_encoding(io_read_encoding(fptr));
13839rb_io_set_encoding(
int argc,
VALUE *argv,
VALUE io)
13845 return forward(io, id_set_encoding, argc, argv);
13848 argc =
rb_scan_args(argc, argv,
"11:", &v1, &v2, &opt);
13850 io_encoding_set(fptr, v1, v2, opt);
13855rb_stdio_set_default_encoding(
void)
13860 if (isatty(fileno(stdin))) {
13862 rb_encoding *internal = rb_default_internal_encoding();
13863 if (!internal) internal = rb_default_external_encoding();
13865 rb_enc_from_encoding(external),
13866 rb_enc_from_encoding(internal),
13871 rb_io_set_encoding(1, &val,
rb_stdin);
13872 rb_io_set_encoding(1, &val,
rb_stdout);
13873 rb_io_set_encoding(1, &val,
rb_stderr);
13877global_argf_p(
VALUE arg)
13879 return arg ==
argf;
13882typedef VALUE (*argf_encoding_func)(
VALUE io);
13885argf_encoding(
VALUE argf, argf_encoding_func func)
13887 if (!
RTEST(ARGF.current_file)) {
13888 return rb_enc_default_external();
13912 return argf_encoding(
argf, rb_io_external_encoding);
13931 return argf_encoding(
argf, rb_io_internal_encoding);
13970 if (!next_argv()) {
13971 rb_raise(rb_eArgError,
"no stream to set encoding");
13973 rb_io_set_encoding(argc, argv, ARGF.current_file);
13975 ARGF.encs = fptr->
encs;
13995 if (!next_argv()) {
13996 rb_raise(rb_eArgError,
"no stream to tell");
13998 ARGF_FORWARD(0, 0);
13999 return rb_io_tell(ARGF.current_file);
14012 if (!next_argv()) {
14013 rb_raise(rb_eArgError,
"no stream to seek");
14015 ARGF_FORWARD(argc, argv);
14016 return rb_io_seek_m(argc, argv, ARGF.current_file);
14033 if (!next_argv()) {
14034 rb_raise(rb_eArgError,
"no stream to set position");
14036 ARGF_FORWARD(1, &offset);
14037 return rb_io_set_pos(ARGF.current_file, offset);
14058 if (!next_argv()) {
14059 rb_raise(rb_eArgError,
"no stream to rewind");
14061 ARGF_FORWARD(0, 0);
14062 old_lineno =
RFILE(ARGF.current_file)->fptr->lineno;
14063 ret = rb_io_rewind(ARGF.current_file);
14064 if (!global_argf_p(
argf)) {
14065 ARGF.last_lineno = ARGF.lineno -= old_lineno;
14083 if (!next_argv()) {
14084 rb_raise(rb_eArgError,
"no stream");
14086 ARGF_FORWARD(0, 0);
14087 return rb_io_fileno(ARGF.current_file);
14106 ARGF_FORWARD(0, 0);
14107 return ARGF.current_file;
14132 if (
RTEST(ARGF.current_file)) {
14133 if (ARGF.init_p == 0)
return Qtrue;
14135 ARGF_FORWARD(0, 0);
14194 VALUE tmp, str, length;
14198 if (!
NIL_P(length)) {
14203 rb_str_resize(str,0);
14208 if (!next_argv()) {
14211 if (ARGF_GENERIC_INPUT_P()) {
14212 tmp = argf_forward(argc, argv,
argf);
14215 tmp = io_read(argc, argv, ARGF.current_file);
14217 if (
NIL_P(str)) str = tmp;
14220 if (ARGF.next_p != -1) {
14226 else if (argc >= 1) {
14227 long slen = RSTRING_LEN(str);
14243argf_forward_call(
VALUE arg)
14246 argf_forward(p->argc, p->argv, p->argf);
14276 return argf_getpartial(argc, argv,
argf,
Qnil, 0);
14297 return argf_getpartial(argc, argv,
argf, opts, 1);
14303 VALUE tmp, str, length;
14311 no_exception = no_exception_p(opts);
14313 if (!next_argv()) {
14315 rb_str_resize(str, 0);
14319 if (ARGF_GENERIC_INPUT_P()) {
14329 tmp = io_getpartial(argc, argv, ARGF.current_file, no_exception, nonblock);
14332 if (ARGF.next_p == -1) {
14333 return io_nonblock_eof(no_exception);
14338 return io_nonblock_eof(no_exception);
14376 if (!next_argv())
return Qnil;
14377 if (ARGF_GENERIC_INPUT_P()) {
14378 ch = forward_current(rb_intern(
"getc"), 0, 0);
14381 ch = rb_io_getc(ARGF.current_file);
14383 if (
NIL_P(ch) && ARGF.next_p != -1) {
14416 if (!next_argv())
return Qnil;
14418 ch = forward_current(rb_intern(
"getbyte"), 0, 0);
14423 if (
NIL_P(ch) && ARGF.next_p != -1) {
14456 if (!next_argv()) rb_eof_error();
14458 ch = forward_current(rb_intern(
"getc"), 0, 0);
14461 ch = rb_io_getc(ARGF.current_file);
14463 if (
NIL_P(ch) && ARGF.next_p != -1) {
14495 NEXT_ARGF_FORWARD(0, 0);
14496 c = argf_getbyte(
argf);
14503#define FOREACH_ARGF() while (next_argv())
14508 const VALUE current = ARGF.current_file;
14510 if (ARGF.init_p == -1 || current != ARGF.current_file) {
14516#define ARGF_block_call(mid, argc, argv, func, argf) \
14517 rb_block_call_kw(ARGF.current_file, mid, argc, argv, \
14518 func, argf, rb_keyword_given_p())
14523 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_i,
argf);
14524 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14530 if (!global_argf_p(
argf)) {
14531 ARGF.last_lineno = ++ARGF.lineno;
14533 return argf_block_call_i(i,
argf, argc, argv, blockarg);
14539 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_line_i,
argf);
14540 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14588 argf_block_call_line(rb_intern(
"each_line"), argc, argv,
argf);
14619 argf_block_call(rb_intern(
"each_byte"), 0, 0,
argf);
14645 argf_block_call(rb_intern(
"each_char"), 0, 0,
argf);
14671 argf_block_call(rb_intern(
"each_codepoint"), 0, 0,
argf);
14702 return ARGF.filename;
14706argf_filename_getter(
ID id,
VALUE *var)
14708 return argf_filename(*var);
14733 return ARGF.current_file;
14752 ARGF_FORWARD(0, 0);
14773 return RBOOL(ARGF.binmode);
14793 if (ARGF.init_p && ARGF.next_p == 0) {
14822 if (ARGF.next_p != -1) {
14840 ARGF_FORWARD(0, 0);
14867 if (!ARGF.inplace)
return Qnil;
14875 return argf_inplace_mode_get(*var);
14906 ARGF.inplace =
Qnil;
14917 argf_inplace_mode_set(*var, val);
14921ruby_set_inplace_mode(
const char *suffix)
14947argf_argv_getter(
ID id,
VALUE *var)
14949 return argf_argv(*var);
14968 if (!
RTEST(ARGF.current_file)) {
14971 return GetWriteIO(ARGF.current_file);
14983 return rb_io_writev(argf_write_io(
argf), argc, argv);
14998 case RB_IO_WAIT_WRITABLE:
15001 c = rb_eEAGAINWaitWritable;
15003#if EAGAIN != EWOULDBLOCK
15005 c = rb_eEWOULDBLOCKWaitWritable;
15009 c = rb_eEINPROGRESSWaitWritable;
15015 case RB_IO_WAIT_READABLE:
15018 c = rb_eEAGAINWaitReadable;
15020#if EAGAIN != EWOULDBLOCK
15022 c = rb_eEWOULDBLOCKWaitReadable;
15026 c = rb_eEINPROGRESSWaitReadable;
15033 rb_bug(
"invalid read/write type passed to rb_readwrite_sys_fail: %d", waiting);
15039get_LAST_READ_LINE(
ID _x,
VALUE *_y)
15929#include <sys/cygwin.h>
15930 static struct __cygwin_perfile pf[] =
15932 {
"", O_RDONLY | O_BINARY},
15933 {
"", O_WRONLY | O_BINARY},
15934 {
"", O_RDWR | O_BINARY},
15935 {
"", O_APPEND | O_BINARY},
15938 cygwin_internal(CW_PERFILE, pf);
15987 rb_eEAGAINWaitReadable = rb_define_class_under(
rb_cIO,
"EAGAINWaitReadable", rb_eEAGAIN);
15990 rb_eEAGAINWaitWritable = rb_define_class_under(
rb_cIO,
"EAGAINWaitWritable", rb_eEAGAIN);
15992#if EAGAIN == EWOULDBLOCK
15994 rb_define_const(
rb_cIO,
"EWOULDBLOCKWaitReadable", rb_eEAGAINWaitReadable);
15996 rb_define_const(
rb_cIO,
"EWOULDBLOCKWaitWritable", rb_eEAGAINWaitWritable);
15999 rb_eEWOULDBLOCKWaitReadable = rb_define_class_under(
rb_cIO,
"EWOULDBLOCKWaitReadable", rb_eEWOULDBLOCK);
16002 rb_eEWOULDBLOCKWaitWritable = rb_define_class_under(
rb_cIO,
"EWOULDBLOCKWaitWritable", rb_eEWOULDBLOCK);
16006 rb_eEINPROGRESSWaitReadable = rb_define_class_under(
rb_cIO,
"EINPROGRESSWaitReadable", rb_eEINPROGRESS);
16009 rb_eEINPROGRESSWaitWritable = rb_define_class_under(
rb_cIO,
"EINPROGRESSWaitWritable", rb_eEINPROGRESS);
16044 rb_gvar_ractor_local(
"$/");
16046 rb_gvar_ractor_local(
"$-0");
16050 rb_gvar_ractor_local(
"$_");
16051 rb_gvar_box_dynamic(
"$_");
16167 rb_gvar_ractor_local(
"$stdin");
16168 rb_gvar_ractor_local(
"$stdout");
16169 rb_gvar_ractor_local(
"$>");
16170 rb_gvar_ractor_local(
"$stderr");
16172 rb_gvar_box_dynamic(
"$stdin");
16173 rb_gvar_box_dynamic(
"$stdout");
16174 rb_gvar_box_dynamic(
"$>");
16175 rb_gvar_box_dynamic(
"$stderr");
16196 rb_cARGF = rb_define_class(
"ARGF",
rb_cObject);
16261 rb_define_method(rb_cARGF,
"external_encoding", argf_external_encoding, 0);
16262 rb_define_method(rb_cARGF,
"internal_encoding", argf_internal_encoding, 0);
16281 rb_gvar_ractor_local(
"$-i");
16285#if defined (_WIN32) || defined(__CYGWIN__)
16286 atexit(pipe_atexit);
16298 sym_encoding =
ID2SYM(rb_id_encoding());
16322static void init_builtin_io(
void);
16323#define Init_builtin_io init_builtin_io
16325#undef Init_builtin_io
16328Init_builtin_io(
void)
#define RUBY_ASSERT(...)
Asserts that the given expression is truthy if and only if RUBY_DEBUG is truthy.
std::atomic< unsigned > rb_atomic_t
Type that is eligible for atomic operations.
unsigned long ruby_strtoul(const char *str, char **endptr, int base)
Our own locale-insensitive version of strtoul(3).
#define rb_define_method(klass, mid, func, arity)
Defines klass#mid.
#define rb_define_singleton_method(klass, mid, func, arity)
Defines klass.mid.
#define rb_define_global_function(mid, func, arity)
Defines rb_mKernel #mid.
void rb_include_module(VALUE klass, VALUE module)
Includes a module to a class.
VALUE rb_class_new(VALUE super)
Creates a new, anonymous class.
void rb_define_alias(VALUE klass, const char *name1, const char *name2)
Defines an alias of a method.
int rb_scan_args_kw(int kw_flag, int argc, const VALUE *argv, const char *fmt,...)
Identical to rb_scan_args(), except it also accepts kw_splat.
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Retrieves argument from argc and argv to given VALUE references according to the format string.
int rb_block_given_p(void)
Determines if the current method is given a block.
int rb_get_kwargs(VALUE keyword_hash, const ID *table, int required, int optional, VALUE *values)
Keyword argument deconstructor.
#define ECONV_AFTER_OUTPUT
Old name of RUBY_ECONV_AFTER_OUTPUT.
#define rb_str_new2
Old name of rb_str_new_cstr.
#define TYPE(_)
Old name of rb_type.
#define RB_INTEGER_TYPE_P
Old name of rb_integer_type_p.
#define ENC_CODERANGE_7BIT
Old name of RUBY_ENC_CODERANGE_7BIT.
#define T_FILE
Old name of RUBY_T_FILE.
#define ENC_CODERANGE_VALID
Old name of RUBY_ENC_CODERANGE_VALID.
#define ECONV_UNIVERSAL_NEWLINE_DECORATOR
Old name of RUBY_ECONV_UNIVERSAL_NEWLINE_DECORATOR.
#define REALLOC_N
Old name of RB_REALLOC_N.
#define OBJ_INIT_COPY(obj, orig)
Old name of RB_OBJ_INIT_COPY.
#define ALLOC
Old name of RB_ALLOC.
#define RFLOAT_VALUE
Old name of rb_float_value.
#define T_STRING
Old name of RUBY_T_STRING.
#define Qundef
Old name of RUBY_Qundef.
#define INT2FIX
Old name of RB_INT2FIX.
#define rb_str_cat2
Old name of rb_str_cat_cstr.
#define T_NIL
Old name of RUBY_T_NIL.
#define UNREACHABLE
Old name of RBIMPL_UNREACHABLE.
#define ID2SYM
Old name of RB_ID2SYM.
#define T_BIGNUM
Old name of RUBY_T_BIGNUM.
#define OBJ_FREEZE
Old name of RB_OBJ_FREEZE.
#define T_FIXNUM
Old name of RUBY_T_FIXNUM.
#define UNREACHABLE_RETURN
Old name of RBIMPL_UNREACHABLE_RETURN.
#define FIX2UINT
Old name of RB_FIX2UINT.
#define SSIZET2NUM
Old name of RB_SSIZE2NUM.
#define ZALLOC
Old name of RB_ZALLOC.
#define CLASS_OF
Old name of rb_class_of.
#define rb_ary_new4
Old name of rb_ary_new_from_values.
#define ENCODING_MAXNAMELEN
Old name of RUBY_ENCODING_MAXNAMELEN.
#define MBCLEN_NEEDMORE_LEN(ret)
Old name of ONIGENC_MBCLEN_NEEDMORE_LEN.
#define ENCODING_GET(obj)
Old name of RB_ENCODING_GET.
#define LONG2FIX
Old name of RB_INT2FIX.
#define NUM2UINT
Old name of RB_NUM2UINT.
#define ALLOC_N
Old name of RB_ALLOC_N.
#define MBCLEN_CHARFOUND_LEN(ret)
Old name of ONIGENC_MBCLEN_CHARFOUND_LEN.
#define LONG2NUM
Old name of RB_LONG2NUM.
#define rb_exc_new3
Old name of rb_exc_new_str.
#define STRNCASECMP
Old name of st_locale_insensitive_strncasecmp.
#define MBCLEN_INVALID_P(ret)
Old name of ONIGENC_MBCLEN_INVALID_P.
#define ISASCII
Old name of rb_isascii.
#define ECONV_STATEFUL_DECORATOR_MASK
Old name of RUBY_ECONV_STATEFUL_DECORATOR_MASK.
#define Qtrue
Old name of RUBY_Qtrue.
#define MBCLEN_NEEDMORE_P(ret)
Old name of ONIGENC_MBCLEN_NEEDMORE_P.
#define ECONV_PARTIAL_INPUT
Old name of RUBY_ECONV_PARTIAL_INPUT.
#define NUM2INT
Old name of RB_NUM2INT.
#define ECONV_ERROR_HANDLER_MASK
Old name of RUBY_ECONV_ERROR_HANDLER_MASK.
#define INT2NUM
Old name of RB_INT2NUM.
#define Qnil
Old name of RUBY_Qnil.
#define Qfalse
Old name of RUBY_Qfalse.
#define FIX2LONG
Old name of RB_FIX2LONG.
#define ENC_CODERANGE_BROKEN
Old name of RUBY_ENC_CODERANGE_BROKEN.
#define T_ARRAY
Old name of RUBY_T_ARRAY.
#define NIL_P
Old name of RB_NIL_P.
#define ALLOCV_N
Old name of RB_ALLOCV_N.
#define MBCLEN_CHARFOUND_P(ret)
Old name of ONIGENC_MBCLEN_CHARFOUND_P.
#define NUM2CHR
Old name of RB_NUM2CHR.
#define NUM2LONG
Old name of RB_NUM2LONG.
#define UINT2NUM
Old name of RB_UINT2NUM.
#define FIXNUM_P
Old name of RB_FIXNUM_P.
#define ECONV_NEWLINE_DECORATOR_MASK
Old name of RUBY_ECONV_NEWLINE_DECORATOR_MASK.
#define CONST_ID
Old name of RUBY_CONST_ID.
#define rb_ary_new2
Old name of rb_ary_new_capa.
#define NUM2SIZET
Old name of RB_NUM2SIZE.
#define ENC_CODERANGE_SET(obj, cr)
Old name of RB_ENC_CODERANGE_SET.
#define rb_str_new4
Old name of rb_str_new_frozen.
#define ALLOCV_END
Old name of RB_ALLOCV_END.
#define SYMBOL_P
Old name of RB_SYMBOL_P.
#define ECONV_DEFAULT_NEWLINE_DECORATOR
Old name of RUBY_ECONV_DEFAULT_NEWLINE_DECORATOR.
void rb_category_warn(rb_warning_category_t category, const char *fmt,...)
Identical to rb_category_warning(), except it reports unless $VERBOSE is nil.
void rb_category_warning(rb_warning_category_t category, const char *fmt,...)
Identical to rb_warning(), except it takes additional "category" parameter.
VALUE rb_eNotImpError
NotImplementedError exception.
void rb_exc_raise(VALUE mesg)
Raises an exception in the current thread.
void rb_syserr_fail(int e, const char *mesg)
Raises appropriate exception that represents a C errno.
void rb_readwrite_syserr_fail(enum rb_io_wait_readwrite waiting, int n, const char *mesg)
Identical to rb_readwrite_sys_fail(), except it does not depend on C global variable errno.
VALUE rb_eIOError
IOError exception.
VALUE rb_eStandardError
StandardError exception.
void rb_mod_syserr_fail_str(VALUE mod, int e, VALUE mesg)
Identical to rb_mod_syserr_fail(), except it takes the message in Ruby's String instead of C's.
void rb_syserr_fail_str(int e, VALUE mesg)
Identical to rb_syserr_fail(), except it takes the message in Ruby's String instead of C's.
#define ruby_verbose
This variable controls whether the interpreter is in debug mode.
VALUE rb_eTypeError
TypeError exception.
VALUE rb_eEOFError
EOFError exception.
void rb_readwrite_sys_fail(enum rb_io_wait_readwrite waiting, const char *mesg)
Raises appropriate exception using the parameters.
void rb_iter_break_value(VALUE val)
Identical to rb_iter_break(), except it additionally takes the "value" of this breakage.
rb_io_wait_readwrite
for rb_readwrite_sys_fail first argument
VALUE rb_eRuntimeError
RuntimeError exception.
void rb_warn(const char *fmt,...)
Identical to rb_warning(), except it reports unless $VERBOSE is nil.
VALUE rb_eSystemCallError
SystemCallError exception.
@ RB_WARN_CATEGORY_DEPRECATED
Warning is for deprecated features.
VALUE rb_mKernel
Kernel module.
VALUE rb_check_to_int(VALUE val)
Identical to rb_check_to_integer(), except it uses #to_int for conversion.
VALUE rb_cObject
Object class.
VALUE rb_any_to_s(VALUE obj)
Generates a textual representation of the given object.
VALUE rb_obj_alloc(VALUE klass)
Allocates an instance of the given class.
VALUE rb_class_new_instance(int argc, const VALUE *argv, VALUE klass)
Allocates, then initialises an instance of the given class.
VALUE rb_class_new_instance_kw(int argc, const VALUE *argv, VALUE klass, int kw_splat)
Identical to rb_class_new_instance(), except you can specify how to handle the last element of the gi...
VALUE rb_mEnumerable
Enumerable module.
VALUE rb_stdin
STDIN constant.
VALUE rb_stderr
STDERR constant.
VALUE rb_obj_class(VALUE obj)
Queries the class of an object.
VALUE rb_obj_dup(VALUE obj)
Duplicates the given object.
VALUE rb_inspect(VALUE obj)
Generates a human-readable textual representation of the given object.
VALUE rb_mWaitReadable
IO::WaitReadable module.
VALUE rb_mWaitWritable
IO::WaitReadable module.
VALUE rb_obj_freeze(VALUE obj)
Same as RB_OBJ_FREEZE(), but returns the given object.
VALUE rb_check_to_integer(VALUE val, const char *mid)
Identical to rb_check_convert_type(), except the return value type is fixed to rb_cInteger.
VALUE rb_cFile
File class.
VALUE rb_stdout
STDOUT constant.
VALUE rb_to_int(VALUE val)
Identical to rb_check_to_int(), except it raises in case of conversion mismatch.
#define RB_OBJ_WRITTEN(old, oldv, young)
Identical to RB_OBJ_WRITE(), except it doesn't write any values, but only a WB declaration.
#define RB_OBJ_WRITE(old, slot, young)
Declaration of a "back" pointer.
VALUE rb_fiber_scheduler_current(void)
Identical to rb_fiber_scheduler_get(), except it also returns RUBY_Qnil in case of a blocking fiber.
VALUE rb_fiber_scheduler_make_timeout(struct timeval *timeout)
Converts the passed timeout to an expression that rb_fiber_scheduler_block() etc.
VALUE rb_fiber_scheduler_io_wait_readable(VALUE scheduler, VALUE io)
Non-blocking wait until the passed IO is ready for reading.
VALUE rb_fiber_scheduler_io_wait(VALUE scheduler, VALUE io, VALUE events, VALUE timeout)
Non-blocking version of rb_io_wait().
static ssize_t rb_fiber_scheduler_io_result_apply(VALUE result)
Apply an io result to the local thread, returning the value of the original system call that created ...
VALUE rb_fiber_scheduler_io_pread_memory(VALUE scheduler, VALUE io, rb_off_t from, void *base, size_t size)
Non-blocking pread from the passed IO using a native buffer.
VALUE rb_fiber_scheduler_io_selectv(VALUE scheduler, int argc, VALUE *argv)
Non-blocking version of IO.select, argv variant.
VALUE rb_fiber_scheduler_io_read_memory(VALUE scheduler, VALUE io, void *base, size_t size)
Non-blocking read from the passed IO using a native buffer.
VALUE rb_fiber_scheduler_current_for_thread(VALUE thread)
Identical to rb_fiber_scheduler_current(), except it queries for that of the passed thread value inst...
VALUE rb_fiber_scheduler_io_pwrite_memory(VALUE scheduler, VALUE io, rb_off_t from, const void *base, size_t size)
Non-blocking pwrite to the passed IO using a native buffer.
VALUE rb_fiber_scheduler_current_for_threadptr(struct rb_thread_struct *thread)
Identical to rb_fiber_scheduler_current_for_thread(), except it expects a threadptr instead of a thre...
VALUE rb_fiber_scheduler_io_wait_writable(VALUE scheduler, VALUE io)
Non-blocking wait until the passed IO is ready for writing.
VALUE rb_fiber_scheduler_io_close(VALUE scheduler, VALUE io)
Non-blocking close the given IO.
VALUE rb_fiber_scheduler_io_write_memory(VALUE scheduler, VALUE io, const void *base, size_t size)
Non-blocking write to the passed IO using a native buffer.
static unsigned int rb_enc_codepoint(const char *p, const char *e, rb_encoding *enc)
Queries the code point of character pointed by the passed pointer.
static int rb_enc_mbmaxlen(rb_encoding *enc)
Queries the maximum number of bytes that the passed encoding needs to represent a character.
VALUE rb_str_conv_enc(VALUE str, rb_encoding *from, rb_encoding *to)
Encoding conversion main routine.
VALUE rb_enc_uint_chr(unsigned int code, rb_encoding *enc)
Encodes the passed code point into a series of bytes.
long rb_str_coderange_scan_restartable(const char *str, const char *end, rb_encoding *enc, int *cr)
Scans the passed string until it finds something odd.
int rb_econv_prepare_options(VALUE opthash, VALUE *ecopts, int ecflags)
Identical to rb_econv_prepare_opts(), except it additionally takes the initial value of flags.
VALUE rb_econv_open_exc(const char *senc, const char *denc, int ecflags)
Creates a rb_eConverterNotFoundError exception object (but does not raise).
rb_econv_result_t rb_econv_convert(rb_econv_t *ec, const unsigned char **source_buffer_ptr, const unsigned char *source_buffer_end, unsigned char **destination_buffer_ptr, unsigned char *destination_buffer_end, int flags)
Converts a string from an encoding to another.
rb_econv_result_t
return value of rb_econv_convert()
@ econv_incomplete_input
The conversion stopped in middle of reading a character, possibly due to a partial read of a socket e...
@ econv_finished
The conversion stopped after converting everything.
@ econv_undefined_conversion
The conversion stopped when it found a character in the input which cannot be representable in the ou...
@ econv_source_buffer_empty
The conversion stopped because there is no input.
@ econv_destination_buffer_full
The conversion stopped because there is no destination.
@ econv_invalid_byte_sequence
The conversion stopped when it found an invalid sequence.
int rb_econv_putbackable(rb_econv_t *ec)
Queries if rb_econv_putback() makes sense, i.e.
const char * rb_econv_asciicompat_encoding(const char *encname)
Queries the passed encoding's corresponding ASCII compatible encoding.
VALUE rb_econv_str_convert(rb_econv_t *ec, VALUE src, int flags)
Identical to rb_econv_convert(), except it takes Ruby's string instead of C's pointer.
rb_econv_t * rb_econv_open_opts(const char *source_encoding, const char *destination_encoding, int ecflags, VALUE ecopts)
Identical to rb_econv_open(), except it additionally takes a hash of optional strings.
void rb_econv_binmode(rb_econv_t *ec)
This badly named function does not set the destination encoding to binary, but instead just nullifies...
VALUE rb_str_encode(VALUE str, VALUE to, int ecflags, VALUE ecopts)
Converts the contents of the passed string from its encoding to the passed one.
VALUE rb_econv_make_exception(rb_econv_t *ec)
This function makes sense right after rb_econv_convert() returns.
void rb_econv_check_error(rb_econv_t *ec)
This is a rb_econv_make_exception() + rb_exc_raise() combo.
void rb_econv_close(rb_econv_t *ec)
Destructs a converter.
void rb_econv_putback(rb_econv_t *ec, unsigned char *p, int n)
Puts back the bytes.
VALUE rb_funcall(VALUE recv, ID mid, int n,...)
Calls a method.
VALUE rb_funcallv_kw(VALUE recv, ID mid, int argc, const VALUE *argv, int kw_splat)
Identical to rb_funcallv(), except you can specify how to handle the last element of the given array.
VALUE rb_funcallv(VALUE recv, ID mid, int argc, const VALUE *argv)
Identical to rb_funcall(), except it takes the method arguments as a C array.
Defines RBIMPL_HAS_BUILTIN.
VALUE rb_ary_concat(VALUE lhs, VALUE rhs)
Destructively appends the contents of latter into the end of former.
VALUE rb_ary_shift(VALUE ary)
Destructively deletes an element from the beginning of the passed array and returns what was deleted.
VALUE rb_check_array_type(VALUE obj)
Try converting an object to its array representation using its to_ary method, if any.
VALUE rb_ary_new(void)
Allocates a new, empty array.
VALUE rb_ary_new_capa(long capa)
Identical to rb_ary_new(), except it additionally specifies how many rooms of objects it should alloc...
VALUE rb_ary_push(VALUE ary, VALUE elem)
Special case of rb_ary_cat() that it adds only one element.
VALUE rb_ary_entry(VALUE ary, long off)
Queries an element of an array.
VALUE rb_assoc_new(VALUE car, VALUE cdr)
Identical to rb_ary_new_from_values(), except it expects exactly two parameters.
#define RETURN_ENUMERATOR(obj, argc, argv)
Identical to RETURN_SIZED_ENUMERATOR(), except its size is unknown.
static int rb_check_arity(int argc, int min, int max)
Ensures that the passed integer is in the passed range.
VALUE rb_io_printf(int argc, const VALUE *argv, VALUE io)
This is a rb_f_sprintf() + rb_io_write() combo.
VALUE rb_io_gets(VALUE io)
Reads a "line" from the given IO.
int rb_cloexec_pipe(int fildes[2])
Opens a pipe with closing on exec.
VALUE rb_io_print(int argc, const VALUE *argv, VALUE io)
Iterates over the passed array to apply rb_io_write() individually.
VALUE rb_io_addstr(VALUE io, VALUE str)
Identical to rb_io_write(), except it always returns the passed IO.
void rb_write_error(const char *str)
Writes the given error message to somewhere applicable.
VALUE rb_io_ungetbyte(VALUE io, VALUE b)
Identical to rb_io_ungetc(), except it doesn't take the encoding of the passed IO into account.
VALUE rb_io_getbyte(VALUE io)
Reads a byte from the given IO.
int rb_cloexec_dup2(int oldfd, int newfd)
Identical to rb_cloexec_dup(), except you can specify the destination file descriptor.
VALUE rb_io_fdopen(int fd, int flags, const char *path)
Creates an IO instance whose backend is the given file descriptor.
void rb_update_max_fd(int fd)
Informs the interpreter that the passed fd can be the max.
int rb_cloexec_open(const char *pathname, int flags, mode_t mode)
Opens a file that closes on exec.
VALUE rb_output_rs
The record separator character for outputs, or the $\.
VALUE rb_io_eof(VALUE io)
Queries if the passed IO is at the end of file.
void rb_write_error2(const char *str, long len)
Identical to rb_write_error(), except it additionally takes the message's length.
void rb_close_before_exec(int lowfd, int maxhint, VALUE noclose_fds)
Closes everything.
int rb_reserved_fd_p(int fd)
Queries if the given FD is reserved or not.
void rb_fd_fix_cloexec(int fd)
Sets or clears the close-on-exec flag of the passed file descriptor to the desired state.
VALUE rb_io_ascii8bit_binmode(VALUE io)
Forces no conversions be applied to the passed IO.
VALUE rb_io_binmode(VALUE io)
Sets the binmode.
VALUE rb_io_ungetc(VALUE io, VALUE c)
"Unget"s a string.
int rb_pipe(int *pipes)
This is an rb_cloexec_pipe() + rb_update_max_fd() combo.
VALUE rb_gets(void)
Much like rb_io_gets(), but it reads from the mysterious ARGF object.
int rb_cloexec_fcntl_dupfd(int fd, int minfd)
Duplicates a file descriptor with closing on exec.
VALUE rb_output_fs
The field separator character for outputs, or the $,.
VALUE rb_file_open_str(VALUE fname, const char *fmode)
Identical to rb_file_open(), except it takes the pathname as a Ruby's string instead of C's.
int rb_cloexec_dup(int oldfd)
Identical to rb_cloexec_fcntl_dupfd(), except it implies minfd is 3.
VALUE rb_file_open(const char *fname, const char *fmode)
Opens a file located at the given path.
VALUE rb_io_close(VALUE io)
Closes the IO.
VALUE rb_default_rs
This is the default value of rb_rs, i.e.
void rb_provide(const char *feature)
Declares that the given feature is already provided by someone else.
void rb_lastline_set(VALUE str)
Updates $_.
VALUE rb_lastline_get(void)
Queries the last line, or the $_.
int rb_obj_method_arity(VALUE obj, ID mid)
Identical to rb_mod_method_arity(), except it searches for singleton methods rather than instance met...
rb_pid_t rb_waitpid(rb_pid_t pid, int *status, int flags)
Waits for a process, with releasing GVL.
void rb_last_status_set(int status, rb_pid_t pid)
Sets the "last status", or the $?.
VALUE rb_str_append(VALUE dst, VALUE src)
Identical to rb_str_buf_append(), except it converts the right hand side before concatenating.
#define rb_str_new(str, len)
Allocates an instance of rb_cString.
#define rb_str_buf_cat
Just another name of rb_str_cat.
#define rb_usascii_str_new(str, len)
Identical to rb_str_new, except it generates a string of "US ASCII" encoding.
size_t rb_str_capacity(VALUE str)
Queries the capacity of the given string.
VALUE rb_str_new_frozen(VALUE str)
Creates a frozen copy of the string, if necessary.
VALUE rb_str_dup(VALUE str)
Duplicates a string.
VALUE rb_str_cat(VALUE dst, const char *src, long srclen)
Destructively appends the passed contents to the string.
VALUE rb_str_locktmp(VALUE str)
Obtains a "temporary lock" of the string.
VALUE rb_str_no_gvl_safe_acquire(VALUE orig)
Creates a frozen copy of orig that guarantees the RSTRING_PTR is safe to use in operations that relea...
VALUE rb_str_equal(VALUE str1, VALUE str2)
Equality of two strings.
void rb_str_no_gvl_safe_release(VALUE orig, VALUE tmp)
Releases a string created from rb_str_no_gvl_safe_acquire.
void rb_str_set_len(VALUE str, long len)
Overwrites the length of the string.
VALUE rb_str_buf_cat_ascii(VALUE dst, const char *src)
Identical to rb_str_cat_cstr(), except it additionally assumes the source string be a NUL terminated ...
VALUE rb_check_string_type(VALUE obj)
Try converting an object to its stringised representation using its to_str method,...
VALUE rb_str_substr(VALUE str, long beg, long len)
This is the implementation of two-argumented String#slice.
VALUE rb_str_unlocktmp(VALUE str)
Releases a lock formerly obtained by rb_str_locktmp().
void rb_str_modify_expand(VALUE str, long capa)
Identical to rb_str_modify(), except it additionally expands the capacity of the receiver.
VALUE rb_str_buf_new(long capa)
Allocates a "string buffer".
#define rb_str_new_cstr(str)
Identical to rb_str_new, except it assumes the passed pointer is a pointer to a C string.
VALUE rb_obj_as_string(VALUE obj)
Try converting an object to its stringised representation using its to_s method, if any.
int rb_thread_interrupted(VALUE thval)
Checks if the thread's execution was recently interrupted.
VALUE rb_mutex_new(void)
Creates a mutex.
int rb_thread_fd_writable(int fd)
Identical to rb_thread_wait_fd(), except it blocks the current thread until the given file descriptor...
VALUE rb_exec_recursive(VALUE(*f)(VALUE g, VALUE h, int r), VALUE g, VALUE h)
"Recursion" API entry point.
VALUE rb_mutex_synchronize(VALUE mutex, VALUE(*func)(VALUE arg), VALUE arg)
Obtains the lock, runs the passed function, and releases the lock when it completes.
void rb_thread_check_ints(void)
Checks for interrupts.
VALUE rb_thread_current(void)
Obtains the "current" thread.
int rb_thread_wait_fd(int fd)
Blocks the current thread until the given file descriptor is ready to be read.
void rb_thread_sleep(int sec)
Blocks for the given period of time.
struct timeval rb_time_interval(VALUE num)
Creates a "time interval".
void rb_set_class_path(VALUE klass, VALUE space, const char *name)
Names a class.
VALUE rb_ivar_set(VALUE obj, ID name, VALUE val)
Identical to rb_iv_set(), except it accepts the name as an ID instead of a C string.
VALUE rb_class_name(VALUE obj)
Queries the name of the given object's class.
int rb_respond_to(VALUE obj, ID mid)
Queries if the object responds to the method.
int rb_method_basic_definition_p(VALUE klass, ID mid)
Well... Let us hesitate from describing what a "basic definition" is.
VALUE rb_check_funcall(VALUE recv, ID mid, int argc, const VALUE *argv)
Identical to rb_funcallv(), except it returns RUBY_Qundef instead of raising rb_eNoMethodError.
void rb_define_alloc_func(VALUE klass, rb_alloc_func_t func)
Sets the allocator function of a class.
static ID rb_intern_const(const char *str)
This is a "tiny optimisation" over rb_intern().
#define RB_ID2SYM
Just another name of rb_id2sym.
void rb_define_global_const(const char *name, VALUE val)
Identical to rb_define_const(), except it defines that of "global", i.e.
void rb_define_readonly_variable(const char *name, const VALUE *var)
Identical to rb_define_variable(), except it does not allow Ruby programs to assign values to such gl...
rb_gvar_setter_t rb_gvar_readonly_setter
This function just raises rb_eNameError.
#define FMODE_READABLE
The IO is opened for reading.
enum rb_io_mode rb_io_modestr_fmode(const char *modestr)
Maps a file mode string (that rb_file_open() takes) into a mixture of FMODE_ flags.
VALUE rb_io_get_io(VALUE io)
Identical to rb_io_check_io(), except it raises exceptions on conversion failures.
VALUE rb_io_timeout(VALUE io)
Get the timeout associated with the specified io object.
VALUE rb_io_taint_check(VALUE obj)
void rb_io_read_check(rb_io_t *fptr)
Blocks until there is a pending read in the passed IO.
int rb_io_modestr_oflags(const char *modestr)
Identical to rb_io_modestr_fmode(), except it returns a mixture of O_ flags.
#define FMODE_SETENC_BY_BOM
This flag amends the encoding of the IO so that the BOM of the contents of the IO takes effect.
rb_io_event
Type of events that an IO can wait.
@ RUBY_IO_READABLE
IO::READABLE
@ RUBY_IO_PRIORITY
IO::PRIORITY
@ RUBY_IO_WRITABLE
IO::WRITABLE
#define FMODE_READWRITE
The IO is opened for both read/write.
#define FMODE_EXTERNAL
This flag means that an IO object is wrapping an "external" file descriptor, which is owned by someth...
#define GetOpenFile
This is an old name of RB_IO_POINTER.
void rb_io_check_byte_readable(rb_io_t *fptr)
Asserts that an IO is opened for byte-based reading.
#define FMODE_TTY
The IO is a TTY.
#define FMODE_CREATE
The IO is opened for creating.
void rb_io_check_readable(rb_io_t *fptr)
Just another name of rb_io_check_byte_readable.
int rb_wait_for_single_fd(int fd, int events, struct timeval *tv)
Blocks until the passed file descriptor is ready for the passed events.
FILE * rb_fdopen(int fd, const char *modestr)
Identical to rb_io_stdio_file(), except it takes file descriptors instead of Ruby's IO.
int rb_io_extract_encoding_option(VALUE opt, rb_encoding **enc_p, rb_encoding **enc2_p, enum rb_io_mode *fmode_p)
This function breaks down the option hash that IO#initialize takes into components.
int rb_io_descriptor(VALUE io)
Returns an integer representing the numeric file descriptor for io.
#define FMODE_WRITABLE
The IO is opened for writing.
FILE * rb_io_stdio_file(rb_io_t *fptr)
Finds or creates a stdio's file structure from a Ruby's one.
#define FMODE_APPEND
The IO is opened for appending.
#define MakeOpenFile
This is an old name of RB_IO_OPEN.
#define FMODE_DUPLEX
Ruby eventually detects that the IO is bidirectional.
#define FMODE_BINMODE
The IO is in "binary mode".
int rb_io_maybe_wait_readable(int error, VALUE io, VALUE timeout)
Blocks until the passed IO is ready for reading, if that makes sense for the passed errno.
int capa
Designed capacity of the buffer.
#define RB_IO_POINTER(obj, fp)
Queries the underlying IO pointer.
VALUE rb_io_maybe_wait(int error, VALUE io, VALUE events, VALUE timeout)
Identical to rb_io_wait() except it additionally takes previous errno.
VALUE rb_eIOTimeoutError
Indicates that a timeout has occurred while performing an IO operation.
char * ptr
Pointer to the underlying memory region, of at least capa bytes.
#define FMODE_SYNC
The IO is in "sync mode".
int off
Offset inside of ptr.
VALUE rb_io_path(VALUE io)
Returns the path for the given IO.
void rb_io_extract_modeenc(VALUE *vmode_p, VALUE *vperm_p, VALUE opthash, int *oflags_p, enum rb_io_mode *fmode_p, rb_io_enc_t *convconfig_p)
This function can be seen as an extended version of rb_io_extract_encoding_option() that not only con...
void rb_io_check_initialized(rb_io_t *fptr)
Asserts that the passed IO is initialised.
#define FMODE_EXCL
This flag amends the effect of FMODE_CREATE, so that if there already is a file at the given path the...
#define FMODE_TEXTMODE
The IO is in "text mode".
int rb_io_fptr_finalize(rb_io_t *fptr)
Destroys the given IO.
VALUE rb_io_check_io(VALUE io)
Try converting an object to its IO representation using its to_io method, if any.
VALUE rb_io_closed_p(VALUE io)
Returns whether or not the underlying IO is closed.
VALUE rb_io_set_timeout(VALUE io, VALUE timeout)
Set the timeout associated with the specified io object.
ssize_t rb_io_bufwrite(VALUE io, const void *buf, size_t size)
Buffered write to the passed IO.
void rb_io_check_char_readable(rb_io_t *fptr)
Asserts that an IO is opened for character-based reading.
#define FMODE_TRUNC
This flag amends the effect of FMODE_CREATE, so that if there already is a file at the given path it ...
VALUE rb_io_get_write_io(VALUE io)
Queries the tied IO for writing.
void rb_io_set_nonblock(rb_io_t *fptr)
Instructs the OS to put its internal file structure into "nonblocking mode".
int rb_io_wait_writable(int fd)
Blocks until the passed file descriptor gets writable.
VALUE rb_io_open_descriptor(VALUE klass, int descriptor, int mode, VALUE path, VALUE timeout, struct rb_io_encoding *encoding)
Allocate a new IO object, with the given file descriptor.
VALUE rb_io_set_write_io(VALUE io, VALUE w)
Assigns the tied IO for writing.
void rb_io_check_writable(rb_io_t *fptr)
Asserts that an IO is opened for writing.
int rb_io_maybe_wait_writable(int error, VALUE io, VALUE timeout)
Blocks until the passed IO is ready for writing, if that makes sense for the passed errno.
void rb_io_check_closed(rb_io_t *fptr)
This badly named function asserts that the passed IO is open.
int rb_io_wait_readable(int fd)
Blocks until the passed file descriptor gets readable.
void rb_io_synchronized(rb_io_t *fptr)
Sets FMODE_SYNC.
VALUE rb_io_wait(VALUE io, VALUE events, VALUE timeout)
Blocks until the passed IO is ready for the passed events.
int len
Length of the buffer.
VALUE rb_ractor_stdin(void)
Queries the standard input of the current Ractor that is calling this function.
void rb_ractor_stderr_set(VALUE io)
Assigns an IO to the standard error of the Ractor that is calling this function.
void rb_ractor_stdout_set(VALUE io)
Assigns an IO to the standard output of the Ractor that is calling this function.
void rb_ractor_stdin_set(VALUE io)
Assigns an IO to the standard input of the Ractor that is calling this function.
void * rb_thread_call_with_gvl(void *(*func)(void *), void *data1)
(Re-)acquires the GVL.
#define RB_NUM2INT
Just another name of rb_num2int_inline.
#define RB_INT2NUM
Just another name of rb_int2num_inline.
VALUE rb_f_sprintf(int argc, const VALUE *argv)
Identical to rb_str_format(), except how the arguments are arranged.
#define RB_BLOCK_CALL_FUNC_ARGLIST(yielded_arg, callback_arg)
Shim for block function parameters.
VALUE rb_yield_values2(int n, const VALUE *argv)
Identical to rb_yield_values(), except it takes the parameters as a C array instead of variadic argum...
VALUE rb_yield(VALUE val)
Yields the block.
void rb_fd_term(rb_fdset_t *f)
Destroys the rb_fdset_t, releasing any memory and resources it used.
#define MEMZERO(p, type, n)
Handy macro to erase a region of memory.
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
#define MEMMOVE(p1, p2, type, n)
Handy macro to call memmove.
#define NUM2MODET
Converts a C's mode_t into an instance of rb_cInteger.
void rb_define_hooked_variable(const char *q, VALUE *w, type *e, void_type *r)
Define a function-backended global variable.
void rb_define_virtual_variable(const char *q, type *w, void_type *e)
Define a function-backended global variable.
VALUE rb_rescue2(type *q, VALUE w, type *e, VALUE r,...)
An equivalent of rescue clause.
VALUE rb_ensure(type *q, VALUE w, type *e, VALUE r)
An equivalent of ensure clause.
#define PRI_OFFT_PREFIX
A rb_sprintf() format prefix to be used for an off_t parameter.
#define OFFT2NUM
Converts a C's off_t into an instance of rb_cInteger.
#define NUM2OFFT
Converts an instance of rb_cNumeric into C's off_t.
#define PIDT2NUM
Converts a C's pid_t into an instance of rb_cInteger.
#define rb_fd_isset
Queries if the given fd is in the rb_fdset_t.
#define rb_fd_select
Waits for multiple file descriptors at once.
#define rb_fd_init
Initialises the :given :rb_fdset_t.
#define rb_fd_set
Sets the given fd to the rb_fdset_t.
#define RARRAY_LEN
Just another name of rb_array_len.
static int RARRAY_LENINT(VALUE ary)
Identical to rb_array_len(), except it differs for the return type.
#define RARRAY_AREF(a, i)
#define RARRAY_CONST_PTR
Just another name of rb_array_const_ptr.
#define RFILE(obj)
Convenient casting macro.
#define StringValue(v)
Ensures that the parameter object is a String.
static char * RSTRING_END(VALUE str)
Queries the end of the contents pointer of the string.
#define RSTRING_GETMEM(str, ptrvar, lenvar)
Convenient macro to obtain the contents and length at once.
#define StringValueCStr(v)
Identical to StringValuePtr, except it additionally checks for the contents for viability as a C stri...
#define RUBY_TYPED_DEFAULT_FREE
This is a value you can set to rb_data_type_struct::dfree.
#define TypedData_Make_Struct(klass, type, data_type, sval)
Identical to TypedData_Wrap_Struct, except it allocates a new data region internally instead of takin...
VALUE rb_get_argv(void)
Queries the arguments passed to the current process that you can access from Ruby as ARGV.
void rb_p(VALUE obj)
Inspects an object.
#define FilePathValue(v)
Ensures that the parameter object is a path.
#define errno
Ractor-aware version of errno.
#define RB_SCAN_ARGS_LAST_HASH_KEYWORDS
Treat a final argument as keywords if it is a hash, and not as keywords otherwise.
#define RB_PASS_CALLED_KEYWORDS
Pass keywords if current method is called with keywords, useful for argument delegation.
int rb_thread_fd_select(int nfds, rb_fdset_t *rfds, rb_fdset_t *wfds, rb_fdset_t *efds, struct timeval *timeout)
Waits for multiple file descriptors at once.
static bool RB_TEST(VALUE obj)
Emulates Ruby's "if" statement.
#define RTEST
This is an old name of RB_TEST.
#define _(args)
This was a transition path from K&R to ANSI.
This is the struct that holds necessary info for a struct.
The data structure which wraps the fd_set bitmap used by select(2).
Decomposed encoding flags (e.g.
VALUE ecopts
Flags as Ruby hash.
rb_encoding * enc2
External encoding.
rb_encoding * enc
Internal encoding.
char * ptr
Pointer to the underlying memory region, of at least capa bytes.
int off
Offset inside of ptr.
int len
Length of the buffer.
int capa
Designed capacity of the buffer.
Ruby's IO, metadata and buffers.
rb_io_buffer_t wbuf
Write buffer.
enum rb_io_mode mode
mode flags: FMODE_XXXs
void(* finalize)(struct rb_io *, int)
finalize proc
rb_econv_t * readconv
Encoding converter used when reading from this IO.
rb_econv_t * writeconv
Encoding converter used when writing to this IO.
struct rb_io_encoding encs
Decomposed encoding flags.
VALUE self
The IO's Ruby level counterpart.
VALUE write_lock
This is a Ruby level mutex.
VALUE timeout
The timeout associated with this IO when performing blocking operations.
FILE * stdio_file
stdio ptr for read/write, if available.
VALUE writeconv_pre_ecopts
Value of ::rb_io_t::rb_io_enc_t::ecopts stored right before initialising rb_io_t::writeconv.
VALUE tied_io_for_writing
Duplex IO object, if set.
int writeconv_initialized
Whether rb_io_t::writeconv is already set up.
rb_io_buffer_t rbuf
(Byte) read buffer.
int lineno
number of lines read
struct ccan_list_head blocking_operations
Threads that are performing a blocking operation without the GVL using this IO.
VALUE writeconv_asciicompat
This is, when set, an instance of rb_cString which holds the "common" encoding.
rb_io_buffer_t cbuf
rb_io_ungetc() destination.
rb_pid_t pid
child's pid (for pipes)
int writeconv_pre_ecflags
Value of ::rb_io_t::rb_io_enc_t::ecflags stored right before initialising rb_io_t::writeconv.
VALUE pathv
pathname for file
intptr_t SIGNED_VALUE
A signed integer type that has the same width with VALUE.
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
uintptr_t VALUE
Type that represents a Ruby object.
static bool RB_FLOAT_TYPE_P(VALUE obj)
Queries if the object is an instance of rb_cFloat.
static bool RB_SYMBOL_P(VALUE obj)
Queries if the object is an instance of rb_cSymbol.
static void Check_Type(VALUE v, enum ruby_value_type t)
Identical to RB_TYPE_P(), except it raises exceptions on predication failure.
static bool RB_TYPE_P(VALUE obj, enum ruby_value_type t)
Queries if the given object is of given type.
#define RBIMPL_WARNING_IGNORED(flag)
Suppresses a warning.
#define RBIMPL_WARNING_PUSH()
Pushes compiler warning state.
#define RBIMPL_WARNING_POP()
Pops compiler warning state.