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>
110#include "ccan/list/list.h"
115#include "internal/encoding.h"
116#include "internal/error.h"
117#include "internal/inits.h"
118#include "internal/io.h"
119#include "internal/numeric.h"
120#include "internal/object.h"
121#include "internal/process.h"
122#include "internal/thread.h"
123#include "internal/transcode.h"
124#include "internal/variable.h"
127#include "ruby/missing.h"
130#include "ruby_atomic.h"
140#define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR)
144# ifdef _POSIX_PIPE_BUF
145# define PIPE_BUF _POSIX_PIPE_BUF
152# define EWOULDBLOCK EAGAIN
155#if defined(HAVE___SYSCALL) && (defined(__APPLE__) || defined(__OpenBSD__))
157off_t __syscall(quad_t number, ...);
160#define IO_RBUF_CAPA_MIN 8192
161#define IO_CBUF_CAPA_MIN (128*1024)
162#define IO_RBUF_CAPA_FOR(fptr) (NEED_READCONV(fptr) ? IO_CBUF_CAPA_MIN : IO_RBUF_CAPA_MIN)
163#define IO_WBUF_CAPA_MIN 8192
165#define IO_MAX_BUFFER_GROWTH 8 * 1024 * 1024
170#define open rb_w32_uopen
172#define rename(f, t) rb_w32_urename((f), (t))
173#include "win32/file.h"
183static VALUE rb_eEAGAINWaitReadable;
184static VALUE rb_eEAGAINWaitWritable;
185static VALUE rb_eEWOULDBLOCKWaitReadable;
186static VALUE rb_eEWOULDBLOCKWaitWritable;
187static VALUE rb_eEINPROGRESSWaitWritable;
188static VALUE rb_eEINPROGRESSWaitReadable;
191static VALUE orig_stdout, orig_stderr;
200static ID id_write, id_read, id_getc, id_flush, id_readpartial, id_set_encoding, id_fileno;
201static VALUE sym_mode, sym_perm, sym_flags, sym_extenc, sym_intenc, sym_encoding, sym_open_args;
202static VALUE sym_textmode, sym_binmode, sym_autoclose;
203static VALUE sym_SET, sym_CUR, sym_END;
204static VALUE sym_wait_readable, sym_wait_writable;
206static VALUE sym_DATA;
209static VALUE sym_HOLE;
212static VALUE prep_io(
int fd,
int fmode,
VALUE klass,
const char *path);
215 VALUE filename, current_file;
221 int8_t init_p, next_p, binmode;
232 if (fd < 0 || afd <= max_fd)
235#if defined(HAVE_FCNTL) && defined(F_GETFL)
236 err = fcntl(fd, F_GETFL) == -1;
240 err = fstat(fd, &buf) != 0;
243 if (err &&
errno == EBADF) {
244 rb_bug(
"rb_update_max_fd: invalid fd (%d) given.", fd);
247 while (max_fd < afd) {
248 max_fd = ATOMIC_CAS(max_file_descriptor, max_fd, afd);
253rb_maygvl_fd_fix_cloexec(
int fd)
256#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
257 int flags, flags2, ret;
258 flags = fcntl(fd, F_GETFD);
260 rb_bug(
"rb_maygvl_fd_fix_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(
errno));
263 flags2 = flags & ~FD_CLOEXEC;
265 flags2 = flags | FD_CLOEXEC;
266 if (flags != flags2) {
267 ret = fcntl(fd, F_SETFD, flags2);
269 rb_bug(
"rb_maygvl_fd_fix_cloexec: fcntl(%d, F_SETFD, %d) failed: %s", fd, flags2, strerror(
errno));
278 rb_maygvl_fd_fix_cloexec(fd);
284rb_fix_detect_o_cloexec(
int fd)
286#if defined(O_CLOEXEC) && defined(F_GETFD)
287 int flags = fcntl(fd, F_GETFD);
290 rb_bug(
"rb_fix_detect_o_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(
errno));
292 if (flags & FD_CLOEXEC)
295 rb_maygvl_fd_fix_cloexec(fd);
302 return (e == EWOULDBLOCK) || (e == EAGAIN);
309 static int o_cloexec_state = -1;
311 static const int retry_interval = 0;
312 static const int retry_max_count = 10000;
319#elif defined O_NOINHERIT
320 flags |= O_NOINHERIT;
323 while ((ret = open(pathname, flags, mode)) == -1) {
325 if (!io_again_p(e))
break;
326 if (retry_count++ >= retry_max_count)
break;
328 sleep(retry_interval);
331 if (ret < 0)
return ret;
332 if (ret <= 2 || o_cloexec_state == 0) {
333 rb_maygvl_fd_fix_cloexec(ret);
335 else if (o_cloexec_state > 0) {
339 o_cloexec_state = rb_fix_detect_o_cloexec(ret);
358 if (oldfd == newfd) {
362#if defined(HAVE_DUP3) && defined(O_CLOEXEC)
363 static int try_dup3 = 1;
364 if (2 < newfd && try_dup3) {
365 ret = dup3(oldfd, newfd, O_CLOEXEC);
369 if (
errno == ENOSYS) {
371 ret = dup2(oldfd, newfd);
375 ret = dup2(oldfd, newfd);
378 ret = dup2(oldfd, newfd);
380 if (ret < 0)
return ret;
382 rb_maygvl_fd_fix_cloexec(ret);
387rb_fd_set_nonblock(
int fd)
390 return rb_w32_set_nonblock(fd);
391#elif defined(F_GETFL)
392 int oflags = fcntl(fd, F_GETFL);
396 if (oflags & O_NONBLOCK)
398 oflags |= O_NONBLOCK;
399 return fcntl(fd, F_SETFL, oflags);
408 int result = pipe2(descriptors, O_CLOEXEC | O_NONBLOCK);
410 int result = pipe(descriptors);
417 if (result == 0 && descriptors[1] == -1) {
418 close(descriptors[0]);
426 rb_maygvl_fd_fix_cloexec(descriptors[0]);
427 rb_maygvl_fd_fix_cloexec(descriptors[1]);
430 rb_fd_set_nonblock(descriptors[0]);
431 rb_fd_set_nonblock(descriptors[1]);
443#if defined(HAVE_FCNTL) && defined(F_DUPFD_CLOEXEC) && defined(F_DUPFD)
444 static int try_dupfd_cloexec = 1;
445 if (try_dupfd_cloexec) {
446 ret = fcntl(fd, F_DUPFD_CLOEXEC, minfd);
449 rb_maygvl_fd_fix_cloexec(ret);
453 if (
errno == EINVAL) {
454 ret = fcntl(fd, F_DUPFD, minfd);
456 try_dupfd_cloexec = 0;
461 ret = fcntl(fd, F_DUPFD, minfd);
463#elif defined(HAVE_FCNTL) && defined(F_DUPFD)
464 ret = fcntl(fd, F_DUPFD, minfd);
467 if (ret >= 0 && ret < minfd) {
468 const int prev_fd = ret;
474 if (ret < 0)
return ret;
475 rb_maygvl_fd_fix_cloexec(ret);
479#define argf_of(obj) (*(struct argf *)DATA_PTR(obj))
480#define ARGF argf_of(argf)
482#define GetWriteIO(io) rb_io_get_write_io(io)
484#define READ_DATA_PENDING(fptr) ((fptr)->rbuf.len)
485#define READ_DATA_PENDING_COUNT(fptr) ((fptr)->rbuf.len)
486#define READ_DATA_PENDING_PTR(fptr) ((fptr)->rbuf.ptr+(fptr)->rbuf.off)
487#define READ_DATA_BUFFERED(fptr) READ_DATA_PENDING(fptr)
489#define READ_CHAR_PENDING(fptr) ((fptr)->cbuf.len)
490#define READ_CHAR_PENDING_COUNT(fptr) ((fptr)->cbuf.len)
491#define READ_CHAR_PENDING_PTR(fptr) ((fptr)->cbuf.ptr+(fptr)->cbuf.off)
494#define WAIT_FD_IN_WIN32(fptr) \
495 (rb_w32_io_cancelable_p((fptr)->fd) ? Qnil : rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_READABLE), RUBY_IO_TIMEOUT_DEFAULT))
497#define WAIT_FD_IN_WIN32(fptr)
500#define READ_CHECK(fptr) do {\
501 if (!READ_DATA_PENDING(fptr)) {\
502 WAIT_FD_IN_WIN32(fptr);\
503 rb_io_check_closed(fptr);\
509# define S_ISSOCK(m) _S_ISSOCK(m)
512# define S_ISSOCK(m) (((m) & S_IFMT) == _S_IFSOCK)
515# define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
521static int io_fflush(
rb_io_t *);
524#define FMODE_SIGNAL_ON_EPIPE (1<<17)
526#define fptr_signal_on_epipe(fptr) \
527 (((fptr)->mode & FMODE_SIGNAL_ON_EPIPE) != 0)
529#define fptr_set_signal_on_epipe(fptr, flag) \
531 (fptr)->mode |= FMODE_SIGNAL_ON_EPIPE : \
532 (fptr)->mode &= ~FMODE_SIGNAL_ON_EPIPE)
534extern ID ruby_static_id_signo;
536NORETURN(
static void raise_on_write(
rb_io_t *fptr,
int e,
VALUE errinfo));
541 if (fptr_signal_on_epipe(fptr) && (e == EPIPE)) {
550 rb_exc_raise(errinfo);
553#define rb_sys_fail_on_write(fptr) \
556 raise_on_write(fptr, e, rb_syserr_new_path(e, (fptr)->pathv)); \
559#define NEED_NEWLINE_DECORATOR_ON_READ(fptr) ((fptr)->mode & FMODE_TEXTMODE)
560#define NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) ((fptr)->mode & FMODE_TEXTMODE)
561#if defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32)
562# define RUBY_CRLF_ENVIRONMENT 1
564# define RUBY_CRLF_ENVIRONMENT 0
567#if RUBY_CRLF_ENVIRONMENT
569# define DEFAULT_TEXTMODE FMODE_TEXTMODE
570# define TEXTMODE_NEWLINE_DECORATOR_ON_WRITE ECONV_CRLF_NEWLINE_DECORATOR
578#define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || (fptr)->encs.ecflags & ~ECONV_CRLF_NEWLINE_DECORATOR)
579#define WRITECONV_MASK ( \
580 (ECONV_DECORATOR_MASK & ~ECONV_CRLF_NEWLINE_DECORATOR)|\
581 ECONV_STATEFUL_DECORATOR_MASK|\
583#define NEED_WRITECONV(fptr) ( \
584 ((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || \
585 ((fptr)->encs.ecflags & WRITECONV_MASK) || \
587#define SET_BINARY_MODE(fptr) setmode((fptr)->fd, O_BINARY)
589#define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) do {\
590 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {\
591 if (((fptr)->mode & FMODE_READABLE) &&\
592 !((fptr)->encs.ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {\
593 setmode((fptr)->fd, O_BINARY);\
596 setmode((fptr)->fd, O_TEXT);\
601#define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) do {\
602 if ((enc2) && ((ecflags) & ECONV_DEFAULT_NEWLINE_DECORATOR)) {\
603 (ecflags) |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;\
627 if (!rb_w32_fd_is_text(fptr->
fd)) {
628 r = lseek(fptr->
fd, -fptr->
rbuf.
len, SEEK_CUR);
629 if (r < 0 &&
errno) {
640 pos = lseek(fptr->
fd, 0, SEEK_CUR);
641 if (pos < 0 &&
errno) {
648 extra_max = (long)(pos - fptr->
rbuf.
len);
656 for (i = 0; i < fptr->
rbuf.
len; i++) {
657 if (*p ==
'\n') newlines++;
658 if (extra_max == newlines)
break;
663 while (newlines >= 0) {
664 r = lseek(fptr->
fd, pos - fptr->
rbuf.
len - newlines, SEEK_SET);
665 if (newlines == 0)
break;
670 read_size = _read(fptr->
fd, buf, fptr->
rbuf.
len + newlines);
674 rb_syserr_fail_path(e, fptr->
pathv);
676 if (read_size == fptr->
rbuf.
len) {
677 lseek(fptr->
fd, r, SEEK_SET);
698set_binary_mode_with_seek_cur(
rb_io_t *fptr)
700 if (!rb_w32_fd_is_text(fptr->
fd))
return O_BINARY;
703 return setmode(fptr->
fd, O_BINARY);
705 flush_before_seek(fptr);
706 return setmode(fptr->
fd, O_BINARY);
708#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) set_binary_mode_with_seek_cur(fptr)
712# define DEFAULT_TEXTMODE 0
713#define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || NEED_NEWLINE_DECORATOR_ON_READ(fptr))
714#define NEED_WRITECONV(fptr) ( \
715 ((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || \
716 NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) || \
717 ((fptr)->encs.ecflags & (ECONV_DECORATOR_MASK|ECONV_STATEFUL_DECORATOR_MASK)) || \
719#define SET_BINARY_MODE(fptr) (void)(fptr)
720#define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) (void)(fptr)
721#define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) ((void)(enc2), (void)(ecflags))
722#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) (void)(fptr)
725#if !defined HAVE_SHUTDOWN && !defined shutdown
726#define shutdown(a,b) 0
730#define is_socket(fd, path) rb_w32_is_socket(fd)
731#elif !defined(S_ISSOCK)
732#define is_socket(fd, path) 0
735is_socket(
int fd,
VALUE path)
738 if (fstat(fd, &sbuf) < 0)
739 rb_sys_fail_path(path);
740 return S_ISSOCK(sbuf.st_mode);
744static const char closed_stream[] =
"closed stream";
747io_fd_check_closed(
int fd)
780 io_fd_check_closed(fptr->
fd);
784rb_io_get_fptr(
VALUE io)
794 return rb_convert_type_with_id(io,
T_FILE,
"IO", idTo_io);
800 return rb_check_convert_type_with_id(io,
T_FILE,
"IO", idTo_io);
818 rb_io_t *fptr = rb_io_get_fptr(io);
827 return write_io ? write_io :
Qnil;
840 rb_io_t *fptr = rb_io_get_fptr(self);
870 if (
RTEST(timeout)) {
874 rb_io_t *fptr = rb_io_get_fptr(self);
899#if !RUBY_CRLF_ENVIRONMENT
909 r = lseek(fptr->
fd, -fptr->
rbuf.
len, SEEK_CUR);
910 if (r < 0 &&
errno) {
926 long len = RSTRING_LEN(str);
929 const int min_capa = IO_RBUF_CAPA_FOR(fptr);
932#if SIZEOF_LONG > SIZEOF_INT
957flush_before_seek(
rb_io_t *fptr)
959 if (io_fflush(fptr) < 0)
960 rb_sys_fail_on_write(fptr);
966#define io_seek(fptr, ofs, whence) (errno = 0, lseek(flush_before_seek(fptr)->fd, (ofs), (whence)))
967#define io_tell(fptr) lseek(flush_before_seek(fptr)->fd, 0, SEEK_CUR)
983 if (io_fflush(fptr) < 0)
984 rb_sys_fail_on_write(fptr);
989 if (io_fflush(wfptr) < 0)
990 rb_sys_fail_on_write(wfptr);
998 if (READ_CHAR_PENDING(fptr)) {
999 rb_raise(
rb_eIOError,
"byte oriented read for character buffered IO");
1010io_read_encoding(
rb_io_t *fptr)
1015 return rb_default_external_encoding();
1019io_input_encoding(
rb_io_t *fptr)
1024 return io_read_encoding(fptr);
1043 if (READ_CHAR_PENDING(fptr))
1045 return READ_DATA_PENDING(fptr);
1051 if (!READ_DATA_PENDING(fptr)) {
1058rb_gc_for_fd(
int err)
1060 if (err == EMFILE || err == ENFILE || err == ENOMEM) {
1070#define TRY_WITH_GC(expr) \
1071 for (int first_errno, retried_errno = 0, retried = 0; \
1074 (!rb_gc_for_fd(first_errno = errno) || !(expr)) && \
1075 (retried_errno = errno, 1)); \
1076 (void)retried_errno, retried = 1)
1091io_alloc(
VALUE klass)
1101# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
1127struct io_internal_writev_struct {
1134 const struct iovec *iov;
1147io_internal_wait(
VALUE thread,
rb_io_t *fptr,
int error,
int events,
struct timeval *timeout)
1149 int ready = nogvl_wait_for(thread, fptr, events, timeout);
1154 else if (ready == 0) {
1164internal_read_func(
void *ptr)
1169 if (iis->timeout && !iis->nonblock) {
1170 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_IN, iis->timeout) == -1) {
1176 result = read(iis->fd, iis->buf, iis->capa);
1178 if (result < 0 && !iis->nonblock) {
1179 if (io_again_p(
errno)) {
1180 if (io_internal_wait(iis->th, iis->fptr,
errno, RB_WAITFD_IN, iis->timeout) == -1) {
1192#if defined __APPLE__
1193# define do_write_retry(code) do {result = code;} while (result == -1 && errno == EPROTOTYPE)
1195# define do_write_retry(code) result = code
1199internal_write_func(
void *ptr)
1204 if (iis->timeout && !iis->nonblock) {
1205 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1211 do_write_retry(write(iis->fd, iis->buf, iis->capa));
1213 if (result < 0 && !iis->nonblock) {
1215 if (io_again_p(e)) {
1216 if (io_internal_wait(iis->th, iis->fptr,
errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1230internal_writev_func(
void *ptr)
1232 struct io_internal_writev_struct *iis = ptr;
1235 if (iis->timeout && !iis->nonblock) {
1236 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1242 do_write_retry(writev(iis->fd, iis->iov, iis->iovcnt));
1244 if (result < 0 && !iis->nonblock) {
1245 if (io_again_p(
errno)) {
1246 if (io_internal_wait(iis->th, iis->fptr,
errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1260rb_io_read_memory(
rb_io_t *fptr,
void *buf,
size_t count)
1263 if (scheduler !=
Qnil) {
1266 if (!UNDEF_P(result)) {
1282 struct timeval timeout_storage;
1286 iis.timeout = &timeout_storage;
1289 return (ssize_t)rb_thread_io_blocking_call(internal_read_func, &iis, fptr->
fd, RB_WAITFD_IN);
1293rb_io_write_memory(
rb_io_t *fptr,
const void *buf,
size_t count)
1296 if (scheduler !=
Qnil) {
1299 if (!UNDEF_P(result)) {
1315 struct timeval timeout_storage;
1319 iis.timeout = &timeout_storage;
1322 return (ssize_t)rb_thread_io_blocking_call(internal_write_func, &iis, fptr->
fd, RB_WAITFD_OUT);
1327rb_writev_internal(
rb_io_t *fptr,
const struct iovec *iov,
int iovcnt)
1329 if (!iovcnt)
return 0;
1332 if (scheduler !=
Qnil) {
1336 if (!UNDEF_P(result)) {
1341 struct io_internal_writev_struct iis = {
1352 struct timeval timeout_storage;
1356 iis.timeout = &timeout_storage;
1359 return (ssize_t)rb_thread_io_blocking_call(internal_writev_func, &iis, fptr->
fd, RB_WAITFD_OUT);
1364io_flush_buffer_sync(
void *arg)
1386io_flush_buffer_async(
VALUE arg)
1389 return rb_thread_io_blocking_call(io_flush_buffer_sync, fptr, fptr->
fd, RB_WAITFD_OUT);
1396 return (
int)io_flush_buffer_async((
VALUE)fptr);
1411 while (fptr->
wbuf.
len > 0 && io_flush_buffer(fptr) != 0) {
1426 if (scheduler !=
Qnil) {
1436 if (NIL_OR_UNDEF_P(timeout)) {
1440 if (timeout !=
Qnil) {
1445 int ready = rb_thread_wait_for_single_fd(fptr->
fd,
RB_NUM2INT(events), tv);
1469io_wait_for_single_fd(
int fd,
int events,
struct timeval *timeout)
1473 if (scheduler !=
Qnil) {
1479 return rb_thread_wait_for_single_fd(fd, events, timeout);
1485 io_fd_check_closed(f);
1491#if defined(ERESTART)
1498#if EWOULDBLOCK != EAGAIN
1501 if (scheduler !=
Qnil) {
1519 io_fd_check_closed(f);
1525#if defined(ERESTART)
1541#if EWOULDBLOCK != EAGAIN
1544 if (scheduler !=
Qnil) {
1562 return io_wait_for_single_fd(fd, events, timeout);
1596#if defined(ERESTART)
1606#if EWOULDBLOCK != EAGAIN
1623 if (
RTEST(result)) {
1636 if (
RTEST(result)) {
1648 const char *senc, *denc;
1655 ecflags = fptr->
encs.
ecflags & ~ECONV_NEWLINE_DECORATOR_READ_MASK;
1682 denc = rb_enc_name(enc);
1715io_binwrite_string_internal(
rb_io_t *fptr,
const char *ptr,
long length)
1718 struct iovec iov[2];
1721 iov[0].iov_len = fptr->
wbuf.
len;
1722 iov[1].iov_base = (
void*)ptr;
1723 iov[1].iov_len = length;
1725 ssize_t result = rb_writev_internal(fptr, iov, 2);
1730 if (result >= fptr->
wbuf.
len) {
1738 fptr->
wbuf.
off += (int)result;
1739 fptr->
wbuf.
len -= (int)result;
1747 return rb_io_write_memory(fptr, ptr, length);
1752io_binwrite_string_internal(
rb_io_t *fptr,
const char *ptr,
long length)
1754 long remaining = length;
1757 if (fptr->
wbuf.
len+length <= fptr->wbuf.capa) {
1764 fptr->
wbuf.
len += (int)length;
1771 if (io_fflush(fptr) < 0) {
1776 if (remaining == 0) {
1782 return rb_io_write_memory(fptr, ptr, length);
1787io_binwrite_string(
VALUE arg)
1791 const char *ptr = p->ptr;
1792 size_t remaining = p->length;
1796 ssize_t result = io_binwrite_string_internal(p->fptr, ptr, remaining);
1802 else if (result > 0) {
1803 if ((
size_t)result == remaining)
break;
1805 remaining -= result;
1821io_allocate_write_buffer(
rb_io_t *fptr,
int sync)
1826 fptr->
wbuf.
capa = IO_WBUF_CAPA_MIN;
1837io_binwrite_requires_flush_write(
rb_io_t *fptr,
long len,
int nosync)
1852io_binwrite(
VALUE str,
const char *ptr,
long len,
rb_io_t *fptr,
int nosync)
1854 if (
len <= 0)
return len;
1859 io_allocate_write_buffer(fptr, !nosync);
1861 if (io_binwrite_requires_flush_write(fptr,
len, nosync)) {
1873 return io_binwrite_string((
VALUE)&arg);
1890# define MODE_BTMODE(a,b,c) ((fmode & FMODE_BINMODE) ? (b) : \
1891 (fmode & FMODE_TEXTMODE) ? (c) : (a))
1893#define MODE_BTXMODE(a, b, c, d, e, f) ((fmode & FMODE_EXCL) ? \
1894 MODE_BTMODE(d, e, f) : \
1895 MODE_BTMODE(a, b, c))
1900 if (NEED_WRITECONV(fptr)) {
1902 SET_BINARY_MODE(fptr);
1904 make_writeconv(fptr);
1907#define fmode (fptr->mode)
1910 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1) && !rb_enc_asciicompat(rb_enc_get(str))) {
1911 rb_raise(rb_eArgError,
"ASCII incompatible string written for text mode IO without encoding conversion: %s",
1912 rb_enc_name(rb_enc_get(str)));
1918 common_encoding = rb_enc_from_encoding(fptr->
encs.
enc2);
1919 else if (fptr->
encs.
enc != rb_ascii8bit_encoding())
1920 common_encoding = rb_enc_from_encoding(fptr->
encs.
enc);
1923 if (!
NIL_P(common_encoding)) {
1934#if RUBY_CRLF_ENVIRONMENT
1935#define fmode (fptr->mode)
1936 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1)) {
1939 setmode(fptr->
fd, O_BINARY);
1942 setmode(fptr->
fd, O_TEXT);
1944 if (!rb_enc_asciicompat(rb_enc_get(str))) {
1945 rb_raise(rb_eArgError,
"ASCII incompatible string written for text mode IO without encoding conversion: %s",
1946 rb_enc_name(rb_enc_get(str)));
1964 long len = rb_w32_write_console(str, fptr->
fd);
1969 str = do_writeconv(str, fptr, &converted);
1973 tmp = rb_str_tmp_frozen_no_embed_acquire(str);
1975 n = io_binwrite(tmp, ptr,
len, fptr, nosync);
1976 rb_str_tmp_frozen_release(str, tmp);
1988 return (ssize_t)io_binwrite(0, buf, (
long)size, fptr, 0);
1998 io = GetWriteIO(io);
1999 str = rb_obj_as_string(str);
2008 if (RSTRING_LEN(str) == 0)
return INT2FIX(0);
2013 n = io_fwrite(str, fptr, nosync);
2014 if (n < 0L) rb_sys_fail_on_write(fptr);
2020struct binwritev_arg {
2028io_binwritev_internal(
VALUE arg)
2030 struct binwritev_arg *p = (
struct binwritev_arg *)arg;
2032 size_t remaining = p->total;
2036 struct iovec *iov = p->iov;
2037 int iovcnt = p->iovcnt;
2040 long result = rb_writev_internal(fptr, iov, iovcnt);
2045 if (offset < (
size_t)fptr->
wbuf.
len) {
2050 offset -= (size_t)fptr->
wbuf.
len;
2056 if (offset == p->total) {
2060 while (result >= (ssize_t)iov->iov_len) {
2062 result -= iov->iov_len;
2072 iov->iov_base = (
char *)iov->iov_base + result;
2073 iov->iov_len -= result;
2087io_binwritev(
struct iovec *iov,
int iovcnt,
rb_io_t *fptr)
2092 if (iovcnt == 0)
return 0;
2095 for (
int i = 1; i < iovcnt; i++) total += iov[i].iov_len;
2097 io_allocate_write_buffer(fptr, 1);
2103 if (offset + total <= (
size_t)fptr->
wbuf.
capa) {
2104 for (
int i = 1; i < iovcnt; i++) {
2105 memcpy(fptr->
wbuf.
ptr+offset, iov[i].iov_base, iov[i].iov_len);
2106 offset += iov[i].iov_len;
2115 iov[0].iov_len = fptr->
wbuf.
len;
2128 struct binwritev_arg arg;
2131 arg.iovcnt = iovcnt;
2138 return io_binwritev_internal((
VALUE)&arg);
2145 int i, converted, iovcnt = argc + 1;
2147 VALUE v1, v2, str, tmp, *tmp_array;
2153 for (i = 0; i < argc; i++) {
2154 str = rb_obj_as_string(argv[i]);
2156 str = do_writeconv(str, fptr, &converted);
2161 tmp = rb_str_tmp_frozen_acquire(str);
2165 iov[i+1].iov_base = RSTRING_PTR(tmp);
2166 iov[i+1].iov_len = RSTRING_LEN(tmp);
2169 n = io_binwritev(iov, iovcnt, fptr);
2172 for (i = 0; i < argc; i++) {
2173 rb_str_tmp_frozen_release(argv[i], tmp_array[i]);
2182iovcnt_ok(
int iovcnt)
2185 return iovcnt < IOV_MAX;
2193io_writev(
int argc,
const VALUE *argv,
VALUE io)
2200 io = GetWriteIO(io);
2205 return rb_funcallv(io, id_write, argc, argv);
2213 for (i = 0; i < argc; i += cnt) {
2216 n = io_fwritev(cnt, &argv[i], fptr);
2223 n = io_fwrite(rb_obj_as_string(argv[i]), fptr, (i < argc-1));
2227 rb_sys_fail_on_write(fptr);
2229 total = rb_fix_plus(
LONG2FIX(n), total);
2260 return io_writev(argc, argv, io);
2263 VALUE str = argv[0];
2264 return io_write(io, str, 0);
2271 return rb_funcallv(io, id_write, 1, &str);
2275rb_io_writev(
VALUE io,
int argc,
const VALUE *argv)
2283 " which accepts just one argument",
2288 do rb_io_write(io, *argv++);
while (--argc);
2293 return rb_funcallv(io, id_write, argc, argv);
2319 rb_io_write(io, str);
2325nogvl_fsync(
void *ptr)
2330 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->
fd)) != FILE_TYPE_DISK)
2333 return (
VALUE)fsync(fptr->
fd);
2338rb_io_flush_raw(
VALUE io,
int sync)
2342 if (!RB_TYPE_P(io,
T_FILE)) {
2346 io = GetWriteIO(io);
2350 if (io_fflush(fptr) < 0)
2351 rb_sys_fail_on_write(fptr);
2375 return rb_io_flush_raw(io, 1);
2401 pos = io_tell(fptr);
2402 if (pos < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
2408rb_io_seek(
VALUE io,
VALUE offset,
int whence)
2415 pos = io_seek(fptr, pos, whence);
2416 if (pos < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
2422interpret_seek_whence(
VALUE vwhence)
2424 if (vwhence == sym_SET)
2426 if (vwhence == sym_CUR)
2428 if (vwhence == sym_END)
2431 if (vwhence == sym_DATA)
2435 if (vwhence == sym_HOLE)
2491 VALUE offset, ptrname;
2492 int whence = SEEK_SET;
2494 if (
rb_scan_args(argc, argv,
"11", &offset, &ptrname) == 2) {
2495 whence = interpret_seek_whence(ptrname);
2498 return rb_io_seek(io, offset, whence);
2526 pos = io_seek(fptr, pos, SEEK_SET);
2527 if (pos < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
2532static void clear_readconv(
rb_io_t *fptr);
2559rb_io_rewind(
VALUE io)
2564 if (io_seek(fptr, 0L, 0) < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
2565 if (io == ARGF.current_file) {
2566 ARGF.lineno -= fptr->
lineno;
2570 clear_readconv(fptr);
2577fptr_wait_readable(
rb_io_t *fptr)
2595 fptr->
rbuf.
capa = IO_RBUF_CAPA_FOR(fptr);
2606 if (fptr_wait_readable(fptr))
2610 VALUE path = rb_sprintf(
"fd:%d ", fptr->
fd);
2615 rb_syserr_fail_path(e, path);
2669 if (READ_CHAR_PENDING(fptr))
return Qfalse;
2670 if (READ_DATA_PENDING(fptr))
return Qfalse;
2672#if RUBY_CRLF_ENVIRONMENT
2673 if (!NEED_READCONV(fptr) && NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
2674 return RBOOL(eof(fptr->
fd));;
2677 return RBOOL(io_fillbuf(fptr) < 0);
2701 io = GetWriteIO(io);
2738 io = GetWriteIO(io);
2744 fptr->
mode &= ~FMODE_SYNC;
2768rb_io_fsync(
VALUE io)
2772 io = GetWriteIO(io);
2775 if (io_fflush(fptr) < 0)
2776 rb_sys_fail_on_write(fptr);
2777 if ((
int)rb_thread_io_blocking_region(nogvl_fsync, fptr, fptr->
fd) < 0)
2778 rb_sys_fail_path(fptr->
pathv);
2782# define rb_io_fsync rb_f_notimplement
2783# define rb_io_sync rb_f_notimplement
2792#ifdef HAVE_FDATASYNC
2794nogvl_fdatasync(
void *ptr)
2799 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->
fd)) != FILE_TYPE_DISK)
2802 return (
VALUE)fdatasync(fptr->
fd);
2817rb_io_fdatasync(
VALUE io)
2821 io = GetWriteIO(io);
2824 if (io_fflush(fptr) < 0)
2825 rb_sys_fail_on_write(fptr);
2827 if ((
int)rb_thread_io_blocking_region(nogvl_fdatasync, fptr, fptr->
fd) == 0)
2831 return rb_io_fsync(io);
2834#define rb_io_fdatasync rb_io_fsync
2852rb_io_fileno(
VALUE io)
2865 if (RB_TYPE_P(io,
T_FILE)) {
2872 if (!UNDEF_P(fileno)) {
2960rb_io_inspect(
VALUE obj)
2964 static const char closed[] =
" (closed)";
2966 fptr =
RFILE(obj)->fptr;
2973 rb_str_cat(result, closed+1, strlen(closed)-1);
2976 rb_str_catf(result,
"fd %d", fptr->
fd);
2982 rb_str_cat(result, closed, strlen(closed));
2997rb_io_to_io(
VALUE io)
3004read_buffered_data(
char *ptr,
long len,
rb_io_t *fptr)
3008 n = READ_DATA_PENDING_COUNT(fptr);
3009 if (n <= 0)
return 0;
3010 if (n >
len) n = (int)
len;
3018io_bufread(
char *ptr,
long len,
rb_io_t *fptr)
3024 if (READ_DATA_PENDING(fptr) == 0) {
3028 c = rb_io_read_memory(fptr, ptr+offset, n);
3031 if (fptr_wait_readable(fptr))
3036 if ((n -= c) <= 0)
break;
3042 c = read_buffered_data(ptr+offset, n, fptr);
3045 if ((n -= c) <= 0)
break;
3048 if (io_fillbuf(fptr) < 0) {
3055static int io_setstrbuf(
VALUE *str,
long len);
3064bufread_call(
VALUE arg)
3067 p->len = io_bufread(p->str_ptr, p->len, p->fptr);
3072io_fread(
VALUE str,
long offset,
long size,
rb_io_t *fptr)
3077 io_setstrbuf(&str, offset + size);
3078 arg.str_ptr = RSTRING_PTR(str) + offset;
3081 rb_str_locktmp_ensure(str, bufread_call, (
VALUE)&arg);
3083 if (
len < 0) rb_sys_fail_path(fptr->
pathv);
3091 rb_off_t siz = READ_DATA_PENDING_COUNT(fptr);
3094 if (fstat(fptr->
fd, &st) == 0 && S_ISREG(st.st_mode)
3095#
if defined(__HAIKU__)
3100 if (io_fflush(fptr) < 0)
3101 rb_sys_fail_on_write(fptr);
3102 pos = lseek(fptr->
fd, 0, SEEK_CUR);
3103 if (st.st_size >= pos && pos >= 0) {
3104 siz += st.st_size - pos;
3105 if (siz > LONG_MAX) {
3106 rb_raise(
rb_eIOError,
"file too big for single read");
3119 rb_enc_associate(str, io_read_encoding(fptr));
3126make_readconv(
rb_io_t *fptr,
int size)
3131 const char *sname, *dname;
3132 ecflags = fptr->
encs.
ecflags & ~ECONV_NEWLINE_DECORATOR_WRITE_MASK;
3135 sname = rb_enc_name(fptr->
encs.
enc2);
3136 dname = rb_enc_name(io_read_encoding(fptr));
3146 if (size < IO_CBUF_CAPA_MIN) size = IO_CBUF_CAPA_MIN;
3152#define MORE_CHAR_SUSPENDED Qtrue
3153#define MORE_CHAR_FINISHED Qnil
3155fill_cbuf(
rb_io_t *fptr,
int ec_flags)
3157 const unsigned char *ss, *sp, *se;
3158 unsigned char *ds, *dp, *de;
3167 return MORE_CHAR_SUSPENDED;
3178 ss = sp = (
const unsigned char *)fptr->
rbuf.
ptr + fptr->
rbuf.
off;
3183 fptr->
rbuf.
off += (int)(sp - ss);
3184 fptr->
rbuf.
len -= (int)(sp - ss);
3185 fptr->
cbuf.
len += (int)(dp - ds);
3190 fptr->
rbuf.
off -= putbackable;
3191 fptr->
rbuf.
len += putbackable;
3198 if (cbuf_len0 != fptr->
cbuf.
len)
3199 return MORE_CHAR_SUSPENDED;
3202 return MORE_CHAR_FINISHED;
3208 if (io_fillbuf(fptr) < 0) {
3210 return MORE_CHAR_FINISHED;
3215 fptr->
cbuf.
len += (int)(dp - ds);
3222 if (cbuf_len0 != fptr->
cbuf.
len)
3223 return MORE_CHAR_SUSPENDED;
3225 return MORE_CHAR_FINISHED;
3233 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED)
3250 rb_enc_associate(str, fptr->
encs.
enc);
3279 long clen = RSTRING_LEN(s);
3291#define MAX_REALLOC_GAP 4096
3293io_shrink_read_string(
VALUE str,
long n)
3296 rb_str_resize(str, n);
3301io_set_read_length(
VALUE str,
long n,
int shrinkable)
3303 if (RSTRING_LEN(str) != n) {
3305 rb_str_set_len(str, n);
3306 if (shrinkable) io_shrink_read_string(str, n);
3320 if (NEED_READCONV(fptr)) {
3321 int first = !
NIL_P(str);
3322 SET_BINARY_MODE(fptr);
3323 shrinkable = io_setstrbuf(&str,0);
3324 make_readconv(fptr, 0);
3328 if (first) rb_str_set_len(str, first = 0);
3329 io_shift_cbuf(fptr, fptr->
cbuf.
len, &str);
3331 v = fill_cbuf(fptr, 0);
3332 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED) {
3334 if (first) rb_str_set_len(str, first = 0);
3335 io_shift_cbuf(fptr, fptr->
cbuf.
len, &str);
3339 if (v == MORE_CHAR_FINISHED) {
3340 clear_readconv(fptr);
3341 if (first) rb_str_set_len(str, first = 0);
3342 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3343 return io_enc_str(str, fptr);
3348 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3352 enc = io_read_encoding(fptr);
3355 if (siz == 0) siz = BUFSIZ;
3356 shrinkable = io_setstrbuf(&str, siz);
3359 n = io_fread(str, bytes, siz - bytes, fptr);
3360 if (n == 0 && bytes == 0) {
3361 rb_str_set_len(str, 0);
3365 rb_str_set_len(str, bytes);
3368 if (bytes < siz)
break;
3372 if (
capa < (
size_t)RSTRING_LEN(str) + BUFSIZ) {
3373 if (
capa < BUFSIZ) {
3376 else if (
capa > IO_MAX_BUFFER_GROWTH) {
3377 capa = IO_MAX_BUFFER_GROWTH;
3382 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3383 str = io_enc_str(str, fptr);
3391 if (rb_fd_set_nonblock(fptr->
fd) != 0) {
3392 rb_sys_fail_path(fptr->
pathv);
3397io_read_memory_call(
VALUE arg)
3402 if (scheduler !=
Qnil) {
3405 if (!UNDEF_P(result)) {
3411 if (iis->nonblock) {
3412 return rb_thread_io_blocking_call(internal_read_func, iis, iis->fptr->
fd, 0);
3415 return rb_thread_io_blocking_call(internal_read_func, iis, iis->fptr->
fd, RB_WAITFD_IN);
3422 return (
long)rb_str_locktmp_ensure(str, io_read_memory_call, (
VALUE)iis);
3425#define no_exception_p(opts) !rb_opts_exception_p((opts), TRUE)
3428io_getpartial(
int argc,
VALUE *argv,
VALUE io,
int no_exception,
int nonblock)
3439 rb_raise(rb_eArgError,
"negative length %ld given",
len);
3442 shrinkable = io_setstrbuf(&str,
len);
3448 io_set_read_length(str, 0, shrinkable);
3454 n = read_buffered_data(RSTRING_PTR(str),
len, fptr);
3460 io_setstrbuf(&str,
len);
3463 iis.nonblock = nonblock;
3465 iis.buf = RSTRING_PTR(str);
3468 n = io_read_memory_locktmp(str, &iis);
3471 if (!nonblock && fptr_wait_readable(fptr))
3473 if (nonblock && (io_again_p(e))) {
3475 return sym_wait_readable;
3478 e,
"read would block");
3480 rb_syserr_fail_path(e, fptr->
pathv);
3483 io_set_read_length(str, n, shrinkable);
3584io_readpartial(
int argc,
VALUE *argv,
VALUE io)
3588 ret = io_getpartial(argc, argv, io,
Qnil, 0);
3595io_nonblock_eof(
int no_exception)
3597 if (!no_exception) {
3613 rb_raise(rb_eArgError,
"negative length %ld given",
len);
3616 shrinkable = io_setstrbuf(&str,
len);
3617 rb_bool_expected(ex,
"exception", TRUE);
3623 io_set_read_length(str, 0, shrinkable);
3627 n = read_buffered_data(RSTRING_PTR(str),
len, fptr);
3629 rb_fd_set_nonblock(fptr->
fd);
3630 shrinkable |= io_setstrbuf(&str,
len);
3634 iis.buf = RSTRING_PTR(str);
3637 n = io_read_memory_locktmp(str, &iis);
3640 if (io_again_p(e)) {
3641 if (!ex)
return sym_wait_readable;
3643 e,
"read would block");
3645 rb_syserr_fail_path(e, fptr->
pathv);
3648 io_set_read_length(str, n, shrinkable);
3651 if (!ex)
return Qnil;
3666 str = rb_obj_as_string(str);
3667 rb_bool_expected(ex,
"exception", TRUE);
3669 io = GetWriteIO(io);
3673 if (io_fflush(fptr) < 0)
3674 rb_sys_fail_on_write(fptr);
3676 rb_fd_set_nonblock(fptr->
fd);
3677 n = write(fptr->
fd, RSTRING_PTR(str), RSTRING_LEN(str));
3682 if (io_again_p(e)) {
3684 return sym_wait_writable;
3690 rb_syserr_fail_path(e, fptr->
pathv);
3774#if RUBY_CRLF_ENVIRONMENT
3780 if (
NIL_P(length)) {
3783 return read_all(fptr, remain_size(fptr), str);
3787 rb_raise(rb_eArgError,
"negative length %ld given",
len);
3790 shrinkable = io_setstrbuf(&str,
len);
3795 io_set_read_length(str, 0, shrinkable);
3800#if RUBY_CRLF_ENVIRONMENT
3801 previous_mode = set_binary_mode_with_seek_cur(fptr);
3803 n = io_fread(str, 0,
len, fptr);
3804 io_set_read_length(str, n, shrinkable);
3805#if RUBY_CRLF_ENVIRONMENT
3806 if (previous_mode == O_TEXT) {
3807 setmode(fptr->
fd, O_TEXT);
3810 if (n == 0)
return Qnil;
3816rscheck(
const char *rsptr,
long rslen,
VALUE rs)
3819 if (RSTRING_PTR(rs) != rsptr && RSTRING_LEN(rs) != rslen)
3824appendline(
rb_io_t *fptr,
int delim,
VALUE *strp,
long *lp)
3829 if (NEED_READCONV(fptr)) {
3830 SET_BINARY_MODE(fptr);
3831 make_readconv(fptr, 0);
3834 int searchlen = READ_CHAR_PENDING_COUNT(fptr);
3836 p = READ_CHAR_PENDING_PTR(fptr);
3837 if (0 < limit && limit < searchlen)
3838 searchlen = (int)limit;
3839 e = memchr(p, delim, searchlen);
3841 int len = (int)(e-p+1);
3863 return (
unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
3866 }
while (more_char(fptr) != MORE_CHAR_FINISHED);
3867 clear_readconv(fptr);
3872 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3874 long pending = READ_DATA_PENDING_COUNT(fptr);
3876 const char *p = READ_DATA_PENDING_PTR(fptr);
3880 if (limit > 0 && pending > limit) pending = limit;
3881 e = memchr(p, delim, pending);
3882 if (e) pending = e - p + 1;
3884 last = RSTRING_LEN(str);
3885 rb_str_resize(str, last + pending);
3889 *strp = str = rb_str_buf_new(pending);
3890 rb_str_set_len(str, pending);
3892 read_buffered_data(RSTRING_PTR(str) + last, pending, fptr);
3895 if (e)
return delim;
3897 return (
unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
3900 }
while (io_fillbuf(fptr) >= 0);
3906swallow(
rb_io_t *fptr,
int term)
3908 if (NEED_READCONV(fptr)) {
3911 SET_BINARY_MODE(fptr);
3912 make_readconv(fptr, 0);
3915 while ((cnt = READ_CHAR_PENDING_COUNT(fptr)) > 0) {
3916 const char *p = READ_CHAR_PENDING_PTR(fptr);
3919 if (*p != term)
return TRUE;
3921 while (--i && *++p == term);
3924 const char *e = p + cnt;
3925 if (rb_enc_ascget(p, e, &i, enc) != term)
return TRUE;
3926 while ((p += i) < e && rb_enc_ascget(p, e, &i, enc) == term);
3929 io_shift_cbuf(fptr, (
int)cnt - i, NULL);
3931 }
while (more_char(fptr) != MORE_CHAR_FINISHED);
3935 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3938 while ((cnt = READ_DATA_PENDING_COUNT(fptr)) > 0) {
3940 const char *p = READ_DATA_PENDING_PTR(fptr);
3942 if (cnt >
sizeof buf) cnt =
sizeof buf;
3943 if (*p != term)
return TRUE;
3945 while (--i && *++p == term);
3946 if (!read_buffered_data(buf, cnt - i, fptr))
3947 rb_sys_fail_path(fptr->
pathv);
3950 }
while (io_fillbuf(fptr) == 0);
3963 int pending = READ_DATA_PENDING_COUNT(fptr);
3966 const char *p = READ_DATA_PENDING_PTR(fptr);
3970 e = memchr(p,
'\n', pending);
3972 pending = (int)(e - p + 1);
3974 chomplen = (pending > 1 && *(e-1) ==
'\r') + 1;
3983 rb_str_resize(str,
len + pending - chomplen);
3984 read_buffered_data(RSTRING_PTR(str)+
len, pending - chomplen, fptr);
3987 if (pending == 1 && chomplen == 1 &&
len > 0) {
3988 if (RSTRING_PTR(str)[
len-1] ==
'\r') {
3989 rb_str_resize(str, --
len);
3994 len += pending - chomplen;
4000 }
while (io_fillbuf(fptr) >= 0);
4003 str = io_enc_str(str, fptr);
4014 unsigned int chomp: 1;
4028 chomp = (!UNDEF_P(vchomp)) &&
RTEST(vchomp);
4030 args->chomp = chomp;
4048 else if (2 <= argc) {
4049 rs = argv[0], lim = argv[1];
4058check_getline_args(
VALUE *rsp,
long *limit,
VALUE io)
4067 enc_rs = rb_enc_get(rs);
4068 enc_io = io_read_encoding(fptr);
4069 if (enc_io != enc_rs &&
4070 (!is_ascii_string(rs) ||
4071 (RSTRING_LEN(rs) > 0 && !rb_enc_asciicompat(enc_io)))) {
4072 if (rs == rb_default_rs) {
4073 rs = rb_enc_str_new(0, 0, enc_io);
4078 rb_raise(rb_eArgError,
"encoding mismatch: %s IO with %s RS",
4079 rb_enc_name(enc_io),
4080 rb_enc_name(enc_rs));
4090 argc =
rb_scan_args(argc, argv,
"02:", NULL, NULL, &opts);
4091 extract_getline_args(argc, argv, args);
4092 extract_getline_opts(opts, args);
4093 check_getline_args(&args->rs, &args->limit, io);
4097rb_io_getline_0(
VALUE rs,
long limit,
int chomp,
rb_io_t *fptr)
4104 if (
NIL_P(rs) && limit < 0) {
4105 str = read_all(fptr, 0,
Qnil);
4106 if (RSTRING_LEN(str) == 0)
return Qnil;
4108 else if (limit == 0) {
4109 return rb_enc_str_new(0, 0, io_read_encoding(fptr));
4111 else if (rs == rb_default_rs && limit < 0 && !NEED_READCONV(fptr) &&
4112 rb_enc_asciicompat(enc = io_read_encoding(fptr))) {
4113 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4114 return rb_io_getline_fast(fptr, enc, chomp);
4117 int c, newline = -1;
4118 const char *rsptr = 0;
4121 int extra_limit = 16;
4122 int chomp_cr = chomp;
4124 SET_BINARY_MODE(fptr);
4125 enc = io_read_encoding(fptr);
4128 rslen = RSTRING_LEN(rs);
4133 swallow(fptr,
'\n');
4135 if (!rb_enc_asciicompat(enc)) {
4139 rsptr = RSTRING_PTR(rs);
4140 rslen = RSTRING_LEN(rs);
4144 rsptr = RSTRING_PTR(rs);
4146 newline = (
unsigned char)rsptr[rslen - 1];
4147 chomp_cr = chomp && rslen == 1 && newline ==
'\n';
4151 while ((c = appendline(fptr, newline, &str, &limit)) != EOF) {
4152 const char *s, *p, *pp, *e;
4155 if (RSTRING_LEN(str) < rslen)
continue;
4156 s = RSTRING_PTR(str);
4157 e = RSTRING_END(str);
4159 if (!at_char_boundary(s, p, e, enc))
continue;
4160 if (!rspara) rscheck(rsptr, rslen, rs);
4161 if (memcmp(p, rsptr, rslen) == 0) {
4163 if (chomp_cr && p > s && *(p-1) ==
'\r') --p;
4164 rb_str_set_len(str, p - s);
4170 s = RSTRING_PTR(str);
4171 p = RSTRING_END(str);
4187 if (rspara && c != EOF)
4188 swallow(fptr,
'\n');
4190 str = io_enc_str(str, fptr);
4193 if (!
NIL_P(str) && !nolimit) {
4201rb_io_getline_1(
VALUE rs,
long limit,
int chomp,
VALUE io)
4204 int old_lineno, new_lineno;
4208 old_lineno = fptr->
lineno;
4209 str = rb_io_getline_0(rs, limit, chomp, fptr);
4210 if (!
NIL_P(str) && (new_lineno = fptr->
lineno) != old_lineno) {
4211 if (io == ARGF.current_file) {
4212 ARGF.lineno += new_lineno - old_lineno;
4213 ARGF.last_lineno = ARGF.lineno;
4216 ARGF.last_lineno = new_lineno;
4224rb_io_getline(
int argc,
VALUE *argv,
VALUE io)
4228 prepare_getline_args(argc, argv, &args, io);
4229 return rb_io_getline_1(args.rs, args.limit, args.chomp, io);
4235 return rb_io_getline_1(rb_default_rs, -1, FALSE, io);
4239rb_io_gets_internal(
VALUE io)
4243 return rb_io_getline_0(rb_default_rs, -1, FALSE, fptr);
4326 str = rb_io_getline(argc, argv, io);
4342rb_io_lineno(
VALUE io)
4392 rb_lastline_set_up(line, 1);
4469rb_io_readlines(
int argc,
VALUE *argv,
VALUE io)
4473 prepare_getline_args(argc, argv, &args, io);
4474 return io_readlines(&args, io);
4482 if (arg->limit == 0)
4483 rb_raise(rb_eArgError,
"invalid limit: 0 for readlines");
4485 while (!
NIL_P(line = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, io))) {
4486 rb_ary_push(ary, line);
4600rb_io_each_line(
int argc,
VALUE *argv,
VALUE io)
4606 prepare_getline_args(argc, argv, &args, io);
4607 if (args.limit == 0)
4608 rb_raise(rb_eArgError,
"invalid limit: 0 for each_line");
4609 while (!
NIL_P(str = rb_io_getline_1(args.rs, args.limit, args.chomp, io))) {
4636rb_io_each_byte(
VALUE io)
4652 }
while (io_fillbuf(fptr) >= 0);
4662 if (NEED_READCONV(fptr)) {
4666 SET_BINARY_MODE(fptr);
4667 make_readconv(fptr, 0);
4681 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4683 clear_readconv(fptr);
4687 str = rb_enc_str_new(fptr->
cbuf.
ptr+fptr->
cbuf.
off, 1, read_enc);
4690 if (fptr->
cbuf.
len == 0) clear_readconv(fptr);
4699 io_shift_cbuf(fptr, r, &str);
4706 ISASCII(RSTRING_PTR(str)[0])) {
4710 str = io_enc_str(str, fptr);
4715 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4716 if (io_fillbuf(fptr) < 0) {
4738 if (io_fillbuf(fptr) != -1) {
4742 r = rb_enc_precise_mbclen(RSTRING_PTR(str), RSTRING_PTR(str)+RSTRING_LEN(str), enc);
4758 str = io_enc_str(str, fptr);
4784rb_io_each_char(
VALUE io)
4794 enc = io_input_encoding(fptr);
4796 while (!
NIL_P(c = io_getc(fptr, enc))) {
4822rb_io_each_codepoint(
VALUE io)
4834 if (NEED_READCONV(fptr)) {
4835 SET_BINARY_MODE(fptr);
4838 make_readconv(fptr, 0);
4846 r = ONIGENC_CONSTRUCT_MBCLEN_CHARFOUND(1);
4853 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4854 clear_readconv(fptr);
4881 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4882 enc = io_input_encoding(fptr);
4883 while (io_fillbuf(fptr) >= 0) {
4898 char cbuf[8], *p = cbuf;
4900 if (more > numberof(cbuf))
goto invalid;
4902 if (more > numberof(cbuf))
goto invalid;
4903 while ((n = (
int)read_buffered_data(p, more, fptr)) > 0 &&
4904 (p += n, (more -= n) > 0)) {
4905 if (io_fillbuf(fptr) < 0)
goto invalid;
4906 if ((n = fptr->
rbuf.
len) > more) n = more;
4908 r = rb_enc_precise_mbclen(cbuf, p, enc);
4921 rb_raise(rb_eArgError,
"invalid byte sequence in %s", rb_enc_name(enc));
4953 enc = io_input_encoding(fptr);
4955 return io_getc(fptr, enc);
4978rb_io_readchar(
VALUE io)
4980 VALUE c = rb_io_getc(io);
5015 VALUE r_stdout = rb_ractor_stdout();
5020 rb_io_flush(r_stdout);
5023 if (io_fillbuf(fptr) < 0) {
5052rb_io_readbyte(
VALUE io)
5113 unsigned char c =
NUM2INT(v) & 0xFF;
5119 io_ungetbyte(b, fptr);
5175 else if (RB_BIGNUM_TYPE_P(c)) {
5181 if (NEED_READCONV(fptr)) {
5182 SET_BINARY_MODE(fptr);
5183 len = RSTRING_LEN(c);
5184#if SIZEOF_LONG > SIZEOF_INT
5188 make_readconv(fptr, (
int)
len);
5202 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
5203 io_ungetbyte(c, fptr);
5223rb_io_isatty(
VALUE io)
5228 return RBOOL(isatty(fptr->
fd) != 0);
5231#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5247rb_io_close_on_exec_p(
VALUE io)
5253 write_io = GetWriteIO(io);
5254 if (io != write_io) {
5256 if (fptr && 0 <= (fd = fptr->
fd)) {
5257 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->
pathv);
5258 if (!(ret & FD_CLOEXEC))
return Qfalse;
5263 if (fptr && 0 <= (fd = fptr->
fd)) {
5264 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->
pathv);
5265 if (!(ret & FD_CLOEXEC))
return Qfalse;
5270#define rb_io_close_on_exec_p rb_f_notimplement
5273#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5297 int flag =
RTEST(arg) ? FD_CLOEXEC : 0;
5302 write_io = GetWriteIO(io);
5303 if (io != write_io) {
5305 if (fptr && 0 <= (fd = fptr->
fd)) {
5306 if ((ret = fcntl(fptr->
fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->
pathv);
5307 if ((ret & FD_CLOEXEC) != flag) {
5308 ret = (ret & ~FD_CLOEXEC) | flag;
5309 ret = fcntl(fd, F_SETFD, ret);
5310 if (ret != 0) rb_sys_fail_path(fptr->
pathv);
5317 if (fptr && 0 <= (fd = fptr->
fd)) {
5318 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->
pathv);
5319 if ((ret & FD_CLOEXEC) != flag) {
5320 ret = (ret & ~FD_CLOEXEC) | flag;
5321 ret = fcntl(fd, F_SETFD, ret);
5322 if (ret != 0) rb_sys_fail_path(fptr->
pathv);
5328#define rb_io_set_close_on_exec rb_f_notimplement
5331#define RUBY_IO_EXTERNAL_P(f) ((f)->mode & FMODE_EXTERNAL)
5332#define PREP_STDIO_NAME(f) (RSTRING_PTR((f)->pathv))
5335finish_writeconv(
rb_io_t *fptr,
int noalloc)
5337 unsigned char *ds, *dp, *de;
5341 unsigned char buf[1024];
5346 de = buf +
sizeof(buf);
5349 size_t remaining = dp-ds;
5350 long result = rb_io_write_memory(fptr, ds, remaining);
5354 if ((
size_t)result == remaining)
break;
5377 if (io_fflush(fptr) < 0) {
5385 fptr->
wbuf.
len += (int)(dp - ds);
5401finish_writeconv_sync(
VALUE arg)
5404 return finish_writeconv(p->fptr, p->noalloc);
5408nogvl_close(
void *ptr)
5412 return (
void*)(intptr_t)close(*fd);
5416maygvl_close(
int fd,
int keepgvl)
5429nogvl_fclose(
void *ptr)
5433 return (
void*)(intptr_t)fclose(file);
5437maygvl_fclose(
FILE *file,
int keepgvl)
5440 return fclose(file);
5446static void clear_codeconv(
rb_io_t *fptr);
5449fptr_finalize_flush(
rb_io_t *fptr,
int noraise,
int keepgvl,
5455 int mode = fptr->
mode;
5461 arg.noalloc = noraise;
5465 error = finish_writeconv(fptr, noraise);
5470 io_flush_buffer_sync(fptr);
5473 if (io_fflush(fptr) < 0 &&
NIL_P(error)) {
5481 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2) {
5493 rb_notify_fd_close_wait(busy);
5505 if (!done && stdio_file) {
5507 if ((maygvl_fclose(stdio_file, noraise) < 0) &&
NIL_P(error)) {
5516 if (!done && fd >= 0) {
5522 if ((maygvl_close(fd, keepgvl) < 0) &&
NIL_P(error)) {
5531 if (!
NIL_P(error) && !noraise) {
5535 rb_exc_raise(error);
5540fptr_finalize(
rb_io_t *fptr,
int noraise)
5542 fptr_finalize_flush(fptr, noraise, FALSE, 0);
5543 free_io_buffer(&fptr->
rbuf);
5544 free_io_buffer(&fptr->
wbuf);
5545 clear_codeconv(fptr);
5549rb_io_fptr_cleanup(
rb_io_t *fptr,
int noraise)
5555 fptr_finalize(fptr, noraise);
5563 ruby_sized_xfree(buf->
ptr, (
size_t)buf->
capa);
5575 free_io_buffer(&fptr->
cbuf);
5591 clear_readconv(fptr);
5592 clear_writeconv(fptr);
5596rb_io_fptr_cleanup_all(
rb_io_t *fptr)
5600 rb_io_fptr_cleanup(fptr, TRUE);
5602 free_io_buffer(&fptr->
rbuf);
5603 free_io_buffer(&fptr->
wbuf);
5604 clear_codeconv(fptr);
5608rb_io_fptr_finalize_internal(
void *ptr)
5611 rb_io_fptr_cleanup_all(ptr);
5615#undef rb_io_fptr_finalize
5623 rb_io_fptr_finalize_internal(fptr);
5627#define rb_io_fptr_finalize(fptr) rb_io_fptr_finalize_internal(fptr)
5629RUBY_FUNC_EXPORTED
size_t
5630rb_io_memsize(
const rb_io_t *fptr)
5632 size_t size =
sizeof(
rb_io_t);
5643# define KEEPGVL TRUE
5645# define KEEPGVL FALSE
5649io_close_fptr(
VALUE io)
5656 write_io = GetWriteIO(io);
5657 if (io != write_io) {
5658 write_fptr =
RFILE(write_io)->fptr;
5659 if (write_fptr && 0 <= write_fptr->
fd) {
5660 rb_io_fptr_cleanup(write_fptr, TRUE);
5664 fptr =
RFILE(io)->fptr;
5665 if (!fptr)
return 0;
5666 if (fptr->
fd < 0)
return 0;
5668 if (rb_notify_fd_close(fptr->
fd, &busy)) {
5670 fptr_finalize_flush(fptr, FALSE, KEEPGVL, &busy);
5672 rb_io_fptr_cleanup(fptr, FALSE);
5677fptr_waitpid(
rb_io_t *fptr,
int nohang)
5681 rb_last_status_clear();
5690 rb_io_t *fptr = io_close_fptr(io);
5691 if (fptr) fptr_waitpid(fptr, 0);
5728rb_io_close_m(
VALUE io)
5730 rb_io_t *fptr = rb_io_get_fptr(io);
5739io_call_close(
VALUE io)
5748 enum {mesg_len =
sizeof(closed_stream)-1};
5749 VALUE mesg = rb_attr_get(exc, idMesg);
5751 RSTRING_LEN(mesg) != mesg_len ||
5752 memcmp(RSTRING_PTR(mesg), closed_stream, mesg_len)) {
5762 if (!UNDEF_P(closed) &&
RTEST(closed))
return io;
5763 rb_rescue2(io_call_close, io, ignore_closed_stream, io,
5799 write_io = GetWriteIO(io);
5800 if (io != write_io) {
5801 write_fptr =
RFILE(write_io)->fptr;
5802 if (write_fptr && 0 <= write_fptr->
fd) {
5807 fptr = rb_io_get_fptr(io);
5808 return RBOOL(0 > fptr->
fd);
5844rb_io_close_read(
VALUE io)
5850 if (fptr->
fd < 0)
return Qnil;
5851 if (is_socket(fptr->
fd, fptr->
pathv)) {
5855 if (shutdown(fptr->
fd, SHUT_RD) < 0)
5856 rb_sys_fail_path(fptr->
pathv);
5857 fptr->
mode &= ~FMODE_READABLE;
5863 write_io = GetWriteIO(io);
5864 if (io != write_io) {
5869 RFILE(io)->fptr = wfptr;
5872 RFILE(write_io)->fptr = fptr;
5873 rb_io_fptr_cleanup(fptr, FALSE);
5879 rb_raise(
rb_eIOError,
"closing non-duplex IO for reading");
5917rb_io_close_write(
VALUE io)
5922 write_io = GetWriteIO(io);
5924 if (fptr->
fd < 0)
return Qnil;
5925 if (is_socket(fptr->
fd, fptr->
pathv)) {
5929 if (shutdown(fptr->
fd, SHUT_WR) < 0)
5930 rb_sys_fail_path(fptr->
pathv);
5931 fptr->
mode &= ~FMODE_WRITABLE;
5938 rb_raise(
rb_eIOError,
"closing non-duplex IO for writing");
5941 if (io != write_io) {
5961rb_io_sysseek(
int argc,
VALUE *argv,
VALUE io)
5963 VALUE offset, ptrname;
5964 int whence = SEEK_SET;
5968 if (
rb_scan_args(argc, argv,
"11", &offset, &ptrname) == 2) {
5969 whence = interpret_seek_whence(ptrname);
5974 (READ_DATA_BUFFERED(fptr) || READ_CHAR_PENDING(fptr))) {
5978 rb_warn(
"sysseek for buffered IO");
5981 pos = lseek(fptr->
fd, pos, whence);
5982 if (pos < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
6014 str = rb_obj_as_string(str);
6016 io = GetWriteIO(io);
6021 rb_warn(
"syswrite for buffered IO");
6024 tmp = rb_str_tmp_frozen_acquire(str);
6026 n = rb_io_write_memory(fptr, ptr,
len);
6027 if (n < 0) rb_sys_fail_path(fptr->
pathv);
6028 rb_str_tmp_frozen_release(str, tmp);
6045rb_io_sysread(
int argc,
VALUE *argv,
VALUE io)
6056 shrinkable = io_setstrbuf(&str, ilen);
6057 if (ilen == 0)
return str;
6062 if (READ_DATA_BUFFERED(fptr)) {
6068 io_setstrbuf(&str, ilen);
6073 iis.buf = RSTRING_PTR(str);
6076 n = io_read_memory_locktmp(str, &iis);
6079 rb_sys_fail_path(fptr->
pathv);
6082 io_set_read_length(str, n, shrinkable);
6084 if (n == 0 && ilen > 0) {
6100internal_pread_func(
void *_arg)
6104 return (
VALUE)pread(arg->fd, arg->buf, arg->count, arg->offset);
6108pread_internal_call(
VALUE _arg)
6113 if (scheduler !=
Qnil) {
6116 if (!UNDEF_P(result)) {
6121 return rb_thread_io_blocking_call(internal_pread_func, arg, arg->fd, RB_WAITFD_IN);
6165 shrinkable = io_setstrbuf(&str, (
long)arg.count);
6166 if (arg.count == 0)
return str;
6167 arg.buf = RSTRING_PTR(str);
6179 rb_sys_fail_path(fptr->
pathv);
6181 io_set_read_length(str, n, shrinkable);
6182 if (n == 0 && arg.count > 0) {
6190internal_pwrite_func(
void *_arg)
6195 if (scheduler !=
Qnil) {
6198 if (!UNDEF_P(result)) {
6204 return (
VALUE)pwrite(arg->fd, arg->buf, arg->count, arg->offset);
6241 str = rb_obj_as_string(str);
6245 io = GetWriteIO(io);
6250 tmp = rb_str_tmp_frozen_acquire(str);
6251 arg.buf = RSTRING_PTR(tmp);
6252 arg.count = (size_t)RSTRING_LEN(tmp);
6254 n = (ssize_t)rb_thread_io_blocking_call(internal_pwrite_func, &arg, fptr->
fd, RB_WAITFD_OUT);
6255 if (n < 0) rb_sys_fail_path(fptr->
pathv);
6256 rb_str_tmp_frozen_release(str, tmp);
6272 fptr->
mode &= ~FMODE_TEXTMODE;
6276 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6279 setmode(fptr->
fd, O_BINARY);
6286io_ascii8bit_binmode(
rb_io_t *fptr)
6297 fptr->
mode &= ~FMODE_TEXTMODE;
6298 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6300 fptr->
encs.
enc = rb_ascii8bit_encoding();
6304 clear_codeconv(fptr);
6313 io_ascii8bit_binmode(fptr);
6330rb_io_binmode_m(
VALUE io)
6336 write_io = GetWriteIO(io);
6351rb_io_binmode_p(
VALUE io)
6359rb_io_fmode_modestr(
int fmode)
6363 return MODE_BTMODE(
"a+",
"ab+",
"at+");
6365 return MODE_BTMODE(
"a",
"ab",
"at");
6369 rb_raise(rb_eArgError,
"invalid access fmode 0x%x", fmode);
6371 return MODE_BTMODE(
"r",
"rb",
"rt");
6373 return MODE_BTXMODE(
"w",
"wb",
"wt",
"wx",
"wbx",
"wtx");
6376 return MODE_BTXMODE(
"w+",
"wb+",
"wt+",
"w+x",
"wb+x",
"wt+x");
6378 return MODE_BTMODE(
"r+",
"rb+",
"rt+");
6382static const char bom_prefix[] =
"bom|";
6383static const char utf_prefix[] =
"utf-";
6384enum {bom_prefix_len = (int)
sizeof(bom_prefix) - 1};
6385enum {utf_prefix_len = (int)
sizeof(utf_prefix) - 1};
6388io_encname_bom_p(
const char *name,
long len)
6390 return len > bom_prefix_len &&
STRNCASECMP(name, bom_prefix, bom_prefix_len) == 0;
6397 const char *m = modestr, *p = NULL;
6425 if (modestr[0] !=
'w')
6433 if (io_encname_bom_p(m, p ? (
long)(p - m) : (
long)strlen(m)))
6446 rb_raise(rb_eArgError,
"invalid access mode %s", modestr);
6455 switch (oflags & O_ACCMODE) {
6467 if (oflags & O_APPEND) {
6470 if (oflags & O_TRUNC) {
6473 if (oflags & O_CREAT) {
6476 if (oflags & O_EXCL) {
6480 if (oflags & O_BINARY) {
6489rb_io_fmode_oflags(
int fmode)
6533rb_io_oflags_modestr(
int oflags)
6536# define MODE_BINARY(a,b) ((oflags & O_BINARY) ? (b) : (a))
6538# define MODE_BINARY(a,b) (a)
6541 if (oflags & O_EXCL) {
6542 rb_raise(rb_eArgError,
"exclusive access mode is not supported");
6544 accmode = oflags & (O_RDONLY|O_WRONLY|O_RDWR);
6545 if (oflags & O_APPEND) {
6546 if (accmode == O_WRONLY) {
6547 return MODE_BINARY(
"a",
"ab");
6549 if (accmode == O_RDWR) {
6550 return MODE_BINARY(
"a+",
"ab+");
6555 rb_raise(rb_eArgError,
"invalid access oflags 0x%x", oflags);
6557 return MODE_BINARY(
"r",
"rb");
6559 return MODE_BINARY(
"w",
"wb");
6561 if (oflags & O_TRUNC) {
6562 return MODE_BINARY(
"w+",
"wb+");
6564 return MODE_BINARY(
"r+",
"rb+");
6576 int default_ext = 0;
6579 ext = rb_default_external_encoding();
6582 if (rb_is_ascii8bit_enc(ext)) {
6586 else if (intern == NULL) {
6587 intern = rb_default_internal_encoding();
6592 *enc = (default_ext && intern != ext) ? NULL : ext;
6602unsupported_encoding(
const char *name,
rb_encoding *enc)
6604 rb_enc_warn(enc,
"Unsupported encoding %s ignored", name);
6608parse_mode_enc(
const char *estr,
rb_encoding *estr_enc,
6614 int fmode = fmode_p ? *fmode_p : 0;
6620 p = strrchr(estr,
':');
6621 len = p ? (p++ - estr) : (long)strlen(estr);
6623 estr += bom_prefix_len;
6624 len -= bom_prefix_len;
6625 if (!
STRNCASECMP(estr, utf_prefix, utf_prefix_len)) {
6629 rb_enc_warn(estr_enc,
"BOM with non-UTF encoding %s is nonsense", estr);
6630 fmode &= ~FMODE_SETENC_BY_BOM;
6638 memcpy(encname, estr,
len);
6639 encname[
len] =
'\0';
6642 idx = rb_enc_find_index(estr);
6644 if (fmode_p) *fmode_p = fmode;
6647 ext_enc = rb_enc_from_index(idx);
6650 unsupported_encoding(estr, estr_enc);
6656 if (*p ==
'-' && *(p+1) ==
'\0') {
6661 idx2 = rb_enc_find_index(p);
6663 unsupported_encoding(p, estr_enc);
6668 int_enc = rb_enc_from_index(idx2);
6672 rb_io_ext_int_to_encs(ext_enc, int_enc, enc_p, enc2_p, fmode);
6685 v = rb_hash_lookup2(opt, sym_encoding,
Qnil);
6686 if (v !=
Qnil) encoding = v;
6687 v = rb_hash_lookup2(opt, sym_extenc,
Qundef);
6688 if (v !=
Qnil) extenc = v;
6689 v = rb_hash_lookup2(opt, sym_intenc,
Qundef);
6690 if (!UNDEF_P(v)) intenc = v;
6692 if ((!UNDEF_P(extenc) || !UNDEF_P(intenc)) && !
NIL_P(encoding)) {
6694 int idx = rb_to_encoding_index(encoding);
6695 if (idx >= 0) encoding = rb_enc_from_encoding(rb_enc_from_index(idx));
6696 rb_warn(
"Ignoring encoding parameter '%"PRIsVALUE
"': %s_encoding is used",
6697 encoding, UNDEF_P(extenc) ?
"internal" :
"external");
6701 if (!UNDEF_P(extenc) && !
NIL_P(extenc)) {
6702 extencoding = rb_to_encoding(extenc);
6704 if (!UNDEF_P(intenc)) {
6705 if (
NIL_P(intenc)) {
6712 if (*p ==
'-' && *(p+1) ==
'\0') {
6717 intencoding = rb_to_encoding(intenc);
6721 intencoding = rb_to_encoding(intenc);
6723 if (extencoding == intencoding) {
6727 if (!
NIL_P(encoding)) {
6731 enc_p, enc2_p, fmode_p);
6734 rb_io_ext_int_to_encs(rb_to_encoding(encoding), NULL, enc_p, enc2_p, 0);
6737 else if (!UNDEF_P(extenc) || !UNDEF_P(intenc)) {
6739 rb_io_ext_int_to_encs(extencoding, intencoding, enc_p, enc2_p, 0);
6747 int fmode = *fmode_p;
6752 !rb_enc_asciicompat(enc ? enc : rb_default_external_encoding()))
6753 rb_raise(rb_eArgError,
"ASCII incompatible encoding needs binmode");
6756 rb_raise(rb_eArgError,
"newline decorator with binary mode");
6763#if !DEFAULT_TEXTMODE
6765 fmode &= ~FMODE_TEXTMODE;
6772extract_binmode(
VALUE opthash,
int *fmode)
6774 if (!
NIL_P(opthash)) {
6776 v = rb_hash_aref(opthash, sym_textmode);
6779 rb_raise(rb_eArgError,
"textmode specified twice");
6781 rb_raise(rb_eArgError,
"both textmode and binmode specified");
6785 v = rb_hash_aref(opthash, sym_binmode);
6788 rb_raise(rb_eArgError,
"binmode specified twice");
6790 rb_raise(rb_eArgError,
"both textmode and binmode specified");
6796 rb_raise(rb_eArgError,
"both textmode and binmode specified");
6802 int *oflags_p,
int *fmode_p,
struct rb_io_encoding *convconfig_p)
6809 int has_enc = 0, has_vmode = 0;
6815 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
6833 oflags = rb_io_fmode_oflags(fmode);
6837 parse_mode_enc(p+1, rb_enc_get(vmode), &enc, &enc2, &fmode);
6842 e = (fmode &
FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
6843 rb_io_ext_int_to_encs(e, NULL, &enc, &enc2, fmode);
6847 if (
NIL_P(opthash)) {
6851#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
6853 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
6854 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
6856 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
6863 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
6866 else if (
NIL_P(vmode)) {
6867 fmode |= DEFAULT_TEXTMODE;
6874 v = rb_hash_aref(opthash, sym_mode);
6876 if (!
NIL_P(vmode)) {
6877 rb_raise(rb_eArgError,
"mode specified twice");
6884 v = rb_hash_aref(opthash, sym_flags);
6891 extract_binmode(opthash, &fmode);
6897 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
6900 else if (
NIL_P(vmode)) {
6901 fmode |= DEFAULT_TEXTMODE;
6904 v = rb_hash_aref(opthash, sym_perm);
6907 if (!
NIL_P(*vperm_p)) {
6908 rb_raise(rb_eArgError,
"perm specified twice");
6919#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
6921 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
6922 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
6927 rb_raise(rb_eArgError,
"encoding specified twice");
6930 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
6934 validate_enc_binmode(&fmode, ecflags, enc, enc2);
6940 convconfig_p->
enc = enc;
6941 convconfig_p->
enc2 = enc2;
6942 convconfig_p->
ecflags = ecflags;
6943 convconfig_p->
ecopts = ecopts;
6953sysopen_func(
void *ptr)
6956 const char *fname = RSTRING_PTR(data->fname);
6971rb_sysopen(
VALUE fname,
int oflags, mode_t perm)
6976 data.fname = rb_str_encode_ospath(fname);
6978 data.oflags = oflags;
6981 TRY_WITH_GC((fd = rb_sysopen_internal(&data)) >= 0) {
6982 rb_syserr_fail_path(first_errno, fname);
6988fdopen_internal(
int fd,
const char *modestr)
6995 file = fdopen(fd, modestr);
7011 TRY_WITH_GC((file = fdopen_internal(fd, modestr)) != 0) {
7017 if (setvbuf(file, NULL, _IOFBF, 0) != 0)
7018 rb_warn(
"setvbuf() can't be honoured (fd=%d)", fd);
7026 int t = isatty(fptr->
fd);
7036io_strip_bom(
VALUE io)
7038 VALUE b1, b2, b3, b4;
7049 return rb_utf8_encindex();
7059 return ENCINDEX_UTF_16BE;
7070 return ENCINDEX_UTF_32LE;
7075 return ENCINDEX_UTF_16LE;
7085 return ENCINDEX_UTF_32BE;
7099io_set_encoding_by_bom(
VALUE io)
7101 int idx = io_strip_bom(io);
7107 extenc = rb_enc_from_index(idx);
7108 io_encoding_set(fptr, rb_enc_from_encoding(extenc),
7109 rb_io_internal_encoding(io),
Qnil);
7118rb_file_open_generic(
VALUE io,
VALUE filename,
int oflags,
int fmode,
7126 rb_io_ext_int_to_encs(NULL, NULL, &cc.enc, &cc.enc2, fmode);
7131 validate_enc_binmode(&fmode, convconfig->
ecflags,
7132 convconfig->
enc, convconfig->
enc2);
7136 fptr->
encs = *convconfig;
7137 pathv = rb_str_new_frozen(filename);
7139 if (!(oflags & O_TMPFILE)) {
7140 fptr->
pathv = pathv;
7143 fptr->
pathv = pathv;
7145 fptr->
fd = rb_sysopen(pathv, oflags, perm);
7153rb_file_open_internal(
VALUE io,
VALUE filename,
const char *modestr)
7156 const char *p = strchr(modestr,
':');
7160 parse_mode_enc(p+1, rb_usascii_encoding(),
7161 &convconfig.
enc, &convconfig.
enc2, &fmode);
7169 e = (fmode &
FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
7170 rb_io_ext_int_to_encs(e, NULL, &convconfig.
enc, &convconfig.
enc2, fmode);
7175 return rb_file_open_generic(io, filename,
7176 rb_io_fmode_oflags(fmode),
7186 return rb_file_open_internal(io_alloc(
rb_cFile), fname, modestr);
7195#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7218 while ((tmp = *prev) != 0) {
7219 if (tmp->fptr == fptr) {
7228#if defined (_WIN32) || defined(__CYGWIN__)
7237 rb_io_fptr_finalize(list->fptr);
7244pipe_finalize(
rb_io_t *fptr,
int noraise)
7246#if !defined(HAVE_WORKING_FORK) && !defined(_WIN32)
7255 fptr_finalize(fptr, noraise);
7257 pipe_del_fptr(fptr);
7264#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7265 void (*
const old_finalize)(
struct rb_io*,int) = fptr->
finalize;
7267 if (old_finalize == orig->finalize)
return;
7272#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7273 if (old_finalize != pipe_finalize) {
7275 for (list =
pipe_list; list; list = list->next) {
7276 if (list->fptr == fptr)
break;
7278 if (!list) pipe_add_fptr(fptr);
7281 pipe_del_fptr(fptr);
7294rb_io_unbuffered(
rb_io_t *fptr)
7312#define HAVE_SPAWNV 1
7313#define spawnv(mode, cmd, args) rb_w32_uaspawn((mode), (cmd), (args))
7314#define spawn(mode, cmd) rb_w32_uspawn((mode), (cmd), 0)
7317#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7327#ifdef HAVE_WORKING_FORK
7328# ifndef __EMSCRIPTEN__
7330popen_redirect(
struct popen_arg *p)
7333 close(p->write_pair[1]);
7334 if (p->write_pair[0] != 0) {
7335 dup2(p->write_pair[0], 0);
7336 close(p->write_pair[0]);
7339 if (p->pair[1] != 1) {
7340 dup2(p->pair[1], 1);
7346 if (p->pair[1] != 1) {
7347 dup2(p->pair[1], 1);
7353 if (p->pair[0] != 0) {
7354 dup2(p->pair[0], 0);
7361#if defined(__linux__)
7372linux_get_maxfd(
void)
7375 char buf[4096], *p, *np, *e;
7378 if (fd < 0)
return fd;
7379 ss = read(fd, buf,
sizeof(buf));
7380 if (ss < 0)
goto err;
7383 while ((
int)
sizeof(
"FDSize:\t0\n")-1 <= e-p &&
7384 (np = memchr(p,
'\n', e-p)) != NULL) {
7385 if (memcmp(p,
"FDSize:",
sizeof(
"FDSize:")-1) == 0) {
7387 p +=
sizeof(
"FDSize:")-1;
7407#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
7409 int max = (int)max_file_descriptor;
7412 ret = fcntl(0, F_MAXFD);
7414 maxhint = max = ret;
7415# elif defined(__linux__)
7416 ret = linux_get_maxfd();
7423 for (fd = lowfd; fd <= max; fd++) {
7424 if (!
NIL_P(noclose_fds) &&
7427 ret = fcntl(fd, F_GETFD);
7428 if (ret != -1 && !(ret & FD_CLOEXEC)) {
7429 fcntl(fd, F_SETFD, ret|FD_CLOEXEC);
7431# define CONTIGUOUS_CLOSED_FDS 20
7433 if (max < fd + CONTIGUOUS_CLOSED_FDS)
7434 max = fd + CONTIGUOUS_CLOSED_FDS;
7440# ifndef __EMSCRIPTEN__
7442popen_exec(
void *pp,
char *errmsg,
size_t errmsg_len)
7444 struct popen_arg *p = (
struct popen_arg*)pp;
7446 return rb_exec_async_signal_safe(p->eargp, errmsg, errmsg_len);
7451#if (defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)) && !defined __EMSCRIPTEN__
7453rb_execarg_fixup_v(
VALUE execarg_obj)
7455 rb_execarg_parent_start(execarg_obj);
7459char *rb_execarg_commandline(
const struct rb_execarg *eargp,
VALUE *prog);
7462#ifndef __EMSCRIPTEN__
7464pipe_open(
VALUE execarg_obj,
const char *modestr,
int fmode,
7467 struct rb_execarg *eargp =
NIL_P(execarg_obj) ? NULL : rb_execarg_get(execarg_obj);
7468 VALUE prog = eargp ? (eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name) :
Qfalse ;
7474#if defined(HAVE_WORKING_FORK)
7476 char errmsg[80] = {
'\0' };
7478#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7480 struct popen_arg arg;
7483#if defined(HAVE_SPAWNV)
7484# if defined(HAVE_SPAWNVE)
7485# define DO_SPAWN(cmd, args, envp) ((args) ? \
7486 spawnve(P_NOWAIT, (cmd), (args), (envp)) : \
7487 spawne(P_NOWAIT, (cmd), (envp)))
7489# define DO_SPAWN(cmd, args, envp) ((args) ? \
7490 spawnv(P_NOWAIT, (cmd), (args)) : \
7491 spawn(P_NOWAIT, (cmd)))
7493# if !defined(HAVE_WORKING_FORK)
7495# if defined(HAVE_SPAWNVE)
7500#if !defined(HAVE_WORKING_FORK)
7506#if !defined(HAVE_WORKING_FORK)
7507 const char *cmd = 0;
7513#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7514 arg.execarg_obj = execarg_obj;
7517 arg.pair[0] = arg.pair[1] = -1;
7518 arg.write_pair[0] = arg.write_pair[1] = -1;
7519# if !defined(HAVE_WORKING_FORK)
7520 if (eargp && !eargp->use_shell) {
7521 args = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
7526 if (
rb_pipe(arg.write_pair) < 0)
7527 rb_sys_fail_str(prog);
7530 close(arg.write_pair[0]);
7531 close(arg.write_pair[1]);
7535 rb_execarg_addopt(execarg_obj,
INT2FIX(0),
INT2FIX(arg.write_pair[0]));
7536 rb_execarg_addopt(execarg_obj,
INT2FIX(1),
INT2FIX(arg.pair[1]));
7541 rb_sys_fail_str(prog);
7543 rb_execarg_addopt(execarg_obj,
INT2FIX(1),
INT2FIX(arg.pair[1]));
7547 rb_sys_fail_str(prog);
7549 rb_execarg_addopt(execarg_obj,
INT2FIX(0),
INT2FIX(arg.pair[0]));
7552 rb_sys_fail_str(prog);
7554 if (!
NIL_P(execarg_obj)) {
7555 rb_protect(rb_execarg_fixup_v, execarg_obj, &state);
7557 if (0 <= arg.write_pair[0]) close(arg.write_pair[0]);
7558 if (0 <= arg.write_pair[1]) close(arg.write_pair[1]);
7559 if (0 <= arg.pair[0]) close(arg.pair[0]);
7560 if (0 <= arg.pair[1]) close(arg.pair[1]);
7561 rb_execarg_parent_end(execarg_obj);
7565# if defined(HAVE_WORKING_FORK)
7566 pid = rb_fork_async_signal_safe(&status, popen_exec, &arg, arg.eargp->redirect_fds, errmsg,
sizeof(errmsg));
7568 rb_execarg_run_options(eargp, sargp, NULL, 0);
7569# if defined(HAVE_SPAWNVE)
7570 if (eargp->envp_str) envp = (
char **)RSTRING_PTR(eargp->envp_str);
7572 while ((pid = DO_SPAWN(cmd, args, envp)) < 0) {
7574 switch (e =
errno) {
7576# if EWOULDBLOCK != EAGAIN
7585 rb_execarg_run_options(sargp, NULL, NULL, 0);
7587 rb_execarg_parent_end(execarg_obj);
7590# if defined(HAVE_WORKING_FORK)
7591 pid = rb_call_proc__fork();
7593 popen_redirect(&arg);
7605# if defined(HAVE_WORKING_FORK)
7611 close(arg.write_pair[0]);
7612 close(arg.write_pair[1]);
7614# if defined(HAVE_WORKING_FORK)
7623 close(arg.write_pair[0]);
7624 write_fd = arg.write_pair[1];
7635 cmd = rb_execarg_commandline(eargp, &prog);
7636 if (!
NIL_P(execarg_obj)) {
7637 rb_execarg_parent_start(execarg_obj);
7638 rb_execarg_run_options(eargp, sargp, NULL, 0);
7640 fp = popen(cmd, modestr);
7643 rb_execarg_parent_end(execarg_obj);
7644 rb_execarg_run_options(sargp, NULL, NULL, 0);
7646 if (!fp) rb_syserr_fail_path(e, prog);
7656 fptr->
encs = *convconfig;
7657#if RUBY_CRLF_ENVIRONMENT
7664 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
7667#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7668 if (NEED_NEWLINE_DECORATOR_ON_WRITE(fptr)) {
7669 fptr->
encs.
ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
7675 if (0 <= write_fd) {
7676 write_port = io_alloc(
rb_cIO);
7678 write_fptr->
fd = write_fd;
7680 fptr->
mode &= ~FMODE_WRITABLE;
7682 rb_ivar_set(port, rb_intern(
"@tied_io_for_writing"), write_port);
7685#if defined (__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7687 pipe_add_fptr(fptr);
7693pipe_open(
VALUE execarg_obj,
const char *modestr,
int fmode,
7701is_popen_fork(
VALUE prog)
7703 if (RSTRING_LEN(prog) == 1 && RSTRING_PTR(prog)[0] ==
'-') {
7704#if !defined(HAVE_WORKING_FORK)
7706 "fork() function is unimplemented on this machine");
7715pipe_open_s(
VALUE prog,
const char *modestr,
int fmode,
7719 VALUE *argv = &prog;
7722 if (!is_popen_fork(prog))
7723 execarg_obj = rb_execarg_new(argc, argv, TRUE, FALSE);
7724 return pipe_open(execarg_obj, modestr, fmode, convconfig);
7730 rb_io_t *fptr = io_close_fptr(io);
7898rb_io_s_popen(
int argc,
VALUE *argv,
VALUE klass)
7902 if (argc > 1 && !
NIL_P(opt = rb_check_hash_type(argv[argc-1]))) --argc;
7903 if (argc > 1 && !
NIL_P(env = rb_check_hash_type(argv[0]))) --argc, ++argv;
7912 int ex = !
NIL_P(opt);
7913 rb_error_arity(argc + ex, 1 + ex, 2 + ex);
7916 return popen_finish(rb_io_popen(pname, pmode, env, opt), klass);
7922 const char *modestr;
7927 tmp = rb_check_array_type(pname);
7930#if SIZEOF_LONG > SIZEOF_INT
7931 if (
len > INT_MAX) {
7932 rb_raise(rb_eArgError,
"too many arguments");
7941 if (!is_popen_fork(pname))
7942 execarg_obj = rb_execarg_new(1, &pname, TRUE, FALSE);
7944 if (!
NIL_P(execarg_obj)) {
7946 opt = rb_execarg_extract_options(execarg_obj, opt);
7948 rb_execarg_setenv(execarg_obj, env);
7951 modestr = rb_io_oflags_modestr(oflags);
7953 return pipe_open(execarg_obj, modestr, fmode, &convconfig);
7963 rb_io_flush(rb_ractor_stdout());
7964 rb_io_flush(rb_ractor_stderr());
7969 RBASIC_SET_CLASS(port, klass);
7976#if defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)
7977struct popen_writer_arg {
7979 struct popen_arg popen;
7983exec_popen_writer(
void *arg,
char *errmsg,
size_t buflen)
7985 struct popen_writer_arg *pw = arg;
7987 popen_redirect(&pw->popen);
7988 execv(pw->argv[0], pw->argv);
7989 strlcpy(errmsg, strerror(
errno), buflen);
7995ruby_popen_writer(
char *
const *argv, rb_pid_t *pid)
7997#if (defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)) || defined(_WIN32)
7998# ifdef HAVE_WORKING_FORK
7999 struct popen_writer_arg pw;
8000 int *
const write_pair = pw.popen.pair;
8008# ifdef HAVE_WORKING_FORK
8011 char errmsg[80] = {
'\0'};
8012 *pid = rb_fork_async_signal_safe(&status, exec_popen_writer, &pw,
Qnil, errmsg,
sizeof(errmsg));
8014 *pid = rb_w32_uspawn_process(P_NOWAIT, argv[0], argv, write_pair[0], -1, -1, 0);
8015 const char *errmsg = (*pid < 0) ? strerror(
errno) : NULL;
8017 close(write_pair[0]);
8019 close(write_pair[1]);
8020 fprintf(stderr,
"ruby_popen_writer(%s): %s\n", argv[0], errmsg);
8023 return fdopen(write_pair[1],
"w");
8031rb_scan_open_args(
int argc,
const VALUE *argv,
8032 VALUE *fname_p,
int *oflags_p,
int *fmode_p,
8035 VALUE opt, fname, vmode, vperm;
8039 argc =
rb_scan_args(argc, argv,
"12:", &fname, &vmode, &vperm, &opt);
8053rb_open_file(
int argc,
const VALUE *argv,
VALUE io)
8060 rb_scan_open_args(argc, argv, &fname, &oflags, &fmode, &convconfig, &perm);
8061 rb_file_open_generic(io, fname, oflags, fmode, &convconfig, perm);
8099rb_io_s_open(
int argc,
VALUE *argv,
VALUE klass)
8131 VALUE fname, vmode, vperm;
8136 rb_scan_args(argc, argv,
"12", &fname, &vmode, &vperm);
8147 if (
NIL_P(vperm)) perm = 0666;
8151 fd = rb_sysopen(fname, oflags, perm);
8156check_pipe_command(
VALUE filename_or_command)
8158 char *s = RSTRING_PTR(filename_or_command);
8159 long l = RSTRING_LEN(filename_or_command);
8163 if (rb_enc_ascget(s, e, &chlen, rb_enc_get(filename_or_command)) ==
'|') {
8201 int redirect = FALSE;
8209 VALUE tmp = argv[0];
8215 VALUE cmd = check_pipe_command(tmp);
8218 rb_warn_deprecated_to_remove_at(4.0,
"Calling Kernel#open with a leading '|'",
"IO.popen");
8220 return rb_io_s_popen(argc, argv,
rb_cIO);
8233 return rb_io_s_open(argc, argv,
rb_cFile);
8247 return rb_io_open_generic(io, filename, oflags, fmode, &convconfig, perm);
8251rb_io_open_generic(
VALUE klass,
VALUE filename,
int oflags,
int fmode,
8255 if (klass ==
rb_cIO && !
NIL_P(cmd = check_pipe_command(filename))) {
8257 rb_warn_deprecated_to_remove_at(4.0,
"IO process creation with a leading '|'",
"IO.popen");
8258 return pipe_open_s(cmd, rb_io_oflags_modestr(oflags), fmode, convconfig);
8261 return rb_file_open_generic(io_alloc(klass), filename,
8262 oflags, fmode, convconfig, perm);
8277 if (fptr == orig)
return io;
8278 if (RUBY_IO_EXTERNAL_P(fptr)) {
8282 rb_raise(rb_eArgError,
8283 "%s can't change access mode from \"%s\" to \"%s\"",
8284 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->
mode),
8285 rb_io_fmode_modestr(orig->
mode));
8289 if (io_fflush(fptr) < 0)
8290 rb_sys_fail_on_write(fptr);
8293 flush_before_seek(fptr);
8296 pos = io_tell(orig);
8299 if (io_fflush(orig) < 0)
8300 rb_sys_fail_on_write(fptr);
8308 else if (!RUBY_IO_EXTERNAL_P(fptr)) fptr->
pathv =
Qnil;
8309 fptr_copy_finalizer(fptr, orig);
8314 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2 || !fptr->stdio_file) {
8317 rb_sys_fail_path(orig->
pathv);
8325 rb_sys_fail_path(orig->
pathv);
8331 if (io_seek(fptr, pos, SEEK_SET) < 0 &&
errno) {
8332 rb_sys_fail_path(fptr->
pathv);
8334 if (io_seek(orig, pos, SEEK_SET) < 0 &&
errno) {
8335 rb_sys_fail_path(orig->
pathv);
8349int rb_freopen(
VALUE fname,
const char *mode,
FILE *fp);
8352rb_freopen(
VALUE fname,
const char *mode,
FILE *fp)
8354 if (!freopen(RSTRING_PTR(fname), mode, fp)) {
8397rb_io_reopen(
int argc,
VALUE *argv,
VALUE file)
8399 VALUE fname, nmode, opt;
8403 if (
rb_scan_args(argc, argv,
"11:", &fname, &nmode, &opt) == 1) {
8406 return io_reopen(file, tmp);
8412 fptr =
RFILE(file)->fptr;
8422 if (RUBY_IO_EXTERNAL_P(fptr) &&
8425 rb_raise(rb_eArgError,
8426 "%s can't change access mode from \"%s\" to \"%s\"",
8427 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->
mode),
8428 rb_io_fmode_modestr(fmode));
8431 fptr->
encs = convconfig;
8434 oflags = rb_io_fmode_oflags(fptr->
mode);
8437 fptr->
pathv = fname;
8439 fptr->
fd = rb_sysopen(fptr->
pathv, oflags, 0666);
8445 if (io_fflush(fptr) < 0)
8446 rb_sys_fail_on_write(fptr);
8451 int e = rb_freopen(rb_str_encode_ospath(fptr->
pathv),
8452 rb_io_oflags_modestr(oflags),
8454 if (e) rb_syserr_fail_path(e, fptr->
pathv);
8458 if (setvbuf(fptr->
stdio_file, NULL, _IOFBF, 0) != 0)
8459 rb_warn(
"setvbuf() can't be honoured for %"PRIsVALUE, fptr->
pathv);
8462 if (setvbuf(fptr->
stdio_file, NULL, _IONBF, BUFSIZ) != 0)
8463 rb_warn(
"setvbuf() can't be honoured for %"PRIsVALUE, fptr->
pathv);
8465 else if (fptr->
stdio_file == stdout && isatty(fptr->
fd)) {
8466 if (setvbuf(fptr->
stdio_file, NULL, _IOLBF, BUFSIZ) != 0)
8467 rb_warn(
"setvbuf() can't be honoured for %"PRIsVALUE, fptr->
pathv);
8471 int tmpfd = rb_sysopen(fptr->
pathv, oflags, 0666);
8477 rb_syserr_fail_path(err, fptr->
pathv);
8501 fptr->
mode = orig->
mode & ~FMODE_EXTERNAL;
8507 fptr_copy_finalizer(fptr, orig);
8509 fd = ruby_dup(orig->
fd);
8511 pos = io_tell(orig);
8513 io_seek(fptr, pos, SEEK_SET);
8518 write_io = GetWriteIO(io);
8519 if (io != write_io) {
8522 rb_ivar_set(dest, rb_intern(
"@tied_io_for_writing"), write_io);
8585 if (argc == 0)
return Qnil;
8586 if (RB_TYPE_P(argv[0],
T_STRING)) {
8587 out = rb_ractor_stdout();
8604 rb_warn_deprecated(
"`%s'", NULL, rb_id2name(
id));
8677 if (argc > 1 && !
NIL_P(rb_output_fs)) {
8680 for (i=0; i<argc; i++) {
8681 if (!
NIL_P(rb_output_fs) && i>0) {
8682 rb_io_write(out, rb_output_fs);
8684 rb_io_write(out, argv[i]);
8781 rb_io_write(io, str);
8785#define forward(obj, id, argc, argv) \
8786 rb_funcallv_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8787#define forward_public(obj, id, argc, argv) \
8788 rb_funcallv_public_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8789#define forward_current(id, argc, argv) \
8790 forward_public(ARGF.current_file, id, argc, argv)
8807 VALUE r_stdout = rb_ractor_stdout();
8808 if (recv == r_stdout) {
8809 return rb_io_putc(recv, ch);
8811 return forward(r_stdout, rb_intern(
"putc"), 1, &ch);
8816rb_str_end_with_asciichar(
VALUE str,
int c)
8818 long len = RSTRING_LEN(str);
8819 const char *
ptr = RSTRING_PTR(str);
8823 if (
len == 0)
return 0;
8825 return ptr[
len - 1] == c;
8827 return rb_enc_ascget(
ptr + ((
len - 1) / n) * n,
ptr +
len, &n,
enc) == c;
8838 rb_io_puts(1, &tmp, out);
8841 ary = rb_check_array_type(ary);
8845 rb_io_puts(1, &tmp, out);
8900 VALUE line, args[2];
8904 rb_io_write(out, rb_default_rs);
8907 for (
int i = 0; i < argc; i++) {
8909 if (RB_TYPE_P(argv[i],
T_STRING)) {
8916 line = rb_obj_as_string(argv[i]);
8921 if (RSTRING_LEN(line) == 0) {
8922 args[n++] = rb_default_rs;
8926 if (!rb_str_end_with_asciichar(line,
'\n')) {
8927 args[n++] = rb_default_rs;
8931 rb_io_writev(out, n, args);
8949 VALUE r_stdout = rb_ractor_stdout();
8950 if (recv == r_stdout) {
8951 return rb_io_puts(argc, argv, recv);
8953 return forward(r_stdout, rb_intern(
"puts"), argc, argv);
8957rb_p_write(
VALUE str)
8961 args[1] = rb_default_rs;
8962 VALUE r_stdout = rb_ractor_stdout();
8963 if (RB_TYPE_P(r_stdout,
T_FILE) &&
8964 rb_method_basic_definition_p(
CLASS_OF(r_stdout), id_write)) {
8965 io_writev(2, args, r_stdout);
8968 rb_io_writev(r_stdout, 2, args);
8976 rb_p_write(rb_obj_as_string(
rb_inspect(obj)));
8980rb_p_result(
int argc,
const VALUE *argv)
8987 else if (argc > 1) {
8990 VALUE r_stdout = rb_ractor_stdout();
8991 if (RB_TYPE_P(r_stdout,
T_FILE)) {
8992 rb_uninterruptible(rb_io_flush, r_stdout);
9033 for (i=0; i<argc; i++) {
9035 rb_uninterruptible(rb_p_write, inspected);
9037 return rb_p_result(argc, argv);
9058rb_obj_display(
int argc,
VALUE *argv,
VALUE self)
9062 out = (!
rb_check_arity(argc, 0, 1) ? rb_ractor_stdout() : argv[0]);
9063 rb_io_write(out, self);
9069rb_stderr_to_original_p(
VALUE err)
9071 return (err == orig_stderr ||
RFILE(orig_stderr)->fptr->
fd < 0);
9077 VALUE out = rb_ractor_stderr();
9078 if (rb_stderr_to_original_p(out)) {
9080 if (isatty(fileno(stderr))) {
9081 if (rb_w32_write_console(
rb_str_new(mesg,
len), fileno(stderr)) > 0)
return;
9084 if (fwrite(mesg,
sizeof(
char), (
size_t)
len, stderr) < (
size_t)
len) {
9101rb_write_error_str(
VALUE mesg)
9103 VALUE out = rb_ractor_stderr();
9105 if (rb_stderr_to_original_p(out)) {
9106 size_t len = (size_t)RSTRING_LEN(mesg);
9108 if (isatty(fileno(stderr))) {
9109 if (rb_w32_write_console(mesg, fileno(stderr)) > 0)
return;
9112 if (fwrite(RSTRING_PTR(mesg),
sizeof(
char),
len, stderr) <
len) {
9119 rb_io_write(out, mesg);
9124rb_stderr_tty_p(
void)
9126 if (rb_stderr_to_original_p(rb_ractor_stderr()))
9127 return isatty(fileno(stderr));
9132must_respond_to(
ID mid,
VALUE val,
ID id)
9135 rb_raise(
rb_eTypeError,
"%"PRIsVALUE
" must have %"PRIsVALUE
" method, %"PRIsVALUE
" given",
9136 rb_id2str(
id), rb_id2str(mid),
9156 must_respond_to(id_write, val,
id);
9163 return rb_ractor_stdout();
9169 must_respond_to(id_write, val,
id);
9176 return rb_ractor_stderr();
9180allocate_and_open_new_file(
VALUE klass)
9182 VALUE self = io_alloc(klass);
9183 rb_io_make_open_file(self);
9191 VALUE self = rb_protect(allocate_and_open_new_file, klass, &state);
9199 maygvl_close(descriptor, 0);
9207 io->
fd = descriptor;
9219 io->
pathv = rb_str_new_frozen(path);
9225 io->
encs = *encoding;
9234prep_io(
int fd,
int fmode,
VALUE klass,
const char *path)
9244 if (!io_check_tty(io)) {
9247 setmode(fd, O_BINARY);
9259 if (path && strcmp(path,
"-")) klass =
rb_cFile;
9264prep_stdio(
FILE *f,
int fmode,
VALUE klass,
const char *path)
9271#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9272 fptr->
encs.
ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
9283rb_io_prep_stdin(
void)
9289rb_io_prep_stdout(
void)
9295rb_io_prep_stderr(
void)
9304 int oflags = rb_io_fmode_oflags(fptr->
mode) & ~O_EXCL;
9331 rb_io_buffer_init(&fp->
wbuf);
9332 rb_io_buffer_init(&fp->
rbuf);
9333 rb_io_buffer_init(&fp->
cbuf);
9351rb_io_make_open_file(
VALUE obj)
9356 if (
RFILE(obj)->fptr) {
9358 rb_io_fptr_finalize(
RFILE(obj)->fptr);
9359 RFILE(obj)->fptr = 0;
9361 fp = rb_io_fptr_new();
9363 RFILE(obj)->fptr = fp;
9409rb_io_initialize(
int argc,
VALUE *argv,
VALUE io)
9413 int fd, fmode, oflags = O_RDONLY;
9416#if defined(HAVE_FCNTL) && defined(F_GETFL)
9423 argc =
rb_scan_args(argc, argv,
"11:", &fnum, &vmode, &opt);
9428 rb_raise(rb_eArgError,
"The given fd is not accessible because RubyVM reserves it");
9430#if defined(HAVE_FCNTL) && defined(F_GETFL)
9431 oflags = fcntl(fd, F_GETFL);
9432 if (oflags == -1) rb_sys_fail(0);
9434 if (fstat(fd, &st) < 0) rb_sys_fail(0);
9437#if defined(HAVE_FCNTL) && defined(F_GETFL)
9450 if (rb_hash_aref(opt, sym_autoclose) ==
Qfalse) {
9454 path = rb_hash_aref(opt,
RB_ID2SYM(idPath));
9457 path = rb_str_new_frozen(path);
9465 fp->
encs = convconfig;
9470 if (fileno(stdin) == fd)
9472 else if (fileno(stdout) == fd)
9474 else if (fileno(stderr) == fd)
9506rb_io_set_encoding_by_bom(
VALUE io)
9512 rb_raise(rb_eArgError,
"ASCII incompatible encoding needs binmode");
9515 rb_raise(rb_eArgError,
"encoding conversion is set");
9517 else if (fptr->
encs.
enc && fptr->
encs.
enc != rb_ascii8bit_encoding()) {
9518 rb_raise(rb_eArgError,
"encoding is set to %s already",
9521 if (!io_set_encoding_by_bom(io))
return Qnil;
9522 return rb_enc_from_encoding(fptr->
encs.
enc);
9567rb_file_initialize(
int argc,
VALUE *argv,
VALUE io)
9569 if (
RFILE(io)->fptr) {
9572 if (0 < argc && argc < 3) {
9577 return rb_io_initialize(argc, argv, io);
9580 rb_open_file(argc, argv, io);
9587rb_io_s_new(
int argc,
VALUE *argv,
VALUE klass)
9590 VALUE cname = rb_obj_as_string(klass);
9592 rb_warn(
"%"PRIsVALUE
"::new() does not take block; use %"PRIsVALUE
"::open() instead",
9608rb_io_s_for_fd(
int argc,
VALUE *argv,
VALUE klass)
9611 rb_io_initialize(argc, argv, io);
9624rb_io_autoclose_p(
VALUE io)
9649rb_io_set_autoclose(
VALUE io,
VALUE autoclose)
9653 if (!
RTEST(autoclose))
9656 fptr->
mode &= ~FMODE_EXTERNAL;
9661io_wait_event(
VALUE io,
int event,
VALUE timeout,
int return_io)
9693io_wait_readable(
int argc,
VALUE *argv,
VALUE io)
9703 VALUE timeout = (argc == 1 ? argv[0] :
Qnil);
9717io_wait_writable(
int argc,
VALUE *argv,
VALUE io)
9725 VALUE timeout = (argc == 1 ? argv[0] :
Qnil);
9740io_wait_priority(
int argc,
VALUE *argv,
VALUE io)
9750 VALUE timeout = argc == 1 ? argv[0] :
Qnil;
9756wait_mode_sym(
VALUE mode)
9758 if (mode ==
ID2SYM(rb_intern(
"r"))) {
9759 return RB_WAITFD_IN;
9761 if (mode ==
ID2SYM(rb_intern(
"read"))) {
9762 return RB_WAITFD_IN;
9764 if (mode ==
ID2SYM(rb_intern(
"readable"))) {
9765 return RB_WAITFD_IN;
9767 if (mode ==
ID2SYM(rb_intern(
"w"))) {
9768 return RB_WAITFD_OUT;
9770 if (mode ==
ID2SYM(rb_intern(
"write"))) {
9771 return RB_WAITFD_OUT;
9773 if (mode ==
ID2SYM(rb_intern(
"writable"))) {
9774 return RB_WAITFD_OUT;
9776 if (mode ==
ID2SYM(rb_intern(
"rw"))) {
9777 return RB_WAITFD_IN|RB_WAITFD_OUT;
9779 if (mode ==
ID2SYM(rb_intern(
"read_write"))) {
9780 return RB_WAITFD_IN|RB_WAITFD_OUT;
9782 if (mode ==
ID2SYM(rb_intern(
"readable_writable"))) {
9783 return RB_WAITFD_IN|RB_WAITFD_OUT;
9786 rb_raise(rb_eArgError,
"unsupported mode: %"PRIsVALUE, mode);
9790io_event_from_value(
VALUE value)
9794 if (events <= 0) rb_raise(rb_eArgError,
"Events must be positive integer!");
9832 for (
int i = 0; i < argc; i += 1) {
9834 events |= wait_mode_sym(argv[i]);
9836 else if (UNDEF_P(timeout)) {
9840 rb_raise(rb_eArgError,
"timeout given more than once");
9844 if (UNDEF_P(timeout)) timeout =
Qnil;
9852 events = io_event_from_value(argv[0]);
9862 if (return_io)
return Qtrue;
9868 return io_wait_event(io, events, timeout, return_io);
9874 struct argf *p = ptr;
9875 rb_gc_mark(p->filename);
9876 rb_gc_mark(p->current_file);
9877 rb_gc_mark(p->argv);
9878 rb_gc_mark(p->inplace);
9879 rb_gc_mark(p->encs.
ecopts);
9883argf_memsize(
const void *ptr)
9885 const struct argf *p = ptr;
9886 size_t size =
sizeof(*p);
9893 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
9900 p->current_file =
Qnil;
9906argf_alloc(
VALUE klass)
9921 memset(&ARGF, 0,
sizeof(ARGF));
9922 argf_init(&ARGF, argv);
9932 ARGF = argf_of(orig);
9959 ARGF.last_lineno = ARGF.lineno;
9985 return forward_current(rb_frame_this_func(), argc, argv);
9988#define next_argv() argf_next_argv(argf)
9989#define ARGF_GENERIC_INPUT_P() \
9990 (ARGF.current_file == rb_stdin && !RB_TYPE_P(ARGF.current_file, T_FILE))
9991#define ARGF_FORWARD(argc, argv) do {\
9992 if (ARGF_GENERIC_INPUT_P())\
9993 return argf_forward((argc), (argv), argf);\
9995#define NEXT_ARGF_FORWARD(argc, argv) do {\
9996 if (!next_argv()) return Qnil;\
9997 ARGF_FORWARD((argc), (argv));\
10003 VALUE file = ARGF.current_file;
10005 if (RB_TYPE_P(file,
T_FILE)) {
10017 int stdout_binmode = 0;
10020 VALUE r_stdout = rb_ractor_stdout();
10022 if (RB_TYPE_P(r_stdout,
T_FILE)) {
10025 stdout_binmode = 1;
10028 if (ARGF.init_p == 0) {
10038 if (
NIL_P(ARGF.argv)) {
10041 else if (ARGF.next_p == -1 &&
RARRAY_LEN(ARGF.argv) > 0) {
10046 if (ARGF.next_p == 1) {
10047 if (ARGF.init_p == 1) argf_close(
argf);
10050 VALUE filename = rb_ary_shift(ARGF.argv);
10052 ARGF.filename = filename;
10053 filename = rb_str_encode_ospath(filename);
10055 if (RSTRING_LEN(filename) == 1 && fn[0] ==
'-') {
10057 if (ARGF.inplace) {
10058 rb_warn(
"Can't do inplace edit for stdio; skipping");
10064 int fr = rb_sysopen(filename, O_RDONLY, 0);
10066 if (ARGF.inplace) {
10068#ifndef NO_SAFE_RENAME
10074 if (RB_TYPE_P(r_stdout,
T_FILE) && r_stdout != orig_stdout) {
10079 if (!
NIL_P(ARGF.inplace)) {
10080 VALUE suffix = ARGF.inplace;
10081 str = rb_str_dup(str);
10082 if (
NIL_P(rb_str_cat_conv_enc_opts(str, RSTRING_LEN(str),
10083 RSTRING_PTR(suffix), RSTRING_LEN(suffix),
10084 rb_enc_get(suffix), 0,
Qnil))) {
10087#ifdef NO_SAFE_RENAME
10089 (void)unlink(RSTRING_PTR(str));
10090 if (rename(fn, RSTRING_PTR(str)) < 0) {
10091 rb_warn(
"Can't rename %"PRIsVALUE
" to %"PRIsVALUE
": %s, skipping file",
10092 filename, str, strerror(
errno));
10095 fr = rb_sysopen(str, O_RDONLY, 0);
10097 if (rename(fn, RSTRING_PTR(str)) < 0) {
10098 rb_warn(
"Can't rename %"PRIsVALUE
" to %"PRIsVALUE
": %s, skipping file",
10099 filename, str, strerror(
errno));
10106#ifdef NO_SAFE_RENAME
10107 rb_fatal(
"Can't do inplace edit without backup");
10109 if (unlink(fn) < 0) {
10110 rb_warn(
"Can't remove %"PRIsVALUE
": %s, skipping file",
10111 filename, strerror(
errno));
10117 fw = rb_sysopen(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666);
10118#ifndef NO_SAFE_RENAME
10121 fchmod(fw, st.st_mode);
10123 chmod(fn, st.st_mode);
10125 if (st.st_uid!=st2.st_uid || st.st_gid!=st2.st_gid) {
10128 err = fchown(fw, st.st_uid, st.st_gid);
10130 err = chown(fn, st.st_uid, st.st_gid);
10132 if (err && getuid() == 0 && st2.st_uid == 0) {
10133 const char *wkfn = RSTRING_PTR(filename);
10134 rb_warn(
"Can't set owner/group of %"PRIsVALUE
" to same as %"PRIsVALUE
": %s, skipping file",
10135 filename, str, strerror(
errno));
10138 (void)unlink(wkfn);
10148 if (!ARGF.binmode) {
10149 fmode |= DEFAULT_TEXTMODE;
10151 ARGF.current_file = prep_io(fr, fmode,
rb_cFile, fn);
10152 if (!
NIL_P(write_io)) {
10159 if (ARGF.encs.enc) {
10160 fptr->
encs = ARGF.encs;
10161 clear_codeconv(fptr);
10164 fptr->
encs.
ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
10165 if (!ARGF.binmode) {
10167#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
10168 fptr->
encs.
ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
10179 else if (ARGF.next_p == -1) {
10182 if (ARGF.inplace) {
10183 rb_warn(
"Can't do inplace edit for stdio");
10187 if (ARGF.init_p == -1) ARGF.init_p = 1;
10195 long lineno = ARGF.lineno;
10198 if (!next_argv())
return Qnil;
10199 if (ARGF_GENERIC_INPUT_P()) {
10200 line = forward_current(idGets, argc, argv);
10203 if (argc == 0 && rb_rs == rb_default_rs) {
10207 line = rb_io_getline(argc, argv, ARGF.current_file);
10209 if (
NIL_P(line) && ARGF.next_p != -1) {
10215 if (!
NIL_P(line)) {
10216 ARGF.lineno = ++lineno;
10217 ARGF.last_lineno = ARGF.lineno;
10223argf_lineno_getter(
ID id,
VALUE *var)
10226 return INT2FIX(ARGF.last_lineno);
10234 ARGF.last_lineno = ARGF.lineno = n;
10238rb_reset_argf_lineno(
long n)
10240 ARGF.last_lineno = ARGF.lineno = n;
10281 if (recv ==
argf) {
10282 return argf_gets(argc, argv,
argf);
10284 return forward(
argf, idGets, argc, argv);
10310 line = argf_getline(argc, argv,
argf);
10321 if (rb_rs != rb_default_rs) {
10322 return rb_f_gets(0, 0,
argf);
10326 if (!next_argv())
return Qnil;
10328 if (
NIL_P(line) && ARGF.next_p != -1) {
10334 if (!
NIL_P(line)) {
10336 ARGF.last_lineno = ARGF.lineno;
10362rb_f_readline(
int argc,
VALUE *argv,
VALUE recv)
10364 if (recv ==
argf) {
10365 return argf_readline(argc, argv,
argf);
10367 return forward(
argf, rb_intern(
"readline"), argc, argv);
10394 ARGF_FORWARD(argc, argv);
10395 line = argf_gets(argc, argv,
argf);
10464rb_f_readlines(
int argc,
VALUE *argv,
VALUE recv)
10466 if (recv ==
argf) {
10467 return argf_readlines(argc, argv,
argf);
10469 return forward(
argf, rb_intern(
"readlines"), argc, argv);
10493 long lineno = ARGF.lineno;
10496 ary = rb_ary_new();
10497 while (next_argv()) {
10498 if (ARGF_GENERIC_INPUT_P()) {
10499 lines = forward_current(rb_intern(
"readlines"), argc, argv);
10502 lines = rb_io_readlines(argc, argv, ARGF.current_file);
10506 rb_ary_concat(ary, lines);
10508 ARGF.last_lineno = ARGF.lineno;
10543 rb_last_status_clear();
10544 port = pipe_open_s(str,
"r",
FMODE_READABLE|DEFAULT_TEXTMODE, NULL);
10548 result = read_all(fptr, remain_size(fptr),
Qnil);
10550 rb_io_fptr_cleanup_all(fptr);
10556#ifdef HAVE_SYS_SELECT_H
10557#include <sys/select.h>
10571 if (!
NIL_P(read)) {
10576 if (READ_DATA_PENDING(fptr) || READ_CHAR_PENDING(fptr)) {
10580 if (max < fptr->fd) max = fptr->
fd;
10583 timerec.tv_sec = timerec.tv_usec = 0;
10591 if (!
NIL_P(write)) {
10597 if (max < fptr->fd) max = fptr->
fd;
10604 if (!
NIL_P(except)) {
10608 VALUE write_io = GetWriteIO(io);
10611 if (max < fptr->fd) max = fptr->
fd;
10612 if (io != write_io) {
10615 if (max < fptr->fd) max = fptr->
fd;
10630 if (!pending && n == 0)
return Qnil;
10633 rb_ary_push(res, rp?rb_ary_new():
rb_ary_new2(0));
10634 rb_ary_push(res, wp?rb_ary_new():
rb_ary_new2(0));
10635 rb_ary_push(res, ep?rb_ary_new():
rb_ary_new2(0));
10640 VALUE obj = rb_ary_entry(read, i);
10645 rb_ary_push(list, obj);
10653 VALUE obj = rb_ary_entry(write, i);
10655 VALUE write_io = GetWriteIO(io);
10658 rb_ary_push(list, obj);
10666 VALUE obj = rb_ary_entry(except, i);
10668 VALUE write_io = GetWriteIO(io);
10671 rb_ary_push(list, obj);
10673 else if (io != write_io) {
10676 rb_ary_push(list, obj);
10686 VALUE read, write, except;
10692select_call(
VALUE arg)
10696 return select_internal(p->read, p->write, p->except, p->timeout, p->fdsets);
10700select_end(
VALUE arg)
10705 for (i = 0; i < numberof(p->fdsets); ++i)
10710static VALUE sym_normal, sym_sequential, sym_random,
10711 sym_willneed, sym_dontneed, sym_noreuse;
10713#ifdef HAVE_POSIX_FADVISE
10714struct io_advise_struct {
10722io_advise_internal(
void *arg)
10724 struct io_advise_struct *ptr = arg;
10725 return posix_fadvise(ptr->fd, ptr->offset, ptr->len, ptr->advice);
10729io_advise_sym_to_const(
VALUE sym)
10731#ifdef POSIX_FADV_NORMAL
10732 if (sym == sym_normal)
10733 return INT2NUM(POSIX_FADV_NORMAL);
10736#ifdef POSIX_FADV_RANDOM
10737 if (sym == sym_random)
10738 return INT2NUM(POSIX_FADV_RANDOM);
10741#ifdef POSIX_FADV_SEQUENTIAL
10742 if (sym == sym_sequential)
10743 return INT2NUM(POSIX_FADV_SEQUENTIAL);
10746#ifdef POSIX_FADV_WILLNEED
10747 if (sym == sym_willneed)
10748 return INT2NUM(POSIX_FADV_WILLNEED);
10751#ifdef POSIX_FADV_DONTNEED
10752 if (sym == sym_dontneed)
10753 return INT2NUM(POSIX_FADV_DONTNEED);
10756#ifdef POSIX_FADV_NOREUSE
10757 if (sym == sym_noreuse)
10758 return INT2NUM(POSIX_FADV_NOREUSE);
10765do_io_advise(
rb_io_t *fptr,
VALUE advice, rb_off_t offset, rb_off_t
len)
10768 struct io_advise_struct ias;
10771 num_adv = io_advise_sym_to_const(advice);
10777 if (
NIL_P(num_adv))
10781 ias.advice =
NUM2INT(num_adv);
10782 ias.offset = offset;
10785 rv = (int)rb_thread_io_blocking_region(io_advise_internal, &ias, fptr->
fd);
10786 if (rv && rv != ENOSYS) {
10789 VALUE message = rb_sprintf(
"%"PRIsVALUE
" "
10793 fptr->
pathv, offset,
len, advice);
10803advice_arg_check(
VALUE advice)
10808 if (advice != sym_normal &&
10809 advice != sym_sequential &&
10810 advice != sym_random &&
10811 advice != sym_willneed &&
10812 advice != sym_dontneed &&
10813 advice != sym_noreuse) {
10814 rb_raise(
rb_eNotImpError,
"Unsupported advice: %+"PRIsVALUE, advice);
10852rb_io_advise(
int argc,
VALUE *argv,
VALUE io)
10859 advice_arg_check(advice);
10861 io = GetWriteIO(io);
10867#ifdef HAVE_POSIX_FADVISE
10868 return do_io_advise(fptr, advice,
off, l);
10870 ((void)
off, (void)l);
11025rb_f_select(
int argc,
VALUE *argv,
VALUE obj)
11028 if (scheduler !=
Qnil) {
11031 if (!UNDEF_P(result))
return result;
11039 rb_scan_args(argc, argv,
"13", &args.read, &args.write, &args.except, &timeout);
11040 if (
NIL_P(timeout)) {
11045 args.timeout = &timerec;
11048 for (i = 0; i < numberof(args.fdsets); ++i)
11054#ifdef IOCTL_REQ_TYPE
11055 typedef IOCTL_REQ_TYPE ioctl_req_t;
11057 typedef int ioctl_req_t;
11058# define NUM2IOCTLREQ(num) ((int)NUM2LONG(num))
11069nogvl_ioctl(
void *ptr)
11071 struct ioctl_arg *arg = ptr;
11073 return (
VALUE)ioctl(arg->fd, arg->cmd, arg->narg);
11077do_ioctl(
int fd, ioctl_req_t cmd,
long narg)
11080 struct ioctl_arg arg;
11086 retval = (int)rb_thread_io_blocking_region(nogvl_ioctl, &arg, fd);
11092#define DEFAULT_IOCTL_NARG_LEN (256)
11094#if defined(__linux__) && defined(_IOC_SIZE)
11096linux_iocparm_len(ioctl_req_t cmd)
11100 if ((cmd & 0xFFFF0000) == 0) {
11102 return DEFAULT_IOCTL_NARG_LEN;
11105 len = _IOC_SIZE(cmd);
11108 if (
len < DEFAULT_IOCTL_NARG_LEN)
11109 len = DEFAULT_IOCTL_NARG_LEN;
11117ioctl_narg_len(ioctl_req_t cmd)
11123#define IOCPARM_LEN(x) (((x) >> 16) & IOCPARM_MASK)
11127 len = IOCPARM_LEN(cmd);
11128#elif defined(__linux__) && defined(_IOC_SIZE)
11129 len = linux_iocparm_len(cmd);
11132 len = DEFAULT_IOCTL_NARG_LEN;
11141typedef long fcntl_arg_t;
11144typedef int fcntl_arg_t;
11148fcntl_narg_len(ioctl_req_t cmd)
11155 len =
sizeof(fcntl_arg_t);
11163#ifdef F_DUPFD_CLOEXEC
11164 case F_DUPFD_CLOEXEC:
11165 len =
sizeof(fcntl_arg_t);
11175 len =
sizeof(fcntl_arg_t);
11185 len =
sizeof(fcntl_arg_t);
11195 len =
sizeof(fcntl_arg_t);
11200 len =
sizeof(
struct f_owner_ex);
11205 len =
sizeof(
struct f_owner_ex);
11210 len =
sizeof(
struct flock);
11215 len =
sizeof(
struct flock);
11220 len =
sizeof(
struct flock);
11240 len =
sizeof(fcntl_arg_t);
11250 len =
sizeof(fcntl_arg_t);
11255 len =
sizeof(fcntl_arg_t);
11268fcntl_narg_len(ioctl_req_t cmd)
11274#define NARG_SENTINEL 17
11277setup_narg(ioctl_req_t cmd,
VALUE *argp,
long (*narg_len)(ioctl_req_t))
11288 else if (arg ==
Qtrue) {
11302 len = narg_len(cmd);
11303 rb_str_modify(arg);
11305 slen = RSTRING_LEN(arg);
11307 if (slen <
len+1) {
11308 rb_str_resize(arg,
len+1);
11309 MEMZERO(RSTRING_PTR(arg)+slen,
char,
len-slen);
11313 ptr = RSTRING_PTR(arg);
11314 ptr[slen - 1] = NARG_SENTINEL;
11323finish_narg(
int retval,
VALUE arg,
const rb_io_t *fptr)
11325 if (retval < 0) rb_sys_fail_path(fptr->
pathv);
11330 if (ptr[slen-1] != NARG_SENTINEL)
11331 rb_raise(rb_eArgError,
"return value overflowed string");
11332 ptr[slen-1] =
'\0';
11342 ioctl_req_t cmd = NUM2IOCTLREQ(req);
11347 narg = setup_narg(cmd, &arg, ioctl_narg_len);
11349 retval = do_ioctl(fptr->
fd, cmd, narg);
11350 return finish_narg(retval, arg, fptr);
11377 return rb_ioctl(io, req, arg);
11380#define rb_io_ioctl rb_f_notimplement
11391nogvl_fcntl(
void *ptr)
11393 struct fcntl_arg *arg = ptr;
11395#if defined(F_DUPFD)
11396 if (arg->cmd == F_DUPFD)
11399 return (
VALUE)fcntl(arg->fd, arg->cmd, arg->narg);
11403do_fcntl(
int fd,
int cmd,
long narg)
11406 struct fcntl_arg arg;
11412 retval = (int)rb_thread_io_blocking_region(nogvl_fcntl, &arg, fd);
11413 if (retval != -1) {
11415#if defined(F_DUPFD)
11418#if defined(F_DUPFD_CLOEXEC)
11419 case F_DUPFD_CLOEXEC:
11436 narg = setup_narg(cmd, &arg, fcntl_narg_len);
11438 retval = do_fcntl(fptr->
fd, cmd, narg);
11439 return finish_narg(retval, arg, fptr);
11465 return rb_fcntl(io, req, arg);
11468#define rb_io_fcntl rb_f_notimplement
11471#if defined(HAVE_SYSCALL) || defined(HAVE___SYSCALL)
11503#if SIZEOF_VOIDP == 8 && defined(HAVE___SYSCALL) && SIZEOF_INT != 8
11504# define SYSCALL __syscall
11505# define NUM2SYSCALLID(x) NUM2LONG(x)
11506# define RETVAL2NUM(x) LONG2NUM(x)
11507# if SIZEOF_LONG == 8
11508 long num, retval = -1;
11509# elif SIZEOF_LONG_LONG == 8
11510 long long num, retval = -1;
11512# error ---->> it is asserted that __syscall takes the first argument and returns retval in 64bit signed integer. <<----
11514#elif defined(__linux__)
11515# define SYSCALL syscall
11516# define NUM2SYSCALLID(x) NUM2LONG(x)
11517# define RETVAL2NUM(x) LONG2NUM(x)
11525 long num, retval = -1;
11527# define SYSCALL syscall
11528# define NUM2SYSCALLID(x) NUM2INT(x)
11529# define RETVAL2NUM(x) INT2NUM(x)
11530 int num, retval = -1;
11536 "We plan to remove a syscall function at future release. DL(Fiddle) provides safer alternative.");
11540 rb_raise(rb_eArgError,
"too few arguments for syscall");
11541 if (argc > numberof(arg))
11542 rb_raise(rb_eArgError,
"too many arguments for syscall");
11543 num = NUM2SYSCALLID(argv[0]); ++argv;
11544 for (i = argc - 1; i--; ) {
11559 retval = SYSCALL(num);
11562 retval = SYSCALL(num, arg[0]);
11565 retval = SYSCALL(num, arg[0],arg[1]);
11568 retval = SYSCALL(num, arg[0],arg[1],arg[2]);
11571 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3]);
11574 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4]);
11577 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5]);
11580 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6]);
11586 return RETVAL2NUM(retval);
11588#undef NUM2SYSCALLID
11592#define rb_f_syscall rb_f_notimplement
11596io_new_instance(
VALUE args)
11602find_encoding(
VALUE v)
11605 if (!enc)
rb_warn(
"Unsupported encoding %"PRIsVALUE
" ignored", v);
11617 enc2 = find_encoding(v1);
11620 if (RSTRING_LEN(tmp) == 1 && RSTRING_PTR(tmp)[0] ==
'-') {
11626 enc = find_encoding(v2);
11633 enc = find_encoding(v2);
11639 if (enc2 == rb_ascii8bit_encoding()) {
11644 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11650 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
11651 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11656 if (!
NIL_P(tmp) && rb_enc_asciicompat(enc = rb_enc_get(tmp))) {
11657 parse_mode_enc(RSTRING_PTR(tmp), enc, &enc, &enc2, NULL);
11658 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11662 rb_io_ext_int_to_encs(find_encoding(v1), NULL, &enc, &enc2, 0);
11663 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11668 validate_enc_binmode(&fptr->
mode, ecflags, enc, enc2);
11673 clear_codeconv(fptr);
11685io_encoding_set_v(
VALUE v)
11688 io_encoding_set(arg->fptr, arg->v1, arg->v2, arg->opt);
11693pipe_pair_close(
VALUE rw)
11696 return rb_ensure(io_close, rwp[0], io_close, rwp[1]);
11779rb_io_s_pipe(
int argc,
VALUE *argv,
VALUE klass)
11781 int pipes[2], state;
11782 VALUE r, w, args[3], v1, v2;
11789 argc =
rb_scan_args(argc, argv,
"02:", &v1, &v2, &opt);
11796 r = rb_protect(io_new_instance, (
VALUE)args, &state);
11800 rb_jump_tag(state);
11804 ies_args.fptr = fptr;
11807 ies_args.opt = opt;
11808 rb_protect(io_encoding_set_v, (
VALUE)&ies_args, &state);
11812 rb_jump_tag(state);
11817 w = rb_protect(io_new_instance, (
VALUE)args, &state);
11821 rb_jump_tag(state);
11826 extract_binmode(opt, &fmode);
11833#if DEFAULT_TEXTMODE
11835 fptr->
mode &= ~FMODE_TEXTMODE;
11836 setmode(fptr->
fd, O_BINARY);
11838#if RUBY_CRLF_ENVIRONMENT
11844 fptr->
mode |= fmode;
11845#if DEFAULT_TEXTMODE
11847 fptr2->
mode &= ~FMODE_TEXTMODE;
11848 setmode(fptr2->
fd, O_BINARY);
11851 fptr2->
mode |= fmode;
11853 ret = rb_assoc_new(r, w);
11885 else if (!
NIL_P(v = rb_hash_aref(opt, sym_open_args))) {
11888 v = rb_to_array_type(v);
11893 arg->io = rb_io_open(klass, path, vmode, vperm, opt);
11897io_s_foreach(
VALUE v)
11902 if (arg->limit == 0)
11903 rb_raise(rb_eArgError,
"invalid limit: 0 for foreach");
11904 while (!
NIL_P(str = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, arg->io))) {
11993rb_io_s_foreach(
int argc,
VALUE *argv,
VALUE self)
11996 int orig_argc = argc;
12000 argc =
rb_scan_args(argc, argv,
"12:", NULL, NULL, NULL, &opt);
12002 extract_getline_args(argc-1, argv+1, &garg);
12003 open_key_args(self, argc, argv, opt, &arg);
12005 extract_getline_opts(opt, &garg);
12006 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12007 return rb_ensure(io_s_foreach, (
VALUE)&garg, rb_io_close, arg.io);
12011io_s_readlines(
VALUE v)
12014 return io_readlines(arg, arg->io);
12072rb_io_s_readlines(
int argc,
VALUE *argv,
VALUE io)
12078 argc =
rb_scan_args(argc, argv,
"12:", NULL, NULL, NULL, &opt);
12079 extract_getline_args(argc-1, argv+1, &garg);
12080 open_key_args(io, argc, argv, opt, &arg);
12082 extract_getline_opts(opt, &garg);
12083 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12084 return rb_ensure(io_s_readlines, (
VALUE)&garg, rb_io_close, arg.io);
12091 return io_read(arg->argc, arg->argv, arg->io);
12101seek_before_access(
VALUE argp)
12105 return rb_io_seek(arg->io, arg->offset, arg->mode);
12151rb_io_s_read(
int argc,
VALUE *argv,
VALUE io)
12157 argc =
rb_scan_args(argc, argv,
"13:", NULL, NULL, &offset, NULL, &opt);
12159 rb_raise(rb_eArgError,
"negative offset %ld given",
off);
12161 open_key_args(io, argc, argv, opt, &arg);
12163 if (!
NIL_P(offset)) {
12167 sarg.offset = offset;
12168 sarg.mode = SEEK_SET;
12169 rb_protect(seek_before_access, (
VALUE)&sarg, &state);
12172 rb_jump_tag(state);
12174 if (arg.argc == 2) arg.argc = 1;
12193rb_io_s_binread(
int argc,
VALUE *argv,
VALUE io)
12208 convconfig.
enc = rb_ascii8bit_encoding();
12209 arg.io = rb_io_open_generic(io, argv[0], oflags, fmode, &convconfig, 0);
12212 arg.argc = (argc > 1) ? 1 : 0;
12213 if (!
NIL_P(offset)) {
12217 sarg.offset = offset;
12218 sarg.mode = SEEK_SET;
12219 rb_protect(seek_before_access, (
VALUE)&sarg, &state);
12222 rb_jump_tag(state);
12229io_s_write0(
VALUE v)
12232 return io_write(arg->io,arg->str,arg->nosync);
12236io_s_write(
int argc,
VALUE *argv,
VALUE klass,
int binary)
12238 VALUE string, offset, opt;
12242 rb_scan_args(argc, argv,
"21:", NULL, &
string, &offset, &opt);
12244 if (
NIL_P(opt)) opt = rb_hash_new();
12245 else opt = rb_hash_dup(opt);
12248 if (
NIL_P(rb_hash_aref(opt,sym_mode))) {
12249 int mode = O_WRONLY|O_CREAT;
12251 if (binary) mode |= O_BINARY;
12253 if (
NIL_P(offset)) mode |= O_TRUNC;
12254 rb_hash_aset(opt,sym_mode,
INT2NUM(mode));
12256 open_key_args(klass, argc, argv, opt, &arg);
12259 if (binary) rb_io_binmode_m(arg.io);
12263 if (!
NIL_P(offset)) {
12267 sarg.offset = offset;
12268 sarg.mode = SEEK_SET;
12269 rb_protect(seek_before_access, (
VALUE)&sarg, &state);
12272 rb_jump_tag(state);
12280 return rb_ensure(io_s_write0, (
VALUE)&warg, rb_io_close, arg.io);
12328rb_io_s_write(
int argc,
VALUE *argv,
VALUE io)
12330 return io_s_write(argc, argv, io, 0);
12347rb_io_s_binwrite(
int argc,
VALUE *argv,
VALUE io)
12349 return io_s_write(argc, argv, io, 1);
12355 rb_off_t copy_length;
12356 rb_off_t src_offset;
12360 unsigned close_src : 1;
12361 unsigned close_dst : 1;
12364 const char *syserr;
12365 const char *notimp;
12367 struct stat src_stat;
12368 struct stat dst_stat;
12369#ifdef HAVE_FCOPYFILE
12370 copyfile_state_t copyfile_state;
12375exec_interrupts(
void *arg)
12378 rb_thread_execute_interrupts(th);
12392#if defined(ERESTART)
12397 rb_thread_execute_interrupts(stp->th);
12416fiber_scheduler_wait_for(
void * _arguments)
12426# define IOWAIT_SYSCALL "poll"
12427STATIC_ASSERT(pollin_expected, POLLIN == RB_WAITFD_IN);
12428STATIC_ASSERT(pollout_expected, POLLOUT == RB_WAITFD_OUT);
12433 if (scheduler !=
Qnil) {
12436 return RTEST(args.result);
12440 if (fd == -1)
return 0;
12445 fds.events = events;
12447 int timeout_milliseconds = -1;
12450 timeout_milliseconds = (int)(timeout->tv_sec * 1000) + (int)(timeout->tv_usec / 1000);
12453 return poll(&fds, 1, timeout_milliseconds);
12456# define IOWAIT_SYSCALL "select"
12461 if (scheduler !=
Qnil) {
12464 return RTEST(args.result);
12484 case RB_WAITFD_OUT:
12488 VM_UNREACHABLE(nogvl_wait_for);
12508 ret = nogvl_wait_for(stp->th, stp->src_fptr, RB_WAITFD_IN, NULL);
12510 }
while (ret < 0 && maygvl_copy_stream_continue_p(has_gvl, stp));
12513 stp->syserr = IOWAIT_SYSCALL;
12514 stp->error_no =
errno;
12526 ret = nogvl_wait_for(stp->th, stp->dst_fptr, RB_WAITFD_OUT, NULL);
12527 }
while (ret < 0 && maygvl_copy_stream_continue_p(0, stp));
12530 stp->syserr = IOWAIT_SYSCALL;
12531 stp->error_no =
errno;
12537#ifdef USE_COPY_FILE_RANGE
12540simple_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)
12542#ifdef HAVE_COPY_FILE_RANGE
12543 return copy_file_range(in_fd, in_offset, out_fd, out_offset, count, flags);
12545 return syscall(__NR_copy_file_range, in_fd, in_offset, out_fd, out_offset, count, flags);
12554 rb_off_t copy_length, src_offset, *src_offset_ptr;
12556 if (!S_ISREG(stp->src_stat.st_mode))
12559 src_size = stp->src_stat.st_size;
12560 src_offset = stp->src_offset;
12561 if (src_offset >= (rb_off_t)0) {
12562 src_offset_ptr = &src_offset;
12565 src_offset_ptr = NULL;
12568 copy_length = stp->copy_length;
12569 if (copy_length < (rb_off_t)0) {
12570 if (src_offset < (rb_off_t)0) {
12571 rb_off_t current_offset;
12573 current_offset = lseek(stp->src_fptr->
fd, 0, SEEK_CUR);
12574 if (current_offset < (rb_off_t)0 &&
errno) {
12575 stp->syserr =
"lseek";
12576 stp->error_no =
errno;
12577 return (
int)current_offset;
12579 copy_length = src_size - current_offset;
12582 copy_length = src_size - src_offset;
12586 retry_copy_file_range:
12587# if SIZEOF_OFF_T > SIZEOF_SIZE_T
12589 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
12591 ss = (ssize_t)copy_length;
12593 ss = simple_copy_file_range(stp->src_fptr->
fd, src_offset_ptr, stp->dst_fptr->
fd, NULL, ss, 0);
12597 if (0 < copy_length) {
12598 goto retry_copy_file_range;
12602 if (maygvl_copy_stream_continue_p(0, stp)) {
12603 goto retry_copy_file_range;
12617#if EWOULDBLOCK != EAGAIN
12621 int ret = nogvl_copy_stream_wait_write(stp);
12622 if (ret < 0)
return ret;
12624 goto retry_copy_file_range;
12628 int flags = fcntl(stp->dst_fptr->
fd, F_GETFL);
12630 if (flags != -1 && flags & O_APPEND) {
12636 stp->syserr =
"copy_file_range";
12637 stp->error_no =
errno;
12644#ifdef HAVE_FCOPYFILE
12648 rb_off_t cur, ss = 0;
12649 const rb_off_t src_offset = stp->src_offset;
12652 if (stp->copy_length >= (rb_off_t)0) {
12657 if (!S_ISREG(stp->src_stat.st_mode))
12660 if (!S_ISREG(stp->dst_stat.st_mode))
12662 if (lseek(stp->dst_fptr->
fd, 0, SEEK_CUR) > (rb_off_t)0)
12664 if (fcntl(stp->dst_fptr->
fd, F_GETFL) & O_APPEND) {
12667 rb_off_t end = lseek(stp->dst_fptr->
fd, 0, SEEK_END);
12668 lseek(stp->dst_fptr->
fd, 0, SEEK_SET);
12669 if (end > (rb_off_t)0)
return 0;
12672 if (src_offset > (rb_off_t)0) {
12677 cur = lseek(stp->src_fptr->
fd, 0, SEEK_CUR);
12678 if (cur < (rb_off_t)0 &&
errno) {
12679 stp->error_no =
errno;
12684 r = lseek(stp->src_fptr->
fd, src_offset, SEEK_SET);
12685 if (r < (rb_off_t)0 &&
errno) {
12686 stp->error_no =
errno;
12691 stp->copyfile_state = copyfile_state_alloc();
12692 ret = fcopyfile(stp->src_fptr->
fd, stp->dst_fptr->
fd, stp->copyfile_state, COPYFILE_DATA);
12693 copyfile_state_get(stp->copyfile_state, COPYFILE_STATE_COPIED, &ss);
12697 if (src_offset > (rb_off_t)0) {
12701 r = lseek(stp->src_fptr->
fd, cur, SEEK_SET);
12702 if (r < (rb_off_t)0 &&
errno) {
12703 stp->error_no =
errno;
12715 stp->syserr =
"fcopyfile";
12716 stp->error_no =
errno;
12723#ifdef HAVE_SENDFILE
12726# define USE_SENDFILE
12728# ifdef HAVE_SYS_SENDFILE_H
12729# include <sys/sendfile.h>
12733simple_sendfile(
int out_fd,
int in_fd, rb_off_t *offset, rb_off_t count)
12735 return sendfile(out_fd, in_fd, offset, (
size_t)count);
12738# elif 0 || defined(__APPLE__)
12742# define USE_SENDFILE
12745simple_sendfile(
int out_fd,
int in_fd, rb_off_t *offset, rb_off_t count)
12748 rb_off_t pos = offset ? *offset : lseek(in_fd, 0, SEEK_CUR);
12751 r = sendfile(in_fd, out_fd, pos, &count, NULL, 0);
12754 r = sendfile(in_fd, out_fd, pos, (
size_t)count, NULL, &sbytes, 0);
12756 if (r != 0 && sbytes == 0)
return r;
12761 lseek(in_fd, sbytes, SEEK_CUR);
12763 return (ssize_t)sbytes;
12776 rb_off_t copy_length;
12777 rb_off_t src_offset;
12780 if (!S_ISREG(stp->src_stat.st_mode))
12783 src_size = stp->src_stat.st_size;
12785 if ((stp->dst_stat.st_mode & S_IFMT) != S_IFSOCK)
12789 src_offset = stp->src_offset;
12790 use_pread = src_offset >= (rb_off_t)0;
12792 copy_length = stp->copy_length;
12793 if (copy_length < (rb_off_t)0) {
12795 copy_length = src_size - src_offset;
12799 cur = lseek(stp->src_fptr->
fd, 0, SEEK_CUR);
12800 if (cur < (rb_off_t)0 &&
errno) {
12801 stp->syserr =
"lseek";
12802 stp->error_no =
errno;
12805 copy_length = src_size - cur;
12810# if SIZEOF_OFF_T > SIZEOF_SIZE_T
12812 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
12814 ss = (ssize_t)copy_length;
12817 ss = simple_sendfile(stp->dst_fptr->
fd, stp->src_fptr->
fd, &src_offset, ss);
12820 ss = simple_sendfile(stp->dst_fptr->
fd, stp->src_fptr->
fd, NULL, ss);
12825 if (0 < copy_length) {
12826 goto retry_sendfile;
12830 if (maygvl_copy_stream_continue_p(0, stp))
12831 goto retry_sendfile;
12844#if EWOULDBLOCK != EAGAIN
12857 ret = maygvl_copy_stream_wait_read(0, stp);
12858 if (ret < 0)
return ret;
12860 ret = nogvl_copy_stream_wait_write(stp);
12861 if (ret < 0)
return ret;
12863 goto retry_sendfile;
12865 stp->syserr =
"sendfile";
12866 stp->error_no =
errno;
12874maygvl_read(
int has_gvl,
rb_io_t *fptr,
void *buf,
size_t count)
12877 return rb_io_read_memory(fptr, buf, count);
12879 return read(fptr->
fd, buf, count);
12883maygvl_copy_stream_read(
int has_gvl,
struct copy_stream_struct *stp,
char *buf,
size_t len, rb_off_t offset)
12887 if (offset < (rb_off_t)0) {
12888 ss = maygvl_read(has_gvl, stp->src_fptr, buf,
len);
12891 ss = pread(stp->src_fptr->
fd, buf,
len, offset);
12897 if (maygvl_copy_stream_continue_p(has_gvl, stp))
12901#if EWOULDBLOCK != EAGAIN
12905 int ret = maygvl_copy_stream_wait_read(has_gvl, stp);
12906 if (ret < 0)
return ret;
12911 stp->notimp =
"pread";
12915 stp->syserr = offset < (rb_off_t)0 ?
"read" :
"pread";
12916 stp->error_no =
errno;
12927 ss = write(stp->dst_fptr->
fd, buf+
off,
len);
12929 if (maygvl_copy_stream_continue_p(0, stp))
12931 if (io_again_p(
errno)) {
12932 int ret = nogvl_copy_stream_wait_write(stp);
12933 if (ret < 0)
return ret;
12936 stp->syserr =
"write";
12937 stp->error_no =
errno;
12954 rb_off_t copy_length;
12955 rb_off_t src_offset;
12959 copy_length = stp->copy_length;
12960 use_eof = copy_length < (rb_off_t)0;
12961 src_offset = stp->src_offset;
12962 use_pread = src_offset >= (rb_off_t)0;
12964 if (use_pread && stp->close_src) {
12967 r = lseek(stp->src_fptr->
fd, src_offset, SEEK_SET);
12968 if (r < (rb_off_t)0 &&
errno) {
12969 stp->syserr =
"lseek";
12970 stp->error_no =
errno;
12973 src_offset = (rb_off_t)-1;
12977 while (use_eof || 0 < copy_length) {
12978 if (!use_eof && copy_length < (rb_off_t)
sizeof(buf)) {
12979 len = (size_t)copy_length;
12985 ss = maygvl_copy_stream_read(0, stp, buf,
len, src_offset);
12990 ss = maygvl_copy_stream_read(0, stp, buf,
len, (rb_off_t)-1);
12995 ret = nogvl_copy_stream_write(stp, buf, ss);
13005nogvl_copy_stream_func(
void *arg)
13008#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13012#ifdef USE_COPY_FILE_RANGE
13013 ret = nogvl_copy_file_range(stp);
13018#ifdef HAVE_FCOPYFILE
13019 ret = nogvl_fcopyfile(stp);
13025 ret = nogvl_copy_stream_sendfile(stp);
13030 nogvl_copy_stream_read_write(stp);
13032#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13039copy_stream_fallback_body(
VALUE arg)
13042 const int buflen = 16*1024;
13044 VALUE buf = rb_str_buf_new(buflen);
13045 rb_off_t rest = stp->copy_length;
13046 rb_off_t
off = stp->src_offset;
13047 ID read_method = id_readpartial;
13049 if (!stp->src_fptr) {
13051 read_method = id_read;
13058 if (stp->copy_length < (rb_off_t)0) {
13063 rb_str_resize(buf, 0);
13066 l = buflen < rest ? buflen : (long)rest;
13068 if (!stp->src_fptr) {
13071 if (read_method == id_read &&
NIL_P(rc))
13076 rb_str_resize(buf, buflen);
13077 ss = maygvl_copy_stream_read(1, stp, RSTRING_PTR(buf), l,
off);
13078 rb_str_resize(buf, ss > 0 ? ss : 0);
13083 if (
off >= (rb_off_t)0)
13086 n = rb_io_write(stp->dst, buf);
13088 stp->total += numwrote;
13090 if (read_method == id_read && RSTRING_LEN(buf) == 0) {
13101 if (!stp->src_fptr && stp->src_offset >= (rb_off_t)0) {
13102 rb_raise(rb_eArgError,
"cannot specify src_offset for non-IO");
13111copy_stream_body(
VALUE arg)
13114 VALUE src_io = stp->src, dst_io = stp->dst;
13115 const int common_oflags = 0
13125 if (src_io ==
argf ||
13126 !(RB_TYPE_P(src_io,
T_FILE) ||
13129 stp->src_fptr = NULL;
13134 if (!
NIL_P(tmp_io)) {
13137 else if (!RB_TYPE_P(src_io,
T_FILE)) {
13141 args[1] =
INT2NUM(O_RDONLY|common_oflags);
13144 stp->close_src = 1;
13149 stat_ret = fstat(stp->src_fptr->
fd, &stp->src_stat);
13150 if (stat_ret < 0) {
13151 stp->syserr =
"fstat";
13152 stp->error_no =
errno;
13157 if (dst_io ==
argf ||
13158 !(RB_TYPE_P(dst_io,
T_FILE) ||
13161 stp->dst_fptr = NULL;
13166 if (!
NIL_P(tmp_io)) {
13167 dst_io = GetWriteIO(tmp_io);
13169 else if (!RB_TYPE_P(dst_io,
T_FILE)) {
13173 args[1] =
INT2NUM(O_WRONLY|O_CREAT|O_TRUNC|common_oflags);
13177 stp->close_dst = 1;
13180 dst_io = GetWriteIO(dst_io);
13186 stat_ret = fstat(stp->dst_fptr->
fd, &stp->dst_stat);
13187 if (stat_ret < 0) {
13188 stp->syserr =
"fstat";
13189 stp->error_no =
errno;
13196 SET_BINARY_MODE_WITH_SEEK_CUR(stp->src_fptr);
13199 io_ascii8bit_binmode(stp->dst_fptr);
13201 if (stp->src_offset < (rb_off_t)0 && stp->src_fptr && stp->src_fptr->
rbuf.
len) {
13204 if (stp->copy_length >= (rb_off_t)0 && stp->copy_length < (rb_off_t)
len) {
13205 len = (size_t)stp->copy_length;
13207 str = rb_str_buf_new(
len);
13208 rb_str_resize(str,
len);
13209 read_buffered_data(RSTRING_PTR(str),
len, stp->src_fptr);
13210 if (stp->dst_fptr) {
13211 if (io_binwrite(str, RSTRING_PTR(str), RSTRING_LEN(str), stp->dst_fptr, 0) < 0)
13212 rb_sys_fail_on_write(stp->dst_fptr);
13215 rb_io_write(dst_io, str);
13216 rb_str_resize(str, 0);
13218 if (stp->copy_length >= (rb_off_t)0)
13219 stp->copy_length -=
len;
13222 if (stp->dst_fptr && io_fflush(stp->dst_fptr) < 0) {
13226 if (stp->copy_length == 0)
13229 if (stp->src_fptr == NULL || stp->dst_fptr == NULL) {
13230 return copy_stream_fallback(stp);
13238copy_stream_finalize(
VALUE arg)
13242#ifdef HAVE_FCOPYFILE
13243 if (stp->copyfile_state) {
13244 copyfile_state_free(stp->copyfile_state);
13248 if (stp->close_src) {
13249 rb_io_close_m(stp->src);
13251 if (stp->close_dst) {
13252 rb_io_close_m(stp->dst);
13315rb_io_s_copy_stream(
int argc,
VALUE *argv,
VALUE io)
13317 VALUE src, dst, length, src_offset;
13322 rb_scan_args(argc, argv,
"22", &src, &dst, &length, &src_offset);
13327 st.src_fptr = NULL;
13328 st.dst_fptr = NULL;
13331 st.copy_length = (rb_off_t)-1;
13333 st.copy_length =
NUM2OFFT(length);
13335 if (
NIL_P(src_offset))
13336 st.src_offset = (rb_off_t)-1;
13338 st.src_offset =
NUM2OFFT(src_offset);
13357rb_io_external_encoding(
VALUE io)
13362 return rb_enc_from_encoding(fptr->
encs.
enc2);
13366 return rb_enc_from_encoding(fptr->
encs.
enc);
13369 return rb_enc_from_encoding(io_read_encoding(fptr));
13385rb_io_internal_encoding(
VALUE io)
13390 return rb_enc_from_encoding(io_read_encoding(fptr));
13424rb_io_set_encoding(
int argc,
VALUE *argv,
VALUE io)
13429 if (!RB_TYPE_P(io,
T_FILE)) {
13430 return forward(io, id_set_encoding, argc, argv);
13433 argc =
rb_scan_args(argc, argv,
"11:", &v1, &v2, &opt);
13435 io_encoding_set(fptr, v1, v2, opt);
13440rb_stdio_set_default_encoding(
void)
13445 if (isatty(fileno(stdin))) {
13447 rb_encoding *internal = rb_default_internal_encoding();
13448 if (!internal) internal = rb_default_external_encoding();
13450 rb_enc_from_encoding(external),
13451 rb_enc_from_encoding(internal),
13456 rb_io_set_encoding(1, &val,
rb_stdin);
13457 rb_io_set_encoding(1, &val,
rb_stdout);
13458 rb_io_set_encoding(1, &val,
rb_stderr);
13462global_argf_p(
VALUE arg)
13464 return arg ==
argf;
13467typedef VALUE (*argf_encoding_func)(
VALUE io);
13470argf_encoding(
VALUE argf, argf_encoding_func func)
13472 if (!
RTEST(ARGF.current_file)) {
13473 return rb_enc_default_external();
13497 return argf_encoding(
argf, rb_io_external_encoding);
13516 return argf_encoding(
argf, rb_io_internal_encoding);
13555 if (!next_argv()) {
13556 rb_raise(rb_eArgError,
"no stream to set encoding");
13558 rb_io_set_encoding(argc, argv, ARGF.current_file);
13560 ARGF.encs = fptr->
encs;
13579 if (!next_argv()) {
13580 rb_raise(rb_eArgError,
"no stream to tell");
13582 ARGF_FORWARD(0, 0);
13583 return rb_io_tell(ARGF.current_file);
13596 if (!next_argv()) {
13597 rb_raise(rb_eArgError,
"no stream to seek");
13599 ARGF_FORWARD(argc, argv);
13600 return rb_io_seek_m(argc, argv, ARGF.current_file);
13617 if (!next_argv()) {
13618 rb_raise(rb_eArgError,
"no stream to set position");
13620 ARGF_FORWARD(1, &offset);
13621 return rb_io_set_pos(ARGF.current_file, offset);
13642 if (!next_argv()) {
13643 rb_raise(rb_eArgError,
"no stream to rewind");
13645 ARGF_FORWARD(0, 0);
13646 old_lineno =
RFILE(ARGF.current_file)->fptr->lineno;
13647 ret = rb_io_rewind(ARGF.current_file);
13648 if (!global_argf_p(
argf)) {
13649 ARGF.last_lineno = ARGF.lineno -= old_lineno;
13667 if (!next_argv()) {
13668 rb_raise(rb_eArgError,
"no stream");
13670 ARGF_FORWARD(0, 0);
13671 return rb_io_fileno(ARGF.current_file);
13690 ARGF_FORWARD(0, 0);
13691 return ARGF.current_file;
13716 if (
RTEST(ARGF.current_file)) {
13717 if (ARGF.init_p == 0)
return Qtrue;
13719 ARGF_FORWARD(0, 0);
13778 VALUE tmp, str, length;
13782 if (!
NIL_P(length)) {
13787 rb_str_resize(str,0);
13792 if (!next_argv()) {
13795 if (ARGF_GENERIC_INPUT_P()) {
13796 tmp = argf_forward(argc, argv,
argf);
13799 tmp = io_read(argc, argv, ARGF.current_file);
13801 if (
NIL_P(str)) str = tmp;
13804 if (ARGF.next_p != -1) {
13810 else if (argc >= 1) {
13811 long slen = RSTRING_LEN(str);
13827argf_forward_call(
VALUE arg)
13830 argf_forward(p->argc, p->argv, p->argf);
13860 return argf_getpartial(argc, argv,
argf,
Qnil, 0);
13881 return argf_getpartial(argc, argv,
argf, opts, 1);
13887 VALUE tmp, str, length;
13895 no_exception = no_exception_p(opts);
13897 if (!next_argv()) {
13899 rb_str_resize(str, 0);
13903 if (ARGF_GENERIC_INPUT_P()) {
13913 tmp = io_getpartial(argc, argv, ARGF.current_file, no_exception, nonblock);
13916 if (ARGF.next_p == -1) {
13917 return io_nonblock_eof(no_exception);
13922 return io_nonblock_eof(no_exception);
13960 if (!next_argv())
return Qnil;
13961 if (ARGF_GENERIC_INPUT_P()) {
13962 ch = forward_current(rb_intern(
"getc"), 0, 0);
13965 ch = rb_io_getc(ARGF.current_file);
13967 if (
NIL_P(ch) && ARGF.next_p != -1) {
14000 if (!next_argv())
return Qnil;
14001 if (!RB_TYPE_P(ARGF.current_file,
T_FILE)) {
14002 ch = forward_current(rb_intern(
"getbyte"), 0, 0);
14007 if (
NIL_P(ch) && ARGF.next_p != -1) {
14041 if (!RB_TYPE_P(ARGF.current_file,
T_FILE)) {
14042 ch = forward_current(rb_intern(
"getc"), 0, 0);
14045 ch = rb_io_getc(ARGF.current_file);
14047 if (
NIL_P(ch) && ARGF.next_p != -1) {
14079 NEXT_ARGF_FORWARD(0, 0);
14080 c = argf_getbyte(
argf);
14087#define FOREACH_ARGF() while (next_argv())
14092 const VALUE current = ARGF.current_file;
14094 if (ARGF.init_p == -1 || current != ARGF.current_file) {
14100#define ARGF_block_call(mid, argc, argv, func, argf) \
14101 rb_block_call_kw(ARGF.current_file, mid, argc, argv, \
14102 func, argf, rb_keyword_given_p())
14107 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_i,
argf);
14108 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14114 if (!global_argf_p(
argf)) {
14115 ARGF.last_lineno = ++ARGF.lineno;
14117 return argf_block_call_i(i,
argf, argc, argv, blockarg);
14123 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_line_i,
argf);
14124 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14172 argf_block_call_line(rb_intern(
"each_line"), argc, argv,
argf);
14203 argf_block_call(rb_intern(
"each_byte"), 0, 0,
argf);
14229 argf_block_call(rb_intern(
"each_char"), 0, 0,
argf);
14255 argf_block_call(rb_intern(
"each_codepoint"), 0, 0,
argf);
14286 return ARGF.filename;
14290argf_filename_getter(
ID id,
VALUE *var)
14292 return argf_filename(*var);
14317 return ARGF.current_file;
14336 ARGF_FORWARD(0, 0);
14357 return RBOOL(ARGF.binmode);
14377 if (ARGF.init_p && ARGF.next_p == 0) {
14406 if (ARGF.next_p != -1) {
14424 ARGF_FORWARD(0, 0);
14451 if (!ARGF.inplace)
return Qnil;
14453 return rb_str_dup(ARGF.inplace);
14459 return argf_inplace_mode_get(*var);
14490 ARGF.inplace =
Qnil;
14493 ARGF.inplace = rb_str_new_frozen(val);
14501 argf_inplace_mode_set(*var, val);
14505ruby_set_inplace_mode(
const char *suffix)
14531argf_argv_getter(
ID id,
VALUE *var)
14533 return argf_argv(*var);
14552 if (!
RTEST(ARGF.current_file)) {
14555 return GetWriteIO(ARGF.current_file);
14567 return rb_io_write(argf_write_io(
argf), str);
14582 case RB_IO_WAIT_WRITABLE:
14585 c = rb_eEAGAINWaitWritable;
14587#if EAGAIN != EWOULDBLOCK
14589 c = rb_eEWOULDBLOCKWaitWritable;
14593 c = rb_eEINPROGRESSWaitWritable;
14599 case RB_IO_WAIT_READABLE:
14602 c = rb_eEAGAINWaitReadable;
14604#if EAGAIN != EWOULDBLOCK
14606 c = rb_eEWOULDBLOCKWaitReadable;
14610 c = rb_eEINPROGRESSWaitReadable;
14617 rb_bug(
"invalid read/write type passed to rb_readwrite_sys_fail: %d", waiting);
14623get_LAST_READ_LINE(
ID _x,
VALUE *_y)
15280#include <sys/cygwin.h>
15281 static struct __cygwin_perfile pf[] =
15283 {
"", O_RDONLY | O_BINARY},
15284 {
"", O_WRONLY | O_BINARY},
15285 {
"", O_RDWR | O_BINARY},
15286 {
"", O_APPEND | O_BINARY},
15289 cygwin_internal(CW_PERFILE, pf);
15344#if EAGAIN == EWOULDBLOCK
15345 rb_eEWOULDBLOCKWaitReadable = rb_eEAGAINWaitReadable;
15348 rb_eEWOULDBLOCKWaitWritable = rb_eEAGAINWaitWritable;
15390 rb_output_fs =
Qnil;
15393 rb_default_rs = rb_fstring_lit(
"\n");
15394 rb_gc_register_mark_object(rb_default_rs);
15395 rb_rs = rb_default_rs;
15402 rb_gvar_ractor_local(
"$_");
15518 rb_gvar_ractor_local(
"$stdin");
15519 rb_gvar_ractor_local(
"$stdout");
15520 rb_gvar_ractor_local(
"$>");
15521 rb_gvar_ractor_local(
"$stderr");
15607 rb_define_method(rb_cARGF,
"external_encoding", argf_external_encoding, 0);
15608 rb_define_method(rb_cARGF,
"internal_encoding", argf_internal_encoding, 0);
15627 rb_gvar_ractor_local(
"$-i");
15631#if defined (_WIN32) || defined(__CYGWIN__)
15632 atexit(pipe_atexit);
15644 sym_encoding =
ID2SYM(rb_id_encoding());
std::atomic< unsigned > rb_atomic_t
Type that is eligible for atomic operations.
unsigned long ruby_strtoul(const char *str, char **endptr, int base)
Our own locale-insensitive version of strtoul(3).
#define rb_define_method(klass, mid, func, arity)
Defines klass#mid.
#define rb_define_singleton_method(klass, mid, func, arity)
Defines klass.mid.
#define rb_define_global_function(mid, func, arity)
Defines rb_mKernel #mid.
void rb_include_module(VALUE klass, VALUE module)
Includes a module to a class.
VALUE rb_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 NEWOBJ_OF
Old name of RB_NEWOBJ_OF.
#define FL_SINGLETON
Old name of RUBY_FL_SINGLETON.
#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 T_STRING
Old name of RUBY_T_STRING.
#define Qundef
Old name of RUBY_Qundef.
#define INT2FIX
Old name of RB_INT2FIX.
#define rb_str_cat2
Old name of rb_str_cat_cstr.
#define T_NIL
Old name of RUBY_T_NIL.
#define UNREACHABLE
Old name of RBIMPL_UNREACHABLE.
#define ID2SYM
Old name of RB_ID2SYM.
#define T_BIGNUM
Old name of RUBY_T_BIGNUM.
#define OBJ_FREEZE
Old name of RB_OBJ_FREEZE.
#define T_FIXNUM
Old name of RUBY_T_FIXNUM.
#define UNREACHABLE_RETURN
Old name of RBIMPL_UNREACHABLE_RETURN.
#define FIX2UINT
Old name of RB_FIX2UINT.
#define SSIZET2NUM
Old name of RB_SSIZE2NUM.
#define ZALLOC
Old name of RB_ZALLOC.
#define CLASS_OF
Old name of rb_class_of.
#define rb_ary_new4
Old name of rb_ary_new_from_values.
#define ENCODING_MAXNAMELEN
Old name of RUBY_ENCODING_MAXNAMELEN.
#define MBCLEN_NEEDMORE_LEN(ret)
Old name of ONIGENC_MBCLEN_NEEDMORE_LEN.
#define ENCODING_GET(obj)
Old name of RB_ENCODING_GET.
#define LONG2FIX
Old name of RB_INT2FIX.
#define NUM2UINT
Old name of RB_NUM2UINT.
#define ALLOC_N
Old name of RB_ALLOC_N.
#define MBCLEN_CHARFOUND_LEN(ret)
Old name of ONIGENC_MBCLEN_CHARFOUND_LEN.
#define LONG2NUM
Old name of RB_LONG2NUM.
#define rb_exc_new3
Old name of rb_exc_new_str.
#define STRNCASECMP
Old name of st_locale_insensitive_strncasecmp.
#define MBCLEN_INVALID_P(ret)
Old name of ONIGENC_MBCLEN_INVALID_P.
#define ISASCII
Old name of rb_isascii.
#define ECONV_STATEFUL_DECORATOR_MASK
Old name of RUBY_ECONV_STATEFUL_DECORATOR_MASK.
#define Qtrue
Old name of RUBY_Qtrue.
#define MBCLEN_NEEDMORE_P(ret)
Old name of ONIGENC_MBCLEN_NEEDMORE_P.
#define ECONV_PARTIAL_INPUT
Old name of RUBY_ECONV_PARTIAL_INPUT.
#define NUM2INT
Old name of RB_NUM2INT.
#define ECONV_ERROR_HANDLER_MASK
Old name of RUBY_ECONV_ERROR_HANDLER_MASK.
#define INT2NUM
Old name of RB_INT2NUM.
#define Qnil
Old name of RUBY_Qnil.
#define Qfalse
Old name of RUBY_Qfalse.
#define FIX2LONG
Old name of RB_FIX2LONG.
#define ENC_CODERANGE_BROKEN
Old name of RUBY_ENC_CODERANGE_BROKEN.
#define T_ARRAY
Old name of RUBY_T_ARRAY.
#define NIL_P
Old name of RB_NIL_P.
#define ALLOCV_N
Old name of RB_ALLOCV_N.
#define MBCLEN_CHARFOUND_P(ret)
Old name of ONIGENC_MBCLEN_CHARFOUND_P.
#define NUM2CHR
Old name of RB_NUM2CHR.
#define FL_TEST
Old name of RB_FL_TEST.
#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_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_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.
static char * rb_enc_left_char_head(const char *s, const char *p, const char *e, rb_encoding *enc)
Queries the left boundary of a character.
static unsigned int rb_enc_codepoint(const char *p, const char *e, rb_encoding *enc)
Queries the code point of character pointed by the passed pointer.
static int rb_enc_mbminlen(rb_encoding *enc)
Queries the minimum number of bytes that the passed encoding needs to represent a character.
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.
#define RETURN_ENUMERATOR(obj, argc, argv)
Identical to RETURN_SIZED_ENUMERATOR(), except its size is unknown.
#define rb_check_frozen
Just another name of rb_check_frozen.
static int rb_check_arity(int argc, int min, int max)
Ensures that the passed integer is in the passed range.
VALUE rb_io_printf(int argc, const VALUE *argv, VALUE io)
This is a rb_f_sprintf() + rb_io_write() combo.
VALUE rb_io_gets(VALUE io)
Reads a "line" from the given IO.
int rb_cloexec_pipe(int fildes[2])
Opens a pipe with closing on exec.
VALUE rb_io_print(int argc, const VALUE *argv, VALUE io)
Iterates over the passed array to apply rb_io_write() individually.
VALUE rb_io_addstr(VALUE io, VALUE str)
Identical to rb_io_write(), except it always returns the passed IO.
void rb_write_error(const char *str)
Writes the given error message to somewhere applicable.
VALUE rb_io_ungetbyte(VALUE io, VALUE b)
Identical to rb_io_ungetc(), except it doesn't take the encoding of the passed IO into account.
VALUE rb_io_getbyte(VALUE io)
Reads a byte from the given IO.
int rb_cloexec_dup2(int oldfd, int newfd)
Identical to rb_cloexec_dup(), except you can specify the destination file descriptor.
VALUE rb_io_fdopen(int fd, int flags, const char *path)
Creates an IO instance whose backend is the given file descriptor.
void rb_update_max_fd(int fd)
Informs the interpreter that the passed fd can be the max.
int rb_cloexec_open(const char *pathname, int flags, mode_t mode)
Opens a file that closes on exec.
VALUE rb_output_rs
The record separator character for outputs, or the $\.
VALUE rb_io_eof(VALUE io)
Queries if the passed IO is at the end of file.
void rb_write_error2(const char *str, long len)
Identical to rb_write_error(), except it additionally takes the message's length.
void rb_close_before_exec(int lowfd, int maxhint, VALUE noclose_fds)
Closes everything.
int rb_reserved_fd_p(int fd)
Queries if the given FD is reserved or not.
void rb_fd_fix_cloexec(int fd)
Sets or clears the close-on-exec flag of the passed file descriptor to the desired state.
VALUE rb_io_ascii8bit_binmode(VALUE io)
Forces no conversions be applied to the passed IO.
VALUE rb_io_binmode(VALUE io)
Sets the binmode.
VALUE rb_io_ungetc(VALUE io, VALUE c)
"Unget"s a string.
int rb_pipe(int *pipes)
This is an rb_cloexec_pipe() + rb_update_max_fd() combo.
VALUE rb_gets(void)
Much like rb_io_gets(), but it reads from the mysterious ARGF object.
int rb_cloexec_fcntl_dupfd(int fd, int minfd)
Duplicates a file descriptor with closing on exec.
VALUE rb_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.
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_locktmp(VALUE str)
Obtains a "temporary lock" of the string.
rb_gvar_setter_t rb_str_setter
This is a rb_gvar_setter_t that refutes non-string assignments.
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.
#define rb_str_new_cstr(str)
Identical to rb_str_new, except it assumes the passed pointer is a pointer to a C string.
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...
#define RUBY_UBF_IO
A special UBF for blocking IO operations.
VALUE rb_exec_recursive(VALUE(*f)(VALUE g, VALUE h, int r), VALUE g, VALUE h)
"Recursion" API entry point.
void rb_thread_fd_close(int fd)
Notifies a closing of a file descriptor to other threads.
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.
void rb_define_const(VALUE klass, const char *name, VALUE val)
Defines a Ruby level constant under a namespace.
#define FMODE_READABLE
The IO is opened for reading.
int 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.
int rb_io_mode(VALUE io)
Get the mode of the IO.
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_extract_encoding_option(VALUE opt, rb_encoding **enc_p, rb_encoding **enc2_p, int *fmode_p)
This function breaks down the option hash that IO#initialize takes into components.
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_descriptor(VALUE io)
Returns an integer representing the numeric file descriptor for io.
#define FMODE_WRITABLE
The IO is opened for writing.
FILE * rb_io_stdio_file(rb_io_t *fptr)
Finds or creates a stdio's file structure from a Ruby's one.
#define FMODE_APPEND
The IO is opened for appending.
#define MakeOpenFile
This is an old name of RB_IO_OPEN.
#define FMODE_DUPLEX
Ruby eventually detects that the IO is bidirectional.
#define FMODE_BINMODE
The IO is in "binary mode".
int rb_io_maybe_wait_readable(int error, VALUE io, VALUE timeout)
Blocks until the passed IO is ready for reading, if that makes sense for the passed errno.
int capa
Designed capacity of the buffer.
#define RB_IO_POINTER(obj, fp)
Queries the underlying IO pointer.
VALUE rb_io_maybe_wait(int error, VALUE io, VALUE events, VALUE timeout)
Identical to rb_io_wait() except it additionally takes previous errno.
VALUE rb_eIOTimeoutError
Indicates that a timeout has occurred while performing an IO operation.
char * ptr
Pointer to the underlying memory region, of at least capa bytes.
#define FMODE_SYNC
The IO is in "sync mode".
int off
Offset inside of ptr.
VALUE rb_io_path(VALUE io)
Returns the path for the given IO.
void rb_io_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".
VALUE rb_io_check_io(VALUE io)
Try converting an object to its IO representation using its to_io method, if any.
VALUE rb_io_closed_p(VALUE io)
Returns whether or not the underlying IO is closed.
VALUE rb_io_set_timeout(VALUE io, VALUE timeout)
Set the timeout associated with the specified io object.
ssize_t rb_io_bufwrite(VALUE io, const void *buf, size_t size)
Buffered write to the passed IO.
void rb_io_check_char_readable(rb_io_t *fptr)
Asserts that an IO is opened for character-based reading.
#define FMODE_TRUNC
This flag amends the effect of FMODE_CREATE, so that if there already is a file at the given path it ...
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".
void rb_io_extract_modeenc(VALUE *vmode_p, VALUE *vperm_p, VALUE opthash, int *oflags_p, int *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...
int rb_io_wait_writable(int fd)
Blocks until the passed file descriptor gets writable.
VALUE rb_io_open_descriptor(VALUE klass, int descriptor, int mode, VALUE path, VALUE timeout, struct rb_io_encoding *encoding)
Allocate a new IO object, with the given file descriptor.
VALUE rb_io_set_write_io(VALUE io, VALUE w)
Assigns the tied IO for writing.
void rb_io_check_writable(rb_io_t *fptr)
Asserts that an IO is opened for writing.
int rb_io_maybe_wait_writable(int error, VALUE io, VALUE timeout)
Blocks until the passed IO is ready for writing, if that makes sense for the passed errno.
void rb_io_check_closed(rb_io_t *fptr)
This badly named function asserts that the passed IO is open.
void rb_eof_error(void)
Utility function to raise rb_eEOFError.
int rb_io_wait_readable(int fd)
Blocks until the passed file descriptor gets readable.
void rb_io_synchronized(rb_io_t *fptr)
Sets FMODE_SYNC.
VALUE rb_io_wait(VALUE io, VALUE events, VALUE timeout)
Blocks until the passed IO is ready for the passed events.
int len
Length of the buffer.
VALUE rb_ractor_stdin(void)
Queries the standard input of the current Ractor that is calling this function.
void rb_ractor_stderr_set(VALUE io)
Assigns an IO to the standard error of the Ractor that is calling this function.
void rb_ractor_stdout_set(VALUE io)
Assigns an IO to the standard output of the Ractor that is calling this function.
void rb_ractor_stdin_set(VALUE io)
Assigns an IO to the standard input of the Ractor that is calling this function.
void * rb_thread_call_with_gvl(void *(*func)(void *), void *data1)
(Re-)acquires the GVL.
void * rb_thread_call_without_gvl(void *(*func)(void *), void *data1, rb_unblock_function_t *ubf, void *data2)
Allows the passed function to run in parallel with other Ruby threads.
#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 SafeStringValue(v)
#define StringValue(v)
Ensures that the parameter object is a String.
#define RSTRING_GETMEM(str, ptrvar, lenvar)
Convenient macro to obtain the contents and length at once.
#define StringValueCStr(v)
Identical to StringValuePtr, except it additionally checks for the contents for viability as a C stri...
#define RUBY_TYPED_DEFAULT_FREE
This is a value you can set to rb_data_type_struct::dfree.
#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 instead of...
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_io_wait_writable(VALUE scheduler, VALUE io)
Non-blocking wait until the passed IO is ready for writing.
int rb_thread_fd_select(int nfds, rb_fdset_t *rfds, rb_fdset_t *wfds, rb_fdset_t *efds, struct timeval *timeout)
Waits for multiple file descriptors at once.
static bool RB_TEST(VALUE obj)
Emulates Ruby's "if" statement.
#define RTEST
This is an old name of RB_TEST.
#define _(args)
This was a transition path from K&R to ANSI.
This is the struct that holds necessary info for a struct.
The data structure which wraps the fd_set bitmap used by select(2).
Decomposed encoding flags (e.g.
VALUE ecopts
Flags as Ruby hash.
rb_encoding * enc2
External encoding.
rb_encoding * enc
Internal encoding.
char * ptr
Pointer to the underlying memory region, of at least capa bytes.
int off
Offset inside of ptr.
int len
Length of the buffer.
int capa
Designed capacity of the buffer.
Ruby's IO, metadata and buffers.
int mode
mode flags: FMODE_XXXs
rb_io_buffer_t wbuf
Write buffer.
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
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_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.