14#include "ruby/internal/config.h"
25# if defined(__linux__)
28# if defined(__FreeBSD_version) && __FreeBSD_version >= 1100000
38#define free(x) xfree(x)
40#if defined(DOSISH) || defined(__CYGWIN__)
45#if defined HAVE_NET_SOCKET_H
46# include <net/socket.h>
47#elif defined HAVE_SYS_SOCKET_H
48# include <sys/socket.h>
51#if defined(__BOW__) || defined(__CYGWIN__) || defined(_WIN32)
52# define NO_SAFE_RENAME
55#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__sun) || defined(_nec_ews)
64#if defined(HAVE_SYS_IOCTL_H) && !defined(_WIN32)
67#if defined(HAVE_FCNTL_H) || defined(_WIN32)
69#elif defined(HAVE_SYS_FCNTL_H)
79#if defined(HAVE_SYS_PARAM_H) || defined(__HIUX_MPP__)
80# include <sys/param.h>
93#elif defined HAVE_SYS_SYSCALL_H
94#include <sys/syscall.h>
101#ifdef HAVE_SYS_WAIT_H
102# include <sys/wait.h>
105#ifdef HAVE_COPYFILE_H
106# include <copyfile.h>
108# ifndef COPYFILE_STATE_COPIED
114# undef HAVE_FCOPYFILE
120#include "ccan/list/list.h"
125#include "internal/class.h"
126#include "internal/encoding.h"
127#include "internal/error.h"
128#include "internal/inits.h"
129#include "internal/io.h"
130#include "internal/numeric.h"
131#include "internal/object.h"
132#include "internal/process.h"
133#include "internal/thread.h"
134#include "internal/transcode.h"
135#include "internal/variable.h"
138#include "ruby/missing.h"
141#include "ruby_atomic.h"
151#define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR)
155# ifdef _POSIX_PIPE_BUF
156# define PIPE_BUF _POSIX_PIPE_BUF
163# define EWOULDBLOCK EAGAIN
166#if defined(HAVE___SYSCALL) && (defined(__APPLE__) || defined(__OpenBSD__))
168off_t __syscall(quad_t number, ...);
171#define IO_RBUF_CAPA_MIN 8192
172#define IO_CBUF_CAPA_MIN (128*1024)
173#define IO_RBUF_CAPA_FOR(fptr) (NEED_READCONV(fptr) ? IO_CBUF_CAPA_MIN : IO_RBUF_CAPA_MIN)
174#define IO_WBUF_CAPA_MIN 8192
176#define IO_MAX_BUFFER_GROWTH 8 * 1024 * 1024
181#define open rb_w32_uopen
183#define rename(f, t) rb_w32_urename((f), (t))
184#include "win32/file.h"
194static VALUE rb_eEAGAINWaitReadable;
195static VALUE rb_eEAGAINWaitWritable;
196static VALUE rb_eEWOULDBLOCKWaitReadable;
197static VALUE rb_eEWOULDBLOCKWaitWritable;
198static VALUE rb_eEINPROGRESSWaitWritable;
199static VALUE rb_eEINPROGRESSWaitReadable;
202static VALUE orig_stdout, orig_stderr;
211static ID id_write, id_read, id_getc, id_flush, id_readpartial, id_set_encoding, id_fileno;
212static VALUE sym_mode, sym_perm, sym_flags, sym_extenc, sym_intenc, sym_encoding, sym_open_args;
213static VALUE sym_textmode, sym_binmode, sym_autoclose;
214static VALUE sym_SET, sym_CUR, sym_END;
215static VALUE sym_wait_readable, sym_wait_writable;
217static VALUE sym_DATA;
220static VALUE sym_HOLE;
223static VALUE prep_io(
int fd,
int fmode,
VALUE klass,
const char *path);
226rb_io_blocking_region_wait(
struct rb_io *io, rb_blocking_function_t *function,
void *argument,
enum rb_io_event events)
228 return rb_thread_io_blocking_call(function, argument, io->
fd, events);
231VALUE rb_io_blocking_region(
struct rb_io *io, rb_blocking_function_t *function,
void *argument)
233 return rb_io_blocking_region_wait(io, function, argument, 0);
237 VALUE filename, current_file;
243 int8_t init_p, next_p, binmode;
254 if (fd < 0 || afd <= max_fd)
257#if defined(HAVE_FCNTL) && defined(F_GETFL)
258 err = fcntl(fd, F_GETFL) == -1;
262 err = fstat(fd, &buf) != 0;
265 if (err &&
errno == EBADF) {
266 rb_bug(
"rb_update_max_fd: invalid fd (%d) given.", fd);
269 while (max_fd < afd) {
270 max_fd = ATOMIC_CAS(max_file_descriptor, max_fd, afd);
275rb_maygvl_fd_fix_cloexec(
int fd)
278#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
279 int flags, flags2, ret;
280 flags = fcntl(fd, F_GETFD);
282 rb_bug(
"rb_maygvl_fd_fix_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(
errno));
285 flags2 = flags & ~FD_CLOEXEC;
287 flags2 = flags | FD_CLOEXEC;
288 if (flags != flags2) {
289 ret = fcntl(fd, F_SETFD, flags2);
291 rb_bug(
"rb_maygvl_fd_fix_cloexec: fcntl(%d, F_SETFD, %d) failed: %s", fd, flags2, strerror(
errno));
300 rb_maygvl_fd_fix_cloexec(fd);
306rb_fix_detect_o_cloexec(
int fd)
308#if defined(O_CLOEXEC) && defined(F_GETFD)
309 int flags = fcntl(fd, F_GETFD);
312 rb_bug(
"rb_fix_detect_o_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(
errno));
314 if (flags & FD_CLOEXEC)
317 rb_maygvl_fd_fix_cloexec(fd);
324 return (e == EWOULDBLOCK) || (e == EAGAIN);
331 static int o_cloexec_state = -1;
333 static const int retry_interval = 0;
334 static const int retry_max_count = 10000;
341#elif defined O_NOINHERIT
342 flags |= O_NOINHERIT;
345 while ((ret = open(pathname, flags, mode)) == -1) {
347 if (!io_again_p(e))
break;
348 if (retry_count++ >= retry_max_count)
break;
350 sleep(retry_interval);
353 if (ret < 0)
return ret;
354 if (ret <= 2 || o_cloexec_state == 0) {
355 rb_maygvl_fd_fix_cloexec(ret);
357 else if (o_cloexec_state > 0) {
361 o_cloexec_state = rb_fix_detect_o_cloexec(ret);
380 if (oldfd == newfd) {
384#if defined(HAVE_DUP3) && defined(O_CLOEXEC)
385 static int try_dup3 = 1;
386 if (2 < newfd && try_dup3) {
387 ret = dup3(oldfd, newfd, O_CLOEXEC);
391 if (
errno == ENOSYS) {
393 ret = dup2(oldfd, newfd);
397 ret = dup2(oldfd, newfd);
400 ret = dup2(oldfd, newfd);
402 if (ret < 0)
return ret;
404 rb_maygvl_fd_fix_cloexec(ret);
409rb_fd_set_nonblock(
int fd)
412 return rb_w32_set_nonblock(fd);
413#elif defined(F_GETFL)
414 int oflags = fcntl(fd, F_GETFL);
418 if (oflags & O_NONBLOCK)
420 oflags |= O_NONBLOCK;
421 return fcntl(fd, F_SETFL, oflags);
430 int result = pipe2(descriptors, O_CLOEXEC | O_NONBLOCK);
432 int result = pipe(descriptors);
439 if (result == 0 && descriptors[1] == -1) {
440 close(descriptors[0]);
448 rb_maygvl_fd_fix_cloexec(descriptors[0]);
449 rb_maygvl_fd_fix_cloexec(descriptors[1]);
452 rb_fd_set_nonblock(descriptors[0]);
453 rb_fd_set_nonblock(descriptors[1]);
465#if defined(HAVE_FCNTL) && defined(F_DUPFD_CLOEXEC) && defined(F_DUPFD)
466 static int try_dupfd_cloexec = 1;
467 if (try_dupfd_cloexec) {
468 ret = fcntl(fd, F_DUPFD_CLOEXEC, minfd);
471 rb_maygvl_fd_fix_cloexec(ret);
475 if (
errno == EINVAL) {
476 ret = fcntl(fd, F_DUPFD, minfd);
478 try_dupfd_cloexec = 0;
483 ret = fcntl(fd, F_DUPFD, minfd);
485#elif defined(HAVE_FCNTL) && defined(F_DUPFD)
486 ret = fcntl(fd, F_DUPFD, minfd);
489 if (ret >= 0 && ret < minfd) {
490 const int prev_fd = ret;
496 if (ret < 0)
return ret;
497 rb_maygvl_fd_fix_cloexec(ret);
501#define argf_of(obj) (*(struct argf *)DATA_PTR(obj))
502#define ARGF argf_of(argf)
504#define GetWriteIO(io) rb_io_get_write_io(io)
506#define READ_DATA_PENDING(fptr) ((fptr)->rbuf.len)
507#define READ_DATA_PENDING_COUNT(fptr) ((fptr)->rbuf.len)
508#define READ_DATA_PENDING_PTR(fptr) ((fptr)->rbuf.ptr+(fptr)->rbuf.off)
509#define READ_DATA_BUFFERED(fptr) READ_DATA_PENDING(fptr)
511#define READ_CHAR_PENDING(fptr) ((fptr)->cbuf.len)
512#define READ_CHAR_PENDING_COUNT(fptr) ((fptr)->cbuf.len)
513#define READ_CHAR_PENDING_PTR(fptr) ((fptr)->cbuf.ptr+(fptr)->cbuf.off)
516#define WAIT_FD_IN_WIN32(fptr) \
517 (rb_w32_io_cancelable_p((fptr)->fd) ? Qnil : rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_READABLE), RUBY_IO_TIMEOUT_DEFAULT))
519#define WAIT_FD_IN_WIN32(fptr)
522#define READ_CHECK(fptr) do {\
523 if (!READ_DATA_PENDING(fptr)) {\
524 WAIT_FD_IN_WIN32(fptr);\
525 rb_io_check_closed(fptr);\
531# define S_ISSOCK(m) _S_ISSOCK(m)
534# define S_ISSOCK(m) (((m) & S_IFMT) == _S_IFSOCK)
537# define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
543static int io_fflush(rb_io_t *);
544static rb_io_t *flush_before_seek(rb_io_t *fptr,
bool discard_rbuf);
545static void clear_codeconv(rb_io_t *fptr);
547#define FMODE_SIGNAL_ON_EPIPE (1<<17)
549#define fptr_signal_on_epipe(fptr) \
550 (((fptr)->mode & FMODE_SIGNAL_ON_EPIPE) != 0)
552#define fptr_set_signal_on_epipe(fptr, flag) \
554 (fptr)->mode |= FMODE_SIGNAL_ON_EPIPE : \
555 (fptr)->mode &= ~FMODE_SIGNAL_ON_EPIPE)
557extern ID ruby_static_id_signo;
559NORETURN(
static void rb_sys_fail_on_write(rb_io_t *fptr));
561rb_sys_fail_on_write(rb_io_t *fptr)
564 VALUE errinfo = rb_syserr_new_path(e, (fptr)->pathv);
566 if (fptr_signal_on_epipe(fptr) && (e == EPIPE)) {
575 rb_exc_raise(errinfo);
578#define NEED_NEWLINE_DECORATOR_ON_READ(fptr) ((fptr)->mode & FMODE_TEXTMODE)
579#define NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) ((fptr)->mode & FMODE_TEXTMODE)
580#if defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32)
581# define RUBY_CRLF_ENVIRONMENT 1
583# define RUBY_CRLF_ENVIRONMENT 0
586#if RUBY_CRLF_ENVIRONMENT
588# define DEFAULT_TEXTMODE FMODE_TEXTMODE
589# define TEXTMODE_NEWLINE_DECORATOR_ON_WRITE ECONV_CRLF_NEWLINE_DECORATOR
597#define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || (fptr)->encs.ecflags & ~ECONV_CRLF_NEWLINE_DECORATOR)
598#define WRITECONV_MASK ( \
599 (ECONV_DECORATOR_MASK & ~ECONV_CRLF_NEWLINE_DECORATOR)|\
600 ECONV_STATEFUL_DECORATOR_MASK|\
602#define NEED_WRITECONV(fptr) ( \
603 ((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || \
604 ((fptr)->encs.ecflags & WRITECONV_MASK) || \
606#define SET_BINARY_MODE(fptr) setmode((fptr)->fd, O_BINARY)
608#define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) do {\
609 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {\
610 if (((fptr)->mode & FMODE_READABLE) &&\
611 !((fptr)->encs.ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {\
612 setmode((fptr)->fd, O_BINARY);\
615 setmode((fptr)->fd, O_TEXT);\
620#define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) do {\
621 if ((enc2) && ((ecflags) & ECONV_DEFAULT_NEWLINE_DECORATOR)) {\
622 (ecflags) |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;\
630io_unread(rb_io_t *fptr,
bool discard_rbuf)
646 if (!rb_w32_fd_is_text(fptr->
fd)) {
647 r = lseek(fptr->
fd, -fptr->
rbuf.
len, SEEK_CUR);
648 if (r < 0 &&
errno) {
651 if (!discard_rbuf)
return;
657 pos = lseek(fptr->
fd, 0, SEEK_CUR);
658 if (pos < 0 &&
errno) {
661 if (!discard_rbuf)
goto end;
665 extra_max = (long)(pos - fptr->
rbuf.
len);
673 for (i = 0; i < fptr->
rbuf.
len; i++) {
674 if (*p ==
'\n') newlines++;
675 if (extra_max == newlines)
break;
680 while (newlines >= 0) {
681 r = lseek(fptr->
fd, pos - fptr->
rbuf.
len - newlines, SEEK_SET);
682 if (newlines == 0)
break;
687 read_size = _read(fptr->
fd, buf, fptr->
rbuf.
len + newlines);
691 rb_syserr_fail_path(e, fptr->
pathv);
693 if (read_size == fptr->
rbuf.
len) {
694 lseek(fptr->
fd, r, SEEK_SET);
705 clear_codeconv(fptr);
717set_binary_mode_with_seek_cur(rb_io_t *fptr)
719 if (!rb_w32_fd_is_text(fptr->
fd))
return O_BINARY;
722 return setmode(fptr->
fd, O_BINARY);
724 flush_before_seek(fptr,
false);
725 return setmode(fptr->
fd, O_BINARY);
727#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) set_binary_mode_with_seek_cur(fptr)
731# define DEFAULT_TEXTMODE 0
732#define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || NEED_NEWLINE_DECORATOR_ON_READ(fptr))
733#define NEED_WRITECONV(fptr) ( \
734 ((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || \
735 NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) || \
736 ((fptr)->encs.ecflags & (ECONV_DECORATOR_MASK|ECONV_STATEFUL_DECORATOR_MASK)) || \
738#define SET_BINARY_MODE(fptr) (void)(fptr)
739#define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) (void)(fptr)
740#define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) ((void)(enc2), (void)(ecflags))
741#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) (void)(fptr)
744#if !defined HAVE_SHUTDOWN && !defined shutdown
745#define shutdown(a,b) 0
749#define is_socket(fd, path) rb_w32_is_socket(fd)
750#elif !defined(S_ISSOCK)
751#define is_socket(fd, path) 0
754is_socket(
int fd,
VALUE path)
757 if (fstat(fd, &sbuf) < 0)
758 rb_sys_fail_path(path);
759 return S_ISSOCK(sbuf.st_mode);
763static const char closed_stream[] =
"closed stream";
766io_fd_check_closed(
int fd)
799 io_fd_check_closed(fptr->
fd);
803rb_io_get_fptr(
VALUE io)
805 rb_io_t *fptr =
RFILE(io)->fptr;
813 return rb_convert_type_with_id(io,
T_FILE,
"IO", idTo_io);
819 return rb_check_convert_type_with_id(io,
T_FILE,
"IO", idTo_io);
826 write_io = rb_io_get_fptr(io)->tied_io_for_writing;
837 rb_io_t *fptr = rb_io_get_fptr(io);
846 return write_io ? write_io :
Qnil;
859 rb_io_t *fptr = rb_io_get_fptr(self);
889 if (
RTEST(timeout)) {
893 rb_io_t *fptr = rb_io_get_fptr(self);
918#if !RUBY_CRLF_ENVIRONMENT
920io_unread(rb_io_t *fptr,
bool discard_rbuf)
928 r = lseek(fptr->
fd, -fptr->
rbuf.
len, SEEK_CUR);
929 if (r < 0 &&
errno) {
932 if (!discard_rbuf)
return;
936 clear_codeconv(fptr);
941static rb_encoding *io_input_encoding(rb_io_t *fptr);
944io_ungetbyte(
VALUE str, rb_io_t *fptr)
946 long len = RSTRING_LEN(str);
949 const int min_capa = IO_RBUF_CAPA_FOR(fptr);
952#if SIZEOF_LONG > SIZEOF_INT
977flush_before_seek(rb_io_t *fptr,
bool discard_rbuf)
979 if (io_fflush(fptr) < 0)
980 rb_sys_fail_on_write(fptr);
981 io_unread(fptr, discard_rbuf);
986#define io_seek(fptr, ofs, whence) (errno = 0, lseek(flush_before_seek(fptr, true)->fd, (ofs), (whence)))
987#define io_tell(fptr) lseek(flush_before_seek(fptr, false)->fd, 0, SEEK_CUR)
1003 if (io_fflush(fptr) < 0)
1004 rb_sys_fail_on_write(fptr);
1009 if (io_fflush(wfptr) < 0)
1010 rb_sys_fail_on_write(wfptr);
1018 if (READ_CHAR_PENDING(fptr)) {
1019 rb_raise(
rb_eIOError,
"byte oriented read for character buffered IO");
1030io_read_encoding(rb_io_t *fptr)
1039io_input_encoding(rb_io_t *fptr)
1044 return io_read_encoding(fptr);
1055 io_unread(fptr,
true);
1063 if (READ_CHAR_PENDING(fptr))
1065 return READ_DATA_PENDING(fptr);
1071 if (!READ_DATA_PENDING(fptr)) {
1078rb_gc_for_fd(
int err)
1080 if (err == EMFILE || err == ENFILE || err == ENOMEM) {
1090#define TRY_WITH_GC(expr) \
1091 for (int first_errno, retried_errno = 0, retried = 0; \
1094 (!rb_gc_for_fd(first_errno = errno) || !(expr)) && \
1095 (retried_errno = errno, 1)); \
1096 (void)retried_errno, retried = 1)
1111io_alloc(
VALUE klass)
1121# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
1147struct io_internal_writev_struct {
1154 const struct iovec *iov;
1159static int nogvl_wait_for(
VALUE th, rb_io_t *fptr,
short events,
struct timeval *timeout);
1167io_internal_wait(
VALUE thread, rb_io_t *fptr,
int error,
int events,
struct timeval *timeout)
1169 if (!timeout && rb_thread_mn_schedulable(thread)) {
1174 int ready = nogvl_wait_for(thread, fptr, events, timeout);
1179 else if (ready == 0) {
1195internal_read_func(
void *ptr)
1200 if (iis->timeout && !iis->nonblock) {
1201 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_IN, iis->timeout) == -1) {
1207 result = read(iis->fd, iis->buf, iis->capa);
1209 if (result < 0 && !iis->nonblock) {
1210 if (io_again_p(
errno)) {
1211 if (io_internal_wait(iis->th, iis->fptr,
errno, RB_WAITFD_IN, iis->timeout) == -1) {
1223#if defined __APPLE__
1224# define do_write_retry(code) do {result = code;} while (result == -1 && errno == EPROTOTYPE)
1226# define do_write_retry(code) result = code
1230internal_write_func(
void *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(write(iis->fd, iis->buf, iis->capa));
1244 if (result < 0 && !iis->nonblock) {
1246 if (io_again_p(e)) {
1247 if (io_internal_wait(iis->th, iis->fptr,
errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1261internal_writev_func(
void *ptr)
1263 struct io_internal_writev_struct *iis = ptr;
1266 if (iis->timeout && !iis->nonblock) {
1267 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1273 do_write_retry(writev(iis->fd, iis->iov, iis->iovcnt));
1275 if (result < 0 && !iis->nonblock) {
1276 if (io_again_p(
errno)) {
1277 if (io_internal_wait(iis->th, iis->fptr,
errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1291rb_io_read_memory(rb_io_t *fptr,
void *buf,
size_t count)
1294 if (scheduler !=
Qnil) {
1297 if (!UNDEF_P(result)) {
1313 struct timeval timeout_storage;
1317 iis.timeout = &timeout_storage;
1320 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_read_func, &iis,
RUBY_IO_READABLE);
1324rb_io_write_memory(rb_io_t *fptr,
const void *buf,
size_t count)
1327 if (scheduler !=
Qnil) {
1330 if (!UNDEF_P(result)) {
1346 struct timeval timeout_storage;
1350 iis.timeout = &timeout_storage;
1353 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_write_func, &iis,
RUBY_IO_WRITABLE);
1358rb_writev_internal(rb_io_t *fptr,
const struct iovec *iov,
int iovcnt)
1360 if (!iovcnt)
return 0;
1363 if (scheduler !=
Qnil) {
1367 if (!UNDEF_P(result)) {
1372 struct io_internal_writev_struct iis = {
1383 struct timeval timeout_storage;
1387 iis.timeout = &timeout_storage;
1390 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_writev_func, &iis,
RUBY_IO_WRITABLE);
1395io_flush_buffer_sync(
void *arg)
1397 rb_io_t *fptr = arg;
1417io_flush_buffer_async(
VALUE arg)
1419 rb_io_t *fptr = (rb_io_t *)arg;
1420 return rb_io_blocking_region_wait(fptr, io_flush_buffer_sync, fptr,
RUBY_IO_WRITABLE);
1424io_flush_buffer(rb_io_t *fptr)
1427 return (
int)io_flush_buffer_async((
VALUE)fptr);
1435io_fflush(rb_io_t *fptr)
1442 while (fptr->
wbuf.
len > 0 && io_flush_buffer(fptr) != 0) {
1457 if (scheduler !=
Qnil) {
1461 rb_io_t * fptr = NULL;
1467 if (NIL_OR_UNDEF_P(timeout)) {
1471 if (timeout !=
Qnil) {
1476 int ready = rb_thread_wait_for_single_fd(fptr->
fd,
RB_NUM2INT(events), tv);
1500io_wait_for_single_fd(
int fd,
int events,
struct timeval *timeout)
1504 if (scheduler !=
Qnil) {
1510 return rb_thread_wait_for_single_fd(fd, events, timeout);
1516 io_fd_check_closed(f);
1522#if defined(ERESTART)
1529#if EWOULDBLOCK != EAGAIN
1532 if (scheduler !=
Qnil) {
1550 io_fd_check_closed(f);
1556#if defined(ERESTART)
1572#if EWOULDBLOCK != EAGAIN
1575 if (scheduler !=
Qnil) {
1593 return io_wait_for_single_fd(fd, events, timeout);
1627#if defined(ERESTART)
1637#if EWOULDBLOCK != EAGAIN
1654 if (
RTEST(result)) {
1669 if (
RTEST(result)) {
1680make_writeconv(rb_io_t *fptr)
1683 const char *senc, *denc;
1717 denc = rb_enc_name(enc);
1749io_binwrite_string_internal(rb_io_t *fptr,
const char *ptr,
long length)
1752 struct iovec iov[2];
1755 iov[0].iov_len = fptr->
wbuf.
len;
1756 iov[1].iov_base = (
void*)ptr;
1757 iov[1].iov_len = length;
1759 ssize_t result = rb_writev_internal(fptr, iov, 2);
1764 if (result >= fptr->
wbuf.
len) {
1772 fptr->
wbuf.
off += (int)result;
1773 fptr->
wbuf.
len -= (int)result;
1781 return rb_io_write_memory(fptr, ptr, length);
1786io_binwrite_string_internal(rb_io_t *fptr,
const char *ptr,
long length)
1788 long remaining = length;
1791 if (fptr->
wbuf.
len+length <= fptr->wbuf.capa) {
1798 fptr->
wbuf.
len += (int)length;
1805 if (io_fflush(fptr) < 0) {
1810 if (remaining == 0) {
1816 return rb_io_write_memory(fptr, ptr, length);
1821io_binwrite_string(
VALUE arg)
1825 const char *ptr = p->ptr;
1826 size_t remaining = p->length;
1830 ssize_t result = io_binwrite_string_internal(p->fptr, ptr, remaining);
1836 else if (result > 0) {
1837 if ((
size_t)result == remaining)
break;
1839 remaining -= result;
1855io_allocate_write_buffer(rb_io_t *fptr,
int sync)
1860 fptr->
wbuf.
capa = IO_WBUF_CAPA_MIN;
1871io_binwrite_requires_flush_write(rb_io_t *fptr,
long len,
int nosync)
1886io_binwrite(
const char *ptr,
long len, rb_io_t *fptr,
int nosync)
1888 if (
len <= 0)
return len;
1893 io_allocate_write_buffer(fptr, !nosync);
1895 if (io_binwrite_requires_flush_write(fptr,
len, nosync)) {
1906 return io_binwrite_string((
VALUE)&arg);
1923# define MODE_BTMODE(a,b,c) ((fmode & FMODE_BINMODE) ? (b) : \
1924 (fmode & FMODE_TEXTMODE) ? (c) : (a))
1926#define MODE_BTXMODE(a, b, c, d, e, f) ((fmode & FMODE_EXCL) ? \
1927 MODE_BTMODE(d, e, f) : \
1928 MODE_BTMODE(a, b, c))
1931do_writeconv(
VALUE str, rb_io_t *fptr,
int *converted)
1933 if (NEED_WRITECONV(fptr)) {
1935 SET_BINARY_MODE(fptr);
1937 make_writeconv(fptr);
1940#define fmode (fptr->mode)
1943 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1) && !rb_enc_asciicompat(rb_enc_get(str))) {
1944 rb_raise(rb_eArgError,
"ASCII incompatible string written for text mode IO without encoding conversion: %s",
1945 rb_enc_name(rb_enc_get(str)));
1951 common_encoding = rb_enc_from_encoding(fptr->
encs.
enc2);
1952 else if (fptr->
encs.
enc != rb_ascii8bit_encoding())
1953 common_encoding = rb_enc_from_encoding(fptr->
encs.
enc);
1956 if (!
NIL_P(common_encoding)) {
1967#if RUBY_CRLF_ENVIRONMENT
1968#define fmode (fptr->mode)
1969 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1)) {
1972 setmode(fptr->
fd, O_BINARY);
1975 setmode(fptr->
fd, O_TEXT);
1977 if (!rb_enc_asciicompat(rb_enc_get(str))) {
1978 rb_raise(rb_eArgError,
"ASCII incompatible string written for text mode IO without encoding conversion: %s",
1979 rb_enc_name(rb_enc_get(str)));
1988io_fwrite(
VALUE str, rb_io_t *fptr,
int nosync)
1997 long len = rb_w32_write_console(str, fptr->
fd);
2002 str = do_writeconv(str, fptr, &converted);
2006 tmp = rb_str_tmp_frozen_no_embed_acquire(str);
2008 n = io_binwrite(ptr,
len, fptr, nosync);
2009 rb_str_tmp_frozen_release(str, tmp);
2021 return (ssize_t)io_binwrite(buf, (
long)size, fptr, 0);
2031 io = GetWriteIO(io);
2032 str = rb_obj_as_string(str);
2041 if (RSTRING_LEN(str) == 0)
return INT2FIX(0);
2046 n = io_fwrite(str, fptr, nosync);
2047 if (n < 0L) rb_sys_fail_on_write(fptr);
2053struct binwritev_arg {
2061io_binwritev_internal(
VALUE arg)
2063 struct binwritev_arg *p = (
struct binwritev_arg *)arg;
2065 size_t remaining = p->total;
2068 rb_io_t *fptr = p->fptr;
2069 struct iovec *iov = p->iov;
2070 int iovcnt = p->iovcnt;
2073 long result = rb_writev_internal(fptr, iov, iovcnt);
2078 if (offset < (
size_t)fptr->
wbuf.
len) {
2083 offset -= (size_t)fptr->
wbuf.
len;
2089 if (offset == p->total) {
2093 while (result >= (ssize_t)iov->iov_len) {
2095 result -= iov->iov_len;
2105 iov->iov_base = (
char *)iov->iov_base + result;
2106 iov->iov_len -= result;
2120io_binwritev(
struct iovec *iov,
int iovcnt, rb_io_t *fptr)
2125 if (iovcnt == 0)
return 0;
2128 for (
int i = 1; i < iovcnt; i++) total += iov[i].iov_len;
2130 io_allocate_write_buffer(fptr, 1);
2136 if (offset + total <= (
size_t)fptr->
wbuf.
capa) {
2137 for (
int i = 1; i < iovcnt; i++) {
2138 memcpy(fptr->
wbuf.
ptr+offset, iov[i].iov_base, iov[i].iov_len);
2139 offset += iov[i].iov_len;
2148 iov[0].iov_len = fptr->
wbuf.
len;
2161 struct binwritev_arg arg;
2164 arg.iovcnt = iovcnt;
2171 return io_binwritev_internal((
VALUE)&arg);
2176io_fwritev(
int argc,
const VALUE *argv, rb_io_t *fptr)
2178 int i, converted, iovcnt = argc + 1;
2180 VALUE v1, v2, str, tmp, *tmp_array;
2186 for (i = 0; i < argc; i++) {
2187 str = rb_obj_as_string(argv[i]);
2189 str = do_writeconv(str, fptr, &converted);
2194 tmp = rb_str_tmp_frozen_acquire(str);
2198 iov[i+1].iov_base = RSTRING_PTR(tmp);
2199 iov[i+1].iov_len = RSTRING_LEN(tmp);
2202 n = io_binwritev(iov, iovcnt, fptr);
2205 for (i = 0; i < argc; i++) {
2206 rb_str_tmp_frozen_release(argv[i], tmp_array[i]);
2215iovcnt_ok(
int iovcnt)
2218 return iovcnt < IOV_MAX;
2226io_writev(
int argc,
const VALUE *argv,
VALUE io)
2233 io = GetWriteIO(io);
2238 return rb_funcallv(io, id_write, argc, argv);
2246 for (i = 0; i < argc; i += cnt) {
2249 n = io_fwritev(cnt, &argv[i], fptr);
2256 n = io_fwrite(rb_obj_as_string(argv[i]), fptr, (i < argc-1));
2260 rb_sys_fail_on_write(fptr);
2262 total = rb_fix_plus(
LONG2FIX(n), total);
2293 return io_writev(argc, argv, io);
2296 VALUE str = argv[0];
2297 return io_write(io, str, 0);
2304 return rb_funcallv(io, id_write, 1, &str);
2308rb_io_writev(
VALUE io,
int argc,
const VALUE *argv)
2313 char sep = RCLASS_SINGLETON_P(klass) ? (klass = io,
'.') :
'#';
2316 " which accepts just one argument",
2321 do rb_io_write(io, *argv++);
while (--argc);
2326 return rb_funcallv(io, id_write, argc, argv);
2352 rb_io_write(io, str);
2358nogvl_fsync(
void *ptr)
2360 rb_io_t *fptr = ptr;
2363 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->
fd)) != FILE_TYPE_DISK)
2366 return (
VALUE)fsync(fptr->
fd);
2371rb_io_flush_raw(
VALUE io,
int sync)
2379 io = GetWriteIO(io);
2383 if (io_fflush(fptr) < 0)
2384 rb_sys_fail_on_write(fptr);
2387 io_unread(fptr,
true);
2408 return rb_io_flush_raw(io, 1);
2434 pos = io_tell(fptr);
2435 if (pos < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
2441rb_io_seek(
VALUE io,
VALUE offset,
int whence)
2448 pos = io_seek(fptr, pos, whence);
2449 if (pos < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
2455interpret_seek_whence(
VALUE vwhence)
2457 if (vwhence == sym_SET)
2459 if (vwhence == sym_CUR)
2461 if (vwhence == sym_END)
2464 if (vwhence == sym_DATA)
2468 if (vwhence == sym_HOLE)
2524 VALUE offset, ptrname;
2525 int whence = SEEK_SET;
2527 if (
rb_scan_args(argc, argv,
"11", &offset, &ptrname) == 2) {
2528 whence = interpret_seek_whence(ptrname);
2531 return rb_io_seek(io, offset, whence);
2559 pos = io_seek(fptr, pos, SEEK_SET);
2560 if (pos < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
2565static void clear_readconv(rb_io_t *fptr);
2592rb_io_rewind(
VALUE io)
2597 if (io_seek(fptr, 0L, 0) < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
2598 if (io == ARGF.current_file) {
2599 ARGF.lineno -= fptr->
lineno;
2603 clear_readconv(fptr);
2610fptr_wait_readable(rb_io_t *fptr)
2621io_fillbuf(rb_io_t *fptr)
2628 fptr->
rbuf.
capa = IO_RBUF_CAPA_FOR(fptr);
2639 if (fptr_wait_readable(fptr))
2643 VALUE path = rb_sprintf(
"fd:%d ", fptr->
fd);
2648 rb_syserr_fail_path(e, path);
2702 if (READ_CHAR_PENDING(fptr))
return Qfalse;
2703 if (READ_DATA_PENDING(fptr))
return Qfalse;
2705#if RUBY_CRLF_ENVIRONMENT
2706 if (!NEED_READCONV(fptr) && NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
2707 return RBOOL(eof(fptr->
fd));
2710 return RBOOL(io_fillbuf(fptr) < 0);
2734 io = GetWriteIO(io);
2771 io = GetWriteIO(io);
2801rb_io_fsync(
VALUE io)
2805 io = GetWriteIO(io);
2808 if (io_fflush(fptr) < 0)
2809 rb_sys_fail_on_write(fptr);
2811 if ((
int)rb_io_blocking_region(fptr, nogvl_fsync, fptr))
2812 rb_sys_fail_path(fptr->
pathv);
2817# define rb_io_fsync rb_f_notimplement
2818# define rb_io_sync rb_f_notimplement
2827#ifdef HAVE_FDATASYNC
2829nogvl_fdatasync(
void *ptr)
2831 rb_io_t *fptr = ptr;
2834 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->
fd)) != FILE_TYPE_DISK)
2837 return (
VALUE)fdatasync(fptr->
fd);
2852rb_io_fdatasync(
VALUE io)
2856 io = GetWriteIO(io);
2859 if (io_fflush(fptr) < 0)
2860 rb_sys_fail_on_write(fptr);
2862 if ((
int)rb_io_blocking_region(fptr, nogvl_fdatasync, fptr) == 0)
2866 return rb_io_fsync(io);
2869#define rb_io_fdatasync rb_io_fsync
2887rb_io_fileno(
VALUE io)
2889 rb_io_t *fptr =
RFILE(io)->fptr;
2901 rb_io_t *fptr =
RFILE(io)->fptr;
2907 if (!UNDEF_P(fileno)) {
2974 rb_io_t *fptr =
RFILE(io)->fptr;
2995rb_io_inspect(
VALUE obj)
2999 static const char closed[] =
" (closed)";
3001 fptr =
RFILE(obj)->fptr;
3008 rb_str_cat(result, closed+1, strlen(closed)-1);
3011 rb_str_catf(result,
"fd %d", fptr->
fd);
3032rb_io_to_io(
VALUE io)
3039read_buffered_data(
char *ptr,
long len, rb_io_t *fptr)
3043 n = READ_DATA_PENDING_COUNT(fptr);
3044 if (n <= 0)
return 0;
3045 if (n >
len) n = (int)
len;
3053io_bufread(
char *ptr,
long len, rb_io_t *fptr)
3059 if (READ_DATA_PENDING(fptr) == 0) {
3063 c = rb_io_read_memory(fptr, ptr+offset, n);
3066 if (fptr_wait_readable(fptr))
3071 if ((n -= c) <= 0)
break;
3077 c = read_buffered_data(ptr+offset, n, fptr);
3080 if ((n -= c) <= 0)
break;
3083 if (io_fillbuf(fptr) < 0) {
3090static int io_setstrbuf(
VALUE *str,
long len);
3099bufread_call(
VALUE arg)
3102 p->len = io_bufread(p->str_ptr, p->len, p->fptr);
3107io_fread(
VALUE str,
long offset,
long size, rb_io_t *fptr)
3112 io_setstrbuf(&str, offset + size);
3113 arg.str_ptr = RSTRING_PTR(str) + offset;
3116 rb_str_locktmp_ensure(str, bufread_call, (
VALUE)&arg);
3118 if (
len < 0) rb_sys_fail_path(fptr->
pathv);
3123remain_size(rb_io_t *fptr)
3126 rb_off_t siz = READ_DATA_PENDING_COUNT(fptr);
3129 if (fstat(fptr->
fd, &st) == 0 && S_ISREG(st.st_mode)
3130#
if defined(__HAIKU__)
3135 if (io_fflush(fptr) < 0)
3136 rb_sys_fail_on_write(fptr);
3137 pos = lseek(fptr->
fd, 0, SEEK_CUR);
3138 if (st.st_size >= pos && pos >= 0) {
3139 siz += st.st_size - pos;
3140 if (siz > LONG_MAX) {
3141 rb_raise(
rb_eIOError,
"file too big for single read");
3152io_enc_str(
VALUE str, rb_io_t *fptr)
3154 rb_enc_associate(str, io_read_encoding(fptr));
3158static rb_encoding *io_read_encoding(rb_io_t *fptr);
3161make_readconv(rb_io_t *fptr,
int size)
3166 const char *sname, *dname;
3170 sname = rb_enc_name(fptr->
encs.
enc2);
3171 dname = rb_enc_name(io_read_encoding(fptr));
3181 if (size < IO_CBUF_CAPA_MIN) size = IO_CBUF_CAPA_MIN;
3187#define MORE_CHAR_SUSPENDED Qtrue
3188#define MORE_CHAR_FINISHED Qnil
3190fill_cbuf(rb_io_t *fptr,
int ec_flags)
3192 const unsigned char *ss, *sp, *se;
3193 unsigned char *ds, *dp, *de;
3202 return MORE_CHAR_SUSPENDED;
3213 ss = sp = (
const unsigned char *)fptr->
rbuf.
ptr + fptr->
rbuf.
off;
3218 fptr->
rbuf.
off += (int)(sp - ss);
3219 fptr->
rbuf.
len -= (int)(sp - ss);
3220 fptr->
cbuf.
len += (int)(dp - ds);
3225 fptr->
rbuf.
off -= putbackable;
3226 fptr->
rbuf.
len += putbackable;
3233 if (cbuf_len0 != fptr->
cbuf.
len)
3234 return MORE_CHAR_SUSPENDED;
3237 return MORE_CHAR_FINISHED;
3243 if (io_fillbuf(fptr) < 0) {
3245 return MORE_CHAR_FINISHED;
3250 fptr->
cbuf.
len += (int)(dp - ds);
3257 if (cbuf_len0 != fptr->
cbuf.
len)
3258 return MORE_CHAR_SUSPENDED;
3260 return MORE_CHAR_FINISHED;
3264more_char(rb_io_t *fptr)
3268 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED)
3274io_shift_cbuf(rb_io_t *fptr,
int len,
VALUE *strp)
3285 rb_enc_associate(str, fptr->
encs.
enc);
3314 long clen = RSTRING_LEN(s);
3326#define MAX_REALLOC_GAP 4096
3328io_shrink_read_string(
VALUE str,
long n)
3331 rb_str_resize(str, n);
3336io_set_read_length(
VALUE str,
long n,
int shrinkable)
3338 if (RSTRING_LEN(str) != n) {
3341 if (shrinkable) io_shrink_read_string(str, n);
3346read_all(rb_io_t *fptr,
long siz,
VALUE str)
3355 if (NEED_READCONV(fptr)) {
3356 int first = !
NIL_P(str);
3357 SET_BINARY_MODE(fptr);
3358 shrinkable = io_setstrbuf(&str,0);
3359 make_readconv(fptr, 0);
3364 io_shift_cbuf(fptr, fptr->
cbuf.
len, &str);
3366 v = fill_cbuf(fptr, 0);
3367 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED) {
3370 io_shift_cbuf(fptr, fptr->
cbuf.
len, &str);
3374 if (v == MORE_CHAR_FINISHED) {
3375 clear_readconv(fptr);
3377 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3378 return io_enc_str(str, fptr);
3383 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3387 enc = io_read_encoding(fptr);
3390 if (siz == 0) siz = BUFSIZ;
3391 shrinkable = io_setstrbuf(&str, siz);
3394 n = io_fread(str, bytes, siz - bytes, fptr);
3395 if (n == 0 && bytes == 0) {
3403 if (bytes < siz)
break;
3407 if (
capa < (
size_t)RSTRING_LEN(str) + BUFSIZ) {
3408 if (
capa < BUFSIZ) {
3411 else if (
capa > IO_MAX_BUFFER_GROWTH) {
3412 capa = IO_MAX_BUFFER_GROWTH;
3417 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3418 str = io_enc_str(str, fptr);
3426 if (rb_fd_set_nonblock(fptr->
fd) != 0) {
3427 rb_sys_fail_path(fptr->
pathv);
3432io_read_memory_call(
VALUE arg)
3437 if (scheduler !=
Qnil) {
3440 if (!UNDEF_P(result)) {
3446 if (iis->nonblock) {
3447 return rb_io_blocking_region(iis->fptr, internal_read_func, iis);
3450 return rb_io_blocking_region_wait(iis->fptr, internal_read_func, iis,
RUBY_IO_READABLE);
3457 return (
long)rb_str_locktmp_ensure(str, io_read_memory_call, (
VALUE)iis);
3460#define no_exception_p(opts) !rb_opts_exception_p((opts), TRUE)
3463io_getpartial(
int argc,
VALUE *argv,
VALUE io,
int no_exception,
int nonblock)
3474 rb_raise(rb_eArgError,
"negative length %ld given",
len);
3477 shrinkable = io_setstrbuf(&str,
len);
3483 io_set_read_length(str, 0, shrinkable);
3489 n = read_buffered_data(RSTRING_PTR(str),
len, fptr);
3495 io_setstrbuf(&str,
len);
3498 iis.nonblock = nonblock;
3500 iis.buf = RSTRING_PTR(str);
3503 n = io_read_memory_locktmp(str, &iis);
3506 if (!nonblock && fptr_wait_readable(fptr))
3508 if (nonblock && (io_again_p(e))) {
3510 return sym_wait_readable;
3513 e,
"read would block");
3515 rb_syserr_fail_path(e, fptr->
pathv);
3518 io_set_read_length(str, n, shrinkable);
3619io_readpartial(
int argc,
VALUE *argv,
VALUE io)
3623 ret = io_getpartial(argc, argv, io,
Qnil, 0);
3630io_nonblock_eof(
int no_exception)
3632 if (!no_exception) {
3648 rb_raise(rb_eArgError,
"negative length %ld given",
len);
3651 shrinkable = io_setstrbuf(&str,
len);
3652 rb_bool_expected(ex,
"exception", TRUE);
3658 io_set_read_length(str, 0, shrinkable);
3662 n = read_buffered_data(RSTRING_PTR(str),
len, fptr);
3664 rb_fd_set_nonblock(fptr->
fd);
3665 shrinkable |= io_setstrbuf(&str,
len);
3669 iis.buf = RSTRING_PTR(str);
3672 n = io_read_memory_locktmp(str, &iis);
3675 if (io_again_p(e)) {
3676 if (!ex)
return sym_wait_readable;
3678 e,
"read would block");
3680 rb_syserr_fail_path(e, fptr->
pathv);
3683 io_set_read_length(str, n, shrinkable);
3686 if (!ex)
return Qnil;
3695io_write_nonblock(rb_execution_context_t *ec,
VALUE io,
VALUE str,
VALUE ex)
3701 str = rb_obj_as_string(str);
3702 rb_bool_expected(ex,
"exception", TRUE);
3704 io = GetWriteIO(io);
3708 if (io_fflush(fptr) < 0)
3709 rb_sys_fail_on_write(fptr);
3711 rb_fd_set_nonblock(fptr->
fd);
3712 n = write(fptr->
fd, RSTRING_PTR(str), RSTRING_LEN(str));
3717 if (io_again_p(e)) {
3719 return sym_wait_writable;
3725 rb_syserr_fail_path(e, fptr->
pathv);
3809#if RUBY_CRLF_ENVIRONMENT
3815 if (
NIL_P(length)) {
3818 return read_all(fptr, remain_size(fptr), str);
3822 rb_raise(rb_eArgError,
"negative length %ld given",
len);
3825 shrinkable = io_setstrbuf(&str,
len);
3830 io_set_read_length(str, 0, shrinkable);
3835#if RUBY_CRLF_ENVIRONMENT
3836 previous_mode = set_binary_mode_with_seek_cur(fptr);
3838 n = io_fread(str, 0,
len, fptr);
3839 io_set_read_length(str, n, shrinkable);
3840#if RUBY_CRLF_ENVIRONMENT
3841 if (previous_mode == O_TEXT) {
3842 setmode(fptr->
fd, O_TEXT);
3845 if (n == 0)
return Qnil;
3851rscheck(
const char *rsptr,
long rslen,
VALUE rs)
3854 if (RSTRING_PTR(rs) != rsptr && RSTRING_LEN(rs) != rslen)
3859search_delim(
const char *p,
long len,
int delim, rb_encoding *enc)
3861 if (rb_enc_mbminlen(enc) == 1) {
3862 p = memchr(p, delim,
len);
3863 if (p)
return p + 1;
3866 const char *end = p +
len;
3868 int r = rb_enc_precise_mbclen(p, end, enc);
3870 p += rb_enc_mbminlen(enc);
3874 if (rb_enc_mbc_to_codepoint(p, end, enc) == (
unsigned int)delim) {
3884appendline(rb_io_t *fptr,
int delim,
VALUE *strp,
long *lp, rb_encoding *enc)
3889 if (NEED_READCONV(fptr)) {
3890 SET_BINARY_MODE(fptr);
3891 make_readconv(fptr, 0);
3894 int searchlen = READ_CHAR_PENDING_COUNT(fptr);
3896 p = READ_CHAR_PENDING_PTR(fptr);
3897 if (0 < limit && limit < searchlen)
3898 searchlen = (int)limit;
3899 e = search_delim(p, searchlen, delim, enc);
3901 int len = (int)(e-p);
3923 return (
unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
3926 }
while (more_char(fptr) != MORE_CHAR_FINISHED);
3927 clear_readconv(fptr);
3932 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3934 long pending = READ_DATA_PENDING_COUNT(fptr);
3936 const char *p = READ_DATA_PENDING_PTR(fptr);
3940 if (limit > 0 && pending > limit) pending = limit;
3941 e = search_delim(p, pending, delim, enc);
3942 if (e) pending = e - p;
3944 last = RSTRING_LEN(str);
3945 rb_str_resize(str, last + pending);
3952 read_buffered_data(RSTRING_PTR(str) + last, pending, fptr);
3955 if (e)
return delim;
3957 return (
unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
3960 }
while (io_fillbuf(fptr) >= 0);
3966swallow(rb_io_t *fptr,
int term)
3968 if (NEED_READCONV(fptr)) {
3969 rb_encoding *enc = io_read_encoding(fptr);
3970 int needconv = rb_enc_mbminlen(enc) != 1;
3971 SET_BINARY_MODE(fptr);
3972 make_readconv(fptr, 0);
3975 while ((cnt = READ_CHAR_PENDING_COUNT(fptr)) > 0) {
3976 const char *p = READ_CHAR_PENDING_PTR(fptr);
3979 if (*p != term)
return TRUE;
3981 while (--i && *++p == term);
3984 const char *e = p + cnt;
3985 if (rb_enc_ascget(p, e, &i, enc) != term)
return TRUE;
3986 while ((p += i) < e && rb_enc_ascget(p, e, &i, enc) == term);
3989 io_shift_cbuf(fptr, (
int)cnt - i, NULL);
3991 }
while (more_char(fptr) != MORE_CHAR_FINISHED);
3995 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3998 while ((cnt = READ_DATA_PENDING_COUNT(fptr)) > 0) {
4000 const char *p = READ_DATA_PENDING_PTR(fptr);
4002 if (cnt >
sizeof buf) cnt =
sizeof buf;
4003 if (*p != term)
return TRUE;
4005 while (--i && *++p == term);
4006 if (!read_buffered_data(buf, cnt - i, fptr))
4007 rb_sys_fail_path(fptr->
pathv);
4010 }
while (io_fillbuf(fptr) == 0);
4015rb_io_getline_fast(rb_io_t *fptr, rb_encoding *enc,
int chomp)
4023 int pending = READ_DATA_PENDING_COUNT(fptr);
4026 const char *p = READ_DATA_PENDING_PTR(fptr);
4030 e = memchr(p,
'\n', pending);
4032 pending = (int)(e - p + 1);
4034 chomplen = (pending > 1 && *(e-1) ==
'\r') + 1;
4043 rb_str_resize(str,
len + pending - chomplen);
4044 read_buffered_data(RSTRING_PTR(str)+
len, pending - chomplen, fptr);
4047 if (pending == 1 && chomplen == 1 &&
len > 0) {
4048 if (RSTRING_PTR(str)[
len-1] ==
'\r') {
4049 rb_str_resize(str, --
len);
4054 len += pending - chomplen;
4060 }
while (io_fillbuf(fptr) >= 0);
4063 str = io_enc_str(str, fptr);
4074 unsigned int chomp: 1;
4088 chomp = (!UNDEF_P(vchomp)) &&
RTEST(vchomp);
4090 args->chomp = chomp;
4108 else if (2 <= argc) {
4109 rs = argv[0], lim = argv[1];
4118check_getline_args(
VALUE *rsp,
long *limit,
VALUE io)
4124 rb_encoding *enc_rs, *enc_io;
4127 enc_rs = rb_enc_get(rs);
4128 enc_io = io_read_encoding(fptr);
4129 if (enc_io != enc_rs &&
4130 (!is_ascii_string(rs) ||
4131 (RSTRING_LEN(rs) > 0 && !rb_enc_asciicompat(enc_io)))) {
4133 rs = rb_enc_str_new(0, 0, enc_io);
4138 rb_raise(rb_eArgError,
"encoding mismatch: %s IO with %s RS",
4139 rb_enc_name(enc_io),
4140 rb_enc_name(enc_rs));
4150 argc =
rb_scan_args(argc, argv,
"02:", NULL, NULL, &opts);
4151 extract_getline_args(argc, argv, args);
4152 extract_getline_opts(opts, args);
4153 check_getline_args(&args->rs, &args->limit, io);
4157rb_io_getline_0(
VALUE rs,
long limit,
int chomp, rb_io_t *fptr)
4164 if (
NIL_P(rs) && limit < 0) {
4165 str = read_all(fptr, 0,
Qnil);
4166 if (RSTRING_LEN(str) == 0)
return Qnil;
4168 else if (limit == 0) {
4169 return rb_enc_str_new(0, 0, io_read_encoding(fptr));
4171 else if (rs ==
rb_default_rs && limit < 0 && !NEED_READCONV(fptr) &&
4172 rb_enc_asciicompat(enc = io_read_encoding(fptr))) {
4173 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4174 return rb_io_getline_fast(fptr, enc, chomp);
4177 int c, newline = -1;
4178 const char *rsptr = 0;
4181 int extra_limit = 16;
4182 int chomp_cr = chomp;
4184 SET_BINARY_MODE(fptr);
4185 enc = io_read_encoding(fptr);
4188 rslen = RSTRING_LEN(rs);
4193 swallow(fptr,
'\n');
4195 if (!rb_enc_asciicompat(enc)) {
4199 rsptr = RSTRING_PTR(rs);
4200 rslen = RSTRING_LEN(rs);
4204 else if (rb_enc_mbminlen(enc) == 1) {
4205 rsptr = RSTRING_PTR(rs);
4206 newline = (
unsigned char)rsptr[rslen - 1];
4210 rsptr = RSTRING_PTR(rs);
4211 const char *e = rsptr + rslen;
4212 const char *last = rb_enc_prev_char(rsptr, e, e, enc);
4214 newline = rb_enc_codepoint_len(last, e, &n, enc);
4215 if (last + n != e) rb_raise(rb_eArgError,
"broken separator");
4217 chomp_cr = chomp && newline ==
'\n' && rslen == rb_enc_mbminlen(enc);
4221 while ((c = appendline(fptr, newline, &str, &limit, enc)) != EOF) {
4222 const char *s, *p, *pp, *e;
4225 if (RSTRING_LEN(str) < rslen)
continue;
4226 s = RSTRING_PTR(str);
4229 if (!at_char_boundary(s, p, e, enc))
continue;
4230 if (!rspara) rscheck(rsptr, rslen, rs);
4231 if (memcmp(p, rsptr, rslen) == 0) {
4233 if (chomp_cr && p > s && *(p-1) ==
'\r') --p;
4240 s = RSTRING_PTR(str);
4242 pp = rb_enc_prev_char(s, p, p, enc);
4243 if (extra_limit && pp &&
4257 if (rspara && c != EOF)
4258 swallow(fptr,
'\n');
4260 str = io_enc_str(str, fptr);
4263 if (!
NIL_P(str) && !nolimit) {
4271rb_io_getline_1(
VALUE rs,
long limit,
int chomp,
VALUE io)
4274 int old_lineno, new_lineno;
4278 old_lineno = fptr->
lineno;
4279 str = rb_io_getline_0(rs, limit, chomp, fptr);
4280 if (!
NIL_P(str) && (new_lineno = fptr->
lineno) != old_lineno) {
4281 if (io == ARGF.current_file) {
4282 ARGF.lineno += new_lineno - old_lineno;
4283 ARGF.last_lineno = ARGF.lineno;
4286 ARGF.last_lineno = new_lineno;
4294rb_io_getline(
int argc,
VALUE *argv,
VALUE io)
4298 prepare_getline_args(argc, argv, &args, io);
4299 return rb_io_getline_1(args.rs, args.limit, args.chomp, io);
4309rb_io_gets_internal(
VALUE io)
4393 str = rb_io_getline(argc, argv, io);
4409rb_io_lineno(
VALUE io)
4464 check_getline_args(&sep, &limit, io);
4466 VALUE line = rb_io_getline_1(sep, limit,
RTEST(chomp), io);
4467 rb_lastline_set_up(line, 1);
4542rb_io_readlines(
int argc,
VALUE *argv,
VALUE io)
4546 prepare_getline_args(argc, argv, &args, io);
4547 return io_readlines(&args, io);
4555 if (arg->limit == 0)
4556 rb_raise(rb_eArgError,
"invalid limit: 0 for readlines");
4558 while (!
NIL_P(line = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, io))) {
4559 rb_ary_push(ary, line);
4671rb_io_each_line(
int argc,
VALUE *argv,
VALUE io)
4677 prepare_getline_args(argc, argv, &args, io);
4678 if (args.limit == 0)
4679 rb_raise(rb_eArgError,
"invalid limit: 0 for each_line");
4680 while (!
NIL_P(str = rb_io_getline_1(args.rs, args.limit, args.chomp, io))) {
4707rb_io_each_byte(
VALUE io)
4723 }
while (io_fillbuf(fptr) >= 0);
4728io_getc(rb_io_t *fptr, rb_encoding *enc)
4733 if (NEED_READCONV(fptr)) {
4734 rb_encoding *read_enc = io_read_encoding(fptr);
4737 SET_BINARY_MODE(fptr);
4738 make_readconv(fptr, 0);
4752 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4754 clear_readconv(fptr);
4758 str = rb_enc_str_new(fptr->
cbuf.
ptr+fptr->
cbuf.
off, 1, read_enc);
4761 if (fptr->
cbuf.
len == 0) clear_readconv(fptr);
4770 io_shift_cbuf(fptr, r, &str);
4777 ISASCII(RSTRING_PTR(str)[0])) {
4781 str = io_enc_str(str, fptr);
4786 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4787 if (io_fillbuf(fptr) < 0) {
4790 if (rb_enc_asciicompat(enc) && ISASCII(fptr->
rbuf.
ptr[fptr->
rbuf.
off])) {
4809 if (io_fillbuf(fptr) != -1) {
4813 r = rb_enc_precise_mbclen(RSTRING_PTR(str), RSTRING_PTR(str)+RSTRING_LEN(str), enc);
4829 str = io_enc_str(str, fptr);
4855rb_io_each_char(
VALUE io)
4865 enc = io_input_encoding(fptr);
4867 while (!
NIL_P(c = io_getc(fptr, enc))) {
4893rb_io_each_codepoint(
VALUE io)
4905 if (NEED_READCONV(fptr)) {
4906 SET_BINARY_MODE(fptr);
4909 make_readconv(fptr, 0);
4917 r = ONIGENC_CONSTRUCT_MBCLEN_CHARFOUND(1);
4924 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4925 clear_readconv(fptr);
4952 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4953 enc = io_input_encoding(fptr);
4954 while (io_fillbuf(fptr) >= 0) {
4969 char cbuf[8], *p = cbuf;
4971 if (more > numberof(cbuf))
goto invalid;
4973 if (more > numberof(cbuf))
goto invalid;
4974 while ((n = (
int)read_buffered_data(p, more, fptr)) > 0 &&
4975 (p += n, (more -= n) > 0)) {
4976 if (io_fillbuf(fptr) < 0)
goto invalid;
4977 if ((n = fptr->
rbuf.
len) > more) n = more;
4979 r = rb_enc_precise_mbclen(cbuf, p, enc);
4992 rb_raise(rb_eArgError,
"invalid byte sequence in %s", rb_enc_name(enc));
5024 enc = io_input_encoding(fptr);
5026 return io_getc(fptr, enc);
5049rb_io_readchar(
VALUE io)
5051 VALUE c = rb_io_getc(io);
5091 rb_io_flush(r_stdout);
5094 if (io_fillbuf(fptr) < 0) {
5123rb_io_readbyte(
VALUE io)
5184 unsigned char c =
NUM2INT(v) & 0xFF;
5190 io_ungetbyte(b, fptr);
5246 else if (RB_BIGNUM_TYPE_P(c)) {
5252 if (NEED_READCONV(fptr)) {
5253 SET_BINARY_MODE(fptr);
5254 len = RSTRING_LEN(c);
5255#if SIZEOF_LONG > SIZEOF_INT
5259 make_readconv(fptr, (
int)
len);
5273 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
5274 io_ungetbyte(c, fptr);
5294rb_io_isatty(
VALUE io)
5299 return RBOOL(isatty(fptr->
fd) != 0);
5302#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5318rb_io_close_on_exec_p(
VALUE io)
5324 write_io = GetWriteIO(io);
5325 if (io != write_io) {
5327 if (fptr && 0 <= (fd = fptr->
fd)) {
5328 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->
pathv);
5329 if (!(ret & FD_CLOEXEC))
return Qfalse;
5334 if (fptr && 0 <= (fd = fptr->
fd)) {
5335 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->
pathv);
5336 if (!(ret & FD_CLOEXEC))
return Qfalse;
5341#define rb_io_close_on_exec_p rb_f_notimplement
5344#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5368 int flag =
RTEST(arg) ? FD_CLOEXEC : 0;
5373 write_io = GetWriteIO(io);
5374 if (io != write_io) {
5376 if (fptr && 0 <= (fd = fptr->
fd)) {
5377 if ((ret = fcntl(fptr->
fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->
pathv);
5378 if ((ret & FD_CLOEXEC) != flag) {
5379 ret = (ret & ~FD_CLOEXEC) | flag;
5380 ret = fcntl(fd, F_SETFD, ret);
5381 if (ret != 0) rb_sys_fail_path(fptr->
pathv);
5388 if (fptr && 0 <= (fd = fptr->
fd)) {
5389 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->
pathv);
5390 if ((ret & FD_CLOEXEC) != flag) {
5391 ret = (ret & ~FD_CLOEXEC) | flag;
5392 ret = fcntl(fd, F_SETFD, ret);
5393 if (ret != 0) rb_sys_fail_path(fptr->
pathv);
5399#define rb_io_set_close_on_exec rb_f_notimplement
5402#define RUBY_IO_EXTERNAL_P(f) ((f)->mode & FMODE_EXTERNAL)
5403#define PREP_STDIO_NAME(f) (RSTRING_PTR((f)->pathv))
5406finish_writeconv(rb_io_t *fptr,
int noalloc)
5408 unsigned char *ds, *dp, *de;
5412 unsigned char buf[1024];
5417 de = buf +
sizeof(buf);
5420 size_t remaining = dp-ds;
5421 long result = rb_io_write_memory(fptr, ds, remaining);
5425 if ((
size_t)result == remaining)
break;
5448 if (io_fflush(fptr) < 0) {
5456 fptr->
wbuf.
len += (int)(dp - ds);
5472finish_writeconv_sync(
VALUE arg)
5475 return finish_writeconv(p->fptr, p->noalloc);
5479nogvl_close(
void *ptr)
5483 return (
void*)(intptr_t)close(*fd);
5487maygvl_close(
int fd,
int keepgvl)
5496 return IO_WITHOUT_GVL_INT(nogvl_close, &fd);
5500nogvl_fclose(
void *ptr)
5504 return (
void*)(intptr_t)fclose(file);
5508maygvl_fclose(FILE *file,
int keepgvl)
5511 return fclose(file);
5513 return IO_WITHOUT_GVL_INT(nogvl_fclose, file);
5519fptr_finalize_flush(rb_io_t *fptr,
int noraise,
int keepgvl,
5525 int mode = fptr->
mode;
5531 arg.noalloc = noraise;
5535 error = finish_writeconv(fptr, noraise);
5540 io_flush_buffer_sync(fptr);
5543 if (io_fflush(fptr) < 0 &&
NIL_P(error)) {
5551 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2) {
5563 rb_notify_fd_close_wait(busy);
5575 if (!done && stdio_file) {
5577 if ((maygvl_fclose(stdio_file, noraise) < 0) &&
NIL_P(error)) {
5586 if (!done && fd >= 0) {
5592 if ((maygvl_close(fd, keepgvl) < 0) &&
NIL_P(error)) {
5601 if (!
NIL_P(error) && !noraise) {
5605 rb_exc_raise(error);
5610fptr_finalize(rb_io_t *fptr,
int noraise)
5612 fptr_finalize_flush(fptr, noraise, FALSE, 0);
5613 free_io_buffer(&fptr->
rbuf);
5614 free_io_buffer(&fptr->
wbuf);
5615 clear_codeconv(fptr);
5619rb_io_fptr_cleanup(rb_io_t *fptr,
int noraise)
5625 fptr_finalize(fptr, noraise);
5633 ruby_sized_xfree(buf->ptr, (
size_t)buf->capa);
5639clear_readconv(rb_io_t *fptr)
5645 free_io_buffer(&fptr->
cbuf);
5649clear_writeconv(rb_io_t *fptr)
5659clear_codeconv(rb_io_t *fptr)
5661 clear_readconv(fptr);
5662 clear_writeconv(fptr);
5666rb_io_fptr_cleanup_all(rb_io_t *fptr)
5670 rb_io_fptr_cleanup(fptr, TRUE);
5672 free_io_buffer(&fptr->
rbuf);
5673 free_io_buffer(&fptr->
wbuf);
5674 clear_codeconv(fptr);
5678rb_io_fptr_finalize_internal(
void *ptr)
5681 rb_io_fptr_cleanup_all(ptr);
5685#undef rb_io_fptr_finalize
5687rb_io_fptr_finalize(rb_io_t *fptr)
5693 rb_io_fptr_finalize_internal(fptr);
5697#define rb_io_fptr_finalize(fptr) rb_io_fptr_finalize_internal(fptr)
5700rb_io_memsize(
const rb_io_t *fptr)
5702 size_t size =
sizeof(rb_io_t);
5713# define KEEPGVL TRUE
5715# define KEEPGVL FALSE
5719io_close_fptr(
VALUE io)
5723 rb_io_t *write_fptr;
5726 write_io = GetWriteIO(io);
5727 if (io != write_io) {
5728 write_fptr =
RFILE(write_io)->fptr;
5729 if (write_fptr && 0 <= write_fptr->
fd) {
5730 rb_io_fptr_cleanup(write_fptr, TRUE);
5734 fptr =
RFILE(io)->fptr;
5735 if (!fptr)
return 0;
5736 if (fptr->
fd < 0)
return 0;
5738 if (rb_notify_fd_close(fptr->
fd, &busy)) {
5740 fptr_finalize_flush(fptr, FALSE, KEEPGVL, &busy);
5742 rb_io_fptr_cleanup(fptr, FALSE);
5747fptr_waitpid(rb_io_t *fptr,
int nohang)
5751 rb_last_status_clear();
5760 rb_io_t *fptr = io_close_fptr(io);
5761 if (fptr) fptr_waitpid(fptr, 0);
5801rb_io_close_m(
VALUE io)
5803 rb_io_t *fptr = rb_io_get_fptr(io);
5812io_call_close(
VALUE io)
5821 enum {mesg_len =
sizeof(closed_stream)-1};
5822 VALUE mesg = rb_attr_get(exc, idMesg);
5824 RSTRING_LEN(mesg) != mesg_len ||
5825 memcmp(RSTRING_PTR(mesg), closed_stream, mesg_len)) {
5835 if (!UNDEF_P(closed) &&
RTEST(closed))
return io;
5836 rb_rescue2(io_call_close, io, ignore_closed_stream, io,
5870 rb_io_t *write_fptr;
5872 write_io = GetWriteIO(io);
5873 if (io != write_io) {
5874 write_fptr =
RFILE(write_io)->fptr;
5875 if (write_fptr && 0 <= write_fptr->
fd) {
5880 fptr = rb_io_get_fptr(io);
5881 return RBOOL(0 > fptr->
fd);
5917rb_io_close_read(
VALUE io)
5923 if (fptr->
fd < 0)
return Qnil;
5924 if (is_socket(fptr->
fd, fptr->
pathv)) {
5928 if (shutdown(fptr->
fd, SHUT_RD) < 0)
5929 rb_sys_fail_path(fptr->
pathv);
5936 write_io = GetWriteIO(io);
5937 if (io != write_io) {
5942 RFILE(io)->fptr = wfptr;
5945 RFILE(write_io)->fptr = fptr;
5946 rb_io_fptr_cleanup(fptr, FALSE);
5952 rb_raise(
rb_eIOError,
"closing non-duplex IO for reading");
5990rb_io_close_write(
VALUE io)
5995 write_io = GetWriteIO(io);
5997 if (fptr->
fd < 0)
return Qnil;
5998 if (is_socket(fptr->
fd, fptr->
pathv)) {
6002 if (shutdown(fptr->
fd, SHUT_WR) < 0)
6003 rb_sys_fail_path(fptr->
pathv);
6011 rb_raise(
rb_eIOError,
"closing non-duplex IO for writing");
6014 if (io != write_io) {
6034rb_io_sysseek(
int argc,
VALUE *argv,
VALUE io)
6036 VALUE offset, ptrname;
6037 int whence = SEEK_SET;
6041 if (
rb_scan_args(argc, argv,
"11", &offset, &ptrname) == 2) {
6042 whence = interpret_seek_whence(ptrname);
6047 (READ_DATA_BUFFERED(fptr) || READ_CHAR_PENDING(fptr))) {
6051 rb_warn(
"sysseek for buffered IO");
6054 pos = lseek(fptr->
fd, pos, whence);
6055 if (pos < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
6087 str = rb_obj_as_string(str);
6089 io = GetWriteIO(io);
6094 rb_warn(
"syswrite for buffered IO");
6097 tmp = rb_str_tmp_frozen_acquire(str);
6099 n = rb_io_write_memory(fptr, ptr,
len);
6100 if (n < 0) rb_sys_fail_path(fptr->
pathv);
6101 rb_str_tmp_frozen_release(str, tmp);
6118rb_io_sysread(
int argc,
VALUE *argv,
VALUE io)
6129 shrinkable = io_setstrbuf(&str, ilen);
6130 if (ilen == 0)
return str;
6135 if (READ_DATA_BUFFERED(fptr)) {
6141 io_setstrbuf(&str, ilen);
6146 iis.buf = RSTRING_PTR(str);
6149 n = io_read_memory_locktmp(str, &iis);
6152 rb_sys_fail_path(fptr->
pathv);
6155 io_set_read_length(str, n, shrinkable);
6157 if (n == 0 && ilen > 0) {
6173internal_pread_func(
void *_arg)
6177 return (
VALUE)pread(arg->fd, arg->buf, arg->count, arg->offset);
6181pread_internal_call(
VALUE _arg)
6186 if (scheduler !=
Qnil) {
6189 if (!UNDEF_P(result)) {
6194 return rb_io_blocking_region_wait(arg->io, internal_pread_func, arg,
RUBY_IO_READABLE);
6238 shrinkable = io_setstrbuf(&str, (
long)arg.count);
6239 if (arg.count == 0)
return str;
6240 arg.buf = RSTRING_PTR(str);
6253 rb_sys_fail_path(fptr->
pathv);
6255 io_set_read_length(str, n, shrinkable);
6256 if (n == 0 && arg.count > 0) {
6264internal_pwrite_func(
void *_arg)
6269 if (scheduler !=
Qnil) {
6272 if (!UNDEF_P(result)) {
6278 return (
VALUE)pwrite(arg->fd, arg->buf, arg->count, arg->offset);
6315 str = rb_obj_as_string(str);
6319 io = GetWriteIO(io);
6326 tmp = rb_str_tmp_frozen_acquire(str);
6327 arg.buf = RSTRING_PTR(tmp);
6328 arg.count = (size_t)RSTRING_LEN(tmp);
6330 n = (ssize_t)rb_io_blocking_region_wait(fptr, internal_pwrite_func, &arg,
RUBY_IO_WRITABLE);
6331 if (n < 0) rb_sys_fail_path(fptr->
pathv);
6332 rb_str_tmp_frozen_release(str, tmp);
6352 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6355 setmode(fptr->
fd, O_BINARY);
6362io_ascii8bit_binmode(rb_io_t *fptr)
6374 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6380 clear_codeconv(fptr);
6389 io_ascii8bit_binmode(fptr);
6406rb_io_binmode_m(
VALUE io)
6412 write_io = GetWriteIO(io);
6427rb_io_binmode_p(
VALUE io)
6435rb_io_fmode_modestr(
int fmode)
6439 return MODE_BTMODE(
"a+",
"ab+",
"at+");
6441 return MODE_BTMODE(
"a",
"ab",
"at");
6445 rb_raise(rb_eArgError,
"invalid access fmode 0x%x", fmode);
6447 return MODE_BTMODE(
"r",
"rb",
"rt");
6449 return MODE_BTXMODE(
"w",
"wb",
"wt",
"wx",
"wbx",
"wtx");
6452 return MODE_BTXMODE(
"w+",
"wb+",
"wt+",
"w+x",
"wb+x",
"wt+x");
6454 return MODE_BTMODE(
"r+",
"rb+",
"rt+");
6458static const char bom_prefix[] =
"bom|";
6459static const char utf_prefix[] =
"utf-";
6460enum {bom_prefix_len = (int)
sizeof(bom_prefix) - 1};
6461enum {utf_prefix_len = (int)
sizeof(utf_prefix) - 1};
6464io_encname_bom_p(
const char *name,
long len)
6466 return len > bom_prefix_len &&
STRNCASECMP(name, bom_prefix, bom_prefix_len) == 0;
6473 const char *m = modestr, *p = NULL;
6501 if (modestr[0] !=
'w')
6509 if (io_encname_bom_p(m, p ? (
long)(p - m) : (
long)strlen(m)))
6522 rb_raise(rb_eArgError,
"invalid access mode %s", modestr);
6531 switch (oflags & O_ACCMODE) {
6543 if (oflags & O_APPEND) {
6546 if (oflags & O_TRUNC) {
6549 if (oflags & O_CREAT) {
6552 if (oflags & O_EXCL) {
6556 if (oflags & O_BINARY) {
6565rb_io_fmode_oflags(
int fmode)
6609rb_io_oflags_modestr(
int oflags)
6612# define MODE_BINARY(a,b) ((oflags & O_BINARY) ? (b) : (a))
6614# define MODE_BINARY(a,b) (a)
6617 if (oflags & O_EXCL) {
6618 rb_raise(rb_eArgError,
"exclusive access mode is not supported");
6620 accmode = oflags & (O_RDONLY|O_WRONLY|O_RDWR);
6621 if (oflags & O_APPEND) {
6622 if (accmode == O_WRONLY) {
6623 return MODE_BINARY(
"a",
"ab");
6625 if (accmode == O_RDWR) {
6626 return MODE_BINARY(
"a+",
"ab+");
6631 rb_raise(rb_eArgError,
"invalid access oflags 0x%x", oflags);
6633 return MODE_BINARY(
"r",
"rb");
6635 return MODE_BINARY(
"w",
"wb");
6637 if (oflags & O_TRUNC) {
6638 return MODE_BINARY(
"w+",
"wb+");
6640 return MODE_BINARY(
"r+",
"rb+");
6650rb_io_ext_int_to_encs(rb_encoding *ext, rb_encoding *intern, rb_encoding **enc, rb_encoding **enc2,
int fmode)
6652 int default_ext = 0;
6658 if (rb_is_ascii8bit_enc(ext)) {
6662 else if (intern == NULL) {
6665 if (intern == NULL || intern == (rb_encoding *)
Qnil ||
6668 *enc = (default_ext && intern != ext) ? NULL : ext;
6678unsupported_encoding(
const char *name, rb_encoding *enc)
6680 rb_enc_warn(enc,
"Unsupported encoding %s ignored", name);
6684parse_mode_enc(
const char *estr, rb_encoding *estr_enc,
6685 rb_encoding **enc_p, rb_encoding **enc2_p,
int *fmode_p)
6690 int fmode = fmode_p ? *fmode_p : 0;
6691 rb_encoding *ext_enc, *int_enc;
6696 p = strrchr(estr,
':');
6697 len = p ? (p++ - estr) : (long)strlen(estr);
6699 estr += bom_prefix_len;
6700 len -= bom_prefix_len;
6701 if (!
STRNCASECMP(estr, utf_prefix, utf_prefix_len)) {
6705 rb_enc_warn(estr_enc,
"BOM with non-UTF encoding %s is nonsense", estr);
6714 memcpy(encname, estr,
len);
6715 encname[
len] =
'\0';
6718 idx = rb_enc_find_index(estr);
6720 if (fmode_p) *fmode_p = fmode;
6723 ext_enc = rb_enc_from_index(idx);
6726 unsupported_encoding(estr, estr_enc);
6732 if (*p ==
'-' && *(p+1) ==
'\0') {
6734 int_enc = (rb_encoding *)
Qnil;
6737 idx2 = rb_enc_find_index(p);
6739 unsupported_encoding(p, estr_enc);
6741 int_enc = (rb_encoding *)
Qnil;
6744 int_enc = rb_enc_from_index(idx2);
6748 rb_io_ext_int_to_encs(ext_enc, int_enc, enc_p, enc2_p, fmode);
6756 rb_encoding *extencoding = NULL;
6757 rb_encoding *intencoding = NULL;
6761 v = rb_hash_lookup2(opt, sym_encoding,
Qnil);
6762 if (v !=
Qnil) encoding = v;
6763 v = rb_hash_lookup2(opt, sym_extenc,
Qundef);
6764 if (v !=
Qnil) extenc = v;
6765 v = rb_hash_lookup2(opt, sym_intenc,
Qundef);
6766 if (!UNDEF_P(v)) intenc = v;
6768 if ((!UNDEF_P(extenc) || !UNDEF_P(intenc)) && !
NIL_P(encoding)) {
6770 int idx = rb_to_encoding_index(encoding);
6771 if (idx >= 0) encoding = rb_enc_from_encoding(rb_enc_from_index(idx));
6772 rb_warn(
"Ignoring encoding parameter '%"PRIsVALUE
"': %s_encoding is used",
6773 encoding, UNDEF_P(extenc) ?
"internal" :
"external");
6777 if (!UNDEF_P(extenc) && !
NIL_P(extenc)) {
6778 extencoding = rb_to_encoding(extenc);
6780 if (!UNDEF_P(intenc)) {
6781 if (
NIL_P(intenc)) {
6783 intencoding = (rb_encoding *)
Qnil;
6788 if (*p ==
'-' && *(p+1) ==
'\0') {
6790 intencoding = (rb_encoding *)
Qnil;
6793 intencoding = rb_to_encoding(intenc);
6797 intencoding = rb_to_encoding(intenc);
6799 if (extencoding == intencoding) {
6800 intencoding = (rb_encoding *)
Qnil;
6803 if (!
NIL_P(encoding)) {
6807 enc_p, enc2_p, fmode_p);
6810 rb_io_ext_int_to_encs(rb_to_encoding(encoding), NULL, enc_p, enc2_p, 0);
6813 else if (!UNDEF_P(extenc) || !UNDEF_P(intenc)) {
6815 rb_io_ext_int_to_encs(extencoding, intencoding, enc_p, enc2_p, 0);
6821validate_enc_binmode(
int *fmode_p,
int ecflags, rb_encoding *enc, rb_encoding *enc2)
6823 int fmode = *fmode_p;
6829 rb_raise(rb_eArgError,
"ASCII incompatible encoding needs binmode");
6832 rb_raise(rb_eArgError,
"newline decorator with binary mode");
6839#if !DEFAULT_TEXTMODE
6848extract_binmode(
VALUE opthash,
int *fmode)
6850 if (!
NIL_P(opthash)) {
6852 v = rb_hash_aref(opthash, sym_textmode);
6855 rb_raise(rb_eArgError,
"textmode specified twice");
6857 rb_raise(rb_eArgError,
"both textmode and binmode specified");
6861 v = rb_hash_aref(opthash, sym_binmode);
6864 rb_raise(rb_eArgError,
"binmode specified twice");
6866 rb_raise(rb_eArgError,
"both textmode and binmode specified");
6872 rb_raise(rb_eArgError,
"both textmode and binmode specified");
6878 int *oflags_p,
int *fmode_p,
struct rb_io_encoding *convconfig_p)
6882 rb_encoding *enc, *enc2;
6885 int has_enc = 0, has_vmode = 0;
6891 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
6909 oflags = rb_io_fmode_oflags(fmode);
6913 parse_mode_enc(p+1, rb_enc_get(vmode), &enc, &enc2, &fmode);
6919 rb_io_ext_int_to_encs(e, NULL, &enc, &enc2, fmode);
6923 if (
NIL_P(opthash)) {
6927#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
6929 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
6930 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
6932 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
6942 else if (
NIL_P(vmode)) {
6943 fmode |= DEFAULT_TEXTMODE;
6950 v = rb_hash_aref(opthash, sym_mode);
6952 if (!
NIL_P(vmode)) {
6953 rb_raise(rb_eArgError,
"mode specified twice");
6960 v = rb_hash_aref(opthash, sym_flags);
6967 extract_binmode(opthash, &fmode);
6976 else if (
NIL_P(vmode)) {
6977 fmode |= DEFAULT_TEXTMODE;
6980 v = rb_hash_aref(opthash, sym_perm);
6983 if (!
NIL_P(*vperm_p)) {
6984 rb_raise(rb_eArgError,
"perm specified twice");
6995#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
6997 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
6998 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7003 rb_raise(rb_eArgError,
"encoding specified twice");
7006 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
7010 validate_enc_binmode(&fmode, ecflags, enc, enc2);
7016 convconfig_p->
enc = enc;
7017 convconfig_p->
enc2 = enc2;
7018 convconfig_p->
ecflags = ecflags;
7019 convconfig_p->
ecopts = ecopts;
7029sysopen_func(
void *ptr)
7032 const char *fname = RSTRING_PTR(data->fname);
7041 fd = IO_WITHOUT_GVL_INT(sysopen_func, data);
7042 }
while (fd < 0 &&
errno == EINTR);
7049rb_sysopen(
VALUE fname,
int oflags, mode_t perm)
7054 data.fname = rb_str_encode_ospath(fname);
7056 data.oflags = oflags;
7059 TRY_WITH_GC((fd = rb_sysopen_internal(&data)) >= 0) {
7060 rb_syserr_fail_path(first_errno, fname);
7066fdopen_internal(
int fd,
const char *modestr)
7073 file = fdopen(fd, modestr);
7089 TRY_WITH_GC((file = fdopen_internal(fd, modestr)) != 0) {
7095 if (setvbuf(file, NULL, _IOFBF, 0) != 0)
7096 rb_warn(
"setvbuf() can't be honoured (fd=%d)", fd);
7102io_check_tty(rb_io_t *fptr)
7104 int t = isatty(fptr->
fd);
7114io_strip_bom(
VALUE io)
7116 VALUE b1, b2, b3, b4;
7137 return ENCINDEX_UTF_16BE;
7148 return ENCINDEX_UTF_32LE;
7153 return ENCINDEX_UTF_16LE;
7163 return ENCINDEX_UTF_32BE;
7177io_set_encoding_by_bom(
VALUE io)
7179 int idx = io_strip_bom(io);
7181 rb_encoding *extenc = NULL;
7185 extenc = rb_enc_from_index(idx);
7186 io_encoding_set(fptr, rb_enc_from_encoding(extenc),
7187 rb_io_internal_encoding(io),
Qnil);
7196rb_file_open_generic(
VALUE io,
VALUE filename,
int oflags,
int fmode,
7204 rb_io_ext_int_to_encs(NULL, NULL, &cc.enc, &cc.enc2, fmode);
7209 validate_enc_binmode(&fmode, convconfig->
ecflags,
7210 convconfig->
enc, convconfig->
enc2);
7214 fptr->
encs = *convconfig;
7217 if (!(oflags & O_TMPFILE)) {
7218 fptr->
pathv = pathv;
7221 fptr->
pathv = pathv;
7223 fptr->
fd = rb_sysopen(pathv, oflags, perm);
7231rb_file_open_internal(
VALUE io,
VALUE filename,
const char *modestr)
7234 const char *p = strchr(modestr,
':');
7239 &convconfig.
enc, &convconfig.
enc2, &fmode);
7246 rb_io_ext_int_to_encs(e, NULL, &convconfig.
enc, &convconfig.
enc2, fmode);
7252#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7254 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7255 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7257 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.
enc2, convconfig.
ecflags);
7260 return rb_file_open_generic(io, filename,
7261 rb_io_fmode_oflags(fmode),
7271 return rb_file_open_internal(io_alloc(
rb_cFile), fname, modestr);
7280#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7287pipe_add_fptr(rb_io_t *fptr)
7298pipe_del_fptr(rb_io_t *fptr)
7303 while ((tmp = *prev) != 0) {
7304 if (tmp->fptr == fptr) {
7313#if defined (_WIN32) || defined(__CYGWIN__)
7322 rb_io_fptr_finalize(list->fptr);
7329pipe_finalize(rb_io_t *fptr,
int noraise)
7331#if !defined(HAVE_WORKING_FORK) && !defined(_WIN32)
7340 fptr_finalize(fptr, noraise);
7342 pipe_del_fptr(fptr);
7347fptr_copy_finalizer(rb_io_t *fptr,
const rb_io_t *orig)
7349#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7350 void (*
const old_finalize)(
struct rb_io*,int) = fptr->
finalize;
7352 if (old_finalize == orig->finalize)
return;
7357#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7358 if (old_finalize != pipe_finalize) {
7360 for (list =
pipe_list; list; list = list->next) {
7361 if (list->fptr == fptr)
break;
7363 if (!list) pipe_add_fptr(fptr);
7366 pipe_del_fptr(fptr);
7379rb_io_unbuffered(rb_io_t *fptr)
7397#define HAVE_SPAWNV 1
7398#define spawnv(mode, cmd, args) rb_w32_uaspawn((mode), (cmd), (args))
7399#define spawn(mode, cmd) rb_w32_uspawn((mode), (cmd), 0)
7402#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7405 struct rb_execarg *eargp;
7412#ifdef HAVE_WORKING_FORK
7413# ifndef __EMSCRIPTEN__
7415popen_redirect(
struct popen_arg *p)
7418 close(p->write_pair[1]);
7419 if (p->write_pair[0] != 0) {
7420 dup2(p->write_pair[0], 0);
7421 close(p->write_pair[0]);
7424 if (p->pair[1] != 1) {
7425 dup2(p->pair[1], 1);
7431 if (p->pair[1] != 1) {
7432 dup2(p->pair[1], 1);
7438 if (p->pair[0] != 0) {
7439 dup2(p->pair[0], 0);
7446#if defined(__linux__)
7457linux_get_maxfd(
void)
7460 char buf[4096], *p, *np, *e;
7463 if (fd < 0)
return fd;
7464 ss = read(fd, buf,
sizeof(buf));
7465 if (ss < 0)
goto err;
7468 while ((
int)
sizeof(
"FDSize:\t0\n")-1 <= e-p &&
7469 (np = memchr(p,
'\n', e-p)) != NULL) {
7470 if (memcmp(p,
"FDSize:",
sizeof(
"FDSize:")-1) == 0) {
7472 p +=
sizeof(
"FDSize:")-1;
7492#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
7494 int max = (int)max_file_descriptor;
7497 ret = fcntl(0, F_MAXFD);
7499 maxhint = max = ret;
7500# elif defined(__linux__)
7501 ret = linux_get_maxfd();
7508 for (fd = lowfd; fd <= max; fd++) {
7509 if (!
NIL_P(noclose_fds) &&
7512 ret = fcntl(fd, F_GETFD);
7513 if (ret != -1 && !(ret & FD_CLOEXEC)) {
7514 fcntl(fd, F_SETFD, ret|FD_CLOEXEC);
7516# define CONTIGUOUS_CLOSED_FDS 20
7518 if (max < fd + CONTIGUOUS_CLOSED_FDS)
7519 max = fd + CONTIGUOUS_CLOSED_FDS;
7525# ifndef __EMSCRIPTEN__
7527popen_exec(
void *pp,
char *errmsg,
size_t errmsg_len)
7529 struct popen_arg *p = (
struct popen_arg*)pp;
7531 return rb_exec_async_signal_safe(p->eargp, errmsg, errmsg_len);
7536#if (defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)) && !defined __EMSCRIPTEN__
7538rb_execarg_fixup_v(
VALUE execarg_obj)
7540 rb_execarg_parent_start(execarg_obj);
7544char *rb_execarg_commandline(
const struct rb_execarg *eargp,
VALUE *prog);
7547#ifndef __EMSCRIPTEN__
7549pipe_open(
VALUE execarg_obj,
const char *modestr,
int fmode,
7552 struct rb_execarg *eargp =
NIL_P(execarg_obj) ? NULL : rb_execarg_get(execarg_obj);
7553 VALUE prog = eargp ? (eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name) :
Qfalse ;
7557 rb_io_t *write_fptr;
7559#if defined(HAVE_WORKING_FORK)
7561 char errmsg[80] = {
'\0' };
7563#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7565 struct popen_arg arg;
7568#if defined(HAVE_SPAWNV)
7569# if defined(HAVE_SPAWNVE)
7570# define DO_SPAWN(cmd, args, envp) ((args) ? \
7571 spawnve(P_NOWAIT, (cmd), (args), (envp)) : \
7572 spawne(P_NOWAIT, (cmd), (envp)))
7574# define DO_SPAWN(cmd, args, envp) ((args) ? \
7575 spawnv(P_NOWAIT, (cmd), (args)) : \
7576 spawn(P_NOWAIT, (cmd)))
7578# if !defined(HAVE_WORKING_FORK)
7580# if defined(HAVE_SPAWNVE)
7585#if !defined(HAVE_WORKING_FORK)
7591#if !defined(HAVE_WORKING_FORK)
7592 const char *cmd = 0;
7598#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7599 arg.execarg_obj = execarg_obj;
7602 arg.pair[0] = arg.pair[1] = -1;
7603 arg.write_pair[0] = arg.write_pair[1] = -1;
7604# if !defined(HAVE_WORKING_FORK)
7605 if (eargp && !eargp->use_shell) {
7606 args = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
7611 if (
rb_pipe(arg.write_pair) < 0)
7612 rb_sys_fail_str(prog);
7615 close(arg.write_pair[0]);
7616 close(arg.write_pair[1]);
7620 rb_execarg_addopt(execarg_obj,
INT2FIX(0),
INT2FIX(arg.write_pair[0]));
7621 rb_execarg_addopt(execarg_obj,
INT2FIX(1),
INT2FIX(arg.pair[1]));
7626 rb_sys_fail_str(prog);
7628 rb_execarg_addopt(execarg_obj,
INT2FIX(1),
INT2FIX(arg.pair[1]));
7632 rb_sys_fail_str(prog);
7634 rb_execarg_addopt(execarg_obj,
INT2FIX(0),
INT2FIX(arg.pair[0]));
7637 rb_sys_fail_str(prog);
7639 if (!
NIL_P(execarg_obj)) {
7640 rb_protect(rb_execarg_fixup_v, execarg_obj, &state);
7642 if (0 <= arg.write_pair[0]) close(arg.write_pair[0]);
7643 if (0 <= arg.write_pair[1]) close(arg.write_pair[1]);
7644 if (0 <= arg.pair[0]) close(arg.pair[0]);
7645 if (0 <= arg.pair[1]) close(arg.pair[1]);
7646 rb_execarg_parent_end(execarg_obj);
7650# if defined(HAVE_WORKING_FORK)
7651 pid = rb_fork_async_signal_safe(&status, popen_exec, &arg, arg.eargp->redirect_fds, errmsg,
sizeof(errmsg));
7653 rb_execarg_run_options(eargp, sargp, NULL, 0);
7654# if defined(HAVE_SPAWNVE)
7655 if (eargp->envp_str) envp = (
char **)RSTRING_PTR(eargp->envp_str);
7657 while ((pid = DO_SPAWN(cmd, args, envp)) < 0) {
7659 switch (e =
errno) {
7661# if EWOULDBLOCK != EAGAIN
7670 rb_execarg_run_options(sargp, NULL, NULL, 0);
7672 rb_execarg_parent_end(execarg_obj);
7675# if defined(HAVE_WORKING_FORK)
7676 pid = rb_call_proc__fork();
7678 popen_redirect(&arg);
7690# if defined(HAVE_WORKING_FORK)
7696 close(arg.write_pair[0]);
7697 close(arg.write_pair[1]);
7699# if defined(HAVE_WORKING_FORK)
7708 close(arg.write_pair[0]);
7709 write_fd = arg.write_pair[1];
7720 cmd = rb_execarg_commandline(eargp, &prog);
7721 if (!
NIL_P(execarg_obj)) {
7722 rb_execarg_parent_start(execarg_obj);
7723 rb_execarg_run_options(eargp, sargp, NULL, 0);
7725 fp = popen(cmd, modestr);
7728 rb_execarg_parent_end(execarg_obj);
7729 rb_execarg_run_options(sargp, NULL, NULL, 0);
7731 if (!fp) rb_syserr_fail_path(e, prog);
7741 fptr->
encs = *convconfig;
7742#if RUBY_CRLF_ENVIRONMENT
7749 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
7752#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7753 if (NEED_NEWLINE_DECORATOR_ON_WRITE(fptr)) {
7754 fptr->
encs.
ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
7760 if (0 <= write_fd) {
7761 write_port = io_alloc(
rb_cIO);
7763 write_fptr->
fd = write_fd;
7767 rb_ivar_set(port, rb_intern(
"@tied_io_for_writing"), write_port);
7770#if defined (__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7772 pipe_add_fptr(fptr);
7778pipe_open(
VALUE execarg_obj,
const char *modestr,
int fmode,
7786is_popen_fork(
VALUE prog)
7788 if (RSTRING_LEN(prog) == 1 && RSTRING_PTR(prog)[0] ==
'-') {
7789#if !defined(HAVE_WORKING_FORK)
7791 "fork() function is unimplemented on this machine");
7800pipe_open_s(
VALUE prog,
const char *modestr,
int fmode,
7804 VALUE *argv = &prog;
7807 if (!is_popen_fork(prog))
7808 execarg_obj = rb_execarg_new(argc, argv, TRUE, FALSE);
7809 return pipe_open(execarg_obj, modestr, fmode, convconfig);
7815 rb_io_t *fptr = io_close_fptr(io);
7983rb_io_s_popen(
int argc,
VALUE *argv,
VALUE klass)
7987 if (argc > 1 && !
NIL_P(opt = rb_check_hash_type(argv[argc-1]))) --argc;
7988 if (argc > 1 && !
NIL_P(env = rb_check_hash_type(argv[0]))) --argc, ++argv;
7997 int ex = !
NIL_P(opt);
7998 rb_error_arity(argc + ex, 1 + ex, 2 + ex);
8001 return popen_finish(rb_io_popen(pname, pmode, env, opt), klass);
8007 const char *modestr;
8012 tmp = rb_check_array_type(pname);
8015#if SIZEOF_LONG > SIZEOF_INT
8016 if (
len > INT_MAX) {
8017 rb_raise(rb_eArgError,
"too many arguments");
8026 if (!is_popen_fork(pname))
8027 execarg_obj = rb_execarg_new(1, &pname, TRUE, FALSE);
8029 if (!
NIL_P(execarg_obj)) {
8031 opt = rb_execarg_extract_options(execarg_obj, opt);
8033 rb_execarg_setenv(execarg_obj, env);
8036 modestr = rb_io_oflags_modestr(oflags);
8038 return pipe_open(execarg_obj, modestr, fmode, &convconfig);
8054 RBASIC_SET_CLASS(port, klass);
8061#if defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)
8062struct popen_writer_arg {
8064 struct popen_arg popen;
8068exec_popen_writer(
void *arg,
char *errmsg,
size_t buflen)
8070 struct popen_writer_arg *pw = arg;
8072 popen_redirect(&pw->popen);
8073 execv(pw->argv[0], pw->argv);
8074 strlcpy(errmsg, strerror(
errno), buflen);
8080ruby_popen_writer(
char *
const *argv, rb_pid_t *pid)
8082#if (defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)) || defined(_WIN32)
8083# ifdef HAVE_WORKING_FORK
8084 struct popen_writer_arg pw;
8085 int *
const write_pair = pw.popen.pair;
8091 int result = pipe2(write_pair, O_CLOEXEC);
8093 int result = pipe(write_pair);
8098# ifdef HAVE_WORKING_FORK
8101 char errmsg[80] = {
'\0'};
8102 *pid = rb_fork_async_signal_safe(&status, exec_popen_writer, &pw,
Qnil, errmsg,
sizeof(errmsg));
8104 *pid = rb_w32_uspawn_process(P_NOWAIT, argv[0], argv, write_pair[0], -1, -1, 0);
8105 const char *errmsg = (*pid < 0) ? strerror(
errno) : NULL;
8107 close(write_pair[0]);
8109 close(write_pair[1]);
8110 fprintf(stderr,
"ruby_popen_writer(%s): %s\n", argv[0], errmsg);
8113 return fdopen(write_pair[1],
"w");
8132 rb_file_open_generic(io, fname, oflags, fmode, &convconfig, perm);
8170rb_io_s_open(
int argc,
VALUE *argv,
VALUE klass)
8202 VALUE fname, vmode, vperm;
8207 rb_scan_args(argc, argv,
"12", &fname, &vmode, &vperm);
8218 if (
NIL_P(vperm)) perm = 0666;
8222 fd = rb_sysopen(fname, oflags, perm);
8227check_pipe_command(
VALUE filename_or_command)
8229 char *s = RSTRING_PTR(filename_or_command);
8230 long l = RSTRING_LEN(filename_or_command);
8234 if (rb_enc_ascget(s, e, &chlen, rb_enc_get(filename_or_command)) ==
'|') {
8272 int redirect = FALSE;
8280 VALUE tmp = argv[0];
8286 VALUE cmd = check_pipe_command(tmp);
8289 rb_warn_deprecated_to_remove_at(4.0,
"Calling Kernel#open with a leading '|'",
"IO.popen");
8291 return rb_io_s_popen(argc, argv,
rb_cIO);
8304 return rb_io_s_open(argc, argv,
rb_cFile);
8318 return rb_io_open_generic(io, filename, oflags, fmode, &convconfig, perm);
8322rb_io_open_generic(
VALUE klass,
VALUE filename,
int oflags,
int fmode,
8326 if (klass ==
rb_cIO && !
NIL_P(cmd = check_pipe_command(filename))) {
8328 rb_warn_deprecated_to_remove_at(4.0,
"IO process creation with a leading '|'",
"IO.popen");
8329 return pipe_open_s(cmd, rb_io_oflags_modestr(oflags), fmode, convconfig);
8332 return rb_file_open_generic(io_alloc(klass), filename,
8333 oflags, fmode, convconfig, perm);
8340 rb_io_t *fptr, *orig;
8348 if (fptr == orig)
return io;
8349 if (RUBY_IO_EXTERNAL_P(fptr)) {
8353 rb_raise(rb_eArgError,
8354 "%s can't change access mode from \"%s\" to \"%s\"",
8355 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->
mode),
8356 rb_io_fmode_modestr(orig->
mode));
8360 if (io_fflush(fptr) < 0)
8361 rb_sys_fail_on_write(fptr);
8364 flush_before_seek(fptr,
true);
8367 pos = io_tell(orig);
8370 if (io_fflush(orig) < 0)
8371 rb_sys_fail_on_write(fptr);
8380 else if (!RUBY_IO_EXTERNAL_P(fptr)) fptr->
pathv =
Qnil;
8381 fptr_copy_finalizer(fptr, orig);
8386 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2 || !fptr->stdio_file) {
8389 rb_sys_fail_path(orig->
pathv);
8397 rb_sys_fail_path(orig->
pathv);
8403 if (io_seek(fptr, pos, SEEK_SET) < 0 &&
errno) {
8404 rb_sys_fail_path(fptr->
pathv);
8406 if (io_seek(orig, pos, SEEK_SET) < 0 &&
errno) {
8407 rb_sys_fail_path(orig->
pathv);
8421int rb_freopen(
VALUE fname,
const char *mode, FILE *fp);
8424rb_freopen(
VALUE fname,
const char *mode, FILE *fp)
8426 if (!freopen(RSTRING_PTR(fname), mode, fp)) {
8469rb_io_reopen(
int argc,
VALUE *argv,
VALUE file)
8471 VALUE fname, nmode, opt;
8475 if (
rb_scan_args(argc, argv,
"11:", &fname, &nmode, &opt) == 1) {
8478 return io_reopen(file, tmp);
8484 fptr =
RFILE(file)->fptr;
8494 if (RUBY_IO_EXTERNAL_P(fptr) &&
8497 rb_raise(rb_eArgError,
8498 "%s can't change access mode from \"%s\" to \"%s\"",
8499 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->
mode),
8500 rb_io_fmode_modestr(fmode));
8503 fptr->
encs = convconfig;
8506 oflags = rb_io_fmode_oflags(fptr->
mode);
8509 fptr->
pathv = fname;
8511 fptr->
fd = rb_sysopen(fptr->
pathv, oflags, 0666);
8517 if (io_fflush(fptr) < 0)
8518 rb_sys_fail_on_write(fptr);
8523 int e = rb_freopen(rb_str_encode_ospath(fptr->
pathv),
8524 rb_io_oflags_modestr(oflags),
8526 if (e) rb_syserr_fail_path(e, fptr->
pathv);
8530 if (setvbuf(fptr->
stdio_file, NULL, _IOFBF, 0) != 0)
8531 rb_warn(
"setvbuf() can't be honoured for %"PRIsVALUE, fptr->
pathv);
8534 if (setvbuf(fptr->
stdio_file, NULL, _IONBF, BUFSIZ) != 0)
8535 rb_warn(
"setvbuf() can't be honoured for %"PRIsVALUE, fptr->
pathv);
8537 else if (fptr->
stdio_file == stdout && isatty(fptr->
fd)) {
8538 if (setvbuf(fptr->
stdio_file, NULL, _IOLBF, BUFSIZ) != 0)
8539 rb_warn(
"setvbuf() can't be honoured for %"PRIsVALUE, fptr->
pathv);
8543 int tmpfd = rb_sysopen(fptr->
pathv, oflags, 0666);
8549 rb_syserr_fail_path(err, fptr->
pathv);
8560 rb_io_t *fptr, *orig;
8579 fptr_copy_finalizer(fptr, orig);
8581 fd = ruby_dup(orig->
fd);
8583 pos = io_tell(orig);
8585 io_seek(fptr, pos, SEEK_SET);
8590 write_io = GetWriteIO(io);
8591 if (io != write_io) {
8594 rb_ivar_set(dest, rb_intern(
"@tied_io_for_writing"), write_io);
8657 if (argc == 0)
return Qnil;
8676 rb_warn_deprecated(
"'%s'", NULL, rb_id2name(
id));
8749 if (argc > 1 && !
NIL_P(rb_output_fs)) {
8752 for (i=0; i<argc; i++) {
8753 if (!
NIL_P(rb_output_fs) && i>0) {
8754 rb_io_write(out, rb_output_fs);
8756 rb_io_write(out, argv[i]);
8853 rb_io_write(io, str);
8857#define forward(obj, id, argc, argv) \
8858 rb_funcallv_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8859#define forward_public(obj, id, argc, argv) \
8860 rb_funcallv_public_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8861#define forward_current(id, argc, argv) \
8862 forward_public(ARGF.current_file, id, argc, argv)
8880 if (recv == r_stdout) {
8881 return rb_io_putc(recv, ch);
8883 return forward(r_stdout, rb_intern(
"putc"), 1, &ch);
8888rb_str_end_with_asciichar(
VALUE str,
int c)
8890 long len = RSTRING_LEN(str);
8891 const char *ptr = RSTRING_PTR(str);
8895 if (
len == 0)
return 0;
8896 if ((n = rb_enc_mbminlen(
enc)) == 1) {
8897 return ptr[
len - 1] == c;
8899 return rb_enc_ascget(ptr + ((
len - 1) / n) * n, ptr +
len, &n,
enc) == c;
8910 rb_io_puts(1, &tmp, out);
8913 ary = rb_check_array_type(ary);
8917 rb_io_puts(1, &tmp, out);
8972 VALUE line, args[2];
8979 for (
int i = 0; i < argc; i++) {
8988 line = rb_obj_as_string(argv[i]);
8993 if (RSTRING_LEN(line) == 0) {
8998 if (!rb_str_end_with_asciichar(line,
'\n')) {
9003 rb_io_writev(out, n, args);
9022 if (recv == r_stdout) {
9023 return rb_io_puts(argc, argv, recv);
9025 return forward(r_stdout, rb_intern(
"puts"), argc, argv);
9029rb_p_write(
VALUE str)
9036 rb_method_basic_definition_p(
CLASS_OF(r_stdout), id_write)) {
9037 io_writev(2, args, r_stdout);
9040 rb_io_writev(r_stdout, 2, args);
9048 rb_p_write(rb_obj_as_string(
rb_inspect(obj)));
9052rb_p_result(
int argc,
const VALUE *argv)
9059 else if (argc > 1) {
9064 rb_uninterruptible(rb_io_flush, r_stdout);
9105 for (i=0; i<argc; i++) {
9107 rb_uninterruptible(rb_p_write, inspected);
9109 return rb_p_result(argc, argv);
9130rb_obj_display(
int argc,
VALUE *argv,
VALUE self)
9135 rb_io_write(out, self);
9141rb_stderr_to_original_p(
VALUE err)
9143 return (err == orig_stderr ||
RFILE(orig_stderr)->fptr->
fd < 0);
9150 if (rb_stderr_to_original_p(out)) {
9152 if (isatty(fileno(stderr))) {
9153 if (rb_w32_write_console(
rb_str_new(mesg,
len), fileno(stderr)) > 0)
return;
9156 if (fwrite(mesg,
sizeof(
char), (
size_t)
len, stderr) < (
size_t)
len) {
9173rb_write_error_str(
VALUE mesg)
9177 if (rb_stderr_to_original_p(out)) {
9178 size_t len = (size_t)RSTRING_LEN(mesg);
9180 if (isatty(fileno(stderr))) {
9181 if (rb_w32_write_console(mesg, fileno(stderr)) > 0)
return;
9184 if (fwrite(RSTRING_PTR(mesg),
sizeof(
char),
len, stderr) <
len) {
9191 rb_io_write(out, mesg);
9196rb_stderr_tty_p(
void)
9199 return isatty(fileno(stderr));
9204must_respond_to(
ID mid,
VALUE val,
ID id)
9207 rb_raise(
rb_eTypeError,
"%"PRIsVALUE
" must have %"PRIsVALUE
" method, %"PRIsVALUE
" given",
9208 rb_id2str(
id), rb_id2str(mid),
9220stdin_getter(
ID id,
VALUE *ptr)
9228 must_respond_to(id_write, val,
id);
9233stdout_getter(
ID id,
VALUE *ptr)
9241 must_respond_to(id_write, val,
id);
9246stderr_getter(
ID id,
VALUE *ptr)
9252allocate_and_open_new_file(
VALUE klass)
9254 VALUE self = io_alloc(klass);
9255 rb_io_make_open_file(self);
9263 VALUE self = rb_protect(allocate_and_open_new_file, klass, &state);
9271 maygvl_close(descriptor, 0);
9277 rb_io_t *io =
RFILE(self)->fptr;
9279 io->
fd = descriptor;
9297 io->
encs = *encoding;
9306prep_io(
int fd,
int fmode,
VALUE klass,
const char *path)
9317 rb_io_ext_int_to_encs(e, NULL, &convconfig.
enc, &convconfig.
enc2, fmode);
9321#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9323 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
9324 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
9326 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.
enc2, convconfig.
ecflags);
9330 rb_io_t*io =
RFILE(self)->fptr;
9332 if (!io_check_tty(io)) {
9335 setmode(fd, O_BINARY);
9347 if (path && strcmp(path,
"-")) klass =
rb_cFile;
9352prep_stdio(FILE *f,
int fmode,
VALUE klass,
const char *path)
9359#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9360 fptr->
encs.
ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
9371rb_io_prep_stdin(
void)
9377rb_io_prep_stdout(
void)
9383rb_io_prep_stderr(
void)
9392 int oflags = rb_io_fmode_oflags(fptr->
mode) & ~O_EXCL;
9407static inline rb_io_t *
9410 rb_io_t *fp =
ALLOC(rb_io_t);
9419 rb_io_buffer_init(&fp->
wbuf);
9420 rb_io_buffer_init(&fp->
rbuf);
9421 rb_io_buffer_init(&fp->
cbuf);
9439rb_io_make_open_file(
VALUE obj)
9444 if (
RFILE(obj)->fptr) {
9447 RFILE(obj)->fptr = 0;
9449 fp = rb_io_fptr_new();
9451 RFILE(obj)->fptr = fp;
9499rb_io_initialize(
int argc,
VALUE *argv,
VALUE io)
9505 return io_initialize(io, fnum, vmode, opt);
9512 int fd, fmode, oflags = O_RDONLY;
9514#if defined(HAVE_FCNTL) && defined(F_GETFL)
9524 rb_raise(rb_eArgError,
"The given fd is not accessible because RubyVM reserves it");
9526#if defined(HAVE_FCNTL) && defined(F_GETFL)
9527 oflags = fcntl(fd, F_GETFL);
9528 if (oflags == -1) rb_sys_fail(0);
9530 if (fstat(fd, &st) < 0) rb_sys_fail(0);
9533#if defined(HAVE_FCNTL) && defined(F_GETFL)
9546 if (rb_hash_aref(opt, sym_autoclose) ==
Qfalse) {
9550 path = rb_hash_aref(opt,
RB_ID2SYM(idPath));
9561 fp->
encs = convconfig;
9566 if (fileno(stdin) == fd)
9568 else if (fileno(stdout) == fd)
9570 else if (fileno(stderr) == fd)
9602rb_io_set_encoding_by_bom(
VALUE io)
9608 rb_raise(rb_eArgError,
"ASCII incompatible encoding needs binmode");
9611 rb_raise(rb_eArgError,
"encoding conversion is set");
9613 else if (fptr->
encs.
enc && fptr->
encs.
enc != rb_ascii8bit_encoding()) {
9614 rb_raise(rb_eArgError,
"encoding is set to %s already",
9617 if (!io_set_encoding_by_bom(io))
return Qnil;
9618 return rb_enc_from_encoding(fptr->
encs.
enc);
9663rb_file_initialize(
int argc,
VALUE *argv,
VALUE io)
9665 if (
RFILE(io)->fptr) {
9668 VALUE fname, vmode, vperm, opt;
9669 int posargc =
rb_scan_args(argc, argv,
"12:", &fname, &vmode, &vperm, &opt);
9674 return io_initialize(io, fd, vmode, opt);
9677 return rb_open_file(io, fname, vmode, vperm, opt);
9682rb_io_s_new(
int argc,
VALUE *argv,
VALUE klass)
9685 VALUE cname = rb_obj_as_string(klass);
9687 rb_warn(
"%"PRIsVALUE
"::new() does not take block; use %"PRIsVALUE
"::open() instead",
9703rb_io_s_for_fd(
int argc,
VALUE *argv,
VALUE klass)
9706 rb_io_initialize(argc, argv, io);
9719rb_io_autoclose_p(
VALUE io)
9721 rb_io_t *fptr =
RFILE(io)->fptr;
9744rb_io_set_autoclose(
VALUE io,
VALUE autoclose)
9748 if (!
RTEST(autoclose))
9756io_wait_event(
VALUE io,
int event,
VALUE timeout,
int return_io)
9788io_wait_readable(
int argc,
VALUE *argv,
VALUE io)
9798 VALUE timeout = (argc == 1 ? argv[0] :
Qnil);
9812io_wait_writable(
int argc,
VALUE *argv,
VALUE io)
9820 VALUE timeout = (argc == 1 ? argv[0] :
Qnil);
9835io_wait_priority(
int argc,
VALUE *argv,
VALUE io)
9837 rb_io_t *fptr = NULL;
9845 VALUE timeout = argc == 1 ? argv[0] :
Qnil;
9851wait_mode_sym(
VALUE mode)
9853 if (mode ==
ID2SYM(rb_intern(
"r"))) {
9854 return RB_WAITFD_IN;
9856 if (mode ==
ID2SYM(rb_intern(
"read"))) {
9857 return RB_WAITFD_IN;
9859 if (mode ==
ID2SYM(rb_intern(
"readable"))) {
9860 return RB_WAITFD_IN;
9862 if (mode ==
ID2SYM(rb_intern(
"w"))) {
9863 return RB_WAITFD_OUT;
9865 if (mode ==
ID2SYM(rb_intern(
"write"))) {
9866 return RB_WAITFD_OUT;
9868 if (mode ==
ID2SYM(rb_intern(
"writable"))) {
9869 return RB_WAITFD_OUT;
9871 if (mode ==
ID2SYM(rb_intern(
"rw"))) {
9872 return RB_WAITFD_IN|RB_WAITFD_OUT;
9874 if (mode ==
ID2SYM(rb_intern(
"read_write"))) {
9875 return RB_WAITFD_IN|RB_WAITFD_OUT;
9877 if (mode ==
ID2SYM(rb_intern(
"readable_writable"))) {
9878 return RB_WAITFD_IN|RB_WAITFD_OUT;
9881 rb_raise(rb_eArgError,
"unsupported mode: %"PRIsVALUE, mode);
9885io_event_from_value(
VALUE value)
9889 if (events <= 0) rb_raise(rb_eArgError,
"Events must be positive integer!");
9927 for (
int i = 0; i < argc; i += 1) {
9929 events |= wait_mode_sym(argv[i]);
9931 else if (UNDEF_P(timeout)) {
9935 rb_raise(rb_eArgError,
"timeout given more than once");
9939 if (UNDEF_P(timeout)) timeout =
Qnil;
9947 events = io_event_from_value(argv[0]);
9952 rb_io_t *fptr = NULL;
9957 if (return_io)
return Qtrue;
9963 return io_wait_event(io, events, timeout, return_io);
9969 struct argf *p = ptr;
9970 rb_gc_mark(p->filename);
9971 rb_gc_mark(p->current_file);
9972 rb_gc_mark(p->argv);
9973 rb_gc_mark(p->inplace);
9974 rb_gc_mark(p->encs.
ecopts);
9978argf_memsize(
const void *ptr)
9980 const struct argf *p = ptr;
9981 size_t size =
sizeof(*p);
9988 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
9995 p->current_file =
Qnil;
10001argf_alloc(
VALUE klass)
10006 argf_init(p,
Qnil);
10016 memset(&ARGF, 0,
sizeof(ARGF));
10017 argf_init(&ARGF, argv);
10027 ARGF = argf_of(orig);
10054 ARGF.last_lineno = ARGF.lineno;
10083#define next_argv() argf_next_argv(argf)
10084#define ARGF_GENERIC_INPUT_P() \
10085 (ARGF.current_file == rb_stdin && !RB_TYPE_P(ARGF.current_file, T_FILE))
10086#define ARGF_FORWARD(argc, argv) do {\
10087 if (ARGF_GENERIC_INPUT_P())\
10088 return argf_forward((argc), (argv), argf);\
10090#define NEXT_ARGF_FORWARD(argc, argv) do {\
10091 if (!next_argv()) return Qnil;\
10092 ARGF_FORWARD((argc), (argv));\
10098 VALUE file = ARGF.current_file;
10112 int stdout_binmode = 0;
10120 stdout_binmode = 1;
10123 if (ARGF.init_p == 0) {
10133 if (
NIL_P(ARGF.argv)) {
10136 else if (ARGF.next_p == -1 &&
RARRAY_LEN(ARGF.argv) > 0) {
10141 if (ARGF.next_p == 1) {
10142 if (ARGF.init_p == 1) argf_close(
argf);
10145 VALUE filename = rb_ary_shift(ARGF.argv);
10147 ARGF.filename = filename;
10148 filename = rb_str_encode_ospath(filename);
10150 if (RSTRING_LEN(filename) == 1 && fn[0] ==
'-') {
10152 if (ARGF.inplace) {
10153 rb_warn(
"Can't do inplace edit for stdio; skipping");
10159 int fr = rb_sysopen(filename, O_RDONLY, 0);
10161 if (ARGF.inplace) {
10163#ifndef NO_SAFE_RENAME
10174 if (!
NIL_P(ARGF.inplace)) {
10175 VALUE suffix = ARGF.inplace;
10177 if (
NIL_P(rb_str_cat_conv_enc_opts(str, RSTRING_LEN(str),
10178 RSTRING_PTR(suffix), RSTRING_LEN(suffix),
10179 rb_enc_get(suffix), 0,
Qnil))) {
10182#ifdef NO_SAFE_RENAME
10184 (void)unlink(RSTRING_PTR(str));
10185 if (rename(fn, RSTRING_PTR(str)) < 0) {
10186 rb_warn(
"Can't rename %"PRIsVALUE
" to %"PRIsVALUE
": %s, skipping file",
10187 filename, str, strerror(
errno));
10190 fr = rb_sysopen(str, O_RDONLY, 0);
10192 if (rename(fn, RSTRING_PTR(str)) < 0) {
10193 rb_warn(
"Can't rename %"PRIsVALUE
" to %"PRIsVALUE
": %s, skipping file",
10194 filename, str, strerror(
errno));
10201#ifdef NO_SAFE_RENAME
10202 rb_fatal(
"Can't do inplace edit without backup");
10204 if (unlink(fn) < 0) {
10205 rb_warn(
"Can't remove %"PRIsVALUE
": %s, skipping file",
10206 filename, strerror(
errno));
10212 fw = rb_sysopen(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666);
10213#ifndef NO_SAFE_RENAME
10216 fchmod(fw, st.st_mode);
10218 chmod(fn, st.st_mode);
10220 if (st.st_uid!=st2.st_uid || st.st_gid!=st2.st_gid) {
10223 err = fchown(fw, st.st_uid, st.st_gid);
10225 err = chown(fn, st.st_uid, st.st_gid);
10227 if (err && getuid() == 0 && st2.st_uid == 0) {
10228 const char *wkfn = RSTRING_PTR(filename);
10229 rb_warn(
"Can't set owner/group of %"PRIsVALUE
" to same as %"PRIsVALUE
": %s, skipping file",
10230 filename, str, strerror(
errno));
10233 (void)unlink(wkfn);
10243 if (!ARGF.binmode) {
10244 fmode |= DEFAULT_TEXTMODE;
10246 ARGF.current_file = prep_io(fr, fmode,
rb_cFile, fn);
10247 if (!
NIL_P(write_io)) {
10254 if (ARGF.encs.enc) {
10255 fptr->
encs = ARGF.encs;
10256 clear_codeconv(fptr);
10260 if (!ARGF.binmode) {
10262#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
10263 fptr->
encs.
ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
10274 else if (ARGF.next_p == -1) {
10277 if (ARGF.inplace) {
10278 rb_warn(
"Can't do inplace edit for stdio");
10282 if (ARGF.init_p == -1) ARGF.init_p = 1;
10290 long lineno = ARGF.lineno;
10293 if (!next_argv())
return Qnil;
10294 if (ARGF_GENERIC_INPUT_P()) {
10295 line = forward_current(idGets, argc, argv);
10302 line = rb_io_getline(argc, argv, ARGF.current_file);
10304 if (
NIL_P(line) && ARGF.next_p != -1) {
10310 if (!
NIL_P(line)) {
10311 ARGF.lineno = ++lineno;
10312 ARGF.last_lineno = ARGF.lineno;
10318argf_lineno_getter(
ID id,
VALUE *var)
10321 return INT2FIX(ARGF.last_lineno);
10329 ARGF.last_lineno = ARGF.lineno = n;
10333rb_reset_argf_lineno(
long n)
10335 ARGF.last_lineno = ARGF.lineno = n;
10376 if (recv ==
argf) {
10377 return argf_gets(argc, argv,
argf);
10379 return forward(
argf, idGets, argc, argv);
10405 line = argf_getline(argc, argv,
argf);
10417 return rb_f_gets(0, 0,
argf);
10421 if (!next_argv())
return Qnil;
10423 if (
NIL_P(line) && ARGF.next_p != -1) {
10429 if (!
NIL_P(line)) {
10431 ARGF.last_lineno = ARGF.lineno;
10457rb_f_readline(
int argc,
VALUE *argv,
VALUE recv)
10459 if (recv ==
argf) {
10460 return argf_readline(argc, argv,
argf);
10462 return forward(
argf, rb_intern(
"readline"), argc, argv);
10489 ARGF_FORWARD(argc, argv);
10490 line = argf_gets(argc, argv,
argf);
10560rb_f_readlines(
int argc,
VALUE *argv,
VALUE recv)
10562 if (recv ==
argf) {
10563 return argf_readlines(argc, argv,
argf);
10565 return forward(
argf, rb_intern(
"readlines"), argc, argv);
10589 long lineno = ARGF.lineno;
10593 while (next_argv()) {
10594 if (ARGF_GENERIC_INPUT_P()) {
10595 lines = forward_current(rb_intern(
"readlines"), argc, argv);
10598 lines = rb_io_readlines(argc, argv, ARGF.current_file);
10602 rb_ary_concat(ary, lines);
10604 ARGF.last_lineno = ARGF.lineno;
10639 rb_last_status_clear();
10640 port = pipe_open_s(str,
"r",
FMODE_READABLE|DEFAULT_TEXTMODE, NULL);
10644 result = read_all(fptr, remain_size(fptr),
Qnil);
10646 rb_io_fptr_cleanup_all(fptr);
10652#ifdef HAVE_SYS_SELECT_H
10653#include <sys/select.h>
10667 if (!
NIL_P(read)) {
10672 if (READ_DATA_PENDING(fptr) || READ_CHAR_PENDING(fptr)) {
10676 if (max < fptr->fd) max = fptr->
fd;
10679 timerec.tv_sec = timerec.tv_usec = 0;
10687 if (!
NIL_P(write)) {
10693 if (max < fptr->fd) max = fptr->
fd;
10700 if (!
NIL_P(except)) {
10704 VALUE write_io = GetWriteIO(io);
10707 if (max < fptr->fd) max = fptr->
fd;
10708 if (io != write_io) {
10711 if (max < fptr->fd) max = fptr->
fd;
10726 if (!pending && n == 0)
return Qnil;
10736 VALUE obj = rb_ary_entry(read, i);
10741 rb_ary_push(list, obj);
10749 VALUE obj = rb_ary_entry(write, i);
10751 VALUE write_io = GetWriteIO(io);
10754 rb_ary_push(list, obj);
10762 VALUE obj = rb_ary_entry(except, i);
10764 VALUE write_io = GetWriteIO(io);
10767 rb_ary_push(list, obj);
10769 else if (io != write_io) {
10772 rb_ary_push(list, obj);
10782 VALUE read, write, except;
10788select_call(
VALUE arg)
10792 return select_internal(p->read, p->write, p->except, p->timeout, p->fdsets);
10796select_end(
VALUE arg)
10801 for (i = 0; i < numberof(p->fdsets); ++i)
10806static VALUE sym_normal, sym_sequential, sym_random,
10807 sym_willneed, sym_dontneed, sym_noreuse;
10809#ifdef HAVE_POSIX_FADVISE
10810struct io_advise_struct {
10818io_advise_internal(
void *arg)
10820 struct io_advise_struct *ptr = arg;
10821 return posix_fadvise(ptr->fd, ptr->offset, ptr->len, ptr->advice);
10825io_advise_sym_to_const(
VALUE sym)
10827#ifdef POSIX_FADV_NORMAL
10828 if (sym == sym_normal)
10829 return INT2NUM(POSIX_FADV_NORMAL);
10832#ifdef POSIX_FADV_RANDOM
10833 if (sym == sym_random)
10834 return INT2NUM(POSIX_FADV_RANDOM);
10837#ifdef POSIX_FADV_SEQUENTIAL
10838 if (sym == sym_sequential)
10839 return INT2NUM(POSIX_FADV_SEQUENTIAL);
10842#ifdef POSIX_FADV_WILLNEED
10843 if (sym == sym_willneed)
10844 return INT2NUM(POSIX_FADV_WILLNEED);
10847#ifdef POSIX_FADV_DONTNEED
10848 if (sym == sym_dontneed)
10849 return INT2NUM(POSIX_FADV_DONTNEED);
10852#ifdef POSIX_FADV_NOREUSE
10853 if (sym == sym_noreuse)
10854 return INT2NUM(POSIX_FADV_NOREUSE);
10861do_io_advise(rb_io_t *fptr,
VALUE advice, rb_off_t offset, rb_off_t
len)
10864 struct io_advise_struct ias;
10867 num_adv = io_advise_sym_to_const(advice);
10873 if (
NIL_P(num_adv))
10877 ias.advice =
NUM2INT(num_adv);
10878 ias.offset = offset;
10881 rv = (int)rb_io_blocking_region(fptr, io_advise_internal, &ias);
10882 if (rv && rv != ENOSYS) {
10885 VALUE message = rb_sprintf(
"%"PRIsVALUE
" "
10889 fptr->
pathv, offset,
len, advice);
10899advice_arg_check(
VALUE advice)
10904 if (advice != sym_normal &&
10905 advice != sym_sequential &&
10906 advice != sym_random &&
10907 advice != sym_willneed &&
10908 advice != sym_dontneed &&
10909 advice != sym_noreuse) {
10910 rb_raise(
rb_eNotImpError,
"Unsupported advice: %+"PRIsVALUE, advice);
10948rb_io_advise(
int argc,
VALUE *argv,
VALUE io)
10955 advice_arg_check(advice);
10957 io = GetWriteIO(io);
10963#ifdef HAVE_POSIX_FADVISE
10964 return do_io_advise(fptr, advice,
off, l);
10966 ((void)
off, (void)l);
11122rb_f_select(
int argc,
VALUE *argv,
VALUE obj)
11125 if (scheduler !=
Qnil) {
11128 if (!UNDEF_P(result))
return result;
11136 rb_scan_args(argc, argv,
"13", &args.read, &args.write, &args.except, &timeout);
11137 if (
NIL_P(timeout)) {
11142 args.timeout = &timerec;
11145 for (i = 0; i < numberof(args.fdsets); ++i)
11151#ifdef IOCTL_REQ_TYPE
11152 typedef IOCTL_REQ_TYPE ioctl_req_t;
11154 typedef int ioctl_req_t;
11155# define NUM2IOCTLREQ(num) ((int)NUM2LONG(num))
11166nogvl_ioctl(
void *ptr)
11168 struct ioctl_arg *arg = ptr;
11170 return (
VALUE)ioctl(arg->fd, arg->cmd, arg->narg);
11174do_ioctl(
struct rb_io *io, ioctl_req_t cmd,
long narg)
11177 struct ioctl_arg arg;
11183 retval = (int)rb_io_blocking_region(io, nogvl_ioctl, &arg);
11189#define DEFAULT_IOCTL_NARG_LEN (256)
11191#if defined(__linux__) && defined(_IOC_SIZE)
11193linux_iocparm_len(ioctl_req_t cmd)
11197 if ((cmd & 0xFFFF0000) == 0) {
11199 return DEFAULT_IOCTL_NARG_LEN;
11202 len = _IOC_SIZE(cmd);
11205 if (
len < DEFAULT_IOCTL_NARG_LEN)
11206 len = DEFAULT_IOCTL_NARG_LEN;
11214ioctl_narg_len(ioctl_req_t cmd)
11220#define IOCPARM_LEN(x) (((x) >> 16) & IOCPARM_MASK)
11224 len = IOCPARM_LEN(cmd);
11225#elif defined(__linux__) && defined(_IOC_SIZE)
11226 len = linux_iocparm_len(cmd);
11229 len = DEFAULT_IOCTL_NARG_LEN;
11238typedef long fcntl_arg_t;
11241typedef int fcntl_arg_t;
11245fcntl_narg_len(ioctl_req_t cmd)
11252 len =
sizeof(fcntl_arg_t);
11260#ifdef F_DUPFD_CLOEXEC
11261 case F_DUPFD_CLOEXEC:
11262 len =
sizeof(fcntl_arg_t);
11272 len =
sizeof(fcntl_arg_t);
11282 len =
sizeof(fcntl_arg_t);
11292 len =
sizeof(fcntl_arg_t);
11297 len =
sizeof(
struct f_owner_ex);
11302 len =
sizeof(
struct f_owner_ex);
11307 len =
sizeof(
struct flock);
11312 len =
sizeof(
struct flock);
11317 len =
sizeof(
struct flock);
11337 len =
sizeof(fcntl_arg_t);
11347 len =
sizeof(fcntl_arg_t);
11352 len =
sizeof(fcntl_arg_t);
11365fcntl_narg_len(ioctl_req_t cmd)
11371#define NARG_SENTINEL 17
11374setup_narg(ioctl_req_t cmd,
VALUE *argp,
long (*narg_len)(ioctl_req_t))
11385 else if (arg ==
Qtrue) {
11399 len = narg_len(cmd);
11400 rb_str_modify(arg);
11402 slen = RSTRING_LEN(arg);
11404 if (slen <
len+1) {
11405 rb_str_resize(arg,
len+1);
11406 MEMZERO(RSTRING_PTR(arg)+slen,
char,
len-slen);
11410 ptr = RSTRING_PTR(arg);
11411 ptr[slen - 1] = NARG_SENTINEL;
11420finish_narg(
int retval,
VALUE arg,
const rb_io_t *fptr)
11422 if (retval < 0) rb_sys_fail_path(fptr->
pathv);
11427 if (ptr[slen-1] != NARG_SENTINEL)
11428 rb_raise(rb_eArgError,
"return value overflowed string");
11429 ptr[slen-1] =
'\0';
11439 ioctl_req_t cmd = NUM2IOCTLREQ(req);
11444 narg = setup_narg(cmd, &arg, ioctl_narg_len);
11446 retval = do_ioctl(fptr, cmd, narg);
11447 return finish_narg(retval, arg, fptr);
11474 return rb_ioctl(io, req, arg);
11477#define rb_io_ioctl rb_f_notimplement
11488nogvl_fcntl(
void *ptr)
11490 struct fcntl_arg *arg = ptr;
11492#if defined(F_DUPFD)
11493 if (arg->cmd == F_DUPFD)
11496 return (
VALUE)fcntl(arg->fd, arg->cmd, arg->narg);
11500do_fcntl(
struct rb_io *io,
int cmd,
long narg)
11503 struct fcntl_arg arg;
11509 retval = (int)rb_io_blocking_region(io, nogvl_fcntl, &arg);
11510 if (retval != -1) {
11512#if defined(F_DUPFD)
11515#if defined(F_DUPFD_CLOEXEC)
11516 case F_DUPFD_CLOEXEC:
11533 narg = setup_narg(cmd, &arg, fcntl_narg_len);
11535 retval = do_fcntl(fptr, cmd, narg);
11536 return finish_narg(retval, arg, fptr);
11562 return rb_fcntl(io, req, arg);
11565#define rb_io_fcntl rb_f_notimplement
11568#if defined(HAVE_SYSCALL) || defined(HAVE___SYSCALL)
11600#if SIZEOF_VOIDP == 8 && defined(HAVE___SYSCALL) && SIZEOF_INT != 8
11601# define SYSCALL __syscall
11602# define NUM2SYSCALLID(x) NUM2LONG(x)
11603# define RETVAL2NUM(x) LONG2NUM(x)
11604# if SIZEOF_LONG == 8
11605 long num, retval = -1;
11606# elif SIZEOF_LONG_LONG == 8
11607 long long num, retval = -1;
11609# error ---->> it is asserted that __syscall takes the first argument and returns retval in 64bit signed integer. <<----
11611#elif defined(__linux__)
11612# define SYSCALL syscall
11613# define NUM2SYSCALLID(x) NUM2LONG(x)
11614# define RETVAL2NUM(x) LONG2NUM(x)
11622 long num, retval = -1;
11624# define SYSCALL syscall
11625# define NUM2SYSCALLID(x) NUM2INT(x)
11626# define RETVAL2NUM(x) INT2NUM(x)
11627 int num, retval = -1;
11633 "We plan to remove a syscall function at future release. DL(Fiddle) provides safer alternative.");
11637 rb_raise(rb_eArgError,
"too few arguments for syscall");
11638 if (argc > numberof(arg))
11639 rb_raise(rb_eArgError,
"too many arguments for syscall");
11640 num = NUM2SYSCALLID(argv[0]); ++argv;
11641 for (i = argc - 1; i--; ) {
11656 retval = SYSCALL(num);
11659 retval = SYSCALL(num, arg[0]);
11662 retval = SYSCALL(num, arg[0],arg[1]);
11665 retval = SYSCALL(num, arg[0],arg[1],arg[2]);
11668 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3]);
11671 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4]);
11674 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5]);
11677 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6]);
11683 return RETVAL2NUM(retval);
11685#undef NUM2SYSCALLID
11689#define rb_f_syscall rb_f_notimplement
11693io_new_instance(
VALUE args)
11698static rb_encoding *
11699find_encoding(
VALUE v)
11701 rb_encoding *enc = rb_find_encoding(v);
11702 if (!enc)
rb_warn(
"Unsupported encoding %"PRIsVALUE
" ignored", v);
11709 rb_encoding *enc, *enc2;
11714 enc2 = find_encoding(v1);
11717 if (RSTRING_LEN(tmp) == 1 && RSTRING_PTR(tmp)[0] ==
'-') {
11723 enc = find_encoding(v2);
11730 enc = find_encoding(v2);
11741 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11747 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
11748 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11753 if (!
NIL_P(tmp) && rb_enc_asciicompat(enc = rb_enc_get(tmp))) {
11754 parse_mode_enc(RSTRING_PTR(tmp), enc, &enc, &enc2, NULL);
11755 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11759 rb_io_ext_int_to_encs(find_encoding(v1), NULL, &enc, &enc2, 0);
11760 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11765 validate_enc_binmode(&fptr->
mode, ecflags, enc, enc2);
11770 clear_codeconv(fptr);
11782io_encoding_set_v(
VALUE v)
11785 io_encoding_set(arg->fptr, arg->v1, arg->v2, arg->opt);
11790pipe_pair_close(
VALUE rw)
11793 return rb_ensure(io_close, rwp[0], io_close, rwp[1]);
11876rb_io_s_pipe(
int argc,
VALUE *argv,
VALUE klass)
11878 int pipes[2], state;
11879 VALUE r, w, args[3], v1, v2;
11881 rb_io_t *fptr, *fptr2;
11886 argc =
rb_scan_args(argc, argv,
"02:", &v1, &v2, &opt);
11893 r = rb_protect(io_new_instance, (
VALUE)args, &state);
11897 rb_jump_tag(state);
11901 ies_args.fptr = fptr;
11904 ies_args.opt = opt;
11905 rb_protect(io_encoding_set_v, (
VALUE)&ies_args, &state);
11909 rb_jump_tag(state);
11914 w = rb_protect(io_new_instance, (
VALUE)args, &state);
11918 rb_jump_tag(state);
11923 extract_binmode(opt, &fmode);
11930#if DEFAULT_TEXTMODE
11933 setmode(fptr->
fd, O_BINARY);
11935#if RUBY_CRLF_ENVIRONMENT
11941 fptr->
mode |= fmode;
11942#if DEFAULT_TEXTMODE
11945 setmode(fptr2->
fd, O_BINARY);
11948 fptr2->
mode |= fmode;
11950 ret = rb_assoc_new(r, w);
11982 else if (!
NIL_P(v = rb_hash_aref(opt, sym_open_args))) {
11985 v = rb_to_array_type(v);
11990 arg->io = rb_io_open(klass, path, vmode, vperm, opt);
11994io_s_foreach(
VALUE v)
11999 if (arg->limit == 0)
12000 rb_raise(rb_eArgError,
"invalid limit: 0 for foreach");
12001 while (!
NIL_P(str = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, arg->io))) {
12089rb_io_s_foreach(
int argc,
VALUE *argv,
VALUE self)
12092 int orig_argc = argc;
12096 argc =
rb_scan_args(argc, argv,
"12:", NULL, NULL, NULL, &opt);
12098 extract_getline_args(argc-1, argv+1, &garg);
12099 open_key_args(self, argc, argv, opt, &arg);
12101 extract_getline_opts(opt, &garg);
12102 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12107io_s_readlines(
VALUE v)
12110 return io_readlines(arg, arg->io);
12167rb_io_s_readlines(
int argc,
VALUE *argv,
VALUE io)
12173 argc =
rb_scan_args(argc, argv,
"12:", NULL, NULL, NULL, &opt);
12174 extract_getline_args(argc-1, argv+1, &garg);
12175 open_key_args(io, argc, argv, opt, &arg);
12177 extract_getline_opts(opt, &garg);
12178 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12186 return io_read(arg->argc, arg->argv, arg->io);
12196seek_before_access(
VALUE argp)
12200 return rb_io_seek(arg->io, arg->offset, arg->mode);
12246rb_io_s_read(
int argc,
VALUE *argv,
VALUE io)
12252 argc =
rb_scan_args(argc, argv,
"13:", NULL, NULL, &offset, NULL, &opt);
12254 rb_raise(rb_eArgError,
"negative offset %ld given",
off);
12256 open_key_args(io, argc, argv, opt, &arg);
12258 if (!
NIL_P(offset)) {
12262 sarg.offset = offset;
12263 sarg.mode = SEEK_SET;
12264 rb_protect(seek_before_access, (
VALUE)&sarg, &state);
12267 rb_jump_tag(state);
12269 if (arg.argc == 2) arg.argc = 1;
12288rb_io_s_binread(
int argc,
VALUE *argv,
VALUE io)
12304 arg.io = rb_io_open_generic(io, argv[0], oflags, fmode, &convconfig, 0);
12307 arg.argc = (argc > 1) ? 1 : 0;
12308 if (!
NIL_P(offset)) {
12312 sarg.offset = offset;
12313 sarg.mode = SEEK_SET;
12314 rb_protect(seek_before_access, (
VALUE)&sarg, &state);
12317 rb_jump_tag(state);
12324io_s_write0(
VALUE v)
12327 return io_write(arg->io,arg->str,arg->nosync);
12331io_s_write(
int argc,
VALUE *argv,
VALUE klass,
int binary)
12333 VALUE string, offset, opt;
12337 rb_scan_args(argc, argv,
"21:", NULL, &
string, &offset, &opt);
12340 else opt = rb_hash_dup(opt);
12343 if (
NIL_P(rb_hash_aref(opt,sym_mode))) {
12344 int mode = O_WRONLY|O_CREAT;
12346 if (binary) mode |= O_BINARY;
12348 if (
NIL_P(offset)) mode |= O_TRUNC;
12349 rb_hash_aset(opt,sym_mode,
INT2NUM(mode));
12351 open_key_args(klass, argc, argv, opt, &arg);
12354 if (binary) rb_io_binmode_m(arg.io);
12358 if (!
NIL_P(offset)) {
12362 sarg.offset = offset;
12363 sarg.mode = SEEK_SET;
12364 rb_protect(seek_before_access, (
VALUE)&sarg, &state);
12367 rb_jump_tag(state);
12423rb_io_s_write(
int argc,
VALUE *argv,
VALUE io)
12425 return io_s_write(argc, argv, io, 0);
12442rb_io_s_binwrite(
int argc,
VALUE *argv,
VALUE io)
12444 return io_s_write(argc, argv, io, 1);
12450 rb_off_t copy_length;
12451 rb_off_t src_offset;
12455 unsigned close_src : 1;
12456 unsigned close_dst : 1;
12459 const char *syserr;
12460 const char *notimp;
12462 struct stat src_stat;
12463 struct stat dst_stat;
12464#ifdef HAVE_FCOPYFILE
12465 copyfile_state_t copyfile_state;
12470exec_interrupts(
void *arg)
12473 rb_thread_execute_interrupts(th);
12487#if defined(ERESTART)
12492 rb_thread_execute_interrupts(stp->th);
12511fiber_scheduler_wait_for(
void * _arguments)
12521# define IOWAIT_SYSCALL "poll"
12522STATIC_ASSERT(pollin_expected, POLLIN == RB_WAITFD_IN);
12523STATIC_ASSERT(pollout_expected, POLLOUT == RB_WAITFD_OUT);
12525nogvl_wait_for(
VALUE th, rb_io_t *fptr,
short events,
struct timeval *timeout)
12528 if (scheduler !=
Qnil) {
12531 return RTEST(args.result);
12535 if (fd == -1)
return 0;
12540 fds.events = events;
12542 int timeout_milliseconds = -1;
12545 timeout_milliseconds = (int)(timeout->tv_sec * 1000) + (int)(timeout->tv_usec / 1000);
12548 return poll(&fds, 1, timeout_milliseconds);
12551# define IOWAIT_SYSCALL "select"
12553nogvl_wait_for(
VALUE th, rb_io_t *fptr,
short events,
struct timeval *timeout)
12556 if (scheduler !=
Qnil) {
12559 return RTEST(args.result);
12579 case RB_WAITFD_OUT:
12583 VM_UNREACHABLE(nogvl_wait_for);
12603 ret = nogvl_wait_for(stp->th, stp->src_fptr, RB_WAITFD_IN, NULL);
12605 }
while (ret < 0 && maygvl_copy_stream_continue_p(has_gvl, stp));
12608 stp->syserr = IOWAIT_SYSCALL;
12609 stp->error_no =
errno;
12621 ret = nogvl_wait_for(stp->th, stp->dst_fptr, RB_WAITFD_OUT, NULL);
12622 }
while (ret < 0 && maygvl_copy_stream_continue_p(0, stp));
12625 stp->syserr = IOWAIT_SYSCALL;
12626 stp->error_no =
errno;
12632#ifdef USE_COPY_FILE_RANGE
12635simple_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)
12637#ifdef HAVE_COPY_FILE_RANGE
12638 return copy_file_range(in_fd, in_offset, out_fd, out_offset, count, flags);
12640 return syscall(__NR_copy_file_range, in_fd, in_offset, out_fd, out_offset, count, flags);
12649 rb_off_t copy_length, src_offset, *src_offset_ptr;
12651 if (!S_ISREG(stp->src_stat.st_mode))
12654 src_size = stp->src_stat.st_size;
12655 src_offset = stp->src_offset;
12656 if (src_offset >= (rb_off_t)0) {
12657 src_offset_ptr = &src_offset;
12660 src_offset_ptr = NULL;
12663 copy_length = stp->copy_length;
12664 if (copy_length < (rb_off_t)0) {
12665 if (src_offset < (rb_off_t)0) {
12666 rb_off_t current_offset;
12668 current_offset = lseek(stp->src_fptr->
fd, 0, SEEK_CUR);
12669 if (current_offset < (rb_off_t)0 &&
errno) {
12670 stp->syserr =
"lseek";
12671 stp->error_no =
errno;
12672 return (
int)current_offset;
12674 copy_length = src_size - current_offset;
12677 copy_length = src_size - src_offset;
12681 retry_copy_file_range:
12682# if SIZEOF_OFF_T > SIZEOF_SIZE_T
12684 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
12686 ss = (ssize_t)copy_length;
12688 ss = simple_copy_file_range(stp->src_fptr->
fd, src_offset_ptr, stp->dst_fptr->
fd, NULL, ss, 0);
12692 if (0 < copy_length) {
12693 goto retry_copy_file_range;
12697 if (maygvl_copy_stream_continue_p(0, stp)) {
12698 goto retry_copy_file_range;
12712#if EWOULDBLOCK != EAGAIN
12716 int ret = nogvl_copy_stream_wait_write(stp);
12717 if (ret < 0)
return ret;
12719 goto retry_copy_file_range;
12723 int flags = fcntl(stp->dst_fptr->
fd, F_GETFL);
12725 if (flags != -1 && flags & O_APPEND) {
12731 stp->syserr =
"copy_file_range";
12732 stp->error_no =
errno;
12739#ifdef HAVE_FCOPYFILE
12743 rb_off_t cur, ss = 0;
12744 const rb_off_t src_offset = stp->src_offset;
12747 if (stp->copy_length >= (rb_off_t)0) {
12752 if (!S_ISREG(stp->src_stat.st_mode))
12755 if (!S_ISREG(stp->dst_stat.st_mode))
12757 if (lseek(stp->dst_fptr->
fd, 0, SEEK_CUR) > (rb_off_t)0)
12759 if (fcntl(stp->dst_fptr->
fd, F_GETFL) & O_APPEND) {
12762 rb_off_t end = lseek(stp->dst_fptr->
fd, 0, SEEK_END);
12763 lseek(stp->dst_fptr->
fd, 0, SEEK_SET);
12764 if (end > (rb_off_t)0)
return 0;
12767 if (src_offset > (rb_off_t)0) {
12772 cur = lseek(stp->src_fptr->
fd, 0, SEEK_CUR);
12773 if (cur < (rb_off_t)0 &&
errno) {
12774 stp->error_no =
errno;
12779 r = lseek(stp->src_fptr->
fd, src_offset, SEEK_SET);
12780 if (r < (rb_off_t)0 &&
errno) {
12781 stp->error_no =
errno;
12786 stp->copyfile_state = copyfile_state_alloc();
12787 ret = fcopyfile(stp->src_fptr->
fd, stp->dst_fptr->
fd, stp->copyfile_state, COPYFILE_DATA);
12788 copyfile_state_get(stp->copyfile_state, COPYFILE_STATE_COPIED, &ss);
12792 if (src_offset > (rb_off_t)0) {
12796 r = lseek(stp->src_fptr->
fd, cur, SEEK_SET);
12797 if (r < (rb_off_t)0 &&
errno) {
12798 stp->error_no =
errno;
12810 stp->syserr =
"fcopyfile";
12811 stp->error_no =
errno;
12818#ifdef HAVE_SENDFILE
12821# define USE_SENDFILE
12823# ifdef HAVE_SYS_SENDFILE_H
12824# include <sys/sendfile.h>
12828simple_sendfile(
int out_fd,
int in_fd, rb_off_t *offset, rb_off_t count)
12830 return sendfile(out_fd, in_fd, offset, (
size_t)count);
12833# elif 0 || defined(__APPLE__)
12837# define USE_SENDFILE
12840simple_sendfile(
int out_fd,
int in_fd, rb_off_t *offset, rb_off_t count)
12843 rb_off_t pos = offset ? *offset : lseek(in_fd, 0, SEEK_CUR);
12846 r = sendfile(in_fd, out_fd, pos, &count, NULL, 0);
12849 r = sendfile(in_fd, out_fd, pos, (
size_t)count, NULL, &sbytes, 0);
12851 if (r != 0 && sbytes == 0)
return r;
12856 lseek(in_fd, sbytes, SEEK_CUR);
12858 return (ssize_t)sbytes;
12871 rb_off_t copy_length;
12872 rb_off_t src_offset;
12875 if (!S_ISREG(stp->src_stat.st_mode))
12878 src_size = stp->src_stat.st_size;
12880 if ((stp->dst_stat.st_mode & S_IFMT) != S_IFSOCK)
12884 src_offset = stp->src_offset;
12885 use_pread = src_offset >= (rb_off_t)0;
12887 copy_length = stp->copy_length;
12888 if (copy_length < (rb_off_t)0) {
12890 copy_length = src_size - src_offset;
12894 cur = lseek(stp->src_fptr->
fd, 0, SEEK_CUR);
12895 if (cur < (rb_off_t)0 &&
errno) {
12896 stp->syserr =
"lseek";
12897 stp->error_no =
errno;
12900 copy_length = src_size - cur;
12905# if SIZEOF_OFF_T > SIZEOF_SIZE_T
12907 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
12909 ss = (ssize_t)copy_length;
12912 ss = simple_sendfile(stp->dst_fptr->
fd, stp->src_fptr->
fd, &src_offset, ss);
12915 ss = simple_sendfile(stp->dst_fptr->
fd, stp->src_fptr->
fd, NULL, ss);
12920 if (0 < copy_length) {
12921 goto retry_sendfile;
12925 if (maygvl_copy_stream_continue_p(0, stp))
12926 goto retry_sendfile;
12939#if EWOULDBLOCK != EAGAIN
12952 ret = maygvl_copy_stream_wait_read(0, stp);
12953 if (ret < 0)
return ret;
12955 ret = nogvl_copy_stream_wait_write(stp);
12956 if (ret < 0)
return ret;
12958 goto retry_sendfile;
12960 stp->syserr =
"sendfile";
12961 stp->error_no =
errno;
12969maygvl_read(
int has_gvl, rb_io_t *fptr,
void *buf,
size_t count)
12972 return rb_io_read_memory(fptr, buf, count);
12974 return read(fptr->
fd, buf, count);
12978maygvl_copy_stream_read(
int has_gvl,
struct copy_stream_struct *stp,
char *buf,
size_t len, rb_off_t offset)
12982 if (offset < (rb_off_t)0) {
12983 ss = maygvl_read(has_gvl, stp->src_fptr, buf,
len);
12986 ss = pread(stp->src_fptr->
fd, buf,
len, offset);
12992 if (maygvl_copy_stream_continue_p(has_gvl, stp))
12996#if EWOULDBLOCK != EAGAIN
13000 int ret = maygvl_copy_stream_wait_read(has_gvl, stp);
13001 if (ret < 0)
return ret;
13006 stp->notimp =
"pread";
13010 stp->syserr = offset < (rb_off_t)0 ?
"read" :
"pread";
13011 stp->error_no =
errno;
13022 ss = write(stp->dst_fptr->
fd, buf+
off,
len);
13024 if (maygvl_copy_stream_continue_p(0, stp))
13026 if (io_again_p(
errno)) {
13027 int ret = nogvl_copy_stream_wait_write(stp);
13028 if (ret < 0)
return ret;
13031 stp->syserr =
"write";
13032 stp->error_no =
errno;
13049 rb_off_t copy_length;
13050 rb_off_t src_offset;
13054 copy_length = stp->copy_length;
13055 use_eof = copy_length < (rb_off_t)0;
13056 src_offset = stp->src_offset;
13057 use_pread = src_offset >= (rb_off_t)0;
13059 if (use_pread && stp->close_src) {
13062 r = lseek(stp->src_fptr->
fd, src_offset, SEEK_SET);
13063 if (r < (rb_off_t)0 &&
errno) {
13064 stp->syserr =
"lseek";
13065 stp->error_no =
errno;
13068 src_offset = (rb_off_t)-1;
13072 while (use_eof || 0 < copy_length) {
13073 if (!use_eof && copy_length < (rb_off_t)
sizeof(buf)) {
13074 len = (size_t)copy_length;
13080 ss = maygvl_copy_stream_read(0, stp, buf,
len, src_offset);
13085 ss = maygvl_copy_stream_read(0, stp, buf,
len, (rb_off_t)-1);
13090 ret = nogvl_copy_stream_write(stp, buf, ss);
13100nogvl_copy_stream_func(
void *arg)
13103#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13107#ifdef USE_COPY_FILE_RANGE
13108 ret = nogvl_copy_file_range(stp);
13113#ifdef HAVE_FCOPYFILE
13114 ret = nogvl_fcopyfile(stp);
13120 ret = nogvl_copy_stream_sendfile(stp);
13125 nogvl_copy_stream_read_write(stp);
13127#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13134copy_stream_fallback_body(
VALUE arg)
13137 const int buflen = 16*1024;
13140 rb_off_t rest = stp->copy_length;
13141 rb_off_t
off = stp->src_offset;
13142 ID read_method = id_readpartial;
13144 if (!stp->src_fptr) {
13146 read_method = id_read;
13153 rb_str_make_independent(buf);
13154 if (stp->copy_length < (rb_off_t)0) {
13159 rb_str_resize(buf, 0);
13162 l = buflen < rest ? buflen : (long)rest;
13164 if (!stp->src_fptr) {
13167 if (read_method == id_read &&
NIL_P(rc))
13172 rb_str_resize(buf, buflen);
13173 ss = maygvl_copy_stream_read(1, stp, RSTRING_PTR(buf), l,
off);
13174 rb_str_resize(buf, ss > 0 ? ss : 0);
13179 if (
off >= (rb_off_t)0)
13182 n = rb_io_write(stp->dst, buf);
13184 stp->total += numwrote;
13186 if (read_method == id_read && RSTRING_LEN(buf) == 0) {
13197 if (!stp->src_fptr && stp->src_offset >= (rb_off_t)0) {
13198 rb_raise(rb_eArgError,
"cannot specify src_offset for non-IO");
13207copy_stream_body(
VALUE arg)
13210 VALUE src_io = stp->src, dst_io = stp->dst;
13211 const int common_oflags = 0
13221 if (src_io ==
argf ||
13225 stp->src_fptr = NULL;
13230 if (!
NIL_P(tmp_io)) {
13237 args[1] =
INT2NUM(O_RDONLY|common_oflags);
13240 stp->close_src = 1;
13245 stat_ret = fstat(stp->src_fptr->
fd, &stp->src_stat);
13246 if (stat_ret < 0) {
13247 stp->syserr =
"fstat";
13248 stp->error_no =
errno;
13253 if (dst_io ==
argf ||
13257 stp->dst_fptr = NULL;
13262 if (!
NIL_P(tmp_io)) {
13263 dst_io = GetWriteIO(tmp_io);
13269 args[1] =
INT2NUM(O_WRONLY|O_CREAT|O_TRUNC|common_oflags);
13273 stp->close_dst = 1;
13276 dst_io = GetWriteIO(dst_io);
13282 stat_ret = fstat(stp->dst_fptr->
fd, &stp->dst_stat);
13283 if (stat_ret < 0) {
13284 stp->syserr =
"fstat";
13285 stp->error_no =
errno;
13292 SET_BINARY_MODE_WITH_SEEK_CUR(stp->src_fptr);
13295 io_ascii8bit_binmode(stp->dst_fptr);
13297 if (stp->src_offset < (rb_off_t)0 && stp->src_fptr && stp->src_fptr->
rbuf.
len) {
13300 if (stp->copy_length >= (rb_off_t)0 && stp->copy_length < (rb_off_t)
len) {
13301 len = (size_t)stp->copy_length;
13304 rb_str_resize(str,
len);
13305 read_buffered_data(RSTRING_PTR(str),
len, stp->src_fptr);
13306 if (stp->dst_fptr) {
13307 if (io_binwrite(RSTRING_PTR(str), RSTRING_LEN(str), stp->dst_fptr, 0) < 0)
13308 rb_sys_fail_on_write(stp->dst_fptr);
13311 rb_io_write(dst_io, str);
13312 rb_str_resize(str, 0);
13314 if (stp->copy_length >= (rb_off_t)0)
13315 stp->copy_length -=
len;
13318 if (stp->dst_fptr && io_fflush(stp->dst_fptr) < 0) {
13322 if (stp->copy_length == 0)
13325 if (stp->src_fptr == NULL || stp->dst_fptr == NULL) {
13326 return copy_stream_fallback(stp);
13329 IO_WITHOUT_GVL(nogvl_copy_stream_func, stp);
13334copy_stream_finalize(
VALUE arg)
13338#ifdef HAVE_FCOPYFILE
13339 if (stp->copyfile_state) {
13340 copyfile_state_free(stp->copyfile_state);
13344 if (stp->close_src) {
13345 rb_io_close_m(stp->src);
13347 if (stp->close_dst) {
13348 rb_io_close_m(stp->dst);
13411rb_io_s_copy_stream(
int argc,
VALUE *argv,
VALUE io)
13413 VALUE src, dst, length, src_offset;
13418 rb_scan_args(argc, argv,
"22", &src, &dst, &length, &src_offset);
13423 st.src_fptr = NULL;
13424 st.dst_fptr = NULL;
13427 st.copy_length = (rb_off_t)-1;
13429 st.copy_length =
NUM2OFFT(length);
13431 if (
NIL_P(src_offset))
13432 st.src_offset = (rb_off_t)-1;
13434 st.src_offset =
NUM2OFFT(src_offset);
13453rb_io_external_encoding(
VALUE io)
13458 return rb_enc_from_encoding(fptr->
encs.
enc2);
13462 return rb_enc_from_encoding(fptr->
encs.
enc);
13465 return rb_enc_from_encoding(io_read_encoding(fptr));
13481rb_io_internal_encoding(
VALUE io)
13486 return rb_enc_from_encoding(io_read_encoding(fptr));
13520rb_io_set_encoding(
int argc,
VALUE *argv,
VALUE io)
13526 return forward(io, id_set_encoding, argc, argv);
13529 argc =
rb_scan_args(argc, argv,
"11:", &v1, &v2, &opt);
13531 io_encoding_set(fptr, v1, v2, opt);
13536rb_stdio_set_default_encoding(
void)
13541 if (isatty(fileno(stdin))) {
13546 rb_enc_from_encoding(external),
13547 rb_enc_from_encoding(internal),
13552 rb_io_set_encoding(1, &val,
rb_stdin);
13553 rb_io_set_encoding(1, &val,
rb_stdout);
13554 rb_io_set_encoding(1, &val,
rb_stderr);
13558global_argf_p(
VALUE arg)
13560 return arg ==
argf;
13563typedef VALUE (*argf_encoding_func)(
VALUE io);
13566argf_encoding(
VALUE argf, argf_encoding_func func)
13568 if (!
RTEST(ARGF.current_file)) {
13593 return argf_encoding(
argf, rb_io_external_encoding);
13612 return argf_encoding(
argf, rb_io_internal_encoding);
13651 if (!next_argv()) {
13652 rb_raise(rb_eArgError,
"no stream to set encoding");
13654 rb_io_set_encoding(argc, argv, ARGF.current_file);
13656 ARGF.encs = fptr->
encs;
13675 if (!next_argv()) {
13676 rb_raise(rb_eArgError,
"no stream to tell");
13678 ARGF_FORWARD(0, 0);
13679 return rb_io_tell(ARGF.current_file);
13692 if (!next_argv()) {
13693 rb_raise(rb_eArgError,
"no stream to seek");
13695 ARGF_FORWARD(argc, argv);
13696 return rb_io_seek_m(argc, argv, ARGF.current_file);
13713 if (!next_argv()) {
13714 rb_raise(rb_eArgError,
"no stream to set position");
13716 ARGF_FORWARD(1, &offset);
13717 return rb_io_set_pos(ARGF.current_file, offset);
13738 if (!next_argv()) {
13739 rb_raise(rb_eArgError,
"no stream to rewind");
13741 ARGF_FORWARD(0, 0);
13742 old_lineno =
RFILE(ARGF.current_file)->fptr->lineno;
13743 ret = rb_io_rewind(ARGF.current_file);
13744 if (!global_argf_p(
argf)) {
13745 ARGF.last_lineno = ARGF.lineno -= old_lineno;
13763 if (!next_argv()) {
13764 rb_raise(rb_eArgError,
"no stream");
13766 ARGF_FORWARD(0, 0);
13767 return rb_io_fileno(ARGF.current_file);
13786 ARGF_FORWARD(0, 0);
13787 return ARGF.current_file;
13812 if (
RTEST(ARGF.current_file)) {
13813 if (ARGF.init_p == 0)
return Qtrue;
13815 ARGF_FORWARD(0, 0);
13874 VALUE tmp, str, length;
13878 if (!
NIL_P(length)) {
13883 rb_str_resize(str,0);
13888 if (!next_argv()) {
13891 if (ARGF_GENERIC_INPUT_P()) {
13892 tmp = argf_forward(argc, argv,
argf);
13895 tmp = io_read(argc, argv, ARGF.current_file);
13897 if (
NIL_P(str)) str = tmp;
13900 if (ARGF.next_p != -1) {
13906 else if (argc >= 1) {
13907 long slen = RSTRING_LEN(str);
13923argf_forward_call(
VALUE arg)
13926 argf_forward(p->argc, p->argv, p->argf);
13956 return argf_getpartial(argc, argv,
argf,
Qnil, 0);
13977 return argf_getpartial(argc, argv,
argf, opts, 1);
13983 VALUE tmp, str, length;
13991 no_exception = no_exception_p(opts);
13993 if (!next_argv()) {
13995 rb_str_resize(str, 0);
13999 if (ARGF_GENERIC_INPUT_P()) {
14009 tmp = io_getpartial(argc, argv, ARGF.current_file, no_exception, nonblock);
14012 if (ARGF.next_p == -1) {
14013 return io_nonblock_eof(no_exception);
14018 return io_nonblock_eof(no_exception);
14056 if (!next_argv())
return Qnil;
14057 if (ARGF_GENERIC_INPUT_P()) {
14058 ch = forward_current(rb_intern(
"getc"), 0, 0);
14061 ch = rb_io_getc(ARGF.current_file);
14063 if (
NIL_P(ch) && ARGF.next_p != -1) {
14096 if (!next_argv())
return Qnil;
14098 ch = forward_current(rb_intern(
"getbyte"), 0, 0);
14103 if (
NIL_P(ch) && ARGF.next_p != -1) {
14138 ch = forward_current(rb_intern(
"getc"), 0, 0);
14141 ch = rb_io_getc(ARGF.current_file);
14143 if (
NIL_P(ch) && ARGF.next_p != -1) {
14175 NEXT_ARGF_FORWARD(0, 0);
14176 c = argf_getbyte(
argf);
14183#define FOREACH_ARGF() while (next_argv())
14188 const VALUE current = ARGF.current_file;
14190 if (ARGF.init_p == -1 || current != ARGF.current_file) {
14196#define ARGF_block_call(mid, argc, argv, func, argf) \
14197 rb_block_call_kw(ARGF.current_file, mid, argc, argv, \
14198 func, argf, rb_keyword_given_p())
14203 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_i,
argf);
14204 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14210 if (!global_argf_p(
argf)) {
14211 ARGF.last_lineno = ++ARGF.lineno;
14213 return argf_block_call_i(i,
argf, argc, argv, blockarg);
14219 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_line_i,
argf);
14220 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14268 argf_block_call_line(rb_intern(
"each_line"), argc, argv,
argf);
14299 argf_block_call(rb_intern(
"each_byte"), 0, 0,
argf);
14325 argf_block_call(rb_intern(
"each_char"), 0, 0,
argf);
14351 argf_block_call(rb_intern(
"each_codepoint"), 0, 0,
argf);
14382 return ARGF.filename;
14386argf_filename_getter(
ID id,
VALUE *var)
14388 return argf_filename(*var);
14413 return ARGF.current_file;
14432 ARGF_FORWARD(0, 0);
14453 return RBOOL(ARGF.binmode);
14473 if (ARGF.init_p && ARGF.next_p == 0) {
14502 if (ARGF.next_p != -1) {
14520 ARGF_FORWARD(0, 0);
14547 if (!ARGF.inplace)
return Qnil;
14555 return argf_inplace_mode_get(*var);
14586 ARGF.inplace =
Qnil;
14597 argf_inplace_mode_set(*var, val);
14601ruby_set_inplace_mode(
const char *suffix)
14627argf_argv_getter(
ID id,
VALUE *var)
14629 return argf_argv(*var);
14648 if (!
RTEST(ARGF.current_file)) {
14651 return GetWriteIO(ARGF.current_file);
14663 return rb_io_writev(argf_write_io(
argf), argc, argv);
14678 case RB_IO_WAIT_WRITABLE:
14681 c = rb_eEAGAINWaitWritable;
14683#if EAGAIN != EWOULDBLOCK
14685 c = rb_eEWOULDBLOCKWaitWritable;
14689 c = rb_eEINPROGRESSWaitWritable;
14695 case RB_IO_WAIT_READABLE:
14698 c = rb_eEAGAINWaitReadable;
14700#if EAGAIN != EWOULDBLOCK
14702 c = rb_eEWOULDBLOCKWaitReadable;
14706 c = rb_eEINPROGRESSWaitReadable;
14713 rb_bug(
"invalid read/write type passed to rb_readwrite_sys_fail: %d", waiting);
14719get_LAST_READ_LINE(
ID _x,
VALUE *_y)
15604#include <sys/cygwin.h>
15605 static struct __cygwin_perfile pf[] =
15607 {
"", O_RDONLY | O_BINARY},
15608 {
"", O_WRONLY | O_BINARY},
15609 {
"", O_RDWR | O_BINARY},
15610 {
"", O_APPEND | O_BINARY},
15613 cygwin_internal(CW_PERFILE, pf);
15668#if EAGAIN == EWOULDBLOCK
15669 rb_eEWOULDBLOCKWaitReadable = rb_eEAGAINWaitReadable;
15672 rb_eEWOULDBLOCKWaitWritable = rb_eEAGAINWaitWritable;
15714 rb_output_fs =
Qnil;
15726 rb_gvar_ractor_local(
"$_");
15842 rb_gvar_ractor_local(
"$stdin");
15843 rb_gvar_ractor_local(
"$stdout");
15844 rb_gvar_ractor_local(
"$>");
15845 rb_gvar_ractor_local(
"$stderr");
15931 rb_define_method(rb_cARGF,
"external_encoding", argf_external_encoding, 0);
15932 rb_define_method(rb_cARGF,
"internal_encoding", argf_internal_encoding, 0);
15951 rb_gvar_ractor_local(
"$-i");
15955#if defined (_WIN32) || defined(__CYGWIN__)
15956 atexit(pipe_atexit);
15968 sym_encoding =
ID2SYM(rb_id_encoding());
#define RUBY_ASSERT(...)
Asserts that the given expression is truthy if and only if RUBY_DEBUG is truthy.
std::atomic< unsigned > rb_atomic_t
Type that is eligible for atomic operations.
#define STRNCASECMP
@old{st_locale_insensitive_strncasecmp}
unsigned long ruby_strtoul(const char *str, char **endptr, int base)
Our own locale-insensitive version of strtoul(3).
#define rb_define_method(klass, mid, func, arity)
Defines klass#mid.
#define rb_define_singleton_method(klass, mid, func, arity)
Defines klass.mid.
#define rb_define_global_function(mid, func, arity)
Defines rb_mKernel #mid.
void rb_include_module(VALUE klass, VALUE module)
Includes a module to a class.
VALUE rb_define_class(const char *name, VALUE super)
Defines a top-level class.
VALUE rb_class_new(VALUE super)
Creates a new, anonymous class.
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
VALUE rb_define_module_under(VALUE outer, const char *name)
Defines a module under the namespace of outer.
void rb_define_alias(VALUE klass, const char *name1, const char *name2)
Defines an alias of a method.
int rb_scan_args_kw(int kw_flag, int argc, const VALUE *argv, const char *fmt,...)
Identical to rb_scan_args(), except it also accepts kw_splat.
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Retrieves argument from argc and argv to given VALUE references according to the format string.
int rb_block_given_p(void)
Determines if the current method is given a block.
int rb_get_kwargs(VALUE keyword_hash, const ID *table, int required, int optional, VALUE *values)
Keyword argument deconstructor.
#define ECONV_AFTER_OUTPUT
Old name of RUBY_ECONV_AFTER_OUTPUT.
#define rb_str_new2
Old name of rb_str_new_cstr.
#define TYPE(_)
Old name of rb_type.
#define RB_INTEGER_TYPE_P
Old name of rb_integer_type_p.
#define ENC_CODERANGE_7BIT
Old name of RUBY_ENC_CODERANGE_7BIT.
#define T_FILE
Old name of RUBY_T_FILE.
#define ENC_CODERANGE_VALID
Old name of RUBY_ENC_CODERANGE_VALID.
#define ECONV_UNIVERSAL_NEWLINE_DECORATOR
Old name of RUBY_ECONV_UNIVERSAL_NEWLINE_DECORATOR.
#define OBJ_INIT_COPY(obj, orig)
Old name of RB_OBJ_INIT_COPY.
#define ALLOC
Old name of RB_ALLOC.
#define T_STRING
Old name of RUBY_T_STRING.
#define Qundef
Old name of RUBY_Qundef.
#define INT2FIX
Old name of RB_INT2FIX.
#define rb_str_cat2
Old name of rb_str_cat_cstr.
#define T_NIL
Old name of RUBY_T_NIL.
#define UNREACHABLE
Old name of RBIMPL_UNREACHABLE.
#define ID2SYM
Old name of RB_ID2SYM.
#define T_BIGNUM
Old name of RUBY_T_BIGNUM.
#define OBJ_FREEZE
Old name of RB_OBJ_FREEZE.
#define T_FIXNUM
Old name of RUBY_T_FIXNUM.
#define UNREACHABLE_RETURN
Old name of RBIMPL_UNREACHABLE_RETURN.
#define FIX2UINT
Old name of RB_FIX2UINT.
#define SSIZET2NUM
Old name of RB_SSIZE2NUM.
#define ZALLOC
Old name of RB_ZALLOC.
#define CLASS_OF
Old name of rb_class_of.
#define rb_ary_new4
Old name of rb_ary_new_from_values.
#define ECONV_NEWLINE_DECORATOR_WRITE_MASK
Old name of RUBY_ECONV_NEWLINE_DECORATOR_WRITE_MASK.
#define ENCODING_MAXNAMELEN
Old name of RUBY_ENCODING_MAXNAMELEN.
#define MBCLEN_NEEDMORE_LEN(ret)
Old name of ONIGENC_MBCLEN_NEEDMORE_LEN.
#define ENCODING_GET(obj)
Old name of RB_ENCODING_GET.
#define LONG2FIX
Old name of RB_INT2FIX.
#define NUM2UINT
Old name of RB_NUM2UINT.
#define ALLOC_N
Old name of RB_ALLOC_N.
#define MBCLEN_CHARFOUND_LEN(ret)
Old name of ONIGENC_MBCLEN_CHARFOUND_LEN.
#define LONG2NUM
Old name of RB_LONG2NUM.
#define rb_exc_new3
Old name of rb_exc_new_str.
#define MBCLEN_INVALID_P(ret)
Old name of ONIGENC_MBCLEN_INVALID_P.
#define ECONV_STATEFUL_DECORATOR_MASK
Old name of RUBY_ECONV_STATEFUL_DECORATOR_MASK.
#define Qtrue
Old name of RUBY_Qtrue.
#define MBCLEN_NEEDMORE_P(ret)
Old name of ONIGENC_MBCLEN_NEEDMORE_P.
#define ECONV_PARTIAL_INPUT
Old name of RUBY_ECONV_PARTIAL_INPUT.
#define NUM2INT
Old name of RB_NUM2INT.
#define ECONV_ERROR_HANDLER_MASK
Old name of RUBY_ECONV_ERROR_HANDLER_MASK.
#define INT2NUM
Old name of RB_INT2NUM.
#define Qnil
Old name of RUBY_Qnil.
#define Qfalse
Old name of RUBY_Qfalse.
#define FIX2LONG
Old name of RB_FIX2LONG.
#define ENC_CODERANGE_BROKEN
Old name of RUBY_ENC_CODERANGE_BROKEN.
#define T_ARRAY
Old name of RUBY_T_ARRAY.
#define NIL_P
Old name of RB_NIL_P.
#define ALLOCV_N
Old name of RB_ALLOCV_N.
#define MBCLEN_CHARFOUND_P(ret)
Old name of ONIGENC_MBCLEN_CHARFOUND_P.
#define ECONV_NEWLINE_DECORATOR_READ_MASK
Old name of RUBY_ECONV_NEWLINE_DECORATOR_READ_MASK.
#define NUM2CHR
Old name of RB_NUM2CHR.
#define NUM2LONG
Old name of RB_NUM2LONG.
#define UINT2NUM
Old name of RB_UINT2NUM.
#define FIXNUM_P
Old name of RB_FIXNUM_P.
#define ECONV_NEWLINE_DECORATOR_MASK
Old name of RUBY_ECONV_NEWLINE_DECORATOR_MASK.
#define CONST_ID
Old name of RUBY_CONST_ID.
#define rb_ary_new2
Old name of rb_ary_new_capa.
#define NUM2SIZET
Old name of RB_NUM2SIZE.
#define ENC_CODERANGE_SET(obj, cr)
Old name of RB_ENC_CODERANGE_SET.
#define rb_str_new4
Old name of rb_str_new_frozen.
#define ALLOCV_END
Old name of RB_ALLOCV_END.
#define SYMBOL_P
Old name of RB_SYMBOL_P.
#define ECONV_DEFAULT_NEWLINE_DECORATOR
Old name of RUBY_ECONV_DEFAULT_NEWLINE_DECORATOR.
void rb_notimplement(void)
void rb_category_warn(rb_warning_category_t category, const char *fmt,...)
Identical to rb_category_warning(), except it reports unless $VERBOSE is nil.
void rb_category_warning(rb_warning_category_t category, const char *fmt,...)
Identical to rb_warning(), except it takes additional "category" parameter.
VALUE rb_eNotImpError
NotImplementedError exception.
void rb_syserr_fail(int e, const char *mesg)
Raises appropriate exception that represents a C errno.
void rb_readwrite_syserr_fail(enum rb_io_wait_readwrite waiting, int n, const char *mesg)
Identical to rb_readwrite_sys_fail(), except it does not depend on C global variable errno.
VALUE rb_eIOError
IOError exception.
VALUE rb_eStandardError
StandardError exception.
void rb_mod_syserr_fail_str(VALUE mod, int e, VALUE mesg)
Identical to rb_mod_syserr_fail(), except it takes the message in Ruby's String instead of C's.
void rb_syserr_fail_str(int e, VALUE mesg)
Identical to rb_syserr_fail(), except it takes the message in Ruby's String instead of C's.
#define ruby_verbose
This variable controls whether the interpreter is in debug mode.
VALUE rb_eTypeError
TypeError exception.
VALUE rb_eEOFError
EOFError exception.
void rb_readwrite_sys_fail(enum rb_io_wait_readwrite waiting, const char *mesg)
Raises appropriate exception using the parameters.
void rb_iter_break_value(VALUE val)
Identical to rb_iter_break(), except it additionally takes the "value" of this breakage.
rb_io_wait_readwrite
for rb_readwrite_sys_fail first argument
VALUE rb_eRuntimeError
RuntimeError exception.
void rb_warn(const char *fmt,...)
Identical to rb_warning(), except it reports unless $VERBOSE is nil.
VALUE rb_eSystemCallError
SystemCallError exception.
@ RB_WARN_CATEGORY_DEPRECATED
Warning is for deprecated features.
VALUE rb_mKernel
Kernel module.
VALUE rb_check_to_int(VALUE val)
Identical to rb_check_to_integer(), except it uses #to_int for conversion.
VALUE rb_any_to_s(VALUE obj)
Generates a textual representation of the given object.
VALUE rb_obj_alloc(VALUE klass)
Allocates an instance of the given class.
VALUE rb_class_new_instance(int argc, const VALUE *argv, VALUE klass)
Allocates, then initialises an instance of the given class.
VALUE rb_class_new_instance_kw(int argc, const VALUE *argv, VALUE klass, int kw_splat)
Identical to rb_class_new_instance(), except you can specify how to handle the last element of the gi...
VALUE rb_mEnumerable
Enumerable module.
VALUE rb_stdin
STDIN constant.
VALUE rb_stderr
STDERR constant.
VALUE rb_obj_class(VALUE obj)
Queries the class of an object.
VALUE rb_obj_dup(VALUE obj)
Duplicates the given object.
VALUE rb_inspect(VALUE obj)
Generates a human-readable textual representation of the given object.
VALUE rb_mWaitReadable
IO::WaitReadable module.
VALUE rb_mWaitWritable
IO::WaitReadable module.
VALUE rb_obj_freeze(VALUE obj)
Just calls rb_obj_freeze_inline() inside.
VALUE rb_check_to_integer(VALUE val, const char *mid)
Identical to rb_check_convert_type(), except the return value type is fixed to rb_cInteger.
VALUE rb_cFile
File class.
VALUE rb_stdout
STDOUT constant.
VALUE rb_to_int(VALUE val)
Identical to rb_check_to_int(), except it raises in case of conversion mismatch.
rb_encoding * rb_ascii8bit_encoding(void)
Queries the encoding that represents ASCII-8BIT a.k.a.
rb_encoding * rb_default_internal_encoding(void)
Queries the "default internal" encoding.
int rb_utf8_encindex(void)
Identical to rb_utf8_encoding(), except it returns the encoding's index instead of the encoding itsel...
VALUE rb_enc_default_external(void)
Identical to rb_default_external_encoding(), except it returns the Ruby-level counterpart instance of...
static unsigned int rb_enc_codepoint(const char *p, const char *e, rb_encoding *enc)
Queries the code point of character pointed by the passed pointer.
rb_encoding * rb_default_external_encoding(void)
Queries the "default external" encoding.
rb_encoding * rb_locale_encoding(void)
Queries the encoding that represents the current locale.
rb_encoding * rb_usascii_encoding(void)
Queries the encoding that represents US-ASCII.
VALUE rb_str_conv_enc(VALUE str, rb_encoding *from, rb_encoding *to)
Encoding conversion main routine.
VALUE rb_enc_uint_chr(unsigned int code, rb_encoding *enc)
Encodes the passed code point into a series of bytes.
long rb_str_coderange_scan_restartable(const char *str, const char *end, rb_encoding *enc, int *cr)
Scans the passed string until it finds something odd.
int rb_econv_prepare_options(VALUE opthash, VALUE *ecopts, int ecflags)
Identical to rb_econv_prepare_opts(), except it additionally takes the initial value of flags.
VALUE rb_econv_open_exc(const char *senc, const char *denc, int ecflags)
Creates a rb_eConverterNotFoundError exception object (but does not raise).
rb_econv_result_t rb_econv_convert(rb_econv_t *ec, const unsigned char **source_buffer_ptr, const unsigned char *source_buffer_end, unsigned char **destination_buffer_ptr, unsigned char *destination_buffer_end, int flags)
Converts a string from an encoding to another.
rb_econv_result_t
return value of rb_econv_convert()
@ econv_incomplete_input
The conversion stopped in middle of reading a character, possibly due to a partial read of a socket e...
@ econv_finished
The conversion stopped after converting everything.
@ econv_undefined_conversion
The conversion stopped when it found a character in the input which cannot be representable in the ou...
@ econv_source_buffer_empty
The conversion stopped because there is no input.
@ econv_destination_buffer_full
The conversion stopped because there is no destination.
@ econv_invalid_byte_sequence
The conversion stopped when it found an invalid sequence.
int rb_econv_putbackable(rb_econv_t *ec)
Queries if rb_econv_putback() makes sense, i.e.
const char * rb_econv_asciicompat_encoding(const char *encname)
Queries the passed encoding's corresponding ASCII compatible encoding.
VALUE rb_econv_str_convert(rb_econv_t *ec, VALUE src, int flags)
Identical to rb_econv_convert(), except it takes Ruby's string instead of C's pointer.
rb_econv_t * rb_econv_open_opts(const char *source_encoding, const char *destination_encoding, int ecflags, VALUE ecopts)
Identical to rb_econv_open(), except it additionally takes a hash of optional strings.
void rb_econv_binmode(rb_econv_t *ec)
This badly named function does not set the destination encoding to binary, but instead just nullifies...
VALUE rb_str_encode(VALUE str, VALUE to, int ecflags, VALUE ecopts)
Converts the contents of the passed string from its encoding to the passed one.
VALUE rb_econv_make_exception(rb_econv_t *ec)
This function makes sense right after rb_econv_convert() returns.
void rb_econv_check_error(rb_econv_t *ec)
This is a rb_econv_make_exception() + rb_exc_raise() combo.
void rb_econv_close(rb_econv_t *ec)
Destructs a converter.
void rb_econv_putback(rb_econv_t *ec, unsigned char *p, int n)
Puts back the bytes.
VALUE rb_funcall(VALUE recv, ID mid, int n,...)
Calls a method.
VALUE rb_funcallv_kw(VALUE recv, ID mid, int argc, const VALUE *argv, int kw_splat)
Identical to rb_funcallv(), except you can specify how to handle the last element of the given array.
void rb_gc(void)
Triggers a GC process.
VALUE rb_ary_new(void)
Allocates a new, empty array.
#define RETURN_ENUMERATOR(obj, argc, argv)
Identical to RETURN_SIZED_ENUMERATOR(), except its size is unknown.
static int rb_check_arity(int argc, int min, int max)
Ensures that the passed integer is in the passed range.
ID rb_frame_this_func(void)
Queries the name of the Ruby level method that is calling this function.
VALUE rb_hash_new(void)
Creates a new, empty hash object.
VALUE rb_io_printf(int argc, const VALUE *argv, VALUE io)
This is a rb_f_sprintf() + rb_io_write() combo.
VALUE rb_io_gets(VALUE io)
Reads a "line" from the given IO.
int rb_cloexec_pipe(int fildes[2])
Opens a pipe with closing on exec.
VALUE rb_io_print(int argc, const VALUE *argv, VALUE io)
Iterates over the passed array to apply rb_io_write() individually.
VALUE rb_io_addstr(VALUE io, VALUE str)
Identical to rb_io_write(), except it always returns the passed IO.
void rb_write_error(const char *str)
Writes the given error message to somewhere applicable.
VALUE rb_io_ungetbyte(VALUE io, VALUE b)
Identical to rb_io_ungetc(), except it doesn't take the encoding of the passed IO into account.
VALUE rb_io_getbyte(VALUE io)
Reads a byte from the given IO.
int rb_cloexec_dup2(int oldfd, int newfd)
Identical to rb_cloexec_dup(), except you can specify the destination file descriptor.
VALUE rb_io_fdopen(int fd, int flags, const char *path)
Creates an IO instance whose backend is the given file descriptor.
void rb_update_max_fd(int fd)
Informs the interpreter that the passed fd can be the max.
int rb_cloexec_open(const char *pathname, int flags, mode_t mode)
Opens a file that closes on exec.
VALUE rb_output_rs
The record separator character for outputs, or the $\\endiskip.
VALUE rb_io_eof(VALUE io)
Queries if the passed IO is at the end of file.
void rb_write_error2(const char *str, long len)
Identical to rb_write_error(), except it additionally takes the message's length.
void rb_close_before_exec(int lowfd, int maxhint, VALUE noclose_fds)
Closes everything.
int rb_reserved_fd_p(int fd)
Queries if the given FD is reserved or not.
void rb_fd_fix_cloexec(int fd)
Sets or clears the close-on-exec flag of the passed file descriptor to the desired state.
VALUE rb_io_ascii8bit_binmode(VALUE io)
Forces no conversions be applied to the passed IO.
VALUE rb_io_binmode(VALUE io)
Sets the binmode.
VALUE rb_io_ungetc(VALUE io, VALUE c)
"Unget"s a string.
int rb_pipe(int *pipes)
This is an rb_cloexec_pipe() + rb_update_max_fd() combo.
VALUE rb_gets(void)
Much like rb_io_gets(), but it reads from the mysterious ARGF object.
int rb_cloexec_fcntl_dupfd(int fd, int minfd)
Duplicates a file descriptor with closing on exec.
VALUE rb_file_open_str(VALUE fname, const char *fmode)
Identical to rb_file_open(), except it takes the pathname as a Ruby's string instead of C's.
int rb_cloexec_dup(int oldfd)
Identical to rb_cloexec_fcntl_dupfd(), except it implies minfd is 3.
VALUE rb_file_open(const char *fname, const char *fmode)
Opens a file located at the given path.
VALUE rb_io_close(VALUE io)
Closes the IO.
VALUE rb_default_rs
This is the default value of rb_rs, i.e.
void rb_lastline_set(VALUE str)
Updates $_.
VALUE rb_lastline_get(void)
Queries the last line, or the $_.
int rb_obj_method_arity(VALUE obj, ID mid)
Identical to rb_mod_method_arity(), except it searches for singleton methods rather than instance met...
rb_pid_t rb_waitpid(rb_pid_t pid, int *status, int flags)
Waits for a process, with releasing GVL.
void rb_last_status_set(int status, rb_pid_t pid)
Sets the "last status", or the $?.
VALUE rb_str_append(VALUE dst, VALUE src)
Identical to rb_str_buf_append(), except it converts the right hand side before concatenating.
#define rb_str_new(str, len)
Allocates an instance of rb_cString.
#define rb_str_buf_cat
Just another name of rb_str_cat.
#define rb_usascii_str_new(str, len)
Identical to rb_str_new, except it generates a string of "US ASCII" encoding.
size_t rb_str_capacity(VALUE str)
Queries the capacity of the given string.
VALUE rb_str_new_frozen(VALUE str)
Creates a frozen copy of the string, if necessary.
VALUE rb_str_dup(VALUE str)
Duplicates a string.
VALUE rb_str_cat(VALUE dst, const char *src, long srclen)
Destructively appends the passed contents to the string.
VALUE rb_str_locktmp(VALUE str)
Obtains a "temporary lock" of the string.
rb_gvar_setter_t rb_str_setter
This is a rb_gvar_setter_t that refutes non-string assignments.
void rb_str_set_len(VALUE str, long len)
Overwrites the length of the string.
VALUE rb_str_buf_cat_ascii(VALUE dst, const char *src)
Identical to rb_str_cat_cstr(), except it additionally assumes the source string be a NUL terminated ...
VALUE rb_check_string_type(VALUE obj)
Try converting an object to its stringised representation using its to_str method,...
VALUE rb_str_substr(VALUE str, long beg, long len)
This is the implementation of two-argumented String#slice.
VALUE rb_str_unlocktmp(VALUE str)
Releases a lock formerly obtained by rb_str_locktmp().
void rb_str_modify_expand(VALUE str, long capa)
Identical to rb_str_modify(), except it additionally expands the capacity of the receiver.
VALUE rb_str_buf_new(long capa)
Allocates a "string buffer".
#define rb_str_new_cstr(str)
Identical to rb_str_new, except it assumes the passed pointer is a pointer to a C string.
int rb_thread_interrupted(VALUE thval)
Checks if the thread's execution was recently interrupted.
VALUE rb_mutex_new(void)
Creates a mutex.
int rb_thread_fd_writable(int fd)
Identical to rb_thread_wait_fd(), except it blocks the current thread until the given file descriptor...
VALUE rb_exec_recursive(VALUE(*f)(VALUE g, VALUE h, int r), VALUE g, VALUE h)
"Recursion" API entry point.
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".
int rb_io_fptr_finalize(rb_io_t *fptr)
Destroys the given IO.
VALUE rb_io_check_io(VALUE io)
Try converting an object to its IO representation using its to_io method, if any.
VALUE rb_io_closed_p(VALUE io)
Returns whether or not the underlying IO is closed.
struct rb_io_internal_buffer rb_io_buffer_t
Just another name of rb_io_buffer_t.
VALUE rb_io_set_timeout(VALUE io, VALUE timeout)
Set the timeout associated with the specified io object.
ssize_t rb_io_bufwrite(VALUE io, const void *buf, size_t size)
Buffered write to the passed IO.
void rb_io_check_char_readable(rb_io_t *fptr)
Asserts that an IO is opened for character-based reading.
#define FMODE_TRUNC
This flag amends the effect of FMODE_CREATE, so that if there already is a file at the given path it ...
int rb_io_read_pending(rb_io_t *fptr)
Queries if the passed IO has any pending reads.
VALUE rb_io_get_write_io(VALUE io)
Queries the tied IO for writing.
void rb_io_set_nonblock(rb_io_t *fptr)
Instructs the OS to put its internal file structure into "nonblocking mode".
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_stderr(void)
Queries the standard error of the current Ractor that is calling this function.
VALUE rb_ractor_stdin(void)
Queries the standard input of the current Ractor that is calling this function.
void rb_ractor_stderr_set(VALUE io)
Assigns an IO to the standard error of the Ractor that is calling this function.
VALUE rb_ractor_stdout(void)
Queries the standard output of the current Ractor that is calling this function.
void rb_ractor_stdout_set(VALUE io)
Assigns an IO to the standard output of the Ractor that is calling this function.
void rb_ractor_stdin_set(VALUE io)
Assigns an IO to the standard input of the Ractor that is calling this function.
void * rb_thread_call_with_gvl(void *(*func)(void *), void *data1)
(Re-)acquires the GVL.
#define RB_NUM2INT
Just another name of rb_num2int_inline.
#define RB_INT2NUM
Just another name of rb_int2num_inline.
VALUE rb_f_sprintf(int argc, const VALUE *argv)
Identical to rb_str_format(), except how the arguments are arranged.
#define RB_BLOCK_CALL_FUNC_ARGLIST(yielded_arg, callback_arg)
Shim for block function parameters.
VALUE rb_yield_values2(int n, const VALUE *argv)
Identical to rb_yield_values(), except it takes the parameters as a C array instead of variadic argum...
VALUE rb_yield(VALUE val)
Yields the block.
void rb_fd_term(rb_fdset_t *f)
Destroys the rb_fdset_t, releasing any memory and resources it used.
#define MEMZERO(p, type, n)
Handy macro to erase a region of memory.
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
#define MEMMOVE(p1, p2, type, n)
Handy macro to call memmove.
#define NUM2MODET
Converts a C's mode_t into an instance of rb_cInteger.
void rb_define_hooked_variable(const char *q, VALUE *w, type *e, void_type *r)
Define a function-backended global variable.
void rb_define_virtual_variable(const char *q, type *w, void_type *e)
Define a function-backended global variable.
VALUE rb_rescue2(type *q, VALUE w, type *e, VALUE r,...)
An equivalent of rescue clause.
VALUE rb_ensure(type *q, VALUE w, type *e, VALUE r)
An equivalent of ensure clause.
#define PRI_OFFT_PREFIX
A rb_sprintf() format prefix to be used for an off_t parameter.
#define OFFT2NUM
Converts a C's off_t into an instance of rb_cInteger.
#define NUM2OFFT
Converts an instance of rb_cNumeric into C's off_t.
#define PIDT2NUM
Converts a C's pid_t into an instance of rb_cInteger.
#define rb_fd_isset
Queries if the given fd is in the rb_fdset_t.
#define rb_fd_select
Waits for multiple file descriptors at once.
#define rb_fd_init
Initialises the :given :rb_fdset_t.
#define rb_fd_set
Sets the given fd to the rb_fdset_t.
#define RARRAY_LEN
Just another name of rb_array_len.
static int RARRAY_LENINT(VALUE ary)
Identical to rb_array_len(), except it differs for the return type.
#define RARRAY_AREF(a, i)
#define RARRAY_CONST_PTR
Just another name of rb_array_const_ptr.
#define RFILE(obj)
Convenient casting macro.
#define StringValue(v)
Ensures that the parameter object is a String.
static char * RSTRING_END(VALUE str)
Queries the end of the contents pointer of the string.
#define RSTRING_GETMEM(str, ptrvar, lenvar)
Convenient macro to obtain the contents and length at once.
#define StringValueCStr(v)
Identical to StringValuePtr, except it additionally checks for the contents for viability as a C stri...
#define RUBY_TYPED_DEFAULT_FREE
This is a value you can set to rb_data_type_struct::dfree.
struct rb_data_type_struct rb_data_type_t
This is the struct that holds necessary info for a struct.
#define TypedData_Make_Struct(klass, type, data_type, sval)
Identical to TypedData_Wrap_Struct, except it allocates a new data region internally instead of takin...
VALUE rb_get_argv(void)
Queries the arguments passed to the current process that you can access from Ruby as ARGV.
void rb_p(VALUE obj)
Inspects an object.
#define FilePathValue(v)
Ensures that the parameter object is a path.
#define errno
Ractor-aware version of errno.
#define RB_SCAN_ARGS_LAST_HASH_KEYWORDS
Treat a final argument as keywords if it is a hash, and not as keywords otherwise.
#define RB_PASS_CALLED_KEYWORDS
Pass keywords if current method is called with keywords, useful for argument delegation.
VALUE rb_fiber_scheduler_current(void)
Identical to rb_fiber_scheduler_get(), except it also returns RUBY_Qnil in case of a blocking fiber.
VALUE rb_fiber_scheduler_io_pread_memory(VALUE scheduler, VALUE io, rb_off_t from, void *base, size_t size, size_t length)
Non-blocking pread from the passed IO using a native buffer.
VALUE rb_fiber_scheduler_make_timeout(struct timeval *timeout)
Converts the passed timeout to an expression that rb_fiber_scheduler_block() etc.
VALUE rb_fiber_scheduler_io_wait_readable(VALUE scheduler, VALUE io)
Non-blocking wait until the passed IO is ready for reading.
VALUE rb_fiber_scheduler_io_read_memory(VALUE scheduler, VALUE io, void *base, size_t size, size_t length)
Non-blocking read from the passed IO using a native buffer.
VALUE rb_fiber_scheduler_io_wait(VALUE scheduler, VALUE io, VALUE events, VALUE timeout)
Non-blocking version of rb_io_wait().
static ssize_t rb_fiber_scheduler_io_result_apply(VALUE result)
Apply an io result to the local thread, returning the value of the original system call that created ...
VALUE rb_fiber_scheduler_io_selectv(VALUE scheduler, int argc, VALUE *argv)
Non-blocking version of IO.select, argv variant.
VALUE rb_fiber_scheduler_io_pwrite_memory(VALUE scheduler, VALUE io, rb_off_t from, const void *base, size_t size, size_t length)
Non-blocking pwrite to the passed IO using a native buffer.
VALUE rb_fiber_scheduler_current_for_thread(VALUE thread)
Identical to rb_fiber_scheduler_current(), except it queries for that of the passed thread 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.
C99 shim for <stdbool.h>.
The data structure which wraps the fd_set bitmap used by select(2).
Decomposed encoding flags (e.g.
VALUE ecopts
Flags as Ruby hash.
rb_encoding * enc2
External encoding.
rb_encoding * enc
Internal encoding.
char * ptr
Pointer to the underlying memory region, of at least capa bytes.
int off
Offset inside of ptr.
int len
Length of the buffer.
int capa
Designed capacity of the buffer.
Ruby's IO, metadata and buffers.
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.
static bool RB_TYPE_P(VALUE obj, enum ruby_value_type t)
Queries if the given object is of given type.