14#include "ruby/internal/config.h"
25# if defined(__linux__)
28# if defined(__FreeBSD_version) && __FreeBSD_version >= 1100000
38#define free(x) xfree(x)
40#if defined(DOSISH) || defined(__CYGWIN__)
45#if defined HAVE_NET_SOCKET_H
46# include <net/socket.h>
47#elif defined HAVE_SYS_SOCKET_H
48# include <sys/socket.h>
51#if defined(__BOW__) || defined(__CYGWIN__) || defined(_WIN32)
52# define NO_SAFE_RENAME
55#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__sun) || defined(_nec_ews)
64#if defined(HAVE_SYS_IOCTL_H) && !defined(_WIN32)
67#if defined(HAVE_FCNTL_H) || defined(_WIN32)
69#elif defined(HAVE_SYS_FCNTL_H)
79#if defined(HAVE_SYS_PARAM_H) || defined(__HIUX_MPP__)
80# include <sys/param.h>
93#elif defined HAVE_SYS_SYSCALL_H
94#include <sys/syscall.h>
101#ifdef HAVE_SYS_WAIT_H
102# include <sys/wait.h>
105#ifdef HAVE_COPYFILE_H
106# include <copyfile.h>
108# ifndef COPYFILE_STATE_COPIED
114# undef HAVE_FCOPYFILE
120#include "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;
196static VALUE rb_eEWOULDBLOCKWaitReadable;
197static VALUE rb_eEWOULDBLOCKWaitWritable;
198static VALUE rb_eEINPROGRESSWaitWritable;
199static VALUE rb_eEINPROGRESSWaitReadable;
202static VALUE orig_stdout, orig_stderr;
211static ID id_write, id_read, id_getc, id_flush, id_readpartial, id_set_encoding, id_fileno;
212static VALUE sym_mode, sym_perm, sym_flags, sym_extenc, sym_intenc, sym_encoding, sym_open_args;
213static VALUE sym_textmode, sym_binmode, sym_autoclose;
214static VALUE sym_SET, sym_CUR, sym_END;
215static VALUE sym_wait_readable, sym_wait_writable;
217static VALUE sym_DATA;
220static VALUE sym_HOLE;
223static VALUE prep_io(
int fd,
enum rb_io_mode fmode,
VALUE klass,
const char *path);
226rb_io_blocking_region_wait(
struct rb_io *io, rb_blocking_function_t *function,
void *argument,
enum rb_io_event events)
228 return rb_thread_io_blocking_call(io, function, argument, events);
231VALUE rb_io_blocking_region(
struct rb_io *io, rb_blocking_function_t *function,
void *argument)
233 return rb_io_blocking_region_wait(io, function, argument, 0);
237 VALUE filename, current_file;
243 int8_t init_p, next_p, binmode;
254 if (fd < 0 || afd <= max_fd)
257#if defined(HAVE_FCNTL) && defined(F_GETFL)
258 err = fcntl(fd, F_GETFL) == -1;
262 err = fstat(fd, &buf) != 0;
265 if (err &&
errno == EBADF) {
266 rb_bug(
"rb_update_max_fd: invalid fd (%d) given.", fd);
269 while (max_fd < afd) {
270 max_fd = ATOMIC_CAS(max_file_descriptor, max_fd, afd);
275rb_maygvl_fd_fix_cloexec(
int fd)
278#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
279 int flags, flags2, ret;
280 flags = fcntl(fd, F_GETFD);
282 rb_bug(
"rb_maygvl_fd_fix_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(
errno));
285 flags2 = flags & ~FD_CLOEXEC;
287 flags2 = flags | FD_CLOEXEC;
288 if (flags != flags2) {
289 ret = fcntl(fd, F_SETFD, flags2);
291 rb_bug(
"rb_maygvl_fd_fix_cloexec: fcntl(%d, F_SETFD, %d) failed: %s", fd, flags2, strerror(
errno));
300 rb_maygvl_fd_fix_cloexec(fd);
306rb_fix_detect_o_cloexec(
int fd)
308#if defined(O_CLOEXEC) && defined(F_GETFD)
309 int flags = fcntl(fd, F_GETFD);
312 rb_bug(
"rb_fix_detect_o_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(
errno));
314 if (flags & FD_CLOEXEC)
317 rb_maygvl_fd_fix_cloexec(fd);
324 return (e == EWOULDBLOCK) || (e == EAGAIN);
331 static int o_cloexec_state = -1;
333 static const int retry_interval = 0;
334 static const int retry_max_count = 10000;
341#elif defined O_NOINHERIT
342 flags |= O_NOINHERIT;
345 while ((ret = open(pathname, flags, mode)) == -1) {
347 if (!io_again_p(e))
break;
348 if (retry_count++ >= retry_max_count)
break;
350 sleep(retry_interval);
353 if (ret < 0)
return ret;
354 if (ret <= 2 || o_cloexec_state == 0) {
355 rb_maygvl_fd_fix_cloexec(ret);
357 else if (o_cloexec_state > 0) {
361 o_cloexec_state = rb_fix_detect_o_cloexec(ret);
380 if (oldfd == newfd) {
384#if defined(HAVE_DUP3) && defined(O_CLOEXEC)
385 static int try_dup3 = 1;
386 if (2 < newfd && try_dup3) {
387 ret = dup3(oldfd, newfd, O_CLOEXEC);
391 if (
errno == ENOSYS) {
393 ret = dup2(oldfd, newfd);
397 ret = dup2(oldfd, newfd);
400 ret = dup2(oldfd, newfd);
402 if (ret < 0)
return ret;
404 rb_maygvl_fd_fix_cloexec(ret);
409rb_fd_set_nonblock(
int fd)
412 return rb_w32_set_nonblock(fd);
413#elif defined(F_GETFL)
414 int oflags = fcntl(fd, F_GETFL);
418 if (oflags & O_NONBLOCK)
420 oflags |= O_NONBLOCK;
421 return fcntl(fd, F_SETFL, oflags);
430 int result = pipe2(descriptors, O_CLOEXEC | O_NONBLOCK);
432 int result = pipe(descriptors);
439 if (result == 0 && descriptors[1] == -1) {
440 close(descriptors[0]);
448 rb_maygvl_fd_fix_cloexec(descriptors[0]);
449 rb_maygvl_fd_fix_cloexec(descriptors[1]);
452 rb_fd_set_nonblock(descriptors[0]);
453 rb_fd_set_nonblock(descriptors[1]);
465#if defined(HAVE_FCNTL) && defined(F_DUPFD_CLOEXEC) && defined(F_DUPFD)
466 static int try_dupfd_cloexec = 1;
467 if (try_dupfd_cloexec) {
468 ret = fcntl(fd, F_DUPFD_CLOEXEC, minfd);
471 rb_maygvl_fd_fix_cloexec(ret);
475 if (
errno == EINVAL) {
476 ret = fcntl(fd, F_DUPFD, minfd);
478 try_dupfd_cloexec = 0;
483 ret = fcntl(fd, F_DUPFD, minfd);
485#elif defined(HAVE_FCNTL) && defined(F_DUPFD)
486 ret = fcntl(fd, F_DUPFD, minfd);
489 if (ret >= 0 && ret < minfd) {
490 const int prev_fd = ret;
496 if (ret < 0)
return ret;
497 rb_maygvl_fd_fix_cloexec(ret);
501#define argf_of(obj) (*(struct argf *)DATA_PTR(obj))
502#define ARGF argf_of(argf)
504#define GetWriteIO(io) rb_io_get_write_io(io)
506#define READ_DATA_PENDING(fptr) ((fptr)->rbuf.len)
507#define READ_DATA_PENDING_COUNT(fptr) ((fptr)->rbuf.len)
508#define READ_DATA_PENDING_PTR(fptr) ((fptr)->rbuf.ptr+(fptr)->rbuf.off)
509#define READ_DATA_BUFFERED(fptr) READ_DATA_PENDING(fptr)
511#define READ_CHAR_PENDING(fptr) ((fptr)->cbuf.len)
512#define READ_CHAR_PENDING_COUNT(fptr) ((fptr)->cbuf.len)
513#define READ_CHAR_PENDING_PTR(fptr) ((fptr)->cbuf.ptr+(fptr)->cbuf.off)
516#define WAIT_FD_IN_WIN32(fptr) \
517 (rb_w32_io_cancelable_p((fptr)->fd) ? Qnil : rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_READABLE), RUBY_IO_TIMEOUT_DEFAULT))
519#define WAIT_FD_IN_WIN32(fptr)
522#define READ_CHECK(fptr) do {\
523 if (!READ_DATA_PENDING(fptr)) {\
524 WAIT_FD_IN_WIN32(fptr);\
525 rb_io_check_closed(fptr);\
531# define S_ISSOCK(m) _S_ISSOCK(m)
534# define S_ISSOCK(m) (((m) & S_IFMT) == _S_IFSOCK)
537# define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
543static int io_fflush(rb_io_t *);
544static rb_io_t *flush_before_seek(rb_io_t *fptr,
bool discard_rbuf);
545static void clear_codeconv(rb_io_t *fptr);
547#define FMODE_SIGNAL_ON_EPIPE (1<<17)
549#define fptr_signal_on_epipe(fptr) \
550 (((fptr)->mode & FMODE_SIGNAL_ON_EPIPE) != 0)
552#define fptr_set_signal_on_epipe(fptr, flag) \
554 (fptr)->mode |= FMODE_SIGNAL_ON_EPIPE : \
555 (fptr)->mode &= ~FMODE_SIGNAL_ON_EPIPE)
557extern ID ruby_static_id_signo;
559NORETURN(
static void rb_sys_fail_on_write(rb_io_t *fptr));
561rb_sys_fail_on_write(rb_io_t *fptr)
564 VALUE errinfo = rb_syserr_new_path(e, (fptr)->pathv);
566 if (fptr_signal_on_epipe(fptr) && (e == EPIPE)) {
578#define NEED_NEWLINE_DECORATOR_ON_READ(fptr) ((fptr)->mode & FMODE_TEXTMODE)
579#define NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) ((fptr)->mode & FMODE_TEXTMODE)
580#if defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32)
581# define RUBY_CRLF_ENVIRONMENT 1
583# define RUBY_CRLF_ENVIRONMENT 0
586#if RUBY_CRLF_ENVIRONMENT
588# define DEFAULT_TEXTMODE FMODE_TEXTMODE
589# define TEXTMODE_NEWLINE_DECORATOR_ON_WRITE ECONV_CRLF_NEWLINE_DECORATOR
597#define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || (fptr)->encs.ecflags & ~ECONV_CRLF_NEWLINE_DECORATOR)
598#define WRITECONV_MASK ( \
599 (ECONV_DECORATOR_MASK & ~ECONV_CRLF_NEWLINE_DECORATOR)|\
600 ECONV_STATEFUL_DECORATOR_MASK|\
602#define NEED_WRITECONV(fptr) ( \
603 ((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || \
604 ((fptr)->encs.ecflags & WRITECONV_MASK) || \
606#define SET_BINARY_MODE(fptr) setmode((fptr)->fd, O_BINARY)
608#define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) do {\
609 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {\
610 if (((fptr)->mode & FMODE_READABLE) &&\
611 !((fptr)->encs.ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {\
612 setmode((fptr)->fd, O_BINARY);\
615 setmode((fptr)->fd, O_TEXT);\
620#define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) do {\
621 if ((enc2) && ((ecflags) & ECONV_DEFAULT_NEWLINE_DECORATOR)) {\
622 (ecflags) |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;\
630io_unread(rb_io_t *fptr,
bool discard_rbuf)
646 if (!rb_w32_fd_is_text(fptr->
fd)) {
647 r = lseek(fptr->
fd, -fptr->
rbuf.
len, SEEK_CUR);
648 if (r < 0 &&
errno) {
651 if (!discard_rbuf)
return;
657 pos = lseek(fptr->
fd, 0, SEEK_CUR);
658 if (pos < 0 &&
errno) {
661 if (!discard_rbuf)
goto end;
665 extra_max = (long)(pos - fptr->
rbuf.
len);
673 for (i = 0; i < fptr->
rbuf.
len; i++) {
674 if (*p ==
'\n') newlines++;
675 if (extra_max == newlines)
break;
680 while (newlines >= 0) {
681 r = lseek(fptr->
fd, pos - fptr->
rbuf.
len - newlines, SEEK_SET);
682 if (newlines == 0)
break;
687 read_size = _read(fptr->
fd, buf, fptr->
rbuf.
len + newlines);
691 rb_syserr_fail_path(e, fptr->
pathv);
693 if (read_size == fptr->
rbuf.
len) {
694 lseek(fptr->
fd, r, SEEK_SET);
705 clear_codeconv(fptr);
717set_binary_mode_with_seek_cur(rb_io_t *fptr)
719 if (!rb_w32_fd_is_text(fptr->
fd))
return O_BINARY;
722 return setmode(fptr->
fd, O_BINARY);
724 flush_before_seek(fptr,
false);
725 return setmode(fptr->
fd, O_BINARY);
727#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) set_binary_mode_with_seek_cur(fptr)
731# define DEFAULT_TEXTMODE 0
732#define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || NEED_NEWLINE_DECORATOR_ON_READ(fptr))
733#define NEED_WRITECONV(fptr) ( \
734 ((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || \
735 NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) || \
736 ((fptr)->encs.ecflags & (ECONV_DECORATOR_MASK|ECONV_STATEFUL_DECORATOR_MASK)) || \
738#define SET_BINARY_MODE(fptr) (void)(fptr)
739#define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) (void)(fptr)
740#define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) ((void)(enc2), (void)(ecflags))
741#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) (void)(fptr)
744#if !defined HAVE_SHUTDOWN && !defined shutdown
745#define shutdown(a,b) 0
749#define is_socket(fd, path) rb_w32_is_socket(fd)
750#elif !defined(S_ISSOCK)
751#define is_socket(fd, path) 0
754is_socket(
int fd,
VALUE path)
757 if (fstat(fd, &sbuf) < 0)
758 rb_sys_fail_path(path);
759 return S_ISSOCK(sbuf.st_mode);
763static const char closed_stream[] =
"closed stream";
766io_fd_check_closed(
int fd)
799 io_fd_check_closed(fptr->
fd);
803rb_io_get_fptr(
VALUE io)
805 rb_io_t *fptr =
RFILE(io)->fptr;
813 return rb_convert_type_with_id(io,
T_FILE,
"IO", idTo_io);
819 return rb_check_convert_type_with_id(io,
T_FILE,
"IO", idTo_io);
826 write_io = rb_io_get_fptr(io)->tied_io_for_writing;
837 rb_io_t *fptr = rb_io_get_fptr(io);
846 return write_io ? write_io :
Qnil;
859 rb_io_t *fptr = rb_io_get_fptr(self);
889 if (
RTEST(timeout)) {
893 rb_io_t *fptr = rb_io_get_fptr(self);
918#if !RUBY_CRLF_ENVIRONMENT
920io_unread(rb_io_t *fptr,
bool discard_rbuf)
928 r = lseek(fptr->
fd, -fptr->
rbuf.
len, SEEK_CUR);
929 if (r < 0 &&
errno) {
932 if (!discard_rbuf)
return;
936 clear_codeconv(fptr);
941static rb_encoding *io_input_encoding(rb_io_t *fptr);
944io_ungetbyte(
VALUE str, rb_io_t *fptr)
946 long len = RSTRING_LEN(str);
949 const int min_capa = IO_RBUF_CAPA_FOR(fptr);
952#if SIZEOF_LONG > SIZEOF_INT
977flush_before_seek(rb_io_t *fptr,
bool discard_rbuf)
979 if (io_fflush(fptr) < 0)
980 rb_sys_fail_on_write(fptr);
981 io_unread(fptr, discard_rbuf);
986#define io_seek(fptr, ofs, whence) (errno = 0, lseek(flush_before_seek(fptr, true)->fd, (ofs), (whence)))
987#define io_tell(fptr) lseek(flush_before_seek(fptr, false)->fd, 0, SEEK_CUR)
1003 if (io_fflush(fptr) < 0)
1004 rb_sys_fail_on_write(fptr);
1009 if (io_fflush(wfptr) < 0)
1010 rb_sys_fail_on_write(wfptr);
1018 if (READ_CHAR_PENDING(fptr)) {
1019 rb_raise(
rb_eIOError,
"byte oriented read for character buffered IO");
1030io_read_encoding(rb_io_t *fptr)
1039io_input_encoding(rb_io_t *fptr)
1044 return io_read_encoding(fptr);
1055 io_unread(fptr,
true);
1063 if (READ_CHAR_PENDING(fptr))
1065 return READ_DATA_PENDING(fptr);
1071 if (!READ_DATA_PENDING(fptr)) {
1078rb_gc_for_fd(
int err)
1080 if (err == EMFILE || err == ENFILE || err == ENOMEM) {
1090#define TRY_WITH_GC(expr) \
1091 for (int first_errno, retried_errno = 0, retried = 0; \
1094 (!rb_gc_for_fd(first_errno = errno) || !(expr)) && \
1095 (retried_errno = errno, 1)); \
1096 (void)retried_errno, retried = 1)
1111io_alloc(
VALUE klass)
1121# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
1147struct io_internal_writev_struct {
1154 const struct iovec *iov;
1159static int nogvl_wait_for(
VALUE th, rb_io_t *fptr,
short events,
struct timeval *timeout);
1167io_internal_wait(
VALUE thread, rb_io_t *fptr,
int error,
int events,
struct timeval *timeout)
1169 if (!timeout && rb_thread_mn_schedulable(thread)) {
1174 int ready = nogvl_wait_for(thread, fptr, events, timeout);
1179 else if (ready == 0) {
1196internal_read_func(
void *ptr)
1201 if (iis->timeout && !iis->nonblock) {
1202 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_IN, iis->timeout) == -1) {
1208 result = read(iis->fd, iis->buf, iis->capa);
1210 if (result < 0 && !iis->nonblock) {
1211 if (io_again_p(
errno)) {
1212 if (io_internal_wait(iis->th, iis->fptr,
errno, RB_WAITFD_IN, iis->timeout) == -1) {
1224#if defined __APPLE__
1225# define do_write_retry(code) do {result = code;} while (result == -1 && errno == EPROTOTYPE)
1227# define do_write_retry(code) result = code
1231internal_write_func(
void *ptr)
1236 if (iis->timeout && !iis->nonblock) {
1237 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1243 do_write_retry(write(iis->fd, iis->buf, iis->capa));
1245 if (result < 0 && !iis->nonblock) {
1247 if (io_again_p(e)) {
1248 if (io_internal_wait(iis->th, iis->fptr,
errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1262internal_writev_func(
void *ptr)
1264 struct io_internal_writev_struct *iis = ptr;
1267 if (iis->timeout && !iis->nonblock) {
1268 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1274 do_write_retry(writev(iis->fd, iis->iov, iis->iovcnt));
1276 if (result < 0 && !iis->nonblock) {
1277 if (io_again_p(
errno)) {
1278 if (io_internal_wait(iis->th, iis->fptr,
errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1292rb_io_read_memory(rb_io_t *fptr,
void *buf,
size_t count)
1294 rb_thread_t *th = GET_THREAD();
1296 if (scheduler !=
Qnil) {
1299 if (!UNDEF_P(result)) {
1315 struct timeval timeout_storage;
1319 iis.timeout = &timeout_storage;
1322 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_read_func, &iis,
RUBY_IO_READABLE);
1326rb_io_write_memory(rb_io_t *fptr,
const void *buf,
size_t count)
1328 rb_thread_t *th = GET_THREAD();
1330 if (scheduler !=
Qnil) {
1333 if (!UNDEF_P(result)) {
1349 struct timeval timeout_storage;
1353 iis.timeout = &timeout_storage;
1356 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_write_func, &iis,
RUBY_IO_WRITABLE);
1361rb_writev_internal(rb_io_t *fptr,
const struct iovec *iov,
int iovcnt)
1363 if (!iovcnt)
return 0;
1365 rb_thread_t *th = GET_THREAD();
1368 if (scheduler !=
Qnil) {
1372 if (!UNDEF_P(result)) {
1377 struct io_internal_writev_struct iis = {
1388 struct timeval timeout_storage;
1392 iis.timeout = &timeout_storage;
1395 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_writev_func, &iis,
RUBY_IO_WRITABLE);
1400io_flush_buffer_sync(
void *arg)
1402 rb_io_t *fptr = arg;
1422io_flush_buffer_fiber_scheduler(
VALUE scheduler, rb_io_t *fptr)
1425 if (!UNDEF_P(ret)) {
1437io_flush_buffer_async(
VALUE arg)
1439 rb_io_t *fptr = (rb_io_t *)arg;
1442 if (scheduler !=
Qnil) {
1443 VALUE result = io_flush_buffer_fiber_scheduler(scheduler, fptr);
1444 if (!UNDEF_P(result)) {
1449 return rb_io_blocking_region_wait(fptr, io_flush_buffer_sync, fptr,
RUBY_IO_WRITABLE);
1453io_flush_buffer(rb_io_t *fptr)
1456 return (
int)io_flush_buffer_async((
VALUE)fptr);
1464io_fflush(rb_io_t *fptr)
1471 while (fptr->
wbuf.
len > 0 && io_flush_buffer(fptr) != 0) {
1484 rb_thread_t *th = GET_THREAD();
1487 if (scheduler !=
Qnil) {
1491 rb_io_t * fptr = NULL;
1497 if (NIL_OR_UNDEF_P(timeout)) {
1501 if (timeout !=
Qnil) {
1506 int ready = rb_thread_io_wait(th, fptr,
RB_NUM2INT(events), tv);
1530io_wait_for_single_fd(
int fd,
int events,
struct timeval *timeout, rb_thread_t *th,
VALUE scheduler)
1532 if (scheduler !=
Qnil) {
1538 return rb_thread_wait_for_single_fd(th, fd, events, timeout);
1544 io_fd_check_closed(f);
1546 rb_thread_t *th = GET_THREAD();
1551#if defined(ERESTART)
1558#if EWOULDBLOCK != EAGAIN
1561 if (scheduler !=
Qnil) {
1579 io_fd_check_closed(f);
1581 rb_thread_t *th = GET_THREAD();
1586#if defined(ERESTART)
1602#if EWOULDBLOCK != EAGAIN
1605 if (scheduler !=
Qnil) {
1623 rb_thread_t *th = GET_THREAD();
1625 return io_wait_for_single_fd(fd, events, timeout, th, scheduler);
1659#if defined(ERESTART)
1669#if EWOULDBLOCK != EAGAIN
1686 if (
RTEST(result)) {
1701 if (
RTEST(result)) {
1712make_writeconv(rb_io_t *fptr)
1715 const char *senc, *denc;
1749 denc = rb_enc_name(enc);
1781io_binwrite_string_internal(rb_io_t *fptr,
const char *ptr,
long length)
1784 struct iovec iov[2];
1787 iov[0].iov_len = fptr->
wbuf.
len;
1788 iov[1].iov_base = (
void*)ptr;
1789 iov[1].iov_len = length;
1791 ssize_t result = rb_writev_internal(fptr, iov, 2);
1796 if (result >= fptr->
wbuf.
len) {
1804 fptr->
wbuf.
off += (int)result;
1805 fptr->
wbuf.
len -= (int)result;
1813 return rb_io_write_memory(fptr, ptr, length);
1818io_binwrite_string_internal(rb_io_t *fptr,
const char *ptr,
long length)
1820 long remaining = length;
1823 if (fptr->
wbuf.
len+length <= fptr->wbuf.capa) {
1830 fptr->
wbuf.
len += (int)length;
1837 if (io_fflush(fptr) < 0) {
1842 if (remaining == 0) {
1848 return rb_io_write_memory(fptr, ptr, length);
1853io_binwrite_string(
VALUE arg)
1857 const char *ptr = p->ptr;
1858 size_t remaining = p->length;
1862 ssize_t result = io_binwrite_string_internal(p->fptr, ptr, remaining);
1868 else if (result > 0) {
1869 if ((
size_t)result == remaining)
break;
1871 remaining -= result;
1887io_allocate_write_buffer(rb_io_t *fptr,
int sync)
1892 fptr->
wbuf.
capa = IO_WBUF_CAPA_MIN;
1903io_binwrite_requires_flush_write(rb_io_t *fptr,
long len,
int nosync)
1918io_binwrite(
const char *ptr,
long len, rb_io_t *fptr,
int nosync)
1920 if (
len <= 0)
return len;
1925 io_allocate_write_buffer(fptr, !nosync);
1927 if (io_binwrite_requires_flush_write(fptr,
len, nosync)) {
1938 return io_binwrite_string((
VALUE)&arg);
1955# define MODE_BTMODE(a,b,c) ((fmode & FMODE_BINMODE) ? (b) : \
1956 (fmode & FMODE_TEXTMODE) ? (c) : (a))
1958#define MODE_BTXMODE(a, b, c, d, e, f) ((fmode & FMODE_EXCL) ? \
1959 MODE_BTMODE(d, e, f) : \
1960 MODE_BTMODE(a, b, c))
1963do_writeconv(
VALUE str, rb_io_t *fptr,
int *converted)
1965 if (NEED_WRITECONV(fptr)) {
1967 SET_BINARY_MODE(fptr);
1969 make_writeconv(fptr);
1972#define fmode (fptr->mode)
1975 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1) && !rb_enc_asciicompat(rb_enc_get(str))) {
1976 rb_raise(rb_eArgError,
"ASCII incompatible string written for text mode IO without encoding conversion: %s",
1977 rb_enc_name(rb_enc_get(str)));
1983 common_encoding = rb_enc_from_encoding(fptr->
encs.
enc2);
1984 else if (fptr->
encs.
enc != rb_ascii8bit_encoding())
1985 common_encoding = rb_enc_from_encoding(fptr->
encs.
enc);
1988 if (!
NIL_P(common_encoding)) {
1999#if RUBY_CRLF_ENVIRONMENT
2000#define fmode (fptr->mode)
2001 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1)) {
2004 setmode(fptr->
fd, O_BINARY);
2007 setmode(fptr->
fd, O_TEXT);
2009 if (!rb_enc_asciicompat(rb_enc_get(str))) {
2010 rb_raise(rb_eArgError,
"ASCII incompatible string written for text mode IO without encoding conversion: %s",
2011 rb_enc_name(rb_enc_get(str)));
2020io_fwrite(
VALUE str, rb_io_t *fptr,
int nosync)
2029 long len = rb_w32_write_console(str, fptr->
fd);
2034 str = do_writeconv(str, fptr, &converted);
2038 tmp = rb_str_tmp_frozen_no_embed_acquire(str);
2040 n = io_binwrite(ptr,
len, fptr, nosync);
2041 rb_str_tmp_frozen_release(str, tmp);
2053 return (ssize_t)io_binwrite(buf, (
long)size, fptr, 0);
2063 io = GetWriteIO(io);
2073 if (RSTRING_LEN(str) == 0)
return INT2FIX(0);
2078 n = io_fwrite(str, fptr, nosync);
2079 if (n < 0L) rb_sys_fail_on_write(fptr);
2085struct binwritev_arg {
2093io_binwritev_internal(
VALUE arg)
2095 struct binwritev_arg *p = (
struct binwritev_arg *)arg;
2097 size_t remaining = p->total;
2100 rb_io_t *fptr = p->fptr;
2101 struct iovec *iov = p->iov;
2102 int iovcnt = p->iovcnt;
2105 long result = rb_writev_internal(fptr, iov, iovcnt);
2110 if (offset < (
size_t)fptr->
wbuf.
len) {
2115 offset -= (size_t)fptr->
wbuf.
len;
2121 if (offset == p->total) {
2125 while (result >= (ssize_t)iov->iov_len) {
2127 result -= iov->iov_len;
2137 iov->iov_base = (
char *)iov->iov_base + result;
2138 iov->iov_len -= result;
2152io_binwritev(
struct iovec *iov,
int iovcnt, rb_io_t *fptr)
2157 if (iovcnt == 0)
return 0;
2160 for (
int i = 1; i < iovcnt; i++) total += iov[i].iov_len;
2162 io_allocate_write_buffer(fptr, 1);
2168 if (offset + total <= (
size_t)fptr->
wbuf.
capa) {
2169 for (
int i = 1; i < iovcnt; i++) {
2170 memcpy(fptr->
wbuf.
ptr+offset, iov[i].iov_base, iov[i].iov_len);
2171 offset += iov[i].iov_len;
2180 iov[0].iov_len = fptr->
wbuf.
len;
2193 struct binwritev_arg arg;
2196 arg.iovcnt = iovcnt;
2203 return io_binwritev_internal((
VALUE)&arg);
2208io_fwritev(
int argc,
const VALUE *argv, rb_io_t *fptr)
2210 int i, converted, iovcnt = argc + 1;
2212 VALUE v1, v2, str, tmp, *tmp_array;
2218 for (i = 0; i < argc; i++) {
2221 str = do_writeconv(str, fptr, &converted);
2226 tmp = rb_str_tmp_frozen_acquire(str);
2230 iov[i+1].iov_base = RSTRING_PTR(tmp);
2231 iov[i+1].iov_len = RSTRING_LEN(tmp);
2234 n = io_binwritev(iov, iovcnt, fptr);
2237 for (i = 0; i < argc; i++) {
2238 rb_str_tmp_frozen_release(argv[i], tmp_array[i]);
2247iovcnt_ok(
int iovcnt)
2250 return iovcnt < IOV_MAX;
2258io_writev(
int argc,
const VALUE *argv,
VALUE io)
2265 io = GetWriteIO(io);
2270 return rb_funcallv(io, id_write, argc, argv);
2278 for (i = 0; i < argc; i += cnt) {
2281 n = io_fwritev(cnt, &argv[i], fptr);
2292 rb_sys_fail_on_write(fptr);
2294 total = rb_fix_plus(
LONG2FIX(n), total);
2325 return io_writev(argc, argv, io);
2328 VALUE str = argv[0];
2329 return io_write(io, str, 0);
2336 return rb_funcallv(io, id_write, 1, &str);
2340rb_io_writev(
VALUE io,
int argc,
const VALUE *argv)
2345 char sep = RCLASS_SINGLETON_P(klass) ? (klass = io,
'.') :
'#';
2348 " which accepts just one argument",
2353 do rb_io_write(io, *argv++);
while (--argc);
2358 return rb_funcallv(io, id_write, argc, argv);
2384 rb_io_write(io, str);
2390nogvl_fsync(
void *ptr)
2392 rb_io_t *fptr = ptr;
2395 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->
fd)) != FILE_TYPE_DISK)
2398 return (
VALUE)fsync(fptr->
fd);
2403rb_io_flush_raw(
VALUE io,
int sync)
2411 io = GetWriteIO(io);
2415 if (io_fflush(fptr) < 0)
2416 rb_sys_fail_on_write(fptr);
2419 io_unread(fptr,
true);
2440 return rb_io_flush_raw(io, 1);
2466 pos = io_tell(fptr);
2467 if (pos < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
2473rb_io_seek(
VALUE io,
VALUE offset,
int whence)
2480 pos = io_seek(fptr, pos, whence);
2481 if (pos < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
2487interpret_seek_whence(
VALUE vwhence)
2489 if (vwhence == sym_SET)
2491 if (vwhence == sym_CUR)
2493 if (vwhence == sym_END)
2496 if (vwhence == sym_DATA)
2500 if (vwhence == sym_HOLE)
2556 VALUE offset, ptrname;
2557 int whence = SEEK_SET;
2559 if (
rb_scan_args(argc, argv,
"11", &offset, &ptrname) == 2) {
2560 whence = interpret_seek_whence(ptrname);
2563 return rb_io_seek(io, offset, whence);
2591 pos = io_seek(fptr, pos, SEEK_SET);
2592 if (pos < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
2597static void clear_readconv(rb_io_t *fptr);
2624rb_io_rewind(
VALUE io)
2629 if (io_seek(fptr, 0L, 0) < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
2630 if (io == ARGF.current_file) {
2631 ARGF.lineno -= fptr->
lineno;
2635 clear_readconv(fptr);
2642fptr_wait_readable(rb_io_t *fptr)
2653io_fillbuf(rb_io_t *fptr)
2660 fptr->
rbuf.
capa = IO_RBUF_CAPA_FOR(fptr);
2668 if (fptr_wait_readable(fptr))
2672 VALUE path = rb_sprintf(
"fd:%d ", fptr->
fd);
2677 rb_syserr_fail_path(e, path);
2731 if (READ_CHAR_PENDING(fptr))
return Qfalse;
2732 if (READ_DATA_PENDING(fptr))
return Qfalse;
2734#if RUBY_CRLF_ENVIRONMENT
2735 if (!NEED_READCONV(fptr) && NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
2736 return RBOOL(eof(fptr->
fd));
2739 return RBOOL(io_fillbuf(fptr) < 0);
2763 io = GetWriteIO(io);
2800 io = GetWriteIO(io);
2830rb_io_fsync(
VALUE io)
2834 io = GetWriteIO(io);
2837 if (io_fflush(fptr) < 0)
2838 rb_sys_fail_on_write(fptr);
2840 if ((
int)rb_io_blocking_region(fptr, nogvl_fsync, fptr))
2841 rb_sys_fail_path(fptr->
pathv);
2846# define rb_io_fsync rb_f_notimplement
2847# define rb_io_sync rb_f_notimplement
2856#ifdef HAVE_FDATASYNC
2858nogvl_fdatasync(
void *ptr)
2860 rb_io_t *fptr = ptr;
2863 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->
fd)) != FILE_TYPE_DISK)
2866 return (
VALUE)fdatasync(fptr->
fd);
2881rb_io_fdatasync(
VALUE io)
2885 io = GetWriteIO(io);
2888 if (io_fflush(fptr) < 0)
2889 rb_sys_fail_on_write(fptr);
2891 if ((
int)rb_io_blocking_region(fptr, nogvl_fdatasync, fptr) == 0)
2895 return rb_io_fsync(io);
2898#define rb_io_fdatasync rb_io_fsync
2916rb_io_fileno(
VALUE io)
2918 rb_io_t *fptr =
RFILE(io)->fptr;
2930 rb_io_t *fptr =
RFILE(io)->fptr;
2936 if (!UNDEF_P(fileno)) {
3003 rb_io_t *fptr =
RFILE(io)->fptr;
3024rb_io_inspect(
VALUE obj)
3028 static const char closed[] =
" (closed)";
3030 fptr =
RFILE(obj)->fptr;
3037 rb_str_cat(result, closed+1, strlen(closed)-1);
3040 rb_str_catf(result,
"fd %d", fptr->
fd);
3061rb_io_to_io(
VALUE io)
3068read_buffered_data(
char *ptr,
long len, rb_io_t *fptr)
3072 n = READ_DATA_PENDING_COUNT(fptr);
3073 if (n <= 0)
return 0;
3074 if (n >
len) n = (int)
len;
3082io_bufread(
char *ptr,
long len, rb_io_t *fptr)
3088 if (READ_DATA_PENDING(fptr) == 0) {
3092 c = rb_io_read_memory(fptr, ptr+offset, n);
3095 if (fptr_wait_readable(fptr))
3100 if ((n -= c) <= 0)
break;
3106 c = read_buffered_data(ptr+offset, n, fptr);
3109 if ((n -= c) <= 0)
break;
3112 if (io_fillbuf(fptr) < 0) {
3119static int io_setstrbuf(
VALUE *str,
long len);
3128bufread_call(
VALUE arg)
3131 p->len = io_bufread(p->str_ptr, p->len, p->fptr);
3136io_fread(
VALUE str,
long offset,
long size, rb_io_t *fptr)
3141 io_setstrbuf(&str, offset + size);
3142 arg.str_ptr = RSTRING_PTR(str) + offset;
3145 rb_str_locktmp_ensure(str, bufread_call, (
VALUE)&arg);
3147 if (
len < 0) rb_sys_fail_path(fptr->
pathv);
3152remain_size(rb_io_t *fptr)
3155 rb_off_t siz = READ_DATA_PENDING_COUNT(fptr);
3158 if (fstat(fptr->
fd, &st) == 0 && S_ISREG(st.st_mode)
3159#
if defined(__HAIKU__)
3164 if (io_fflush(fptr) < 0)
3165 rb_sys_fail_on_write(fptr);
3166 pos = lseek(fptr->
fd, 0, SEEK_CUR);
3167 if (st.st_size >= pos && pos >= 0) {
3168 siz += st.st_size - pos;
3169 if (siz > LONG_MAX) {
3170 rb_raise(
rb_eIOError,
"file too big for single read");
3181io_enc_str(
VALUE str, rb_io_t *fptr)
3183 rb_enc_associate(str, io_read_encoding(fptr));
3188make_readconv(rb_io_t *fptr,
int size)
3193 const char *sname, *dname;
3197 sname = rb_enc_name(fptr->
encs.
enc2);
3198 dname = rb_enc_name(io_read_encoding(fptr));
3208 if (size < IO_CBUF_CAPA_MIN) size = IO_CBUF_CAPA_MIN;
3214#define MORE_CHAR_SUSPENDED Qtrue
3215#define MORE_CHAR_FINISHED Qnil
3217fill_cbuf(rb_io_t *fptr,
int ec_flags)
3219 const unsigned char *ss, *sp, *se;
3220 unsigned char *ds, *dp, *de;
3229 return MORE_CHAR_SUSPENDED;
3240 ss = sp = (
const unsigned char *)fptr->
rbuf.
ptr + fptr->
rbuf.
off;
3245 fptr->
rbuf.
off += (int)(sp - ss);
3246 fptr->
rbuf.
len -= (int)(sp - ss);
3247 fptr->
cbuf.
len += (int)(dp - ds);
3252 fptr->
rbuf.
off -= putbackable;
3253 fptr->
rbuf.
len += putbackable;
3260 if (cbuf_len0 != fptr->
cbuf.
len)
3261 return MORE_CHAR_SUSPENDED;
3264 return MORE_CHAR_FINISHED;
3270 if (io_fillbuf(fptr) < 0) {
3272 return MORE_CHAR_FINISHED;
3277 fptr->
cbuf.
len += (int)(dp - ds);
3284 if (cbuf_len0 != fptr->
cbuf.
len)
3285 return MORE_CHAR_SUSPENDED;
3287 return MORE_CHAR_FINISHED;
3291more_char(rb_io_t *fptr)
3295 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED)
3301io_shift_cbuf(rb_io_t *fptr,
int len,
VALUE *strp)
3312 rb_enc_associate(str, fptr->
encs.
enc);
3337 long clen = RSTRING_LEN(s);
3349#define MAX_REALLOC_GAP 4096
3351io_shrink_read_string(
VALUE str,
long n)
3354 rb_str_resize(str, n);
3359io_set_read_length(
VALUE str,
long n,
int shrinkable)
3361 if (RSTRING_LEN(str) != n) {
3364 if (shrinkable) io_shrink_read_string(str, n);
3369read_all(rb_io_t *fptr,
long siz,
VALUE str)
3378 if (NEED_READCONV(fptr)) {
3379 int first = !
NIL_P(str);
3380 SET_BINARY_MODE(fptr);
3381 shrinkable = io_setstrbuf(&str,0);
3382 make_readconv(fptr, 0);
3387 io_shift_cbuf(fptr, fptr->
cbuf.
len, &str);
3389 v = fill_cbuf(fptr, 0);
3390 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED) {
3393 io_shift_cbuf(fptr, fptr->
cbuf.
len, &str);
3397 if (v == MORE_CHAR_FINISHED) {
3398 clear_readconv(fptr);
3400 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3401 return io_enc_str(str, fptr);
3406 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3410 enc = io_read_encoding(fptr);
3413 if (siz == 0) siz = BUFSIZ;
3414 shrinkable = io_setstrbuf(&str, siz);
3417 n = io_fread(str, bytes, siz - bytes, fptr);
3418 if (n == 0 && bytes == 0) {
3426 if (bytes < siz)
break;
3430 if (
capa < (
size_t)RSTRING_LEN(str) + BUFSIZ) {
3431 if (
capa < BUFSIZ) {
3434 else if (
capa > IO_MAX_BUFFER_GROWTH) {
3435 capa = IO_MAX_BUFFER_GROWTH;
3440 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3441 str = io_enc_str(str, fptr);
3449 if (rb_fd_set_nonblock(fptr->
fd) != 0) {
3450 rb_sys_fail_path(fptr->
pathv);
3455io_read_memory_call(
VALUE arg)
3460 if (scheduler !=
Qnil) {
3463 if (!UNDEF_P(result)) {
3469 if (iis->nonblock) {
3470 return rb_io_blocking_region(iis->fptr, internal_read_func, iis);
3473 return rb_io_blocking_region_wait(iis->fptr, internal_read_func, iis,
RUBY_IO_READABLE);
3480 return (
long)rb_str_locktmp_ensure(str, io_read_memory_call, (
VALUE)iis);
3483#define no_exception_p(opts) !rb_opts_exception_p((opts), TRUE)
3486io_getpartial(
int argc,
VALUE *argv,
VALUE io,
int no_exception,
int nonblock)
3497 rb_raise(rb_eArgError,
"negative length %ld given",
len);
3500 shrinkable = io_setstrbuf(&str,
len);
3506 io_set_read_length(str, 0, shrinkable);
3512 n = read_buffered_data(RSTRING_PTR(str),
len, fptr);
3518 io_setstrbuf(&str,
len);
3521 iis.nonblock = nonblock;
3523 iis.buf = RSTRING_PTR(str);
3526 n = io_read_memory_locktmp(str, &iis);
3529 if (!nonblock && fptr_wait_readable(fptr))
3531 if (nonblock && (io_again_p(e))) {
3533 return sym_wait_readable;
3536 e,
"read would block");
3538 rb_syserr_fail_path(e, fptr->
pathv);
3541 io_set_read_length(str, n, shrinkable);
3642io_readpartial(
int argc,
VALUE *argv,
VALUE io)
3646 ret = io_getpartial(argc, argv, io,
Qnil, 0);
3653io_nonblock_eof(
int no_exception)
3655 if (!no_exception) {
3671 rb_raise(rb_eArgError,
"negative length %ld given",
len);
3674 shrinkable = io_setstrbuf(&str,
len);
3675 rb_bool_expected(ex,
"exception", TRUE);
3681 io_set_read_length(str, 0, shrinkable);
3685 n = read_buffered_data(RSTRING_PTR(str),
len, fptr);
3687 rb_fd_set_nonblock(fptr->
fd);
3688 shrinkable |= io_setstrbuf(&str,
len);
3692 iis.buf = RSTRING_PTR(str);
3695 n = io_read_memory_locktmp(str, &iis);
3698 if (io_again_p(e)) {
3699 if (!ex)
return sym_wait_readable;
3701 e,
"read would block");
3703 rb_syserr_fail_path(e, fptr->
pathv);
3706 io_set_read_length(str, n, shrinkable);
3709 if (!ex)
return Qnil;
3718io_write_nonblock(rb_execution_context_t *ec,
VALUE io,
VALUE str,
VALUE ex)
3725 rb_bool_expected(ex,
"exception", TRUE);
3727 io = GetWriteIO(io);
3731 if (io_fflush(fptr) < 0)
3732 rb_sys_fail_on_write(fptr);
3734 rb_fd_set_nonblock(fptr->
fd);
3735 n = write(fptr->
fd, RSTRING_PTR(str), RSTRING_LEN(str));
3740 if (io_again_p(e)) {
3742 return sym_wait_writable;
3748 rb_syserr_fail_path(e, fptr->
pathv);
3832#if RUBY_CRLF_ENVIRONMENT
3838 if (
NIL_P(length)) {
3841 return read_all(fptr, remain_size(fptr), str);
3845 rb_raise(rb_eArgError,
"negative length %ld given",
len);
3848 shrinkable = io_setstrbuf(&str,
len);
3853 io_set_read_length(str, 0, shrinkable);
3858#if RUBY_CRLF_ENVIRONMENT
3859 previous_mode = set_binary_mode_with_seek_cur(fptr);
3861 n = io_fread(str, 0,
len, fptr);
3862 io_set_read_length(str, n, shrinkable);
3863#if RUBY_CRLF_ENVIRONMENT
3864 if (previous_mode == O_TEXT) {
3865 setmode(fptr->
fd, O_TEXT);
3868 if (n == 0)
return Qnil;
3874rscheck(
const char *rsptr,
long rslen,
VALUE rs)
3877 if (RSTRING_PTR(rs) != rsptr && RSTRING_LEN(rs) != rslen)
3882search_delim(
const char *p,
long len,
int delim, rb_encoding *enc)
3884 if (rb_enc_mbminlen(enc) == 1) {
3885 p = memchr(p, delim,
len);
3886 if (p)
return p + 1;
3889 const char *end = p +
len;
3891 int r = rb_enc_precise_mbclen(p, end, enc);
3893 p += rb_enc_mbminlen(enc);
3897 if (rb_enc_mbc_to_codepoint(p, end, enc) == (
unsigned int)delim) {
3907appendline(rb_io_t *fptr,
int delim,
VALUE *strp,
long *lp, rb_encoding *enc)
3912 if (NEED_READCONV(fptr)) {
3913 SET_BINARY_MODE(fptr);
3914 make_readconv(fptr, 0);
3917 int searchlen = READ_CHAR_PENDING_COUNT(fptr);
3919 p = READ_CHAR_PENDING_PTR(fptr);
3920 if (0 < limit && limit < searchlen)
3921 searchlen = (int)limit;
3922 e = search_delim(p, searchlen, delim, enc);
3924 int len = (int)(e-p);
3946 return (
unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
3949 }
while (more_char(fptr) != MORE_CHAR_FINISHED);
3950 clear_readconv(fptr);
3955 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3957 long pending = READ_DATA_PENDING_COUNT(fptr);
3959 const char *p = READ_DATA_PENDING_PTR(fptr);
3963 if (limit > 0 && pending > limit) pending = limit;
3964 e = search_delim(p, pending, delim, enc);
3965 if (e) pending = e - p;
3967 last = RSTRING_LEN(str);
3968 rb_str_resize(str, last + pending);
3975 read_buffered_data(RSTRING_PTR(str) + last, pending, fptr);
3978 if (e)
return delim;
3980 return (
unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
3983 }
while (io_fillbuf(fptr) >= 0);
3989swallow(rb_io_t *fptr,
int term)
3991 if (NEED_READCONV(fptr)) {
3992 rb_encoding *enc = io_read_encoding(fptr);
3993 int needconv = rb_enc_mbminlen(enc) != 1;
3994 SET_BINARY_MODE(fptr);
3995 make_readconv(fptr, 0);
3998 while ((cnt = READ_CHAR_PENDING_COUNT(fptr)) > 0) {
3999 const char *p = READ_CHAR_PENDING_PTR(fptr);
4002 if (*p != term)
return TRUE;
4004 while (--i && *++p == term);
4007 const char *e = p + cnt;
4008 if (rb_enc_ascget(p, e, &i, enc) != term)
return TRUE;
4009 while ((p += i) < e && rb_enc_ascget(p, e, &i, enc) == term);
4012 io_shift_cbuf(fptr, (
int)cnt - i, NULL);
4014 }
while (more_char(fptr) != MORE_CHAR_FINISHED);
4018 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4021 while ((cnt = READ_DATA_PENDING_COUNT(fptr)) > 0) {
4023 const char *p = READ_DATA_PENDING_PTR(fptr);
4025 if (cnt >
sizeof buf) cnt =
sizeof buf;
4026 if (*p != term)
return TRUE;
4028 while (--i && *++p == term);
4029 if (!read_buffered_data(buf, cnt - i, fptr))
4030 rb_sys_fail_path(fptr->
pathv);
4033 }
while (io_fillbuf(fptr) == 0);
4038rb_io_getline_fast(rb_io_t *fptr, rb_encoding *enc,
int chomp)
4046 int pending = READ_DATA_PENDING_COUNT(fptr);
4049 const char *p = READ_DATA_PENDING_PTR(fptr);
4053 e = memchr(p,
'\n', pending);
4055 pending = (int)(e - p + 1);
4057 chomplen = (pending > 1 && *(e-1) ==
'\r') + 1;
4066 rb_str_resize(str,
len + pending - chomplen);
4067 read_buffered_data(RSTRING_PTR(str)+
len, pending - chomplen, fptr);
4070 if (pending == 1 && chomplen == 1 &&
len > 0) {
4071 if (RSTRING_PTR(str)[
len-1] ==
'\r') {
4072 rb_str_resize(str, --
len);
4077 len += pending - chomplen;
4083 }
while (io_fillbuf(fptr) >= 0);
4086 str = io_enc_str(str, fptr);
4097 unsigned int chomp: 1;
4111 chomp = (!UNDEF_P(vchomp)) &&
RTEST(vchomp);
4113 args->chomp = chomp;
4131 else if (2 <= argc) {
4132 rs = argv[0], lim = argv[1];
4141check_getline_args(
VALUE *rsp,
long *limit,
VALUE io)
4147 rb_encoding *enc_rs, *enc_io;
4150 enc_rs = rb_enc_get(rs);
4151 enc_io = io_read_encoding(fptr);
4152 if (enc_io != enc_rs &&
4153 (!is_ascii_string(rs) ||
4154 (RSTRING_LEN(rs) > 0 && !rb_enc_asciicompat(enc_io)))) {
4156 rs = rb_enc_str_new(0, 0, enc_io);
4161 rb_raise(rb_eArgError,
"encoding mismatch: %s IO with %s RS",
4162 rb_enc_name(enc_io),
4163 rb_enc_name(enc_rs));
4173 argc =
rb_scan_args(argc, argv,
"02:", NULL, NULL, &opts);
4174 extract_getline_args(argc, argv, args);
4175 extract_getline_opts(opts, args);
4176 check_getline_args(&args->rs, &args->limit, io);
4180rb_io_getline_0(
VALUE rs,
long limit,
int chomp, rb_io_t *fptr)
4187 if (
NIL_P(rs) && limit < 0) {
4188 str = read_all(fptr, 0,
Qnil);
4189 if (RSTRING_LEN(str) == 0)
return Qnil;
4191 else if (limit == 0) {
4192 return rb_enc_str_new(0, 0, io_read_encoding(fptr));
4194 else if (rs ==
rb_default_rs && limit < 0 && !NEED_READCONV(fptr) &&
4195 rb_enc_asciicompat(enc = io_read_encoding(fptr))) {
4196 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4197 return rb_io_getline_fast(fptr, enc, chomp);
4200 int c, newline = -1;
4201 const char *rsptr = 0;
4204 int extra_limit = 16;
4205 int chomp_cr = chomp;
4207 SET_BINARY_MODE(fptr);
4208 enc = io_read_encoding(fptr);
4211 rslen = RSTRING_LEN(rs);
4216 swallow(fptr,
'\n');
4218 if (!rb_enc_asciicompat(enc)) {
4222 rsptr = RSTRING_PTR(rs);
4223 rslen = RSTRING_LEN(rs);
4227 else if (rb_enc_mbminlen(enc) == 1) {
4228 rsptr = RSTRING_PTR(rs);
4229 newline = (
unsigned char)rsptr[rslen - 1];
4233 rsptr = RSTRING_PTR(rs);
4234 const char *e = rsptr + rslen;
4235 const char *last = rb_enc_prev_char(rsptr, e, e, enc);
4237 newline = rb_enc_codepoint_len(last, e, &n, enc);
4238 if (last + n != e) rb_raise(rb_eArgError,
"broken separator");
4240 chomp_cr = chomp && newline ==
'\n' && rslen == rb_enc_mbminlen(enc);
4244 while ((c = appendline(fptr, newline, &str, &limit, enc)) != EOF) {
4245 const char *s, *p, *pp, *e;
4248 if (RSTRING_LEN(str) < rslen)
continue;
4249 s = RSTRING_PTR(str);
4252 if (!at_char_boundary(s, p, e, enc))
continue;
4253 if (!rspara) rscheck(rsptr, rslen, rs);
4254 if (memcmp(p, rsptr, rslen) == 0) {
4256 if (chomp_cr && p > s && *(p-1) ==
'\r') --p;
4263 s = RSTRING_PTR(str);
4265 pp = rb_enc_prev_char(s, p, p, enc);
4266 if (extra_limit && pp &&
4280 if (rspara && c != EOF)
4281 swallow(fptr,
'\n');
4283 str = io_enc_str(str, fptr);
4286 if (!
NIL_P(str) && !nolimit) {
4294rb_io_getline_1(
VALUE rs,
long limit,
int chomp,
VALUE io)
4297 int old_lineno, new_lineno;
4301 old_lineno = fptr->
lineno;
4302 str = rb_io_getline_0(rs, limit, chomp, fptr);
4303 if (!
NIL_P(str) && (new_lineno = fptr->
lineno) != old_lineno) {
4304 if (io == ARGF.current_file) {
4305 ARGF.lineno += new_lineno - old_lineno;
4306 ARGF.last_lineno = ARGF.lineno;
4309 ARGF.last_lineno = new_lineno;
4317rb_io_getline(
int argc,
VALUE *argv,
VALUE io)
4321 prepare_getline_args(argc, argv, &args, io);
4322 return rb_io_getline_1(args.rs, args.limit, args.chomp, io);
4332rb_io_gets_limit_internal(
VALUE io,
long limit)
4340rb_io_gets_internal(
VALUE io)
4342 return rb_io_gets_limit_internal(io, -1);
4422 str = rb_io_getline(argc, argv, io);
4438rb_io_lineno(
VALUE io)
4493 check_getline_args(&sep, &limit, io);
4495 VALUE line = rb_io_getline_1(sep, limit,
RTEST(chomp), io);
4496 rb_lastline_set_up(line, 1);
4571rb_io_readlines(
int argc,
VALUE *argv,
VALUE io)
4575 prepare_getline_args(argc, argv, &args, io);
4576 return io_readlines(&args, io);
4584 if (arg->limit == 0)
4585 rb_raise(rb_eArgError,
"invalid limit: 0 for readlines");
4587 while (!
NIL_P(line = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, io))) {
4700rb_io_each_line(
int argc,
VALUE *argv,
VALUE io)
4706 prepare_getline_args(argc, argv, &args, io);
4707 if (args.limit == 0)
4708 rb_raise(rb_eArgError,
"invalid limit: 0 for each_line");
4709 while (!
NIL_P(str = rb_io_getline_1(args.rs, args.limit, args.chomp, io))) {
4736rb_io_each_byte(
VALUE io)
4752 }
while (io_fillbuf(fptr) >= 0);
4757io_getc(rb_io_t *fptr, rb_encoding *enc)
4762 if (NEED_READCONV(fptr)) {
4763 rb_encoding *read_enc = io_read_encoding(fptr);
4766 SET_BINARY_MODE(fptr);
4767 make_readconv(fptr, 0);
4781 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4783 clear_readconv(fptr);
4787 str = rb_enc_str_new(fptr->
cbuf.
ptr+fptr->
cbuf.
off, 1, read_enc);
4790 if (fptr->
cbuf.
len == 0) clear_readconv(fptr);
4799 io_shift_cbuf(fptr, r, &str);
4806 ISASCII(RSTRING_PTR(str)[0])) {
4810 str = io_enc_str(str, fptr);
4815 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4816 if (io_fillbuf(fptr) < 0) {
4819 if (rb_enc_asciicompat(enc) && ISASCII(fptr->
rbuf.
ptr[fptr->
rbuf.
off])) {
4838 if (io_fillbuf(fptr) != -1) {
4842 r = rb_enc_precise_mbclen(RSTRING_PTR(str), RSTRING_PTR(str)+RSTRING_LEN(str), enc);
4858 str = io_enc_str(str, fptr);
4884rb_io_each_char(
VALUE io)
4894 enc = io_input_encoding(fptr);
4896 while (!
NIL_P(c = io_getc(fptr, enc))) {
4922rb_io_each_codepoint(
VALUE io)
4934 enc = io_read_encoding(fptr);
4935 if (NEED_READCONV(fptr)) {
4936 SET_BINARY_MODE(fptr);
4939 make_readconv(fptr, 0);
4951 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4952 clear_readconv(fptr);
4972 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4973 while (io_fillbuf(fptr) >= 0) {
4988 char cbuf[8], *p = cbuf;
4990 if (more > numberof(cbuf))
goto invalid;
4992 if (more > numberof(cbuf))
goto invalid;
4993 while ((n = (
int)read_buffered_data(p, more, fptr)) > 0 &&
4994 (p += n, (more -= n) > 0)) {
4995 if (io_fillbuf(fptr) < 0)
goto invalid;
4996 if ((n = fptr->
rbuf.
len) > more) n = more;
4998 r = rb_enc_precise_mbclen(cbuf, p, enc);
5011 rb_raise(rb_eArgError,
"invalid byte sequence in %s", rb_enc_name(enc));
5043 enc = io_input_encoding(fptr);
5045 return io_getc(fptr, enc);
5068rb_io_readchar(
VALUE io)
5070 VALUE c = rb_io_getc(io);
5110 rb_io_flush(r_stdout);
5113 if (io_fillbuf(fptr) < 0) {
5142rb_io_readbyte(
VALUE io)
5203 unsigned char c =
NUM2INT(v) & 0xFF;
5209 io_ungetbyte(b, fptr);
5265 else if (RB_BIGNUM_TYPE_P(c)) {
5271 if (NEED_READCONV(fptr)) {
5272 SET_BINARY_MODE(fptr);
5273 len = RSTRING_LEN(c);
5274#if SIZEOF_LONG > SIZEOF_INT
5278 make_readconv(fptr, (
int)
len);
5292 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
5293 io_ungetbyte(c, fptr);
5313rb_io_isatty(
VALUE io)
5318 return RBOOL(isatty(fptr->
fd) != 0);
5321#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5337rb_io_close_on_exec_p(
VALUE io)
5343 write_io = GetWriteIO(io);
5344 if (io != write_io) {
5346 if (fptr && 0 <= (fd = fptr->
fd)) {
5347 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->
pathv);
5348 if (!(ret & FD_CLOEXEC))
return Qfalse;
5353 if (fptr && 0 <= (fd = fptr->
fd)) {
5354 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->
pathv);
5355 if (!(ret & FD_CLOEXEC))
return Qfalse;
5360#define rb_io_close_on_exec_p rb_f_notimplement
5363#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5387 int flag =
RTEST(arg) ? FD_CLOEXEC : 0;
5392 write_io = GetWriteIO(io);
5393 if (io != write_io) {
5395 if (fptr && 0 <= (fd = fptr->
fd)) {
5396 if ((ret = fcntl(fptr->
fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->
pathv);
5397 if ((ret & FD_CLOEXEC) != flag) {
5398 ret = (ret & ~FD_CLOEXEC) | flag;
5399 ret = fcntl(fd, F_SETFD, ret);
5400 if (ret != 0) rb_sys_fail_path(fptr->
pathv);
5407 if (fptr && 0 <= (fd = fptr->
fd)) {
5408 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->
pathv);
5409 if ((ret & FD_CLOEXEC) != flag) {
5410 ret = (ret & ~FD_CLOEXEC) | flag;
5411 ret = fcntl(fd, F_SETFD, ret);
5412 if (ret != 0) rb_sys_fail_path(fptr->
pathv);
5418#define rb_io_set_close_on_exec rb_f_notimplement
5421#define RUBY_IO_EXTERNAL_P(f) ((f)->mode & FMODE_EXTERNAL)
5422#define PREP_STDIO_NAME(f) (RSTRING_PTR((f)->pathv))
5425finish_writeconv(rb_io_t *fptr,
int noalloc)
5427 unsigned char *ds, *dp, *de;
5431 unsigned char buf[1024];
5436 de = buf +
sizeof(buf);
5439 size_t remaining = dp-ds;
5440 long result = rb_io_write_memory(fptr, ds, remaining);
5444 if ((
size_t)result == remaining)
break;
5467 if (io_fflush(fptr) < 0) {
5475 fptr->
wbuf.
len += (int)(dp - ds);
5491finish_writeconv_sync(
VALUE arg)
5494 return finish_writeconv(p->fptr, p->noalloc);
5498nogvl_close(
void *ptr)
5502 return (
void*)(intptr_t)close(*fd);
5506maygvl_close(
int fd,
int keepgvl)
5515 return IO_WITHOUT_GVL_INT(nogvl_close, &fd);
5519nogvl_fclose(
void *ptr)
5523 return (
void*)(intptr_t)fclose(file);
5527maygvl_fclose(FILE *file,
int keepgvl)
5530 return fclose(file);
5532 return IO_WITHOUT_GVL_INT(nogvl_fclose, file);
5538fptr_finalize_flush(rb_io_t *fptr,
int noraise,
int keepgvl)
5543 int mode = fptr->
mode;
5549 arg.noalloc = noraise;
5553 error = finish_writeconv(fptr, noraise);
5558 io_flush_buffer_sync(fptr);
5561 if (io_fflush(fptr) < 0 &&
NIL_P(error)) {
5569 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2) {
5579 rb_thread_io_close_wait(fptr);
5581 if (!done && stdio_file) {
5583 if ((maygvl_fclose(stdio_file, noraise) < 0) &&
NIL_P(error)) {
5593 if (!done && fd >= 0 && scheduler !=
Qnil) {
5596 if (!UNDEF_P(result)) {
5597 done =
RTEST(result);
5601 if (!done && fd >= 0) {
5607 if ((maygvl_close(fd, keepgvl) < 0) &&
NIL_P(error)) {
5616 if (!
NIL_P(error) && !noraise) {
5625fptr_finalize(rb_io_t *fptr,
int noraise)
5627 fptr_finalize_flush(fptr, noraise, FALSE);
5628 free_io_buffer(&fptr->
rbuf);
5629 free_io_buffer(&fptr->
wbuf);
5630 clear_codeconv(fptr);
5634rb_io_fptr_cleanup(rb_io_t *fptr,
int noraise)
5640 fptr_finalize(fptr, noraise);
5648 ruby_sized_xfree(buf->ptr, (
size_t)buf->capa);
5654clear_readconv(rb_io_t *fptr)
5660 free_io_buffer(&fptr->
cbuf);
5664clear_writeconv(rb_io_t *fptr)
5674clear_codeconv(rb_io_t *fptr)
5676 clear_readconv(fptr);
5677 clear_writeconv(fptr);
5681rb_io_fptr_cleanup_all(rb_io_t *fptr)
5685 rb_io_fptr_cleanup(fptr, TRUE);
5687 free_io_buffer(&fptr->
rbuf);
5688 free_io_buffer(&fptr->
wbuf);
5689 clear_codeconv(fptr);
5696 rb_io_fptr_cleanup_all(io);
5703rb_io_memsize(
const rb_io_t *io)
5705 size_t size =
sizeof(rb_io_t);
5715 rb_serial_t fork_generation = GET_VM()->fork_gen;
5716 if (io->fork_generation == fork_generation) {
5727# define KEEPGVL TRUE
5729# define KEEPGVL FALSE
5733io_close_fptr(
VALUE io)
5737 rb_io_t *write_fptr;
5739 write_io = GetWriteIO(io);
5740 if (io != write_io) {
5741 write_fptr =
RFILE(write_io)->fptr;
5742 if (write_fptr && 0 <= write_fptr->
fd) {
5743 rb_io_fptr_cleanup(write_fptr, TRUE);
5747 fptr =
RFILE(io)->fptr;
5748 if (!fptr)
return 0;
5749 if (fptr->
fd < 0)
return 0;
5752 if (rb_thread_io_close_interrupt(fptr)) {
5754 fptr_finalize_flush(fptr, FALSE, KEEPGVL);
5757 rb_io_fptr_cleanup(fptr, FALSE);
5762fptr_waitpid(rb_io_t *fptr,
int nohang)
5766 rb_last_status_clear();
5775 rb_io_t *fptr = io_close_fptr(io);
5776 if (fptr) fptr_waitpid(fptr, 0);
5816rb_io_close_m(
VALUE io)
5818 rb_io_t *fptr = rb_io_get_fptr(io);
5827io_call_close(
VALUE io)
5836 enum {mesg_len =
sizeof(closed_stream)-1};
5837 VALUE mesg = rb_attr_get(exc, idMesg);
5839 RSTRING_LEN(mesg) != mesg_len ||
5840 memcmp(RSTRING_PTR(mesg), closed_stream, mesg_len)) {
5850 if (!UNDEF_P(closed) &&
RTEST(closed))
return io;
5851 rb_rescue2(io_call_close, io, ignore_closed_stream, io,
5885 rb_io_t *write_fptr;
5887 write_io = GetWriteIO(io);
5888 if (io != write_io) {
5889 write_fptr =
RFILE(write_io)->fptr;
5890 if (write_fptr && 0 <= write_fptr->
fd) {
5895 fptr = rb_io_get_fptr(io);
5896 return RBOOL(0 > fptr->
fd);
5932rb_io_close_read(
VALUE io)
5938 if (fptr->
fd < 0)
return Qnil;
5939 if (is_socket(fptr->
fd, fptr->
pathv)) {
5943 if (shutdown(fptr->
fd, SHUT_RD) < 0)
5944 rb_sys_fail_path(fptr->
pathv);
5951 write_io = GetWriteIO(io);
5952 if (io != write_io) {
5957 RFILE(io)->fptr = wfptr;
5960 RFILE(write_io)->fptr = fptr;
5961 rb_io_fptr_cleanup(fptr, FALSE);
5967 rb_raise(
rb_eIOError,
"closing non-duplex IO for reading");
6005rb_io_close_write(
VALUE io)
6010 write_io = GetWriteIO(io);
6012 if (fptr->
fd < 0)
return Qnil;
6013 if (is_socket(fptr->
fd, fptr->
pathv)) {
6017 if (shutdown(fptr->
fd, SHUT_WR) < 0)
6018 rb_sys_fail_path(fptr->
pathv);
6026 rb_raise(
rb_eIOError,
"closing non-duplex IO for writing");
6029 if (io != write_io) {
6049rb_io_sysseek(
int argc,
VALUE *argv,
VALUE io)
6051 VALUE offset, ptrname;
6052 int whence = SEEK_SET;
6056 if (
rb_scan_args(argc, argv,
"11", &offset, &ptrname) == 2) {
6057 whence = interpret_seek_whence(ptrname);
6062 (READ_DATA_BUFFERED(fptr) || READ_CHAR_PENDING(fptr))) {
6066 rb_warn(
"sysseek for buffered IO");
6069 pos = lseek(fptr->
fd, pos, whence);
6070 if (pos < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
6104 io = GetWriteIO(io);
6109 rb_warn(
"syswrite for buffered IO");
6112 tmp = rb_str_tmp_frozen_acquire(str);
6114 n = rb_io_write_memory(fptr, ptr,
len);
6115 if (n < 0) rb_sys_fail_path(fptr->
pathv);
6116 rb_str_tmp_frozen_release(str, tmp);
6133rb_io_sysread(
int argc,
VALUE *argv,
VALUE io)
6144 shrinkable = io_setstrbuf(&str, ilen);
6145 if (ilen == 0)
return str;
6150 if (READ_DATA_BUFFERED(fptr)) {
6156 io_setstrbuf(&str, ilen);
6161 iis.buf = RSTRING_PTR(str);
6164 n = io_read_memory_locktmp(str, &iis);
6167 rb_sys_fail_path(fptr->
pathv);
6170 io_set_read_length(str, n, shrinkable);
6172 if (n == 0 && ilen > 0) {
6188internal_pread_func(
void *_arg)
6192 return (
VALUE)pread(arg->fd, arg->buf, arg->count, arg->offset);
6196pread_internal_call(
VALUE _arg)
6201 if (scheduler !=
Qnil) {
6204 if (!UNDEF_P(result)) {
6209 return rb_io_blocking_region_wait(arg->io, internal_pread_func, arg,
RUBY_IO_READABLE);
6253 shrinkable = io_setstrbuf(&str, (
long)arg.count);
6254 if (arg.count == 0)
return str;
6255 arg.buf = RSTRING_PTR(str);
6268 rb_sys_fail_path(fptr->
pathv);
6270 io_set_read_length(str, n, shrinkable);
6271 if (n == 0 && arg.count > 0) {
6279internal_pwrite_func(
void *_arg)
6283 return (
VALUE)pwrite(arg->fd, arg->buf, arg->count, arg->offset);
6287pwrite_internal_call(
VALUE _arg)
6292 if (scheduler !=
Qnil) {
6295 if (!UNDEF_P(result)) {
6300 return rb_io_blocking_region_wait(arg->io, internal_pwrite_func, arg,
RUBY_IO_WRITABLE);
6341 io = GetWriteIO(io);
6348 tmp = rb_str_tmp_frozen_acquire(str);
6349 arg.buf = RSTRING_PTR(tmp);
6350 arg.count = (size_t)RSTRING_LEN(tmp);
6352 n = (ssize_t)pwrite_internal_call((
VALUE)&arg);
6353 if (n < 0) rb_sys_fail_path(fptr->
pathv);
6354 rb_str_tmp_frozen_release(str, tmp);
6374 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6377 setmode(fptr->
fd, O_BINARY);
6384io_ascii8bit_binmode(rb_io_t *fptr)
6396 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6402 clear_codeconv(fptr);
6411 io_ascii8bit_binmode(fptr);
6428rb_io_binmode_m(
VALUE io)
6434 write_io = GetWriteIO(io);
6449rb_io_binmode_p(
VALUE io)
6457rb_io_fmode_modestr(
enum rb_io_mode fmode)
6461 return MODE_BTMODE(
"a+",
"ab+",
"at+");
6463 return MODE_BTMODE(
"a",
"ab",
"at");
6467 rb_raise(rb_eArgError,
"invalid access fmode 0x%x", fmode);
6469 return MODE_BTMODE(
"r",
"rb",
"rt");
6471 return MODE_BTXMODE(
"w",
"wb",
"wt",
"wx",
"wbx",
"wtx");
6474 return MODE_BTXMODE(
"w+",
"wb+",
"wt+",
"w+x",
"wb+x",
"wt+x");
6476 return MODE_BTMODE(
"r+",
"rb+",
"rt+");
6480static const char bom_prefix[] =
"bom|";
6481static const char utf_prefix[] =
"utf-";
6482enum {bom_prefix_len = (int)
sizeof(bom_prefix) - 1};
6483enum {utf_prefix_len = (int)
sizeof(utf_prefix) - 1};
6486io_encname_bom_p(
const char *name,
long len)
6488 return len > bom_prefix_len &&
STRNCASECMP(name, bom_prefix, bom_prefix_len) == 0;
6494 enum rb_io_mode fmode = 0;
6495 const char *m = modestr, *p = NULL;
6523 if (modestr[0] !=
'w')
6531 if (io_encname_bom_p(m, p ? (
long)(p - m) : (
long)strlen(m)))
6544 rb_raise(rb_eArgError,
"invalid access mode %s", modestr);
6551 enum rb_io_mode fmode = 0;
6553 switch (oflags & O_ACCMODE) {
6565 if (oflags & O_APPEND) {
6568 if (oflags & O_TRUNC) {
6571 if (oflags & O_CREAT) {
6574 if (oflags & O_EXCL) {
6578 if (oflags & O_BINARY) {
6587rb_io_fmode_oflags(
enum rb_io_mode fmode)
6631rb_io_oflags_modestr(
int oflags)
6634# define MODE_BINARY(a,b) ((oflags & O_BINARY) ? (b) : (a))
6636# define MODE_BINARY(a,b) (a)
6639 if (oflags & O_EXCL) {
6640 rb_raise(rb_eArgError,
"exclusive access mode is not supported");
6642 accmode = oflags & (O_RDONLY|O_WRONLY|O_RDWR);
6643 if (oflags & O_APPEND) {
6644 if (accmode == O_WRONLY) {
6645 return MODE_BINARY(
"a",
"ab");
6647 if (accmode == O_RDWR) {
6648 return MODE_BINARY(
"a+",
"ab+");
6653 rb_raise(rb_eArgError,
"invalid access oflags 0x%x", oflags);
6655 return MODE_BINARY(
"r",
"rb");
6657 return MODE_BINARY(
"w",
"wb");
6659 if (oflags & O_TRUNC) {
6660 return MODE_BINARY(
"w+",
"wb+");
6662 return MODE_BINARY(
"r+",
"rb+");
6672rb_io_ext_int_to_encs(rb_encoding *ext, rb_encoding *intern, rb_encoding **enc, rb_encoding **enc2,
enum rb_io_mode fmode)
6674 int default_ext = 0;
6680 if (rb_is_ascii8bit_enc(ext)) {
6684 else if (intern == NULL) {
6687 if (intern == NULL || intern == (rb_encoding *)
Qnil ||
6690 *enc = (default_ext && intern != ext) ? NULL : ext;
6700unsupported_encoding(
const char *name, rb_encoding *enc)
6702 rb_enc_warn(enc,
"Unsupported encoding %s ignored", name);
6706parse_mode_enc(
const char *estr, rb_encoding *estr_enc,
6707 rb_encoding **enc_p, rb_encoding **enc2_p,
enum rb_io_mode *fmode_p)
6712 enum rb_io_mode fmode = fmode_p ? *fmode_p : 0;
6713 rb_encoding *ext_enc, *int_enc;
6718 p = strrchr(estr,
':');
6719 len = p ? (p++ - estr) : (long)strlen(estr);
6721 estr += bom_prefix_len;
6722 len -= bom_prefix_len;
6723 if (!
STRNCASECMP(estr, utf_prefix, utf_prefix_len)) {
6727 rb_enc_warn(estr_enc,
"BOM with non-UTF encoding %s is nonsense", estr);
6736 memcpy(encname, estr,
len);
6737 encname[
len] =
'\0';
6740 idx = rb_enc_find_index(estr);
6742 if (fmode_p) *fmode_p = fmode;
6745 ext_enc = rb_enc_from_index(idx);
6748 unsupported_encoding(estr, estr_enc);
6754 if (*p ==
'-' && *(p+1) ==
'\0') {
6756 int_enc = (rb_encoding *)
Qnil;
6759 idx2 = rb_enc_find_index(p);
6761 unsupported_encoding(p, estr_enc);
6763 int_enc = (rb_encoding *)
Qnil;
6766 int_enc = rb_enc_from_index(idx2);
6770 rb_io_ext_int_to_encs(ext_enc, int_enc, enc_p, enc2_p, fmode);
6778 rb_encoding *extencoding = NULL;
6779 rb_encoding *intencoding = NULL;
6783 v = rb_hash_lookup2(opt, sym_encoding,
Qnil);
6784 if (v !=
Qnil) encoding = v;
6785 v = rb_hash_lookup2(opt, sym_extenc,
Qundef);
6786 if (v !=
Qnil) extenc = v;
6787 v = rb_hash_lookup2(opt, sym_intenc,
Qundef);
6788 if (!UNDEF_P(v)) intenc = v;
6790 if ((!UNDEF_P(extenc) || !UNDEF_P(intenc)) && !
NIL_P(encoding)) {
6792 int idx = rb_to_encoding_index(encoding);
6793 if (idx >= 0) encoding = rb_enc_from_encoding(rb_enc_from_index(idx));
6794 rb_warn(
"Ignoring encoding parameter '%"PRIsVALUE
"': %s_encoding is used",
6795 encoding, UNDEF_P(extenc) ?
"internal" :
"external");
6799 if (!UNDEF_P(extenc) && !
NIL_P(extenc)) {
6800 extencoding = rb_to_encoding(extenc);
6802 if (!UNDEF_P(intenc)) {
6803 if (
NIL_P(intenc)) {
6805 intencoding = (rb_encoding *)
Qnil;
6810 if (*p ==
'-' && *(p+1) ==
'\0') {
6812 intencoding = (rb_encoding *)
Qnil;
6815 intencoding = rb_to_encoding(intenc);
6819 intencoding = rb_to_encoding(intenc);
6821 if (extencoding == intencoding) {
6822 intencoding = (rb_encoding *)
Qnil;
6825 if (!
NIL_P(encoding)) {
6829 enc_p, enc2_p, fmode_p);
6832 rb_io_ext_int_to_encs(rb_to_encoding(encoding), NULL, enc_p, enc2_p, 0);
6835 else if (!UNDEF_P(extenc) || !UNDEF_P(intenc)) {
6837 rb_io_ext_int_to_encs(extencoding, intencoding, enc_p, enc2_p, 0);
6843validate_enc_binmode(
enum rb_io_mode *fmode_p,
int ecflags, rb_encoding *enc, rb_encoding *enc2)
6845 enum rb_io_mode fmode = *fmode_p;
6851 rb_raise(rb_eArgError,
"ASCII incompatible encoding needs binmode");
6854 rb_raise(rb_eArgError,
"newline decorator with binary mode");
6861#if !DEFAULT_TEXTMODE
6870extract_binmode(
VALUE opthash,
enum rb_io_mode *fmode)
6872 if (!
NIL_P(opthash)) {
6874 v = rb_hash_aref(opthash, sym_textmode);
6877 rb_raise(rb_eArgError,
"textmode specified twice");
6879 rb_raise(rb_eArgError,
"both textmode and binmode specified");
6883 v = rb_hash_aref(opthash, sym_binmode);
6886 rb_raise(rb_eArgError,
"binmode specified twice");
6888 rb_raise(rb_eArgError,
"both textmode and binmode specified");
6894 rb_raise(rb_eArgError,
"both textmode and binmode specified");
6900 int *oflags_p,
enum rb_io_mode *fmode_p,
struct rb_io_encoding *convconfig_p)
6904 enum rb_io_mode fmode;
6905 rb_encoding *enc, *enc2;
6908 int has_enc = 0, has_vmode = 0;
6914 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
6932 oflags = rb_io_fmode_oflags(fmode);
6936 parse_mode_enc(p+1, rb_enc_get(vmode), &enc, &enc2, &fmode);
6942 rb_io_ext_int_to_encs(e, NULL, &enc, &enc2, fmode);
6946 if (
NIL_P(opthash)) {
6950#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
6952 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
6953 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
6955 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
6965 else if (
NIL_P(vmode)) {
6966 fmode |= DEFAULT_TEXTMODE;
6973 v = rb_hash_aref(opthash, sym_mode);
6975 if (!
NIL_P(vmode)) {
6976 rb_raise(rb_eArgError,
"mode specified twice");
6983 v = rb_hash_aref(opthash, sym_flags);
6990 extract_binmode(opthash, &fmode);
6999 else if (
NIL_P(vmode)) {
7000 fmode |= DEFAULT_TEXTMODE;
7003 v = rb_hash_aref(opthash, sym_perm);
7006 if (!
NIL_P(*vperm_p)) {
7007 rb_raise(rb_eArgError,
"perm specified twice");
7018#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7020 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7021 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7026 rb_raise(rb_eArgError,
"encoding specified twice");
7029 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
7033 validate_enc_binmode(&fmode, ecflags, enc, enc2);
7039 convconfig_p->
enc = enc;
7040 convconfig_p->
enc2 = enc2;
7041 convconfig_p->
ecflags = ecflags;
7042 convconfig_p->
ecopts = ecopts;
7052sysopen_func(
void *ptr)
7055 const char *fname = RSTRING_PTR(data->fname);
7064 fd = IO_WITHOUT_GVL_INT(sysopen_func, data);
7065 }
while (fd < 0 &&
errno == EINTR);
7072rb_sysopen(
VALUE fname,
int oflags, mode_t perm)
7077 data.fname = rb_str_encode_ospath(fname);
7079 data.oflags = oflags;
7082 TRY_WITH_GC((fd = rb_sysopen_internal(&data)) >= 0) {
7083 rb_syserr_fail_path(first_errno, fname);
7089fdopen_internal(
int fd,
const char *modestr)
7096 file = fdopen(fd, modestr);
7112 TRY_WITH_GC((file = fdopen_internal(fd, modestr)) != 0) {
7118 if (setvbuf(file, NULL, _IOFBF, 0) != 0)
7119 rb_warn(
"setvbuf() can't be honoured (fd=%d)", fd);
7125io_check_tty(rb_io_t *fptr)
7127 int t = isatty(fptr->
fd);
7137io_strip_bom(
VALUE io)
7139 VALUE b1, b2, b3, b4;
7160 return ENCINDEX_UTF_16BE;
7171 return ENCINDEX_UTF_32LE;
7176 return ENCINDEX_UTF_16LE;
7186 return ENCINDEX_UTF_32BE;
7200io_set_encoding_by_bom(
VALUE io)
7202 int idx = io_strip_bom(io);
7204 rb_encoding *extenc = NULL;
7208 extenc = rb_enc_from_index(idx);
7209 io_encoding_set(fptr, rb_enc_from_encoding(extenc),
7210 rb_io_internal_encoding(io),
Qnil);
7219rb_file_open_generic(
VALUE io,
VALUE filename,
int oflags,
enum rb_io_mode fmode,
7227 rb_io_ext_int_to_encs(NULL, NULL, &cc.enc, &cc.enc2, fmode);
7232 validate_enc_binmode(&fmode, convconfig->
ecflags,
7233 convconfig->
enc, convconfig->
enc2);
7237 fptr->
encs = *convconfig;
7240 if (!(oflags & O_TMPFILE)) {
7241 fptr->
pathv = pathv;
7244 fptr->
pathv = pathv;
7246 fptr->
fd = rb_sysopen(pathv, oflags, perm);
7254rb_file_open_internal(
VALUE io,
VALUE filename,
const char *modestr)
7257 const char *p = strchr(modestr,
':');
7262 &convconfig.
enc, &convconfig.
enc2, &fmode);
7269 rb_io_ext_int_to_encs(e, NULL, &convconfig.
enc, &convconfig.
enc2, fmode);
7275#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7277 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7278 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7280 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.
enc2, convconfig.
ecflags);
7283 return rb_file_open_generic(io, filename,
7284 rb_io_fmode_oflags(fmode),
7294 return rb_file_open_internal(io_alloc(
rb_cFile), fname, modestr);
7303#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7310pipe_add_fptr(rb_io_t *fptr)
7321pipe_del_fptr(rb_io_t *fptr)
7326 while ((tmp = *prev) != 0) {
7327 if (tmp->fptr == fptr) {
7336#if defined (_WIN32) || defined(__CYGWIN__)
7352pipe_finalize(rb_io_t *fptr,
int noraise)
7354#if !defined(HAVE_WORKING_FORK) && !defined(_WIN32)
7363 fptr_finalize(fptr, noraise);
7365 pipe_del_fptr(fptr);
7370fptr_copy_finalizer(rb_io_t *fptr,
const rb_io_t *orig)
7372#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7373 void (*
const old_finalize)(
struct rb_io*,int) = fptr->
finalize;
7375 if (old_finalize == orig->finalize)
return;
7380#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7381 if (old_finalize != pipe_finalize) {
7383 for (list =
pipe_list; list; list = list->next) {
7384 if (list->fptr == fptr)
break;
7386 if (!list) pipe_add_fptr(fptr);
7389 pipe_del_fptr(fptr);
7402rb_io_unbuffered(rb_io_t *fptr)
7420#define HAVE_SPAWNV 1
7421#define spawnv(mode, cmd, args) rb_w32_uaspawn((mode), (cmd), (args))
7422#define spawn(mode, cmd) rb_w32_uspawn((mode), (cmd), 0)
7425#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7428 struct rb_execarg *eargp;
7435#ifdef HAVE_WORKING_FORK
7436# ifndef __EMSCRIPTEN__
7438popen_redirect(
struct popen_arg *p)
7441 close(p->write_pair[1]);
7442 if (p->write_pair[0] != 0) {
7443 dup2(p->write_pair[0], 0);
7444 close(p->write_pair[0]);
7447 if (p->pair[1] != 1) {
7448 dup2(p->pair[1], 1);
7454 if (p->pair[1] != 1) {
7455 dup2(p->pair[1], 1);
7461 if (p->pair[0] != 0) {
7462 dup2(p->pair[0], 0);
7469#if defined(__linux__)
7480linux_get_maxfd(
void)
7483 char buf[4096], *p, *np, *e;
7486 if (fd < 0)
return fd;
7487 ss = read(fd, buf,
sizeof(buf));
7488 if (ss < 0)
goto err;
7491 while ((
int)
sizeof(
"FDSize:\t0\n")-1 <= e-p &&
7492 (np = memchr(p,
'\n', e-p)) != NULL) {
7493 if (memcmp(p,
"FDSize:",
sizeof(
"FDSize:")-1) == 0) {
7495 p +=
sizeof(
"FDSize:")-1;
7515#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
7517 int max = (int)max_file_descriptor;
7520 ret = fcntl(0, F_MAXFD);
7522 maxhint = max = ret;
7523# elif defined(__linux__)
7524 ret = linux_get_maxfd();
7531 for (fd = lowfd; fd <= max; fd++) {
7532 if (!
NIL_P(noclose_fds) &&
7535 ret = fcntl(fd, F_GETFD);
7536 if (ret != -1 && !(ret & FD_CLOEXEC)) {
7537 fcntl(fd, F_SETFD, ret|FD_CLOEXEC);
7539# define CONTIGUOUS_CLOSED_FDS 20
7541 if (max < fd + CONTIGUOUS_CLOSED_FDS)
7542 max = fd + CONTIGUOUS_CLOSED_FDS;
7548# ifndef __EMSCRIPTEN__
7550popen_exec(
void *pp,
char *errmsg,
size_t errmsg_len)
7552 struct popen_arg *p = (
struct popen_arg*)pp;
7554 return rb_exec_async_signal_safe(p->eargp, errmsg, errmsg_len);
7559#if (defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)) && !defined __EMSCRIPTEN__
7561rb_execarg_fixup_v(
VALUE execarg_obj)
7563 rb_execarg_parent_start(execarg_obj);
7567char *rb_execarg_commandline(
const struct rb_execarg *eargp,
VALUE *prog);
7570#ifndef __EMSCRIPTEN__
7572pipe_open(
VALUE execarg_obj,
const char *modestr,
enum rb_io_mode fmode,
7575 struct rb_execarg *eargp =
NIL_P(execarg_obj) ? NULL : rb_execarg_get(execarg_obj);
7576 VALUE prog = eargp ? (eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name) :
Qfalse ;
7580 rb_io_t *write_fptr;
7582#if defined(HAVE_WORKING_FORK)
7584 char errmsg[80] = {
'\0' };
7586#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7588 struct popen_arg arg;
7591#if defined(HAVE_SPAWNV)
7592# if defined(HAVE_SPAWNVE)
7593# define DO_SPAWN(cmd, args, envp) ((args) ? \
7594 spawnve(P_NOWAIT, (cmd), (args), (envp)) : \
7595 spawne(P_NOWAIT, (cmd), (envp)))
7597# define DO_SPAWN(cmd, args, envp) ((args) ? \
7598 spawnv(P_NOWAIT, (cmd), (args)) : \
7599 spawn(P_NOWAIT, (cmd)))
7601# if !defined(HAVE_WORKING_FORK)
7603# if defined(HAVE_SPAWNVE)
7608#if !defined(HAVE_WORKING_FORK)
7614#if !defined(HAVE_WORKING_FORK)
7615 const char *cmd = 0;
7621#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7622 arg.execarg_obj = execarg_obj;
7625 arg.pair[0] = arg.pair[1] = -1;
7626 arg.write_pair[0] = arg.write_pair[1] = -1;
7627# if !defined(HAVE_WORKING_FORK)
7628 if (eargp && !eargp->use_shell) {
7629 args = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
7634 if (
rb_pipe(arg.write_pair) < 0)
7635 rb_sys_fail_str(prog);
7638 close(arg.write_pair[0]);
7639 close(arg.write_pair[1]);
7643 rb_execarg_addopt(execarg_obj,
INT2FIX(0),
INT2FIX(arg.write_pair[0]));
7644 rb_execarg_addopt(execarg_obj,
INT2FIX(1),
INT2FIX(arg.pair[1]));
7649 rb_sys_fail_str(prog);
7651 rb_execarg_addopt(execarg_obj,
INT2FIX(1),
INT2FIX(arg.pair[1]));
7655 rb_sys_fail_str(prog);
7657 rb_execarg_addopt(execarg_obj,
INT2FIX(0),
INT2FIX(arg.pair[0]));
7660 rb_sys_fail_str(prog);
7662 if (!
NIL_P(execarg_obj)) {
7663 rb_protect(rb_execarg_fixup_v, execarg_obj, &state);
7665 if (0 <= arg.write_pair[0]) close(arg.write_pair[0]);
7666 if (0 <= arg.write_pair[1]) close(arg.write_pair[1]);
7667 if (0 <= arg.pair[0]) close(arg.pair[0]);
7668 if (0 <= arg.pair[1]) close(arg.pair[1]);
7669 rb_execarg_parent_end(execarg_obj);
7673# if defined(HAVE_WORKING_FORK)
7674 pid = rb_fork_async_signal_safe(&status, popen_exec, &arg, arg.eargp->redirect_fds, errmsg,
sizeof(errmsg));
7676 rb_execarg_run_options(eargp, sargp, NULL, 0);
7677# if defined(HAVE_SPAWNVE)
7678 if (eargp->envp_str) envp = (
char **)RSTRING_PTR(eargp->envp_str);
7680 while ((pid = DO_SPAWN(cmd, args, envp)) < 0) {
7682 switch (e =
errno) {
7684# if EWOULDBLOCK != EAGAIN
7693 rb_execarg_run_options(sargp, NULL, NULL, 0);
7695 rb_execarg_parent_end(execarg_obj);
7698# if defined(HAVE_WORKING_FORK)
7699 pid = rb_call_proc__fork();
7701 popen_redirect(&arg);
7713# if defined(HAVE_WORKING_FORK)
7719 close(arg.write_pair[0]);
7720 close(arg.write_pair[1]);
7722# if defined(HAVE_WORKING_FORK)
7731 close(arg.write_pair[0]);
7732 write_fd = arg.write_pair[1];
7743 cmd = rb_execarg_commandline(eargp, &prog);
7744 if (!
NIL_P(execarg_obj)) {
7745 rb_execarg_parent_start(execarg_obj);
7746 rb_execarg_run_options(eargp, sargp, NULL, 0);
7748 fp = popen(cmd, modestr);
7751 rb_execarg_parent_end(execarg_obj);
7752 rb_execarg_run_options(sargp, NULL, NULL, 0);
7754 if (!fp) rb_syserr_fail_path(e, prog);
7764 fptr->
encs = *convconfig;
7765#if RUBY_CRLF_ENVIRONMENT
7772 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
7775#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7776 if (NEED_NEWLINE_DECORATOR_ON_WRITE(fptr)) {
7777 fptr->
encs.
ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
7783 if (0 <= write_fd) {
7784 write_port = io_alloc(
rb_cIO);
7786 write_fptr->
fd = write_fd;
7790 rb_ivar_set(port, rb_intern(
"@tied_io_for_writing"), write_port);
7793#if defined (__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7795 pipe_add_fptr(fptr);
7801pipe_open(
VALUE execarg_obj,
const char *modestr,
enum rb_io_mode fmode,
7809is_popen_fork(
VALUE prog)
7811 if (RSTRING_LEN(prog) == 1 && RSTRING_PTR(prog)[0] ==
'-') {
7812#if !defined(HAVE_WORKING_FORK)
7814 "fork() function is unimplemented on this machine");
7823pipe_open_s(
VALUE prog,
const char *modestr,
enum rb_io_mode fmode,
7827 VALUE *argv = &prog;
7830 if (!is_popen_fork(prog))
7831 execarg_obj = rb_execarg_new(argc, argv, TRUE, FALSE);
7832 return pipe_open(execarg_obj, modestr, fmode, convconfig);
7838 rb_io_t *fptr = io_close_fptr(io);
8007rb_io_s_popen(
int argc,
VALUE *argv,
VALUE klass)
8011 if (argc > 1 && !
NIL_P(opt = rb_check_hash_type(argv[argc-1]))) --argc;
8012 if (argc > 1 && !
NIL_P(env = rb_check_hash_type(argv[0]))) --argc, ++argv;
8021 int ex = !
NIL_P(opt);
8022 rb_error_arity(argc + ex, 1 + ex, 2 + ex);
8025 return popen_finish(rb_io_popen(pname, pmode, env, opt), klass);
8031 const char *modestr;
8034 enum rb_io_mode fmode;
8040#if SIZEOF_LONG > SIZEOF_INT
8041 if (
len > INT_MAX) {
8042 rb_raise(rb_eArgError,
"too many arguments");
8051 if (!is_popen_fork(pname))
8052 execarg_obj = rb_execarg_new(1, &pname, TRUE, FALSE);
8054 if (!
NIL_P(execarg_obj)) {
8056 opt = rb_execarg_extract_options(execarg_obj, opt);
8058 rb_execarg_setenv(execarg_obj, env);
8061 modestr = rb_io_oflags_modestr(oflags);
8063 return pipe_open(execarg_obj, modestr, fmode, &convconfig);
8079 RBASIC_SET_CLASS(port, klass);
8086#if defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)
8087struct popen_writer_arg {
8089 struct popen_arg popen;
8093exec_popen_writer(
void *arg,
char *errmsg,
size_t buflen)
8095 struct popen_writer_arg *pw = arg;
8097 popen_redirect(&pw->popen);
8098 execv(pw->argv[0], pw->argv);
8099 strlcpy(errmsg, strerror(
errno), buflen);
8105ruby_popen_writer(
char *
const *argv, rb_pid_t *pid)
8107#if (defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)) || defined(_WIN32)
8108# ifdef HAVE_WORKING_FORK
8109 struct popen_writer_arg pw;
8110 int *
const write_pair = pw.popen.pair;
8116 int result = pipe2(write_pair, O_CLOEXEC);
8118 int result = pipe(write_pair);
8123# ifdef HAVE_WORKING_FORK
8126 char errmsg[80] = {
'\0'};
8127 *pid = rb_fork_async_signal_safe(&status, exec_popen_writer, &pw,
Qnil, errmsg,
sizeof(errmsg));
8129 *pid = rb_w32_uspawn_process(P_NOWAIT, argv[0], argv, write_pair[0], -1, -1, 0);
8130 const char *errmsg = (*pid < 0) ? strerror(
errno) : NULL;
8132 close(write_pair[0]);
8134 close(write_pair[1]);
8135 fprintf(stderr,
"ruby_popen_writer(%s): %s\n", argv[0], errmsg);
8138 return fdopen(write_pair[1],
"w");
8149 enum rb_io_mode fmode;
8158 rb_file_open_generic(io, fname, oflags, fmode, &convconfig, perm);
8196rb_io_s_open(
int argc,
VALUE *argv,
VALUE klass)
8228 VALUE fname, vmode, vperm;
8233 rb_scan_args(argc, argv,
"12", &fname, &vmode, &vperm);
8244 if (
NIL_P(vperm)) perm = 0666;
8248 fd = rb_sysopen(fname, oflags, perm);
8280 int redirect = FALSE;
8288 VALUE tmp = argv[0];
8306 return rb_io_s_open(argc, argv,
rb_cFile);
8310rb_io_open_generic(
VALUE klass,
VALUE filename,
int oflags,
enum rb_io_mode fmode,
8313 return rb_file_open_generic(io_alloc(klass), filename,
8314 oflags, fmode, convconfig, perm);
8321 enum rb_io_mode fmode;
8327 return rb_io_open_generic(io, filename, oflags, fmode, &convconfig, perm);
8333 rb_io_t *fptr, *orig;
8341 if (fptr == orig)
return io;
8342 if (RUBY_IO_EXTERNAL_P(fptr)) {
8346 rb_raise(rb_eArgError,
8347 "%s can't change access mode from \"%s\" to \"%s\"",
8348 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->
mode),
8349 rb_io_fmode_modestr(orig->
mode));
8353 if (io_fflush(fptr) < 0)
8354 rb_sys_fail_on_write(fptr);
8357 flush_before_seek(fptr,
true);
8360 pos = io_tell(orig);
8363 if (io_fflush(orig) < 0)
8364 rb_sys_fail_on_write(fptr);
8373 else if (!RUBY_IO_EXTERNAL_P(fptr)) fptr->
pathv =
Qnil;
8374 fptr_copy_finalizer(fptr, orig);
8380 rb_thread_io_close_interrupt(fptr);
8381 rb_thread_io_close_wait(fptr);
8383 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2 || !fptr->stdio_file) {
8386 rb_sys_fail_path(orig->
pathv);
8394 rb_sys_fail_path(orig->
pathv);
8400 if (io_seek(fptr, pos, SEEK_SET) < 0 &&
errno) {
8401 rb_sys_fail_path(fptr->
pathv);
8403 if (io_seek(orig, pos, SEEK_SET) < 0 &&
errno) {
8404 rb_sys_fail_path(orig->
pathv);
8418int rb_freopen(
VALUE fname,
const char *mode, FILE *fp);
8421rb_freopen(
VALUE fname,
const char *mode, FILE *fp)
8423 if (!freopen(RSTRING_PTR(fname), mode, fp)) {
8466rb_io_reopen(
int argc,
VALUE *argv,
VALUE file)
8468 VALUE fname, nmode, opt;
8472 if (
rb_scan_args(argc, argv,
"11:", &fname, &nmode, &opt) == 1) {
8475 return io_reopen(file, tmp);
8481 fptr =
RFILE(file)->fptr;
8487 enum rb_io_mode fmode;
8491 if (RUBY_IO_EXTERNAL_P(fptr) &&
8494 rb_raise(rb_eArgError,
8495 "%s can't change access mode from \"%s\" to \"%s\"",
8496 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->
mode),
8497 rb_io_fmode_modestr(fmode));
8500 fptr->
encs = convconfig;
8503 oflags = rb_io_fmode_oflags(fptr->
mode);
8506 fptr->
pathv = fname;
8508 fptr->
fd = rb_sysopen(fptr->
pathv, oflags, 0666);
8514 if (io_fflush(fptr) < 0)
8515 rb_sys_fail_on_write(fptr);
8520 int e = rb_freopen(rb_str_encode_ospath(fptr->
pathv),
8521 rb_io_oflags_modestr(oflags),
8523 if (e) rb_syserr_fail_path(e, fptr->
pathv);
8527 if (setvbuf(fptr->
stdio_file, NULL, _IOFBF, 0) != 0)
8528 rb_warn(
"setvbuf() can't be honoured for %"PRIsVALUE, fptr->
pathv);
8531 if (setvbuf(fptr->
stdio_file, NULL, _IONBF, BUFSIZ) != 0)
8532 rb_warn(
"setvbuf() can't be honoured for %"PRIsVALUE, fptr->
pathv);
8534 else if (fptr->
stdio_file == stdout && isatty(fptr->
fd)) {
8535 if (setvbuf(fptr->
stdio_file, NULL, _IOLBF, BUFSIZ) != 0)
8536 rb_warn(
"setvbuf() can't be honoured for %"PRIsVALUE, fptr->
pathv);
8540 int tmpfd = rb_sysopen(fptr->
pathv, oflags, 0666);
8546 rb_syserr_fail_path(err, fptr->
pathv);
8557 rb_io_t *fptr, *orig;
8577 fptr->closing_ec = NULL;
8578 fptr->wakeup_mutex =
Qnil;
8579 fptr->fork_generation = GET_VM()->fork_gen;
8582 fptr_copy_finalizer(fptr, orig);
8584 fd = ruby_dup(orig->
fd);
8586 pos = io_tell(orig);
8588 io_seek(fptr, pos, SEEK_SET);
8593 write_io = GetWriteIO(io);
8594 if (io != write_io) {
8597 rb_ivar_set(dest, rb_intern(
"@tied_io_for_writing"), write_io);
8660 if (argc == 0)
return Qnil;
8674extern void rb_deprecated_str_setter(
VALUE val,
ID id,
VALUE *var);
8679 rb_deprecated_str_setter(val,
id, &val);
8685 val = rb_str_frozen_bare_string(val);
8762 for (i=0; i<argc; i++) {
8766 rb_io_write(out, argv[i]);
8863 rb_io_write(io, str);
8867#define forward(obj, id, argc, argv) \
8868 rb_funcallv_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8869#define forward_public(obj, id, argc, argv) \
8870 rb_funcallv_public_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8871#define forward_current(id, argc, argv) \
8872 forward_public(ARGF.current_file, id, argc, argv)
8890 if (recv == r_stdout) {
8891 return rb_io_putc(recv, ch);
8893 return forward(r_stdout, rb_intern(
"putc"), 1, &ch);
8898rb_str_end_with_asciichar(
VALUE str,
int c)
8900 long len = RSTRING_LEN(str);
8901 const char *ptr = RSTRING_PTR(str);
8905 if (
len == 0)
return 0;
8906 if ((n = rb_enc_mbminlen(
enc)) == 1) {
8907 return ptr[
len - 1] == c;
8909 return rb_enc_ascget(ptr + ((
len - 1) / n) * n, ptr +
len, &n,
enc) == c;
8920 rb_io_puts(1, &tmp, out);
8927 rb_io_puts(1, &tmp, out);
8982 VALUE line, args[2];
8989 for (
int i = 0; i < argc; i++) {
9003 if (RSTRING_LEN(line) == 0) {
9008 if (!rb_str_end_with_asciichar(line,
'\n')) {
9013 rb_io_writev(out, n, args);
9032 if (recv == r_stdout) {
9033 return rb_io_puts(argc, argv, recv);
9035 return forward(r_stdout, rb_intern(
"puts"), argc, argv);
9039rb_p_write(
VALUE str)
9046 rb_method_basic_definition_p(
CLASS_OF(r_stdout), id_write)) {
9047 io_writev(2, args, r_stdout);
9050 rb_io_writev(r_stdout, 2, args);
9062rb_p_result(
int argc,
const VALUE *argv)
9069 else if (argc > 1) {
9074 rb_uninterruptible(rb_io_flush, r_stdout);
9115 for (i=0; i<argc; i++) {
9117 rb_uninterruptible(rb_p_write, inspected);
9119 return rb_p_result(argc, argv);
9140rb_obj_display(
int argc,
VALUE *argv,
VALUE self)
9145 rb_io_write(out, self);
9151rb_stderr_to_original_p(
VALUE err)
9153 return (err == orig_stderr ||
RFILE(orig_stderr)->fptr->
fd < 0);
9160 if (rb_stderr_to_original_p(out)) {
9162 if (isatty(fileno(stderr))) {
9163 if (rb_w32_write_console(
rb_str_new(mesg,
len), fileno(stderr)) > 0)
return;
9166 if (fwrite(mesg,
sizeof(
char), (
size_t)
len, stderr) < (
size_t)
len) {
9183rb_write_error_str(
VALUE mesg)
9187 if (rb_stderr_to_original_p(out)) {
9188 size_t len = (size_t)RSTRING_LEN(mesg);
9190 if (isatty(fileno(stderr))) {
9191 if (rb_w32_write_console(mesg, fileno(stderr)) > 0)
return;
9194 if (fwrite(RSTRING_PTR(mesg),
sizeof(
char),
len, stderr) <
len) {
9201 rb_io_write(out, mesg);
9206rb_stderr_tty_p(
void)
9209 return isatty(fileno(stderr));
9214must_respond_to(
ID mid,
VALUE val,
ID id)
9217 rb_raise(
rb_eTypeError,
"%"PRIsVALUE
" must have %"PRIsVALUE
" method, %"PRIsVALUE
" given",
9218 rb_id2str(
id), rb_id2str(mid),
9230stdin_getter(
ID id,
VALUE *ptr)
9238 must_respond_to(id_write, val,
id);
9243stdout_getter(
ID id,
VALUE *ptr)
9251 must_respond_to(id_write, val,
id);
9256stderr_getter(
ID id,
VALUE *ptr)
9262allocate_and_open_new_file(
VALUE klass)
9264 VALUE self = io_alloc(klass);
9265 rb_io_make_open_file(self);
9273 VALUE self = rb_protect(allocate_and_open_new_file, klass, &state);
9281 maygvl_close(descriptor, 0);
9287 rb_io_t *io =
RFILE(self)->fptr;
9289 io->
fd = descriptor;
9307 io->closing_ec = NULL;
9308 io->wakeup_mutex =
Qnil;
9309 io->fork_generation = GET_VM()->fork_gen;
9312 io->
encs = *encoding;
9321prep_io(
int fd,
enum rb_io_mode fmode,
VALUE klass,
const char *path)
9332 rb_io_ext_int_to_encs(e, NULL, &convconfig.
enc, &convconfig.
enc2, fmode);
9336#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9338 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
9339 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
9341 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.
enc2, convconfig.
ecflags);
9345 rb_io_t*io =
RFILE(self)->fptr;
9347 if (!io_check_tty(io)) {
9350 setmode(fd, O_BINARY);
9362 if (path && strcmp(path,
"-")) klass =
rb_cFile;
9367prep_stdio(FILE *f,
enum rb_io_mode fmode,
VALUE klass,
const char *path)
9374#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9375 fptr->
encs.
ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
9386rb_io_prep_stdin(
void)
9392rb_io_prep_stdout(
void)
9398rb_io_prep_stderr(
void)
9407 int oflags = rb_io_fmode_oflags(fptr->
mode) & ~O_EXCL;
9422static inline rb_io_t *
9425 rb_io_t *fp =
ALLOC(rb_io_t);
9434 rb_io_buffer_init(&fp->
wbuf);
9435 rb_io_buffer_init(&fp->
rbuf);
9436 rb_io_buffer_init(&fp->
cbuf);
9451 fp->closing_ec = NULL;
9452 fp->wakeup_mutex =
Qnil;
9453 fp->fork_generation = GET_VM()->fork_gen;
9458rb_io_make_open_file(
VALUE obj)
9463 if (
RFILE(obj)->fptr) {
9466 RFILE(obj)->fptr = 0;
9468 fp = rb_io_fptr_new();
9470 RFILE(obj)->fptr = fp;
9518rb_io_initialize(
int argc,
VALUE *argv,
VALUE io)
9524 return io_initialize(io, fnum, vmode, opt);
9531 int fd, oflags = O_RDONLY;
9532 enum rb_io_mode fmode;
9534#if defined(HAVE_FCNTL) && defined(F_GETFL)
9544 rb_raise(rb_eArgError,
"The given fd is not accessible because RubyVM reserves it");
9546#if defined(HAVE_FCNTL) && defined(F_GETFL)
9547 oflags = fcntl(fd, F_GETFL);
9548 if (oflags == -1) rb_sys_fail(0);
9550 if (fstat(fd, &st) < 0) rb_sys_fail(0);
9553#if defined(HAVE_FCNTL) && defined(F_GETFL)
9566 if (rb_hash_aref(opt, sym_autoclose) ==
Qfalse) {
9570 path = rb_hash_aref(opt,
RB_ID2SYM(idPath));
9581 fp->
encs = convconfig;
9585 fp->closing_ec = NULL;
9586 fp->wakeup_mutex =
Qnil;
9587 fp->fork_generation = GET_VM()->fork_gen;
9590 if (fileno(stdin) == fd)
9592 else if (fileno(stdout) == fd)
9594 else if (fileno(stderr) == fd)
9626rb_io_set_encoding_by_bom(
VALUE io)
9632 rb_raise(rb_eArgError,
"ASCII incompatible encoding needs binmode");
9635 rb_raise(rb_eArgError,
"encoding conversion is set");
9637 else if (fptr->
encs.
enc && fptr->
encs.
enc != rb_ascii8bit_encoding()) {
9638 rb_raise(rb_eArgError,
"encoding is set to %s already",
9641 if (!io_set_encoding_by_bom(io))
return Qnil;
9642 return rb_enc_from_encoding(fptr->
encs.
enc);
9687rb_file_initialize(
int argc,
VALUE *argv,
VALUE io)
9689 if (
RFILE(io)->fptr) {
9692 VALUE fname, vmode, vperm, opt;
9693 int posargc =
rb_scan_args(argc, argv,
"12:", &fname, &vmode, &vperm, &opt);
9698 return io_initialize(io, fd, vmode, opt);
9701 return rb_open_file(io, fname, vmode, vperm, opt);
9706rb_io_s_new(
int argc,
VALUE *argv,
VALUE klass)
9711 rb_warn(
"%"PRIsVALUE
"::new() does not take block; use %"PRIsVALUE
"::open() instead",
9727rb_io_s_for_fd(
int argc,
VALUE *argv,
VALUE klass)
9730 rb_io_initialize(argc, argv, io);
9743rb_io_autoclose_p(
VALUE io)
9745 rb_io_t *fptr =
RFILE(io)->fptr;
9768rb_io_set_autoclose(
VALUE io,
VALUE autoclose)
9772 if (!
RTEST(autoclose))
9780io_wait_event(
VALUE io,
int event,
VALUE timeout,
int return_io)
9812io_wait_readable(
int argc,
VALUE *argv,
VALUE io)
9822 VALUE timeout = (argc == 1 ? argv[0] :
Qnil);
9836io_wait_writable(
int argc,
VALUE *argv,
VALUE io)
9844 VALUE timeout = (argc == 1 ? argv[0] :
Qnil);
9859io_wait_priority(
int argc,
VALUE *argv,
VALUE io)
9861 rb_io_t *fptr = NULL;
9869 VALUE timeout = argc == 1 ? argv[0] :
Qnil;
9875wait_mode_sym(
VALUE mode)
9877 if (mode ==
ID2SYM(rb_intern(
"r"))) {
9878 return RB_WAITFD_IN;
9880 if (mode ==
ID2SYM(rb_intern(
"read"))) {
9881 return RB_WAITFD_IN;
9883 if (mode ==
ID2SYM(rb_intern(
"readable"))) {
9884 return RB_WAITFD_IN;
9886 if (mode ==
ID2SYM(rb_intern(
"w"))) {
9887 return RB_WAITFD_OUT;
9889 if (mode ==
ID2SYM(rb_intern(
"write"))) {
9890 return RB_WAITFD_OUT;
9892 if (mode ==
ID2SYM(rb_intern(
"writable"))) {
9893 return RB_WAITFD_OUT;
9895 if (mode ==
ID2SYM(rb_intern(
"rw"))) {
9896 return RB_WAITFD_IN|RB_WAITFD_OUT;
9898 if (mode ==
ID2SYM(rb_intern(
"read_write"))) {
9899 return RB_WAITFD_IN|RB_WAITFD_OUT;
9901 if (mode ==
ID2SYM(rb_intern(
"readable_writable"))) {
9902 return RB_WAITFD_IN|RB_WAITFD_OUT;
9905 rb_raise(rb_eArgError,
"unsupported mode: %"PRIsVALUE, mode);
9909io_event_from_value(
VALUE value)
9913 if (events <= 0) rb_raise(rb_eArgError,
"Events must be positive integer!");
9951 for (
int i = 0; i < argc; i += 1) {
9953 events |= wait_mode_sym(argv[i]);
9955 else if (UNDEF_P(timeout)) {
9959 rb_raise(rb_eArgError,
"timeout given more than once");
9963 if (UNDEF_P(timeout)) timeout =
Qnil;
9971 events = io_event_from_value(argv[0]);
9976 rb_io_t *fptr = NULL;
9981 if (return_io)
return Qtrue;
9987 return io_wait_event(io, events, timeout, return_io);
9991argf_mark_and_move(
void *ptr)
9993 struct argf *p = ptr;
9994 rb_gc_mark_and_move(&p->filename);
9995 rb_gc_mark_and_move(&p->current_file);
9996 rb_gc_mark_and_move(&p->argv);
9997 rb_gc_mark_and_move(&p->inplace);
9998 rb_gc_mark_and_move(&p->encs.
ecopts);
10002argf_memsize(
const void *ptr)
10004 const struct argf *p = ptr;
10005 size_t size =
sizeof(*p);
10012 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
10018 p->filename =
Qnil;
10019 p->current_file =
Qnil;
10025argf_alloc(
VALUE klass)
10030 argf_init(p,
Qnil);
10040 memset(&ARGF, 0,
sizeof(ARGF));
10041 argf_init(&ARGF, argv);
10051 ARGF = argf_of(orig);
10078 ARGF.last_lineno = ARGF.lineno;
10107#define next_argv() argf_next_argv(argf)
10108#define ARGF_GENERIC_INPUT_P() \
10109 (ARGF.current_file == rb_stdin && !RB_TYPE_P(ARGF.current_file, T_FILE))
10110#define ARGF_FORWARD(argc, argv) do {\
10111 if (ARGF_GENERIC_INPUT_P())\
10112 return argf_forward((argc), (argv), argf);\
10114#define NEXT_ARGF_FORWARD(argc, argv) do {\
10115 if (!next_argv()) return Qnil;\
10116 ARGF_FORWARD((argc), (argv));\
10122 VALUE file = ARGF.current_file;
10136 int stdout_binmode = 0;
10137 enum rb_io_mode fmode;
10144 stdout_binmode = 1;
10147 if (ARGF.init_p == 0) {
10157 if (
NIL_P(ARGF.argv)) {
10160 else if (ARGF.next_p == -1 &&
RARRAY_LEN(ARGF.argv) > 0) {
10165 if (ARGF.next_p == 1) {
10166 if (ARGF.init_p == 1) argf_close(
argf);
10171 ARGF.filename = filename;
10172 filename = rb_str_encode_ospath(filename);
10174 if (RSTRING_LEN(filename) == 1 && fn[0] ==
'-') {
10176 if (ARGF.inplace) {
10177 rb_warn(
"Can't do inplace edit for stdio; skipping");
10183 int fr = rb_sysopen(filename, O_RDONLY, 0);
10185 if (ARGF.inplace) {
10187#ifndef NO_SAFE_RENAME
10198 if (!
NIL_P(ARGF.inplace)) {
10199 VALUE suffix = ARGF.inplace;
10201 if (
NIL_P(rb_str_cat_conv_enc_opts(str, RSTRING_LEN(str),
10202 RSTRING_PTR(suffix), RSTRING_LEN(suffix),
10203 rb_enc_get(suffix), 0,
Qnil))) {
10206#ifdef NO_SAFE_RENAME
10208 (void)unlink(RSTRING_PTR(str));
10209 if (rename(fn, RSTRING_PTR(str)) < 0) {
10210 rb_warn(
"Can't rename %"PRIsVALUE
" to %"PRIsVALUE
": %s, skipping file",
10211 filename, str, strerror(
errno));
10214 fr = rb_sysopen(str, O_RDONLY, 0);
10216 if (rename(fn, RSTRING_PTR(str)) < 0) {
10217 rb_warn(
"Can't rename %"PRIsVALUE
" to %"PRIsVALUE
": %s, skipping file",
10218 filename, str, strerror(
errno));
10225#ifdef NO_SAFE_RENAME
10226 rb_fatal(
"Can't do inplace edit without backup");
10228 if (unlink(fn) < 0) {
10229 rb_warn(
"Can't remove %"PRIsVALUE
": %s, skipping file",
10230 filename, strerror(
errno));
10236 fw = rb_sysopen(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666);
10237#ifndef NO_SAFE_RENAME
10240 fchmod(fw, st.st_mode);
10242 chmod(fn, st.st_mode);
10244 if (st.st_uid!=st2.st_uid || st.st_gid!=st2.st_gid) {
10247 err = fchown(fw, st.st_uid, st.st_gid);
10249 err = chown(fn, st.st_uid, st.st_gid);
10251 if (err && getuid() == 0 && st2.st_uid == 0) {
10252 const char *wkfn = RSTRING_PTR(filename);
10253 rb_warn(
"Can't set owner/group of %"PRIsVALUE
" to same as %"PRIsVALUE
": %s, skipping file",
10254 filename, str, strerror(
errno));
10257 (void)unlink(wkfn);
10267 if (!ARGF.binmode) {
10268 fmode |= DEFAULT_TEXTMODE;
10270 ARGF.current_file = prep_io(fr, fmode,
rb_cFile, fn);
10271 if (!
NIL_P(write_io)) {
10278 if (ARGF.encs.enc) {
10279 fptr->
encs = ARGF.encs;
10280 clear_codeconv(fptr);
10284 if (!ARGF.binmode) {
10286#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
10287 fptr->
encs.
ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
10298 else if (ARGF.next_p == -1) {
10301 if (ARGF.inplace) {
10302 rb_warn(
"Can't do inplace edit for stdio");
10306 if (ARGF.init_p == -1) ARGF.init_p = 1;
10314 long lineno = ARGF.lineno;
10317 if (!next_argv())
return Qnil;
10318 if (ARGF_GENERIC_INPUT_P()) {
10319 line = forward_current(idGets, argc, argv);
10326 line = rb_io_getline(argc, argv, ARGF.current_file);
10328 if (
NIL_P(line) && ARGF.next_p != -1) {
10334 if (!
NIL_P(line)) {
10335 ARGF.lineno = ++lineno;
10336 ARGF.last_lineno = ARGF.lineno;
10342argf_lineno_getter(
ID id,
VALUE *var)
10345 return INT2FIX(ARGF.last_lineno);
10353 ARGF.last_lineno = ARGF.lineno = n;
10357rb_reset_argf_lineno(
long n)
10359 ARGF.last_lineno = ARGF.lineno = n;
10400 if (recv ==
argf) {
10401 return argf_gets(argc, argv,
argf);
10403 return forward(
argf, idGets, argc, argv);
10429 line = argf_getline(argc, argv,
argf);
10441 return rb_f_gets(0, 0,
argf);
10445 if (!next_argv())
return Qnil;
10447 if (
NIL_P(line) && ARGF.next_p != -1) {
10453 if (!
NIL_P(line)) {
10455 ARGF.last_lineno = ARGF.lineno;
10481rb_f_readline(
int argc,
VALUE *argv,
VALUE recv)
10483 if (recv ==
argf) {
10484 return argf_readline(argc, argv,
argf);
10486 return forward(
argf, rb_intern(
"readline"), argc, argv);
10513 ARGF_FORWARD(argc, argv);
10514 line = argf_gets(argc, argv,
argf);
10584rb_f_readlines(
int argc,
VALUE *argv,
VALUE recv)
10586 if (recv ==
argf) {
10587 return argf_readlines(argc, argv,
argf);
10589 return forward(
argf, rb_intern(
"readlines"), argc, argv);
10613 long lineno = ARGF.lineno;
10617 while (next_argv()) {
10618 if (ARGF_GENERIC_INPUT_P()) {
10619 lines = forward_current(rb_intern(
"readlines"), argc, argv);
10622 lines = rb_io_readlines(argc, argv, ARGF.current_file);
10628 ARGF.last_lineno = ARGF.lineno;
10663 rb_last_status_clear();
10664 port = pipe_open_s(str,
"r",
FMODE_READABLE|DEFAULT_TEXTMODE, NULL);
10668 result = read_all(fptr, remain_size(fptr),
Qnil);
10670 rb_io_fptr_cleanup_all(fptr);
10676#ifdef HAVE_SYS_SELECT_H
10677#include <sys/select.h>
10691 if (!
NIL_P(read)) {
10696 if (READ_DATA_PENDING(fptr) || READ_CHAR_PENDING(fptr)) {
10700 if (max < fptr->fd) max = fptr->
fd;
10703 timerec.tv_sec = timerec.tv_usec = 0;
10711 if (!
NIL_P(write)) {
10717 if (max < fptr->fd) max = fptr->
fd;
10724 if (!
NIL_P(except)) {
10728 VALUE write_io = GetWriteIO(io);
10731 if (max < fptr->fd) max = fptr->
fd;
10732 if (io != write_io) {
10735 if (max < fptr->fd) max = fptr->
fd;
10750 if (!pending && n == 0)
return Qnil;
10775 VALUE write_io = GetWriteIO(io);
10788 VALUE write_io = GetWriteIO(io);
10793 else if (io != write_io) {
10806 VALUE read, write, except;
10812select_call(
VALUE arg)
10816 return select_internal(p->read, p->write, p->except, p->timeout, p->fdsets);
10820select_end(
VALUE arg)
10825 for (i = 0; i < numberof(p->fdsets); ++i)
10830static VALUE sym_normal, sym_sequential, sym_random,
10831 sym_willneed, sym_dontneed, sym_noreuse;
10833#ifdef HAVE_POSIX_FADVISE
10834struct io_advise_struct {
10842io_advise_internal(
void *arg)
10844 struct io_advise_struct *ptr = arg;
10845 return posix_fadvise(ptr->fd, ptr->offset, ptr->len, ptr->advice);
10849io_advise_sym_to_const(
VALUE sym)
10851#ifdef POSIX_FADV_NORMAL
10852 if (sym == sym_normal)
10853 return INT2NUM(POSIX_FADV_NORMAL);
10856#ifdef POSIX_FADV_RANDOM
10857 if (sym == sym_random)
10858 return INT2NUM(POSIX_FADV_RANDOM);
10861#ifdef POSIX_FADV_SEQUENTIAL
10862 if (sym == sym_sequential)
10863 return INT2NUM(POSIX_FADV_SEQUENTIAL);
10866#ifdef POSIX_FADV_WILLNEED
10867 if (sym == sym_willneed)
10868 return INT2NUM(POSIX_FADV_WILLNEED);
10871#ifdef POSIX_FADV_DONTNEED
10872 if (sym == sym_dontneed)
10873 return INT2NUM(POSIX_FADV_DONTNEED);
10876#ifdef POSIX_FADV_NOREUSE
10877 if (sym == sym_noreuse)
10878 return INT2NUM(POSIX_FADV_NOREUSE);
10885do_io_advise(rb_io_t *fptr,
VALUE advice, rb_off_t offset, rb_off_t
len)
10888 struct io_advise_struct ias;
10891 num_adv = io_advise_sym_to_const(advice);
10897 if (
NIL_P(num_adv))
10901 ias.advice =
NUM2INT(num_adv);
10902 ias.offset = offset;
10905 rv = (int)rb_io_blocking_region(fptr, io_advise_internal, &ias);
10906 if (rv && rv != ENOSYS) {
10909 VALUE message = rb_sprintf(
"%"PRIsVALUE
" "
10913 fptr->
pathv, offset,
len, advice);
10923advice_arg_check(
VALUE advice)
10928 if (advice != sym_normal &&
10929 advice != sym_sequential &&
10930 advice != sym_random &&
10931 advice != sym_willneed &&
10932 advice != sym_dontneed &&
10933 advice != sym_noreuse) {
10934 rb_raise(
rb_eNotImpError,
"Unsupported advice: %+"PRIsVALUE, advice);
10972rb_io_advise(
int argc,
VALUE *argv,
VALUE io)
10979 advice_arg_check(advice);
10981 io = GetWriteIO(io);
10987#ifdef HAVE_POSIX_FADVISE
10988 return do_io_advise(fptr, advice,
off, l);
10990 ((void)
off, (void)l);
11002 return isinf(f) && 0 < f;
11158rb_f_select(
int argc,
VALUE *argv,
VALUE obj)
11161 if (scheduler !=
Qnil) {
11164 if (!UNDEF_P(result))
return result;
11172 rb_scan_args(argc, argv,
"13", &args.read, &args.write, &args.except, &timeout);
11173 if (
NIL_P(timeout) || is_pos_inf(timeout)) {
11178 args.timeout = &timerec;
11181 for (i = 0; i < numberof(args.fdsets); ++i)
11187#ifdef IOCTL_REQ_TYPE
11188 typedef IOCTL_REQ_TYPE ioctl_req_t;
11190 typedef int ioctl_req_t;
11191# define NUM2IOCTLREQ(num) ((int)NUM2LONG(num))
11202nogvl_ioctl(
void *ptr)
11204 struct ioctl_arg *arg = ptr;
11206 return (
VALUE)ioctl(arg->fd, arg->cmd, arg->narg);
11210do_ioctl(
struct rb_io *io, ioctl_req_t cmd,
long narg)
11213 struct ioctl_arg arg;
11219 retval = (int)rb_io_blocking_region(io, nogvl_ioctl, &arg);
11225#define DEFAULT_IOCTL_NARG_LEN (256)
11227#if defined(__linux__) && defined(_IOC_SIZE)
11229linux_iocparm_len(ioctl_req_t cmd)
11233 if ((cmd & 0xFFFF0000) == 0) {
11235 return DEFAULT_IOCTL_NARG_LEN;
11238 len = _IOC_SIZE(cmd);
11241 if (
len < DEFAULT_IOCTL_NARG_LEN)
11242 len = DEFAULT_IOCTL_NARG_LEN;
11250ioctl_narg_len(ioctl_req_t cmd)
11256#define IOCPARM_LEN(x) (((x) >> 16) & IOCPARM_MASK)
11260 len = IOCPARM_LEN(cmd);
11261#elif defined(__linux__) && defined(_IOC_SIZE)
11262 len = linux_iocparm_len(cmd);
11265 len = DEFAULT_IOCTL_NARG_LEN;
11274typedef long fcntl_arg_t;
11277typedef int fcntl_arg_t;
11281fcntl_narg_len(ioctl_req_t cmd)
11288 len =
sizeof(fcntl_arg_t);
11296#ifdef F_DUPFD_CLOEXEC
11297 case F_DUPFD_CLOEXEC:
11298 len =
sizeof(fcntl_arg_t);
11308 len =
sizeof(fcntl_arg_t);
11318 len =
sizeof(fcntl_arg_t);
11328 len =
sizeof(fcntl_arg_t);
11333 len =
sizeof(
struct f_owner_ex);
11338 len =
sizeof(
struct f_owner_ex);
11343 len =
sizeof(
struct flock);
11348 len =
sizeof(
struct flock);
11353 len =
sizeof(
struct flock);
11373 len =
sizeof(fcntl_arg_t);
11383 len =
sizeof(fcntl_arg_t);
11388 len =
sizeof(fcntl_arg_t);
11401fcntl_narg_len(ioctl_req_t cmd)
11407#define NARG_SENTINEL 17
11410setup_narg(ioctl_req_t cmd,
VALUE *argp,
long (*narg_len)(ioctl_req_t))
11421 else if (arg ==
Qtrue) {
11435 len = narg_len(cmd);
11436 rb_str_modify(arg);
11438 slen = RSTRING_LEN(arg);
11440 if (slen <
len+1) {
11441 rb_str_resize(arg,
len+1);
11442 MEMZERO(RSTRING_PTR(arg)+slen,
char,
len-slen);
11446 ptr = RSTRING_PTR(arg);
11447 ptr[slen - 1] = NARG_SENTINEL;
11456finish_narg(
int retval,
VALUE arg,
const rb_io_t *fptr)
11458 if (retval < 0) rb_sys_fail_path(fptr->
pathv);
11463 if (ptr[slen-1] != NARG_SENTINEL)
11464 rb_raise(rb_eArgError,
"return value overflowed string");
11465 ptr[slen-1] =
'\0';
11475 ioctl_req_t cmd = NUM2IOCTLREQ(req);
11480 narg = setup_narg(cmd, &arg, ioctl_narg_len);
11482 retval = do_ioctl(fptr, cmd, narg);
11483 return finish_narg(retval, arg, fptr);
11510 return rb_ioctl(io, req, arg);
11513#define rb_io_ioctl rb_f_notimplement
11524nogvl_fcntl(
void *ptr)
11526 struct fcntl_arg *arg = ptr;
11528#if defined(F_DUPFD)
11529 if (arg->cmd == F_DUPFD)
11532 return (
VALUE)fcntl(arg->fd, arg->cmd, arg->narg);
11536do_fcntl(
struct rb_io *io,
int cmd,
long narg)
11539 struct fcntl_arg arg;
11545 retval = (int)rb_io_blocking_region(io, nogvl_fcntl, &arg);
11546 if (retval != -1) {
11548#if defined(F_DUPFD)
11551#if defined(F_DUPFD_CLOEXEC)
11552 case F_DUPFD_CLOEXEC:
11569 narg = setup_narg(cmd, &arg, fcntl_narg_len);
11571 retval = do_fcntl(fptr, cmd, narg);
11572 return finish_narg(retval, arg, fptr);
11598 return rb_fcntl(io, req, arg);
11601#define rb_io_fcntl rb_f_notimplement
11604#if defined(HAVE_SYSCALL) || defined(HAVE___SYSCALL)
11636#if SIZEOF_VOIDP == 8 && defined(HAVE___SYSCALL) && SIZEOF_INT != 8
11637# define SYSCALL __syscall
11638# define NUM2SYSCALLID(x) NUM2LONG(x)
11639# define RETVAL2NUM(x) LONG2NUM(x)
11640# if SIZEOF_LONG == 8
11641 long num, retval = -1;
11642# elif SIZEOF_LONG_LONG == 8
11643 long long num, retval = -1;
11645# error ---->> it is asserted that __syscall takes the first argument and returns retval in 64bit signed integer. <<----
11647#elif defined(__linux__)
11648# define SYSCALL syscall
11649# define NUM2SYSCALLID(x) NUM2LONG(x)
11650# define RETVAL2NUM(x) LONG2NUM(x)
11658 long num, retval = -1;
11660# define SYSCALL syscall
11661# define NUM2SYSCALLID(x) NUM2INT(x)
11662# define RETVAL2NUM(x) INT2NUM(x)
11663 int num, retval = -1;
11669 "We plan to remove a syscall function at future release. DL(Fiddle) provides safer alternative.");
11673 rb_raise(rb_eArgError,
"too few arguments for syscall");
11674 if (argc > numberof(arg))
11675 rb_raise(rb_eArgError,
"too many arguments for syscall");
11676 num = NUM2SYSCALLID(argv[0]); ++argv;
11677 for (i = argc - 1; i--; ) {
11692 retval = SYSCALL(num);
11695 retval = SYSCALL(num, arg[0]);
11698 retval = SYSCALL(num, arg[0],arg[1]);
11701 retval = SYSCALL(num, arg[0],arg[1],arg[2]);
11704 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3]);
11707 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4]);
11710 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5]);
11713 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6]);
11719 return RETVAL2NUM(retval);
11721#undef NUM2SYSCALLID
11725#define rb_f_syscall rb_f_notimplement
11729io_new_instance(
VALUE args)
11734static rb_encoding *
11735find_encoding(
VALUE v)
11737 rb_encoding *enc = rb_find_encoding(v);
11738 if (!enc)
rb_warn(
"Unsupported encoding %"PRIsVALUE
" ignored", v);
11745 rb_encoding *enc, *enc2;
11750 enc2 = find_encoding(v1);
11753 if (RSTRING_LEN(tmp) == 1 && RSTRING_PTR(tmp)[0] ==
'-') {
11759 enc = find_encoding(v2);
11766 enc = find_encoding(v2);
11777 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11783 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
11784 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11789 if (!
NIL_P(tmp) && rb_enc_asciicompat(enc = rb_enc_get(tmp))) {
11790 parse_mode_enc(RSTRING_PTR(tmp), enc, &enc, &enc2, NULL);
11791 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11795 rb_io_ext_int_to_encs(find_encoding(v1), NULL, &enc, &enc2, 0);
11796 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11801 validate_enc_binmode(&fptr->
mode, ecflags, enc, enc2);
11806 clear_codeconv(fptr);
11818io_encoding_set_v(
VALUE v)
11821 io_encoding_set(arg->fptr, arg->v1, arg->v2, arg->opt);
11826pipe_pair_close(
VALUE rw)
11829 return rb_ensure(io_close, rwp[0], io_close, rwp[1]);
11912rb_io_s_pipe(
int argc,
VALUE *argv,
VALUE klass)
11914 int pipes[2], state;
11915 VALUE r, w, args[3], v1, v2;
11917 rb_io_t *fptr, *fptr2;
11919 enum rb_io_mode fmode = 0;
11922 argc =
rb_scan_args(argc, argv,
"02:", &v1, &v2, &opt);
11929 r = rb_protect(io_new_instance, (
VALUE)args, &state);
11933 rb_jump_tag(state);
11937 ies_args.fptr = fptr;
11940 ies_args.opt = opt;
11941 rb_protect(io_encoding_set_v, (
VALUE)&ies_args, &state);
11945 rb_jump_tag(state);
11950 w = rb_protect(io_new_instance, (
VALUE)args, &state);
11954 rb_jump_tag(state);
11959 extract_binmode(opt, &fmode);
11966#if DEFAULT_TEXTMODE
11969 setmode(fptr->
fd, O_BINARY);
11971#if RUBY_CRLF_ENVIRONMENT
11977 fptr->
mode |= fmode;
11978#if DEFAULT_TEXTMODE
11981 setmode(fptr2->
fd, O_BINARY);
11984 fptr2->
mode |= fmode;
12018 else if (!
NIL_P(v = rb_hash_aref(opt, sym_open_args))) {
12021 v = rb_to_array_type(v);
12026 arg->io = rb_io_open(klass, path, vmode, vperm, opt);
12030io_s_foreach(
VALUE v)
12035 if (arg->limit == 0)
12036 rb_raise(rb_eArgError,
"invalid limit: 0 for foreach");
12037 while (!
NIL_P(str = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, arg->io))) {
12121rb_io_s_foreach(
int argc,
VALUE *argv,
VALUE self)
12124 int orig_argc = argc;
12128 argc =
rb_scan_args(argc, argv,
"12:", NULL, NULL, NULL, &opt);
12130 extract_getline_args(argc-1, argv+1, &garg);
12131 open_key_args(self, argc, argv, opt, &arg);
12133 extract_getline_opts(opt, &garg);
12134 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12139io_s_readlines(
VALUE v)
12142 return io_readlines(arg, arg->io);
12195rb_io_s_readlines(
int argc,
VALUE *argv,
VALUE io)
12201 argc =
rb_scan_args(argc, argv,
"12:", NULL, NULL, NULL, &opt);
12202 extract_getline_args(argc-1, argv+1, &garg);
12203 open_key_args(io, argc, argv, opt, &arg);
12205 extract_getline_opts(opt, &garg);
12206 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12214 return io_read(arg->argc, arg->argv, arg->io);
12224seek_before_access(
VALUE argp)
12228 return rb_io_seek(arg->io, arg->offset, arg->mode);
12270rb_io_s_read(
int argc,
VALUE *argv,
VALUE io)
12276 argc =
rb_scan_args(argc, argv,
"13:", NULL, NULL, &offset, NULL, &opt);
12278 rb_raise(rb_eArgError,
"negative offset %ld given",
off);
12280 open_key_args(io, argc, argv, opt, &arg);
12282 if (!
NIL_P(offset)) {
12286 sarg.offset = offset;
12287 sarg.mode = SEEK_SET;
12288 rb_protect(seek_before_access, (
VALUE)&sarg, &state);
12291 rb_jump_tag(state);
12293 if (arg.argc == 2) arg.argc = 1;
12308rb_io_s_binread(
int argc,
VALUE *argv,
VALUE io)
12324 arg.io = rb_io_open_generic(io, argv[0], oflags, fmode, &convconfig, 0);
12327 arg.argc = (argc > 1) ? 1 : 0;
12328 if (!
NIL_P(offset)) {
12332 sarg.offset = offset;
12333 sarg.mode = SEEK_SET;
12334 rb_protect(seek_before_access, (
VALUE)&sarg, &state);
12337 rb_jump_tag(state);
12344io_s_write0(
VALUE v)
12347 return io_write(arg->io,arg->str,arg->nosync);
12351io_s_write(
int argc,
VALUE *argv,
VALUE klass,
int binary)
12353 VALUE string, offset, opt;
12357 rb_scan_args(argc, argv,
"21:", NULL, &
string, &offset, &opt);
12360 else opt = rb_hash_dup(opt);
12363 if (
NIL_P(rb_hash_aref(opt,sym_mode))) {
12364 int mode = O_WRONLY|O_CREAT;
12366 if (binary) mode |= O_BINARY;
12368 if (
NIL_P(offset)) mode |= O_TRUNC;
12369 rb_hash_aset(opt,sym_mode,
INT2NUM(mode));
12371 open_key_args(klass, argc, argv, opt, &arg);
12374 if (binary) rb_io_binmode_m(arg.io);
12378 if (!
NIL_P(offset)) {
12382 sarg.offset = offset;
12383 sarg.mode = SEEK_SET;
12384 rb_protect(seek_before_access, (
VALUE)&sarg, &state);
12387 rb_jump_tag(state);
12439rb_io_s_write(
int argc,
VALUE *argv,
VALUE io)
12441 return io_s_write(argc, argv, io, 0);
12454rb_io_s_binwrite(
int argc,
VALUE *argv,
VALUE io)
12456 return io_s_write(argc, argv, io, 1);
12462 rb_off_t copy_length;
12463 rb_off_t src_offset;
12467 unsigned close_src : 1;
12468 unsigned close_dst : 1;
12471 const char *syserr;
12472 const char *notimp;
12474 struct stat src_stat;
12475 struct stat dst_stat;
12476#ifdef HAVE_FCOPYFILE
12477 copyfile_state_t copyfile_state;
12482exec_interrupts(
void *arg)
12485 rb_thread_execute_interrupts(th);
12499#if defined(ERESTART)
12504 rb_thread_execute_interrupts(stp->th);
12523fiber_scheduler_wait_for(
void * _arguments)
12533# define IOWAIT_SYSCALL "poll"
12534STATIC_ASSERT(pollin_expected, POLLIN == RB_WAITFD_IN);
12535STATIC_ASSERT(pollout_expected, POLLOUT == RB_WAITFD_OUT);
12537nogvl_wait_for(
VALUE th, rb_io_t *fptr,
short events,
struct timeval *timeout)
12540 if (scheduler !=
Qnil) {
12543 return RTEST(args.result);
12547 if (fd == -1)
return 0;
12552 fds.events = events;
12554 int timeout_milliseconds = -1;
12557 timeout_milliseconds = (int)(timeout->tv_sec * 1000) + (int)(timeout->tv_usec / 1000);
12560 return poll(&fds, 1, timeout_milliseconds);
12563# define IOWAIT_SYSCALL "select"
12565nogvl_wait_for(
VALUE th, rb_io_t *fptr,
short events,
struct timeval *timeout)
12568 if (scheduler !=
Qnil) {
12571 return RTEST(args.result);
12591 case RB_WAITFD_OUT:
12595 VM_UNREACHABLE(nogvl_wait_for);
12615 ret = nogvl_wait_for(stp->th, stp->src_fptr, RB_WAITFD_IN, NULL);
12617 }
while (ret < 0 && maygvl_copy_stream_continue_p(has_gvl, stp));
12620 stp->syserr = IOWAIT_SYSCALL;
12621 stp->error_no =
errno;
12633 ret = nogvl_wait_for(stp->th, stp->dst_fptr, RB_WAITFD_OUT, NULL);
12634 }
while (ret < 0 && maygvl_copy_stream_continue_p(0, stp));
12637 stp->syserr = IOWAIT_SYSCALL;
12638 stp->error_no =
errno;
12644#ifdef USE_COPY_FILE_RANGE
12647simple_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)
12649#ifdef HAVE_COPY_FILE_RANGE
12650 return copy_file_range(in_fd, in_offset, out_fd, out_offset, count, flags);
12652 return syscall(__NR_copy_file_range, in_fd, in_offset, out_fd, out_offset, count, flags);
12661 rb_off_t copy_length, src_offset, *src_offset_ptr;
12663 if (!S_ISREG(stp->src_stat.st_mode))
12666 src_size = stp->src_stat.st_size;
12667 src_offset = stp->src_offset;
12668 if (src_offset >= (rb_off_t)0) {
12669 src_offset_ptr = &src_offset;
12672 src_offset_ptr = NULL;
12675 copy_length = stp->copy_length;
12676 if (copy_length < (rb_off_t)0) {
12677 if (src_offset < (rb_off_t)0) {
12678 rb_off_t current_offset;
12680 current_offset = lseek(stp->src_fptr->
fd, 0, SEEK_CUR);
12681 if (current_offset < (rb_off_t)0 &&
errno) {
12682 stp->syserr =
"lseek";
12683 stp->error_no =
errno;
12684 return (
int)current_offset;
12686 copy_length = src_size - current_offset;
12689 copy_length = src_size - src_offset;
12693 retry_copy_file_range:
12694# if SIZEOF_OFF_T > SIZEOF_SIZE_T
12696 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
12698 ss = (ssize_t)copy_length;
12700 ss = simple_copy_file_range(stp->src_fptr->
fd, src_offset_ptr, stp->dst_fptr->
fd, NULL, ss, 0);
12704 if (0 < copy_length) {
12705 goto retry_copy_file_range;
12709 if (maygvl_copy_stream_continue_p(0, stp)) {
12710 goto retry_copy_file_range;
12724#if EWOULDBLOCK != EAGAIN
12728 int ret = nogvl_copy_stream_wait_write(stp);
12729 if (ret < 0)
return ret;
12731 goto retry_copy_file_range;
12735 int flags = fcntl(stp->dst_fptr->
fd, F_GETFL);
12737 if (flags != -1 && flags & O_APPEND) {
12743 stp->syserr =
"copy_file_range";
12744 stp->error_no =
errno;
12751#ifdef HAVE_FCOPYFILE
12755 rb_off_t cur, ss = 0;
12756 const rb_off_t src_offset = stp->src_offset;
12759 if (stp->copy_length >= (rb_off_t)0) {
12764 if (!S_ISREG(stp->src_stat.st_mode))
12767 if (!S_ISREG(stp->dst_stat.st_mode))
12769 if (lseek(stp->dst_fptr->
fd, 0, SEEK_CUR) > (rb_off_t)0)
12771 if (fcntl(stp->dst_fptr->
fd, F_GETFL) & O_APPEND) {
12774 rb_off_t end = lseek(stp->dst_fptr->
fd, 0, SEEK_END);
12775 lseek(stp->dst_fptr->
fd, 0, SEEK_SET);
12776 if (end > (rb_off_t)0)
return 0;
12779 if (src_offset > (rb_off_t)0) {
12784 cur = lseek(stp->src_fptr->
fd, 0, SEEK_CUR);
12785 if (cur < (rb_off_t)0 &&
errno) {
12786 stp->error_no =
errno;
12791 r = lseek(stp->src_fptr->
fd, src_offset, SEEK_SET);
12792 if (r < (rb_off_t)0 &&
errno) {
12793 stp->error_no =
errno;
12798 stp->copyfile_state = copyfile_state_alloc();
12799 ret = fcopyfile(stp->src_fptr->
fd, stp->dst_fptr->
fd, stp->copyfile_state, COPYFILE_DATA);
12800 copyfile_state_get(stp->copyfile_state, COPYFILE_STATE_COPIED, &ss);
12804 if (src_offset > (rb_off_t)0) {
12808 r = lseek(stp->src_fptr->
fd, cur, SEEK_SET);
12809 if (r < (rb_off_t)0 &&
errno) {
12810 stp->error_no =
errno;
12822 stp->syserr =
"fcopyfile";
12823 stp->error_no =
errno;
12830#ifdef HAVE_SENDFILE
12833# define USE_SENDFILE
12835# ifdef HAVE_SYS_SENDFILE_H
12836# include <sys/sendfile.h>
12840simple_sendfile(
int out_fd,
int in_fd, rb_off_t *offset, rb_off_t count)
12842 return sendfile(out_fd, in_fd, offset, (
size_t)count);
12845# elif 0 || defined(__APPLE__)
12849# define USE_SENDFILE
12852simple_sendfile(
int out_fd,
int in_fd, rb_off_t *offset, rb_off_t count)
12855 rb_off_t pos = offset ? *offset : lseek(in_fd, 0, SEEK_CUR);
12858 r = sendfile(in_fd, out_fd, pos, &count, NULL, 0);
12861 r = sendfile(in_fd, out_fd, pos, (
size_t)count, NULL, &sbytes, 0);
12863 if (r != 0 && sbytes == 0)
return r;
12868 lseek(in_fd, sbytes, SEEK_CUR);
12870 return (ssize_t)sbytes;
12883 rb_off_t copy_length;
12884 rb_off_t src_offset;
12887 if (!S_ISREG(stp->src_stat.st_mode))
12890 src_size = stp->src_stat.st_size;
12892 if ((stp->dst_stat.st_mode & S_IFMT) != S_IFSOCK)
12896 src_offset = stp->src_offset;
12897 use_pread = src_offset >= (rb_off_t)0;
12899 copy_length = stp->copy_length;
12900 if (copy_length < (rb_off_t)0) {
12902 copy_length = src_size - src_offset;
12906 cur = lseek(stp->src_fptr->
fd, 0, SEEK_CUR);
12907 if (cur < (rb_off_t)0 &&
errno) {
12908 stp->syserr =
"lseek";
12909 stp->error_no =
errno;
12912 copy_length = src_size - cur;
12917# if SIZEOF_OFF_T > SIZEOF_SIZE_T
12919 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
12921 ss = (ssize_t)copy_length;
12924 ss = simple_sendfile(stp->dst_fptr->
fd, stp->src_fptr->
fd, &src_offset, ss);
12927 ss = simple_sendfile(stp->dst_fptr->
fd, stp->src_fptr->
fd, NULL, ss);
12932 if (0 < copy_length) {
12933 goto retry_sendfile;
12937 if (maygvl_copy_stream_continue_p(0, stp))
12938 goto retry_sendfile;
12951#if EWOULDBLOCK != EAGAIN
12964 ret = maygvl_copy_stream_wait_read(0, stp);
12965 if (ret < 0)
return ret;
12967 ret = nogvl_copy_stream_wait_write(stp);
12968 if (ret < 0)
return ret;
12970 goto retry_sendfile;
12972 stp->syserr =
"sendfile";
12973 stp->error_no =
errno;
12981maygvl_read(
int has_gvl, rb_io_t *fptr,
void *buf,
size_t count)
12984 return rb_io_read_memory(fptr, buf, count);
12986 return read(fptr->
fd, buf, count);
12990maygvl_copy_stream_read(
int has_gvl,
struct copy_stream_struct *stp,
char *buf,
size_t len, rb_off_t offset)
12994 if (offset < (rb_off_t)0) {
12995 ss = maygvl_read(has_gvl, stp->src_fptr, buf,
len);
12998 ss = pread(stp->src_fptr->
fd, buf,
len, offset);
13004 if (maygvl_copy_stream_continue_p(has_gvl, stp))
13008#if EWOULDBLOCK != EAGAIN
13012 int ret = maygvl_copy_stream_wait_read(has_gvl, stp);
13013 if (ret < 0)
return ret;
13018 stp->notimp =
"pread";
13022 stp->syserr = offset < (rb_off_t)0 ?
"read" :
"pread";
13023 stp->error_no =
errno;
13034 ss = write(stp->dst_fptr->
fd, buf+
off,
len);
13036 if (maygvl_copy_stream_continue_p(0, stp))
13038 if (io_again_p(
errno)) {
13039 int ret = nogvl_copy_stream_wait_write(stp);
13040 if (ret < 0)
return ret;
13043 stp->syserr =
"write";
13044 stp->error_no =
errno;
13061 rb_off_t copy_length;
13062 rb_off_t src_offset;
13066 copy_length = stp->copy_length;
13067 use_eof = copy_length < (rb_off_t)0;
13068 src_offset = stp->src_offset;
13069 use_pread = src_offset >= (rb_off_t)0;
13071 if (use_pread && stp->close_src) {
13074 r = lseek(stp->src_fptr->
fd, src_offset, SEEK_SET);
13075 if (r < (rb_off_t)0 &&
errno) {
13076 stp->syserr =
"lseek";
13077 stp->error_no =
errno;
13080 src_offset = (rb_off_t)-1;
13084 while (use_eof || 0 < copy_length) {
13085 if (!use_eof && copy_length < (rb_off_t)
sizeof(buf)) {
13086 len = (size_t)copy_length;
13092 ss = maygvl_copy_stream_read(0, stp, buf,
len, src_offset);
13097 ss = maygvl_copy_stream_read(0, stp, buf,
len, (rb_off_t)-1);
13102 ret = nogvl_copy_stream_write(stp, buf, ss);
13112nogvl_copy_stream_func(
void *arg)
13115#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13119#ifdef USE_COPY_FILE_RANGE
13120 ret = nogvl_copy_file_range(stp);
13125#ifdef HAVE_FCOPYFILE
13126 ret = nogvl_fcopyfile(stp);
13132 ret = nogvl_copy_stream_sendfile(stp);
13137 nogvl_copy_stream_read_write(stp);
13139#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13146copy_stream_fallback_body(
VALUE arg)
13149 const int buflen = 16*1024;
13152 rb_off_t rest = stp->copy_length;
13153 rb_off_t
off = stp->src_offset;
13154 ID read_method = id_readpartial;
13156 if (!stp->src_fptr) {
13158 read_method = id_read;
13165 rb_str_make_independent(buf);
13166 if (stp->copy_length < (rb_off_t)0) {
13171 rb_str_resize(buf, 0);
13174 l = buflen < rest ? buflen : (long)rest;
13176 if (!stp->src_fptr) {
13179 if (read_method == id_read &&
NIL_P(rc))
13184 rb_str_resize(buf, buflen);
13185 ss = maygvl_copy_stream_read(1, stp, RSTRING_PTR(buf), l,
off);
13186 rb_str_resize(buf, ss > 0 ? ss : 0);
13191 if (
off >= (rb_off_t)0)
13194 n = rb_io_write(stp->dst, buf);
13196 stp->total += numwrote;
13198 if (read_method == id_read && RSTRING_LEN(buf) == 0) {
13209 if (!stp->src_fptr && stp->src_offset >= (rb_off_t)0) {
13210 rb_raise(rb_eArgError,
"cannot specify src_offset for non-IO");
13219copy_stream_body(
VALUE arg)
13222 VALUE src_io = stp->src, dst_io = stp->dst;
13223 const int common_oflags = 0
13233 if (src_io ==
argf ||
13237 stp->src_fptr = NULL;
13242 if (!
NIL_P(tmp_io)) {
13249 args[1] =
INT2NUM(O_RDONLY|common_oflags);
13252 stp->close_src = 1;
13257 stat_ret = fstat(stp->src_fptr->
fd, &stp->src_stat);
13258 if (stat_ret < 0) {
13259 stp->syserr =
"fstat";
13260 stp->error_no =
errno;
13265 if (dst_io ==
argf ||
13269 stp->dst_fptr = NULL;
13274 if (!
NIL_P(tmp_io)) {
13275 dst_io = GetWriteIO(tmp_io);
13281 args[1] =
INT2NUM(O_WRONLY|O_CREAT|O_TRUNC|common_oflags);
13285 stp->close_dst = 1;
13288 dst_io = GetWriteIO(dst_io);
13294 stat_ret = fstat(stp->dst_fptr->
fd, &stp->dst_stat);
13295 if (stat_ret < 0) {
13296 stp->syserr =
"fstat";
13297 stp->error_no =
errno;
13304 SET_BINARY_MODE_WITH_SEEK_CUR(stp->src_fptr);
13307 io_ascii8bit_binmode(stp->dst_fptr);
13309 if (stp->src_offset < (rb_off_t)0 && stp->src_fptr && stp->src_fptr->
rbuf.
len) {
13312 if (stp->copy_length >= (rb_off_t)0 && stp->copy_length < (rb_off_t)
len) {
13313 len = (size_t)stp->copy_length;
13316 rb_str_resize(str,
len);
13317 read_buffered_data(RSTRING_PTR(str),
len, stp->src_fptr);
13318 if (stp->dst_fptr) {
13319 if (io_binwrite(RSTRING_PTR(str), RSTRING_LEN(str), stp->dst_fptr, 0) < 0)
13320 rb_sys_fail_on_write(stp->dst_fptr);
13323 rb_io_write(dst_io, str);
13324 rb_str_resize(str, 0);
13326 if (stp->copy_length >= (rb_off_t)0)
13327 stp->copy_length -=
len;
13330 if (stp->dst_fptr && io_fflush(stp->dst_fptr) < 0) {
13334 if (stp->copy_length == 0)
13337 if (stp->src_fptr == NULL || stp->dst_fptr == NULL) {
13338 return copy_stream_fallback(stp);
13341 IO_WITHOUT_GVL(nogvl_copy_stream_func, stp);
13346copy_stream_finalize(
VALUE arg)
13350#ifdef HAVE_FCOPYFILE
13351 if (stp->copyfile_state) {
13352 copyfile_state_free(stp->copyfile_state);
13356 if (stp->close_src) {
13357 rb_io_close_m(stp->src);
13359 if (stp->close_dst) {
13360 rb_io_close_m(stp->dst);
13423rb_io_s_copy_stream(
int argc,
VALUE *argv,
VALUE io)
13425 VALUE src, dst, length, src_offset;
13430 rb_scan_args(argc, argv,
"22", &src, &dst, &length, &src_offset);
13435 st.src_fptr = NULL;
13436 st.dst_fptr = NULL;
13439 st.copy_length = (rb_off_t)-1;
13441 st.copy_length =
NUM2OFFT(length);
13443 if (
NIL_P(src_offset))
13444 st.src_offset = (rb_off_t)-1;
13446 st.src_offset =
NUM2OFFT(src_offset);
13465rb_io_external_encoding(
VALUE io)
13470 return rb_enc_from_encoding(fptr->
encs.
enc2);
13474 return rb_enc_from_encoding(fptr->
encs.
enc);
13477 return rb_enc_from_encoding(io_read_encoding(fptr));
13493rb_io_internal_encoding(
VALUE io)
13498 return rb_enc_from_encoding(io_read_encoding(fptr));
13532rb_io_set_encoding(
int argc,
VALUE *argv,
VALUE io)
13538 return forward(io, id_set_encoding, argc, argv);
13541 argc =
rb_scan_args(argc, argv,
"11:", &v1, &v2, &opt);
13543 io_encoding_set(fptr, v1, v2, opt);
13548rb_stdio_set_default_encoding(
void)
13553 if (isatty(fileno(stdin))) {
13558 rb_enc_from_encoding(external),
13559 rb_enc_from_encoding(internal),
13564 rb_io_set_encoding(1, &val,
rb_stdin);
13565 rb_io_set_encoding(1, &val,
rb_stdout);
13566 rb_io_set_encoding(1, &val,
rb_stderr);
13570global_argf_p(
VALUE arg)
13572 return arg ==
argf;
13575typedef VALUE (*argf_encoding_func)(
VALUE io);
13578argf_encoding(
VALUE argf, argf_encoding_func func)
13580 if (!
RTEST(ARGF.current_file)) {
13605 return argf_encoding(
argf, rb_io_external_encoding);
13624 return argf_encoding(
argf, rb_io_internal_encoding);
13663 if (!next_argv()) {
13664 rb_raise(rb_eArgError,
"no stream to set encoding");
13666 rb_io_set_encoding(argc, argv, ARGF.current_file);
13668 ARGF.encs = fptr->
encs;
13687 if (!next_argv()) {
13688 rb_raise(rb_eArgError,
"no stream to tell");
13690 ARGF_FORWARD(0, 0);
13691 return rb_io_tell(ARGF.current_file);
13704 if (!next_argv()) {
13705 rb_raise(rb_eArgError,
"no stream to seek");
13707 ARGF_FORWARD(argc, argv);
13708 return rb_io_seek_m(argc, argv, ARGF.current_file);
13725 if (!next_argv()) {
13726 rb_raise(rb_eArgError,
"no stream to set position");
13728 ARGF_FORWARD(1, &offset);
13729 return rb_io_set_pos(ARGF.current_file, offset);
13750 if (!next_argv()) {
13751 rb_raise(rb_eArgError,
"no stream to rewind");
13753 ARGF_FORWARD(0, 0);
13754 old_lineno =
RFILE(ARGF.current_file)->fptr->lineno;
13755 ret = rb_io_rewind(ARGF.current_file);
13756 if (!global_argf_p(
argf)) {
13757 ARGF.last_lineno = ARGF.lineno -= old_lineno;
13775 if (!next_argv()) {
13776 rb_raise(rb_eArgError,
"no stream");
13778 ARGF_FORWARD(0, 0);
13779 return rb_io_fileno(ARGF.current_file);
13798 ARGF_FORWARD(0, 0);
13799 return ARGF.current_file;
13824 if (
RTEST(ARGF.current_file)) {
13825 if (ARGF.init_p == 0)
return Qtrue;
13827 ARGF_FORWARD(0, 0);
13886 VALUE tmp, str, length;
13890 if (!
NIL_P(length)) {
13895 rb_str_resize(str,0);
13900 if (!next_argv()) {
13903 if (ARGF_GENERIC_INPUT_P()) {
13904 tmp = argf_forward(argc, argv,
argf);
13907 tmp = io_read(argc, argv, ARGF.current_file);
13909 if (
NIL_P(str)) str = tmp;
13912 if (ARGF.next_p != -1) {
13918 else if (argc >= 1) {
13919 long slen = RSTRING_LEN(str);
13935argf_forward_call(
VALUE arg)
13938 argf_forward(p->argc, p->argv, p->argf);
13968 return argf_getpartial(argc, argv,
argf,
Qnil, 0);
13989 return argf_getpartial(argc, argv,
argf, opts, 1);
13995 VALUE tmp, str, length;
14003 no_exception = no_exception_p(opts);
14005 if (!next_argv()) {
14007 rb_str_resize(str, 0);
14011 if (ARGF_GENERIC_INPUT_P()) {
14021 tmp = io_getpartial(argc, argv, ARGF.current_file, no_exception, nonblock);
14024 if (ARGF.next_p == -1) {
14025 return io_nonblock_eof(no_exception);
14030 return io_nonblock_eof(no_exception);
14068 if (!next_argv())
return Qnil;
14069 if (ARGF_GENERIC_INPUT_P()) {
14070 ch = forward_current(rb_intern(
"getc"), 0, 0);
14073 ch = rb_io_getc(ARGF.current_file);
14075 if (
NIL_P(ch) && ARGF.next_p != -1) {
14108 if (!next_argv())
return Qnil;
14110 ch = forward_current(rb_intern(
"getbyte"), 0, 0);
14115 if (
NIL_P(ch) && ARGF.next_p != -1) {
14150 ch = forward_current(rb_intern(
"getc"), 0, 0);
14153 ch = rb_io_getc(ARGF.current_file);
14155 if (
NIL_P(ch) && ARGF.next_p != -1) {
14187 NEXT_ARGF_FORWARD(0, 0);
14188 c = argf_getbyte(
argf);
14195#define FOREACH_ARGF() while (next_argv())
14200 const VALUE current = ARGF.current_file;
14202 if (ARGF.init_p == -1 || current != ARGF.current_file) {
14208#define ARGF_block_call(mid, argc, argv, func, argf) \
14209 rb_block_call_kw(ARGF.current_file, mid, argc, argv, \
14210 func, argf, rb_keyword_given_p())
14215 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_i,
argf);
14216 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14222 if (!global_argf_p(
argf)) {
14223 ARGF.last_lineno = ++ARGF.lineno;
14225 return argf_block_call_i(i,
argf, argc, argv, blockarg);
14231 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_line_i,
argf);
14232 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14280 argf_block_call_line(rb_intern(
"each_line"), argc, argv,
argf);
14311 argf_block_call(rb_intern(
"each_byte"), 0, 0,
argf);
14337 argf_block_call(rb_intern(
"each_char"), 0, 0,
argf);
14363 argf_block_call(rb_intern(
"each_codepoint"), 0, 0,
argf);
14394 return ARGF.filename;
14398argf_filename_getter(
ID id,
VALUE *var)
14400 return argf_filename(*var);
14425 return ARGF.current_file;
14444 ARGF_FORWARD(0, 0);
14465 return RBOOL(ARGF.binmode);
14485 if (ARGF.init_p && ARGF.next_p == 0) {
14514 if (ARGF.next_p != -1) {
14532 ARGF_FORWARD(0, 0);
14559 if (!ARGF.inplace)
return Qnil;
14567 return argf_inplace_mode_get(*var);
14598 ARGF.inplace =
Qnil;
14609 argf_inplace_mode_set(*var, val);
14613ruby_set_inplace_mode(
const char *suffix)
14639argf_argv_getter(
ID id,
VALUE *var)
14641 return argf_argv(*var);
14660 if (!
RTEST(ARGF.current_file)) {
14663 return GetWriteIO(ARGF.current_file);
14675 return rb_io_writev(argf_write_io(
argf), argc, argv);
14690 case RB_IO_WAIT_WRITABLE:
14693 c = rb_eEAGAINWaitWritable;
14695#if EAGAIN != EWOULDBLOCK
14697 c = rb_eEWOULDBLOCKWaitWritable;
14701 c = rb_eEINPROGRESSWaitWritable;
14707 case RB_IO_WAIT_READABLE:
14710 c = rb_eEAGAINWaitReadable;
14712#if EAGAIN != EWOULDBLOCK
14714 c = rb_eEWOULDBLOCKWaitReadable;
14718 c = rb_eEINPROGRESSWaitReadable;
14725 rb_bug(
"invalid read/write type passed to rb_readwrite_sys_fail: %d", waiting);
14731get_LAST_READ_LINE(
ID _x,
VALUE *_y)
15616#include <sys/cygwin.h>
15617 static struct __cygwin_perfile pf[] =
15619 {
"", O_RDONLY | O_BINARY},
15620 {
"", O_WRONLY | O_BINARY},
15621 {
"", O_RDWR | O_BINARY},
15622 {
"", O_APPEND | O_BINARY},
15625 cygwin_internal(CW_PERFILE, pf);
15680#if EAGAIN == EWOULDBLOCK
15681 rb_eEWOULDBLOCKWaitReadable = rb_eEAGAINWaitReadable;
15683 rb_define_const(
rb_cIO,
"EWOULDBLOCKWaitReadable", rb_eEAGAINWaitReadable);
15684 rb_eEWOULDBLOCKWaitWritable = rb_eEAGAINWaitWritable;
15686 rb_define_const(
rb_cIO,
"EWOULDBLOCKWaitWritable", rb_eEAGAINWaitWritable);
15734 rb_gvar_ractor_local(
"$/");
15736 rb_gvar_ractor_local(
"$-0");
15740 rb_gvar_ractor_local(
"$_");
15741 rb_gvar_box_dynamic(
"$_");
15857 rb_gvar_ractor_local(
"$stdin");
15858 rb_gvar_ractor_local(
"$stdout");
15859 rb_gvar_ractor_local(
"$>");
15860 rb_gvar_ractor_local(
"$stderr");
15946 rb_define_method(rb_cARGF,
"external_encoding", argf_external_encoding, 0);
15947 rb_define_method(rb_cARGF,
"internal_encoding", argf_internal_encoding, 0);
15966 rb_gvar_ractor_local(
"$-i");
15970#if defined (_WIN32) || defined(__CYGWIN__)
15971 atexit(pipe_atexit);
15983 sym_encoding =
ID2SYM(rb_id_encoding());
#define RUBY_ASSERT(...)
Asserts that the given expression is truthy if and only if RUBY_DEBUG is truthy.
std::atomic< unsigned > rb_atomic_t
Type that is eligible for atomic operations.
#define STRNCASECMP
@old{st_locale_insensitive_strncasecmp}
unsigned long ruby_strtoul(const char *str, char **endptr, int base)
Our own locale-insensitive version of strtoul(3).
#define rb_define_method(klass, mid, func, arity)
Defines klass#mid.
#define rb_define_singleton_method(klass, mid, func, arity)
Defines klass.mid.
#define rb_define_global_function(mid, func, arity)
Defines rb_mKernel #mid.
void rb_include_module(VALUE klass, VALUE module)
Includes a module to a class.
VALUE rb_define_class(const char *name, VALUE super)
Defines a top-level class.
VALUE rb_class_new(VALUE super)
Creates a new, anonymous class.
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
VALUE rb_define_module_under(VALUE outer, const char *name)
Defines a module under the namespace of outer.
void rb_define_alias(VALUE klass, const char *name1, const char *name2)
Defines an alias of a method.
int rb_scan_args_kw(int kw_flag, int argc, const VALUE *argv, const char *fmt,...)
Identical to rb_scan_args(), except it also accepts kw_splat.
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Retrieves argument from argc and argv to given VALUE references according to the format string.
int rb_block_given_p(void)
Determines if the current method is given a block.
int rb_get_kwargs(VALUE keyword_hash, const ID *table, int required, int optional, VALUE *values)
Keyword argument deconstructor.
#define ECONV_AFTER_OUTPUT
Old name of RUBY_ECONV_AFTER_OUTPUT.
#define rb_str_new2
Old name of rb_str_new_cstr.
#define TYPE(_)
Old name of rb_type.
#define RB_INTEGER_TYPE_P
Old name of rb_integer_type_p.
#define ENC_CODERANGE_7BIT
Old name of RUBY_ENC_CODERANGE_7BIT.
#define T_FILE
Old name of RUBY_T_FILE.
#define ENC_CODERANGE_VALID
Old name of RUBY_ENC_CODERANGE_VALID.
#define ECONV_UNIVERSAL_NEWLINE_DECORATOR
Old name of RUBY_ECONV_UNIVERSAL_NEWLINE_DECORATOR.
#define OBJ_INIT_COPY(obj, orig)
Old name of RB_OBJ_INIT_COPY.
#define ALLOC
Old name of RB_ALLOC.
#define RFLOAT_VALUE
Old name of rb_float_value.
#define T_STRING
Old name of RUBY_T_STRING.
#define Qundef
Old name of RUBY_Qundef.
#define INT2FIX
Old name of RB_INT2FIX.
#define rb_str_cat2
Old name of rb_str_cat_cstr.
#define T_NIL
Old name of RUBY_T_NIL.
#define UNREACHABLE
Old name of RBIMPL_UNREACHABLE.
#define ID2SYM
Old name of RB_ID2SYM.
#define T_BIGNUM
Old name of RUBY_T_BIGNUM.
#define OBJ_FREEZE
Old name of RB_OBJ_FREEZE.
#define T_FIXNUM
Old name of RUBY_T_FIXNUM.
#define UNREACHABLE_RETURN
Old name of RBIMPL_UNREACHABLE_RETURN.
#define FIX2UINT
Old name of RB_FIX2UINT.
#define SSIZET2NUM
Old name of RB_SSIZE2NUM.
#define ZALLOC
Old name of RB_ZALLOC.
#define CLASS_OF
Old name of rb_class_of.
#define rb_ary_new4
Old name of rb_ary_new_from_values.
#define ECONV_NEWLINE_DECORATOR_WRITE_MASK
Old name of RUBY_ECONV_NEWLINE_DECORATOR_WRITE_MASK.
#define ENCODING_MAXNAMELEN
Old name of RUBY_ENCODING_MAXNAMELEN.
#define MBCLEN_NEEDMORE_LEN(ret)
Old name of ONIGENC_MBCLEN_NEEDMORE_LEN.
#define ENCODING_GET(obj)
Old name of RB_ENCODING_GET.
#define LONG2FIX
Old name of RB_INT2FIX.
#define NUM2UINT
Old name of RB_NUM2UINT.
#define ALLOC_N
Old name of RB_ALLOC_N.
#define MBCLEN_CHARFOUND_LEN(ret)
Old name of ONIGENC_MBCLEN_CHARFOUND_LEN.
#define LONG2NUM
Old name of RB_LONG2NUM.
#define rb_exc_new3
Old name of rb_exc_new_str.
#define MBCLEN_INVALID_P(ret)
Old name of ONIGENC_MBCLEN_INVALID_P.
#define ECONV_STATEFUL_DECORATOR_MASK
Old name of RUBY_ECONV_STATEFUL_DECORATOR_MASK.
#define Qtrue
Old name of RUBY_Qtrue.
#define MBCLEN_NEEDMORE_P(ret)
Old name of ONIGENC_MBCLEN_NEEDMORE_P.
#define ECONV_PARTIAL_INPUT
Old name of RUBY_ECONV_PARTIAL_INPUT.
#define NUM2INT
Old name of RB_NUM2INT.
#define ECONV_ERROR_HANDLER_MASK
Old name of RUBY_ECONV_ERROR_HANDLER_MASK.
#define INT2NUM
Old name of RB_INT2NUM.
#define Qnil
Old name of RUBY_Qnil.
#define Qfalse
Old name of RUBY_Qfalse.
#define FIX2LONG
Old name of RB_FIX2LONG.
#define ENC_CODERANGE_BROKEN
Old name of RUBY_ENC_CODERANGE_BROKEN.
#define T_ARRAY
Old name of RUBY_T_ARRAY.
#define NIL_P
Old name of RB_NIL_P.
#define ALLOCV_N
Old name of RB_ALLOCV_N.
#define MBCLEN_CHARFOUND_P(ret)
Old name of ONIGENC_MBCLEN_CHARFOUND_P.
#define ECONV_NEWLINE_DECORATOR_READ_MASK
Old name of RUBY_ECONV_NEWLINE_DECORATOR_READ_MASK.
#define NUM2CHR
Old name of RB_NUM2CHR.
#define NUM2LONG
Old name of RB_NUM2LONG.
#define UINT2NUM
Old name of RB_UINT2NUM.
#define FIXNUM_P
Old name of RB_FIXNUM_P.
#define ECONV_NEWLINE_DECORATOR_MASK
Old name of RUBY_ECONV_NEWLINE_DECORATOR_MASK.
#define CONST_ID
Old name of RUBY_CONST_ID.
#define rb_ary_new2
Old name of rb_ary_new_capa.
#define NUM2SIZET
Old name of RB_NUM2SIZE.
#define ENC_CODERANGE_SET(obj, cr)
Old name of RB_ENC_CODERANGE_SET.
#define rb_str_new4
Old name of rb_str_new_frozen.
#define ALLOCV_END
Old name of RB_ALLOCV_END.
#define SYMBOL_P
Old name of RB_SYMBOL_P.
#define ECONV_DEFAULT_NEWLINE_DECORATOR
Old name of RUBY_ECONV_DEFAULT_NEWLINE_DECORATOR.
void rb_notimplement(void)
void rb_category_warn(rb_warning_category_t category, const char *fmt,...)
Identical to rb_category_warning(), except it reports unless $VERBOSE is nil.
void rb_category_warning(rb_warning_category_t category, const char *fmt,...)
Identical to rb_warning(), except it takes additional "category" parameter.
VALUE rb_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_any_to_s(VALUE obj)
Generates a textual representation of the given object.
VALUE rb_obj_alloc(VALUE klass)
Allocates an instance of the given class.
VALUE rb_class_new_instance(int argc, const VALUE *argv, VALUE klass)
Allocates, then initialises an instance of the given class.
VALUE rb_class_new_instance_kw(int argc, const VALUE *argv, VALUE klass, int kw_splat)
Identical to rb_class_new_instance(), except you can specify how to handle the last element of the gi...
VALUE rb_mEnumerable
Enumerable module.
VALUE rb_stdin
STDIN constant.
VALUE rb_stderr
STDERR constant.
VALUE rb_obj_class(VALUE obj)
Queries the class of an object.
VALUE rb_obj_dup(VALUE obj)
Duplicates the given object.
VALUE rb_inspect(VALUE obj)
Generates a human-readable textual representation of the given object.
VALUE rb_mWaitReadable
IO::WaitReadable module.
VALUE rb_mWaitWritable
IO::WaitReadable module.
VALUE rb_obj_freeze(VALUE obj)
Just calls rb_obj_freeze_inline() inside.
VALUE rb_check_to_integer(VALUE val, const char *mid)
Identical to rb_check_convert_type(), except the return value type is fixed to rb_cInteger.
VALUE rb_cFile
File class.
VALUE rb_stdout
STDOUT constant.
VALUE rb_to_int(VALUE val)
Identical to rb_check_to_int(), except it raises in case of conversion mismatch.
rb_encoding * rb_ascii8bit_encoding(void)
Queries the encoding that represents ASCII-8BIT a.k.a.
rb_encoding * rb_default_internal_encoding(void)
Queries the "default internal" encoding.
int rb_utf8_encindex(void)
Identical to rb_utf8_encoding(), except it returns the encoding's index instead of the encoding itsel...
VALUE rb_enc_default_external(void)
Identical to rb_default_external_encoding(), except it returns the Ruby-level counterpart instance of...
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.
rb_encoding * rb_default_external_encoding(void)
Queries the "default external" encoding.
rb_encoding * rb_locale_encoding(void)
Queries the encoding that represents the current locale.
rb_encoding * rb_usascii_encoding(void)
Queries the encoding that represents US-ASCII.
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.
void rb_gc(void)
Triggers a GC process.
VALUE rb_ary_concat(VALUE lhs, VALUE rhs)
Destructively appends the contents of latter into the end of former.
VALUE rb_ary_shift(VALUE ary)
Destructively deletes an element from the beginning of the passed array and returns what was deleted.
VALUE rb_check_array_type(VALUE obj)
Try converting an object to its array representation using its to_ary method, if any.
VALUE rb_ary_new(void)
Allocates a new, empty array.
VALUE rb_ary_push(VALUE ary, VALUE elem)
Special case of rb_ary_cat() that it adds only one element.
VALUE rb_ary_entry(VALUE ary, long off)
Queries an element of an array.
VALUE rb_assoc_new(VALUE car, VALUE cdr)
Identical to rb_ary_new_from_values(), except it expects exactly two parameters.
#define RETURN_ENUMERATOR(obj, argc, argv)
Identical to RETURN_SIZED_ENUMERATOR(), except its size is unknown.
static int rb_check_arity(int argc, int min, int max)
Ensures that the passed integer is in the passed range.
ID rb_frame_this_func(void)
Queries the name of the Ruby level method that is calling this function.
VALUE rb_hash_new(void)
Creates a new, empty hash object.
VALUE rb_io_printf(int argc, const VALUE *argv, VALUE io)
This is a rb_f_sprintf() + rb_io_write() combo.
VALUE rb_io_gets(VALUE io)
Reads a "line" from the given IO.
int rb_cloexec_pipe(int fildes[2])
Opens a pipe with closing on exec.
VALUE rb_io_print(int argc, const VALUE *argv, VALUE io)
Iterates over the passed array to apply rb_io_write() individually.
VALUE rb_io_addstr(VALUE io, VALUE str)
Identical to rb_io_write(), except it always returns the passed IO.
void rb_write_error(const char *str)
Writes the given error message to somewhere applicable.
VALUE rb_io_ungetbyte(VALUE io, VALUE b)
Identical to rb_io_ungetc(), except it doesn't take the encoding of the passed IO into account.
VALUE rb_io_getbyte(VALUE io)
Reads a byte from the given IO.
int rb_cloexec_dup2(int oldfd, int newfd)
Identical to rb_cloexec_dup(), except you can specify the destination file descriptor.
VALUE rb_io_fdopen(int fd, int flags, const char *path)
Creates an IO instance whose backend is the given file descriptor.
void rb_update_max_fd(int fd)
Informs the interpreter that the passed fd can be the max.
int rb_cloexec_open(const char *pathname, int flags, mode_t mode)
Opens a file that closes on exec.
VALUE rb_output_rs
The record separator character for outputs, or the $\\endiskip.
VALUE rb_io_eof(VALUE io)
Queries if the passed IO is at the end of file.
void rb_write_error2(const char *str, long len)
Identical to rb_write_error(), except it additionally takes the message's length.
void rb_close_before_exec(int lowfd, int maxhint, VALUE noclose_fds)
Closes everything.
int rb_reserved_fd_p(int fd)
Queries if the given FD is reserved or not.
void rb_fd_fix_cloexec(int fd)
Sets or clears the close-on-exec flag of the passed file descriptor to the desired state.
VALUE rb_io_ascii8bit_binmode(VALUE io)
Forces no conversions be applied to the passed IO.
VALUE rb_io_binmode(VALUE io)
Sets the binmode.
VALUE rb_io_ungetc(VALUE io, VALUE c)
"Unget"s a string.
int rb_pipe(int *pipes)
This is an rb_cloexec_pipe() + rb_update_max_fd() combo.
VALUE rb_gets(void)
Much like rb_io_gets(), but it reads from the mysterious ARGF object.
int rb_cloexec_fcntl_dupfd(int fd, int minfd)
Duplicates a file descriptor with closing on exec.
VALUE rb_output_fs
The field separator character for outputs, or the $,.
VALUE rb_file_open_str(VALUE fname, const char *fmode)
Identical to rb_file_open(), except it takes the pathname as a Ruby's string instead of C's.
int rb_cloexec_dup(int oldfd)
Identical to rb_cloexec_fcntl_dupfd(), except it implies minfd is 3.
VALUE rb_file_open(const char *fname, const char *fmode)
Opens a file located at the given path.
VALUE rb_io_close(VALUE io)
Closes the IO.
VALUE rb_default_rs
This is the default value of rb_rs, i.e.
void rb_lastline_set(VALUE str)
Updates $_.
VALUE rb_lastline_get(void)
Queries the last line, or the $_.
int rb_obj_method_arity(VALUE obj, ID mid)
Identical to rb_mod_method_arity(), except it searches for singleton methods rather than instance met...
rb_pid_t rb_waitpid(rb_pid_t pid, int *status, int flags)
Waits for a process, with releasing GVL.
void rb_last_status_set(int status, rb_pid_t pid)
Sets the "last status", or the $?.
VALUE rb_str_append(VALUE dst, VALUE src)
Identical to rb_str_buf_append(), except it converts the right hand side before concatenating.
#define rb_str_new(str, len)
Allocates an instance of rb_cString.
#define rb_str_buf_cat
Just another name of rb_str_cat.
#define rb_usascii_str_new(str, len)
Identical to rb_str_new, except it generates a string of "US ASCII" encoding.
size_t rb_str_capacity(VALUE str)
Queries the capacity of the given string.
VALUE rb_str_new_frozen(VALUE str)
Creates a frozen copy of the string, if necessary.
VALUE rb_str_dup(VALUE str)
Duplicates a string.
VALUE rb_str_cat(VALUE dst, const char *src, long srclen)
Destructively appends the passed contents to the string.
VALUE rb_str_locktmp(VALUE str)
Obtains a "temporary lock" of the string.
VALUE rb_str_equal(VALUE str1, VALUE str2)
Equality of two strings.
void rb_str_set_len(VALUE str, long len)
Overwrites the length of the string.
VALUE rb_str_buf_cat_ascii(VALUE dst, const char *src)
Identical to rb_str_cat_cstr(), except it additionally assumes the source string be a NUL terminated ...
VALUE rb_check_string_type(VALUE obj)
Try converting an object to its stringised representation using its to_str method,...
VALUE rb_str_substr(VALUE str, long beg, long len)
This is the implementation of two-argumented String#slice.
VALUE rb_str_unlocktmp(VALUE str)
Releases a lock formerly obtained by rb_str_locktmp().
void rb_str_modify_expand(VALUE str, long capa)
Identical to rb_str_modify(), except it additionally expands the capacity of the receiver.
VALUE rb_str_buf_new(long capa)
Allocates a "string buffer".
#define rb_str_new_cstr(str)
Identical to rb_str_new, except it assumes the passed pointer is a pointer to a C string.
VALUE rb_obj_as_string(VALUE obj)
Try converting an object to its stringised representation using its to_s method, if any.
int rb_thread_interrupted(VALUE thval)
Checks if the thread's execution was recently interrupted.
VALUE rb_mutex_new(void)
Creates a mutex.
int rb_thread_fd_writable(int fd)
Identical to rb_thread_wait_fd(), except it blocks the current thread until the given file descriptor...
VALUE rb_exec_recursive(VALUE(*f)(VALUE g, VALUE h, int r), VALUE g, VALUE h)
"Recursion" API entry point.
VALUE rb_mutex_synchronize(VALUE mutex, VALUE(*func)(VALUE arg), VALUE arg)
Obtains the lock, runs the passed function, and releases the lock when it completes.
void rb_thread_check_ints(void)
Checks for interrupts.
VALUE rb_thread_current(void)
Obtains the "current" thread.
int rb_thread_wait_fd(int fd)
Blocks the current thread until the given file descriptor is ready to be read.
void rb_thread_sleep(int sec)
Blocks for the given period of time.
struct timeval rb_time_interval(VALUE num)
Creates a "time interval".
void rb_set_class_path(VALUE klass, VALUE space, const char *name)
Names a class.
VALUE rb_ivar_set(VALUE obj, ID name, VALUE val)
Identical to rb_iv_set(), except it accepts the name as an ID instead of a C string.
VALUE rb_class_name(VALUE obj)
Queries the name of the given object's class.
int rb_respond_to(VALUE obj, ID mid)
Queries if the object responds to the method.
VALUE rb_check_funcall(VALUE recv, ID mid, int argc, const VALUE *argv)
Identical to rb_funcallv(), except it returns RUBY_Qundef instead of raising rb_eNoMethodError.
void rb_define_alloc_func(VALUE klass, rb_alloc_func_t func)
Sets the allocator function of a class.
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_io_oflags_fmode(int oflags)
Converts an oflags (that rb_io_modestr_oflags() returns) to a fmode (that rb_io_mode_flags() returns)...
int rb_wait_for_single_fd(int fd, int events, struct timeval *tv)
Blocks until the passed file descriptor is ready for the passed events.
FILE * rb_fdopen(int fd, const char *modestr)
Identical to rb_io_stdio_file(), except it takes file descriptors instead of Ruby's IO.
int rb_io_extract_encoding_option(VALUE opt, rb_encoding **enc_p, rb_encoding **enc2_p, enum rb_io_mode *fmode_p)
This function breaks down the option hash that IO#initialize takes into components.
int rb_io_descriptor(VALUE io)
Returns an integer representing the numeric file descriptor for io.
#define FMODE_WRITABLE
The IO is opened for writing.
FILE * rb_io_stdio_file(rb_io_t *fptr)
Finds or creates a stdio's file structure from a Ruby's one.
#define FMODE_APPEND
The IO is opened for appending.
#define MakeOpenFile
This is an old name of RB_IO_OPEN.
#define FMODE_DUPLEX
Ruby eventually detects that the IO is bidirectional.
#define FMODE_BINMODE
The IO is in "binary mode".
int rb_io_maybe_wait_readable(int error, VALUE io, VALUE timeout)
Blocks until the passed IO is ready for reading, if that makes sense for the passed errno.
int capa
Designed capacity of the buffer.
#define RB_IO_POINTER(obj, fp)
Queries the underlying IO pointer.
VALUE rb_io_maybe_wait(int error, VALUE io, VALUE events, VALUE timeout)
Identical to rb_io_wait() except it additionally takes previous errno.
VALUE rb_eIOTimeoutError
Indicates that a timeout has occurred while performing an IO operation.
#define FMODE_SYNC
The IO is in "sync mode".
int off
Offset inside of ptr.
VALUE rb_io_path(VALUE io)
Returns the path for the given IO.
void rb_io_extract_modeenc(VALUE *vmode_p, VALUE *vperm_p, VALUE opthash, int *oflags_p, enum rb_io_mode *fmode_p, rb_io_enc_t *convconfig_p)
This function can be seen as an extended version of rb_io_extract_encoding_option() that not only con...
void rb_io_check_initialized(rb_io_t *fptr)
Asserts that the passed IO is initialised.
#define FMODE_EXCL
This flag amends the effect of FMODE_CREATE, so that if there already is a file at the given path the...
#define FMODE_TEXTMODE
The IO is in "text mode".
int rb_io_fptr_finalize(rb_io_t *fptr)
Destroys the given IO.
VALUE rb_io_check_io(VALUE io)
Try converting an object to its IO representation using its to_io method, if any.
VALUE rb_io_closed_p(VALUE io)
Returns whether or not the underlying IO is closed.
struct rb_io_internal_buffer rb_io_buffer_t
Just another name of rb_io_buffer_t.
VALUE rb_io_set_timeout(VALUE io, VALUE timeout)
Set the timeout associated with the specified io object.
ssize_t rb_io_bufwrite(VALUE io, const void *buf, size_t size)
Buffered write to the passed IO.
void rb_io_check_char_readable(rb_io_t *fptr)
Asserts that an IO is opened for character-based reading.
#define FMODE_TRUNC
This flag amends the effect of FMODE_CREATE, so that if there already is a file at the given path it ...
int rb_io_read_pending(rb_io_t *fptr)
Queries if the passed IO has any pending reads.
VALUE rb_io_get_write_io(VALUE io)
Queries the tied IO for writing.
void rb_io_set_nonblock(rb_io_t *fptr)
Instructs the OS to put its internal file structure into "nonblocking mode".
int rb_io_wait_writable(int fd)
Blocks until the passed file descriptor gets writable.
VALUE rb_io_open_descriptor(VALUE klass, int descriptor, int mode, VALUE path, VALUE timeout, struct rb_io_encoding *encoding)
Allocate a new IO object, with the given file descriptor.
VALUE rb_io_set_write_io(VALUE io, VALUE w)
Assigns the tied IO for writing.
void rb_io_check_writable(rb_io_t *fptr)
Asserts that an IO is opened for writing.
int rb_io_maybe_wait_writable(int error, VALUE io, VALUE timeout)
Blocks until the passed IO is ready for writing, if that makes sense for the passed errno.
void rb_io_check_closed(rb_io_t *fptr)
This badly named function asserts that the passed IO is open.
void rb_eof_error(void)
Utility function to raise rb_eEOFError.
int rb_io_wait_readable(int fd)
Blocks until the passed file descriptor gets readable.
void rb_io_synchronized(rb_io_t *fptr)
Sets FMODE_SYNC.
VALUE rb_io_wait(VALUE io, VALUE events, VALUE timeout)
Blocks until the passed IO is ready for the passed events.
int len
Length of the buffer.
VALUE rb_ractor_stderr(void)
Queries the standard error of the current Ractor that is calling this function.
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.
VALUE rb_ractor_stdout(void)
Queries the standard output of the current 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.
struct rb_data_type_struct rb_data_type_t
This is the struct that holds necessary info for a struct.
#define TypedData_Make_Struct(klass, type, data_type, sval)
Identical to TypedData_Wrap_Struct, except it allocates a new data region internally instead of takin...
VALUE rb_get_argv(void)
Queries the arguments passed to the current process that you can access from Ruby as ARGV.
void rb_p(VALUE obj)
Inspects an object.
#define FilePathValue(v)
Ensures that the parameter object is a path.
#define errno
Ractor-aware version of errno.
#define RB_SCAN_ARGS_LAST_HASH_KEYWORDS
Treat a final argument as keywords if it is a hash, and not as keywords otherwise.
#define RB_PASS_CALLED_KEYWORDS
Pass keywords if current method is called with keywords, useful for argument delegation.
VALUE rb_fiber_scheduler_current(void)
Identical to rb_fiber_scheduler_get(), except it also returns RUBY_Qnil in case of a blocking fiber.
VALUE rb_fiber_scheduler_io_pread_memory(VALUE scheduler, VALUE io, rb_off_t from, void *base, size_t size, size_t length)
Non-blocking pread from the passed IO using a native buffer.
VALUE rb_fiber_scheduler_make_timeout(struct timeval *timeout)
Converts the passed timeout to an expression that rb_fiber_scheduler_block() etc.
VALUE rb_fiber_scheduler_io_wait_readable(VALUE scheduler, VALUE io)
Non-blocking wait until the passed IO is ready for reading.
VALUE rb_fiber_scheduler_io_read_memory(VALUE scheduler, VALUE io, void *base, size_t size, size_t length)
Non-blocking read from the passed IO using a native buffer.
VALUE rb_fiber_scheduler_io_wait(VALUE scheduler, VALUE io, VALUE events, VALUE timeout)
Non-blocking version of rb_io_wait().
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_selectv(VALUE scheduler, int argc, VALUE *argv)
Non-blocking version of IO.select, argv variant.
VALUE rb_fiber_scheduler_io_pwrite_memory(VALUE scheduler, VALUE io, rb_off_t from, const void *base, size_t size, size_t length)
Non-blocking pwrite to the passed IO using a native buffer.
VALUE rb_fiber_scheduler_current_for_thread(VALUE thread)
Identical to rb_fiber_scheduler_current(), except it queries for that of the passed thread value inst...
VALUE rb_fiber_scheduler_io_write_memory(VALUE scheduler, VALUE io, const void *base, size_t size, size_t length)
Non-blocking write to the passed IO using a native buffer.
VALUE rb_fiber_scheduler_current_for_threadptr(struct rb_thread_struct *thread)
Identical to rb_fiber_scheduler_current_for_thread(), except it expects a threadptr instead of a thre...
VALUE rb_fiber_scheduler_io_wait_writable(VALUE scheduler, VALUE io)
Non-blocking wait until the passed IO is ready for writing.
VALUE rb_fiber_scheduler_io_close(VALUE scheduler, VALUE io)
Non-blocking close the given IO.
int rb_thread_fd_select(int nfds, rb_fdset_t *rfds, rb_fdset_t *wfds, rb_fdset_t *efds, struct timeval *timeout)
Waits for multiple file descriptors at once.
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.
C99 shim for <stdbool.h>.
The data structure which wraps the fd_set bitmap used by select(2).
Decomposed encoding flags (e.g.
VALUE ecopts
Flags as Ruby hash.
rb_encoding * enc2
External encoding.
rb_encoding * enc
Internal encoding.
char * ptr
Pointer to the underlying memory region, of at least capa bytes.
int off
Offset inside of ptr.
int len
Length of the buffer.
int capa
Designed capacity of the buffer.
Ruby's IO, metadata and buffers.
rb_io_buffer_t wbuf
Write buffer.
enum rb_io_mode mode
mode flags: FMODE_XXXs
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.