Ruby 3.5.0dev (2025-10-30 revision 15f2dcceb4787c5738dde48f580019c3765ce1b8)
io.c (15f2dcceb4787c5738dde48f580019c3765ce1b8)
1/**********************************************************************
2
3 io.c -
4
5 $Author$
6 created at: Fri Oct 15 18:08:59 JST 1993
7
8 Copyright (C) 1993-2007 Yukihiro Matsumoto
9 Copyright (C) 2000 Network Applied Communication Laboratory, Inc.
10 Copyright (C) 2000 Information-technology Promotion Agency, Japan
11
12**********************************************************************/
13
14#include "ruby/internal/config.h"
15
17#include "ruby/io/buffer.h"
18
19#include <ctype.h>
20#include <errno.h>
21#include <stddef.h>
22
23/* non-Linux poll may not work on all FDs */
24#if defined(HAVE_POLL)
25# if defined(__linux__)
26# define USE_POLL 1
27# endif
28# if defined(__FreeBSD_version) && __FreeBSD_version >= 1100000
29# define USE_POLL 1
30# endif
31#endif
32
33#ifndef USE_POLL
34# define USE_POLL 0
35#endif
36
37#undef free
38#define free(x) xfree(x)
39
40#if defined(DOSISH) || defined(__CYGWIN__)
41#include <io.h>
42#endif
43
44#include <sys/types.h>
45#if defined HAVE_NET_SOCKET_H
46# include <net/socket.h>
47#elif defined HAVE_SYS_SOCKET_H
48# include <sys/socket.h>
49#endif
50
51#if defined(__BOW__) || defined(__CYGWIN__) || defined(_WIN32)
52# define NO_SAFE_RENAME
53#endif
54
55#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__sun) || defined(_nec_ews)
56# define USE_SETVBUF
57#endif
58
59#ifdef __QNXNTO__
60#include <unix.h>
61#endif
62
63#include <sys/types.h>
64#if defined(HAVE_SYS_IOCTL_H) && !defined(_WIN32)
65#include <sys/ioctl.h>
66#endif
67#if defined(HAVE_FCNTL_H) || defined(_WIN32)
68#include <fcntl.h>
69#elif defined(HAVE_SYS_FCNTL_H)
70#include <sys/fcntl.h>
71#endif
72
73#ifdef HAVE_SYS_TIME_H
74# include <sys/time.h>
75#endif
76
77#include <sys/stat.h>
78
79#if defined(HAVE_SYS_PARAM_H) || defined(__HIUX_MPP__)
80# include <sys/param.h>
81#endif
82
83#if !defined NOFILE
84# define NOFILE 64
85#endif
86
87#ifdef HAVE_UNISTD_H
88#include <unistd.h>
89#endif
90
91#ifdef HAVE_SYSCALL_H
92#include <syscall.h>
93#elif defined HAVE_SYS_SYSCALL_H
94#include <sys/syscall.h>
95#endif
96
97#ifdef HAVE_SYS_UIO_H
98#include <sys/uio.h>
99#endif
100
101#ifdef HAVE_SYS_WAIT_H
102# include <sys/wait.h> /* for WNOHANG on BSD */
103#endif
104
105#ifdef HAVE_COPYFILE_H
106# include <copyfile.h>
107
108# ifndef COPYFILE_STATE_COPIED
109/*
110 * Some OSes (e.g., OSX < 10.6) implement fcopyfile() but not
111 * COPYFILE_STATE_COPIED. Since the only use of the former here
112 * requires the latter, we disable the former when the latter is undefined.
113 */
114# undef HAVE_FCOPYFILE
115# endif
116
117#endif
118
120#include "ccan/list/list.h"
121#include "dln.h"
122#include "encindex.h"
123#include "id.h"
124#include "internal.h"
125#include "internal/class.h"
126#include "internal/encoding.h"
127#include "internal/error.h"
128#include "internal/inits.h"
129#include "internal/io.h"
130#include "internal/numeric.h"
131#include "internal/object.h"
132#include "internal/process.h"
133#include "internal/thread.h"
134#include "internal/transcode.h"
135#include "internal/variable.h"
136#include "ruby/io.h"
137#include "ruby/io/buffer.h"
138#include "ruby/missing.h"
139#include "ruby/thread.h"
140#include "ruby/util.h"
141#include "ruby_atomic.h"
142#include "ruby/ractor.h"
143
144#if !USE_POLL
145# include "vm_core.h"
146#endif
147
148#include "builtin.h"
149
150#ifndef O_ACCMODE
151#define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR)
152#endif
153
154#ifndef PIPE_BUF
155# ifdef _POSIX_PIPE_BUF
156# define PIPE_BUF _POSIX_PIPE_BUF
157# else
158# define PIPE_BUF 512 /* is this ok? */
159# endif
160#endif
161
162#ifndef EWOULDBLOCK
163# define EWOULDBLOCK EAGAIN
164#endif
165
166#if defined(HAVE___SYSCALL) && (defined(__APPLE__) || defined(__OpenBSD__))
167/* Mac OS X and OpenBSD have __syscall but don't define it in headers */
168off_t __syscall(quad_t number, ...);
169#endif
170
171#define IO_RBUF_CAPA_MIN 8192
172#define IO_CBUF_CAPA_MIN (128*1024)
173#define IO_RBUF_CAPA_FOR(fptr) (NEED_READCONV(fptr) ? IO_CBUF_CAPA_MIN : IO_RBUF_CAPA_MIN)
174#define IO_WBUF_CAPA_MIN 8192
175
176#define IO_MAX_BUFFER_GROWTH 8 * 1024 * 1024 // 8MB
177
178/* define system APIs */
179#ifdef _WIN32
180#undef open
181#define open rb_w32_uopen
182#undef rename
183#define rename(f, t) rb_w32_urename((f), (t))
184#include "win32/file.h"
185#endif
186
193
194static VALUE rb_eEAGAINWaitReadable;
195static VALUE rb_eEAGAINWaitWritable;
196static VALUE rb_eEWOULDBLOCKWaitReadable;
197static VALUE rb_eEWOULDBLOCKWaitWritable;
198static VALUE rb_eEINPROGRESSWaitWritable;
199static VALUE rb_eEINPROGRESSWaitReadable;
200
202static VALUE orig_stdout, orig_stderr;
203
205VALUE rb_rs;
208
209static VALUE argf;
210
211static ID id_write, id_read, id_getc, id_flush, id_readpartial, id_set_encoding, id_fileno;
212static VALUE sym_mode, sym_perm, sym_flags, sym_extenc, sym_intenc, sym_encoding, sym_open_args;
213static VALUE sym_textmode, sym_binmode, sym_autoclose;
214static VALUE sym_SET, sym_CUR, sym_END;
215static VALUE sym_wait_readable, sym_wait_writable;
216#ifdef SEEK_DATA
217static VALUE sym_DATA;
218#endif
219#ifdef SEEK_HOLE
220static VALUE sym_HOLE;
221#endif
222
223static VALUE prep_io(int fd, enum rb_io_mode fmode, VALUE klass, const char *path);
224
225VALUE
226rb_io_blocking_region_wait(struct rb_io *io, rb_blocking_function_t *function, void *argument, enum rb_io_event events)
227{
228 return rb_thread_io_blocking_call(io, function, argument, events);
229}
230
231VALUE rb_io_blocking_region(struct rb_io *io, rb_blocking_function_t *function, void *argument)
232{
233 return rb_io_blocking_region_wait(io, function, argument, 0);
234}
235
236struct argf {
237 VALUE filename, current_file;
238 long last_lineno; /* $. */
239 long lineno;
240 VALUE argv;
241 VALUE inplace;
242 struct rb_io_encoding encs;
243 int8_t init_p, next_p, binmode;
244};
245
246static rb_atomic_t max_file_descriptor = NOFILE;
247void
249{
250 rb_atomic_t afd = (rb_atomic_t)fd;
251 rb_atomic_t max_fd = max_file_descriptor;
252 int err;
253
254 if (fd < 0 || afd <= max_fd)
255 return;
256
257#if defined(HAVE_FCNTL) && defined(F_GETFL)
258 err = fcntl(fd, F_GETFL) == -1;
259#else
260 {
261 struct stat buf;
262 err = fstat(fd, &buf) != 0;
263 }
264#endif
265 if (err && errno == EBADF) {
266 rb_bug("rb_update_max_fd: invalid fd (%d) given.", fd);
267 }
268
269 while (max_fd < afd) {
270 max_fd = ATOMIC_CAS(max_file_descriptor, max_fd, afd);
271 }
272}
273
274void
275rb_maygvl_fd_fix_cloexec(int fd)
276{
277 /* MinGW don't have F_GETFD and FD_CLOEXEC. [ruby-core:40281] */
278#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
279 int flags, flags2, ret;
280 flags = fcntl(fd, F_GETFD); /* should not fail except EBADF. */
281 if (flags == -1) {
282 rb_bug("rb_maygvl_fd_fix_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(errno));
283 }
284 if (fd <= 2)
285 flags2 = flags & ~FD_CLOEXEC; /* Clear CLOEXEC for standard file descriptors: 0, 1, 2. */
286 else
287 flags2 = flags | FD_CLOEXEC; /* Set CLOEXEC for non-standard file descriptors: 3, 4, 5, ... */
288 if (flags != flags2) {
289 ret = fcntl(fd, F_SETFD, flags2);
290 if (ret != 0) {
291 rb_bug("rb_maygvl_fd_fix_cloexec: fcntl(%d, F_SETFD, %d) failed: %s", fd, flags2, strerror(errno));
292 }
293 }
294#endif
295}
296
297void
299{
300 rb_maygvl_fd_fix_cloexec(fd);
302}
303
304/* this is only called once */
305static int
306rb_fix_detect_o_cloexec(int fd)
307{
308#if defined(O_CLOEXEC) && defined(F_GETFD)
309 int flags = fcntl(fd, F_GETFD);
310
311 if (flags == -1)
312 rb_bug("rb_fix_detect_o_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(errno));
313
314 if (flags & FD_CLOEXEC)
315 return 1;
316#endif /* fall through if O_CLOEXEC does not work: */
317 rb_maygvl_fd_fix_cloexec(fd);
318 return 0;
319}
320
321static inline bool
322io_again_p(int e)
323{
324 return (e == EWOULDBLOCK) || (e == EAGAIN);
325}
326
327int
328rb_cloexec_open(const char *pathname, int flags, mode_t mode)
329{
330 int ret;
331 static int o_cloexec_state = -1; /* <0: unknown, 0: ignored, >0: working */
332
333 static const int retry_interval = 0;
334 static const int retry_max_count = 10000;
335
336 int retry_count = 0;
337
338#ifdef O_CLOEXEC
339 /* O_CLOEXEC is available since Linux 2.6.23. Linux 2.6.18 silently ignore it. */
340 flags |= O_CLOEXEC;
341#elif defined O_NOINHERIT
342 flags |= O_NOINHERIT;
343#endif
344
345 while ((ret = open(pathname, flags, mode)) == -1) {
346 int e = errno;
347 if (!io_again_p(e)) break;
348 if (retry_count++ >= retry_max_count) break;
349
350 sleep(retry_interval);
351 }
352
353 if (ret < 0) return ret;
354 if (ret <= 2 || o_cloexec_state == 0) {
355 rb_maygvl_fd_fix_cloexec(ret);
356 }
357 else if (o_cloexec_state > 0) {
358 return ret;
359 }
360 else {
361 o_cloexec_state = rb_fix_detect_o_cloexec(ret);
362 }
363 return ret;
364}
365
366int
368{
369 /* Don't allocate standard file descriptors: 0, 1, 2 */
370 return rb_cloexec_fcntl_dupfd(oldfd, 3);
371}
372
373int
374rb_cloexec_dup2(int oldfd, int newfd)
375{
376 int ret;
377
378 /* When oldfd == newfd, dup2 succeeds but dup3 fails with EINVAL.
379 * rb_cloexec_dup2 succeeds as dup2. */
380 if (oldfd == newfd) {
381 ret = newfd;
382 }
383 else {
384#if defined(HAVE_DUP3) && defined(O_CLOEXEC)
385 static int try_dup3 = 1;
386 if (2 < newfd && try_dup3) {
387 ret = dup3(oldfd, newfd, O_CLOEXEC);
388 if (ret != -1)
389 return ret;
390 /* dup3 is available since Linux 2.6.27, glibc 2.9. */
391 if (errno == ENOSYS) {
392 try_dup3 = 0;
393 ret = dup2(oldfd, newfd);
394 }
395 }
396 else {
397 ret = dup2(oldfd, newfd);
398 }
399#else
400 ret = dup2(oldfd, newfd);
401#endif
402 if (ret < 0) return ret;
403 }
404 rb_maygvl_fd_fix_cloexec(ret);
405 return ret;
406}
407
408static int
409rb_fd_set_nonblock(int fd)
410{
411#ifdef _WIN32
412 return rb_w32_set_nonblock(fd);
413#elif defined(F_GETFL)
414 int oflags = fcntl(fd, F_GETFL);
415
416 if (oflags == -1)
417 return -1;
418 if (oflags & O_NONBLOCK)
419 return 0;
420 oflags |= O_NONBLOCK;
421 return fcntl(fd, F_SETFL, oflags);
422#endif
423 return 0;
424}
425
426int
427rb_cloexec_pipe(int descriptors[2])
428{
429#ifdef HAVE_PIPE2
430 int result = pipe2(descriptors, O_CLOEXEC | O_NONBLOCK);
431#else
432 int result = pipe(descriptors);
433#endif
434
435 if (result < 0)
436 return result;
437
438#ifdef __CYGWIN__
439 if (result == 0 && descriptors[1] == -1) {
440 close(descriptors[0]);
441 descriptors[0] = -1;
442 errno = ENFILE;
443 return -1;
444 }
445#endif
446
447#ifndef HAVE_PIPE2
448 rb_maygvl_fd_fix_cloexec(descriptors[0]);
449 rb_maygvl_fd_fix_cloexec(descriptors[1]);
450
451#ifndef _WIN32
452 rb_fd_set_nonblock(descriptors[0]);
453 rb_fd_set_nonblock(descriptors[1]);
454#endif
455#endif
456
457 return result;
458}
459
460int
461rb_cloexec_fcntl_dupfd(int fd, int minfd)
462{
463 int ret;
464
465#if defined(HAVE_FCNTL) && defined(F_DUPFD_CLOEXEC) && defined(F_DUPFD)
466 static int try_dupfd_cloexec = 1;
467 if (try_dupfd_cloexec) {
468 ret = fcntl(fd, F_DUPFD_CLOEXEC, minfd);
469 if (ret != -1) {
470 if (ret <= 2)
471 rb_maygvl_fd_fix_cloexec(ret);
472 return ret;
473 }
474 /* F_DUPFD_CLOEXEC is available since Linux 2.6.24. Linux 2.6.18 fails with EINVAL */
475 if (errno == EINVAL) {
476 ret = fcntl(fd, F_DUPFD, minfd);
477 if (ret != -1) {
478 try_dupfd_cloexec = 0;
479 }
480 }
481 }
482 else {
483 ret = fcntl(fd, F_DUPFD, minfd);
484 }
485#elif defined(HAVE_FCNTL) && defined(F_DUPFD)
486 ret = fcntl(fd, F_DUPFD, minfd);
487#else
488 ret = dup(fd);
489 if (ret >= 0 && ret < minfd) {
490 const int prev_fd = ret;
491 ret = rb_cloexec_fcntl_dupfd(fd, minfd);
492 close(prev_fd);
493 }
494 return ret;
495#endif
496 if (ret < 0) return ret;
497 rb_maygvl_fd_fix_cloexec(ret);
498 return ret;
499}
500
501#define argf_of(obj) (*(struct argf *)DATA_PTR(obj))
502#define ARGF argf_of(argf)
503
504#define GetWriteIO(io) rb_io_get_write_io(io)
505
506#define READ_DATA_PENDING(fptr) ((fptr)->rbuf.len)
507#define READ_DATA_PENDING_COUNT(fptr) ((fptr)->rbuf.len)
508#define READ_DATA_PENDING_PTR(fptr) ((fptr)->rbuf.ptr+(fptr)->rbuf.off)
509#define READ_DATA_BUFFERED(fptr) READ_DATA_PENDING(fptr)
510
511#define READ_CHAR_PENDING(fptr) ((fptr)->cbuf.len)
512#define READ_CHAR_PENDING_COUNT(fptr) ((fptr)->cbuf.len)
513#define READ_CHAR_PENDING_PTR(fptr) ((fptr)->cbuf.ptr+(fptr)->cbuf.off)
514
515#if defined(_WIN32)
516#define WAIT_FD_IN_WIN32(fptr) \
517 (rb_w32_io_cancelable_p((fptr)->fd) ? Qnil : rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_READABLE), RUBY_IO_TIMEOUT_DEFAULT))
518#else
519#define WAIT_FD_IN_WIN32(fptr)
520#endif
521
522#define READ_CHECK(fptr) do {\
523 if (!READ_DATA_PENDING(fptr)) {\
524 WAIT_FD_IN_WIN32(fptr);\
525 rb_io_check_closed(fptr);\
526 }\
527} while(0)
528
529#ifndef S_ISSOCK
530# ifdef _S_ISSOCK
531# define S_ISSOCK(m) _S_ISSOCK(m)
532# else
533# ifdef _S_IFSOCK
534# define S_ISSOCK(m) (((m) & S_IFMT) == _S_IFSOCK)
535# else
536# ifdef S_IFSOCK
537# define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
538# endif
539# endif
540# endif
541#endif
542
543static int io_fflush(rb_io_t *);
544static rb_io_t *flush_before_seek(rb_io_t *fptr, bool discard_rbuf);
545static void clear_codeconv(rb_io_t *fptr);
546
547#define FMODE_SIGNAL_ON_EPIPE (1<<17)
548
549#define fptr_signal_on_epipe(fptr) \
550 (((fptr)->mode & FMODE_SIGNAL_ON_EPIPE) != 0)
551
552#define fptr_set_signal_on_epipe(fptr, flag) \
553 ((flag) ? \
554 (fptr)->mode |= FMODE_SIGNAL_ON_EPIPE : \
555 (fptr)->mode &= ~FMODE_SIGNAL_ON_EPIPE)
556
557extern ID ruby_static_id_signo;
558
559NORETURN(static void rb_sys_fail_on_write(rb_io_t *fptr));
560static void
561rb_sys_fail_on_write(rb_io_t *fptr)
562{
563 int e = errno;
564 VALUE errinfo = rb_syserr_new_path(e, (fptr)->pathv);
565#if defined EPIPE
566 if (fptr_signal_on_epipe(fptr) && (e == EPIPE)) {
567 const VALUE sig =
568# if defined SIGPIPE
569 INT2FIX(SIGPIPE) - INT2FIX(0) +
570# endif
571 INT2FIX(0);
572 rb_ivar_set(errinfo, ruby_static_id_signo, sig);
573 }
574#endif
575 rb_exc_raise(errinfo);
576}
577
578#define NEED_NEWLINE_DECORATOR_ON_READ(fptr) ((fptr)->mode & FMODE_TEXTMODE)
579#define NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) ((fptr)->mode & FMODE_TEXTMODE)
580#if defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32)
581# define RUBY_CRLF_ENVIRONMENT 1
582#else
583# define RUBY_CRLF_ENVIRONMENT 0
584#endif
585
586#if RUBY_CRLF_ENVIRONMENT
587/* Windows */
588# define DEFAULT_TEXTMODE FMODE_TEXTMODE
589# define TEXTMODE_NEWLINE_DECORATOR_ON_WRITE ECONV_CRLF_NEWLINE_DECORATOR
590/*
591 * CRLF newline is set as default newline decorator.
592 * If only CRLF newline conversion is needed, we use binary IO process
593 * with OS's text mode for IO performance improvement.
594 * If encoding conversion is needed or a user sets text mode, we use encoding
595 * conversion IO process and universal newline decorator by default.
596 */
597#define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || (fptr)->encs.ecflags & ~ECONV_CRLF_NEWLINE_DECORATOR)
598#define WRITECONV_MASK ( \
599 (ECONV_DECORATOR_MASK & ~ECONV_CRLF_NEWLINE_DECORATOR)|\
600 ECONV_STATEFUL_DECORATOR_MASK|\
601 0)
602#define NEED_WRITECONV(fptr) ( \
603 ((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || \
604 ((fptr)->encs.ecflags & WRITECONV_MASK) || \
605 0)
606#define SET_BINARY_MODE(fptr) setmode((fptr)->fd, O_BINARY)
607
608#define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) do {\
609 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {\
610 if (((fptr)->mode & FMODE_READABLE) &&\
611 !((fptr)->encs.ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {\
612 setmode((fptr)->fd, O_BINARY);\
613 }\
614 else {\
615 setmode((fptr)->fd, O_TEXT);\
616 }\
617 }\
618} while(0)
619
620#define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) do {\
621 if ((enc2) && ((ecflags) & ECONV_DEFAULT_NEWLINE_DECORATOR)) {\
622 (ecflags) |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;\
623 }\
624} while(0)
625
626/*
627 * IO unread with taking care of removed '\r' in text mode.
628 */
629static void
630io_unread(rb_io_t *fptr, bool discard_rbuf)
631{
632 rb_off_t r, pos;
633 ssize_t read_size;
634 long i;
635 long newlines = 0;
636 long extra_max;
637 char *p;
638 char *buf;
639
640 rb_io_check_closed(fptr);
641 if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX) {
642 return;
643 }
644
645 errno = 0;
646 if (!rb_w32_fd_is_text(fptr->fd)) {
647 r = lseek(fptr->fd, -fptr->rbuf.len, SEEK_CUR);
648 if (r < 0 && errno) {
649 if (errno == ESPIPE)
650 fptr->mode |= FMODE_DUPLEX;
651 if (!discard_rbuf) return;
652 }
653
654 goto end;
655 }
656
657 pos = lseek(fptr->fd, 0, SEEK_CUR);
658 if (pos < 0 && errno) {
659 if (errno == ESPIPE)
660 fptr->mode |= FMODE_DUPLEX;
661 if (!discard_rbuf) goto end;
662 }
663
664 /* add extra offset for removed '\r' in rbuf */
665 extra_max = (long)(pos - fptr->rbuf.len);
666 p = fptr->rbuf.ptr + fptr->rbuf.off;
667
668 /* if the end of rbuf is '\r', rbuf doesn't have '\r' within rbuf.len */
669 if (*(fptr->rbuf.ptr + fptr->rbuf.capa - 1) == '\r') {
670 newlines++;
671 }
672
673 for (i = 0; i < fptr->rbuf.len; i++) {
674 if (*p == '\n') newlines++;
675 if (extra_max == newlines) break;
676 p++;
677 }
678
679 buf = ALLOC_N(char, fptr->rbuf.len + newlines);
680 while (newlines >= 0) {
681 r = lseek(fptr->fd, pos - fptr->rbuf.len - newlines, SEEK_SET);
682 if (newlines == 0) break;
683 if (r < 0) {
684 newlines--;
685 continue;
686 }
687 read_size = _read(fptr->fd, buf, fptr->rbuf.len + newlines);
688 if (read_size < 0) {
689 int e = errno;
690 free(buf);
691 rb_syserr_fail_path(e, fptr->pathv);
692 }
693 if (read_size == fptr->rbuf.len) {
694 lseek(fptr->fd, r, SEEK_SET);
695 break;
696 }
697 else {
698 newlines--;
699 }
700 }
701 free(buf);
702 end:
703 fptr->rbuf.off = 0;
704 fptr->rbuf.len = 0;
705 clear_codeconv(fptr);
706 return;
707}
708
709/*
710 * We use io_seek to back cursor position when changing mode from text to binary,
711 * but stdin and pipe cannot seek back. Stdin and pipe read should use encoding
712 * conversion for working properly with mode change.
713 *
714 * Return previous translation mode.
715 */
716static inline int
717set_binary_mode_with_seek_cur(rb_io_t *fptr)
718{
719 if (!rb_w32_fd_is_text(fptr->fd)) return O_BINARY;
720
721 if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX) {
722 return setmode(fptr->fd, O_BINARY);
723 }
724 flush_before_seek(fptr, false);
725 return setmode(fptr->fd, O_BINARY);
726}
727#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) set_binary_mode_with_seek_cur(fptr)
728
729#else
730/* Unix */
731# define DEFAULT_TEXTMODE 0
732#define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || NEED_NEWLINE_DECORATOR_ON_READ(fptr))
733#define NEED_WRITECONV(fptr) ( \
734 ((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || \
735 NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) || \
736 ((fptr)->encs.ecflags & (ECONV_DECORATOR_MASK|ECONV_STATEFUL_DECORATOR_MASK)) || \
737 0)
738#define SET_BINARY_MODE(fptr) (void)(fptr)
739#define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) (void)(fptr)
740#define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) ((void)(enc2), (void)(ecflags))
741#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) (void)(fptr)
742#endif
743
744#if !defined HAVE_SHUTDOWN && !defined shutdown
745#define shutdown(a,b) 0
746#endif
747
748#if defined(_WIN32)
749#define is_socket(fd, path) rb_w32_is_socket(fd)
750#elif !defined(S_ISSOCK)
751#define is_socket(fd, path) 0
752#else
753static int
754is_socket(int fd, VALUE path)
755{
756 struct stat sbuf;
757 if (fstat(fd, &sbuf) < 0)
758 rb_sys_fail_path(path);
759 return S_ISSOCK(sbuf.st_mode);
760}
761#endif
762
763static const char closed_stream[] = "closed stream";
764
765static void
766io_fd_check_closed(int fd)
767{
768 if (fd < 0) {
769 rb_thread_check_ints(); /* check for ruby_error_stream_closed */
770 rb_raise(rb_eIOError, closed_stream);
771 }
772}
773
774void
775rb_eof_error(void)
776{
777 rb_raise(rb_eEOFError, "end of file reached");
778}
779
780VALUE
782{
783 rb_check_frozen(io);
784 return io;
785}
786
787void
789{
790 if (!fptr) {
791 rb_raise(rb_eIOError, "uninitialized stream");
792 }
793}
794
795void
797{
799 io_fd_check_closed(fptr->fd);
800}
801
802static rb_io_t *
803rb_io_get_fptr(VALUE io)
804{
805 rb_io_t *fptr = RFILE(io)->fptr;
807 return fptr;
808}
809
810VALUE
812{
813 return rb_convert_type_with_id(io, T_FILE, "IO", idTo_io);
814}
815
816VALUE
818{
819 return rb_check_convert_type_with_id(io, T_FILE, "IO", idTo_io);
820}
821
822VALUE
824{
825 VALUE write_io;
826 write_io = rb_io_get_fptr(io)->tied_io_for_writing;
827 if (write_io) {
828 return write_io;
829 }
830 return io;
831}
832
833VALUE
835{
836 VALUE write_io;
837 rb_io_t *fptr = rb_io_get_fptr(io);
838 if (!RTEST(w)) {
839 w = 0;
840 }
841 else {
842 GetWriteIO(w);
843 }
844 write_io = fptr->tied_io_for_writing;
845 fptr->tied_io_for_writing = w;
846 return write_io ? write_io : Qnil;
847}
848
849/*
850 * call-seq:
851 * timeout -> duration or nil
852 *
853 * Get the internal timeout duration or nil if it was not set.
854 *
855 */
856VALUE
858{
859 rb_io_t *fptr = rb_io_get_fptr(self);
860
861 return fptr->timeout;
862}
863
864/*
865 * call-seq:
866 * timeout = duration -> duration
867 * timeout = nil -> nil
868 *
869 * Sets the internal timeout to the specified duration or nil. The timeout
870 * applies to all blocking operations where possible.
871 *
872 * When the operation performs longer than the timeout set, IO::TimeoutError
873 * is raised.
874 *
875 * This affects the following methods (but is not limited to): #gets, #puts,
876 * #read, #write, #wait_readable and #wait_writable. This also affects
877 * blocking socket operations like Socket#accept and Socket#connect.
878 *
879 * Some operations like File#open and IO#close are not affected by the
880 * timeout. A timeout during a write operation may leave the IO in an
881 * inconsistent state, e.g. data was partially written. Generally speaking, a
882 * timeout is a last ditch effort to prevent an application from hanging on
883 * slow I/O operations, such as those that occur during a slowloris attack.
884 */
885VALUE
887{
888 // Validate it:
889 if (RTEST(timeout)) {
890 rb_time_interval(timeout);
891 }
892
893 rb_io_t *fptr = rb_io_get_fptr(self);
894
895 fptr->timeout = timeout;
896
897 return self;
898}
899
900/*
901 * call-seq:
902 * IO.try_convert(object) -> new_io or nil
903 *
904 * Attempts to convert +object+ into an \IO object via method +to_io+;
905 * returns the new \IO object if successful, or +nil+ otherwise:
906 *
907 * IO.try_convert(STDOUT) # => #<IO:<STDOUT>>
908 * IO.try_convert(ARGF) # => #<IO:<STDIN>>
909 * IO.try_convert('STDOUT') # => nil
910 *
911 */
912static VALUE
913rb_io_s_try_convert(VALUE dummy, VALUE io)
914{
915 return rb_io_check_io(io);
916}
917
918#if !RUBY_CRLF_ENVIRONMENT
919static void
920io_unread(rb_io_t *fptr, bool discard_rbuf)
921{
922 rb_off_t r;
923 rb_io_check_closed(fptr);
924 if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX)
925 return;
926 /* xxx: target position may be negative if buffer is filled by ungetc */
927 errno = 0;
928 r = lseek(fptr->fd, -fptr->rbuf.len, SEEK_CUR);
929 if (r < 0 && errno) {
930 if (errno == ESPIPE)
931 fptr->mode |= FMODE_DUPLEX;
932 if (!discard_rbuf) return;
933 }
934 fptr->rbuf.off = 0;
935 fptr->rbuf.len = 0;
936 clear_codeconv(fptr);
937 return;
938}
939#endif
940
941static rb_encoding *io_input_encoding(rb_io_t *fptr);
942
943static void
944io_ungetbyte(VALUE str, rb_io_t *fptr)
945{
946 long len = RSTRING_LEN(str);
947
948 if (fptr->rbuf.ptr == NULL) {
949 const int min_capa = IO_RBUF_CAPA_FOR(fptr);
950 fptr->rbuf.off = 0;
951 fptr->rbuf.len = 0;
952#if SIZEOF_LONG > SIZEOF_INT
953 if (len > INT_MAX)
954 rb_raise(rb_eIOError, "ungetbyte failed");
955#endif
956 if (len > min_capa)
957 fptr->rbuf.capa = (int)len;
958 else
959 fptr->rbuf.capa = min_capa;
960 fptr->rbuf.ptr = ALLOC_N(char, fptr->rbuf.capa);
961 }
962 if (fptr->rbuf.capa < len + fptr->rbuf.len) {
963 rb_raise(rb_eIOError, "ungetbyte failed");
964 }
965 if (fptr->rbuf.off < len) {
966 MEMMOVE(fptr->rbuf.ptr+fptr->rbuf.capa-fptr->rbuf.len,
967 fptr->rbuf.ptr+fptr->rbuf.off,
968 char, fptr->rbuf.len);
969 fptr->rbuf.off = fptr->rbuf.capa-fptr->rbuf.len;
970 }
971 fptr->rbuf.off-=(int)len;
972 fptr->rbuf.len+=(int)len;
973 MEMMOVE(fptr->rbuf.ptr+fptr->rbuf.off, RSTRING_PTR(str), char, len);
974}
975
976static rb_io_t *
977flush_before_seek(rb_io_t *fptr, bool discard_rbuf)
978{
979 if (io_fflush(fptr) < 0)
980 rb_sys_fail_on_write(fptr);
981 io_unread(fptr, discard_rbuf);
982 errno = 0;
983 return fptr;
984}
985
986#define io_seek(fptr, ofs, whence) (errno = 0, lseek(flush_before_seek(fptr, true)->fd, (ofs), (whence)))
987#define io_tell(fptr) lseek(flush_before_seek(fptr, false)->fd, 0, SEEK_CUR)
988
989#ifndef SEEK_CUR
990# define SEEK_SET 0
991# define SEEK_CUR 1
992# define SEEK_END 2
993#endif
994
995void
997{
998 rb_io_check_closed(fptr);
999 if (!(fptr->mode & FMODE_READABLE)) {
1000 rb_raise(rb_eIOError, "not opened for reading");
1001 }
1002 if (fptr->wbuf.len) {
1003 if (io_fflush(fptr) < 0)
1004 rb_sys_fail_on_write(fptr);
1005 }
1006 if (fptr->tied_io_for_writing) {
1007 rb_io_t *wfptr;
1008 GetOpenFile(fptr->tied_io_for_writing, wfptr);
1009 if (io_fflush(wfptr) < 0)
1010 rb_sys_fail_on_write(wfptr);
1011 }
1012}
1013
1014void
1016{
1018 if (READ_CHAR_PENDING(fptr)) {
1019 rb_raise(rb_eIOError, "byte oriented read for character buffered IO");
1020 }
1021}
1022
1023void
1028
1029static rb_encoding*
1030io_read_encoding(rb_io_t *fptr)
1031{
1032 if (fptr->encs.enc) {
1033 return fptr->encs.enc;
1034 }
1035 return rb_default_external_encoding();
1036}
1037
1038static rb_encoding*
1039io_input_encoding(rb_io_t *fptr)
1040{
1041 if (fptr->encs.enc2) {
1042 return fptr->encs.enc2;
1043 }
1044 return io_read_encoding(fptr);
1045}
1046
1047void
1049{
1050 rb_io_check_closed(fptr);
1051 if (!(fptr->mode & FMODE_WRITABLE)) {
1052 rb_raise(rb_eIOError, "not opened for writing");
1053 }
1054 if (fptr->rbuf.len) {
1055 io_unread(fptr, true);
1056 }
1057}
1058
1059int
1060rb_io_read_pending(rb_io_t *fptr)
1061{
1062 /* This function is used for bytes and chars. Confusing. */
1063 if (READ_CHAR_PENDING(fptr))
1064 return 1; /* should raise? */
1065 return READ_DATA_PENDING(fptr);
1066}
1067
1068void
1070{
1071 if (!READ_DATA_PENDING(fptr)) {
1072 rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_READABLE), RUBY_IO_TIMEOUT_DEFAULT);
1073 }
1074 return;
1075}
1076
1077int
1078rb_gc_for_fd(int err)
1079{
1080 if (err == EMFILE || err == ENFILE || err == ENOMEM) {
1081 rb_gc();
1082 return 1;
1083 }
1084 return 0;
1085}
1086
1087/* try `expr` upto twice while it returns false and `errno`
1088 * is to GC. Each `errno`s are available as `first_errno` and
1089 * `retried_errno` respectively */
1090#define TRY_WITH_GC(expr) \
1091 for (int first_errno, retried_errno = 0, retried = 0; \
1092 (!retried && \
1093 !(expr) && \
1094 (!rb_gc_for_fd(first_errno = errno) || !(expr)) && \
1095 (retried_errno = errno, 1)); \
1096 (void)retried_errno, retried = 1)
1097
1098static int
1099ruby_dup(int orig)
1100{
1101 int fd = -1;
1102
1103 TRY_WITH_GC((fd = rb_cloexec_dup(orig)) >= 0) {
1104 rb_syserr_fail(first_errno, 0);
1105 }
1106 rb_update_max_fd(fd);
1107 return fd;
1108}
1109
1110static VALUE
1111io_alloc(VALUE klass)
1112{
1113 NEWOBJ_OF(io, struct RFile, klass, T_FILE, sizeof(struct RFile), 0);
1114
1115 io->fptr = 0;
1116
1117 return (VALUE)io;
1118}
1119
1120#ifndef S_ISREG
1121# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
1122#endif
1123
1125 VALUE th;
1126 rb_io_t *fptr;
1127 int nonblock;
1128 int fd;
1129
1130 void *buf;
1131 size_t capa;
1132 struct timeval *timeout;
1133};
1134
1136 VALUE th;
1137 rb_io_t *fptr;
1138 int nonblock;
1139 int fd;
1140
1141 const void *buf;
1142 size_t capa;
1143 struct timeval *timeout;
1144};
1145
1146#ifdef HAVE_WRITEV
1147struct io_internal_writev_struct {
1148 VALUE th;
1149 rb_io_t *fptr;
1150 int nonblock;
1151 int fd;
1152
1153 int iovcnt;
1154 const struct iovec *iov;
1155 struct timeval *timeout;
1156};
1157#endif
1158
1159static int nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout);
1160
1166static inline int
1167io_internal_wait(VALUE thread, rb_io_t *fptr, int error, int events, struct timeval *timeout)
1168{
1169 if (!timeout && rb_thread_mn_schedulable(thread)) {
1170 RUBY_ASSERT(errno == EWOULDBLOCK || errno == EAGAIN);
1171 return -1;
1172 }
1173
1174 int ready = nogvl_wait_for(thread, fptr, events, timeout);
1175
1176 if (ready > 0) {
1177 return ready;
1178 }
1179 else if (ready == 0) {
1180 errno = ETIMEDOUT;
1181 return -1;
1182 }
1183
1184 // If there was an error BEFORE we started waiting, return it:
1185 if (error) {
1186 errno = error;
1187 return -1;
1188 }
1189 else {
1190 // Otherwise, whatever error was generated by `nogvl_wait_for` is the one we want:
1191 return ready;
1192 }
1193}
1194
1195static VALUE
1196internal_read_func(void *ptr)
1197{
1198 struct io_internal_read_struct *iis = ptr;
1199 ssize_t result;
1200
1201 if (iis->timeout && !iis->nonblock) {
1202 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_IN, iis->timeout) == -1) {
1203 return -1;
1204 }
1205 }
1206
1207 retry:
1208 result = read(iis->fd, iis->buf, iis->capa);
1209
1210 if (result < 0 && !iis->nonblock) {
1211 if (io_again_p(errno)) {
1212 if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_IN, iis->timeout) == -1) {
1213 return -1;
1214 }
1215 else {
1216 goto retry;
1217 }
1218 }
1219 }
1220
1221 return result;
1222}
1223
1224#if defined __APPLE__
1225# define do_write_retry(code) do {result = code;} while (result == -1 && errno == EPROTOTYPE)
1226#else
1227# define do_write_retry(code) result = code
1228#endif
1229
1230static VALUE
1231internal_write_func(void *ptr)
1232{
1233 struct io_internal_write_struct *iis = ptr;
1234 ssize_t result;
1235
1236 if (iis->timeout && !iis->nonblock) {
1237 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1238 return -1;
1239 }
1240 }
1241
1242 retry:
1243 do_write_retry(write(iis->fd, iis->buf, iis->capa));
1244
1245 if (result < 0 && !iis->nonblock) {
1246 int e = errno;
1247 if (io_again_p(e)) {
1248 if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1249 return -1;
1250 }
1251 else {
1252 goto retry;
1253 }
1254 }
1255 }
1256
1257 return result;
1258}
1259
1260#ifdef HAVE_WRITEV
1261static VALUE
1262internal_writev_func(void *ptr)
1263{
1264 struct io_internal_writev_struct *iis = ptr;
1265 ssize_t result;
1266
1267 if (iis->timeout && !iis->nonblock) {
1268 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1269 return -1;
1270 }
1271 }
1272
1273 retry:
1274 do_write_retry(writev(iis->fd, iis->iov, iis->iovcnt));
1275
1276 if (result < 0 && !iis->nonblock) {
1277 if (io_again_p(errno)) {
1278 if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1279 return -1;
1280 }
1281 else {
1282 goto retry;
1283 }
1284 }
1285 }
1286
1287 return result;
1288}
1289#endif
1290
1291static ssize_t
1292rb_io_read_memory(rb_io_t *fptr, void *buf, size_t count)
1293{
1294 VALUE scheduler = rb_fiber_scheduler_current();
1295 if (scheduler != Qnil) {
1296 VALUE result = rb_fiber_scheduler_io_read_memory(scheduler, fptr->self, buf, count, 0);
1297
1298 if (!UNDEF_P(result)) {
1300 }
1301 }
1302
1303 struct io_internal_read_struct iis = {
1304 .th = rb_thread_current(),
1305 .fptr = fptr,
1306 .nonblock = 0,
1307 .fd = fptr->fd,
1308
1309 .buf = buf,
1310 .capa = count,
1311 .timeout = NULL,
1312 };
1313
1314 struct timeval timeout_storage;
1315
1316 if (fptr->timeout != Qnil) {
1317 timeout_storage = rb_time_interval(fptr->timeout);
1318 iis.timeout = &timeout_storage;
1319 }
1320
1321 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_read_func, &iis, RUBY_IO_READABLE);
1322}
1323
1324static ssize_t
1325rb_io_write_memory(rb_io_t *fptr, const void *buf, size_t count)
1326{
1327 VALUE scheduler = rb_fiber_scheduler_current();
1328 if (scheduler != Qnil) {
1329 VALUE result = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, buf, count, 0);
1330
1331 if (!UNDEF_P(result)) {
1333 }
1334 }
1335
1336 struct io_internal_write_struct iis = {
1337 .th = rb_thread_current(),
1338 .fptr = fptr,
1339 .nonblock = 0,
1340 .fd = fptr->fd,
1341
1342 .buf = buf,
1343 .capa = count,
1344 .timeout = NULL
1345 };
1346
1347 struct timeval timeout_storage;
1348
1349 if (fptr->timeout != Qnil) {
1350 timeout_storage = rb_time_interval(fptr->timeout);
1351 iis.timeout = &timeout_storage;
1352 }
1353
1354 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_write_func, &iis, RUBY_IO_WRITABLE);
1355}
1356
1357#ifdef HAVE_WRITEV
1358static ssize_t
1359rb_writev_internal(rb_io_t *fptr, const struct iovec *iov, int iovcnt)
1360{
1361 if (!iovcnt) return 0;
1362
1363 VALUE scheduler = rb_fiber_scheduler_current();
1364 if (scheduler != Qnil) {
1365 // This path assumes at least one `iov`:
1366 VALUE result = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, iov[0].iov_base, iov[0].iov_len, 0);
1367
1368 if (!UNDEF_P(result)) {
1370 }
1371 }
1372
1373 struct io_internal_writev_struct iis = {
1374 .th = rb_thread_current(),
1375 .fptr = fptr,
1376 .nonblock = 0,
1377 .fd = fptr->fd,
1378
1379 .iov = iov,
1380 .iovcnt = iovcnt,
1381 .timeout = NULL
1382 };
1383
1384 struct timeval timeout_storage;
1385
1386 if (fptr->timeout != Qnil) {
1387 timeout_storage = rb_time_interval(fptr->timeout);
1388 iis.timeout = &timeout_storage;
1389 }
1390
1391 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_writev_func, &iis, RUBY_IO_WRITABLE);
1392}
1393#endif
1394
1395static VALUE
1396io_flush_buffer_sync(void *arg)
1397{
1398 rb_io_t *fptr = arg;
1399 long l = fptr->wbuf.len;
1400 ssize_t r = write(fptr->fd, fptr->wbuf.ptr+fptr->wbuf.off, (size_t)l);
1401
1402 if (fptr->wbuf.len <= r) {
1403 fptr->wbuf.off = 0;
1404 fptr->wbuf.len = 0;
1405 return 0;
1406 }
1407
1408 if (0 <= r) {
1409 fptr->wbuf.off += (int)r;
1410 fptr->wbuf.len -= (int)r;
1411 errno = EAGAIN;
1412 }
1413
1414 return (VALUE)-1;
1415}
1416
1417static VALUE
1418io_flush_buffer_async(VALUE arg)
1419{
1420 rb_io_t *fptr = (rb_io_t *)arg;
1421 return rb_io_blocking_region_wait(fptr, io_flush_buffer_sync, fptr, RUBY_IO_WRITABLE);
1422}
1423
1424static inline int
1425io_flush_buffer(rb_io_t *fptr)
1426{
1427 if (!NIL_P(fptr->write_lock) && rb_mutex_owned_p(fptr->write_lock)) {
1428 return (int)io_flush_buffer_async((VALUE)fptr);
1429 }
1430 else {
1431 return (int)rb_mutex_synchronize(fptr->write_lock, io_flush_buffer_async, (VALUE)fptr);
1432 }
1433}
1434
1435static int
1436io_fflush(rb_io_t *fptr)
1437{
1438 rb_io_check_closed(fptr);
1439
1440 if (fptr->wbuf.len == 0)
1441 return 0;
1442
1443 while (fptr->wbuf.len > 0 && io_flush_buffer(fptr) != 0) {
1444 if (!rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT))
1445 return -1;
1446
1447 rb_io_check_closed(fptr);
1448 }
1449
1450 return 0;
1451}
1452
1453VALUE
1454rb_io_wait(VALUE io, VALUE events, VALUE timeout)
1455{
1456 VALUE scheduler = rb_fiber_scheduler_current();
1457
1458 if (scheduler != Qnil) {
1459 return rb_fiber_scheduler_io_wait(scheduler, io, events, timeout);
1460 }
1461
1462 rb_io_t * fptr = NULL;
1463 RB_IO_POINTER(io, fptr);
1464
1465 struct timeval tv_storage;
1466 struct timeval *tv = NULL;
1467
1468 if (NIL_OR_UNDEF_P(timeout)) {
1469 timeout = fptr->timeout;
1470 }
1471
1472 if (timeout != Qnil) {
1473 tv_storage = rb_time_interval(timeout);
1474 tv = &tv_storage;
1475 }
1476
1477 int ready = rb_thread_io_wait(fptr, RB_NUM2INT(events), tv);
1478
1479 if (ready < 0) {
1480 rb_sys_fail(0);
1481 }
1482
1483 // Not sure if this is necessary:
1484 rb_io_check_closed(fptr);
1485
1486 if (ready) {
1487 return RB_INT2NUM(ready);
1488 }
1489 else {
1490 return Qfalse;
1491 }
1492}
1493
1494static VALUE
1495io_from_fd(int fd)
1496{
1497 return prep_io(fd, FMODE_EXTERNAL, rb_cIO, NULL);
1498}
1499
1500static int
1501io_wait_for_single_fd(int fd, int events, struct timeval *timeout)
1502{
1503 VALUE scheduler = rb_fiber_scheduler_current();
1504
1505 if (scheduler != Qnil) {
1506 return RTEST(
1507 rb_fiber_scheduler_io_wait(scheduler, io_from_fd(fd), RB_INT2NUM(events), rb_fiber_scheduler_make_timeout(timeout))
1508 );
1509 }
1510
1511 return rb_thread_wait_for_single_fd(fd, events, timeout);
1512}
1513
1514int
1516{
1517 io_fd_check_closed(f);
1518
1519 VALUE scheduler = rb_fiber_scheduler_current();
1520
1521 switch (errno) {
1522 case EINTR:
1523#if defined(ERESTART)
1524 case ERESTART:
1525#endif
1527 return TRUE;
1528
1529 case EAGAIN:
1530#if EWOULDBLOCK != EAGAIN
1531 case EWOULDBLOCK:
1532#endif
1533 if (scheduler != Qnil) {
1534 return RTEST(
1535 rb_fiber_scheduler_io_wait_readable(scheduler, io_from_fd(f))
1536 );
1537 }
1538 else {
1539 io_wait_for_single_fd(f, RUBY_IO_READABLE, NULL);
1540 }
1541 return TRUE;
1542
1543 default:
1544 return FALSE;
1545 }
1546}
1547
1548int
1550{
1551 io_fd_check_closed(f);
1552
1553 VALUE scheduler = rb_fiber_scheduler_current();
1554
1555 switch (errno) {
1556 case EINTR:
1557#if defined(ERESTART)
1558 case ERESTART:
1559#endif
1560 /*
1561 * In old Linux, several special files under /proc and /sys don't handle
1562 * select properly. Thus we need avoid to call if don't use O_NONBLOCK.
1563 * Otherwise, we face nasty hang up. Sigh.
1564 * e.g. https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1565 * https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1566 * In EINTR case, we only need to call RUBY_VM_CHECK_INTS_BLOCKING().
1567 * Then rb_thread_check_ints() is enough.
1568 */
1570 return TRUE;
1571
1572 case EAGAIN:
1573#if EWOULDBLOCK != EAGAIN
1574 case EWOULDBLOCK:
1575#endif
1576 if (scheduler != Qnil) {
1577 return RTEST(
1578 rb_fiber_scheduler_io_wait_writable(scheduler, io_from_fd(f))
1579 );
1580 }
1581 else {
1582 io_wait_for_single_fd(f, RUBY_IO_WRITABLE, NULL);
1583 }
1584 return TRUE;
1585
1586 default:
1587 return FALSE;
1588 }
1589}
1590
1591int
1592rb_wait_for_single_fd(int fd, int events, struct timeval *timeout)
1593{
1594 return io_wait_for_single_fd(fd, events, timeout);
1595}
1596
1597int
1599{
1600 return rb_wait_for_single_fd(fd, RUBY_IO_READABLE, NULL);
1601}
1602
1603int
1605{
1606 return rb_wait_for_single_fd(fd, RUBY_IO_WRITABLE, NULL);
1607}
1608
1609VALUE
1610rb_io_maybe_wait(int error, VALUE io, VALUE events, VALUE timeout)
1611{
1612 // fptr->fd can be set to -1 at any time by another thread when the GVL is
1613 // released. Many code, e.g. `io_bufread` didn't check this correctly and
1614 // instead relies on `read(-1) -> -1` which causes this code path. We then
1615 // check here whether the IO was in fact closed. Probably it's better to
1616 // check that `fptr->fd != -1` before using it in syscall.
1617 rb_io_check_closed(RFILE(io)->fptr);
1618
1619 switch (error) {
1620 // In old Linux, several special files under /proc and /sys don't handle
1621 // select properly. Thus we need avoid to call if don't use O_NONBLOCK.
1622 // Otherwise, we face nasty hang up. Sigh.
1623 // e.g. https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1624 // https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1625 // In EINTR case, we only need to call RUBY_VM_CHECK_INTS_BLOCKING().
1626 // Then rb_thread_check_ints() is enough.
1627 case EINTR:
1628#if defined(ERESTART)
1629 case ERESTART:
1630#endif
1631 // We might have pending interrupts since the previous syscall was interrupted:
1633
1634 // The operation was interrupted, so retry it immediately:
1635 return events;
1636
1637 case EAGAIN:
1638#if EWOULDBLOCK != EAGAIN
1639 case EWOULDBLOCK:
1640#endif
1641 // The operation would block, so wait for the specified events:
1642 return rb_io_wait(io, events, timeout);
1643
1644 default:
1645 // Non-specific error, no event is ready:
1646 return Qnil;
1647 }
1648}
1649
1650int
1652{
1653 VALUE result = rb_io_maybe_wait(error, io, RB_INT2NUM(RUBY_IO_READABLE), timeout);
1654
1655 if (RTEST(result)) {
1656 return RB_NUM2INT(result);
1657 }
1658 else if (result == RUBY_Qfalse) {
1659 rb_raise(rb_eIOTimeoutError, "Timed out waiting for IO to become readable!");
1660 }
1661
1662 return 0;
1663}
1664
1665int
1667{
1668 VALUE result = rb_io_maybe_wait(error, io, RB_INT2NUM(RUBY_IO_WRITABLE), timeout);
1669
1670 if (RTEST(result)) {
1671 return RB_NUM2INT(result);
1672 }
1673 else if (result == RUBY_Qfalse) {
1674 rb_raise(rb_eIOTimeoutError, "Timed out waiting for IO to become writable!");
1675 }
1676
1677 return 0;
1678}
1679
1680static void
1681make_writeconv(rb_io_t *fptr)
1682{
1683 if (!fptr->writeconv_initialized) {
1684 const char *senc, *denc;
1685 rb_encoding *enc;
1686 int ecflags;
1687 VALUE ecopts;
1688
1689 fptr->writeconv_initialized = 1;
1690
1691 ecflags = fptr->encs.ecflags & ~ECONV_NEWLINE_DECORATOR_READ_MASK;
1692 ecopts = fptr->encs.ecopts;
1693
1694 if (!fptr->encs.enc || (rb_is_ascii8bit_enc(fptr->encs.enc) && !fptr->encs.enc2)) {
1695 /* no encoding conversion */
1696 fptr->writeconv_pre_ecflags = 0;
1697 fptr->writeconv_pre_ecopts = Qnil;
1698 fptr->writeconv = rb_econv_open_opts("", "", ecflags, ecopts);
1699 if (!fptr->writeconv)
1700 rb_exc_raise(rb_econv_open_exc("", "", ecflags));
1702 }
1703 else {
1704 enc = fptr->encs.enc2 ? fptr->encs.enc2 : fptr->encs.enc;
1705 senc = rb_econv_asciicompat_encoding(rb_enc_name(enc));
1706 if (!senc && !(fptr->encs.ecflags & ECONV_STATEFUL_DECORATOR_MASK)) {
1707 /* single conversion */
1708 fptr->writeconv_pre_ecflags = ecflags;
1709 fptr->writeconv_pre_ecopts = ecopts;
1710 fptr->writeconv = NULL;
1712 }
1713 else {
1714 /* double conversion */
1715 fptr->writeconv_pre_ecflags = ecflags & ~ECONV_STATEFUL_DECORATOR_MASK;
1716 fptr->writeconv_pre_ecopts = ecopts;
1717 if (senc) {
1718 denc = rb_enc_name(enc);
1719 fptr->writeconv_asciicompat = rb_str_new2(senc);
1720 }
1721 else {
1722 senc = denc = "";
1723 fptr->writeconv_asciicompat = rb_str_new2(rb_enc_name(enc));
1724 }
1726 ecopts = fptr->encs.ecopts;
1727 fptr->writeconv = rb_econv_open_opts(senc, denc, ecflags, ecopts);
1728 if (!fptr->writeconv)
1729 rb_exc_raise(rb_econv_open_exc(senc, denc, ecflags));
1730 }
1731 }
1732 }
1733}
1734
1735/* writing functions */
1737 rb_io_t *fptr;
1738 const char *ptr;
1739 long length;
1740};
1741
1743 VALUE io;
1744 VALUE str;
1745 int nosync;
1746};
1747
1748#ifdef HAVE_WRITEV
1749static ssize_t
1750io_binwrite_string_internal(rb_io_t *fptr, const char *ptr, long length)
1751{
1752 if (fptr->wbuf.len) {
1753 struct iovec iov[2];
1754
1755 iov[0].iov_base = fptr->wbuf.ptr+fptr->wbuf.off;
1756 iov[0].iov_len = fptr->wbuf.len;
1757 iov[1].iov_base = (void*)ptr;
1758 iov[1].iov_len = length;
1759
1760 ssize_t result = rb_writev_internal(fptr, iov, 2);
1761
1762 if (result < 0)
1763 return result;
1764
1765 if (result >= fptr->wbuf.len) {
1766 // We wrote more than the internal buffer:
1767 result -= fptr->wbuf.len;
1768 fptr->wbuf.off = 0;
1769 fptr->wbuf.len = 0;
1770 }
1771 else {
1772 // We only wrote less data than the internal buffer:
1773 fptr->wbuf.off += (int)result;
1774 fptr->wbuf.len -= (int)result;
1775
1776 result = 0;
1777 }
1778
1779 return result;
1780 }
1781 else {
1782 return rb_io_write_memory(fptr, ptr, length);
1783 }
1784}
1785#else
1786static ssize_t
1787io_binwrite_string_internal(rb_io_t *fptr, const char *ptr, long length)
1788{
1789 long remaining = length;
1790
1791 if (fptr->wbuf.len) {
1792 if (fptr->wbuf.len+length <= fptr->wbuf.capa) {
1793 if (fptr->wbuf.capa < fptr->wbuf.off+fptr->wbuf.len+length) {
1794 MEMMOVE(fptr->wbuf.ptr, fptr->wbuf.ptr+fptr->wbuf.off, char, fptr->wbuf.len);
1795 fptr->wbuf.off = 0;
1796 }
1797
1798 MEMMOVE(fptr->wbuf.ptr+fptr->wbuf.off+fptr->wbuf.len, ptr, char, length);
1799 fptr->wbuf.len += (int)length;
1800
1801 // We copied the entire incoming data to the internal buffer:
1802 remaining = 0;
1803 }
1804
1805 // Flush the internal buffer:
1806 if (io_fflush(fptr) < 0) {
1807 return -1;
1808 }
1809
1810 // If all the data was buffered, we are done:
1811 if (remaining == 0) {
1812 return length;
1813 }
1814 }
1815
1816 // Otherwise, we should write the data directly:
1817 return rb_io_write_memory(fptr, ptr, length);
1818}
1819#endif
1820
1821static VALUE
1822io_binwrite_string(VALUE arg)
1823{
1824 struct binwrite_arg *p = (struct binwrite_arg *)arg;
1825
1826 const char *ptr = p->ptr;
1827 size_t remaining = p->length;
1828
1829 while (remaining) {
1830 // Write as much as possible:
1831 ssize_t result = io_binwrite_string_internal(p->fptr, ptr, remaining);
1832
1833 if (result == 0) {
1834 // If only the internal buffer is written, result will be zero [bytes of given data written]. This means we
1835 // should try again immediately.
1836 }
1837 else if (result > 0) {
1838 if ((size_t)result == remaining) break;
1839 ptr += result;
1840 remaining -= result;
1841 }
1842 // Wait for it to become writable:
1843 else if (rb_io_maybe_wait_writable(errno, p->fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
1844 rb_io_check_closed(p->fptr);
1845 }
1846 else {
1847 // The error was unrelated to waiting for it to become writable, so we fail:
1848 return -1;
1849 }
1850 }
1851
1852 return p->length;
1853}
1854
1855inline static void
1856io_allocate_write_buffer(rb_io_t *fptr, int sync)
1857{
1858 if (fptr->wbuf.ptr == NULL && !(sync && (fptr->mode & FMODE_SYNC))) {
1859 fptr->wbuf.off = 0;
1860 fptr->wbuf.len = 0;
1861 fptr->wbuf.capa = IO_WBUF_CAPA_MIN;
1862 fptr->wbuf.ptr = ALLOC_N(char, fptr->wbuf.capa);
1863 }
1864
1865 if (NIL_P(fptr->write_lock)) {
1866 fptr->write_lock = rb_mutex_new();
1867 rb_mutex_allow_trap(fptr->write_lock, 1);
1868 }
1869}
1870
1871static inline int
1872io_binwrite_requires_flush_write(rb_io_t *fptr, long len, int nosync)
1873{
1874 // If the requested operation was synchronous and the output mode is synchronous or a TTY:
1875 if (!nosync && (fptr->mode & (FMODE_SYNC|FMODE_TTY)))
1876 return 1;
1877
1878 // If the amount of data we want to write exceeds the internal buffer:
1879 if (fptr->wbuf.ptr && fptr->wbuf.capa <= fptr->wbuf.len + len)
1880 return 1;
1881
1882 // Otherwise, we can append to the internal buffer:
1883 return 0;
1884}
1885
1886static long
1887io_binwrite(const char *ptr, long len, rb_io_t *fptr, int nosync)
1888{
1889 if (len <= 0) return len;
1890
1891 // Don't write anything if current thread has a pending interrupt:
1893
1894 io_allocate_write_buffer(fptr, !nosync);
1895
1896 if (io_binwrite_requires_flush_write(fptr, len, nosync)) {
1897 struct binwrite_arg arg;
1898
1899 arg.fptr = fptr;
1900 arg.ptr = ptr;
1901 arg.length = len;
1902
1903 if (!NIL_P(fptr->write_lock)) {
1904 return rb_mutex_synchronize(fptr->write_lock, io_binwrite_string, (VALUE)&arg);
1905 }
1906 else {
1907 return io_binwrite_string((VALUE)&arg);
1908 }
1909 }
1910 else {
1911 if (fptr->wbuf.off) {
1912 if (fptr->wbuf.len)
1913 MEMMOVE(fptr->wbuf.ptr, fptr->wbuf.ptr+fptr->wbuf.off, char, fptr->wbuf.len);
1914 fptr->wbuf.off = 0;
1915 }
1916
1917 MEMMOVE(fptr->wbuf.ptr+fptr->wbuf.off+fptr->wbuf.len, ptr, char, len);
1918 fptr->wbuf.len += (int)len;
1919
1920 return len;
1921 }
1922}
1923
1924# define MODE_BTMODE(a,b,c) ((fmode & FMODE_BINMODE) ? (b) : \
1925 (fmode & FMODE_TEXTMODE) ? (c) : (a))
1926
1927#define MODE_BTXMODE(a, b, c, d, e, f) ((fmode & FMODE_EXCL) ? \
1928 MODE_BTMODE(d, e, f) : \
1929 MODE_BTMODE(a, b, c))
1930
1931static VALUE
1932do_writeconv(VALUE str, rb_io_t *fptr, int *converted)
1933{
1934 if (NEED_WRITECONV(fptr)) {
1935 VALUE common_encoding = Qnil;
1936 SET_BINARY_MODE(fptr);
1937
1938 make_writeconv(fptr);
1939
1940 if (fptr->writeconv) {
1941#define fmode (fptr->mode)
1942 if (!NIL_P(fptr->writeconv_asciicompat))
1943 common_encoding = fptr->writeconv_asciicompat;
1944 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1) && !rb_enc_asciicompat(rb_enc_get(str))) {
1945 rb_raise(rb_eArgError, "ASCII incompatible string written for text mode IO without encoding conversion: %s",
1946 rb_enc_name(rb_enc_get(str)));
1947 }
1948#undef fmode
1949 }
1950 else {
1951 if (fptr->encs.enc2)
1952 common_encoding = rb_enc_from_encoding(fptr->encs.enc2);
1953 else if (fptr->encs.enc != rb_ascii8bit_encoding())
1954 common_encoding = rb_enc_from_encoding(fptr->encs.enc);
1955 }
1956
1957 if (!NIL_P(common_encoding)) {
1958 str = rb_str_encode(str, common_encoding,
1960 *converted = 1;
1961 }
1962
1963 if (fptr->writeconv) {
1965 *converted = 1;
1966 }
1967 }
1968#if RUBY_CRLF_ENVIRONMENT
1969#define fmode (fptr->mode)
1970 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1)) {
1971 if ((fptr->mode & FMODE_READABLE) &&
1973 setmode(fptr->fd, O_BINARY);
1974 }
1975 else {
1976 setmode(fptr->fd, O_TEXT);
1977 }
1978 if (!rb_enc_asciicompat(rb_enc_get(str))) {
1979 rb_raise(rb_eArgError, "ASCII incompatible string written for text mode IO without encoding conversion: %s",
1980 rb_enc_name(rb_enc_get(str)));
1981 }
1982 }
1983#undef fmode
1984#endif
1985 return str;
1986}
1987
1988static long
1989io_fwrite(VALUE str, rb_io_t *fptr, int nosync)
1990{
1991 int converted = 0;
1992 VALUE tmp;
1993 long n, len;
1994 const char *ptr;
1995
1996#ifdef _WIN32
1997 if (fptr->mode & FMODE_TTY) {
1998 long len = rb_w32_write_console(str, fptr->fd);
1999 if (len > 0) return len;
2000 }
2001#endif
2002
2003 str = do_writeconv(str, fptr, &converted);
2004 if (converted)
2005 OBJ_FREEZE(str);
2006
2007 tmp = rb_str_tmp_frozen_no_embed_acquire(str);
2008 RSTRING_GETMEM(tmp, ptr, len);
2009 n = io_binwrite(ptr, len, fptr, nosync);
2010 rb_str_tmp_frozen_release(str, tmp);
2011
2012 return n;
2013}
2014
2015ssize_t
2016rb_io_bufwrite(VALUE io, const void *buf, size_t size)
2017{
2018 rb_io_t *fptr;
2019
2020 GetOpenFile(io, fptr);
2022 return (ssize_t)io_binwrite(buf, (long)size, fptr, 0);
2023}
2024
2025static VALUE
2026io_write(VALUE io, VALUE str, int nosync)
2027{
2028 rb_io_t *fptr;
2029 long n;
2030 VALUE tmp;
2031
2032 io = GetWriteIO(io);
2033 str = rb_obj_as_string(str);
2034 tmp = rb_io_check_io(io);
2035
2036 if (NIL_P(tmp)) {
2037 /* port is not IO, call write method for it. */
2038 return rb_funcall(io, id_write, 1, str);
2039 }
2040
2041 io = tmp;
2042 if (RSTRING_LEN(str) == 0) return INT2FIX(0);
2043
2044 GetOpenFile(io, fptr);
2046
2047 n = io_fwrite(str, fptr, nosync);
2048 if (n < 0L) rb_sys_fail_on_write(fptr);
2049
2050 return LONG2FIX(n);
2051}
2052
2053#ifdef HAVE_WRITEV
2054struct binwritev_arg {
2055 rb_io_t *fptr;
2056 struct iovec *iov;
2057 int iovcnt;
2058 size_t total;
2059};
2060
2061static VALUE
2062io_binwritev_internal(VALUE arg)
2063{
2064 struct binwritev_arg *p = (struct binwritev_arg *)arg;
2065
2066 size_t remaining = p->total;
2067 size_t offset = 0;
2068
2069 rb_io_t *fptr = p->fptr;
2070 struct iovec *iov = p->iov;
2071 int iovcnt = p->iovcnt;
2072
2073 while (remaining) {
2074 long result = rb_writev_internal(fptr, iov, iovcnt);
2075
2076 if (result >= 0) {
2077 offset += result;
2078 if (fptr->wbuf.ptr && fptr->wbuf.len) {
2079 if (offset < (size_t)fptr->wbuf.len) {
2080 fptr->wbuf.off += result;
2081 fptr->wbuf.len -= result;
2082 }
2083 else {
2084 offset -= (size_t)fptr->wbuf.len;
2085 fptr->wbuf.off = 0;
2086 fptr->wbuf.len = 0;
2087 }
2088 }
2089
2090 if (offset == p->total) {
2091 return p->total;
2092 }
2093
2094 while (result >= (ssize_t)iov->iov_len) {
2095 /* iovcnt > 0 */
2096 result -= iov->iov_len;
2097 iov->iov_len = 0;
2098 iov++;
2099
2100 if (!--iovcnt) {
2101 // I don't believe this code path can ever occur.
2102 return offset;
2103 }
2104 }
2105
2106 iov->iov_base = (char *)iov->iov_base + result;
2107 iov->iov_len -= result;
2108 }
2109 else if (rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
2110 rb_io_check_closed(fptr);
2111 }
2112 else {
2113 return -1;
2114 }
2115 }
2116
2117 return offset;
2118}
2119
2120static long
2121io_binwritev(struct iovec *iov, int iovcnt, rb_io_t *fptr)
2122{
2123 // Don't write anything if current thread has a pending interrupt:
2125
2126 if (iovcnt == 0) return 0;
2127
2128 size_t total = 0;
2129 for (int i = 1; i < iovcnt; i++) total += iov[i].iov_len;
2130
2131 io_allocate_write_buffer(fptr, 1);
2132
2133 if (fptr->wbuf.ptr && fptr->wbuf.len) {
2134 // The end of the buffered data:
2135 size_t offset = fptr->wbuf.off + fptr->wbuf.len;
2136
2137 if (offset + total <= (size_t)fptr->wbuf.capa) {
2138 for (int i = 1; i < iovcnt; i++) {
2139 memcpy(fptr->wbuf.ptr+offset, iov[i].iov_base, iov[i].iov_len);
2140 offset += iov[i].iov_len;
2141 }
2142
2143 fptr->wbuf.len += total;
2144
2145 return total;
2146 }
2147 else {
2148 iov[0].iov_base = fptr->wbuf.ptr + fptr->wbuf.off;
2149 iov[0].iov_len = fptr->wbuf.len;
2150 }
2151 }
2152 else {
2153 // The first iov is reserved for the internal buffer, and it's empty.
2154 iov++;
2155
2156 if (!--iovcnt) {
2157 // If there are no other io vectors we are done.
2158 return 0;
2159 }
2160 }
2161
2162 struct binwritev_arg arg;
2163 arg.fptr = fptr;
2164 arg.iov = iov;
2165 arg.iovcnt = iovcnt;
2166 arg.total = total;
2167
2168 if (!NIL_P(fptr->write_lock)) {
2169 return rb_mutex_synchronize(fptr->write_lock, io_binwritev_internal, (VALUE)&arg);
2170 }
2171 else {
2172 return io_binwritev_internal((VALUE)&arg);
2173 }
2174}
2175
2176static long
2177io_fwritev(int argc, const VALUE *argv, rb_io_t *fptr)
2178{
2179 int i, converted, iovcnt = argc + 1;
2180 long n;
2181 VALUE v1, v2, str, tmp, *tmp_array;
2182 struct iovec *iov;
2183
2184 iov = ALLOCV_N(struct iovec, v1, iovcnt);
2185 tmp_array = ALLOCV_N(VALUE, v2, argc);
2186
2187 for (i = 0; i < argc; i++) {
2188 str = rb_obj_as_string(argv[i]);
2189 converted = 0;
2190 str = do_writeconv(str, fptr, &converted);
2191
2192 if (converted)
2193 OBJ_FREEZE(str);
2194
2195 tmp = rb_str_tmp_frozen_acquire(str);
2196 tmp_array[i] = tmp;
2197
2198 /* iov[0] is reserved for buffer of fptr */
2199 iov[i+1].iov_base = RSTRING_PTR(tmp);
2200 iov[i+1].iov_len = RSTRING_LEN(tmp);
2201 }
2202
2203 n = io_binwritev(iov, iovcnt, fptr);
2204 if (v1) ALLOCV_END(v1);
2205
2206 for (i = 0; i < argc; i++) {
2207 rb_str_tmp_frozen_release(argv[i], tmp_array[i]);
2208 }
2209
2210 if (v2) ALLOCV_END(v2);
2211
2212 return n;
2213}
2214
2215static int
2216iovcnt_ok(int iovcnt)
2217{
2218#ifdef IOV_MAX
2219 return iovcnt < IOV_MAX;
2220#else /* GNU/Hurd has writev, but no IOV_MAX */
2221 return 1;
2222#endif
2223}
2224#endif /* HAVE_WRITEV */
2225
2226static VALUE
2227io_writev(int argc, const VALUE *argv, VALUE io)
2228{
2229 rb_io_t *fptr;
2230 long n;
2231 VALUE tmp, total = INT2FIX(0);
2232 int i, cnt = 1;
2233
2234 io = GetWriteIO(io);
2235 tmp = rb_io_check_io(io);
2236
2237 if (NIL_P(tmp)) {
2238 /* port is not IO, call write method for it. */
2239 return rb_funcallv(io, id_write, argc, argv);
2240 }
2241
2242 io = tmp;
2243
2244 GetOpenFile(io, fptr);
2246
2247 for (i = 0; i < argc; i += cnt) {
2248#ifdef HAVE_WRITEV
2249 if ((fptr->mode & (FMODE_SYNC|FMODE_TTY)) && iovcnt_ok(cnt = argc - i)) {
2250 n = io_fwritev(cnt, &argv[i], fptr);
2251 }
2252 else
2253#endif
2254 {
2255 cnt = 1;
2256 /* sync at last item */
2257 n = io_fwrite(rb_obj_as_string(argv[i]), fptr, (i < argc-1));
2258 }
2259
2260 if (n < 0L)
2261 rb_sys_fail_on_write(fptr);
2262
2263 total = rb_fix_plus(LONG2FIX(n), total);
2264 }
2265
2266 return total;
2267}
2268
2269/*
2270 * call-seq:
2271 * write(*objects) -> integer
2272 *
2273 * Writes each of the given +objects+ to +self+,
2274 * which must be opened for writing
2275 * (see {Access Modes}[rdoc-ref:File@Access+Modes]);
2276 * returns the total number bytes written;
2277 * each of +objects+ that is not a string is converted via method +to_s+:
2278 *
2279 * $stdout.write('Hello', ', ', 'World!', "\n") # => 14
2280 * $stdout.write('foo', :bar, 2, "\n") # => 8
2281 *
2282 * Output:
2283 *
2284 * Hello, World!
2285 * foobar2
2286 *
2287 * Related: IO#read.
2288 */
2289
2290static VALUE
2291io_write_m(int argc, VALUE *argv, VALUE io)
2292{
2293 if (argc != 1) {
2294 return io_writev(argc, argv, io);
2295 }
2296 else {
2297 VALUE str = argv[0];
2298 return io_write(io, str, 0);
2299 }
2300}
2301
2302VALUE
2303rb_io_write(VALUE io, VALUE str)
2304{
2305 return rb_funcallv(io, id_write, 1, &str);
2306}
2307
2308static VALUE
2309rb_io_writev(VALUE io, int argc, const VALUE *argv)
2310{
2311 if (argc > 1 && rb_obj_method_arity(io, id_write) == 1) {
2312 if (io != rb_ractor_stderr() && RTEST(ruby_verbose)) {
2313 VALUE klass = CLASS_OF(io);
2314 char sep = RCLASS_SINGLETON_P(klass) ? (klass = io, '.') : '#';
2316 RB_WARN_CATEGORY_DEPRECATED, "%+"PRIsVALUE"%c""write is outdated interface"
2317 " which accepts just one argument",
2318 klass, sep
2319 );
2320 }
2321
2322 do rb_io_write(io, *argv++); while (--argc);
2323
2324 return Qnil;
2325 }
2326
2327 return rb_funcallv(io, id_write, argc, argv);
2328}
2329
2330/*
2331 * call-seq:
2332 * self << object -> self
2333 *
2334 * Writes the given +object+ to +self+,
2335 * which must be opened for writing (see {Access Modes}[rdoc-ref:File@Access+Modes]);
2336 * returns +self+;
2337 * if +object+ is not a string, it is converted via method +to_s+:
2338 *
2339 * $stdout << 'Hello' << ', ' << 'World!' << "\n"
2340 * $stdout << 'foo' << :bar << 2 << "\n"
2341 *
2342 * Output:
2343 *
2344 * Hello, World!
2345 * foobar2
2346 *
2347 */
2348
2349
2350VALUE
2352{
2353 rb_io_write(io, str);
2354 return io;
2355}
2356
2357#ifdef HAVE_FSYNC
2358static VALUE
2359nogvl_fsync(void *ptr)
2360{
2361 rb_io_t *fptr = ptr;
2362
2363#ifdef _WIN32
2364 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->fd)) != FILE_TYPE_DISK)
2365 return 0;
2366#endif
2367 return (VALUE)fsync(fptr->fd);
2368}
2369#endif
2370
2371VALUE
2372rb_io_flush_raw(VALUE io, int sync)
2373{
2374 rb_io_t *fptr;
2375
2376 if (!RB_TYPE_P(io, T_FILE)) {
2377 return rb_funcall(io, id_flush, 0);
2378 }
2379
2380 io = GetWriteIO(io);
2381 GetOpenFile(io, fptr);
2382
2383 if (fptr->mode & FMODE_WRITABLE) {
2384 if (io_fflush(fptr) < 0)
2385 rb_sys_fail_on_write(fptr);
2386 }
2387 if (fptr->mode & FMODE_READABLE) {
2388 io_unread(fptr, true);
2389 }
2390
2391 return io;
2392}
2393
2394/*
2395 * call-seq:
2396 * flush -> self
2397 *
2398 * Flushes data buffered in +self+ to the operating system
2399 * (but does not necessarily flush data buffered in the operating system):
2400 *
2401 * $stdout.print 'no newline' # Not necessarily flushed.
2402 * $stdout.flush # Flushed.
2403 *
2404 */
2405
2406VALUE
2407rb_io_flush(VALUE io)
2408{
2409 return rb_io_flush_raw(io, 1);
2410}
2411
2412/*
2413 * call-seq:
2414 * tell -> integer
2415 *
2416 * Returns the current position (in bytes) in +self+
2417 * (see {Position}[rdoc-ref:IO@Position]):
2418 *
2419 * f = File.open('t.txt')
2420 * f.tell # => 0
2421 * f.gets # => "First line\n"
2422 * f.tell # => 12
2423 * f.close
2424 *
2425 * Related: IO#pos=, IO#seek.
2426 */
2427
2428static VALUE
2429rb_io_tell(VALUE io)
2430{
2431 rb_io_t *fptr;
2432 rb_off_t pos;
2433
2434 GetOpenFile(io, fptr);
2435 pos = io_tell(fptr);
2436 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2437 pos -= fptr->rbuf.len;
2438 return OFFT2NUM(pos);
2439}
2440
2441static VALUE
2442rb_io_seek(VALUE io, VALUE offset, int whence)
2443{
2444 rb_io_t *fptr;
2445 rb_off_t pos;
2446
2447 pos = NUM2OFFT(offset);
2448 GetOpenFile(io, fptr);
2449 pos = io_seek(fptr, pos, whence);
2450 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2451
2452 return INT2FIX(0);
2453}
2454
2455static int
2456interpret_seek_whence(VALUE vwhence)
2457{
2458 if (vwhence == sym_SET)
2459 return SEEK_SET;
2460 if (vwhence == sym_CUR)
2461 return SEEK_CUR;
2462 if (vwhence == sym_END)
2463 return SEEK_END;
2464#ifdef SEEK_DATA
2465 if (vwhence == sym_DATA)
2466 return SEEK_DATA;
2467#endif
2468#ifdef SEEK_HOLE
2469 if (vwhence == sym_HOLE)
2470 return SEEK_HOLE;
2471#endif
2472 return NUM2INT(vwhence);
2473}
2474
2475/*
2476 * call-seq:
2477 * seek(offset, whence = IO::SEEK_SET) -> 0
2478 *
2479 * Seeks to the position given by integer +offset+
2480 * (see {Position}[rdoc-ref:IO@Position])
2481 * and constant +whence+, which is one of:
2482 *
2483 * - +:CUR+ or <tt>IO::SEEK_CUR</tt>:
2484 * Repositions the stream to its current position plus the given +offset+:
2485 *
2486 * f = File.open('t.txt')
2487 * f.tell # => 0
2488 * f.seek(20, :CUR) # => 0
2489 * f.tell # => 20
2490 * f.seek(-10, :CUR) # => 0
2491 * f.tell # => 10
2492 * f.close
2493 *
2494 * - +:END+ or <tt>IO::SEEK_END</tt>:
2495 * Repositions the stream to its end plus the given +offset+:
2496 *
2497 * f = File.open('t.txt')
2498 * f.tell # => 0
2499 * f.seek(0, :END) # => 0 # Repositions to stream end.
2500 * f.tell # => 52
2501 * f.seek(-20, :END) # => 0
2502 * f.tell # => 32
2503 * f.seek(-40, :END) # => 0
2504 * f.tell # => 12
2505 * f.close
2506 *
2507 * - +:SET+ or <tt>IO:SEEK_SET</tt>:
2508 * Repositions the stream to the given +offset+:
2509 *
2510 * f = File.open('t.txt')
2511 * f.tell # => 0
2512 * f.seek(20, :SET) # => 0
2513 * f.tell # => 20
2514 * f.seek(40, :SET) # => 0
2515 * f.tell # => 40
2516 * f.close
2517 *
2518 * Related: IO#pos=, IO#tell.
2519 *
2520 */
2521
2522static VALUE
2523rb_io_seek_m(int argc, VALUE *argv, VALUE io)
2524{
2525 VALUE offset, ptrname;
2526 int whence = SEEK_SET;
2527
2528 if (rb_scan_args(argc, argv, "11", &offset, &ptrname) == 2) {
2529 whence = interpret_seek_whence(ptrname);
2530 }
2531
2532 return rb_io_seek(io, offset, whence);
2533}
2534
2535/*
2536 * call-seq:
2537 * pos = new_position -> new_position
2538 *
2539 * Seeks to the given +new_position+ (in bytes);
2540 * see {Position}[rdoc-ref:IO@Position]:
2541 *
2542 * f = File.open('t.txt')
2543 * f.tell # => 0
2544 * f.pos = 20 # => 20
2545 * f.tell # => 20
2546 * f.close
2547 *
2548 * Related: IO#seek, IO#tell.
2549 *
2550 */
2551
2552static VALUE
2553rb_io_set_pos(VALUE io, VALUE offset)
2554{
2555 rb_io_t *fptr;
2556 rb_off_t pos;
2557
2558 pos = NUM2OFFT(offset);
2559 GetOpenFile(io, fptr);
2560 pos = io_seek(fptr, pos, SEEK_SET);
2561 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2562
2563 return OFFT2NUM(pos);
2564}
2565
2566static void clear_readconv(rb_io_t *fptr);
2567
2568/*
2569 * call-seq:
2570 * rewind -> 0
2571 *
2572 * Repositions the stream to its beginning,
2573 * setting both the position and the line number to zero;
2574 * see {Position}[rdoc-ref:IO@Position]
2575 * and {Line Number}[rdoc-ref:IO@Line+Number]:
2576 *
2577 * f = File.open('t.txt')
2578 * f.tell # => 0
2579 * f.lineno # => 0
2580 * f.gets # => "First line\n"
2581 * f.tell # => 12
2582 * f.lineno # => 1
2583 * f.rewind # => 0
2584 * f.tell # => 0
2585 * f.lineno # => 0
2586 * f.close
2587 *
2588 * Note that this method cannot be used with streams such as pipes, ttys, and sockets.
2589 *
2590 */
2591
2592static VALUE
2593rb_io_rewind(VALUE io)
2594{
2595 rb_io_t *fptr;
2596
2597 GetOpenFile(io, fptr);
2598 if (io_seek(fptr, 0L, 0) < 0 && errno) rb_sys_fail_path(fptr->pathv);
2599 if (io == ARGF.current_file) {
2600 ARGF.lineno -= fptr->lineno;
2601 }
2602 fptr->lineno = 0;
2603 if (fptr->readconv) {
2604 clear_readconv(fptr);
2605 }
2606
2607 return INT2FIX(0);
2608}
2609
2610static int
2611fptr_wait_readable(rb_io_t *fptr)
2612{
2613 int result = rb_io_maybe_wait_readable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT);
2614
2615 if (result)
2616 rb_io_check_closed(fptr);
2617
2618 return result;
2619}
2620
2621static int
2622io_fillbuf(rb_io_t *fptr)
2623{
2624 ssize_t r;
2625
2626 if (fptr->rbuf.ptr == NULL) {
2627 fptr->rbuf.off = 0;
2628 fptr->rbuf.len = 0;
2629 fptr->rbuf.capa = IO_RBUF_CAPA_FOR(fptr);
2630 fptr->rbuf.ptr = ALLOC_N(char, fptr->rbuf.capa);
2631#ifdef _WIN32
2632 fptr->rbuf.capa--;
2633#endif
2634 }
2635 if (fptr->rbuf.len == 0) {
2636 retry:
2637 r = rb_io_read_memory(fptr, fptr->rbuf.ptr, fptr->rbuf.capa);
2638
2639 if (r < 0) {
2640 if (fptr_wait_readable(fptr))
2641 goto retry;
2642
2643 int e = errno;
2644 VALUE path = rb_sprintf("fd:%d ", fptr->fd);
2645 if (!NIL_P(fptr->pathv)) {
2646 rb_str_append(path, fptr->pathv);
2647 }
2648
2649 rb_syserr_fail_path(e, path);
2650 }
2651 if (r > 0) rb_io_check_closed(fptr);
2652 fptr->rbuf.off = 0;
2653 fptr->rbuf.len = (int)r; /* r should be <= rbuf_capa */
2654 if (r == 0)
2655 return -1; /* EOF */
2656 }
2657 return 0;
2658}
2659
2660/*
2661 * call-seq:
2662 * eof -> true or false
2663 *
2664 * Returns +true+ if the stream is positioned at its end, +false+ otherwise;
2665 * see {Position}[rdoc-ref:IO@Position]:
2666 *
2667 * f = File.open('t.txt')
2668 * f.eof # => false
2669 * f.seek(0, :END) # => 0
2670 * f.eof # => true
2671 * f.close
2672 *
2673 * Raises an exception unless the stream is opened for reading;
2674 * see {Mode}[rdoc-ref:File@Access+Modes].
2675 *
2676 * If +self+ is a stream such as pipe or socket, this method
2677 * blocks until the other end sends some data or closes it:
2678 *
2679 * r, w = IO.pipe
2680 * Thread.new { sleep 1; w.close }
2681 * r.eof? # => true # After 1-second wait.
2682 *
2683 * r, w = IO.pipe
2684 * Thread.new { sleep 1; w.puts "a" }
2685 * r.eof? # => false # After 1-second wait.
2686 *
2687 * r, w = IO.pipe
2688 * r.eof? # blocks forever
2689 *
2690 * Note that this method reads data to the input byte buffer. So
2691 * IO#sysread may not behave as you intend with IO#eof?, unless you
2692 * call IO#rewind first (which is not available for some streams).
2693 */
2694
2695VALUE
2697{
2698 rb_io_t *fptr;
2699
2700 GetOpenFile(io, fptr);
2702
2703 if (READ_CHAR_PENDING(fptr)) return Qfalse;
2704 if (READ_DATA_PENDING(fptr)) return Qfalse;
2705 READ_CHECK(fptr);
2706#if RUBY_CRLF_ENVIRONMENT
2707 if (!NEED_READCONV(fptr) && NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
2708 return RBOOL(eof(fptr->fd));
2709 }
2710#endif
2711 return RBOOL(io_fillbuf(fptr) < 0);
2712}
2713
2714/*
2715 * call-seq:
2716 * sync -> true or false
2717 *
2718 * Returns the current sync mode of the stream.
2719 * When sync mode is true, all output is immediately flushed to the underlying
2720 * operating system and is not buffered by Ruby internally. See also #fsync.
2721 *
2722 * f = File.open('t.tmp', 'w')
2723 * f.sync # => false
2724 * f.sync = true
2725 * f.sync # => true
2726 * f.close
2727 *
2728 */
2729
2730static VALUE
2731rb_io_sync(VALUE io)
2732{
2733 rb_io_t *fptr;
2734
2735 io = GetWriteIO(io);
2736 GetOpenFile(io, fptr);
2737 return RBOOL(fptr->mode & FMODE_SYNC);
2738}
2739
2740#ifdef HAVE_FSYNC
2741
2742/*
2743 * call-seq:
2744 * sync = boolean -> boolean
2745 *
2746 * Sets the _sync_ _mode_ for the stream to the given value;
2747 * returns the given value.
2748 *
2749 * Values for the sync mode:
2750 *
2751 * - +true+: All output is immediately flushed to the
2752 * underlying operating system and is not buffered internally.
2753 * - +false+: Output may be buffered internally.
2754 *
2755 * Example;
2756 *
2757 * f = File.open('t.tmp', 'w')
2758 * f.sync # => false
2759 * f.sync = true
2760 * f.sync # => true
2761 * f.close
2762 *
2763 * Related: IO#fsync.
2764 *
2765 */
2766
2767static VALUE
2768rb_io_set_sync(VALUE io, VALUE sync)
2769{
2770 rb_io_t *fptr;
2771
2772 io = GetWriteIO(io);
2773 GetOpenFile(io, fptr);
2774 if (RTEST(sync)) {
2775 fptr->mode |= FMODE_SYNC;
2776 }
2777 else {
2778 fptr->mode &= ~FMODE_SYNC;
2779 }
2780 return sync;
2781}
2782
2783/*
2784 * call-seq:
2785 * fsync -> 0
2786 *
2787 * Immediately writes to disk all data buffered in the stream,
2788 * via the operating system's <tt>fsync(2)</tt>.
2789
2790 * Note this difference:
2791 *
2792 * - IO#sync=: Ensures that data is flushed from the stream's internal buffers,
2793 * but does not guarantee that the operating system actually writes the data to disk.
2794 * - IO#fsync: Ensures both that data is flushed from internal buffers,
2795 * and that data is written to disk.
2796 *
2797 * Raises an exception if the operating system does not support <tt>fsync(2)</tt>.
2798 *
2799 */
2800
2801static VALUE
2802rb_io_fsync(VALUE io)
2803{
2804 rb_io_t *fptr;
2805
2806 io = GetWriteIO(io);
2807 GetOpenFile(io, fptr);
2808
2809 if (io_fflush(fptr) < 0)
2810 rb_sys_fail_on_write(fptr);
2811
2812 if ((int)rb_io_blocking_region(fptr, nogvl_fsync, fptr))
2813 rb_sys_fail_path(fptr->pathv);
2814
2815 return INT2FIX(0);
2816}
2817#else
2818# define rb_io_fsync rb_f_notimplement
2819# define rb_io_sync rb_f_notimplement
2820static VALUE
2821rb_io_set_sync(VALUE io, VALUE sync)
2822{
2825}
2826#endif
2827
2828#ifdef HAVE_FDATASYNC
2829static VALUE
2830nogvl_fdatasync(void *ptr)
2831{
2832 rb_io_t *fptr = ptr;
2833
2834#ifdef _WIN32
2835 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->fd)) != FILE_TYPE_DISK)
2836 return 0;
2837#endif
2838 return (VALUE)fdatasync(fptr->fd);
2839}
2840
2841/*
2842 * call-seq:
2843 * fdatasync -> 0
2844 *
2845 * Immediately writes to disk all data buffered in the stream,
2846 * via the operating system's: <tt>fdatasync(2)</tt>, if supported,
2847 * otherwise via <tt>fsync(2)</tt>, if supported;
2848 * otherwise raises an exception.
2849 *
2850 */
2851
2852static VALUE
2853rb_io_fdatasync(VALUE io)
2854{
2855 rb_io_t *fptr;
2856
2857 io = GetWriteIO(io);
2858 GetOpenFile(io, fptr);
2859
2860 if (io_fflush(fptr) < 0)
2861 rb_sys_fail_on_write(fptr);
2862
2863 if ((int)rb_io_blocking_region(fptr, nogvl_fdatasync, fptr) == 0)
2864 return INT2FIX(0);
2865
2866 /* fall back */
2867 return rb_io_fsync(io);
2868}
2869#else
2870#define rb_io_fdatasync rb_io_fsync
2871#endif
2872
2873/*
2874 * call-seq:
2875 * fileno -> integer
2876 *
2877 * Returns the integer file descriptor for the stream:
2878 *
2879 * $stdin.fileno # => 0
2880 * $stdout.fileno # => 1
2881 * $stderr.fileno # => 2
2882 * File.open('t.txt').fileno # => 10
2883 * f.close
2884 *
2885 */
2886
2887static VALUE
2888rb_io_fileno(VALUE io)
2889{
2890 rb_io_t *fptr = RFILE(io)->fptr;
2891 int fd;
2892
2893 rb_io_check_closed(fptr);
2894 fd = fptr->fd;
2895 return INT2FIX(fd);
2896}
2897
2898int
2900{
2901 if (RB_TYPE_P(io, T_FILE)) {
2902 rb_io_t *fptr = RFILE(io)->fptr;
2903 rb_io_check_closed(fptr);
2904 return fptr->fd;
2905 }
2906 else {
2907 VALUE fileno = rb_check_funcall(io, id_fileno, 0, NULL);
2908 if (!UNDEF_P(fileno)) {
2909 return RB_NUM2INT(fileno);
2910 }
2911 }
2912
2913 rb_raise(rb_eTypeError, "expected IO or #fileno, %"PRIsVALUE" given", rb_obj_class(io));
2914
2916}
2917
2918int
2919rb_io_mode(VALUE io)
2920{
2921 rb_io_t *fptr;
2922 GetOpenFile(io, fptr);
2923 return fptr->mode;
2924}
2925
2926/*
2927 * call-seq:
2928 * pid -> integer or nil
2929 *
2930 * Returns the process ID of a child process associated with the stream,
2931 * which will have been set by IO#popen, or +nil+ if the stream was not
2932 * created by IO#popen:
2933 *
2934 * pipe = IO.popen("-")
2935 * if pipe
2936 * $stderr.puts "In parent, child pid is #{pipe.pid}"
2937 * else
2938 * $stderr.puts "In child, pid is #{$$}"
2939 * end
2940 *
2941 * Output:
2942 *
2943 * In child, pid is 26209
2944 * In parent, child pid is 26209
2945 *
2946 */
2947
2948static VALUE
2949rb_io_pid(VALUE io)
2950{
2951 rb_io_t *fptr;
2952
2953 GetOpenFile(io, fptr);
2954 if (!fptr->pid)
2955 return Qnil;
2956 return PIDT2NUM(fptr->pid);
2957}
2958
2959/*
2960 * call-seq:
2961 * path -> string or nil
2962 *
2963 * Returns the path associated with the IO, or +nil+ if there is no path
2964 * associated with the IO. It is not guaranteed that the path exists on
2965 * the filesystem.
2966 *
2967 * $stdin.path # => "<STDIN>"
2968 *
2969 * File.open("testfile") {|f| f.path} # => "testfile"
2970 */
2971
2972VALUE
2974{
2975 rb_io_t *fptr = RFILE(io)->fptr;
2976
2977 if (!fptr)
2978 return Qnil;
2979
2980 return rb_obj_dup(fptr->pathv);
2981}
2982
2983/*
2984 * call-seq:
2985 * inspect -> string
2986 *
2987 * Returns a string representation of +self+:
2988 *
2989 * f = File.open('t.txt')
2990 * f.inspect # => "#<File:t.txt>"
2991 * f.close
2992 *
2993 */
2994
2995static VALUE
2996rb_io_inspect(VALUE obj)
2997{
2998 rb_io_t *fptr;
2999 VALUE result;
3000 static const char closed[] = " (closed)";
3001
3002 fptr = RFILE(obj)->fptr;
3003 if (!fptr) return rb_any_to_s(obj);
3004 result = rb_str_new_cstr("#<");
3005 rb_str_append(result, rb_class_name(CLASS_OF(obj)));
3006 rb_str_cat2(result, ":");
3007 if (NIL_P(fptr->pathv)) {
3008 if (fptr->fd < 0) {
3009 rb_str_cat(result, closed+1, strlen(closed)-1);
3010 }
3011 else {
3012 rb_str_catf(result, "fd %d", fptr->fd);
3013 }
3014 }
3015 else {
3016 rb_str_append(result, fptr->pathv);
3017 if (fptr->fd < 0) {
3018 rb_str_cat(result, closed, strlen(closed));
3019 }
3020 }
3021 return rb_str_cat2(result, ">");
3022}
3023
3024/*
3025 * call-seq:
3026 * to_io -> self
3027 *
3028 * Returns +self+.
3029 *
3030 */
3031
3032static VALUE
3033rb_io_to_io(VALUE io)
3034{
3035 return io;
3036}
3037
3038/* reading functions */
3039static long
3040read_buffered_data(char *ptr, long len, rb_io_t *fptr)
3041{
3042 int n;
3043
3044 n = READ_DATA_PENDING_COUNT(fptr);
3045 if (n <= 0) return 0;
3046 if (n > len) n = (int)len;
3047 MEMMOVE(ptr, fptr->rbuf.ptr+fptr->rbuf.off, char, n);
3048 fptr->rbuf.off += n;
3049 fptr->rbuf.len -= n;
3050 return n;
3051}
3052
3053static long
3054io_bufread(char *ptr, long len, rb_io_t *fptr)
3055{
3056 long offset = 0;
3057 long n = len;
3058 long c;
3059
3060 if (READ_DATA_PENDING(fptr) == 0) {
3061 while (n > 0) {
3062 again:
3063 rb_io_check_closed(fptr);
3064 c = rb_io_read_memory(fptr, ptr+offset, n);
3065 if (c == 0) break;
3066 if (c < 0) {
3067 if (fptr_wait_readable(fptr))
3068 goto again;
3069 return -1;
3070 }
3071 offset += c;
3072 if ((n -= c) <= 0) break;
3073 }
3074 return len - n;
3075 }
3076
3077 while (n > 0) {
3078 c = read_buffered_data(ptr+offset, n, fptr);
3079 if (c > 0) {
3080 offset += c;
3081 if ((n -= c) <= 0) break;
3082 }
3083 rb_io_check_closed(fptr);
3084 if (io_fillbuf(fptr) < 0) {
3085 break;
3086 }
3087 }
3088 return len - n;
3089}
3090
3091static int io_setstrbuf(VALUE *str, long len);
3092
3094 char *str_ptr;
3095 long len;
3096 rb_io_t *fptr;
3097};
3098
3099static VALUE
3100bufread_call(VALUE arg)
3101{
3102 struct bufread_arg *p = (struct bufread_arg *)arg;
3103 p->len = io_bufread(p->str_ptr, p->len, p->fptr);
3104 return Qundef;
3105}
3106
3107static long
3108io_fread(VALUE str, long offset, long size, rb_io_t *fptr)
3109{
3110 long len;
3111 struct bufread_arg arg;
3112
3113 io_setstrbuf(&str, offset + size);
3114 arg.str_ptr = RSTRING_PTR(str) + offset;
3115 arg.len = size;
3116 arg.fptr = fptr;
3117 rb_str_locktmp_ensure(str, bufread_call, (VALUE)&arg);
3118 len = arg.len;
3119 if (len < 0) rb_sys_fail_path(fptr->pathv);
3120 return len;
3121}
3122
3123static long
3124remain_size(rb_io_t *fptr)
3125{
3126 struct stat st;
3127 rb_off_t siz = READ_DATA_PENDING_COUNT(fptr);
3128 rb_off_t pos;
3129
3130 if (fstat(fptr->fd, &st) == 0 && S_ISREG(st.st_mode)
3131#if defined(__HAIKU__)
3132 && (st.st_dev > 3)
3133#endif
3134 )
3135 {
3136 if (io_fflush(fptr) < 0)
3137 rb_sys_fail_on_write(fptr);
3138 pos = lseek(fptr->fd, 0, SEEK_CUR);
3139 if (st.st_size >= pos && pos >= 0) {
3140 siz += st.st_size - pos;
3141 if (siz > LONG_MAX) {
3142 rb_raise(rb_eIOError, "file too big for single read");
3143 }
3144 }
3145 }
3146 else {
3147 siz += BUFSIZ;
3148 }
3149 return (long)siz;
3150}
3151
3152static VALUE
3153io_enc_str(VALUE str, rb_io_t *fptr)
3154{
3155 rb_enc_associate(str, io_read_encoding(fptr));
3156 return str;
3157}
3158
3159static rb_encoding *io_read_encoding(rb_io_t *fptr);
3160
3161static void
3162make_readconv(rb_io_t *fptr, int size)
3163{
3164 if (!fptr->readconv) {
3165 int ecflags;
3166 VALUE ecopts;
3167 const char *sname, *dname;
3168 ecflags = fptr->encs.ecflags & ~ECONV_NEWLINE_DECORATOR_WRITE_MASK;
3169 ecopts = fptr->encs.ecopts;
3170 if (fptr->encs.enc2) {
3171 sname = rb_enc_name(fptr->encs.enc2);
3172 dname = rb_enc_name(io_read_encoding(fptr));
3173 }
3174 else {
3175 sname = dname = "";
3176 }
3177 fptr->readconv = rb_econv_open_opts(sname, dname, ecflags, ecopts);
3178 if (!fptr->readconv)
3179 rb_exc_raise(rb_econv_open_exc(sname, dname, ecflags));
3180 fptr->cbuf.off = 0;
3181 fptr->cbuf.len = 0;
3182 if (size < IO_CBUF_CAPA_MIN) size = IO_CBUF_CAPA_MIN;
3183 fptr->cbuf.capa = size;
3184 fptr->cbuf.ptr = ALLOC_N(char, fptr->cbuf.capa);
3185 }
3186}
3187
3188#define MORE_CHAR_SUSPENDED Qtrue
3189#define MORE_CHAR_FINISHED Qnil
3190static VALUE
3191fill_cbuf(rb_io_t *fptr, int ec_flags)
3192{
3193 const unsigned char *ss, *sp, *se;
3194 unsigned char *ds, *dp, *de;
3196 int putbackable;
3197 int cbuf_len0;
3198 VALUE exc;
3199
3200 ec_flags |= ECONV_PARTIAL_INPUT;
3201
3202 if (fptr->cbuf.len == fptr->cbuf.capa)
3203 return MORE_CHAR_SUSPENDED; /* cbuf full */
3204 if (fptr->cbuf.len == 0)
3205 fptr->cbuf.off = 0;
3206 else if (fptr->cbuf.off + fptr->cbuf.len == fptr->cbuf.capa) {
3207 memmove(fptr->cbuf.ptr, fptr->cbuf.ptr+fptr->cbuf.off, fptr->cbuf.len);
3208 fptr->cbuf.off = 0;
3209 }
3210
3211 cbuf_len0 = fptr->cbuf.len;
3212
3213 while (1) {
3214 ss = sp = (const unsigned char *)fptr->rbuf.ptr + fptr->rbuf.off;
3215 se = sp + fptr->rbuf.len;
3216 ds = dp = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.off + fptr->cbuf.len;
3217 de = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.capa;
3218 res = rb_econv_convert(fptr->readconv, &sp, se, &dp, de, ec_flags);
3219 fptr->rbuf.off += (int)(sp - ss);
3220 fptr->rbuf.len -= (int)(sp - ss);
3221 fptr->cbuf.len += (int)(dp - ds);
3222
3223 putbackable = rb_econv_putbackable(fptr->readconv);
3224 if (putbackable) {
3225 rb_econv_putback(fptr->readconv, (unsigned char *)fptr->rbuf.ptr + fptr->rbuf.off - putbackable, putbackable);
3226 fptr->rbuf.off -= putbackable;
3227 fptr->rbuf.len += putbackable;
3228 }
3229
3230 exc = rb_econv_make_exception(fptr->readconv);
3231 if (!NIL_P(exc))
3232 return exc;
3233
3234 if (cbuf_len0 != fptr->cbuf.len)
3235 return MORE_CHAR_SUSPENDED;
3236
3237 if (res == econv_finished) {
3238 return MORE_CHAR_FINISHED;
3239 }
3240
3241 if (res == econv_source_buffer_empty) {
3242 if (fptr->rbuf.len == 0) {
3243 READ_CHECK(fptr);
3244 if (io_fillbuf(fptr) < 0) {
3245 if (!fptr->readconv) {
3246 return MORE_CHAR_FINISHED;
3247 }
3248 ds = dp = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.off + fptr->cbuf.len;
3249 de = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.capa;
3250 res = rb_econv_convert(fptr->readconv, NULL, NULL, &dp, de, 0);
3251 fptr->cbuf.len += (int)(dp - ds);
3253 break;
3254 }
3255 }
3256 }
3257 }
3258 if (cbuf_len0 != fptr->cbuf.len)
3259 return MORE_CHAR_SUSPENDED;
3260
3261 return MORE_CHAR_FINISHED;
3262}
3263
3264static VALUE
3265more_char(rb_io_t *fptr)
3266{
3267 VALUE v;
3268 v = fill_cbuf(fptr, ECONV_AFTER_OUTPUT);
3269 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED)
3270 rb_exc_raise(v);
3271 return v;
3272}
3273
3274static VALUE
3275io_shift_cbuf(rb_io_t *fptr, int len, VALUE *strp)
3276{
3277 VALUE str = Qnil;
3278 if (strp) {
3279 str = *strp;
3280 if (NIL_P(str)) {
3281 *strp = str = rb_str_new(fptr->cbuf.ptr+fptr->cbuf.off, len);
3282 }
3283 else {
3284 rb_str_cat(str, fptr->cbuf.ptr+fptr->cbuf.off, len);
3285 }
3286 rb_enc_associate(str, fptr->encs.enc);
3287 }
3288 fptr->cbuf.off += len;
3289 fptr->cbuf.len -= len;
3290 /* xxx: set coderange */
3291 if (fptr->cbuf.len == 0)
3292 fptr->cbuf.off = 0;
3293 else if (fptr->cbuf.capa/2 < fptr->cbuf.off) {
3294 memmove(fptr->cbuf.ptr, fptr->cbuf.ptr+fptr->cbuf.off, fptr->cbuf.len);
3295 fptr->cbuf.off = 0;
3296 }
3297 return str;
3298}
3299
3300static int
3301io_setstrbuf(VALUE *str, long len)
3302{
3303#ifdef _WIN32
3304 if (len > 0)
3305 len = (len + 1) & ~1L; /* round up for wide char */
3306#endif
3307 if (NIL_P(*str)) {
3308 *str = rb_str_new(0, len);
3309 return TRUE;
3310 }
3311 else {
3312 VALUE s = StringValue(*str);
3313 rb_str_modify(s);
3314
3315 long clen = RSTRING_LEN(s);
3316 if (clen >= len) {
3317 return FALSE;
3318 }
3319 len -= clen;
3320 }
3321 if ((rb_str_capacity(*str) - (size_t)RSTRING_LEN(*str)) < (size_t)len) {
3323 }
3324 return FALSE;
3325}
3326
3327#define MAX_REALLOC_GAP 4096
3328static void
3329io_shrink_read_string(VALUE str, long n)
3330{
3331 if (rb_str_capacity(str) - n > MAX_REALLOC_GAP) {
3332 rb_str_resize(str, n);
3333 }
3334}
3335
3336static void
3337io_set_read_length(VALUE str, long n, int shrinkable)
3338{
3339 if (RSTRING_LEN(str) != n) {
3340 rb_str_modify(str);
3341 rb_str_set_len(str, n);
3342 if (shrinkable) io_shrink_read_string(str, n);
3343 }
3344}
3345
3346static VALUE
3347read_all(rb_io_t *fptr, long siz, VALUE str)
3348{
3349 long bytes;
3350 long n;
3351 long pos;
3352 rb_encoding *enc;
3353 int cr;
3354 int shrinkable;
3355
3356 if (NEED_READCONV(fptr)) {
3357 int first = !NIL_P(str);
3358 SET_BINARY_MODE(fptr);
3359 shrinkable = io_setstrbuf(&str,0);
3360 make_readconv(fptr, 0);
3361 while (1) {
3362 VALUE v;
3363 if (fptr->cbuf.len) {
3364 if (first) rb_str_set_len(str, first = 0);
3365 io_shift_cbuf(fptr, fptr->cbuf.len, &str);
3366 }
3367 v = fill_cbuf(fptr, 0);
3368 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED) {
3369 if (fptr->cbuf.len) {
3370 if (first) rb_str_set_len(str, first = 0);
3371 io_shift_cbuf(fptr, fptr->cbuf.len, &str);
3372 }
3373 rb_exc_raise(v);
3374 }
3375 if (v == MORE_CHAR_FINISHED) {
3376 clear_readconv(fptr);
3377 if (first) rb_str_set_len(str, first = 0);
3378 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3379 return io_enc_str(str, fptr);
3380 }
3381 }
3382 }
3383
3384 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3385 bytes = 0;
3386 pos = 0;
3387
3388 enc = io_read_encoding(fptr);
3389 cr = 0;
3390
3391 if (siz == 0) siz = BUFSIZ;
3392 shrinkable = io_setstrbuf(&str, siz);
3393 for (;;) {
3394 READ_CHECK(fptr);
3395 n = io_fread(str, bytes, siz - bytes, fptr);
3396 if (n == 0 && bytes == 0) {
3397 rb_str_set_len(str, 0);
3398 break;
3399 }
3400 bytes += n;
3401 rb_str_set_len(str, bytes);
3402 if (cr != ENC_CODERANGE_BROKEN)
3403 pos += rb_str_coderange_scan_restartable(RSTRING_PTR(str) + pos, RSTRING_PTR(str) + bytes, enc, &cr);
3404 if (bytes < siz) break;
3405 siz += BUFSIZ;
3406
3407 size_t capa = rb_str_capacity(str);
3408 if (capa < (size_t)RSTRING_LEN(str) + BUFSIZ) {
3409 if (capa < BUFSIZ) {
3410 capa = BUFSIZ;
3411 }
3412 else if (capa > IO_MAX_BUFFER_GROWTH) {
3413 capa = IO_MAX_BUFFER_GROWTH;
3414 }
3416 }
3417 }
3418 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3419 str = io_enc_str(str, fptr);
3420 ENC_CODERANGE_SET(str, cr);
3421 return str;
3422}
3423
3424void
3426{
3427 if (rb_fd_set_nonblock(fptr->fd) != 0) {
3428 rb_sys_fail_path(fptr->pathv);
3429 }
3430}
3431
3432static VALUE
3433io_read_memory_call(VALUE arg)
3434{
3435 struct io_internal_read_struct *iis = (struct io_internal_read_struct *)arg;
3436
3437 VALUE scheduler = rb_fiber_scheduler_current();
3438 if (scheduler != Qnil) {
3439 VALUE result = rb_fiber_scheduler_io_read_memory(scheduler, iis->fptr->self, iis->buf, iis->capa, 0);
3440
3441 if (!UNDEF_P(result)) {
3442 // This is actually returned as a pseudo-VALUE and later cast to a long:
3444 }
3445 }
3446
3447 if (iis->nonblock) {
3448 return rb_io_blocking_region(iis->fptr, internal_read_func, iis);
3449 }
3450 else {
3451 return rb_io_blocking_region_wait(iis->fptr, internal_read_func, iis, RUBY_IO_READABLE);
3452 }
3453}
3454
3455static long
3456io_read_memory_locktmp(VALUE str, struct io_internal_read_struct *iis)
3457{
3458 return (long)rb_str_locktmp_ensure(str, io_read_memory_call, (VALUE)iis);
3459}
3460
3461#define no_exception_p(opts) !rb_opts_exception_p((opts), TRUE)
3462
3463static VALUE
3464io_getpartial(int argc, VALUE *argv, VALUE io, int no_exception, int nonblock)
3465{
3466 rb_io_t *fptr;
3467 VALUE length, str;
3468 long n, len;
3469 struct io_internal_read_struct iis;
3470 int shrinkable;
3471
3472 rb_scan_args(argc, argv, "11", &length, &str);
3473
3474 if ((len = NUM2LONG(length)) < 0) {
3475 rb_raise(rb_eArgError, "negative length %ld given", len);
3476 }
3477
3478 shrinkable = io_setstrbuf(&str, len);
3479
3480 GetOpenFile(io, fptr);
3482
3483 if (len == 0) {
3484 io_set_read_length(str, 0, shrinkable);
3485 return str;
3486 }
3487
3488 if (!nonblock)
3489 READ_CHECK(fptr);
3490 n = read_buffered_data(RSTRING_PTR(str), len, fptr);
3491 if (n <= 0) {
3492 again:
3493 if (nonblock) {
3494 rb_io_set_nonblock(fptr);
3495 }
3496 io_setstrbuf(&str, len);
3497 iis.th = rb_thread_current();
3498 iis.fptr = fptr;
3499 iis.nonblock = nonblock;
3500 iis.fd = fptr->fd;
3501 iis.buf = RSTRING_PTR(str);
3502 iis.capa = len;
3503 iis.timeout = NULL;
3504 n = io_read_memory_locktmp(str, &iis);
3505 if (n < 0) {
3506 int e = errno;
3507 if (!nonblock && fptr_wait_readable(fptr))
3508 goto again;
3509 if (nonblock && (io_again_p(e))) {
3510 if (no_exception)
3511 return sym_wait_readable;
3512 else
3513 rb_readwrite_syserr_fail(RB_IO_WAIT_READABLE,
3514 e, "read would block");
3515 }
3516 rb_syserr_fail_path(e, fptr->pathv);
3517 }
3518 }
3519 io_set_read_length(str, n, shrinkable);
3520
3521 if (n == 0)
3522 return Qnil;
3523 else
3524 return str;
3525}
3526
3527/*
3528 * call-seq:
3529 * readpartial(maxlen) -> string
3530 * readpartial(maxlen, out_string) -> out_string
3531 *
3532 * Reads up to +maxlen+ bytes from the stream;
3533 * returns a string (either a new string or the given +out_string+).
3534 * Its encoding is:
3535 *
3536 * - The unchanged encoding of +out_string+, if +out_string+ is given.
3537 * - ASCII-8BIT, otherwise.
3538 *
3539 * - Contains +maxlen+ bytes from the stream, if available.
3540 * - Otherwise contains all available bytes, if any available.
3541 * - Otherwise is an empty string.
3542 *
3543 * With the single non-negative integer argument +maxlen+ given,
3544 * returns a new string:
3545 *
3546 * f = File.new('t.txt')
3547 * f.readpartial(20) # => "First line\nSecond l"
3548 * f.readpartial(20) # => "ine\n\nFourth line\n"
3549 * f.readpartial(20) # => "Fifth line\n"
3550 * f.readpartial(20) # Raises EOFError.
3551 * f.close
3552 *
3553 * With both argument +maxlen+ and string argument +out_string+ given,
3554 * returns modified +out_string+:
3555 *
3556 * f = File.new('t.txt')
3557 * s = 'foo'
3558 * f.readpartial(20, s) # => "First line\nSecond l"
3559 * s = 'bar'
3560 * f.readpartial(0, s) # => ""
3561 * f.close
3562 *
3563 * This method is useful for a stream such as a pipe, a socket, or a tty.
3564 * It blocks only when no data is immediately available.
3565 * This means that it blocks only when _all_ of the following are true:
3566 *
3567 * - The byte buffer in the stream is empty.
3568 * - The content of the stream is empty.
3569 * - The stream is not at EOF.
3570 *
3571 * When blocked, the method waits for either more data or EOF on the stream:
3572 *
3573 * - If more data is read, the method returns the data.
3574 * - If EOF is reached, the method raises EOFError.
3575 *
3576 * When not blocked, the method responds immediately:
3577 *
3578 * - Returns data from the buffer if there is any.
3579 * - Otherwise returns data from the stream if there is any.
3580 * - Otherwise raises EOFError if the stream has reached EOF.
3581 *
3582 * Note that this method is similar to sysread. The differences are:
3583 *
3584 * - If the byte buffer is not empty, read from the byte buffer
3585 * instead of "sysread for buffered IO (IOError)".
3586 * - It doesn't cause Errno::EWOULDBLOCK and Errno::EINTR. When
3587 * readpartial meets EWOULDBLOCK and EINTR by read system call,
3588 * readpartial retries the system call.
3589 *
3590 * The latter means that readpartial is non-blocking-flag insensitive.
3591 * It blocks on the situation IO#sysread causes Errno::EWOULDBLOCK as
3592 * if the fd is blocking mode.
3593 *
3594 * Examples:
3595 *
3596 * # # Returned Buffer Content Pipe Content
3597 * r, w = IO.pipe #
3598 * w << 'abc' # "" "abc".
3599 * r.readpartial(4096) # => "abc" "" ""
3600 * r.readpartial(4096) # (Blocks because buffer and pipe are empty.)
3601 *
3602 * # # Returned Buffer Content Pipe Content
3603 * r, w = IO.pipe #
3604 * w << 'abc' # "" "abc"
3605 * w.close # "" "abc" EOF
3606 * r.readpartial(4096) # => "abc" "" EOF
3607 * r.readpartial(4096) # raises EOFError
3608 *
3609 * # # Returned Buffer Content Pipe Content
3610 * r, w = IO.pipe #
3611 * w << "abc\ndef\n" # "" "abc\ndef\n"
3612 * r.gets # => "abc\n" "def\n" ""
3613 * w << "ghi\n" # "def\n" "ghi\n"
3614 * r.readpartial(4096) # => "def\n" "" "ghi\n"
3615 * r.readpartial(4096) # => "ghi\n" "" ""
3616 *
3617 */
3618
3619static VALUE
3620io_readpartial(int argc, VALUE *argv, VALUE io)
3621{
3622 VALUE ret;
3623
3624 ret = io_getpartial(argc, argv, io, Qnil, 0);
3625 if (NIL_P(ret))
3626 rb_eof_error();
3627 return ret;
3628}
3629
3630static VALUE
3631io_nonblock_eof(int no_exception)
3632{
3633 if (!no_exception) {
3634 rb_eof_error();
3635 }
3636 return Qnil;
3637}
3638
3639/* :nodoc: */
3640static VALUE
3641io_read_nonblock(rb_execution_context_t *ec, VALUE io, VALUE length, VALUE str, VALUE ex)
3642{
3643 rb_io_t *fptr;
3644 long n, len;
3645 struct io_internal_read_struct iis;
3646 int shrinkable;
3647
3648 if ((len = NUM2LONG(length)) < 0) {
3649 rb_raise(rb_eArgError, "negative length %ld given", len);
3650 }
3651
3652 shrinkable = io_setstrbuf(&str, len);
3653 rb_bool_expected(ex, "exception", TRUE);
3654
3655 GetOpenFile(io, fptr);
3657
3658 if (len == 0) {
3659 io_set_read_length(str, 0, shrinkable);
3660 return str;
3661 }
3662
3663 n = read_buffered_data(RSTRING_PTR(str), len, fptr);
3664 if (n <= 0) {
3665 rb_fd_set_nonblock(fptr->fd);
3666 shrinkable |= io_setstrbuf(&str, len);
3667 iis.fptr = fptr;
3668 iis.nonblock = 1;
3669 iis.fd = fptr->fd;
3670 iis.buf = RSTRING_PTR(str);
3671 iis.capa = len;
3672 iis.timeout = NULL;
3673 n = io_read_memory_locktmp(str, &iis);
3674 if (n < 0) {
3675 int e = errno;
3676 if (io_again_p(e)) {
3677 if (!ex) return sym_wait_readable;
3678 rb_readwrite_syserr_fail(RB_IO_WAIT_READABLE,
3679 e, "read would block");
3680 }
3681 rb_syserr_fail_path(e, fptr->pathv);
3682 }
3683 }
3684 io_set_read_length(str, n, shrinkable);
3685
3686 if (n == 0) {
3687 if (!ex) return Qnil;
3688 rb_eof_error();
3689 }
3690
3691 return str;
3692}
3693
3694/* :nodoc: */
3695static VALUE
3696io_write_nonblock(rb_execution_context_t *ec, VALUE io, VALUE str, VALUE ex)
3697{
3698 rb_io_t *fptr;
3699 long n;
3700
3701 if (!RB_TYPE_P(str, T_STRING))
3702 str = rb_obj_as_string(str);
3703 rb_bool_expected(ex, "exception", TRUE);
3704
3705 io = GetWriteIO(io);
3706 GetOpenFile(io, fptr);
3708
3709 if (io_fflush(fptr) < 0)
3710 rb_sys_fail_on_write(fptr);
3711
3712 rb_fd_set_nonblock(fptr->fd);
3713 n = write(fptr->fd, RSTRING_PTR(str), RSTRING_LEN(str));
3714 RB_GC_GUARD(str);
3715
3716 if (n < 0) {
3717 int e = errno;
3718 if (io_again_p(e)) {
3719 if (!ex) {
3720 return sym_wait_writable;
3721 }
3722 else {
3723 rb_readwrite_syserr_fail(RB_IO_WAIT_WRITABLE, e, "write would block");
3724 }
3725 }
3726 rb_syserr_fail_path(e, fptr->pathv);
3727 }
3728
3729 return LONG2FIX(n);
3730}
3731
3732/*
3733 * call-seq:
3734 * read(maxlen = nil, out_string = nil) -> new_string, out_string, or nil
3735 *
3736 * Reads bytes from the stream; the stream must be opened for reading
3737 * (see {Access Modes}[rdoc-ref:File@Access+Modes]):
3738 *
3739 * - If +maxlen+ is +nil+, reads all bytes using the stream's data mode.
3740 * - Otherwise reads up to +maxlen+ bytes in binary mode.
3741 *
3742 * Returns a string (either a new string or the given +out_string+)
3743 * containing the bytes read.
3744 * The encoding of the string depends on both +maxLen+ and +out_string+:
3745 *
3746 * - +maxlen+ is +nil+: uses internal encoding of +self+
3747 * (regardless of whether +out_string+ was given).
3748 * - +maxlen+ not +nil+:
3749 *
3750 * - +out_string+ given: encoding of +out_string+ not modified.
3751 * - +out_string+ not given: ASCII-8BIT is used.
3752 *
3753 * <b>Without Argument +out_string+</b>
3754 *
3755 * When argument +out_string+ is omitted,
3756 * the returned value is a new string:
3757 *
3758 * f = File.new('t.txt')
3759 * f.read
3760 * # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3761 * f.rewind
3762 * f.read(30) # => "First line\r\nSecond line\r\n\r\nFou"
3763 * f.read(30) # => "rth line\r\nFifth line\r\n"
3764 * f.read(30) # => nil
3765 * f.close
3766 *
3767 * If +maxlen+ is zero, returns an empty string.
3768 *
3769 * <b> With Argument +out_string+</b>
3770 *
3771 * When argument +out_string+ is given,
3772 * the returned value is +out_string+, whose content is replaced:
3773 *
3774 * f = File.new('t.txt')
3775 * s = 'foo' # => "foo"
3776 * f.read(nil, s) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3777 * s # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3778 * f.rewind
3779 * s = 'bar'
3780 * f.read(30, s) # => "First line\r\nSecond line\r\n\r\nFou"
3781 * s # => "First line\r\nSecond line\r\n\r\nFou"
3782 * s = 'baz'
3783 * f.read(30, s) # => "rth line\r\nFifth line\r\n"
3784 * s # => "rth line\r\nFifth line\r\n"
3785 * s = 'bat'
3786 * f.read(30, s) # => nil
3787 * s # => ""
3788 * f.close
3789 *
3790 * Note that this method behaves like the fread() function in C.
3791 * This means it retries to invoke read(2) system calls to read data
3792 * with the specified maxlen (or until EOF).
3793 *
3794 * This behavior is preserved even if the stream is in non-blocking mode.
3795 * (This method is non-blocking-flag insensitive as other methods.)
3796 *
3797 * If you need the behavior like a single read(2) system call,
3798 * consider #readpartial, #read_nonblock, and #sysread.
3799 *
3800 * Related: IO#write.
3801 */
3802
3803static VALUE
3804io_read(int argc, VALUE *argv, VALUE io)
3805{
3806 rb_io_t *fptr;
3807 long n, len;
3808 VALUE length, str;
3809 int shrinkable;
3810#if RUBY_CRLF_ENVIRONMENT
3811 int previous_mode;
3812#endif
3813
3814 rb_scan_args(argc, argv, "02", &length, &str);
3815
3816 if (NIL_P(length)) {
3817 GetOpenFile(io, fptr);
3819 return read_all(fptr, remain_size(fptr), str);
3820 }
3821 len = NUM2LONG(length);
3822 if (len < 0) {
3823 rb_raise(rb_eArgError, "negative length %ld given", len);
3824 }
3825
3826 shrinkable = io_setstrbuf(&str,len);
3827
3828 GetOpenFile(io, fptr);
3830 if (len == 0) {
3831 io_set_read_length(str, 0, shrinkable);
3832 return str;
3833 }
3834
3835 READ_CHECK(fptr);
3836#if RUBY_CRLF_ENVIRONMENT
3837 previous_mode = set_binary_mode_with_seek_cur(fptr);
3838#endif
3839 n = io_fread(str, 0, len, fptr);
3840 io_set_read_length(str, n, shrinkable);
3841#if RUBY_CRLF_ENVIRONMENT
3842 if (previous_mode == O_TEXT) {
3843 setmode(fptr->fd, O_TEXT);
3844 }
3845#endif
3846 if (n == 0) return Qnil;
3847
3848 return str;
3849}
3850
3851static void
3852rscheck(const char *rsptr, long rslen, VALUE rs)
3853{
3854 if (!rs) return;
3855 if (RSTRING_PTR(rs) != rsptr && RSTRING_LEN(rs) != rslen)
3856 rb_raise(rb_eRuntimeError, "rs modified");
3857}
3858
3859static const char *
3860search_delim(const char *p, long len, int delim, rb_encoding *enc)
3861{
3862 if (rb_enc_mbminlen(enc) == 1) {
3863 p = memchr(p, delim, len);
3864 if (p) return p + 1;
3865 }
3866 else {
3867 const char *end = p + len;
3868 while (p < end) {
3869 int r = rb_enc_precise_mbclen(p, end, enc);
3870 if (!MBCLEN_CHARFOUND_P(r)) {
3871 p += rb_enc_mbminlen(enc);
3872 continue;
3873 }
3874 int n = MBCLEN_CHARFOUND_LEN(r);
3875 if (rb_enc_mbc_to_codepoint(p, end, enc) == (unsigned int)delim) {
3876 return p + n;
3877 }
3878 p += n;
3879 }
3880 }
3881 return NULL;
3882}
3883
3884static int
3885appendline(rb_io_t *fptr, int delim, VALUE *strp, long *lp, rb_encoding *enc)
3886{
3887 VALUE str = *strp;
3888 long limit = *lp;
3889
3890 if (NEED_READCONV(fptr)) {
3891 SET_BINARY_MODE(fptr);
3892 make_readconv(fptr, 0);
3893 do {
3894 const char *p, *e;
3895 int searchlen = READ_CHAR_PENDING_COUNT(fptr);
3896 if (searchlen) {
3897 p = READ_CHAR_PENDING_PTR(fptr);
3898 if (0 < limit && limit < searchlen)
3899 searchlen = (int)limit;
3900 e = search_delim(p, searchlen, delim, enc);
3901 if (e) {
3902 int len = (int)(e-p);
3903 if (NIL_P(str))
3904 *strp = str = rb_str_new(p, len);
3905 else
3906 rb_str_buf_cat(str, p, len);
3907 fptr->cbuf.off += len;
3908 fptr->cbuf.len -= len;
3909 limit -= len;
3910 *lp = limit;
3911 return delim;
3912 }
3913
3914 if (NIL_P(str))
3915 *strp = str = rb_str_new(p, searchlen);
3916 else
3917 rb_str_buf_cat(str, p, searchlen);
3918 fptr->cbuf.off += searchlen;
3919 fptr->cbuf.len -= searchlen;
3920 limit -= searchlen;
3921
3922 if (limit == 0) {
3923 *lp = limit;
3924 return (unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
3925 }
3926 }
3927 } while (more_char(fptr) != MORE_CHAR_FINISHED);
3928 clear_readconv(fptr);
3929 *lp = limit;
3930 return EOF;
3931 }
3932
3933 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3934 do {
3935 long pending = READ_DATA_PENDING_COUNT(fptr);
3936 if (pending > 0) {
3937 const char *p = READ_DATA_PENDING_PTR(fptr);
3938 const char *e;
3939 long last;
3940
3941 if (limit > 0 && pending > limit) pending = limit;
3942 e = search_delim(p, pending, delim, enc);
3943 if (e) pending = e - p;
3944 if (!NIL_P(str)) {
3945 last = RSTRING_LEN(str);
3946 rb_str_resize(str, last + pending);
3947 }
3948 else {
3949 last = 0;
3950 *strp = str = rb_str_buf_new(pending);
3951 rb_str_set_len(str, pending);
3952 }
3953 read_buffered_data(RSTRING_PTR(str) + last, pending, fptr); /* must not fail */
3954 limit -= pending;
3955 *lp = limit;
3956 if (e) return delim;
3957 if (limit == 0)
3958 return (unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
3959 }
3960 READ_CHECK(fptr);
3961 } while (io_fillbuf(fptr) >= 0);
3962 *lp = limit;
3963 return EOF;
3964}
3965
3966static inline int
3967swallow(rb_io_t *fptr, int term)
3968{
3969 if (NEED_READCONV(fptr)) {
3970 rb_encoding *enc = io_read_encoding(fptr);
3971 int needconv = rb_enc_mbminlen(enc) != 1;
3972 SET_BINARY_MODE(fptr);
3973 make_readconv(fptr, 0);
3974 do {
3975 size_t cnt;
3976 while ((cnt = READ_CHAR_PENDING_COUNT(fptr)) > 0) {
3977 const char *p = READ_CHAR_PENDING_PTR(fptr);
3978 int i;
3979 if (!needconv) {
3980 if (*p != term) return TRUE;
3981 i = (int)cnt;
3982 while (--i && *++p == term);
3983 }
3984 else {
3985 const char *e = p + cnt;
3986 if (rb_enc_ascget(p, e, &i, enc) != term) return TRUE;
3987 while ((p += i) < e && rb_enc_ascget(p, e, &i, enc) == term);
3988 i = (int)(e - p);
3989 }
3990 io_shift_cbuf(fptr, (int)cnt - i, NULL);
3991 }
3992 } while (more_char(fptr) != MORE_CHAR_FINISHED);
3993 return FALSE;
3994 }
3995
3996 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3997 do {
3998 size_t cnt;
3999 while ((cnt = READ_DATA_PENDING_COUNT(fptr)) > 0) {
4000 char buf[1024];
4001 const char *p = READ_DATA_PENDING_PTR(fptr);
4002 int i;
4003 if (cnt > sizeof buf) cnt = sizeof buf;
4004 if (*p != term) return TRUE;
4005 i = (int)cnt;
4006 while (--i && *++p == term);
4007 if (!read_buffered_data(buf, cnt - i, fptr)) /* must not fail */
4008 rb_sys_fail_path(fptr->pathv);
4009 }
4010 READ_CHECK(fptr);
4011 } while (io_fillbuf(fptr) == 0);
4012 return FALSE;
4013}
4014
4015static VALUE
4016rb_io_getline_fast(rb_io_t *fptr, rb_encoding *enc, int chomp)
4017{
4018 VALUE str = Qnil;
4019 int len = 0;
4020 long pos = 0;
4021 int cr = 0;
4022
4023 do {
4024 int pending = READ_DATA_PENDING_COUNT(fptr);
4025
4026 if (pending > 0) {
4027 const char *p = READ_DATA_PENDING_PTR(fptr);
4028 const char *e;
4029 int chomplen = 0;
4030
4031 e = memchr(p, '\n', pending);
4032 if (e) {
4033 pending = (int)(e - p + 1);
4034 if (chomp) {
4035 chomplen = (pending > 1 && *(e-1) == '\r') + 1;
4036 }
4037 }
4038 if (NIL_P(str)) {
4039 str = rb_str_new(p, pending - chomplen);
4040 fptr->rbuf.off += pending;
4041 fptr->rbuf.len -= pending;
4042 }
4043 else {
4044 rb_str_resize(str, len + pending - chomplen);
4045 read_buffered_data(RSTRING_PTR(str)+len, pending - chomplen, fptr);
4046 fptr->rbuf.off += chomplen;
4047 fptr->rbuf.len -= chomplen;
4048 if (pending == 1 && chomplen == 1 && len > 0) {
4049 if (RSTRING_PTR(str)[len-1] == '\r') {
4050 rb_str_resize(str, --len);
4051 break;
4052 }
4053 }
4054 }
4055 len += pending - chomplen;
4056 if (cr != ENC_CODERANGE_BROKEN)
4057 pos += rb_str_coderange_scan_restartable(RSTRING_PTR(str) + pos, RSTRING_PTR(str) + len, enc, &cr);
4058 if (e) break;
4059 }
4060 READ_CHECK(fptr);
4061 } while (io_fillbuf(fptr) >= 0);
4062 if (NIL_P(str)) return Qnil;
4063
4064 str = io_enc_str(str, fptr);
4065 ENC_CODERANGE_SET(str, cr);
4066 fptr->lineno++;
4067
4068 return str;
4069}
4070
4072 VALUE io;
4073 VALUE rs;
4074 long limit;
4075 unsigned int chomp: 1;
4076};
4077
4078static void
4079extract_getline_opts(VALUE opts, struct getline_arg *args)
4080{
4081 int chomp = FALSE;
4082 if (!NIL_P(opts)) {
4083 static ID kwds[1];
4084 VALUE vchomp;
4085 if (!kwds[0]) {
4086 kwds[0] = rb_intern_const("chomp");
4087 }
4088 rb_get_kwargs(opts, kwds, 0, -2, &vchomp);
4089 chomp = (!UNDEF_P(vchomp)) && RTEST(vchomp);
4090 }
4091 args->chomp = chomp;
4092}
4093
4094static void
4095extract_getline_args(int argc, VALUE *argv, struct getline_arg *args)
4096{
4097 VALUE rs = rb_rs, lim = Qnil;
4098
4099 if (argc == 1) {
4100 VALUE tmp = Qnil;
4101
4102 if (NIL_P(argv[0]) || !NIL_P(tmp = rb_check_string_type(argv[0]))) {
4103 rs = tmp;
4104 }
4105 else {
4106 lim = argv[0];
4107 }
4108 }
4109 else if (2 <= argc) {
4110 rs = argv[0], lim = argv[1];
4111 if (!NIL_P(rs))
4112 StringValue(rs);
4113 }
4114 args->rs = rs;
4115 args->limit = NIL_P(lim) ? -1L : NUM2LONG(lim);
4116}
4117
4118static void
4119check_getline_args(VALUE *rsp, long *limit, VALUE io)
4120{
4121 rb_io_t *fptr;
4122 VALUE rs = *rsp;
4123
4124 if (!NIL_P(rs)) {
4125 rb_encoding *enc_rs, *enc_io;
4126
4127 GetOpenFile(io, fptr);
4128 enc_rs = rb_enc_get(rs);
4129 enc_io = io_read_encoding(fptr);
4130 if (enc_io != enc_rs &&
4131 (!is_ascii_string(rs) ||
4132 (RSTRING_LEN(rs) > 0 && !rb_enc_asciicompat(enc_io)))) {
4133 if (rs == rb_default_rs) {
4134 rs = rb_enc_str_new(0, 0, enc_io);
4135 rb_str_buf_cat_ascii(rs, "\n");
4136 *rsp = rs;
4137 }
4138 else {
4139 rb_raise(rb_eArgError, "encoding mismatch: %s IO with %s RS",
4140 rb_enc_name(enc_io),
4141 rb_enc_name(enc_rs));
4142 }
4143 }
4144 }
4145}
4146
4147static void
4148prepare_getline_args(int argc, VALUE *argv, struct getline_arg *args, VALUE io)
4149{
4150 VALUE opts;
4151 argc = rb_scan_args(argc, argv, "02:", NULL, NULL, &opts);
4152 extract_getline_args(argc, argv, args);
4153 extract_getline_opts(opts, args);
4154 check_getline_args(&args->rs, &args->limit, io);
4155}
4156
4157static VALUE
4158rb_io_getline_0(VALUE rs, long limit, int chomp, rb_io_t *fptr)
4159{
4160 VALUE str = Qnil;
4161 int nolimit = 0;
4162 rb_encoding *enc;
4163
4165 if (NIL_P(rs) && limit < 0) {
4166 str = read_all(fptr, 0, Qnil);
4167 if (RSTRING_LEN(str) == 0) return Qnil;
4168 }
4169 else if (limit == 0) {
4170 return rb_enc_str_new(0, 0, io_read_encoding(fptr));
4171 }
4172 else if (rs == rb_default_rs && limit < 0 && !NEED_READCONV(fptr) &&
4173 rb_enc_asciicompat(enc = io_read_encoding(fptr))) {
4174 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4175 return rb_io_getline_fast(fptr, enc, chomp);
4176 }
4177 else {
4178 int c, newline = -1;
4179 const char *rsptr = 0;
4180 long rslen = 0;
4181 int rspara = 0;
4182 int extra_limit = 16;
4183 int chomp_cr = chomp;
4184
4185 SET_BINARY_MODE(fptr);
4186 enc = io_read_encoding(fptr);
4187
4188 if (!NIL_P(rs)) {
4189 rslen = RSTRING_LEN(rs);
4190 if (rslen == 0) {
4191 rsptr = "\n\n";
4192 rslen = 2;
4193 rspara = 1;
4194 swallow(fptr, '\n');
4195 rs = 0;
4196 if (!rb_enc_asciicompat(enc)) {
4197 rs = rb_usascii_str_new(rsptr, rslen);
4198 rs = rb_str_conv_enc(rs, 0, enc);
4199 OBJ_FREEZE(rs);
4200 rsptr = RSTRING_PTR(rs);
4201 rslen = RSTRING_LEN(rs);
4202 }
4203 newline = '\n';
4204 }
4205 else if (rb_enc_mbminlen(enc) == 1) {
4206 rsptr = RSTRING_PTR(rs);
4207 newline = (unsigned char)rsptr[rslen - 1];
4208 }
4209 else {
4210 rs = rb_str_conv_enc(rs, 0, enc);
4211 rsptr = RSTRING_PTR(rs);
4212 const char *e = rsptr + rslen;
4213 const char *last = rb_enc_prev_char(rsptr, e, e, enc);
4214 int n;
4215 newline = rb_enc_codepoint_len(last, e, &n, enc);
4216 if (last + n != e) rb_raise(rb_eArgError, "broken separator");
4217 }
4218 chomp_cr = chomp && newline == '\n' && rslen == rb_enc_mbminlen(enc);
4219 }
4220
4221 /* MS - Optimization */
4222 while ((c = appendline(fptr, newline, &str, &limit, enc)) != EOF) {
4223 const char *s, *p, *pp, *e;
4224
4225 if (c == newline) {
4226 if (RSTRING_LEN(str) < rslen) continue;
4227 s = RSTRING_PTR(str);
4228 e = RSTRING_END(str);
4229 p = e - rslen;
4230 if (!at_char_boundary(s, p, e, enc)) continue;
4231 if (!rspara) rscheck(rsptr, rslen, rs);
4232 if (memcmp(p, rsptr, rslen) == 0) {
4233 if (chomp) {
4234 if (chomp_cr && p > s && *(p-1) == '\r') --p;
4235 rb_str_set_len(str, p - s);
4236 }
4237 break;
4238 }
4239 }
4240 if (limit == 0) {
4241 s = RSTRING_PTR(str);
4242 p = RSTRING_END(str);
4243 pp = rb_enc_prev_char(s, p, p, enc);
4244 if (extra_limit && pp &&
4245 MBCLEN_NEEDMORE_P(rb_enc_precise_mbclen(pp, p, enc))) {
4246 /* relax the limit while incomplete character.
4247 * extra_limit limits the relax length */
4248 limit = 1;
4249 extra_limit--;
4250 }
4251 else {
4252 nolimit = 1;
4253 break;
4254 }
4255 }
4256 }
4257
4258 if (rspara && c != EOF)
4259 swallow(fptr, '\n');
4260 if (!NIL_P(str))
4261 str = io_enc_str(str, fptr);
4262 }
4263
4264 if (!NIL_P(str) && !nolimit) {
4265 fptr->lineno++;
4266 }
4267
4268 return str;
4269}
4270
4271static VALUE
4272rb_io_getline_1(VALUE rs, long limit, int chomp, VALUE io)
4273{
4274 rb_io_t *fptr;
4275 int old_lineno, new_lineno;
4276 VALUE str;
4277
4278 GetOpenFile(io, fptr);
4279 old_lineno = fptr->lineno;
4280 str = rb_io_getline_0(rs, limit, chomp, fptr);
4281 if (!NIL_P(str) && (new_lineno = fptr->lineno) != old_lineno) {
4282 if (io == ARGF.current_file) {
4283 ARGF.lineno += new_lineno - old_lineno;
4284 ARGF.last_lineno = ARGF.lineno;
4285 }
4286 else {
4287 ARGF.last_lineno = new_lineno;
4288 }
4289 }
4290
4291 return str;
4292}
4293
4294static VALUE
4295rb_io_getline(int argc, VALUE *argv, VALUE io)
4296{
4297 struct getline_arg args;
4298
4299 prepare_getline_args(argc, argv, &args, io);
4300 return rb_io_getline_1(args.rs, args.limit, args.chomp, io);
4301}
4302
4303VALUE
4305{
4306 return rb_io_getline_1(rb_default_rs, -1, FALSE, io);
4307}
4308
4309VALUE
4310rb_io_gets_limit_internal(VALUE io, long limit)
4311{
4312 rb_io_t *fptr;
4313 GetOpenFile(io, fptr);
4314 return rb_io_getline_0(rb_default_rs, limit, FALSE, fptr);
4315}
4316
4317VALUE
4318rb_io_gets_internal(VALUE io)
4319{
4320 return rb_io_gets_limit_internal(io, -1);
4321}
4322
4323/*
4324 * call-seq:
4325 * gets(sep = $/, chomp: false) -> string or nil
4326 * gets(limit, chomp: false) -> string or nil
4327 * gets(sep, limit, chomp: false) -> string or nil
4328 *
4329 * Reads and returns a line from the stream;
4330 * assigns the return value to <tt>$_</tt>.
4331 * See {Line IO}[rdoc-ref:IO@Line+IO].
4332 *
4333 * With no arguments given, returns the next line
4334 * as determined by line separator <tt>$/</tt>, or +nil+ if none:
4335 *
4336 * f = File.open('t.txt')
4337 * f.gets # => "First line\n"
4338 * $_ # => "First line\n"
4339 * f.gets # => "\n"
4340 * f.gets # => "Fourth line\n"
4341 * f.gets # => "Fifth line\n"
4342 * f.gets # => nil
4343 * f.close
4344 *
4345 * With only string argument +sep+ given,
4346 * returns the next line as determined by line separator +sep+,
4347 * or +nil+ if none;
4348 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4349 *
4350 * f = File.new('t.txt')
4351 * f.gets('l') # => "First l"
4352 * f.gets('li') # => "ine\nSecond li"
4353 * f.gets('lin') # => "ne\n\nFourth lin"
4354 * f.gets # => "e\n"
4355 * f.close
4356 *
4357 * The two special values for +sep+ are honored:
4358 *
4359 * f = File.new('t.txt')
4360 * # Get all.
4361 * f.gets(nil) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
4362 * f.rewind
4363 * # Get paragraph (up to two line separators).
4364 * f.gets('') # => "First line\nSecond line\n\n"
4365 * f.close
4366 *
4367 * With only integer argument +limit+ given,
4368 * limits the number of bytes in the line;
4369 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4370 *
4371 * # No more than one line.
4372 * File.open('t.txt') {|f| f.gets(10) } # => "First line"
4373 * File.open('t.txt') {|f| f.gets(11) } # => "First line\n"
4374 * File.open('t.txt') {|f| f.gets(12) } # => "First line\n"
4375 *
4376 * With arguments +sep+ and +limit+ given,
4377 * combines the two behaviors
4378 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
4379 *
4380 * Optional keyword argument +chomp+ specifies whether line separators
4381 * are to be omitted:
4382 *
4383 * f = File.open('t.txt')
4384 * # Chomp the lines.
4385 * f.gets(chomp: true) # => "First line"
4386 * f.gets(chomp: true) # => "Second line"
4387 * f.gets(chomp: true) # => ""
4388 * f.gets(chomp: true) # => "Fourth line"
4389 * f.gets(chomp: true) # => "Fifth line"
4390 * f.gets(chomp: true) # => nil
4391 * f.close
4392 *
4393 */
4394
4395static VALUE
4396rb_io_gets_m(int argc, VALUE *argv, VALUE io)
4397{
4398 VALUE str;
4399
4400 str = rb_io_getline(argc, argv, io);
4401 rb_lastline_set(str);
4402
4403 return str;
4404}
4405
4406/*
4407 * call-seq:
4408 * lineno -> integer
4409 *
4410 * Returns the current line number for the stream;
4411 * see {Line Number}[rdoc-ref:IO@Line+Number].
4412 *
4413 */
4414
4415static VALUE
4416rb_io_lineno(VALUE io)
4417{
4418 rb_io_t *fptr;
4419
4420 GetOpenFile(io, fptr);
4422 return INT2NUM(fptr->lineno);
4423}
4424
4425/*
4426 * call-seq:
4427 * lineno = integer -> integer
4428 *
4429 * Sets and returns the line number for the stream;
4430 * see {Line Number}[rdoc-ref:IO@Line+Number].
4431 *
4432 */
4433
4434static VALUE
4435rb_io_set_lineno(VALUE io, VALUE lineno)
4436{
4437 rb_io_t *fptr;
4438
4439 GetOpenFile(io, fptr);
4441 fptr->lineno = NUM2INT(lineno);
4442 return lineno;
4443}
4444
4445/* :nodoc: */
4446static VALUE
4447io_readline(rb_execution_context_t *ec, VALUE io, VALUE sep, VALUE lim, VALUE chomp)
4448{
4449 long limit = -1;
4450 if (NIL_P(lim)) {
4451 VALUE tmp = Qnil;
4452 // If sep is specified, but it's not a string and not nil, then assume
4453 // it's the limit (it should be an integer)
4454 if (!NIL_P(sep) && NIL_P(tmp = rb_check_string_type(sep))) {
4455 // If the user has specified a non-nil / non-string value
4456 // for the separator, we assume it's the limit and set the
4457 // separator to default: rb_rs.
4458 lim = sep;
4459 limit = NUM2LONG(lim);
4460 sep = rb_rs;
4461 }
4462 else {
4463 sep = tmp;
4464 }
4465 }
4466 else {
4467 if (!NIL_P(sep)) StringValue(sep);
4468 limit = NUM2LONG(lim);
4469 }
4470
4471 check_getline_args(&sep, &limit, io);
4472
4473 VALUE line = rb_io_getline_1(sep, limit, RTEST(chomp), io);
4474 rb_lastline_set_up(line, 1);
4475
4476 if (NIL_P(line)) {
4477 rb_eof_error();
4478 }
4479 return line;
4480}
4481
4482static VALUE io_readlines(const struct getline_arg *arg, VALUE io);
4483
4484/*
4485 * call-seq:
4486 * readlines(sep = $/, chomp: false) -> array
4487 * readlines(limit, chomp: false) -> array
4488 * readlines(sep, limit, chomp: false) -> array
4489 *
4490 * Reads and returns all remaining line from the stream;
4491 * does not modify <tt>$_</tt>.
4492 * See {Line IO}[rdoc-ref:IO@Line+IO].
4493 *
4494 * With no arguments given, returns lines
4495 * as determined by line separator <tt>$/</tt>, or +nil+ if none:
4496 *
4497 * f = File.new('t.txt')
4498 * f.readlines
4499 * # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
4500 * f.readlines # => []
4501 * f.close
4502 *
4503 * With only string argument +sep+ given,
4504 * returns lines as determined by line separator +sep+,
4505 * or +nil+ if none;
4506 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4507 *
4508 * f = File.new('t.txt')
4509 * f.readlines('li')
4510 * # => ["First li", "ne\nSecond li", "ne\n\nFourth li", "ne\nFifth li", "ne\n"]
4511 * f.close
4512 *
4513 * The two special values for +sep+ are honored:
4514 *
4515 * f = File.new('t.txt')
4516 * # Get all into one string.
4517 * f.readlines(nil)
4518 * # => ["First line\nSecond line\n\nFourth line\nFifth line\n"]
4519 * # Get paragraphs (up to two line separators).
4520 * f.rewind
4521 * f.readlines('')
4522 * # => ["First line\nSecond line\n\n", "Fourth line\nFifth line\n"]
4523 * f.close
4524 *
4525 * With only integer argument +limit+ given,
4526 * limits the number of bytes in each line;
4527 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4528 *
4529 * f = File.new('t.txt')
4530 * f.readlines(8)
4531 * # => ["First li", "ne\n", "Second l", "ine\n", "\n", "Fourth l", "ine\n", "Fifth li", "ne\n"]
4532 * f.close
4533 *
4534 * With arguments +sep+ and +limit+ given,
4535 * combines the two behaviors
4536 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
4537 *
4538 * Optional keyword argument +chomp+ specifies whether line separators
4539 * are to be omitted:
4540 *
4541 * f = File.new('t.txt')
4542 * f.readlines(chomp: true)
4543 * # => ["First line", "Second line", "", "Fourth line", "Fifth line"]
4544 * f.close
4545 *
4546 */
4547
4548static VALUE
4549rb_io_readlines(int argc, VALUE *argv, VALUE io)
4550{
4551 struct getline_arg args;
4552
4553 prepare_getline_args(argc, argv, &args, io);
4554 return io_readlines(&args, io);
4555}
4556
4557static VALUE
4558io_readlines(const struct getline_arg *arg, VALUE io)
4559{
4560 VALUE line, ary;
4561
4562 if (arg->limit == 0)
4563 rb_raise(rb_eArgError, "invalid limit: 0 for readlines");
4564 ary = rb_ary_new();
4565 while (!NIL_P(line = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, io))) {
4566 rb_ary_push(ary, line);
4567 }
4568 return ary;
4569}
4570
4571/*
4572 * call-seq:
4573 * each_line(sep = $/, chomp: false) {|line| ... } -> self
4574 * each_line(limit, chomp: false) {|line| ... } -> self
4575 * each_line(sep, limit, chomp: false) {|line| ... } -> self
4576 * each_line -> enumerator
4577 *
4578 * Calls the block with each remaining line read from the stream;
4579 * returns +self+.
4580 * Does nothing if already at end-of-stream;
4581 * See {Line IO}[rdoc-ref:IO@Line+IO].
4582 *
4583 * With no arguments given, reads lines
4584 * as determined by line separator <tt>$/</tt>:
4585 *
4586 * f = File.new('t.txt')
4587 * f.each_line {|line| p line }
4588 * f.each_line {|line| fail 'Cannot happen' }
4589 * f.close
4590 *
4591 * Output:
4592 *
4593 * "First line\n"
4594 * "Second line\n"
4595 * "\n"
4596 * "Fourth line\n"
4597 * "Fifth line\n"
4598 *
4599 * With only string argument +sep+ given,
4600 * reads lines as determined by line separator +sep+;
4601 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4602 *
4603 * f = File.new('t.txt')
4604 * f.each_line('li') {|line| p line }
4605 * f.close
4606 *
4607 * Output:
4608 *
4609 * "First li"
4610 * "ne\nSecond li"
4611 * "ne\n\nFourth li"
4612 * "ne\nFifth li"
4613 * "ne\n"
4614 *
4615 * The two special values for +sep+ are honored:
4616 *
4617 * f = File.new('t.txt')
4618 * # Get all into one string.
4619 * f.each_line(nil) {|line| p line }
4620 * f.close
4621 *
4622 * Output:
4623 *
4624 * "First line\nSecond line\n\nFourth line\nFifth line\n"
4625 *
4626 * f.rewind
4627 * # Get paragraphs (up to two line separators).
4628 * f.each_line('') {|line| p line }
4629 *
4630 * Output:
4631 *
4632 * "First line\nSecond line\n\n"
4633 * "Fourth line\nFifth line\n"
4634 *
4635 * With only integer argument +limit+ given,
4636 * limits the number of bytes in each line;
4637 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4638 *
4639 * f = File.new('t.txt')
4640 * f.each_line(8) {|line| p line }
4641 * f.close
4642 *
4643 * Output:
4644 *
4645 * "First li"
4646 * "ne\n"
4647 * "Second l"
4648 * "ine\n"
4649 * "\n"
4650 * "Fourth l"
4651 * "ine\n"
4652 * "Fifth li"
4653 * "ne\n"
4654 *
4655 * With arguments +sep+ and +limit+ given,
4656 * combines the two behaviors
4657 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
4658 *
4659 * Optional keyword argument +chomp+ specifies whether line separators
4660 * are to be omitted:
4661 *
4662 * f = File.new('t.txt')
4663 * f.each_line(chomp: true) {|line| p line }
4664 * f.close
4665 *
4666 * Output:
4667 *
4668 * "First line"
4669 * "Second line"
4670 * ""
4671 * "Fourth line"
4672 * "Fifth line"
4673 *
4674 * Returns an Enumerator if no block is given.
4675 */
4676
4677static VALUE
4678rb_io_each_line(int argc, VALUE *argv, VALUE io)
4679{
4680 VALUE str;
4681 struct getline_arg args;
4682
4683 RETURN_ENUMERATOR(io, argc, argv);
4684 prepare_getline_args(argc, argv, &args, io);
4685 if (args.limit == 0)
4686 rb_raise(rb_eArgError, "invalid limit: 0 for each_line");
4687 while (!NIL_P(str = rb_io_getline_1(args.rs, args.limit, args.chomp, io))) {
4688 rb_yield(str);
4689 }
4690 return io;
4691}
4692
4693/*
4694 * call-seq:
4695 * each_byte {|byte| ... } -> self
4696 * each_byte -> enumerator
4697 *
4698 * Calls the given block with each byte (0..255) in the stream; returns +self+.
4699 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
4700 *
4701 * f = File.new('t.rus')
4702 * a = []
4703 * f.each_byte {|b| a << b }
4704 * a # => [209, 130, 208, 181, 209, 129, 209, 130]
4705 * f.close
4706 *
4707 * Returns an Enumerator if no block is given.
4708 *
4709 * Related: IO#each_char, IO#each_codepoint.
4710 *
4711 */
4712
4713static VALUE
4714rb_io_each_byte(VALUE io)
4715{
4716 rb_io_t *fptr;
4717
4718 RETURN_ENUMERATOR(io, 0, 0);
4719 GetOpenFile(io, fptr);
4720
4721 do {
4722 while (fptr->rbuf.len > 0) {
4723 char *p = fptr->rbuf.ptr + fptr->rbuf.off++;
4724 fptr->rbuf.len--;
4725 rb_yield(INT2FIX(*p & 0xff));
4727 errno = 0;
4728 }
4729 READ_CHECK(fptr);
4730 } while (io_fillbuf(fptr) >= 0);
4731 return io;
4732}
4733
4734static VALUE
4735io_getc(rb_io_t *fptr, rb_encoding *enc)
4736{
4737 int r, n, cr = 0;
4738 VALUE str;
4739
4740 if (NEED_READCONV(fptr)) {
4741 rb_encoding *read_enc = io_read_encoding(fptr);
4742
4743 str = Qnil;
4744 SET_BINARY_MODE(fptr);
4745 make_readconv(fptr, 0);
4746
4747 while (1) {
4748 if (fptr->cbuf.len) {
4749 r = rb_enc_precise_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4750 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4751 read_enc);
4752 if (!MBCLEN_NEEDMORE_P(r))
4753 break;
4754 if (fptr->cbuf.len == fptr->cbuf.capa) {
4755 rb_raise(rb_eIOError, "too long character");
4756 }
4757 }
4758
4759 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4760 if (fptr->cbuf.len == 0) {
4761 clear_readconv(fptr);
4762 return Qnil;
4763 }
4764 /* return an unit of an incomplete character just before EOF */
4765 str = rb_enc_str_new(fptr->cbuf.ptr+fptr->cbuf.off, 1, read_enc);
4766 fptr->cbuf.off += 1;
4767 fptr->cbuf.len -= 1;
4768 if (fptr->cbuf.len == 0) clear_readconv(fptr);
4770 return str;
4771 }
4772 }
4773 if (MBCLEN_INVALID_P(r)) {
4774 r = rb_enc_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4775 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4776 read_enc);
4777 io_shift_cbuf(fptr, r, &str);
4779 }
4780 else {
4781 io_shift_cbuf(fptr, MBCLEN_CHARFOUND_LEN(r), &str);
4783 if (MBCLEN_CHARFOUND_LEN(r) == 1 && rb_enc_asciicompat(read_enc) &&
4784 ISASCII(RSTRING_PTR(str)[0])) {
4785 cr = ENC_CODERANGE_7BIT;
4786 }
4787 }
4788 str = io_enc_str(str, fptr);
4789 ENC_CODERANGE_SET(str, cr);
4790 return str;
4791 }
4792
4793 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4794 if (io_fillbuf(fptr) < 0) {
4795 return Qnil;
4796 }
4797 if (rb_enc_asciicompat(enc) && ISASCII(fptr->rbuf.ptr[fptr->rbuf.off])) {
4798 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, 1);
4799 fptr->rbuf.off += 1;
4800 fptr->rbuf.len -= 1;
4801 cr = ENC_CODERANGE_7BIT;
4802 }
4803 else {
4804 r = rb_enc_precise_mbclen(fptr->rbuf.ptr+fptr->rbuf.off, fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
4805 if (MBCLEN_CHARFOUND_P(r) &&
4806 (n = MBCLEN_CHARFOUND_LEN(r)) <= fptr->rbuf.len) {
4807 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, n);
4808 fptr->rbuf.off += n;
4809 fptr->rbuf.len -= n;
4811 }
4812 else if (MBCLEN_NEEDMORE_P(r)) {
4813 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, fptr->rbuf.len);
4814 fptr->rbuf.len = 0;
4815 getc_needmore:
4816 if (io_fillbuf(fptr) != -1) {
4817 rb_str_cat(str, fptr->rbuf.ptr+fptr->rbuf.off, 1);
4818 fptr->rbuf.off++;
4819 fptr->rbuf.len--;
4820 r = rb_enc_precise_mbclen(RSTRING_PTR(str), RSTRING_PTR(str)+RSTRING_LEN(str), enc);
4821 if (MBCLEN_NEEDMORE_P(r)) {
4822 goto getc_needmore;
4823 }
4824 else if (MBCLEN_CHARFOUND_P(r)) {
4826 }
4827 }
4828 }
4829 else {
4830 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, 1);
4831 fptr->rbuf.off++;
4832 fptr->rbuf.len--;
4833 }
4834 }
4835 if (!cr) cr = ENC_CODERANGE_BROKEN;
4836 str = io_enc_str(str, fptr);
4837 ENC_CODERANGE_SET(str, cr);
4838 return str;
4839}
4840
4841/*
4842 * call-seq:
4843 * each_char {|c| ... } -> self
4844 * each_char -> enumerator
4845 *
4846 * Calls the given block with each character in the stream; returns +self+.
4847 * See {Character IO}[rdoc-ref:IO@Character+IO].
4848 *
4849 * f = File.new('t.rus')
4850 * a = []
4851 * f.each_char {|c| a << c.ord }
4852 * a # => [1090, 1077, 1089, 1090]
4853 * f.close
4854 *
4855 * Returns an Enumerator if no block is given.
4856 *
4857 * Related: IO#each_byte, IO#each_codepoint.
4858 *
4859 */
4860
4861static VALUE
4862rb_io_each_char(VALUE io)
4863{
4864 rb_io_t *fptr;
4865 rb_encoding *enc;
4866 VALUE c;
4867
4868 RETURN_ENUMERATOR(io, 0, 0);
4869 GetOpenFile(io, fptr);
4871
4872 enc = io_input_encoding(fptr);
4873 READ_CHECK(fptr);
4874 while (!NIL_P(c = io_getc(fptr, enc))) {
4875 rb_yield(c);
4876 }
4877 return io;
4878}
4879
4880/*
4881 * call-seq:
4882 * each_codepoint {|c| ... } -> self
4883 * each_codepoint -> enumerator
4884 *
4885 * Calls the given block with each codepoint in the stream; returns +self+:
4886 *
4887 * f = File.new('t.rus')
4888 * a = []
4889 * f.each_codepoint {|c| a << c }
4890 * a # => [1090, 1077, 1089, 1090]
4891 * f.close
4892 *
4893 * Returns an Enumerator if no block is given.
4894 *
4895 * Related: IO#each_byte, IO#each_char.
4896 *
4897 */
4898
4899static VALUE
4900rb_io_each_codepoint(VALUE io)
4901{
4902 rb_io_t *fptr;
4903 rb_encoding *enc;
4904 unsigned int c;
4905 int r, n;
4906
4907 RETURN_ENUMERATOR(io, 0, 0);
4908 GetOpenFile(io, fptr);
4910
4911 READ_CHECK(fptr);
4912 if (NEED_READCONV(fptr)) {
4913 SET_BINARY_MODE(fptr);
4914 r = 1; /* no invalid char yet */
4915 for (;;) {
4916 make_readconv(fptr, 0);
4917 for (;;) {
4918 if (fptr->cbuf.len) {
4919 if (fptr->encs.enc)
4920 r = rb_enc_precise_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4921 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4922 fptr->encs.enc);
4923 else
4924 r = ONIGENC_CONSTRUCT_MBCLEN_CHARFOUND(1);
4925 if (!MBCLEN_NEEDMORE_P(r))
4926 break;
4927 if (fptr->cbuf.len == fptr->cbuf.capa) {
4928 rb_raise(rb_eIOError, "too long character");
4929 }
4930 }
4931 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4932 clear_readconv(fptr);
4933 if (!MBCLEN_CHARFOUND_P(r)) {
4934 enc = fptr->encs.enc;
4935 goto invalid;
4936 }
4937 return io;
4938 }
4939 }
4940 if (MBCLEN_INVALID_P(r)) {
4941 enc = fptr->encs.enc;
4942 goto invalid;
4943 }
4944 n = MBCLEN_CHARFOUND_LEN(r);
4945 if (fptr->encs.enc) {
4946 c = rb_enc_codepoint(fptr->cbuf.ptr+fptr->cbuf.off,
4947 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4948 fptr->encs.enc);
4949 }
4950 else {
4951 c = (unsigned char)fptr->cbuf.ptr[fptr->cbuf.off];
4952 }
4953 fptr->cbuf.off += n;
4954 fptr->cbuf.len -= n;
4955 rb_yield(UINT2NUM(c));
4957 }
4958 }
4959 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4960 enc = io_input_encoding(fptr);
4961 while (io_fillbuf(fptr) >= 0) {
4962 r = rb_enc_precise_mbclen(fptr->rbuf.ptr+fptr->rbuf.off,
4963 fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
4964 if (MBCLEN_CHARFOUND_P(r) &&
4965 (n = MBCLEN_CHARFOUND_LEN(r)) <= fptr->rbuf.len) {
4966 c = rb_enc_codepoint(fptr->rbuf.ptr+fptr->rbuf.off,
4967 fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
4968 fptr->rbuf.off += n;
4969 fptr->rbuf.len -= n;
4970 rb_yield(UINT2NUM(c));
4971 }
4972 else if (MBCLEN_INVALID_P(r)) {
4973 goto invalid;
4974 }
4975 else if (MBCLEN_NEEDMORE_P(r)) {
4976 char cbuf[8], *p = cbuf;
4977 int more = MBCLEN_NEEDMORE_LEN(r);
4978 if (more > numberof(cbuf)) goto invalid;
4979 more += n = fptr->rbuf.len;
4980 if (more > numberof(cbuf)) goto invalid;
4981 while ((n = (int)read_buffered_data(p, more, fptr)) > 0 &&
4982 (p += n, (more -= n) > 0)) {
4983 if (io_fillbuf(fptr) < 0) goto invalid;
4984 if ((n = fptr->rbuf.len) > more) n = more;
4985 }
4986 r = rb_enc_precise_mbclen(cbuf, p, enc);
4987 if (!MBCLEN_CHARFOUND_P(r)) goto invalid;
4988 c = rb_enc_codepoint(cbuf, p, enc);
4989 rb_yield(UINT2NUM(c));
4990 }
4991 else {
4992 continue;
4993 }
4995 }
4996 return io;
4997
4998 invalid:
4999 rb_raise(rb_eArgError, "invalid byte sequence in %s", rb_enc_name(enc));
5001}
5002
5003/*
5004 * call-seq:
5005 * getc -> character or nil
5006 *
5007 * Reads and returns the next 1-character string from the stream;
5008 * returns +nil+ if already at end-of-stream.
5009 * See {Character IO}[rdoc-ref:IO@Character+IO].
5010 *
5011 * f = File.open('t.txt')
5012 * f.getc # => "F"
5013 * f.close
5014 * f = File.open('t.rus')
5015 * f.getc.ord # => 1090
5016 * f.close
5017 *
5018 * Related: IO#readchar (may raise EOFError).
5019 *
5020 */
5021
5022static VALUE
5023rb_io_getc(VALUE io)
5024{
5025 rb_io_t *fptr;
5026 rb_encoding *enc;
5027
5028 GetOpenFile(io, fptr);
5030
5031 enc = io_input_encoding(fptr);
5032 READ_CHECK(fptr);
5033 return io_getc(fptr, enc);
5034}
5035
5036/*
5037 * call-seq:
5038 * readchar -> string
5039 *
5040 * Reads and returns the next 1-character string from the stream;
5041 * raises EOFError if already at end-of-stream.
5042 * See {Character IO}[rdoc-ref:IO@Character+IO].
5043 *
5044 * f = File.open('t.txt')
5045 * f.readchar # => "F"
5046 * f.close
5047 * f = File.open('t.rus')
5048 * f.readchar.ord # => 1090
5049 * f.close
5050 *
5051 * Related: IO#getc (will not raise EOFError).
5052 *
5053 */
5054
5055static VALUE
5056rb_io_readchar(VALUE io)
5057{
5058 VALUE c = rb_io_getc(io);
5059
5060 if (NIL_P(c)) {
5061 rb_eof_error();
5062 }
5063 return c;
5064}
5065
5066/*
5067 * call-seq:
5068 * getbyte -> integer or nil
5069 *
5070 * Reads and returns the next byte (in range 0..255) from the stream;
5071 * returns +nil+ if already at end-of-stream.
5072 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5073 *
5074 * f = File.open('t.txt')
5075 * f.getbyte # => 70
5076 * f.close
5077 * f = File.open('t.rus')
5078 * f.getbyte # => 209
5079 * f.close
5080 *
5081 * Related: IO#readbyte (may raise EOFError).
5082 */
5083
5084VALUE
5086{
5087 rb_io_t *fptr;
5088 int c;
5089
5090 GetOpenFile(io, fptr);
5092 READ_CHECK(fptr);
5093 VALUE r_stdout = rb_ractor_stdout();
5094 if (fptr->fd == 0 && (fptr->mode & FMODE_TTY) && RB_TYPE_P(r_stdout, T_FILE)) {
5095 rb_io_t *ofp;
5096 GetOpenFile(r_stdout, ofp);
5097 if (ofp->mode & FMODE_TTY) {
5098 rb_io_flush(r_stdout);
5099 }
5100 }
5101 if (io_fillbuf(fptr) < 0) {
5102 return Qnil;
5103 }
5104 fptr->rbuf.off++;
5105 fptr->rbuf.len--;
5106 c = (unsigned char)fptr->rbuf.ptr[fptr->rbuf.off-1];
5107 return INT2FIX(c & 0xff);
5108}
5109
5110/*
5111 * call-seq:
5112 * readbyte -> integer
5113 *
5114 * Reads and returns the next byte (in range 0..255) from the stream;
5115 * raises EOFError if already at end-of-stream.
5116 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5117 *
5118 * f = File.open('t.txt')
5119 * f.readbyte # => 70
5120 * f.close
5121 * f = File.open('t.rus')
5122 * f.readbyte # => 209
5123 * f.close
5124 *
5125 * Related: IO#getbyte (will not raise EOFError).
5126 *
5127 */
5128
5129static VALUE
5130rb_io_readbyte(VALUE io)
5131{
5132 VALUE c = rb_io_getbyte(io);
5133
5134 if (NIL_P(c)) {
5135 rb_eof_error();
5136 }
5137 return c;
5138}
5139
5140/*
5141 * call-seq:
5142 * ungetbyte(integer) -> nil
5143 * ungetbyte(string) -> nil
5144 *
5145 * Pushes back ("unshifts") the given data onto the stream's buffer,
5146 * placing the data so that it is next to be read; returns +nil+.
5147 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5148 *
5149 * Note that:
5150 *
5151 * - Calling the method has no effect with unbuffered reads (such as IO#sysread).
5152 * - Calling #rewind on the stream discards the pushed-back data.
5153 *
5154 * When argument +integer+ is given, uses only its low-order byte:
5155 *
5156 * File.write('t.tmp', '012')
5157 * f = File.open('t.tmp')
5158 * f.ungetbyte(0x41) # => nil
5159 * f.read # => "A012"
5160 * f.rewind
5161 * f.ungetbyte(0x4243) # => nil
5162 * f.read # => "C012"
5163 * f.close
5164 *
5165 * When argument +string+ is given, uses all bytes:
5166 *
5167 * File.write('t.tmp', '012')
5168 * f = File.open('t.tmp')
5169 * f.ungetbyte('A') # => nil
5170 * f.read # => "A012"
5171 * f.rewind
5172 * f.ungetbyte('BCDE') # => nil
5173 * f.read # => "BCDE012"
5174 * f.close
5175 *
5176 */
5177
5178VALUE
5180{
5181 rb_io_t *fptr;
5182
5183 GetOpenFile(io, fptr);
5185 switch (TYPE(b)) {
5186 case T_NIL:
5187 return Qnil;
5188 case T_FIXNUM:
5189 case T_BIGNUM: ;
5190 VALUE v = rb_int_modulo(b, INT2FIX(256));
5191 unsigned char c = NUM2INT(v) & 0xFF;
5192 b = rb_str_new((const char *)&c, 1);
5193 break;
5194 default:
5195 StringValue(b);
5196 }
5197 io_ungetbyte(b, fptr);
5198 return Qnil;
5199}
5200
5201/*
5202 * call-seq:
5203 * ungetc(integer) -> nil
5204 * ungetc(string) -> nil
5205 *
5206 * Pushes back ("unshifts") the given data onto the stream's buffer,
5207 * placing the data so that it is next to be read; returns +nil+.
5208 * See {Character IO}[rdoc-ref:IO@Character+IO].
5209 *
5210 * Note that:
5211 *
5212 * - Calling the method has no effect with unbuffered reads (such as IO#sysread).
5213 * - Calling #rewind on the stream discards the pushed-back data.
5214 *
5215 * When argument +integer+ is given, interprets the integer as a character:
5216 *
5217 * File.write('t.tmp', '012')
5218 * f = File.open('t.tmp')
5219 * f.ungetc(0x41) # => nil
5220 * f.read # => "A012"
5221 * f.rewind
5222 * f.ungetc(0x0442) # => nil
5223 * f.getc.ord # => 1090
5224 * f.close
5225 *
5226 * When argument +string+ is given, uses all characters:
5227 *
5228 * File.write('t.tmp', '012')
5229 * f = File.open('t.tmp')
5230 * f.ungetc('A') # => nil
5231 * f.read # => "A012"
5232 * f.rewind
5233 * f.ungetc("\u0442\u0435\u0441\u0442") # => nil
5234 * f.getc.ord # => 1090
5235 * f.getc.ord # => 1077
5236 * f.getc.ord # => 1089
5237 * f.getc.ord # => 1090
5238 * f.close
5239 *
5240 */
5241
5242VALUE
5244{
5245 rb_io_t *fptr;
5246 long len;
5247
5248 GetOpenFile(io, fptr);
5250 if (FIXNUM_P(c)) {
5251 c = rb_enc_uint_chr(FIX2UINT(c), io_read_encoding(fptr));
5252 }
5253 else if (RB_BIGNUM_TYPE_P(c)) {
5254 c = rb_enc_uint_chr(NUM2UINT(c), io_read_encoding(fptr));
5255 }
5256 else {
5257 StringValue(c);
5258 }
5259 if (NEED_READCONV(fptr)) {
5260 SET_BINARY_MODE(fptr);
5261 len = RSTRING_LEN(c);
5262#if SIZEOF_LONG > SIZEOF_INT
5263 if (len > INT_MAX)
5264 rb_raise(rb_eIOError, "ungetc failed");
5265#endif
5266 make_readconv(fptr, (int)len);
5267 if (fptr->cbuf.capa - fptr->cbuf.len < len)
5268 rb_raise(rb_eIOError, "ungetc failed");
5269 if (fptr->cbuf.off < len) {
5270 MEMMOVE(fptr->cbuf.ptr+fptr->cbuf.capa-fptr->cbuf.len,
5271 fptr->cbuf.ptr+fptr->cbuf.off,
5272 char, fptr->cbuf.len);
5273 fptr->cbuf.off = fptr->cbuf.capa-fptr->cbuf.len;
5274 }
5275 fptr->cbuf.off -= (int)len;
5276 fptr->cbuf.len += (int)len;
5277 MEMMOVE(fptr->cbuf.ptr+fptr->cbuf.off, RSTRING_PTR(c), char, len);
5278 }
5279 else {
5280 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
5281 io_ungetbyte(c, fptr);
5282 }
5283 return Qnil;
5284}
5285
5286/*
5287 * call-seq:
5288 * isatty -> true or false
5289 *
5290 * Returns +true+ if the stream is associated with a terminal device (tty),
5291 * +false+ otherwise:
5292 *
5293 * f = File.new('t.txt').isatty #=> false
5294 * f.close
5295 * f = File.new('/dev/tty').isatty #=> true
5296 * f.close
5297 *
5298 */
5299
5300static VALUE
5301rb_io_isatty(VALUE io)
5302{
5303 rb_io_t *fptr;
5304
5305 GetOpenFile(io, fptr);
5306 return RBOOL(isatty(fptr->fd) != 0);
5307}
5308
5309#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5310/*
5311 * call-seq:
5312 * close_on_exec? -> true or false
5313 *
5314 * Returns +true+ if the stream will be closed on exec, +false+ otherwise:
5315 *
5316 * f = File.open('t.txt')
5317 * f.close_on_exec? # => true
5318 * f.close_on_exec = false
5319 * f.close_on_exec? # => false
5320 * f.close
5321 *
5322 */
5323
5324static VALUE
5325rb_io_close_on_exec_p(VALUE io)
5326{
5327 rb_io_t *fptr;
5328 VALUE write_io;
5329 int fd, ret;
5330
5331 write_io = GetWriteIO(io);
5332 if (io != write_io) {
5333 GetOpenFile(write_io, fptr);
5334 if (fptr && 0 <= (fd = fptr->fd)) {
5335 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5336 if (!(ret & FD_CLOEXEC)) return Qfalse;
5337 }
5338 }
5339
5340 GetOpenFile(io, fptr);
5341 if (fptr && 0 <= (fd = fptr->fd)) {
5342 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5343 if (!(ret & FD_CLOEXEC)) return Qfalse;
5344 }
5345 return Qtrue;
5346}
5347#else
5348#define rb_io_close_on_exec_p rb_f_notimplement
5349#endif
5350
5351#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5352/*
5353 * call-seq:
5354 * self.close_on_exec = bool -> true or false
5355 *
5356 * Sets a close-on-exec flag.
5357 *
5358 * f = File.open(File::NULL)
5359 * f.close_on_exec = true
5360 * system("cat", "/proc/self/fd/#{f.fileno}") # cat: /proc/self/fd/3: No such file or directory
5361 * f.closed? #=> false
5362 *
5363 * Ruby sets close-on-exec flags of all file descriptors by default
5364 * since Ruby 2.0.0.
5365 * So you don't need to set by yourself.
5366 * Also, unsetting a close-on-exec flag can cause file descriptor leak
5367 * if another thread use fork() and exec() (via system() method for example).
5368 * If you really needs file descriptor inheritance to child process,
5369 * use spawn()'s argument such as fd=>fd.
5370 */
5371
5372static VALUE
5373rb_io_set_close_on_exec(VALUE io, VALUE arg)
5374{
5375 int flag = RTEST(arg) ? FD_CLOEXEC : 0;
5376 rb_io_t *fptr;
5377 VALUE write_io;
5378 int fd, ret;
5379
5380 write_io = GetWriteIO(io);
5381 if (io != write_io) {
5382 GetOpenFile(write_io, fptr);
5383 if (fptr && 0 <= (fd = fptr->fd)) {
5384 if ((ret = fcntl(fptr->fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5385 if ((ret & FD_CLOEXEC) != flag) {
5386 ret = (ret & ~FD_CLOEXEC) | flag;
5387 ret = fcntl(fd, F_SETFD, ret);
5388 if (ret != 0) rb_sys_fail_path(fptr->pathv);
5389 }
5390 }
5391
5392 }
5393
5394 GetOpenFile(io, fptr);
5395 if (fptr && 0 <= (fd = fptr->fd)) {
5396 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5397 if ((ret & FD_CLOEXEC) != flag) {
5398 ret = (ret & ~FD_CLOEXEC) | flag;
5399 ret = fcntl(fd, F_SETFD, ret);
5400 if (ret != 0) rb_sys_fail_path(fptr->pathv);
5401 }
5402 }
5403 return Qnil;
5404}
5405#else
5406#define rb_io_set_close_on_exec rb_f_notimplement
5407#endif
5408
5409#define RUBY_IO_EXTERNAL_P(f) ((f)->mode & FMODE_EXTERNAL)
5410#define PREP_STDIO_NAME(f) (RSTRING_PTR((f)->pathv))
5411
5412static VALUE
5413finish_writeconv(rb_io_t *fptr, int noalloc)
5414{
5415 unsigned char *ds, *dp, *de;
5417
5418 if (!fptr->wbuf.ptr) {
5419 unsigned char buf[1024];
5420
5422 while (res == econv_destination_buffer_full) {
5423 ds = dp = buf;
5424 de = buf + sizeof(buf);
5425 res = rb_econv_convert(fptr->writeconv, NULL, NULL, &dp, de, 0);
5426 while (dp-ds) {
5427 size_t remaining = dp-ds;
5428 long result = rb_io_write_memory(fptr, ds, remaining);
5429
5430 if (result > 0) {
5431 ds += result;
5432 if ((size_t)result == remaining) break;
5433 }
5434 else if (rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
5435 if (fptr->fd < 0)
5436 return noalloc ? Qtrue : rb_exc_new3(rb_eIOError, rb_str_new_cstr(closed_stream));
5437 }
5438 else {
5439 return noalloc ? Qtrue : INT2NUM(errno);
5440 }
5441 }
5442 if (res == econv_invalid_byte_sequence ||
5443 res == econv_incomplete_input ||
5445 return noalloc ? Qtrue : rb_econv_make_exception(fptr->writeconv);
5446 }
5447 }
5448
5449 return Qnil;
5450 }
5451
5453 while (res == econv_destination_buffer_full) {
5454 if (fptr->wbuf.len == fptr->wbuf.capa) {
5455 if (io_fflush(fptr) < 0) {
5456 return noalloc ? Qtrue : INT2NUM(errno);
5457 }
5458 }
5459
5460 ds = dp = (unsigned char *)fptr->wbuf.ptr + fptr->wbuf.off + fptr->wbuf.len;
5461 de = (unsigned char *)fptr->wbuf.ptr + fptr->wbuf.capa;
5462 res = rb_econv_convert(fptr->writeconv, NULL, NULL, &dp, de, 0);
5463 fptr->wbuf.len += (int)(dp - ds);
5464 if (res == econv_invalid_byte_sequence ||
5465 res == econv_incomplete_input ||
5467 return noalloc ? Qtrue : rb_econv_make_exception(fptr->writeconv);
5468 }
5469 }
5470 return Qnil;
5471}
5472
5474 rb_io_t *fptr;
5475 int noalloc;
5476};
5477
5478static VALUE
5479finish_writeconv_sync(VALUE arg)
5480{
5481 struct finish_writeconv_arg *p = (struct finish_writeconv_arg *)arg;
5482 return finish_writeconv(p->fptr, p->noalloc);
5483}
5484
5485static void*
5486nogvl_close(void *ptr)
5487{
5488 int *fd = ptr;
5489
5490 return (void*)(intptr_t)close(*fd);
5491}
5492
5493static int
5494maygvl_close(int fd, int keepgvl)
5495{
5496 if (keepgvl)
5497 return close(fd);
5498
5499 /*
5500 * close() may block for certain file types (NFS, SO_LINGER sockets,
5501 * inotify), so let other threads run.
5502 */
5503 return IO_WITHOUT_GVL_INT(nogvl_close, &fd);
5504}
5505
5506static void*
5507nogvl_fclose(void *ptr)
5508{
5509 FILE *file = ptr;
5510
5511 return (void*)(intptr_t)fclose(file);
5512}
5513
5514static int
5515maygvl_fclose(FILE *file, int keepgvl)
5516{
5517 if (keepgvl)
5518 return fclose(file);
5519
5520 return IO_WITHOUT_GVL_INT(nogvl_fclose, file);
5521}
5522
5523static void free_io_buffer(rb_io_buffer_t *buf);
5524
5525static void
5526fptr_finalize_flush(rb_io_t *fptr, int noraise, int keepgvl)
5527{
5528 VALUE error = Qnil;
5529 int fd = fptr->fd;
5530 FILE *stdio_file = fptr->stdio_file;
5531 int mode = fptr->mode;
5532
5533 if (fptr->writeconv) {
5534 if (!NIL_P(fptr->write_lock) && !noraise) {
5535 struct finish_writeconv_arg arg;
5536 arg.fptr = fptr;
5537 arg.noalloc = noraise;
5538 error = rb_mutex_synchronize(fptr->write_lock, finish_writeconv_sync, (VALUE)&arg);
5539 }
5540 else {
5541 error = finish_writeconv(fptr, noraise);
5542 }
5543 }
5544 if (fptr->wbuf.len) {
5545 if (noraise) {
5546 io_flush_buffer_sync(fptr);
5547 }
5548 else {
5549 if (io_fflush(fptr) < 0 && NIL_P(error)) {
5550 error = INT2NUM(errno);
5551 }
5552 }
5553 }
5554
5555 int done = 0;
5556
5557 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2) {
5558 // Need to keep FILE objects of stdin, stdout and stderr, so we are done:
5559 done = 1;
5560 }
5561
5562 fptr->fd = -1;
5563 fptr->stdio_file = 0;
5565
5566 // wait for blocking operations to ensure they do not hit EBADF:
5567 rb_thread_io_close_wait(fptr);
5568
5569 // Disable for now.
5570 // if (!done && fd >= 0) {
5571 // VALUE scheduler = rb_fiber_scheduler_current();
5572 // if (scheduler != Qnil) {
5573 // VALUE result = rb_fiber_scheduler_io_close(scheduler, fptr->self);
5574 // if (!UNDEF_P(result)) done = 1;
5575 // }
5576 // }
5577
5578 if (!done && stdio_file) {
5579 // stdio_file is deallocated anyway even if fclose failed.
5580 if ((maygvl_fclose(stdio_file, noraise) < 0) && NIL_P(error)) {
5581 if (!noraise) {
5582 error = INT2NUM(errno);
5583 }
5584 }
5585
5586 done = 1;
5587 }
5588
5589 if (!done && fd >= 0) {
5590 // fptr->fd may be closed even if close fails. POSIX doesn't specify it.
5591 // We assumes it is closed.
5592
5593 keepgvl |= !(mode & FMODE_WRITABLE);
5594 keepgvl |= noraise;
5595 if ((maygvl_close(fd, keepgvl) < 0) && NIL_P(error)) {
5596 if (!noraise) {
5597 error = INT2NUM(errno);
5598 }
5599 }
5600
5601 done = 1;
5602 }
5603
5604 if (!NIL_P(error) && !noraise) {
5605 if (RB_INTEGER_TYPE_P(error))
5606 rb_syserr_fail_path(NUM2INT(error), fptr->pathv);
5607 else
5608 rb_exc_raise(error);
5609 }
5610}
5611
5612static void
5613fptr_finalize(rb_io_t *fptr, int noraise)
5614{
5615 fptr_finalize_flush(fptr, noraise, FALSE);
5616 free_io_buffer(&fptr->rbuf);
5617 free_io_buffer(&fptr->wbuf);
5618 clear_codeconv(fptr);
5619}
5620
5621static void
5622rb_io_fptr_cleanup(rb_io_t *fptr, int noraise)
5623{
5624 if (fptr->finalize) {
5625 (*fptr->finalize)(fptr, noraise);
5626 }
5627 else {
5628 fptr_finalize(fptr, noraise);
5629 }
5630}
5631
5632static void
5633free_io_buffer(rb_io_buffer_t *buf)
5634{
5635 if (buf->ptr) {
5636 ruby_sized_xfree(buf->ptr, (size_t)buf->capa);
5637 buf->ptr = NULL;
5638 }
5639}
5640
5641static void
5642clear_readconv(rb_io_t *fptr)
5643{
5644 if (fptr->readconv) {
5645 rb_econv_close(fptr->readconv);
5646 fptr->readconv = NULL;
5647 }
5648 free_io_buffer(&fptr->cbuf);
5649}
5650
5651static void
5652clear_writeconv(rb_io_t *fptr)
5653{
5654 if (fptr->writeconv) {
5656 fptr->writeconv = NULL;
5657 }
5658 fptr->writeconv_initialized = 0;
5659}
5660
5661static void
5662clear_codeconv(rb_io_t *fptr)
5663{
5664 clear_readconv(fptr);
5665 clear_writeconv(fptr);
5666}
5667
5668static void
5669rb_io_fptr_cleanup_all(rb_io_t *fptr)
5670{
5671 fptr->pathv = Qnil;
5672 if (0 <= fptr->fd)
5673 rb_io_fptr_cleanup(fptr, TRUE);
5674 fptr->write_lock = Qnil;
5675 free_io_buffer(&fptr->rbuf);
5676 free_io_buffer(&fptr->wbuf);
5677 clear_codeconv(fptr);
5678}
5679
5680int
5682{
5683 if (!io) return 0;
5684 rb_io_fptr_cleanup_all(io);
5685 free(io);
5686
5687 return 1;
5688}
5689
5690size_t
5691rb_io_memsize(const rb_io_t *io)
5692{
5693 size_t size = sizeof(rb_io_t);
5694 size += io->rbuf.capa;
5695 size += io->wbuf.capa;
5696 size += io->cbuf.capa;
5697 if (io->readconv) size += rb_econv_memsize(io->readconv);
5698 if (io->writeconv) size += rb_econv_memsize(io->writeconv);
5699
5700 struct rb_io_blocking_operation *blocking_operation = 0;
5701
5702 // Validate the fork generation of the IO object. If the IO object fork generation is different, the list of blocking operations is not valid memory. See `rb_io_blocking_operations` for the exact semantics.
5703 rb_serial_t fork_generation = GET_VM()->fork_gen;
5704 if (io->fork_generation == fork_generation) {
5705 ccan_list_for_each(&io->blocking_operations, blocking_operation, list) {
5706 size += sizeof(struct rb_io_blocking_operation);
5707 }
5708 }
5709
5710 return size;
5711}
5712
5713#ifdef _WIN32
5714/* keep GVL while closing to prevent crash on Windows */
5715# define KEEPGVL TRUE
5716#else
5717# define KEEPGVL FALSE
5718#endif
5719
5720static rb_io_t *
5721io_close_fptr(VALUE io)
5722{
5723 rb_io_t *fptr;
5724 VALUE write_io;
5725 rb_io_t *write_fptr;
5726
5727 write_io = GetWriteIO(io);
5728 if (io != write_io) {
5729 write_fptr = RFILE(write_io)->fptr;
5730 if (write_fptr && 0 <= write_fptr->fd) {
5731 rb_io_fptr_cleanup(write_fptr, TRUE);
5732 }
5733 }
5734
5735 fptr = RFILE(io)->fptr;
5736 if (!fptr) return 0;
5737 if (fptr->fd < 0) return 0;
5738
5739 if (rb_thread_io_close_interrupt(fptr)) {
5740 /* calls close(fptr->fd): */
5741 fptr_finalize_flush(fptr, FALSE, KEEPGVL);
5742 }
5743 rb_io_fptr_cleanup(fptr, FALSE);
5744 return fptr;
5745}
5746
5747static void
5748fptr_waitpid(rb_io_t *fptr, int nohang)
5749{
5750 int status;
5751 if (fptr->pid) {
5752 rb_last_status_clear();
5753 rb_waitpid(fptr->pid, &status, nohang ? WNOHANG : 0);
5754 fptr->pid = 0;
5755 }
5756}
5757
5758VALUE
5760{
5761 rb_io_t *fptr = io_close_fptr(io);
5762 if (fptr) fptr_waitpid(fptr, 0);
5763 return Qnil;
5764}
5765
5766/*
5767 * call-seq:
5768 * close -> nil
5769 *
5770 * Closes the stream for both reading and writing
5771 * if open for either or both; returns +nil+.
5772 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5773 *
5774 * If the stream is open for writing, flushes any buffered writes
5775 * to the operating system before closing.
5776 *
5777 * If the stream was opened by IO.popen, sets global variable <tt>$?</tt>
5778 * (child exit status).
5779 *
5780 * It is not an error to close an IO object that has already been closed.
5781 * It just returns nil.
5782 *
5783 * Example:
5784 *
5785 * IO.popen('ruby', 'r+') do |pipe|
5786 * puts pipe.closed?
5787 * pipe.close
5788 * puts $?
5789 * puts pipe.closed?
5790 * end
5791 *
5792 * Output:
5793 *
5794 * false
5795 * pid 13760 exit 0
5796 * true
5797 *
5798 * Related: IO#close_read, IO#close_write, IO#closed?.
5799 */
5800
5801static VALUE
5802rb_io_close_m(VALUE io)
5803{
5804 rb_io_t *fptr = rb_io_get_fptr(io);
5805 if (fptr->fd < 0) {
5806 return Qnil;
5807 }
5808 rb_io_close(io);
5809 return Qnil;
5810}
5811
5812static VALUE
5813io_call_close(VALUE io)
5814{
5815 rb_check_funcall(io, rb_intern("close"), 0, 0);
5816 return io;
5817}
5818
5819static VALUE
5820ignore_closed_stream(VALUE io, VALUE exc)
5821{
5822 enum {mesg_len = sizeof(closed_stream)-1};
5823 VALUE mesg = rb_attr_get(exc, idMesg);
5824 if (!RB_TYPE_P(mesg, T_STRING) ||
5825 RSTRING_LEN(mesg) != mesg_len ||
5826 memcmp(RSTRING_PTR(mesg), closed_stream, mesg_len)) {
5827 rb_exc_raise(exc);
5828 }
5829 return io;
5830}
5831
5832static VALUE
5833io_close(VALUE io)
5834{
5835 VALUE closed = rb_check_funcall(io, rb_intern("closed?"), 0, 0);
5836 if (!UNDEF_P(closed) && RTEST(closed)) return io;
5837 rb_rescue2(io_call_close, io, ignore_closed_stream, io,
5838 rb_eIOError, (VALUE)0);
5839 return io;
5840}
5841
5842/*
5843 * call-seq:
5844 * closed? -> true or false
5845 *
5846 * Returns +true+ if the stream is closed for both reading and writing,
5847 * +false+ otherwise.
5848 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5849 *
5850 * IO.popen('ruby', 'r+') do |pipe|
5851 * puts pipe.closed?
5852 * pipe.close_read
5853 * puts pipe.closed?
5854 * pipe.close_write
5855 * puts pipe.closed?
5856 * end
5857 *
5858 * Output:
5859 *
5860 * false
5861 * false
5862 * true
5863 *
5864 * Related: IO#close_read, IO#close_write, IO#close.
5865 */
5866VALUE
5868{
5869 rb_io_t *fptr;
5870 VALUE write_io;
5871 rb_io_t *write_fptr;
5872
5873 write_io = GetWriteIO(io);
5874 if (io != write_io) {
5875 write_fptr = RFILE(write_io)->fptr;
5876 if (write_fptr && 0 <= write_fptr->fd) {
5877 return Qfalse;
5878 }
5879 }
5880
5881 fptr = rb_io_get_fptr(io);
5882 return RBOOL(0 > fptr->fd);
5883}
5884
5885/*
5886 * call-seq:
5887 * close_read -> nil
5888 *
5889 * Closes the stream for reading if open for reading;
5890 * returns +nil+.
5891 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5892 *
5893 * If the stream was opened by IO.popen and is also closed for writing,
5894 * sets global variable <tt>$?</tt> (child exit status).
5895 *
5896 * Example:
5897 *
5898 * IO.popen('ruby', 'r+') do |pipe|
5899 * puts pipe.closed?
5900 * pipe.close_write
5901 * puts pipe.closed?
5902 * pipe.close_read
5903 * puts $?
5904 * puts pipe.closed?
5905 * end
5906 *
5907 * Output:
5908 *
5909 * false
5910 * false
5911 * pid 14748 exit 0
5912 * true
5913 *
5914 * Related: IO#close, IO#close_write, IO#closed?.
5915 */
5916
5917static VALUE
5918rb_io_close_read(VALUE io)
5919{
5920 rb_io_t *fptr;
5921 VALUE write_io;
5922
5923 fptr = rb_io_get_fptr(rb_io_taint_check(io));
5924 if (fptr->fd < 0) return Qnil;
5925 if (is_socket(fptr->fd, fptr->pathv)) {
5926#ifndef SHUT_RD
5927# define SHUT_RD 0
5928#endif
5929 if (shutdown(fptr->fd, SHUT_RD) < 0)
5930 rb_sys_fail_path(fptr->pathv);
5931 fptr->mode &= ~FMODE_READABLE;
5932 if (!(fptr->mode & FMODE_WRITABLE))
5933 return rb_io_close(io);
5934 return Qnil;
5935 }
5936
5937 write_io = GetWriteIO(io);
5938 if (io != write_io) {
5939 rb_io_t *wfptr;
5940 wfptr = rb_io_get_fptr(rb_io_taint_check(write_io));
5941 wfptr->pid = fptr->pid;
5942 fptr->pid = 0;
5943 RFILE(io)->fptr = wfptr;
5944 /* bind to write_io temporarily to get rid of memory/fd leak */
5945 fptr->tied_io_for_writing = 0;
5946 RFILE(write_io)->fptr = fptr;
5947 rb_io_fptr_cleanup(fptr, FALSE);
5948 /* should not finalize fptr because another thread may be reading it */
5949 return Qnil;
5950 }
5951
5952 if ((fptr->mode & (FMODE_DUPLEX|FMODE_WRITABLE)) == FMODE_WRITABLE) {
5953 rb_raise(rb_eIOError, "closing non-duplex IO for reading");
5954 }
5955 return rb_io_close(io);
5956}
5957
5958/*
5959 * call-seq:
5960 * close_write -> nil
5961 *
5962 * Closes the stream for writing if open for writing;
5963 * returns +nil+.
5964 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5965 *
5966 * Flushes any buffered writes to the operating system before closing.
5967 *
5968 * If the stream was opened by IO.popen and is also closed for reading,
5969 * sets global variable <tt>$?</tt> (child exit status).
5970 *
5971 * IO.popen('ruby', 'r+') do |pipe|
5972 * puts pipe.closed?
5973 * pipe.close_read
5974 * puts pipe.closed?
5975 * pipe.close_write
5976 * puts $?
5977 * puts pipe.closed?
5978 * end
5979 *
5980 * Output:
5981 *
5982 * false
5983 * false
5984 * pid 15044 exit 0
5985 * true
5986 *
5987 * Related: IO#close, IO#close_read, IO#closed?.
5988 */
5989
5990static VALUE
5991rb_io_close_write(VALUE io)
5992{
5993 rb_io_t *fptr;
5994 VALUE write_io;
5995
5996 write_io = GetWriteIO(io);
5997 fptr = rb_io_get_fptr(rb_io_taint_check(write_io));
5998 if (fptr->fd < 0) return Qnil;
5999 if (is_socket(fptr->fd, fptr->pathv)) {
6000#ifndef SHUT_WR
6001# define SHUT_WR 1
6002#endif
6003 if (shutdown(fptr->fd, SHUT_WR) < 0)
6004 rb_sys_fail_path(fptr->pathv);
6005 fptr->mode &= ~FMODE_WRITABLE;
6006 if (!(fptr->mode & FMODE_READABLE))
6007 return rb_io_close(write_io);
6008 return Qnil;
6009 }
6010
6011 if ((fptr->mode & (FMODE_DUPLEX|FMODE_READABLE)) == FMODE_READABLE) {
6012 rb_raise(rb_eIOError, "closing non-duplex IO for writing");
6013 }
6014
6015 if (io != write_io) {
6016 fptr = rb_io_get_fptr(rb_io_taint_check(io));
6017 fptr->tied_io_for_writing = 0;
6018 }
6019 rb_io_close(write_io);
6020 return Qnil;
6021}
6022
6023/*
6024 * call-seq:
6025 * sysseek(offset, whence = IO::SEEK_SET) -> integer
6026 *
6027 * Behaves like IO#seek, except that it:
6028 *
6029 * - Uses low-level system functions.
6030 * - Returns the new position.
6031 *
6032 */
6033
6034static VALUE
6035rb_io_sysseek(int argc, VALUE *argv, VALUE io)
6036{
6037 VALUE offset, ptrname;
6038 int whence = SEEK_SET;
6039 rb_io_t *fptr;
6040 rb_off_t pos;
6041
6042 if (rb_scan_args(argc, argv, "11", &offset, &ptrname) == 2) {
6043 whence = interpret_seek_whence(ptrname);
6044 }
6045 pos = NUM2OFFT(offset);
6046 GetOpenFile(io, fptr);
6047 if ((fptr->mode & FMODE_READABLE) &&
6048 (READ_DATA_BUFFERED(fptr) || READ_CHAR_PENDING(fptr))) {
6049 rb_raise(rb_eIOError, "sysseek for buffered IO");
6050 }
6051 if ((fptr->mode & FMODE_WRITABLE) && fptr->wbuf.len) {
6052 rb_warn("sysseek for buffered IO");
6053 }
6054 errno = 0;
6055 pos = lseek(fptr->fd, pos, whence);
6056 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
6057
6058 return OFFT2NUM(pos);
6059}
6060
6061/*
6062 * call-seq:
6063 * syswrite(object) -> integer
6064 *
6065 * Writes the given +object+ to self, which must be opened for writing (see Modes);
6066 * returns the number bytes written.
6067 * If +object+ is not a string is converted via method to_s:
6068 *
6069 * f = File.new('t.tmp', 'w')
6070 * f.syswrite('foo') # => 3
6071 * f.syswrite(30) # => 2
6072 * f.syswrite(:foo) # => 3
6073 * f.close
6074 *
6075 * This methods should not be used with other stream-writer methods.
6076 *
6077 */
6078
6079static VALUE
6080rb_io_syswrite(VALUE io, VALUE str)
6081{
6082 VALUE tmp;
6083 rb_io_t *fptr;
6084 long n, len;
6085 const char *ptr;
6086
6087 if (!RB_TYPE_P(str, T_STRING))
6088 str = rb_obj_as_string(str);
6089
6090 io = GetWriteIO(io);
6091 GetOpenFile(io, fptr);
6093
6094 if (fptr->wbuf.len) {
6095 rb_warn("syswrite for buffered IO");
6096 }
6097
6098 tmp = rb_str_tmp_frozen_acquire(str);
6099 RSTRING_GETMEM(tmp, ptr, len);
6100 n = rb_io_write_memory(fptr, ptr, len);
6101 if (n < 0) rb_sys_fail_path(fptr->pathv);
6102 rb_str_tmp_frozen_release(str, tmp);
6103
6104 return LONG2FIX(n);
6105}
6106
6107/*
6108 * call-seq:
6109 * sysread(maxlen) -> string
6110 * sysread(maxlen, out_string) -> string
6111 *
6112 * Behaves like IO#readpartial, except that it uses low-level system functions.
6113 *
6114 * This method should not be used with other stream-reader methods.
6115 *
6116 */
6117
6118static VALUE
6119rb_io_sysread(int argc, VALUE *argv, VALUE io)
6120{
6121 VALUE len, str;
6122 rb_io_t *fptr;
6123 long n, ilen;
6124 struct io_internal_read_struct iis;
6125 int shrinkable;
6126
6127 rb_scan_args(argc, argv, "11", &len, &str);
6128 ilen = NUM2LONG(len);
6129
6130 shrinkable = io_setstrbuf(&str, ilen);
6131 if (ilen == 0) return str;
6132
6133 GetOpenFile(io, fptr);
6135
6136 if (READ_DATA_BUFFERED(fptr)) {
6137 rb_raise(rb_eIOError, "sysread for buffered IO");
6138 }
6139
6140 rb_io_check_closed(fptr);
6141
6142 io_setstrbuf(&str, ilen);
6143 iis.th = rb_thread_current();
6144 iis.fptr = fptr;
6145 iis.nonblock = 0;
6146 iis.fd = fptr->fd;
6147 iis.buf = RSTRING_PTR(str);
6148 iis.capa = ilen;
6149 iis.timeout = NULL;
6150 n = io_read_memory_locktmp(str, &iis);
6151
6152 if (n < 0) {
6153 rb_sys_fail_path(fptr->pathv);
6154 }
6155
6156 io_set_read_length(str, n, shrinkable);
6157
6158 if (n == 0 && ilen > 0) {
6159 rb_eof_error();
6160 }
6161
6162 return str;
6163}
6164
6166 struct rb_io *io;
6167 int fd;
6168 void *buf;
6169 size_t count;
6170 rb_off_t offset;
6171};
6172
6173static VALUE
6174internal_pread_func(void *_arg)
6175{
6176 struct prdwr_internal_arg *arg = _arg;
6177
6178 return (VALUE)pread(arg->fd, arg->buf, arg->count, arg->offset);
6179}
6180
6181static VALUE
6182pread_internal_call(VALUE _arg)
6183{
6184 struct prdwr_internal_arg *arg = (struct prdwr_internal_arg *)_arg;
6185
6186 VALUE scheduler = rb_fiber_scheduler_current();
6187 if (scheduler != Qnil) {
6188 VALUE result = rb_fiber_scheduler_io_pread_memory(scheduler, arg->io->self, arg->offset, arg->buf, arg->count, 0);
6189
6190 if (!UNDEF_P(result)) {
6192 }
6193 }
6194
6195 return rb_io_blocking_region_wait(arg->io, internal_pread_func, arg, RUBY_IO_READABLE);
6196}
6197
6198/*
6199 * call-seq:
6200 * pread(maxlen, offset) -> string
6201 * pread(maxlen, offset, out_string) -> string
6202 *
6203 * Behaves like IO#readpartial, except that it:
6204 *
6205 * - Reads at the given +offset+ (in bytes).
6206 * - Disregards, and does not modify, the stream's position
6207 * (see {Position}[rdoc-ref:IO@Position]).
6208 * - Bypasses any user space buffering in the stream.
6209 *
6210 * Because this method does not disturb the stream's state
6211 * (its position, in particular), +pread+ allows multiple threads and processes
6212 * to use the same \IO object for reading at various offsets.
6213 *
6214 * f = File.open('t.txt')
6215 * f.read # => "First line\nSecond line\n\nFourth line\nFifth line\n"
6216 * f.pos # => 52
6217 * # Read 12 bytes at offset 0.
6218 * f.pread(12, 0) # => "First line\n"
6219 * # Read 9 bytes at offset 8.
6220 * f.pread(9, 8) # => "ne\nSecon"
6221 * f.close
6222 *
6223 * Not available on some platforms.
6224 *
6225 */
6226static VALUE
6227rb_io_pread(int argc, VALUE *argv, VALUE io)
6228{
6229 VALUE len, offset, str;
6230 rb_io_t *fptr;
6231 ssize_t n;
6232 struct prdwr_internal_arg arg;
6233 int shrinkable;
6234
6235 rb_scan_args(argc, argv, "21", &len, &offset, &str);
6236 arg.count = NUM2SIZET(len);
6237 arg.offset = NUM2OFFT(offset);
6238
6239 shrinkable = io_setstrbuf(&str, (long)arg.count);
6240 if (arg.count == 0) return str;
6241 arg.buf = RSTRING_PTR(str);
6242
6243 GetOpenFile(io, fptr);
6245
6246 arg.io = fptr;
6247 arg.fd = fptr->fd;
6248 rb_io_check_closed(fptr);
6249
6250 rb_str_locktmp(str);
6251 n = (ssize_t)rb_ensure(pread_internal_call, (VALUE)&arg, rb_str_unlocktmp, str);
6252
6253 if (n < 0) {
6254 rb_sys_fail_path(fptr->pathv);
6255 }
6256 io_set_read_length(str, n, shrinkable);
6257 if (n == 0 && arg.count > 0) {
6258 rb_eof_error();
6259 }
6260
6261 return str;
6262}
6263
6264static VALUE
6265internal_pwrite_func(void *_arg)
6266{
6267 struct prdwr_internal_arg *arg = _arg;
6268
6269 VALUE scheduler = rb_fiber_scheduler_current();
6270 if (scheduler != Qnil) {
6271 VALUE result = rb_fiber_scheduler_io_pwrite_memory(scheduler, arg->io->self, arg->offset, arg->buf, arg->count, 0);
6272
6273 if (!UNDEF_P(result)) {
6275 }
6276 }
6277
6278
6279 return (VALUE)pwrite(arg->fd, arg->buf, arg->count, arg->offset);
6280}
6281
6282/*
6283 * call-seq:
6284 * pwrite(object, offset) -> integer
6285 *
6286 * Behaves like IO#write, except that it:
6287 *
6288 * - Writes at the given +offset+ (in bytes).
6289 * - Disregards, and does not modify, the stream's position
6290 * (see {Position}[rdoc-ref:IO@Position]).
6291 * - Bypasses any user space buffering in the stream.
6292 *
6293 * Because this method does not disturb the stream's state
6294 * (its position, in particular), +pwrite+ allows multiple threads and processes
6295 * to use the same \IO object for writing at various offsets.
6296 *
6297 * f = File.open('t.tmp', 'w+')
6298 * # Write 6 bytes at offset 3.
6299 * f.pwrite('ABCDEF', 3) # => 6
6300 * f.rewind
6301 * f.read # => "\u0000\u0000\u0000ABCDEF"
6302 * f.close
6303 *
6304 * Not available on some platforms.
6305 *
6306 */
6307static VALUE
6308rb_io_pwrite(VALUE io, VALUE str, VALUE offset)
6309{
6310 rb_io_t *fptr;
6311 ssize_t n;
6312 struct prdwr_internal_arg arg;
6313 VALUE tmp;
6314
6315 if (!RB_TYPE_P(str, T_STRING))
6316 str = rb_obj_as_string(str);
6317
6318 arg.offset = NUM2OFFT(offset);
6319
6320 io = GetWriteIO(io);
6321 GetOpenFile(io, fptr);
6323
6324 arg.io = fptr;
6325 arg.fd = fptr->fd;
6326
6327 tmp = rb_str_tmp_frozen_acquire(str);
6328 arg.buf = RSTRING_PTR(tmp);
6329 arg.count = (size_t)RSTRING_LEN(tmp);
6330
6331 n = (ssize_t)rb_io_blocking_region_wait(fptr, internal_pwrite_func, &arg, RUBY_IO_WRITABLE);
6332 if (n < 0) rb_sys_fail_path(fptr->pathv);
6333 rb_str_tmp_frozen_release(str, tmp);
6334
6335 return SSIZET2NUM(n);
6336}
6337
6338VALUE
6340{
6341 rb_io_t *fptr;
6342
6343 GetOpenFile(io, fptr);
6344 if (fptr->readconv)
6346 if (fptr->writeconv)
6348 fptr->mode |= FMODE_BINMODE;
6349 fptr->mode &= ~FMODE_TEXTMODE;
6350 fptr->writeconv_pre_ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
6351#ifdef O_BINARY
6352 if (!fptr->readconv) {
6353 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6354 }
6355 else {
6356 setmode(fptr->fd, O_BINARY);
6357 }
6358#endif
6359 return io;
6360}
6361
6362static void
6363io_ascii8bit_binmode(rb_io_t *fptr)
6364{
6365 if (fptr->readconv) {
6366 rb_econv_close(fptr->readconv);
6367 fptr->readconv = NULL;
6368 }
6369 if (fptr->writeconv) {
6371 fptr->writeconv = NULL;
6372 }
6373 fptr->mode |= FMODE_BINMODE;
6374 fptr->mode &= ~FMODE_TEXTMODE;
6375 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6376
6377 fptr->encs.enc = rb_ascii8bit_encoding();
6378 fptr->encs.enc2 = NULL;
6379 fptr->encs.ecflags = 0;
6380 fptr->encs.ecopts = Qnil;
6381 clear_codeconv(fptr);
6382}
6383
6384VALUE
6386{
6387 rb_io_t *fptr;
6388
6389 GetOpenFile(io, fptr);
6390 io_ascii8bit_binmode(fptr);
6391
6392 return io;
6393}
6394
6395/*
6396 * call-seq:
6397 * binmode -> self
6398 *
6399 * Sets the stream's data mode as binary
6400 * (see {Data Mode}[rdoc-ref:File@Data+Mode]).
6401 *
6402 * A stream's data mode may not be changed from binary to text.
6403 *
6404 */
6405
6406static VALUE
6407rb_io_binmode_m(VALUE io)
6408{
6409 VALUE write_io;
6410
6412
6413 write_io = GetWriteIO(io);
6414 if (write_io != io)
6415 rb_io_ascii8bit_binmode(write_io);
6416 return io;
6417}
6418
6419/*
6420 * call-seq:
6421 * binmode? -> true or false
6422 *
6423 * Returns +true+ if the stream is on binary mode, +false+ otherwise.
6424 * See {Data Mode}[rdoc-ref:File@Data+Mode].
6425 *
6426 */
6427static VALUE
6428rb_io_binmode_p(VALUE io)
6429{
6430 rb_io_t *fptr;
6431 GetOpenFile(io, fptr);
6432 return RBOOL(fptr->mode & FMODE_BINMODE);
6433}
6434
6435static const char*
6436rb_io_fmode_modestr(enum rb_io_mode fmode)
6437{
6438 if (fmode & FMODE_APPEND) {
6439 if ((fmode & FMODE_READWRITE) == FMODE_READWRITE) {
6440 return MODE_BTMODE("a+", "ab+", "at+");
6441 }
6442 return MODE_BTMODE("a", "ab", "at");
6443 }
6444 switch (fmode & FMODE_READWRITE) {
6445 default:
6446 rb_raise(rb_eArgError, "invalid access fmode 0x%x", fmode);
6447 case FMODE_READABLE:
6448 return MODE_BTMODE("r", "rb", "rt");
6449 case FMODE_WRITABLE:
6450 return MODE_BTXMODE("w", "wb", "wt", "wx", "wbx", "wtx");
6451 case FMODE_READWRITE:
6452 if (fmode & FMODE_CREATE) {
6453 return MODE_BTXMODE("w+", "wb+", "wt+", "w+x", "wb+x", "wt+x");
6454 }
6455 return MODE_BTMODE("r+", "rb+", "rt+");
6456 }
6457}
6458
6459static const char bom_prefix[] = "bom|";
6460static const char utf_prefix[] = "utf-";
6461enum {bom_prefix_len = (int)sizeof(bom_prefix) - 1};
6462enum {utf_prefix_len = (int)sizeof(utf_prefix) - 1};
6463
6464static int
6465io_encname_bom_p(const char *name, long len)
6466{
6467 return len > bom_prefix_len && STRNCASECMP(name, bom_prefix, bom_prefix_len) == 0;
6468}
6469
6470enum rb_io_mode
6471rb_io_modestr_fmode(const char *modestr)
6472{
6473 enum rb_io_mode fmode = 0;
6474 const char *m = modestr, *p = NULL;
6475
6476 switch (*m++) {
6477 case 'r':
6478 fmode |= FMODE_READABLE;
6479 break;
6480 case 'w':
6482 break;
6483 case 'a':
6485 break;
6486 default:
6487 goto error;
6488 }
6489
6490 while (*m) {
6491 switch (*m++) {
6492 case 'b':
6493 fmode |= FMODE_BINMODE;
6494 break;
6495 case 't':
6496 fmode |= FMODE_TEXTMODE;
6497 break;
6498 case '+':
6499 fmode |= FMODE_READWRITE;
6500 break;
6501 case 'x':
6502 if (modestr[0] != 'w')
6503 goto error;
6504 fmode |= FMODE_EXCL;
6505 break;
6506 default:
6507 goto error;
6508 case ':':
6509 p = strchr(m, ':');
6510 if (io_encname_bom_p(m, p ? (long)(p - m) : (long)strlen(m)))
6511 fmode |= FMODE_SETENC_BY_BOM;
6512 goto finished;
6513 }
6514 }
6515
6516 finished:
6517 if ((fmode & FMODE_BINMODE) && (fmode & FMODE_TEXTMODE))
6518 goto error;
6519
6520 return fmode;
6521
6522 error:
6523 rb_raise(rb_eArgError, "invalid access mode %s", modestr);
6525}
6526
6527int
6528rb_io_oflags_fmode(int oflags)
6529{
6530 enum rb_io_mode fmode = 0;
6531
6532 switch (oflags & O_ACCMODE) {
6533 case O_RDONLY:
6534 fmode = FMODE_READABLE;
6535 break;
6536 case O_WRONLY:
6537 fmode = FMODE_WRITABLE;
6538 break;
6539 case O_RDWR:
6540 fmode = FMODE_READWRITE;
6541 break;
6542 }
6543
6544 if (oflags & O_APPEND) {
6545 fmode |= FMODE_APPEND;
6546 }
6547 if (oflags & O_TRUNC) {
6548 fmode |= FMODE_TRUNC;
6549 }
6550 if (oflags & O_CREAT) {
6551 fmode |= FMODE_CREATE;
6552 }
6553 if (oflags & O_EXCL) {
6554 fmode |= FMODE_EXCL;
6555 }
6556#ifdef O_BINARY
6557 if (oflags & O_BINARY) {
6558 fmode |= FMODE_BINMODE;
6559 }
6560#endif
6561
6562 return fmode;
6563}
6564
6565static int
6566rb_io_fmode_oflags(enum rb_io_mode fmode)
6567{
6568 int oflags = 0;
6569
6570 switch (fmode & FMODE_READWRITE) {
6571 case FMODE_READABLE:
6572 oflags |= O_RDONLY;
6573 break;
6574 case FMODE_WRITABLE:
6575 oflags |= O_WRONLY;
6576 break;
6577 case FMODE_READWRITE:
6578 oflags |= O_RDWR;
6579 break;
6580 }
6581
6582 if (fmode & FMODE_APPEND) {
6583 oflags |= O_APPEND;
6584 }
6585 if (fmode & FMODE_TRUNC) {
6586 oflags |= O_TRUNC;
6587 }
6588 if (fmode & FMODE_CREATE) {
6589 oflags |= O_CREAT;
6590 }
6591 if (fmode & FMODE_EXCL) {
6592 oflags |= O_EXCL;
6593 }
6594#ifdef O_BINARY
6595 if (fmode & FMODE_BINMODE) {
6596 oflags |= O_BINARY;
6597 }
6598#endif
6599
6600 return oflags;
6601}
6602
6603int
6604rb_io_modestr_oflags(const char *modestr)
6605{
6606 return rb_io_fmode_oflags(rb_io_modestr_fmode(modestr));
6607}
6608
6609static const char*
6610rb_io_oflags_modestr(int oflags)
6611{
6612#ifdef O_BINARY
6613# define MODE_BINARY(a,b) ((oflags & O_BINARY) ? (b) : (a))
6614#else
6615# define MODE_BINARY(a,b) (a)
6616#endif
6617 int accmode;
6618 if (oflags & O_EXCL) {
6619 rb_raise(rb_eArgError, "exclusive access mode is not supported");
6620 }
6621 accmode = oflags & (O_RDONLY|O_WRONLY|O_RDWR);
6622 if (oflags & O_APPEND) {
6623 if (accmode == O_WRONLY) {
6624 return MODE_BINARY("a", "ab");
6625 }
6626 if (accmode == O_RDWR) {
6627 return MODE_BINARY("a+", "ab+");
6628 }
6629 }
6630 switch (accmode) {
6631 default:
6632 rb_raise(rb_eArgError, "invalid access oflags 0x%x", oflags);
6633 case O_RDONLY:
6634 return MODE_BINARY("r", "rb");
6635 case O_WRONLY:
6636 return MODE_BINARY("w", "wb");
6637 case O_RDWR:
6638 if (oflags & O_TRUNC) {
6639 return MODE_BINARY("w+", "wb+");
6640 }
6641 return MODE_BINARY("r+", "rb+");
6642 }
6643}
6644
6645/*
6646 * Convert external/internal encodings to enc/enc2
6647 * NULL => use default encoding
6648 * Qnil => no encoding specified (internal only)
6649 */
6650static void
6651rb_io_ext_int_to_encs(rb_encoding *ext, rb_encoding *intern, rb_encoding **enc, rb_encoding **enc2, enum rb_io_mode fmode)
6652{
6653 int default_ext = 0;
6654
6655 if (ext == NULL) {
6656 ext = rb_default_external_encoding();
6657 default_ext = 1;
6658 }
6659 if (rb_is_ascii8bit_enc(ext)) {
6660 /* If external is ASCII-8BIT, no transcoding */
6661 intern = NULL;
6662 }
6663 else if (intern == NULL) {
6664 intern = rb_default_internal_encoding();
6665 }
6666 if (intern == NULL || intern == (rb_encoding *)Qnil ||
6667 (!(fmode & FMODE_SETENC_BY_BOM) && (intern == ext))) {
6668 /* No internal encoding => use external + no transcoding */
6669 *enc = (default_ext && intern != ext) ? NULL : ext;
6670 *enc2 = NULL;
6671 }
6672 else {
6673 *enc = intern;
6674 *enc2 = ext;
6675 }
6676}
6677
6678static void
6679unsupported_encoding(const char *name, rb_encoding *enc)
6680{
6681 rb_enc_warn(enc, "Unsupported encoding %s ignored", name);
6682}
6683
6684static void
6685parse_mode_enc(const char *estr, rb_encoding *estr_enc,
6686 rb_encoding **enc_p, rb_encoding **enc2_p, enum rb_io_mode *fmode_p)
6687{
6688 const char *p;
6689 char encname[ENCODING_MAXNAMELEN+1];
6690 int idx, idx2;
6691 enum rb_io_mode fmode = fmode_p ? *fmode_p : 0;
6692 rb_encoding *ext_enc, *int_enc;
6693 long len;
6694
6695 /* parse estr as "enc" or "enc2:enc" or "enc:-" */
6696
6697 p = strrchr(estr, ':');
6698 len = p ? (p++ - estr) : (long)strlen(estr);
6699 if ((fmode & FMODE_SETENC_BY_BOM) || io_encname_bom_p(estr, len)) {
6700 estr += bom_prefix_len;
6701 len -= bom_prefix_len;
6702 if (!STRNCASECMP(estr, utf_prefix, utf_prefix_len)) {
6703 fmode |= FMODE_SETENC_BY_BOM;
6704 }
6705 else {
6706 rb_enc_warn(estr_enc, "BOM with non-UTF encoding %s is nonsense", estr);
6707 fmode &= ~FMODE_SETENC_BY_BOM;
6708 }
6709 }
6710 if (len == 0 || len > ENCODING_MAXNAMELEN) {
6711 idx = -1;
6712 }
6713 else {
6714 if (p) {
6715 memcpy(encname, estr, len);
6716 encname[len] = '\0';
6717 estr = encname;
6718 }
6719 idx = rb_enc_find_index(estr);
6720 }
6721 if (fmode_p) *fmode_p = fmode;
6722
6723 if (idx >= 0)
6724 ext_enc = rb_enc_from_index(idx);
6725 else {
6726 if (idx != -2)
6727 unsupported_encoding(estr, estr_enc);
6728 ext_enc = NULL;
6729 }
6730
6731 int_enc = NULL;
6732 if (p) {
6733 if (*p == '-' && *(p+1) == '\0') {
6734 /* Special case - "-" => no transcoding */
6735 int_enc = (rb_encoding *)Qnil;
6736 }
6737 else {
6738 idx2 = rb_enc_find_index(p);
6739 if (idx2 < 0)
6740 unsupported_encoding(p, estr_enc);
6741 else if (!(fmode & FMODE_SETENC_BY_BOM) && (idx2 == idx)) {
6742 int_enc = (rb_encoding *)Qnil;
6743 }
6744 else
6745 int_enc = rb_enc_from_index(idx2);
6746 }
6747 }
6748
6749 rb_io_ext_int_to_encs(ext_enc, int_enc, enc_p, enc2_p, fmode);
6750}
6751
6752int
6753rb_io_extract_encoding_option(VALUE opt, rb_encoding **enc_p, rb_encoding **enc2_p, enum rb_io_mode *fmode_p)
6754{
6755 VALUE encoding=Qnil, extenc=Qundef, intenc=Qundef, tmp;
6756 int extracted = 0;
6757 rb_encoding *extencoding = NULL;
6758 rb_encoding *intencoding = NULL;
6759
6760 if (!NIL_P(opt)) {
6761 VALUE v;
6762 v = rb_hash_lookup2(opt, sym_encoding, Qnil);
6763 if (v != Qnil) encoding = v;
6764 v = rb_hash_lookup2(opt, sym_extenc, Qundef);
6765 if (v != Qnil) extenc = v;
6766 v = rb_hash_lookup2(opt, sym_intenc, Qundef);
6767 if (!UNDEF_P(v)) intenc = v;
6768 }
6769 if ((!UNDEF_P(extenc) || !UNDEF_P(intenc)) && !NIL_P(encoding)) {
6770 if (!NIL_P(ruby_verbose)) {
6771 int idx = rb_to_encoding_index(encoding);
6772 if (idx >= 0) encoding = rb_enc_from_encoding(rb_enc_from_index(idx));
6773 rb_warn("Ignoring encoding parameter '%"PRIsVALUE"': %s_encoding is used",
6774 encoding, UNDEF_P(extenc) ? "internal" : "external");
6775 }
6776 encoding = Qnil;
6777 }
6778 if (!UNDEF_P(extenc) && !NIL_P(extenc)) {
6779 extencoding = rb_to_encoding(extenc);
6780 }
6781 if (!UNDEF_P(intenc)) {
6782 if (NIL_P(intenc)) {
6783 /* internal_encoding: nil => no transcoding */
6784 intencoding = (rb_encoding *)Qnil;
6785 }
6786 else if (!NIL_P(tmp = rb_check_string_type(intenc))) {
6787 char *p = StringValueCStr(tmp);
6788
6789 if (*p == '-' && *(p+1) == '\0') {
6790 /* Special case - "-" => no transcoding */
6791 intencoding = (rb_encoding *)Qnil;
6792 }
6793 else {
6794 intencoding = rb_to_encoding(intenc);
6795 }
6796 }
6797 else {
6798 intencoding = rb_to_encoding(intenc);
6799 }
6800 if (extencoding == intencoding) {
6801 intencoding = (rb_encoding *)Qnil;
6802 }
6803 }
6804 if (!NIL_P(encoding)) {
6805 extracted = 1;
6806 if (!NIL_P(tmp = rb_check_string_type(encoding))) {
6807 parse_mode_enc(StringValueCStr(tmp), rb_enc_get(tmp),
6808 enc_p, enc2_p, fmode_p);
6809 }
6810 else {
6811 rb_io_ext_int_to_encs(rb_to_encoding(encoding), NULL, enc_p, enc2_p, 0);
6812 }
6813 }
6814 else if (!UNDEF_P(extenc) || !UNDEF_P(intenc)) {
6815 extracted = 1;
6816 rb_io_ext_int_to_encs(extencoding, intencoding, enc_p, enc2_p, 0);
6817 }
6818 return extracted;
6819}
6820
6821static void
6822validate_enc_binmode(enum rb_io_mode *fmode_p, int ecflags, rb_encoding *enc, rb_encoding *enc2)
6823{
6824 enum rb_io_mode fmode = *fmode_p;
6825
6826 if ((fmode & FMODE_READABLE) &&
6827 !enc2 &&
6828 !(fmode & FMODE_BINMODE) &&
6829 !rb_enc_asciicompat(enc ? enc : rb_default_external_encoding()))
6830 rb_raise(rb_eArgError, "ASCII incompatible encoding needs binmode");
6831
6832 if ((fmode & FMODE_BINMODE) && (ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
6833 rb_raise(rb_eArgError, "newline decorator with binary mode");
6834 }
6835 if (!(fmode & FMODE_BINMODE) &&
6836 (DEFAULT_TEXTMODE || (ecflags & ECONV_NEWLINE_DECORATOR_MASK))) {
6837 fmode |= FMODE_TEXTMODE;
6838 *fmode_p = fmode;
6839 }
6840#if !DEFAULT_TEXTMODE
6841 else if (!(ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
6842 fmode &= ~FMODE_TEXTMODE;
6843 *fmode_p = fmode;
6844 }
6845#endif
6846}
6847
6848static void
6849extract_binmode(VALUE opthash, enum rb_io_mode *fmode)
6850{
6851 if (!NIL_P(opthash)) {
6852 VALUE v;
6853 v = rb_hash_aref(opthash, sym_textmode);
6854 if (!NIL_P(v)) {
6855 if (*fmode & FMODE_TEXTMODE)
6856 rb_raise(rb_eArgError, "textmode specified twice");
6857 if (*fmode & FMODE_BINMODE)
6858 rb_raise(rb_eArgError, "both textmode and binmode specified");
6859 if (RTEST(v))
6860 *fmode |= FMODE_TEXTMODE;
6861 }
6862 v = rb_hash_aref(opthash, sym_binmode);
6863 if (!NIL_P(v)) {
6864 if (*fmode & FMODE_BINMODE)
6865 rb_raise(rb_eArgError, "binmode specified twice");
6866 if (*fmode & FMODE_TEXTMODE)
6867 rb_raise(rb_eArgError, "both textmode and binmode specified");
6868 if (RTEST(v))
6869 *fmode |= FMODE_BINMODE;
6870 }
6871
6872 if ((*fmode & FMODE_BINMODE) && (*fmode & FMODE_TEXTMODE))
6873 rb_raise(rb_eArgError, "both textmode and binmode specified");
6874 }
6875}
6876
6877void
6878rb_io_extract_modeenc(VALUE *vmode_p, VALUE *vperm_p, VALUE opthash,
6879 int *oflags_p, enum rb_io_mode *fmode_p, struct rb_io_encoding *convconfig_p)
6880{
6881 VALUE vmode;
6882 int oflags;
6883 enum rb_io_mode fmode;
6884 rb_encoding *enc, *enc2;
6885 int ecflags;
6886 VALUE ecopts;
6887 int has_enc = 0, has_vmode = 0;
6888 VALUE intmode;
6889
6890 vmode = *vmode_p;
6891
6892 /* Set to defaults */
6893 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
6894
6895 vmode_handle:
6896 if (NIL_P(vmode)) {
6897 fmode = FMODE_READABLE;
6898 oflags = O_RDONLY;
6899 }
6900 else if (!NIL_P(intmode = rb_check_to_integer(vmode, "to_int"))) {
6901 vmode = intmode;
6902 oflags = NUM2INT(intmode);
6903 fmode = rb_io_oflags_fmode(oflags);
6904 }
6905 else {
6906 const char *p;
6907
6908 StringValue(vmode);
6909 p = StringValueCStr(vmode);
6910 fmode = rb_io_modestr_fmode(p);
6911 oflags = rb_io_fmode_oflags(fmode);
6912 p = strchr(p, ':');
6913 if (p) {
6914 has_enc = 1;
6915 parse_mode_enc(p+1, rb_enc_get(vmode), &enc, &enc2, &fmode);
6916 }
6917 else {
6918 rb_encoding *e;
6919
6920 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
6921 rb_io_ext_int_to_encs(e, NULL, &enc, &enc2, fmode);
6922 }
6923 }
6924
6925 if (NIL_P(opthash)) {
6926 ecflags = (fmode & FMODE_READABLE) ?
6929#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
6930 ecflags |= (fmode & FMODE_WRITABLE) ?
6931 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
6932 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
6933#endif
6934 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
6935 ecopts = Qnil;
6936 if (fmode & FMODE_BINMODE) {
6937#ifdef O_BINARY
6938 oflags |= O_BINARY;
6939#endif
6940 if (!has_enc)
6941 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
6942 }
6943#if DEFAULT_TEXTMODE
6944 else if (NIL_P(vmode)) {
6945 fmode |= DEFAULT_TEXTMODE;
6946 }
6947#endif
6948 }
6949 else {
6950 VALUE v;
6951 if (!has_vmode) {
6952 v = rb_hash_aref(opthash, sym_mode);
6953 if (!NIL_P(v)) {
6954 if (!NIL_P(vmode)) {
6955 rb_raise(rb_eArgError, "mode specified twice");
6956 }
6957 has_vmode = 1;
6958 vmode = v;
6959 goto vmode_handle;
6960 }
6961 }
6962 v = rb_hash_aref(opthash, sym_flags);
6963 if (!NIL_P(v)) {
6964 v = rb_to_int(v);
6965 oflags |= NUM2INT(v);
6966 vmode = INT2NUM(oflags);
6967 fmode = rb_io_oflags_fmode(oflags);
6968 }
6969 extract_binmode(opthash, &fmode);
6970 if (fmode & FMODE_BINMODE) {
6971#ifdef O_BINARY
6972 oflags |= O_BINARY;
6973#endif
6974 if (!has_enc)
6975 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
6976 }
6977#if DEFAULT_TEXTMODE
6978 else if (NIL_P(vmode)) {
6979 fmode |= DEFAULT_TEXTMODE;
6980 }
6981#endif
6982 v = rb_hash_aref(opthash, sym_perm);
6983 if (!NIL_P(v)) {
6984 if (vperm_p) {
6985 if (!NIL_P(*vperm_p)) {
6986 rb_raise(rb_eArgError, "perm specified twice");
6987 }
6988 *vperm_p = v;
6989 }
6990 else {
6991 /* perm no use, just ignore */
6992 }
6993 }
6994 ecflags = (fmode & FMODE_READABLE) ?
6997#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
6998 ecflags |= (fmode & FMODE_WRITABLE) ?
6999 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7000 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7001#endif
7002
7003 if (rb_io_extract_encoding_option(opthash, &enc, &enc2, &fmode)) {
7004 if (has_enc) {
7005 rb_raise(rb_eArgError, "encoding specified twice");
7006 }
7007 }
7008 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
7009 ecflags = rb_econv_prepare_options(opthash, &ecopts, ecflags);
7010 }
7011
7012 validate_enc_binmode(&fmode, ecflags, enc, enc2);
7013
7014 *vmode_p = vmode;
7015
7016 *oflags_p = oflags;
7017 *fmode_p = fmode;
7018 convconfig_p->enc = enc;
7019 convconfig_p->enc2 = enc2;
7020 convconfig_p->ecflags = ecflags;
7021 convconfig_p->ecopts = ecopts;
7022}
7023
7025 VALUE fname;
7026 int oflags;
7027 mode_t perm;
7028};
7029
7030static void *
7031sysopen_func(void *ptr)
7032{
7033 const struct sysopen_struct *data = ptr;
7034 const char *fname = RSTRING_PTR(data->fname);
7035 return (void *)(VALUE)rb_cloexec_open(fname, data->oflags, data->perm);
7036}
7037
7038static inline int
7039rb_sysopen_internal(struct sysopen_struct *data)
7040{
7041 int fd;
7042 do {
7043 fd = IO_WITHOUT_GVL_INT(sysopen_func, data);
7044 } while (fd < 0 && errno == EINTR);
7045 if (0 <= fd)
7046 rb_update_max_fd(fd);
7047 return fd;
7048}
7049
7050static int
7051rb_sysopen(VALUE fname, int oflags, mode_t perm)
7052{
7053 int fd = -1;
7054 struct sysopen_struct data;
7055
7056 data.fname = rb_str_encode_ospath(fname);
7057 StringValueCStr(data.fname);
7058 data.oflags = oflags;
7059 data.perm = perm;
7060
7061 TRY_WITH_GC((fd = rb_sysopen_internal(&data)) >= 0) {
7062 rb_syserr_fail_path(first_errno, fname);
7063 }
7064 return fd;
7065}
7066
7067static inline FILE *
7068fdopen_internal(int fd, const char *modestr)
7069{
7070 FILE *file;
7071
7072#if defined(__sun)
7073 errno = 0;
7074#endif
7075 file = fdopen(fd, modestr);
7076 if (!file) {
7077#ifdef _WIN32
7078 if (errno == 0) errno = EINVAL;
7079#elif defined(__sun)
7080 if (errno == 0) errno = EMFILE;
7081#endif
7082 }
7083 return file;
7084}
7085
7086FILE *
7087rb_fdopen(int fd, const char *modestr)
7088{
7089 FILE *file = 0;
7090
7091 TRY_WITH_GC((file = fdopen_internal(fd, modestr)) != 0) {
7092 rb_syserr_fail(first_errno, 0);
7093 }
7094
7095 /* xxx: should be _IONBF? A buffer in FILE may have trouble. */
7096#ifdef USE_SETVBUF
7097 if (setvbuf(file, NULL, _IOFBF, 0) != 0)
7098 rb_warn("setvbuf() can't be honoured (fd=%d)", fd);
7099#endif
7100 return file;
7101}
7102
7103static int
7104io_check_tty(rb_io_t *fptr)
7105{
7106 int t = isatty(fptr->fd);
7107 if (t)
7108 fptr->mode |= FMODE_TTY|FMODE_DUPLEX;
7109 return t;
7110}
7111
7112static VALUE rb_io_internal_encoding(VALUE);
7113static void io_encoding_set(rb_io_t *, VALUE, VALUE, VALUE);
7114
7115static int
7116io_strip_bom(VALUE io)
7117{
7118 VALUE b1, b2, b3, b4;
7119 rb_io_t *fptr;
7120
7121 GetOpenFile(io, fptr);
7122 if (!(fptr->mode & FMODE_READABLE)) return 0;
7123 if (NIL_P(b1 = rb_io_getbyte(io))) return 0;
7124 switch (b1) {
7125 case INT2FIX(0xEF):
7126 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7127 if (b2 == INT2FIX(0xBB) && !NIL_P(b3 = rb_io_getbyte(io))) {
7128 if (b3 == INT2FIX(0xBF)) {
7129 return rb_utf8_encindex();
7130 }
7131 rb_io_ungetbyte(io, b3);
7132 }
7133 rb_io_ungetbyte(io, b2);
7134 break;
7135
7136 case INT2FIX(0xFE):
7137 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7138 if (b2 == INT2FIX(0xFF)) {
7139 return ENCINDEX_UTF_16BE;
7140 }
7141 rb_io_ungetbyte(io, b2);
7142 break;
7143
7144 case INT2FIX(0xFF):
7145 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7146 if (b2 == INT2FIX(0xFE)) {
7147 b3 = rb_io_getbyte(io);
7148 if (b3 == INT2FIX(0) && !NIL_P(b4 = rb_io_getbyte(io))) {
7149 if (b4 == INT2FIX(0)) {
7150 return ENCINDEX_UTF_32LE;
7151 }
7152 rb_io_ungetbyte(io, b4);
7153 }
7154 rb_io_ungetbyte(io, b3);
7155 return ENCINDEX_UTF_16LE;
7156 }
7157 rb_io_ungetbyte(io, b2);
7158 break;
7159
7160 case INT2FIX(0):
7161 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7162 if (b2 == INT2FIX(0) && !NIL_P(b3 = rb_io_getbyte(io))) {
7163 if (b3 == INT2FIX(0xFE) && !NIL_P(b4 = rb_io_getbyte(io))) {
7164 if (b4 == INT2FIX(0xFF)) {
7165 return ENCINDEX_UTF_32BE;
7166 }
7167 rb_io_ungetbyte(io, b4);
7168 }
7169 rb_io_ungetbyte(io, b3);
7170 }
7171 rb_io_ungetbyte(io, b2);
7172 break;
7173 }
7174 rb_io_ungetbyte(io, b1);
7175 return 0;
7176}
7177
7178static rb_encoding *
7179io_set_encoding_by_bom(VALUE io)
7180{
7181 int idx = io_strip_bom(io);
7182 rb_io_t *fptr;
7183 rb_encoding *extenc = NULL;
7184
7185 GetOpenFile(io, fptr);
7186 if (idx) {
7187 extenc = rb_enc_from_index(idx);
7188 io_encoding_set(fptr, rb_enc_from_encoding(extenc),
7189 rb_io_internal_encoding(io), Qnil);
7190 }
7191 else {
7192 fptr->encs.enc2 = NULL;
7193 }
7194 return extenc;
7195}
7196
7197static VALUE
7198rb_file_open_generic(VALUE io, VALUE filename, int oflags, enum rb_io_mode fmode,
7199 const struct rb_io_encoding *convconfig, mode_t perm)
7200{
7201 VALUE pathv;
7202 rb_io_t *fptr;
7203 struct rb_io_encoding cc;
7204 if (!convconfig) {
7205 /* Set to default encodings */
7206 rb_io_ext_int_to_encs(NULL, NULL, &cc.enc, &cc.enc2, fmode);
7207 cc.ecflags = 0;
7208 cc.ecopts = Qnil;
7209 convconfig = &cc;
7210 }
7211 validate_enc_binmode(&fmode, convconfig->ecflags,
7212 convconfig->enc, convconfig->enc2);
7213
7214 MakeOpenFile(io, fptr);
7215 fptr->mode = fmode;
7216 fptr->encs = *convconfig;
7217 pathv = rb_str_new_frozen(filename);
7218#ifdef O_TMPFILE
7219 if (!(oflags & O_TMPFILE)) {
7220 fptr->pathv = pathv;
7221 }
7222#else
7223 fptr->pathv = pathv;
7224#endif
7225 fptr->fd = rb_sysopen(pathv, oflags, perm);
7226 io_check_tty(fptr);
7227 if (fmode & FMODE_SETENC_BY_BOM) io_set_encoding_by_bom(io);
7228
7229 return io;
7230}
7231
7232static VALUE
7233rb_file_open_internal(VALUE io, VALUE filename, const char *modestr)
7234{
7235 enum rb_io_mode fmode = rb_io_modestr_fmode(modestr);
7236 const char *p = strchr(modestr, ':');
7237 struct rb_io_encoding convconfig;
7238
7239 if (p) {
7240 parse_mode_enc(p+1, rb_usascii_encoding(),
7241 &convconfig.enc, &convconfig.enc2, &fmode);
7242 }
7243 else {
7244 rb_encoding *e;
7245 /* Set to default encodings */
7246
7247 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
7248 rb_io_ext_int_to_encs(e, NULL, &convconfig.enc, &convconfig.enc2, fmode);
7249 }
7250
7251 convconfig.ecflags = (fmode & FMODE_READABLE) ?
7254#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7255 convconfig.ecflags |= (fmode & FMODE_WRITABLE) ?
7256 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7257 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7258#endif
7259 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.enc2, convconfig.ecflags);
7260 convconfig.ecopts = Qnil;
7261
7262 return rb_file_open_generic(io, filename,
7263 rb_io_fmode_oflags(fmode),
7264 fmode,
7265 &convconfig,
7266 0666);
7267}
7268
7269VALUE
7270rb_file_open_str(VALUE fname, const char *modestr)
7271{
7272 FilePathValue(fname);
7273 return rb_file_open_internal(io_alloc(rb_cFile), fname, modestr);
7274}
7275
7276VALUE
7277rb_file_open(const char *fname, const char *modestr)
7278{
7279 return rb_file_open_internal(io_alloc(rb_cFile), rb_str_new_cstr(fname), modestr);
7280}
7281
7282#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7283static struct pipe_list {
7284 rb_io_t *fptr;
7285 struct pipe_list *next;
7286} *pipe_list;
7287
7288static void
7289pipe_add_fptr(rb_io_t *fptr)
7290{
7291 struct pipe_list *list;
7292
7293 list = ALLOC(struct pipe_list);
7294 list->fptr = fptr;
7295 list->next = pipe_list;
7296 pipe_list = list;
7297}
7298
7299static void
7300pipe_del_fptr(rb_io_t *fptr)
7301{
7302 struct pipe_list **prev = &pipe_list;
7303 struct pipe_list *tmp;
7304
7305 while ((tmp = *prev) != 0) {
7306 if (tmp->fptr == fptr) {
7307 *prev = tmp->next;
7308 free(tmp);
7309 return;
7310 }
7311 prev = &tmp->next;
7312 }
7313}
7314
7315#if defined (_WIN32) || defined(__CYGWIN__)
7316static void
7317pipe_atexit(void)
7318{
7319 struct pipe_list *list = pipe_list;
7320 struct pipe_list *tmp;
7321
7322 while (list) {
7323 tmp = list->next;
7324 rb_io_fptr_finalize(list->fptr);
7325 list = tmp;
7326 }
7327}
7328#endif
7329
7330static void
7331pipe_finalize(rb_io_t *fptr, int noraise)
7332{
7333#if !defined(HAVE_WORKING_FORK) && !defined(_WIN32)
7334 int status = 0;
7335 if (fptr->stdio_file) {
7336 status = pclose(fptr->stdio_file);
7337 }
7338 fptr->fd = -1;
7339 fptr->stdio_file = 0;
7340 rb_last_status_set(status, fptr->pid);
7341#else
7342 fptr_finalize(fptr, noraise);
7343#endif
7344 pipe_del_fptr(fptr);
7345}
7346#endif
7347
7348static void
7349fptr_copy_finalizer(rb_io_t *fptr, const rb_io_t *orig)
7350{
7351#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7352 void (*const old_finalize)(struct rb_io*,int) = fptr->finalize;
7353
7354 if (old_finalize == orig->finalize) return;
7355#endif
7356
7357 fptr->finalize = orig->finalize;
7358
7359#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7360 if (old_finalize != pipe_finalize) {
7361 struct pipe_list *list;
7362 for (list = pipe_list; list; list = list->next) {
7363 if (list->fptr == fptr) break;
7364 }
7365 if (!list) pipe_add_fptr(fptr);
7366 }
7367 else {
7368 pipe_del_fptr(fptr);
7369 }
7370#endif
7371}
7372
7373void
7375{
7377 fptr->mode |= FMODE_SYNC;
7378}
7379
7380void
7381rb_io_unbuffered(rb_io_t *fptr)
7382{
7383 rb_io_synchronized(fptr);
7384}
7385
7386int
7387rb_pipe(int *pipes)
7388{
7389 int ret;
7390 TRY_WITH_GC((ret = rb_cloexec_pipe(pipes)) >= 0);
7391 if (ret == 0) {
7392 rb_update_max_fd(pipes[0]);
7393 rb_update_max_fd(pipes[1]);
7394 }
7395 return ret;
7396}
7397
7398#ifdef _WIN32
7399#define HAVE_SPAWNV 1
7400#define spawnv(mode, cmd, args) rb_w32_uaspawn((mode), (cmd), (args))
7401#define spawn(mode, cmd) rb_w32_uspawn((mode), (cmd), 0)
7402#endif
7403
7404#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7405struct popen_arg {
7406 VALUE execarg_obj;
7407 struct rb_execarg *eargp;
7408 int modef;
7409 int pair[2];
7410 int write_pair[2];
7411};
7412#endif
7413
7414#ifdef HAVE_WORKING_FORK
7415# ifndef __EMSCRIPTEN__
7416static void
7417popen_redirect(struct popen_arg *p)
7418{
7419 if ((p->modef & FMODE_READABLE) && (p->modef & FMODE_WRITABLE)) {
7420 close(p->write_pair[1]);
7421 if (p->write_pair[0] != 0) {
7422 dup2(p->write_pair[0], 0);
7423 close(p->write_pair[0]);
7424 }
7425 close(p->pair[0]);
7426 if (p->pair[1] != 1) {
7427 dup2(p->pair[1], 1);
7428 close(p->pair[1]);
7429 }
7430 }
7431 else if (p->modef & FMODE_READABLE) {
7432 close(p->pair[0]);
7433 if (p->pair[1] != 1) {
7434 dup2(p->pair[1], 1);
7435 close(p->pair[1]);
7436 }
7437 }
7438 else {
7439 close(p->pair[1]);
7440 if (p->pair[0] != 0) {
7441 dup2(p->pair[0], 0);
7442 close(p->pair[0]);
7443 }
7444 }
7445}
7446# endif
7447
7448#if defined(__linux__)
7449/* Linux /proc/self/status contains a line: "FDSize:\t<nnn>\n"
7450 * Since /proc may not be available, linux_get_maxfd is just a hint.
7451 * This function, linux_get_maxfd, must be async-signal-safe.
7452 * I.e. opendir() is not usable.
7453 *
7454 * Note that memchr() and memcmp is *not* async-signal-safe in POSIX.
7455 * However they are easy to re-implement in async-signal-safe manner.
7456 * (Also note that there is missing/memcmp.c.)
7457 */
7458static int
7459linux_get_maxfd(void)
7460{
7461 int fd;
7462 char buf[4096], *p, *np, *e;
7463 ssize_t ss;
7464 fd = rb_cloexec_open("/proc/self/status", O_RDONLY|O_NOCTTY, 0);
7465 if (fd < 0) return fd;
7466 ss = read(fd, buf, sizeof(buf));
7467 if (ss < 0) goto err;
7468 p = buf;
7469 e = buf + ss;
7470 while ((int)sizeof("FDSize:\t0\n")-1 <= e-p &&
7471 (np = memchr(p, '\n', e-p)) != NULL) {
7472 if (memcmp(p, "FDSize:", sizeof("FDSize:")-1) == 0) {
7473 int fdsize;
7474 p += sizeof("FDSize:")-1;
7475 *np = '\0';
7476 fdsize = (int)ruby_strtoul(p, (char **)NULL, 10);
7477 close(fd);
7478 return fdsize;
7479 }
7480 p = np+1;
7481 }
7482 /* fall through */
7483
7484 err:
7485 close(fd);
7486 return (int)ss;
7487}
7488#endif
7489
7490/* This function should be async-signal-safe. */
7491void
7492rb_close_before_exec(int lowfd, int maxhint, VALUE noclose_fds)
7493{
7494#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
7495 int fd, ret;
7496 int max = (int)max_file_descriptor;
7497# ifdef F_MAXFD
7498 /* F_MAXFD is available since NetBSD 2.0. */
7499 ret = fcntl(0, F_MAXFD); /* async-signal-safe */
7500 if (ret != -1)
7501 maxhint = max = ret;
7502# elif defined(__linux__)
7503 ret = linux_get_maxfd();
7504 if (maxhint < ret)
7505 maxhint = ret;
7506 /* maxhint = max = ret; if (ret == -1) abort(); // test */
7507# endif
7508 if (max < maxhint)
7509 max = maxhint;
7510 for (fd = lowfd; fd <= max; fd++) {
7511 if (!NIL_P(noclose_fds) &&
7512 RTEST(rb_hash_lookup(noclose_fds, INT2FIX(fd)))) /* async-signal-safe */
7513 continue;
7514 ret = fcntl(fd, F_GETFD); /* async-signal-safe */
7515 if (ret != -1 && !(ret & FD_CLOEXEC)) {
7516 fcntl(fd, F_SETFD, ret|FD_CLOEXEC); /* async-signal-safe */
7517 }
7518# define CONTIGUOUS_CLOSED_FDS 20
7519 if (ret != -1) {
7520 if (max < fd + CONTIGUOUS_CLOSED_FDS)
7521 max = fd + CONTIGUOUS_CLOSED_FDS;
7522 }
7523 }
7524#endif
7525}
7526
7527# ifndef __EMSCRIPTEN__
7528static int
7529popen_exec(void *pp, char *errmsg, size_t errmsg_len)
7530{
7531 struct popen_arg *p = (struct popen_arg*)pp;
7532
7533 return rb_exec_async_signal_safe(p->eargp, errmsg, errmsg_len);
7534}
7535# endif
7536#endif
7537
7538#if (defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)) && !defined __EMSCRIPTEN__
7539static VALUE
7540rb_execarg_fixup_v(VALUE execarg_obj)
7541{
7542 rb_execarg_parent_start(execarg_obj);
7543 return Qnil;
7544}
7545#else
7546char *rb_execarg_commandline(const struct rb_execarg *eargp, VALUE *prog);
7547#endif
7548
7549#ifndef __EMSCRIPTEN__
7550static VALUE
7551pipe_open(VALUE execarg_obj, const char *modestr, enum rb_io_mode fmode,
7552 const struct rb_io_encoding *convconfig)
7553{
7554 struct rb_execarg *eargp = NIL_P(execarg_obj) ? NULL : rb_execarg_get(execarg_obj);
7555 VALUE prog = eargp ? (eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name) : Qfalse ;
7556 rb_pid_t pid = 0;
7557 rb_io_t *fptr;
7558 VALUE port;
7559 rb_io_t *write_fptr;
7560 VALUE write_port;
7561#if defined(HAVE_WORKING_FORK)
7562 int status;
7563 char errmsg[80] = { '\0' };
7564#endif
7565#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7566 int state;
7567 struct popen_arg arg;
7568#endif
7569 int e = 0;
7570#if defined(HAVE_SPAWNV)
7571# if defined(HAVE_SPAWNVE)
7572# define DO_SPAWN(cmd, args, envp) ((args) ? \
7573 spawnve(P_NOWAIT, (cmd), (args), (envp)) : \
7574 spawne(P_NOWAIT, (cmd), (envp)))
7575# else
7576# define DO_SPAWN(cmd, args, envp) ((args) ? \
7577 spawnv(P_NOWAIT, (cmd), (args)) : \
7578 spawn(P_NOWAIT, (cmd)))
7579# endif
7580# if !defined(HAVE_WORKING_FORK)
7581 char **args = NULL;
7582# if defined(HAVE_SPAWNVE)
7583 char **envp = NULL;
7584# endif
7585# endif
7586#endif
7587#if !defined(HAVE_WORKING_FORK)
7588 struct rb_execarg sarg, *sargp = &sarg;
7589#endif
7590 FILE *fp = 0;
7591 int fd = -1;
7592 int write_fd = -1;
7593#if !defined(HAVE_WORKING_FORK)
7594 const char *cmd = 0;
7595
7596 if (prog)
7597 cmd = StringValueCStr(prog);
7598#endif
7599
7600#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7601 arg.execarg_obj = execarg_obj;
7602 arg.eargp = eargp;
7603 arg.modef = fmode;
7604 arg.pair[0] = arg.pair[1] = -1;
7605 arg.write_pair[0] = arg.write_pair[1] = -1;
7606# if !defined(HAVE_WORKING_FORK)
7607 if (eargp && !eargp->use_shell) {
7608 args = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
7609 }
7610# endif
7611 switch (fmode & (FMODE_READABLE|FMODE_WRITABLE)) {
7613 if (rb_pipe(arg.write_pair) < 0)
7614 rb_sys_fail_str(prog);
7615 if (rb_pipe(arg.pair) < 0) {
7616 e = errno;
7617 close(arg.write_pair[0]);
7618 close(arg.write_pair[1]);
7619 rb_syserr_fail_str(e, prog);
7620 }
7621 if (eargp) {
7622 rb_execarg_addopt(execarg_obj, INT2FIX(0), INT2FIX(arg.write_pair[0]));
7623 rb_execarg_addopt(execarg_obj, INT2FIX(1), INT2FIX(arg.pair[1]));
7624 }
7625 break;
7626 case FMODE_READABLE:
7627 if (rb_pipe(arg.pair) < 0)
7628 rb_sys_fail_str(prog);
7629 if (eargp)
7630 rb_execarg_addopt(execarg_obj, INT2FIX(1), INT2FIX(arg.pair[1]));
7631 break;
7632 case FMODE_WRITABLE:
7633 if (rb_pipe(arg.pair) < 0)
7634 rb_sys_fail_str(prog);
7635 if (eargp)
7636 rb_execarg_addopt(execarg_obj, INT2FIX(0), INT2FIX(arg.pair[0]));
7637 break;
7638 default:
7639 rb_sys_fail_str(prog);
7640 }
7641 if (!NIL_P(execarg_obj)) {
7642 rb_protect(rb_execarg_fixup_v, execarg_obj, &state);
7643 if (state) {
7644 if (0 <= arg.write_pair[0]) close(arg.write_pair[0]);
7645 if (0 <= arg.write_pair[1]) close(arg.write_pair[1]);
7646 if (0 <= arg.pair[0]) close(arg.pair[0]);
7647 if (0 <= arg.pair[1]) close(arg.pair[1]);
7648 rb_execarg_parent_end(execarg_obj);
7649 rb_jump_tag(state);
7650 }
7651
7652# if defined(HAVE_WORKING_FORK)
7653 pid = rb_fork_async_signal_safe(&status, popen_exec, &arg, arg.eargp->redirect_fds, errmsg, sizeof(errmsg));
7654# else
7655 rb_execarg_run_options(eargp, sargp, NULL, 0);
7656# if defined(HAVE_SPAWNVE)
7657 if (eargp->envp_str) envp = (char **)RSTRING_PTR(eargp->envp_str);
7658# endif
7659 while ((pid = DO_SPAWN(cmd, args, envp)) < 0) {
7660 /* exec failed */
7661 switch (e = errno) {
7662 case EAGAIN:
7663# if EWOULDBLOCK != EAGAIN
7664 case EWOULDBLOCK:
7665# endif
7666 rb_thread_sleep(1);
7667 continue;
7668 }
7669 break;
7670 }
7671 if (eargp)
7672 rb_execarg_run_options(sargp, NULL, NULL, 0);
7673# endif
7674 rb_execarg_parent_end(execarg_obj);
7675 }
7676 else {
7677# if defined(HAVE_WORKING_FORK)
7678 pid = rb_call_proc__fork();
7679 if (pid == 0) { /* child */
7680 popen_redirect(&arg);
7681 rb_io_synchronized(RFILE(orig_stdout)->fptr);
7682 rb_io_synchronized(RFILE(orig_stderr)->fptr);
7683 return Qnil;
7684 }
7685# else
7687# endif
7688 }
7689
7690 /* parent */
7691 if (pid < 0) {
7692# if defined(HAVE_WORKING_FORK)
7693 e = errno;
7694# endif
7695 close(arg.pair[0]);
7696 close(arg.pair[1]);
7698 close(arg.write_pair[0]);
7699 close(arg.write_pair[1]);
7700 }
7701# if defined(HAVE_WORKING_FORK)
7702 if (errmsg[0])
7703 rb_syserr_fail(e, errmsg);
7704# endif
7705 rb_syserr_fail_str(e, prog);
7706 }
7707 if ((fmode & FMODE_READABLE) && (fmode & FMODE_WRITABLE)) {
7708 close(arg.pair[1]);
7709 fd = arg.pair[0];
7710 close(arg.write_pair[0]);
7711 write_fd = arg.write_pair[1];
7712 }
7713 else if (fmode & FMODE_READABLE) {
7714 close(arg.pair[1]);
7715 fd = arg.pair[0];
7716 }
7717 else {
7718 close(arg.pair[0]);
7719 fd = arg.pair[1];
7720 }
7721#else
7722 cmd = rb_execarg_commandline(eargp, &prog);
7723 if (!NIL_P(execarg_obj)) {
7724 rb_execarg_parent_start(execarg_obj);
7725 rb_execarg_run_options(eargp, sargp, NULL, 0);
7726 }
7727 fp = popen(cmd, modestr);
7728 e = errno;
7729 if (eargp) {
7730 rb_execarg_parent_end(execarg_obj);
7731 rb_execarg_run_options(sargp, NULL, NULL, 0);
7732 }
7733 if (!fp) rb_syserr_fail_path(e, prog);
7734 fd = fileno(fp);
7735#endif
7736
7737 port = io_alloc(rb_cIO);
7738 MakeOpenFile(port, fptr);
7739 fptr->fd = fd;
7740 fptr->stdio_file = fp;
7741 fptr->mode = fmode | FMODE_SYNC|FMODE_DUPLEX;
7742 if (convconfig) {
7743 fptr->encs = *convconfig;
7744#if RUBY_CRLF_ENVIRONMENT
7747 }
7748#endif
7749 }
7750 else {
7751 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
7753 }
7754#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7755 if (NEED_NEWLINE_DECORATOR_ON_WRITE(fptr)) {
7756 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
7757 }
7758#endif
7759 }
7760 fptr->pid = pid;
7761
7762 if (0 <= write_fd) {
7763 write_port = io_alloc(rb_cIO);
7764 MakeOpenFile(write_port, write_fptr);
7765 write_fptr->fd = write_fd;
7766 write_fptr->mode = (fmode & ~FMODE_READABLE)| FMODE_SYNC|FMODE_DUPLEX;
7767 fptr->mode &= ~FMODE_WRITABLE;
7768 fptr->tied_io_for_writing = write_port;
7769 rb_ivar_set(port, rb_intern("@tied_io_for_writing"), write_port);
7770 }
7771
7772#if defined (__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7773 fptr->finalize = pipe_finalize;
7774 pipe_add_fptr(fptr);
7775#endif
7776 return port;
7777}
7778#else
7779static VALUE
7780pipe_open(VALUE execarg_obj, const char *modestr, enum rb_io_mode fmode,
7781 const struct rb_io_encoding *convconfig)
7782{
7783 rb_raise(rb_eNotImpError, "popen() is not available");
7784}
7785#endif
7786
7787static int
7788is_popen_fork(VALUE prog)
7789{
7790 if (RSTRING_LEN(prog) == 1 && RSTRING_PTR(prog)[0] == '-') {
7791#if !defined(HAVE_WORKING_FORK)
7792 rb_raise(rb_eNotImpError,
7793 "fork() function is unimplemented on this machine");
7794#else
7795 return TRUE;
7796#endif
7797 }
7798 return FALSE;
7799}
7800
7801static VALUE
7802pipe_open_s(VALUE prog, const char *modestr, enum rb_io_mode fmode,
7803 const struct rb_io_encoding *convconfig)
7804{
7805 int argc = 1;
7806 VALUE *argv = &prog;
7807 VALUE execarg_obj = Qnil;
7808
7809 if (!is_popen_fork(prog))
7810 execarg_obj = rb_execarg_new(argc, argv, TRUE, FALSE);
7811 return pipe_open(execarg_obj, modestr, fmode, convconfig);
7812}
7813
7814static VALUE
7815pipe_close(VALUE io)
7816{
7817 rb_io_t *fptr = io_close_fptr(io);
7818 if (fptr) {
7819 fptr_waitpid(fptr, rb_thread_to_be_killed(rb_thread_current()));
7820 }
7821 return Qnil;
7822}
7823
7824static VALUE popen_finish(VALUE port, VALUE klass);
7825
7826/*
7827 * call-seq:
7828 * IO.popen(env = {}, cmd, mode = 'r', **opts) -> io
7829 * IO.popen(env = {}, cmd, mode = 'r', **opts) {|io| ... } -> object
7830 *
7831 * Executes the given command +cmd+ as a subprocess
7832 * whose $stdin and $stdout are connected to a new stream +io+.
7833 *
7834 * This method has potential security vulnerabilities if called with untrusted input;
7835 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
7836 *
7837 * If no block is given, returns the new stream,
7838 * which depending on given +mode+ may be open for reading, writing, or both.
7839 * The stream should be explicitly closed (eventually) to avoid resource leaks.
7840 *
7841 * If a block is given, the stream is passed to the block
7842 * (again, open for reading, writing, or both);
7843 * when the block exits, the stream is closed,
7844 * the block's value is returned,
7845 * and the global variable <tt>$?</tt> is set to the child's exit status.
7846 *
7847 * Optional argument +mode+ may be any valid \IO mode.
7848 * See {Access Modes}[rdoc-ref:File@Access+Modes].
7849 *
7850 * Required argument +cmd+ determines which of the following occurs:
7851 *
7852 * - The process forks.
7853 * - A specified program runs in a shell.
7854 * - A specified program runs with specified arguments.
7855 * - A specified program runs with specified arguments and a specified +argv0+.
7856 *
7857 * Each of these is detailed below.
7858 *
7859 * The optional hash argument +env+ specifies name/value pairs that are to be added
7860 * to the environment variables for the subprocess:
7861 *
7862 * IO.popen({'FOO' => 'bar'}, 'ruby', 'r+') do |pipe|
7863 * pipe.puts 'puts ENV["FOO"]'
7864 * pipe.close_write
7865 * pipe.gets
7866 * end => "bar\n"
7867 *
7868 * Optional keyword arguments +opts+ specify:
7869 *
7870 * - {Open options}[rdoc-ref:IO@Open+Options].
7871 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
7872 * - Options for Kernel#spawn.
7873 *
7874 * <b>Forked Process</b>
7875 *
7876 * When argument +cmd+ is the 1-character string <tt>'-'</tt>, causes the process to fork:
7877 * IO.popen('-') do |pipe|
7878 * if pipe
7879 * $stderr.puts "In parent, child pid is #{pipe.pid}\n"
7880 * else
7881 * $stderr.puts "In child, pid is #{$$}\n"
7882 * end
7883 * end
7884 *
7885 * Output:
7886 *
7887 * In parent, child pid is 26253
7888 * In child, pid is 26253
7889 *
7890 * Note that this is not supported on all platforms.
7891 *
7892 * <b>Shell Subprocess</b>
7893 *
7894 * When argument +cmd+ is a single string (but not <tt>'-'</tt>),
7895 * the program named +cmd+ is run as a shell command:
7896 *
7897 * IO.popen('uname') do |pipe|
7898 * pipe.readlines
7899 * end
7900 *
7901 * Output:
7902 *
7903 * ["Linux\n"]
7904 *
7905 * Another example:
7906 *
7907 * IO.popen('/bin/sh', 'r+') do |pipe|
7908 * pipe.puts('ls')
7909 * pipe.close_write
7910 * $stderr.puts pipe.readlines.size
7911 * end
7912 *
7913 * Output:
7914 *
7915 * 213
7916 *
7917 * <b>Program Subprocess</b>
7918 *
7919 * When argument +cmd+ is an array of strings,
7920 * the program named <tt>cmd[0]</tt> is run with all elements of +cmd+ as its arguments:
7921 *
7922 * IO.popen(['du', '..', '.']) do |pipe|
7923 * $stderr.puts pipe.readlines.size
7924 * end
7925 *
7926 * Output:
7927 *
7928 * 1111
7929 *
7930 * <b>Program Subprocess with <tt>argv0</tt></b>
7931 *
7932 * When argument +cmd+ is an array whose first element is a 2-element string array
7933 * and whose remaining elements (if any) are strings:
7934 *
7935 * - <tt>cmd[0][0]</tt> (the first string in the nested array) is the name of a program that is run.
7936 * - <tt>cmd[0][1]</tt> (the second string in the nested array) is set as the program's <tt>argv[0]</tt>.
7937 * - <tt>cmd[1..-1]</tt> (the strings in the outer array) are the program's arguments.
7938 *
7939 * Example (sets <tt>$0</tt> to 'foo'):
7940 *
7941 * IO.popen([['/bin/sh', 'foo'], '-c', 'echo $0']).read # => "foo\n"
7942 *
7943 * <b>Some Special Examples</b>
7944 *
7945 * # Set IO encoding.
7946 * IO.popen("nkf -e filename", :external_encoding=>"EUC-JP") {|nkf_io|
7947 * euc_jp_string = nkf_io.read
7948 * }
7949 *
7950 * # Merge standard output and standard error using Kernel#spawn option. See Kernel#spawn.
7951 * IO.popen(["ls", "/", :err=>[:child, :out]]) do |io|
7952 * ls_result_with_error = io.read
7953 * end
7954 *
7955 * # Use mixture of spawn options and IO options.
7956 * IO.popen(["ls", "/"], :err=>[:child, :out]) do |io|
7957 * ls_result_with_error = io.read
7958 * end
7959 *
7960 * f = IO.popen("uname")
7961 * p f.readlines
7962 * f.close
7963 * puts "Parent is #{Process.pid}"
7964 * IO.popen("date") {|f| puts f.gets }
7965 * IO.popen("-") {|f| $stderr.puts "#{Process.pid} is here, f is #{f.inspect}"}
7966 * p $?
7967 * IO.popen(%w"sed -e s|^|<foo>| -e s&$&;zot;&", "r+") {|f|
7968 * f.puts "bar"; f.close_write; puts f.gets
7969 * }
7970 *
7971 * Output (from last section):
7972 *
7973 * ["Linux\n"]
7974 * Parent is 21346
7975 * Thu Jan 15 22:41:19 JST 2009
7976 * 21346 is here, f is #<IO:fd 3>
7977 * 21352 is here, f is nil
7978 * #<Process::Status: pid 21352 exit 0>
7979 * <foo>bar;zot;
7980 *
7981 * Raises exceptions that IO.pipe and Kernel.spawn raise.
7982 *
7983 */
7984
7985static VALUE
7986rb_io_s_popen(int argc, VALUE *argv, VALUE klass)
7987{
7988 VALUE pname, pmode = Qnil, opt = Qnil, env = Qnil;
7989
7990 if (argc > 1 && !NIL_P(opt = rb_check_hash_type(argv[argc-1]))) --argc;
7991 if (argc > 1 && !NIL_P(env = rb_check_hash_type(argv[0]))) --argc, ++argv;
7992 switch (argc) {
7993 case 2:
7994 pmode = argv[1];
7995 case 1:
7996 pname = argv[0];
7997 break;
7998 default:
7999 {
8000 int ex = !NIL_P(opt);
8001 rb_error_arity(argc + ex, 1 + ex, 2 + ex);
8002 }
8003 }
8004 return popen_finish(rb_io_popen(pname, pmode, env, opt), klass);
8005}
8006
8007VALUE
8008rb_io_popen(VALUE pname, VALUE pmode, VALUE env, VALUE opt)
8009{
8010 const char *modestr;
8011 VALUE tmp, execarg_obj = Qnil;
8012 int oflags;
8013 enum rb_io_mode fmode;
8014 struct rb_io_encoding convconfig;
8015
8016 tmp = rb_check_array_type(pname);
8017 if (!NIL_P(tmp)) {
8018 long len = RARRAY_LEN(tmp);
8019#if SIZEOF_LONG > SIZEOF_INT
8020 if (len > INT_MAX) {
8021 rb_raise(rb_eArgError, "too many arguments");
8022 }
8023#endif
8024 execarg_obj = rb_execarg_new((int)len, RARRAY_CONST_PTR(tmp), FALSE, FALSE);
8025 RB_GC_GUARD(tmp);
8026 }
8027 else {
8028 StringValue(pname);
8029 execarg_obj = Qnil;
8030 if (!is_popen_fork(pname))
8031 execarg_obj = rb_execarg_new(1, &pname, TRUE, FALSE);
8032 }
8033 if (!NIL_P(execarg_obj)) {
8034 if (!NIL_P(opt))
8035 opt = rb_execarg_extract_options(execarg_obj, opt);
8036 if (!NIL_P(env))
8037 rb_execarg_setenv(execarg_obj, env);
8038 }
8039 rb_io_extract_modeenc(&pmode, 0, opt, &oflags, &fmode, &convconfig);
8040 modestr = rb_io_oflags_modestr(oflags);
8041
8042 return pipe_open(execarg_obj, modestr, fmode, &convconfig);
8043}
8044
8045static VALUE
8046popen_finish(VALUE port, VALUE klass)
8047{
8048 if (NIL_P(port)) {
8049 /* child */
8050 if (rb_block_given_p()) {
8051 rb_protect(rb_yield, Qnil, NULL);
8052 rb_io_flush(rb_ractor_stdout());
8053 rb_io_flush(rb_ractor_stderr());
8054 _exit(0);
8055 }
8056 return Qnil;
8057 }
8058 RBASIC_SET_CLASS(port, klass);
8059 if (rb_block_given_p()) {
8060 return rb_ensure(rb_yield, port, pipe_close, port);
8061 }
8062 return port;
8063}
8064
8065#if defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)
8066struct popen_writer_arg {
8067 char *const *argv;
8068 struct popen_arg popen;
8069};
8070
8071static int
8072exec_popen_writer(void *arg, char *errmsg, size_t buflen)
8073{
8074 struct popen_writer_arg *pw = arg;
8075 pw->popen.modef = FMODE_WRITABLE;
8076 popen_redirect(&pw->popen);
8077 execv(pw->argv[0], pw->argv);
8078 strlcpy(errmsg, strerror(errno), buflen);
8079 return -1;
8080}
8081#endif
8082
8083FILE *
8084ruby_popen_writer(char *const *argv, rb_pid_t *pid)
8085{
8086#if (defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)) || defined(_WIN32)
8087# ifdef HAVE_WORKING_FORK
8088 struct popen_writer_arg pw;
8089 int *const write_pair = pw.popen.pair;
8090# else
8091 int write_pair[2];
8092# endif
8093
8094 int result = rb_cloexec_pipe(write_pair);
8095 *pid = -1;
8096 if (result == 0) {
8097# ifdef HAVE_WORKING_FORK
8098 pw.argv = argv;
8099 int status;
8100 char errmsg[80] = {'\0'};
8101 *pid = rb_fork_async_signal_safe(&status, exec_popen_writer, &pw, Qnil, errmsg, sizeof(errmsg));
8102# else
8103 *pid = rb_w32_uspawn_process(P_NOWAIT, argv[0], argv, write_pair[0], -1, -1, 0);
8104 const char *errmsg = (*pid < 0) ? strerror(errno) : NULL;
8105# endif
8106 close(write_pair[0]);
8107 if (*pid < 0) {
8108 close(write_pair[1]);
8109 fprintf(stderr, "ruby_popen_writer(%s): %s\n", argv[0], errmsg);
8110 }
8111 else {
8112 return fdopen(write_pair[1], "w");
8113 }
8114 }
8115#endif
8116 return NULL;
8117}
8118
8119static VALUE
8120rb_open_file(VALUE io, VALUE fname, VALUE vmode, VALUE vperm, VALUE opt)
8121{
8122 int oflags;
8123 enum rb_io_mode fmode;
8124 struct rb_io_encoding convconfig;
8125 mode_t perm;
8126
8127 FilePathValue(fname);
8128
8129 rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, &convconfig);
8130 perm = NIL_P(vperm) ? 0666 : NUM2MODET(vperm);
8131
8132 rb_file_open_generic(io, fname, oflags, fmode, &convconfig, perm);
8133
8134 return io;
8135}
8136
8137/*
8138 * Document-method: File::open
8139 *
8140 * call-seq:
8141 * File.open(path, mode = 'r', perm = 0666, **opts) -> file
8142 * File.open(path, mode = 'r', perm = 0666, **opts) {|f| ... } -> object
8143 *
8144 * Creates a new File object, via File.new with the given arguments.
8145 *
8146 * With no block given, returns the File object.
8147 *
8148 * With a block given, calls the block with the File object
8149 * and returns the block's value.
8150 *
8151 */
8152
8153/*
8154 * Document-method: IO::open
8155 *
8156 * call-seq:
8157 * IO.open(fd, mode = 'r', **opts) -> io
8158 * IO.open(fd, mode = 'r', **opts) {|io| ... } -> object
8159 *
8160 * Creates a new \IO object, via IO.new with the given arguments.
8161 *
8162 * With no block given, returns the \IO object.
8163 *
8164 * With a block given, calls the block with the \IO object
8165 * and returns the block's value.
8166 *
8167 */
8168
8169static VALUE
8170rb_io_s_open(int argc, VALUE *argv, VALUE klass)
8171{
8173
8174 if (rb_block_given_p()) {
8175 return rb_ensure(rb_yield, io, io_close, io);
8176 }
8177
8178 return io;
8179}
8180
8181/*
8182 * call-seq:
8183 * IO.sysopen(path, mode = 'r', perm = 0666) -> integer
8184 *
8185 * Opens the file at the given path with the given mode and permissions;
8186 * returns the integer file descriptor.
8187 *
8188 * If the file is to be readable, it must exist;
8189 * if the file is to be writable and does not exist,
8190 * it is created with the given permissions:
8191 *
8192 * File.write('t.tmp', '') # => 0
8193 * IO.sysopen('t.tmp') # => 8
8194 * IO.sysopen('t.tmp', 'w') # => 9
8195 *
8196 *
8197 */
8198
8199static VALUE
8200rb_io_s_sysopen(int argc, VALUE *argv, VALUE _)
8201{
8202 VALUE fname, vmode, vperm;
8203 VALUE intmode;
8204 int oflags, fd;
8205 mode_t perm;
8206
8207 rb_scan_args(argc, argv, "12", &fname, &vmode, &vperm);
8208 FilePathValue(fname);
8209
8210 if (NIL_P(vmode))
8211 oflags = O_RDONLY;
8212 else if (!NIL_P(intmode = rb_check_to_integer(vmode, "to_int")))
8213 oflags = NUM2INT(intmode);
8214 else {
8215 StringValue(vmode);
8216 oflags = rb_io_modestr_oflags(StringValueCStr(vmode));
8217 }
8218 if (NIL_P(vperm)) perm = 0666;
8219 else perm = NUM2MODET(vperm);
8220
8221 RB_GC_GUARD(fname) = rb_str_new4(fname);
8222 fd = rb_sysopen(fname, oflags, perm);
8223 return INT2NUM(fd);
8224}
8225
8226static VALUE
8227check_pipe_command(VALUE filename_or_command)
8228{
8229 char *s = RSTRING_PTR(filename_or_command);
8230 long l = RSTRING_LEN(filename_or_command);
8231 char *e = s + l;
8232 int chlen;
8233
8234 if (rb_enc_ascget(s, e, &chlen, rb_enc_get(filename_or_command)) == '|') {
8235 VALUE cmd = rb_str_new(s+chlen, l-chlen);
8236 return cmd;
8237 }
8238 return Qnil;
8239}
8240
8241/*
8242 * call-seq:
8243 * open(path, mode = 'r', perm = 0666, **opts) -> io or nil
8244 * open(path, mode = 'r', perm = 0666, **opts) {|io| ... } -> obj
8245 *
8246 * Creates an IO object connected to the given file.
8247 *
8248 * This method has potential security vulnerabilities if called with untrusted input;
8249 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
8250 *
8251 * With no block given, file stream is returned:
8252 *
8253 * open('t.txt') # => #<File:t.txt>
8254 *
8255 * With a block given, calls the block with the open file stream,
8256 * then closes the stream:
8257 *
8258 * open('t.txt') {|f| p f } # => #<File:t.txt (closed)>
8259 *
8260 * Output:
8261 *
8262 * #<File:t.txt>
8263 *
8264 * See File.open for details.
8265 *
8266 */
8267
8268static VALUE
8269rb_f_open(int argc, VALUE *argv, VALUE _)
8270{
8271 ID to_open = 0;
8272 int redirect = FALSE;
8273
8274 if (argc >= 1) {
8275 CONST_ID(to_open, "to_open");
8276 if (rb_respond_to(argv[0], to_open)) {
8277 redirect = TRUE;
8278 }
8279 else {
8280 VALUE tmp = argv[0];
8281 FilePathValue(tmp);
8282 if (NIL_P(tmp)) {
8283 redirect = TRUE;
8284 }
8285 else {
8286 VALUE cmd = check_pipe_command(tmp);
8287 if (!NIL_P(cmd)) {
8288 // TODO: when removed in 4.0, update command_injection.rdoc
8289 rb_warn_deprecated_to_remove_at(4.0, "Calling Kernel#open with a leading '|'", "IO.popen");
8290 argv[0] = cmd;
8291 return rb_io_s_popen(argc, argv, rb_cIO);
8292 }
8293 }
8294 }
8295 }
8296 if (redirect) {
8297 VALUE io = rb_funcallv_kw(argv[0], to_open, argc-1, argv+1, RB_PASS_CALLED_KEYWORDS);
8298
8299 if (rb_block_given_p()) {
8300 return rb_ensure(rb_yield, io, io_close, io);
8301 }
8302 return io;
8303 }
8304 return rb_io_s_open(argc, argv, rb_cFile);
8305}
8306
8307static VALUE
8308rb_io_open_generic(VALUE klass, VALUE filename, int oflags, enum rb_io_mode fmode,
8309 const struct rb_io_encoding *convconfig, mode_t perm)
8310{
8311 VALUE cmd;
8312 if (klass == rb_cIO && !NIL_P(cmd = check_pipe_command(filename))) {
8313 // TODO: when removed in 4.0, update command_injection.rdoc
8314 rb_warn_deprecated_to_remove_at(4.0, "IO process creation with a leading '|'", "IO.popen");
8315 return pipe_open_s(cmd, rb_io_oflags_modestr(oflags), fmode, convconfig);
8316 }
8317 else {
8318 return rb_file_open_generic(io_alloc(klass), filename,
8319 oflags, fmode, convconfig, perm);
8320 }
8321}
8322
8323static VALUE
8324rb_io_open(VALUE io, VALUE filename, VALUE vmode, VALUE vperm, VALUE opt)
8325{
8326 int oflags;
8327 enum rb_io_mode fmode;
8328 struct rb_io_encoding convconfig;
8329 mode_t perm;
8330
8331 rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, &convconfig);
8332 perm = NIL_P(vperm) ? 0666 : NUM2MODET(vperm);
8333 return rb_io_open_generic(io, filename, oflags, fmode, &convconfig, perm);
8334}
8335
8336static VALUE
8337io_reopen(VALUE io, VALUE nfile)
8338{
8339 rb_io_t *fptr, *orig;
8340 int fd, fd2;
8341 rb_off_t pos = 0;
8342
8343 nfile = rb_io_get_io(nfile);
8344 GetOpenFile(io, fptr);
8345 GetOpenFile(nfile, orig);
8346
8347 if (fptr == orig) return io;
8348 if (RUBY_IO_EXTERNAL_P(fptr)) {
8349 if ((fptr->stdio_file == stdin && !(orig->mode & FMODE_READABLE)) ||
8350 (fptr->stdio_file == stdout && !(orig->mode & FMODE_WRITABLE)) ||
8351 (fptr->stdio_file == stderr && !(orig->mode & FMODE_WRITABLE))) {
8352 rb_raise(rb_eArgError,
8353 "%s can't change access mode from \"%s\" to \"%s\"",
8354 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->mode),
8355 rb_io_fmode_modestr(orig->mode));
8356 }
8357 }
8358 if (fptr->mode & FMODE_WRITABLE) {
8359 if (io_fflush(fptr) < 0)
8360 rb_sys_fail_on_write(fptr);
8361 }
8362 else {
8363 flush_before_seek(fptr, true);
8364 }
8365 if (orig->mode & FMODE_READABLE) {
8366 pos = io_tell(orig);
8367 }
8368 if (orig->mode & FMODE_WRITABLE) {
8369 if (io_fflush(orig) < 0)
8370 rb_sys_fail_on_write(fptr);
8371 }
8372
8373 /* copy rb_io_t structure */
8374 fptr->mode = orig->mode | (fptr->mode & FMODE_EXTERNAL);
8375 fptr->encs = orig->encs;
8376 fptr->pid = orig->pid;
8377 fptr->lineno = orig->lineno;
8378 if (RTEST(orig->pathv)) fptr->pathv = orig->pathv;
8379 else if (!RUBY_IO_EXTERNAL_P(fptr)) fptr->pathv = Qnil;
8380 fptr_copy_finalizer(fptr, orig);
8381
8382 fd = fptr->fd;
8383 fd2 = orig->fd;
8384 if (fd != fd2) {
8385 // Interrupt all usage of the old file descriptor:
8386 rb_thread_io_close_interrupt(fptr);
8387 rb_thread_io_close_wait(fptr);
8388
8389 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2 || !fptr->stdio_file) {
8390 /* need to keep FILE objects of stdin, stdout and stderr */
8391 if (rb_cloexec_dup2(fd2, fd) < 0)
8392 rb_sys_fail_path(orig->pathv);
8393 rb_update_max_fd(fd);
8394 }
8395 else {
8396 fclose(fptr->stdio_file);
8397 fptr->stdio_file = 0;
8398 fptr->fd = -1;
8399 if (rb_cloexec_dup2(fd2, fd) < 0)
8400 rb_sys_fail_path(orig->pathv);
8401 rb_update_max_fd(fd);
8402 fptr->fd = fd;
8403 }
8404
8405 if ((orig->mode & FMODE_READABLE) && pos >= 0) {
8406 if (io_seek(fptr, pos, SEEK_SET) < 0 && errno) {
8407 rb_sys_fail_path(fptr->pathv);
8408 }
8409 if (io_seek(orig, pos, SEEK_SET) < 0 && errno) {
8410 rb_sys_fail_path(orig->pathv);
8411 }
8412 }
8413 }
8414
8415 if (fptr->mode & FMODE_BINMODE) {
8416 rb_io_binmode(io);
8417 }
8418
8419 RBASIC_SET_CLASS(io, rb_obj_class(nfile));
8420 return io;
8421}
8422
8423#ifdef _WIN32
8424int rb_freopen(VALUE fname, const char *mode, FILE *fp);
8425#else
8426static int
8427rb_freopen(VALUE fname, const char *mode, FILE *fp)
8428{
8429 if (!freopen(RSTRING_PTR(fname), mode, fp)) {
8430 RB_GC_GUARD(fname);
8431 return errno;
8432 }
8433 return 0;
8434}
8435#endif
8436
8437/*
8438 * call-seq:
8439 * reopen(other_io) -> self
8440 * reopen(path, mode = 'r', **opts) -> self
8441 *
8442 * Reassociates the stream with another stream,
8443 * which may be of a different class.
8444 * This method may be used to redirect an existing stream
8445 * to a new destination.
8446 *
8447 * With argument +other_io+ given, reassociates with that stream:
8448 *
8449 * # Redirect $stdin from a file.
8450 * f = File.open('t.txt')
8451 * $stdin.reopen(f)
8452 * f.close
8453 *
8454 * # Redirect $stdout to a file.
8455 * f = File.open('t.tmp', 'w')
8456 * $stdout.reopen(f)
8457 * f.close
8458 *
8459 * With argument +path+ given, reassociates with a new stream to that file path:
8460 *
8461 * $stdin.reopen('t.txt')
8462 * $stdout.reopen('t.tmp', 'w')
8463 *
8464 * Optional keyword arguments +opts+ specify:
8465 *
8466 * - {Open Options}[rdoc-ref:IO@Open+Options].
8467 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
8468 *
8469 */
8470
8471static VALUE
8472rb_io_reopen(int argc, VALUE *argv, VALUE file)
8473{
8474 VALUE fname, nmode, opt;
8475 int oflags;
8476 rb_io_t *fptr;
8477
8478 if (rb_scan_args(argc, argv, "11:", &fname, &nmode, &opt) == 1) {
8479 VALUE tmp = rb_io_check_io(fname);
8480 if (!NIL_P(tmp)) {
8481 return io_reopen(file, tmp);
8482 }
8483 }
8484
8485 FilePathValue(fname);
8486 rb_io_taint_check(file);
8487 fptr = RFILE(file)->fptr;
8488 if (!fptr) {
8489 fptr = RFILE(file)->fptr = ZALLOC(rb_io_t);
8490 }
8491
8492 if (!NIL_P(nmode) || !NIL_P(opt)) {
8493 enum rb_io_mode fmode;
8494 struct rb_io_encoding convconfig;
8495
8496 rb_io_extract_modeenc(&nmode, 0, opt, &oflags, &fmode, &convconfig);
8497 if (RUBY_IO_EXTERNAL_P(fptr) &&
8498 ((fptr->mode & FMODE_READWRITE) & (fmode & FMODE_READWRITE)) !=
8499 (fptr->mode & FMODE_READWRITE)) {
8500 rb_raise(rb_eArgError,
8501 "%s can't change access mode from \"%s\" to \"%s\"",
8502 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->mode),
8503 rb_io_fmode_modestr(fmode));
8504 }
8505 fptr->mode = fmode;
8506 fptr->encs = convconfig;
8507 }
8508 else {
8509 oflags = rb_io_fmode_oflags(fptr->mode);
8510 }
8511
8512 fptr->pathv = fname;
8513 if (fptr->fd < 0) {
8514 fptr->fd = rb_sysopen(fptr->pathv, oflags, 0666);
8515 fptr->stdio_file = 0;
8516 return file;
8517 }
8518
8519 if (fptr->mode & FMODE_WRITABLE) {
8520 if (io_fflush(fptr) < 0)
8521 rb_sys_fail_on_write(fptr);
8522 }
8523 fptr->rbuf.off = fptr->rbuf.len = 0;
8524
8525 if (fptr->stdio_file) {
8526 int e = rb_freopen(rb_str_encode_ospath(fptr->pathv),
8527 rb_io_oflags_modestr(oflags),
8528 fptr->stdio_file);
8529 if (e) rb_syserr_fail_path(e, fptr->pathv);
8530 fptr->fd = fileno(fptr->stdio_file);
8531 rb_fd_fix_cloexec(fptr->fd);
8532#ifdef USE_SETVBUF
8533 if (setvbuf(fptr->stdio_file, NULL, _IOFBF, 0) != 0)
8534 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8535#endif
8536 if (fptr->stdio_file == stderr) {
8537 if (setvbuf(fptr->stdio_file, NULL, _IONBF, BUFSIZ) != 0)
8538 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8539 }
8540 else if (fptr->stdio_file == stdout && isatty(fptr->fd)) {
8541 if (setvbuf(fptr->stdio_file, NULL, _IOLBF, BUFSIZ) != 0)
8542 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8543 }
8544 }
8545 else {
8546 int tmpfd = rb_sysopen(fptr->pathv, oflags, 0666);
8547 int err = 0;
8548 if (rb_cloexec_dup2(tmpfd, fptr->fd) < 0)
8549 err = errno;
8550 (void)close(tmpfd);
8551 if (err) {
8552 rb_syserr_fail_path(err, fptr->pathv);
8553 }
8554 }
8555
8556 return file;
8557}
8558
8559/* :nodoc: */
8560static VALUE
8561rb_io_init_copy(VALUE dest, VALUE io)
8562{
8563 rb_io_t *fptr, *orig;
8564 int fd;
8565 VALUE write_io;
8566 rb_off_t pos;
8567
8568 io = rb_io_get_io(io);
8569 if (!OBJ_INIT_COPY(dest, io)) return dest;
8570 GetOpenFile(io, orig);
8571 MakeOpenFile(dest, fptr);
8572
8573 rb_io_flush(io);
8574
8575 /* copy rb_io_t structure */
8576 fptr->mode = orig->mode & ~FMODE_EXTERNAL;
8577 fptr->encs = orig->encs;
8578 fptr->pid = orig->pid;
8579 fptr->lineno = orig->lineno;
8580 fptr->timeout = orig->timeout;
8581
8582 ccan_list_head_init(&fptr->blocking_operations);
8583 fptr->closing_ec = NULL;
8584 fptr->wakeup_mutex = Qnil;
8585 fptr->fork_generation = GET_VM()->fork_gen;
8586
8587 if (!NIL_P(orig->pathv)) fptr->pathv = orig->pathv;
8588 fptr_copy_finalizer(fptr, orig);
8589
8590 fd = ruby_dup(orig->fd);
8591 fptr->fd = fd;
8592 pos = io_tell(orig);
8593 if (0 <= pos)
8594 io_seek(fptr, pos, SEEK_SET);
8595 if (fptr->mode & FMODE_BINMODE) {
8596 rb_io_binmode(dest);
8597 }
8598
8599 write_io = GetWriteIO(io);
8600 if (io != write_io) {
8601 write_io = rb_obj_dup(write_io);
8602 fptr->tied_io_for_writing = write_io;
8603 rb_ivar_set(dest, rb_intern("@tied_io_for_writing"), write_io);
8604 }
8605
8606 return dest;
8607}
8608
8609/*
8610 * call-seq:
8611 * printf(format_string, *objects) -> nil
8612 *
8613 * Formats and writes +objects+ to the stream.
8614 *
8615 * For details on +format_string+, see
8616 * {Format Specifications}[rdoc-ref:format_specifications.rdoc].
8617 *
8618 */
8619
8620VALUE
8621rb_io_printf(int argc, const VALUE *argv, VALUE out)
8622{
8623 rb_io_write(out, rb_f_sprintf(argc, argv));
8624 return Qnil;
8625}
8626
8627/*
8628 * call-seq:
8629 * printf(format_string, *objects) -> nil
8630 * printf(io, format_string, *objects) -> nil
8631 *
8632 * Equivalent to:
8633 *
8634 * io.write(sprintf(format_string, *objects))
8635 *
8636 * For details on +format_string+, see
8637 * {Format Specifications}[rdoc-ref:format_specifications.rdoc].
8638 *
8639 * With the single argument +format_string+, formats +objects+ into the string,
8640 * then writes the formatted string to $stdout:
8641 *
8642 * printf('%4.4d %10s %2.2f', 24, 24, 24.0)
8643 *
8644 * Output (on $stdout):
8645 *
8646 * 0024 24 24.00#
8647 *
8648 * With arguments +io+ and +format_string+, formats +objects+ into the string,
8649 * then writes the formatted string to +io+:
8650 *
8651 * printf($stderr, '%4.4d %10s %2.2f', 24, 24, 24.0)
8652 *
8653 * Output (on $stderr):
8654 *
8655 * 0024 24 24.00# => nil
8656 *
8657 * With no arguments, does nothing.
8658 *
8659 */
8660
8661static VALUE
8662rb_f_printf(int argc, VALUE *argv, VALUE _)
8663{
8664 VALUE out;
8665
8666 if (argc == 0) return Qnil;
8667 if (RB_TYPE_P(argv[0], T_STRING)) {
8668 out = rb_ractor_stdout();
8669 }
8670 else {
8671 out = argv[0];
8672 argv++;
8673 argc--;
8674 }
8675 rb_io_write(out, rb_f_sprintf(argc, argv));
8676
8677 return Qnil;
8678}
8679
8680static void
8681deprecated_str_setter(VALUE val, ID id, VALUE *var)
8682{
8683 rb_str_setter(val, id, &val);
8684 if (!NIL_P(val)) {
8685 rb_warn_deprecated("'%s'", NULL, rb_id2name(id));
8686 }
8687 *var = val;
8688}
8689
8690static void
8691deprecated_rs_setter(VALUE val, ID id, VALUE *var)
8692{
8693 if (!NIL_P(val)) {
8694 if (!RB_TYPE_P(val, T_STRING)) {
8695 rb_raise(rb_eTypeError, "value of %"PRIsVALUE" must be String", rb_id2str(id));
8696 }
8697 if (rb_str_equal(val, rb_default_rs)) {
8698 val = rb_default_rs;
8699 }
8700 else {
8701 val = rb_str_frozen_bare_string(val);
8702 }
8704 rb_warn_deprecated("'%s'", NULL, rb_id2name(id));
8705 }
8706 *var = val;
8707}
8708
8709/*
8710 * call-seq:
8711 * print(*objects) -> nil
8712 *
8713 * Writes the given objects to the stream; returns +nil+.
8714 * Appends the output record separator <tt>$OUTPUT_RECORD_SEPARATOR</tt>
8715 * (<tt>$\</tt>), if it is not +nil+.
8716 * See {Line IO}[rdoc-ref:IO@Line+IO].
8717 *
8718 * With argument +objects+ given, for each object:
8719 *
8720 * - Converts via its method +to_s+ if not a string.
8721 * - Writes to the stream.
8722 * - If not the last object, writes the output field separator
8723 * <tt>$OUTPUT_FIELD_SEPARATOR</tt> (<tt>$,</tt>) if it is not +nil+.
8724 *
8725 * With default separators:
8726 *
8727 * f = File.open('t.tmp', 'w+')
8728 * objects = [0, 0.0, Rational(0, 1), Complex(0, 0), :zero, 'zero']
8729 * p $OUTPUT_RECORD_SEPARATOR
8730 * p $OUTPUT_FIELD_SEPARATOR
8731 * f.print(*objects)
8732 * f.rewind
8733 * p f.read
8734 * f.close
8735 *
8736 * Output:
8737 *
8738 * nil
8739 * nil
8740 * "00.00/10+0izerozero"
8741 *
8742 * With specified separators:
8743 *
8744 * $\ = "\n"
8745 * $, = ','
8746 * f.rewind
8747 * f.print(*objects)
8748 * f.rewind
8749 * p f.read
8750 *
8751 * Output:
8752 *
8753 * "0,0.0,0/1,0+0i,zero,zero\n"
8754 *
8755 * With no argument given, writes the content of <tt>$_</tt>
8756 * (which is usually the most recent user input):
8757 *
8758 * f = File.open('t.tmp', 'w+')
8759 * gets # Sets $_ to the most recent user input.
8760 * f.print
8761 * f.close
8762 *
8763 */
8764
8765VALUE
8766rb_io_print(int argc, const VALUE *argv, VALUE out)
8767{
8768 int i;
8769 VALUE line;
8770
8771 /* if no argument given, print `$_' */
8772 if (argc == 0) {
8773 argc = 1;
8774 line = rb_lastline_get();
8775 argv = &line;
8776 }
8777 if (argc > 1 && !NIL_P(rb_output_fs)) {
8778 rb_category_warn(RB_WARN_CATEGORY_DEPRECATED, "$, is set to non-nil value");
8779 }
8780 for (i=0; i<argc; i++) {
8781 if (!NIL_P(rb_output_fs) && i>0) {
8782 rb_io_write(out, rb_output_fs);
8783 }
8784 rb_io_write(out, argv[i]);
8785 }
8786 if (argc > 0 && !NIL_P(rb_output_rs)) {
8787 rb_io_write(out, rb_output_rs);
8788 }
8789
8790 return Qnil;
8791}
8792
8793/*
8794 * call-seq:
8795 * print(*objects) -> nil
8796 *
8797 * Equivalent to <tt>$stdout.print(*objects)</tt>,
8798 * this method is the straightforward way to write to <tt>$stdout</tt>.
8799 *
8800 * Writes the given objects to <tt>$stdout</tt>; returns +nil+.
8801 * Appends the output record separator <tt>$OUTPUT_RECORD_SEPARATOR</tt>
8802 * <tt>$\</tt>), if it is not +nil+.
8803 *
8804 * With argument +objects+ given, for each object:
8805 *
8806 * - Converts via its method +to_s+ if not a string.
8807 * - Writes to <tt>stdout</tt>.
8808 * - If not the last object, writes the output field separator
8809 * <tt>$OUTPUT_FIELD_SEPARATOR</tt> (<tt>$,</tt> if it is not +nil+.
8810 *
8811 * With default separators:
8812 *
8813 * objects = [0, 0.0, Rational(0, 1), Complex(0, 0), :zero, 'zero']
8814 * $OUTPUT_RECORD_SEPARATOR
8815 * $OUTPUT_FIELD_SEPARATOR
8816 * print(*objects)
8817 *
8818 * Output:
8819 *
8820 * nil
8821 * nil
8822 * 00.00/10+0izerozero
8823 *
8824 * With specified separators:
8825 *
8826 * $OUTPUT_RECORD_SEPARATOR = "\n"
8827 * $OUTPUT_FIELD_SEPARATOR = ','
8828 * print(*objects)
8829 *
8830 * Output:
8831 *
8832 * 0,0.0,0/1,0+0i,zero,zero
8833 *
8834 * With no argument given, writes the content of <tt>$_</tt>
8835 * (which is usually the most recent user input):
8836 *
8837 * gets # Sets $_ to the most recent user input.
8838 * print # Prints $_.
8839 *
8840 */
8841
8842static VALUE
8843rb_f_print(int argc, const VALUE *argv, VALUE _)
8844{
8845 rb_io_print(argc, argv, rb_ractor_stdout());
8846 return Qnil;
8847}
8848
8849/*
8850 * call-seq:
8851 * putc(object) -> object
8852 *
8853 * Writes a character to the stream.
8854 * See {Character IO}[rdoc-ref:IO@Character+IO].
8855 *
8856 * If +object+ is numeric, converts to integer if necessary,
8857 * then writes the character whose code is the
8858 * least significant byte;
8859 * if +object+ is a string, writes the first character:
8860 *
8861 * $stdout.putc "A"
8862 * $stdout.putc 65
8863 *
8864 * Output:
8865 *
8866 * AA
8867 *
8868 */
8869
8870static VALUE
8871rb_io_putc(VALUE io, VALUE ch)
8872{
8873 VALUE str;
8874 if (RB_TYPE_P(ch, T_STRING)) {
8875 str = rb_str_substr(ch, 0, 1);
8876 }
8877 else {
8878 char c = NUM2CHR(ch);
8879 str = rb_str_new(&c, 1);
8880 }
8881 rb_io_write(io, str);
8882 return ch;
8883}
8884
8885#define forward(obj, id, argc, argv) \
8886 rb_funcallv_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8887#define forward_public(obj, id, argc, argv) \
8888 rb_funcallv_public_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8889#define forward_current(id, argc, argv) \
8890 forward_public(ARGF.current_file, id, argc, argv)
8891
8892/*
8893 * call-seq:
8894 * putc(int) -> int
8895 *
8896 * Equivalent to:
8897 *
8898 * $stdout.putc(int)
8899 *
8900 * See IO#putc for important information regarding multi-byte characters.
8901 *
8902 */
8903
8904static VALUE
8905rb_f_putc(VALUE recv, VALUE ch)
8906{
8907 VALUE r_stdout = rb_ractor_stdout();
8908 if (recv == r_stdout) {
8909 return rb_io_putc(recv, ch);
8910 }
8911 return forward(r_stdout, rb_intern("putc"), 1, &ch);
8912}
8913
8914
8915int
8916rb_str_end_with_asciichar(VALUE str, int c)
8917{
8918 long len = RSTRING_LEN(str);
8919 const char *ptr = RSTRING_PTR(str);
8920 rb_encoding *enc = rb_enc_from_index(ENCODING_GET(str));
8921 int n;
8922
8923 if (len == 0) return 0;
8924 if ((n = rb_enc_mbminlen(enc)) == 1) {
8925 return ptr[len - 1] == c;
8926 }
8927 return rb_enc_ascget(ptr + ((len - 1) / n) * n, ptr + len, &n, enc) == c;
8928}
8929
8930static VALUE
8931io_puts_ary(VALUE ary, VALUE out, int recur)
8932{
8933 VALUE tmp;
8934 long i;
8935
8936 if (recur) {
8937 tmp = rb_str_new2("[...]");
8938 rb_io_puts(1, &tmp, out);
8939 return Qtrue;
8940 }
8941 ary = rb_check_array_type(ary);
8942 if (NIL_P(ary)) return Qfalse;
8943 for (i=0; i<RARRAY_LEN(ary); i++) {
8944 tmp = RARRAY_AREF(ary, i);
8945 rb_io_puts(1, &tmp, out);
8946 }
8947 return Qtrue;
8948}
8949
8950/*
8951 * call-seq:
8952 * puts(*objects) -> nil
8953 *
8954 * Writes the given +objects+ to the stream, which must be open for writing;
8955 * returns +nil+.\
8956 * Writes a newline after each that does not already end with a newline sequence.
8957 * If called without arguments, writes a newline.
8958 * See {Line IO}[rdoc-ref:IO@Line+IO].
8959 *
8960 * Note that each added newline is the character <tt>"\n"<//tt>,
8961 * not the output record separator (<tt>$\</tt>).
8962 *
8963 * Treatment for each object:
8964 *
8965 * - String: writes the string.
8966 * - Neither string nor array: writes <tt>object.to_s</tt>.
8967 * - Array: writes each element of the array; arrays may be nested.
8968 *
8969 * To keep these examples brief, we define this helper method:
8970 *
8971 * def show(*objects)
8972 * # Puts objects to file.
8973 * f = File.new('t.tmp', 'w+')
8974 * f.puts(objects)
8975 * # Return file content.
8976 * f.rewind
8977 * p f.read
8978 * f.close
8979 * end
8980 *
8981 * # Strings without newlines.
8982 * show('foo', 'bar', 'baz') # => "foo\nbar\nbaz\n"
8983 * # Strings, some with newlines.
8984 * show("foo\n", 'bar', "baz\n") # => "foo\nbar\nbaz\n"
8985 *
8986 * # Neither strings nor arrays:
8987 * show(0, 0.0, Rational(0, 1), Complex(9, 0), :zero)
8988 * # => "0\n0.0\n0/1\n9+0i\nzero\n"
8989 *
8990 * # Array of strings.
8991 * show(['foo', "bar\n", 'baz']) # => "foo\nbar\nbaz\n"
8992 * # Nested arrays.
8993 * show([[[0, 1], 2, 3], 4, 5]) # => "0\n1\n2\n3\n4\n5\n"
8994 *
8995 */
8996
8997VALUE
8998rb_io_puts(int argc, const VALUE *argv, VALUE out)
8999{
9000 VALUE line, args[2];
9001
9002 /* if no argument given, print newline. */
9003 if (argc == 0) {
9004 rb_io_write(out, rb_default_rs);
9005 return Qnil;
9006 }
9007 for (int i = 0; i < argc; i++) {
9008 // Convert the argument to a string:
9009 if (RB_TYPE_P(argv[i], T_STRING)) {
9010 line = argv[i];
9011 }
9012 else if (rb_exec_recursive(io_puts_ary, argv[i], out)) {
9013 continue;
9014 }
9015 else {
9016 line = rb_obj_as_string(argv[i]);
9017 }
9018
9019 // Write the line:
9020 int n = 0;
9021 if (RSTRING_LEN(line) == 0) {
9022 args[n++] = rb_default_rs;
9023 }
9024 else {
9025 args[n++] = line;
9026 if (!rb_str_end_with_asciichar(line, '\n')) {
9027 args[n++] = rb_default_rs;
9028 }
9029 }
9030
9031 rb_io_writev(out, n, args);
9032 }
9033
9034 return Qnil;
9035}
9036
9037/*
9038 * call-seq:
9039 * puts(*objects) -> nil
9040 *
9041 * Equivalent to
9042 *
9043 * $stdout.puts(objects)
9044 */
9045
9046static VALUE
9047rb_f_puts(int argc, VALUE *argv, VALUE recv)
9048{
9049 VALUE r_stdout = rb_ractor_stdout();
9050 if (recv == r_stdout) {
9051 return rb_io_puts(argc, argv, recv);
9052 }
9053 return forward(r_stdout, rb_intern("puts"), argc, argv);
9054}
9055
9056static VALUE
9057rb_p_write(VALUE str)
9058{
9059 VALUE args[2];
9060 args[0] = str;
9061 args[1] = rb_default_rs;
9062 VALUE r_stdout = rb_ractor_stdout();
9063 if (RB_TYPE_P(r_stdout, T_FILE) &&
9064 rb_method_basic_definition_p(CLASS_OF(r_stdout), id_write)) {
9065 io_writev(2, args, r_stdout);
9066 }
9067 else {
9068 rb_io_writev(r_stdout, 2, args);
9069 }
9070 return Qnil;
9071}
9072
9073void
9074rb_p(VALUE obj) /* for debug print within C code */
9075{
9076 rb_p_write(rb_obj_as_string(rb_inspect(obj)));
9077}
9078
9079static VALUE
9080rb_p_result(int argc, const VALUE *argv)
9081{
9082 VALUE ret = Qnil;
9083
9084 if (argc == 1) {
9085 ret = argv[0];
9086 }
9087 else if (argc > 1) {
9088 ret = rb_ary_new4(argc, argv);
9089 }
9090 VALUE r_stdout = rb_ractor_stdout();
9091 if (RB_TYPE_P(r_stdout, T_FILE)) {
9092 rb_uninterruptible(rb_io_flush, r_stdout);
9093 }
9094 return ret;
9095}
9096
9097/*
9098 * call-seq:
9099 * p(object) -> obj
9100 * p(*objects) -> array of objects
9101 * p -> nil
9102 *
9103 * For each object +obj+, executes:
9104 *
9105 * $stdout.write(obj.inspect, "\n")
9106 *
9107 * With one object given, returns the object;
9108 * with multiple objects given, returns an array containing the objects;
9109 * with no object given, returns +nil+.
9110 *
9111 * Examples:
9112 *
9113 * r = Range.new(0, 4)
9114 * p r # => 0..4
9115 * p [r, r, r] # => [0..4, 0..4, 0..4]
9116 * p # => nil
9117 *
9118 * Output:
9119 *
9120 * 0..4
9121 * [0..4, 0..4, 0..4]
9122 *
9123 * Kernel#p is designed for debugging purposes.
9124 * Ruby implementations may define Kernel#p to be uninterruptible
9125 * in whole or in part.
9126 * On CRuby, Kernel#p's writing of data is uninterruptible.
9127 */
9128
9129static VALUE
9130rb_f_p(int argc, VALUE *argv, VALUE self)
9131{
9132 int i;
9133 for (i=0; i<argc; i++) {
9134 VALUE inspected = rb_obj_as_string(rb_inspect(argv[i]));
9135 rb_uninterruptible(rb_p_write, inspected);
9136 }
9137 return rb_p_result(argc, argv);
9138}
9139
9140/*
9141 * call-seq:
9142 * display(port = $>) -> nil
9143 *
9144 * Writes +self+ on the given port:
9145 *
9146 * 1.display
9147 * "cat".display
9148 * [ 4, 5, 6 ].display
9149 * puts
9150 *
9151 * Output:
9152 *
9153 * 1cat[4, 5, 6]
9154 *
9155 */
9156
9157static VALUE
9158rb_obj_display(int argc, VALUE *argv, VALUE self)
9159{
9160 VALUE out;
9161
9162 out = (!rb_check_arity(argc, 0, 1) ? rb_ractor_stdout() : argv[0]);
9163 rb_io_write(out, self);
9164
9165 return Qnil;
9166}
9167
9168static int
9169rb_stderr_to_original_p(VALUE err)
9170{
9171 return (err == orig_stderr || RFILE(orig_stderr)->fptr->fd < 0);
9172}
9173
9174void
9175rb_write_error2(const char *mesg, long len)
9176{
9177 VALUE out = rb_ractor_stderr();
9178 if (rb_stderr_to_original_p(out)) {
9179#ifdef _WIN32
9180 if (isatty(fileno(stderr))) {
9181 if (rb_w32_write_console(rb_str_new(mesg, len), fileno(stderr)) > 0) return;
9182 }
9183#endif
9184 if (fwrite(mesg, sizeof(char), (size_t)len, stderr) < (size_t)len) {
9185 /* failed to write to stderr, what can we do? */
9186 return;
9187 }
9188 }
9189 else {
9190 rb_io_write(out, rb_str_new(mesg, len));
9191 }
9192}
9193
9194void
9195rb_write_error(const char *mesg)
9196{
9197 rb_write_error2(mesg, strlen(mesg));
9198}
9199
9200void
9201rb_write_error_str(VALUE mesg)
9202{
9203 VALUE out = rb_ractor_stderr();
9204 /* a stopgap measure for the time being */
9205 if (rb_stderr_to_original_p(out)) {
9206 size_t len = (size_t)RSTRING_LEN(mesg);
9207#ifdef _WIN32
9208 if (isatty(fileno(stderr))) {
9209 if (rb_w32_write_console(mesg, fileno(stderr)) > 0) return;
9210 }
9211#endif
9212 if (fwrite(RSTRING_PTR(mesg), sizeof(char), len, stderr) < len) {
9213 RB_GC_GUARD(mesg);
9214 return;
9215 }
9216 }
9217 else {
9218 /* may unlock GVL, and */
9219 rb_io_write(out, mesg);
9220 }
9221}
9222
9223int
9224rb_stderr_tty_p(void)
9225{
9226 if (rb_stderr_to_original_p(rb_ractor_stderr()))
9227 return isatty(fileno(stderr));
9228 return 0;
9229}
9230
9231static void
9232must_respond_to(ID mid, VALUE val, ID id)
9233{
9234 if (!rb_respond_to(val, mid)) {
9235 rb_raise(rb_eTypeError, "%"PRIsVALUE" must have %"PRIsVALUE" method, %"PRIsVALUE" given",
9236 rb_id2str(id), rb_id2str(mid),
9237 rb_obj_class(val));
9238 }
9239}
9240
9241static void
9242stdin_setter(VALUE val, ID id, VALUE *ptr)
9243{
9245}
9246
9247static VALUE
9248stdin_getter(ID id, VALUE *ptr)
9249{
9250 return rb_ractor_stdin();
9251}
9252
9253static void
9254stdout_setter(VALUE val, ID id, VALUE *ptr)
9255{
9256 must_respond_to(id_write, val, id);
9258}
9259
9260static VALUE
9261stdout_getter(ID id, VALUE *ptr)
9262{
9263 return rb_ractor_stdout();
9264}
9265
9266static void
9267stderr_setter(VALUE val, ID id, VALUE *ptr)
9268{
9269 must_respond_to(id_write, val, id);
9271}
9272
9273static VALUE
9274stderr_getter(ID id, VALUE *ptr)
9275{
9276 return rb_ractor_stderr();
9277}
9278
9279static VALUE
9280allocate_and_open_new_file(VALUE klass)
9281{
9282 VALUE self = io_alloc(klass);
9283 rb_io_make_open_file(self);
9284 return self;
9285}
9286
9287VALUE
9288rb_io_open_descriptor(VALUE klass, int descriptor, int mode, VALUE path, VALUE timeout, struct rb_io_encoding *encoding)
9289{
9290 int state;
9291 VALUE self = rb_protect(allocate_and_open_new_file, klass, &state);
9292 if (state) {
9293 /* if we raised an exception allocating an IO object, but the caller
9294 intended to transfer ownership of this FD to us, close the fd before
9295 raising the exception. Otherwise, we would leak a FD - the caller
9296 expects GC to close the file, but we never got around to assigning
9297 it to a rb_io. */
9298 if (!(mode & FMODE_EXTERNAL)) {
9299 maygvl_close(descriptor, 0);
9300 }
9301 rb_jump_tag(state);
9302 }
9303
9304
9305 rb_io_t *io = RFILE(self)->fptr;
9306 io->self = self;
9307 io->fd = descriptor;
9308 io->mode = mode;
9309
9310 /* At this point, Ruby fully owns the descriptor, and will close it when
9311 the IO gets GC'd (unless FMODE_EXTERNAL was set), no matter what happens
9312 in the rest of this method. */
9313
9314 if (NIL_P(path)) {
9315 io->pathv = Qnil;
9316 }
9317 else {
9318 StringValue(path);
9319 io->pathv = rb_str_new_frozen(path);
9320 }
9321
9322 io->timeout = timeout;
9323
9324 ccan_list_head_init(&io->blocking_operations);
9325 io->closing_ec = NULL;
9326 io->wakeup_mutex = Qnil;
9327 io->fork_generation = GET_VM()->fork_gen;
9328
9329 if (encoding) {
9330 io->encs = *encoding;
9331 }
9332
9333 rb_update_max_fd(descriptor);
9334
9335 return self;
9336}
9337
9338static VALUE
9339prep_io(int fd, enum rb_io_mode fmode, VALUE klass, const char *path)
9340{
9341 VALUE path_value = Qnil;
9342 rb_encoding *e;
9343 struct rb_io_encoding convconfig;
9344
9345 if (path) {
9346 path_value = rb_obj_freeze(rb_str_new_cstr(path));
9347 }
9348
9349 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
9350 rb_io_ext_int_to_encs(e, NULL, &convconfig.enc, &convconfig.enc2, fmode);
9351 convconfig.ecflags = (fmode & FMODE_READABLE) ?
9354#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9355 convconfig.ecflags |= (fmode & FMODE_WRITABLE) ?
9356 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
9357 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
9358#endif
9359 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.enc2, convconfig.ecflags);
9360 convconfig.ecopts = Qnil;
9361
9362 VALUE self = rb_io_open_descriptor(klass, fd, fmode, path_value, Qnil, &convconfig);
9363 rb_io_t*io = RFILE(self)->fptr;
9364
9365 if (!io_check_tty(io)) {
9366#ifdef __CYGWIN__
9367 io->mode |= FMODE_BINMODE;
9368 setmode(fd, O_BINARY);
9369#endif
9370 }
9371
9372 return self;
9373}
9374
9375VALUE
9376rb_io_fdopen(int fd, int oflags, const char *path)
9377{
9378 VALUE klass = rb_cIO;
9379
9380 if (path && strcmp(path, "-")) klass = rb_cFile;
9381 return prep_io(fd, rb_io_oflags_fmode(oflags), klass, path);
9382}
9383
9384static VALUE
9385prep_stdio(FILE *f, enum rb_io_mode fmode, VALUE klass, const char *path)
9386{
9387 rb_io_t *fptr;
9388 VALUE io = prep_io(fileno(f), fmode|FMODE_EXTERNAL|DEFAULT_TEXTMODE, klass, path);
9389
9390 GetOpenFile(io, fptr);
9392#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9393 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
9394 if (fmode & FMODE_READABLE) {
9396 }
9397#endif
9398 fptr->stdio_file = f;
9399
9400 return io;
9401}
9402
9403VALUE
9404rb_io_prep_stdin(void)
9405{
9406 return prep_stdio(stdin, FMODE_READABLE, rb_cIO, "<STDIN>");
9407}
9408
9409VALUE
9410rb_io_prep_stdout(void)
9411{
9412 return prep_stdio(stdout, FMODE_WRITABLE|FMODE_SIGNAL_ON_EPIPE, rb_cIO, "<STDOUT>");
9413}
9414
9415VALUE
9416rb_io_prep_stderr(void)
9417{
9418 return prep_stdio(stderr, FMODE_WRITABLE|FMODE_SYNC, rb_cIO, "<STDERR>");
9419}
9420
9421FILE *
9423{
9424 if (!fptr->stdio_file) {
9425 int oflags = rb_io_fmode_oflags(fptr->mode) & ~O_EXCL;
9426 fptr->stdio_file = rb_fdopen(fptr->fd, rb_io_oflags_modestr(oflags));
9427 }
9428 return fptr->stdio_file;
9429}
9430
9431static inline void
9432rb_io_buffer_init(struct rb_io_internal_buffer *buf)
9433{
9434 buf->ptr = NULL;
9435 buf->off = 0;
9436 buf->len = 0;
9437 buf->capa = 0;
9438}
9439
9440static inline rb_io_t *
9441rb_io_fptr_new(void)
9442{
9443 rb_io_t *fp = ALLOC(rb_io_t);
9444 fp->self = Qnil;
9445 fp->fd = -1;
9446 fp->stdio_file = NULL;
9447 fp->mode = 0;
9448 fp->pid = 0;
9449 fp->lineno = 0;
9450 fp->pathv = Qnil;
9451 fp->finalize = 0;
9452 rb_io_buffer_init(&fp->wbuf);
9453 rb_io_buffer_init(&fp->rbuf);
9454 rb_io_buffer_init(&fp->cbuf);
9455 fp->readconv = NULL;
9456 fp->writeconv = NULL;
9458 fp->writeconv_pre_ecflags = 0;
9460 fp->writeconv_initialized = 0;
9461 fp->tied_io_for_writing = 0;
9462 fp->encs.enc = NULL;
9463 fp->encs.enc2 = NULL;
9464 fp->encs.ecflags = 0;
9465 fp->encs.ecopts = Qnil;
9466 fp->write_lock = Qnil;
9467 fp->timeout = Qnil;
9468 ccan_list_head_init(&fp->blocking_operations);
9469 fp->closing_ec = NULL;
9470 fp->wakeup_mutex = Qnil;
9471 fp->fork_generation = GET_VM()->fork_gen;
9472 return fp;
9473}
9474
9475rb_io_t *
9476rb_io_make_open_file(VALUE obj)
9477{
9478 rb_io_t *fp = 0;
9479
9480 Check_Type(obj, T_FILE);
9481 if (RFILE(obj)->fptr) {
9482 rb_io_close(obj);
9483 rb_io_fptr_finalize(RFILE(obj)->fptr);
9484 RFILE(obj)->fptr = 0;
9485 }
9486 fp = rb_io_fptr_new();
9487 fp->self = obj;
9488 RFILE(obj)->fptr = fp;
9489 return fp;
9490}
9491
9492static VALUE io_initialize(VALUE io, VALUE fnum, VALUE vmode, VALUE opt);
9493
9494/*
9495 * call-seq:
9496 * IO.new(fd, mode = 'r', **opts) -> io
9497 *
9498 * Creates and returns a new \IO object (file stream) from a file descriptor.
9499 *
9500 * \IO.new may be useful for interaction with low-level libraries.
9501 * For higher-level interactions, it may be simpler to create
9502 * the file stream using File.open.
9503 *
9504 * Argument +fd+ must be a valid file descriptor (integer):
9505 *
9506 * path = 't.tmp'
9507 * fd = IO.sysopen(path) # => 3
9508 * IO.new(fd) # => #<IO:fd 3>
9509 *
9510 * The new \IO object does not inherit encoding
9511 * (because the integer file descriptor does not have an encoding):
9512 *
9513 * fd = IO.sysopen('t.rus', 'rb')
9514 * io = IO.new(fd)
9515 * io.external_encoding # => #<Encoding:UTF-8> # Not ASCII-8BIT.
9516 *
9517 * Optional argument +mode+ (defaults to 'r') must specify a valid mode;
9518 * see {Access Modes}[rdoc-ref:File@Access+Modes]:
9519 *
9520 * IO.new(fd, 'w') # => #<IO:fd 3>
9521 * IO.new(fd, File::WRONLY) # => #<IO:fd 3>
9522 *
9523 * Optional keyword arguments +opts+ specify:
9524 *
9525 * - {Open Options}[rdoc-ref:IO@Open+Options].
9526 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
9527 *
9528 * Examples:
9529 *
9530 * IO.new(fd, internal_encoding: nil) # => #<IO:fd 3>
9531 * IO.new(fd, autoclose: true) # => #<IO:fd 3>
9532 *
9533 */
9534
9535static VALUE
9536rb_io_initialize(int argc, VALUE *argv, VALUE io)
9537{
9538 VALUE fnum, vmode;
9539 VALUE opt;
9540
9541 rb_scan_args(argc, argv, "11:", &fnum, &vmode, &opt);
9542 return io_initialize(io, fnum, vmode, opt);
9543}
9544
9545static VALUE
9546io_initialize(VALUE io, VALUE fnum, VALUE vmode, VALUE opt)
9547{
9548 rb_io_t *fp;
9549 int fd, oflags = O_RDONLY;
9550 enum rb_io_mode fmode;
9551 struct rb_io_encoding convconfig;
9552#if defined(HAVE_FCNTL) && defined(F_GETFL)
9553 int ofmode;
9554#else
9555 struct stat st;
9556#endif
9557
9558 rb_io_extract_modeenc(&vmode, 0, opt, &oflags, &fmode, &convconfig);
9559
9560 fd = NUM2INT(fnum);
9561 if (rb_reserved_fd_p(fd)) {
9562 rb_raise(rb_eArgError, "The given fd is not accessible because RubyVM reserves it");
9563 }
9564#if defined(HAVE_FCNTL) && defined(F_GETFL)
9565 oflags = fcntl(fd, F_GETFL);
9566 if (oflags == -1) rb_sys_fail(0);
9567#else
9568 if (fstat(fd, &st) < 0) rb_sys_fail(0);
9569#endif
9570 rb_update_max_fd(fd);
9571#if defined(HAVE_FCNTL) && defined(F_GETFL)
9572 ofmode = rb_io_oflags_fmode(oflags);
9573 if (NIL_P(vmode)) {
9574 fmode = ofmode;
9575 }
9576 else if ((~ofmode & fmode) & FMODE_READWRITE) {
9577 VALUE error = INT2FIX(EINVAL);
9579 }
9580#endif
9581 VALUE path = Qnil;
9582
9583 if (!NIL_P(opt)) {
9584 if (rb_hash_aref(opt, sym_autoclose) == Qfalse) {
9585 fmode |= FMODE_EXTERNAL;
9586 }
9587
9588 path = rb_hash_aref(opt, RB_ID2SYM(idPath));
9589 if (!NIL_P(path)) {
9590 StringValue(path);
9591 path = rb_str_new_frozen(path);
9592 }
9593 }
9594
9595 MakeOpenFile(io, fp);
9596 fp->self = io;
9597 fp->fd = fd;
9598 fp->mode = fmode;
9599 fp->encs = convconfig;
9600 fp->pathv = path;
9601 fp->timeout = Qnil;
9602 ccan_list_head_init(&fp->blocking_operations);
9603 fp->closing_ec = NULL;
9604 fp->wakeup_mutex = Qnil;
9605 fp->fork_generation = GET_VM()->fork_gen;
9606 clear_codeconv(fp);
9607 io_check_tty(fp);
9608 if (fileno(stdin) == fd)
9609 fp->stdio_file = stdin;
9610 else if (fileno(stdout) == fd)
9611 fp->stdio_file = stdout;
9612 else if (fileno(stderr) == fd)
9613 fp->stdio_file = stderr;
9614
9615 if (fmode & FMODE_SETENC_BY_BOM) io_set_encoding_by_bom(io);
9616 return io;
9617}
9618
9619/*
9620 * call-seq:
9621 * set_encoding_by_bom -> encoding or nil
9622 *
9623 * If the stream begins with a BOM
9624 * ({byte order marker}[https://en.wikipedia.org/wiki/Byte_order_mark]),
9625 * consumes the BOM and sets the external encoding accordingly;
9626 * returns the result encoding if found, or +nil+ otherwise:
9627 *
9628 * File.write('t.tmp', "\u{FEFF}abc")
9629 * io = File.open('t.tmp', 'rb')
9630 * io.set_encoding_by_bom # => #<Encoding:UTF-8>
9631 * io.close
9632 *
9633 * File.write('t.tmp', 'abc')
9634 * io = File.open('t.tmp', 'rb')
9635 * io.set_encoding_by_bom # => nil
9636 * io.close
9637 *
9638 * Raises an exception if the stream is not binmode
9639 * or its encoding has already been set.
9640 *
9641 */
9642
9643static VALUE
9644rb_io_set_encoding_by_bom(VALUE io)
9645{
9646 rb_io_t *fptr;
9647
9648 GetOpenFile(io, fptr);
9649 if (!(fptr->mode & FMODE_BINMODE)) {
9650 rb_raise(rb_eArgError, "ASCII incompatible encoding needs binmode");
9651 }
9652 if (fptr->encs.enc2) {
9653 rb_raise(rb_eArgError, "encoding conversion is set");
9654 }
9655 else if (fptr->encs.enc && fptr->encs.enc != rb_ascii8bit_encoding()) {
9656 rb_raise(rb_eArgError, "encoding is set to %s already",
9657 rb_enc_name(fptr->encs.enc));
9658 }
9659 if (!io_set_encoding_by_bom(io)) return Qnil;
9660 return rb_enc_from_encoding(fptr->encs.enc);
9661}
9662
9663/*
9664 * call-seq:
9665 * File.new(path, mode = 'r', perm = 0666, **opts) -> file
9666 *
9667 * Opens the file at the given +path+ according to the given +mode+;
9668 * creates and returns a new File object for that file.
9669 *
9670 * The new File object is buffered mode (or non-sync mode), unless
9671 * +filename+ is a tty.
9672 * See IO#flush, IO#fsync, IO#fdatasync, and IO#sync=.
9673 *
9674 * Argument +path+ must be a valid file path:
9675 *
9676 * f = File.new('/etc/fstab')
9677 * f.close
9678 * f = File.new('t.txt')
9679 * f.close
9680 *
9681 * Optional argument +mode+ (defaults to 'r') must specify a valid mode;
9682 * see {Access Modes}[rdoc-ref:File@Access+Modes]:
9683 *
9684 * f = File.new('t.tmp', 'w')
9685 * f.close
9686 * f = File.new('t.tmp', File::RDONLY)
9687 * f.close
9688 *
9689 * Optional argument +perm+ (defaults to 0666) must specify valid permissions
9690 * see {File Permissions}[rdoc-ref:File@File+Permissions]:
9691 *
9692 * f = File.new('t.tmp', File::CREAT, 0644)
9693 * f.close
9694 * f = File.new('t.tmp', File::CREAT, 0444)
9695 * f.close
9696 *
9697 * Optional keyword arguments +opts+ specify:
9698 *
9699 * - {Open Options}[rdoc-ref:IO@Open+Options].
9700 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
9701 *
9702 */
9703
9704static VALUE
9705rb_file_initialize(int argc, VALUE *argv, VALUE io)
9706{
9707 if (RFILE(io)->fptr) {
9708 rb_raise(rb_eRuntimeError, "reinitializing File");
9709 }
9710 VALUE fname, vmode, vperm, opt;
9711 int posargc = rb_scan_args(argc, argv, "12:", &fname, &vmode, &vperm, &opt);
9712 if (posargc < 3) { /* perm is File only */
9713 VALUE fd = rb_check_to_int(fname);
9714
9715 if (!NIL_P(fd)) {
9716 return io_initialize(io, fd, vmode, opt);
9717 }
9718 }
9719 return rb_open_file(io, fname, vmode, vperm, opt);
9720}
9721
9722/* :nodoc: */
9723static VALUE
9724rb_io_s_new(int argc, VALUE *argv, VALUE klass)
9725{
9726 if (rb_block_given_p()) {
9727 VALUE cname = rb_obj_as_string(klass);
9728
9729 rb_warn("%"PRIsVALUE"::new() does not take block; use %"PRIsVALUE"::open() instead",
9730 cname, cname);
9731 }
9732 return rb_class_new_instance_kw(argc, argv, klass, RB_PASS_CALLED_KEYWORDS);
9733}
9734
9735
9736/*
9737 * call-seq:
9738 * IO.for_fd(fd, mode = 'r', **opts) -> io
9739 *
9740 * Synonym for IO.new.
9741 *
9742 */
9743
9744static VALUE
9745rb_io_s_for_fd(int argc, VALUE *argv, VALUE klass)
9746{
9747 VALUE io = rb_obj_alloc(klass);
9748 rb_io_initialize(argc, argv, io);
9749 return io;
9750}
9751
9752/*
9753 * call-seq:
9754 * ios.autoclose? -> true or false
9755 *
9756 * Returns +true+ if the underlying file descriptor of _ios_ will be
9757 * closed at its finalization or at calling #close, otherwise +false+.
9758 */
9759
9760static VALUE
9761rb_io_autoclose_p(VALUE io)
9762{
9763 rb_io_t *fptr = RFILE(io)->fptr;
9764 rb_io_check_closed(fptr);
9765 return RBOOL(!(fptr->mode & FMODE_EXTERNAL));
9766}
9767
9768/*
9769 * call-seq:
9770 * io.autoclose = bool -> true or false
9771 *
9772 * Sets auto-close flag.
9773 *
9774 * f = File.open(File::NULL)
9775 * IO.for_fd(f.fileno).close
9776 * f.gets # raises Errno::EBADF
9777 *
9778 * f = File.open(File::NULL)
9779 * g = IO.for_fd(f.fileno)
9780 * g.autoclose = false
9781 * g.close
9782 * f.gets # won't cause Errno::EBADF
9783 */
9784
9785static VALUE
9786rb_io_set_autoclose(VALUE io, VALUE autoclose)
9787{
9788 rb_io_t *fptr;
9789 GetOpenFile(io, fptr);
9790 if (!RTEST(autoclose))
9791 fptr->mode |= FMODE_EXTERNAL;
9792 else
9793 fptr->mode &= ~FMODE_EXTERNAL;
9794 return autoclose;
9795}
9796
9797static VALUE
9798io_wait_event(VALUE io, int event, VALUE timeout, int return_io)
9799{
9800 VALUE result = rb_io_wait(io, RB_INT2NUM(event), timeout);
9801
9802 if (!RB_TEST(result)) {
9803 return Qnil;
9804 }
9805
9806 int mask = RB_NUM2INT(result);
9807
9808 if (mask & event) {
9809 if (return_io)
9810 return io;
9811 else
9812 return result;
9813 }
9814 else {
9815 return Qfalse;
9816 }
9817}
9818
9819/*
9820 * call-seq:
9821 * io.wait_readable -> truthy or falsy
9822 * io.wait_readable(timeout) -> truthy or falsy
9823 *
9824 * Waits until IO is readable and returns a truthy value, or a falsy
9825 * value when times out. Returns a truthy value immediately when
9826 * buffered data is available.
9827 */
9828
9829static VALUE
9830io_wait_readable(int argc, VALUE *argv, VALUE io)
9831{
9832 rb_io_t *fptr;
9833
9834 RB_IO_POINTER(io, fptr);
9836
9837 if (rb_io_read_pending(fptr)) return Qtrue;
9838
9839 rb_check_arity(argc, 0, 1);
9840 VALUE timeout = (argc == 1 ? argv[0] : Qnil);
9841
9842 return io_wait_event(io, RUBY_IO_READABLE, timeout, 1);
9843}
9844
9845/*
9846 * call-seq:
9847 * io.wait_writable -> truthy or falsy
9848 * io.wait_writable(timeout) -> truthy or falsy
9849 *
9850 * Waits until IO is writable and returns a truthy value or a falsy
9851 * value when times out.
9852 */
9853static VALUE
9854io_wait_writable(int argc, VALUE *argv, VALUE io)
9855{
9856 rb_io_t *fptr;
9857
9858 RB_IO_POINTER(io, fptr);
9860
9861 rb_check_arity(argc, 0, 1);
9862 VALUE timeout = (argc == 1 ? argv[0] : Qnil);
9863
9864 return io_wait_event(io, RUBY_IO_WRITABLE, timeout, 1);
9865}
9866
9867/*
9868 * call-seq:
9869 * io.wait_priority -> truthy or falsy
9870 * io.wait_priority(timeout) -> truthy or falsy
9871 *
9872 * Waits until IO is priority and returns a truthy value or a falsy
9873 * value when times out. Priority data is sent and received using
9874 * the Socket::MSG_OOB flag and is typically limited to streams.
9875 */
9876static VALUE
9877io_wait_priority(int argc, VALUE *argv, VALUE io)
9878{
9879 rb_io_t *fptr = NULL;
9880
9881 RB_IO_POINTER(io, fptr);
9883
9884 if (rb_io_read_pending(fptr)) return Qtrue;
9885
9886 rb_check_arity(argc, 0, 1);
9887 VALUE timeout = argc == 1 ? argv[0] : Qnil;
9888
9889 return io_wait_event(io, RUBY_IO_PRIORITY, timeout, 1);
9890}
9891
9892static int
9893wait_mode_sym(VALUE mode)
9894{
9895 if (mode == ID2SYM(rb_intern("r"))) {
9896 return RB_WAITFD_IN;
9897 }
9898 if (mode == ID2SYM(rb_intern("read"))) {
9899 return RB_WAITFD_IN;
9900 }
9901 if (mode == ID2SYM(rb_intern("readable"))) {
9902 return RB_WAITFD_IN;
9903 }
9904 if (mode == ID2SYM(rb_intern("w"))) {
9905 return RB_WAITFD_OUT;
9906 }
9907 if (mode == ID2SYM(rb_intern("write"))) {
9908 return RB_WAITFD_OUT;
9909 }
9910 if (mode == ID2SYM(rb_intern("writable"))) {
9911 return RB_WAITFD_OUT;
9912 }
9913 if (mode == ID2SYM(rb_intern("rw"))) {
9914 return RB_WAITFD_IN|RB_WAITFD_OUT;
9915 }
9916 if (mode == ID2SYM(rb_intern("read_write"))) {
9917 return RB_WAITFD_IN|RB_WAITFD_OUT;
9918 }
9919 if (mode == ID2SYM(rb_intern("readable_writable"))) {
9920 return RB_WAITFD_IN|RB_WAITFD_OUT;
9921 }
9922
9923 rb_raise(rb_eArgError, "unsupported mode: %"PRIsVALUE, mode);
9924}
9925
9926static inline enum rb_io_event
9927io_event_from_value(VALUE value)
9928{
9929 int events = RB_NUM2INT(value);
9930
9931 if (events <= 0) rb_raise(rb_eArgError, "Events must be positive integer!");
9932
9933 return events;
9934}
9935
9936/*
9937 * call-seq:
9938 * io.wait(events, timeout) -> event mask, false or nil
9939 * io.wait(*event_symbols[, timeout]) -> self, true, or false
9940 *
9941 * Waits until the IO becomes ready for the specified events and returns the
9942 * subset of events that become ready, or a falsy value when times out.
9943 *
9944 * The events can be a bit mask of +IO::READABLE+, +IO::WRITABLE+ or
9945 * +IO::PRIORITY+.
9946 *
9947 * Returns an event mask (truthy value) immediately when buffered data is
9948 * available.
9949 *
9950 * The second form: if one or more event symbols (+:read+, +:write+, or
9951 * +:read_write+) are passed, the event mask is the bit OR of the bitmask
9952 * corresponding to those symbols. In this form, +timeout+ is optional, the
9953 * order of the arguments is arbitrary, and returns +io+ if any of the
9954 * events is ready.
9955 */
9956
9957static VALUE
9958io_wait(int argc, VALUE *argv, VALUE io)
9959{
9960 VALUE timeout = Qundef;
9961 enum rb_io_event events = 0;
9962 int return_io = 0;
9963
9964 if (argc != 2 || (RB_SYMBOL_P(argv[0]) || RB_SYMBOL_P(argv[1]))) {
9965 // We'd prefer to return the actual mask, but this form would return the io itself:
9966 return_io = 1;
9967
9968 // Slow/messy path:
9969 for (int i = 0; i < argc; i += 1) {
9970 if (RB_SYMBOL_P(argv[i])) {
9971 events |= wait_mode_sym(argv[i]);
9972 }
9973 else if (UNDEF_P(timeout)) {
9974 rb_time_interval(timeout = argv[i]);
9975 }
9976 else {
9977 rb_raise(rb_eArgError, "timeout given more than once");
9978 }
9979 }
9980
9981 if (UNDEF_P(timeout)) timeout = Qnil;
9982
9983 if (events == 0) {
9984 events = RUBY_IO_READABLE;
9985 }
9986 }
9987 else /* argc == 2 and neither are symbols */ {
9988 // This is the fast path:
9989 events = io_event_from_value(argv[0]);
9990 timeout = argv[1];
9991 }
9992
9993 if (events & RUBY_IO_READABLE) {
9994 rb_io_t *fptr = NULL;
9995 RB_IO_POINTER(io, fptr);
9996
9997 if (rb_io_read_pending(fptr)) {
9998 // This was the original behaviour:
9999 if (return_io) return Qtrue;
10000 // New behaviour always returns an event mask:
10001 else return RB_INT2NUM(RUBY_IO_READABLE);
10002 }
10003 }
10004
10005 return io_wait_event(io, events, timeout, return_io);
10006}
10007
10008static void
10009argf_mark_and_move(void *ptr)
10010{
10011 struct argf *p = ptr;
10012 rb_gc_mark_and_move(&p->filename);
10013 rb_gc_mark_and_move(&p->current_file);
10014 rb_gc_mark_and_move(&p->argv);
10015 rb_gc_mark_and_move(&p->inplace);
10016 rb_gc_mark_and_move(&p->encs.ecopts);
10017}
10018
10019static size_t
10020argf_memsize(const void *ptr)
10021{
10022 const struct argf *p = ptr;
10023 size_t size = sizeof(*p);
10024 return size;
10025}
10026
10027static const rb_data_type_t argf_type = {
10028 "ARGF",
10029 {argf_mark_and_move, RUBY_TYPED_DEFAULT_FREE, argf_memsize, argf_mark_and_move},
10030 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
10031};
10032
10033static inline void
10034argf_init(struct argf *p, VALUE v)
10035{
10036 p->filename = Qnil;
10037 p->current_file = Qnil;
10038 p->lineno = 0;
10039 p->argv = v;
10040}
10041
10042static VALUE
10043argf_alloc(VALUE klass)
10044{
10045 struct argf *p;
10046 VALUE argf = TypedData_Make_Struct(klass, struct argf, &argf_type, p);
10047
10048 argf_init(p, Qnil);
10049 return argf;
10050}
10051
10052#undef rb_argv
10053
10054/* :nodoc: */
10055static VALUE
10056argf_initialize(VALUE argf, VALUE argv)
10057{
10058 memset(&ARGF, 0, sizeof(ARGF));
10059 argf_init(&ARGF, argv);
10060
10061 return argf;
10062}
10063
10064/* :nodoc: */
10065static VALUE
10066argf_initialize_copy(VALUE argf, VALUE orig)
10067{
10068 if (!OBJ_INIT_COPY(argf, orig)) return argf;
10069 ARGF = argf_of(orig);
10070 ARGF.argv = rb_obj_dup(ARGF.argv);
10071 return argf;
10072}
10073
10074/*
10075 * call-seq:
10076 * ARGF.lineno = integer -> integer
10077 *
10078 * Sets the line number of ARGF as a whole to the given Integer.
10079 *
10080 * ARGF sets the line number automatically as you read data, so normally
10081 * you will not need to set it explicitly. To access the current line number
10082 * use ARGF.lineno.
10083 *
10084 * For example:
10085 *
10086 * ARGF.lineno #=> 0
10087 * ARGF.readline #=> "This is line 1\n"
10088 * ARGF.lineno #=> 1
10089 * ARGF.lineno = 0 #=> 0
10090 * ARGF.lineno #=> 0
10091 */
10092static VALUE
10093argf_set_lineno(VALUE argf, VALUE val)
10094{
10095 ARGF.lineno = NUM2INT(val);
10096 ARGF.last_lineno = ARGF.lineno;
10097 return val;
10098}
10099
10100/*
10101 * call-seq:
10102 * ARGF.lineno -> integer
10103 *
10104 * Returns the current line number of ARGF as a whole. This value
10105 * can be set manually with ARGF.lineno=.
10106 *
10107 * For example:
10108 *
10109 * ARGF.lineno #=> 0
10110 * ARGF.readline #=> "This is line 1\n"
10111 * ARGF.lineno #=> 1
10112 */
10113static VALUE
10114argf_lineno(VALUE argf)
10115{
10116 return INT2FIX(ARGF.lineno);
10117}
10118
10119static VALUE
10120argf_forward(int argc, VALUE *argv, VALUE argf)
10121{
10122 return forward_current(rb_frame_this_func(), argc, argv);
10123}
10124
10125#define next_argv() argf_next_argv(argf)
10126#define ARGF_GENERIC_INPUT_P() \
10127 (ARGF.current_file == rb_stdin && !RB_TYPE_P(ARGF.current_file, T_FILE))
10128#define ARGF_FORWARD(argc, argv) do {\
10129 if (ARGF_GENERIC_INPUT_P())\
10130 return argf_forward((argc), (argv), argf);\
10131} while (0)
10132#define NEXT_ARGF_FORWARD(argc, argv) do {\
10133 if (!next_argv()) return Qnil;\
10134 ARGF_FORWARD((argc), (argv));\
10135} while (0)
10136
10137static void
10138argf_close(VALUE argf)
10139{
10140 VALUE file = ARGF.current_file;
10141 if (file == rb_stdin) return;
10142 if (RB_TYPE_P(file, T_FILE)) {
10143 rb_io_set_write_io(file, Qnil);
10144 }
10145 io_close(file);
10146 ARGF.init_p = -1;
10147}
10148
10149static int
10150argf_next_argv(VALUE argf)
10151{
10152 char *fn;
10153 rb_io_t *fptr;
10154 int stdout_binmode = 0;
10155 enum rb_io_mode fmode;
10156
10157 VALUE r_stdout = rb_ractor_stdout();
10158
10159 if (RB_TYPE_P(r_stdout, T_FILE)) {
10160 GetOpenFile(r_stdout, fptr);
10161 if (fptr->mode & FMODE_BINMODE)
10162 stdout_binmode = 1;
10163 }
10164
10165 if (ARGF.init_p == 0) {
10166 if (!NIL_P(ARGF.argv) && RARRAY_LEN(ARGF.argv) > 0) {
10167 ARGF.next_p = 1;
10168 }
10169 else {
10170 ARGF.next_p = -1;
10171 }
10172 ARGF.init_p = 1;
10173 }
10174 else {
10175 if (NIL_P(ARGF.argv)) {
10176 ARGF.next_p = -1;
10177 }
10178 else if (ARGF.next_p == -1 && RARRAY_LEN(ARGF.argv) > 0) {
10179 ARGF.next_p = 1;
10180 }
10181 }
10182
10183 if (ARGF.next_p == 1) {
10184 if (ARGF.init_p == 1) argf_close(argf);
10185 retry:
10186 if (RARRAY_LEN(ARGF.argv) > 0) {
10187 VALUE filename = rb_ary_shift(ARGF.argv);
10188 FilePathValue(filename);
10189 ARGF.filename = filename;
10190 filename = rb_str_encode_ospath(filename);
10191 fn = StringValueCStr(filename);
10192 if (RSTRING_LEN(filename) == 1 && fn[0] == '-') {
10193 ARGF.current_file = rb_stdin;
10194 if (ARGF.inplace) {
10195 rb_warn("Can't do inplace edit for stdio; skipping");
10196 goto retry;
10197 }
10198 }
10199 else {
10200 VALUE write_io = Qnil;
10201 int fr = rb_sysopen(filename, O_RDONLY, 0);
10202
10203 if (ARGF.inplace) {
10204 struct stat st;
10205#ifndef NO_SAFE_RENAME
10206 struct stat st2;
10207#endif
10208 VALUE str;
10209 int fw;
10210
10211 if (RB_TYPE_P(r_stdout, T_FILE) && r_stdout != orig_stdout) {
10212 rb_io_close(r_stdout);
10213 }
10214 fstat(fr, &st);
10215 str = filename;
10216 if (!NIL_P(ARGF.inplace)) {
10217 VALUE suffix = ARGF.inplace;
10218 str = rb_str_dup(str);
10219 if (NIL_P(rb_str_cat_conv_enc_opts(str, RSTRING_LEN(str),
10220 RSTRING_PTR(suffix), RSTRING_LEN(suffix),
10221 rb_enc_get(suffix), 0, Qnil))) {
10222 rb_str_append(str, suffix);
10223 }
10224#ifdef NO_SAFE_RENAME
10225 (void)close(fr);
10226 (void)unlink(RSTRING_PTR(str));
10227 if (rename(fn, RSTRING_PTR(str)) < 0) {
10228 rb_warn("Can't rename %"PRIsVALUE" to %"PRIsVALUE": %s, skipping file",
10229 filename, str, strerror(errno));
10230 goto retry;
10231 }
10232 fr = rb_sysopen(str, O_RDONLY, 0);
10233#else
10234 if (rename(fn, RSTRING_PTR(str)) < 0) {
10235 rb_warn("Can't rename %"PRIsVALUE" to %"PRIsVALUE": %s, skipping file",
10236 filename, str, strerror(errno));
10237 close(fr);
10238 goto retry;
10239 }
10240#endif
10241 }
10242 else {
10243#ifdef NO_SAFE_RENAME
10244 rb_fatal("Can't do inplace edit without backup");
10245#else
10246 if (unlink(fn) < 0) {
10247 rb_warn("Can't remove %"PRIsVALUE": %s, skipping file",
10248 filename, strerror(errno));
10249 close(fr);
10250 goto retry;
10251 }
10252#endif
10253 }
10254 fw = rb_sysopen(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666);
10255#ifndef NO_SAFE_RENAME
10256 fstat(fw, &st2);
10257#ifdef HAVE_FCHMOD
10258 fchmod(fw, st.st_mode);
10259#else
10260 chmod(fn, st.st_mode);
10261#endif
10262 if (st.st_uid!=st2.st_uid || st.st_gid!=st2.st_gid) {
10263 int err;
10264#ifdef HAVE_FCHOWN
10265 err = fchown(fw, st.st_uid, st.st_gid);
10266#else
10267 err = chown(fn, st.st_uid, st.st_gid);
10268#endif
10269 if (err && getuid() == 0 && st2.st_uid == 0) {
10270 const char *wkfn = RSTRING_PTR(filename);
10271 rb_warn("Can't set owner/group of %"PRIsVALUE" to same as %"PRIsVALUE": %s, skipping file",
10272 filename, str, strerror(errno));
10273 (void)close(fr);
10274 (void)close(fw);
10275 (void)unlink(wkfn);
10276 goto retry;
10277 }
10278 }
10279#endif
10280 write_io = prep_io(fw, FMODE_WRITABLE, rb_cFile, fn);
10281 rb_ractor_stdout_set(write_io);
10282 if (stdout_binmode) rb_io_binmode(rb_stdout);
10283 }
10284 fmode = FMODE_READABLE;
10285 if (!ARGF.binmode) {
10286 fmode |= DEFAULT_TEXTMODE;
10287 }
10288 ARGF.current_file = prep_io(fr, fmode, rb_cFile, fn);
10289 if (!NIL_P(write_io)) {
10290 rb_io_set_write_io(ARGF.current_file, write_io);
10291 }
10292 RB_GC_GUARD(filename);
10293 }
10294 if (ARGF.binmode) rb_io_ascii8bit_binmode(ARGF.current_file);
10295 GetOpenFile(ARGF.current_file, fptr);
10296 if (ARGF.encs.enc) {
10297 fptr->encs = ARGF.encs;
10298 clear_codeconv(fptr);
10299 }
10300 else {
10301 fptr->encs.ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
10302 if (!ARGF.binmode) {
10304#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
10305 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
10306#endif
10307 }
10308 }
10309 ARGF.next_p = 0;
10310 }
10311 else {
10312 ARGF.next_p = 1;
10313 return FALSE;
10314 }
10315 }
10316 else if (ARGF.next_p == -1) {
10317 ARGF.current_file = rb_stdin;
10318 ARGF.filename = rb_str_new2("-");
10319 if (ARGF.inplace) {
10320 rb_warn("Can't do inplace edit for stdio");
10321 rb_ractor_stdout_set(orig_stdout);
10322 }
10323 }
10324 if (ARGF.init_p == -1) ARGF.init_p = 1;
10325 return TRUE;
10326}
10327
10328static VALUE
10329argf_getline(int argc, VALUE *argv, VALUE argf)
10330{
10331 VALUE line;
10332 long lineno = ARGF.lineno;
10333
10334 retry:
10335 if (!next_argv()) return Qnil;
10336 if (ARGF_GENERIC_INPUT_P()) {
10337 line = forward_current(idGets, argc, argv);
10338 }
10339 else {
10340 if (argc == 0 && rb_rs == rb_default_rs) {
10341 line = rb_io_gets(ARGF.current_file);
10342 }
10343 else {
10344 line = rb_io_getline(argc, argv, ARGF.current_file);
10345 }
10346 if (NIL_P(line) && ARGF.next_p != -1) {
10347 argf_close(argf);
10348 ARGF.next_p = 1;
10349 goto retry;
10350 }
10351 }
10352 if (!NIL_P(line)) {
10353 ARGF.lineno = ++lineno;
10354 ARGF.last_lineno = ARGF.lineno;
10355 }
10356 return line;
10357}
10358
10359static VALUE
10360argf_lineno_getter(ID id, VALUE *var)
10361{
10362 VALUE argf = *var;
10363 return INT2FIX(ARGF.last_lineno);
10364}
10365
10366static void
10367argf_lineno_setter(VALUE val, ID id, VALUE *var)
10368{
10369 VALUE argf = *var;
10370 int n = NUM2INT(val);
10371 ARGF.last_lineno = ARGF.lineno = n;
10372}
10373
10374void
10375rb_reset_argf_lineno(long n)
10376{
10377 ARGF.last_lineno = ARGF.lineno = n;
10378}
10379
10380static VALUE argf_gets(int, VALUE *, VALUE);
10381
10382/*
10383 * call-seq:
10384 * gets(sep=$/ [, getline_args]) -> string or nil
10385 * gets(limit [, getline_args]) -> string or nil
10386 * gets(sep, limit [, getline_args]) -> string or nil
10387 *
10388 * Returns (and assigns to <code>$_</code>) the next line from the list
10389 * of files in +ARGV+ (or <code>$*</code>), or from standard input if
10390 * no files are present on the command line. Returns +nil+ at end of
10391 * file. The optional argument specifies the record separator. The
10392 * separator is included with the contents of each record. A separator
10393 * of +nil+ reads the entire contents, and a zero-length separator
10394 * reads the input one paragraph at a time, where paragraphs are
10395 * divided by two consecutive newlines. If the first argument is an
10396 * integer, or optional second argument is given, the returning string
10397 * would not be longer than the given value in bytes. If multiple
10398 * filenames are present in +ARGV+, <code>gets(nil)</code> will read
10399 * the contents one file at a time.
10400 *
10401 * ARGV << "testfile"
10402 * print while gets
10403 *
10404 * <em>produces:</em>
10405 *
10406 * This is line one
10407 * This is line two
10408 * This is line three
10409 * And so on...
10410 *
10411 * The style of programming using <code>$_</code> as an implicit
10412 * parameter is gradually losing favor in the Ruby community.
10413 */
10414
10415static VALUE
10416rb_f_gets(int argc, VALUE *argv, VALUE recv)
10417{
10418 if (recv == argf) {
10419 return argf_gets(argc, argv, argf);
10420 }
10421 return forward(argf, idGets, argc, argv);
10422}
10423
10424/*
10425 * call-seq:
10426 * ARGF.gets(sep=$/ [, getline_args]) -> string or nil
10427 * ARGF.gets(limit [, getline_args]) -> string or nil
10428 * ARGF.gets(sep, limit [, getline_args]) -> string or nil
10429 *
10430 * Returns the next line from the current file in ARGF.
10431 *
10432 * By default lines are assumed to be separated by <code>$/</code>;
10433 * to use a different character as a separator, supply it as a String
10434 * for the _sep_ argument.
10435 *
10436 * The optional _limit_ argument specifies how many characters of each line
10437 * to return. By default all characters are returned.
10438 *
10439 * See IO.readlines for details about getline_args.
10440 *
10441 */
10442static VALUE
10443argf_gets(int argc, VALUE *argv, VALUE argf)
10444{
10445 VALUE line;
10446
10447 line = argf_getline(argc, argv, argf);
10448 rb_lastline_set(line);
10449
10450 return line;
10451}
10452
10453VALUE
10455{
10456 VALUE line;
10457
10458 if (rb_rs != rb_default_rs) {
10459 return rb_f_gets(0, 0, argf);
10460 }
10461
10462 retry:
10463 if (!next_argv()) return Qnil;
10464 line = rb_io_gets(ARGF.current_file);
10465 if (NIL_P(line) && ARGF.next_p != -1) {
10466 rb_io_close(ARGF.current_file);
10467 ARGF.next_p = 1;
10468 goto retry;
10469 }
10470 rb_lastline_set(line);
10471 if (!NIL_P(line)) {
10472 ARGF.lineno++;
10473 ARGF.last_lineno = ARGF.lineno;
10474 }
10475
10476 return line;
10477}
10478
10479static VALUE argf_readline(int, VALUE *, VALUE);
10480
10481/*
10482 * call-seq:
10483 * readline(sep = $/, chomp: false) -> string
10484 * readline(limit, chomp: false) -> string
10485 * readline(sep, limit, chomp: false) -> string
10486 *
10487 * Equivalent to method Kernel#gets, except that it raises an exception
10488 * if called at end-of-stream:
10489 *
10490 * $ cat t.txt | ruby -e "p readlines; readline"
10491 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10492 * in `readline': end of file reached (EOFError)
10493 *
10494 * Optional keyword argument +chomp+ specifies whether line separators
10495 * are to be omitted.
10496 */
10497
10498static VALUE
10499rb_f_readline(int argc, VALUE *argv, VALUE recv)
10500{
10501 if (recv == argf) {
10502 return argf_readline(argc, argv, argf);
10503 }
10504 return forward(argf, rb_intern("readline"), argc, argv);
10505}
10506
10507
10508/*
10509 * call-seq:
10510 * ARGF.readline(sep=$/) -> string
10511 * ARGF.readline(limit) -> string
10512 * ARGF.readline(sep, limit) -> string
10513 *
10514 * Returns the next line from the current file in ARGF.
10515 *
10516 * By default lines are assumed to be separated by <code>$/</code>;
10517 * to use a different character as a separator, supply it as a String
10518 * for the _sep_ argument.
10519 *
10520 * The optional _limit_ argument specifies how many characters of each line
10521 * to return. By default all characters are returned.
10522 *
10523 * An EOFError is raised at the end of the file.
10524 */
10525static VALUE
10526argf_readline(int argc, VALUE *argv, VALUE argf)
10527{
10528 VALUE line;
10529
10530 if (!next_argv()) rb_eof_error();
10531 ARGF_FORWARD(argc, argv);
10532 line = argf_gets(argc, argv, argf);
10533 if (NIL_P(line)) {
10534 rb_eof_error();
10535 }
10536
10537 return line;
10538}
10539
10540static VALUE argf_readlines(int, VALUE *, VALUE);
10541
10542/*
10543 * call-seq:
10544 * readlines(sep = $/, chomp: false, **enc_opts) -> array
10545 * readlines(limit, chomp: false, **enc_opts) -> array
10546 * readlines(sep, limit, chomp: false, **enc_opts) -> array
10547 *
10548 * Returns an array containing the lines returned by calling
10549 * Kernel#gets until the end-of-stream is reached;
10550 * (see {Line IO}[rdoc-ref:IO@Line+IO]).
10551 *
10552 * With only string argument +sep+ given,
10553 * returns the remaining lines as determined by line separator +sep+,
10554 * or +nil+ if none;
10555 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
10556 *
10557 * # Default separator.
10558 * $ cat t.txt | ruby -e "p readlines"
10559 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10560 *
10561 * # Specified separator.
10562 * $ cat t.txt | ruby -e "p readlines 'li'"
10563 * ["First li", "ne\nSecond li", "ne\n\nFourth li", "ne\nFifth li", "ne\n"]
10564 *
10565 * # Get-all separator.
10566 * $ cat t.txt | ruby -e "p readlines nil"
10567 * ["First line\nSecond line\n\nFourth line\nFifth line\n"]
10568 *
10569 * # Get-paragraph separator.
10570 * $ cat t.txt | ruby -e "p readlines ''"
10571 * ["First line\nSecond line\n\n", "Fourth line\nFifth line\n"]
10572 *
10573 * With only integer argument +limit+ given,
10574 * limits the number of bytes in the line;
10575 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
10576 *
10577 * $cat t.txt | ruby -e "p readlines 10"
10578 * ["First line", "\n", "Second lin", "e\n", "\n", "Fourth lin", "e\n", "Fifth line", "\n"]
10579 *
10580 * $cat t.txt | ruby -e "p readlines 11"
10581 * ["First line\n", "Second line", "\n", "\n", "Fourth line", "\n", "Fifth line\n"]
10582 *
10583 * $cat t.txt | ruby -e "p readlines 12"
10584 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10585 *
10586 * With arguments +sep+ and +limit+ given,
10587 * combines the two behaviors
10588 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
10589 *
10590 * Optional keyword argument +chomp+ specifies whether line separators
10591 * are to be omitted:
10592 *
10593 * $ cat t.txt | ruby -e "p readlines(chomp: true)"
10594 * ["First line", "Second line", "", "Fourth line", "Fifth line"]
10595 *
10596 * Optional keyword arguments +enc_opts+ specify encoding options;
10597 * see {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
10598 *
10599 */
10600
10601static VALUE
10602rb_f_readlines(int argc, VALUE *argv, VALUE recv)
10603{
10604 if (recv == argf) {
10605 return argf_readlines(argc, argv, argf);
10606 }
10607 return forward(argf, rb_intern("readlines"), argc, argv);
10608}
10609
10610/*
10611 * call-seq:
10612 * ARGF.readlines(sep = $/, chomp: false) -> array
10613 * ARGF.readlines(limit, chomp: false) -> array
10614 * ARGF.readlines(sep, limit, chomp: false) -> array
10615 *
10616 * ARGF.to_a(sep = $/, chomp: false) -> array
10617 * ARGF.to_a(limit, chomp: false) -> array
10618 * ARGF.to_a(sep, limit, chomp: false) -> array
10619 *
10620 * Reads each file in ARGF in its entirety, returning an Array containing
10621 * lines from the files. Lines are assumed to be separated by _sep_.
10622 *
10623 * lines = ARGF.readlines
10624 * lines[0] #=> "This is line one\n"
10625 *
10626 * See +IO.readlines+ for a full description of all options.
10627 */
10628static VALUE
10629argf_readlines(int argc, VALUE *argv, VALUE argf)
10630{
10631 long lineno = ARGF.lineno;
10632 VALUE lines, ary;
10633
10634 ary = rb_ary_new();
10635 while (next_argv()) {
10636 if (ARGF_GENERIC_INPUT_P()) {
10637 lines = forward_current(rb_intern("readlines"), argc, argv);
10638 }
10639 else {
10640 lines = rb_io_readlines(argc, argv, ARGF.current_file);
10641 argf_close(argf);
10642 }
10643 ARGF.next_p = 1;
10644 rb_ary_concat(ary, lines);
10645 ARGF.lineno = lineno + RARRAY_LEN(ary);
10646 ARGF.last_lineno = ARGF.lineno;
10647 }
10648 ARGF.init_p = 0;
10649 return ary;
10650}
10651
10652/*
10653 * call-seq:
10654 * `command` -> string
10655 *
10656 * Returns the <tt>$stdout</tt> output from running +command+ in a subshell;
10657 * sets global variable <tt>$?</tt> to the process status.
10658 *
10659 * This method has potential security vulnerabilities if called with untrusted input;
10660 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
10661 *
10662 * Examples:
10663 *
10664 * $ `date` # => "Wed Apr 9 08:56:30 CDT 2003\n"
10665 * $ `echo oops && exit 99` # => "oops\n"
10666 * $ $? # => #<Process::Status: pid 17088 exit 99>
10667 * $ $?.exitstatus # => 99
10668 *
10669 * The built-in syntax <tt>%x{...}</tt> uses this method.
10670 *
10671 */
10672
10673static VALUE
10674rb_f_backquote(VALUE obj, VALUE str)
10675{
10676 VALUE port;
10677 VALUE result;
10678 rb_io_t *fptr;
10679
10680 StringValue(str);
10681 rb_last_status_clear();
10682 port = pipe_open_s(str, "r", FMODE_READABLE|DEFAULT_TEXTMODE, NULL);
10683 if (NIL_P(port)) return rb_str_new(0,0);
10684
10685 GetOpenFile(port, fptr);
10686 result = read_all(fptr, remain_size(fptr), Qnil);
10687 rb_io_close(port);
10688 rb_io_fptr_cleanup_all(fptr);
10689 RB_GC_GUARD(port);
10690
10691 return result;
10692}
10693
10694#ifdef HAVE_SYS_SELECT_H
10695#include <sys/select.h>
10696#endif
10697
10698static VALUE
10699select_internal(VALUE read, VALUE write, VALUE except, struct timeval *tp, rb_fdset_t *fds)
10700{
10701 VALUE res, list;
10702 rb_fdset_t *rp, *wp, *ep;
10703 rb_io_t *fptr;
10704 long i;
10705 int max = 0, n;
10706 int pending = 0;
10707 struct timeval timerec;
10708
10709 if (!NIL_P(read)) {
10710 Check_Type(read, T_ARRAY);
10711 for (i=0; i<RARRAY_LEN(read); i++) {
10712 GetOpenFile(rb_io_get_io(RARRAY_AREF(read, i)), fptr);
10713 rb_fd_set(fptr->fd, &fds[0]);
10714 if (READ_DATA_PENDING(fptr) || READ_CHAR_PENDING(fptr)) { /* check for buffered data */
10715 pending++;
10716 rb_fd_set(fptr->fd, &fds[3]);
10717 }
10718 if (max < fptr->fd) max = fptr->fd;
10719 }
10720 if (pending) { /* no blocking if there's buffered data */
10721 timerec.tv_sec = timerec.tv_usec = 0;
10722 tp = &timerec;
10723 }
10724 rp = &fds[0];
10725 }
10726 else
10727 rp = 0;
10728
10729 if (!NIL_P(write)) {
10730 Check_Type(write, T_ARRAY);
10731 for (i=0; i<RARRAY_LEN(write); i++) {
10732 VALUE write_io = GetWriteIO(rb_io_get_io(RARRAY_AREF(write, i)));
10733 GetOpenFile(write_io, fptr);
10734 rb_fd_set(fptr->fd, &fds[1]);
10735 if (max < fptr->fd) max = fptr->fd;
10736 }
10737 wp = &fds[1];
10738 }
10739 else
10740 wp = 0;
10741
10742 if (!NIL_P(except)) {
10743 Check_Type(except, T_ARRAY);
10744 for (i=0; i<RARRAY_LEN(except); i++) {
10745 VALUE io = rb_io_get_io(RARRAY_AREF(except, i));
10746 VALUE write_io = GetWriteIO(io);
10747 GetOpenFile(io, fptr);
10748 rb_fd_set(fptr->fd, &fds[2]);
10749 if (max < fptr->fd) max = fptr->fd;
10750 if (io != write_io) {
10751 GetOpenFile(write_io, fptr);
10752 rb_fd_set(fptr->fd, &fds[2]);
10753 if (max < fptr->fd) max = fptr->fd;
10754 }
10755 }
10756 ep = &fds[2];
10757 }
10758 else {
10759 ep = 0;
10760 }
10761
10762 max++;
10763
10764 n = rb_thread_fd_select(max, rp, wp, ep, tp);
10765 if (n < 0) {
10766 rb_sys_fail(0);
10767 }
10768 if (!pending && n == 0) return Qnil; /* returns nil on timeout */
10769
10770 res = rb_ary_new2(3);
10771 rb_ary_push(res, rp?rb_ary_new():rb_ary_new2(0));
10772 rb_ary_push(res, wp?rb_ary_new():rb_ary_new2(0));
10773 rb_ary_push(res, ep?rb_ary_new():rb_ary_new2(0));
10774
10775 if (rp) {
10776 list = RARRAY_AREF(res, 0);
10777 for (i=0; i< RARRAY_LEN(read); i++) {
10778 VALUE obj = rb_ary_entry(read, i);
10779 VALUE io = rb_io_get_io(obj);
10780 GetOpenFile(io, fptr);
10781 if (rb_fd_isset(fptr->fd, &fds[0]) ||
10782 rb_fd_isset(fptr->fd, &fds[3])) {
10783 rb_ary_push(list, obj);
10784 }
10785 }
10786 }
10787
10788 if (wp) {
10789 list = RARRAY_AREF(res, 1);
10790 for (i=0; i< RARRAY_LEN(write); i++) {
10791 VALUE obj = rb_ary_entry(write, i);
10792 VALUE io = rb_io_get_io(obj);
10793 VALUE write_io = GetWriteIO(io);
10794 GetOpenFile(write_io, fptr);
10795 if (rb_fd_isset(fptr->fd, &fds[1])) {
10796 rb_ary_push(list, obj);
10797 }
10798 }
10799 }
10800
10801 if (ep) {
10802 list = RARRAY_AREF(res, 2);
10803 for (i=0; i< RARRAY_LEN(except); i++) {
10804 VALUE obj = rb_ary_entry(except, i);
10805 VALUE io = rb_io_get_io(obj);
10806 VALUE write_io = GetWriteIO(io);
10807 GetOpenFile(io, fptr);
10808 if (rb_fd_isset(fptr->fd, &fds[2])) {
10809 rb_ary_push(list, obj);
10810 }
10811 else if (io != write_io) {
10812 GetOpenFile(write_io, fptr);
10813 if (rb_fd_isset(fptr->fd, &fds[2])) {
10814 rb_ary_push(list, obj);
10815 }
10816 }
10817 }
10818 }
10819
10820 return res; /* returns an empty array on interrupt */
10821}
10822
10824 VALUE read, write, except;
10825 struct timeval *timeout;
10826 rb_fdset_t fdsets[4];
10827};
10828
10829static VALUE
10830select_call(VALUE arg)
10831{
10832 struct select_args *p = (struct select_args *)arg;
10833
10834 return select_internal(p->read, p->write, p->except, p->timeout, p->fdsets);
10835}
10836
10837static VALUE
10838select_end(VALUE arg)
10839{
10840 struct select_args *p = (struct select_args *)arg;
10841 int i;
10842
10843 for (i = 0; i < numberof(p->fdsets); ++i)
10844 rb_fd_term(&p->fdsets[i]);
10845 return Qnil;
10846}
10847
10848static VALUE sym_normal, sym_sequential, sym_random,
10849 sym_willneed, sym_dontneed, sym_noreuse;
10850
10851#ifdef HAVE_POSIX_FADVISE
10852struct io_advise_struct {
10853 int fd;
10854 int advice;
10855 rb_off_t offset;
10856 rb_off_t len;
10857};
10858
10859static VALUE
10860io_advise_internal(void *arg)
10861{
10862 struct io_advise_struct *ptr = arg;
10863 return posix_fadvise(ptr->fd, ptr->offset, ptr->len, ptr->advice);
10864}
10865
10866static VALUE
10867io_advise_sym_to_const(VALUE sym)
10868{
10869#ifdef POSIX_FADV_NORMAL
10870 if (sym == sym_normal)
10871 return INT2NUM(POSIX_FADV_NORMAL);
10872#endif
10873
10874#ifdef POSIX_FADV_RANDOM
10875 if (sym == sym_random)
10876 return INT2NUM(POSIX_FADV_RANDOM);
10877#endif
10878
10879#ifdef POSIX_FADV_SEQUENTIAL
10880 if (sym == sym_sequential)
10881 return INT2NUM(POSIX_FADV_SEQUENTIAL);
10882#endif
10883
10884#ifdef POSIX_FADV_WILLNEED
10885 if (sym == sym_willneed)
10886 return INT2NUM(POSIX_FADV_WILLNEED);
10887#endif
10888
10889#ifdef POSIX_FADV_DONTNEED
10890 if (sym == sym_dontneed)
10891 return INT2NUM(POSIX_FADV_DONTNEED);
10892#endif
10893
10894#ifdef POSIX_FADV_NOREUSE
10895 if (sym == sym_noreuse)
10896 return INT2NUM(POSIX_FADV_NOREUSE);
10897#endif
10898
10899 return Qnil;
10900}
10901
10902static VALUE
10903do_io_advise(rb_io_t *fptr, VALUE advice, rb_off_t offset, rb_off_t len)
10904{
10905 int rv;
10906 struct io_advise_struct ias;
10907 VALUE num_adv;
10908
10909 num_adv = io_advise_sym_to_const(advice);
10910
10911 /*
10912 * The platform doesn't support this hint. We don't raise exception, instead
10913 * silently ignore it. Because IO::advise is only hint.
10914 */
10915 if (NIL_P(num_adv))
10916 return Qnil;
10917
10918 ias.fd = fptr->fd;
10919 ias.advice = NUM2INT(num_adv);
10920 ias.offset = offset;
10921 ias.len = len;
10922
10923 rv = (int)rb_io_blocking_region(fptr, io_advise_internal, &ias);
10924 if (rv && rv != ENOSYS) {
10925 /* posix_fadvise(2) doesn't set errno. On success it returns 0; otherwise
10926 it returns the error code. */
10927 VALUE message = rb_sprintf("%"PRIsVALUE" "
10928 "(%"PRI_OFFT_PREFIX"d, "
10929 "%"PRI_OFFT_PREFIX"d, "
10930 "%"PRIsVALUE")",
10931 fptr->pathv, offset, len, advice);
10932 rb_syserr_fail_str(rv, message);
10933 }
10934
10935 return Qnil;
10936}
10937
10938#endif /* HAVE_POSIX_FADVISE */
10939
10940static void
10941advice_arg_check(VALUE advice)
10942{
10943 if (!SYMBOL_P(advice))
10944 rb_raise(rb_eTypeError, "advice must be a Symbol");
10945
10946 if (advice != sym_normal &&
10947 advice != sym_sequential &&
10948 advice != sym_random &&
10949 advice != sym_willneed &&
10950 advice != sym_dontneed &&
10951 advice != sym_noreuse) {
10952 rb_raise(rb_eNotImpError, "Unsupported advice: %+"PRIsVALUE, advice);
10953 }
10954}
10955
10956/*
10957 * call-seq:
10958 * advise(advice, offset = 0, len = 0) -> nil
10959 *
10960 * Invokes Posix system call
10961 * {posix_fadvise(2)}[https://linux.die.net/man/2/posix_fadvise],
10962 * which announces an intention to access data from the current file
10963 * in a particular manner.
10964 *
10965 * The arguments and results are platform-dependent.
10966 *
10967 * The relevant data is specified by:
10968 *
10969 * - +offset+: The offset of the first byte of data.
10970 * - +len+: The number of bytes to be accessed;
10971 * if +len+ is zero, or is larger than the number of bytes remaining,
10972 * all remaining bytes will be accessed.
10973 *
10974 * Argument +advice+ is one of the following symbols:
10975 *
10976 * - +:normal+: The application has no advice to give
10977 * about its access pattern for the specified data.
10978 * If no advice is given for an open file, this is the default assumption.
10979 * - +:sequential+: The application expects to access the specified data sequentially
10980 * (with lower offsets read before higher ones).
10981 * - +:random+: The specified data will be accessed in random order.
10982 * - +:noreuse+: The specified data will be accessed only once.
10983 * - +:willneed+: The specified data will be accessed in the near future.
10984 * - +:dontneed+: The specified data will not be accessed in the near future.
10985 *
10986 * Not implemented on all platforms.
10987 *
10988 */
10989static VALUE
10990rb_io_advise(int argc, VALUE *argv, VALUE io)
10991{
10992 VALUE advice, offset, len;
10993 rb_off_t off, l;
10994 rb_io_t *fptr;
10995
10996 rb_scan_args(argc, argv, "12", &advice, &offset, &len);
10997 advice_arg_check(advice);
10998
10999 io = GetWriteIO(io);
11000 GetOpenFile(io, fptr);
11001
11002 off = NIL_P(offset) ? 0 : NUM2OFFT(offset);
11003 l = NIL_P(len) ? 0 : NUM2OFFT(len);
11004
11005#ifdef HAVE_POSIX_FADVISE
11006 return do_io_advise(fptr, advice, off, l);
11007#else
11008 ((void)off, (void)l); /* Ignore all hint */
11009 return Qnil;
11010#endif
11011}
11012
11013static int
11014is_pos_inf(VALUE x)
11015{
11016 double f;
11017 if (!RB_FLOAT_TYPE_P(x))
11018 return 0;
11019 f = RFLOAT_VALUE(x);
11020 return isinf(f) && 0 < f;
11021}
11022
11023/*
11024 * call-seq:
11025 * IO.select(read_ios, write_ios = [], error_ios = [], timeout = nil) -> array or nil
11026 *
11027 * Invokes system call {select(2)}[https://linux.die.net/man/2/select],
11028 * which monitors multiple file descriptors,
11029 * waiting until one or more of the file descriptors
11030 * becomes ready for some class of I/O operation.
11031 *
11032 * Not implemented on all platforms.
11033 *
11034 * Each of the arguments +read_ios+, +write_ios+, and +error_ios+
11035 * is an array of IO objects.
11036 *
11037 * Argument +timeout+ is a numeric value (such as integer or float) timeout
11038 * interval in seconds.
11039 * +timeout+ can also be +nil+ or +Float::INFINITY+.
11040 * +nil+ and +Float::INFINITY+ means no timeout.
11041 *
11042 * The method monitors the \IO objects given in all three arrays,
11043 * waiting for some to be ready;
11044 * returns a 3-element array whose elements are:
11045 *
11046 * - An array of the objects in +read_ios+ that are ready for reading.
11047 * - An array of the objects in +write_ios+ that are ready for writing.
11048 * - An array of the objects in +error_ios+ have pending exceptions.
11049 *
11050 * If no object becomes ready within the given +timeout+, +nil+ is returned.
11051 *
11052 * \IO.select peeks the buffer of \IO objects for testing readability.
11053 * If the \IO buffer is not empty, \IO.select immediately notifies
11054 * readability. This "peek" only happens for \IO objects. It does not
11055 * happen for IO-like objects such as OpenSSL::SSL::SSLSocket.
11056 *
11057 * The best way to use \IO.select is invoking it after non-blocking
11058 * methods such as #read_nonblock, #write_nonblock, etc. The methods
11059 * raise an exception which is extended by IO::WaitReadable or
11060 * IO::WaitWritable. The modules notify how the caller should wait
11061 * with \IO.select. If IO::WaitReadable is raised, the caller should
11062 * wait for reading. If IO::WaitWritable is raised, the caller should
11063 * wait for writing.
11064 *
11065 * So, blocking read (#readpartial) can be emulated using
11066 * #read_nonblock and \IO.select as follows:
11067 *
11068 * begin
11069 * result = io_like.read_nonblock(maxlen)
11070 * rescue IO::WaitReadable
11071 * IO.select([io_like])
11072 * retry
11073 * rescue IO::WaitWritable
11074 * IO.select(nil, [io_like])
11075 * retry
11076 * end
11077 *
11078 * Especially, the combination of non-blocking methods and \IO.select is
11079 * preferred for IO like objects such as OpenSSL::SSL::SSLSocket. It
11080 * has #to_io method to return underlying IO object. IO.select calls
11081 * #to_io to obtain the file descriptor to wait.
11082 *
11083 * This means that readability notified by \IO.select doesn't mean
11084 * readability from OpenSSL::SSL::SSLSocket object.
11085 *
11086 * The most likely situation is that OpenSSL::SSL::SSLSocket buffers
11087 * some data. \IO.select doesn't see the buffer. So \IO.select can
11088 * block when OpenSSL::SSL::SSLSocket#readpartial doesn't block.
11089 *
11090 * However, several more complicated situations exist.
11091 *
11092 * SSL is a protocol which is sequence of records.
11093 * The record consists of multiple bytes.
11094 * So, the remote side of SSL sends a partial record, IO.select
11095 * notifies readability but OpenSSL::SSL::SSLSocket cannot decrypt a
11096 * byte and OpenSSL::SSL::SSLSocket#readpartial will block.
11097 *
11098 * Also, the remote side can request SSL renegotiation which forces
11099 * the local SSL engine to write some data.
11100 * This means OpenSSL::SSL::SSLSocket#readpartial may invoke #write
11101 * system call and it can block.
11102 * In such a situation, OpenSSL::SSL::SSLSocket#read_nonblock raises
11103 * IO::WaitWritable instead of blocking.
11104 * So, the caller should wait for ready for writability as above
11105 * example.
11106 *
11107 * The combination of non-blocking methods and \IO.select is also useful
11108 * for streams such as tty, pipe socket socket when multiple processes
11109 * read from a stream.
11110 *
11111 * Finally, Linux kernel developers don't guarantee that
11112 * readability of select(2) means readability of following read(2) even
11113 * for a single process;
11114 * see {select(2)}[https://linux.die.net/man/2/select]
11115 *
11116 * Invoking \IO.select before IO#readpartial works well as usual.
11117 * However it is not the best way to use \IO.select.
11118 *
11119 * The writability notified by select(2) doesn't show
11120 * how many bytes are writable.
11121 * IO#write method blocks until given whole string is written.
11122 * So, <tt>IO#write(two or more bytes)</tt> can block after
11123 * writability is notified by \IO.select. IO#write_nonblock is required
11124 * to avoid the blocking.
11125 *
11126 * Blocking write (#write) can be emulated using #write_nonblock and
11127 * IO.select as follows: IO::WaitReadable should also be rescued for
11128 * SSL renegotiation in OpenSSL::SSL::SSLSocket.
11129 *
11130 * while 0 < string.bytesize
11131 * begin
11132 * written = io_like.write_nonblock(string)
11133 * rescue IO::WaitReadable
11134 * IO.select([io_like])
11135 * retry
11136 * rescue IO::WaitWritable
11137 * IO.select(nil, [io_like])
11138 * retry
11139 * end
11140 * string = string.byteslice(written..-1)
11141 * end
11142 *
11143 * Example:
11144 *
11145 * rp, wp = IO.pipe
11146 * mesg = "ping "
11147 * 100.times {
11148 * # IO.select follows IO#read. Not the best way to use IO.select.
11149 * rs, ws, = IO.select([rp], [wp])
11150 * if r = rs[0]
11151 * ret = r.read(5)
11152 * print ret
11153 * case ret
11154 * when /ping/
11155 * mesg = "pong\n"
11156 * when /pong/
11157 * mesg = "ping "
11158 * end
11159 * end
11160 * if w = ws[0]
11161 * w.write(mesg)
11162 * end
11163 * }
11164 *
11165 * Output:
11166 *
11167 * ping pong
11168 * ping pong
11169 * ping pong
11170 * (snipped)
11171 * ping
11172 *
11173 */
11174
11175static VALUE
11176rb_f_select(int argc, VALUE *argv, VALUE obj)
11177{
11178 VALUE scheduler = rb_fiber_scheduler_current();
11179 if (scheduler != Qnil) {
11180 // It's optionally supported.
11181 VALUE result = rb_fiber_scheduler_io_selectv(scheduler, argc, argv);
11182 if (!UNDEF_P(result)) return result;
11183 }
11184
11185 VALUE timeout;
11186 struct select_args args;
11187 struct timeval timerec;
11188 int i;
11189
11190 rb_scan_args(argc, argv, "13", &args.read, &args.write, &args.except, &timeout);
11191 if (NIL_P(timeout) || is_pos_inf(timeout)) {
11192 args.timeout = 0;
11193 }
11194 else {
11195 timerec = rb_time_interval(timeout);
11196 args.timeout = &timerec;
11197 }
11198
11199 for (i = 0; i < numberof(args.fdsets); ++i)
11200 rb_fd_init(&args.fdsets[i]);
11201
11202 return rb_ensure(select_call, (VALUE)&args, select_end, (VALUE)&args);
11203}
11204
11205#ifdef IOCTL_REQ_TYPE
11206 typedef IOCTL_REQ_TYPE ioctl_req_t;
11207#else
11208 typedef int ioctl_req_t;
11209# define NUM2IOCTLREQ(num) ((int)NUM2LONG(num))
11210#endif
11211
11212#ifdef HAVE_IOCTL
11213struct ioctl_arg {
11214 int fd;
11215 ioctl_req_t cmd;
11216 long narg;
11217};
11218
11219static VALUE
11220nogvl_ioctl(void *ptr)
11221{
11222 struct ioctl_arg *arg = ptr;
11223
11224 return (VALUE)ioctl(arg->fd, arg->cmd, arg->narg);
11225}
11226
11227static int
11228do_ioctl(struct rb_io *io, ioctl_req_t cmd, long narg)
11229{
11230 int retval;
11231 struct ioctl_arg arg;
11232
11233 arg.fd = io->fd;
11234 arg.cmd = cmd;
11235 arg.narg = narg;
11236
11237 retval = (int)rb_io_blocking_region(io, nogvl_ioctl, &arg);
11238
11239 return retval;
11240}
11241#endif
11242
11243#define DEFAULT_IOCTL_NARG_LEN (256)
11244
11245#if defined(__linux__) && defined(_IOC_SIZE)
11246static long
11247linux_iocparm_len(ioctl_req_t cmd)
11248{
11249 long len;
11250
11251 if ((cmd & 0xFFFF0000) == 0) {
11252 /* legacy and unstructured ioctl number. */
11253 return DEFAULT_IOCTL_NARG_LEN;
11254 }
11255
11256 len = _IOC_SIZE(cmd);
11257
11258 /* paranoia check for silly drivers which don't keep ioctl convention */
11259 if (len < DEFAULT_IOCTL_NARG_LEN)
11260 len = DEFAULT_IOCTL_NARG_LEN;
11261
11262 return len;
11263}
11264#endif
11265
11266#ifdef HAVE_IOCTL
11267static long
11268ioctl_narg_len(ioctl_req_t cmd)
11269{
11270 long len;
11271
11272#ifdef IOCPARM_MASK
11273#ifndef IOCPARM_LEN
11274#define IOCPARM_LEN(x) (((x) >> 16) & IOCPARM_MASK)
11275#endif
11276#endif
11277#ifdef IOCPARM_LEN
11278 len = IOCPARM_LEN(cmd); /* on BSDish systems we're safe */
11279#elif defined(__linux__) && defined(_IOC_SIZE)
11280 len = linux_iocparm_len(cmd);
11281#else
11282 /* otherwise guess at what's safe */
11283 len = DEFAULT_IOCTL_NARG_LEN;
11284#endif
11285
11286 return len;
11287}
11288#endif
11289
11290#ifdef HAVE_FCNTL
11291#ifdef __linux__
11292typedef long fcntl_arg_t;
11293#else
11294/* posix */
11295typedef int fcntl_arg_t;
11296#endif
11297
11298static long
11299fcntl_narg_len(ioctl_req_t cmd)
11300{
11301 long len;
11302
11303 switch (cmd) {
11304#ifdef F_DUPFD
11305 case F_DUPFD:
11306 len = sizeof(fcntl_arg_t);
11307 break;
11308#endif
11309#ifdef F_DUP2FD /* bsd specific */
11310 case F_DUP2FD:
11311 len = sizeof(int);
11312 break;
11313#endif
11314#ifdef F_DUPFD_CLOEXEC /* linux specific */
11315 case F_DUPFD_CLOEXEC:
11316 len = sizeof(fcntl_arg_t);
11317 break;
11318#endif
11319#ifdef F_GETFD
11320 case F_GETFD:
11321 len = 1;
11322 break;
11323#endif
11324#ifdef F_SETFD
11325 case F_SETFD:
11326 len = sizeof(fcntl_arg_t);
11327 break;
11328#endif
11329#ifdef F_GETFL
11330 case F_GETFL:
11331 len = 1;
11332 break;
11333#endif
11334#ifdef F_SETFL
11335 case F_SETFL:
11336 len = sizeof(fcntl_arg_t);
11337 break;
11338#endif
11339#ifdef F_GETOWN
11340 case F_GETOWN:
11341 len = 1;
11342 break;
11343#endif
11344#ifdef F_SETOWN
11345 case F_SETOWN:
11346 len = sizeof(fcntl_arg_t);
11347 break;
11348#endif
11349#ifdef F_GETOWN_EX /* linux specific */
11350 case F_GETOWN_EX:
11351 len = sizeof(struct f_owner_ex);
11352 break;
11353#endif
11354#ifdef F_SETOWN_EX /* linux specific */
11355 case F_SETOWN_EX:
11356 len = sizeof(struct f_owner_ex);
11357 break;
11358#endif
11359#ifdef F_GETLK
11360 case F_GETLK:
11361 len = sizeof(struct flock);
11362 break;
11363#endif
11364#ifdef F_SETLK
11365 case F_SETLK:
11366 len = sizeof(struct flock);
11367 break;
11368#endif
11369#ifdef F_SETLKW
11370 case F_SETLKW:
11371 len = sizeof(struct flock);
11372 break;
11373#endif
11374#ifdef F_READAHEAD /* bsd specific */
11375 case F_READAHEAD:
11376 len = sizeof(int);
11377 break;
11378#endif
11379#ifdef F_RDAHEAD /* Darwin specific */
11380 case F_RDAHEAD:
11381 len = sizeof(int);
11382 break;
11383#endif
11384#ifdef F_GETSIG /* linux specific */
11385 case F_GETSIG:
11386 len = 1;
11387 break;
11388#endif
11389#ifdef F_SETSIG /* linux specific */
11390 case F_SETSIG:
11391 len = sizeof(fcntl_arg_t);
11392 break;
11393#endif
11394#ifdef F_GETLEASE /* linux specific */
11395 case F_GETLEASE:
11396 len = 1;
11397 break;
11398#endif
11399#ifdef F_SETLEASE /* linux specific */
11400 case F_SETLEASE:
11401 len = sizeof(fcntl_arg_t);
11402 break;
11403#endif
11404#ifdef F_NOTIFY /* linux specific */
11405 case F_NOTIFY:
11406 len = sizeof(fcntl_arg_t);
11407 break;
11408#endif
11409
11410 default:
11411 len = 256;
11412 break;
11413 }
11414
11415 return len;
11416}
11417#else /* HAVE_FCNTL */
11418static long
11419fcntl_narg_len(ioctl_req_t cmd)
11420{
11421 return 0;
11422}
11423#endif /* HAVE_FCNTL */
11424
11425#define NARG_SENTINEL 17
11426
11427static long
11428setup_narg(ioctl_req_t cmd, VALUE *argp, long (*narg_len)(ioctl_req_t))
11429{
11430 long narg = 0;
11431 VALUE arg = *argp;
11432
11433 if (!RTEST(arg)) {
11434 narg = 0;
11435 }
11436 else if (FIXNUM_P(arg)) {
11437 narg = FIX2LONG(arg);
11438 }
11439 else if (arg == Qtrue) {
11440 narg = 1;
11441 }
11442 else {
11443 VALUE tmp = rb_check_string_type(arg);
11444
11445 if (NIL_P(tmp)) {
11446 narg = NUM2LONG(arg);
11447 }
11448 else {
11449 char *ptr;
11450 long len, slen;
11451
11452 *argp = arg = tmp;
11453 len = narg_len(cmd);
11454 rb_str_modify(arg);
11455
11456 slen = RSTRING_LEN(arg);
11457 /* expand for data + sentinel. */
11458 if (slen < len+1) {
11459 rb_str_resize(arg, len+1);
11460 MEMZERO(RSTRING_PTR(arg)+slen, char, len-slen);
11461 slen = len+1;
11462 }
11463 /* a little sanity check here */
11464 ptr = RSTRING_PTR(arg);
11465 ptr[slen - 1] = NARG_SENTINEL;
11466 narg = (long)(SIGNED_VALUE)ptr;
11467 }
11468 }
11469
11470 return narg;
11471}
11472
11473static VALUE
11474finish_narg(int retval, VALUE arg, const rb_io_t *fptr)
11475{
11476 if (retval < 0) rb_sys_fail_path(fptr->pathv);
11477 if (RB_TYPE_P(arg, T_STRING)) {
11478 char *ptr;
11479 long slen;
11480 RSTRING_GETMEM(arg, ptr, slen);
11481 if (ptr[slen-1] != NARG_SENTINEL)
11482 rb_raise(rb_eArgError, "return value overflowed string");
11483 ptr[slen-1] = '\0';
11484 }
11485
11486 return INT2NUM(retval);
11487}
11488
11489#ifdef HAVE_IOCTL
11490static VALUE
11491rb_ioctl(VALUE io, VALUE req, VALUE arg)
11492{
11493 ioctl_req_t cmd = NUM2IOCTLREQ(req);
11494 rb_io_t *fptr;
11495 long narg;
11496 int retval;
11497
11498 narg = setup_narg(cmd, &arg, ioctl_narg_len);
11499 GetOpenFile(io, fptr);
11500 retval = do_ioctl(fptr, cmd, narg);
11501 return finish_narg(retval, arg, fptr);
11502}
11503
11504/*
11505 * call-seq:
11506 * ioctl(integer_cmd, argument) -> integer
11507 *
11508 * Invokes Posix system call {ioctl(2)}[https://linux.die.net/man/2/ioctl],
11509 * which issues a low-level command to an I/O device.
11510 *
11511 * Issues a low-level command to an I/O device.
11512 * The arguments and returned value are platform-dependent.
11513 * The effect of the call is platform-dependent.
11514 *
11515 * If argument +argument+ is an integer, it is passed directly;
11516 * if it is a string, it is interpreted as a binary sequence of bytes.
11517 *
11518 * Not implemented on all platforms.
11519 *
11520 */
11521
11522static VALUE
11523rb_io_ioctl(int argc, VALUE *argv, VALUE io)
11524{
11525 VALUE req, arg;
11526
11527 rb_scan_args(argc, argv, "11", &req, &arg);
11528 return rb_ioctl(io, req, arg);
11529}
11530#else
11531#define rb_io_ioctl rb_f_notimplement
11532#endif
11533
11534#ifdef HAVE_FCNTL
11535struct fcntl_arg {
11536 int fd;
11537 int cmd;
11538 long narg;
11539};
11540
11541static VALUE
11542nogvl_fcntl(void *ptr)
11543{
11544 struct fcntl_arg *arg = ptr;
11545
11546#if defined(F_DUPFD)
11547 if (arg->cmd == F_DUPFD)
11548 return (VALUE)rb_cloexec_fcntl_dupfd(arg->fd, (int)arg->narg);
11549#endif
11550 return (VALUE)fcntl(arg->fd, arg->cmd, arg->narg);
11551}
11552
11553static int
11554do_fcntl(struct rb_io *io, int cmd, long narg)
11555{
11556 int retval;
11557 struct fcntl_arg arg;
11558
11559 arg.fd = io->fd;
11560 arg.cmd = cmd;
11561 arg.narg = narg;
11562
11563 retval = (int)rb_io_blocking_region(io, nogvl_fcntl, &arg);
11564 if (retval != -1) {
11565 switch (cmd) {
11566#if defined(F_DUPFD)
11567 case F_DUPFD:
11568#endif
11569#if defined(F_DUPFD_CLOEXEC)
11570 case F_DUPFD_CLOEXEC:
11571#endif
11572 rb_update_max_fd(retval);
11573 }
11574 }
11575
11576 return retval;
11577}
11578
11579static VALUE
11580rb_fcntl(VALUE io, VALUE req, VALUE arg)
11581{
11582 int cmd = NUM2INT(req);
11583 rb_io_t *fptr;
11584 long narg;
11585 int retval;
11586
11587 narg = setup_narg(cmd, &arg, fcntl_narg_len);
11588 GetOpenFile(io, fptr);
11589 retval = do_fcntl(fptr, cmd, narg);
11590 return finish_narg(retval, arg, fptr);
11591}
11592
11593/*
11594 * call-seq:
11595 * fcntl(integer_cmd, argument) -> integer
11596 *
11597 * Invokes Posix system call {fcntl(2)}[https://linux.die.net/man/2/fcntl],
11598 * which provides a mechanism for issuing low-level commands to control or query
11599 * a file-oriented I/O stream. Arguments and results are platform
11600 * dependent.
11601 *
11602 * If +argument+ is a number, its value is passed directly;
11603 * if it is a string, it is interpreted as a binary sequence of bytes.
11604 * (Array#pack might be a useful way to build this string.)
11605 *
11606 * Not implemented on all platforms.
11607 *
11608 */
11609
11610static VALUE
11611rb_io_fcntl(int argc, VALUE *argv, VALUE io)
11612{
11613 VALUE req, arg;
11614
11615 rb_scan_args(argc, argv, "11", &req, &arg);
11616 return rb_fcntl(io, req, arg);
11617}
11618#else
11619#define rb_io_fcntl rb_f_notimplement
11620#endif
11621
11622#if defined(HAVE_SYSCALL) || defined(HAVE___SYSCALL)
11623/*
11624 * call-seq:
11625 * syscall(integer_callno, *arguments) -> integer
11626 *
11627 * Invokes Posix system call {syscall(2)}[https://linux.die.net/man/2/syscall],
11628 * which calls a specified function.
11629 *
11630 * Calls the operating system function identified by +integer_callno+;
11631 * returns the result of the function or raises SystemCallError if it failed.
11632 * The effect of the call is platform-dependent.
11633 * The arguments and returned value are platform-dependent.
11634 *
11635 * For each of +arguments+: if it is an integer, it is passed directly;
11636 * if it is a string, it is interpreted as a binary sequence of bytes.
11637 * There may be as many as nine such arguments.
11638 *
11639 * Arguments +integer_callno+ and +argument+, as well as the returned value,
11640 * are platform-dependent.
11641 *
11642 * Note: Method +syscall+ is essentially unsafe and unportable.
11643 * The DL (Fiddle) library is preferred for safer and a bit
11644 * more portable programming.
11645 *
11646 * Not implemented on all platforms.
11647 *
11648 */
11649
11650static VALUE
11651rb_f_syscall(int argc, VALUE *argv, VALUE _)
11652{
11653 VALUE arg[8];
11654#if SIZEOF_VOIDP == 8 && defined(HAVE___SYSCALL) && SIZEOF_INT != 8 /* mainly *BSD */
11655# define SYSCALL __syscall
11656# define NUM2SYSCALLID(x) NUM2LONG(x)
11657# define RETVAL2NUM(x) LONG2NUM(x)
11658# if SIZEOF_LONG == 8
11659 long num, retval = -1;
11660# elif SIZEOF_LONG_LONG == 8
11661 long long num, retval = -1;
11662# else
11663# error ---->> it is asserted that __syscall takes the first argument and returns retval in 64bit signed integer. <<----
11664# endif
11665#elif defined(__linux__)
11666# define SYSCALL syscall
11667# define NUM2SYSCALLID(x) NUM2LONG(x)
11668# define RETVAL2NUM(x) LONG2NUM(x)
11669 /*
11670 * Linux man page says, syscall(2) function prototype is below.
11671 *
11672 * int syscall(int number, ...);
11673 *
11674 * But, it's incorrect. Actual one takes and returned long. (see unistd.h)
11675 */
11676 long num, retval = -1;
11677#else
11678# define SYSCALL syscall
11679# define NUM2SYSCALLID(x) NUM2INT(x)
11680# define RETVAL2NUM(x) INT2NUM(x)
11681 int num, retval = -1;
11682#endif
11683 int i;
11684
11685 if (RTEST(ruby_verbose)) {
11687 "We plan to remove a syscall function at future release. DL(Fiddle) provides safer alternative.");
11688 }
11689
11690 if (argc == 0)
11691 rb_raise(rb_eArgError, "too few arguments for syscall");
11692 if (argc > numberof(arg))
11693 rb_raise(rb_eArgError, "too many arguments for syscall");
11694 num = NUM2SYSCALLID(argv[0]); ++argv;
11695 for (i = argc - 1; i--; ) {
11696 VALUE v = rb_check_string_type(argv[i]);
11697
11698 if (!NIL_P(v)) {
11699 StringValue(v);
11700 rb_str_modify(v);
11701 arg[i] = (VALUE)StringValueCStr(v);
11702 }
11703 else {
11704 arg[i] = (VALUE)NUM2LONG(argv[i]);
11705 }
11706 }
11707
11708 switch (argc) {
11709 case 1:
11710 retval = SYSCALL(num);
11711 break;
11712 case 2:
11713 retval = SYSCALL(num, arg[0]);
11714 break;
11715 case 3:
11716 retval = SYSCALL(num, arg[0],arg[1]);
11717 break;
11718 case 4:
11719 retval = SYSCALL(num, arg[0],arg[1],arg[2]);
11720 break;
11721 case 5:
11722 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3]);
11723 break;
11724 case 6:
11725 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4]);
11726 break;
11727 case 7:
11728 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5]);
11729 break;
11730 case 8:
11731 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6]);
11732 break;
11733 }
11734
11735 if (retval == -1)
11736 rb_sys_fail(0);
11737 return RETVAL2NUM(retval);
11738#undef SYSCALL
11739#undef NUM2SYSCALLID
11740#undef RETVAL2NUM
11741}
11742#else
11743#define rb_f_syscall rb_f_notimplement
11744#endif
11745
11746static VALUE
11747io_new_instance(VALUE args)
11748{
11749 return rb_class_new_instance(2, (VALUE*)args+1, *(VALUE*)args);
11750}
11751
11752static rb_encoding *
11753find_encoding(VALUE v)
11754{
11755 rb_encoding *enc = rb_find_encoding(v);
11756 if (!enc) rb_warn("Unsupported encoding %"PRIsVALUE" ignored", v);
11757 return enc;
11758}
11759
11760static void
11761io_encoding_set(rb_io_t *fptr, VALUE v1, VALUE v2, VALUE opt)
11762{
11763 rb_encoding *enc, *enc2;
11764 int ecflags = fptr->encs.ecflags;
11765 VALUE ecopts, tmp;
11766
11767 if (!NIL_P(v2)) {
11768 enc2 = find_encoding(v1);
11769 tmp = rb_check_string_type(v2);
11770 if (!NIL_P(tmp)) {
11771 if (RSTRING_LEN(tmp) == 1 && RSTRING_PTR(tmp)[0] == '-') {
11772 /* Special case - "-" => no transcoding */
11773 enc = enc2;
11774 enc2 = NULL;
11775 }
11776 else
11777 enc = find_encoding(v2);
11778 if (enc == enc2) {
11779 /* Special case - "-" => no transcoding */
11780 enc2 = NULL;
11781 }
11782 }
11783 else {
11784 enc = find_encoding(v2);
11785 if (enc == enc2) {
11786 /* Special case - "-" => no transcoding */
11787 enc2 = NULL;
11788 }
11789 }
11790 if (enc2 == rb_ascii8bit_encoding()) {
11791 /* If external is ASCII-8BIT, no transcoding */
11792 enc = enc2;
11793 enc2 = NULL;
11794 }
11795 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11796 ecflags = rb_econv_prepare_options(opt, &ecopts, ecflags);
11797 }
11798 else {
11799 if (NIL_P(v1)) {
11800 /* Set to default encodings */
11801 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
11802 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11803 ecopts = Qnil;
11804 }
11805 else {
11806 tmp = rb_check_string_type(v1);
11807 if (!NIL_P(tmp) && rb_enc_asciicompat(enc = rb_enc_get(tmp))) {
11808 parse_mode_enc(RSTRING_PTR(tmp), enc, &enc, &enc2, NULL);
11809 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11810 ecflags = rb_econv_prepare_options(opt, &ecopts, ecflags);
11811 }
11812 else {
11813 rb_io_ext_int_to_encs(find_encoding(v1), NULL, &enc, &enc2, 0);
11814 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11815 ecopts = Qnil;
11816 }
11817 }
11818 }
11819 validate_enc_binmode(&fptr->mode, ecflags, enc, enc2);
11820 fptr->encs.enc = enc;
11821 fptr->encs.enc2 = enc2;
11822 fptr->encs.ecflags = ecflags;
11823 fptr->encs.ecopts = ecopts;
11824 clear_codeconv(fptr);
11825
11826}
11827
11829 rb_io_t *fptr;
11830 VALUE v1;
11831 VALUE v2;
11832 VALUE opt;
11833};
11834
11835static VALUE
11836io_encoding_set_v(VALUE v)
11837{
11838 struct io_encoding_set_args *arg = (struct io_encoding_set_args *)v;
11839 io_encoding_set(arg->fptr, arg->v1, arg->v2, arg->opt);
11840 return Qnil;
11841}
11842
11843static VALUE
11844pipe_pair_close(VALUE rw)
11845{
11846 VALUE *rwp = (VALUE *)rw;
11847 return rb_ensure(io_close, rwp[0], io_close, rwp[1]);
11848}
11849
11850/*
11851 * call-seq:
11852 * IO.pipe(**opts) -> [read_io, write_io]
11853 * IO.pipe(enc, **opts) -> [read_io, write_io]
11854 * IO.pipe(ext_enc, int_enc, **opts) -> [read_io, write_io]
11855 * IO.pipe(**opts) {|read_io, write_io| ...} -> object
11856 * IO.pipe(enc, **opts) {|read_io, write_io| ...} -> object
11857 * IO.pipe(ext_enc, int_enc, **opts) {|read_io, write_io| ...} -> object
11858 *
11859 * Creates a pair of pipe endpoints, +read_io+ and +write_io+,
11860 * connected to each other.
11861 *
11862 * If argument +enc_string+ is given, it must be a string containing one of:
11863 *
11864 * - The name of the encoding to be used as the external encoding.
11865 * - The colon-separated names of two encodings to be used as the external
11866 * and internal encodings.
11867 *
11868 * If argument +int_enc+ is given, it must be an Encoding object
11869 * or encoding name string that specifies the internal encoding to be used;
11870 * if argument +ext_enc+ is also given, it must be an Encoding object
11871 * or encoding name string that specifies the external encoding to be used.
11872 *
11873 * The string read from +read_io+ is tagged with the external encoding;
11874 * if an internal encoding is also specified, the string is converted
11875 * to, and tagged with, that encoding.
11876 *
11877 * If any encoding is specified,
11878 * optional hash arguments specify the conversion option.
11879 *
11880 * Optional keyword arguments +opts+ specify:
11881 *
11882 * - {Open Options}[rdoc-ref:IO@Open+Options].
11883 * - {Encoding Options}[rdoc-ref:encodings.rdoc@Encoding+Options].
11884 *
11885 * With no block given, returns the two endpoints in an array:
11886 *
11887 * IO.pipe # => [#<IO:fd 4>, #<IO:fd 5>]
11888 *
11889 * With a block given, calls the block with the two endpoints;
11890 * closes both endpoints and returns the value of the block:
11891 *
11892 * IO.pipe {|read_io, write_io| p read_io; p write_io }
11893 *
11894 * Output:
11895 *
11896 * #<IO:fd 6>
11897 * #<IO:fd 7>
11898 *
11899 * Not available on all platforms.
11900 *
11901 * In the example below, the two processes close the ends of the pipe
11902 * that they are not using. This is not just a cosmetic nicety. The
11903 * read end of a pipe will not generate an end of file condition if
11904 * there are any writers with the pipe still open. In the case of the
11905 * parent process, the <tt>rd.read</tt> will never return if it
11906 * does not first issue a <tt>wr.close</tt>:
11907 *
11908 * rd, wr = IO.pipe
11909 *
11910 * if fork
11911 * wr.close
11912 * puts "Parent got: <#{rd.read}>"
11913 * rd.close
11914 * Process.wait
11915 * else
11916 * rd.close
11917 * puts 'Sending message to parent'
11918 * wr.write "Hi Dad"
11919 * wr.close
11920 * end
11921 *
11922 * <em>produces:</em>
11923 *
11924 * Sending message to parent
11925 * Parent got: <Hi Dad>
11926 *
11927 */
11928
11929static VALUE
11930rb_io_s_pipe(int argc, VALUE *argv, VALUE klass)
11931{
11932 int pipes[2], state;
11933 VALUE r, w, args[3], v1, v2;
11934 VALUE opt;
11935 rb_io_t *fptr, *fptr2;
11936 struct io_encoding_set_args ies_args;
11937 enum rb_io_mode fmode = 0;
11938 VALUE ret;
11939
11940 argc = rb_scan_args(argc, argv, "02:", &v1, &v2, &opt);
11941 if (rb_pipe(pipes) < 0)
11942 rb_sys_fail(0);
11943
11944 args[0] = klass;
11945 args[1] = INT2NUM(pipes[0]);
11946 args[2] = INT2FIX(O_RDONLY);
11947 r = rb_protect(io_new_instance, (VALUE)args, &state);
11948 if (state) {
11949 close(pipes[0]);
11950 close(pipes[1]);
11951 rb_jump_tag(state);
11952 }
11953 GetOpenFile(r, fptr);
11954
11955 ies_args.fptr = fptr;
11956 ies_args.v1 = v1;
11957 ies_args.v2 = v2;
11958 ies_args.opt = opt;
11959 rb_protect(io_encoding_set_v, (VALUE)&ies_args, &state);
11960 if (state) {
11961 close(pipes[1]);
11962 io_close(r);
11963 rb_jump_tag(state);
11964 }
11965
11966 args[1] = INT2NUM(pipes[1]);
11967 args[2] = INT2FIX(O_WRONLY);
11968 w = rb_protect(io_new_instance, (VALUE)args, &state);
11969 if (state) {
11970 close(pipes[1]);
11971 if (!NIL_P(r)) rb_io_close(r);
11972 rb_jump_tag(state);
11973 }
11974 GetOpenFile(w, fptr2);
11975 rb_io_synchronized(fptr2);
11976
11977 extract_binmode(opt, &fmode);
11978
11979 if ((fmode & FMODE_BINMODE) && NIL_P(v1)) {
11982 }
11983
11984#if DEFAULT_TEXTMODE
11985 if ((fptr->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
11986 fptr->mode &= ~FMODE_TEXTMODE;
11987 setmode(fptr->fd, O_BINARY);
11988 }
11989#if RUBY_CRLF_ENVIRONMENT
11992 }
11993#endif
11994#endif
11995 fptr->mode |= fmode;
11996#if DEFAULT_TEXTMODE
11997 if ((fptr2->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
11998 fptr2->mode &= ~FMODE_TEXTMODE;
11999 setmode(fptr2->fd, O_BINARY);
12000 }
12001#endif
12002 fptr2->mode |= fmode;
12003
12004 ret = rb_assoc_new(r, w);
12005 if (rb_block_given_p()) {
12006 VALUE rw[2];
12007 rw[0] = r;
12008 rw[1] = w;
12009 return rb_ensure(rb_yield, ret, pipe_pair_close, (VALUE)rw);
12010 }
12011 return ret;
12012}
12013
12015 int argc;
12016 VALUE *argv;
12017 VALUE io;
12018};
12019
12020static void
12021open_key_args(VALUE klass, int argc, VALUE *argv, VALUE opt, struct foreach_arg *arg)
12022{
12023 VALUE path, v;
12024 VALUE vmode = Qnil, vperm = Qnil;
12025
12026 path = *argv++;
12027 argc--;
12028 FilePathValue(path);
12029 arg->io = 0;
12030 arg->argc = argc;
12031 arg->argv = argv;
12032 if (NIL_P(opt)) {
12033 vmode = INT2NUM(O_RDONLY);
12034 vperm = INT2FIX(0666);
12035 }
12036 else if (!NIL_P(v = rb_hash_aref(opt, sym_open_args))) {
12037 int n;
12038
12039 v = rb_to_array_type(v);
12040 n = RARRAY_LENINT(v);
12041 rb_check_arity(n, 0, 3); /* rb_io_open */
12042 rb_scan_args_kw(RB_SCAN_ARGS_LAST_HASH_KEYWORDS, n, RARRAY_CONST_PTR(v), "02:", &vmode, &vperm, &opt);
12043 }
12044 arg->io = rb_io_open(klass, path, vmode, vperm, opt);
12045}
12046
12047static VALUE
12048io_s_foreach(VALUE v)
12049{
12050 struct getline_arg *arg = (void *)v;
12051 VALUE str;
12052
12053 if (arg->limit == 0)
12054 rb_raise(rb_eArgError, "invalid limit: 0 for foreach");
12055 while (!NIL_P(str = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, arg->io))) {
12056 rb_lastline_set(str);
12057 rb_yield(str);
12058 }
12060 return Qnil;
12061}
12062
12063/*
12064 * call-seq:
12065 * IO.foreach(path, sep = $/, **opts) {|line| block } -> nil
12066 * IO.foreach(path, limit, **opts) {|line| block } -> nil
12067 * IO.foreach(path, sep, limit, **opts) {|line| block } -> nil
12068 * IO.foreach(...) -> an_enumerator
12069 *
12070 * Calls the block with each successive line read from the stream.
12071 *
12072 * When called from class \IO (but not subclasses of \IO),
12073 * this method has potential security vulnerabilities if called with untrusted input;
12074 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12075 *
12076 * The first argument must be a string that is the path to a file.
12077 *
12078 * With only argument +path+ given, parses lines from the file at the given +path+,
12079 * as determined by the default line separator,
12080 * and calls the block with each successive line:
12081 *
12082 * File.foreach('t.txt') {|line| p line }
12083 *
12084 * Output: the same as above.
12085 *
12086 * For both forms, command and path, the remaining arguments are the same.
12087 *
12088 * With argument +sep+ given, parses lines as determined by that line separator
12089 * (see {Line Separator}[rdoc-ref:IO@Line+Separator]):
12090 *
12091 * File.foreach('t.txt', 'li') {|line| p line }
12092 *
12093 * Output:
12094 *
12095 * "First li"
12096 * "ne\nSecond li"
12097 * "ne\n\nThird li"
12098 * "ne\nFourth li"
12099 * "ne\n"
12100 *
12101 * Each paragraph:
12102 *
12103 * File.foreach('t.txt', '') {|paragraph| p paragraph }
12104 *
12105 * Output:
12106 *
12107 * "First line\nSecond line\n\n"
12108 * "Third line\nFourth line\n"
12109 *
12110 * With argument +limit+ given, parses lines as determined by the default
12111 * line separator and the given line-length limit
12112 * (see {Line Separator}[rdoc-ref:IO@Line+Separator] and {Line Limit}[rdoc-ref:IO@Line+Limit]):
12113 *
12114 * File.foreach('t.txt', 7) {|line| p line }
12115 *
12116 * Output:
12117 *
12118 * "First l"
12119 * "ine\n"
12120 * "Second "
12121 * "line\n"
12122 * "\n"
12123 * "Third l"
12124 * "ine\n"
12125 * "Fourth l"
12126 * "line\n"
12127 *
12128 * With arguments +sep+ and +limit+ given,
12129 * combines the two behaviors
12130 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
12131 *
12132 * Optional keyword arguments +opts+ specify:
12133 *
12134 * - {Open Options}[rdoc-ref:IO@Open+Options].
12135 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12136 * - {Line Options}[rdoc-ref:IO@Line+IO].
12137 *
12138 * Returns an Enumerator if no block is given.
12139 *
12140 */
12141
12142static VALUE
12143rb_io_s_foreach(int argc, VALUE *argv, VALUE self)
12144{
12145 VALUE opt;
12146 int orig_argc = argc;
12147 struct foreach_arg arg;
12148 struct getline_arg garg;
12149
12150 argc = rb_scan_args(argc, argv, "12:", NULL, NULL, NULL, &opt);
12151 RETURN_ENUMERATOR(self, orig_argc, argv);
12152 extract_getline_args(argc-1, argv+1, &garg);
12153 open_key_args(self, argc, argv, opt, &arg);
12154 if (NIL_P(arg.io)) return Qnil;
12155 extract_getline_opts(opt, &garg);
12156 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12157 return rb_ensure(io_s_foreach, (VALUE)&garg, rb_io_close, arg.io);
12158}
12159
12160static VALUE
12161io_s_readlines(VALUE v)
12162{
12163 struct getline_arg *arg = (void *)v;
12164 return io_readlines(arg, arg->io);
12165}
12166
12167/*
12168 * call-seq:
12169 * IO.readlines(path, sep = $/, **opts) -> array
12170 * IO.readlines(path, limit, **opts) -> array
12171 * IO.readlines(path, sep, limit, **opts) -> array
12172 *
12173 * Returns an array of all lines read from the stream.
12174 *
12175 * When called from class \IO (but not subclasses of \IO),
12176 * this method has potential security vulnerabilities if called with untrusted input;
12177 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12178 *
12179 * The first argument must be a string that is the path to a file.
12180 *
12181 * With only argument +path+ given, parses lines from the file at the given +path+,
12182 * as determined by the default line separator,
12183 * and returns those lines in an array:
12184 *
12185 * IO.readlines('t.txt')
12186 * # => ["First line\n", "Second line\n", "\n", "Third line\n", "Fourth line\n"]
12187 *
12188 * With argument +sep+ given, parses lines as determined by that line separator
12189 * (see {Line Separator}[rdoc-ref:IO@Line+Separator]):
12190 *
12191 * # Ordinary separator.
12192 * IO.readlines('t.txt', 'li')
12193 * # =>["First li", "ne\nSecond li", "ne\n\nThird li", "ne\nFourth li", "ne\n"]
12194 * # Get-paragraphs separator.
12195 * IO.readlines('t.txt', '')
12196 * # => ["First line\nSecond line\n\n", "Third line\nFourth line\n"]
12197 * # Get-all separator.
12198 * IO.readlines('t.txt', nil)
12199 * # => ["First line\nSecond line\n\nThird line\nFourth line\n"]
12200 *
12201 * With argument +limit+ given, parses lines as determined by the default
12202 * line separator and the given line-length limit
12203 * (see {Line Separator}[rdoc-ref:IO@Line+Separator] and {Line Limit}[rdoc-ref:IO@Line+Limit]:
12204 *
12205 * IO.readlines('t.txt', 7)
12206 * # => ["First l", "ine\n", "Second ", "line\n", "\n", "Third l", "ine\n", "Fourth ", "line\n"]
12207 *
12208 * With arguments +sep+ and +limit+ given,
12209 * combines the two behaviors
12210 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
12211 *
12212 * Optional keyword arguments +opts+ specify:
12213 *
12214 * - {Open Options}[rdoc-ref:IO@Open+Options].
12215 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12216 * - {Line Options}[rdoc-ref:IO@Line+IO].
12217 *
12218 */
12219
12220static VALUE
12221rb_io_s_readlines(int argc, VALUE *argv, VALUE io)
12222{
12223 VALUE opt;
12224 struct foreach_arg arg;
12225 struct getline_arg garg;
12226
12227 argc = rb_scan_args(argc, argv, "12:", NULL, NULL, NULL, &opt);
12228 extract_getline_args(argc-1, argv+1, &garg);
12229 open_key_args(io, argc, argv, opt, &arg);
12230 if (NIL_P(arg.io)) return Qnil;
12231 extract_getline_opts(opt, &garg);
12232 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12233 return rb_ensure(io_s_readlines, (VALUE)&garg, rb_io_close, arg.io);
12234}
12235
12236static VALUE
12237io_s_read(VALUE v)
12238{
12239 struct foreach_arg *arg = (void *)v;
12240 return io_read(arg->argc, arg->argv, arg->io);
12241}
12242
12243struct seek_arg {
12244 VALUE io;
12245 VALUE offset;
12246 int mode;
12247};
12248
12249static VALUE
12250seek_before_access(VALUE argp)
12251{
12252 struct seek_arg *arg = (struct seek_arg *)argp;
12253 rb_io_binmode(arg->io);
12254 return rb_io_seek(arg->io, arg->offset, arg->mode);
12255}
12256
12257/*
12258 * call-seq:
12259 * IO.read(path, length = nil, offset = 0, **opts) -> string or nil
12260 *
12261 * Opens the stream, reads and returns some or all of its content,
12262 * and closes the stream; returns +nil+ if no bytes were read.
12263 *
12264 * When called from class \IO (but not subclasses of \IO),
12265 * this method has potential security vulnerabilities if called with untrusted input;
12266 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12267 *
12268 * The first argument must be a string that is the path to a file.
12269 *
12270 * With only argument +path+ given, reads in text mode and returns the entire content
12271 * of the file at the given path:
12272 *
12273 * IO.read('t.txt')
12274 * # => "First line\nSecond line\n\nThird line\nFourth line\n"
12275 *
12276 * On Windows, text mode can terminate reading and leave bytes in the file
12277 * unread when encountering certain special bytes. Consider using
12278 * IO.binread if all bytes in the file should be read.
12279 *
12280 * With argument +length+, returns +length+ bytes if available:
12281 *
12282 * IO.read('t.txt', 7) # => "First l"
12283 * IO.read('t.txt', 700)
12284 * # => "First line\r\nSecond line\r\n\r\nFourth line\r\nFifth line\r\n"
12285 *
12286 * With arguments +length+ and +offset+, returns +length+ bytes
12287 * if available, beginning at the given +offset+:
12288 *
12289 * IO.read('t.txt', 10, 2) # => "rst line\nS"
12290 * IO.read('t.txt', 10, 200) # => nil
12291 *
12292 * Optional keyword arguments +opts+ specify:
12293 *
12294 * - {Open Options}[rdoc-ref:IO@Open+Options].
12295 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12296 *
12297 */
12298
12299static VALUE
12300rb_io_s_read(int argc, VALUE *argv, VALUE io)
12301{
12302 VALUE opt, offset;
12303 long off;
12304 struct foreach_arg arg;
12305
12306 argc = rb_scan_args(argc, argv, "13:", NULL, NULL, &offset, NULL, &opt);
12307 if (!NIL_P(offset) && (off = NUM2LONG(offset)) < 0) {
12308 rb_raise(rb_eArgError, "negative offset %ld given", off);
12309 }
12310 open_key_args(io, argc, argv, opt, &arg);
12311 if (NIL_P(arg.io)) return Qnil;
12312 if (!NIL_P(offset)) {
12313 struct seek_arg sarg;
12314 int state = 0;
12315 sarg.io = arg.io;
12316 sarg.offset = offset;
12317 sarg.mode = SEEK_SET;
12318 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12319 if (state) {
12320 rb_io_close(arg.io);
12321 rb_jump_tag(state);
12322 }
12323 if (arg.argc == 2) arg.argc = 1;
12324 }
12325 return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
12326}
12327
12328/*
12329 * call-seq:
12330 * IO.binread(path, length = nil, offset = 0) -> string or nil
12331 *
12332 * Behaves like IO.read, except that the stream is opened in binary mode
12333 * with ASCII-8BIT encoding.
12334 *
12335 * When called from class \IO (but not subclasses of \IO),
12336 * this method has potential security vulnerabilities if called with untrusted input;
12337 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12338 *
12339 */
12340
12341static VALUE
12342rb_io_s_binread(int argc, VALUE *argv, VALUE io)
12343{
12344 VALUE offset;
12345 struct foreach_arg arg;
12346 enum rb_io_mode fmode = FMODE_READABLE|FMODE_BINMODE;
12347 enum {
12348 oflags = O_RDONLY
12349#ifdef O_BINARY
12350 |O_BINARY
12351#endif
12352 };
12353 struct rb_io_encoding convconfig = {NULL, NULL, 0, Qnil};
12354
12355 rb_scan_args(argc, argv, "12", NULL, NULL, &offset);
12356 FilePathValue(argv[0]);
12357 convconfig.enc = rb_ascii8bit_encoding();
12358 arg.io = rb_io_open_generic(io, argv[0], oflags, fmode, &convconfig, 0);
12359 if (NIL_P(arg.io)) return Qnil;
12360 arg.argv = argv+1;
12361 arg.argc = (argc > 1) ? 1 : 0;
12362 if (!NIL_P(offset)) {
12363 struct seek_arg sarg;
12364 int state = 0;
12365 sarg.io = arg.io;
12366 sarg.offset = offset;
12367 sarg.mode = SEEK_SET;
12368 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12369 if (state) {
12370 rb_io_close(arg.io);
12371 rb_jump_tag(state);
12372 }
12373 }
12374 return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
12375}
12376
12377static VALUE
12378io_s_write0(VALUE v)
12379{
12380 struct write_arg *arg = (void *)v;
12381 return io_write(arg->io,arg->str,arg->nosync);
12382}
12383
12384static VALUE
12385io_s_write(int argc, VALUE *argv, VALUE klass, int binary)
12386{
12387 VALUE string, offset, opt;
12388 struct foreach_arg arg;
12389 struct write_arg warg;
12390
12391 rb_scan_args(argc, argv, "21:", NULL, &string, &offset, &opt);
12392
12393 if (NIL_P(opt)) opt = rb_hash_new();
12394 else opt = rb_hash_dup(opt);
12395
12396
12397 if (NIL_P(rb_hash_aref(opt,sym_mode))) {
12398 int mode = O_WRONLY|O_CREAT;
12399#ifdef O_BINARY
12400 if (binary) mode |= O_BINARY;
12401#endif
12402 if (NIL_P(offset)) mode |= O_TRUNC;
12403 rb_hash_aset(opt,sym_mode,INT2NUM(mode));
12404 }
12405 open_key_args(klass, argc, argv, opt, &arg);
12406
12407#ifndef O_BINARY
12408 if (binary) rb_io_binmode_m(arg.io);
12409#endif
12410
12411 if (NIL_P(arg.io)) return Qnil;
12412 if (!NIL_P(offset)) {
12413 struct seek_arg sarg;
12414 int state = 0;
12415 sarg.io = arg.io;
12416 sarg.offset = offset;
12417 sarg.mode = SEEK_SET;
12418 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12419 if (state) {
12420 rb_io_close(arg.io);
12421 rb_jump_tag(state);
12422 }
12423 }
12424
12425 warg.io = arg.io;
12426 warg.str = string;
12427 warg.nosync = 0;
12428
12429 return rb_ensure(io_s_write0, (VALUE)&warg, rb_io_close, arg.io);
12430}
12431
12432/*
12433 * call-seq:
12434 * IO.write(path, data, offset = 0, **opts) -> integer
12435 *
12436 * Opens the stream, writes the given +data+ to it,
12437 * and closes the stream; returns the number of bytes written.
12438 *
12439 * When called from class \IO (but not subclasses of \IO),
12440 * this method has potential security vulnerabilities if called with untrusted input;
12441 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12442 *
12443 * The first argument must be a string that is the path to a file.
12444 *
12445 * With only argument +path+ given, writes the given +data+ to the file at that path:
12446 *
12447 * IO.write('t.tmp', 'abc') # => 3
12448 * File.read('t.tmp') # => "abc"
12449 *
12450 * If +offset+ is zero (the default), the file is overwritten:
12451 *
12452 * IO.write('t.tmp', 'A') # => 1
12453 * File.read('t.tmp') # => "A"
12454 *
12455 * If +offset+ in within the file content, the file is partly overwritten:
12456 *
12457 * IO.write('t.tmp', 'abcdef') # => 3
12458 * File.read('t.tmp') # => "abcdef"
12459 * # Offset within content.
12460 * IO.write('t.tmp', '012', 2) # => 3
12461 * File.read('t.tmp') # => "ab012f"
12462 *
12463 * If +offset+ is outside the file content,
12464 * the file is padded with null characters <tt>"\u0000"</tt>:
12465 *
12466 * IO.write('t.tmp', 'xyz', 10) # => 3
12467 * File.read('t.tmp') # => "ab012f\u0000\u0000\u0000\u0000xyz"
12468 *
12469 * Optional keyword arguments +opts+ specify:
12470 *
12471 * - {Open Options}[rdoc-ref:IO@Open+Options].
12472 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12473 *
12474 */
12475
12476static VALUE
12477rb_io_s_write(int argc, VALUE *argv, VALUE io)
12478{
12479 return io_s_write(argc, argv, io, 0);
12480}
12481
12482/*
12483 * call-seq:
12484 * IO.binwrite(path, string, offset = 0) -> integer
12485 *
12486 * Behaves like IO.write, except that the stream is opened in binary mode
12487 * with ASCII-8BIT encoding.
12488 *
12489 * When called from class \IO (but not subclasses of \IO),
12490 * this method has potential security vulnerabilities if called with untrusted input;
12491 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12492 *
12493 */
12494
12495static VALUE
12496rb_io_s_binwrite(int argc, VALUE *argv, VALUE io)
12497{
12498 return io_s_write(argc, argv, io, 1);
12499}
12500
12502 VALUE src;
12503 VALUE dst;
12504 rb_off_t copy_length; /* (rb_off_t)-1 if not specified */
12505 rb_off_t src_offset; /* (rb_off_t)-1 if not specified */
12506
12507 rb_io_t *src_fptr;
12508 rb_io_t *dst_fptr;
12509 unsigned close_src : 1;
12510 unsigned close_dst : 1;
12511 int error_no;
12512 rb_off_t total;
12513 const char *syserr;
12514 const char *notimp;
12515 VALUE th;
12516 struct stat src_stat;
12517 struct stat dst_stat;
12518#ifdef HAVE_FCOPYFILE
12519 copyfile_state_t copyfile_state;
12520#endif
12521};
12522
12523static void *
12524exec_interrupts(void *arg)
12525{
12526 VALUE th = (VALUE)arg;
12527 rb_thread_execute_interrupts(th);
12528 return NULL;
12529}
12530
12531/*
12532 * returns TRUE if the preceding system call was interrupted
12533 * so we can continue. If the thread was interrupted, we
12534 * reacquire the GVL to execute interrupts before continuing.
12535 */
12536static int
12537maygvl_copy_stream_continue_p(int has_gvl, struct copy_stream_struct *stp)
12538{
12539 switch (errno) {
12540 case EINTR:
12541#if defined(ERESTART)
12542 case ERESTART:
12543#endif
12544 if (rb_thread_interrupted(stp->th)) {
12545 if (has_gvl)
12546 rb_thread_execute_interrupts(stp->th);
12547 else
12548 rb_thread_call_with_gvl(exec_interrupts, (void *)stp->th);
12549 }
12550 return TRUE;
12551 }
12552 return FALSE;
12553}
12554
12556 VALUE scheduler;
12557
12558 rb_io_t *fptr;
12559 short events;
12560
12561 VALUE result;
12562};
12563
12564static void *
12565fiber_scheduler_wait_for(void * _arguments)
12566{
12567 struct fiber_scheduler_wait_for_arguments *arguments = (struct fiber_scheduler_wait_for_arguments *)_arguments;
12568
12569 arguments->result = rb_fiber_scheduler_io_wait(arguments->scheduler, arguments->fptr->self, INT2NUM(arguments->events), RUBY_IO_TIMEOUT_DEFAULT);
12570
12571 return NULL;
12572}
12573
12574#if USE_POLL
12575# define IOWAIT_SYSCALL "poll"
12576STATIC_ASSERT(pollin_expected, POLLIN == RB_WAITFD_IN);
12577STATIC_ASSERT(pollout_expected, POLLOUT == RB_WAITFD_OUT);
12578static int
12579nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout)
12580{
12582 if (scheduler != Qnil) {
12583 struct fiber_scheduler_wait_for_arguments args = {.scheduler = scheduler, .fptr = fptr, .events = events};
12584 rb_thread_call_with_gvl(fiber_scheduler_wait_for, &args);
12585 return RTEST(args.result);
12586 }
12587
12588 int fd = fptr->fd;
12589 if (fd == -1) return 0;
12590
12591 struct pollfd fds;
12592
12593 fds.fd = fd;
12594 fds.events = events;
12595
12596 int timeout_milliseconds = -1;
12597
12598 if (timeout) {
12599 timeout_milliseconds = (int)(timeout->tv_sec * 1000) + (int)(timeout->tv_usec / 1000);
12600 }
12601
12602 return poll(&fds, 1, timeout_milliseconds);
12603}
12604#else /* !USE_POLL */
12605# define IOWAIT_SYSCALL "select"
12606static int
12607nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout)
12608{
12610 if (scheduler != Qnil) {
12611 struct fiber_scheduler_wait_for_arguments args = {.scheduler = scheduler, .fptr = fptr, .events = events};
12612 rb_thread_call_with_gvl(fiber_scheduler_wait_for, &args);
12613 return RTEST(args.result);
12614 }
12615
12616 int fd = fptr->fd;
12617
12618 if (fd == -1) {
12619 errno = EBADF;
12620 return -1;
12621 }
12622
12623 rb_fdset_t fds;
12624 int ret;
12625
12626 rb_fd_init(&fds);
12627 rb_fd_set(fd, &fds);
12628
12629 switch (events) {
12630 case RB_WAITFD_IN:
12631 ret = rb_fd_select(fd + 1, &fds, 0, 0, timeout);
12632 break;
12633 case RB_WAITFD_OUT:
12634 ret = rb_fd_select(fd + 1, 0, &fds, 0, timeout);
12635 break;
12636 default:
12637 VM_UNREACHABLE(nogvl_wait_for);
12638 }
12639
12640 rb_fd_term(&fds);
12641
12642 // On timeout, this returns 0.
12643 return ret;
12644}
12645#endif /* !USE_POLL */
12646
12647static int
12648maygvl_copy_stream_wait_read(int has_gvl, struct copy_stream_struct *stp)
12649{
12650 int ret;
12651
12652 do {
12653 if (has_gvl) {
12655 }
12656 else {
12657 ret = nogvl_wait_for(stp->th, stp->src_fptr, RB_WAITFD_IN, NULL);
12658 }
12659 } while (ret < 0 && maygvl_copy_stream_continue_p(has_gvl, stp));
12660
12661 if (ret < 0) {
12662 stp->syserr = IOWAIT_SYSCALL;
12663 stp->error_no = errno;
12664 return ret;
12665 }
12666 return 0;
12667}
12668
12669static int
12670nogvl_copy_stream_wait_write(struct copy_stream_struct *stp)
12671{
12672 int ret;
12673
12674 do {
12675 ret = nogvl_wait_for(stp->th, stp->dst_fptr, RB_WAITFD_OUT, NULL);
12676 } while (ret < 0 && maygvl_copy_stream_continue_p(0, stp));
12677
12678 if (ret < 0) {
12679 stp->syserr = IOWAIT_SYSCALL;
12680 stp->error_no = errno;
12681 return ret;
12682 }
12683 return 0;
12684}
12685
12686#ifdef USE_COPY_FILE_RANGE
12687
12688static ssize_t
12689simple_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)
12690{
12691#ifdef HAVE_COPY_FILE_RANGE
12692 return copy_file_range(in_fd, in_offset, out_fd, out_offset, count, flags);
12693#else
12694 return syscall(__NR_copy_file_range, in_fd, in_offset, out_fd, out_offset, count, flags);
12695#endif
12696}
12697
12698static int
12699nogvl_copy_file_range(struct copy_stream_struct *stp)
12700{
12701 ssize_t ss;
12702 rb_off_t src_size;
12703 rb_off_t copy_length, src_offset, *src_offset_ptr;
12704
12705 if (!S_ISREG(stp->src_stat.st_mode))
12706 return 0;
12707
12708 src_size = stp->src_stat.st_size;
12709 src_offset = stp->src_offset;
12710 if (src_offset >= (rb_off_t)0) {
12711 src_offset_ptr = &src_offset;
12712 }
12713 else {
12714 src_offset_ptr = NULL; /* if src_offset_ptr is NULL, then bytes are read from in_fd starting from the file offset */
12715 }
12716
12717 copy_length = stp->copy_length;
12718 if (copy_length < (rb_off_t)0) {
12719 if (src_offset < (rb_off_t)0) {
12720 rb_off_t current_offset;
12721 errno = 0;
12722 current_offset = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12723 if (current_offset < (rb_off_t)0 && errno) {
12724 stp->syserr = "lseek";
12725 stp->error_no = errno;
12726 return (int)current_offset;
12727 }
12728 copy_length = src_size - current_offset;
12729 }
12730 else {
12731 copy_length = src_size - src_offset;
12732 }
12733 }
12734
12735 retry_copy_file_range:
12736# if SIZEOF_OFF_T > SIZEOF_SIZE_T
12737 /* we are limited by the 32-bit ssize_t return value on 32-bit */
12738 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
12739# else
12740 ss = (ssize_t)copy_length;
12741# endif
12742 ss = simple_copy_file_range(stp->src_fptr->fd, src_offset_ptr, stp->dst_fptr->fd, NULL, ss, 0);
12743 if (0 < ss) {
12744 stp->total += ss;
12745 copy_length -= ss;
12746 if (0 < copy_length) {
12747 goto retry_copy_file_range;
12748 }
12749 }
12750 if (ss < 0) {
12751 if (maygvl_copy_stream_continue_p(0, stp)) {
12752 goto retry_copy_file_range;
12753 }
12754 switch (errno) {
12755 case EINVAL:
12756 case EPERM: /* copy_file_range(2) doesn't exist (may happen in
12757 docker container) */
12758#ifdef ENOSYS
12759 case ENOSYS:
12760#endif
12761#ifdef EXDEV
12762 case EXDEV: /* in_fd and out_fd are not on the same filesystem */
12763#endif
12764 return 0;
12765 case EAGAIN:
12766#if EWOULDBLOCK != EAGAIN
12767 case EWOULDBLOCK:
12768#endif
12769 {
12770 int ret = nogvl_copy_stream_wait_write(stp);
12771 if (ret < 0) return ret;
12772 }
12773 goto retry_copy_file_range;
12774 case EBADF:
12775 {
12776 int e = errno;
12777 int flags = fcntl(stp->dst_fptr->fd, F_GETFL);
12778
12779 if (flags != -1 && flags & O_APPEND) {
12780 return 0;
12781 }
12782 errno = e;
12783 }
12784 }
12785 stp->syserr = "copy_file_range";
12786 stp->error_no = errno;
12787 return (int)ss;
12788 }
12789 return 1;
12790}
12791#endif
12792
12793#ifdef HAVE_FCOPYFILE
12794static int
12795nogvl_fcopyfile(struct copy_stream_struct *stp)
12796{
12797 rb_off_t cur, ss = 0;
12798 const rb_off_t src_offset = stp->src_offset;
12799 int ret;
12800
12801 if (stp->copy_length >= (rb_off_t)0) {
12802 /* copy_length can't be specified in fcopyfile(3) */
12803 return 0;
12804 }
12805
12806 if (!S_ISREG(stp->src_stat.st_mode))
12807 return 0;
12808
12809 if (!S_ISREG(stp->dst_stat.st_mode))
12810 return 0;
12811 if (lseek(stp->dst_fptr->fd, 0, SEEK_CUR) > (rb_off_t)0) /* if dst IO was already written */
12812 return 0;
12813 if (fcntl(stp->dst_fptr->fd, F_GETFL) & O_APPEND) {
12814 /* fcopyfile(3) appends src IO to dst IO and then truncates
12815 * dst IO to src IO's original size. */
12816 rb_off_t end = lseek(stp->dst_fptr->fd, 0, SEEK_END);
12817 lseek(stp->dst_fptr->fd, 0, SEEK_SET);
12818 if (end > (rb_off_t)0) return 0;
12819 }
12820
12821 if (src_offset > (rb_off_t)0) {
12822 rb_off_t r;
12823
12824 /* get current offset */
12825 errno = 0;
12826 cur = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12827 if (cur < (rb_off_t)0 && errno) {
12828 stp->error_no = errno;
12829 return 1;
12830 }
12831
12832 errno = 0;
12833 r = lseek(stp->src_fptr->fd, src_offset, SEEK_SET);
12834 if (r < (rb_off_t)0 && errno) {
12835 stp->error_no = errno;
12836 return 1;
12837 }
12838 }
12839
12840 stp->copyfile_state = copyfile_state_alloc(); /* this will be freed by copy_stream_finalize() */
12841 ret = fcopyfile(stp->src_fptr->fd, stp->dst_fptr->fd, stp->copyfile_state, COPYFILE_DATA);
12842 copyfile_state_get(stp->copyfile_state, COPYFILE_STATE_COPIED, &ss); /* get copied bytes */
12843
12844 if (ret == 0) { /* success */
12845 stp->total = ss;
12846 if (src_offset > (rb_off_t)0) {
12847 rb_off_t r;
12848 errno = 0;
12849 /* reset offset */
12850 r = lseek(stp->src_fptr->fd, cur, SEEK_SET);
12851 if (r < (rb_off_t)0 && errno) {
12852 stp->error_no = errno;
12853 return 1;
12854 }
12855 }
12856 }
12857 else {
12858 switch (errno) {
12859 case ENOTSUP:
12860 case EPERM:
12861 case EINVAL:
12862 return 0;
12863 }
12864 stp->syserr = "fcopyfile";
12865 stp->error_no = errno;
12866 return (int)ret;
12867 }
12868 return 1;
12869}
12870#endif
12871
12872#ifdef HAVE_SENDFILE
12873
12874# ifdef __linux__
12875# define USE_SENDFILE
12876
12877# ifdef HAVE_SYS_SENDFILE_H
12878# include <sys/sendfile.h>
12879# endif
12880
12881static ssize_t
12882simple_sendfile(int out_fd, int in_fd, rb_off_t *offset, rb_off_t count)
12883{
12884 return sendfile(out_fd, in_fd, offset, (size_t)count);
12885}
12886
12887# elif 0 /* defined(__FreeBSD__) || defined(__DragonFly__) */ || defined(__APPLE__)
12888/* This runs on FreeBSD8.1 r30210, but sendfiles blocks its execution
12889 * without cpuset -l 0.
12890 */
12891# define USE_SENDFILE
12892
12893static ssize_t
12894simple_sendfile(int out_fd, int in_fd, rb_off_t *offset, rb_off_t count)
12895{
12896 int r;
12897 rb_off_t pos = offset ? *offset : lseek(in_fd, 0, SEEK_CUR);
12898 rb_off_t sbytes;
12899# ifdef __APPLE__
12900 r = sendfile(in_fd, out_fd, pos, &count, NULL, 0);
12901 sbytes = count;
12902# else
12903 r = sendfile(in_fd, out_fd, pos, (size_t)count, NULL, &sbytes, 0);
12904# endif
12905 if (r != 0 && sbytes == 0) return r;
12906 if (offset) {
12907 *offset += sbytes;
12908 }
12909 else {
12910 lseek(in_fd, sbytes, SEEK_CUR);
12911 }
12912 return (ssize_t)sbytes;
12913}
12914
12915# endif
12916
12917#endif
12918
12919#ifdef USE_SENDFILE
12920static int
12921nogvl_copy_stream_sendfile(struct copy_stream_struct *stp)
12922{
12923 ssize_t ss;
12924 rb_off_t src_size;
12925 rb_off_t copy_length;
12926 rb_off_t src_offset;
12927 int use_pread;
12928
12929 if (!S_ISREG(stp->src_stat.st_mode))
12930 return 0;
12931
12932 src_size = stp->src_stat.st_size;
12933#ifndef __linux__
12934 if ((stp->dst_stat.st_mode & S_IFMT) != S_IFSOCK)
12935 return 0;
12936#endif
12937
12938 src_offset = stp->src_offset;
12939 use_pread = src_offset >= (rb_off_t)0;
12940
12941 copy_length = stp->copy_length;
12942 if (copy_length < (rb_off_t)0) {
12943 if (use_pread)
12944 copy_length = src_size - src_offset;
12945 else {
12946 rb_off_t cur;
12947 errno = 0;
12948 cur = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12949 if (cur < (rb_off_t)0 && errno) {
12950 stp->syserr = "lseek";
12951 stp->error_no = errno;
12952 return (int)cur;
12953 }
12954 copy_length = src_size - cur;
12955 }
12956 }
12957
12958 retry_sendfile:
12959# if SIZEOF_OFF_T > SIZEOF_SIZE_T
12960 /* we are limited by the 32-bit ssize_t return value on 32-bit */
12961 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
12962# else
12963 ss = (ssize_t)copy_length;
12964# endif
12965 if (use_pread) {
12966 ss = simple_sendfile(stp->dst_fptr->fd, stp->src_fptr->fd, &src_offset, ss);
12967 }
12968 else {
12969 ss = simple_sendfile(stp->dst_fptr->fd, stp->src_fptr->fd, NULL, ss);
12970 }
12971 if (0 < ss) {
12972 stp->total += ss;
12973 copy_length -= ss;
12974 if (0 < copy_length) {
12975 goto retry_sendfile;
12976 }
12977 }
12978 if (ss < 0) {
12979 if (maygvl_copy_stream_continue_p(0, stp))
12980 goto retry_sendfile;
12981 switch (errno) {
12982 case EINVAL:
12983#ifdef ENOSYS
12984 case ENOSYS:
12985#endif
12986#ifdef EOPNOTSUP
12987 /* some RedHat kernels may return EOPNOTSUP on an NFS mount.
12988 see also: [Feature #16965] */
12989 case EOPNOTSUP:
12990#endif
12991 return 0;
12992 case EAGAIN:
12993#if EWOULDBLOCK != EAGAIN
12994 case EWOULDBLOCK:
12995#endif
12996 {
12997 int ret;
12998#ifndef __linux__
12999 /*
13000 * Linux requires stp->src_fptr->fd to be a mmap-able (regular) file,
13001 * select() reports regular files to always be "ready", so
13002 * there is no need to select() on it.
13003 * Other OSes may have the same limitation for sendfile() which
13004 * allow us to bypass maygvl_copy_stream_wait_read()...
13005 */
13006 ret = maygvl_copy_stream_wait_read(0, stp);
13007 if (ret < 0) return ret;
13008#endif
13009 ret = nogvl_copy_stream_wait_write(stp);
13010 if (ret < 0) return ret;
13011 }
13012 goto retry_sendfile;
13013 }
13014 stp->syserr = "sendfile";
13015 stp->error_no = errno;
13016 return (int)ss;
13017 }
13018 return 1;
13019}
13020#endif
13021
13022static ssize_t
13023maygvl_read(int has_gvl, rb_io_t *fptr, void *buf, size_t count)
13024{
13025 if (has_gvl)
13026 return rb_io_read_memory(fptr, buf, count);
13027 else
13028 return read(fptr->fd, buf, count);
13029}
13030
13031static ssize_t
13032maygvl_copy_stream_read(int has_gvl, struct copy_stream_struct *stp, char *buf, size_t len, rb_off_t offset)
13033{
13034 ssize_t ss;
13035 retry_read:
13036 if (offset < (rb_off_t)0) {
13037 ss = maygvl_read(has_gvl, stp->src_fptr, buf, len);
13038 }
13039 else {
13040 ss = pread(stp->src_fptr->fd, buf, len, offset);
13041 }
13042 if (ss == 0) {
13043 return 0;
13044 }
13045 if (ss < 0) {
13046 if (maygvl_copy_stream_continue_p(has_gvl, stp))
13047 goto retry_read;
13048 switch (errno) {
13049 case EAGAIN:
13050#if EWOULDBLOCK != EAGAIN
13051 case EWOULDBLOCK:
13052#endif
13053 {
13054 int ret = maygvl_copy_stream_wait_read(has_gvl, stp);
13055 if (ret < 0) return ret;
13056 }
13057 goto retry_read;
13058#ifdef ENOSYS
13059 case ENOSYS:
13060 stp->notimp = "pread";
13061 return ss;
13062#endif
13063 }
13064 stp->syserr = offset < (rb_off_t)0 ? "read" : "pread";
13065 stp->error_no = errno;
13066 }
13067 return ss;
13068}
13069
13070static int
13071nogvl_copy_stream_write(struct copy_stream_struct *stp, char *buf, size_t len)
13072{
13073 ssize_t ss;
13074 int off = 0;
13075 while (len) {
13076 ss = write(stp->dst_fptr->fd, buf+off, len);
13077 if (ss < 0) {
13078 if (maygvl_copy_stream_continue_p(0, stp))
13079 continue;
13080 if (io_again_p(errno)) {
13081 int ret = nogvl_copy_stream_wait_write(stp);
13082 if (ret < 0) return ret;
13083 continue;
13084 }
13085 stp->syserr = "write";
13086 stp->error_no = errno;
13087 return (int)ss;
13088 }
13089 off += (int)ss;
13090 len -= (int)ss;
13091 stp->total += ss;
13092 }
13093 return 0;
13094}
13095
13096static void
13097nogvl_copy_stream_read_write(struct copy_stream_struct *stp)
13098{
13099 char buf[1024*16];
13100 size_t len;
13101 ssize_t ss;
13102 int ret;
13103 rb_off_t copy_length;
13104 rb_off_t src_offset;
13105 int use_eof;
13106 int use_pread;
13107
13108 copy_length = stp->copy_length;
13109 use_eof = copy_length < (rb_off_t)0;
13110 src_offset = stp->src_offset;
13111 use_pread = src_offset >= (rb_off_t)0;
13112
13113 if (use_pread && stp->close_src) {
13114 rb_off_t r;
13115 errno = 0;
13116 r = lseek(stp->src_fptr->fd, src_offset, SEEK_SET);
13117 if (r < (rb_off_t)0 && errno) {
13118 stp->syserr = "lseek";
13119 stp->error_no = errno;
13120 return;
13121 }
13122 src_offset = (rb_off_t)-1;
13123 use_pread = 0;
13124 }
13125
13126 while (use_eof || 0 < copy_length) {
13127 if (!use_eof && copy_length < (rb_off_t)sizeof(buf)) {
13128 len = (size_t)copy_length;
13129 }
13130 else {
13131 len = sizeof(buf);
13132 }
13133 if (use_pread) {
13134 ss = maygvl_copy_stream_read(0, stp, buf, len, src_offset);
13135 if (0 < ss)
13136 src_offset += ss;
13137 }
13138 else {
13139 ss = maygvl_copy_stream_read(0, stp, buf, len, (rb_off_t)-1);
13140 }
13141 if (ss <= 0) /* EOF or error */
13142 return;
13143
13144 ret = nogvl_copy_stream_write(stp, buf, ss);
13145 if (ret < 0)
13146 return;
13147
13148 if (!use_eof)
13149 copy_length -= ss;
13150 }
13151}
13152
13153static void *
13154nogvl_copy_stream_func(void *arg)
13155{
13156 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13157#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13158 int ret;
13159#endif
13160
13161#ifdef USE_COPY_FILE_RANGE
13162 ret = nogvl_copy_file_range(stp);
13163 if (ret != 0)
13164 goto finish; /* error or success */
13165#endif
13166
13167#ifdef HAVE_FCOPYFILE
13168 ret = nogvl_fcopyfile(stp);
13169 if (ret != 0)
13170 goto finish; /* error or success */
13171#endif
13172
13173#ifdef USE_SENDFILE
13174 ret = nogvl_copy_stream_sendfile(stp);
13175 if (ret != 0)
13176 goto finish; /* error or success */
13177#endif
13178
13179 nogvl_copy_stream_read_write(stp);
13180
13181#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13182 finish:
13183#endif
13184 return 0;
13185}
13186
13187static VALUE
13188copy_stream_fallback_body(VALUE arg)
13189{
13190 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13191 const int buflen = 16*1024;
13192 VALUE n;
13193 VALUE buf = rb_str_buf_new(buflen);
13194 rb_off_t rest = stp->copy_length;
13195 rb_off_t off = stp->src_offset;
13196 ID read_method = id_readpartial;
13197
13198 if (!stp->src_fptr) {
13199 if (!rb_respond_to(stp->src, read_method)) {
13200 read_method = id_read;
13201 }
13202 }
13203
13204 while (1) {
13205 long numwrote;
13206 long l;
13207 rb_str_make_independent(buf);
13208 if (stp->copy_length < (rb_off_t)0) {
13209 l = buflen;
13210 }
13211 else {
13212 if (rest == 0) {
13213 rb_str_resize(buf, 0);
13214 break;
13215 }
13216 l = buflen < rest ? buflen : (long)rest;
13217 }
13218 if (!stp->src_fptr) {
13219 VALUE rc = rb_funcall(stp->src, read_method, 2, INT2FIX(l), buf);
13220
13221 if (read_method == id_read && NIL_P(rc))
13222 break;
13223 }
13224 else {
13225 ssize_t ss;
13226 rb_str_resize(buf, buflen);
13227 ss = maygvl_copy_stream_read(1, stp, RSTRING_PTR(buf), l, off);
13228 rb_str_resize(buf, ss > 0 ? ss : 0);
13229 if (ss < 0)
13230 return Qnil;
13231 if (ss == 0)
13232 rb_eof_error();
13233 if (off >= (rb_off_t)0)
13234 off += ss;
13235 }
13236 n = rb_io_write(stp->dst, buf);
13237 numwrote = NUM2LONG(n);
13238 stp->total += numwrote;
13239 rest -= numwrote;
13240 if (read_method == id_read && RSTRING_LEN(buf) == 0) {
13241 break;
13242 }
13243 }
13244
13245 return Qnil;
13246}
13247
13248static VALUE
13249copy_stream_fallback(struct copy_stream_struct *stp)
13250{
13251 if (!stp->src_fptr && stp->src_offset >= (rb_off_t)0) {
13252 rb_raise(rb_eArgError, "cannot specify src_offset for non-IO");
13253 }
13254 rb_rescue2(copy_stream_fallback_body, (VALUE)stp,
13255 (VALUE (*) (VALUE, VALUE))0, (VALUE)0,
13256 rb_eEOFError, (VALUE)0);
13257 return Qnil;
13258}
13259
13260static VALUE
13261copy_stream_body(VALUE arg)
13262{
13263 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13264 VALUE src_io = stp->src, dst_io = stp->dst;
13265 const int common_oflags = 0
13266#ifdef O_NOCTTY
13267 | O_NOCTTY
13268#endif
13269 ;
13270
13271 stp->th = rb_thread_current();
13272
13273 stp->total = 0;
13274
13275 if (src_io == argf ||
13276 !(RB_TYPE_P(src_io, T_FILE) ||
13277 RB_TYPE_P(src_io, T_STRING) ||
13278 rb_respond_to(src_io, rb_intern("to_path")))) {
13279 stp->src_fptr = NULL;
13280 }
13281 else {
13282 int stat_ret;
13283 VALUE tmp_io = rb_io_check_io(src_io);
13284 if (!NIL_P(tmp_io)) {
13285 src_io = tmp_io;
13286 }
13287 else if (!RB_TYPE_P(src_io, T_FILE)) {
13288 VALUE args[2];
13289 FilePathValue(src_io);
13290 args[0] = src_io;
13291 args[1] = INT2NUM(O_RDONLY|common_oflags);
13292 src_io = rb_class_new_instance(2, args, rb_cFile);
13293 stp->src = src_io;
13294 stp->close_src = 1;
13295 }
13296 RB_IO_POINTER(src_io, stp->src_fptr);
13297 rb_io_check_byte_readable(stp->src_fptr);
13298
13299 stat_ret = fstat(stp->src_fptr->fd, &stp->src_stat);
13300 if (stat_ret < 0) {
13301 stp->syserr = "fstat";
13302 stp->error_no = errno;
13303 return Qnil;
13304 }
13305 }
13306
13307 if (dst_io == argf ||
13308 !(RB_TYPE_P(dst_io, T_FILE) ||
13309 RB_TYPE_P(dst_io, T_STRING) ||
13310 rb_respond_to(dst_io, rb_intern("to_path")))) {
13311 stp->dst_fptr = NULL;
13312 }
13313 else {
13314 int stat_ret;
13315 VALUE tmp_io = rb_io_check_io(dst_io);
13316 if (!NIL_P(tmp_io)) {
13317 dst_io = GetWriteIO(tmp_io);
13318 }
13319 else if (!RB_TYPE_P(dst_io, T_FILE)) {
13320 VALUE args[3];
13321 FilePathValue(dst_io);
13322 args[0] = dst_io;
13323 args[1] = INT2NUM(O_WRONLY|O_CREAT|O_TRUNC|common_oflags);
13324 args[2] = INT2FIX(0666);
13325 dst_io = rb_class_new_instance(3, args, rb_cFile);
13326 stp->dst = dst_io;
13327 stp->close_dst = 1;
13328 }
13329 else {
13330 dst_io = GetWriteIO(dst_io);
13331 stp->dst = dst_io;
13332 }
13333 RB_IO_POINTER(dst_io, stp->dst_fptr);
13334 rb_io_check_writable(stp->dst_fptr);
13335
13336 stat_ret = fstat(stp->dst_fptr->fd, &stp->dst_stat);
13337 if (stat_ret < 0) {
13338 stp->syserr = "fstat";
13339 stp->error_no = errno;
13340 return Qnil;
13341 }
13342 }
13343
13344#ifdef O_BINARY
13345 if (stp->src_fptr)
13346 SET_BINARY_MODE_WITH_SEEK_CUR(stp->src_fptr);
13347#endif
13348 if (stp->dst_fptr)
13349 io_ascii8bit_binmode(stp->dst_fptr);
13350
13351 if (stp->src_offset < (rb_off_t)0 && stp->src_fptr && stp->src_fptr->rbuf.len) {
13352 size_t len = stp->src_fptr->rbuf.len;
13353 VALUE str;
13354 if (stp->copy_length >= (rb_off_t)0 && stp->copy_length < (rb_off_t)len) {
13355 len = (size_t)stp->copy_length;
13356 }
13357 str = rb_str_buf_new(len);
13358 rb_str_resize(str,len);
13359 read_buffered_data(RSTRING_PTR(str), len, stp->src_fptr);
13360 if (stp->dst_fptr) { /* IO or filename */
13361 if (io_binwrite(RSTRING_PTR(str), RSTRING_LEN(str), stp->dst_fptr, 0) < 0)
13362 rb_sys_fail_on_write(stp->dst_fptr);
13363 }
13364 else /* others such as StringIO */
13365 rb_io_write(dst_io, str);
13366 rb_str_resize(str, 0);
13367 stp->total += len;
13368 if (stp->copy_length >= (rb_off_t)0)
13369 stp->copy_length -= len;
13370 }
13371
13372 if (stp->dst_fptr && io_fflush(stp->dst_fptr) < 0) {
13373 rb_raise(rb_eIOError, "flush failed");
13374 }
13375
13376 if (stp->copy_length == 0)
13377 return Qnil;
13378
13379 if (stp->src_fptr == NULL || stp->dst_fptr == NULL) {
13380 return copy_stream_fallback(stp);
13381 }
13382
13383 IO_WITHOUT_GVL(nogvl_copy_stream_func, stp);
13384 return Qnil;
13385}
13386
13387static VALUE
13388copy_stream_finalize(VALUE arg)
13389{
13390 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13391
13392#ifdef HAVE_FCOPYFILE
13393 if (stp->copyfile_state) {
13394 copyfile_state_free(stp->copyfile_state);
13395 }
13396#endif
13397
13398 if (stp->close_src) {
13399 rb_io_close_m(stp->src);
13400 }
13401 if (stp->close_dst) {
13402 rb_io_close_m(stp->dst);
13403 }
13404 if (stp->syserr) {
13405 rb_syserr_fail(stp->error_no, stp->syserr);
13406 }
13407 if (stp->notimp) {
13408 rb_raise(rb_eNotImpError, "%s() not implemented", stp->notimp);
13409 }
13410 return Qnil;
13411}
13412
13413/*
13414 * call-seq:
13415 * IO.copy_stream(src, dst, src_length = nil, src_offset = 0) -> integer
13416 *
13417 * Copies from the given +src+ to the given +dst+,
13418 * returning the number of bytes copied.
13419 *
13420 * - The given +src+ must be one of the following:
13421 *
13422 * - The path to a readable file, from which source data is to be read.
13423 * - An \IO-like object, opened for reading and capable of responding
13424 * to method +:readpartial+ or method +:read+.
13425 *
13426 * - The given +dst+ must be one of the following:
13427 *
13428 * - The path to a writable file, to which data is to be written.
13429 * - An \IO-like object, opened for writing and capable of responding
13430 * to method +:write+.
13431 *
13432 * The examples here use file <tt>t.txt</tt> as source:
13433 *
13434 * File.read('t.txt')
13435 * # => "First line\nSecond line\n\nThird line\nFourth line\n"
13436 * File.read('t.txt').size # => 47
13437 *
13438 * If only arguments +src+ and +dst+ are given,
13439 * the entire source stream is copied:
13440 *
13441 * # Paths.
13442 * IO.copy_stream('t.txt', 't.tmp') # => 47
13443 *
13444 * # IOs (recall that a File is also an IO).
13445 * src_io = File.open('t.txt', 'r') # => #<File:t.txt>
13446 * dst_io = File.open('t.tmp', 'w') # => #<File:t.tmp>
13447 * IO.copy_stream(src_io, dst_io) # => 47
13448 * src_io.close
13449 * dst_io.close
13450 *
13451 * With argument +src_length+ a non-negative integer,
13452 * no more than that many bytes are copied:
13453 *
13454 * IO.copy_stream('t.txt', 't.tmp', 10) # => 10
13455 * File.read('t.tmp') # => "First line"
13456 *
13457 * With argument +src_offset+ also given,
13458 * the source stream is read beginning at that offset:
13459 *
13460 * IO.copy_stream('t.txt', 't.tmp', 11, 11) # => 11
13461 * IO.read('t.tmp') # => "Second line"
13462 *
13463 */
13464static VALUE
13465rb_io_s_copy_stream(int argc, VALUE *argv, VALUE io)
13466{
13467 VALUE src, dst, length, src_offset;
13468 struct copy_stream_struct st;
13469
13470 MEMZERO(&st, struct copy_stream_struct, 1);
13471
13472 rb_scan_args(argc, argv, "22", &src, &dst, &length, &src_offset);
13473
13474 st.src = src;
13475 st.dst = dst;
13476
13477 st.src_fptr = NULL;
13478 st.dst_fptr = NULL;
13479
13480 if (NIL_P(length))
13481 st.copy_length = (rb_off_t)-1;
13482 else
13483 st.copy_length = NUM2OFFT(length);
13484
13485 if (NIL_P(src_offset))
13486 st.src_offset = (rb_off_t)-1;
13487 else
13488 st.src_offset = NUM2OFFT(src_offset);
13489
13490 rb_ensure(copy_stream_body, (VALUE)&st, copy_stream_finalize, (VALUE)&st);
13491
13492 return OFFT2NUM(st.total);
13493}
13494
13495/*
13496 * call-seq:
13497 * external_encoding -> encoding or nil
13498 *
13499 * Returns the Encoding object that represents the encoding of the stream,
13500 * or +nil+ if the stream is in write mode and no encoding is specified.
13501 *
13502 * See {Encodings}[rdoc-ref:File@Encodings].
13503 *
13504 */
13505
13506static VALUE
13507rb_io_external_encoding(VALUE io)
13508{
13509 rb_io_t *fptr = RFILE(rb_io_taint_check(io))->fptr;
13510
13511 if (fptr->encs.enc2) {
13512 return rb_enc_from_encoding(fptr->encs.enc2);
13513 }
13514 if (fptr->mode & FMODE_WRITABLE) {
13515 if (fptr->encs.enc)
13516 return rb_enc_from_encoding(fptr->encs.enc);
13517 return Qnil;
13518 }
13519 return rb_enc_from_encoding(io_read_encoding(fptr));
13520}
13521
13522/*
13523 * call-seq:
13524 * internal_encoding -> encoding or nil
13525 *
13526 * Returns the Encoding object that represents the encoding of the internal string,
13527 * if conversion is specified,
13528 * or +nil+ otherwise.
13529 *
13530 * See {Encodings}[rdoc-ref:File@Encodings].
13531 *
13532 */
13533
13534static VALUE
13535rb_io_internal_encoding(VALUE io)
13536{
13537 rb_io_t *fptr = RFILE(rb_io_taint_check(io))->fptr;
13538
13539 if (!fptr->encs.enc2) return Qnil;
13540 return rb_enc_from_encoding(io_read_encoding(fptr));
13541}
13542
13543/*
13544 * call-seq:
13545 * set_encoding(ext_enc) -> self
13546 * set_encoding(ext_enc, int_enc, **enc_opts) -> self
13547 * set_encoding('ext_enc:int_enc', **enc_opts) -> self
13548 *
13549 * See {Encodings}[rdoc-ref:File@Encodings].
13550 *
13551 * Argument +ext_enc+, if given, must be an Encoding object
13552 * or a String with the encoding name;
13553 * it is assigned as the encoding for the stream.
13554 *
13555 * Argument +int_enc+, if given, must be an Encoding object
13556 * or a String with the encoding name;
13557 * it is assigned as the encoding for the internal string.
13558 *
13559 * Argument <tt>'ext_enc:int_enc'</tt>, if given, is a string
13560 * containing two colon-separated encoding names;
13561 * corresponding Encoding objects are assigned as the external
13562 * and internal encodings for the stream.
13563 *
13564 * If the external encoding of a string is binary/ASCII-8BIT,
13565 * the internal encoding of the string is set to nil, since no
13566 * transcoding is needed.
13567 *
13568 * Optional keyword arguments +enc_opts+ specify
13569 * {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
13570 *
13571 */
13572
13573static VALUE
13574rb_io_set_encoding(int argc, VALUE *argv, VALUE io)
13575{
13576 rb_io_t *fptr;
13577 VALUE v1, v2, opt;
13578
13579 if (!RB_TYPE_P(io, T_FILE)) {
13580 return forward(io, id_set_encoding, argc, argv);
13581 }
13582
13583 argc = rb_scan_args(argc, argv, "11:", &v1, &v2, &opt);
13584 GetOpenFile(io, fptr);
13585 io_encoding_set(fptr, v1, v2, opt);
13586 return io;
13587}
13588
13589void
13590rb_stdio_set_default_encoding(void)
13591{
13592 VALUE val = Qnil;
13593
13594#ifdef _WIN32
13595 if (isatty(fileno(stdin))) {
13596 rb_encoding *external = rb_locale_encoding();
13597 rb_encoding *internal = rb_default_internal_encoding();
13598 if (!internal) internal = rb_default_external_encoding();
13599 io_encoding_set(RFILE(rb_stdin)->fptr,
13600 rb_enc_from_encoding(external),
13601 rb_enc_from_encoding(internal),
13602 Qnil);
13603 }
13604 else
13605#endif
13606 rb_io_set_encoding(1, &val, rb_stdin);
13607 rb_io_set_encoding(1, &val, rb_stdout);
13608 rb_io_set_encoding(1, &val, rb_stderr);
13609}
13610
13611static inline int
13612global_argf_p(VALUE arg)
13613{
13614 return arg == argf;
13615}
13616
13617typedef VALUE (*argf_encoding_func)(VALUE io);
13618
13619static VALUE
13620argf_encoding(VALUE argf, argf_encoding_func func)
13621{
13622 if (!RTEST(ARGF.current_file)) {
13623 return rb_enc_default_external();
13624 }
13625 return func(rb_io_check_io(ARGF.current_file));
13626}
13627
13628/*
13629 * call-seq:
13630 * ARGF.external_encoding -> encoding
13631 *
13632 * Returns the external encoding for files read from ARGF as an Encoding
13633 * object. The external encoding is the encoding of the text as stored in a
13634 * file. Contrast with ARGF.internal_encoding, which is the encoding used to
13635 * represent this text within Ruby.
13636 *
13637 * To set the external encoding use ARGF.set_encoding.
13638 *
13639 * For example:
13640 *
13641 * ARGF.external_encoding #=> #<Encoding:UTF-8>
13642 *
13643 */
13644static VALUE
13645argf_external_encoding(VALUE argf)
13646{
13647 return argf_encoding(argf, rb_io_external_encoding);
13648}
13649
13650/*
13651 * call-seq:
13652 * ARGF.internal_encoding -> encoding
13653 *
13654 * Returns the internal encoding for strings read from ARGF as an
13655 * Encoding object.
13656 *
13657 * If ARGF.set_encoding has been called with two encoding names, the second
13658 * is returned. Otherwise, if +Encoding.default_external+ has been set, that
13659 * value is returned. Failing that, if a default external encoding was
13660 * specified on the command-line, that value is used. If the encoding is
13661 * unknown, +nil+ is returned.
13662 */
13663static VALUE
13664argf_internal_encoding(VALUE argf)
13665{
13666 return argf_encoding(argf, rb_io_internal_encoding);
13667}
13668
13669/*
13670 * call-seq:
13671 * ARGF.set_encoding(ext_enc) -> ARGF
13672 * ARGF.set_encoding("ext_enc:int_enc") -> ARGF
13673 * ARGF.set_encoding(ext_enc, int_enc) -> ARGF
13674 * ARGF.set_encoding("ext_enc:int_enc", opt) -> ARGF
13675 * ARGF.set_encoding(ext_enc, int_enc, opt) -> ARGF
13676 *
13677 * If single argument is specified, strings read from ARGF are tagged with
13678 * the encoding specified.
13679 *
13680 * If two encoding names separated by a colon are given, e.g. "ascii:utf-8",
13681 * the read string is converted from the first encoding (external encoding)
13682 * to the second encoding (internal encoding), then tagged with the second
13683 * encoding.
13684 *
13685 * If two arguments are specified, they must be encoding objects or encoding
13686 * names. Again, the first specifies the external encoding; the second
13687 * specifies the internal encoding.
13688 *
13689 * If the external encoding and the internal encoding are specified, the
13690 * optional Hash argument can be used to adjust the conversion process. The
13691 * structure of this hash is explained in the String#encode documentation.
13692 *
13693 * For example:
13694 *
13695 * ARGF.set_encoding('ascii') # Tag the input as US-ASCII text
13696 * ARGF.set_encoding(Encoding::UTF_8) # Tag the input as UTF-8 text
13697 * ARGF.set_encoding('utf-8','ascii') # Transcode the input from US-ASCII
13698 * # to UTF-8.
13699 */
13700static VALUE
13701argf_set_encoding(int argc, VALUE *argv, VALUE argf)
13702{
13703 rb_io_t *fptr;
13704
13705 if (!next_argv()) {
13706 rb_raise(rb_eArgError, "no stream to set encoding");
13707 }
13708 rb_io_set_encoding(argc, argv, ARGF.current_file);
13709 GetOpenFile(ARGF.current_file, fptr);
13710 ARGF.encs = fptr->encs;
13711 return argf;
13712}
13713
13714/*
13715 * call-seq:
13716 * ARGF.tell -> Integer
13717 * ARGF.pos -> Integer
13718 *
13719 * Returns the current offset (in bytes) of the current file in ARGF.
13720 *
13721 * ARGF.pos #=> 0
13722 * ARGF.gets #=> "This is line one\n"
13723 * ARGF.pos #=> 17
13724 *
13725 */
13726static VALUE
13727argf_tell(VALUE argf)
13728{
13729 if (!next_argv()) {
13730 rb_raise(rb_eArgError, "no stream to tell");
13731 }
13732 ARGF_FORWARD(0, 0);
13733 return rb_io_tell(ARGF.current_file);
13734}
13735
13736/*
13737 * call-seq:
13738 * ARGF.seek(amount, whence=IO::SEEK_SET) -> 0
13739 *
13740 * Seeks to offset _amount_ (an Integer) in the ARGF stream according to
13741 * the value of _whence_. See IO#seek for further details.
13742 */
13743static VALUE
13744argf_seek_m(int argc, VALUE *argv, VALUE argf)
13745{
13746 if (!next_argv()) {
13747 rb_raise(rb_eArgError, "no stream to seek");
13748 }
13749 ARGF_FORWARD(argc, argv);
13750 return rb_io_seek_m(argc, argv, ARGF.current_file);
13751}
13752
13753/*
13754 * call-seq:
13755 * ARGF.pos = position -> Integer
13756 *
13757 * Seeks to the position given by _position_ (in bytes) in ARGF.
13758 *
13759 * For example:
13760 *
13761 * ARGF.pos = 17
13762 * ARGF.gets #=> "This is line two\n"
13763 */
13764static VALUE
13765argf_set_pos(VALUE argf, VALUE offset)
13766{
13767 if (!next_argv()) {
13768 rb_raise(rb_eArgError, "no stream to set position");
13769 }
13770 ARGF_FORWARD(1, &offset);
13771 return rb_io_set_pos(ARGF.current_file, offset);
13772}
13773
13774/*
13775 * call-seq:
13776 * ARGF.rewind -> 0
13777 *
13778 * Positions the current file to the beginning of input, resetting
13779 * ARGF.lineno to zero.
13780 *
13781 * ARGF.readline #=> "This is line one\n"
13782 * ARGF.rewind #=> 0
13783 * ARGF.lineno #=> 0
13784 * ARGF.readline #=> "This is line one\n"
13785 */
13786static VALUE
13787argf_rewind(VALUE argf)
13788{
13789 VALUE ret;
13790 int old_lineno;
13791
13792 if (!next_argv()) {
13793 rb_raise(rb_eArgError, "no stream to rewind");
13794 }
13795 ARGF_FORWARD(0, 0);
13796 old_lineno = RFILE(ARGF.current_file)->fptr->lineno;
13797 ret = rb_io_rewind(ARGF.current_file);
13798 if (!global_argf_p(argf)) {
13799 ARGF.last_lineno = ARGF.lineno -= old_lineno;
13800 }
13801 return ret;
13802}
13803
13804/*
13805 * call-seq:
13806 * ARGF.fileno -> integer
13807 * ARGF.to_i -> integer
13808 *
13809 * Returns an integer representing the numeric file descriptor for
13810 * the current file. Raises an ArgumentError if there isn't a current file.
13811 *
13812 * ARGF.fileno #=> 3
13813 */
13814static VALUE
13815argf_fileno(VALUE argf)
13816{
13817 if (!next_argv()) {
13818 rb_raise(rb_eArgError, "no stream");
13819 }
13820 ARGF_FORWARD(0, 0);
13821 return rb_io_fileno(ARGF.current_file);
13822}
13823
13824/*
13825 * call-seq:
13826 * ARGF.to_io -> IO
13827 *
13828 * Returns an IO object representing the current file. This will be a
13829 * File object unless the current file is a stream such as STDIN.
13830 *
13831 * For example:
13832 *
13833 * ARGF.to_io #=> #<File:glark.txt>
13834 * ARGF.to_io #=> #<IO:<STDIN>>
13835 */
13836static VALUE
13837argf_to_io(VALUE argf)
13838{
13839 next_argv();
13840 ARGF_FORWARD(0, 0);
13841 return ARGF.current_file;
13842}
13843
13844/*
13845 * call-seq:
13846 * ARGF.eof? -> true or false
13847 * ARGF.eof -> true or false
13848 *
13849 * Returns true if the current file in ARGF is at end of file, i.e. it has
13850 * no data to read. The stream must be opened for reading or an IOError
13851 * will be raised.
13852 *
13853 * $ echo "eof" | ruby argf.rb
13854 *
13855 * ARGF.eof? #=> false
13856 * 3.times { ARGF.readchar }
13857 * ARGF.eof? #=> false
13858 * ARGF.readchar #=> "\n"
13859 * ARGF.eof? #=> true
13860 */
13861
13862static VALUE
13863argf_eof(VALUE argf)
13864{
13865 next_argv();
13866 if (RTEST(ARGF.current_file)) {
13867 if (ARGF.init_p == 0) return Qtrue;
13868 next_argv();
13869 ARGF_FORWARD(0, 0);
13870 if (rb_io_eof(ARGF.current_file)) {
13871 return Qtrue;
13872 }
13873 }
13874 return Qfalse;
13875}
13876
13877/*
13878 * call-seq:
13879 * ARGF.read([length [, outbuf]]) -> string, outbuf, or nil
13880 *
13881 * Reads _length_ bytes from ARGF. The files named on the command line
13882 * are concatenated and treated as a single file by this method, so when
13883 * called without arguments the contents of this pseudo file are returned in
13884 * their entirety.
13885 *
13886 * _length_ must be a non-negative integer or +nil+.
13887 *
13888 * If _length_ is a positive integer, +read+ tries to read
13889 * _length_ bytes without any conversion (binary mode).
13890 * It returns +nil+ if an EOF is encountered before anything can be read.
13891 * Fewer than _length_ bytes are returned if an EOF is encountered during
13892 * the read.
13893 * In the case of an integer _length_, the resulting string is always
13894 * in ASCII-8BIT encoding.
13895 *
13896 * If _length_ is omitted or is +nil+, it reads until EOF
13897 * and the encoding conversion is applied, if applicable.
13898 * A string is returned even if EOF is encountered before any data is read.
13899 *
13900 * If _length_ is zero, it returns an empty string (<code>""</code>).
13901 *
13902 * If the optional _outbuf_ argument is present,
13903 * it must reference a String, which will receive the data.
13904 * The _outbuf_ will contain only the received data after the method call
13905 * even if it is not empty at the beginning.
13906 *
13907 * For example:
13908 *
13909 * $ echo "small" > small.txt
13910 * $ echo "large" > large.txt
13911 * $ ./glark.rb small.txt large.txt
13912 *
13913 * ARGF.read #=> "small\nlarge"
13914 * ARGF.read(200) #=> "small\nlarge"
13915 * ARGF.read(2) #=> "sm"
13916 * ARGF.read(0) #=> ""
13917 *
13918 * Note that this method behaves like the fread() function in C.
13919 * This means it retries to invoke read(2) system calls to read data
13920 * with the specified length.
13921 * If you need the behavior like a single read(2) system call,
13922 * consider ARGF#readpartial or ARGF#read_nonblock.
13923 */
13924
13925static VALUE
13926argf_read(int argc, VALUE *argv, VALUE argf)
13927{
13928 VALUE tmp, str, length;
13929 long len = 0;
13930
13931 rb_scan_args(argc, argv, "02", &length, &str);
13932 if (!NIL_P(length)) {
13933 len = NUM2LONG(argv[0]);
13934 }
13935 if (!NIL_P(str)) {
13936 StringValue(str);
13937 rb_str_resize(str,0);
13938 argv[1] = Qnil;
13939 }
13940
13941 retry:
13942 if (!next_argv()) {
13943 return str;
13944 }
13945 if (ARGF_GENERIC_INPUT_P()) {
13946 tmp = argf_forward(argc, argv, argf);
13947 }
13948 else {
13949 tmp = io_read(argc, argv, ARGF.current_file);
13950 }
13951 if (NIL_P(str)) str = tmp;
13952 else if (!NIL_P(tmp)) rb_str_append(str, tmp);
13953 if (NIL_P(tmp) || NIL_P(length)) {
13954 if (ARGF.next_p != -1) {
13955 argf_close(argf);
13956 ARGF.next_p = 1;
13957 goto retry;
13958 }
13959 }
13960 else if (argc >= 1) {
13961 long slen = RSTRING_LEN(str);
13962 if (slen < len) {
13963 argv[0] = LONG2NUM(len - slen);
13964 goto retry;
13965 }
13966 }
13967 return str;
13968}
13969
13971 int argc;
13972 VALUE *argv;
13973 VALUE argf;
13974};
13975
13976static VALUE
13977argf_forward_call(VALUE arg)
13978{
13979 struct argf_call_arg *p = (struct argf_call_arg *)arg;
13980 argf_forward(p->argc, p->argv, p->argf);
13981 return Qnil;
13982}
13983
13984static VALUE argf_getpartial(int argc, VALUE *argv, VALUE argf, VALUE opts,
13985 int nonblock);
13986
13987/*
13988 * call-seq:
13989 * ARGF.readpartial(maxlen) -> string
13990 * ARGF.readpartial(maxlen, outbuf) -> outbuf
13991 *
13992 * Reads at most _maxlen_ bytes from the ARGF stream.
13993 *
13994 * If the optional _outbuf_ argument is present,
13995 * it must reference a String, which will receive the data.
13996 * The _outbuf_ will contain only the received data after the method call
13997 * even if it is not empty at the beginning.
13998 *
13999 * It raises EOFError on end of ARGF stream.
14000 * Since ARGF stream is a concatenation of multiple files,
14001 * internally EOF is occur for each file.
14002 * ARGF.readpartial returns empty strings for EOFs except the last one and
14003 * raises EOFError for the last one.
14004 *
14005 */
14006
14007static VALUE
14008argf_readpartial(int argc, VALUE *argv, VALUE argf)
14009{
14010 return argf_getpartial(argc, argv, argf, Qnil, 0);
14011}
14012
14013/*
14014 * call-seq:
14015 * ARGF.read_nonblock(maxlen[, options]) -> string
14016 * ARGF.read_nonblock(maxlen, outbuf[, options]) -> outbuf
14017 *
14018 * Reads at most _maxlen_ bytes from the ARGF stream in non-blocking mode.
14019 */
14020
14021static VALUE
14022argf_read_nonblock(int argc, VALUE *argv, VALUE argf)
14023{
14024 VALUE opts;
14025
14026 rb_scan_args(argc, argv, "11:", NULL, NULL, &opts);
14027
14028 if (!NIL_P(opts))
14029 argc--;
14030
14031 return argf_getpartial(argc, argv, argf, opts, 1);
14032}
14033
14034static VALUE
14035argf_getpartial(int argc, VALUE *argv, VALUE argf, VALUE opts, int nonblock)
14036{
14037 VALUE tmp, str, length;
14038 int no_exception;
14039
14040 rb_scan_args(argc, argv, "11", &length, &str);
14041 if (!NIL_P(str)) {
14042 StringValue(str);
14043 argv[1] = str;
14044 }
14045 no_exception = no_exception_p(opts);
14046
14047 if (!next_argv()) {
14048 if (!NIL_P(str)) {
14049 rb_str_resize(str, 0);
14050 }
14051 rb_eof_error();
14052 }
14053 if (ARGF_GENERIC_INPUT_P()) {
14054 VALUE (*const rescue_does_nothing)(VALUE, VALUE) = 0;
14055 struct argf_call_arg arg;
14056 arg.argc = argc;
14057 arg.argv = argv;
14058 arg.argf = argf;
14059 tmp = rb_rescue2(argf_forward_call, (VALUE)&arg,
14060 rescue_does_nothing, Qnil, rb_eEOFError, (VALUE)0);
14061 }
14062 else {
14063 tmp = io_getpartial(argc, argv, ARGF.current_file, no_exception, nonblock);
14064 }
14065 if (NIL_P(tmp)) {
14066 if (ARGF.next_p == -1) {
14067 return io_nonblock_eof(no_exception);
14068 }
14069 argf_close(argf);
14070 ARGF.next_p = 1;
14071 if (RARRAY_LEN(ARGF.argv) == 0) {
14072 return io_nonblock_eof(no_exception);
14073 }
14074 if (NIL_P(str))
14075 str = rb_str_new(NULL, 0);
14076 return str;
14077 }
14078 return tmp;
14079}
14080
14081/*
14082 * call-seq:
14083 * ARGF.getc -> String or nil
14084 *
14085 * Reads the next character from ARGF and returns it as a String. Returns
14086 * +nil+ at the end of the stream.
14087 *
14088 * ARGF treats the files named on the command line as a single file created
14089 * by concatenating their contents. After returning the last character of the
14090 * first file, it returns the first character of the second file, and so on.
14091 *
14092 * For example:
14093 *
14094 * $ echo "foo" > file
14095 * $ ruby argf.rb file
14096 *
14097 * ARGF.getc #=> "f"
14098 * ARGF.getc #=> "o"
14099 * ARGF.getc #=> "o"
14100 * ARGF.getc #=> "\n"
14101 * ARGF.getc #=> nil
14102 * ARGF.getc #=> nil
14103 */
14104static VALUE
14105argf_getc(VALUE argf)
14106{
14107 VALUE ch;
14108
14109 retry:
14110 if (!next_argv()) return Qnil;
14111 if (ARGF_GENERIC_INPUT_P()) {
14112 ch = forward_current(rb_intern("getc"), 0, 0);
14113 }
14114 else {
14115 ch = rb_io_getc(ARGF.current_file);
14116 }
14117 if (NIL_P(ch) && ARGF.next_p != -1) {
14118 argf_close(argf);
14119 ARGF.next_p = 1;
14120 goto retry;
14121 }
14122
14123 return ch;
14124}
14125
14126/*
14127 * call-seq:
14128 * ARGF.getbyte -> Integer or nil
14129 *
14130 * Gets the next 8-bit byte (0..255) from ARGF. Returns +nil+ if called at
14131 * the end of the stream.
14132 *
14133 * For example:
14134 *
14135 * $ echo "foo" > file
14136 * $ ruby argf.rb file
14137 *
14138 * ARGF.getbyte #=> 102
14139 * ARGF.getbyte #=> 111
14140 * ARGF.getbyte #=> 111
14141 * ARGF.getbyte #=> 10
14142 * ARGF.getbyte #=> nil
14143 */
14144static VALUE
14145argf_getbyte(VALUE argf)
14146{
14147 VALUE ch;
14148
14149 retry:
14150 if (!next_argv()) return Qnil;
14151 if (!RB_TYPE_P(ARGF.current_file, T_FILE)) {
14152 ch = forward_current(rb_intern("getbyte"), 0, 0);
14153 }
14154 else {
14155 ch = rb_io_getbyte(ARGF.current_file);
14156 }
14157 if (NIL_P(ch) && ARGF.next_p != -1) {
14158 argf_close(argf);
14159 ARGF.next_p = 1;
14160 goto retry;
14161 }
14162
14163 return ch;
14164}
14165
14166/*
14167 * call-seq:
14168 * ARGF.readchar -> String or nil
14169 *
14170 * Reads the next character from ARGF and returns it as a String. Raises
14171 * an EOFError after the last character of the last file has been read.
14172 *
14173 * For example:
14174 *
14175 * $ echo "foo" > file
14176 * $ ruby argf.rb file
14177 *
14178 * ARGF.readchar #=> "f"
14179 * ARGF.readchar #=> "o"
14180 * ARGF.readchar #=> "o"
14181 * ARGF.readchar #=> "\n"
14182 * ARGF.readchar #=> end of file reached (EOFError)
14183 */
14184static VALUE
14185argf_readchar(VALUE argf)
14186{
14187 VALUE ch;
14188
14189 retry:
14190 if (!next_argv()) rb_eof_error();
14191 if (!RB_TYPE_P(ARGF.current_file, T_FILE)) {
14192 ch = forward_current(rb_intern("getc"), 0, 0);
14193 }
14194 else {
14195 ch = rb_io_getc(ARGF.current_file);
14196 }
14197 if (NIL_P(ch) && ARGF.next_p != -1) {
14198 argf_close(argf);
14199 ARGF.next_p = 1;
14200 goto retry;
14201 }
14202
14203 return ch;
14204}
14205
14206/*
14207 * call-seq:
14208 * ARGF.readbyte -> Integer
14209 *
14210 * Reads the next 8-bit byte from ARGF and returns it as an Integer. Raises
14211 * an EOFError after the last byte of the last file has been read.
14212 *
14213 * For example:
14214 *
14215 * $ echo "foo" > file
14216 * $ ruby argf.rb file
14217 *
14218 * ARGF.readbyte #=> 102
14219 * ARGF.readbyte #=> 111
14220 * ARGF.readbyte #=> 111
14221 * ARGF.readbyte #=> 10
14222 * ARGF.readbyte #=> end of file reached (EOFError)
14223 */
14224static VALUE
14225argf_readbyte(VALUE argf)
14226{
14227 VALUE c;
14228
14229 NEXT_ARGF_FORWARD(0, 0);
14230 c = argf_getbyte(argf);
14231 if (NIL_P(c)) {
14232 rb_eof_error();
14233 }
14234 return c;
14235}
14236
14237#define FOREACH_ARGF() while (next_argv())
14238
14239static VALUE
14240argf_block_call_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, argf))
14241{
14242 const VALUE current = ARGF.current_file;
14243 rb_yield_values2(argc, argv);
14244 if (ARGF.init_p == -1 || current != ARGF.current_file) {
14246 }
14247 return Qnil;
14248}
14249
14250#define ARGF_block_call(mid, argc, argv, func, argf) \
14251 rb_block_call_kw(ARGF.current_file, mid, argc, argv, \
14252 func, argf, rb_keyword_given_p())
14253
14254static void
14255argf_block_call(ID mid, int argc, VALUE *argv, VALUE argf)
14256{
14257 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_i, argf);
14258 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14259}
14260
14261static VALUE
14262argf_block_call_line_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, argf))
14263{
14264 if (!global_argf_p(argf)) {
14265 ARGF.last_lineno = ++ARGF.lineno;
14266 }
14267 return argf_block_call_i(i, argf, argc, argv, blockarg);
14268}
14269
14270static void
14271argf_block_call_line(ID mid, int argc, VALUE *argv, VALUE argf)
14272{
14273 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_line_i, argf);
14274 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14275}
14276
14277/*
14278 * call-seq:
14279 * ARGF.each(sep=$/) {|line| block } -> ARGF
14280 * ARGF.each(sep=$/, limit) {|line| block } -> ARGF
14281 * ARGF.each(...) -> an_enumerator
14282 *
14283 * ARGF.each_line(sep=$/) {|line| block } -> ARGF
14284 * ARGF.each_line(sep=$/, limit) {|line| block } -> ARGF
14285 * ARGF.each_line(...) -> an_enumerator
14286 *
14287 * Returns an enumerator which iterates over each line (separated by _sep_,
14288 * which defaults to your platform's newline character) of each file in
14289 * +ARGV+. If a block is supplied, each line in turn will be yielded to the
14290 * block, otherwise an enumerator is returned.
14291 * The optional _limit_ argument is an Integer specifying the maximum
14292 * length of each line; longer lines will be split according to this limit.
14293 *
14294 * This method allows you to treat the files supplied on the command line as
14295 * a single file consisting of the concatenation of each named file. After
14296 * the last line of the first file has been returned, the first line of the
14297 * second file is returned. The ARGF.filename and ARGF.lineno methods can be
14298 * used to determine the filename of the current line and line number of the
14299 * whole input, respectively.
14300 *
14301 * For example, the following code prints out each line of each named file
14302 * prefixed with its line number, displaying the filename once per file:
14303 *
14304 * ARGF.each_line do |line|
14305 * puts ARGF.filename if ARGF.file.lineno == 1
14306 * puts "#{ARGF.file.lineno}: #{line}"
14307 * end
14308 *
14309 * While the following code prints only the first file's name at first, and
14310 * the contents with line number counted through all named files.
14311 *
14312 * ARGF.each_line do |line|
14313 * puts ARGF.filename if ARGF.lineno == 1
14314 * puts "#{ARGF.lineno}: #{line}"
14315 * end
14316 */
14317static VALUE
14318argf_each_line(int argc, VALUE *argv, VALUE argf)
14319{
14320 RETURN_ENUMERATOR(argf, argc, argv);
14321 FOREACH_ARGF() {
14322 argf_block_call_line(rb_intern("each_line"), argc, argv, argf);
14323 }
14324 return argf;
14325}
14326
14327/*
14328 * call-seq:
14329 * ARGF.each_byte {|byte| block } -> ARGF
14330 * ARGF.each_byte -> an_enumerator
14331 *
14332 * Iterates over each byte of each file in +ARGV+.
14333 * A byte is returned as an Integer in the range 0..255.
14334 *
14335 * This method allows you to treat the files supplied on the command line as
14336 * a single file consisting of the concatenation of each named file. After
14337 * the last byte of the first file has been returned, the first byte of the
14338 * second file is returned. The ARGF.filename method can be used to
14339 * determine the filename of the current byte.
14340 *
14341 * If no block is given, an enumerator is returned instead.
14342 *
14343 * For example:
14344 *
14345 * ARGF.bytes.to_a #=> [35, 32, ... 95, 10]
14346 *
14347 */
14348static VALUE
14349argf_each_byte(VALUE argf)
14350{
14351 RETURN_ENUMERATOR(argf, 0, 0);
14352 FOREACH_ARGF() {
14353 argf_block_call(rb_intern("each_byte"), 0, 0, argf);
14354 }
14355 return argf;
14356}
14357
14358/*
14359 * call-seq:
14360 * ARGF.each_char {|char| block } -> ARGF
14361 * ARGF.each_char -> an_enumerator
14362 *
14363 * Iterates over each character of each file in ARGF.
14364 *
14365 * This method allows you to treat the files supplied on the command line as
14366 * a single file consisting of the concatenation of each named file. After
14367 * the last character of the first file has been returned, the first
14368 * character of the second file is returned. The ARGF.filename method can
14369 * be used to determine the name of the file in which the current character
14370 * appears.
14371 *
14372 * If no block is given, an enumerator is returned instead.
14373 */
14374static VALUE
14375argf_each_char(VALUE argf)
14376{
14377 RETURN_ENUMERATOR(argf, 0, 0);
14378 FOREACH_ARGF() {
14379 argf_block_call(rb_intern("each_char"), 0, 0, argf);
14380 }
14381 return argf;
14382}
14383
14384/*
14385 * call-seq:
14386 * ARGF.each_codepoint {|codepoint| block } -> ARGF
14387 * ARGF.each_codepoint -> an_enumerator
14388 *
14389 * Iterates over each codepoint of each file in ARGF.
14390 *
14391 * This method allows you to treat the files supplied on the command line as
14392 * a single file consisting of the concatenation of each named file. After
14393 * the last codepoint of the first file has been returned, the first
14394 * codepoint of the second file is returned. The ARGF.filename method can
14395 * be used to determine the name of the file in which the current codepoint
14396 * appears.
14397 *
14398 * If no block is given, an enumerator is returned instead.
14399 */
14400static VALUE
14401argf_each_codepoint(VALUE argf)
14402{
14403 RETURN_ENUMERATOR(argf, 0, 0);
14404 FOREACH_ARGF() {
14405 argf_block_call(rb_intern("each_codepoint"), 0, 0, argf);
14406 }
14407 return argf;
14408}
14409
14410/*
14411 * call-seq:
14412 * ARGF.filename -> String
14413 * ARGF.path -> String
14414 *
14415 * Returns the current filename. "-" is returned when the current file is
14416 * STDIN.
14417 *
14418 * For example:
14419 *
14420 * $ echo "foo" > foo
14421 * $ echo "bar" > bar
14422 * $ echo "glark" > glark
14423 *
14424 * $ ruby argf.rb foo bar glark
14425 *
14426 * ARGF.filename #=> "foo"
14427 * ARGF.read(5) #=> "foo\nb"
14428 * ARGF.filename #=> "bar"
14429 * ARGF.skip
14430 * ARGF.filename #=> "glark"
14431 */
14432static VALUE
14433argf_filename(VALUE argf)
14434{
14435 next_argv();
14436 return ARGF.filename;
14437}
14438
14439static VALUE
14440argf_filename_getter(ID id, VALUE *var)
14441{
14442 return argf_filename(*var);
14443}
14444
14445/*
14446 * call-seq:
14447 * ARGF.file -> IO or File object
14448 *
14449 * Returns the current file as an IO or File object.
14450 * <code>$stdin</code> is returned when the current file is STDIN.
14451 *
14452 * For example:
14453 *
14454 * $ echo "foo" > foo
14455 * $ echo "bar" > bar
14456 *
14457 * $ ruby argf.rb foo bar
14458 *
14459 * ARGF.file #=> #<File:foo>
14460 * ARGF.read(5) #=> "foo\nb"
14461 * ARGF.file #=> #<File:bar>
14462 */
14463static VALUE
14464argf_file(VALUE argf)
14465{
14466 next_argv();
14467 return ARGF.current_file;
14468}
14469
14470/*
14471 * call-seq:
14472 * ARGF.binmode -> ARGF
14473 *
14474 * Puts ARGF into binary mode. Once a stream is in binary mode, it cannot
14475 * be reset to non-binary mode. This option has the following effects:
14476 *
14477 * * Newline conversion is disabled.
14478 * * Encoding conversion is disabled.
14479 * * Content is treated as ASCII-8BIT.
14480 */
14481static VALUE
14482argf_binmode_m(VALUE argf)
14483{
14484 ARGF.binmode = 1;
14485 next_argv();
14486 ARGF_FORWARD(0, 0);
14487 rb_io_ascii8bit_binmode(ARGF.current_file);
14488 return argf;
14489}
14490
14491/*
14492 * call-seq:
14493 * ARGF.binmode? -> true or false
14494 *
14495 * Returns true if ARGF is being read in binary mode; false otherwise.
14496 * To enable binary mode use ARGF.binmode.
14497 *
14498 * For example:
14499 *
14500 * ARGF.binmode? #=> false
14501 * ARGF.binmode
14502 * ARGF.binmode? #=> true
14503 */
14504static VALUE
14505argf_binmode_p(VALUE argf)
14506{
14507 return RBOOL(ARGF.binmode);
14508}
14509
14510/*
14511 * call-seq:
14512 * ARGF.skip -> ARGF
14513 *
14514 * Sets the current file to the next file in ARGV. If there aren't any more
14515 * files it has no effect.
14516 *
14517 * For example:
14518 *
14519 * $ ruby argf.rb foo bar
14520 * ARGF.filename #=> "foo"
14521 * ARGF.skip
14522 * ARGF.filename #=> "bar"
14523 */
14524static VALUE
14525argf_skip(VALUE argf)
14526{
14527 if (ARGF.init_p && ARGF.next_p == 0) {
14528 argf_close(argf);
14529 ARGF.next_p = 1;
14530 }
14531 return argf;
14532}
14533
14534/*
14535 * call-seq:
14536 * ARGF.close -> ARGF
14537 *
14538 * Closes the current file and skips to the next file in ARGV. If there are
14539 * no more files to open, just closes the current file. STDIN will not be
14540 * closed.
14541 *
14542 * For example:
14543 *
14544 * $ ruby argf.rb foo bar
14545 *
14546 * ARGF.filename #=> "foo"
14547 * ARGF.close
14548 * ARGF.filename #=> "bar"
14549 * ARGF.close
14550 */
14551static VALUE
14552argf_close_m(VALUE argf)
14553{
14554 next_argv();
14555 argf_close(argf);
14556 if (ARGF.next_p != -1) {
14557 ARGF.next_p = 1;
14558 }
14559 ARGF.lineno = 0;
14560 return argf;
14561}
14562
14563/*
14564 * call-seq:
14565 * ARGF.closed? -> true or false
14566 *
14567 * Returns _true_ if the current file has been closed; _false_ otherwise. Use
14568 * ARGF.close to actually close the current file.
14569 */
14570static VALUE
14571argf_closed(VALUE argf)
14572{
14573 next_argv();
14574 ARGF_FORWARD(0, 0);
14575 return rb_io_closed_p(ARGF.current_file);
14576}
14577
14578/*
14579 * call-seq:
14580 * ARGF.to_s -> String
14581 *
14582 * Returns "ARGF".
14583 */
14584static VALUE
14585argf_to_s(VALUE argf)
14586{
14587 return rb_str_new2("ARGF");
14588}
14589
14590/*
14591 * call-seq:
14592 * ARGF.inplace_mode -> String
14593 *
14594 * Returns the file extension appended to the names of backup copies of
14595 * modified files under in-place edit mode. This value can be set using
14596 * ARGF.inplace_mode= or passing the +-i+ switch to the Ruby binary.
14597 */
14598static VALUE
14599argf_inplace_mode_get(VALUE argf)
14600{
14601 if (!ARGF.inplace) return Qnil;
14602 if (NIL_P(ARGF.inplace)) return rb_str_new(0, 0);
14603 return rb_str_dup(ARGF.inplace);
14604}
14605
14606static VALUE
14607opt_i_get(ID id, VALUE *var)
14608{
14609 return argf_inplace_mode_get(*var);
14610}
14611
14612/*
14613 * call-seq:
14614 * ARGF.inplace_mode = ext -> ARGF
14615 *
14616 * Sets the filename extension for in-place editing mode to the given String.
14617 * The backup copy of each file being edited has this value appended to its
14618 * filename.
14619 *
14620 * For example:
14621 *
14622 * $ ruby argf.rb file.txt
14623 *
14624 * ARGF.inplace_mode = '.bak'
14625 * ARGF.each_line do |line|
14626 * print line.sub("foo","bar")
14627 * end
14628 *
14629 * First, _file.txt.bak_ is created as a backup copy of _file.txt_.
14630 * Then, each line of _file.txt_ has the first occurrence of "foo" replaced with
14631 * "bar".
14632 */
14633static VALUE
14634argf_inplace_mode_set(VALUE argf, VALUE val)
14635{
14636 if (!RTEST(val)) {
14637 ARGF.inplace = Qfalse;
14638 }
14639 else if (StringValueCStr(val), !RSTRING_LEN(val)) {
14640 ARGF.inplace = Qnil;
14641 }
14642 else {
14643 ARGF.inplace = rb_str_new_frozen(val);
14644 }
14645 return argf;
14646}
14647
14648static void
14649opt_i_set(VALUE val, ID id, VALUE *var)
14650{
14651 argf_inplace_mode_set(*var, val);
14652}
14653
14654void
14655ruby_set_inplace_mode(const char *suffix)
14656{
14657 ARGF.inplace = !suffix ? Qfalse : !*suffix ? Qnil : rb_str_new(suffix, strlen(suffix));
14658}
14659
14660/*
14661 * call-seq:
14662 * ARGF.argv -> ARGV
14663 *
14664 * Returns the +ARGV+ array, which contains the arguments passed to your
14665 * script, one per element.
14666 *
14667 * For example:
14668 *
14669 * $ ruby argf.rb -v glark.txt
14670 *
14671 * ARGF.argv #=> ["-v", "glark.txt"]
14672 *
14673 */
14674static VALUE
14675argf_argv(VALUE argf)
14676{
14677 return ARGF.argv;
14678}
14679
14680static VALUE
14681argf_argv_getter(ID id, VALUE *var)
14682{
14683 return argf_argv(*var);
14684}
14685
14686VALUE
14688{
14689 return ARGF.argv;
14690}
14691
14692/*
14693 * call-seq:
14694 * ARGF.to_write_io -> io
14695 *
14696 * Returns IO instance tied to _ARGF_ for writing if inplace mode is
14697 * enabled.
14698 */
14699static VALUE
14700argf_write_io(VALUE argf)
14701{
14702 if (!RTEST(ARGF.current_file)) {
14703 rb_raise(rb_eIOError, "not opened for writing");
14704 }
14705 return GetWriteIO(ARGF.current_file);
14706}
14707
14708/*
14709 * call-seq:
14710 * ARGF.write(*objects) -> integer
14711 *
14712 * Writes each of the given +objects+ if inplace mode.
14713 */
14714static VALUE
14715argf_write(int argc, VALUE *argv, VALUE argf)
14716{
14717 return rb_io_writev(argf_write_io(argf), argc, argv);
14718}
14719
14720void
14721rb_readwrite_sys_fail(enum rb_io_wait_readwrite waiting, const char *mesg)
14722{
14723 rb_readwrite_syserr_fail(waiting, errno, mesg);
14724}
14725
14726void
14727rb_readwrite_syserr_fail(enum rb_io_wait_readwrite waiting, int n, const char *mesg)
14728{
14729 VALUE arg, c = Qnil;
14730 arg = mesg ? rb_str_new2(mesg) : Qnil;
14731 switch (waiting) {
14732 case RB_IO_WAIT_WRITABLE:
14733 switch (n) {
14734 case EAGAIN:
14735 c = rb_eEAGAINWaitWritable;
14736 break;
14737#if EAGAIN != EWOULDBLOCK
14738 case EWOULDBLOCK:
14739 c = rb_eEWOULDBLOCKWaitWritable;
14740 break;
14741#endif
14742 case EINPROGRESS:
14743 c = rb_eEINPROGRESSWaitWritable;
14744 break;
14745 default:
14747 }
14748 break;
14749 case RB_IO_WAIT_READABLE:
14750 switch (n) {
14751 case EAGAIN:
14752 c = rb_eEAGAINWaitReadable;
14753 break;
14754#if EAGAIN != EWOULDBLOCK
14755 case EWOULDBLOCK:
14756 c = rb_eEWOULDBLOCKWaitReadable;
14757 break;
14758#endif
14759 case EINPROGRESS:
14760 c = rb_eEINPROGRESSWaitReadable;
14761 break;
14762 default:
14764 }
14765 break;
14766 default:
14767 rb_bug("invalid read/write type passed to rb_readwrite_sys_fail: %d", waiting);
14768 }
14770}
14771
14772static VALUE
14773get_LAST_READ_LINE(ID _x, VALUE *_y)
14774{
14775 return rb_lastline_get();
14776}
14777
14778static void
14779set_LAST_READ_LINE(VALUE val, ID _x, VALUE *_y)
14780{
14781 rb_lastline_set(val);
14782}
14783
14784/*
14785 * Document-class: IOError
14786 *
14787 * Raised when an IO operation fails.
14788 *
14789 * File.open("/etc/hosts") {|f| f << "example"}
14790 * #=> IOError: not opened for writing
14791 *
14792 * File.open("/etc/hosts") {|f| f.close; f.read }
14793 * #=> IOError: closed stream
14794 *
14795 * Note that some IO failures raise <code>SystemCallError</code>s
14796 * and these are not subclasses of IOError:
14797 *
14798 * File.open("does/not/exist")
14799 * #=> Errno::ENOENT: No such file or directory - does/not/exist
14800 */
14801
14802/*
14803 * Document-class: EOFError
14804 *
14805 * Raised by some IO operations when reaching the end of file. Many IO
14806 * methods exist in two forms,
14807 *
14808 * one that returns +nil+ when the end of file is reached, the other
14809 * raises EOFError.
14810 *
14811 * EOFError is a subclass of IOError.
14812 *
14813 * file = File.open("/etc/hosts")
14814 * file.read
14815 * file.gets #=> nil
14816 * file.readline #=> EOFError: end of file reached
14817 * file.close
14818 */
14819
14820/*
14821 * Document-class: ARGF
14822 *
14823 * == \ARGF and +ARGV+
14824 *
14825 * The \ARGF object works with the array at global variable +ARGV+
14826 * to make <tt>$stdin</tt> and file streams available in the Ruby program:
14827 *
14828 * - **ARGV** may be thought of as the <b>argument vector</b> array.
14829 *
14830 * Initially, it contains the command-line arguments and options
14831 * that are passed to the Ruby program;
14832 * the program can modify that array as it likes.
14833 *
14834 * - **ARGF** may be thought of as the <b>argument files</b> object.
14835 *
14836 * It can access file streams and/or the <tt>$stdin</tt> stream,
14837 * based on what it finds in +ARGV+.
14838 * This provides a convenient way for the command line
14839 * to specify streams for a Ruby program to read.
14840 *
14841 * == Reading
14842 *
14843 * \ARGF may read from _source_ streams,
14844 * which at any particular time are determined by the content of +ARGV+.
14845 *
14846 * === Simplest Case
14847 *
14848 * When the <i>very first</i> \ARGF read occurs with an empty +ARGV+ (<tt>[]</tt>),
14849 * the source is <tt>$stdin</tt>:
14850 *
14851 * - \File +t.rb+:
14852 *
14853 * p ['ARGV', ARGV]
14854 * p ['ARGF.read', ARGF.read]
14855 *
14856 * - Commands and outputs
14857 * (see below for the content of files +foo.txt+ and +bar.txt+):
14858 *
14859 * $ echo "Open the pod bay doors, Hal." | ruby t.rb
14860 * ["ARGV", []]
14861 * ["ARGF.read", "Open the pod bay doors, Hal.\n"]
14862 *
14863 * $ cat foo.txt bar.txt | ruby t.rb
14864 * ["ARGV", []]
14865 * ["ARGF.read", "Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"]
14866 *
14867 * === About the Examples
14868 *
14869 * Many examples here assume the existence of files +foo.txt+ and +bar.txt+:
14870 *
14871 * $ cat foo.txt
14872 * Foo 0
14873 * Foo 1
14874 * $ cat bar.txt
14875 * Bar 0
14876 * Bar 1
14877 * Bar 2
14878 * Bar 3
14879 *
14880 * === Sources in +ARGV+
14881 *
14882 * For any \ARGF read _except_ the {simplest case}[rdoc-ref:ARGF@Simplest+Case]
14883 * (that is, _except_ for the <i>very first</i> \ARGF read with an empty +ARGV+),
14884 * the sources are found in +ARGV+.
14885 *
14886 * \ARGF assumes that each element in array +ARGV+ is a potential source,
14887 * and is one of:
14888 *
14889 * - The string path to a file that may be opened as a stream.
14890 * - The character <tt>'-'</tt>, meaning stream <tt>$stdin</tt>.
14891 *
14892 * Each element that is _not_ one of these
14893 * should be removed from +ARGV+ before \ARGF accesses that source.
14894 *
14895 * In the following example:
14896 *
14897 * - Filepaths +foo.txt+ and +bar.txt+ may be retained as potential sources.
14898 * - Options <tt>--xyzzy</tt> and <tt>--mojo</tt> should be removed.
14899 *
14900 * Example:
14901 *
14902 * - \File +t.rb+:
14903 *
14904 * # Print arguments (and options, if any) found on command line.
14905 * p ['ARGV', ARGV]
14906 *
14907 * - Command and output:
14908 *
14909 * $ ruby t.rb --xyzzy --mojo foo.txt bar.txt
14910 * ["ARGV", ["--xyzzy", "--mojo", "foo.txt", "bar.txt"]]
14911 *
14912 * \ARGF's stream access considers the elements of +ARGV+, left to right:
14913 *
14914 * - \File +t.rb+:
14915 *
14916 * p "ARGV: #{ARGV}"
14917 * p "Read: #{ARGF.read}" # Read everything from all specified streams.
14918 *
14919 * - Command and output:
14920 *
14921 * $ ruby t.rb foo.txt bar.txt
14922 * "ARGV: [\"foo.txt\", \"bar.txt\"]"
14923 * "Read: Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"
14924 *
14925 * Because the value at +ARGV+ is an ordinary array,
14926 * you can manipulate it to control which sources \ARGF considers:
14927 *
14928 * - If you remove an element from +ARGV+, \ARGF will not consider the corresponding source.
14929 * - If you add an element to +ARGV+, \ARGF will consider the corresponding source.
14930 *
14931 * Each element in +ARGV+ is removed when its corresponding source is accessed;
14932 * when all sources have been accessed, the array is empty:
14933 *
14934 * - \File +t.rb+:
14935 *
14936 * until ARGV.empty? && ARGF.eof?
14937 * p "ARGV: #{ARGV}"
14938 * p "Line: #{ARGF.readline}" # Read each line from each specified stream.
14939 * end
14940 *
14941 * - Command and output:
14942 *
14943 * $ ruby t.rb foo.txt bar.txt
14944 * "ARGV: [\"foo.txt\", \"bar.txt\"]"
14945 * "Line: Foo 0\n"
14946 * "ARGV: [\"bar.txt\"]"
14947 * "Line: Foo 1\n"
14948 * "ARGV: [\"bar.txt\"]"
14949 * "Line: Bar 0\n"
14950 * "ARGV: []"
14951 * "Line: Bar 1\n"
14952 * "ARGV: []"
14953 * "Line: Bar 2\n"
14954 * "ARGV: []"
14955 * "Line: Bar 3\n"
14956 *
14957 * ==== Filepaths in +ARGV+
14958 *
14959 * The +ARGV+ array may contain filepaths the specify sources for \ARGF reading.
14960 *
14961 * This program prints what it reads from files at the paths specified
14962 * on the command line:
14963 *
14964 * - \File +t.rb+:
14965 *
14966 * p ['ARGV', ARGV]
14967 * # Read and print all content from the specified sources.
14968 * p ['ARGF.read', ARGF.read]
14969 *
14970 * - Command and output:
14971 *
14972 * $ ruby t.rb foo.txt bar.txt
14973 * ["ARGV", [foo.txt, bar.txt]
14974 * ["ARGF.read", "Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"]
14975 *
14976 * ==== Specifying <tt>$stdin</tt> in +ARGV+
14977 *
14978 * To specify stream <tt>$stdin</tt> in +ARGV+, us the character <tt>'-'</tt>:
14979 *
14980 * - \File +t.rb+:
14981 *
14982 * p ['ARGV', ARGV]
14983 * p ['ARGF.read', ARGF.read]
14984 *
14985 * - Command and output:
14986 *
14987 * $ echo "Open the pod bay doors, Hal." | ruby t.rb -
14988 * ["ARGV", ["-"]]
14989 * ["ARGF.read", "Open the pod bay doors, Hal.\n"]
14990 *
14991 * When no character <tt>'-'</tt> is given, stream <tt>$stdin</tt> is ignored
14992 * (exception:
14993 * see {Specifying $stdin in ARGV}[rdoc-ref:ARGF@Specifying+-24stdin+in+ARGV]):
14994 *
14995 * - Command and output:
14996 *
14997 * $ echo "Open the pod bay doors, Hal." | ruby t.rb foo.txt bar.txt
14998 * "ARGV: [\"foo.txt\", \"bar.txt\"]"
14999 * "Read: Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"
15000 *
15001 * ==== Mixtures and Repetitions in +ARGV+
15002 *
15003 * For an \ARGF reader, +ARGV+ may contain any mixture of filepaths
15004 * and character <tt>'-'</tt>, including repetitions.
15005 *
15006 * ==== Modifications to +ARGV+
15007 *
15008 * The running Ruby program may make any modifications to the +ARGV+ array;
15009 * the current value of +ARGV+ affects \ARGF reading.
15010 *
15011 * ==== Empty +ARGV+
15012 *
15013 * For an empty +ARGV+, an \ARGF read method either returns +nil+
15014 * or raises an exception, depending on the specific method.
15015 *
15016 * === More Read Methods
15017 *
15018 * As seen above, method ARGF#read reads the content of all sources
15019 * into a single string.
15020 * Other \ARGF methods provide other ways to access that content;
15021 * these include:
15022 *
15023 * - Byte access: #each_byte, #getbyte, #readbyte.
15024 * - Character access: #each_char, #getc, #readchar.
15025 * - Codepoint access: #each_codepoint.
15026 * - Line access: #each_line, #gets, #readline, #readlines.
15027 * - Source access: #read, #read_nonblock, #readpartial.
15028 *
15029 * === About \Enumerable
15030 *
15031 * \ARGF includes module Enumerable.
15032 * Virtually all methods in \Enumerable call method <tt>#each</tt> in the including class.
15033 *
15034 * <b>Note well</b>: In \ARGF, method #each returns data from the _sources_,
15035 * _not_ from +ARGV+;
15036 * therefore, for example, <tt>ARGF#entries</tt> returns an array of lines from the sources,
15037 * not an array of the strings from +ARGV+:
15038 *
15039 * - \File +t.rb+:
15040 *
15041 * p ['ARGV', ARGV]
15042 * p ['ARGF.entries', ARGF.entries]
15043 *
15044 * - Command and output:
15045 *
15046 * $ ruby t.rb foo.txt bar.txt
15047 * ["ARGV", ["foo.txt", "bar.txt"]]
15048 * ["ARGF.entries", ["Foo 0\n", "Foo 1\n", "Bar 0\n", "Bar 1\n", "Bar 2\n", "Bar 3\n"]]
15049 *
15050 * == Writing
15051 *
15052 * If <i>inplace mode</i> is in effect,
15053 * \ARGF may write to target streams,
15054 * which at any particular time are determined by the content of ARGV.
15055 *
15056 * Methods about inplace mode:
15057 *
15058 * - #inplace_mode
15059 * - #inplace_mode=
15060 * - #to_write_io
15061 *
15062 * Methods for writing:
15063 *
15064 * - #print
15065 * - #printf
15066 * - #putc
15067 * - #puts
15068 * - #write
15069 *
15070 */
15071
15072/*
15073 * An instance of class \IO (commonly called a _stream_)
15074 * represents an input/output stream in the underlying operating system.
15075 * Class \IO is the basis for input and output in Ruby.
15076 *
15077 * Class File is the only class in the Ruby core that is a subclass of \IO.
15078 * Some classes in the Ruby standard library are also subclasses of \IO;
15079 * these include TCPSocket and UDPSocket.
15080 *
15081 * The global constant ARGF (also accessible as <tt>$<</tt>)
15082 * provides an IO-like stream that allows access to all file paths
15083 * found in ARGV (or found in STDIN if ARGV is empty).
15084 * ARGF is not itself a subclass of \IO.
15085 *
15086 * Class StringIO provides an IO-like stream that handles a String.
15087 * StringIO is not itself a subclass of \IO.
15088 *
15089 * Important objects based on \IO include:
15090 *
15091 * - $stdin.
15092 * - $stdout.
15093 * - $stderr.
15094 * - Instances of class File.
15095 *
15096 * An instance of \IO may be created using:
15097 *
15098 * - IO.new: returns a new \IO object for the given integer file descriptor.
15099 * - IO.open: passes a new \IO object to the given block.
15100 * - IO.popen: returns a new \IO object that is connected to the $stdin and $stdout
15101 * of a newly-launched subprocess.
15102 * - Kernel#open: Returns a new \IO object connected to a given source:
15103 * stream, file, or subprocess.
15104 *
15105 * Like a File stream, an \IO stream has:
15106 *
15107 * - A read/write mode, which may be read-only, write-only, or read/write;
15108 * see {Read/Write Mode}[rdoc-ref:File@Read-2FWrite+Mode].
15109 * - A data mode, which may be text-only or binary;
15110 * see {Data Mode}[rdoc-ref:File@Data+Mode].
15111 * - Internal and external encodings;
15112 * see {Encodings}[rdoc-ref:File@Encodings].
15113 *
15114 * And like other \IO streams, it has:
15115 *
15116 * - A position, which determines where in the stream the next
15117 * read or write is to occur;
15118 * see {Position}[rdoc-ref:IO@Position].
15119 * - A line number, which is a special, line-oriented, "position"
15120 * (different from the position mentioned above);
15121 * see {Line Number}[rdoc-ref:IO@Line+Number].
15122 *
15123 * == Extension <tt>io/console</tt>
15124 *
15125 * Extension <tt>io/console</tt> provides numerous methods
15126 * for interacting with the console;
15127 * requiring it adds numerous methods to class \IO.
15128 *
15129 * == Example Files
15130 *
15131 * Many examples here use these variables:
15132 *
15133 * :include: doc/examples/files.rdoc
15134 *
15135 * == Open Options
15136 *
15137 * A number of \IO methods accept optional keyword arguments
15138 * that determine how a new stream is to be opened:
15139 *
15140 * - +:mode+: Stream mode.
15141 * - +:flags+: Integer file open flags;
15142 * If +mode+ is also given, the two are bitwise-ORed.
15143 * - +:external_encoding+: External encoding for the stream.
15144 * - +:internal_encoding+: Internal encoding for the stream.
15145 * <tt>'-'</tt> is a synonym for the default internal encoding.
15146 * If the value is +nil+ no conversion occurs.
15147 * - +:encoding+: Specifies external and internal encodings as <tt>'extern:intern'</tt>.
15148 * - +:textmode+: If a truthy value, specifies the mode as text-only, binary otherwise.
15149 * - +:binmode+: If a truthy value, specifies the mode as binary, text-only otherwise.
15150 * - +:autoclose+: If a truthy value, specifies that the +fd+ will close
15151 * when the stream closes; otherwise it remains open.
15152 * - +:path:+ If a string value is provided, it is used in #inspect and is available as
15153 * #path method.
15154 *
15155 * Also available are the options offered in String#encode,
15156 * which may control conversion between external and internal encoding.
15157 *
15158 * == Basic \IO
15159 *
15160 * You can perform basic stream \IO with these methods,
15161 * which typically operate on multi-byte strings:
15162 *
15163 * - IO#read: Reads and returns some or all of the remaining bytes from the stream.
15164 * - IO#write: Writes zero or more strings to the stream;
15165 * each given object that is not already a string is converted via +to_s+.
15166 *
15167 * === Position
15168 *
15169 * An \IO stream has a nonnegative integer _position_,
15170 * which is the byte offset at which the next read or write is to occur.
15171 * A new stream has position zero (and line number zero);
15172 * method +rewind+ resets the position (and line number) to zero.
15173 *
15174 * These methods discard {buffers}[rdoc-ref:IO@Buffering] and the
15175 * Encoding::Converter instances used for that \IO.
15176 *
15177 * The relevant methods:
15178 *
15179 * - IO#tell (aliased as +#pos+): Returns the current position (in bytes) in the stream.
15180 * - IO#pos=: Sets the position of the stream to a given integer +new_position+ (in bytes).
15181 * - IO#seek: Sets the position of the stream to a given integer +offset+ (in bytes),
15182 * relative to a given position +whence+
15183 * (indicating the beginning, end, or current position).
15184 * - IO#rewind: Positions the stream at the beginning (also resetting the line number).
15185 *
15186 * === Open and Closed Streams
15187 *
15188 * A new \IO stream may be open for reading, open for writing, or both.
15189 *
15190 * A stream is automatically closed when claimed by the garbage collector.
15191 *
15192 * Attempted reading or writing on a closed stream raises an exception.
15193 *
15194 * The relevant methods:
15195 *
15196 * - IO#close: Closes the stream for both reading and writing.
15197 * - IO#close_read: Closes the stream for reading.
15198 * - IO#close_write: Closes the stream for writing.
15199 * - IO#closed?: Returns whether the stream is closed.
15200 *
15201 * === End-of-Stream
15202 *
15203 * You can query whether a stream is positioned at its end:
15204 *
15205 * - IO#eof? (also aliased as +#eof+): Returns whether the stream is at end-of-stream.
15206 *
15207 * You can reposition to end-of-stream by using method IO#seek:
15208 *
15209 * f = File.new('t.txt')
15210 * f.eof? # => false
15211 * f.seek(0, :END)
15212 * f.eof? # => true
15213 * f.close
15214 *
15215 * Or by reading all stream content (which is slower than using IO#seek):
15216 *
15217 * f.rewind
15218 * f.eof? # => false
15219 * f.read # => "First line\nSecond line\n\nFourth line\nFifth line\n"
15220 * f.eof? # => true
15221 *
15222 * == Line \IO
15223 *
15224 * Class \IO supports line-oriented
15225 * {input}[rdoc-ref:IO@Line+Input] and {output}[rdoc-ref:IO@Line+Output]
15226 *
15227 * === Line Input
15228 *
15229 * Class \IO supports line-oriented input for
15230 * {files}[rdoc-ref:IO@File+Line+Input] and {IO streams}[rdoc-ref:IO@Stream+Line+Input]
15231 *
15232 * ==== \File Line Input
15233 *
15234 * You can read lines from a file using these methods:
15235 *
15236 * - IO.foreach: Reads each line and passes it to the given block.
15237 * - IO.readlines: Reads and returns all lines in an array.
15238 *
15239 * For each of these methods:
15240 *
15241 * - You can specify {open options}[rdoc-ref:IO@Open+Options].
15242 * - Line parsing depends on the effective <i>line separator</i>;
15243 * see {Line Separator}[rdoc-ref:IO@Line+Separator].
15244 * - The length of each returned line depends on the effective <i>line limit</i>;
15245 * see {Line Limit}[rdoc-ref:IO@Line+Limit].
15246 *
15247 * ==== Stream Line Input
15248 *
15249 * You can read lines from an \IO stream using these methods:
15250 *
15251 * - IO#each_line: Reads each remaining line, passing it to the given block.
15252 * - IO#gets: Returns the next line.
15253 * - IO#readline: Like #gets, but raises an exception at end-of-stream.
15254 * - IO#readlines: Returns all remaining lines in an array.
15255 *
15256 * For each of these methods:
15257 *
15258 * - Reading may begin mid-line,
15259 * depending on the stream's _position_;
15260 * see {Position}[rdoc-ref:IO@Position].
15261 * - Line parsing depends on the effective <i>line separator</i>;
15262 * see {Line Separator}[rdoc-ref:IO@Line+Separator].
15263 * - The length of each returned line depends on the effective <i>line limit</i>;
15264 * see {Line Limit}[rdoc-ref:IO@Line+Limit].
15265 *
15266 * ===== Line Separator
15267 *
15268 * Each of the {line input methods}[rdoc-ref:IO@Line+Input] uses a <i>line separator</i>:
15269 * the string that determines what is considered a line;
15270 * it is sometimes called the <i>input record separator</i>.
15271 *
15272 * The default line separator is taken from global variable <tt>$/</tt>,
15273 * whose initial value is <tt>"\n"</tt>.
15274 *
15275 * Generally, the line to be read next is all data
15276 * from the current {position}[rdoc-ref:IO@Position]
15277 * to the next line separator
15278 * (but see {Special Line Separator Values}[rdoc-ref:IO@Special+Line+Separator+Values]):
15279 *
15280 * f = File.new('t.txt')
15281 * # Method gets with no sep argument returns the next line, according to $/.
15282 * f.gets # => "First line\n"
15283 * f.gets # => "Second line\n"
15284 * f.gets # => "\n"
15285 * f.gets # => "Fourth line\n"
15286 * f.gets # => "Fifth line\n"
15287 * f.close
15288 *
15289 * You can use a different line separator by passing argument +sep+:
15290 *
15291 * f = File.new('t.txt')
15292 * f.gets('l') # => "First l"
15293 * f.gets('li') # => "ine\nSecond li"
15294 * f.gets('lin') # => "ne\n\nFourth lin"
15295 * f.gets # => "e\n"
15296 * f.close
15297 *
15298 * Or by setting global variable <tt>$/</tt>:
15299 *
15300 * f = File.new('t.txt')
15301 * $/ = 'l'
15302 * f.gets # => "First l"
15303 * f.gets # => "ine\nSecond l"
15304 * f.gets # => "ine\n\nFourth l"
15305 * f.close
15306 *
15307 * ===== Special Line Separator Values
15308 *
15309 * Each of the {line input methods}[rdoc-ref:IO@Line+Input]
15310 * accepts two special values for parameter +sep+:
15311 *
15312 * - +nil+: The entire stream is to be read ("slurped") into a single string:
15313 *
15314 * f = File.new('t.txt')
15315 * f.gets(nil) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
15316 * f.close
15317 *
15318 * - <tt>''</tt> (the empty string): The next "paragraph" is to be read
15319 * (paragraphs being separated by two consecutive line separators):
15320 *
15321 * f = File.new('t.txt')
15322 * f.gets('') # => "First line\nSecond line\n\n"
15323 * f.gets('') # => "Fourth line\nFifth line\n"
15324 * f.close
15325 *
15326 * ===== Line Limit
15327 *
15328 * Each of the {line input methods}[rdoc-ref:IO@Line+Input]
15329 * uses an integer <i>line limit</i>,
15330 * which restricts the number of bytes that may be returned.
15331 * (A multi-byte character will not be split, and so a returned line may be slightly longer
15332 * than the limit).
15333 *
15334 * The default limit value is <tt>-1</tt>;
15335 * any negative limit value means that there is no limit.
15336 *
15337 * If there is no limit, the line is determined only by +sep+.
15338 *
15339 * # Text with 1-byte characters.
15340 * File.open('t.txt') {|f| f.gets(1) } # => "F"
15341 * File.open('t.txt') {|f| f.gets(2) } # => "Fi"
15342 * File.open('t.txt') {|f| f.gets(3) } # => "Fir"
15343 * File.open('t.txt') {|f| f.gets(4) } # => "Firs"
15344 * # No more than one line.
15345 * File.open('t.txt') {|f| f.gets(10) } # => "First line"
15346 * File.open('t.txt') {|f| f.gets(11) } # => "First line\n"
15347 * File.open('t.txt') {|f| f.gets(12) } # => "First line\n"
15348 *
15349 * # Text with 2-byte characters, which will not be split.
15350 * File.open('t.rus') {|f| f.gets(1).size } # => 1
15351 * File.open('t.rus') {|f| f.gets(2).size } # => 1
15352 * File.open('t.rus') {|f| f.gets(3).size } # => 2
15353 * File.open('t.rus') {|f| f.gets(4).size } # => 2
15354 *
15355 * ===== Line Separator and Line Limit
15356 *
15357 * With arguments +sep+ and +limit+ given, combines the two behaviors:
15358 *
15359 * - Returns the next line as determined by line separator +sep+.
15360 * - But returns no more bytes than are allowed by the limit +limit+.
15361 *
15362 * Example:
15363 *
15364 * File.open('t.txt') {|f| f.gets('li', 20) } # => "First li"
15365 * File.open('t.txt') {|f| f.gets('li', 2) } # => "Fi"
15366 *
15367 * ===== Line Number
15368 *
15369 * A readable \IO stream has a non-negative integer <i>line number</i>:
15370 *
15371 * - IO#lineno: Returns the line number.
15372 * - IO#lineno=: Resets and returns the line number.
15373 *
15374 * Unless modified by a call to method IO#lineno=,
15375 * the line number is the number of lines read
15376 * by certain line-oriented methods,
15377 * according to the effective {line separator}[rdoc-ref:IO@Line+Separator]:
15378 *
15379 * - IO.foreach: Increments the line number on each call to the block.
15380 * - IO#each_line: Increments the line number on each call to the block.
15381 * - IO#gets: Increments the line number.
15382 * - IO#readline: Increments the line number.
15383 * - IO#readlines: Increments the line number for each line read.
15384 *
15385 * A new stream is initially has line number zero (and position zero);
15386 * method +rewind+ resets the line number (and position) to zero:
15387 *
15388 * f = File.new('t.txt')
15389 * f.lineno # => 0
15390 * f.gets # => "First line\n"
15391 * f.lineno # => 1
15392 * f.rewind
15393 * f.lineno # => 0
15394 * f.close
15395 *
15396 * Reading lines from a stream usually changes its line number:
15397 *
15398 * f = File.new('t.txt', 'r')
15399 * f.lineno # => 0
15400 * f.readline # => "This is line one.\n"
15401 * f.lineno # => 1
15402 * f.readline # => "This is the second line.\n"
15403 * f.lineno # => 2
15404 * f.readline # => "Here's the third line.\n"
15405 * f.lineno # => 3
15406 * f.eof? # => true
15407 * f.close
15408 *
15409 * Iterating over lines in a stream usually changes its line number:
15410 *
15411 * File.open('t.txt') do |f|
15412 * f.each_line do |line|
15413 * p "position=#{f.pos} eof?=#{f.eof?} lineno=#{f.lineno}"
15414 * end
15415 * end
15416 *
15417 * Output:
15418 *
15419 * "position=11 eof?=false lineno=1"
15420 * "position=23 eof?=false lineno=2"
15421 * "position=24 eof?=false lineno=3"
15422 * "position=36 eof?=false lineno=4"
15423 * "position=47 eof?=true lineno=5"
15424 *
15425 * Unlike the stream's {position}[rdoc-ref:IO@Position],
15426 * the line number does not affect where the next read or write will occur:
15427 *
15428 * f = File.new('t.txt')
15429 * f.lineno = 1000
15430 * f.lineno # => 1000
15431 * f.gets # => "First line\n"
15432 * f.lineno # => 1001
15433 * f.close
15434 *
15435 * Associated with the line number is the global variable <tt>$.</tt>:
15436 *
15437 * - When a stream is opened, <tt>$.</tt> is not set;
15438 * its value is left over from previous activity in the process:
15439 *
15440 * $. = 41
15441 * f = File.new('t.txt')
15442 * $. = 41
15443 * # => 41
15444 * f.close
15445 *
15446 * - When a stream is read, <tt>$.</tt> is set to the line number for that stream:
15447 *
15448 * f0 = File.new('t.txt')
15449 * f1 = File.new('t.dat')
15450 * f0.readlines # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
15451 * $. # => 5
15452 * f1.readlines # => ["\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"]
15453 * $. # => 1
15454 * f0.close
15455 * f1.close
15456 *
15457 * - Methods IO#rewind and IO#seek do not affect <tt>$.</tt>:
15458 *
15459 * f = File.new('t.txt')
15460 * f.readlines # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
15461 * $. # => 5
15462 * f.rewind
15463 * f.seek(0, :SET)
15464 * $. # => 5
15465 * f.close
15466 *
15467 * === Line Output
15468 *
15469 * You can write to an \IO stream line-by-line using this method:
15470 *
15471 * - IO#puts: Writes objects to the stream.
15472 *
15473 * == Character \IO
15474 *
15475 * You can process an \IO stream character-by-character using these methods:
15476 *
15477 * - IO#getc: Reads and returns the next character from the stream.
15478 * - IO#readchar: Like #getc, but raises an exception at end-of-stream.
15479 * - IO#ungetc: Pushes back ("unshifts") a character or integer onto the stream.
15480 * - IO#putc: Writes a character to the stream.
15481 * - IO#each_char: Reads each remaining character in the stream,
15482 * passing the character to the given block.
15483 *
15484 * == Byte \IO
15485 *
15486 * You can process an \IO stream byte-by-byte using these methods:
15487 *
15488 * - IO#getbyte: Returns the next 8-bit byte as an integer in range 0..255.
15489 * - IO#readbyte: Like #getbyte, but raises an exception if at end-of-stream.
15490 * - IO#ungetbyte: Pushes back ("unshifts") a byte back onto the stream.
15491 * - IO#each_byte: Reads each remaining byte in the stream,
15492 * passing the byte to the given block.
15493 *
15494 * == Codepoint \IO
15495 *
15496 * You can process an \IO stream codepoint-by-codepoint:
15497 *
15498 * - IO#each_codepoint: Reads each remaining codepoint, passing it to the given block.
15499 *
15500 * == What's Here
15501 *
15502 * First, what's elsewhere. Class \IO:
15503 *
15504 * - Inherits from {class Object}[rdoc-ref:Object@What-27s+Here].
15505 * - Includes {module Enumerable}[rdoc-ref:Enumerable@What-27s+Here],
15506 * which provides dozens of additional methods.
15507 *
15508 * Here, class \IO provides methods that are useful for:
15509 *
15510 * - {Creating}[rdoc-ref:IO@Creating]
15511 * - {Reading}[rdoc-ref:IO@Reading]
15512 * - {Writing}[rdoc-ref:IO@Writing]
15513 * - {Positioning}[rdoc-ref:IO@Positioning]
15514 * - {Iterating}[rdoc-ref:IO@Iterating]
15515 * - {Settings}[rdoc-ref:IO@Settings]
15516 * - {Querying}[rdoc-ref:IO@Querying]
15517 * - {Buffering}[rdoc-ref:IO@Buffering]
15518 * - {Low-Level Access}[rdoc-ref:IO@Low-Level+Access]
15519 * - {Other}[rdoc-ref:IO@Other]
15520 *
15521 * === Creating
15522 *
15523 * - ::new (aliased as ::for_fd): Creates and returns a new \IO object for the given
15524 * integer file descriptor.
15525 * - ::open: Creates a new \IO object.
15526 * - ::pipe: Creates a connected pair of reader and writer \IO objects.
15527 * - ::popen: Creates an \IO object to interact with a subprocess.
15528 * - ::select: Selects which given \IO instances are ready for reading,
15529 * writing, or have pending exceptions.
15530 *
15531 * === Reading
15532 *
15533 * - ::binread: Returns a binary string with all or a subset of bytes
15534 * from the given file.
15535 * - ::read: Returns a string with all or a subset of bytes from the given file.
15536 * - ::readlines: Returns an array of strings, which are the lines from the given file.
15537 * - #getbyte: Returns the next 8-bit byte read from +self+ as an integer.
15538 * - #getc: Returns the next character read from +self+ as a string.
15539 * - #gets: Returns the line read from +self+.
15540 * - #pread: Returns all or the next _n_ bytes read from +self+,
15541 * not updating the receiver's offset.
15542 * - #read: Returns all remaining or the next _n_ bytes read from +self+
15543 * for a given _n_.
15544 * - #read_nonblock: the next _n_ bytes read from +self+ for a given _n_,
15545 * in non-block mode.
15546 * - #readbyte: Returns the next byte read from +self+;
15547 * same as #getbyte, but raises an exception on end-of-stream.
15548 * - #readchar: Returns the next character read from +self+;
15549 * same as #getc, but raises an exception on end-of-stream.
15550 * - #readline: Returns the next line read from +self+;
15551 * same as #getline, but raises an exception of end-of-stream.
15552 * - #readlines: Returns an array of all lines read read from +self+.
15553 * - #readpartial: Returns up to the given number of bytes from +self+.
15554 *
15555 * === Writing
15556 *
15557 * - ::binwrite: Writes the given string to the file at the given filepath,
15558 * in binary mode.
15559 * - ::write: Writes the given string to +self+.
15560 * - #<<: Appends the given string to +self+.
15561 * - #print: Prints last read line or given objects to +self+.
15562 * - #printf: Writes to +self+ based on the given format string and objects.
15563 * - #putc: Writes a character to +self+.
15564 * - #puts: Writes lines to +self+, making sure line ends with a newline.
15565 * - #pwrite: Writes the given string at the given offset,
15566 * not updating the receiver's offset.
15567 * - #write: Writes one or more given strings to +self+.
15568 * - #write_nonblock: Writes one or more given strings to +self+ in non-blocking mode.
15569 *
15570 * === Positioning
15571 *
15572 * - #lineno: Returns the current line number in +self+.
15573 * - #lineno=: Sets the line number is +self+.
15574 * - #pos (aliased as #tell): Returns the current byte offset in +self+.
15575 * - #pos=: Sets the byte offset in +self+.
15576 * - #reopen: Reassociates +self+ with a new or existing \IO stream.
15577 * - #rewind: Positions +self+ to the beginning of input.
15578 * - #seek: Sets the offset for +self+ relative to given position.
15579 *
15580 * === Iterating
15581 *
15582 * - ::foreach: Yields each line of given file to the block.
15583 * - #each (aliased as #each_line): Calls the given block
15584 * with each successive line in +self+.
15585 * - #each_byte: Calls the given block with each successive byte in +self+
15586 * as an integer.
15587 * - #each_char: Calls the given block with each successive character in +self+
15588 * as a string.
15589 * - #each_codepoint: Calls the given block with each successive codepoint in +self+
15590 * as an integer.
15591 *
15592 * === Settings
15593 *
15594 * - #autoclose=: Sets whether +self+ auto-closes.
15595 * - #binmode: Sets +self+ to binary mode.
15596 * - #close: Closes +self+.
15597 * - #close_on_exec=: Sets the close-on-exec flag.
15598 * - #close_read: Closes +self+ for reading.
15599 * - #close_write: Closes +self+ for writing.
15600 * - #set_encoding: Sets the encoding for +self+.
15601 * - #set_encoding_by_bom: Sets the encoding for +self+, based on its
15602 * Unicode byte-order-mark.
15603 * - #sync=: Sets the sync-mode to the given value.
15604 *
15605 * === Querying
15606 *
15607 * - #autoclose?: Returns whether +self+ auto-closes.
15608 * - #binmode?: Returns whether +self+ is in binary mode.
15609 * - #close_on_exec?: Returns the close-on-exec flag for +self+.
15610 * - #closed?: Returns whether +self+ is closed.
15611 * - #eof? (aliased as #eof): Returns whether +self+ is at end-of-stream.
15612 * - #external_encoding: Returns the external encoding object for +self+.
15613 * - #fileno (aliased as #to_i): Returns the integer file descriptor for +self+
15614 * - #internal_encoding: Returns the internal encoding object for +self+.
15615 * - #pid: Returns the process ID of a child process associated with +self+,
15616 * if +self+ was created by ::popen.
15617 * - #stat: Returns the File::Stat object containing status information for +self+.
15618 * - #sync: Returns whether +self+ is in sync-mode.
15619 * - #tty? (aliased as #isatty): Returns whether +self+ is a terminal.
15620 *
15621 * === Buffering
15622 *
15623 * - #fdatasync: Immediately writes all buffered data in +self+ to disk.
15624 * - #flush: Flushes any buffered data within +self+ to the underlying
15625 * operating system.
15626 * - #fsync: Immediately writes all buffered data and attributes in +self+ to disk.
15627 * - #ungetbyte: Prepends buffer for +self+ with given integer byte or string.
15628 * - #ungetc: Prepends buffer for +self+ with given string.
15629 *
15630 * === Low-Level Access
15631 *
15632 * - ::sysopen: Opens the file given by its path,
15633 * returning the integer file descriptor.
15634 * - #advise: Announces the intention to access data from +self+ in a specific way.
15635 * - #fcntl: Passes a low-level command to the file specified
15636 * by the given file descriptor.
15637 * - #ioctl: Passes a low-level command to the device specified
15638 * by the given file descriptor.
15639 * - #sysread: Returns up to the next _n_ bytes read from self using a low-level read.
15640 * - #sysseek: Sets the offset for +self+.
15641 * - #syswrite: Writes the given string to +self+ using a low-level write.
15642 *
15643 * === Other
15644 *
15645 * - ::copy_stream: Copies data from a source to a destination,
15646 * each of which is a filepath or an \IO-like object.
15647 * - ::try_convert: Returns a new \IO object resulting from converting
15648 * the given object.
15649 * - #inspect: Returns the string representation of +self+.
15650 *
15651 */
15652
15653void
15654Init_IO(void)
15655{
15656 VALUE rb_cARGF;
15657#ifdef __CYGWIN__
15658#include <sys/cygwin.h>
15659 static struct __cygwin_perfile pf[] =
15660 {
15661 {"", O_RDONLY | O_BINARY},
15662 {"", O_WRONLY | O_BINARY},
15663 {"", O_RDWR | O_BINARY},
15664 {"", O_APPEND | O_BINARY},
15665 {NULL, 0}
15666 };
15667 cygwin_internal(CW_PERFILE, pf);
15668#endif
15669
15672
15673 id_write = rb_intern_const("write");
15674 id_read = rb_intern_const("read");
15675 id_getc = rb_intern_const("getc");
15676 id_flush = rb_intern_const("flush");
15677 id_readpartial = rb_intern_const("readpartial");
15678 id_set_encoding = rb_intern_const("set_encoding");
15679 id_fileno = rb_intern_const("fileno");
15680
15681 rb_define_global_function("syscall", rb_f_syscall, -1);
15682
15683 rb_define_global_function("open", rb_f_open, -1);
15684 rb_define_global_function("printf", rb_f_printf, -1);
15685 rb_define_global_function("print", rb_f_print, -1);
15686 rb_define_global_function("putc", rb_f_putc, 1);
15687 rb_define_global_function("puts", rb_f_puts, -1);
15688 rb_define_global_function("gets", rb_f_gets, -1);
15689 rb_define_global_function("readline", rb_f_readline, -1);
15690 rb_define_global_function("select", rb_f_select, -1);
15691
15692 rb_define_global_function("readlines", rb_f_readlines, -1);
15693
15694 rb_define_global_function("`", rb_f_backquote, 1);
15695
15696 rb_define_global_function("p", rb_f_p, -1);
15697 rb_define_method(rb_mKernel, "display", rb_obj_display, -1);
15698
15699 rb_cIO = rb_define_class("IO", rb_cObject);
15701
15702 /* Can be raised by IO operations when IO#timeout= is set. */
15704
15705 /* Readable event mask for IO#wait. */
15706 rb_define_const(rb_cIO, "READABLE", INT2NUM(RUBY_IO_READABLE));
15707 /* Writable event mask for IO#wait. */
15708 rb_define_const(rb_cIO, "WRITABLE", INT2NUM(RUBY_IO_WRITABLE));
15709 /* Priority event mask for IO#wait. */
15710 rb_define_const(rb_cIO, "PRIORITY", INT2NUM(RUBY_IO_PRIORITY));
15711
15712 /* exception to wait for reading. see IO.select. */
15714 /* exception to wait for writing. see IO.select. */
15716 /* exception to wait for reading by EAGAIN. see IO.select. */
15717 rb_eEAGAINWaitReadable = rb_define_class_under(rb_cIO, "EAGAINWaitReadable", rb_eEAGAIN);
15718 rb_include_module(rb_eEAGAINWaitReadable, rb_mWaitReadable);
15719 /* exception to wait for writing by EAGAIN. see IO.select. */
15720 rb_eEAGAINWaitWritable = rb_define_class_under(rb_cIO, "EAGAINWaitWritable", rb_eEAGAIN);
15721 rb_include_module(rb_eEAGAINWaitWritable, rb_mWaitWritable);
15722#if EAGAIN == EWOULDBLOCK
15723 rb_eEWOULDBLOCKWaitReadable = rb_eEAGAINWaitReadable;
15724 /* same as IO::EAGAINWaitReadable */
15725 rb_define_const(rb_cIO, "EWOULDBLOCKWaitReadable", rb_eEAGAINWaitReadable);
15726 rb_eEWOULDBLOCKWaitWritable = rb_eEAGAINWaitWritable;
15727 /* same as IO::EAGAINWaitWritable */
15728 rb_define_const(rb_cIO, "EWOULDBLOCKWaitWritable", rb_eEAGAINWaitWritable);
15729#else
15730 /* exception to wait for reading by EWOULDBLOCK. see IO.select. */
15731 rb_eEWOULDBLOCKWaitReadable = rb_define_class_under(rb_cIO, "EWOULDBLOCKWaitReadable", rb_eEWOULDBLOCK);
15732 rb_include_module(rb_eEWOULDBLOCKWaitReadable, rb_mWaitReadable);
15733 /* exception to wait for writing by EWOULDBLOCK. see IO.select. */
15734 rb_eEWOULDBLOCKWaitWritable = rb_define_class_under(rb_cIO, "EWOULDBLOCKWaitWritable", rb_eEWOULDBLOCK);
15735 rb_include_module(rb_eEWOULDBLOCKWaitWritable, rb_mWaitWritable);
15736#endif
15737 /* exception to wait for reading by EINPROGRESS. see IO.select. */
15738 rb_eEINPROGRESSWaitReadable = rb_define_class_under(rb_cIO, "EINPROGRESSWaitReadable", rb_eEINPROGRESS);
15739 rb_include_module(rb_eEINPROGRESSWaitReadable, rb_mWaitReadable);
15740 /* exception to wait for writing by EINPROGRESS. see IO.select. */
15741 rb_eEINPROGRESSWaitWritable = rb_define_class_under(rb_cIO, "EINPROGRESSWaitWritable", rb_eEINPROGRESS);
15742 rb_include_module(rb_eEINPROGRESSWaitWritable, rb_mWaitWritable);
15743
15744#if 0
15745 /* This is necessary only for forcing rdoc handle File::open */
15746 rb_define_singleton_method(rb_cFile, "open", rb_io_s_open, -1);
15747#endif
15748
15749 rb_define_alloc_func(rb_cIO, io_alloc);
15750 rb_define_singleton_method(rb_cIO, "new", rb_io_s_new, -1);
15751 rb_define_singleton_method(rb_cIO, "open", rb_io_s_open, -1);
15752 rb_define_singleton_method(rb_cIO, "sysopen", rb_io_s_sysopen, -1);
15753 rb_define_singleton_method(rb_cIO, "for_fd", rb_io_s_for_fd, -1);
15754 rb_define_singleton_method(rb_cIO, "popen", rb_io_s_popen, -1);
15755 rb_define_singleton_method(rb_cIO, "foreach", rb_io_s_foreach, -1);
15756 rb_define_singleton_method(rb_cIO, "readlines", rb_io_s_readlines, -1);
15757 rb_define_singleton_method(rb_cIO, "read", rb_io_s_read, -1);
15758 rb_define_singleton_method(rb_cIO, "binread", rb_io_s_binread, -1);
15759 rb_define_singleton_method(rb_cIO, "write", rb_io_s_write, -1);
15760 rb_define_singleton_method(rb_cIO, "binwrite", rb_io_s_binwrite, -1);
15761 rb_define_singleton_method(rb_cIO, "select", rb_f_select, -1);
15762 rb_define_singleton_method(rb_cIO, "pipe", rb_io_s_pipe, -1);
15763 rb_define_singleton_method(rb_cIO, "try_convert", rb_io_s_try_convert, 1);
15764 rb_define_singleton_method(rb_cIO, "copy_stream", rb_io_s_copy_stream, -1);
15765
15766 rb_define_method(rb_cIO, "initialize", rb_io_initialize, -1);
15767
15769 rb_define_hooked_variable("$,", &rb_output_fs, 0, deprecated_str_setter);
15770
15771 rb_default_rs = rb_fstring_lit("\n"); /* avoid modifying RS_default */
15772 rb_vm_register_global_object(rb_default_rs);
15773 rb_rs = rb_default_rs;
15775 rb_define_hooked_variable("$/", &rb_rs, 0, deprecated_rs_setter);
15776 rb_gvar_ractor_local("$/"); // not local but ractor safe
15777 rb_define_hooked_variable("$-0", &rb_rs, 0, deprecated_rs_setter);
15778 rb_gvar_ractor_local("$-0"); // not local but ractor safe
15779 rb_define_hooked_variable("$\\", &rb_output_rs, 0, deprecated_str_setter);
15780
15781 rb_define_virtual_variable("$_", get_LAST_READ_LINE, set_LAST_READ_LINE);
15782 rb_gvar_ractor_local("$_");
15783
15784 rb_define_method(rb_cIO, "initialize_copy", rb_io_init_copy, 1);
15785 rb_define_method(rb_cIO, "reopen", rb_io_reopen, -1);
15786
15787 rb_define_method(rb_cIO, "print", rb_io_print, -1);
15788 rb_define_method(rb_cIO, "putc", rb_io_putc, 1);
15789 rb_define_method(rb_cIO, "puts", rb_io_puts, -1);
15790 rb_define_method(rb_cIO, "printf", rb_io_printf, -1);
15791
15792 rb_define_method(rb_cIO, "each", rb_io_each_line, -1);
15793 rb_define_method(rb_cIO, "each_line", rb_io_each_line, -1);
15794 rb_define_method(rb_cIO, "each_byte", rb_io_each_byte, 0);
15795 rb_define_method(rb_cIO, "each_char", rb_io_each_char, 0);
15796 rb_define_method(rb_cIO, "each_codepoint", rb_io_each_codepoint, 0);
15797
15798 rb_define_method(rb_cIO, "syswrite", rb_io_syswrite, 1);
15799 rb_define_method(rb_cIO, "sysread", rb_io_sysread, -1);
15800
15801 rb_define_method(rb_cIO, "pread", rb_io_pread, -1);
15802 rb_define_method(rb_cIO, "pwrite", rb_io_pwrite, 2);
15803
15804 rb_define_method(rb_cIO, "fileno", rb_io_fileno, 0);
15805 rb_define_alias(rb_cIO, "to_i", "fileno");
15806 rb_define_method(rb_cIO, "to_io", rb_io_to_io, 0);
15807
15808 rb_define_method(rb_cIO, "timeout", rb_io_timeout, 0);
15809 rb_define_method(rb_cIO, "timeout=", rb_io_set_timeout, 1);
15810
15811 rb_define_method(rb_cIO, "fsync", rb_io_fsync, 0);
15812 rb_define_method(rb_cIO, "fdatasync", rb_io_fdatasync, 0);
15813 rb_define_method(rb_cIO, "sync", rb_io_sync, 0);
15814 rb_define_method(rb_cIO, "sync=", rb_io_set_sync, 1);
15815
15816 rb_define_method(rb_cIO, "lineno", rb_io_lineno, 0);
15817 rb_define_method(rb_cIO, "lineno=", rb_io_set_lineno, 1);
15818
15819 rb_define_method(rb_cIO, "readlines", rb_io_readlines, -1);
15820
15821 rb_define_method(rb_cIO, "readpartial", io_readpartial, -1);
15822 rb_define_method(rb_cIO, "read", io_read, -1);
15823 rb_define_method(rb_cIO, "write", io_write_m, -1);
15824 rb_define_method(rb_cIO, "gets", rb_io_gets_m, -1);
15825 rb_define_method(rb_cIO, "getc", rb_io_getc, 0);
15826 rb_define_method(rb_cIO, "getbyte", rb_io_getbyte, 0);
15827 rb_define_method(rb_cIO, "readchar", rb_io_readchar, 0);
15828 rb_define_method(rb_cIO, "readbyte", rb_io_readbyte, 0);
15829 rb_define_method(rb_cIO, "ungetbyte",rb_io_ungetbyte, 1);
15830 rb_define_method(rb_cIO, "ungetc",rb_io_ungetc, 1);
15832 rb_define_method(rb_cIO, "flush", rb_io_flush, 0);
15833 rb_define_method(rb_cIO, "tell", rb_io_tell, 0);
15834 rb_define_method(rb_cIO, "seek", rb_io_seek_m, -1);
15835 /* Set I/O position from the beginning */
15836 rb_define_const(rb_cIO, "SEEK_SET", INT2FIX(SEEK_SET));
15837 /* Set I/O position from the current position */
15838 rb_define_const(rb_cIO, "SEEK_CUR", INT2FIX(SEEK_CUR));
15839 /* Set I/O position from the end */
15840 rb_define_const(rb_cIO, "SEEK_END", INT2FIX(SEEK_END));
15841#ifdef SEEK_DATA
15842 /* Set I/O position to the next location containing data */
15843 rb_define_const(rb_cIO, "SEEK_DATA", INT2FIX(SEEK_DATA));
15844#endif
15845#ifdef SEEK_HOLE
15846 /* Set I/O position to the next hole */
15847 rb_define_const(rb_cIO, "SEEK_HOLE", INT2FIX(SEEK_HOLE));
15848#endif
15849 rb_define_method(rb_cIO, "rewind", rb_io_rewind, 0);
15850 rb_define_method(rb_cIO, "pos", rb_io_tell, 0);
15851 rb_define_method(rb_cIO, "pos=", rb_io_set_pos, 1);
15852 rb_define_method(rb_cIO, "eof", rb_io_eof, 0);
15853 rb_define_method(rb_cIO, "eof?", rb_io_eof, 0);
15854
15855 rb_define_method(rb_cIO, "close_on_exec?", rb_io_close_on_exec_p, 0);
15856 rb_define_method(rb_cIO, "close_on_exec=", rb_io_set_close_on_exec, 1);
15857
15858 rb_define_method(rb_cIO, "close", rb_io_close_m, 0);
15859 rb_define_method(rb_cIO, "closed?", rb_io_closed_p, 0);
15860 rb_define_method(rb_cIO, "close_read", rb_io_close_read, 0);
15861 rb_define_method(rb_cIO, "close_write", rb_io_close_write, 0);
15862
15863 rb_define_method(rb_cIO, "isatty", rb_io_isatty, 0);
15864 rb_define_method(rb_cIO, "tty?", rb_io_isatty, 0);
15865 rb_define_method(rb_cIO, "binmode", rb_io_binmode_m, 0);
15866 rb_define_method(rb_cIO, "binmode?", rb_io_binmode_p, 0);
15867 rb_define_method(rb_cIO, "sysseek", rb_io_sysseek, -1);
15868 rb_define_method(rb_cIO, "advise", rb_io_advise, -1);
15869
15870 rb_define_method(rb_cIO, "ioctl", rb_io_ioctl, -1);
15871 rb_define_method(rb_cIO, "fcntl", rb_io_fcntl, -1);
15872 rb_define_method(rb_cIO, "pid", rb_io_pid, 0);
15873
15874 rb_define_method(rb_cIO, "path", rb_io_path, 0);
15875 rb_define_method(rb_cIO, "to_path", rb_io_path, 0);
15876
15877 rb_define_method(rb_cIO, "inspect", rb_io_inspect, 0);
15878
15879 rb_define_method(rb_cIO, "external_encoding", rb_io_external_encoding, 0);
15880 rb_define_method(rb_cIO, "internal_encoding", rb_io_internal_encoding, 0);
15881 rb_define_method(rb_cIO, "set_encoding", rb_io_set_encoding, -1);
15882 rb_define_method(rb_cIO, "set_encoding_by_bom", rb_io_set_encoding_by_bom, 0);
15883
15884 rb_define_method(rb_cIO, "autoclose?", rb_io_autoclose_p, 0);
15885 rb_define_method(rb_cIO, "autoclose=", rb_io_set_autoclose, 1);
15886
15887 rb_define_method(rb_cIO, "wait", io_wait, -1);
15888
15889 rb_define_method(rb_cIO, "wait_readable", io_wait_readable, -1);
15890 rb_define_method(rb_cIO, "wait_writable", io_wait_writable, -1);
15891 rb_define_method(rb_cIO, "wait_priority", io_wait_priority, -1);
15892
15893 rb_define_virtual_variable("$stdin", stdin_getter, stdin_setter);
15894 rb_define_virtual_variable("$stdout", stdout_getter, stdout_setter);
15895 rb_define_virtual_variable("$>", stdout_getter, stdout_setter);
15896 rb_define_virtual_variable("$stderr", stderr_getter, stderr_setter);
15897
15898 rb_gvar_ractor_local("$stdin");
15899 rb_gvar_ractor_local("$stdout");
15900 rb_gvar_ractor_local("$>");
15901 rb_gvar_ractor_local("$stderr");
15902
15904 rb_stdin = rb_io_prep_stdin();
15906 rb_stdout = rb_io_prep_stdout();
15908 rb_stderr = rb_io_prep_stderr();
15909
15910 orig_stdout = rb_stdout;
15911 orig_stderr = rb_stderr;
15912
15913 /* Holds the original stdin */
15915 /* Holds the original stdout */
15917 /* Holds the original stderr */
15919
15920#if 0
15921 /* Hack to get rdoc to regard ARGF as a class: */
15922 rb_cARGF = rb_define_class("ARGF", rb_cObject);
15923#endif
15924
15925 rb_cARGF = rb_class_new(rb_cObject);
15926 rb_set_class_path(rb_cARGF, rb_cObject, "ARGF.class");
15927 rb_define_alloc_func(rb_cARGF, argf_alloc);
15928
15930
15931 rb_define_method(rb_cARGF, "initialize", argf_initialize, -2);
15932 rb_define_method(rb_cARGF, "initialize_copy", argf_initialize_copy, 1);
15933 rb_define_method(rb_cARGF, "to_s", argf_to_s, 0);
15934 rb_define_alias(rb_cARGF, "inspect", "to_s");
15935 rb_define_method(rb_cARGF, "argv", argf_argv, 0);
15936
15937 rb_define_method(rb_cARGF, "fileno", argf_fileno, 0);
15938 rb_define_method(rb_cARGF, "to_i", argf_fileno, 0);
15939 rb_define_method(rb_cARGF, "to_io", argf_to_io, 0);
15940 rb_define_method(rb_cARGF, "to_write_io", argf_write_io, 0);
15941 rb_define_method(rb_cARGF, "each", argf_each_line, -1);
15942 rb_define_method(rb_cARGF, "each_line", argf_each_line, -1);
15943 rb_define_method(rb_cARGF, "each_byte", argf_each_byte, 0);
15944 rb_define_method(rb_cARGF, "each_char", argf_each_char, 0);
15945 rb_define_method(rb_cARGF, "each_codepoint", argf_each_codepoint, 0);
15946
15947 rb_define_method(rb_cARGF, "read", argf_read, -1);
15948 rb_define_method(rb_cARGF, "readpartial", argf_readpartial, -1);
15949 rb_define_method(rb_cARGF, "read_nonblock", argf_read_nonblock, -1);
15950 rb_define_method(rb_cARGF, "readlines", argf_readlines, -1);
15951 rb_define_method(rb_cARGF, "to_a", argf_readlines, -1);
15952 rb_define_method(rb_cARGF, "gets", argf_gets, -1);
15953 rb_define_method(rb_cARGF, "readline", argf_readline, -1);
15954 rb_define_method(rb_cARGF, "getc", argf_getc, 0);
15955 rb_define_method(rb_cARGF, "getbyte", argf_getbyte, 0);
15956 rb_define_method(rb_cARGF, "readchar", argf_readchar, 0);
15957 rb_define_method(rb_cARGF, "readbyte", argf_readbyte, 0);
15958 rb_define_method(rb_cARGF, "tell", argf_tell, 0);
15959 rb_define_method(rb_cARGF, "seek", argf_seek_m, -1);
15960 rb_define_method(rb_cARGF, "rewind", argf_rewind, 0);
15961 rb_define_method(rb_cARGF, "pos", argf_tell, 0);
15962 rb_define_method(rb_cARGF, "pos=", argf_set_pos, 1);
15963 rb_define_method(rb_cARGF, "eof", argf_eof, 0);
15964 rb_define_method(rb_cARGF, "eof?", argf_eof, 0);
15965 rb_define_method(rb_cARGF, "binmode", argf_binmode_m, 0);
15966 rb_define_method(rb_cARGF, "binmode?", argf_binmode_p, 0);
15967
15968 rb_define_method(rb_cARGF, "write", argf_write, -1);
15969 rb_define_method(rb_cARGF, "print", rb_io_print, -1);
15970 rb_define_method(rb_cARGF, "putc", rb_io_putc, 1);
15971 rb_define_method(rb_cARGF, "puts", rb_io_puts, -1);
15972 rb_define_method(rb_cARGF, "printf", rb_io_printf, -1);
15973
15974 rb_define_method(rb_cARGF, "filename", argf_filename, 0);
15975 rb_define_method(rb_cARGF, "path", argf_filename, 0);
15976 rb_define_method(rb_cARGF, "file", argf_file, 0);
15977 rb_define_method(rb_cARGF, "skip", argf_skip, 0);
15978 rb_define_method(rb_cARGF, "close", argf_close_m, 0);
15979 rb_define_method(rb_cARGF, "closed?", argf_closed, 0);
15980
15981 rb_define_method(rb_cARGF, "lineno", argf_lineno, 0);
15982 rb_define_method(rb_cARGF, "lineno=", argf_set_lineno, 1);
15983
15984 rb_define_method(rb_cARGF, "inplace_mode", argf_inplace_mode_get, 0);
15985 rb_define_method(rb_cARGF, "inplace_mode=", argf_inplace_mode_set, 1);
15986
15987 rb_define_method(rb_cARGF, "external_encoding", argf_external_encoding, 0);
15988 rb_define_method(rb_cARGF, "internal_encoding", argf_internal_encoding, 0);
15989 rb_define_method(rb_cARGF, "set_encoding", argf_set_encoding, -1);
15990
15991 argf = rb_class_new_instance(0, 0, rb_cARGF);
15992
15994 /*
15995 * ARGF is a stream designed for use in scripts that process files given
15996 * as command-line arguments or passed in via STDIN.
15997 *
15998 * See ARGF (the class) for more details.
15999 */
16001
16002 rb_define_hooked_variable("$.", &argf, argf_lineno_getter, argf_lineno_setter);
16003 rb_define_hooked_variable("$FILENAME", &argf, argf_filename_getter, rb_gvar_readonly_setter);
16004 ARGF.filename = rb_str_new2("-");
16005
16006 rb_define_hooked_variable("$-i", &argf, opt_i_get, opt_i_set);
16007 rb_gvar_ractor_local("$-i");
16008
16009 rb_define_hooked_variable("$*", &argf, argf_argv_getter, rb_gvar_readonly_setter);
16010
16011#if defined (_WIN32) || defined(__CYGWIN__)
16012 atexit(pipe_atexit);
16013#endif
16014
16015 Init_File();
16016
16017 rb_define_method(rb_cFile, "initialize", rb_file_initialize, -1);
16018
16019 sym_mode = ID2SYM(rb_intern_const("mode"));
16020 sym_perm = ID2SYM(rb_intern_const("perm"));
16021 sym_flags = ID2SYM(rb_intern_const("flags"));
16022 sym_extenc = ID2SYM(rb_intern_const("external_encoding"));
16023 sym_intenc = ID2SYM(rb_intern_const("internal_encoding"));
16024 sym_encoding = ID2SYM(rb_id_encoding());
16025 sym_open_args = ID2SYM(rb_intern_const("open_args"));
16026 sym_textmode = ID2SYM(rb_intern_const("textmode"));
16027 sym_binmode = ID2SYM(rb_intern_const("binmode"));
16028 sym_autoclose = ID2SYM(rb_intern_const("autoclose"));
16029 sym_normal = ID2SYM(rb_intern_const("normal"));
16030 sym_sequential = ID2SYM(rb_intern_const("sequential"));
16031 sym_random = ID2SYM(rb_intern_const("random"));
16032 sym_willneed = ID2SYM(rb_intern_const("willneed"));
16033 sym_dontneed = ID2SYM(rb_intern_const("dontneed"));
16034 sym_noreuse = ID2SYM(rb_intern_const("noreuse"));
16035 sym_SET = ID2SYM(rb_intern_const("SET"));
16036 sym_CUR = ID2SYM(rb_intern_const("CUR"));
16037 sym_END = ID2SYM(rb_intern_const("END"));
16038#ifdef SEEK_DATA
16039 sym_DATA = ID2SYM(rb_intern_const("DATA"));
16040#endif
16041#ifdef SEEK_HOLE
16042 sym_HOLE = ID2SYM(rb_intern_const("HOLE"));
16043#endif
16044 sym_wait_readable = ID2SYM(rb_intern_const("wait_readable"));
16045 sym_wait_writable = ID2SYM(rb_intern_const("wait_writable"));
16046}
16047
16048#include "io.rbinc"
#define RUBY_ASSERT(...)
Asserts that the given expression is truthy if and only if RUBY_DEBUG is truthy.
Definition assert.h:219
std::atomic< unsigned > rb_atomic_t
Type that is eligible for atomic operations.
Definition atomic.h:69
unsigned long ruby_strtoul(const char *str, char **endptr, int base)
Our own locale-insensitive version of strtoul(3).
Definition util.c:117
#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.
Definition class.c:1820
VALUE rb_define_class(const char *name, VALUE super)
Defines a top-level class.
Definition class.c:1603
VALUE rb_class_new(VALUE super)
Creates a new, anonymous class.
Definition class.c:983
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
Definition class.c:1639
VALUE rb_define_module_under(VALUE outer, const char *name)
Defines a module under the namespace of outer.
Definition class.c:1749
void rb_define_alias(VALUE klass, const char *name1, const char *name2)
Defines an alias of a method.
Definition class.c:2972
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.
Definition class.c:3275
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.
Definition class.c:3262
int rb_block_given_p(void)
Determines if the current method is given a block.
Definition eval.c:1037
int rb_get_kwargs(VALUE keyword_hash, const ID *table, int required, int optional, VALUE *values)
Keyword argument deconstructor.
Definition class.c:3051
#define ECONV_AFTER_OUTPUT
Old name of RUBY_ECONV_AFTER_OUTPUT.
Definition transcode.h:555
#define rb_str_new2
Old name of rb_str_new_cstr.
Definition string.h:1674
#define TYPE(_)
Old name of rb_type.
Definition value_type.h:108
#define RB_INTEGER_TYPE_P
Old name of rb_integer_type_p.
Definition value_type.h:87
#define ENC_CODERANGE_7BIT
Old name of RUBY_ENC_CODERANGE_7BIT.
Definition coderange.h:180
#define T_FILE
Old name of RUBY_T_FILE.
Definition value_type.h:62
#define ENC_CODERANGE_VALID
Old name of RUBY_ENC_CODERANGE_VALID.
Definition coderange.h:181
#define ECONV_UNIVERSAL_NEWLINE_DECORATOR
Old name of RUBY_ECONV_UNIVERSAL_NEWLINE_DECORATOR.
Definition transcode.h:532
#define OBJ_INIT_COPY(obj, orig)
Old name of RB_OBJ_INIT_COPY.
Definition object.h:41
#define ALLOC
Old name of RB_ALLOC.
Definition memory.h:400
#define RFLOAT_VALUE
Old name of rb_float_value.
Definition double.h:28
#define T_STRING
Old name of RUBY_T_STRING.
Definition value_type.h:78
#define Qundef
Old name of RUBY_Qundef.
#define INT2FIX
Old name of RB_INT2FIX.
Definition long.h:48
#define rb_str_cat2
Old name of rb_str_cat_cstr.
Definition string.h:1682
#define T_NIL
Old name of RUBY_T_NIL.
Definition value_type.h:72
#define UNREACHABLE
Old name of RBIMPL_UNREACHABLE.
Definition assume.h:28
#define ID2SYM
Old name of RB_ID2SYM.
Definition symbol.h:44
#define T_BIGNUM
Old name of RUBY_T_BIGNUM.
Definition value_type.h:57
#define OBJ_FREEZE
Old name of RB_OBJ_FREEZE.
Definition fl_type.h:134
#define T_FIXNUM
Old name of RUBY_T_FIXNUM.
Definition value_type.h:63
#define UNREACHABLE_RETURN
Old name of RBIMPL_UNREACHABLE_RETURN.
Definition assume.h:29
#define FIX2UINT
Old name of RB_FIX2UINT.
Definition int.h:42
#define SSIZET2NUM
Old name of RB_SSIZE2NUM.
Definition size_t.h:64
#define ZALLOC
Old name of RB_ZALLOC.
Definition memory.h:402
#define CLASS_OF
Old name of rb_class_of.
Definition globals.h:206
#define rb_ary_new4
Old name of rb_ary_new_from_values.
Definition array.h:659
#define ENCODING_MAXNAMELEN
Old name of RUBY_ENCODING_MAXNAMELEN.
Definition encoding.h:111
#define MBCLEN_NEEDMORE_LEN(ret)
Old name of ONIGENC_MBCLEN_NEEDMORE_LEN.
Definition encoding.h:520
#define ENCODING_GET(obj)
Old name of RB_ENCODING_GET.
Definition encoding.h:109
#define LONG2FIX
Old name of RB_INT2FIX.
Definition long.h:49
#define NUM2UINT
Old name of RB_NUM2UINT.
Definition int.h:45
#define ALLOC_N
Old name of RB_ALLOC_N.
Definition memory.h:399
#define MBCLEN_CHARFOUND_LEN(ret)
Old name of ONIGENC_MBCLEN_CHARFOUND_LEN.
Definition encoding.h:517
#define LONG2NUM
Old name of RB_LONG2NUM.
Definition long.h:50
#define rb_exc_new3
Old name of rb_exc_new_str.
Definition error.h:38
#define STRNCASECMP
Old name of st_locale_insensitive_strncasecmp.
Definition ctype.h:103
#define MBCLEN_INVALID_P(ret)
Old name of ONIGENC_MBCLEN_INVALID_P.
Definition encoding.h:518
#define ISASCII
Old name of rb_isascii.
Definition ctype.h:85
#define ECONV_STATEFUL_DECORATOR_MASK
Old name of RUBY_ECONV_STATEFUL_DECORATOR_MASK.
Definition transcode.h:538
#define Qtrue
Old name of RUBY_Qtrue.
#define MBCLEN_NEEDMORE_P(ret)
Old name of ONIGENC_MBCLEN_NEEDMORE_P.
Definition encoding.h:519
#define ECONV_PARTIAL_INPUT
Old name of RUBY_ECONV_PARTIAL_INPUT.
Definition transcode.h:554
#define NUM2INT
Old name of RB_NUM2INT.
Definition int.h:44
#define ECONV_ERROR_HANDLER_MASK
Old name of RUBY_ECONV_ERROR_HANDLER_MASK.
Definition transcode.h:522
#define INT2NUM
Old name of RB_INT2NUM.
Definition int.h:43
#define Qnil
Old name of RUBY_Qnil.
#define Qfalse
Old name of RUBY_Qfalse.
#define FIX2LONG
Old name of RB_FIX2LONG.
Definition long.h:46
#define ENC_CODERANGE_BROKEN
Old name of RUBY_ENC_CODERANGE_BROKEN.
Definition coderange.h:182
#define T_ARRAY
Old name of RUBY_T_ARRAY.
Definition value_type.h:56
#define NIL_P
Old name of RB_NIL_P.
#define ALLOCV_N
Old name of RB_ALLOCV_N.
Definition memory.h:405
#define MBCLEN_CHARFOUND_P(ret)
Old name of ONIGENC_MBCLEN_CHARFOUND_P.
Definition encoding.h:516
#define NUM2CHR
Old name of RB_NUM2CHR.
Definition char.h:33
#define NUM2LONG
Old name of RB_NUM2LONG.
Definition long.h:51
#define UINT2NUM
Old name of RB_UINT2NUM.
Definition int.h:46
#define FIXNUM_P
Old name of RB_FIXNUM_P.
#define ECONV_NEWLINE_DECORATOR_MASK
Old name of RUBY_ECONV_NEWLINE_DECORATOR_MASK.
Definition transcode.h:529
#define CONST_ID
Old name of RUBY_CONST_ID.
Definition symbol.h:47
#define rb_ary_new2
Old name of rb_ary_new_capa.
Definition array.h:657
#define NUM2SIZET
Old name of RB_NUM2SIZE.
Definition size_t.h:61
#define ENC_CODERANGE_SET(obj, cr)
Old name of RB_ENC_CODERANGE_SET.
Definition coderange.h:186
#define rb_str_new4
Old name of rb_str_new_frozen.
Definition string.h:1676
#define ALLOCV_END
Old name of RB_ALLOCV_END.
Definition memory.h:406
#define SYMBOL_P
Old name of RB_SYMBOL_P.
Definition value_type.h:88
#define ECONV_DEFAULT_NEWLINE_DECORATOR
Old name of RUBY_ECONV_DEFAULT_NEWLINE_DECORATOR.
Definition transcode.h:540
void rb_notimplement(void)
Definition error.c:3839
void rb_category_warn(rb_warning_category_t category, const char *fmt,...)
Identical to rb_category_warning(), except it reports unless $VERBOSE is nil.
Definition error.c:476
void rb_category_warning(rb_warning_category_t category, const char *fmt,...)
Identical to rb_warning(), except it takes additional "category" parameter.
Definition error.c:508
VALUE rb_eNotImpError
NotImplementedError exception.
Definition error.c:1440
void rb_exc_raise(VALUE mesg)
Raises an exception in the current thread.
Definition eval.c:683
void rb_syserr_fail(int e, const char *mesg)
Raises appropriate exception that represents a C errno.
Definition error.c:3908
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.
Definition io.c:14727
VALUE rb_eIOError
IOError exception.
Definition io.c:189
VALUE rb_eStandardError
StandardError exception.
Definition error.c:1427
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.
Definition error.c:3998
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.
Definition error.c:3914
#define ruby_verbose
This variable controls whether the interpreter is in debug mode.
Definition error.h:475
VALUE rb_eTypeError
TypeError exception.
Definition error.c:1430
VALUE rb_eEOFError
EOFError exception.
Definition io.c:188
void rb_readwrite_sys_fail(enum rb_io_wait_readwrite waiting, const char *mesg)
Raises appropriate exception using the parameters.
Definition io.c:14721
void rb_iter_break_value(VALUE val)
Identical to rb_iter_break(), except it additionally takes the "value" of this breakage.
Definition vm.c:2238
rb_io_wait_readwrite
for rb_readwrite_sys_fail first argument
Definition error.h:73
VALUE rb_eRuntimeError
RuntimeError exception.
Definition error.c:1428
void rb_warn(const char *fmt,...)
Identical to rb_warning(), except it reports unless $VERBOSE is nil.
Definition error.c:466
VALUE rb_eSystemCallError
SystemCallError exception.
Definition error.c:1450
@ RB_WARN_CATEGORY_DEPRECATED
Warning is for deprecated features.
Definition error.h:48
VALUE rb_mKernel
Kernel module.
Definition object.c:60
VALUE rb_check_to_int(VALUE val)
Identical to rb_check_to_integer(), except it uses #to_int for conversion.
Definition object.c:3268
VALUE rb_any_to_s(VALUE obj)
Generates a textual representation of the given object.
Definition object.c:676
VALUE rb_obj_alloc(VALUE klass)
Allocates an instance of the given class.
Definition object.c:2164
VALUE rb_class_new_instance(int argc, const VALUE *argv, VALUE klass)
Allocates, then initialises an instance of the given class.
Definition object.c:2205
VALUE rb_cIO
IO class.
Definition io.c:187
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...
Definition object.c:2193
VALUE rb_mEnumerable
Enumerable module.
Definition enum.c:27
VALUE rb_stdin
STDIN constant.
Definition io.c:201
VALUE rb_stderr
STDERR constant.
Definition io.c:201
VALUE rb_obj_class(VALUE obj)
Queries the class of an object.
Definition object.c:265
VALUE rb_obj_dup(VALUE obj)
Duplicates the given object.
Definition object.c:583
VALUE rb_inspect(VALUE obj)
Generates a human-readable textual representation of the given object.
Definition object.c:687
VALUE rb_mWaitReadable
IO::WaitReadable module.
Definition io.c:191
VALUE rb_mWaitWritable
IO::WaitReadable module.
Definition io.c:192
VALUE rb_obj_freeze(VALUE obj)
Just calls rb_obj_freeze_inline() inside.
Definition object.c:1329
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.
Definition object.c:3249
VALUE rb_cFile
File class.
Definition file.c:191
VALUE rb_stdout
STDOUT constant.
Definition io.c:201
VALUE rb_to_int(VALUE val)
Identical to rb_check_to_int(), except it raises in case of conversion mismatch.
Definition object.c:3262
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.
Definition encoding.h:571
VALUE rb_str_conv_enc(VALUE str, rb_encoding *from, rb_encoding *to)
Encoding conversion main routine.
Definition string.c:1332
int rb_enc_str_coderange(VALUE str)
Scans the passed string to collect its code range.
Definition string.c:937
VALUE rb_enc_uint_chr(unsigned int code, rb_encoding *enc)
Encodes the passed code point into a series of bytes.
Definition numeric.c:3803
long rb_str_coderange_scan_restartable(const char *str, const char *end, rb_encoding *enc, int *cr)
Scans the passed string until it finds something odd.
Definition string.c:821
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.
Definition transcode.c:2655
VALUE rb_econv_open_exc(const char *senc, const char *denc, int ecflags)
Creates a rb_eConverterNotFoundError exception object (but does not raise).
Definition transcode.c:2123
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.
Definition transcode.c:1485
rb_econv_result_t
return value of rb_econv_convert()
Definition transcode.h:30
@ econv_incomplete_input
The conversion stopped in middle of reading a character, possibly due to a partial read of a socket e...
Definition transcode.h:69
@ econv_finished
The conversion stopped after converting everything.
Definition transcode.h:57
@ econv_undefined_conversion
The conversion stopped when it found a character in the input which cannot be representable in the ou...
Definition transcode.h:41
@ econv_source_buffer_empty
The conversion stopped because there is no input.
Definition transcode.h:51
@ econv_destination_buffer_full
The conversion stopped because there is no destination.
Definition transcode.h:46
@ econv_invalid_byte_sequence
The conversion stopped when it found an invalid sequence.
Definition transcode.h:35
int rb_econv_putbackable(rb_econv_t *ec)
Queries if rb_econv_putback() makes sense, i.e.
Definition transcode.c:1780
const char * rb_econv_asciicompat_encoding(const char *encname)
Queries the passed encoding's corresponding ASCII compatible encoding.
Definition transcode.c:1824
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.
Definition transcode.c:1959
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.
Definition transcode.c:2706
void rb_econv_binmode(rb_econv_t *ec)
This badly named function does not set the destination encoding to binary, but instead just nullifies...
Definition transcode.c:2022
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.
Definition transcode.c:2969
VALUE rb_econv_make_exception(rb_econv_t *ec)
This function makes sense right after rb_econv_convert() returns.
Definition transcode.c:4335
void rb_econv_check_error(rb_econv_t *ec)
This is a rb_econv_make_exception() + rb_exc_raise() combo.
Definition transcode.c:4341
void rb_econv_close(rb_econv_t *ec)
Destructs a converter.
Definition transcode.c:1741
void rb_econv_putback(rb_econv_t *ec, unsigned char *p, int n)
Puts back the bytes.
Definition transcode.c:1791
VALUE rb_funcall(VALUE recv, ID mid, int n,...)
Calls a method.
Definition vm_eval.c:1117
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.
Definition vm_eval.c:1084
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_check_array_type(VALUE obj)
Try converting an object to its array representation using its to_ary method, if any.
VALUE rb_ary_new(void)
Allocates a new, empty array.
VALUE rb_ary_push(VALUE ary, VALUE elem)
Special case of rb_ary_cat() that it adds only one element.
VALUE rb_ary_entry(VALUE ary, long off)
Queries an element of an array.
VALUE rb_assoc_new(VALUE car, VALUE cdr)
Identical to rb_ary_new_from_values(), except it expects exactly two parameters.
#define RETURN_ENUMERATOR(obj, argc, argv)
Identical to RETURN_SIZED_ENUMERATOR(), except its size is unknown.
Definition enumerator.h:239
static int rb_check_arity(int argc, int min, int max)
Ensures that the passed integer is in the passed range.
Definition error.h:284
VALUE rb_io_printf(int argc, const VALUE *argv, VALUE io)
This is a rb_f_sprintf() + rb_io_write() combo.
Definition io.c:8621
VALUE rb_io_gets(VALUE io)
Reads a "line" from the given IO.
Definition io.c:4304
int rb_cloexec_pipe(int fildes[2])
Opens a pipe with closing on exec.
Definition io.c:427
VALUE rb_io_print(int argc, const VALUE *argv, VALUE io)
Iterates over the passed array to apply rb_io_write() individually.
Definition io.c:8766
VALUE rb_io_addstr(VALUE io, VALUE str)
Identical to rb_io_write(), except it always returns the passed IO.
Definition io.c:2351
void rb_write_error(const char *str)
Writes the given error message to somewhere applicable.
Definition io.c:9195
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.
Definition io.c:5179
VALUE rb_io_getbyte(VALUE io)
Reads a byte from the given IO.
Definition io.c:5085
int rb_cloexec_dup2(int oldfd, int newfd)
Identical to rb_cloexec_dup(), except you can specify the destination file descriptor.
Definition io.c:374
VALUE rb_io_fdopen(int fd, int flags, const char *path)
Creates an IO instance whose backend is the given file descriptor.
Definition io.c:9376
void rb_update_max_fd(int fd)
Informs the interpreter that the passed fd can be the max.
Definition io.c:248
int rb_cloexec_open(const char *pathname, int flags, mode_t mode)
Opens a file that closes on exec.
Definition io.c:328
VALUE rb_output_rs
The record separator character for outputs, or the $\.
Definition io.c:206
VALUE rb_io_eof(VALUE io)
Queries if the passed IO is at the end of file.
Definition io.c:2696
void rb_write_error2(const char *str, long len)
Identical to rb_write_error(), except it additionally takes the message's length.
Definition io.c:9175
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.
Definition io.c:298
VALUE rb_io_ascii8bit_binmode(VALUE io)
Forces no conversions be applied to the passed IO.
Definition io.c:6385
VALUE rb_io_binmode(VALUE io)
Sets the binmode.
Definition io.c:6339
VALUE rb_io_ungetc(VALUE io, VALUE c)
"Unget"s a string.
Definition io.c:5243
int rb_pipe(int *pipes)
This is an rb_cloexec_pipe() + rb_update_max_fd() combo.
Definition io.c:7387
VALUE rb_gets(void)
Much like rb_io_gets(), but it reads from the mysterious ARGF object.
Definition io.c:10454
int rb_cloexec_fcntl_dupfd(int fd, int minfd)
Duplicates a file descriptor with closing on exec.
Definition io.c:461
VALUE rb_output_fs
The field separator character for outputs, or the $,.
Definition io.c:204
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.
Definition io.c:7270
int rb_cloexec_dup(int oldfd)
Identical to rb_cloexec_fcntl_dupfd(), except it implies minfd is 3.
Definition io.c:367
VALUE rb_file_open(const char *fname, const char *fmode)
Opens a file located at the given path.
Definition io.c:7277
VALUE rb_io_close(VALUE io)
Closes the IO.
Definition io.c:5759
VALUE rb_default_rs
This is the default value of rb_rs, i.e.
Definition io.c:207
void rb_lastline_set(VALUE str)
Updates $_.
Definition vm.c:2000
VALUE rb_lastline_get(void)
Queries the last line, or the $_.
Definition vm.c:1994
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...
Definition proc.c:2987
rb_pid_t rb_waitpid(rb_pid_t pid, int *status, int flags)
Waits for a process, with releasing GVL.
Definition process.c:1168
void rb_last_status_set(int status, rb_pid_t pid)
Sets the "last status", or the $?.
Definition process.c:682
VALUE rb_str_append(VALUE dst, VALUE src)
Identical to rb_str_buf_append(), except it converts the right hand side before concatenating.
Definition string.c:3787
#define rb_str_new(str, len)
Allocates an instance of rb_cString.
Definition string.h:1497
#define rb_str_buf_cat
Just another name of rb_str_cat.
Definition string.h:1680
#define rb_usascii_str_new(str, len)
Identical to rb_str_new, except it generates a string of "US ASCII" encoding.
Definition string.h:1531
size_t rb_str_capacity(VALUE str)
Queries the capacity of the given string.
Definition string.c:991
VALUE rb_str_new_frozen(VALUE str)
Creates a frozen copy of the string, if necessary.
Definition string.c:1508
VALUE rb_str_dup(VALUE str)
Duplicates a string.
Definition string.c:1986
VALUE rb_str_cat(VALUE dst, const char *src, long srclen)
Destructively appends the passed contents to the string.
Definition string.c:3555
VALUE rb_str_locktmp(VALUE str)
Obtains a "temporary lock" of the string.
rb_gvar_setter_t rb_str_setter
This is a rb_gvar_setter_t that refutes non-string assignments.
Definition string.h:1145
VALUE rb_str_equal(VALUE str1, VALUE str2)
Equality of two strings.
Definition string.c:4257
void rb_str_set_len(VALUE str, long len)
Overwrites the length of the string.
Definition string.c:3377
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 ...
Definition string.c:3729
VALUE rb_check_string_type(VALUE obj)
Try converting an object to its stringised representation using its to_str method,...
Definition string.c:2940
VALUE rb_str_substr(VALUE str, long beg, long len)
This is the implementation of two-argumented String#slice.
Definition string.c:3240
VALUE rb_str_unlocktmp(VALUE str)
Releases a lock formerly obtained by rb_str_locktmp().
Definition string.c:3359
void rb_str_modify_expand(VALUE str, long capa)
Identical to rb_str_modify(), except it additionally expands the capacity of the receiver.
Definition string.c:2734
VALUE rb_str_buf_new(long capa)
Allocates a "string buffer".
Definition string.c:1708
#define rb_str_new_cstr(str)
Identical to rb_str_new, except it assumes the passed pointer is a pointer to a C string.
Definition string.h:1513
VALUE rb_obj_as_string(VALUE obj)
Try converting an object to its stringised representation using its to_s method, if any.
Definition string.c:1840
int rb_thread_interrupted(VALUE thval)
Checks if the thread's execution was recently interrupted.
Definition thread.c:1469
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...
Definition io.c:1604
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.
Definition thread.c:1452
VALUE rb_thread_current(void)
Obtains the "current" thread.
Definition thread.c:3159
int rb_thread_wait_fd(int fd)
Blocks the current thread until the given file descriptor is ready to be read.
Definition io.c:1598
void rb_thread_sleep(int sec)
Blocks for the given period of time.
Definition thread.c:1475
struct timeval rb_time_interval(VALUE num)
Creates a "time interval".
Definition time.c:2948
void rb_set_class_path(VALUE klass, VALUE space, const char *name)
Names a class.
Definition variable.c:441
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.
Definition variable.c:1986
VALUE rb_class_name(VALUE obj)
Queries the name of the given object's class.
Definition variable.c:500
int rb_respond_to(VALUE obj, ID mid)
Queries if the object responds to the method.
Definition vm_method.c:3361
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.
Definition vm_eval.c:686
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().
Definition symbol.h:284
#define RB_ID2SYM
Just another name of rb_id2sym.
Definition symbol.h:42
void rb_define_global_const(const char *name, VALUE val)
Identical to rb_define_const(), except it defines that of "global", i.e.
Definition variable.c:3999
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...
Definition variable.c:846
rb_gvar_setter_t rb_gvar_readonly_setter
This function just raises rb_eNameError.
Definition variable.h:135
#define FMODE_READABLE
The IO is opened for reading.
Definition io.h:162
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.
Definition io.c:6471
VALUE rb_io_get_io(VALUE io)
Identical to rb_io_check_io(), except it raises exceptions on conversion failures.
Definition io.c:811
VALUE rb_io_timeout(VALUE io)
Get the timeout associated with the specified io object.
Definition io.c:857
VALUE rb_io_taint_check(VALUE obj)
Definition io.c:781
void rb_io_read_check(rb_io_t *fptr)
Blocks until there is a pending read in the passed IO.
Definition io.c:1069
int rb_io_modestr_oflags(const char *modestr)
Identical to rb_io_modestr_fmode(), except it returns a mixture of O_ flags.
Definition io.c:6604
#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.
Definition io.h:260
rb_io_event
Type of events that an IO can wait.
Definition io.h:96
@ RUBY_IO_READABLE
IO::READABLE
Definition io.h:97
@ RUBY_IO_PRIORITY
IO::PRIORITY
Definition io.h:99
@ RUBY_IO_WRITABLE
IO::WRITABLE
Definition io.h:98
#define FMODE_READWRITE
The IO is opened for both read/write.
Definition io.h:168
#define FMODE_EXTERNAL
This flag means that an IO object is wrapping an "external" file descriptor, which is owned by someth...
Definition io.h:252
#define GetOpenFile
This is an old name of RB_IO_POINTER.
Definition io.h:442
void rb_io_check_byte_readable(rb_io_t *fptr)
Asserts that an IO is opened for byte-based reading.
Definition io.c:1015
#define FMODE_TTY
The IO is a TTY.
Definition io.h:192
#define FMODE_CREATE
The IO is opened for creating.
Definition io.h:215
void rb_io_check_readable(rb_io_t *fptr)
Just another name of rb_io_check_byte_readable.
Definition io.c:1024
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.
Definition io.c:1592
FILE * rb_fdopen(int fd, const char *modestr)
Identical to rb_io_stdio_file(), except it takes file descriptors instead of Ruby's IO.
Definition io.c:7087
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.
Definition io.c:6753
int rb_io_descriptor(VALUE io)
Returns an integer representing the numeric file descriptor for io.
Definition io.c:2899
#define FMODE_WRITABLE
The IO is opened for writing.
Definition io.h:165
FILE * rb_io_stdio_file(rb_io_t *fptr)
Finds or creates a stdio's file structure from a Ruby's one.
Definition io.c:9422
#define FMODE_APPEND
The IO is opened for appending.
Definition io.h:207
#define MakeOpenFile
This is an old name of RB_IO_OPEN.
Definition io.h:465
#define FMODE_DUPLEX
Ruby eventually detects that the IO is bidirectional.
Definition io.h:200
#define FMODE_BINMODE
The IO is in "binary mode".
Definition io.h:179
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.
Definition io.c:1651
int capa
Designed capacity of the buffer.
Definition io.h:11
#define RB_IO_POINTER(obj, fp)
Queries the underlying IO pointer.
Definition io.h:436
VALUE rb_io_maybe_wait(int error, VALUE io, VALUE events, VALUE timeout)
Identical to rb_io_wait() except it additionally takes previous errno.
Definition io.c:1610
VALUE rb_eIOTimeoutError
Indicates that a timeout has occurred while performing an IO operation.
Definition io.c:190
char * ptr
Pointer to the underlying memory region, of at least capa bytes.
Definition io.h:2
#define FMODE_SYNC
The IO is in "sync mode".
Definition io.h:186
int off
Offset inside of ptr.
Definition io.h:5
VALUE rb_io_path(VALUE io)
Returns the path for the given IO.
Definition io.c:2973
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...
Definition io.c:6878
void rb_io_check_initialized(rb_io_t *fptr)
Asserts that the passed IO is initialised.
Definition io.c:788
#define FMODE_EXCL
This flag amends the effect of FMODE_CREATE, so that if there already is a file at the given path the...
Definition io.h:223
#define FMODE_TEXTMODE
The IO is in "text mode".
Definition io.h:243
int rb_io_fptr_finalize(rb_io_t *fptr)
Destroys the given IO.
Definition io.c:5681
VALUE rb_io_check_io(VALUE io)
Try converting an object to its IO representation using its to_io method, if any.
Definition io.c:817
VALUE rb_io_closed_p(VALUE io)
Returns whether or not the underlying IO is closed.
Definition io.c:5867
VALUE rb_io_set_timeout(VALUE io, VALUE timeout)
Set the timeout associated with the specified io object.
Definition io.c:886
ssize_t rb_io_bufwrite(VALUE io, const void *buf, size_t size)
Buffered write to the passed IO.
Definition io.c:2016
void rb_io_check_char_readable(rb_io_t *fptr)
Asserts that an IO is opened for character-based reading.
Definition io.c:996
#define FMODE_TRUNC
This flag amends the effect of FMODE_CREATE, so that if there already is a file at the given path it ...
Definition io.h:229
VALUE rb_io_get_write_io(VALUE io)
Queries the tied IO for writing.
Definition io.c:823
void rb_io_set_nonblock(rb_io_t *fptr)
Instructs the OS to put its internal file structure into "nonblocking mode".
Definition io.c:3425
int rb_io_wait_writable(int fd)
Blocks until the passed file descriptor gets writable.
Definition io.c:1549
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.
Definition io.c:9288
VALUE rb_io_set_write_io(VALUE io, VALUE w)
Assigns the tied IO for writing.
Definition io.c:834
void rb_io_check_writable(rb_io_t *fptr)
Asserts that an IO is opened for writing.
Definition io.c:1048
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.
Definition io.c:1666
void rb_io_check_closed(rb_io_t *fptr)
This badly named function asserts that the passed IO is open.
Definition io.c:796
int rb_io_wait_readable(int fd)
Blocks until the passed file descriptor gets readable.
Definition io.c:1515
void rb_io_synchronized(rb_io_t *fptr)
Sets FMODE_SYNC.
Definition io.c:7374
VALUE rb_io_wait(VALUE io, VALUE events, VALUE timeout)
Blocks until the passed IO is ready for the passed events.
Definition io.c:1454
int len
Length of the buffer.
Definition io.h:8
VALUE rb_ractor_stdin(void)
Queries the standard input of the current Ractor that is calling this function.
Definition ractor.c:1046
void rb_ractor_stderr_set(VALUE io)
Assigns an IO to the standard error of the Ractor that is calling this function.
Definition ractor.c:1106
void rb_ractor_stdout_set(VALUE io)
Assigns an IO to the standard output of the Ractor that is calling this function.
Definition ractor.c:1094
void rb_ractor_stdin_set(VALUE io)
Assigns an IO to the standard input of the Ractor that is calling this function.
Definition ractor.c:1082
void * rb_thread_call_with_gvl(void *(*func)(void *), void *data1)
(Re-)acquires the GVL.
Definition thread.c:2046
#define RB_NUM2INT
Just another name of rb_num2int_inline.
Definition int.h:38
#define RB_INT2NUM
Just another name of rb_int2num_inline.
Definition int.h:37
VALUE rb_f_sprintf(int argc, const VALUE *argv)
Identical to rb_str_format(), except how the arguments are arranged.
Definition sprintf.c:209
#define RB_BLOCK_CALL_FUNC_ARGLIST(yielded_arg, callback_arg)
Shim for block function parameters.
Definition iterator.h:58
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...
Definition vm_eval.c:1406
VALUE rb_yield(VALUE val)
Yields the block.
Definition vm_eval.c:1372
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.
Definition memory.h:360
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
Definition memory.h:167
#define MEMMOVE(p1, p2, type, n)
Handy macro to call memmove.
Definition memory.h:384
#define NUM2MODET
Converts a C's mode_t into an instance of rb_cInteger.
Definition mode_t.h:28
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.
Definition off_t.h:55
#define OFFT2NUM
Converts a C's off_t into an instance of rb_cInteger.
Definition off_t.h:33
#define NUM2OFFT
Converts an instance of rb_cNumeric into C's off_t.
Definition off_t.h:44
#define PIDT2NUM
Converts a C's pid_t into an instance of rb_cInteger.
Definition pid_t.h:28
#define rb_fd_isset
Queries if the given fd is in the rb_fdset_t.
Definition posix.h:60
#define rb_fd_select
Waits for multiple file descriptors at once.
Definition posix.h:66
#define rb_fd_init
Initialises the :given :rb_fdset_t.
Definition posix.h:63
#define rb_fd_set
Sets the given fd to the rb_fdset_t.
Definition posix.h:54
#define RARRAY_LEN
Just another name of rb_array_len.
Definition rarray.h:51
static int RARRAY_LENINT(VALUE ary)
Identical to rb_array_len(), except it differs for the return type.
Definition rarray.h:281
#define RARRAY_AREF(a, i)
Definition rarray.h:403
#define RARRAY_CONST_PTR
Just another name of rb_array_const_ptr.
Definition rarray.h:52
#define RFILE(obj)
Convenient casting macro.
Definition rfile.h:50
#define StringValue(v)
Ensures that the parameter object is a String.
Definition rstring.h:66
static char * RSTRING_END(VALUE str)
Queries the end of the contents pointer of the string.
Definition rstring.h:442
#define RSTRING_GETMEM(str, ptrvar, lenvar)
Convenient macro to obtain the contents and length at once.
Definition rstring.h:488
#define StringValueCStr(v)
Identical to StringValuePtr, except it additionally checks for the contents for viability as a C stri...
Definition rstring.h:89
#define RUBY_TYPED_DEFAULT_FREE
This is a value you can set to rb_data_type_struct::dfree.
Definition rtypeddata.h:80
#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...
Definition rtypeddata.h:502
VALUE rb_get_argv(void)
Queries the arguments passed to the current process that you can access from Ruby as ARGV.
Definition io.c:14687
void rb_p(VALUE obj)
Inspects an object.
Definition io.c:9074
#define FilePathValue(v)
Ensures that the parameter object is a path.
Definition ruby.h:90
#define errno
Ractor-aware version of errno.
Definition ruby.h:388
#define RB_SCAN_ARGS_LAST_HASH_KEYWORDS
Treat a final argument as keywords if it is a hash, and not as keywords otherwise.
Definition scan_args.h:59
#define RB_PASS_CALLED_KEYWORDS
Pass keywords if current method is called with keywords, useful for argument delegation.
Definition scan_args.h:78
Scheduler APIs.
VALUE rb_fiber_scheduler_current(void)
Identical to rb_fiber_scheduler_get(), except it also returns RUBY_Qnil in case of a blocking fiber.
Definition scheduler.c:464
VALUE rb_fiber_scheduler_io_pread_memory(VALUE scheduler, VALUE io, rb_off_t from, void *base, size_t size, size_t length)
Non-blocking pread from the passed IO using a native buffer.
Definition scheduler.c:972
VALUE rb_fiber_scheduler_make_timeout(struct timeval *timeout)
Converts the passed timeout to an expression that rb_fiber_scheduler_block() etc.
Definition scheduler.c:507
VALUE rb_fiber_scheduler_io_wait_readable(VALUE scheduler, VALUE io)
Non-blocking wait until the passed IO is ready for reading.
Definition scheduler.c:724
VALUE rb_fiber_scheduler_io_read_memory(VALUE scheduler, VALUE io, void *base, size_t size, size_t length)
Non-blocking read from the passed IO using a native buffer.
Definition scheduler.c:948
VALUE rb_fiber_scheduler_io_wait(VALUE scheduler, VALUE io, VALUE events, VALUE timeout)
Non-blocking version of rb_io_wait().
Definition scheduler.c:710
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 ...
Definition scheduler.h:71
VALUE rb_fiber_scheduler_io_selectv(VALUE scheduler, int argc, VALUE *argv)
Non-blocking version of IO.select, argv variant.
Definition scheduler.c:754
VALUE rb_fiber_scheduler_io_pwrite_memory(VALUE scheduler, VALUE io, rb_off_t from, const void *base, size_t size, size_t length)
Non-blocking pwrite to the passed IO using a native buffer.
Definition scheduler.c:984
VALUE rb_fiber_scheduler_current_for_thread(VALUE thread)
Identical to rb_fiber_scheduler_current(), except it queries for that of the passed thread instead of...
Definition scheduler.c:469
VALUE rb_fiber_scheduler_io_write_memory(VALUE scheduler, VALUE io, const void *base, size_t size, size_t length)
Non-blocking write to the passed IO using a native buffer.
Definition scheduler.c:960
VALUE rb_fiber_scheduler_io_wait_writable(VALUE scheduler, VALUE io)
Non-blocking wait until the passed IO is ready for writing.
Definition scheduler.c:730
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.
Definition thread.c:4512
static bool RB_TEST(VALUE obj)
Emulates Ruby's "if" statement.
@ RUBY_Qfalse
#define RTEST
This is an old name of RB_TEST.
#define _(args)
This was a transition path from K&R to ANSI.
Definition stdarg.h:35
C99 shim for <stdbool.h>
Ruby's File and IO.
Definition rfile.h:35
Definition io.c:236
Definition win32.h:241
This is the struct that holds necessary info for a struct.
Definition rtypeddata.h:202
The data structure which wraps the fd_set bitmap used by select(2).
Definition largesize.h:71
Decomposed encoding flags (e.g.
Definition io.h:134
int ecflags
Flags.
Definition io.h:144
VALUE ecopts
Flags as Ruby hash.
Definition io.h:152
rb_encoding * enc2
External encoding.
Definition io.h:138
rb_encoding * enc
Internal encoding.
Definition io.h:136
IO buffers.
Definition io.h:109
char * ptr
Pointer to the underlying memory region, of at least capa bytes.
Definition io.h:112
int off
Offset inside of ptr.
Definition io.h:115
int len
Length of the buffer.
Definition io.h:118
int capa
Designed capacity of the buffer.
Definition io.h:121
Ruby's IO, metadata and buffers.
Definition io.h:295
rb_io_buffer_t wbuf
Write buffer.
Definition io.h:330
enum rb_io_mode mode
mode flags: FMODE_XXXs
Definition io.h:310
void(* finalize)(struct rb_io *, int)
finalize proc
Definition io.h:326
rb_econv_t * readconv
Encoding converter used when reading from this IO.
Definition io.h:352
rb_econv_t * writeconv
Encoding converter used when writing to this IO.
Definition io.h:363
struct rb_io_encoding encs
Decomposed encoding flags.
Definition io.h:348
VALUE self
The IO's Ruby level counterpart.
Definition io.h:298
VALUE write_lock
This is a Ruby level mutex.
Definition io.h:400
VALUE timeout
The timeout associated with this IO when performing blocking operations.
Definition io.h:406
FILE * stdio_file
stdio ptr for read/write, if available.
Definition io.h:302
VALUE writeconv_pre_ecopts
Value of ::rb_io_t::rb_io_enc_t::ecopts stored right before initialising rb_io_t::writeconv.
Definition io.h:390
VALUE tied_io_for_writing
Duplex IO object, if set.
Definition io.h:345
int writeconv_initialized
Whether rb_io_t::writeconv is already set up.
Definition io.h:376
int fd
file descriptor.
Definition io.h:306
rb_io_buffer_t rbuf
(Byte) read buffer.
Definition io.h:337
int lineno
number of lines read
Definition io.h:318
struct ccan_list_head blocking_operations
Threads that are performing a blocking operation without the GVL using this IO.
Definition io.h:131
VALUE writeconv_asciicompat
This is, when set, an instance of rb_cString which holds the "common" encoding.
Definition io.h:372
rb_io_buffer_t cbuf
rb_io_ungetc() destination.
Definition io.h:359
rb_pid_t pid
child's pid (for pipes)
Definition io.h:314
int writeconv_pre_ecflags
Value of ::rb_io_t::rb_io_enc_t::ecflags stored right before initialising rb_io_t::writeconv.
Definition io.h:383
VALUE pathv
pathname for file
Definition io.h:322
intptr_t SIGNED_VALUE
A signed integer type that has the same width with VALUE.
Definition value.h:63
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
Definition value.h:52
uintptr_t VALUE
Type that represents a Ruby object.
Definition value.h:40
static bool RB_FLOAT_TYPE_P(VALUE obj)
Queries if the object is an instance of rb_cFloat.
Definition value_type.h:264
static bool RB_SYMBOL_P(VALUE obj)
Queries if the object is an instance of rb_cSymbol.
Definition value_type.h:307
static void Check_Type(VALUE v, enum ruby_value_type t)
Identical to RB_TYPE_P(), except it raises exceptions on predication failure.
Definition value_type.h:433
static bool RB_TYPE_P(VALUE obj, enum ruby_value_type t)
Queries if the given object is of given type.
Definition value_type.h:376