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 *);
522static rb_io_t *flush_before_seek(rb_io_t *fptr);
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));
538raise_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;\
611io_unread(rb_io_t *fptr)
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)
786 rb_io_t *fptr =
RFILE(io)->fptr;
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);
807 write_io = rb_io_get_fptr(io)->tied_io_for_writing;
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
901io_unread(rb_io_t *fptr)
909 r = lseek(fptr->
fd, -fptr->
rbuf.
len, SEEK_CUR);
910 if (r < 0 &&
errno) {
921static rb_encoding *io_input_encoding(rb_io_t *fptr);
924io_ungetbyte(
VALUE str, rb_io_t *fptr)
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;
1139static int nogvl_wait_for(
VALUE th, rb_io_t *fptr,
short events,
struct timeval *timeout);
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)
1366 rb_io_t *fptr = arg;
1386io_flush_buffer_async(
VALUE arg)
1388 rb_io_t *fptr = (rb_io_t *)arg;
1389 return rb_thread_io_blocking_call(io_flush_buffer_sync, fptr, fptr->
fd, RB_WAITFD_OUT);
1393io_flush_buffer(rb_io_t *fptr)
1396 return (
int)io_flush_buffer_async((
VALUE)fptr);
1404io_fflush(rb_io_t *fptr)
1411 while (fptr->
wbuf.
len > 0 && io_flush_buffer(fptr) != 0) {
1426 if (scheduler !=
Qnil) {
1430 rb_io_t * fptr = NULL;
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)) {
1645make_writeconv(rb_io_t *fptr)
1648 const char *senc, *denc;
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))
1898do_writeconv(
VALUE str, rb_io_t *fptr,
int *converted)
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)));
1955io_fwrite(
VALUE str, rb_io_t *fptr,
int nosync)
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;
2035 rb_io_t *fptr = p->fptr;
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);
2143io_fwritev(
int argc,
const VALUE *argv, rb_io_t *fptr)
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)
2327 rb_io_t *fptr = 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)
2588io_fillbuf(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);
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)
2796 rb_io_t *fptr = 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)
2854 rb_io_t *fptr =
RFILE(io)->fptr;
2865 if (RB_TYPE_P(io,
T_FILE)) {
2866 rb_io_t *fptr =
RFILE(io)->fptr;
2872 if (!UNDEF_P(fileno)) {
2939 rb_io_t *fptr =
RFILE(io)->fptr;
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);
3088remain_size(rb_io_t *fptr)
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");
3117io_enc_str(
VALUE str, rb_io_t *fptr)
3119 rb_enc_associate(str, io_read_encoding(fptr));
3123static rb_encoding *io_read_encoding(rb_io_t *fptr);
3126make_readconv(rb_io_t *fptr,
int size)
3131 const char *sname, *dname;
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;
3229more_char(rb_io_t *fptr)
3233 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED)
3239io_shift_cbuf(rb_io_t *fptr,
int len,
VALUE *strp)
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);
3311read_all(rb_io_t *fptr,
long siz,
VALUE str)
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;
3660io_write_nonblock(rb_execution_context_t *ec,
VALUE io,
VALUE str,
VALUE ex)
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)
3824search_delim(
const char *p,
long len,
int delim, rb_encoding *enc)
3827 p = memchr(p, delim,
len);
3828 if (p)
return p + 1;
3831 const char *end = p +
len;
3833 int r = rb_enc_precise_mbclen(p, end, enc);
3849appendline(rb_io_t *fptr,
int delim,
VALUE *strp,
long *lp, rb_encoding *enc)
3854 if (NEED_READCONV(fptr)) {
3855 SET_BINARY_MODE(fptr);
3856 make_readconv(fptr, 0);
3859 int searchlen = READ_CHAR_PENDING_COUNT(fptr);
3861 p = READ_CHAR_PENDING_PTR(fptr);
3862 if (0 < limit && limit < searchlen)
3863 searchlen = (int)limit;
3864 e = search_delim(p, searchlen, delim, enc);
3866 int len = (int)(e-p);
3888 return (
unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
3891 }
while (more_char(fptr) != MORE_CHAR_FINISHED);
3892 clear_readconv(fptr);
3897 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3899 long pending = READ_DATA_PENDING_COUNT(fptr);
3901 const char *p = READ_DATA_PENDING_PTR(fptr);
3905 if (limit > 0 && pending > limit) pending = limit;
3906 e = search_delim(p, pending, delim, enc);
3907 if (e) pending = e - p;
3909 last = RSTRING_LEN(str);
3910 rb_str_resize(str, last + pending);
3914 *strp = str = rb_str_buf_new(pending);
3915 rb_str_set_len(str, pending);
3917 read_buffered_data(RSTRING_PTR(str) + last, pending, fptr);
3920 if (e)
return delim;
3922 return (
unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
3925 }
while (io_fillbuf(fptr) >= 0);
3931swallow(rb_io_t *fptr,
int term)
3933 if (NEED_READCONV(fptr)) {
3934 rb_encoding *enc = io_read_encoding(fptr);
3936 SET_BINARY_MODE(fptr);
3937 make_readconv(fptr, 0);
3940 while ((cnt = READ_CHAR_PENDING_COUNT(fptr)) > 0) {
3941 const char *p = READ_CHAR_PENDING_PTR(fptr);
3944 if (*p != term)
return TRUE;
3946 while (--i && *++p == term);
3949 const char *e = p + cnt;
3950 if (rb_enc_ascget(p, e, &i, enc) != term)
return TRUE;
3951 while ((p += i) < e && rb_enc_ascget(p, e, &i, enc) == term);
3954 io_shift_cbuf(fptr, (
int)cnt - i, NULL);
3956 }
while (more_char(fptr) != MORE_CHAR_FINISHED);
3960 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3963 while ((cnt = READ_DATA_PENDING_COUNT(fptr)) > 0) {
3965 const char *p = READ_DATA_PENDING_PTR(fptr);
3967 if (cnt >
sizeof buf) cnt =
sizeof buf;
3968 if (*p != term)
return TRUE;
3970 while (--i && *++p == term);
3971 if (!read_buffered_data(buf, cnt - i, fptr))
3972 rb_sys_fail_path(fptr->
pathv);
3975 }
while (io_fillbuf(fptr) == 0);
3980rb_io_getline_fast(rb_io_t *fptr, rb_encoding *enc,
int chomp)
3988 int pending = READ_DATA_PENDING_COUNT(fptr);
3991 const char *p = READ_DATA_PENDING_PTR(fptr);
3995 e = memchr(p,
'\n', pending);
3997 pending = (int)(e - p + 1);
3999 chomplen = (pending > 1 && *(e-1) ==
'\r') + 1;
4008 rb_str_resize(str,
len + pending - chomplen);
4009 read_buffered_data(RSTRING_PTR(str)+
len, pending - chomplen, fptr);
4012 if (pending == 1 && chomplen == 1 &&
len > 0) {
4013 if (RSTRING_PTR(str)[
len-1] ==
'\r') {
4014 rb_str_resize(str, --
len);
4019 len += pending - chomplen;
4025 }
while (io_fillbuf(fptr) >= 0);
4028 str = io_enc_str(str, fptr);
4039 unsigned int chomp: 1;
4053 chomp = (!UNDEF_P(vchomp)) &&
RTEST(vchomp);
4055 args->chomp = chomp;
4073 else if (2 <= argc) {
4074 rs = argv[0], lim = argv[1];
4083check_getline_args(
VALUE *rsp,
long *limit,
VALUE io)
4089 rb_encoding *enc_rs, *enc_io;
4092 enc_rs = rb_enc_get(rs);
4093 enc_io = io_read_encoding(fptr);
4094 if (enc_io != enc_rs &&
4095 (!is_ascii_string(rs) ||
4096 (RSTRING_LEN(rs) > 0 && !rb_enc_asciicompat(enc_io)))) {
4097 if (rs == rb_default_rs) {
4098 rs = rb_enc_str_new(0, 0, enc_io);
4103 rb_raise(rb_eArgError,
"encoding mismatch: %s IO with %s RS",
4104 rb_enc_name(enc_io),
4105 rb_enc_name(enc_rs));
4115 argc =
rb_scan_args(argc, argv,
"02:", NULL, NULL, &opts);
4116 extract_getline_args(argc, argv, args);
4117 extract_getline_opts(opts, args);
4118 check_getline_args(&args->rs, &args->limit, io);
4122rb_io_getline_0(
VALUE rs,
long limit,
int chomp, rb_io_t *fptr)
4129 if (
NIL_P(rs) && limit < 0) {
4130 str = read_all(fptr, 0,
Qnil);
4131 if (RSTRING_LEN(str) == 0)
return Qnil;
4133 else if (limit == 0) {
4134 return rb_enc_str_new(0, 0, io_read_encoding(fptr));
4136 else if (rs == rb_default_rs && limit < 0 && !NEED_READCONV(fptr) &&
4137 rb_enc_asciicompat(enc = io_read_encoding(fptr))) {
4138 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4139 return rb_io_getline_fast(fptr, enc, chomp);
4142 int c, newline = -1;
4143 const char *rsptr = 0;
4146 int extra_limit = 16;
4147 int chomp_cr = chomp;
4149 SET_BINARY_MODE(fptr);
4150 enc = io_read_encoding(fptr);
4153 rslen = RSTRING_LEN(rs);
4158 swallow(fptr,
'\n');
4160 if (!rb_enc_asciicompat(enc)) {
4164 rsptr = RSTRING_PTR(rs);
4165 rslen = RSTRING_LEN(rs);
4170 rsptr = RSTRING_PTR(rs);
4171 newline = (
unsigned char)rsptr[rslen - 1];
4175 rsptr = RSTRING_PTR(rs);
4176 const char *e = rsptr + rslen;
4177 const char *last = rb_enc_prev_char(rsptr, e, e, enc);
4179 newline = rb_enc_codepoint_len(last, e, &n, enc);
4180 if (last + n != e) rb_raise(rb_eArgError,
"broken separator");
4186 while ((c = appendline(fptr, newline, &str, &limit, enc)) != EOF) {
4187 const char *s, *p, *pp, *e;
4190 if (RSTRING_LEN(str) < rslen)
continue;
4191 s = RSTRING_PTR(str);
4192 e = RSTRING_END(str);
4194 if (!at_char_boundary(s, p, e, enc))
continue;
4195 if (!rspara) rscheck(rsptr, rslen, rs);
4196 if (memcmp(p, rsptr, rslen) == 0) {
4198 if (chomp_cr && p > s && *(p-1) ==
'\r') --p;
4199 rb_str_set_len(str, p - s);
4205 s = RSTRING_PTR(str);
4206 p = RSTRING_END(str);
4207 pp = rb_enc_prev_char(s, p, p, enc);
4208 if (extra_limit && pp &&
4222 if (rspara && c != EOF)
4223 swallow(fptr,
'\n');
4225 str = io_enc_str(str, fptr);
4228 if (!
NIL_P(str) && !nolimit) {
4236rb_io_getline_1(
VALUE rs,
long limit,
int chomp,
VALUE io)
4239 int old_lineno, new_lineno;
4243 old_lineno = fptr->
lineno;
4244 str = rb_io_getline_0(rs, limit, chomp, fptr);
4245 if (!
NIL_P(str) && (new_lineno = fptr->
lineno) != old_lineno) {
4246 if (io == ARGF.current_file) {
4247 ARGF.lineno += new_lineno - old_lineno;
4248 ARGF.last_lineno = ARGF.lineno;
4251 ARGF.last_lineno = new_lineno;
4259rb_io_getline(
int argc,
VALUE *argv,
VALUE io)
4263 prepare_getline_args(argc, argv, &args, io);
4264 return rb_io_getline_1(args.rs, args.limit, args.chomp, io);
4270 return rb_io_getline_1(rb_default_rs, -1, FALSE, io);
4274rb_io_gets_internal(
VALUE io)
4278 return rb_io_getline_0(rb_default_rs, -1, FALSE, fptr);
4361 str = rb_io_getline(argc, argv, io);
4377rb_io_lineno(
VALUE io)
4432 check_getline_args(&sep, &limit, io);
4434 VALUE line = rb_io_getline_1(sep, limit,
RTEST(chomp), io);
4435 rb_lastline_set_up(line, 1);
4512rb_io_readlines(
int argc,
VALUE *argv,
VALUE io)
4516 prepare_getline_args(argc, argv, &args, io);
4517 return io_readlines(&args, io);
4525 if (arg->limit == 0)
4526 rb_raise(rb_eArgError,
"invalid limit: 0 for readlines");
4528 while (!
NIL_P(line = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, io))) {
4529 rb_ary_push(ary, line);
4643rb_io_each_line(
int argc,
VALUE *argv,
VALUE io)
4649 prepare_getline_args(argc, argv, &args, io);
4650 if (args.limit == 0)
4651 rb_raise(rb_eArgError,
"invalid limit: 0 for each_line");
4652 while (!
NIL_P(str = rb_io_getline_1(args.rs, args.limit, args.chomp, io))) {
4679rb_io_each_byte(
VALUE io)
4695 }
while (io_fillbuf(fptr) >= 0);
4700io_getc(rb_io_t *fptr, rb_encoding *enc)
4705 if (NEED_READCONV(fptr)) {
4706 rb_encoding *read_enc = io_read_encoding(fptr);
4709 SET_BINARY_MODE(fptr);
4710 make_readconv(fptr, 0);
4724 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4726 clear_readconv(fptr);
4730 str = rb_enc_str_new(fptr->
cbuf.
ptr+fptr->
cbuf.
off, 1, read_enc);
4733 if (fptr->
cbuf.
len == 0) clear_readconv(fptr);
4742 io_shift_cbuf(fptr, r, &str);
4749 ISASCII(RSTRING_PTR(str)[0])) {
4753 str = io_enc_str(str, fptr);
4758 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4759 if (io_fillbuf(fptr) < 0) {
4781 if (io_fillbuf(fptr) != -1) {
4785 r = rb_enc_precise_mbclen(RSTRING_PTR(str), RSTRING_PTR(str)+RSTRING_LEN(str), enc);
4801 str = io_enc_str(str, fptr);
4827rb_io_each_char(
VALUE io)
4837 enc = io_input_encoding(fptr);
4839 while (!
NIL_P(c = io_getc(fptr, enc))) {
4865rb_io_each_codepoint(
VALUE io)
4877 if (NEED_READCONV(fptr)) {
4878 SET_BINARY_MODE(fptr);
4881 make_readconv(fptr, 0);
4889 r = ONIGENC_CONSTRUCT_MBCLEN_CHARFOUND(1);
4896 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4897 clear_readconv(fptr);
4924 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4925 enc = io_input_encoding(fptr);
4926 while (io_fillbuf(fptr) >= 0) {
4941 char cbuf[8], *p = cbuf;
4943 if (more > numberof(cbuf))
goto invalid;
4945 if (more > numberof(cbuf))
goto invalid;
4946 while ((n = (
int)read_buffered_data(p, more, fptr)) > 0 &&
4947 (p += n, (more -= n) > 0)) {
4948 if (io_fillbuf(fptr) < 0)
goto invalid;
4949 if ((n = fptr->
rbuf.
len) > more) n = more;
4951 r = rb_enc_precise_mbclen(cbuf, p, enc);
4964 rb_raise(rb_eArgError,
"invalid byte sequence in %s", rb_enc_name(enc));
4996 enc = io_input_encoding(fptr);
4998 return io_getc(fptr, enc);
5021rb_io_readchar(
VALUE io)
5023 VALUE c = rb_io_getc(io);
5058 VALUE r_stdout = rb_ractor_stdout();
5063 rb_io_flush(r_stdout);
5066 if (io_fillbuf(fptr) < 0) {
5095rb_io_readbyte(
VALUE io)
5156 unsigned char c =
NUM2INT(v) & 0xFF;
5162 io_ungetbyte(b, fptr);
5218 else if (RB_BIGNUM_TYPE_P(c)) {
5224 if (NEED_READCONV(fptr)) {
5225 SET_BINARY_MODE(fptr);
5226 len = RSTRING_LEN(c);
5227#if SIZEOF_LONG > SIZEOF_INT
5231 make_readconv(fptr, (
int)
len);
5245 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
5246 io_ungetbyte(c, fptr);
5266rb_io_isatty(
VALUE io)
5271 return RBOOL(isatty(fptr->
fd) != 0);
5274#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5290rb_io_close_on_exec_p(
VALUE io)
5296 write_io = GetWriteIO(io);
5297 if (io != write_io) {
5299 if (fptr && 0 <= (fd = fptr->
fd)) {
5300 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->
pathv);
5301 if (!(ret & FD_CLOEXEC))
return Qfalse;
5306 if (fptr && 0 <= (fd = fptr->
fd)) {
5307 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->
pathv);
5308 if (!(ret & FD_CLOEXEC))
return Qfalse;
5313#define rb_io_close_on_exec_p rb_f_notimplement
5316#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5340 int flag =
RTEST(arg) ? FD_CLOEXEC : 0;
5345 write_io = GetWriteIO(io);
5346 if (io != write_io) {
5348 if (fptr && 0 <= (fd = fptr->
fd)) {
5349 if ((ret = fcntl(fptr->
fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->
pathv);
5350 if ((ret & FD_CLOEXEC) != flag) {
5351 ret = (ret & ~FD_CLOEXEC) | flag;
5352 ret = fcntl(fd, F_SETFD, ret);
5353 if (ret != 0) rb_sys_fail_path(fptr->
pathv);
5360 if (fptr && 0 <= (fd = fptr->
fd)) {
5361 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->
pathv);
5362 if ((ret & FD_CLOEXEC) != flag) {
5363 ret = (ret & ~FD_CLOEXEC) | flag;
5364 ret = fcntl(fd, F_SETFD, ret);
5365 if (ret != 0) rb_sys_fail_path(fptr->
pathv);
5371#define rb_io_set_close_on_exec rb_f_notimplement
5374#define RUBY_IO_EXTERNAL_P(f) ((f)->mode & FMODE_EXTERNAL)
5375#define PREP_STDIO_NAME(f) (RSTRING_PTR((f)->pathv))
5378finish_writeconv(rb_io_t *fptr,
int noalloc)
5380 unsigned char *ds, *dp, *de;
5384 unsigned char buf[1024];
5389 de = buf +
sizeof(buf);
5392 size_t remaining = dp-ds;
5393 long result = rb_io_write_memory(fptr, ds, remaining);
5397 if ((
size_t)result == remaining)
break;
5420 if (io_fflush(fptr) < 0) {
5428 fptr->
wbuf.
len += (int)(dp - ds);
5444finish_writeconv_sync(
VALUE arg)
5447 return finish_writeconv(p->fptr, p->noalloc);
5451nogvl_close(
void *ptr)
5455 return (
void*)(intptr_t)close(*fd);
5459maygvl_close(
int fd,
int keepgvl)
5472nogvl_fclose(
void *ptr)
5476 return (
void*)(intptr_t)fclose(file);
5480maygvl_fclose(FILE *file,
int keepgvl)
5483 return fclose(file);
5489static void clear_codeconv(rb_io_t *fptr);
5492fptr_finalize_flush(rb_io_t *fptr,
int noraise,
int keepgvl,
5498 int mode = fptr->
mode;
5504 arg.noalloc = noraise;
5508 error = finish_writeconv(fptr, noraise);
5513 io_flush_buffer_sync(fptr);
5516 if (io_fflush(fptr) < 0 &&
NIL_P(error)) {
5524 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2) {
5536 rb_notify_fd_close_wait(busy);
5548 if (!done && stdio_file) {
5550 if ((maygvl_fclose(stdio_file, noraise) < 0) &&
NIL_P(error)) {
5559 if (!done && fd >= 0) {
5565 if ((maygvl_close(fd, keepgvl) < 0) &&
NIL_P(error)) {
5574 if (!
NIL_P(error) && !noraise) {
5578 rb_exc_raise(error);
5583fptr_finalize(rb_io_t *fptr,
int noraise)
5585 fptr_finalize_flush(fptr, noraise, FALSE, 0);
5586 free_io_buffer(&fptr->
rbuf);
5587 free_io_buffer(&fptr->
wbuf);
5588 clear_codeconv(fptr);
5592rb_io_fptr_cleanup(rb_io_t *fptr,
int noraise)
5598 fptr_finalize(fptr, noraise);
5606 ruby_sized_xfree(buf->ptr, (
size_t)buf->capa);
5612clear_readconv(rb_io_t *fptr)
5618 free_io_buffer(&fptr->
cbuf);
5622clear_writeconv(rb_io_t *fptr)
5632clear_codeconv(rb_io_t *fptr)
5634 clear_readconv(fptr);
5635 clear_writeconv(fptr);
5639rb_io_fptr_cleanup_all(rb_io_t *fptr)
5643 rb_io_fptr_cleanup(fptr, TRUE);
5645 free_io_buffer(&fptr->
rbuf);
5646 free_io_buffer(&fptr->
wbuf);
5647 clear_codeconv(fptr);
5651rb_io_fptr_finalize_internal(
void *ptr)
5654 rb_io_fptr_cleanup_all(ptr);
5658#undef rb_io_fptr_finalize
5660rb_io_fptr_finalize(rb_io_t *fptr)
5666 rb_io_fptr_finalize_internal(fptr);
5670#define rb_io_fptr_finalize(fptr) rb_io_fptr_finalize_internal(fptr)
5672RUBY_FUNC_EXPORTED
size_t
5673rb_io_memsize(
const rb_io_t *fptr)
5675 size_t size =
sizeof(rb_io_t);
5686# define KEEPGVL TRUE
5688# define KEEPGVL FALSE
5692io_close_fptr(
VALUE io)
5696 rb_io_t *write_fptr;
5699 write_io = GetWriteIO(io);
5700 if (io != write_io) {
5701 write_fptr =
RFILE(write_io)->fptr;
5702 if (write_fptr && 0 <= write_fptr->
fd) {
5703 rb_io_fptr_cleanup(write_fptr, TRUE);
5707 fptr =
RFILE(io)->fptr;
5708 if (!fptr)
return 0;
5709 if (fptr->
fd < 0)
return 0;
5711 if (rb_notify_fd_close(fptr->
fd, &busy)) {
5713 fptr_finalize_flush(fptr, FALSE, KEEPGVL, &busy);
5715 rb_io_fptr_cleanup(fptr, FALSE);
5720fptr_waitpid(rb_io_t *fptr,
int nohang)
5724 rb_last_status_clear();
5733 rb_io_t *fptr = io_close_fptr(io);
5734 if (fptr) fptr_waitpid(fptr, 0);
5771rb_io_close_m(
VALUE io)
5773 rb_io_t *fptr = rb_io_get_fptr(io);
5782io_call_close(
VALUE io)
5791 enum {mesg_len =
sizeof(closed_stream)-1};
5792 VALUE mesg = rb_attr_get(exc, idMesg);
5794 RSTRING_LEN(mesg) != mesg_len ||
5795 memcmp(RSTRING_PTR(mesg), closed_stream, mesg_len)) {
5805 if (!UNDEF_P(closed) &&
RTEST(closed))
return io;
5806 rb_rescue2(io_call_close, io, ignore_closed_stream, io,
5840 rb_io_t *write_fptr;
5842 write_io = GetWriteIO(io);
5843 if (io != write_io) {
5844 write_fptr =
RFILE(write_io)->fptr;
5845 if (write_fptr && 0 <= write_fptr->
fd) {
5850 fptr = rb_io_get_fptr(io);
5851 return RBOOL(0 > fptr->
fd);
5887rb_io_close_read(
VALUE io)
5893 if (fptr->
fd < 0)
return Qnil;
5894 if (is_socket(fptr->
fd, fptr->
pathv)) {
5898 if (shutdown(fptr->
fd, SHUT_RD) < 0)
5899 rb_sys_fail_path(fptr->
pathv);
5906 write_io = GetWriteIO(io);
5907 if (io != write_io) {
5912 RFILE(io)->fptr = wfptr;
5915 RFILE(write_io)->fptr = fptr;
5916 rb_io_fptr_cleanup(fptr, FALSE);
5922 rb_raise(
rb_eIOError,
"closing non-duplex IO for reading");
5960rb_io_close_write(
VALUE io)
5965 write_io = GetWriteIO(io);
5967 if (fptr->
fd < 0)
return Qnil;
5968 if (is_socket(fptr->
fd, fptr->
pathv)) {
5972 if (shutdown(fptr->
fd, SHUT_WR) < 0)
5973 rb_sys_fail_path(fptr->
pathv);
5981 rb_raise(
rb_eIOError,
"closing non-duplex IO for writing");
5984 if (io != write_io) {
6004rb_io_sysseek(
int argc,
VALUE *argv,
VALUE io)
6006 VALUE offset, ptrname;
6007 int whence = SEEK_SET;
6011 if (
rb_scan_args(argc, argv,
"11", &offset, &ptrname) == 2) {
6012 whence = interpret_seek_whence(ptrname);
6017 (READ_DATA_BUFFERED(fptr) || READ_CHAR_PENDING(fptr))) {
6021 rb_warn(
"sysseek for buffered IO");
6024 pos = lseek(fptr->
fd, pos, whence);
6025 if (pos < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
6057 str = rb_obj_as_string(str);
6059 io = GetWriteIO(io);
6064 rb_warn(
"syswrite for buffered IO");
6067 tmp = rb_str_tmp_frozen_acquire(str);
6069 n = rb_io_write_memory(fptr, ptr,
len);
6070 if (n < 0) rb_sys_fail_path(fptr->
pathv);
6071 rb_str_tmp_frozen_release(str, tmp);
6088rb_io_sysread(
int argc,
VALUE *argv,
VALUE io)
6099 shrinkable = io_setstrbuf(&str, ilen);
6100 if (ilen == 0)
return str;
6105 if (READ_DATA_BUFFERED(fptr)) {
6111 io_setstrbuf(&str, ilen);
6116 iis.buf = RSTRING_PTR(str);
6119 n = io_read_memory_locktmp(str, &iis);
6122 rb_sys_fail_path(fptr->
pathv);
6125 io_set_read_length(str, n, shrinkable);
6127 if (n == 0 && ilen > 0) {
6143internal_pread_func(
void *_arg)
6147 return (
VALUE)pread(arg->fd, arg->buf, arg->count, arg->offset);
6151pread_internal_call(
VALUE _arg)
6156 if (scheduler !=
Qnil) {
6159 if (!UNDEF_P(result)) {
6164 return rb_thread_io_blocking_call(internal_pread_func, arg, arg->fd, RB_WAITFD_IN);
6208 shrinkable = io_setstrbuf(&str, (
long)arg.count);
6209 if (arg.count == 0)
return str;
6210 arg.buf = RSTRING_PTR(str);
6222 rb_sys_fail_path(fptr->
pathv);
6224 io_set_read_length(str, n, shrinkable);
6225 if (n == 0 && arg.count > 0) {
6233internal_pwrite_func(
void *_arg)
6238 if (scheduler !=
Qnil) {
6241 if (!UNDEF_P(result)) {
6247 return (
VALUE)pwrite(arg->fd, arg->buf, arg->count, arg->offset);
6284 str = rb_obj_as_string(str);
6288 io = GetWriteIO(io);
6293 tmp = rb_str_tmp_frozen_acquire(str);
6294 arg.buf = RSTRING_PTR(tmp);
6295 arg.count = (size_t)RSTRING_LEN(tmp);
6297 n = (ssize_t)rb_thread_io_blocking_call(internal_pwrite_func, &arg, fptr->
fd, RB_WAITFD_OUT);
6298 if (n < 0) rb_sys_fail_path(fptr->
pathv);
6299 rb_str_tmp_frozen_release(str, tmp);
6319 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6322 setmode(fptr->
fd, O_BINARY);
6329io_ascii8bit_binmode(rb_io_t *fptr)
6341 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6343 fptr->
encs.
enc = rb_ascii8bit_encoding();
6347 clear_codeconv(fptr);
6356 io_ascii8bit_binmode(fptr);
6373rb_io_binmode_m(
VALUE io)
6379 write_io = GetWriteIO(io);
6394rb_io_binmode_p(
VALUE io)
6402rb_io_fmode_modestr(
int fmode)
6406 return MODE_BTMODE(
"a+",
"ab+",
"at+");
6408 return MODE_BTMODE(
"a",
"ab",
"at");
6412 rb_raise(rb_eArgError,
"invalid access fmode 0x%x", fmode);
6414 return MODE_BTMODE(
"r",
"rb",
"rt");
6416 return MODE_BTXMODE(
"w",
"wb",
"wt",
"wx",
"wbx",
"wtx");
6419 return MODE_BTXMODE(
"w+",
"wb+",
"wt+",
"w+x",
"wb+x",
"wt+x");
6421 return MODE_BTMODE(
"r+",
"rb+",
"rt+");
6425static const char bom_prefix[] =
"bom|";
6426static const char utf_prefix[] =
"utf-";
6427enum {bom_prefix_len = (int)
sizeof(bom_prefix) - 1};
6428enum {utf_prefix_len = (int)
sizeof(utf_prefix) - 1};
6431io_encname_bom_p(
const char *name,
long len)
6433 return len > bom_prefix_len &&
STRNCASECMP(name, bom_prefix, bom_prefix_len) == 0;
6440 const char *m = modestr, *p = NULL;
6468 if (modestr[0] !=
'w')
6476 if (io_encname_bom_p(m, p ? (
long)(p - m) : (
long)strlen(m)))
6489 rb_raise(rb_eArgError,
"invalid access mode %s", modestr);
6498 switch (oflags & O_ACCMODE) {
6510 if (oflags & O_APPEND) {
6513 if (oflags & O_TRUNC) {
6516 if (oflags & O_CREAT) {
6519 if (oflags & O_EXCL) {
6523 if (oflags & O_BINARY) {
6532rb_io_fmode_oflags(
int fmode)
6576rb_io_oflags_modestr(
int oflags)
6579# define MODE_BINARY(a,b) ((oflags & O_BINARY) ? (b) : (a))
6581# define MODE_BINARY(a,b) (a)
6584 if (oflags & O_EXCL) {
6585 rb_raise(rb_eArgError,
"exclusive access mode is not supported");
6587 accmode = oflags & (O_RDONLY|O_WRONLY|O_RDWR);
6588 if (oflags & O_APPEND) {
6589 if (accmode == O_WRONLY) {
6590 return MODE_BINARY(
"a",
"ab");
6592 if (accmode == O_RDWR) {
6593 return MODE_BINARY(
"a+",
"ab+");
6598 rb_raise(rb_eArgError,
"invalid access oflags 0x%x", oflags);
6600 return MODE_BINARY(
"r",
"rb");
6602 return MODE_BINARY(
"w",
"wb");
6604 if (oflags & O_TRUNC) {
6605 return MODE_BINARY(
"w+",
"wb+");
6607 return MODE_BINARY(
"r+",
"rb+");
6617rb_io_ext_int_to_encs(rb_encoding *ext, rb_encoding *intern, rb_encoding **enc, rb_encoding **enc2,
int fmode)
6619 int default_ext = 0;
6622 ext = rb_default_external_encoding();
6625 if (rb_is_ascii8bit_enc(ext)) {
6629 else if (intern == NULL) {
6630 intern = rb_default_internal_encoding();
6632 if (intern == NULL || intern == (rb_encoding *)
Qnil ||
6635 *enc = (default_ext && intern != ext) ? NULL : ext;
6645unsupported_encoding(
const char *name, rb_encoding *enc)
6647 rb_enc_warn(enc,
"Unsupported encoding %s ignored", name);
6651parse_mode_enc(
const char *estr, rb_encoding *estr_enc,
6652 rb_encoding **enc_p, rb_encoding **enc2_p,
int *fmode_p)
6657 int fmode = fmode_p ? *fmode_p : 0;
6658 rb_encoding *ext_enc, *int_enc;
6663 p = strrchr(estr,
':');
6664 len = p ? (p++ - estr) : (long)strlen(estr);
6666 estr += bom_prefix_len;
6667 len -= bom_prefix_len;
6668 if (!
STRNCASECMP(estr, utf_prefix, utf_prefix_len)) {
6672 rb_enc_warn(estr_enc,
"BOM with non-UTF encoding %s is nonsense", estr);
6681 memcpy(encname, estr,
len);
6682 encname[
len] =
'\0';
6685 idx = rb_enc_find_index(estr);
6687 if (fmode_p) *fmode_p = fmode;
6690 ext_enc = rb_enc_from_index(idx);
6693 unsupported_encoding(estr, estr_enc);
6699 if (*p ==
'-' && *(p+1) ==
'\0') {
6701 int_enc = (rb_encoding *)
Qnil;
6704 idx2 = rb_enc_find_index(p);
6706 unsupported_encoding(p, estr_enc);
6708 int_enc = (rb_encoding *)
Qnil;
6711 int_enc = rb_enc_from_index(idx2);
6715 rb_io_ext_int_to_encs(ext_enc, int_enc, enc_p, enc2_p, fmode);
6723 rb_encoding *extencoding = NULL;
6724 rb_encoding *intencoding = NULL;
6728 v = rb_hash_lookup2(opt, sym_encoding,
Qnil);
6729 if (v !=
Qnil) encoding = v;
6730 v = rb_hash_lookup2(opt, sym_extenc,
Qundef);
6731 if (v !=
Qnil) extenc = v;
6732 v = rb_hash_lookup2(opt, sym_intenc,
Qundef);
6733 if (!UNDEF_P(v)) intenc = v;
6735 if ((!UNDEF_P(extenc) || !UNDEF_P(intenc)) && !
NIL_P(encoding)) {
6737 int idx = rb_to_encoding_index(encoding);
6738 if (idx >= 0) encoding = rb_enc_from_encoding(rb_enc_from_index(idx));
6739 rb_warn(
"Ignoring encoding parameter '%"PRIsVALUE
"': %s_encoding is used",
6740 encoding, UNDEF_P(extenc) ?
"internal" :
"external");
6744 if (!UNDEF_P(extenc) && !
NIL_P(extenc)) {
6745 extencoding = rb_to_encoding(extenc);
6747 if (!UNDEF_P(intenc)) {
6748 if (
NIL_P(intenc)) {
6750 intencoding = (rb_encoding *)
Qnil;
6755 if (*p ==
'-' && *(p+1) ==
'\0') {
6757 intencoding = (rb_encoding *)
Qnil;
6760 intencoding = rb_to_encoding(intenc);
6764 intencoding = rb_to_encoding(intenc);
6766 if (extencoding == intencoding) {
6767 intencoding = (rb_encoding *)
Qnil;
6770 if (!
NIL_P(encoding)) {
6774 enc_p, enc2_p, fmode_p);
6777 rb_io_ext_int_to_encs(rb_to_encoding(encoding), NULL, enc_p, enc2_p, 0);
6780 else if (!UNDEF_P(extenc) || !UNDEF_P(intenc)) {
6782 rb_io_ext_int_to_encs(extencoding, intencoding, enc_p, enc2_p, 0);
6788validate_enc_binmode(
int *fmode_p,
int ecflags, rb_encoding *enc, rb_encoding *enc2)
6790 int fmode = *fmode_p;
6795 !rb_enc_asciicompat(enc ? enc : rb_default_external_encoding()))
6796 rb_raise(rb_eArgError,
"ASCII incompatible encoding needs binmode");
6799 rb_raise(rb_eArgError,
"newline decorator with binary mode");
6806#if !DEFAULT_TEXTMODE
6815extract_binmode(
VALUE opthash,
int *fmode)
6817 if (!
NIL_P(opthash)) {
6819 v = rb_hash_aref(opthash, sym_textmode);
6822 rb_raise(rb_eArgError,
"textmode specified twice");
6824 rb_raise(rb_eArgError,
"both textmode and binmode specified");
6828 v = rb_hash_aref(opthash, sym_binmode);
6831 rb_raise(rb_eArgError,
"binmode specified twice");
6833 rb_raise(rb_eArgError,
"both textmode and binmode specified");
6839 rb_raise(rb_eArgError,
"both textmode and binmode specified");
6845 int *oflags_p,
int *fmode_p,
struct rb_io_encoding *convconfig_p)
6849 rb_encoding *enc, *enc2;
6852 int has_enc = 0, has_vmode = 0;
6858 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
6876 oflags = rb_io_fmode_oflags(fmode);
6880 parse_mode_enc(p+1, rb_enc_get(vmode), &enc, &enc2, &fmode);
6885 e = (fmode &
FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
6886 rb_io_ext_int_to_encs(e, NULL, &enc, &enc2, fmode);
6890 if (
NIL_P(opthash)) {
6894#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
6896 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
6897 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
6899 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
6906 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
6909 else if (
NIL_P(vmode)) {
6910 fmode |= DEFAULT_TEXTMODE;
6917 v = rb_hash_aref(opthash, sym_mode);
6919 if (!
NIL_P(vmode)) {
6920 rb_raise(rb_eArgError,
"mode specified twice");
6927 v = rb_hash_aref(opthash, sym_flags);
6934 extract_binmode(opthash, &fmode);
6940 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
6943 else if (
NIL_P(vmode)) {
6944 fmode |= DEFAULT_TEXTMODE;
6947 v = rb_hash_aref(opthash, sym_perm);
6950 if (!
NIL_P(*vperm_p)) {
6951 rb_raise(rb_eArgError,
"perm specified twice");
6962#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
6964 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
6965 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
6970 rb_raise(rb_eArgError,
"encoding specified twice");
6973 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
6977 validate_enc_binmode(&fmode, ecflags, enc, enc2);
6983 convconfig_p->
enc = enc;
6984 convconfig_p->
enc2 = enc2;
6985 convconfig_p->
ecflags = ecflags;
6986 convconfig_p->
ecopts = ecopts;
6996sysopen_func(
void *ptr)
6999 const char *fname = RSTRING_PTR(data->fname);
7014rb_sysopen(
VALUE fname,
int oflags, mode_t perm)
7019 data.fname = rb_str_encode_ospath(fname);
7021 data.oflags = oflags;
7024 TRY_WITH_GC((fd = rb_sysopen_internal(&data)) >= 0) {
7025 rb_syserr_fail_path(first_errno, fname);
7031fdopen_internal(
int fd,
const char *modestr)
7038 file = fdopen(fd, modestr);
7054 TRY_WITH_GC((file = fdopen_internal(fd, modestr)) != 0) {
7060 if (setvbuf(file, NULL, _IOFBF, 0) != 0)
7061 rb_warn(
"setvbuf() can't be honoured (fd=%d)", fd);
7067io_check_tty(rb_io_t *fptr)
7069 int t = isatty(fptr->
fd);
7079io_strip_bom(
VALUE io)
7081 VALUE b1, b2, b3, b4;
7092 return rb_utf8_encindex();
7102 return ENCINDEX_UTF_16BE;
7113 return ENCINDEX_UTF_32LE;
7118 return ENCINDEX_UTF_16LE;
7128 return ENCINDEX_UTF_32BE;
7142io_set_encoding_by_bom(
VALUE io)
7144 int idx = io_strip_bom(io);
7146 rb_encoding *extenc = NULL;
7150 extenc = rb_enc_from_index(idx);
7151 io_encoding_set(fptr, rb_enc_from_encoding(extenc),
7152 rb_io_internal_encoding(io),
Qnil);
7161rb_file_open_generic(
VALUE io,
VALUE filename,
int oflags,
int fmode,
7169 rb_io_ext_int_to_encs(NULL, NULL, &cc.enc, &cc.enc2, fmode);
7174 validate_enc_binmode(&fmode, convconfig->
ecflags,
7175 convconfig->
enc, convconfig->
enc2);
7179 fptr->
encs = *convconfig;
7180 pathv = rb_str_new_frozen(filename);
7182 if (!(oflags & O_TMPFILE)) {
7183 fptr->
pathv = pathv;
7186 fptr->
pathv = pathv;
7188 fptr->
fd = rb_sysopen(pathv, oflags, perm);
7196rb_file_open_internal(
VALUE io,
VALUE filename,
const char *modestr)
7199 const char *p = strchr(modestr,
':');
7203 parse_mode_enc(p+1, rb_usascii_encoding(),
7204 &convconfig.
enc, &convconfig.
enc2, &fmode);
7212 e = (fmode &
FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
7213 rb_io_ext_int_to_encs(e, NULL, &convconfig.
enc, &convconfig.
enc2, fmode);
7218 return rb_file_open_generic(io, filename,
7219 rb_io_fmode_oflags(fmode),
7229 return rb_file_open_internal(io_alloc(
rb_cFile), fname, modestr);
7238#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7245pipe_add_fptr(rb_io_t *fptr)
7256pipe_del_fptr(rb_io_t *fptr)
7261 while ((tmp = *prev) != 0) {
7262 if (tmp->fptr == fptr) {
7271#if defined (_WIN32) || defined(__CYGWIN__)
7280 rb_io_fptr_finalize(list->fptr);
7287pipe_finalize(rb_io_t *fptr,
int noraise)
7289#if !defined(HAVE_WORKING_FORK) && !defined(_WIN32)
7298 fptr_finalize(fptr, noraise);
7300 pipe_del_fptr(fptr);
7305fptr_copy_finalizer(rb_io_t *fptr,
const rb_io_t *orig)
7307#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7308 void (*
const old_finalize)(
struct rb_io*,int) = fptr->
finalize;
7310 if (old_finalize == orig->finalize)
return;
7315#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7316 if (old_finalize != pipe_finalize) {
7318 for (list =
pipe_list; list; list = list->next) {
7319 if (list->fptr == fptr)
break;
7321 if (!list) pipe_add_fptr(fptr);
7324 pipe_del_fptr(fptr);
7337rb_io_unbuffered(rb_io_t *fptr)
7355#define HAVE_SPAWNV 1
7356#define spawnv(mode, cmd, args) rb_w32_uaspawn((mode), (cmd), (args))
7357#define spawn(mode, cmd) rb_w32_uspawn((mode), (cmd), 0)
7360#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7363 struct rb_execarg *eargp;
7370#ifdef HAVE_WORKING_FORK
7371# ifndef __EMSCRIPTEN__
7373popen_redirect(
struct popen_arg *p)
7376 close(p->write_pair[1]);
7377 if (p->write_pair[0] != 0) {
7378 dup2(p->write_pair[0], 0);
7379 close(p->write_pair[0]);
7382 if (p->pair[1] != 1) {
7383 dup2(p->pair[1], 1);
7389 if (p->pair[1] != 1) {
7390 dup2(p->pair[1], 1);
7396 if (p->pair[0] != 0) {
7397 dup2(p->pair[0], 0);
7404#if defined(__linux__)
7415linux_get_maxfd(
void)
7418 char buf[4096], *p, *np, *e;
7421 if (fd < 0)
return fd;
7422 ss = read(fd, buf,
sizeof(buf));
7423 if (ss < 0)
goto err;
7426 while ((
int)
sizeof(
"FDSize:\t0\n")-1 <= e-p &&
7427 (np = memchr(p,
'\n', e-p)) != NULL) {
7428 if (memcmp(p,
"FDSize:",
sizeof(
"FDSize:")-1) == 0) {
7430 p +=
sizeof(
"FDSize:")-1;
7450#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
7452 int max = (int)max_file_descriptor;
7455 ret = fcntl(0, F_MAXFD);
7457 maxhint = max = ret;
7458# elif defined(__linux__)
7459 ret = linux_get_maxfd();
7466 for (fd = lowfd; fd <= max; fd++) {
7467 if (!
NIL_P(noclose_fds) &&
7470 ret = fcntl(fd, F_GETFD);
7471 if (ret != -1 && !(ret & FD_CLOEXEC)) {
7472 fcntl(fd, F_SETFD, ret|FD_CLOEXEC);
7474# define CONTIGUOUS_CLOSED_FDS 20
7476 if (max < fd + CONTIGUOUS_CLOSED_FDS)
7477 max = fd + CONTIGUOUS_CLOSED_FDS;
7483# ifndef __EMSCRIPTEN__
7485popen_exec(
void *pp,
char *errmsg,
size_t errmsg_len)
7487 struct popen_arg *p = (
struct popen_arg*)pp;
7489 return rb_exec_async_signal_safe(p->eargp, errmsg, errmsg_len);
7494#if (defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)) && !defined __EMSCRIPTEN__
7496rb_execarg_fixup_v(
VALUE execarg_obj)
7498 rb_execarg_parent_start(execarg_obj);
7502char *rb_execarg_commandline(
const struct rb_execarg *eargp,
VALUE *prog);
7505#ifndef __EMSCRIPTEN__
7507pipe_open(
VALUE execarg_obj,
const char *modestr,
int fmode,
7510 struct rb_execarg *eargp =
NIL_P(execarg_obj) ? NULL : rb_execarg_get(execarg_obj);
7511 VALUE prog = eargp ? (eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name) :
Qfalse ;
7515 rb_io_t *write_fptr;
7517#if defined(HAVE_WORKING_FORK)
7519 char errmsg[80] = {
'\0' };
7521#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7523 struct popen_arg arg;
7526#if defined(HAVE_SPAWNV)
7527# if defined(HAVE_SPAWNVE)
7528# define DO_SPAWN(cmd, args, envp) ((args) ? \
7529 spawnve(P_NOWAIT, (cmd), (args), (envp)) : \
7530 spawne(P_NOWAIT, (cmd), (envp)))
7532# define DO_SPAWN(cmd, args, envp) ((args) ? \
7533 spawnv(P_NOWAIT, (cmd), (args)) : \
7534 spawn(P_NOWAIT, (cmd)))
7536# if !defined(HAVE_WORKING_FORK)
7538# if defined(HAVE_SPAWNVE)
7543#if !defined(HAVE_WORKING_FORK)
7549#if !defined(HAVE_WORKING_FORK)
7550 const char *cmd = 0;
7556#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7557 arg.execarg_obj = execarg_obj;
7560 arg.pair[0] = arg.pair[1] = -1;
7561 arg.write_pair[0] = arg.write_pair[1] = -1;
7562# if !defined(HAVE_WORKING_FORK)
7563 if (eargp && !eargp->use_shell) {
7564 args = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
7569 if (
rb_pipe(arg.write_pair) < 0)
7570 rb_sys_fail_str(prog);
7573 close(arg.write_pair[0]);
7574 close(arg.write_pair[1]);
7578 rb_execarg_addopt(execarg_obj,
INT2FIX(0),
INT2FIX(arg.write_pair[0]));
7579 rb_execarg_addopt(execarg_obj,
INT2FIX(1),
INT2FIX(arg.pair[1]));
7584 rb_sys_fail_str(prog);
7586 rb_execarg_addopt(execarg_obj,
INT2FIX(1),
INT2FIX(arg.pair[1]));
7590 rb_sys_fail_str(prog);
7592 rb_execarg_addopt(execarg_obj,
INT2FIX(0),
INT2FIX(arg.pair[0]));
7595 rb_sys_fail_str(prog);
7597 if (!
NIL_P(execarg_obj)) {
7598 rb_protect(rb_execarg_fixup_v, execarg_obj, &state);
7600 if (0 <= arg.write_pair[0]) close(arg.write_pair[0]);
7601 if (0 <= arg.write_pair[1]) close(arg.write_pair[1]);
7602 if (0 <= arg.pair[0]) close(arg.pair[0]);
7603 if (0 <= arg.pair[1]) close(arg.pair[1]);
7604 rb_execarg_parent_end(execarg_obj);
7608# if defined(HAVE_WORKING_FORK)
7609 pid = rb_fork_async_signal_safe(&status, popen_exec, &arg, arg.eargp->redirect_fds, errmsg,
sizeof(errmsg));
7611 rb_execarg_run_options(eargp, sargp, NULL, 0);
7612# if defined(HAVE_SPAWNVE)
7613 if (eargp->envp_str) envp = (
char **)RSTRING_PTR(eargp->envp_str);
7615 while ((pid = DO_SPAWN(cmd, args, envp)) < 0) {
7617 switch (e =
errno) {
7619# if EWOULDBLOCK != EAGAIN
7628 rb_execarg_run_options(sargp, NULL, NULL, 0);
7630 rb_execarg_parent_end(execarg_obj);
7633# if defined(HAVE_WORKING_FORK)
7634 pid = rb_call_proc__fork();
7636 popen_redirect(&arg);
7648# if defined(HAVE_WORKING_FORK)
7654 close(arg.write_pair[0]);
7655 close(arg.write_pair[1]);
7657# if defined(HAVE_WORKING_FORK)
7666 close(arg.write_pair[0]);
7667 write_fd = arg.write_pair[1];
7678 cmd = rb_execarg_commandline(eargp, &prog);
7679 if (!
NIL_P(execarg_obj)) {
7680 rb_execarg_parent_start(execarg_obj);
7681 rb_execarg_run_options(eargp, sargp, NULL, 0);
7683 fp = popen(cmd, modestr);
7686 rb_execarg_parent_end(execarg_obj);
7687 rb_execarg_run_options(sargp, NULL, NULL, 0);
7689 if (!fp) rb_syserr_fail_path(e, prog);
7699 fptr->
encs = *convconfig;
7700#if RUBY_CRLF_ENVIRONMENT
7707 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
7710#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7711 if (NEED_NEWLINE_DECORATOR_ON_WRITE(fptr)) {
7712 fptr->
encs.
ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
7718 if (0 <= write_fd) {
7719 write_port = io_alloc(
rb_cIO);
7721 write_fptr->
fd = write_fd;
7725 rb_ivar_set(port, rb_intern(
"@tied_io_for_writing"), write_port);
7728#if defined (__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7730 pipe_add_fptr(fptr);
7736pipe_open(
VALUE execarg_obj,
const char *modestr,
int fmode,
7744is_popen_fork(
VALUE prog)
7746 if (RSTRING_LEN(prog) == 1 && RSTRING_PTR(prog)[0] ==
'-') {
7747#if !defined(HAVE_WORKING_FORK)
7749 "fork() function is unimplemented on this machine");
7758pipe_open_s(
VALUE prog,
const char *modestr,
int fmode,
7762 VALUE *argv = &prog;
7765 if (!is_popen_fork(prog))
7766 execarg_obj = rb_execarg_new(argc, argv, TRUE, FALSE);
7767 return pipe_open(execarg_obj, modestr, fmode, convconfig);
7773 rb_io_t *fptr = io_close_fptr(io);
7941rb_io_s_popen(
int argc,
VALUE *argv,
VALUE klass)
7945 if (argc > 1 && !
NIL_P(opt = rb_check_hash_type(argv[argc-1]))) --argc;
7946 if (argc > 1 && !
NIL_P(env = rb_check_hash_type(argv[0]))) --argc, ++argv;
7955 int ex = !
NIL_P(opt);
7956 rb_error_arity(argc + ex, 1 + ex, 2 + ex);
7959 return popen_finish(rb_io_popen(pname, pmode, env, opt), klass);
7965 const char *modestr;
7970 tmp = rb_check_array_type(pname);
7973#if SIZEOF_LONG > SIZEOF_INT
7974 if (
len > INT_MAX) {
7975 rb_raise(rb_eArgError,
"too many arguments");
7984 if (!is_popen_fork(pname))
7985 execarg_obj = rb_execarg_new(1, &pname, TRUE, FALSE);
7987 if (!
NIL_P(execarg_obj)) {
7989 opt = rb_execarg_extract_options(execarg_obj, opt);
7991 rb_execarg_setenv(execarg_obj, env);
7994 modestr = rb_io_oflags_modestr(oflags);
7996 return pipe_open(execarg_obj, modestr, fmode, &convconfig);
8006 rb_io_flush(rb_ractor_stdout());
8007 rb_io_flush(rb_ractor_stderr());
8012 RBASIC_SET_CLASS(port, klass);
8019#if defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)
8020struct popen_writer_arg {
8022 struct popen_arg popen;
8026exec_popen_writer(
void *arg,
char *errmsg,
size_t buflen)
8028 struct popen_writer_arg *pw = arg;
8030 popen_redirect(&pw->popen);
8031 execv(pw->argv[0], pw->argv);
8032 strlcpy(errmsg, strerror(
errno), buflen);
8038ruby_popen_writer(
char *
const *argv, rb_pid_t *pid)
8040#if (defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)) || defined(_WIN32)
8041# ifdef HAVE_WORKING_FORK
8042 struct popen_writer_arg pw;
8043 int *
const write_pair = pw.popen.pair;
8051# ifdef HAVE_WORKING_FORK
8054 char errmsg[80] = {
'\0'};
8055 *pid = rb_fork_async_signal_safe(&status, exec_popen_writer, &pw,
Qnil, errmsg,
sizeof(errmsg));
8057 *pid = rb_w32_uspawn_process(P_NOWAIT, argv[0], argv, write_pair[0], -1, -1, 0);
8058 const char *errmsg = (*pid < 0) ? strerror(
errno) : NULL;
8060 close(write_pair[0]);
8062 close(write_pair[1]);
8063 fprintf(stderr,
"ruby_popen_writer(%s): %s\n", argv[0], errmsg);
8066 return fdopen(write_pair[1],
"w");
8074rb_scan_open_args(
int argc,
const VALUE *argv,
8075 VALUE *fname_p,
int *oflags_p,
int *fmode_p,
8078 VALUE opt, fname, vmode, vperm;
8082 argc =
rb_scan_args(argc, argv,
"12:", &fname, &vmode, &vperm, &opt);
8096rb_open_file(
int argc,
const VALUE *argv,
VALUE io)
8103 rb_scan_open_args(argc, argv, &fname, &oflags, &fmode, &convconfig, &perm);
8104 rb_file_open_generic(io, fname, oflags, fmode, &convconfig, perm);
8142rb_io_s_open(
int argc,
VALUE *argv,
VALUE klass)
8174 VALUE fname, vmode, vperm;
8179 rb_scan_args(argc, argv,
"12", &fname, &vmode, &vperm);
8190 if (
NIL_P(vperm)) perm = 0666;
8194 fd = rb_sysopen(fname, oflags, perm);
8199check_pipe_command(
VALUE filename_or_command)
8201 char *s = RSTRING_PTR(filename_or_command);
8202 long l = RSTRING_LEN(filename_or_command);
8206 if (rb_enc_ascget(s, e, &chlen, rb_enc_get(filename_or_command)) ==
'|') {
8244 int redirect = FALSE;
8252 VALUE tmp = argv[0];
8258 VALUE cmd = check_pipe_command(tmp);
8261 rb_warn_deprecated_to_remove_at(4.0,
"Calling Kernel#open with a leading '|'",
"IO.popen");
8263 return rb_io_s_popen(argc, argv,
rb_cIO);
8276 return rb_io_s_open(argc, argv,
rb_cFile);
8290 return rb_io_open_generic(io, filename, oflags, fmode, &convconfig, perm);
8294rb_io_open_generic(
VALUE klass,
VALUE filename,
int oflags,
int fmode,
8298 if (klass ==
rb_cIO && !
NIL_P(cmd = check_pipe_command(filename))) {
8300 rb_warn_deprecated_to_remove_at(4.0,
"IO process creation with a leading '|'",
"IO.popen");
8301 return pipe_open_s(cmd, rb_io_oflags_modestr(oflags), fmode, convconfig);
8304 return rb_file_open_generic(io_alloc(klass), filename,
8305 oflags, fmode, convconfig, perm);
8312 rb_io_t *fptr, *orig;
8320 if (fptr == orig)
return io;
8321 if (RUBY_IO_EXTERNAL_P(fptr)) {
8325 rb_raise(rb_eArgError,
8326 "%s can't change access mode from \"%s\" to \"%s\"",
8327 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->
mode),
8328 rb_io_fmode_modestr(orig->
mode));
8332 if (io_fflush(fptr) < 0)
8333 rb_sys_fail_on_write(fptr);
8336 flush_before_seek(fptr);
8339 pos = io_tell(orig);
8342 if (io_fflush(orig) < 0)
8343 rb_sys_fail_on_write(fptr);
8351 else if (!RUBY_IO_EXTERNAL_P(fptr)) fptr->
pathv =
Qnil;
8352 fptr_copy_finalizer(fptr, orig);
8357 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2 || !fptr->stdio_file) {
8360 rb_sys_fail_path(orig->
pathv);
8368 rb_sys_fail_path(orig->
pathv);
8374 if (io_seek(fptr, pos, SEEK_SET) < 0 &&
errno) {
8375 rb_sys_fail_path(fptr->
pathv);
8377 if (io_seek(orig, pos, SEEK_SET) < 0 &&
errno) {
8378 rb_sys_fail_path(orig->
pathv);
8392int rb_freopen(
VALUE fname,
const char *mode, FILE *fp);
8395rb_freopen(
VALUE fname,
const char *mode, FILE *fp)
8397 if (!freopen(RSTRING_PTR(fname), mode, fp)) {
8440rb_io_reopen(
int argc,
VALUE *argv,
VALUE file)
8442 VALUE fname, nmode, opt;
8446 if (
rb_scan_args(argc, argv,
"11:", &fname, &nmode, &opt) == 1) {
8449 return io_reopen(file, tmp);
8455 fptr =
RFILE(file)->fptr;
8465 if (RUBY_IO_EXTERNAL_P(fptr) &&
8468 rb_raise(rb_eArgError,
8469 "%s can't change access mode from \"%s\" to \"%s\"",
8470 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->
mode),
8471 rb_io_fmode_modestr(fmode));
8474 fptr->
encs = convconfig;
8477 oflags = rb_io_fmode_oflags(fptr->
mode);
8480 fptr->
pathv = fname;
8482 fptr->
fd = rb_sysopen(fptr->
pathv, oflags, 0666);
8488 if (io_fflush(fptr) < 0)
8489 rb_sys_fail_on_write(fptr);
8494 int e = rb_freopen(rb_str_encode_ospath(fptr->
pathv),
8495 rb_io_oflags_modestr(oflags),
8497 if (e) rb_syserr_fail_path(e, fptr->
pathv);
8501 if (setvbuf(fptr->
stdio_file, NULL, _IOFBF, 0) != 0)
8502 rb_warn(
"setvbuf() can't be honoured for %"PRIsVALUE, fptr->
pathv);
8505 if (setvbuf(fptr->
stdio_file, NULL, _IONBF, BUFSIZ) != 0)
8506 rb_warn(
"setvbuf() can't be honoured for %"PRIsVALUE, fptr->
pathv);
8508 else if (fptr->
stdio_file == stdout && isatty(fptr->
fd)) {
8509 if (setvbuf(fptr->
stdio_file, NULL, _IOLBF, BUFSIZ) != 0)
8510 rb_warn(
"setvbuf() can't be honoured for %"PRIsVALUE, fptr->
pathv);
8514 int tmpfd = rb_sysopen(fptr->
pathv, oflags, 0666);
8520 rb_syserr_fail_path(err, fptr->
pathv);
8531 rb_io_t *fptr, *orig;
8550 fptr_copy_finalizer(fptr, orig);
8552 fd = ruby_dup(orig->
fd);
8554 pos = io_tell(orig);
8556 io_seek(fptr, pos, SEEK_SET);
8561 write_io = GetWriteIO(io);
8562 if (io != write_io) {
8565 rb_ivar_set(dest, rb_intern(
"@tied_io_for_writing"), write_io);
8628 if (argc == 0)
return Qnil;
8629 if (RB_TYPE_P(argv[0],
T_STRING)) {
8630 out = rb_ractor_stdout();
8647 rb_warn_deprecated(
"`%s'", NULL, rb_id2name(
id));
8720 if (argc > 1 && !
NIL_P(rb_output_fs)) {
8723 for (i=0; i<argc; i++) {
8724 if (!
NIL_P(rb_output_fs) && i>0) {
8725 rb_io_write(out, rb_output_fs);
8727 rb_io_write(out, argv[i]);
8824 rb_io_write(io, str);
8828#define forward(obj, id, argc, argv) \
8829 rb_funcallv_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8830#define forward_public(obj, id, argc, argv) \
8831 rb_funcallv_public_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8832#define forward_current(id, argc, argv) \
8833 forward_public(ARGF.current_file, id, argc, argv)
8850 VALUE r_stdout = rb_ractor_stdout();
8851 if (recv == r_stdout) {
8852 return rb_io_putc(recv, ch);
8854 return forward(r_stdout, rb_intern(
"putc"), 1, &ch);
8859rb_str_end_with_asciichar(
VALUE str,
int c)
8861 long len = RSTRING_LEN(str);
8862 const char *ptr = RSTRING_PTR(str);
8866 if (
len == 0)
return 0;
8868 return ptr[
len - 1] == c;
8870 return rb_enc_ascget(ptr + ((
len - 1) / n) * n, ptr +
len, &n,
enc) == c;
8881 rb_io_puts(1, &tmp, out);
8884 ary = rb_check_array_type(ary);
8888 rb_io_puts(1, &tmp, out);
8943 VALUE line, args[2];
8947 rb_io_write(out, rb_default_rs);
8950 for (
int i = 0; i < argc; i++) {
8952 if (RB_TYPE_P(argv[i],
T_STRING)) {
8959 line = rb_obj_as_string(argv[i]);
8964 if (RSTRING_LEN(line) == 0) {
8965 args[n++] = rb_default_rs;
8969 if (!rb_str_end_with_asciichar(line,
'\n')) {
8970 args[n++] = rb_default_rs;
8974 rb_io_writev(out, n, args);
8992 VALUE r_stdout = rb_ractor_stdout();
8993 if (recv == r_stdout) {
8994 return rb_io_puts(argc, argv, recv);
8996 return forward(r_stdout, rb_intern(
"puts"), argc, argv);
9000rb_p_write(
VALUE str)
9004 args[1] = rb_default_rs;
9005 VALUE r_stdout = rb_ractor_stdout();
9006 if (RB_TYPE_P(r_stdout,
T_FILE) &&
9007 rb_method_basic_definition_p(
CLASS_OF(r_stdout), id_write)) {
9008 io_writev(2, args, r_stdout);
9011 rb_io_writev(r_stdout, 2, args);
9019 rb_p_write(rb_obj_as_string(
rb_inspect(obj)));
9023rb_p_result(
int argc,
const VALUE *argv)
9030 else if (argc > 1) {
9033 VALUE r_stdout = rb_ractor_stdout();
9034 if (RB_TYPE_P(r_stdout,
T_FILE)) {
9035 rb_uninterruptible(rb_io_flush, r_stdout);
9076 for (i=0; i<argc; i++) {
9078 rb_uninterruptible(rb_p_write, inspected);
9080 return rb_p_result(argc, argv);
9101rb_obj_display(
int argc,
VALUE *argv,
VALUE self)
9105 out = (!
rb_check_arity(argc, 0, 1) ? rb_ractor_stdout() : argv[0]);
9106 rb_io_write(out, self);
9112rb_stderr_to_original_p(
VALUE err)
9114 return (err == orig_stderr ||
RFILE(orig_stderr)->fptr->
fd < 0);
9120 VALUE out = rb_ractor_stderr();
9121 if (rb_stderr_to_original_p(out)) {
9123 if (isatty(fileno(stderr))) {
9124 if (rb_w32_write_console(
rb_str_new(mesg,
len), fileno(stderr)) > 0)
return;
9127 if (fwrite(mesg,
sizeof(
char), (
size_t)
len, stderr) < (
size_t)
len) {
9144rb_write_error_str(
VALUE mesg)
9146 VALUE out = rb_ractor_stderr();
9148 if (rb_stderr_to_original_p(out)) {
9149 size_t len = (size_t)RSTRING_LEN(mesg);
9151 if (isatty(fileno(stderr))) {
9152 if (rb_w32_write_console(mesg, fileno(stderr)) > 0)
return;
9155 if (fwrite(RSTRING_PTR(mesg),
sizeof(
char),
len, stderr) <
len) {
9162 rb_io_write(out, mesg);
9167rb_stderr_tty_p(
void)
9169 if (rb_stderr_to_original_p(rb_ractor_stderr()))
9170 return isatty(fileno(stderr));
9175must_respond_to(
ID mid,
VALUE val,
ID id)
9178 rb_raise(
rb_eTypeError,
"%"PRIsVALUE
" must have %"PRIsVALUE
" method, %"PRIsVALUE
" given",
9179 rb_id2str(
id), rb_id2str(mid),
9191stdin_getter(
ID id,
VALUE *ptr)
9199 must_respond_to(id_write, val,
id);
9204stdout_getter(
ID id,
VALUE *ptr)
9206 return rb_ractor_stdout();
9212 must_respond_to(id_write, val,
id);
9217stderr_getter(
ID id,
VALUE *ptr)
9219 return rb_ractor_stderr();
9223allocate_and_open_new_file(
VALUE klass)
9225 VALUE self = io_alloc(klass);
9226 rb_io_make_open_file(self);
9234 VALUE self = rb_protect(allocate_and_open_new_file, klass, &state);
9242 maygvl_close(descriptor, 0);
9248 rb_io_t *io =
RFILE(self)->fptr;
9250 io->
fd = descriptor;
9262 io->
pathv = rb_str_new_frozen(path);
9268 io->
encs = *encoding;
9277prep_io(
int fd,
int fmode,
VALUE klass,
const char *path)
9285 rb_io_t*io =
RFILE(self)->fptr;
9287 if (!io_check_tty(io)) {
9290 setmode(fd, O_BINARY);
9302 if (path && strcmp(path,
"-")) klass =
rb_cFile;
9307prep_stdio(FILE *f,
int fmode,
VALUE klass,
const char *path)
9314#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9315 fptr->
encs.
ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
9326rb_io_prep_stdin(
void)
9332rb_io_prep_stdout(
void)
9338rb_io_prep_stderr(
void)
9347 int oflags = rb_io_fmode_oflags(fptr->
mode) & ~O_EXCL;
9362static inline rb_io_t *
9365 rb_io_t *fp =
ALLOC(rb_io_t);
9374 rb_io_buffer_init(&fp->
wbuf);
9375 rb_io_buffer_init(&fp->
rbuf);
9376 rb_io_buffer_init(&fp->
cbuf);
9394rb_io_make_open_file(
VALUE obj)
9399 if (
RFILE(obj)->fptr) {
9401 rb_io_fptr_finalize(
RFILE(obj)->fptr);
9402 RFILE(obj)->fptr = 0;
9404 fp = rb_io_fptr_new();
9406 RFILE(obj)->fptr = fp;
9452rb_io_initialize(
int argc,
VALUE *argv,
VALUE io)
9456 int fd, fmode, oflags = O_RDONLY;
9459#if defined(HAVE_FCNTL) && defined(F_GETFL)
9466 argc =
rb_scan_args(argc, argv,
"11:", &fnum, &vmode, &opt);
9471 rb_raise(rb_eArgError,
"The given fd is not accessible because RubyVM reserves it");
9473#if defined(HAVE_FCNTL) && defined(F_GETFL)
9474 oflags = fcntl(fd, F_GETFL);
9475 if (oflags == -1) rb_sys_fail(0);
9477 if (fstat(fd, &st) < 0) rb_sys_fail(0);
9480#if defined(HAVE_FCNTL) && defined(F_GETFL)
9493 if (rb_hash_aref(opt, sym_autoclose) ==
Qfalse) {
9497 path = rb_hash_aref(opt,
RB_ID2SYM(idPath));
9500 path = rb_str_new_frozen(path);
9508 fp->
encs = convconfig;
9513 if (fileno(stdin) == fd)
9515 else if (fileno(stdout) == fd)
9517 else if (fileno(stderr) == fd)
9549rb_io_set_encoding_by_bom(
VALUE io)
9555 rb_raise(rb_eArgError,
"ASCII incompatible encoding needs binmode");
9558 rb_raise(rb_eArgError,
"encoding conversion is set");
9560 else if (fptr->
encs.
enc && fptr->
encs.
enc != rb_ascii8bit_encoding()) {
9561 rb_raise(rb_eArgError,
"encoding is set to %s already",
9564 if (!io_set_encoding_by_bom(io))
return Qnil;
9565 return rb_enc_from_encoding(fptr->
encs.
enc);
9610rb_file_initialize(
int argc,
VALUE *argv,
VALUE io)
9612 if (
RFILE(io)->fptr) {
9615 if (0 < argc && argc < 3) {
9620 return rb_io_initialize(argc, argv, io);
9623 rb_open_file(argc, argv, io);
9630rb_io_s_new(
int argc,
VALUE *argv,
VALUE klass)
9633 VALUE cname = rb_obj_as_string(klass);
9635 rb_warn(
"%"PRIsVALUE
"::new() does not take block; use %"PRIsVALUE
"::open() instead",
9651rb_io_s_for_fd(
int argc,
VALUE *argv,
VALUE klass)
9654 rb_io_initialize(argc, argv, io);
9667rb_io_autoclose_p(
VALUE io)
9669 rb_io_t *fptr =
RFILE(io)->fptr;
9692rb_io_set_autoclose(
VALUE io,
VALUE autoclose)
9696 if (!
RTEST(autoclose))
9704io_wait_event(
VALUE io,
int event,
VALUE timeout,
int return_io)
9736io_wait_readable(
int argc,
VALUE *argv,
VALUE io)
9746 VALUE timeout = (argc == 1 ? argv[0] :
Qnil);
9760io_wait_writable(
int argc,
VALUE *argv,
VALUE io)
9768 VALUE timeout = (argc == 1 ? argv[0] :
Qnil);
9783io_wait_priority(
int argc,
VALUE *argv,
VALUE io)
9785 rb_io_t *fptr = NULL;
9793 VALUE timeout = argc == 1 ? argv[0] :
Qnil;
9799wait_mode_sym(
VALUE mode)
9801 if (mode ==
ID2SYM(rb_intern(
"r"))) {
9802 return RB_WAITFD_IN;
9804 if (mode ==
ID2SYM(rb_intern(
"read"))) {
9805 return RB_WAITFD_IN;
9807 if (mode ==
ID2SYM(rb_intern(
"readable"))) {
9808 return RB_WAITFD_IN;
9810 if (mode ==
ID2SYM(rb_intern(
"w"))) {
9811 return RB_WAITFD_OUT;
9813 if (mode ==
ID2SYM(rb_intern(
"write"))) {
9814 return RB_WAITFD_OUT;
9816 if (mode ==
ID2SYM(rb_intern(
"writable"))) {
9817 return RB_WAITFD_OUT;
9819 if (mode ==
ID2SYM(rb_intern(
"rw"))) {
9820 return RB_WAITFD_IN|RB_WAITFD_OUT;
9822 if (mode ==
ID2SYM(rb_intern(
"read_write"))) {
9823 return RB_WAITFD_IN|RB_WAITFD_OUT;
9825 if (mode ==
ID2SYM(rb_intern(
"readable_writable"))) {
9826 return RB_WAITFD_IN|RB_WAITFD_OUT;
9829 rb_raise(rb_eArgError,
"unsupported mode: %"PRIsVALUE, mode);
9833io_event_from_value(
VALUE value)
9837 if (events <= 0) rb_raise(rb_eArgError,
"Events must be positive integer!");
9875 for (
int i = 0; i < argc; i += 1) {
9877 events |= wait_mode_sym(argv[i]);
9879 else if (UNDEF_P(timeout)) {
9883 rb_raise(rb_eArgError,
"timeout given more than once");
9887 if (UNDEF_P(timeout)) timeout =
Qnil;
9895 events = io_event_from_value(argv[0]);
9900 rb_io_t *fptr = NULL;
9905 if (return_io)
return Qtrue;
9911 return io_wait_event(io, events, timeout, return_io);
9917 struct argf *p = ptr;
9918 rb_gc_mark(p->filename);
9919 rb_gc_mark(p->current_file);
9920 rb_gc_mark(p->argv);
9921 rb_gc_mark(p->inplace);
9922 rb_gc_mark(p->encs.
ecopts);
9926argf_memsize(
const void *ptr)
9928 const struct argf *p = ptr;
9929 size_t size =
sizeof(*p);
9936 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
9943 p->current_file =
Qnil;
9949argf_alloc(
VALUE klass)
9964 memset(&ARGF, 0,
sizeof(ARGF));
9965 argf_init(&ARGF, argv);
9975 ARGF = argf_of(orig);
10002 ARGF.last_lineno = ARGF.lineno;
10028 return forward_current(rb_frame_this_func(), argc, argv);
10031#define next_argv() argf_next_argv(argf)
10032#define ARGF_GENERIC_INPUT_P() \
10033 (ARGF.current_file == rb_stdin && !RB_TYPE_P(ARGF.current_file, T_FILE))
10034#define ARGF_FORWARD(argc, argv) do {\
10035 if (ARGF_GENERIC_INPUT_P())\
10036 return argf_forward((argc), (argv), argf);\
10038#define NEXT_ARGF_FORWARD(argc, argv) do {\
10039 if (!next_argv()) return Qnil;\
10040 ARGF_FORWARD((argc), (argv));\
10046 VALUE file = ARGF.current_file;
10048 if (RB_TYPE_P(file,
T_FILE)) {
10060 int stdout_binmode = 0;
10063 VALUE r_stdout = rb_ractor_stdout();
10065 if (RB_TYPE_P(r_stdout,
T_FILE)) {
10068 stdout_binmode = 1;
10071 if (ARGF.init_p == 0) {
10081 if (
NIL_P(ARGF.argv)) {
10084 else if (ARGF.next_p == -1 &&
RARRAY_LEN(ARGF.argv) > 0) {
10089 if (ARGF.next_p == 1) {
10090 if (ARGF.init_p == 1) argf_close(
argf);
10093 VALUE filename = rb_ary_shift(ARGF.argv);
10095 ARGF.filename = filename;
10096 filename = rb_str_encode_ospath(filename);
10098 if (RSTRING_LEN(filename) == 1 && fn[0] ==
'-') {
10100 if (ARGF.inplace) {
10101 rb_warn(
"Can't do inplace edit for stdio; skipping");
10107 int fr = rb_sysopen(filename, O_RDONLY, 0);
10109 if (ARGF.inplace) {
10111#ifndef NO_SAFE_RENAME
10117 if (RB_TYPE_P(r_stdout,
T_FILE) && r_stdout != orig_stdout) {
10122 if (!
NIL_P(ARGF.inplace)) {
10123 VALUE suffix = ARGF.inplace;
10124 str = rb_str_dup(str);
10125 if (
NIL_P(rb_str_cat_conv_enc_opts(str, RSTRING_LEN(str),
10126 RSTRING_PTR(suffix), RSTRING_LEN(suffix),
10127 rb_enc_get(suffix), 0,
Qnil))) {
10130#ifdef NO_SAFE_RENAME
10132 (void)unlink(RSTRING_PTR(str));
10133 if (rename(fn, RSTRING_PTR(str)) < 0) {
10134 rb_warn(
"Can't rename %"PRIsVALUE
" to %"PRIsVALUE
": %s, skipping file",
10135 filename, str, strerror(
errno));
10138 fr = rb_sysopen(str, O_RDONLY, 0);
10140 if (rename(fn, RSTRING_PTR(str)) < 0) {
10141 rb_warn(
"Can't rename %"PRIsVALUE
" to %"PRIsVALUE
": %s, skipping file",
10142 filename, str, strerror(
errno));
10149#ifdef NO_SAFE_RENAME
10150 rb_fatal(
"Can't do inplace edit without backup");
10152 if (unlink(fn) < 0) {
10153 rb_warn(
"Can't remove %"PRIsVALUE
": %s, skipping file",
10154 filename, strerror(
errno));
10160 fw = rb_sysopen(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666);
10161#ifndef NO_SAFE_RENAME
10164 fchmod(fw, st.st_mode);
10166 chmod(fn, st.st_mode);
10168 if (st.st_uid!=st2.st_uid || st.st_gid!=st2.st_gid) {
10171 err = fchown(fw, st.st_uid, st.st_gid);
10173 err = chown(fn, st.st_uid, st.st_gid);
10175 if (err && getuid() == 0 && st2.st_uid == 0) {
10176 const char *wkfn = RSTRING_PTR(filename);
10177 rb_warn(
"Can't set owner/group of %"PRIsVALUE
" to same as %"PRIsVALUE
": %s, skipping file",
10178 filename, str, strerror(
errno));
10181 (void)unlink(wkfn);
10191 if (!ARGF.binmode) {
10192 fmode |= DEFAULT_TEXTMODE;
10194 ARGF.current_file = prep_io(fr, fmode,
rb_cFile, fn);
10195 if (!
NIL_P(write_io)) {
10202 if (ARGF.encs.enc) {
10203 fptr->
encs = ARGF.encs;
10204 clear_codeconv(fptr);
10208 if (!ARGF.binmode) {
10210#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
10211 fptr->
encs.
ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
10222 else if (ARGF.next_p == -1) {
10225 if (ARGF.inplace) {
10226 rb_warn(
"Can't do inplace edit for stdio");
10230 if (ARGF.init_p == -1) ARGF.init_p = 1;
10238 long lineno = ARGF.lineno;
10241 if (!next_argv())
return Qnil;
10242 if (ARGF_GENERIC_INPUT_P()) {
10243 line = forward_current(idGets, argc, argv);
10246 if (argc == 0 && rb_rs == rb_default_rs) {
10250 line = rb_io_getline(argc, argv, ARGF.current_file);
10252 if (
NIL_P(line) && ARGF.next_p != -1) {
10258 if (!
NIL_P(line)) {
10259 ARGF.lineno = ++lineno;
10260 ARGF.last_lineno = ARGF.lineno;
10266argf_lineno_getter(
ID id,
VALUE *var)
10269 return INT2FIX(ARGF.last_lineno);
10277 ARGF.last_lineno = ARGF.lineno = n;
10281rb_reset_argf_lineno(
long n)
10283 ARGF.last_lineno = ARGF.lineno = n;
10324 if (recv ==
argf) {
10325 return argf_gets(argc, argv,
argf);
10327 return forward(
argf, idGets, argc, argv);
10353 line = argf_getline(argc, argv,
argf);
10364 if (rb_rs != rb_default_rs) {
10365 return rb_f_gets(0, 0,
argf);
10369 if (!next_argv())
return Qnil;
10371 if (
NIL_P(line) && ARGF.next_p != -1) {
10377 if (!
NIL_P(line)) {
10379 ARGF.last_lineno = ARGF.lineno;
10405rb_f_readline(
int argc,
VALUE *argv,
VALUE recv)
10407 if (recv ==
argf) {
10408 return argf_readline(argc, argv,
argf);
10410 return forward(
argf, rb_intern(
"readline"), argc, argv);
10437 ARGF_FORWARD(argc, argv);
10438 line = argf_gets(argc, argv,
argf);
10507rb_f_readlines(
int argc,
VALUE *argv,
VALUE recv)
10509 if (recv ==
argf) {
10510 return argf_readlines(argc, argv,
argf);
10512 return forward(
argf, rb_intern(
"readlines"), argc, argv);
10536 long lineno = ARGF.lineno;
10539 ary = rb_ary_new();
10540 while (next_argv()) {
10541 if (ARGF_GENERIC_INPUT_P()) {
10542 lines = forward_current(rb_intern(
"readlines"), argc, argv);
10545 lines = rb_io_readlines(argc, argv, ARGF.current_file);
10549 rb_ary_concat(ary, lines);
10551 ARGF.last_lineno = ARGF.lineno;
10586 rb_last_status_clear();
10587 port = pipe_open_s(str,
"r",
FMODE_READABLE|DEFAULT_TEXTMODE, NULL);
10591 result = read_all(fptr, remain_size(fptr),
Qnil);
10593 rb_io_fptr_cleanup_all(fptr);
10599#ifdef HAVE_SYS_SELECT_H
10600#include <sys/select.h>
10614 if (!
NIL_P(read)) {
10619 if (READ_DATA_PENDING(fptr) || READ_CHAR_PENDING(fptr)) {
10623 if (max < fptr->fd) max = fptr->
fd;
10626 timerec.tv_sec = timerec.tv_usec = 0;
10634 if (!
NIL_P(write)) {
10640 if (max < fptr->fd) max = fptr->
fd;
10647 if (!
NIL_P(except)) {
10651 VALUE write_io = GetWriteIO(io);
10654 if (max < fptr->fd) max = fptr->
fd;
10655 if (io != write_io) {
10658 if (max < fptr->fd) max = fptr->
fd;
10673 if (!pending && n == 0)
return Qnil;
10676 rb_ary_push(res, rp?rb_ary_new():
rb_ary_new2(0));
10677 rb_ary_push(res, wp?rb_ary_new():
rb_ary_new2(0));
10678 rb_ary_push(res, ep?rb_ary_new():
rb_ary_new2(0));
10683 VALUE obj = rb_ary_entry(read, i);
10688 rb_ary_push(list, obj);
10696 VALUE obj = rb_ary_entry(write, i);
10698 VALUE write_io = GetWriteIO(io);
10701 rb_ary_push(list, obj);
10709 VALUE obj = rb_ary_entry(except, i);
10711 VALUE write_io = GetWriteIO(io);
10714 rb_ary_push(list, obj);
10716 else if (io != write_io) {
10719 rb_ary_push(list, obj);
10729 VALUE read, write, except;
10735select_call(
VALUE arg)
10739 return select_internal(p->read, p->write, p->except, p->timeout, p->fdsets);
10743select_end(
VALUE arg)
10748 for (i = 0; i < numberof(p->fdsets); ++i)
10753static VALUE sym_normal, sym_sequential, sym_random,
10754 sym_willneed, sym_dontneed, sym_noreuse;
10756#ifdef HAVE_POSIX_FADVISE
10757struct io_advise_struct {
10765io_advise_internal(
void *arg)
10767 struct io_advise_struct *ptr = arg;
10768 return posix_fadvise(ptr->fd, ptr->offset, ptr->len, ptr->advice);
10772io_advise_sym_to_const(
VALUE sym)
10774#ifdef POSIX_FADV_NORMAL
10775 if (sym == sym_normal)
10776 return INT2NUM(POSIX_FADV_NORMAL);
10779#ifdef POSIX_FADV_RANDOM
10780 if (sym == sym_random)
10781 return INT2NUM(POSIX_FADV_RANDOM);
10784#ifdef POSIX_FADV_SEQUENTIAL
10785 if (sym == sym_sequential)
10786 return INT2NUM(POSIX_FADV_SEQUENTIAL);
10789#ifdef POSIX_FADV_WILLNEED
10790 if (sym == sym_willneed)
10791 return INT2NUM(POSIX_FADV_WILLNEED);
10794#ifdef POSIX_FADV_DONTNEED
10795 if (sym == sym_dontneed)
10796 return INT2NUM(POSIX_FADV_DONTNEED);
10799#ifdef POSIX_FADV_NOREUSE
10800 if (sym == sym_noreuse)
10801 return INT2NUM(POSIX_FADV_NOREUSE);
10808do_io_advise(rb_io_t *fptr,
VALUE advice, rb_off_t offset, rb_off_t
len)
10811 struct io_advise_struct ias;
10814 num_adv = io_advise_sym_to_const(advice);
10820 if (
NIL_P(num_adv))
10824 ias.advice =
NUM2INT(num_adv);
10825 ias.offset = offset;
10828 rv = (int)rb_thread_io_blocking_region(io_advise_internal, &ias, fptr->
fd);
10829 if (rv && rv != ENOSYS) {
10832 VALUE message = rb_sprintf(
"%"PRIsVALUE
" "
10836 fptr->
pathv, offset,
len, advice);
10846advice_arg_check(
VALUE advice)
10851 if (advice != sym_normal &&
10852 advice != sym_sequential &&
10853 advice != sym_random &&
10854 advice != sym_willneed &&
10855 advice != sym_dontneed &&
10856 advice != sym_noreuse) {
10857 rb_raise(
rb_eNotImpError,
"Unsupported advice: %+"PRIsVALUE, advice);
10895rb_io_advise(
int argc,
VALUE *argv,
VALUE io)
10902 advice_arg_check(advice);
10904 io = GetWriteIO(io);
10910#ifdef HAVE_POSIX_FADVISE
10911 return do_io_advise(fptr, advice,
off, l);
10913 ((void)
off, (void)l);
11068rb_f_select(
int argc,
VALUE *argv,
VALUE obj)
11071 if (scheduler !=
Qnil) {
11074 if (!UNDEF_P(result))
return result;
11082 rb_scan_args(argc, argv,
"13", &args.read, &args.write, &args.except, &timeout);
11083 if (
NIL_P(timeout)) {
11088 args.timeout = &timerec;
11091 for (i = 0; i < numberof(args.fdsets); ++i)
11097#ifdef IOCTL_REQ_TYPE
11098 typedef IOCTL_REQ_TYPE ioctl_req_t;
11100 typedef int ioctl_req_t;
11101# define NUM2IOCTLREQ(num) ((int)NUM2LONG(num))
11112nogvl_ioctl(
void *ptr)
11114 struct ioctl_arg *arg = ptr;
11116 return (
VALUE)ioctl(arg->fd, arg->cmd, arg->narg);
11120do_ioctl(
int fd, ioctl_req_t cmd,
long narg)
11123 struct ioctl_arg arg;
11129 retval = (int)rb_thread_io_blocking_region(nogvl_ioctl, &arg, fd);
11135#define DEFAULT_IOCTL_NARG_LEN (256)
11137#if defined(__linux__) && defined(_IOC_SIZE)
11139linux_iocparm_len(ioctl_req_t cmd)
11143 if ((cmd & 0xFFFF0000) == 0) {
11145 return DEFAULT_IOCTL_NARG_LEN;
11148 len = _IOC_SIZE(cmd);
11151 if (
len < DEFAULT_IOCTL_NARG_LEN)
11152 len = DEFAULT_IOCTL_NARG_LEN;
11160ioctl_narg_len(ioctl_req_t cmd)
11166#define IOCPARM_LEN(x) (((x) >> 16) & IOCPARM_MASK)
11170 len = IOCPARM_LEN(cmd);
11171#elif defined(__linux__) && defined(_IOC_SIZE)
11172 len = linux_iocparm_len(cmd);
11175 len = DEFAULT_IOCTL_NARG_LEN;
11184typedef long fcntl_arg_t;
11187typedef int fcntl_arg_t;
11191fcntl_narg_len(ioctl_req_t cmd)
11198 len =
sizeof(fcntl_arg_t);
11206#ifdef F_DUPFD_CLOEXEC
11207 case F_DUPFD_CLOEXEC:
11208 len =
sizeof(fcntl_arg_t);
11218 len =
sizeof(fcntl_arg_t);
11228 len =
sizeof(fcntl_arg_t);
11238 len =
sizeof(fcntl_arg_t);
11243 len =
sizeof(
struct f_owner_ex);
11248 len =
sizeof(
struct f_owner_ex);
11253 len =
sizeof(
struct flock);
11258 len =
sizeof(
struct flock);
11263 len =
sizeof(
struct flock);
11283 len =
sizeof(fcntl_arg_t);
11293 len =
sizeof(fcntl_arg_t);
11298 len =
sizeof(fcntl_arg_t);
11311fcntl_narg_len(ioctl_req_t cmd)
11317#define NARG_SENTINEL 17
11320setup_narg(ioctl_req_t cmd,
VALUE *argp,
long (*narg_len)(ioctl_req_t))
11331 else if (arg ==
Qtrue) {
11345 len = narg_len(cmd);
11346 rb_str_modify(arg);
11348 slen = RSTRING_LEN(arg);
11350 if (slen <
len+1) {
11351 rb_str_resize(arg,
len+1);
11352 MEMZERO(RSTRING_PTR(arg)+slen,
char,
len-slen);
11356 ptr = RSTRING_PTR(arg);
11357 ptr[slen - 1] = NARG_SENTINEL;
11366finish_narg(
int retval,
VALUE arg,
const rb_io_t *fptr)
11368 if (retval < 0) rb_sys_fail_path(fptr->
pathv);
11373 if (ptr[slen-1] != NARG_SENTINEL)
11374 rb_raise(rb_eArgError,
"return value overflowed string");
11375 ptr[slen-1] =
'\0';
11385 ioctl_req_t cmd = NUM2IOCTLREQ(req);
11390 narg = setup_narg(cmd, &arg, ioctl_narg_len);
11392 retval = do_ioctl(fptr->
fd, cmd, narg);
11393 return finish_narg(retval, arg, fptr);
11420 return rb_ioctl(io, req, arg);
11423#define rb_io_ioctl rb_f_notimplement
11434nogvl_fcntl(
void *ptr)
11436 struct fcntl_arg *arg = ptr;
11438#if defined(F_DUPFD)
11439 if (arg->cmd == F_DUPFD)
11442 return (
VALUE)fcntl(arg->fd, arg->cmd, arg->narg);
11446do_fcntl(
int fd,
int cmd,
long narg)
11449 struct fcntl_arg arg;
11455 retval = (int)rb_thread_io_blocking_region(nogvl_fcntl, &arg, fd);
11456 if (retval != -1) {
11458#if defined(F_DUPFD)
11461#if defined(F_DUPFD_CLOEXEC)
11462 case F_DUPFD_CLOEXEC:
11479 narg = setup_narg(cmd, &arg, fcntl_narg_len);
11481 retval = do_fcntl(fptr->
fd, cmd, narg);
11482 return finish_narg(retval, arg, fptr);
11508 return rb_fcntl(io, req, arg);
11511#define rb_io_fcntl rb_f_notimplement
11514#if defined(HAVE_SYSCALL) || defined(HAVE___SYSCALL)
11546#if SIZEOF_VOIDP == 8 && defined(HAVE___SYSCALL) && SIZEOF_INT != 8
11547# define SYSCALL __syscall
11548# define NUM2SYSCALLID(x) NUM2LONG(x)
11549# define RETVAL2NUM(x) LONG2NUM(x)
11550# if SIZEOF_LONG == 8
11551 long num, retval = -1;
11552# elif SIZEOF_LONG_LONG == 8
11553 long long num, retval = -1;
11555# error ---->> it is asserted that __syscall takes the first argument and returns retval in 64bit signed integer. <<----
11557#elif defined(__linux__)
11558# define SYSCALL syscall
11559# define NUM2SYSCALLID(x) NUM2LONG(x)
11560# define RETVAL2NUM(x) LONG2NUM(x)
11568 long num, retval = -1;
11570# define SYSCALL syscall
11571# define NUM2SYSCALLID(x) NUM2INT(x)
11572# define RETVAL2NUM(x) INT2NUM(x)
11573 int num, retval = -1;
11579 "We plan to remove a syscall function at future release. DL(Fiddle) provides safer alternative.");
11583 rb_raise(rb_eArgError,
"too few arguments for syscall");
11584 if (argc > numberof(arg))
11585 rb_raise(rb_eArgError,
"too many arguments for syscall");
11586 num = NUM2SYSCALLID(argv[0]); ++argv;
11587 for (i = argc - 1; i--; ) {
11602 retval = SYSCALL(num);
11605 retval = SYSCALL(num, arg[0]);
11608 retval = SYSCALL(num, arg[0],arg[1]);
11611 retval = SYSCALL(num, arg[0],arg[1],arg[2]);
11614 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3]);
11617 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4]);
11620 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5]);
11623 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6]);
11629 return RETVAL2NUM(retval);
11631#undef NUM2SYSCALLID
11635#define rb_f_syscall rb_f_notimplement
11639io_new_instance(
VALUE args)
11644static rb_encoding *
11645find_encoding(
VALUE v)
11647 rb_encoding *enc = rb_find_encoding(v);
11648 if (!enc)
rb_warn(
"Unsupported encoding %"PRIsVALUE
" ignored", v);
11655 rb_encoding *enc, *enc2;
11660 enc2 = find_encoding(v1);
11663 if (RSTRING_LEN(tmp) == 1 && RSTRING_PTR(tmp)[0] ==
'-') {
11669 enc = find_encoding(v2);
11676 enc = find_encoding(v2);
11682 if (enc2 == rb_ascii8bit_encoding()) {
11687 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11693 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
11694 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11699 if (!
NIL_P(tmp) && rb_enc_asciicompat(enc = rb_enc_get(tmp))) {
11700 parse_mode_enc(RSTRING_PTR(tmp), enc, &enc, &enc2, NULL);
11701 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11705 rb_io_ext_int_to_encs(find_encoding(v1), NULL, &enc, &enc2, 0);
11706 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11711 validate_enc_binmode(&fptr->
mode, ecflags, enc, enc2);
11716 clear_codeconv(fptr);
11728io_encoding_set_v(
VALUE v)
11731 io_encoding_set(arg->fptr, arg->v1, arg->v2, arg->opt);
11736pipe_pair_close(
VALUE rw)
11739 return rb_ensure(io_close, rwp[0], io_close, rwp[1]);
11822rb_io_s_pipe(
int argc,
VALUE *argv,
VALUE klass)
11824 int pipes[2], state;
11825 VALUE r, w, args[3], v1, v2;
11827 rb_io_t *fptr, *fptr2;
11832 argc =
rb_scan_args(argc, argv,
"02:", &v1, &v2, &opt);
11839 r = rb_protect(io_new_instance, (
VALUE)args, &state);
11843 rb_jump_tag(state);
11847 ies_args.fptr = fptr;
11850 ies_args.opt = opt;
11851 rb_protect(io_encoding_set_v, (
VALUE)&ies_args, &state);
11855 rb_jump_tag(state);
11860 w = rb_protect(io_new_instance, (
VALUE)args, &state);
11864 rb_jump_tag(state);
11869 extract_binmode(opt, &fmode);
11876#if DEFAULT_TEXTMODE
11879 setmode(fptr->
fd, O_BINARY);
11881#if RUBY_CRLF_ENVIRONMENT
11887 fptr->
mode |= fmode;
11888#if DEFAULT_TEXTMODE
11891 setmode(fptr2->
fd, O_BINARY);
11894 fptr2->
mode |= fmode;
11896 ret = rb_assoc_new(r, w);
11928 else if (!
NIL_P(v = rb_hash_aref(opt, sym_open_args))) {
11931 v = rb_to_array_type(v);
11936 arg->io = rb_io_open(klass, path, vmode, vperm, opt);
11940io_s_foreach(
VALUE v)
11945 if (arg->limit == 0)
11946 rb_raise(rb_eArgError,
"invalid limit: 0 for foreach");
11947 while (!
NIL_P(str = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, arg->io))) {
12036rb_io_s_foreach(
int argc,
VALUE *argv,
VALUE self)
12039 int orig_argc = argc;
12043 argc =
rb_scan_args(argc, argv,
"12:", NULL, NULL, NULL, &opt);
12045 extract_getline_args(argc-1, argv+1, &garg);
12046 open_key_args(self, argc, argv, opt, &arg);
12048 extract_getline_opts(opt, &garg);
12049 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12054io_s_readlines(
VALUE v)
12057 return io_readlines(arg, arg->io);
12115rb_io_s_readlines(
int argc,
VALUE *argv,
VALUE io)
12121 argc =
rb_scan_args(argc, argv,
"12:", NULL, NULL, NULL, &opt);
12122 extract_getline_args(argc-1, argv+1, &garg);
12123 open_key_args(io, argc, argv, opt, &arg);
12125 extract_getline_opts(opt, &garg);
12126 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12134 return io_read(arg->argc, arg->argv, arg->io);
12144seek_before_access(
VALUE argp)
12148 return rb_io_seek(arg->io, arg->offset, arg->mode);
12194rb_io_s_read(
int argc,
VALUE *argv,
VALUE io)
12200 argc =
rb_scan_args(argc, argv,
"13:", NULL, NULL, &offset, NULL, &opt);
12202 rb_raise(rb_eArgError,
"negative offset %ld given",
off);
12204 open_key_args(io, argc, argv, opt, &arg);
12206 if (!
NIL_P(offset)) {
12210 sarg.offset = offset;
12211 sarg.mode = SEEK_SET;
12212 rb_protect(seek_before_access, (
VALUE)&sarg, &state);
12215 rb_jump_tag(state);
12217 if (arg.argc == 2) arg.argc = 1;
12236rb_io_s_binread(
int argc,
VALUE *argv,
VALUE io)
12251 convconfig.
enc = rb_ascii8bit_encoding();
12252 arg.io = rb_io_open_generic(io, argv[0], oflags, fmode, &convconfig, 0);
12255 arg.argc = (argc > 1) ? 1 : 0;
12256 if (!
NIL_P(offset)) {
12260 sarg.offset = offset;
12261 sarg.mode = SEEK_SET;
12262 rb_protect(seek_before_access, (
VALUE)&sarg, &state);
12265 rb_jump_tag(state);
12272io_s_write0(
VALUE v)
12275 return io_write(arg->io,arg->str,arg->nosync);
12279io_s_write(
int argc,
VALUE *argv,
VALUE klass,
int binary)
12281 VALUE string, offset, opt;
12285 rb_scan_args(argc, argv,
"21:", NULL, &
string, &offset, &opt);
12287 if (
NIL_P(opt)) opt = rb_hash_new();
12288 else opt = rb_hash_dup(opt);
12291 if (
NIL_P(rb_hash_aref(opt,sym_mode))) {
12292 int mode = O_WRONLY|O_CREAT;
12294 if (binary) mode |= O_BINARY;
12296 if (
NIL_P(offset)) mode |= O_TRUNC;
12297 rb_hash_aset(opt,sym_mode,
INT2NUM(mode));
12299 open_key_args(klass, argc, argv, opt, &arg);
12302 if (binary) rb_io_binmode_m(arg.io);
12306 if (!
NIL_P(offset)) {
12310 sarg.offset = offset;
12311 sarg.mode = SEEK_SET;
12312 rb_protect(seek_before_access, (
VALUE)&sarg, &state);
12315 rb_jump_tag(state);
12371rb_io_s_write(
int argc,
VALUE *argv,
VALUE io)
12373 return io_s_write(argc, argv, io, 0);
12390rb_io_s_binwrite(
int argc,
VALUE *argv,
VALUE io)
12392 return io_s_write(argc, argv, io, 1);
12398 rb_off_t copy_length;
12399 rb_off_t src_offset;
12403 unsigned close_src : 1;
12404 unsigned close_dst : 1;
12407 const char *syserr;
12408 const char *notimp;
12410 struct stat src_stat;
12411 struct stat dst_stat;
12412#ifdef HAVE_FCOPYFILE
12413 copyfile_state_t copyfile_state;
12418exec_interrupts(
void *arg)
12421 rb_thread_execute_interrupts(th);
12435#if defined(ERESTART)
12440 rb_thread_execute_interrupts(stp->th);
12459fiber_scheduler_wait_for(
void * _arguments)
12469# define IOWAIT_SYSCALL "poll"
12470STATIC_ASSERT(pollin_expected, POLLIN == RB_WAITFD_IN);
12471STATIC_ASSERT(pollout_expected, POLLOUT == RB_WAITFD_OUT);
12473nogvl_wait_for(
VALUE th, rb_io_t *fptr,
short events,
struct timeval *timeout)
12476 if (scheduler !=
Qnil) {
12479 return RTEST(args.result);
12483 if (fd == -1)
return 0;
12488 fds.events = events;
12490 int timeout_milliseconds = -1;
12493 timeout_milliseconds = (int)(timeout->tv_sec * 1000) + (int)(timeout->tv_usec / 1000);
12496 return poll(&fds, 1, timeout_milliseconds);
12499# define IOWAIT_SYSCALL "select"
12501nogvl_wait_for(
VALUE th, rb_io_t *fptr,
short events,
struct timeval *timeout)
12504 if (scheduler !=
Qnil) {
12507 return RTEST(args.result);
12527 case RB_WAITFD_OUT:
12531 VM_UNREACHABLE(nogvl_wait_for);
12551 ret = nogvl_wait_for(stp->th, stp->src_fptr, RB_WAITFD_IN, NULL);
12553 }
while (ret < 0 && maygvl_copy_stream_continue_p(has_gvl, stp));
12556 stp->syserr = IOWAIT_SYSCALL;
12557 stp->error_no =
errno;
12569 ret = nogvl_wait_for(stp->th, stp->dst_fptr, RB_WAITFD_OUT, NULL);
12570 }
while (ret < 0 && maygvl_copy_stream_continue_p(0, stp));
12573 stp->syserr = IOWAIT_SYSCALL;
12574 stp->error_no =
errno;
12580#ifdef USE_COPY_FILE_RANGE
12583simple_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)
12585#ifdef HAVE_COPY_FILE_RANGE
12586 return copy_file_range(in_fd, in_offset, out_fd, out_offset, count, flags);
12588 return syscall(__NR_copy_file_range, in_fd, in_offset, out_fd, out_offset, count, flags);
12597 rb_off_t copy_length, src_offset, *src_offset_ptr;
12599 if (!S_ISREG(stp->src_stat.st_mode))
12602 src_size = stp->src_stat.st_size;
12603 src_offset = stp->src_offset;
12604 if (src_offset >= (rb_off_t)0) {
12605 src_offset_ptr = &src_offset;
12608 src_offset_ptr = NULL;
12611 copy_length = stp->copy_length;
12612 if (copy_length < (rb_off_t)0) {
12613 if (src_offset < (rb_off_t)0) {
12614 rb_off_t current_offset;
12616 current_offset = lseek(stp->src_fptr->
fd, 0, SEEK_CUR);
12617 if (current_offset < (rb_off_t)0 &&
errno) {
12618 stp->syserr =
"lseek";
12619 stp->error_no =
errno;
12620 return (
int)current_offset;
12622 copy_length = src_size - current_offset;
12625 copy_length = src_size - src_offset;
12629 retry_copy_file_range:
12630# if SIZEOF_OFF_T > SIZEOF_SIZE_T
12632 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
12634 ss = (ssize_t)copy_length;
12636 ss = simple_copy_file_range(stp->src_fptr->
fd, src_offset_ptr, stp->dst_fptr->
fd, NULL, ss, 0);
12640 if (0 < copy_length) {
12641 goto retry_copy_file_range;
12645 if (maygvl_copy_stream_continue_p(0, stp)) {
12646 goto retry_copy_file_range;
12660#if EWOULDBLOCK != EAGAIN
12664 int ret = nogvl_copy_stream_wait_write(stp);
12665 if (ret < 0)
return ret;
12667 goto retry_copy_file_range;
12671 int flags = fcntl(stp->dst_fptr->
fd, F_GETFL);
12673 if (flags != -1 && flags & O_APPEND) {
12679 stp->syserr =
"copy_file_range";
12680 stp->error_no =
errno;
12687#ifdef HAVE_FCOPYFILE
12691 rb_off_t cur, ss = 0;
12692 const rb_off_t src_offset = stp->src_offset;
12695 if (stp->copy_length >= (rb_off_t)0) {
12700 if (!S_ISREG(stp->src_stat.st_mode))
12703 if (!S_ISREG(stp->dst_stat.st_mode))
12705 if (lseek(stp->dst_fptr->
fd, 0, SEEK_CUR) > (rb_off_t)0)
12707 if (fcntl(stp->dst_fptr->
fd, F_GETFL) & O_APPEND) {
12710 rb_off_t end = lseek(stp->dst_fptr->
fd, 0, SEEK_END);
12711 lseek(stp->dst_fptr->
fd, 0, SEEK_SET);
12712 if (end > (rb_off_t)0)
return 0;
12715 if (src_offset > (rb_off_t)0) {
12720 cur = lseek(stp->src_fptr->
fd, 0, SEEK_CUR);
12721 if (cur < (rb_off_t)0 &&
errno) {
12722 stp->error_no =
errno;
12727 r = lseek(stp->src_fptr->
fd, src_offset, SEEK_SET);
12728 if (r < (rb_off_t)0 &&
errno) {
12729 stp->error_no =
errno;
12734 stp->copyfile_state = copyfile_state_alloc();
12735 ret = fcopyfile(stp->src_fptr->
fd, stp->dst_fptr->
fd, stp->copyfile_state, COPYFILE_DATA);
12736 copyfile_state_get(stp->copyfile_state, COPYFILE_STATE_COPIED, &ss);
12740 if (src_offset > (rb_off_t)0) {
12744 r = lseek(stp->src_fptr->
fd, cur, SEEK_SET);
12745 if (r < (rb_off_t)0 &&
errno) {
12746 stp->error_no =
errno;
12758 stp->syserr =
"fcopyfile";
12759 stp->error_no =
errno;
12766#ifdef HAVE_SENDFILE
12769# define USE_SENDFILE
12771# ifdef HAVE_SYS_SENDFILE_H
12772# include <sys/sendfile.h>
12776simple_sendfile(
int out_fd,
int in_fd, rb_off_t *offset, rb_off_t count)
12778 return sendfile(out_fd, in_fd, offset, (
size_t)count);
12781# elif 0 || defined(__APPLE__)
12785# define USE_SENDFILE
12788simple_sendfile(
int out_fd,
int in_fd, rb_off_t *offset, rb_off_t count)
12791 rb_off_t pos = offset ? *offset : lseek(in_fd, 0, SEEK_CUR);
12794 r = sendfile(in_fd, out_fd, pos, &count, NULL, 0);
12797 r = sendfile(in_fd, out_fd, pos, (
size_t)count, NULL, &sbytes, 0);
12799 if (r != 0 && sbytes == 0)
return r;
12804 lseek(in_fd, sbytes, SEEK_CUR);
12806 return (ssize_t)sbytes;
12819 rb_off_t copy_length;
12820 rb_off_t src_offset;
12823 if (!S_ISREG(stp->src_stat.st_mode))
12826 src_size = stp->src_stat.st_size;
12828 if ((stp->dst_stat.st_mode & S_IFMT) != S_IFSOCK)
12832 src_offset = stp->src_offset;
12833 use_pread = src_offset >= (rb_off_t)0;
12835 copy_length = stp->copy_length;
12836 if (copy_length < (rb_off_t)0) {
12838 copy_length = src_size - src_offset;
12842 cur = lseek(stp->src_fptr->
fd, 0, SEEK_CUR);
12843 if (cur < (rb_off_t)0 &&
errno) {
12844 stp->syserr =
"lseek";
12845 stp->error_no =
errno;
12848 copy_length = src_size - cur;
12853# if SIZEOF_OFF_T > SIZEOF_SIZE_T
12855 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
12857 ss = (ssize_t)copy_length;
12860 ss = simple_sendfile(stp->dst_fptr->
fd, stp->src_fptr->
fd, &src_offset, ss);
12863 ss = simple_sendfile(stp->dst_fptr->
fd, stp->src_fptr->
fd, NULL, ss);
12868 if (0 < copy_length) {
12869 goto retry_sendfile;
12873 if (maygvl_copy_stream_continue_p(0, stp))
12874 goto retry_sendfile;
12887#if EWOULDBLOCK != EAGAIN
12900 ret = maygvl_copy_stream_wait_read(0, stp);
12901 if (ret < 0)
return ret;
12903 ret = nogvl_copy_stream_wait_write(stp);
12904 if (ret < 0)
return ret;
12906 goto retry_sendfile;
12908 stp->syserr =
"sendfile";
12909 stp->error_no =
errno;
12917maygvl_read(
int has_gvl, rb_io_t *fptr,
void *buf,
size_t count)
12920 return rb_io_read_memory(fptr, buf, count);
12922 return read(fptr->
fd, buf, count);
12926maygvl_copy_stream_read(
int has_gvl,
struct copy_stream_struct *stp,
char *buf,
size_t len, rb_off_t offset)
12930 if (offset < (rb_off_t)0) {
12931 ss = maygvl_read(has_gvl, stp->src_fptr, buf,
len);
12934 ss = pread(stp->src_fptr->
fd, buf,
len, offset);
12940 if (maygvl_copy_stream_continue_p(has_gvl, stp))
12944#if EWOULDBLOCK != EAGAIN
12948 int ret = maygvl_copy_stream_wait_read(has_gvl, stp);
12949 if (ret < 0)
return ret;
12954 stp->notimp =
"pread";
12958 stp->syserr = offset < (rb_off_t)0 ?
"read" :
"pread";
12959 stp->error_no =
errno;
12970 ss = write(stp->dst_fptr->
fd, buf+
off,
len);
12972 if (maygvl_copy_stream_continue_p(0, stp))
12974 if (io_again_p(
errno)) {
12975 int ret = nogvl_copy_stream_wait_write(stp);
12976 if (ret < 0)
return ret;
12979 stp->syserr =
"write";
12980 stp->error_no =
errno;
12997 rb_off_t copy_length;
12998 rb_off_t src_offset;
13002 copy_length = stp->copy_length;
13003 use_eof = copy_length < (rb_off_t)0;
13004 src_offset = stp->src_offset;
13005 use_pread = src_offset >= (rb_off_t)0;
13007 if (use_pread && stp->close_src) {
13010 r = lseek(stp->src_fptr->
fd, src_offset, SEEK_SET);
13011 if (r < (rb_off_t)0 &&
errno) {
13012 stp->syserr =
"lseek";
13013 stp->error_no =
errno;
13016 src_offset = (rb_off_t)-1;
13020 while (use_eof || 0 < copy_length) {
13021 if (!use_eof && copy_length < (rb_off_t)
sizeof(buf)) {
13022 len = (size_t)copy_length;
13028 ss = maygvl_copy_stream_read(0, stp, buf,
len, src_offset);
13033 ss = maygvl_copy_stream_read(0, stp, buf,
len, (rb_off_t)-1);
13038 ret = nogvl_copy_stream_write(stp, buf, ss);
13048nogvl_copy_stream_func(
void *arg)
13051#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13055#ifdef USE_COPY_FILE_RANGE
13056 ret = nogvl_copy_file_range(stp);
13061#ifdef HAVE_FCOPYFILE
13062 ret = nogvl_fcopyfile(stp);
13068 ret = nogvl_copy_stream_sendfile(stp);
13073 nogvl_copy_stream_read_write(stp);
13075#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13082copy_stream_fallback_body(
VALUE arg)
13085 const int buflen = 16*1024;
13087 VALUE buf = rb_str_buf_new(buflen);
13088 rb_off_t rest = stp->copy_length;
13089 rb_off_t
off = stp->src_offset;
13090 ID read_method = id_readpartial;
13092 if (!stp->src_fptr) {
13094 read_method = id_read;
13101 if (stp->copy_length < (rb_off_t)0) {
13106 rb_str_resize(buf, 0);
13109 l = buflen < rest ? buflen : (long)rest;
13111 if (!stp->src_fptr) {
13114 if (read_method == id_read &&
NIL_P(rc))
13119 rb_str_resize(buf, buflen);
13120 ss = maygvl_copy_stream_read(1, stp, RSTRING_PTR(buf), l,
off);
13121 rb_str_resize(buf, ss > 0 ? ss : 0);
13126 if (
off >= (rb_off_t)0)
13129 n = rb_io_write(stp->dst, buf);
13131 stp->total += numwrote;
13133 if (read_method == id_read && RSTRING_LEN(buf) == 0) {
13144 if (!stp->src_fptr && stp->src_offset >= (rb_off_t)0) {
13145 rb_raise(rb_eArgError,
"cannot specify src_offset for non-IO");
13154copy_stream_body(
VALUE arg)
13157 VALUE src_io = stp->src, dst_io = stp->dst;
13158 const int common_oflags = 0
13168 if (src_io ==
argf ||
13169 !(RB_TYPE_P(src_io,
T_FILE) ||
13172 stp->src_fptr = NULL;
13177 if (!
NIL_P(tmp_io)) {
13180 else if (!RB_TYPE_P(src_io,
T_FILE)) {
13184 args[1] =
INT2NUM(O_RDONLY|common_oflags);
13187 stp->close_src = 1;
13192 stat_ret = fstat(stp->src_fptr->
fd, &stp->src_stat);
13193 if (stat_ret < 0) {
13194 stp->syserr =
"fstat";
13195 stp->error_no =
errno;
13200 if (dst_io ==
argf ||
13201 !(RB_TYPE_P(dst_io,
T_FILE) ||
13204 stp->dst_fptr = NULL;
13209 if (!
NIL_P(tmp_io)) {
13210 dst_io = GetWriteIO(tmp_io);
13212 else if (!RB_TYPE_P(dst_io,
T_FILE)) {
13216 args[1] =
INT2NUM(O_WRONLY|O_CREAT|O_TRUNC|common_oflags);
13220 stp->close_dst = 1;
13223 dst_io = GetWriteIO(dst_io);
13229 stat_ret = fstat(stp->dst_fptr->
fd, &stp->dst_stat);
13230 if (stat_ret < 0) {
13231 stp->syserr =
"fstat";
13232 stp->error_no =
errno;
13239 SET_BINARY_MODE_WITH_SEEK_CUR(stp->src_fptr);
13242 io_ascii8bit_binmode(stp->dst_fptr);
13244 if (stp->src_offset < (rb_off_t)0 && stp->src_fptr && stp->src_fptr->
rbuf.
len) {
13247 if (stp->copy_length >= (rb_off_t)0 && stp->copy_length < (rb_off_t)
len) {
13248 len = (size_t)stp->copy_length;
13250 str = rb_str_buf_new(
len);
13251 rb_str_resize(str,
len);
13252 read_buffered_data(RSTRING_PTR(str),
len, stp->src_fptr);
13253 if (stp->dst_fptr) {
13254 if (io_binwrite(str, RSTRING_PTR(str), RSTRING_LEN(str), stp->dst_fptr, 0) < 0)
13255 rb_sys_fail_on_write(stp->dst_fptr);
13258 rb_io_write(dst_io, str);
13259 rb_str_resize(str, 0);
13261 if (stp->copy_length >= (rb_off_t)0)
13262 stp->copy_length -=
len;
13265 if (stp->dst_fptr && io_fflush(stp->dst_fptr) < 0) {
13269 if (stp->copy_length == 0)
13272 if (stp->src_fptr == NULL || stp->dst_fptr == NULL) {
13273 return copy_stream_fallback(stp);
13281copy_stream_finalize(
VALUE arg)
13285#ifdef HAVE_FCOPYFILE
13286 if (stp->copyfile_state) {
13287 copyfile_state_free(stp->copyfile_state);
13291 if (stp->close_src) {
13292 rb_io_close_m(stp->src);
13294 if (stp->close_dst) {
13295 rb_io_close_m(stp->dst);
13358rb_io_s_copy_stream(
int argc,
VALUE *argv,
VALUE io)
13360 VALUE src, dst, length, src_offset;
13365 rb_scan_args(argc, argv,
"22", &src, &dst, &length, &src_offset);
13370 st.src_fptr = NULL;
13371 st.dst_fptr = NULL;
13374 st.copy_length = (rb_off_t)-1;
13376 st.copy_length =
NUM2OFFT(length);
13378 if (
NIL_P(src_offset))
13379 st.src_offset = (rb_off_t)-1;
13381 st.src_offset =
NUM2OFFT(src_offset);
13400rb_io_external_encoding(
VALUE io)
13405 return rb_enc_from_encoding(fptr->
encs.
enc2);
13409 return rb_enc_from_encoding(fptr->
encs.
enc);
13412 return rb_enc_from_encoding(io_read_encoding(fptr));
13428rb_io_internal_encoding(
VALUE io)
13433 return rb_enc_from_encoding(io_read_encoding(fptr));
13467rb_io_set_encoding(
int argc,
VALUE *argv,
VALUE io)
13472 if (!RB_TYPE_P(io,
T_FILE)) {
13473 return forward(io, id_set_encoding, argc, argv);
13476 argc =
rb_scan_args(argc, argv,
"11:", &v1, &v2, &opt);
13478 io_encoding_set(fptr, v1, v2, opt);
13483rb_stdio_set_default_encoding(
void)
13488 if (isatty(fileno(stdin))) {
13489 rb_encoding *external = rb_locale_encoding();
13490 rb_encoding *internal = rb_default_internal_encoding();
13491 if (!internal) internal = rb_default_external_encoding();
13493 rb_enc_from_encoding(external),
13494 rb_enc_from_encoding(internal),
13499 rb_io_set_encoding(1, &val,
rb_stdin);
13500 rb_io_set_encoding(1, &val,
rb_stdout);
13501 rb_io_set_encoding(1, &val,
rb_stderr);
13505global_argf_p(
VALUE arg)
13507 return arg ==
argf;
13510typedef VALUE (*argf_encoding_func)(
VALUE io);
13513argf_encoding(
VALUE argf, argf_encoding_func func)
13515 if (!
RTEST(ARGF.current_file)) {
13516 return rb_enc_default_external();
13540 return argf_encoding(
argf, rb_io_external_encoding);
13559 return argf_encoding(
argf, rb_io_internal_encoding);
13598 if (!next_argv()) {
13599 rb_raise(rb_eArgError,
"no stream to set encoding");
13601 rb_io_set_encoding(argc, argv, ARGF.current_file);
13603 ARGF.encs = fptr->
encs;
13622 if (!next_argv()) {
13623 rb_raise(rb_eArgError,
"no stream to tell");
13625 ARGF_FORWARD(0, 0);
13626 return rb_io_tell(ARGF.current_file);
13639 if (!next_argv()) {
13640 rb_raise(rb_eArgError,
"no stream to seek");
13642 ARGF_FORWARD(argc, argv);
13643 return rb_io_seek_m(argc, argv, ARGF.current_file);
13660 if (!next_argv()) {
13661 rb_raise(rb_eArgError,
"no stream to set position");
13663 ARGF_FORWARD(1, &offset);
13664 return rb_io_set_pos(ARGF.current_file, offset);
13685 if (!next_argv()) {
13686 rb_raise(rb_eArgError,
"no stream to rewind");
13688 ARGF_FORWARD(0, 0);
13689 old_lineno =
RFILE(ARGF.current_file)->fptr->lineno;
13690 ret = rb_io_rewind(ARGF.current_file);
13691 if (!global_argf_p(
argf)) {
13692 ARGF.last_lineno = ARGF.lineno -= old_lineno;
13710 if (!next_argv()) {
13711 rb_raise(rb_eArgError,
"no stream");
13713 ARGF_FORWARD(0, 0);
13714 return rb_io_fileno(ARGF.current_file);
13733 ARGF_FORWARD(0, 0);
13734 return ARGF.current_file;
13759 if (
RTEST(ARGF.current_file)) {
13760 if (ARGF.init_p == 0)
return Qtrue;
13762 ARGF_FORWARD(0, 0);
13821 VALUE tmp, str, length;
13825 if (!
NIL_P(length)) {
13830 rb_str_resize(str,0);
13835 if (!next_argv()) {
13838 if (ARGF_GENERIC_INPUT_P()) {
13839 tmp = argf_forward(argc, argv,
argf);
13842 tmp = io_read(argc, argv, ARGF.current_file);
13844 if (
NIL_P(str)) str = tmp;
13847 if (ARGF.next_p != -1) {
13853 else if (argc >= 1) {
13854 long slen = RSTRING_LEN(str);
13870argf_forward_call(
VALUE arg)
13873 argf_forward(p->argc, p->argv, p->argf);
13903 return argf_getpartial(argc, argv,
argf,
Qnil, 0);
13924 return argf_getpartial(argc, argv,
argf, opts, 1);
13930 VALUE tmp, str, length;
13938 no_exception = no_exception_p(opts);
13940 if (!next_argv()) {
13942 rb_str_resize(str, 0);
13946 if (ARGF_GENERIC_INPUT_P()) {
13956 tmp = io_getpartial(argc, argv, ARGF.current_file, no_exception, nonblock);
13959 if (ARGF.next_p == -1) {
13960 return io_nonblock_eof(no_exception);
13965 return io_nonblock_eof(no_exception);
14003 if (!next_argv())
return Qnil;
14004 if (ARGF_GENERIC_INPUT_P()) {
14005 ch = forward_current(rb_intern(
"getc"), 0, 0);
14008 ch = rb_io_getc(ARGF.current_file);
14010 if (
NIL_P(ch) && ARGF.next_p != -1) {
14043 if (!next_argv())
return Qnil;
14044 if (!RB_TYPE_P(ARGF.current_file,
T_FILE)) {
14045 ch = forward_current(rb_intern(
"getbyte"), 0, 0);
14050 if (
NIL_P(ch) && ARGF.next_p != -1) {
14084 if (!RB_TYPE_P(ARGF.current_file,
T_FILE)) {
14085 ch = forward_current(rb_intern(
"getc"), 0, 0);
14088 ch = rb_io_getc(ARGF.current_file);
14090 if (
NIL_P(ch) && ARGF.next_p != -1) {
14122 NEXT_ARGF_FORWARD(0, 0);
14123 c = argf_getbyte(
argf);
14130#define FOREACH_ARGF() while (next_argv())
14135 const VALUE current = ARGF.current_file;
14137 if (ARGF.init_p == -1 || current != ARGF.current_file) {
14143#define ARGF_block_call(mid, argc, argv, func, argf) \
14144 rb_block_call_kw(ARGF.current_file, mid, argc, argv, \
14145 func, argf, rb_keyword_given_p())
14150 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_i,
argf);
14151 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14157 if (!global_argf_p(
argf)) {
14158 ARGF.last_lineno = ++ARGF.lineno;
14160 return argf_block_call_i(i,
argf, argc, argv, blockarg);
14166 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_line_i,
argf);
14167 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14215 argf_block_call_line(rb_intern(
"each_line"), argc, argv,
argf);
14246 argf_block_call(rb_intern(
"each_byte"), 0, 0,
argf);
14272 argf_block_call(rb_intern(
"each_char"), 0, 0,
argf);
14298 argf_block_call(rb_intern(
"each_codepoint"), 0, 0,
argf);
14329 return ARGF.filename;
14333argf_filename_getter(
ID id,
VALUE *var)
14335 return argf_filename(*var);
14360 return ARGF.current_file;
14379 ARGF_FORWARD(0, 0);
14400 return RBOOL(ARGF.binmode);
14420 if (ARGF.init_p && ARGF.next_p == 0) {
14449 if (ARGF.next_p != -1) {
14467 ARGF_FORWARD(0, 0);
14494 if (!ARGF.inplace)
return Qnil;
14496 return rb_str_dup(ARGF.inplace);
14502 return argf_inplace_mode_get(*var);
14533 ARGF.inplace =
Qnil;
14536 ARGF.inplace = rb_str_new_frozen(val);
14544 argf_inplace_mode_set(*var, val);
14548ruby_set_inplace_mode(
const char *suffix)
14574argf_argv_getter(
ID id,
VALUE *var)
14576 return argf_argv(*var);
14595 if (!
RTEST(ARGF.current_file)) {
14598 return GetWriteIO(ARGF.current_file);
14610 return rb_io_write(argf_write_io(
argf), str);
14625 case RB_IO_WAIT_WRITABLE:
14628 c = rb_eEAGAINWaitWritable;
14630#if EAGAIN != EWOULDBLOCK
14632 c = rb_eEWOULDBLOCKWaitWritable;
14636 c = rb_eEINPROGRESSWaitWritable;
14642 case RB_IO_WAIT_READABLE:
14645 c = rb_eEAGAINWaitReadable;
14647#if EAGAIN != EWOULDBLOCK
14649 c = rb_eEWOULDBLOCKWaitReadable;
14653 c = rb_eEINPROGRESSWaitReadable;
14660 rb_bug(
"invalid read/write type passed to rb_readwrite_sys_fail: %d", waiting);
14666get_LAST_READ_LINE(
ID _x,
VALUE *_y)
15323#include <sys/cygwin.h>
15324 static struct __cygwin_perfile pf[] =
15326 {
"", O_RDONLY | O_BINARY},
15327 {
"", O_WRONLY | O_BINARY},
15328 {
"", O_RDWR | O_BINARY},
15329 {
"", O_APPEND | O_BINARY},
15332 cygwin_internal(CW_PERFILE, pf);
15387#if EAGAIN == EWOULDBLOCK
15388 rb_eEWOULDBLOCKWaitReadable = rb_eEAGAINWaitReadable;
15391 rb_eEWOULDBLOCKWaitWritable = rb_eEAGAINWaitWritable;
15433 rb_output_fs =
Qnil;
15436 rb_default_rs = rb_fstring_lit(
"\n");
15437 rb_gc_register_mark_object(rb_default_rs);
15438 rb_rs = rb_default_rs;
15445 rb_gvar_ractor_local(
"$_");
15561 rb_gvar_ractor_local(
"$stdin");
15562 rb_gvar_ractor_local(
"$stdout");
15563 rb_gvar_ractor_local(
"$>");
15564 rb_gvar_ractor_local(
"$stderr");
15650 rb_define_method(rb_cARGF,
"external_encoding", argf_external_encoding, 0);
15651 rb_define_method(rb_cARGF,
"internal_encoding", argf_internal_encoding, 0);
15670 rb_gvar_ractor_local(
"$-i");
15674#if defined (_WIN32) || defined(__CYGWIN__)
15675 atexit(pipe_atexit);
15687 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 ECONV_NEWLINE_DECORATOR_WRITE_MASK
Old name of RUBY_ECONV_NEWLINE_DECORATOR_WRITE_MASK.
#define ENCODING_MAXNAMELEN
Old name of RUBY_ENCODING_MAXNAMELEN.
#define MBCLEN_NEEDMORE_LEN(ret)
Old name of ONIGENC_MBCLEN_NEEDMORE_LEN.
#define ENCODING_GET(obj)
Old name of RB_ENCODING_GET.
#define LONG2FIX
Old name of RB_INT2FIX.
#define NUM2UINT
Old name of RB_NUM2UINT.
#define ALLOC_N
Old name of RB_ALLOC_N.
#define MBCLEN_CHARFOUND_LEN(ret)
Old name of ONIGENC_MBCLEN_CHARFOUND_LEN.
#define LONG2NUM
Old name of RB_LONG2NUM.
#define rb_exc_new3
Old name of rb_exc_new_str.
#define 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 ECONV_NEWLINE_DECORATOR_READ_MASK
Old name of RUBY_ECONV_NEWLINE_DECORATOR_READ_MASK.
#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 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 OnigCodePoint rb_enc_mbc_to_codepoint(const char *p, const char *e, rb_encoding *enc)
Identical to rb_enc_codepoint(), except it assumes the passed character is not broken.
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.
#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.
struct rb_io_internal_buffer rb_io_buffer_t
Just another name of rb_io_buffer_t.
VALUE rb_io_set_timeout(VALUE io, VALUE timeout)
Set the timeout associated with the specified io object.
ssize_t rb_io_bufwrite(VALUE io, const void *buf, size_t size)
Buffered write to the passed IO.
void rb_io_check_char_readable(rb_io_t *fptr)
Asserts that an IO is opened for character-based reading.
#define FMODE_TRUNC
This flag amends the effect of FMODE_CREATE, so that if there already is a file at the given path it ...
int rb_io_read_pending(rb_io_t *fptr)
Queries if the passed IO has any pending reads.
VALUE rb_io_get_write_io(VALUE io)
Queries the tied IO for writing.
void rb_io_set_nonblock(rb_io_t *fptr)
Instructs the OS to put its internal file structure into "nonblocking mode".
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.
struct rb_data_type_struct rb_data_type_t
This is the struct that holds necessary info for a struct.
#define TypedData_Make_Struct(klass, type, data_type, sval)
Identical to TypedData_Wrap_Struct, except it allocates a new data region internally instead of takin...
VALUE rb_get_argv(void)
Queries the arguments passed to the current process that you can access from Ruby as ARGV.
void rb_p(VALUE obj)
Inspects an object.
#define FilePathValue(v)
Ensures that the parameter object is a path.
#define errno
Ractor-aware version of errno.
#define RB_SCAN_ARGS_LAST_HASH_KEYWORDS
Treat a final argument as keywords if it is a hash, and not as keywords otherwise.
#define RB_PASS_CALLED_KEYWORDS
Pass keywords if current method is called with keywords, useful for argument delegation.
VALUE rb_fiber_scheduler_current(void)
Identical to rb_fiber_scheduler_get(), except it also returns RUBY_Qnil in case of a blocking fiber.
VALUE rb_fiber_scheduler_io_pread_memory(VALUE scheduler, VALUE io, rb_off_t from, void *base, size_t size, size_t length)
Non-blocking pread from the passed IO using a native buffer.
VALUE rb_fiber_scheduler_make_timeout(struct timeval *timeout)
Converts the passed timeout to an expression that rb_fiber_scheduler_block() etc.
VALUE rb_fiber_scheduler_io_wait_readable(VALUE scheduler, VALUE io)
Non-blocking wait until the passed IO is ready for reading.
VALUE rb_fiber_scheduler_io_read_memory(VALUE scheduler, VALUE io, void *base, size_t size, size_t length)
Non-blocking read from the passed IO using a native buffer.
VALUE rb_fiber_scheduler_io_wait(VALUE scheduler, VALUE io, VALUE events, VALUE timeout)
Non-blocking version of rb_io_wait().
static ssize_t rb_fiber_scheduler_io_result_apply(VALUE result)
Apply an io result to the local thread, returning the value of the original system call that created ...
VALUE rb_fiber_scheduler_io_selectv(VALUE scheduler, int argc, VALUE *argv)
Non-blocking version of IO.select, argv variant.
VALUE rb_fiber_scheduler_io_pwrite_memory(VALUE scheduler, VALUE io, rb_off_t from, const void *base, size_t size, size_t length)
Non-blocking pwrite to the passed IO using a native buffer.
VALUE rb_fiber_scheduler_current_for_thread(VALUE thread)
Identical to rb_fiber_scheduler_current(), except it queries for that of the passed thread 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.
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.