14#include "ruby/internal/config.h"
25# if defined(__linux__)
28# if defined(__FreeBSD_version) && __FreeBSD_version >= 1100000
38#define free(x) xfree(x)
45#if defined HAVE_NET_SOCKET_H
46# include <net/socket.h>
47#elif defined HAVE_SYS_SOCKET_H
48# include <sys/socket.h>
51#if defined(__CYGWIN__) || defined(_WIN32)
52# define NO_SAFE_RENAME
55#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__sun)
60#ifdef HAVE_SYS_IOCTL_H
63#if defined(HAVE_FCNTL_H)
65#elif defined(HAVE_SYS_FCNTL_H)
75#if defined(HAVE_SYS_PARAM_H)
76# include <sys/param.h>
89#elif defined HAVE_SYS_SYSCALL_H
90#include <sys/syscall.h>
101#ifdef HAVE_COPYFILE_H
102# include <copyfile.h>
106# include <AvailabilityMacros.h>
110#include "ccan/list/list.h"
115#include "internal/class.h"
116#include "internal/encoding.h"
117#include "internal/error.h"
118#include "internal/inits.h"
119#include "internal/io.h"
120#include "internal/numeric.h"
121#include "internal/object.h"
122#include "internal/process.h"
123#include "internal/string.h"
124#include "internal/thread.h"
125#include "internal/transcode.h"
126#include "internal/variable.h"
129#include "ruby/missing.h"
132#include "ruby_atomic.h"
142#define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR)
146# ifdef _POSIX_PIPE_BUF
147# define PIPE_BUF _POSIX_PIPE_BUF
154# define EWOULDBLOCK EAGAIN
157#if defined(HAVE___SYSCALL) && (defined(__APPLE__) || defined(__OpenBSD__))
159off_t __syscall(quad_t number, ...);
162#define IO_RBUF_CAPA_MIN 8192
163#define IO_CBUF_CAPA_MIN (128*1024)
164#define IO_RBUF_CAPA_FOR(fptr) (NEED_READCONV(fptr) ? IO_CBUF_CAPA_MIN : IO_RBUF_CAPA_MIN)
165#define IO_WBUF_CAPA_MIN 8192
167#define IO_MAX_BUFFER_GROWTH 8 * 1024 * 1024
172#define open rb_w32_uopen
174#define rename(f, t) rb_w32_urename((f), (t))
175#include "win32/file.h"
185static VALUE rb_eEAGAINWaitReadable;
186static VALUE rb_eEAGAINWaitWritable;
187#if EAGAIN != EWOULDBLOCK
188static VALUE rb_eEWOULDBLOCKWaitReadable;
189static VALUE rb_eEWOULDBLOCKWaitWritable;
191static VALUE rb_eEINPROGRESSWaitWritable;
192static VALUE rb_eEINPROGRESSWaitReadable;
195static VALUE orig_stdout, orig_stderr;
204static ID id_write, id_read, id_flush, id_readpartial, id_set_encoding, id_fileno;
205static VALUE sym_mode, sym_perm, sym_flags, sym_extenc, sym_intenc, sym_encoding, sym_open_args;
206static VALUE sym_textmode, sym_binmode, sym_autoclose;
207static VALUE sym_SET, sym_CUR, sym_END;
208static VALUE sym_wait_readable, sym_wait_writable;
210static VALUE sym_DATA;
213static VALUE sym_HOLE;
216static VALUE prep_io(
int fd,
enum rb_io_mode fmode,
VALUE klass,
const char *path);
219rb_io_blocking_region_wait(
struct rb_io *io, rb_blocking_function_t *function,
void *argument,
enum rb_io_event events)
221 return rb_thread_io_blocking_call(io, function, argument, events);
224VALUE rb_io_blocking_region(
struct rb_io *io, rb_blocking_function_t *function,
void *argument)
226 return rb_io_blocking_region_wait(io, function, argument, 0);
230 VALUE filename, current_file;
236 int8_t init_p, next_p, binmode;
240#if defined(__APPLE__) && \
241 (!defined(MAC_OS_VERSION_27_0) || (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_VERSION_27_0))
243# if __has_attribute(availability) && __has_warning("-Wunguarded-availability-new")
249static inline int (*rb_dup3(
void))(int, int, int) {
return &dup3;}
250# define dup3 rb_dup3()
254static inline int (*rb_pipe2(
void))(
int [2], int) {
return &pipe2;}
255# define pipe2 rb_pipe2()
280 if (fd < 0 || afd <= max_fd)
283#if defined(HAVE_FCNTL) && defined(F_GETFL)
284 err = fcntl(fd, F_GETFL) == -1;
288 err = fstat(fd, &buf) != 0;
291 if (err &&
errno == EBADF) {
292 rb_bug(
"rb_update_max_fd: invalid fd (%d) given.", fd);
295 while (max_fd < afd) {
296 max_fd = ATOMIC_CAS(max_file_descriptor, max_fd, afd);
301rb_maygvl_fd_fix_cloexec(
int fd)
304#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
305 int flags, flags2, ret;
306 flags = fcntl(fd, F_GETFD);
308 rb_bug(
"rb_maygvl_fd_fix_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(
errno));
311 flags2 = flags & ~FD_CLOEXEC;
313 flags2 = flags | FD_CLOEXEC;
314 if (flags != flags2) {
315 ret = fcntl(fd, F_SETFD, flags2);
317 rb_bug(
"rb_maygvl_fd_fix_cloexec: fcntl(%d, F_SETFD, %d) failed: %s", fd, flags2, strerror(
errno));
326 rb_maygvl_fd_fix_cloexec(fd);
333 return (e == EWOULDBLOCK) || (e == EAGAIN);
341 static const int retry_interval = 0;
342 static const int retry_max_count = 10000;
348#elif defined O_NOINHERIT
349 flags |= O_NOINHERIT;
352 while ((ret = open(pathname, flags, mode)) == -1) {
354 if (!io_again_p(e))
break;
355 if (retry_count++ >= retry_max_count)
break;
357 sleep(retry_interval);
360 if (ret < 0)
return ret;
362 if (ret > 2)
return ret;
364 rb_maygvl_fd_fix_cloexec(ret);
382 if (oldfd == newfd) {
386#if defined(HAVE_DUP3) && defined(O_CLOEXEC)
387# if defined(__APPLE__)
388# define try_dup3 (dup3 != NULL)
389# define abandon_dup3() true
391 static bool try_dup3 =
true;
392# define abandon_dup3() (errno != ENOSYS || !!(try_dup3 = false))
398 ret = dup3(oldfd, newfd, O_CLOEXEC);
405 if (abandon_dup3())
return ret;
408 ret = dup2(oldfd, newfd);
409 if (ret < 0)
return ret;
411 rb_maygvl_fd_fix_cloexec(ret);
416rb_fd_set_nonblock(
int fd)
419 return rb_w32_set_nonblock(fd);
420#elif defined(F_GETFL)
421 int oflags = fcntl(fd, F_GETFL);
425 if (oflags & O_NONBLOCK)
427 oflags |= O_NONBLOCK;
428 return fcntl(fd, F_SETFL, oflags);
434cloexec_pipe(
int descriptors[2],
int flags,
bool force_cloexec)
438# if defined(__APPLE__)
439# define try_pipe2 (pipe2 != NULL)
440# define abandon_pipe2() true
442 static bool try_pipe2 =
true;
443# define abandon_pipe2() (errno != ENOSYS || !!(try_pipe2 = false))
446 result = pipe2(descriptors, O_CLOEXEC | flags);
447 if (result == 0)
return result;
448 if (abandon_pipe2())
return result;
451 if (result < 0 && (result = pipe(descriptors)) < 0)
455 if (result == 0 && descriptors[1] == -1) {
456 close(descriptors[0]);
463 if (!force_cloexec)
return result;
466 rb_maygvl_fd_fix_cloexec(descriptors[0]);
467 rb_maygvl_fd_fix_cloexec(descriptors[1]);
470 rb_fd_set_nonblock(descriptors[0]);
471 rb_fd_set_nonblock(descriptors[1]);
480 return cloexec_pipe(descriptors, O_NONBLOCK,
true);
488#if defined(HAVE_FCNTL) && defined(F_DUPFD_CLOEXEC)
489 ret = fcntl(fd, F_DUPFD_CLOEXEC, minfd);
490 if (ret > 2)
return ret;
491#elif defined(HAVE_FCNTL) && defined(F_DUPFD)
492 ret = fcntl(fd, F_DUPFD, minfd);
495 if (ret >= 0 && ret < minfd) {
496 const int prev_fd = ret;
502 if (ret < 0)
return ret;
503 rb_maygvl_fd_fix_cloexec(ret);
507#define argf_of(obj) (*(struct argf *)DATA_PTR(obj))
508#define ARGF argf_of(argf)
509#define ARGF_SET(field, value) RB_OBJ_WRITE(argf, &ARGF.field, value)
511#define GetWriteIO(io) rb_io_get_write_io(io)
513#define READ_DATA_PENDING(fptr) ((fptr)->rbuf.len)
514#define READ_DATA_PENDING_COUNT(fptr) ((fptr)->rbuf.len)
515#define READ_DATA_PENDING_PTR(fptr) ((fptr)->rbuf.ptr+(fptr)->rbuf.off)
516#define READ_DATA_BUFFERED(fptr) READ_DATA_PENDING(fptr)
518#define READ_CHAR_PENDING(fptr) ((fptr)->cbuf.len)
519#define READ_CHAR_PENDING_COUNT(fptr) ((fptr)->cbuf.len)
520#define READ_CHAR_PENDING_PTR(fptr) ((fptr)->cbuf.ptr+(fptr)->cbuf.off)
523#define WAIT_FD_IN_WIN32(fptr) \
524 (rb_w32_io_cancelable_p((fptr)->fd) ? Qnil : rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_READABLE), RUBY_IO_TIMEOUT_DEFAULT))
526#define WAIT_FD_IN_WIN32(fptr)
529#define READ_CHECK(fptr) do {\
530 if (!READ_DATA_PENDING(fptr)) {\
531 WAIT_FD_IN_WIN32(fptr);\
532 rb_io_check_closed(fptr);\
538# define S_ISSOCK(m) _S_ISSOCK(m)
541# define S_ISSOCK(m) (((m) & S_IFMT) == _S_IFSOCK)
544# define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
550static int io_fflush(
rb_io_t *);
551static rb_io_t *flush_before_seek(
rb_io_t *fptr,
bool discard_rbuf);
552static void clear_readconv(
rb_io_t *fptr);
553static void clear_codeconv(
rb_io_t *fptr);
555#define FMODE_SIGNAL_ON_EPIPE (1<<17)
557#define fptr_signal_on_epipe(fptr) \
558 (((fptr)->mode & FMODE_SIGNAL_ON_EPIPE) != 0)
560#define fptr_set_signal_on_epipe(fptr, flag) \
562 (fptr)->mode |= FMODE_SIGNAL_ON_EPIPE : \
563 (fptr)->mode &= ~FMODE_SIGNAL_ON_EPIPE)
565extern ID ruby_static_id_signo;
567NORETURN(
static void rb_sys_fail_on_write(
rb_io_t *fptr));
569rb_sys_fail_on_write(
rb_io_t *fptr)
572 VALUE errinfo = rb_syserr_new_path(e, (fptr)->pathv);
574 if (fptr_signal_on_epipe(fptr) && (e == EPIPE)) {
586#define NEED_NEWLINE_DECORATOR_ON_READ(fptr) ((fptr)->mode & FMODE_TEXTMODE)
587#define NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) ((fptr)->mode & FMODE_TEXTMODE)
588#if defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32)
589# define RUBY_CRLF_ENVIRONMENT 1
591# define RUBY_CRLF_ENVIRONMENT 0
594#if RUBY_CRLF_ENVIRONMENT
596# define DEFAULT_TEXTMODE FMODE_TEXTMODE
597# define TEXTMODE_NEWLINE_DECORATOR_ON_WRITE ECONV_CRLF_NEWLINE_DECORATOR
605#define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || (fptr)->encs.ecflags & ~ECONV_CRLF_NEWLINE_DECORATOR)
606#define WRITECONV_MASK ( \
607 (ECONV_DECORATOR_MASK & ~ECONV_CRLF_NEWLINE_DECORATOR)|\
608 ECONV_STATEFUL_DECORATOR_MASK|\
610#define NEED_WRITECONV(fptr) ( \
611 ((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || \
612 ((fptr)->encs.ecflags & WRITECONV_MASK) || \
614#define SET_BINARY_MODE(fptr) setmode((fptr)->fd, O_BINARY)
616#define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) do {\
617 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {\
618 if (((fptr)->mode & FMODE_READABLE) &&\
619 !((fptr)->encs.ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {\
620 setmode((fptr)->fd, O_BINARY);\
623 setmode((fptr)->fd, O_TEXT);\
628#define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) do {\
629 if ((enc2) && ((ecflags) & ECONV_DEFAULT_NEWLINE_DECORATOR)) {\
630 (ecflags) |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;\
638io_unread(
rb_io_t *fptr,
bool discard_rbuf)
654 if (!rb_w32_fd_is_text(fptr->
fd)) {
655 r = lseek(fptr->
fd, -fptr->
rbuf.
len, SEEK_CUR);
656 if (r < 0 &&
errno) {
659 if (!discard_rbuf)
return;
665 pos = lseek(fptr->
fd, 0, SEEK_CUR);
666 if (pos < 0 &&
errno) {
669 if (!discard_rbuf)
goto end;
673 extra_max = (long)(pos - fptr->
rbuf.
len);
681 for (i = 0; i < fptr->
rbuf.
len; i++) {
682 if (*p ==
'\n') newlines++;
683 if (extra_max == newlines)
break;
688 while (newlines >= 0) {
689 r = lseek(fptr->
fd, pos - fptr->
rbuf.
len - newlines, SEEK_SET);
690 if (newlines == 0)
break;
695 read_size = _read(fptr->
fd, buf, fptr->
rbuf.
len + newlines);
699 rb_syserr_fail_path(e, fptr->
pathv);
701 if (read_size == fptr->
rbuf.
len) {
702 lseek(fptr->
fd, r, SEEK_SET);
713 clear_codeconv(fptr);
725set_binary_mode_with_seek_cur(
rb_io_t *fptr)
727 if (!rb_w32_fd_is_text(fptr->
fd))
return O_BINARY;
730 return setmode(fptr->
fd, O_BINARY);
732 flush_before_seek(fptr,
false);
733 return setmode(fptr->
fd, O_BINARY);
735#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) set_binary_mode_with_seek_cur(fptr)
739# define DEFAULT_TEXTMODE 0
740#define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || NEED_NEWLINE_DECORATOR_ON_READ(fptr))
741#define NEED_WRITECONV(fptr) ( \
742 ((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || \
743 NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) || \
744 ((fptr)->encs.ecflags & (ECONV_DECORATOR_MASK|ECONV_STATEFUL_DECORATOR_MASK)) || \
746#define SET_BINARY_MODE(fptr) (void)(fptr)
747#define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) (void)(fptr)
748#define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) ((void)(enc2), (void)(ecflags))
749#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) (void)(fptr)
752#if !defined HAVE_SHUTDOWN && !defined shutdown
753#define shutdown(a,b) 0
757#define is_socket(fd, path) rb_w32_is_socket(fd)
758#elif !defined(S_ISSOCK)
759#define is_socket(fd, path) 0
762is_socket(
int fd,
VALUE path)
765 if (fstat(fd, &sbuf) < 0)
766 rb_sys_fail_path(path);
767 return S_ISSOCK(sbuf.st_mode);
771static const char closed_stream[] =
"closed stream";
774io_fd_check_closed(
int fd)
807 io_fd_check_closed(fptr->
fd);
811rb_io_get_fptr(
VALUE io)
821 return rb_convert_type_with_id(io,
T_FILE,
"IO", idTo_io);
827 return rb_check_convert_type_with_id(io,
T_FILE,
"IO", idTo_io);
845 rb_io_t *fptr = rb_io_get_fptr(io);
854 return write_io ? write_io :
Qnil;
867 rb_io_t *fptr = rb_io_get_fptr(self);
897 if (
RTEST(timeout)) {
901 rb_io_t *fptr = rb_io_get_fptr(self);
926#if !RUBY_CRLF_ENVIRONMENT
928io_unread(
rb_io_t *fptr,
bool discard_rbuf)
936 r = lseek(fptr->
fd, -fptr->
rbuf.
len, SEEK_CUR);
937 if (r < 0 &&
errno) {
940 if (!discard_rbuf)
return;
944 clear_codeconv(fptr);
957 const int min_capa = IO_RBUF_CAPA_FOR(fptr);
960#if SIZEOF_RB_LEN_T > SIZEOF_INT
993 io_ungetbyte(str, fptr);
1011flush_before_seek(
rb_io_t *fptr,
bool discard_rbuf)
1013 if (io_fflush(fptr) < 0)
1014 rb_sys_fail_on_write(fptr);
1015 io_unread(fptr, discard_rbuf);
1020#define io_seek(fptr, ofs, whence) (errno = 0, lseek(flush_before_seek(fptr, true)->fd, (ofs), (whence)))
1021#define io_tell(fptr) lseek(flush_before_seek(fptr, false)->fd, 0, SEEK_CUR)
1037 if (io_fflush(fptr) < 0)
1038 rb_sys_fail_on_write(fptr);
1043 if (io_fflush(wfptr) < 0)
1044 rb_sys_fail_on_write(wfptr);
1052 if (READ_CHAR_PENDING(fptr)) {
1053 rb_raise(
rb_eIOError,
"byte oriented read for character buffered IO");
1064io_read_encoding(
rb_io_t *fptr)
1069 return rb_default_external_encoding();
1073io_input_encoding(
rb_io_t *fptr)
1078 return io_read_encoding(fptr);
1089 io_unread(fptr,
true);
1094rb_io_read_pending(
rb_io_t *fptr)
1097 if (READ_CHAR_PENDING(fptr))
1099 return READ_DATA_PENDING(fptr);
1105 if (!READ_DATA_PENDING(fptr)) {
1112rb_gc_for_fd(
int err)
1114 if (err == EMFILE || err == ENFILE || err == ENOMEM) {
1124#define TRY_WITH_GC(expr) \
1125 for (int first_errno, retried_errno = 0, retried = 0; \
1128 (!rb_gc_for_fd(first_errno = errno) || !(expr)) && \
1129 (retried_errno = errno, 1)); \
1130 (void)retried_errno, retried = 1)
1145io_alloc(
VALUE klass)
1147 UNPROTECTED_NEWOBJ_OF(io,
struct RFile, klass,
T_FILE,
sizeof(
struct RFile));
1155# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
1181struct io_internal_writev_struct {
1188 const struct iovec *iov;
1201io_internal_wait(
VALUE thread,
rb_io_t *fptr,
int error,
int events,
struct timeval *timeout)
1203 if (!timeout && rb_thread_mn_schedulable(thread)) {
1208 int ready = nogvl_wait_for(thread, fptr, events, timeout);
1213 else if (ready == 0) {
1230internal_read_func(
void *ptr)
1235 if (iis->timeout && !iis->nonblock) {
1236 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_IN, iis->timeout) == -1) {
1242 result = read(iis->fd, iis->buf, iis->capa);
1244 if (result < 0 && !iis->nonblock) {
1245 if (io_again_p(
errno)) {
1246 if (io_internal_wait(iis->th, iis->fptr,
errno, RB_WAITFD_IN, iis->timeout) == -1) {
1258#if defined __APPLE__
1259# define do_write_retry(code) do {result = code;} while (result == -1 && errno == EPROTOTYPE)
1261# define do_write_retry(code) result = code
1265internal_write_func(
void *ptr)
1270 if (iis->timeout && !iis->nonblock) {
1271 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1277 do_write_retry(write(iis->fd, iis->buf, iis->capa));
1279 if (result < 0 && !iis->nonblock) {
1281 if (io_again_p(e)) {
1282 if (io_internal_wait(iis->th, iis->fptr,
errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1296internal_writev_func(
void *ptr)
1298 struct io_internal_writev_struct *iis = ptr;
1301 if (iis->timeout && !iis->nonblock) {
1302 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1308 do_write_retry(writev(iis->fd, iis->iov, iis->iovcnt));
1310 if (result < 0 && !iis->nonblock) {
1311 if (io_again_p(
errno)) {
1312 if (io_internal_wait(iis->th, iis->fptr,
errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1326rb_io_read_memory(
rb_io_t *fptr,
void *buf,
size_t count)
1330 if (scheduler !=
Qnil) {
1333 if (!UNDEF_P(result)) {
1349 struct timeval timeout_storage;
1353 iis.timeout = &timeout_storage;
1356 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_read_func, &iis,
RUBY_IO_READABLE);
1360rb_io_write_memory(
rb_io_t *fptr,
const void *buf,
size_t count)
1364 if (scheduler !=
Qnil) {
1367 if (!UNDEF_P(result)) {
1383 struct timeval timeout_storage;
1387 iis.timeout = &timeout_storage;
1390 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_write_func, &iis,
RUBY_IO_WRITABLE);
1395rb_writev_internal(
rb_io_t *fptr,
const struct iovec *iov,
int iovcnt)
1397 if (!iovcnt)
return 0;
1402 if (scheduler !=
Qnil) {
1406 if (!UNDEF_P(result)) {
1411 struct io_internal_writev_struct iis = {
1422 struct timeval timeout_storage;
1426 iis.timeout = &timeout_storage;
1429 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_writev_func, &iis,
RUBY_IO_WRITABLE);
1434io_flush_buffer_sync(
void *arg)
1456io_flush_buffer_fiber_scheduler(
VALUE scheduler,
rb_io_t *fptr)
1459 if (!UNDEF_P(ret)) {
1471io_flush_buffer_async(
VALUE arg)
1476 if (scheduler !=
Qnil) {
1477 VALUE result = io_flush_buffer_fiber_scheduler(scheduler, fptr);
1478 if (!UNDEF_P(result)) {
1483 return rb_io_blocking_region_wait(fptr, io_flush_buffer_sync, fptr,
RUBY_IO_WRITABLE);
1490 return (
int)io_flush_buffer_async((
VALUE)fptr);
1505 while (fptr->
wbuf.
len > 0 && io_flush_buffer(fptr) != 0) {
1521 if (scheduler !=
Qnil) {
1531 if (NIL_OR_UNDEF_P(timeout)) {
1535 if (timeout !=
Qnil) {
1540 int ready = rb_thread_io_wait(th, fptr,
RB_NUM2INT(events), tv);
1566 if (scheduler !=
Qnil) {
1572 return rb_thread_wait_for_single_fd(th, fd, events, timeout);
1578 io_fd_check_closed(f);
1585#if defined(ERESTART)
1592#if EWOULDBLOCK != EAGAIN
1595 if (scheduler !=
Qnil) {
1613 io_fd_check_closed(f);
1620#if defined(ERESTART)
1636#if EWOULDBLOCK != EAGAIN
1639 if (scheduler !=
Qnil) {
1659 return io_wait_for_single_fd(fd, events, timeout, th, scheduler);
1693#if defined(ERESTART)
1703#if EWOULDBLOCK != EAGAIN
1726 if (
RTEST(result)) {
1741 if (
RTEST(result)) {
1755 const char *senc, *denc;
1762 ecflags = fptr->
encs.
ecflags & ~ECONV_NEWLINE_DECORATOR_READ_MASK;
1789 denc = rb_enc_name(enc);
1821io_binwrite_string_internal(
rb_io_t *fptr,
const char *ptr,
rb_len_t length)
1824 struct iovec iov[2];
1827 iov[0].iov_len = fptr->
wbuf.
len;
1828 iov[1].iov_base = (
void*)ptr;
1829 iov[1].iov_len = length;
1831 ssize_t result = rb_writev_internal(fptr, iov, 2);
1836 if (result >= fptr->
wbuf.
len) {
1844 fptr->
wbuf.
off += (int)result;
1845 fptr->
wbuf.
len -= (int)result;
1853 return rb_io_write_memory(fptr, ptr, length);
1858io_binwrite_string_internal(
rb_io_t *fptr,
const char *ptr,
rb_len_t length)
1863 if (fptr->
wbuf.
len+length <= fptr->wbuf.capa) {
1870 fptr->
wbuf.
len += (int)length;
1877 if (io_fflush(fptr) < 0) {
1882 if (remaining == 0) {
1888 return rb_io_write_memory(fptr, ptr, length);
1893io_binwrite_string(
VALUE arg)
1897 const char *ptr = p->ptr;
1898 size_t remaining = p->length;
1902 ssize_t result = io_binwrite_string_internal(p->fptr, ptr, remaining);
1908 else if (result > 0) {
1909 if ((
size_t)result == remaining)
break;
1911 remaining -= result;
1927io_allocate_write_buffer(
rb_io_t *fptr,
int sync)
1932 fptr->
wbuf.
capa = IO_WBUF_CAPA_MIN;
1960 if (
len <= 0)
return len;
1965 io_allocate_write_buffer(fptr, !nosync);
1967 if (io_binwrite_requires_flush_write(fptr,
len, nosync)) {
1978 return io_binwrite_string((
VALUE)&arg);
1995# define MODE_BTMODE(a,b,c) ((fmode & FMODE_BINMODE) ? (b) : \
1996 (fmode & FMODE_TEXTMODE) ? (c) : (a))
1998#define MODE_BTXMODE(a, b, c, d, e, f) ((fmode & FMODE_EXCL) ? \
1999 MODE_BTMODE(d, e, f) : \
2000 MODE_BTMODE(a, b, c))
2005 if (NEED_WRITECONV(fptr)) {
2007 SET_BINARY_MODE(fptr);
2009 make_writeconv(fptr);
2012#define fmode (fptr->mode)
2015 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1) && !rb_enc_asciicompat(rb_enc_get(str))) {
2016 rb_raise(rb_eArgError,
"ASCII incompatible string written for text mode IO without encoding conversion: %s",
2017 rb_enc_name(rb_enc_get(str)));
2023 common_encoding = rb_enc_from_encoding(fptr->
encs.
enc2);
2024 else if (fptr->
encs.
enc != rb_ascii8bit_encoding())
2025 common_encoding = rb_enc_from_encoding(fptr->
encs.
enc);
2028 if (!
NIL_P(common_encoding)) {
2039#if RUBY_CRLF_ENVIRONMENT
2040#define fmode (fptr->mode)
2041 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1)) {
2044 setmode(fptr->
fd, O_BINARY);
2047 setmode(fptr->
fd, O_TEXT);
2049 if (!rb_enc_asciicompat(rb_enc_get(str))) {
2050 rb_raise(rb_eArgError,
"ASCII incompatible string written for text mode IO without encoding conversion: %s",
2051 rb_enc_name(rb_enc_get(str)));
2069 if (rb_w32_write_console(str, fptr->
fd) > 0)
return RSTRING_LEN(str);
2073 str = do_writeconv(str, fptr, &converted);
2079 n = io_binwrite(ptr,
len, fptr, nosync);
2092 return (ssize_t)io_binwrite(buf, (
rb_len_t)size, fptr, 0);
2102 io = GetWriteIO(io);
2112 if (RSTRING_LEN(str) == 0)
return INT2FIX(0);
2117 n = io_fwrite(str, fptr, nosync);
2118 if (n < 0L) rb_sys_fail_on_write(fptr);
2124struct binwritev_arg {
2132io_binwritev_internal(
VALUE arg)
2134 struct binwritev_arg *p = (
struct binwritev_arg *)arg;
2136 size_t remaining = p->total;
2140 struct iovec *iov = p->iov;
2141 int iovcnt = p->iovcnt;
2144 rb_len_t result = rb_writev_internal(fptr, iov, iovcnt);
2149 if (offset < (
size_t)fptr->
wbuf.
len) {
2154 offset -= (size_t)fptr->
wbuf.
len;
2160 if (offset == p->total) {
2164 while (result >= (ssize_t)iov->iov_len) {
2166 result -= iov->iov_len;
2176 iov->iov_base = (
char *)iov->iov_base + result;
2177 iov->iov_len -= result;
2191io_binwritev(
struct iovec *iov,
int iovcnt,
rb_io_t *fptr)
2196 if (iovcnt == 0)
return 0;
2199 for (
int i = 1; i < iovcnt; i++) total += iov[i].iov_len;
2201 io_allocate_write_buffer(fptr, 1);
2207 if (offset + total <= (
size_t)fptr->
wbuf.
capa) {
2208 for (
int i = 1; i < iovcnt; i++) {
2209 memcpy(fptr->
wbuf.
ptr+offset, iov[i].iov_base, iov[i].iov_len);
2210 offset += iov[i].iov_len;
2221 if (io_fflush(fptr) < 0)
return -1;
2227 iov[0].iov_len = fptr->
wbuf.
len;
2240 struct binwritev_arg arg;
2243 arg.iovcnt = iovcnt;
2250 return io_binwritev_internal((
VALUE)&arg);
2257 int i, converted, iovcnt = argc + 1;
2259 VALUE v1, v2, str, tmp, *tmp_array;
2265 for (i = 0; i < argc; i++) {
2268 str = do_writeconv(str, fptr, &converted);
2273 tmp = rb_str_tmp_frozen_acquire(str);
2277 iov[i+1].iov_base = RSTRING_PTR(tmp);
2278 iov[i+1].iov_len = RSTRING_LEN(tmp);
2281 n = io_binwritev(iov, iovcnt, fptr);
2284 for (i = 0; i < argc; i++) {
2285 rb_str_tmp_frozen_release(argv[i], tmp_array[i]);
2294iovcnt_ok(
int iovcnt)
2297 return iovcnt < IOV_MAX;
2305io_writev(
int argc,
const VALUE *argv,
VALUE io)
2312 io = GetWriteIO(io);
2325 for (i = 0; i < argc; i += cnt) {
2328 n = io_fwritev(cnt, &argv[i], fptr);
2339 rb_sys_fail_on_write(fptr);
2341 total = rb_int_plus(
LEN2NUM(n), total);
2372 return io_writev(argc, argv, io);
2375 VALUE str = argv[0];
2376 return io_write(io, str, 0);
2387rb_io_writev(
VALUE io,
int argc,
const VALUE *argv)
2392 char sep = RCLASS_SINGLETON_P(klass) ? (klass = io,
'.') :
'#';
2395 " which accepts just one argument",
2400 do rb_io_write(io, *argv++);
while (--argc);
2431 rb_io_write(io, str);
2437nogvl_fsync(
void *ptr)
2442 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->
fd)) != FILE_TYPE_DISK)
2445 return (
VALUE)fsync(fptr->
fd);
2450rb_io_flush_raw(
VALUE io,
int sync)
2458 io = GetWriteIO(io);
2462 if (io_fflush(fptr) < 0)
2463 rb_sys_fail_on_write(fptr);
2466 io_unread(fptr,
true);
2487 return rb_io_flush_raw(io, 1);
2513 pos = io_tell(fptr);
2514 if (pos < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
2520rb_io_seek(
VALUE io,
VALUE offset,
int whence)
2527 pos = io_seek(fptr, pos, whence);
2528 if (pos < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
2529 if (fptr->
readconv) clear_readconv(fptr);
2535interpret_seek_whence(
VALUE vwhence)
2537 if (vwhence == sym_SET)
2539 if (vwhence == sym_CUR)
2541 if (vwhence == sym_END)
2544 if (vwhence == sym_DATA)
2548 if (vwhence == sym_HOLE)
2604 VALUE offset, ptrname;
2605 int whence = SEEK_SET;
2607 if (
rb_scan_args(argc, argv,
"11", &offset, &ptrname) == 2) {
2608 whence = interpret_seek_whence(ptrname);
2611 return rb_io_seek(io, offset, whence);
2639 pos = io_seek(fptr, pos, SEEK_SET);
2640 if (pos < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
2641 if (fptr->
readconv) clear_readconv(fptr);
2671rb_io_rewind(
VALUE io)
2676 if (io_seek(fptr, 0L, 0) < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
2677 if (io == ARGF.current_file) {
2678 ARGF.lineno -= fptr->
lineno;
2682 clear_readconv(fptr);
2689fptr_wait_readable(
rb_io_t *fptr)
2707 fptr->
rbuf.
capa = IO_RBUF_CAPA_FOR(fptr);
2715 if (fptr_wait_readable(fptr))
2719 VALUE path = rb_sprintf(
"fd:%d ", fptr->
fd);
2724 rb_syserr_fail_path(e, path);
2778 if (READ_CHAR_PENDING(fptr))
return Qfalse;
2779 if (READ_DATA_PENDING(fptr))
return Qfalse;
2781#if RUBY_CRLF_ENVIRONMENT
2782 if (!NEED_READCONV(fptr) && NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
2783 return RBOOL(eof(fptr->
fd));
2786 return RBOOL(io_fillbuf(fptr) < 0);
2810 io = GetWriteIO(io);
2847 io = GetWriteIO(io);
2853 fptr->
mode &= ~FMODE_SYNC;
2877rb_io_fsync(
VALUE io)
2881 io = GetWriteIO(io);
2884 if (io_fflush(fptr) < 0)
2885 rb_sys_fail_on_write(fptr);
2887 if ((
int)rb_io_blocking_region(fptr, nogvl_fsync, fptr))
2888 rb_sys_fail_path(fptr->
pathv);
2893# define rb_io_fsync rb_f_notimplement
2894# define rb_io_sync rb_f_notimplement
2903#ifdef HAVE_FDATASYNC
2905nogvl_fdatasync(
void *ptr)
2909 return (
VALUE)fdatasync(fptr->
fd);
2924rb_io_fdatasync(
VALUE io)
2928 io = GetWriteIO(io);
2931 if (io_fflush(fptr) < 0)
2932 rb_sys_fail_on_write(fptr);
2934 if ((
int)rb_io_blocking_region(fptr, nogvl_fdatasync, fptr) == 0)
2938 return rb_io_fsync(io);
2941#define rb_io_fdatasync rb_io_fsync
2959rb_io_fileno(
VALUE io)
2979 if (!UNDEF_P(fileno)) {
3072rb_io_inspect(
VALUE obj)
3076 static const char closed[] =
" (closed)";
3078 fptr =
RFILE(obj)->fptr;
3085 rb_str_cat(result, closed+1, strlen(closed)-1);
3088 rb_str_catf(result,
"fd %d", fptr->
fd);
3109rb_io_to_io(
VALUE io)
3120 n = READ_DATA_PENDING_COUNT(fptr);
3121 if (n <= 0)
return 0;
3122 if (n >
len) n = (int)
len;
3137 if (READ_DATA_PENDING(fptr) == 0) {
3141 c = rb_io_read_memory(fptr, ptr+offset, n);
3144 if (fptr_wait_readable(fptr))
3150 if ((n -= c) <= 0)
break;
3156 c = read_buffered_data(ptr+offset, n, fptr);
3160 if ((n -= c) <= 0)
break;
3163 if (io_fillbuf(fptr) < 0) {
3181bufread_body(
VALUE arg)
3184 p->len = io_bufread(p->str_ptr + p->offset, p->len, p->fptr, &p->read_len);
3193 if (p->offset + p->read_len > 0) {
3195 io_restore_read_buffer(str, p->fptr);
3202bufread_call(
VALUE arg)
3207 return bufread_body(arg);
3209 return rb_rescue2(bufread_body, arg, bufread_timeout, arg,
3210 rb_eIOTimeoutError, (
VALUE)0);
3219 io_setstrbuf(&str, offset + size);
3220 if (!READ_DATA_PENDING(fptr))
3221 rb_str_make_heap(str);
3222 arg.str_ptr = RSTRING_PTR(str);
3223 arg.offset = offset;
3227 rb_str_locktmp_ensure(str, bufread_call, (
VALUE)&arg);
3229 if (
len < 0) rb_sys_fail_path(fptr->
pathv);
3237 rb_off_t siz = READ_DATA_PENDING_COUNT(fptr);
3240 if (fstat(fptr->
fd, &st) == 0 && S_ISREG(st.st_mode)
3241#
if defined(__HAIKU__)
3246 if (io_fflush(fptr) < 0)
3247 rb_sys_fail_on_write(fptr);
3248 pos = lseek(fptr->
fd, 0, SEEK_CUR);
3249 if (st.st_size >= pos && pos >= 0) {
3250 siz += st.st_size - pos;
3252 rb_raise(
rb_eIOError,
"file too big for single read");
3265 rb_enc_associate(str, io_read_encoding(fptr));
3270make_readconv(
rb_io_t *fptr,
int size)
3275 const char *sname, *dname;
3276 ecflags = fptr->
encs.
ecflags & ~ECONV_NEWLINE_DECORATOR_WRITE_MASK;
3279 sname = rb_enc_name(fptr->
encs.
enc2);
3280 dname = rb_enc_name(io_read_encoding(fptr));
3290 if (size < IO_CBUF_CAPA_MIN) size = IO_CBUF_CAPA_MIN;
3296#define MORE_CHAR_SUSPENDED Qtrue
3297#define MORE_CHAR_FINISHED Qnil
3299fill_cbuf(
rb_io_t *fptr,
int ec_flags)
3301 const unsigned char *ss, *sp, *se;
3302 unsigned char *ds, *dp, *de;
3311 return MORE_CHAR_SUSPENDED;
3322 ss = sp = (
const unsigned char *)fptr->
rbuf.
ptr + fptr->
rbuf.
off;
3327 fptr->
rbuf.
off += (int)(sp - ss);
3328 fptr->
rbuf.
len -= (int)(sp - ss);
3329 fptr->
cbuf.
len += (int)(dp - ds);
3335 if (putbackable > fptr->
rbuf.
off)
3339 fptr->
rbuf.
off -= putbackable;
3340 fptr->
rbuf.
len += putbackable;
3347 if (cbuf_len0 != fptr->
cbuf.
len)
3348 return MORE_CHAR_SUSPENDED;
3351 return MORE_CHAR_FINISHED;
3357 if (io_fillbuf(fptr) < 0) {
3359 return MORE_CHAR_FINISHED;
3364 fptr->
cbuf.
len += (int)(dp - ds);
3371 if (cbuf_len0 != fptr->
cbuf.
len)
3372 return MORE_CHAR_SUSPENDED;
3374 return MORE_CHAR_FINISHED;
3382 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED)
3399 rb_enc_associate(str, fptr->
encs.
enc);
3436#define MAX_REALLOC_GAP 4096
3441 rb_str_resize(str, n);
3448 if (RSTRING_LEN(str) != n) {
3451 if (shrinkable) io_shrink_read_string(str, n);
3465 if (NEED_READCONV(fptr)) {
3466 int first = !
NIL_P(str);
3467 SET_BINARY_MODE(fptr);
3468 shrinkable = io_setstrbuf(&str,0);
3469 make_readconv(fptr, 0);
3474 io_shift_cbuf(fptr, fptr->
cbuf.
len, &str);
3476 v = fill_cbuf(fptr, 0);
3477 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED) {
3480 io_shift_cbuf(fptr, fptr->
cbuf.
len, &str);
3484 if (v == MORE_CHAR_FINISHED) {
3485 clear_readconv(fptr);
3487 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3488 return io_enc_str(str, fptr);
3493 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3497 enc = io_read_encoding(fptr);
3510 shrinkable = io_setstrbuf(&str, siz);
3513 n = io_fread(str, bytes, siz - bytes, fptr);
3514 if (n == 0 && bytes == 0) {
3522 if (bytes < siz)
break;
3526 if (
capa < (
size_t)RSTRING_LEN(str) + BUFSIZ) {
3527 if (
capa < BUFSIZ) {
3530 else if (
capa > IO_MAX_BUFFER_GROWTH) {
3531 capa = IO_MAX_BUFFER_GROWTH;
3536 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3537 str = io_enc_str(str, fptr);
3545 if (rb_fd_set_nonblock(fptr->
fd) != 0) {
3546 rb_sys_fail_path(fptr->
pathv);
3551io_read_memory_call(
VALUE arg)
3556 if (scheduler !=
Qnil) {
3559 if (!UNDEF_P(result)) {
3565 if (iis->nonblock) {
3566 return rb_io_blocking_region(iis->fptr, internal_read_func, iis);
3569 return rb_io_blocking_region_wait(iis->fptr, internal_read_func, iis,
RUBY_IO_READABLE);
3576 return (
rb_len_t)rb_str_locktmp_ensure(str, io_read_memory_call, (
VALUE)iis);
3579#define no_exception_p(opts) !rb_opts_exception_p((opts), TRUE)
3582io_getpartial(
VALUE io,
VALUE length,
VALUE str,
int no_exception,
int nonblock)
3590 rb_raise(rb_eArgError,
"negative length %"PRIdLEN
" given",
len);
3593 shrinkable = io_setstrbuf(&str,
len);
3599 io_set_read_length(str, 0, shrinkable);
3605 n = read_buffered_data(RSTRING_PTR(str),
len, fptr);
3610 rb_fd_set_nonblock(fptr->
fd);
3612 io_setstrbuf(&str,
len);
3613 rb_str_make_heap(str);
3616 iis.nonblock = nonblock;
3618 iis.buf = RSTRING_PTR(str);
3621 n = io_read_memory_locktmp(str, &iis);
3624 if (!nonblock && fptr_wait_readable(fptr))
3626 if (nonblock && (io_again_p(e))) {
3628 return sym_wait_readable;
3631 e,
"read would block");
3633 rb_syserr_fail_path(e, fptr->
pathv);
3636 io_set_read_length(str, n, shrinkable);
3737io_readpartial(
int argc,
VALUE *argv,
VALUE io)
3739 VALUE ret, length, str;
3742 ret = io_getpartial(io, length, str, 0, 0);
3749io_nonblock_eof(
int no_exception)
3751 if (!no_exception) {
3761 int no_exception = !rb_bool_expected(ex,
"exception", TRUE);
3762 VALUE ret = io_getpartial(io, length, str, no_exception, 1);
3764 io_nonblock_eof(no_exception);
3778 rb_bool_expected(ex,
"exception", TRUE);
3780 io = GetWriteIO(io);
3784 if (io_fflush(fptr) < 0)
3785 rb_sys_fail_on_write(fptr);
3787 rb_fd_set_nonblock(fptr->
fd);
3788 n = write(fptr->
fd, RSTRING_PTR(str), RSTRING_LEN(str));
3793 if (io_again_p(e)) {
3795 return sym_wait_writable;
3801 rb_syserr_fail_path(e, fptr->
pathv);
3885#if RUBY_CRLF_ENVIRONMENT
3891 if (
NIL_P(length)) {
3894 return read_all(fptr, remain_size(fptr), str);
3898 rb_raise(rb_eArgError,
"negative length %"PRIdLEN
" given",
len);
3901 shrinkable = io_setstrbuf(&str,
len);
3906 io_set_read_length(str, 0, shrinkable);
3911#if RUBY_CRLF_ENVIRONMENT
3912 previous_mode = set_binary_mode_with_seek_cur(fptr);
3914 n = io_fread(str, 0,
len, fptr);
3915 io_set_read_length(str, n, shrinkable);
3916#if RUBY_CRLF_ENVIRONMENT
3917 if (previous_mode == O_TEXT) {
3918 setmode(fptr->
fd, O_TEXT);
3921 if (n == 0)
return Qnil;
3930 if (RSTRING_PTR(rs) != rsptr && RSTRING_LEN(rs) != rslen)
3937 if (rb_enc_mbminlen(enc) == 1) {
3938 p = memchr(p, delim,
len);
3939 if (p)
return p + 1;
3942 const char *end = p +
len;
3944 int r = rb_enc_precise_mbclen(p, end, enc);
3946 p += rb_enc_mbminlen(enc);
3950 if (rb_enc_mbc_to_codepoint(p, end, enc) == (
unsigned int)delim) {
3966 if (!READ_DATA_PENDING(fptr)) {
3968 if (io_fillbuf(fptr) < 0)
break;
3970 buf[n++] = *READ_DATA_PENDING_PTR(fptr);
3973 r = rb_enc_precise_mbclen(buf, buf + n, enc);
3980unread_raw_character(
rb_io_t *fptr,
const char *buf,
int len)
3992search_wide_delim(
const char *p,
long len,
const char *delim,
int width)
3994 const char *e = p +
len;
3997 while (index < width && delim[index] == 0) index++;
3998 if (index == width) index = 0;
4000 const char *candidate = p + index;
4001 while (candidate < e) {
4002 candidate = memchr(candidate, (
unsigned char)delim[index], e - candidate);
4003 if (candidate == NULL)
break;
4004 const char *start = candidate - index;
4005 if ((start - p) % width == 0 && start + width <= e &&
4006 memcmp(start, delim, width) == 0) {
4020 if (NEED_READCONV(fptr)) {
4021 SET_BINARY_MODE(fptr);
4022 make_readconv(fptr, 0);
4025 int searchlen = READ_CHAR_PENDING_COUNT(fptr);
4027 p = READ_CHAR_PENDING_PTR(fptr);
4028 if (0 < limit && limit < searchlen)
4029 searchlen = (int)limit;
4030 e = search_delim(p, searchlen, delim, enc);
4032 int len = (int)(e-p);
4054 return (
unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
4057 }
while (more_char(fptr) != MORE_CHAR_FINISHED);
4058 clear_readconv(fptr);
4063 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4064 if (rb_enc_mbminlen(enc) != 1) {
4065 char buf[ONIGENC_CODE_TO_MBC_MAXLEN];
4069 int width = rb_enc_mbminlen(enc);
4070 int delim_len = rb_enc_codelen(delim, enc);
4072 if (delim_len == width) {
4073 rb_enc_mbcput(delim, buf, enc);
4075 if (!READ_DATA_PENDING(fptr)) {
4077 if (io_fillbuf(fptr) < 0)
return EOF;
4079 long pending = READ_DATA_PENDING_COUNT(fptr);
4080 long complete = pending - pending % width;
4081 const char *p = READ_DATA_PENDING_PTR(fptr);
4082 const char *q = complete ? search_wide_delim(p, complete, buf, width) : NULL;
4083 long take = q ? q - p + width : complete;
4092 if (q)
return delim;
4093 if (complete == pending)
continue;
4095 len = read_raw_character(fptr, enc, buf);
4096 if (
len == 0)
return EOF;
4100 int r = rb_enc_precise_mbclen(buf, buf +
len, enc);
4102 rb_enc_mbc_to_codepoint(buf, buf +
len, enc) == (
unsigned int)delim)
4108 while ((
len = read_raw_character(fptr, enc, buf)) > 0) {
4115 return (
unsigned char)buf[
len - 1];
4119 int r = rb_enc_precise_mbclen(buf, buf +
len, enc);
4121 rb_enc_mbc_to_codepoint(buf, buf +
len, enc) == (
unsigned int)delim)
4124 return (
unsigned char)buf[
len - 1];
4130 rb_len_t pending = READ_DATA_PENDING_COUNT(fptr);
4132 const char *p = READ_DATA_PENDING_PTR(fptr);
4136 if (limit > 0 && pending > limit) pending = limit;
4137 e = search_delim(p, pending, delim, enc);
4138 if (e) pending = e - p;
4140 last = RSTRING_LEN(str);
4141 rb_str_resize(str, last + pending);
4148 read_buffered_data(RSTRING_PTR(str) + last, pending, fptr);
4151 if (e)
return delim;
4153 return (
unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
4156 }
while (io_fillbuf(fptr) >= 0);
4162swallow(
rb_io_t *fptr,
int term)
4164 if (NEED_READCONV(fptr)) {
4166 int needconv = rb_enc_mbminlen(enc) != 1;
4167 SET_BINARY_MODE(fptr);
4168 make_readconv(fptr, 0);
4171 while ((cnt = READ_CHAR_PENDING_COUNT(fptr)) > 0) {
4172 const char *p = READ_CHAR_PENDING_PTR(fptr);
4175 if (*p != term)
return TRUE;
4177 while (--i && *++p == term);
4180 const char *e = p + cnt;
4181 if (rb_enc_ascget(p, e, &i, enc) != term)
return TRUE;
4182 while ((p += i) < e && rb_enc_ascget(p, e, &i, enc) == term);
4185 io_shift_cbuf(fptr, (
int)cnt - i, NULL);
4187 }
while (more_char(fptr) != MORE_CHAR_FINISHED);
4191 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4193 int widechar = rb_enc_mbminlen(enc) != 1;
4195 char buf[ONIGENC_CODE_TO_MBC_MAXLEN];
4198 while ((
len = read_raw_character(fptr, enc, buf)) > 0) {
4199 if (rb_enc_ascget(buf, buf +
len, NULL, enc) != term) {
4200 unread_raw_character(fptr, buf,
len);
4208 while ((cnt = READ_DATA_PENDING_COUNT(fptr)) > 0) {
4210 const char *p = READ_DATA_PENDING_PTR(fptr);
4212 if (cnt >
sizeof buf) cnt =
sizeof buf;
4213 if (*p != term)
return TRUE;
4215 while (--i && *++p == term);
4216 if (!read_buffered_data(buf, cnt - i, fptr))
4217 rb_sys_fail_path(fptr->
pathv);
4220 }
while (io_fillbuf(fptr) == 0);
4233 int pending = READ_DATA_PENDING_COUNT(fptr);
4236 const char *p = READ_DATA_PENDING_PTR(fptr);
4240 e = memchr(p,
'\n', pending);
4242 pending = (int)(e - p + 1);
4244 chomplen = (pending > 1 && *(e-1) ==
'\r') + 1;
4253 rb_str_resize(str,
len + pending - chomplen);
4254 read_buffered_data(RSTRING_PTR(str)+
len, pending - chomplen, fptr);
4257 if (pending == 1 && chomplen == 1 &&
len > 0) {
4258 if (RSTRING_PTR(str)[
len-1] ==
'\r') {
4259 rb_str_resize(str, --
len);
4264 len += pending - chomplen;
4270 }
while (io_fillbuf(fptr) >= 0);
4273 str = io_enc_str(str, fptr);
4284 unsigned int chomp: 1;
4298 chomp = (!UNDEF_P(vchomp)) &&
RTEST(vchomp);
4300 args->chomp = chomp;
4318 else if (2 <= argc) {
4319 rs = argv[0], lim = argv[1];
4337 enc_rs = rb_enc_get(rs);
4338 enc_io = io_read_encoding(fptr);
4339 if (enc_io != enc_rs &&
4340 (!is_ascii_string(rs) ||
4341 (RSTRING_LEN(rs) > 0 && !rb_enc_asciicompat(enc_io)))) {
4342 if (rs == rb_default_rs) {
4343 rs = rb_enc_str_new(0, 0, enc_io);
4348 rb_raise(rb_eArgError,
"encoding mismatch: %s IO with %s RS",
4349 rb_enc_name(enc_io),
4350 rb_enc_name(enc_rs));
4360 argc =
rb_scan_args(argc, argv,
"02:", NULL, NULL, &opts);
4361 extract_getline_args(argc, argv, args);
4362 extract_getline_opts(opts, args);
4363 check_getline_args(&args->rs, &args->limit, io);
4374 if (
NIL_P(rs) && limit < 0) {
4375 str = read_all(fptr, 0,
Qnil);
4376 if (RSTRING_LEN(str) == 0)
return Qnil;
4378 else if (limit == 0) {
4379 return rb_enc_str_new(0, 0, io_read_encoding(fptr));
4381 else if (rs == rb_default_rs && limit < 0 && !NEED_READCONV(fptr) &&
4382 rb_enc_asciicompat(enc = io_read_encoding(fptr))) {
4383 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4384 return rb_io_getline_fast(fptr, enc, chomp);
4387 int c, newline = -1;
4388 const char *rsptr = 0;
4391 int extra_limit = 16;
4392 int chomp_cr = chomp;
4394 SET_BINARY_MODE(fptr);
4395 enc = io_read_encoding(fptr);
4398 rslen = RSTRING_LEN(rs);
4403 swallow(fptr,
'\n');
4405 if (!rb_enc_asciicompat(enc)) {
4409 rsptr = RSTRING_PTR(rs);
4410 rslen = RSTRING_LEN(rs);
4414 else if (rb_enc_mbminlen(enc) == 1) {
4415 rsptr = RSTRING_PTR(rs);
4416 newline = (
unsigned char)rsptr[rslen - 1];
4420 rsptr = RSTRING_PTR(rs);
4421 const char *e = rsptr + rslen;
4422 const char *last = rb_enc_prev_char(rsptr, e, e, enc);
4424 newline = rb_enc_codepoint_len(last, e, &n, enc);
4425 if (last + n != e) rb_raise(rb_eArgError,
"broken separator");
4427 chomp_cr = chomp && newline ==
'\n' && rslen == rb_enc_mbminlen(enc);
4431 while ((c = appendline(fptr, newline, &str, &limit, enc)) != EOF) {
4432 const char *s, *p, *pp, *e;
4434 if (c == newline && RSTRING_LEN(str) >= rslen) {
4435 s = RSTRING_PTR(str);
4438 if (at_char_boundary(s, p, e, enc)) {
4439 if (!rspara) rscheck(rsptr, rslen, rs);
4440 if (memcmp(p, rsptr, rslen) == 0) {
4442 if (chomp_cr && p > s && *(p-1) ==
'\r') --p;
4450 s = RSTRING_PTR(str);
4452 pp = rb_enc_prev_char(s, p, p, enc);
4453 if (extra_limit && pp &&
4467 if (rspara && c != EOF)
4468 swallow(fptr,
'\n');
4470 str = io_enc_str(str, fptr);
4473 if (!
NIL_P(str) && !nolimit) {
4484 int old_lineno, new_lineno;
4488 old_lineno = fptr->
lineno;
4489 str = rb_io_getline_0(rs, limit, chomp, fptr);
4490 if (!
NIL_P(str) && (new_lineno = fptr->
lineno) != old_lineno) {
4491 if (io == ARGF.current_file) {
4492 ARGF.lineno += new_lineno - old_lineno;
4493 ARGF.last_lineno = ARGF.lineno;
4496 ARGF.last_lineno = new_lineno;
4504rb_io_getline(
int argc,
VALUE *argv,
VALUE io)
4508 prepare_getline_args(argc, argv, &args, io);
4509 return rb_io_getline_1(args.rs, args.limit, args.chomp, io);
4523 return rb_io_getline_0(rb_default_rs, limit, FALSE, fptr);
4527rb_io_gets_internal(
VALUE io)
4529 return rb_io_gets_limit_internal(io, -1);
4609 str = rb_io_getline(argc, argv, io);
4625rb_io_lineno(
VALUE io)
4680 check_getline_args(&sep, &limit, io);
4682 VALUE line = rb_io_getline_1(sep, limit,
RTEST(chomp), io);
4683 rb_lastline_set_up(line, 1);
4758rb_io_readlines(
int argc,
VALUE *argv,
VALUE io)
4762 prepare_getline_args(argc, argv, &args, io);
4763 return io_readlines(&args, io);
4771 if (arg->limit == 0)
4772 rb_raise(rb_eArgError,
"invalid limit: 0 for readlines");
4774 while (!
NIL_P(line = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, io))) {
4887rb_io_each_line(
int argc,
VALUE *argv,
VALUE io)
4893 prepare_getline_args(argc, argv, &args, io);
4894 if (args.limit == 0)
4895 rb_raise(rb_eArgError,
"invalid limit: 0 for each_line");
4896 while (!
NIL_P(str = rb_io_getline_1(args.rs, args.limit, args.chomp, io))) {
4924rb_io_each_byte(
VALUE io)
4940 }
while (io_fillbuf(fptr) >= 0);
4950 if (NEED_READCONV(fptr)) {
4954 SET_BINARY_MODE(fptr);
4955 make_readconv(fptr, 0);
4969 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4971 clear_readconv(fptr);
4975 str = rb_enc_str_new(fptr->
cbuf.
ptr+fptr->
cbuf.
off, 1, read_enc);
4978 if (fptr->
cbuf.
len == 0) clear_readconv(fptr);
4987 io_shift_cbuf(fptr, r, &str);
4994 ISASCII(RSTRING_PTR(str)[0])) {
4998 str = io_enc_str(str, fptr);
5003 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
5004 if (io_fillbuf(fptr) < 0) {
5026 if (io_fillbuf(fptr) != -1) {
5030 r = rb_enc_precise_mbclen(RSTRING_PTR(str), RSTRING_PTR(str)+RSTRING_LEN(str), enc);
5046 str = io_enc_str(str, fptr);
5073rb_io_each_char(
VALUE io)
5083 enc = io_input_encoding(fptr);
5085 while (!
NIL_P(c = io_getc(fptr, enc))) {
5112rb_io_each_codepoint(
VALUE io)
5124 enc = io_read_encoding(fptr);
5125 if (NEED_READCONV(fptr)) {
5126 SET_BINARY_MODE(fptr);
5129 make_readconv(fptr, 0);
5141 if (more_char(fptr) == MORE_CHAR_FINISHED) {
5142 clear_readconv(fptr);
5162 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
5163 while (io_fillbuf(fptr) >= 0) {
5178 char cbuf[8], *p = cbuf;
5180 if (more > numberof(cbuf))
goto invalid;
5182 if (more > numberof(cbuf))
goto invalid;
5183 while ((n = (
int)read_buffered_data(p, more, fptr)) > 0 &&
5184 (p += n, (more -= n) > 0)) {
5185 if (io_fillbuf(fptr) < 0)
goto invalid;
5186 if ((n = fptr->
rbuf.
len) > more) n = more;
5188 r = rb_enc_precise_mbclen(cbuf, p, enc);
5201 rb_raise(rb_eArgError,
"invalid byte sequence in %s", rb_enc_name(enc));
5234 enc = io_input_encoding(fptr);
5236 return io_getc(fptr, enc);
5260rb_io_readchar(
VALUE io)
5262 VALUE c = rb_io_getc(io);
5298 VALUE r_stdout = rb_ractor_stdout();
5303 rb_io_flush(r_stdout);
5306 if (io_fillbuf(fptr) < 0) {
5336rb_io_readbyte(
VALUE io)
5397 unsigned char c =
NUM2INT(v) & 0xFF;
5403 io_ungetbyte(b, fptr);
5459 else if (RB_BIGNUM_TYPE_P(c)) {
5465 if (NEED_READCONV(fptr)) {
5466 SET_BINARY_MODE(fptr);
5467 len = RSTRING_LEN(c);
5468#if SIZEOF_RB_LEN_T > SIZEOF_INT
5472 make_readconv(fptr, (
int)
len);
5486 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
5487 io_ungetbyte(c, fptr);
5507rb_io_isatty(
VALUE io)
5512 return RBOOL(isatty(fptr->
fd) != 0);
5515#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5531rb_io_close_on_exec_p(
VALUE io)
5537 write_io = GetWriteIO(io);
5538 if (io != write_io) {
5540 if (fptr && 0 <= (fd = fptr->
fd)) {
5541 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->
pathv);
5542 if (!(ret & FD_CLOEXEC))
return Qfalse;
5547 if (fptr && 0 <= (fd = fptr->
fd)) {
5548 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->
pathv);
5549 if (!(ret & FD_CLOEXEC))
return Qfalse;
5554#define rb_io_close_on_exec_p rb_f_notimplement
5557#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5581 int flag =
RTEST(arg) ? FD_CLOEXEC : 0;
5586 write_io = GetWriteIO(io);
5587 if (io != write_io) {
5589 if (fptr && 0 <= (fd = fptr->
fd)) {
5590 if ((ret = fcntl(fptr->
fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->
pathv);
5591 if ((ret & FD_CLOEXEC) != flag) {
5592 ret = (ret & ~FD_CLOEXEC) | flag;
5593 ret = fcntl(fd, F_SETFD, ret);
5594 if (ret != 0) rb_sys_fail_path(fptr->
pathv);
5601 if (fptr && 0 <= (fd = fptr->
fd)) {
5602 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->
pathv);
5603 if ((ret & FD_CLOEXEC) != flag) {
5604 ret = (ret & ~FD_CLOEXEC) | flag;
5605 ret = fcntl(fd, F_SETFD, ret);
5606 if (ret != 0) rb_sys_fail_path(fptr->
pathv);
5612#define rb_io_set_close_on_exec rb_f_notimplement
5615#define RUBY_IO_EXTERNAL_P(f) ((f)->mode & FMODE_EXTERNAL)
5616#define PREP_STDIO_NAME(f) (RSTRING_PTR((f)->pathv))
5619finish_writeconv(
rb_io_t *fptr,
int noalloc)
5621 unsigned char *ds, *dp, *de;
5625 unsigned char buf[1024];
5630 de = buf +
sizeof(buf);
5633 size_t remaining = dp-ds;
5634 rb_len_t result = rb_io_write_memory(fptr, ds, remaining);
5638 if ((
size_t)result == remaining)
break;
5661 if (io_fflush(fptr) < 0) {
5669 fptr->
wbuf.
len += (int)(dp - ds);
5685finish_writeconv_sync(
VALUE arg)
5688 return finish_writeconv(p->fptr, p->noalloc);
5692nogvl_close(
void *ptr)
5696 return (
void*)(intptr_t)close(*fd);
5700maygvl_close(
int fd,
int keepgvl)
5709 return IO_WITHOUT_GVL_INT(nogvl_close, &fd);
5713nogvl_fclose(
void *ptr)
5717 return (
void*)(intptr_t)fclose(file);
5721maygvl_fclose(
FILE *file,
int keepgvl)
5724 return fclose(file);
5726 return IO_WITHOUT_GVL_INT(nogvl_fclose, file);
5732fptr_finalize_flush(
rb_io_t *fptr,
int noraise,
int keepgvl)
5737 int mode = fptr->
mode;
5743 arg.noalloc = noraise;
5747 error = finish_writeconv(fptr, noraise);
5760 io_flush_buffer_sync(fptr);
5763 if (io_fflush(fptr) < 0 &&
NIL_P(error)) {
5771 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2) {
5781 rb_thread_io_close_wait(fptr);
5783 if (!done && stdio_file) {
5785 if ((maygvl_fclose(stdio_file, noraise) < 0) &&
NIL_P(error)) {
5795 if (!done && fd >= 0 && scheduler !=
Qnil) {
5798 if (!UNDEF_P(result)) {
5799 done =
RTEST(result);
5803 if (!done && fd >= 0) {
5809 if ((maygvl_close(fd, keepgvl) < 0) &&
NIL_P(error)) {
5818 if (!
NIL_P(error) && !noraise) {
5827fptr_finalize(
rb_io_t *fptr,
int noraise)
5829 fptr_finalize_flush(fptr, noraise, FALSE);
5830 free_io_buffer(&fptr->
rbuf);
5831 free_io_buffer(&fptr->
wbuf);
5832 clear_codeconv(fptr);
5836rb_io_fptr_cleanup(
rb_io_t *fptr,
int noraise)
5842 fptr_finalize(fptr, noraise);
5850 ruby_xfree_sized(buf->
ptr, (
size_t)buf->
capa);
5863 free_io_buffer(&fptr->
cbuf);
5879 clear_readconv(fptr);
5880 clear_writeconv(fptr);
5884rb_io_fptr_cleanup_all(
rb_io_t *fptr)
5888 rb_io_fptr_cleanup(fptr, TRUE);
5890 free_io_buffer(&fptr->
rbuf);
5891 free_io_buffer(&fptr->
wbuf);
5892 clear_codeconv(fptr);
5899 rb_io_fptr_cleanup_all(io);
5906rb_io_fptr_finalize_closed(
struct rb_io *io)
5908 if (!io)
return true;
5909 if (io->
fd >= 0)
return false;
5915rb_io_memsize(
const rb_io_t *io)
5917 size_t size =
sizeof(
rb_io_t);
5927 rb_serial_t fork_generation = GET_VM()->fork_gen;
5928 if (io->fork_generation == fork_generation) {
5939# define KEEPGVL TRUE
5941# define KEEPGVL FALSE
5945io_close_fptr(
VALUE io)
5951 write_io = GetWriteIO(io);
5952 if (io != write_io) {
5953 write_fptr =
RFILE(write_io)->fptr;
5954 if (write_fptr && 0 <= write_fptr->
fd) {
5955 rb_io_fptr_cleanup(write_fptr, TRUE);
5959 fptr =
RFILE(io)->fptr;
5960 if (!fptr)
return 0;
5961 if (fptr->
fd < 0)
return 0;
5964 if (rb_thread_io_close_interrupt(fptr)) {
5966 fptr_finalize_flush(fptr, FALSE, KEEPGVL);
5969 rb_io_fptr_cleanup(fptr, FALSE);
5974fptr_waitpid(
rb_io_t *fptr,
int nohang)
5978 rb_last_status_clear();
5987 rb_io_t *fptr = io_close_fptr(io);
5988 if (fptr) fptr_waitpid(fptr, 0);
6028rb_io_close_m(
VALUE io)
6030 rb_io_t *fptr = rb_io_get_fptr(io);
6039io_call_close(
VALUE io)
6048 enum {mesg_len =
sizeof(closed_stream)-1};
6049 VALUE mesg = rb_attr_get(exc, idMesg);
6051 RSTRING_LEN(mesg) != mesg_len ||
6052 memcmp(RSTRING_PTR(mesg), closed_stream, mesg_len)) {
6062 if (!UNDEF_P(closed) &&
RTEST(closed))
return io;
6063 rb_rescue2(io_call_close, io, ignore_closed_stream, io,
6099 write_io = GetWriteIO(io);
6100 if (io != write_io) {
6101 write_fptr =
RFILE(write_io)->fptr;
6102 if (write_fptr && 0 <= write_fptr->
fd) {
6107 fptr = rb_io_get_fptr(io);
6108 return RBOOL(0 > fptr->
fd);
6144rb_io_close_read(
VALUE io)
6150 if (fptr->
fd < 0)
return Qnil;
6151 if (is_socket(fptr->
fd, fptr->
pathv)) {
6155 if (shutdown(fptr->
fd, SHUT_RD) < 0)
6156 rb_sys_fail_path(fptr->
pathv);
6157 fptr->
mode &= ~FMODE_READABLE;
6163 write_io = GetWriteIO(io);
6164 if (io != write_io) {
6169 RFILE(io)->fptr = wfptr;
6172 RFILE(write_io)->fptr = fptr;
6173 rb_io_fptr_cleanup(fptr, FALSE);
6179 rb_raise(
rb_eIOError,
"closing non-duplex IO for reading");
6217rb_io_close_write(
VALUE io)
6222 write_io = GetWriteIO(io);
6224 if (fptr->
fd < 0)
return Qnil;
6225 if (is_socket(fptr->
fd, fptr->
pathv)) {
6236 if (io_fflush(fptr) < 0)
6237 rb_sys_fail_on_write(fptr);
6239 if (shutdown(fptr->
fd, SHUT_WR) < 0)
6240 rb_sys_fail_path(fptr->
pathv);
6241 fptr->
mode &= ~FMODE_WRITABLE;
6248 rb_raise(
rb_eIOError,
"closing non-duplex IO for writing");
6251 if (io != write_io) {
6271rb_io_sysseek(
int argc,
VALUE *argv,
VALUE io)
6273 VALUE offset, ptrname;
6274 int whence = SEEK_SET;
6278 if (
rb_scan_args(argc, argv,
"11", &offset, &ptrname) == 2) {
6279 whence = interpret_seek_whence(ptrname);
6284 (READ_DATA_BUFFERED(fptr) || READ_CHAR_PENDING(fptr))) {
6288 rb_warn(
"sysseek for buffered IO");
6291 pos = lseek(fptr->
fd, pos, whence);
6292 if (pos < 0 &&
errno) rb_sys_fail_path(fptr->
pathv);
6326 io = GetWriteIO(io);
6331 rb_warn(
"syswrite for buffered IO");
6334 tmp = rb_str_tmp_frozen_acquire(str);
6336 n = rb_io_write_memory(fptr, ptr,
len);
6337 if (n < 0) rb_sys_fail_path(fptr->
pathv);
6338 rb_str_tmp_frozen_release(str, tmp);
6355rb_io_sysread(
int argc,
VALUE *argv,
VALUE io)
6366 shrinkable = io_setstrbuf(&str, ilen);
6367 if (ilen == 0)
return str;
6372 if (READ_DATA_BUFFERED(fptr)) {
6378 io_setstrbuf(&str, ilen);
6379 rb_str_make_heap(str);
6384 iis.buf = RSTRING_PTR(str);
6387 n = io_read_memory_locktmp(str, &iis);
6390 rb_sys_fail_path(fptr->
pathv);
6393 io_set_read_length(str, n, shrinkable);
6395 if (n == 0 && ilen > 0) {
6411internal_pread_func(
void *_arg)
6415 return (
VALUE)pread(arg->fd, arg->buf, arg->count, arg->offset);
6419pread_internal_call(
VALUE _arg)
6424 if (scheduler !=
Qnil) {
6427 if (!UNDEF_P(result)) {
6432 return rb_io_blocking_region_wait(arg->io, internal_pread_func, arg,
RUBY_IO_READABLE);
6476 shrinkable = io_setstrbuf(&str, (
rb_len_t)arg.count);
6477 if (arg.count == 0)
return str;
6478 rb_str_make_heap(str);
6479 arg.buf = RSTRING_PTR(str);
6492 rb_sys_fail_path(fptr->
pathv);
6494 io_set_read_length(str, n, shrinkable);
6495 if (n == 0 && arg.count > 0) {
6503internal_pwrite_func(
void *_arg)
6507 return (
VALUE)pwrite(arg->fd, arg->buf, arg->count, arg->offset);
6511pwrite_internal_call(
VALUE _arg)
6516 if (scheduler !=
Qnil) {
6519 if (!UNDEF_P(result)) {
6524 return rb_io_blocking_region_wait(arg->io, internal_pwrite_func, arg,
RUBY_IO_WRITABLE);
6565 io = GetWriteIO(io);
6572 tmp = rb_str_tmp_frozen_acquire(str);
6573 arg.buf = RSTRING_PTR(tmp);
6574 arg.count = (size_t)RSTRING_LEN(tmp);
6576 n = (ssize_t)pwrite_internal_call((
VALUE)&arg);
6577 if (n < 0) rb_sys_fail_path(fptr->
pathv);
6578 rb_str_tmp_frozen_release(str, tmp);
6594 fptr->
mode &= ~FMODE_TEXTMODE;
6598 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6601 setmode(fptr->
fd, O_BINARY);
6608io_ascii8bit_binmode(
rb_io_t *fptr)
6619 fptr->
mode &= ~FMODE_TEXTMODE;
6620 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6622 fptr->
encs.
enc = rb_ascii8bit_encoding();
6626 clear_codeconv(fptr);
6635 io_ascii8bit_binmode(fptr);
6652rb_io_binmode_m(
VALUE io)
6658 write_io = GetWriteIO(io);
6673rb_io_binmode_p(
VALUE io)
6681rb_io_fmode_modestr(
enum rb_io_mode fmode)
6685 return MODE_BTMODE(
"a+",
"ab+",
"at+");
6687 return MODE_BTMODE(
"a",
"ab",
"at");
6691 rb_raise(rb_eArgError,
"invalid access fmode 0x%x", fmode);
6693 return MODE_BTMODE(
"r",
"rb",
"rt");
6695 return MODE_BTXMODE(
"w",
"wb",
"wt",
"wx",
"wbx",
"wtx");
6698 return MODE_BTXMODE(
"w+",
"wb+",
"wt+",
"w+x",
"wb+x",
"wt+x");
6700 return MODE_BTMODE(
"r+",
"rb+",
"rt+");
6704static const char bom_prefix[] =
"bom|";
6705static const char utf_prefix[] =
"utf-";
6706enum {bom_prefix_len = (int)
sizeof(bom_prefix) - 1};
6707enum {utf_prefix_len = (int)
sizeof(utf_prefix) - 1};
6712 return len > bom_prefix_len &&
STRNCASECMP(name, bom_prefix, bom_prefix_len) == 0;
6718 enum rb_io_mode fmode = 0;
6719 const char *m = modestr, *p = NULL;
6747 if (modestr[0] !=
'w')
6768 rb_raise(rb_eArgError,
"invalid access mode %s", modestr);
6773rb_io_oflags_fmode(
int oflags)
6775 enum rb_io_mode fmode = 0;
6777 switch (oflags & O_ACCMODE) {
6789 if (oflags & O_APPEND) {
6792 if (oflags & O_TRUNC) {
6795 if (oflags & O_CREAT) {
6798 if (oflags & O_EXCL) {
6802 if (oflags & O_BINARY) {
6811rb_io_fmode_oflags(
enum rb_io_mode fmode)
6855rb_io_oflags_modestr(
int oflags)
6858# define MODE_BINARY(a,b) ((oflags & O_BINARY) ? (b) : (a))
6860# define MODE_BINARY(a,b) (a)
6863 if (oflags & O_EXCL) {
6864 rb_raise(rb_eArgError,
"exclusive access mode is not supported");
6866 accmode = oflags & (O_RDONLY|O_WRONLY|O_RDWR);
6867 if (oflags & O_APPEND) {
6868 if (accmode == O_WRONLY) {
6869 return MODE_BINARY(
"a",
"ab");
6871 if (accmode == O_RDWR) {
6872 return MODE_BINARY(
"a+",
"ab+");
6877 rb_raise(rb_eArgError,
"invalid access oflags 0x%x", oflags);
6879 return MODE_BINARY(
"r",
"rb");
6881 return MODE_BINARY(
"w",
"wb");
6883 if (oflags & O_TRUNC) {
6884 return MODE_BINARY(
"w+",
"wb+");
6886 return MODE_BINARY(
"r+",
"rb+");
6898 int default_ext = 0;
6901 ext = rb_default_external_encoding();
6904 if (rb_is_ascii8bit_enc(ext)) {
6908 else if (intern == NULL) {
6909 intern = rb_default_internal_encoding();
6914 *enc = (default_ext && intern != ext) ? NULL : ext;
6924unsupported_encoding(
const char *name,
rb_encoding *enc)
6926 rb_enc_warn(enc,
"Unsupported encoding %s ignored", name);
6930parse_mode_enc(
const char *estr,
rb_encoding *estr_enc,
6936 enum rb_io_mode fmode = fmode_p ? *fmode_p : 0;
6942 p = strrchr(estr,
':');
6945 estr += bom_prefix_len;
6946 len -= bom_prefix_len;
6947 if (!
STRNCASECMP(estr, utf_prefix, utf_prefix_len)) {
6951 rb_enc_warn(estr_enc,
"BOM with non-UTF encoding %s is nonsense", estr);
6952 fmode &= ~FMODE_SETENC_BY_BOM;
6960 memcpy(encname, estr,
len);
6961 encname[
len] =
'\0';
6964 idx = rb_enc_find_index(estr);
6966 if (fmode_p) *fmode_p = fmode;
6969 ext_enc = rb_enc_from_index(idx);
6972 unsupported_encoding(estr, estr_enc);
6978 if (*p ==
'-' && *(p+1) ==
'\0') {
6983 idx2 = rb_enc_find_index(p);
6985 unsupported_encoding(p, estr_enc);
6990 int_enc = rb_enc_from_index(idx2);
6994 rb_io_ext_int_to_encs(ext_enc, int_enc, enc_p, enc2_p, fmode);
7007 v = rb_hash_lookup2(opt, sym_encoding,
Qnil);
7008 if (v !=
Qnil) encoding = v;
7009 v = rb_hash_lookup2(opt, sym_extenc,
Qundef);
7010 if (v !=
Qnil) extenc = v;
7011 v = rb_hash_lookup2(opt, sym_intenc,
Qundef);
7012 if (!UNDEF_P(v)) intenc = v;
7014 if ((!UNDEF_P(extenc) || !UNDEF_P(intenc)) && !
NIL_P(encoding)) {
7016 int idx = rb_to_encoding_index(encoding);
7017 if (idx >= 0) encoding = rb_enc_from_encoding(rb_enc_from_index(idx));
7018 rb_warn(
"Ignoring encoding parameter '%"PRIsVALUE
"': %s_encoding is used",
7019 encoding, UNDEF_P(extenc) ?
"internal" :
"external");
7023 if (!NIL_OR_UNDEF_P(extenc)) {
7024 extencoding = rb_to_encoding(extenc);
7026 if (!UNDEF_P(intenc)) {
7027 if (
NIL_P(intenc)) {
7034 if (*p ==
'-' && *(p+1) ==
'\0') {
7039 intencoding = rb_to_encoding(intenc);
7043 intencoding = rb_to_encoding(intenc);
7045 if (extencoding == intencoding) {
7049 if (!
NIL_P(encoding)) {
7053 enc_p, enc2_p, fmode_p);
7056 rb_io_ext_int_to_encs(rb_to_encoding(encoding), NULL, enc_p, enc2_p, 0);
7059 else if (!UNDEF_P(extenc) || !UNDEF_P(intenc)) {
7061 rb_io_ext_int_to_encs(extencoding, intencoding, enc_p, enc2_p, 0);
7069 enum rb_io_mode fmode = *fmode_p;
7074 !rb_enc_asciicompat(enc ? enc : rb_default_external_encoding()))
7075 rb_raise(rb_eArgError,
"ASCII incompatible encoding needs binmode");
7078 rb_raise(rb_eArgError,
"newline decorator with binary mode");
7085#if !DEFAULT_TEXTMODE
7087 fmode &= ~FMODE_TEXTMODE;
7094extract_binmode(
VALUE opthash,
enum rb_io_mode *fmode)
7096 if (!
NIL_P(opthash)) {
7098 v = rb_hash_aref(opthash, sym_textmode);
7101 rb_raise(rb_eArgError,
"textmode specified twice");
7103 rb_raise(rb_eArgError,
"both textmode and binmode specified");
7107 v = rb_hash_aref(opthash, sym_binmode);
7110 rb_raise(rb_eArgError,
"binmode specified twice");
7112 rb_raise(rb_eArgError,
"both textmode and binmode specified");
7118 rb_raise(rb_eArgError,
"both textmode and binmode specified");
7124 int *oflags_p,
enum rb_io_mode *fmode_p,
struct rb_io_encoding *convconfig_p)
7128 enum rb_io_mode fmode;
7132 int has_enc = 0, has_vmode = 0;
7138 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
7148 fmode = rb_io_oflags_fmode(oflags);
7156 oflags = rb_io_fmode_oflags(fmode);
7160 parse_mode_enc(p+1, rb_enc_get(vmode), &enc, &enc2, &fmode);
7165 e = (fmode &
FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
7166 rb_io_ext_int_to_encs(e, NULL, &enc, &enc2, fmode);
7170 if (
NIL_P(opthash)) {
7174#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7176 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7177 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7179 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
7186 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
7189 else if (
NIL_P(vmode)) {
7190 fmode |= DEFAULT_TEXTMODE;
7197 v = rb_hash_aref(opthash, sym_mode);
7199 if (!
NIL_P(vmode)) {
7200 rb_raise(rb_eArgError,
"mode specified twice");
7207 v = rb_hash_aref(opthash, sym_flags);
7212 fmode = rb_io_oflags_fmode(oflags);
7214 extract_binmode(opthash, &fmode);
7220 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
7223 else if (
NIL_P(vmode)) {
7224 fmode |= DEFAULT_TEXTMODE;
7227 v = rb_hash_aref(opthash, sym_perm);
7230 if (!
NIL_P(*vperm_p)) {
7231 rb_raise(rb_eArgError,
"perm specified twice");
7242#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7244 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7245 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7250 rb_raise(rb_eArgError,
"encoding specified twice");
7253 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
7257 validate_enc_binmode(&fmode, ecflags, enc, enc2);
7263 convconfig_p->
enc = enc;
7264 convconfig_p->
enc2 = enc2;
7265 convconfig_p->
ecflags = ecflags;
7266 convconfig_p->
ecopts = ecopts;
7276sysopen_func(
void *ptr)
7279 const char *fname = RSTRING_PTR(data->fname);
7288 fd = IO_WITHOUT_GVL_INT(sysopen_func, data);
7289 }
while (fd < 0 &&
errno == EINTR);
7296rb_sysopen(
VALUE fname,
int oflags, mode_t perm)
7301 data.fname = rb_str_encode_ospath(fname);
7303 data.oflags = oflags;
7306 TRY_WITH_GC((fd = rb_sysopen_internal(&data)) >= 0) {
7307 rb_syserr_fail_path(first_errno, fname);
7313fdopen_internal(
int fd,
const char *modestr)
7320 file = fdopen(fd, modestr);
7336 TRY_WITH_GC((file = fdopen_internal(fd, modestr)) != 0) {
7342 if (setvbuf(file, NULL, _IOFBF, 0) != 0)
7343 rb_warn(
"setvbuf() can't be honoured (fd=%d)", fd);
7351 int t = isatty(fptr->
fd);
7361io_strip_bom(
VALUE io)
7363 VALUE b1, b2, b3, b4;
7374 return rb_utf8_encindex();
7384 return ENCINDEX_UTF_16BE;
7395 return ENCINDEX_UTF_32LE;
7400 return ENCINDEX_UTF_16LE;
7410 return ENCINDEX_UTF_32BE;
7424io_set_encoding_by_bom(
VALUE io)
7426 int idx = io_strip_bom(io);
7432 extenc = rb_enc_from_index(idx);
7433 io_encoding_set(fptr, rb_enc_from_encoding(extenc),
7434 rb_io_internal_encoding(io),
Qnil);
7443rb_file_open_generic(
VALUE io,
VALUE filename,
int oflags,
enum rb_io_mode fmode,
7451 rb_io_ext_int_to_encs(NULL, NULL, &cc.enc, &cc.enc2, fmode);
7456 validate_enc_binmode(&fmode, convconfig->
ecflags,
7457 convconfig->
enc, convconfig->
enc2);
7461 fptr->
encs = *convconfig;
7464 if (!(oflags & O_TMPFILE)) {
7465 fptr->
pathv = pathv;
7468 fptr->
pathv = pathv;
7470 fptr->
fd = rb_sysopen(pathv, oflags, perm);
7478rb_file_open_internal(
VALUE io,
VALUE filename,
const char *modestr)
7481 const char *p = strchr(modestr,
':');
7485 parse_mode_enc(p+1, rb_usascii_encoding(),
7486 &convconfig.
enc, &convconfig.
enc2, &fmode);
7492 e = (fmode &
FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
7493 rb_io_ext_int_to_encs(e, NULL, &convconfig.
enc, &convconfig.
enc2, fmode);
7499#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7501 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7502 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7504 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.
enc2, convconfig.
ecflags);
7507 return rb_file_open_generic(io, filename,
7508 rb_io_fmode_oflags(fmode),
7518 return rb_file_open_internal(io_alloc(
rb_cFile), fname, modestr);
7527#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7550 while ((tmp = *prev) != 0) {
7551 if (tmp->fptr == fptr) {
7560#if defined (_WIN32) || defined(__CYGWIN__)
7569 if (!rb_current_execution_context(
false))
return;
7580pipe_finalize(
rb_io_t *fptr,
int noraise)
7582#if !defined(HAVE_WORKING_FORK) && !defined(_WIN32)
7591 fptr_finalize(fptr, noraise);
7593 pipe_del_fptr(fptr);
7600#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7601 void (*
const old_finalize)(
struct rb_io*,int) = fptr->
finalize;
7603 if (old_finalize == orig->finalize)
return;
7608#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7609 if (old_finalize != pipe_finalize) {
7611 for (list =
pipe_list; list; list = list->next) {
7612 if (list->fptr == fptr)
break;
7614 if (!list) pipe_add_fptr(fptr);
7617 pipe_del_fptr(fptr);
7643#define spawnv(mode, cmd, args) rb_w32_uaspawn((mode), (cmd), (args))
7644#define spawn(mode, cmd) rb_w32_uspawn((mode), (cmd), 0)
7647#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7657#ifdef HAVE_WORKING_FORK
7658# ifndef __EMSCRIPTEN__
7660popen_redirect(
struct popen_arg *p)
7663 close(p->write_pair[1]);
7664 if (p->write_pair[0] != 0) {
7665 dup2(p->write_pair[0], 0);
7666 close(p->write_pair[0]);
7669 if (p->pair[1] != 1) {
7670 dup2(p->pair[1], 1);
7676 if (p->pair[1] != 1) {
7677 dup2(p->pair[1], 1);
7683 if (p->pair[0] != 0) {
7684 dup2(p->pair[0], 0);
7691#if defined(__linux__)
7702linux_get_maxfd(
void)
7705 char buf[4096], *p, *np, *e;
7708 if (fd < 0)
return fd;
7709 ss = read(fd, buf,
sizeof(buf));
7710 if (ss < 0)
goto err;
7713 while ((
int)
sizeof(
"FDSize:\t0\n")-1 <= e-p &&
7714 (np = memchr(p,
'\n', e-p)) != NULL) {
7715 if (memcmp(p,
"FDSize:",
sizeof(
"FDSize:")-1) == 0) {
7717 p +=
sizeof(
"FDSize:")-1;
7737#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
7739 int max = (int)max_file_descriptor;
7742 ret = fcntl(0, F_MAXFD);
7744 maxhint = max = ret;
7745# elif defined(__linux__)
7746 ret = linux_get_maxfd();
7753 for (fd = lowfd; fd <= max; fd++) {
7754 if (!
NIL_P(noclose_fds) &&
7757 ret = fcntl(fd, F_GETFD);
7758 if (ret != -1 && !(ret & FD_CLOEXEC)) {
7759 fcntl(fd, F_SETFD, ret|FD_CLOEXEC);
7761# define CONTIGUOUS_CLOSED_FDS 20
7763 if (max < fd + CONTIGUOUS_CLOSED_FDS)
7764 max = fd + CONTIGUOUS_CLOSED_FDS;
7770# ifndef __EMSCRIPTEN__
7772popen_exec(
void *pp,
char *errmsg,
size_t errmsg_len)
7774 struct popen_arg *p = (
struct popen_arg*)pp;
7776 return rb_exec_async_signal_safe(p->eargp, errmsg, errmsg_len);
7781#if (defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)) && !defined __EMSCRIPTEN__
7783rb_execarg_fixup_v(
VALUE execarg_obj)
7785 rb_execarg_parent_start(execarg_obj);
7789char *rb_execarg_commandline(
const struct rb_execarg *eargp,
VALUE *prog);
7792#ifndef __EMSCRIPTEN__
7794pipe_open(
VALUE execarg_obj,
const char *modestr,
enum rb_io_mode fmode,
7797 struct rb_execarg *eargp =
NIL_P(execarg_obj) ? NULL : rb_execarg_get(execarg_obj);
7798 VALUE prog = eargp ? (eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name) :
Qfalse ;
7804#if defined(HAVE_WORKING_FORK)
7806 char errmsg[80] = {
'\0' };
7808#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7810 struct popen_arg arg;
7813#if defined(HAVE_SPAWNV)
7814# define DO_SPAWN(cmd, args) ((args) ? \
7815 spawnv(P_NOWAIT, (cmd), (args)) : \
7816 spawn(P_NOWAIT, (cmd)))
7817# if !defined(HAVE_WORKING_FORK)
7821#if !defined(HAVE_WORKING_FORK)
7827#if !defined(HAVE_WORKING_FORK)
7828 const char *cmd = 0;
7834#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7835 arg.execarg_obj = execarg_obj;
7838 arg.pair[0] = arg.pair[1] = -1;
7839 arg.write_pair[0] = arg.write_pair[1] = -1;
7840# if !defined(HAVE_WORKING_FORK)
7841 if (eargp && !eargp->use_shell) {
7842 args = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
7847 if (
rb_pipe(arg.write_pair) < 0)
7848 rb_sys_fail_str(prog);
7851 close(arg.write_pair[0]);
7852 close(arg.write_pair[1]);
7856 rb_execarg_addopt(execarg_obj,
INT2FIX(0),
INT2FIX(arg.write_pair[0]));
7857 rb_execarg_addopt(execarg_obj,
INT2FIX(1),
INT2FIX(arg.pair[1]));
7862 rb_sys_fail_str(prog);
7864 rb_execarg_addopt(execarg_obj,
INT2FIX(1),
INT2FIX(arg.pair[1]));
7868 rb_sys_fail_str(prog);
7870 rb_execarg_addopt(execarg_obj,
INT2FIX(0),
INT2FIX(arg.pair[0]));
7873 rb_sys_fail_str(prog);
7875 if (!
NIL_P(execarg_obj)) {
7876 rb_protect(rb_execarg_fixup_v, execarg_obj, &state);
7878 if (0 <= arg.write_pair[0]) close(arg.write_pair[0]);
7879 if (0 <= arg.write_pair[1]) close(arg.write_pair[1]);
7880 if (0 <= arg.pair[0]) close(arg.pair[0]);
7881 if (0 <= arg.pair[1]) close(arg.pair[1]);
7882 rb_execarg_parent_end(execarg_obj);
7886# if defined(HAVE_WORKING_FORK)
7887 pid = rb_fork_async_signal_safe(&status, popen_exec, &arg, arg.eargp->redirect_fds, errmsg,
sizeof(errmsg));
7889 rb_execarg_run_options(eargp, sargp, NULL, 0);
7890 while ((pid = DO_SPAWN(cmd, args)) < 0) {
7892 switch (e =
errno) {
7894# if EWOULDBLOCK != EAGAIN
7903 rb_execarg_run_options(sargp, NULL, NULL, 0);
7905 rb_execarg_parent_end(execarg_obj);
7908# if defined(HAVE_WORKING_FORK)
7909 pid = rb_call_proc__fork();
7911 popen_redirect(&arg);
7923# if defined(HAVE_WORKING_FORK)
7929 close(arg.write_pair[0]);
7930 close(arg.write_pair[1]);
7932# if defined(HAVE_WORKING_FORK)
7941 close(arg.write_pair[0]);
7942 write_fd = arg.write_pair[1];
7953 cmd = rb_execarg_commandline(eargp, &prog);
7954 if (!
NIL_P(execarg_obj)) {
7955 rb_execarg_parent_start(execarg_obj);
7956 rb_execarg_run_options(eargp, sargp, NULL, 0);
7958 fp = popen(cmd, modestr);
7961 rb_execarg_parent_end(execarg_obj);
7962 rb_execarg_run_options(sargp, NULL, NULL, 0);
7964 if (!fp) rb_syserr_fail_path(e, prog);
7974 fptr->
encs = *convconfig;
7975#if RUBY_CRLF_ENVIRONMENT
7982 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
7985#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7986 if (NEED_NEWLINE_DECORATOR_ON_WRITE(fptr)) {
7987 fptr->
encs.
ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
7993 if (0 <= write_fd) {
7994 write_port = io_alloc(
rb_cIO);
7996 write_fptr->
fd = write_fd;
7998 fptr->
mode &= ~FMODE_WRITABLE;
8000 rb_ivar_set(port, rb_intern(
"@tied_io_for_writing"), write_port);
8003#if defined (__CYGWIN__) || !defined(HAVE_WORKING_FORK)
8005 pipe_add_fptr(fptr);
8011pipe_open(
VALUE execarg_obj,
const char *modestr,
enum rb_io_mode fmode,
8019is_popen_fork(
VALUE prog)
8021 if (RSTRING_LEN(prog) == 1 && RSTRING_PTR(prog)[0] ==
'-') {
8022#if !defined(HAVE_WORKING_FORK)
8024 "fork() function is unimplemented on this machine");
8033pipe_open_s(
VALUE prog,
const char *modestr,
enum rb_io_mode fmode,
8037 VALUE *argv = &prog;
8040 if (!is_popen_fork(prog))
8041 execarg_obj = rb_execarg_new(argc, argv, TRUE, FALSE);
8042 return pipe_open(execarg_obj, modestr, fmode, convconfig);
8048 rb_io_t *fptr = io_close_fptr(io);
8217rb_io_s_popen(
int argc,
VALUE *argv,
VALUE klass)
8221 if (argc > 1 && !
NIL_P(opt = rb_check_hash_type(argv[argc-1]))) --argc;
8222 if (argc > 1 && !
NIL_P(env = rb_check_hash_type(argv[0]))) --argc, ++argv;
8231 int ex = !
NIL_P(opt);
8232 rb_error_arity(argc + ex, 1 + ex, 2 + ex);
8235 return popen_finish(rb_io_popen(pname, pmode, env, opt), klass);
8241 const char *modestr;
8244 enum rb_io_mode fmode;
8250#if SIZEOF_RB_LEN_T > SIZEOF_INT
8251 if (
len > INT_MAX) {
8252 rb_raise(rb_eArgError,
"too many arguments");
8261 if (!is_popen_fork(pname))
8262 execarg_obj = rb_execarg_new(1, &pname, TRUE, FALSE);
8264 if (!
NIL_P(execarg_obj)) {
8266 opt = rb_execarg_extract_options(execarg_obj, opt);
8268 rb_execarg_setenv(execarg_obj, env);
8271 modestr = rb_io_oflags_modestr(oflags);
8273 return pipe_open(execarg_obj, modestr, fmode, &convconfig);
8283 rb_io_flush(rb_ractor_stdout());
8284 rb_io_flush(rb_ractor_stderr());
8285 _exit(EXIT_SUCCESS);
8289 RBASIC_SET_CLASS(port, klass);
8296#if defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)
8297struct popen_writer_arg {
8299 struct popen_arg popen;
8303exec_popen_writer(
void *arg,
char *errmsg,
size_t buflen)
8305 struct popen_writer_arg *pw = arg;
8307 popen_redirect(&pw->popen);
8308 execv(pw->argv[0], pw->argv);
8309 strlcpy(errmsg, strerror(
errno), buflen);
8315ruby_popen_writer(
char *
const *argv, rb_pid_t *pid)
8317#if (defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)) || defined(_WIN32)
8318# ifdef HAVE_WORKING_FORK
8319 struct popen_writer_arg pw;
8320 int *
const write_pair = pw.popen.pair;
8326 if (cloexec_pipe(write_pair, 0,
false) == 0) {
8327# ifdef HAVE_WORKING_FORK
8330 char errmsg[80] = {
'\0'};
8331 *pid = rb_fork_async_signal_safe(&status, exec_popen_writer, &pw,
Qnil, errmsg,
sizeof(errmsg));
8333 *pid = rb_w32_uspawn_process(P_NOWAIT, argv[0], argv, write_pair[0], -1, -1, 0);
8334 const char *errmsg = (*pid < 0) ? strerror(
errno) : NULL;
8336 close(write_pair[0]);
8338 close(write_pair[1]);
8339 fprintf(stderr,
"ruby_popen_writer(%s): %s\n", argv[0], errmsg);
8342 return fdopen(write_pair[1],
"w");
8353 enum rb_io_mode fmode;
8362 rb_file_open_generic(io, fname, oflags, fmode, &convconfig, perm);
8414rb_io_s_open(
int argc,
VALUE *argv,
VALUE klass)
8446 VALUE fname, vmode, vperm;
8451 rb_scan_args(argc, argv,
"12", &fname, &vmode, &vperm);
8462 if (
NIL_P(vperm)) perm = 0666;
8466 fd = rb_sysopen(fname, oflags, perm);
8498 int redirect = FALSE;
8506 VALUE tmp = argv[0];
8524 return rb_io_s_open(argc, argv,
rb_cFile);
8528rb_io_open_generic(
VALUE klass,
VALUE filename,
int oflags,
enum rb_io_mode fmode,
8531 return rb_file_open_generic(io_alloc(klass), filename,
8532 oflags, fmode, convconfig, perm);
8539 enum rb_io_mode fmode;
8545 return rb_io_open_generic(io, filename, oflags, fmode, &convconfig, perm);
8559 if (fptr == orig)
return io;
8560 if (RUBY_IO_EXTERNAL_P(fptr)) {
8564 rb_raise(rb_eArgError,
8565 "%s can't change access mode from \"%s\" to \"%s\"",
8566 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->
mode),
8567 rb_io_fmode_modestr(orig->
mode));
8570 flush_before_seek(fptr,
true);
8572 clear_codeconv(fptr);
8574 pos = io_tell(orig);
8577 if (io_fflush(orig) < 0)
8578 rb_sys_fail_on_write(fptr);
8587 else if (!RUBY_IO_EXTERNAL_P(fptr)) fptr->
pathv =
Qnil;
8588 fptr_copy_finalizer(fptr, orig);
8594 rb_thread_io_close_interrupt(fptr);
8595 rb_thread_io_close_wait(fptr);
8597 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2 || !fptr->stdio_file) {
8600 rb_sys_fail_path(orig->
pathv);
8608 rb_sys_fail_path(orig->
pathv);
8614 if (io_seek(fptr, pos, SEEK_SET) < 0 &&
errno) {
8615 rb_sys_fail_path(fptr->
pathv);
8617 if (io_seek(orig, pos, SEEK_SET) < 0 &&
errno) {
8618 rb_sys_fail_path(orig->
pathv);
8632int rb_freopen(
VALUE fname,
const char *mode,
FILE *fp);
8635rb_freopen(
VALUE fname,
const char *mode,
FILE *fp)
8637 if (!freopen(RSTRING_PTR(fname), mode, fp)) {
8680rb_io_reopen(
int argc,
VALUE *argv,
VALUE file)
8682 VALUE fname, nmode, opt;
8686 if (
rb_scan_args(argc, argv,
"11:", &fname, &nmode, &opt) == 1) {
8689 return io_reopen(file, tmp);
8695 fptr =
RFILE(file)->fptr;
8699 enum rb_io_mode fmode;
8703 if (RUBY_IO_EXTERNAL_P(fptr) &&
8706 rb_raise(rb_eArgError,
8707 "%s can't change access mode from \"%s\" to \"%s\"",
8708 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->
mode),
8709 rb_io_fmode_modestr(fmode));
8712 fptr->
encs = convconfig;
8715 oflags = rb_io_fmode_oflags(fptr->
mode);
8718 fptr->
pathv = fname;
8720 fptr->
fd = rb_sysopen(fptr->
pathv, oflags, 0666);
8726 if (io_fflush(fptr) < 0)
8727 rb_sys_fail_on_write(fptr);
8730 clear_codeconv(fptr);
8733 int e = rb_freopen(rb_str_encode_ospath(fptr->
pathv),
8734 rb_io_oflags_modestr(oflags),
8736 if (e) rb_syserr_fail_path(e, fptr->
pathv);
8740 if (setvbuf(fptr->
stdio_file, NULL, _IOFBF, 0) != 0)
8741 rb_warn(
"setvbuf() can't be honoured for %"PRIsVALUE, fptr->
pathv);
8744 if (setvbuf(fptr->
stdio_file, NULL, _IONBF, BUFSIZ) != 0)
8745 rb_warn(
"setvbuf() can't be honoured for %"PRIsVALUE, fptr->
pathv);
8747 else if (fptr->
stdio_file == stdout && isatty(fptr->
fd)) {
8748 if (setvbuf(fptr->
stdio_file, NULL, _IOLBF, BUFSIZ) != 0)
8749 rb_warn(
"setvbuf() can't be honoured for %"PRIsVALUE, fptr->
pathv);
8753 int tmpfd = rb_sysopen(fptr->
pathv, oflags, 0666);
8759 rb_syserr_fail_path(err, fptr->
pathv);
8783 fptr->
mode = orig->
mode & ~FMODE_EXTERNAL;
8790 fptr->closing_ec = NULL;
8791 fptr->wakeup_mutex =
Qnil;
8792 fptr->fork_generation = GET_VM()->fork_gen;
8795 fptr_copy_finalizer(fptr, orig);
8797 fd = ruby_dup(orig->
fd);
8799 pos = io_tell(orig);
8801 io_seek(fptr, pos, SEEK_SET);
8806 write_io = GetWriteIO(io);
8807 if (io != write_io) {
8810 rb_ivar_set(dest, rb_intern(
"@tied_io_for_writing"), write_io);
8873 if (argc == 0)
return Qnil;
8875 out = rb_ractor_stdout();
8887extern void rb_deprecated_str_setter(
VALUE val,
ID id,
VALUE *var);
8892 rb_deprecated_str_setter(val,
id, &val);
8898 val = rb_str_frozen_bare_string(val);
8975 for (i=0; i<argc; i++) {
8979 rb_io_write(out, argv[i]);
9076 rb_io_write(io, str);
9080#define forward(obj, id, argc, argv) \
9081 rb_funcallv_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
9082#define forward_public(obj, id, argc, argv) \
9083 rb_funcallv_public_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
9084#define forward_current(id, argc, argv) \
9085 forward_public(ARGF.current_file, id, argc, argv)
9102 VALUE r_stdout = rb_ractor_stdout();
9103 if (recv == r_stdout) {
9104 return rb_io_putc(recv, ch);
9106 return forward(r_stdout, rb_intern(
"putc"), 1, &ch);
9111rb_str_end_with_asciichar(
VALUE str,
int c)
9114 const char *
ptr = RSTRING_PTR(str);
9118 if (
len == 0)
return 0;
9119 if ((n = rb_enc_mbminlen(
enc)) == 1) {
9120 return ptr[
len - 1] == c;
9122 return rb_enc_ascget(
ptr + ((
len - 1) / n) * n,
ptr +
len, &n,
enc) == c;
9133 rb_io_puts(1, &tmp, out);
9140 rb_io_puts(1, &tmp, out);
9195 VALUE line, args[2];
9202 for (
int i = 0; i < argc; i++) {
9216 if (RSTRING_LEN(line) == 0) {
9221 if (!rb_str_end_with_asciichar(line,
'\n')) {
9226 rb_io_writev(out, n, args);
9244 VALUE r_stdout = rb_ractor_stdout();
9245 if (recv == r_stdout) {
9246 return rb_io_puts(argc, argv, recv);
9248 return forward(r_stdout, rb_intern(
"puts"), argc, argv);
9252rb_p_write(
VALUE str)
9257 VALUE r_stdout = rb_ractor_stdout();
9260 io_writev(2, args, r_stdout);
9263 rb_io_writev(r_stdout, 2, args);
9275rb_p_result(
int argc,
const VALUE *argv)
9282 else if (argc > 1) {
9285 VALUE r_stdout = rb_ractor_stdout();
9287 rb_uninterruptible(rb_io_flush, r_stdout);
9328 for (i=0; i<argc; i++) {
9330 rb_uninterruptible(rb_p_write, inspected);
9332 return rb_p_result(argc, argv);
9353rb_obj_display(
int argc,
VALUE *argv,
VALUE self)
9357 out = (!
rb_check_arity(argc, 0, 1) ? rb_ractor_stdout() : argv[0]);
9358 rb_io_write(out, self);
9364rb_stderr_to_original_p(
VALUE err)
9366 return (err == orig_stderr ||
RFILE(orig_stderr)->fptr->
fd < 0);
9372 VALUE out = rb_ractor_stderr();
9373 if (rb_stderr_to_original_p(out)) {
9375 if (isatty(fileno(stderr))) {
9376 if (rb_w32_write_console(
rb_str_new(mesg,
len), fileno(stderr)) > 0)
return;
9379 if (fwrite(mesg,
sizeof(
char), (
size_t)
len, stderr) < (
size_t)
len) {
9396rb_write_error_str(
VALUE mesg)
9398 VALUE out = rb_ractor_stderr();
9400 if (rb_stderr_to_original_p(out)) {
9401 size_t len = (size_t)RSTRING_LEN(mesg);
9403 if (isatty(fileno(stderr))) {
9404 if (rb_w32_write_console(mesg, fileno(stderr)) > 0)
return;
9407 if (fwrite(RSTRING_PTR(mesg),
sizeof(
char),
len, stderr) <
len) {
9414 rb_io_write(out, mesg);
9419rb_stderr_tty_p(
void)
9421 if (rb_stderr_to_original_p(rb_ractor_stderr()))
9422 return isatty(fileno(stderr));
9427must_respond_to(
ID mid,
VALUE val,
ID id)
9430 rb_raise(
rb_eTypeError,
"%"PRIsVALUE
" must have %"PRIsVALUE
" method, %"PRIsVALUE
" given",
9431 rb_id2str(
id), rb_id2str(mid),
9451 must_respond_to(id_write, val,
id);
9458 return rb_ractor_stdout();
9464 must_respond_to(id_write, val,
id);
9471 return rb_ractor_stderr();
9475allocate_and_open_new_file(
VALUE klass)
9477 VALUE self = io_alloc(klass);
9478 rb_io_make_open_file(self);
9486 VALUE self = rb_protect(allocate_and_open_new_file, klass, &state);
9494 maygvl_close(descriptor, 0);
9502 io->
fd = descriptor;
9520 io->closing_ec = NULL;
9521 io->wakeup_mutex =
Qnil;
9522 io->fork_generation = GET_VM()->fork_gen;
9525 io->
encs = *encoding;
9534prep_io(
int fd,
enum rb_io_mode fmode,
VALUE klass,
const char *path)
9544 e = (fmode &
FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
9545 rb_io_ext_int_to_encs(e, NULL, &convconfig.
enc, &convconfig.
enc2, fmode);
9549#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9551 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
9552 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
9554 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.
enc2, convconfig.
ecflags);
9560 if (!io_check_tty(io)) {
9563 setmode(fd, O_BINARY);
9575 if (path && strcmp(path,
"-")) klass =
rb_cFile;
9576 return prep_io(fd, rb_io_oflags_fmode(oflags), klass, path);
9580prep_stdio(
FILE *f,
enum rb_io_mode fmode,
VALUE klass,
const char *path)
9587#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9588 fptr->
encs.
ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
9599rb_io_prep_stdin(
void)
9605rb_io_prep_stdout(
void)
9611rb_io_prep_stderr(
void)
9620 int oflags = rb_io_fmode_oflags(fptr->
mode) & ~O_EXCL;
9647 rb_io_buffer_init(&fp->
wbuf);
9648 rb_io_buffer_init(&fp->
rbuf);
9649 rb_io_buffer_init(&fp->
cbuf);
9664 fp->closing_ec = NULL;
9665 fp->wakeup_mutex =
Qnil;
9666 fp->fork_generation = GET_VM()->fork_gen;
9671rb_io_make_open_file(
VALUE obj)
9676 if (
RFILE(obj)->fptr) {
9679 RFILE(obj)->fptr = 0;
9681 fp = rb_io_fptr_new();
9683 RFILE(obj)->fptr = fp;
9732rb_io_initialize(
int argc,
VALUE *argv,
VALUE io)
9738 return io_initialize(io, fnum, vmode, opt);
9745 int fd, oflags = O_RDONLY;
9746 enum rb_io_mode fmode;
9748#if defined(HAVE_FCNTL) && defined(F_GETFL)
9758 rb_raise(rb_eArgError,
"The given fd is not accessible because RubyVM reserves it");
9760#if defined(HAVE_FCNTL) && defined(F_GETFL)
9761 oflags = fcntl(fd, F_GETFL);
9762 if (oflags == -1) rb_sys_fail(0);
9764 if (fstat(fd, &st) < 0) rb_sys_fail(0);
9767#if defined(HAVE_FCNTL) && defined(F_GETFL)
9768 ofmode = rb_io_oflags_fmode(oflags);
9780 if (rb_hash_aref(opt, sym_autoclose) ==
Qfalse) {
9784 path = rb_hash_aref(opt,
RB_ID2SYM(idPath));
9795 fp->
encs = convconfig;
9799 fp->closing_ec = NULL;
9800 fp->wakeup_mutex =
Qnil;
9801 fp->fork_generation = GET_VM()->fork_gen;
9804 if (fileno(stdin) == fd)
9806 else if (fileno(stdout) == fd)
9808 else if (fileno(stderr) == fd)
9840rb_io_set_encoding_by_bom(
VALUE io)
9846 rb_raise(rb_eArgError,
"ASCII incompatible encoding needs binmode");
9849 rb_raise(rb_eArgError,
"encoding conversion is set");
9851 else if (fptr->
encs.
enc && fptr->
encs.
enc != rb_ascii8bit_encoding()) {
9852 rb_raise(rb_eArgError,
"encoding is set to %s already",
9855 if (!io_set_encoding_by_bom(io))
return Qnil;
9856 return rb_enc_from_encoding(fptr->
encs.
enc);
9909rb_file_initialize(
int argc,
VALUE *argv,
VALUE io)
9911 if (
RFILE(io)->fptr) {
9914 VALUE fname, vmode, vperm, opt;
9915 int posargc =
rb_scan_args(argc, argv,
"12:", &fname, &vmode, &vperm, &opt);
9920 return io_initialize(io, fd, vmode, opt);
9923 return rb_open_file(io, fname, vmode, vperm, opt);
9928rb_io_s_new(
int argc,
VALUE *argv,
VALUE klass)
9933 rb_warn(
"%"PRIsVALUE
"::new() does not take block; use %"PRIsVALUE
"::open() instead",
9949rb_io_s_for_fd(
int argc,
VALUE *argv,
VALUE klass)
9952 rb_io_initialize(argc, argv, io);
9965rb_io_autoclose_p(
VALUE io)
9990rb_io_set_autoclose(
VALUE io,
VALUE autoclose)
9994 if (!
RTEST(autoclose))
9997 fptr->
mode &= ~FMODE_EXTERNAL;
10002io_wait_event(
VALUE io,
int event,
VALUE timeout,
int return_io)
10012 if (mask & event) {
10034io_wait_readable(
int argc,
VALUE *argv,
VALUE io)
10041 if (rb_io_read_pending(fptr))
return Qtrue;
10044 VALUE timeout = (argc == 1 ? argv[0] :
Qnil);
10058io_wait_writable(
int argc,
VALUE *argv,
VALUE io)
10066 VALUE timeout = (argc == 1 ? argv[0] :
Qnil);
10081io_wait_priority(
int argc,
VALUE *argv,
VALUE io)
10088 if (rb_io_read_pending(fptr))
return Qtrue;
10091 VALUE timeout = argc == 1 ? argv[0] :
Qnil;
10097wait_mode_sym(
VALUE mode)
10099 if (mode ==
ID2SYM(rb_intern(
"r"))) {
10100 return RB_WAITFD_IN;
10102 if (mode ==
ID2SYM(rb_intern(
"read"))) {
10103 return RB_WAITFD_IN;
10105 if (mode ==
ID2SYM(rb_intern(
"readable"))) {
10106 return RB_WAITFD_IN;
10108 if (mode ==
ID2SYM(rb_intern(
"w"))) {
10109 return RB_WAITFD_OUT;
10111 if (mode ==
ID2SYM(rb_intern(
"write"))) {
10112 return RB_WAITFD_OUT;
10114 if (mode ==
ID2SYM(rb_intern(
"writable"))) {
10115 return RB_WAITFD_OUT;
10117 if (mode ==
ID2SYM(rb_intern(
"rw"))) {
10118 return RB_WAITFD_IN|RB_WAITFD_OUT;
10120 if (mode ==
ID2SYM(rb_intern(
"read_write"))) {
10121 return RB_WAITFD_IN|RB_WAITFD_OUT;
10123 if (mode ==
ID2SYM(rb_intern(
"readable_writable"))) {
10124 return RB_WAITFD_IN|RB_WAITFD_OUT;
10127 rb_raise(rb_eArgError,
"unsupported mode: %"PRIsVALUE, mode);
10131io_event_from_value(
VALUE value)
10135 if (events <= 0) rb_raise(rb_eArgError,
"Events must be positive integer!");
10173 for (
int i = 0; i < argc; i += 1) {
10175 events |= wait_mode_sym(argv[i]);
10177 else if (UNDEF_P(timeout)) {
10181 rb_raise(rb_eArgError,
"timeout given more than once");
10185 if (UNDEF_P(timeout)) timeout =
Qnil;
10193 events = io_event_from_value(argv[0]);
10201 if (rb_io_read_pending(fptr)) {
10203 if (return_io)
return Qtrue;
10209 return io_wait_event(io, events, timeout, return_io);
10213argf_mark_and_move(
void *ptr)
10215 struct argf *p = ptr;
10216 rb_gc_mark_and_move(&p->filename);
10217 rb_gc_mark_and_move(&p->current_file);
10218 rb_gc_mark_and_move(&p->argv);
10219 rb_gc_mark_and_move(&p->inplace);
10220 rb_gc_mark_and_move(&p->encs.
ecopts);
10224argf_memsize(
const void *ptr)
10226 const struct argf *p = ptr;
10227 size_t size =
sizeof(*p);
10234 0, 0, RUBY_TYPED_THREAD_SAFE_FREE | RUBY_TYPED_WB_PROTECTED
10240 p->filename =
Qnil;
10241 p->current_file =
Qnil;
10247argf_alloc(
VALUE klass)
10262 memset(&ARGF, 0,
sizeof(ARGF));
10263 argf_init(
argf, &ARGF, argv);
10273 ARGF = argf_of(orig);
10274 rb_gc_writebarrier_remember(
argf);
10301 ARGF.last_lineno = ARGF.lineno;
10327 return forward_current(rb_frame_this_func(), argc, argv);
10330#define next_argv() argf_next_argv(argf)
10331#define ARGF_GENERIC_INPUT_P() \
10332 (ARGF.current_file == rb_stdin && !RB_TYPE_P(ARGF.current_file, T_FILE))
10333#define ARGF_FORWARD(argc, argv) do {\
10334 if (ARGF_GENERIC_INPUT_P())\
10335 return argf_forward((argc), (argv), argf);\
10337#define NEXT_ARGF_FORWARD(argc, argv) do {\
10338 if (!next_argv()) return Qnil;\
10339 ARGF_FORWARD((argc), (argv));\
10345 VALUE file = ARGF.current_file;
10359 int stdout_binmode = 0;
10360 enum rb_io_mode fmode;
10362 VALUE r_stdout = rb_ractor_stdout();
10367 stdout_binmode = 1;
10370 if (ARGF.init_p == 0) {
10380 if (
NIL_P(ARGF.argv)) {
10383 else if (ARGF.next_p == -1 &&
RARRAY_LEN(ARGF.argv) > 0) {
10388 if (ARGF.next_p == 1) {
10389 if (ARGF.init_p == 1) argf_close(
argf);
10394 ARGF_SET(filename, filename);
10395 filename = rb_str_encode_ospath(filename);
10397 if (RSTRING_LEN(filename) == 1 && fn[0] ==
'-') {
10399 if (ARGF.inplace) {
10400 rb_warn(
"Can't do inplace edit for stdio; skipping");
10406 int fr = rb_sysopen(filename, O_RDONLY, 0);
10408 if (ARGF.inplace) {
10410#ifndef NO_SAFE_RENAME
10421 if (!
NIL_P(ARGF.inplace)) {
10422 VALUE suffix = ARGF.inplace;
10424 if (
NIL_P(rb_str_cat_conv_enc_opts(str, RSTRING_LEN(str),
10425 RSTRING_PTR(suffix), RSTRING_LEN(suffix),
10426 rb_enc_get(suffix), 0,
Qnil))) {
10429#ifdef NO_SAFE_RENAME
10431 (void)unlink(RSTRING_PTR(str));
10432 if (rename(fn, RSTRING_PTR(str)) < 0) {
10433 rb_warn(
"Can't rename %"PRIsVALUE
" to %"PRIsVALUE
": %s, skipping file",
10434 filename, str, strerror(
errno));
10437 fr = rb_sysopen(str, O_RDONLY, 0);
10439 if (rename(fn, RSTRING_PTR(str)) < 0) {
10440 rb_warn(
"Can't rename %"PRIsVALUE
" to %"PRIsVALUE
": %s, skipping file",
10441 filename, str, strerror(
errno));
10448#ifdef NO_SAFE_RENAME
10449 rb_fatal(
"Can't do inplace edit without backup");
10451 if (unlink(fn) < 0) {
10452 rb_warn(
"Can't remove %"PRIsVALUE
": %s, skipping file",
10453 filename, strerror(
errno));
10459 fw = rb_sysopen(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666);
10460#ifndef NO_SAFE_RENAME
10463 fchmod(fw, st.st_mode);
10465 chmod(fn, st.st_mode);
10467 if (st.st_uid!=st2.st_uid || st.st_gid!=st2.st_gid) {
10470 err = fchown(fw, st.st_uid, st.st_gid);
10472 err = chown(fn, st.st_uid, st.st_gid);
10474 if (err && getuid() == 0 && st2.st_uid == 0) {
10475 const char *wkfn = RSTRING_PTR(filename);
10476 rb_warn(
"Can't set owner/group of %"PRIsVALUE
" to same as %"PRIsVALUE
": %s, skipping file",
10477 filename, str, strerror(
errno));
10480 (void)unlink(wkfn);
10490 if (!ARGF.binmode) {
10491 fmode |= DEFAULT_TEXTMODE;
10493 ARGF_SET(current_file, prep_io(fr, fmode,
rb_cFile, fn));
10494 if (!
NIL_P(write_io)) {
10501 if (ARGF.encs.enc) {
10502 fptr->
encs = ARGF.encs;
10503 clear_codeconv(fptr);
10506 fptr->
encs.
ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
10507 if (!ARGF.binmode) {
10509#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
10510 fptr->
encs.
ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
10521 else if (ARGF.next_p == -1) {
10524 if (ARGF.inplace) {
10525 rb_warn(
"Can't do inplace edit for stdio");
10529 if (ARGF.init_p == -1) ARGF.init_p = 1;
10537 long lineno = ARGF.lineno;
10540 if (!next_argv())
return Qnil;
10541 if (ARGF_GENERIC_INPUT_P()) {
10542 line = forward_current(idGets, argc, argv);
10549 line = rb_io_getline(argc, argv, ARGF.current_file);
10551 if (
NIL_P(line) && ARGF.next_p != -1) {
10557 if (!
NIL_P(line)) {
10558 ARGF.lineno = ++lineno;
10559 ARGF.last_lineno = ARGF.lineno;
10565argf_lineno_getter(
ID id,
VALUE *var)
10568 return INT2FIX(ARGF.last_lineno);
10576 ARGF.last_lineno = ARGF.lineno = n;
10580rb_reset_argf_lineno(
long n)
10582 ARGF.last_lineno = ARGF.lineno = n;
10623 if (recv ==
argf) {
10624 return argf_gets(argc, argv,
argf);
10626 return forward(
argf, idGets, argc, argv);
10652 line = argf_getline(argc, argv,
argf);
10664 return rb_f_gets(0, 0,
argf);
10668 if (!next_argv())
return Qnil;
10670 if (
NIL_P(line) && ARGF.next_p != -1) {
10676 if (!
NIL_P(line)) {
10678 ARGF.last_lineno = ARGF.lineno;
10704rb_f_readline(
int argc,
VALUE *argv,
VALUE recv)
10706 if (recv ==
argf) {
10707 return argf_readline(argc, argv,
argf);
10709 return forward(
argf, rb_intern(
"readline"), argc, argv);
10735 if (!next_argv()) rb_eof_error();
10736 ARGF_FORWARD(argc, argv);
10737 line = argf_gets(argc, argv,
argf);
10807rb_f_readlines(
int argc,
VALUE *argv,
VALUE recv)
10809 if (recv ==
argf) {
10810 return argf_readlines(argc, argv,
argf);
10812 return forward(
argf, rb_intern(
"readlines"), argc, argv);
10836 long lineno = ARGF.lineno;
10840 while (next_argv()) {
10841 if (ARGF_GENERIC_INPUT_P()) {
10842 lines = forward_current(rb_intern(
"readlines"), argc, argv);
10845 lines = rb_io_readlines(argc, argv, ARGF.current_file);
10851 ARGF.last_lineno = ARGF.lineno;
10886 rb_last_status_clear();
10887 port = pipe_open_s(str,
"r",
FMODE_READABLE|DEFAULT_TEXTMODE, NULL);
10891 result = read_all(fptr, remain_size(fptr),
Qnil);
10893 rb_io_fptr_cleanup_all(fptr);
10899#ifdef HAVE_SYS_SELECT_H
10900#include <sys/select.h>
10914 if (!
NIL_P(read)) {
10919 if (READ_DATA_PENDING(fptr) || READ_CHAR_PENDING(fptr)) {
10923 if (max < fptr->fd) max = fptr->
fd;
10926 timerec.tv_sec = timerec.tv_usec = 0;
10934 if (!
NIL_P(write)) {
10940 if (max < fptr->fd) max = fptr->
fd;
10947 if (!
NIL_P(except)) {
10951 VALUE write_io = GetWriteIO(io);
10954 if (max < fptr->fd) max = fptr->
fd;
10955 if (io != write_io) {
10958 if (max < fptr->fd) max = fptr->
fd;
10973 if (!pending && n == 0)
return Qnil;
10998 VALUE write_io = GetWriteIO(io);
11011 VALUE write_io = GetWriteIO(io);
11016 else if (io != write_io) {
11029 VALUE read, write, except;
11035select_call(
VALUE arg)
11039 return select_internal(p->read, p->write, p->except, p->timeout, p->fdsets);
11043select_end(
VALUE arg)
11048 for (i = 0; i < numberof(p->fdsets); ++i)
11053static VALUE sym_normal, sym_sequential, sym_random,
11054 sym_willneed, sym_dontneed, sym_noreuse;
11056#ifdef HAVE_POSIX_FADVISE
11057struct io_advise_struct {
11065io_advise_internal(
void *arg)
11067 struct io_advise_struct *ptr = arg;
11068 return posix_fadvise(ptr->fd, ptr->offset, ptr->len, ptr->advice);
11072io_advise_sym_to_const(
VALUE sym)
11074#ifdef POSIX_FADV_NORMAL
11075 if (sym == sym_normal)
11076 return INT2NUM(POSIX_FADV_NORMAL);
11079#ifdef POSIX_FADV_RANDOM
11080 if (sym == sym_random)
11081 return INT2NUM(POSIX_FADV_RANDOM);
11084#ifdef POSIX_FADV_SEQUENTIAL
11085 if (sym == sym_sequential)
11086 return INT2NUM(POSIX_FADV_SEQUENTIAL);
11089#ifdef POSIX_FADV_WILLNEED
11090 if (sym == sym_willneed)
11091 return INT2NUM(POSIX_FADV_WILLNEED);
11094#ifdef POSIX_FADV_DONTNEED
11095 if (sym == sym_dontneed)
11096 return INT2NUM(POSIX_FADV_DONTNEED);
11099#ifdef POSIX_FADV_NOREUSE
11100 if (sym == sym_noreuse)
11101 return INT2NUM(POSIX_FADV_NOREUSE);
11108do_io_advise(
rb_io_t *fptr,
VALUE advice, rb_off_t offset, rb_off_t
len)
11111 struct io_advise_struct ias;
11114 num_adv = io_advise_sym_to_const(advice);
11120 if (
NIL_P(num_adv))
11124 ias.advice =
NUM2INT(num_adv);
11125 ias.offset = offset;
11128 rv = (int)rb_io_blocking_region(fptr, io_advise_internal, &ias);
11129 if (rv && rv != ENOSYS) {
11132 VALUE message = rb_sprintf(
"%"PRIsVALUE
" "
11136 fptr->
pathv, offset,
len, advice);
11146advice_arg_check(
VALUE advice)
11151 if (advice != sym_normal &&
11152 advice != sym_sequential &&
11153 advice != sym_random &&
11154 advice != sym_willneed &&
11155 advice != sym_dontneed &&
11156 advice != sym_noreuse) {
11157 rb_raise(
rb_eNotImpError,
"Unsupported advice: %+"PRIsVALUE, advice);
11195rb_io_advise(
int argc,
VALUE *argv,
VALUE io)
11202 advice_arg_check(advice);
11204 io = GetWriteIO(io);
11210#ifdef HAVE_POSIX_FADVISE
11211 return do_io_advise(fptr, advice,
off, l);
11213 ((void)
off, (
void)l);
11225 return isinf(f) && 0 < f;
11381rb_f_select(
int argc,
VALUE *argv,
VALUE obj)
11384 if (scheduler !=
Qnil) {
11387 if (!UNDEF_P(result))
return result;
11395 rb_scan_args(argc, argv,
"13", &args.read, &args.write, &args.except, &timeout);
11396 if (
NIL_P(timeout) || is_pos_inf(timeout)) {
11401 args.timeout = &timerec;
11404 for (i = 0; i < numberof(args.fdsets); ++i)
11410#ifdef IOCTL_REQ_TYPE
11411 typedef IOCTL_REQ_TYPE ioctl_req_t;
11413 typedef int ioctl_req_t;
11414# define NUM2IOCTLREQ(num) ((int)NUM2LONG(num))
11425nogvl_ioctl(
void *ptr)
11427 struct ioctl_arg *arg = ptr;
11429 return (
VALUE)ioctl(arg->fd, arg->cmd, arg->narg);
11433do_ioctl(
struct rb_io *io, ioctl_req_t cmd,
long narg)
11436 struct ioctl_arg arg;
11442 retval = (int)rb_io_blocking_region(io, nogvl_ioctl, &arg);
11448#define DEFAULT_IOCTL_NARG_LEN (256)
11450#if defined(__linux__) && defined(_IOC_SIZE)
11452linux_iocparm_len(ioctl_req_t cmd)
11456 if ((cmd & 0xFFFF0000) == 0) {
11458 return DEFAULT_IOCTL_NARG_LEN;
11461 len = _IOC_SIZE(cmd);
11464 if (
len < DEFAULT_IOCTL_NARG_LEN)
11465 len = DEFAULT_IOCTL_NARG_LEN;
11473ioctl_narg_len(ioctl_req_t cmd)
11479#define IOCPARM_LEN(x) (((x) >> 16) & IOCPARM_MASK)
11483 len = IOCPARM_LEN(cmd);
11484#elif defined(__linux__) && defined(_IOC_SIZE)
11485 len = linux_iocparm_len(cmd);
11488 len = DEFAULT_IOCTL_NARG_LEN;
11497typedef long fcntl_arg_t;
11500typedef int fcntl_arg_t;
11504fcntl_narg_len(ioctl_req_t cmd)
11511 len =
sizeof(fcntl_arg_t);
11519#ifdef F_DUPFD_CLOEXEC
11520 case F_DUPFD_CLOEXEC:
11521 len =
sizeof(fcntl_arg_t);
11531 len =
sizeof(fcntl_arg_t);
11541 len =
sizeof(fcntl_arg_t);
11551 len =
sizeof(fcntl_arg_t);
11556 len =
sizeof(
struct f_owner_ex);
11561 len =
sizeof(
struct f_owner_ex);
11566 len =
sizeof(
struct flock);
11571 len =
sizeof(
struct flock);
11576 len =
sizeof(
struct flock);
11596 len =
sizeof(fcntl_arg_t);
11606 len =
sizeof(fcntl_arg_t);
11611 len =
sizeof(fcntl_arg_t);
11624fcntl_narg_len(ioctl_req_t cmd)
11630#define NARG_SENTINEL 17
11633setup_narg(ioctl_req_t cmd,
VALUE *argp,
long (*narg_len)(ioctl_req_t))
11644 else if (arg ==
Qtrue) {
11659 req_len = narg_len(cmd);
11660 rb_str_modify(arg);
11662 slen = RSTRING_LEN(arg);
11664 if (slen < req_len+1) {
11665 rb_str_resize(arg, req_len+1);
11666 MEMZERO(RSTRING_PTR(arg)+slen,
char, req_len-slen);
11670 ptr = RSTRING_PTR(arg);
11671 ptr[slen - 1] = NARG_SENTINEL;
11680finish_narg(
int retval,
VALUE arg,
const rb_io_t *fptr)
11682 if (retval < 0) rb_sys_fail_path(fptr->
pathv);
11687 if (ptr[slen-1] != NARG_SENTINEL)
11688 rb_raise(rb_eArgError,
"return value overflowed string");
11689 ptr[slen-1] =
'\0';
11699 ioctl_req_t cmd = NUM2IOCTLREQ(req);
11704 narg = setup_narg(cmd, &arg, ioctl_narg_len);
11706 retval = do_ioctl(fptr, cmd, narg);
11707 return finish_narg(retval, arg, fptr);
11734 return rb_ioctl(io, req, arg);
11737#define rb_io_ioctl rb_f_notimplement
11748nogvl_fcntl(
void *ptr)
11750 struct fcntl_arg *arg = ptr;
11752#if defined(F_DUPFD)
11753 if (arg->cmd == F_DUPFD)
11756 return (
VALUE)fcntl(arg->fd, arg->cmd, arg->narg);
11760do_fcntl(
struct rb_io *io,
int cmd,
long narg)
11763 struct fcntl_arg arg;
11769 retval = (int)rb_io_blocking_region(io, nogvl_fcntl, &arg);
11770 if (retval != -1) {
11772#if defined(F_DUPFD)
11775#if defined(F_DUPFD_CLOEXEC)
11776 case F_DUPFD_CLOEXEC:
11793 narg = setup_narg(cmd, &arg, fcntl_narg_len);
11795 retval = do_fcntl(fptr, cmd, narg);
11796 return finish_narg(retval, arg, fptr);
11822 return rb_fcntl(io, req, arg);
11825#define rb_io_fcntl rb_f_notimplement
11828#if defined(HAVE_SYSCALL) || defined(HAVE___SYSCALL)
11860#if SIZEOF_VOIDP == 8 && defined(HAVE___SYSCALL) && SIZEOF_INT != 8
11861# define SYSCALL __syscall
11862# define NUM2SYSCALLID(x) NUM2LONG(x)
11863# define RETVAL2NUM(x) LONG2NUM(x)
11864# if SIZEOF_LONG == 8
11865 long num, retval = -1;
11866# elif SIZEOF_LONG_LONG == 8
11867 long long num, retval = -1;
11869# error ---->> it is asserted that __syscall takes the first argument and returns retval in 64bit signed integer. <<----
11871#elif defined(__linux__)
11872# define SYSCALL syscall
11873# define NUM2SYSCALLID(x) NUM2LONG(x)
11874# define RETVAL2NUM(x) LONG2NUM(x)
11882 long num, retval = -1;
11884# define SYSCALL syscall
11885# define NUM2SYSCALLID(x) NUM2INT(x)
11886# define RETVAL2NUM(x) INT2NUM(x)
11887 int num, retval = -1;
11893 "We plan to remove a syscall function at future release. DL(Fiddle) provides safer alternative.");
11897 rb_raise(rb_eArgError,
"too few arguments for syscall");
11898 if (argc > numberof(arg))
11899 rb_raise(rb_eArgError,
"too many arguments for syscall");
11900 num = NUM2SYSCALLID(argv[0]); ++argv;
11901 for (i = argc - 1; i--; ) {
11916 retval = SYSCALL(num);
11919 retval = SYSCALL(num, arg[0]);
11922 retval = SYSCALL(num, arg[0],arg[1]);
11925 retval = SYSCALL(num, arg[0],arg[1],arg[2]);
11928 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3]);
11931 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4]);
11934 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5]);
11937 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6]);
11943 return RETVAL2NUM(retval);
11945#undef NUM2SYSCALLID
11949#define rb_f_syscall rb_f_notimplement
11953io_new_instance(
VALUE args)
11959find_encoding(
VALUE v)
11962 if (!enc)
rb_warn(
"Unsupported encoding %"PRIsVALUE
" ignored", v);
11974 enc2 = find_encoding(v1);
11977 if (RSTRING_LEN(tmp) == 1 && RSTRING_PTR(tmp)[0] ==
'-') {
11983 enc = find_encoding(v2);
11990 enc = find_encoding(v2);
11996 if (enc2 == rb_ascii8bit_encoding()) {
12001 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
12007 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
12008 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
12013 if (!
NIL_P(tmp) && rb_enc_asciicompat(enc = rb_enc_get(tmp))) {
12014 parse_mode_enc(RSTRING_PTR(tmp), enc, &enc, &enc2, NULL);
12015 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
12018 rb_io_ext_int_to_encs(find_encoding(v1), NULL, &enc, &enc2, 0);
12019 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
12024 validate_enc_binmode(&fptr->
mode, ecflags, enc, enc2);
12029 clear_codeconv(fptr);
12041io_encoding_set_v(
VALUE v)
12044 io_encoding_set(arg->fptr, arg->v1, arg->v2, arg->opt);
12049pipe_pair_close(
VALUE rw)
12052 return rb_ensure(io_close, rwp[0], io_close, rwp[1]);
12135rb_io_s_pipe(
int argc,
VALUE *argv,
VALUE klass)
12137 int pipes[2], state;
12138 VALUE r, w, args[3], v1, v2;
12142 enum rb_io_mode fmode = 0;
12145 argc =
rb_scan_args(argc, argv,
"02:", &v1, &v2, &opt);
12152 r = rb_protect(io_new_instance, (
VALUE)args, &state);
12156 rb_jump_tag(state);
12160 ies_args.fptr = fptr;
12163 ies_args.opt = opt;
12164 rb_protect(io_encoding_set_v, (
VALUE)&ies_args, &state);
12168 rb_jump_tag(state);
12173 w = rb_protect(io_new_instance, (
VALUE)args, &state);
12177 rb_jump_tag(state);
12182 extract_binmode(opt, &fmode);
12189#if DEFAULT_TEXTMODE
12191 fptr->
mode &= ~FMODE_TEXTMODE;
12192 setmode(fptr->
fd, O_BINARY);
12194#if RUBY_CRLF_ENVIRONMENT
12200 fptr->
mode |= fmode;
12201#if DEFAULT_TEXTMODE
12203 fptr2->
mode &= ~FMODE_TEXTMODE;
12204 setmode(fptr2->
fd, O_BINARY);
12207 fptr2->
mode |= fmode;
12241 else if (!
NIL_P(v = rb_hash_aref(opt, sym_open_args))) {
12244 v = rb_to_array_type(v);
12249 arg->io = rb_io_open(klass, path, vmode, vperm, opt);
12253io_s_foreach(
VALUE v)
12258 if (arg->limit == 0)
12259 rb_raise(rb_eArgError,
"invalid limit: 0 for foreach");
12260 while (!
NIL_P(str = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, arg->io))) {
12344rb_io_s_foreach(
int argc,
VALUE *argv,
VALUE self)
12347 int orig_argc = argc;
12351 argc =
rb_scan_args(argc, argv,
"12:", NULL, NULL, NULL, &opt);
12353 extract_getline_args(argc-1, argv+1, &garg);
12354 open_key_args(self, argc, argv, opt, &arg);
12356 extract_getline_opts(opt, &garg);
12357 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12358 return rb_ensure(io_s_foreach, (
VALUE)&garg, rb_io_close, arg.io);
12362io_s_readlines(
VALUE v)
12365 return io_readlines(arg, arg->io);
12418rb_io_s_readlines(
int argc,
VALUE *argv,
VALUE io)
12424 argc =
rb_scan_args(argc, argv,
"12:", NULL, NULL, NULL, &opt);
12425 extract_getline_args(argc-1, argv+1, &garg);
12426 open_key_args(io, argc, argv, opt, &arg);
12428 extract_getline_opts(opt, &garg);
12429 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12430 return rb_ensure(io_s_readlines, (
VALUE)&garg, rb_io_close, arg.io);
12437 return io_read(arg->argc, arg->argv, arg->io);
12447seek_before_access(
VALUE argp)
12451 return rb_io_seek(arg->io, arg->offset, arg->mode);
12518rb_io_s_read(
int argc,
VALUE *argv,
VALUE io)
12524 argc =
rb_scan_args(argc, argv,
"13:", NULL, NULL, &offset, NULL, &opt);
12526 rb_raise(rb_eArgError,
"negative offset %"PRIdLEN
" given",
off);
12528 open_key_args(io, argc, argv, opt, &arg);
12530 if (!
NIL_P(offset)) {
12534 sarg.offset = offset;
12535 sarg.mode = SEEK_SET;
12536 rb_protect(seek_before_access, (
VALUE)&sarg, &state);
12539 rb_jump_tag(state);
12541 if (arg.argc == 2) arg.argc = 1;
12556rb_io_s_binread(
int argc,
VALUE *argv,
VALUE io)
12571 convconfig.
enc = rb_ascii8bit_encoding();
12572 arg.io = rb_io_open_generic(io, argv[0], oflags, fmode, &convconfig, 0);
12575 arg.argc = (argc > 1) ? 1 : 0;
12576 if (!
NIL_P(offset)) {
12580 sarg.offset = offset;
12581 sarg.mode = SEEK_SET;
12582 rb_protect(seek_before_access, (
VALUE)&sarg, &state);
12585 rb_jump_tag(state);
12592io_s_write0(
VALUE v)
12595 return io_write(arg->io,arg->str,arg->nosync);
12599io_s_write(
int argc,
VALUE *argv,
VALUE klass,
int binary)
12601 VALUE string, offset, opt;
12605 rb_scan_args(argc, argv,
"21:", NULL, &
string, &offset, &opt);
12607 if (
NIL_P(opt)) opt = rb_hash_new();
12608 else opt = rb_hash_dup(opt);
12611 if (
NIL_P(rb_hash_aref(opt,sym_mode))) {
12612 int mode = O_WRONLY|O_CREAT;
12614 if (binary) mode |= O_BINARY;
12616 if (
NIL_P(offset)) mode |= O_TRUNC;
12617 rb_hash_aset(opt,sym_mode,
INT2NUM(mode));
12619 open_key_args(klass, argc, argv, opt, &arg);
12622 if (binary) rb_io_binmode_m(arg.io);
12626 if (!
NIL_P(offset)) {
12630 sarg.offset = offset;
12631 sarg.mode = SEEK_SET;
12632 rb_protect(seek_before_access, (
VALUE)&sarg, &state);
12635 rb_jump_tag(state);
12643 return rb_ensure(io_s_write0, (
VALUE)&warg, rb_io_close, arg.io);
12701rb_io_s_write(
int argc,
VALUE *argv,
VALUE io)
12703 return io_s_write(argc, argv, io, 0);
12716rb_io_s_binwrite(
int argc,
VALUE *argv,
VALUE io)
12718 return io_s_write(argc, argv, io, 1);
12724 rb_off_t copy_length;
12725 rb_off_t src_offset;
12729 unsigned close_src : 1;
12730 unsigned close_dst : 1;
12733 const char *syserr;
12734 const char *notimp;
12736 struct stat src_stat;
12737 struct stat dst_stat;
12738#ifdef HAVE_FCOPYFILE
12739 copyfile_state_t copyfile_state;
12744exec_interrupts(
void *arg)
12747 rb_thread_execute_interrupts(th);
12761#if defined(ERESTART)
12766 rb_thread_execute_interrupts(stp->th);
12785fiber_scheduler_wait_for(
void * _arguments)
12795# define IOWAIT_SYSCALL "poll"
12796STATIC_ASSERT(pollin_expected, POLLIN == RB_WAITFD_IN);
12797STATIC_ASSERT(pollout_expected, POLLOUT == RB_WAITFD_OUT);
12802 if (scheduler !=
Qnil) {
12805 return RTEST(args.result);
12809 if (fd == -1)
return 0;
12814 fds.events = events;
12816 int timeout_milliseconds = -1;
12819 timeout_milliseconds = (int)(timeout->tv_sec * 1000) + (int)(timeout->tv_usec / 1000);
12822 return poll(&fds, 1, timeout_milliseconds);
12825# define IOWAIT_SYSCALL "select"
12830 if (scheduler !=
Qnil) {
12833 return RTEST(args.result);
12853 case RB_WAITFD_OUT:
12857 VM_UNREACHABLE(nogvl_wait_for);
12877 ret = nogvl_wait_for(stp->th, stp->src_fptr, RB_WAITFD_IN, NULL);
12879 }
while (ret < 0 && maygvl_copy_stream_continue_p(has_gvl, stp));
12882 stp->syserr = IOWAIT_SYSCALL;
12883 stp->error_no =
errno;
12895 ret = nogvl_wait_for(stp->th, stp->dst_fptr, RB_WAITFD_OUT, NULL);
12896 }
while (ret < 0 && maygvl_copy_stream_continue_p(0, stp));
12899 stp->syserr = IOWAIT_SYSCALL;
12900 stp->error_no =
errno;
12906#ifdef USE_COPY_FILE_RANGE
12909simple_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)
12911#ifdef HAVE_COPY_FILE_RANGE
12912 return copy_file_range(in_fd, in_offset, out_fd, out_offset, count, flags);
12914 return syscall(__NR_copy_file_range, in_fd, in_offset, out_fd, out_offset, count, flags);
12923 rb_off_t copy_length, src_offset, *src_offset_ptr;
12925 if (!S_ISREG(stp->src_stat.st_mode))
12928 src_size = stp->src_stat.st_size;
12929 src_offset = stp->src_offset;
12930 if (src_offset >= (rb_off_t)0) {
12931 src_offset_ptr = &src_offset;
12934 src_offset_ptr = NULL;
12937 copy_length = stp->copy_length;
12938 if (copy_length < (rb_off_t)0) {
12939 if (src_offset < (rb_off_t)0) {
12940 rb_off_t current_offset;
12942 current_offset = lseek(stp->src_fptr->
fd, 0, SEEK_CUR);
12943 if (current_offset < (rb_off_t)0 &&
errno) {
12944 stp->syserr =
"lseek";
12945 stp->error_no =
errno;
12946 return (
int)current_offset;
12948 copy_length = src_size - current_offset;
12951 copy_length = src_size - src_offset;
12955 retry_copy_file_range:
12956# if SIZEOF_OFF_T > SIZEOF_SIZE_T
12958 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
12960 ss = (ssize_t)copy_length;
12962 ss = simple_copy_file_range(stp->src_fptr->
fd, src_offset_ptr, stp->dst_fptr->
fd, NULL, ss, 0);
12966 if (0 < copy_length) {
12967 goto retry_copy_file_range;
12971 if (maygvl_copy_stream_continue_p(0, stp)) {
12972 goto retry_copy_file_range;
12986#if EWOULDBLOCK != EAGAIN
12990 int ret = nogvl_copy_stream_wait_write(stp);
12991 if (ret < 0)
return ret;
12993 goto retry_copy_file_range;
12997 int flags = fcntl(stp->dst_fptr->
fd, F_GETFL);
12999 if (flags != -1 && flags & O_APPEND) {
13005 stp->syserr =
"copy_file_range";
13006 stp->error_no =
errno;
13013#ifdef HAVE_FCOPYFILE
13017 rb_off_t cur, ss = 0;
13018 const rb_off_t src_offset = stp->src_offset;
13021 if (stp->copy_length >= (rb_off_t)0) {
13026 if (!S_ISREG(stp->src_stat.st_mode))
13029 if (!S_ISREG(stp->dst_stat.st_mode))
13031 if (lseek(stp->dst_fptr->
fd, 0, SEEK_CUR) > (rb_off_t)0)
13033 if (fcntl(stp->dst_fptr->
fd, F_GETFL) & O_APPEND) {
13036 rb_off_t end = lseek(stp->dst_fptr->
fd, 0, SEEK_END);
13037 lseek(stp->dst_fptr->
fd, 0, SEEK_SET);
13038 if (end > (rb_off_t)0)
return 0;
13041 if (src_offset > (rb_off_t)0) {
13046 cur = lseek(stp->src_fptr->
fd, 0, SEEK_CUR);
13047 if (cur < (rb_off_t)0 &&
errno) {
13048 stp->error_no =
errno;
13053 r = lseek(stp->src_fptr->
fd, src_offset, SEEK_SET);
13054 if (r < (rb_off_t)0 &&
errno) {
13055 stp->error_no =
errno;
13060 stp->copyfile_state = copyfile_state_alloc();
13061 ret = fcopyfile(stp->src_fptr->
fd, stp->dst_fptr->
fd, stp->copyfile_state, COPYFILE_DATA);
13062 copyfile_state_get(stp->copyfile_state, COPYFILE_STATE_COPIED, &ss);
13066 if (src_offset > (rb_off_t)0) {
13070 r = lseek(stp->src_fptr->
fd, cur, SEEK_SET);
13071 if (r < (rb_off_t)0 &&
errno) {
13072 stp->error_no =
errno;
13084 stp->syserr =
"fcopyfile";
13085 stp->error_no =
errno;
13092#ifdef HAVE_SENDFILE
13095# define USE_SENDFILE
13097# ifdef HAVE_SYS_SENDFILE_H
13098# include <sys/sendfile.h>
13102simple_sendfile(
int out_fd,
int in_fd, rb_off_t *offset, rb_off_t count)
13104 return sendfile(out_fd, in_fd, offset, (
size_t)count);
13107# elif 0 || defined(__APPLE__)
13111# define USE_SENDFILE
13114simple_sendfile(
int out_fd,
int in_fd, rb_off_t *offset, rb_off_t count)
13117 rb_off_t pos = offset ? *offset : lseek(in_fd, 0, SEEK_CUR);
13120 r = sendfile(in_fd, out_fd, pos, &count, NULL, 0);
13123 r = sendfile(in_fd, out_fd, pos, (
size_t)count, NULL, &sbytes, 0);
13125 if (r != 0 && sbytes == 0)
return r;
13130 lseek(in_fd, sbytes, SEEK_CUR);
13132 return (ssize_t)sbytes;
13145 rb_off_t copy_length;
13146 rb_off_t src_offset;
13149 if (!S_ISREG(stp->src_stat.st_mode))
13152 src_size = stp->src_stat.st_size;
13154 if ((stp->dst_stat.st_mode & S_IFMT) != S_IFSOCK)
13158 src_offset = stp->src_offset;
13159 use_pread = src_offset >= (rb_off_t)0;
13161 copy_length = stp->copy_length;
13162 if (copy_length < (rb_off_t)0) {
13164 copy_length = src_size - src_offset;
13168 cur = lseek(stp->src_fptr->
fd, 0, SEEK_CUR);
13169 if (cur < (rb_off_t)0 &&
errno) {
13170 stp->syserr =
"lseek";
13171 stp->error_no =
errno;
13174 copy_length = src_size - cur;
13179# if SIZEOF_OFF_T > SIZEOF_SIZE_T
13181 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
13183 ss = (ssize_t)copy_length;
13186 ss = simple_sendfile(stp->dst_fptr->
fd, stp->src_fptr->
fd, &src_offset, ss);
13189 ss = simple_sendfile(stp->dst_fptr->
fd, stp->src_fptr->
fd, NULL, ss);
13194 if (0 < copy_length) {
13195 goto retry_sendfile;
13199 if (maygvl_copy_stream_continue_p(0, stp))
13200 goto retry_sendfile;
13213#if EWOULDBLOCK != EAGAIN
13226 ret = maygvl_copy_stream_wait_read(0, stp);
13227 if (ret < 0)
return ret;
13229 ret = nogvl_copy_stream_wait_write(stp);
13230 if (ret < 0)
return ret;
13232 goto retry_sendfile;
13234 stp->syserr =
"sendfile";
13235 stp->error_no =
errno;
13243maygvl_read(
int has_gvl,
rb_io_t *fptr,
void *buf,
size_t count)
13246 return rb_io_read_memory(fptr, buf, count);
13248 return read(fptr->
fd, buf, count);
13252maygvl_copy_stream_read(
int has_gvl,
struct copy_stream_struct *stp,
char *buf,
size_t len, rb_off_t offset)
13256 if (offset < (rb_off_t)0) {
13257 ss = maygvl_read(has_gvl, stp->src_fptr, buf,
len);
13260 ss = pread(stp->src_fptr->
fd, buf,
len, offset);
13266 if (maygvl_copy_stream_continue_p(has_gvl, stp))
13270#if EWOULDBLOCK != EAGAIN
13274 int ret = maygvl_copy_stream_wait_read(has_gvl, stp);
13275 if (ret < 0)
return ret;
13280 stp->notimp =
"pread";
13284 stp->syserr = offset < (rb_off_t)0 ?
"read" :
"pread";
13285 stp->error_no =
errno;
13296 ss = write(stp->dst_fptr->
fd, buf+
off,
len);
13298 if (maygvl_copy_stream_continue_p(0, stp))
13300 if (io_again_p(
errno)) {
13301 int ret = nogvl_copy_stream_wait_write(stp);
13302 if (ret < 0)
return ret;
13305 stp->syserr =
"write";
13306 stp->error_no =
errno;
13323 rb_off_t copy_length;
13324 rb_off_t src_offset;
13328 copy_length = stp->copy_length;
13329 use_eof = copy_length < (rb_off_t)0;
13330 src_offset = stp->src_offset;
13331 use_pread = src_offset >= (rb_off_t)0;
13333 if (use_pread && stp->close_src) {
13336 r = lseek(stp->src_fptr->
fd, src_offset, SEEK_SET);
13337 if (r < (rb_off_t)0 &&
errno) {
13338 stp->syserr =
"lseek";
13339 stp->error_no =
errno;
13342 src_offset = (rb_off_t)-1;
13346 while (use_eof || 0 < copy_length) {
13347 if (!use_eof && copy_length < (rb_off_t)
sizeof(buf)) {
13348 len = (size_t)copy_length;
13354 ss = maygvl_copy_stream_read(0, stp, buf,
len, src_offset);
13359 ss = maygvl_copy_stream_read(0, stp, buf,
len, (rb_off_t)-1);
13364 ret = nogvl_copy_stream_write(stp, buf, ss);
13374nogvl_copy_stream_func(
void *arg)
13377#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13381#ifdef USE_COPY_FILE_RANGE
13382 ret = nogvl_copy_file_range(stp);
13387#ifdef HAVE_FCOPYFILE
13388 ret = nogvl_fcopyfile(stp);
13394 ret = nogvl_copy_stream_sendfile(stp);
13399 nogvl_copy_stream_read_write(stp);
13401#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13408copy_stream_fallback_body(
VALUE arg)
13411 const int buflen = 16*1024;
13414 rb_off_t rest = stp->copy_length;
13415 rb_off_t
off = stp->src_offset;
13416 ID read_method = id_readpartial;
13418 if (!stp->src_fptr) {
13420 read_method = id_read;
13427 rb_str_make_independent(buf);
13428 if (stp->copy_length < (rb_off_t)0) {
13433 rb_str_resize(buf, 0);
13436 l = buflen < rest ? buflen : (
rb_len_t)rest;
13438 if (!stp->src_fptr) {
13441 if (read_method == id_read &&
NIL_P(rc))
13446 rb_str_resize(buf, buflen);
13447 ss = maygvl_copy_stream_read(1, stp, RSTRING_PTR(buf), l,
off);
13448 rb_str_resize(buf, ss > 0 ? ss : 0);
13453 if (
off >= (rb_off_t)0)
13456 n = rb_io_write(stp->dst, buf);
13458 stp->total += numwrote;
13460 if (read_method == id_read && RSTRING_LEN(buf) == 0) {
13471 if (!stp->src_fptr && stp->src_offset >= (rb_off_t)0) {
13472 rb_raise(rb_eArgError,
"cannot specify src_offset for non-IO");
13481copy_stream_body(
VALUE arg)
13484 VALUE src_io = stp->src, dst_io = stp->dst;
13485 const int common_oflags = 0
13495 if (src_io ==
argf ||
13499 stp->src_fptr = NULL;
13504 if (!
NIL_P(tmp_io)) {
13511 args[1] =
INT2NUM(O_RDONLY|common_oflags);
13514 stp->close_src = 1;
13519 stat_ret = fstat(stp->src_fptr->
fd, &stp->src_stat);
13520 if (stat_ret < 0) {
13521 stp->syserr =
"fstat";
13522 stp->error_no =
errno;
13527 if (dst_io ==
argf ||
13531 stp->dst_fptr = NULL;
13536 if (!
NIL_P(tmp_io)) {
13537 dst_io = GetWriteIO(tmp_io);
13543 args[1] =
INT2NUM(O_WRONLY|O_CREAT|O_TRUNC|common_oflags);
13547 stp->close_dst = 1;
13550 dst_io = GetWriteIO(dst_io);
13556 stat_ret = fstat(stp->dst_fptr->
fd, &stp->dst_stat);
13557 if (stat_ret < 0) {
13558 stp->syserr =
"fstat";
13559 stp->error_no =
errno;
13566 SET_BINARY_MODE_WITH_SEEK_CUR(stp->src_fptr);
13569 io_ascii8bit_binmode(stp->dst_fptr);
13571 if (stp->src_offset < (rb_off_t)0 && stp->src_fptr && stp->src_fptr->
rbuf.
len) {
13574 if (stp->copy_length >= (rb_off_t)0 && stp->copy_length < (rb_off_t)
len) {
13575 len = (size_t)stp->copy_length;
13578 rb_str_resize(str,
len);
13579 read_buffered_data(RSTRING_PTR(str),
len, stp->src_fptr);
13580 if (stp->dst_fptr) {
13581 if (io_binwrite(RSTRING_PTR(str), RSTRING_LEN(str), stp->dst_fptr, 0) < 0)
13582 rb_sys_fail_on_write(stp->dst_fptr);
13585 rb_io_write(dst_io, str);
13586 rb_str_resize(str, 0);
13588 if (stp->copy_length >= (rb_off_t)0)
13589 stp->copy_length -=
len;
13592 if (stp->dst_fptr && io_fflush(stp->dst_fptr) < 0) {
13596 if (stp->copy_length == 0)
13599 if (stp->src_fptr == NULL || stp->dst_fptr == NULL) {
13600 return copy_stream_fallback(stp);
13603 IO_WITHOUT_GVL(nogvl_copy_stream_func, stp);
13608copy_stream_finalize(
VALUE arg)
13612#ifdef HAVE_FCOPYFILE
13613 if (stp->copyfile_state) {
13614 copyfile_state_free(stp->copyfile_state);
13618 if (stp->close_src) {
13619 rb_io_close_m(stp->src);
13621 if (stp->close_dst) {
13622 rb_io_close_m(stp->dst);
13685rb_io_s_copy_stream(
int argc,
VALUE *argv,
VALUE io)
13687 VALUE src, dst, length, src_offset;
13692 rb_scan_args(argc, argv,
"22", &src, &dst, &length, &src_offset);
13697 st.src_fptr = NULL;
13698 st.dst_fptr = NULL;
13701 st.copy_length = (rb_off_t)-1;
13703 st.copy_length =
NUM2OFFT(length);
13705 if (
NIL_P(src_offset))
13706 st.src_offset = (rb_off_t)-1;
13708 st.src_offset =
NUM2OFFT(src_offset);
13727rb_io_external_encoding(
VALUE io)
13732 return rb_enc_from_encoding(fptr->
encs.
enc2);
13736 return rb_enc_from_encoding(fptr->
encs.
enc);
13739 return rb_enc_from_encoding(io_read_encoding(fptr));
13755rb_io_internal_encoding(
VALUE io)
13760 return rb_enc_from_encoding(io_read_encoding(fptr));
13794rb_io_set_encoding(
int argc,
VALUE *argv,
VALUE io)
13800 return forward(io, id_set_encoding, argc, argv);
13803 argc =
rb_scan_args(argc, argv,
"11:", &v1, &v2, &opt);
13805 io_encoding_set(fptr, v1, v2, opt);
13810rb_stdio_set_default_encoding(
void)
13815 if (isatty(fileno(stdin))) {
13817 rb_encoding *internal = rb_default_internal_encoding();
13818 if (!internal) internal = rb_default_external_encoding();
13820 rb_enc_from_encoding(external),
13821 rb_enc_from_encoding(internal),
13826 rb_io_set_encoding(1, &val,
rb_stdin);
13827 rb_io_set_encoding(1, &val,
rb_stdout);
13828 rb_io_set_encoding(1, &val,
rb_stderr);
13832global_argf_p(
VALUE arg)
13834 return arg ==
argf;
13837typedef VALUE (*argf_encoding_func)(
VALUE io);
13840argf_encoding(
VALUE argf, argf_encoding_func func)
13842 if (!
RTEST(ARGF.current_file)) {
13843 return rb_enc_default_external();
13867 return argf_encoding(
argf, rb_io_external_encoding);
13886 return argf_encoding(
argf, rb_io_internal_encoding);
13925 if (!next_argv()) {
13926 rb_raise(rb_eArgError,
"no stream to set encoding");
13928 rb_io_set_encoding(argc, argv, ARGF.current_file);
13930 ARGF.encs = fptr->
encs;
13950 if (!next_argv()) {
13951 rb_raise(rb_eArgError,
"no stream to tell");
13953 ARGF_FORWARD(0, 0);
13954 return rb_io_tell(ARGF.current_file);
13967 if (!next_argv()) {
13968 rb_raise(rb_eArgError,
"no stream to seek");
13970 ARGF_FORWARD(argc, argv);
13971 return rb_io_seek_m(argc, argv, ARGF.current_file);
13988 if (!next_argv()) {
13989 rb_raise(rb_eArgError,
"no stream to set position");
13991 ARGF_FORWARD(1, &offset);
13992 return rb_io_set_pos(ARGF.current_file, offset);
14013 if (!next_argv()) {
14014 rb_raise(rb_eArgError,
"no stream to rewind");
14016 ARGF_FORWARD(0, 0);
14017 old_lineno =
RFILE(ARGF.current_file)->fptr->lineno;
14018 ret = rb_io_rewind(ARGF.current_file);
14019 if (!global_argf_p(
argf)) {
14020 ARGF.last_lineno = ARGF.lineno -= old_lineno;
14038 if (!next_argv()) {
14039 rb_raise(rb_eArgError,
"no stream");
14041 ARGF_FORWARD(0, 0);
14042 return rb_io_fileno(ARGF.current_file);
14061 ARGF_FORWARD(0, 0);
14062 return ARGF.current_file;
14087 if (
RTEST(ARGF.current_file)) {
14088 if (ARGF.init_p == 0)
return Qtrue;
14090 ARGF_FORWARD(0, 0);
14149 VALUE tmp, str, length;
14153 if (!
NIL_P(length)) {
14158 rb_str_resize(str,0);
14163 if (!next_argv()) {
14166 if (ARGF_GENERIC_INPUT_P()) {
14167 tmp = argf_forward(argc, argv,
argf);
14170 tmp = io_read(argc, argv, ARGF.current_file);
14172 if (
NIL_P(str)) str = tmp;
14175 if (ARGF.next_p != -1) {
14181 else if (argc >= 1) {
14198argf_forward_call(
VALUE arg)
14201 argf_forward(p->argc, p->argv, p->argf);
14231 return argf_getpartial(argc, argv,
argf,
Qnil, 0);
14252 return argf_getpartial(argc, argv,
argf, opts, 1);
14258 VALUE tmp, str, length;
14266 no_exception = no_exception_p(opts);
14268 if (!next_argv()) {
14270 rb_str_resize(str, 0);
14274 if (ARGF_GENERIC_INPUT_P()) {
14284 tmp = io_getpartial(ARGF.current_file, length, str, no_exception, nonblock);
14287 if (ARGF.next_p == -1) {
14288 return io_nonblock_eof(no_exception);
14293 return io_nonblock_eof(no_exception);
14331 if (!next_argv())
return Qnil;
14332 if (ARGF_GENERIC_INPUT_P()) {
14333 ch = forward_current(rb_intern(
"getc"), 0, 0);
14336 ch = rb_io_getc(ARGF.current_file);
14338 if (
NIL_P(ch) && ARGF.next_p != -1) {
14371 if (!next_argv())
return Qnil;
14373 ch = forward_current(rb_intern(
"getbyte"), 0, 0);
14378 if (
NIL_P(ch) && ARGF.next_p != -1) {
14411 if (!next_argv()) rb_eof_error();
14413 ch = forward_current(rb_intern(
"getc"), 0, 0);
14416 ch = rb_io_getc(ARGF.current_file);
14418 if (
NIL_P(ch) && ARGF.next_p != -1) {
14450 NEXT_ARGF_FORWARD(0, 0);
14451 c = argf_getbyte(
argf);
14458#define FOREACH_ARGF() while (next_argv())
14463 const VALUE current = ARGF.current_file;
14465 if (ARGF.init_p == -1 || current != ARGF.current_file) {
14471#define ARGF_block_call(mid, argc, argv, func, argf) \
14472 rb_block_call_kw(ARGF.current_file, mid, argc, argv, \
14473 func, argf, rb_keyword_given_p())
14478 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_i,
argf);
14479 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14485 if (!global_argf_p(
argf)) {
14486 ARGF.last_lineno = ++ARGF.lineno;
14488 return argf_block_call_i(i,
argf, argc, argv, blockarg);
14494 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_line_i,
argf);
14495 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14543 argf_block_call_line(rb_intern(
"each_line"), argc, argv,
argf);
14574 argf_block_call(rb_intern(
"each_byte"), 0, 0,
argf);
14600 argf_block_call(rb_intern(
"each_char"), 0, 0,
argf);
14626 argf_block_call(rb_intern(
"each_codepoint"), 0, 0,
argf);
14657 return ARGF.filename;
14661argf_filename_getter(
ID id,
VALUE *var)
14663 return argf_filename(*var);
14688 return ARGF.current_file;
14707 ARGF_FORWARD(0, 0);
14728 return RBOOL(ARGF.binmode);
14748 if (ARGF.init_p && ARGF.next_p == 0) {
14777 if (ARGF.next_p != -1) {
14795 ARGF_FORWARD(0, 0);
14822 if (!ARGF.inplace)
return Qnil;
14830 return argf_inplace_mode_get(*var);
14861 ARGF.inplace =
Qnil;
14872 argf_inplace_mode_set(*var, val);
14876ruby_set_inplace_mode(
const char *suffix)
14902argf_argv_getter(
ID id,
VALUE *var)
14904 return argf_argv(*var);
14923 if (!
RTEST(ARGF.current_file)) {
14926 return GetWriteIO(ARGF.current_file);
14938 return rb_io_writev(argf_write_io(
argf), argc, argv);
14953 case RB_IO_WAIT_WRITABLE:
14956 c = rb_eEAGAINWaitWritable;
14958#if EAGAIN != EWOULDBLOCK
14960 c = rb_eEWOULDBLOCKWaitWritable;
14964 c = rb_eEINPROGRESSWaitWritable;
14970 case RB_IO_WAIT_READABLE:
14973 c = rb_eEAGAINWaitReadable;
14975#if EAGAIN != EWOULDBLOCK
14977 c = rb_eEWOULDBLOCKWaitReadable;
14981 c = rb_eEINPROGRESSWaitReadable;
14988 rb_bug(
"invalid read/write type passed to rb_readwrite_sys_fail: %d", waiting);
14994get_LAST_READ_LINE(
ID _x,
VALUE *_y)
15884#include <sys/cygwin.h>
15885 static struct __cygwin_perfile pf[] =
15887 {
"", O_RDONLY | O_BINARY},
15888 {
"", O_WRONLY | O_BINARY},
15889 {
"", O_RDWR | O_BINARY},
15890 {
"", O_APPEND | O_BINARY},
15893 cygwin_internal(CW_PERFILE, pf);
15942 rb_eEAGAINWaitReadable = rb_define_class_under(
rb_cIO,
"EAGAINWaitReadable", rb_eEAGAIN);
15945 rb_eEAGAINWaitWritable = rb_define_class_under(
rb_cIO,
"EAGAINWaitWritable", rb_eEAGAIN);
15947#if EAGAIN == EWOULDBLOCK
15949 rb_define_const(
rb_cIO,
"EWOULDBLOCKWaitReadable", rb_eEAGAINWaitReadable);
15951 rb_define_const(
rb_cIO,
"EWOULDBLOCKWaitWritable", rb_eEAGAINWaitWritable);
15954 rb_eEWOULDBLOCKWaitReadable = rb_define_class_under(
rb_cIO,
"EWOULDBLOCKWaitReadable", rb_eEWOULDBLOCK);
15957 rb_eEWOULDBLOCKWaitWritable = rb_define_class_under(
rb_cIO,
"EWOULDBLOCKWaitWritable", rb_eEWOULDBLOCK);
15961 rb_eEINPROGRESSWaitReadable = rb_define_class_under(
rb_cIO,
"EINPROGRESSWaitReadable", rb_eEINPROGRESS);
15964 rb_eEINPROGRESSWaitWritable = rb_define_class_under(
rb_cIO,
"EINPROGRESSWaitWritable", rb_eEINPROGRESS);
15999 rb_gvar_ractor_local(
"$/");
16001 rb_gvar_ractor_local(
"$-0");
16005 rb_gvar_ractor_local(
"$_");
16006 rb_gvar_box_dynamic(
"$_");
16122 rb_gvar_ractor_local(
"$stdin");
16123 rb_gvar_ractor_local(
"$stdout");
16124 rb_gvar_ractor_local(
"$>");
16125 rb_gvar_ractor_local(
"$stderr");
16127 rb_gvar_box_dynamic(
"$stdin");
16128 rb_gvar_box_dynamic(
"$stdout");
16129 rb_gvar_box_dynamic(
"$>");
16130 rb_gvar_box_dynamic(
"$stderr");
16151 rb_cARGF = rb_define_class(
"ARGF",
rb_cObject);
16216 rb_define_method(rb_cARGF,
"external_encoding", argf_external_encoding, 0);
16217 rb_define_method(rb_cARGF,
"internal_encoding", argf_internal_encoding, 0);
16236 rb_gvar_ractor_local(
"$-i");
16240#if defined (_WIN32) || defined(__CYGWIN__)
16241 atexit(pipe_atexit);
16253 sym_encoding =
ID2SYM(rb_id_encoding());
16277static void init_builtin_io(
void);
16278#define Init_builtin_io init_builtin_io
16280#undef Init_builtin_io
16283Init_builtin_io(
void)
#define RUBY_ASSERT(...)
Asserts that the given expression is truthy if and only if RUBY_DEBUG is truthy.
std::atomic< unsigned > rb_atomic_t
Type that is eligible for atomic operations.
unsigned long ruby_strtoul(const char *str, char **endptr, int base)
Our own locale-insensitive version of strtoul(3).
#define rb_define_method(klass, mid, func, arity)
Defines klass#mid.
#define rb_define_singleton_method(klass, mid, func, arity)
Defines klass.mid.
#define rb_define_global_function(mid, func, arity)
Defines rb_mKernel #mid.
void rb_include_module(VALUE klass, VALUE module)
Includes a module to a class.
VALUE rb_class_new(VALUE super)
Creates a new, anonymous class.
void rb_define_alias(VALUE klass, const char *name1, const char *name2)
Defines an alias of a method.
int rb_scan_args_kw(int kw_flag, int argc, const VALUE *argv, const char *fmt,...)
Identical to rb_scan_args(), except it also accepts kw_splat.
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Retrieves argument from argc and argv to given VALUE references according to the format string.
int rb_block_given_p(void)
Determines if the current method is given a block.
int rb_get_kwargs(VALUE keyword_hash, const ID *table, int required, int optional, VALUE *values)
Keyword argument deconstructor.
#define ECONV_AFTER_OUTPUT
Old name of RUBY_ECONV_AFTER_OUTPUT.
#define rb_str_new2
Old name of rb_str_new_cstr.
#define TYPE(_)
Old name of rb_type.
#define RB_INTEGER_TYPE_P
Old name of rb_integer_type_p.
#define ENC_CODERANGE_7BIT
Old name of RUBY_ENC_CODERANGE_7BIT.
#define T_FILE
Old name of RUBY_T_FILE.
#define ENC_CODERANGE_VALID
Old name of RUBY_ENC_CODERANGE_VALID.
#define ECONV_UNIVERSAL_NEWLINE_DECORATOR
Old name of RUBY_ECONV_UNIVERSAL_NEWLINE_DECORATOR.
#define REALLOC_N
Old name of RB_REALLOC_N.
#define OBJ_INIT_COPY(obj, orig)
Old name of RB_OBJ_INIT_COPY.
#define ALLOC
Old name of RB_ALLOC.
#define RFLOAT_VALUE
Old name of rb_float_value.
#define T_STRING
Old name of RUBY_T_STRING.
#define Qundef
Old name of RUBY_Qundef.
#define INT2FIX
Old name of RB_INT2FIX.
#define LEN2NUM
Old name of RB_LEN2NUM.
#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 CLASS_OF
Old name of rb_class_of.
#define rb_ary_new4
Old name of rb_ary_new_from_values.
#define ENCODING_MAXNAMELEN
Old name of RUBY_ENCODING_MAXNAMELEN.
#define MBCLEN_NEEDMORE_LEN(ret)
Old name of ONIGENC_MBCLEN_NEEDMORE_LEN.
#define ENCODING_GET(obj)
Old name of RB_ENCODING_GET.
#define 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 rb_exc_new3
Old name of rb_exc_new_str.
#define STRNCASECMP
Old name of st_locale_insensitive_strncasecmp.
#define MBCLEN_INVALID_P(ret)
Old name of ONIGENC_MBCLEN_INVALID_P.
#define ISASCII
Old name of rb_isascii.
#define ECONV_STATEFUL_DECORATOR_MASK
Old name of RUBY_ECONV_STATEFUL_DECORATOR_MASK.
#define Qtrue
Old name of RUBY_Qtrue.
#define MBCLEN_NEEDMORE_P(ret)
Old name of ONIGENC_MBCLEN_NEEDMORE_P.
#define ECONV_PARTIAL_INPUT
Old name of RUBY_ECONV_PARTIAL_INPUT.
#define NUM2INT
Old name of RB_NUM2INT.
#define ECONV_ERROR_HANDLER_MASK
Old name of RUBY_ECONV_ERROR_HANDLER_MASK.
#define INT2NUM
Old name of RB_INT2NUM.
#define Qnil
Old name of RUBY_Qnil.
#define Qfalse
Old name of RUBY_Qfalse.
#define FIX2LONG
Old name of RB_FIX2LONG.
#define ENC_CODERANGE_BROKEN
Old name of RUBY_ENC_CODERANGE_BROKEN.
#define T_ARRAY
Old name of RUBY_T_ARRAY.
#define NIL_P
Old name of RB_NIL_P.
#define ALLOCV_N
Old name of RB_ALLOCV_N.
#define MBCLEN_CHARFOUND_P(ret)
Old name of ONIGENC_MBCLEN_CHARFOUND_P.
#define NUM2CHR
Old name of RB_NUM2CHR.
#define NUM2LONG
Old name of RB_NUM2LONG.
#define UINT2NUM
Old name of RB_UINT2NUM.
#define FIXNUM_P
Old name of RB_FIXNUM_P.
#define NUM2LEN
Old name of RB_NUM2LEN.
#define ECONV_NEWLINE_DECORATOR_MASK
Old name of RUBY_ECONV_NEWLINE_DECORATOR_MASK.
#define CONST_ID
Old name of RUBY_CONST_ID.
#define rb_ary_new2
Old name of rb_ary_new_capa.
#define NUM2SIZET
Old name of RB_NUM2SIZE.
#define ENC_CODERANGE_SET(obj, cr)
Old name of RB_ENC_CODERANGE_SET.
#define rb_str_new4
Old name of rb_str_new_frozen.
#define ALLOCV_END
Old name of RB_ALLOCV_END.
#define SYMBOL_P
Old name of RB_SYMBOL_P.
#define ECONV_DEFAULT_NEWLINE_DECORATOR
Old name of RUBY_ECONV_DEFAULT_NEWLINE_DECORATOR.
void rb_category_warn(rb_warning_category_t category, const char *fmt,...)
Identical to rb_category_warning(), except it reports unless $VERBOSE is nil.
void rb_category_warning(rb_warning_category_t category, const char *fmt,...)
Identical to rb_warning(), except it takes additional "category" parameter.
VALUE rb_eNotImpError
NotImplementedError exception.
void rb_exc_raise(VALUE mesg)
Raises an exception in the current thread.
void rb_syserr_fail(int e, const char *mesg)
Raises appropriate exception that represents a C errno.
void rb_readwrite_syserr_fail(enum rb_io_wait_readwrite waiting, int n, const char *mesg)
Identical to rb_readwrite_sys_fail(), except it does not depend on C global variable errno.
VALUE rb_eIOError
IOError exception.
VALUE rb_eStandardError
StandardError exception.
void rb_mod_syserr_fail_str(VALUE mod, int e, VALUE mesg)
Identical to rb_mod_syserr_fail(), except it takes the message in Ruby's String instead of C's.
void rb_syserr_fail_str(int e, VALUE mesg)
Identical to rb_syserr_fail(), except it takes the message in Ruby's String instead of C's.
#define ruby_verbose
This variable controls whether the interpreter is in debug mode.
VALUE rb_eTypeError
TypeError exception.
VALUE rb_eEOFError
EOFError exception.
void rb_readwrite_sys_fail(enum rb_io_wait_readwrite waiting, const char *mesg)
Raises appropriate exception using the parameters.
void rb_iter_break_value(VALUE val)
Identical to rb_iter_break(), except it additionally takes the "value" of this breakage.
rb_io_wait_readwrite
for rb_readwrite_sys_fail first argument
VALUE rb_eRuntimeError
RuntimeError exception.
void rb_warn(const char *fmt,...)
Identical to rb_warning(), except it reports unless $VERBOSE is nil.
VALUE rb_eSystemCallError
SystemCallError exception.
@ RB_WARN_CATEGORY_DEPRECATED
Warning is for deprecated features.
VALUE rb_mKernel
Kernel module.
VALUE rb_check_to_int(VALUE val)
Identical to rb_check_to_integer(), except it uses #to_int for conversion.
VALUE rb_cObject
Object class.
VALUE rb_any_to_s(VALUE obj)
Generates a textual representation of the given object.
VALUE rb_obj_alloc(VALUE klass)
Allocates an instance of the given class.
VALUE rb_class_new_instance(int argc, const VALUE *argv, VALUE klass)
Allocates, then initialises an instance of the given class.
VALUE rb_class_new_instance_kw(int argc, const VALUE *argv, VALUE klass, int kw_splat)
Identical to rb_class_new_instance(), except you can specify how to handle the last element of the gi...
VALUE rb_mEnumerable
Enumerable module.
VALUE rb_stdin
STDIN constant.
VALUE rb_stderr
STDERR constant.
VALUE rb_obj_class(VALUE obj)
Queries the class of an object.
VALUE rb_obj_dup(VALUE obj)
Duplicates the given object.
VALUE rb_inspect(VALUE obj)
Generates a human-readable textual representation of the given object.
VALUE rb_mWaitReadable
IO::WaitReadable module.
VALUE rb_mWaitWritable
IO::WaitReadable module.
VALUE rb_obj_freeze(VALUE obj)
Same as RB_OBJ_FREEZE(), but returns the given object.
VALUE rb_check_to_integer(VALUE val, const char *mid)
Identical to rb_check_convert_type(), except the return value type is fixed to rb_cInteger.
VALUE rb_cFile
File class.
VALUE rb_stdout
STDOUT constant.
VALUE rb_to_int(VALUE val)
Identical to rb_check_to_int(), except it raises in case of conversion mismatch.
#define RB_OBJ_WRITTEN(old, oldv, young)
Identical to RB_OBJ_WRITE(), except it doesn't write any values, but only a WB declaration.
#define RB_OBJ_WRITE(old, slot, young)
Declaration of a "back" pointer.
VALUE rb_fiber_scheduler_current(void)
Identical to rb_fiber_scheduler_get(), except it also returns RUBY_Qnil in case of a blocking fiber.
VALUE rb_fiber_scheduler_make_timeout(struct timeval *timeout)
Converts the passed timeout to an expression that rb_fiber_scheduler_block() etc.
VALUE rb_fiber_scheduler_io_wait_readable(VALUE scheduler, VALUE io)
Non-blocking wait until the passed IO is ready for reading.
VALUE rb_fiber_scheduler_io_wait(VALUE scheduler, VALUE io, VALUE events, VALUE timeout)
Non-blocking version of rb_io_wait().
static ssize_t rb_fiber_scheduler_io_result_apply(VALUE result)
Apply an io result to the local thread, returning the value of the original system call that created ...
VALUE rb_fiber_scheduler_io_pread_memory(VALUE scheduler, VALUE io, rb_off_t from, void *base, size_t size)
Non-blocking pread from the passed IO using a native buffer.
VALUE rb_fiber_scheduler_io_selectv(VALUE scheduler, int argc, VALUE *argv)
Non-blocking version of IO.select, argv variant.
VALUE rb_fiber_scheduler_io_read_memory(VALUE scheduler, VALUE io, void *base, size_t size)
Non-blocking read from the passed IO using a native buffer.
VALUE rb_fiber_scheduler_current_for_thread(VALUE thread)
Identical to rb_fiber_scheduler_current(), except it queries for that of the passed thread value inst...
VALUE rb_fiber_scheduler_io_pwrite_memory(VALUE scheduler, VALUE io, rb_off_t from, const void *base, size_t size)
Non-blocking pwrite to the passed IO using a native buffer.
VALUE rb_fiber_scheduler_current_for_threadptr(struct rb_thread_struct *thread)
Identical to rb_fiber_scheduler_current_for_thread(), except it expects a threadptr instead of a thre...
VALUE rb_fiber_scheduler_io_wait_writable(VALUE scheduler, VALUE io)
Non-blocking wait until the passed IO is ready for writing.
VALUE rb_fiber_scheduler_io_close(VALUE scheduler, VALUE io)
Non-blocking close the given IO.
VALUE rb_fiber_scheduler_io_write_memory(VALUE scheduler, VALUE io, const void *base, size_t size)
Non-blocking write to the passed IO using a native buffer.
static unsigned int rb_enc_codepoint(const char *p, const char *e, rb_encoding *enc)
Queries the code point of character pointed by the passed pointer.
static int rb_enc_mbmaxlen(rb_encoding *enc)
Queries the maximum number of bytes that the passed encoding needs to represent a character.
VALUE rb_str_conv_enc(VALUE str, rb_encoding *from, rb_encoding *to)
Encoding conversion main routine.
rb_len_t 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.
VALUE rb_enc_uint_chr(unsigned int code, rb_encoding *enc)
Encodes the passed code point into a series of bytes.
int rb_econv_prepare_options(VALUE opthash, VALUE *ecopts, int ecflags)
Identical to rb_econv_prepare_opts(), except it additionally takes the initial value of flags.
VALUE rb_econv_open_exc(const char *senc, const char *denc, int ecflags)
Creates a rb_eConverterNotFoundError exception object (but does not raise).
rb_econv_result_t rb_econv_convert(rb_econv_t *ec, const unsigned char **source_buffer_ptr, const unsigned char *source_buffer_end, unsigned char **destination_buffer_ptr, unsigned char *destination_buffer_end, int flags)
Converts a string from an encoding to another.
rb_econv_result_t
return value of rb_econv_convert()
@ econv_incomplete_input
The conversion stopped in middle of reading a character, possibly due to a partial read of a socket e...
@ econv_finished
The conversion stopped after converting everything.
@ econv_undefined_conversion
The conversion stopped when it found a character in the input which cannot be representable in the ou...
@ econv_source_buffer_empty
The conversion stopped because there is no input.
@ econv_destination_buffer_full
The conversion stopped because there is no destination.
@ econv_invalid_byte_sequence
The conversion stopped when it found an invalid sequence.
int rb_econv_putbackable(rb_econv_t *ec)
Queries if rb_econv_putback() makes sense, i.e.
const char * rb_econv_asciicompat_encoding(const char *encname)
Queries the passed encoding's corresponding ASCII compatible encoding.
VALUE rb_econv_str_convert(rb_econv_t *ec, VALUE src, int flags)
Identical to rb_econv_convert(), except it takes Ruby's string instead of C's pointer.
rb_econv_t * rb_econv_open_opts(const char *source_encoding, const char *destination_encoding, int ecflags, VALUE ecopts)
Identical to rb_econv_open(), except it additionally takes a hash of optional strings.
void rb_econv_binmode(rb_econv_t *ec)
This badly named function does not set the destination encoding to binary, but instead just nullifies...
VALUE rb_str_encode(VALUE str, VALUE to, int ecflags, VALUE ecopts)
Converts the contents of the passed string from its encoding to the passed one.
VALUE rb_econv_make_exception(rb_econv_t *ec)
This function makes sense right after rb_econv_convert() returns.
void rb_econv_check_error(rb_econv_t *ec)
This is a rb_econv_make_exception() + rb_exc_raise() combo.
void rb_econv_close(rb_econv_t *ec)
Destructs a converter.
void rb_econv_putback(rb_econv_t *ec, unsigned char *p, int n)
Puts back the bytes.
VALUE rb_funcall(VALUE recv, ID mid, int n,...)
Calls a method.
VALUE rb_funcallv_kw(VALUE recv, ID mid, int argc, const VALUE *argv, int kw_splat)
Identical to rb_funcallv(), except you can specify how to handle the last element of the given array.
VALUE rb_funcallv(VALUE recv, ID mid, int argc, const VALUE *argv)
Identical to rb_funcall(), except it takes the method arguments as a C array.
Defines RBIMPL_HAS_BUILTIN.
VALUE rb_ary_concat(VALUE lhs, VALUE rhs)
Destructively appends the contents of latter into the end of former.
VALUE rb_ary_shift(VALUE ary)
Destructively deletes an element from the beginning of the passed array and returns what was deleted.
VALUE rb_ary_entry(VALUE ary, rb_len_t off)
Queries an element of an array.
VALUE rb_ary_new_capa(rb_len_t capa)
Identical to rb_ary_new(), except it additionally specifies how many rooms of objects it should alloc...
VALUE rb_check_array_type(VALUE obj)
Try converting an object to its array representation using its to_ary method, if any.
VALUE rb_ary_new(void)
Allocates a new, empty array.
VALUE rb_ary_push(VALUE ary, VALUE elem)
Special case of rb_ary_cat() that it adds only one element.
VALUE rb_assoc_new(VALUE car, VALUE cdr)
Identical to rb_ary_new_from_values(), except it expects exactly two parameters.
#define RETURN_ENUMERATOR(obj, argc, argv)
Identical to RETURN_SIZED_ENUMERATOR(), except its size is unknown.
static int rb_check_arity(int argc, int min, int max)
Ensures that the passed integer is in the passed range.
VALUE rb_io_printf(int argc, const VALUE *argv, VALUE io)
This is a rb_f_sprintf() + rb_io_write() combo.
VALUE rb_io_gets(VALUE io)
Reads a "line" from the given IO.
int rb_cloexec_pipe(int fildes[2])
Opens a pipe with closing on exec.
VALUE rb_io_print(int argc, const VALUE *argv, VALUE io)
Iterates over the passed array to apply rb_io_write() individually.
VALUE rb_io_addstr(VALUE io, VALUE str)
Identical to rb_io_write(), except it always returns the passed IO.
void rb_write_error2(const char *str, rb_len_t len)
Identical to rb_write_error(), except it additionally takes the message's length.
void rb_write_error(const char *str)
Writes the given error message to somewhere applicable.
VALUE rb_io_ungetbyte(VALUE io, VALUE b)
Identical to rb_io_ungetc(), except it doesn't take the encoding of the passed IO into account.
VALUE rb_io_getbyte(VALUE io)
Reads a byte from the given IO.
int rb_cloexec_dup2(int oldfd, int newfd)
Identical to rb_cloexec_dup(), except you can specify the destination file descriptor.
VALUE rb_io_fdopen(int fd, int flags, const char *path)
Creates an IO instance whose backend is the given file descriptor.
void rb_update_max_fd(int fd)
Informs the interpreter that the passed fd can be the max.
int rb_cloexec_open(const char *pathname, int flags, mode_t mode)
Opens a file that closes on exec.
VALUE rb_output_rs
The record separator character for outputs, or the $\.
VALUE rb_io_eof(VALUE io)
Queries if the passed IO is at the end of file.
void rb_close_before_exec(int lowfd, int maxhint, VALUE noclose_fds)
Closes everything.
int rb_reserved_fd_p(int fd)
Queries if the given FD is reserved or not.
void rb_fd_fix_cloexec(int fd)
Sets or clears the close-on-exec flag of the passed file descriptor to the desired state.
VALUE rb_io_ascii8bit_binmode(VALUE io)
Forces no conversions be applied to the passed IO.
VALUE rb_io_binmode(VALUE io)
Sets the binmode.
VALUE rb_io_ungetc(VALUE io, VALUE c)
"Unget"s a string.
int rb_pipe(int *pipes)
This is an rb_cloexec_pipe() + rb_update_max_fd() combo.
VALUE rb_gets(void)
Much like rb_io_gets(), but it reads from the mysterious ARGF object.
int rb_cloexec_fcntl_dupfd(int fd, int minfd)
Duplicates a file descriptor with closing on exec.
VALUE rb_output_fs
The field separator character for outputs, or the $,.
VALUE rb_file_open_str(VALUE fname, const char *fmode)
Identical to rb_file_open(), except it takes the pathname as a Ruby's string instead of C's.
int rb_cloexec_dup(int oldfd)
Identical to rb_cloexec_fcntl_dupfd(), except it implies minfd is 3.
VALUE rb_file_open(const char *fname, const char *fmode)
Opens a file located at the given path.
VALUE rb_io_close(VALUE io)
Closes the IO.
VALUE rb_default_rs
This is the default value of rb_rs, i.e.
void rb_provide(const char *feature)
Declares that the given feature is already provided by someone else.
void rb_lastline_set(VALUE str)
Updates $_.
VALUE rb_lastline_get(void)
Queries the last line, or the $_.
int rb_obj_method_arity(VALUE obj, ID mid)
Identical to rb_mod_method_arity(), except it searches for singleton methods rather than instance met...
rb_pid_t rb_waitpid(rb_pid_t pid, int *status, int flags)
Waits for a process, with releasing GVL.
void rb_last_status_set(int status, rb_pid_t pid)
Sets the "last status", or the $?.
void rb_str_modify_expand(VALUE str, rb_len_t capa)
Identical to rb_str_modify(), except it additionally expands the capacity of the receiver.
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.
void rb_str_set_len(VALUE str, rb_len_t len)
Overwrites the length of the string.
VALUE rb_str_dup(VALUE str)
Duplicates a string.
VALUE rb_str_cat(VALUE dst, const char *src, rb_len_t srclen)
Destructively appends the passed contents to the string.
VALUE rb_str_locktmp(VALUE str)
Obtains a "temporary lock" of the string.
VALUE rb_str_no_gvl_safe_acquire(VALUE orig)
Creates a frozen copy of orig that guarantees the RSTRING_PTR is safe to use in operations that relea...
VALUE rb_str_equal(VALUE str1, VALUE str2)
Equality of two strings.
void rb_str_no_gvl_safe_release(VALUE orig, VALUE tmp)
Releases a string created from rb_str_no_gvl_safe_acquire.
VALUE rb_str_substr(VALUE str, rb_len_t beg, rb_len_t len)
This is the implementation of two-argumented String#slice.
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_str_buf_new(rb_len_t capa)
Allocates a "string buffer".
VALUE rb_check_string_type(VALUE obj)
Try converting an object to its stringised representation using its to_str method,...
VALUE rb_str_unlocktmp(VALUE str)
Releases a lock formerly obtained by rb_str_locktmp().
#define rb_str_new_cstr(str)
Identical to rb_str_new, except it assumes the passed pointer is a pointer to a C string.
VALUE rb_obj_as_string(VALUE obj)
Try converting an object to its stringised representation using its to_s method, if any.
int rb_thread_interrupted(VALUE thval)
Checks if the thread's execution was recently interrupted.
VALUE rb_mutex_new(void)
Creates a mutex.
int rb_thread_fd_writable(int fd)
Identical to rb_thread_wait_fd(), except it blocks the current thread until the given file descriptor...
VALUE rb_exec_recursive(VALUE(*f)(VALUE g, VALUE h, int r), VALUE g, VALUE h)
"Recursion" API entry point.
VALUE rb_mutex_synchronize(VALUE mutex, VALUE(*func)(VALUE arg), VALUE arg)
Obtains the lock, runs the passed function, and releases the lock when it completes.
void rb_thread_check_ints(void)
Checks for interrupts.
VALUE rb_thread_current(void)
Obtains the "current" thread.
int rb_thread_wait_fd(int fd)
Blocks the current thread until the given file descriptor is ready to be read.
void rb_thread_sleep(int sec)
Blocks for the given period of time.
struct timeval rb_time_interval(VALUE num)
Creates a "time interval".
void rb_set_class_path(VALUE klass, VALUE space, const char *name)
Names a class.
VALUE rb_ivar_set(VALUE obj, ID name, VALUE val)
Identical to rb_iv_set(), except it accepts the name as an ID instead of a C string.
VALUE rb_class_name(VALUE obj)
Queries the name of the given object's class.
int rb_respond_to(VALUE obj, ID mid)
Queries if the object responds to the method.
int rb_method_basic_definition_p(VALUE klass, ID mid)
Well... Let us hesitate from describing what a "basic definition" is.
VALUE rb_check_funcall(VALUE recv, ID mid, int argc, const VALUE *argv)
Identical to rb_funcallv(), except it returns RUBY_Qundef instead of raising rb_eNoMethodError.
void rb_define_alloc_func(VALUE klass, rb_alloc_func_t func)
Sets the allocator function of a class.
static ID rb_intern_const(const char *str)
This is a "tiny optimisation" over rb_intern().
#define RB_ID2SYM
Just another name of rb_id2sym.
void rb_define_global_const(const char *name, VALUE val)
Identical to rb_define_const(), except it defines that of "global", i.e.
void rb_define_readonly_variable(const char *name, const VALUE *var)
Identical to rb_define_variable(), except it does not allow Ruby programs to assign values to such gl...
rb_gvar_setter_t rb_gvar_readonly_setter
This function just raises rb_eNameError.
#define FMODE_READABLE
The IO is opened for reading.
enum rb_io_mode rb_io_modestr_fmode(const char *modestr)
Maps a file mode string (that rb_file_open() takes) into a mixture of FMODE_ flags.
VALUE rb_io_get_io(VALUE io)
Identical to rb_io_check_io(), except it raises exceptions on conversion failures.
VALUE rb_io_timeout(VALUE io)
Get the timeout associated with the specified io object.
VALUE rb_io_taint_check(VALUE obj)
void rb_io_read_check(rb_io_t *fptr)
Blocks until there is a pending read in the passed IO.
int rb_io_modestr_oflags(const char *modestr)
Identical to rb_io_modestr_fmode(), except it returns a mixture of O_ flags.
#define FMODE_SETENC_BY_BOM
This flag amends the encoding of the IO so that the BOM of the contents of the IO takes effect.
rb_io_event
Type of events that an IO can wait.
@ RUBY_IO_READABLE
IO::READABLE
@ RUBY_IO_PRIORITY
IO::PRIORITY
@ RUBY_IO_WRITABLE
IO::WRITABLE
#define FMODE_READWRITE
The IO is opened for both read/write.
#define FMODE_EXTERNAL
This flag means that an IO object is wrapping an "external" file descriptor, which is owned by someth...
#define GetOpenFile
This is an old name of RB_IO_POINTER.
void rb_io_check_byte_readable(rb_io_t *fptr)
Asserts that an IO is opened for byte-based reading.
#define FMODE_TTY
The IO is a TTY.
#define FMODE_CREATE
The IO is opened for creating.
void rb_io_check_readable(rb_io_t *fptr)
Just another name of rb_io_check_byte_readable.
int rb_wait_for_single_fd(int fd, int events, struct timeval *tv)
Blocks until the passed file descriptor is ready for the passed events.
FILE * rb_fdopen(int fd, const char *modestr)
Identical to rb_io_stdio_file(), except it takes file descriptors instead of Ruby's IO.
int rb_io_extract_encoding_option(VALUE opt, rb_encoding **enc_p, rb_encoding **enc2_p, enum rb_io_mode *fmode_p)
This function breaks down the option hash that IO#initialize takes into components.
int rb_io_descriptor(VALUE io)
Returns an integer representing the numeric file descriptor for io.
#define FMODE_WRITABLE
The IO is opened for writing.
FILE * rb_io_stdio_file(rb_io_t *fptr)
Finds or creates a stdio's file structure from a Ruby's one.
#define FMODE_APPEND
The IO is opened for appending.
#define MakeOpenFile
This is an old name of RB_IO_OPEN.
#define FMODE_DUPLEX
Ruby eventually detects that the IO is bidirectional.
#define FMODE_BINMODE
The IO is in "binary mode".
int rb_io_maybe_wait_readable(int error, VALUE io, VALUE timeout)
Blocks until the passed IO is ready for reading, if that makes sense for the passed errno.
int capa
Designed capacity of the buffer.
#define RB_IO_POINTER(obj, fp)
Queries the underlying IO pointer.
VALUE rb_io_maybe_wait(int error, VALUE io, VALUE events, VALUE timeout)
Identical to rb_io_wait() except it additionally takes previous errno.
VALUE rb_eIOTimeoutError
Indicates that a timeout has occurred while performing an IO operation.
char * ptr
Pointer to the underlying memory region, of at least capa bytes.
#define FMODE_SYNC
The IO is in "sync mode".
int off
Offset inside of ptr.
VALUE rb_io_path(VALUE io)
Returns the path for the given IO.
void rb_io_extract_modeenc(VALUE *vmode_p, VALUE *vperm_p, VALUE opthash, int *oflags_p, enum rb_io_mode *fmode_p, rb_io_enc_t *convconfig_p)
This function can be seen as an extended version of rb_io_extract_encoding_option() that not only con...
void rb_io_check_initialized(rb_io_t *fptr)
Asserts that the passed IO is initialised.
#define FMODE_EXCL
This flag amends the effect of FMODE_CREATE, so that if there already is a file at the given path the...
#define FMODE_TEXTMODE
The IO is in "text mode".
int rb_io_fptr_finalize(rb_io_t *fptr)
Destroys the given IO.
VALUE rb_io_check_io(VALUE io)
Try converting an object to its IO representation using its to_io method, if any.
VALUE rb_io_closed_p(VALUE io)
Returns whether or not the underlying IO is closed.
VALUE rb_io_set_timeout(VALUE io, VALUE timeout)
Set the timeout associated with the specified io object.
ssize_t rb_io_bufwrite(VALUE io, const void *buf, size_t size)
Buffered write to the passed IO.
void rb_io_check_char_readable(rb_io_t *fptr)
Asserts that an IO is opened for character-based reading.
#define FMODE_TRUNC
This flag amends the effect of FMODE_CREATE, so that if there already is a file at the given path it ...
VALUE rb_io_get_write_io(VALUE io)
Queries the tied IO for writing.
void rb_io_set_nonblock(rb_io_t *fptr)
Instructs the OS to put its internal file structure into "nonblocking mode".
int rb_io_wait_writable(int fd)
Blocks until the passed file descriptor gets writable.
VALUE rb_io_open_descriptor(VALUE klass, int descriptor, int mode, VALUE path, VALUE timeout, struct rb_io_encoding *encoding)
Allocate a new IO object, with the given file descriptor.
VALUE rb_io_set_write_io(VALUE io, VALUE w)
Assigns the tied IO for writing.
void rb_io_check_writable(rb_io_t *fptr)
Asserts that an IO is opened for writing.
int rb_io_maybe_wait_writable(int error, VALUE io, VALUE timeout)
Blocks until the passed IO is ready for writing, if that makes sense for the passed errno.
void rb_io_check_closed(rb_io_t *fptr)
This badly named function asserts that the passed IO is open.
int rb_io_wait_readable(int fd)
Blocks until the passed file descriptor gets readable.
void rb_io_synchronized(rb_io_t *fptr)
Sets FMODE_SYNC.
VALUE rb_io_wait(VALUE io, VALUE events, VALUE timeout)
Blocks until the passed IO is ready for the passed events.
int len
Length of the buffer.
VALUE rb_ractor_stdin(void)
Queries the standard input of the current Ractor that is calling this function.
void rb_ractor_stderr_set(VALUE io)
Assigns an IO to the standard error of the Ractor that is calling this function.
void rb_ractor_stdout_set(VALUE io)
Assigns an IO to the standard output of the Ractor that is calling this function.
void rb_ractor_stdin_set(VALUE io)
Assigns an IO to the standard input of the Ractor that is calling this function.
void * rb_thread_call_with_gvl(void *(*func)(void *), void *data1)
(Re-)acquires the GVL.
#define RB_NUM2INT
Just another name of rb_num2int_inline.
#define RB_INT2NUM
Just another name of rb_int2num_inline.
VALUE rb_f_sprintf(int argc, const VALUE *argv)
Identical to rb_str_format(), except how the arguments are arranged.
#define RB_BLOCK_CALL_FUNC_ARGLIST(yielded_arg, callback_arg)
Shim for block function parameters.
VALUE rb_yield_values2(int n, const VALUE *argv)
Identical to rb_yield_values(), except it takes the parameters as a C array instead of variadic argum...
VALUE rb_yield(VALUE val)
Yields the block.
void rb_fd_term(rb_fdset_t *f)
Destroys the rb_fdset_t, releasing any memory and resources it used.
#define MEMZERO(p, type, n)
Handy macro to erase a region of memory.
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
#define MEMMOVE(p1, p2, type, n)
Handy macro to call memmove.
#define NUM2MODET
Converts a C's mode_t into an instance of rb_cInteger.
void rb_define_hooked_variable(const char *q, VALUE *w, type *e, void_type *r)
Define a function-backended global variable.
void rb_define_virtual_variable(const char *q, type *w, void_type *e)
Define a function-backended global variable.
VALUE rb_rescue2(type *q, VALUE w, type *e, VALUE r,...)
An equivalent of rescue clause.
VALUE rb_ensure(type *q, VALUE w, type *e, VALUE r)
An equivalent of ensure clause.
#define PRI_OFFT_PREFIX
A rb_sprintf() format prefix to be used for an off_t parameter.
#define OFFT2NUM
Converts a C's off_t into an instance of rb_cInteger.
#define NUM2OFFT
Converts an instance of rb_cNumeric into C's off_t.
#define PIDT2NUM
Converts a C's pid_t into an instance of rb_cInteger.
#define rb_fd_isset
Queries if the given fd is in the rb_fdset_t.
#define rb_fd_select
Waits for multiple file descriptors at once.
#define rb_fd_init
Initialises the :given :rb_fdset_t.
#define rb_fd_set
Sets the given fd to the rb_fdset_t.
#define RARRAY_LEN
Just another name of rb_array_len.
static int RARRAY_LENINT(VALUE ary)
Identical to rb_array_len(), except it differs for the return type.
#define RARRAY_AREF(a, i)
References an object in an array.
#define RARRAY_CONST_PTR
Just another name of rb_array_const_ptr.
#define RFILE(obj)
Convenient casting macro.
#define StringValue(v)
Ensures that the parameter object is a String.
static char * RSTRING_END(VALUE str)
Queries the end of the contents pointer of the string.
#define RSTRING_GETMEM(str, ptrvar, lenvar)
Convenient macro to obtain the contents and length at once.
#define StringValueCStr(v)
Identical to StringValuePtr, except it additionally checks for the contents for viability as a C stri...
#define RUBY_TYPED_DEFAULT_FREE
This is a value you can set to rb_data_type_struct::dfree.
#define TypedData_Make_Struct(klass, type, data_type, sval)
Identical to TypedData_Wrap_Struct, except it allocates a new data region internally instead of takin...
VALUE rb_get_argv(void)
Queries the arguments passed to the current process that you can access from Ruby as ARGV.
void rb_p(VALUE obj)
Inspects an object.
#define FilePathValue(v)
Ensures that the parameter object is a path.
#define errno
Ractor-aware version of errno.
#define RB_SCAN_ARGS_LAST_HASH_KEYWORDS
Treat a final argument as keywords if it is a hash, and not as keywords otherwise.
#define RB_PASS_CALLED_KEYWORDS
Pass keywords if current method is called with keywords, useful for argument delegation.
int rb_thread_fd_select(int nfds, rb_fdset_t *rfds, rb_fdset_t *wfds, rb_fdset_t *efds, struct timeval *timeout)
Waits for multiple file descriptors at once.
static bool RB_TEST(VALUE obj)
Emulates Ruby's "if" statement.
#define RTEST
This is an old name of RB_TEST.
#define _(args)
This was a transition path from K&R to ANSI.
This is the struct that holds necessary info for a struct.
The data structure which wraps the fd_set bitmap used by select(2).
Decomposed encoding flags (e.g.
VALUE ecopts
Flags as Ruby hash.
rb_encoding * enc2
External encoding.
rb_encoding * enc
Internal encoding.
char * ptr
Pointer to the underlying memory region, of at least capa bytes.
int off
Offset inside of ptr.
int len
Length of the buffer.
int capa
Designed capacity of the buffer.
Ruby's IO, metadata and buffers.
rb_io_buffer_t wbuf
Write buffer.
enum rb_io_mode mode
mode flags: FMODE_XXXs
void(* finalize)(struct rb_io *, int)
finalize proc
rb_econv_t * readconv
Encoding converter used when reading from this IO.
rb_econv_t * writeconv
Encoding converter used when writing to this IO.
struct rb_io_encoding encs
Decomposed encoding flags.
VALUE self
The IO's Ruby level counterpart.
VALUE write_lock
This is a Ruby level mutex.
VALUE timeout
The timeout associated with this IO when performing blocking operations.
FILE * stdio_file
stdio ptr for read/write, if available.
VALUE writeconv_pre_ecopts
Value of ::rb_io_t::rb_io_enc_t::ecopts stored right before initialising rb_io_t::writeconv.
VALUE tied_io_for_writing
Duplex IO object, if set.
int writeconv_initialized
Whether rb_io_t::writeconv is already set up.
rb_io_buffer_t rbuf
(Byte) read buffer.
int lineno
number of lines read
struct ccan_list_head blocking_operations
Threads that are performing a blocking operation without the GVL using this IO.
VALUE writeconv_asciicompat
This is, when set, an instance of rb_cString which holds the "common" encoding.
rb_io_buffer_t cbuf
rb_io_ungetc() destination.
rb_pid_t pid
child's pid (for pipes)
int writeconv_pre_ecflags
Value of ::rb_io_t::rb_io_enc_t::ecflags stored right before initialising rb_io_t::writeconv.
VALUE pathv
pathname for file
long rb_len_t
A signed integer type for lengths and indices of objects such as String and Array.
#define RB_LEN_MAX
Maximum possible value that a rb_len_t can take.
intptr_t SIGNED_VALUE
A signed integer type that has the same width with VALUE.
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
uintptr_t VALUE
Type that represents a Ruby object.
static bool RB_FLOAT_TYPE_P(VALUE obj)
Queries if the object is an instance of rb_cFloat.
static bool RB_SYMBOL_P(VALUE obj)
Queries if the object is an instance of rb_cSymbol.
static void Check_Type(VALUE v, enum ruby_value_type t)
Identical to RB_TYPE_P(), except it raises exceptions on predication failure.
static bool RB_TYPE_P(VALUE obj, enum ruby_value_type t)
Queries if the given object is of given type.
#define RBIMPL_WARNING_IGNORED(flag)
Suppresses a warning.
#define RBIMPL_WARNING_PUSH()
Pushes compiler warning state.
#define RBIMPL_WARNING_POP()
Pops compiler warning state.