Ruby 4.1.0dev (2025-12-29 revision 65634d8df57ea1636efffb5f040fa31c156d307f)
io.c (65634d8df57ea1636efffb5f040fa31c156d307f)
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 rb_thread_t *th = GET_THREAD();
1296 if (scheduler != Qnil) {
1297 VALUE result = rb_fiber_scheduler_io_read_memory(scheduler, fptr->self, buf, count, 0);
1298
1299 if (!UNDEF_P(result)) {
1301 }
1302 }
1303
1304 struct io_internal_read_struct iis = {
1305 .th = th->self,
1306 .fptr = fptr,
1307 .nonblock = 0,
1308 .fd = fptr->fd,
1309
1310 .buf = buf,
1311 .capa = count,
1312 .timeout = NULL,
1313 };
1314
1315 struct timeval timeout_storage;
1316
1317 if (fptr->timeout != Qnil) {
1318 timeout_storage = rb_time_interval(fptr->timeout);
1319 iis.timeout = &timeout_storage;
1320 }
1321
1322 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_read_func, &iis, RUBY_IO_READABLE);
1323}
1324
1325static ssize_t
1326rb_io_write_memory(rb_io_t *fptr, const void *buf, size_t count)
1327{
1328 rb_thread_t *th = GET_THREAD();
1330 if (scheduler != Qnil) {
1331 VALUE result = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, buf, count, 0);
1332
1333 if (!UNDEF_P(result)) {
1335 }
1336 }
1337
1338 struct io_internal_write_struct iis = {
1339 .th = th->self,
1340 .fptr = fptr,
1341 .nonblock = 0,
1342 .fd = fptr->fd,
1343
1344 .buf = buf,
1345 .capa = count,
1346 .timeout = NULL
1347 };
1348
1349 struct timeval timeout_storage;
1350
1351 if (fptr->timeout != Qnil) {
1352 timeout_storage = rb_time_interval(fptr->timeout);
1353 iis.timeout = &timeout_storage;
1354 }
1355
1356 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_write_func, &iis, RUBY_IO_WRITABLE);
1357}
1358
1359#ifdef HAVE_WRITEV
1360static ssize_t
1361rb_writev_internal(rb_io_t *fptr, const struct iovec *iov, int iovcnt)
1362{
1363 if (!iovcnt) return 0;
1364
1365 rb_thread_t *th = GET_THREAD();
1366
1368 if (scheduler != Qnil) {
1369 // This path assumes at least one `iov`:
1370 VALUE result = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, iov[0].iov_base, iov[0].iov_len, 0);
1371
1372 if (!UNDEF_P(result)) {
1374 }
1375 }
1376
1377 struct io_internal_writev_struct iis = {
1378 .th = th->self,
1379 .fptr = fptr,
1380 .nonblock = 0,
1381 .fd = fptr->fd,
1382
1383 .iov = iov,
1384 .iovcnt = iovcnt,
1385 .timeout = NULL
1386 };
1387
1388 struct timeval timeout_storage;
1389
1390 if (fptr->timeout != Qnil) {
1391 timeout_storage = rb_time_interval(fptr->timeout);
1392 iis.timeout = &timeout_storage;
1393 }
1394
1395 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_writev_func, &iis, RUBY_IO_WRITABLE);
1396}
1397#endif
1398
1399static VALUE
1400io_flush_buffer_sync(void *arg)
1401{
1402 rb_io_t *fptr = arg;
1403 long l = fptr->wbuf.len;
1404 ssize_t r = write(fptr->fd, fptr->wbuf.ptr+fptr->wbuf.off, (size_t)l);
1405
1406 if (fptr->wbuf.len <= r) {
1407 fptr->wbuf.off = 0;
1408 fptr->wbuf.len = 0;
1409 return 0;
1410 }
1411
1412 if (0 <= r) {
1413 fptr->wbuf.off += (int)r;
1414 fptr->wbuf.len -= (int)r;
1415 errno = EAGAIN;
1416 }
1417
1418 return (VALUE)-1;
1419}
1420
1421static inline VALUE
1422io_flush_buffer_fiber_scheduler(VALUE scheduler, rb_io_t *fptr)
1423{
1424 VALUE ret = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, fptr->wbuf.ptr+fptr->wbuf.off, fptr->wbuf.len, 0);
1425 if (!UNDEF_P(ret)) {
1426 ssize_t result = rb_fiber_scheduler_io_result_apply(ret);
1427 if (result > 0) {
1428 fptr->wbuf.off += result;
1429 fptr->wbuf.len -= result;
1430 }
1431 return result >= 0 ? (VALUE)0 : (VALUE)-1;
1432 }
1433 return ret;
1434}
1435
1436static VALUE
1437io_flush_buffer_async(VALUE arg)
1438{
1439 rb_io_t *fptr = (rb_io_t *)arg;
1440
1441 VALUE scheduler = rb_fiber_scheduler_current();
1442 if (scheduler != Qnil) {
1443 VALUE result = io_flush_buffer_fiber_scheduler(scheduler, fptr);
1444 if (!UNDEF_P(result)) {
1445 return result;
1446 }
1447 }
1448
1449 return rb_io_blocking_region_wait(fptr, io_flush_buffer_sync, fptr, RUBY_IO_WRITABLE);
1450}
1451
1452static inline int
1453io_flush_buffer(rb_io_t *fptr)
1454{
1455 if (!NIL_P(fptr->write_lock) && rb_mutex_owned_p(fptr->write_lock)) {
1456 return (int)io_flush_buffer_async((VALUE)fptr);
1457 }
1458 else {
1459 return (int)rb_mutex_synchronize(fptr->write_lock, io_flush_buffer_async, (VALUE)fptr);
1460 }
1461}
1462
1463static int
1464io_fflush(rb_io_t *fptr)
1465{
1466 rb_io_check_closed(fptr);
1467
1468 if (fptr->wbuf.len == 0)
1469 return 0;
1470
1471 while (fptr->wbuf.len > 0 && io_flush_buffer(fptr) != 0) {
1472 if (!rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT))
1473 return -1;
1474
1475 rb_io_check_closed(fptr);
1476 }
1477
1478 return 0;
1479}
1480
1481VALUE
1482rb_io_wait(VALUE io, VALUE events, VALUE timeout)
1483{
1484 rb_thread_t *th = GET_THREAD();
1486
1487 if (scheduler != Qnil) {
1488 return rb_fiber_scheduler_io_wait(scheduler, io, events, timeout);
1489 }
1490
1491 rb_io_t * fptr = NULL;
1492 RB_IO_POINTER(io, fptr);
1493
1494 struct timeval tv_storage;
1495 struct timeval *tv = NULL;
1496
1497 if (NIL_OR_UNDEF_P(timeout)) {
1498 timeout = fptr->timeout;
1499 }
1500
1501 if (timeout != Qnil) {
1502 tv_storage = rb_time_interval(timeout);
1503 tv = &tv_storage;
1504 }
1505
1506 int ready = rb_thread_io_wait(th, fptr, RB_NUM2INT(events), tv);
1507
1508 if (ready < 0) {
1509 rb_sys_fail(0);
1510 }
1511
1512 // Not sure if this is necessary:
1513 rb_io_check_closed(fptr);
1514
1515 if (ready) {
1516 return RB_INT2NUM(ready);
1517 }
1518 else {
1519 return Qfalse;
1520 }
1521}
1522
1523static VALUE
1524io_from_fd(int fd)
1525{
1526 return prep_io(fd, FMODE_EXTERNAL, rb_cIO, NULL);
1527}
1528
1529static int
1530io_wait_for_single_fd(int fd, int events, struct timeval *timeout, rb_thread_t *th, VALUE scheduler)
1531{
1532 if (scheduler != Qnil) {
1533 return RTEST(
1534 rb_fiber_scheduler_io_wait(scheduler, io_from_fd(fd), RB_INT2NUM(events), rb_fiber_scheduler_make_timeout(timeout))
1535 );
1536 }
1537
1538 return rb_thread_wait_for_single_fd(th, fd, events, timeout);
1539}
1540
1541int
1543{
1544 io_fd_check_closed(f);
1545
1546 rb_thread_t *th = GET_THREAD();
1548
1549 switch (errno) {
1550 case EINTR:
1551#if defined(ERESTART)
1552 case ERESTART:
1553#endif
1555 return TRUE;
1556
1557 case EAGAIN:
1558#if EWOULDBLOCK != EAGAIN
1559 case EWOULDBLOCK:
1560#endif
1561 if (scheduler != Qnil) {
1562 return RTEST(
1563 rb_fiber_scheduler_io_wait_readable(scheduler, io_from_fd(f))
1564 );
1565 }
1566 else {
1567 io_wait_for_single_fd(f, RUBY_IO_READABLE, NULL, th, scheduler);
1568 }
1569 return TRUE;
1570
1571 default:
1572 return FALSE;
1573 }
1574}
1575
1576int
1578{
1579 io_fd_check_closed(f);
1580
1581 rb_thread_t *th = GET_THREAD();
1583
1584 switch (errno) {
1585 case EINTR:
1586#if defined(ERESTART)
1587 case ERESTART:
1588#endif
1589 /*
1590 * In old Linux, several special files under /proc and /sys don't handle
1591 * select properly. Thus we need avoid to call if don't use O_NONBLOCK.
1592 * Otherwise, we face nasty hang up. Sigh.
1593 * e.g. https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1594 * https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1595 * In EINTR case, we only need to call RUBY_VM_CHECK_INTS_BLOCKING().
1596 * Then rb_thread_check_ints() is enough.
1597 */
1599 return TRUE;
1600
1601 case EAGAIN:
1602#if EWOULDBLOCK != EAGAIN
1603 case EWOULDBLOCK:
1604#endif
1605 if (scheduler != Qnil) {
1606 return RTEST(
1607 rb_fiber_scheduler_io_wait_writable(scheduler, io_from_fd(f))
1608 );
1609 }
1610 else {
1611 io_wait_for_single_fd(f, RUBY_IO_WRITABLE, NULL, th, scheduler);
1612 }
1613 return TRUE;
1614
1615 default:
1616 return FALSE;
1617 }
1618}
1619
1620int
1621rb_wait_for_single_fd(int fd, int events, struct timeval *timeout)
1622{
1623 rb_thread_t *th = GET_THREAD();
1625 return io_wait_for_single_fd(fd, events, timeout, th, scheduler);
1626}
1627
1628int
1630{
1631 return rb_wait_for_single_fd(fd, RUBY_IO_READABLE, NULL);
1632}
1633
1634int
1636{
1637 return rb_wait_for_single_fd(fd, RUBY_IO_WRITABLE, NULL);
1638}
1639
1640VALUE
1641rb_io_maybe_wait(int error, VALUE io, VALUE events, VALUE timeout)
1642{
1643 // fptr->fd can be set to -1 at any time by another thread when the GVL is
1644 // released. Many code, e.g. `io_bufread` didn't check this correctly and
1645 // instead relies on `read(-1) -> -1` which causes this code path. We then
1646 // check here whether the IO was in fact closed. Probably it's better to
1647 // check that `fptr->fd != -1` before using it in syscall.
1648 rb_io_check_closed(RFILE(io)->fptr);
1649
1650 switch (error) {
1651 // In old Linux, several special files under /proc and /sys don't handle
1652 // select properly. Thus we need avoid to call if don't use O_NONBLOCK.
1653 // Otherwise, we face nasty hang up. Sigh.
1654 // e.g. https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1655 // https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1656 // In EINTR case, we only need to call RUBY_VM_CHECK_INTS_BLOCKING().
1657 // Then rb_thread_check_ints() is enough.
1658 case EINTR:
1659#if defined(ERESTART)
1660 case ERESTART:
1661#endif
1662 // We might have pending interrupts since the previous syscall was interrupted:
1664
1665 // The operation was interrupted, so retry it immediately:
1666 return events;
1667
1668 case EAGAIN:
1669#if EWOULDBLOCK != EAGAIN
1670 case EWOULDBLOCK:
1671#endif
1672 // The operation would block, so wait for the specified events:
1673 return rb_io_wait(io, events, timeout);
1674
1675 default:
1676 // Non-specific error, no event is ready:
1677 return Qnil;
1678 }
1679}
1680
1681int
1683{
1684 VALUE result = rb_io_maybe_wait(error, io, RB_INT2NUM(RUBY_IO_READABLE), timeout);
1685
1686 if (RTEST(result)) {
1687 return RB_NUM2INT(result);
1688 }
1689 else if (result == RUBY_Qfalse) {
1690 rb_raise(rb_eIOTimeoutError, "Timed out waiting for IO to become readable!");
1691 }
1692
1693 return 0;
1694}
1695
1696int
1698{
1699 VALUE result = rb_io_maybe_wait(error, io, RB_INT2NUM(RUBY_IO_WRITABLE), timeout);
1700
1701 if (RTEST(result)) {
1702 return RB_NUM2INT(result);
1703 }
1704 else if (result == RUBY_Qfalse) {
1705 rb_raise(rb_eIOTimeoutError, "Timed out waiting for IO to become writable!");
1706 }
1707
1708 return 0;
1709}
1710
1711static void
1712make_writeconv(rb_io_t *fptr)
1713{
1714 if (!fptr->writeconv_initialized) {
1715 const char *senc, *denc;
1716 rb_encoding *enc;
1717 int ecflags;
1718 VALUE ecopts;
1719
1720 fptr->writeconv_initialized = 1;
1721
1722 ecflags = fptr->encs.ecflags & ~ECONV_NEWLINE_DECORATOR_READ_MASK;
1723 ecopts = fptr->encs.ecopts;
1724
1725 if (!fptr->encs.enc || (rb_is_ascii8bit_enc(fptr->encs.enc) && !fptr->encs.enc2)) {
1726 /* no encoding conversion */
1727 fptr->writeconv_pre_ecflags = 0;
1728 fptr->writeconv_pre_ecopts = Qnil;
1729 fptr->writeconv = rb_econv_open_opts("", "", ecflags, ecopts);
1730 if (!fptr->writeconv)
1731 rb_exc_raise(rb_econv_open_exc("", "", ecflags));
1733 }
1734 else {
1735 enc = fptr->encs.enc2 ? fptr->encs.enc2 : fptr->encs.enc;
1736 senc = rb_econv_asciicompat_encoding(rb_enc_name(enc));
1737 if (!senc && !(fptr->encs.ecflags & ECONV_STATEFUL_DECORATOR_MASK)) {
1738 /* single conversion */
1739 fptr->writeconv_pre_ecflags = ecflags;
1740 fptr->writeconv_pre_ecopts = ecopts;
1741 fptr->writeconv = NULL;
1743 }
1744 else {
1745 /* double conversion */
1746 fptr->writeconv_pre_ecflags = ecflags & ~ECONV_STATEFUL_DECORATOR_MASK;
1747 fptr->writeconv_pre_ecopts = ecopts;
1748 if (senc) {
1749 denc = rb_enc_name(enc);
1750 fptr->writeconv_asciicompat = rb_str_new2(senc);
1751 }
1752 else {
1753 senc = denc = "";
1754 fptr->writeconv_asciicompat = rb_str_new2(rb_enc_name(enc));
1755 }
1757 ecopts = fptr->encs.ecopts;
1758 fptr->writeconv = rb_econv_open_opts(senc, denc, ecflags, ecopts);
1759 if (!fptr->writeconv)
1760 rb_exc_raise(rb_econv_open_exc(senc, denc, ecflags));
1761 }
1762 }
1763 }
1764}
1765
1766/* writing functions */
1768 rb_io_t *fptr;
1769 const char *ptr;
1770 long length;
1771};
1772
1774 VALUE io;
1775 VALUE str;
1776 int nosync;
1777};
1778
1779#ifdef HAVE_WRITEV
1780static ssize_t
1781io_binwrite_string_internal(rb_io_t *fptr, const char *ptr, long length)
1782{
1783 if (fptr->wbuf.len) {
1784 struct iovec iov[2];
1785
1786 iov[0].iov_base = fptr->wbuf.ptr+fptr->wbuf.off;
1787 iov[0].iov_len = fptr->wbuf.len;
1788 iov[1].iov_base = (void*)ptr;
1789 iov[1].iov_len = length;
1790
1791 ssize_t result = rb_writev_internal(fptr, iov, 2);
1792
1793 if (result < 0)
1794 return result;
1795
1796 if (result >= fptr->wbuf.len) {
1797 // We wrote more than the internal buffer:
1798 result -= fptr->wbuf.len;
1799 fptr->wbuf.off = 0;
1800 fptr->wbuf.len = 0;
1801 }
1802 else {
1803 // We only wrote less data than the internal buffer:
1804 fptr->wbuf.off += (int)result;
1805 fptr->wbuf.len -= (int)result;
1806
1807 result = 0;
1808 }
1809
1810 return result;
1811 }
1812 else {
1813 return rb_io_write_memory(fptr, ptr, length);
1814 }
1815}
1816#else
1817static ssize_t
1818io_binwrite_string_internal(rb_io_t *fptr, const char *ptr, long length)
1819{
1820 long remaining = length;
1821
1822 if (fptr->wbuf.len) {
1823 if (fptr->wbuf.len+length <= fptr->wbuf.capa) {
1824 if (fptr->wbuf.capa < fptr->wbuf.off+fptr->wbuf.len+length) {
1825 MEMMOVE(fptr->wbuf.ptr, fptr->wbuf.ptr+fptr->wbuf.off, char, fptr->wbuf.len);
1826 fptr->wbuf.off = 0;
1827 }
1828
1829 MEMMOVE(fptr->wbuf.ptr+fptr->wbuf.off+fptr->wbuf.len, ptr, char, length);
1830 fptr->wbuf.len += (int)length;
1831
1832 // We copied the entire incoming data to the internal buffer:
1833 remaining = 0;
1834 }
1835
1836 // Flush the internal buffer:
1837 if (io_fflush(fptr) < 0) {
1838 return -1;
1839 }
1840
1841 // If all the data was buffered, we are done:
1842 if (remaining == 0) {
1843 return length;
1844 }
1845 }
1846
1847 // Otherwise, we should write the data directly:
1848 return rb_io_write_memory(fptr, ptr, length);
1849}
1850#endif
1851
1852static VALUE
1853io_binwrite_string(VALUE arg)
1854{
1855 struct binwrite_arg *p = (struct binwrite_arg *)arg;
1856
1857 const char *ptr = p->ptr;
1858 size_t remaining = p->length;
1859
1860 while (remaining) {
1861 // Write as much as possible:
1862 ssize_t result = io_binwrite_string_internal(p->fptr, ptr, remaining);
1863
1864 if (result == 0) {
1865 // If only the internal buffer is written, result will be zero [bytes of given data written]. This means we
1866 // should try again immediately.
1867 }
1868 else if (result > 0) {
1869 if ((size_t)result == remaining) break;
1870 ptr += result;
1871 remaining -= result;
1872 }
1873 // Wait for it to become writable:
1874 else if (rb_io_maybe_wait_writable(errno, p->fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
1875 rb_io_check_closed(p->fptr);
1876 }
1877 else {
1878 // The error was unrelated to waiting for it to become writable, so we fail:
1879 return -1;
1880 }
1881 }
1882
1883 return p->length;
1884}
1885
1886inline static void
1887io_allocate_write_buffer(rb_io_t *fptr, int sync)
1888{
1889 if (fptr->wbuf.ptr == NULL && !(sync && (fptr->mode & FMODE_SYNC))) {
1890 fptr->wbuf.off = 0;
1891 fptr->wbuf.len = 0;
1892 fptr->wbuf.capa = IO_WBUF_CAPA_MIN;
1893 fptr->wbuf.ptr = ALLOC_N(char, fptr->wbuf.capa);
1894 }
1895
1896 if (NIL_P(fptr->write_lock)) {
1897 fptr->write_lock = rb_mutex_new();
1898 rb_mutex_allow_trap(fptr->write_lock, 1);
1899 }
1900}
1901
1902static inline int
1903io_binwrite_requires_flush_write(rb_io_t *fptr, long len, int nosync)
1904{
1905 // If the requested operation was synchronous and the output mode is synchronous or a TTY:
1906 if (!nosync && (fptr->mode & (FMODE_SYNC|FMODE_TTY)))
1907 return 1;
1908
1909 // If the amount of data we want to write exceeds the internal buffer:
1910 if (fptr->wbuf.ptr && fptr->wbuf.capa <= fptr->wbuf.len + len)
1911 return 1;
1912
1913 // Otherwise, we can append to the internal buffer:
1914 return 0;
1915}
1916
1917static long
1918io_binwrite(const char *ptr, long len, rb_io_t *fptr, int nosync)
1919{
1920 if (len <= 0) return len;
1921
1922 // Don't write anything if current thread has a pending interrupt:
1924
1925 io_allocate_write_buffer(fptr, !nosync);
1926
1927 if (io_binwrite_requires_flush_write(fptr, len, nosync)) {
1928 struct binwrite_arg arg;
1929
1930 arg.fptr = fptr;
1931 arg.ptr = ptr;
1932 arg.length = len;
1933
1934 if (!NIL_P(fptr->write_lock)) {
1935 return rb_mutex_synchronize(fptr->write_lock, io_binwrite_string, (VALUE)&arg);
1936 }
1937 else {
1938 return io_binwrite_string((VALUE)&arg);
1939 }
1940 }
1941 else {
1942 if (fptr->wbuf.off) {
1943 if (fptr->wbuf.len)
1944 MEMMOVE(fptr->wbuf.ptr, fptr->wbuf.ptr+fptr->wbuf.off, char, fptr->wbuf.len);
1945 fptr->wbuf.off = 0;
1946 }
1947
1948 MEMMOVE(fptr->wbuf.ptr+fptr->wbuf.off+fptr->wbuf.len, ptr, char, len);
1949 fptr->wbuf.len += (int)len;
1950
1951 return len;
1952 }
1953}
1954
1955# define MODE_BTMODE(a,b,c) ((fmode & FMODE_BINMODE) ? (b) : \
1956 (fmode & FMODE_TEXTMODE) ? (c) : (a))
1957
1958#define MODE_BTXMODE(a, b, c, d, e, f) ((fmode & FMODE_EXCL) ? \
1959 MODE_BTMODE(d, e, f) : \
1960 MODE_BTMODE(a, b, c))
1961
1962static VALUE
1963do_writeconv(VALUE str, rb_io_t *fptr, int *converted)
1964{
1965 if (NEED_WRITECONV(fptr)) {
1966 VALUE common_encoding = Qnil;
1967 SET_BINARY_MODE(fptr);
1968
1969 make_writeconv(fptr);
1970
1971 if (fptr->writeconv) {
1972#define fmode (fptr->mode)
1973 if (!NIL_P(fptr->writeconv_asciicompat))
1974 common_encoding = fptr->writeconv_asciicompat;
1975 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1) && !rb_enc_asciicompat(rb_enc_get(str))) {
1976 rb_raise(rb_eArgError, "ASCII incompatible string written for text mode IO without encoding conversion: %s",
1977 rb_enc_name(rb_enc_get(str)));
1978 }
1979#undef fmode
1980 }
1981 else {
1982 if (fptr->encs.enc2)
1983 common_encoding = rb_enc_from_encoding(fptr->encs.enc2);
1984 else if (fptr->encs.enc != rb_ascii8bit_encoding())
1985 common_encoding = rb_enc_from_encoding(fptr->encs.enc);
1986 }
1987
1988 if (!NIL_P(common_encoding)) {
1989 str = rb_str_encode(str, common_encoding,
1991 *converted = 1;
1992 }
1993
1994 if (fptr->writeconv) {
1996 *converted = 1;
1997 }
1998 }
1999#if RUBY_CRLF_ENVIRONMENT
2000#define fmode (fptr->mode)
2001 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1)) {
2002 if ((fptr->mode & FMODE_READABLE) &&
2004 setmode(fptr->fd, O_BINARY);
2005 }
2006 else {
2007 setmode(fptr->fd, O_TEXT);
2008 }
2009 if (!rb_enc_asciicompat(rb_enc_get(str))) {
2010 rb_raise(rb_eArgError, "ASCII incompatible string written for text mode IO without encoding conversion: %s",
2011 rb_enc_name(rb_enc_get(str)));
2012 }
2013 }
2014#undef fmode
2015#endif
2016 return str;
2017}
2018
2019static long
2020io_fwrite(VALUE str, rb_io_t *fptr, int nosync)
2021{
2022 int converted = 0;
2023 VALUE tmp;
2024 long n, len;
2025 const char *ptr;
2026
2027#ifdef _WIN32
2028 if (fptr->mode & FMODE_TTY) {
2029 long len = rb_w32_write_console(str, fptr->fd);
2030 if (len > 0) return len;
2031 }
2032#endif
2033
2034 str = do_writeconv(str, fptr, &converted);
2035 if (converted)
2036 OBJ_FREEZE(str);
2037
2038 tmp = rb_str_tmp_frozen_no_embed_acquire(str);
2039 RSTRING_GETMEM(tmp, ptr, len);
2040 n = io_binwrite(ptr, len, fptr, nosync);
2041 rb_str_tmp_frozen_release(str, tmp);
2042
2043 return n;
2044}
2045
2046ssize_t
2047rb_io_bufwrite(VALUE io, const void *buf, size_t size)
2048{
2049 rb_io_t *fptr;
2050
2051 GetOpenFile(io, fptr);
2053 return (ssize_t)io_binwrite(buf, (long)size, fptr, 0);
2054}
2055
2056static VALUE
2057io_write(VALUE io, VALUE str, int nosync)
2058{
2059 rb_io_t *fptr;
2060 long n;
2061 VALUE tmp;
2062
2063 io = GetWriteIO(io);
2064 str = rb_obj_as_string(str);
2065 tmp = rb_io_check_io(io);
2066
2067 if (NIL_P(tmp)) {
2068 /* port is not IO, call write method for it. */
2069 return rb_funcall(io, id_write, 1, str);
2070 }
2071
2072 io = tmp;
2073 if (RSTRING_LEN(str) == 0) return INT2FIX(0);
2074
2075 GetOpenFile(io, fptr);
2077
2078 n = io_fwrite(str, fptr, nosync);
2079 if (n < 0L) rb_sys_fail_on_write(fptr);
2080
2081 return LONG2FIX(n);
2082}
2083
2084#ifdef HAVE_WRITEV
2085struct binwritev_arg {
2086 rb_io_t *fptr;
2087 struct iovec *iov;
2088 int iovcnt;
2089 size_t total;
2090};
2091
2092static VALUE
2093io_binwritev_internal(VALUE arg)
2094{
2095 struct binwritev_arg *p = (struct binwritev_arg *)arg;
2096
2097 size_t remaining = p->total;
2098 size_t offset = 0;
2099
2100 rb_io_t *fptr = p->fptr;
2101 struct iovec *iov = p->iov;
2102 int iovcnt = p->iovcnt;
2103
2104 while (remaining) {
2105 long result = rb_writev_internal(fptr, iov, iovcnt);
2106
2107 if (result >= 0) {
2108 offset += result;
2109 if (fptr->wbuf.ptr && fptr->wbuf.len) {
2110 if (offset < (size_t)fptr->wbuf.len) {
2111 fptr->wbuf.off += result;
2112 fptr->wbuf.len -= result;
2113 }
2114 else {
2115 offset -= (size_t)fptr->wbuf.len;
2116 fptr->wbuf.off = 0;
2117 fptr->wbuf.len = 0;
2118 }
2119 }
2120
2121 if (offset == p->total) {
2122 return p->total;
2123 }
2124
2125 while (result >= (ssize_t)iov->iov_len) {
2126 /* iovcnt > 0 */
2127 result -= iov->iov_len;
2128 iov->iov_len = 0;
2129 iov++;
2130
2131 if (!--iovcnt) {
2132 // I don't believe this code path can ever occur.
2133 return offset;
2134 }
2135 }
2136
2137 iov->iov_base = (char *)iov->iov_base + result;
2138 iov->iov_len -= result;
2139 }
2140 else if (rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
2141 rb_io_check_closed(fptr);
2142 }
2143 else {
2144 return -1;
2145 }
2146 }
2147
2148 return offset;
2149}
2150
2151static long
2152io_binwritev(struct iovec *iov, int iovcnt, rb_io_t *fptr)
2153{
2154 // Don't write anything if current thread has a pending interrupt:
2156
2157 if (iovcnt == 0) return 0;
2158
2159 size_t total = 0;
2160 for (int i = 1; i < iovcnt; i++) total += iov[i].iov_len;
2161
2162 io_allocate_write_buffer(fptr, 1);
2163
2164 if (fptr->wbuf.ptr && fptr->wbuf.len) {
2165 // The end of the buffered data:
2166 size_t offset = fptr->wbuf.off + fptr->wbuf.len;
2167
2168 if (offset + total <= (size_t)fptr->wbuf.capa) {
2169 for (int i = 1; i < iovcnt; i++) {
2170 memcpy(fptr->wbuf.ptr+offset, iov[i].iov_base, iov[i].iov_len);
2171 offset += iov[i].iov_len;
2172 }
2173
2174 fptr->wbuf.len += total;
2175
2176 return total;
2177 }
2178 else {
2179 iov[0].iov_base = fptr->wbuf.ptr + fptr->wbuf.off;
2180 iov[0].iov_len = fptr->wbuf.len;
2181 }
2182 }
2183 else {
2184 // The first iov is reserved for the internal buffer, and it's empty.
2185 iov++;
2186
2187 if (!--iovcnt) {
2188 // If there are no other io vectors we are done.
2189 return 0;
2190 }
2191 }
2192
2193 struct binwritev_arg arg;
2194 arg.fptr = fptr;
2195 arg.iov = iov;
2196 arg.iovcnt = iovcnt;
2197 arg.total = total;
2198
2199 if (!NIL_P(fptr->write_lock)) {
2200 return rb_mutex_synchronize(fptr->write_lock, io_binwritev_internal, (VALUE)&arg);
2201 }
2202 else {
2203 return io_binwritev_internal((VALUE)&arg);
2204 }
2205}
2206
2207static long
2208io_fwritev(int argc, const VALUE *argv, rb_io_t *fptr)
2209{
2210 int i, converted, iovcnt = argc + 1;
2211 long n;
2212 VALUE v1, v2, str, tmp, *tmp_array;
2213 struct iovec *iov;
2214
2215 iov = ALLOCV_N(struct iovec, v1, iovcnt);
2216 tmp_array = ALLOCV_N(VALUE, v2, argc);
2217
2218 for (i = 0; i < argc; i++) {
2219 str = rb_obj_as_string(argv[i]);
2220 converted = 0;
2221 str = do_writeconv(str, fptr, &converted);
2222
2223 if (converted)
2224 OBJ_FREEZE(str);
2225
2226 tmp = rb_str_tmp_frozen_acquire(str);
2227 tmp_array[i] = tmp;
2228
2229 /* iov[0] is reserved for buffer of fptr */
2230 iov[i+1].iov_base = RSTRING_PTR(tmp);
2231 iov[i+1].iov_len = RSTRING_LEN(tmp);
2232 }
2233
2234 n = io_binwritev(iov, iovcnt, fptr);
2235 if (v1) ALLOCV_END(v1);
2236
2237 for (i = 0; i < argc; i++) {
2238 rb_str_tmp_frozen_release(argv[i], tmp_array[i]);
2239 }
2240
2241 if (v2) ALLOCV_END(v2);
2242
2243 return n;
2244}
2245
2246static int
2247iovcnt_ok(int iovcnt)
2248{
2249#ifdef IOV_MAX
2250 return iovcnt < IOV_MAX;
2251#else /* GNU/Hurd has writev, but no IOV_MAX */
2252 return 1;
2253#endif
2254}
2255#endif /* HAVE_WRITEV */
2256
2257static VALUE
2258io_writev(int argc, const VALUE *argv, VALUE io)
2259{
2260 rb_io_t *fptr;
2261 long n;
2262 VALUE tmp, total = INT2FIX(0);
2263 int i, cnt = 1;
2264
2265 io = GetWriteIO(io);
2266 tmp = rb_io_check_io(io);
2267
2268 if (NIL_P(tmp)) {
2269 /* port is not IO, call write method for it. */
2270 return rb_funcallv(io, id_write, argc, argv);
2271 }
2272
2273 io = tmp;
2274
2275 GetOpenFile(io, fptr);
2277
2278 for (i = 0; i < argc; i += cnt) {
2279#ifdef HAVE_WRITEV
2280 if ((fptr->mode & (FMODE_SYNC|FMODE_TTY)) && iovcnt_ok(cnt = argc - i)) {
2281 n = io_fwritev(cnt, &argv[i], fptr);
2282 }
2283 else
2284#endif
2285 {
2286 cnt = 1;
2287 /* sync at last item */
2288 n = io_fwrite(rb_obj_as_string(argv[i]), fptr, (i < argc-1));
2289 }
2290
2291 if (n < 0L)
2292 rb_sys_fail_on_write(fptr);
2293
2294 total = rb_fix_plus(LONG2FIX(n), total);
2295 }
2296
2297 return total;
2298}
2299
2300/*
2301 * call-seq:
2302 * write(*objects) -> integer
2303 *
2304 * Writes each of the given +objects+ to +self+,
2305 * which must be opened for writing
2306 * (see {Access Modes}[rdoc-ref:File@Access+Modes]);
2307 * returns the total number bytes written;
2308 * each of +objects+ that is not a string is converted via method +to_s+:
2309 *
2310 * $stdout.write('Hello', ', ', 'World!', "\n") # => 14
2311 * $stdout.write('foo', :bar, 2, "\n") # => 8
2312 *
2313 * Output:
2314 *
2315 * Hello, World!
2316 * foobar2
2317 *
2318 * Related: IO#read.
2319 */
2320
2321static VALUE
2322io_write_m(int argc, VALUE *argv, VALUE io)
2323{
2324 if (argc != 1) {
2325 return io_writev(argc, argv, io);
2326 }
2327 else {
2328 VALUE str = argv[0];
2329 return io_write(io, str, 0);
2330 }
2331}
2332
2333VALUE
2334rb_io_write(VALUE io, VALUE str)
2335{
2336 return rb_funcallv(io, id_write, 1, &str);
2337}
2338
2339static VALUE
2340rb_io_writev(VALUE io, int argc, const VALUE *argv)
2341{
2342 if (argc > 1 && rb_obj_method_arity(io, id_write) == 1) {
2343 if (io != rb_ractor_stderr() && RTEST(ruby_verbose)) {
2344 VALUE klass = CLASS_OF(io);
2345 char sep = RCLASS_SINGLETON_P(klass) ? (klass = io, '.') : '#';
2347 RB_WARN_CATEGORY_DEPRECATED, "%+"PRIsVALUE"%c""write is outdated interface"
2348 " which accepts just one argument",
2349 klass, sep
2350 );
2351 }
2352
2353 do rb_io_write(io, *argv++); while (--argc);
2354
2355 return Qnil;
2356 }
2357
2358 return rb_funcallv(io, id_write, argc, argv);
2359}
2360
2361/*
2362 * call-seq:
2363 * self << object -> self
2364 *
2365 * Writes the given +object+ to +self+,
2366 * which must be opened for writing (see {Access Modes}[rdoc-ref:File@Access+Modes]);
2367 * returns +self+;
2368 * if +object+ is not a string, it is converted via method +to_s+:
2369 *
2370 * $stdout << 'Hello' << ', ' << 'World!' << "\n"
2371 * $stdout << 'foo' << :bar << 2 << "\n"
2372 *
2373 * Output:
2374 *
2375 * Hello, World!
2376 * foobar2
2377 *
2378 */
2379
2380
2381VALUE
2383{
2384 rb_io_write(io, str);
2385 return io;
2386}
2387
2388#ifdef HAVE_FSYNC
2389static VALUE
2390nogvl_fsync(void *ptr)
2391{
2392 rb_io_t *fptr = ptr;
2393
2394#ifdef _WIN32
2395 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->fd)) != FILE_TYPE_DISK)
2396 return 0;
2397#endif
2398 return (VALUE)fsync(fptr->fd);
2399}
2400#endif
2401
2402VALUE
2403rb_io_flush_raw(VALUE io, int sync)
2404{
2405 rb_io_t *fptr;
2406
2407 if (!RB_TYPE_P(io, T_FILE)) {
2408 return rb_funcall(io, id_flush, 0);
2409 }
2410
2411 io = GetWriteIO(io);
2412 GetOpenFile(io, fptr);
2413
2414 if (fptr->mode & FMODE_WRITABLE) {
2415 if (io_fflush(fptr) < 0)
2416 rb_sys_fail_on_write(fptr);
2417 }
2418 if (fptr->mode & FMODE_READABLE) {
2419 io_unread(fptr, true);
2420 }
2421
2422 return io;
2423}
2424
2425/*
2426 * call-seq:
2427 * flush -> self
2428 *
2429 * Flushes data buffered in +self+ to the operating system
2430 * (but does not necessarily flush data buffered in the operating system):
2431 *
2432 * $stdout.print 'no newline' # Not necessarily flushed.
2433 * $stdout.flush # Flushed.
2434 *
2435 */
2436
2437VALUE
2438rb_io_flush(VALUE io)
2439{
2440 return rb_io_flush_raw(io, 1);
2441}
2442
2443/*
2444 * call-seq:
2445 * tell -> integer
2446 *
2447 * Returns the current position (in bytes) in +self+
2448 * (see {Position}[rdoc-ref:IO@Position]):
2449 *
2450 * f = File.open('t.txt')
2451 * f.tell # => 0
2452 * f.gets # => "First line\n"
2453 * f.tell # => 12
2454 * f.close
2455 *
2456 * Related: IO#pos=, IO#seek.
2457 */
2458
2459static VALUE
2460rb_io_tell(VALUE io)
2461{
2462 rb_io_t *fptr;
2463 rb_off_t pos;
2464
2465 GetOpenFile(io, fptr);
2466 pos = io_tell(fptr);
2467 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2468 pos -= fptr->rbuf.len;
2469 return OFFT2NUM(pos);
2470}
2471
2472static VALUE
2473rb_io_seek(VALUE io, VALUE offset, int whence)
2474{
2475 rb_io_t *fptr;
2476 rb_off_t pos;
2477
2478 pos = NUM2OFFT(offset);
2479 GetOpenFile(io, fptr);
2480 pos = io_seek(fptr, pos, whence);
2481 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2482
2483 return INT2FIX(0);
2484}
2485
2486static int
2487interpret_seek_whence(VALUE vwhence)
2488{
2489 if (vwhence == sym_SET)
2490 return SEEK_SET;
2491 if (vwhence == sym_CUR)
2492 return SEEK_CUR;
2493 if (vwhence == sym_END)
2494 return SEEK_END;
2495#ifdef SEEK_DATA
2496 if (vwhence == sym_DATA)
2497 return SEEK_DATA;
2498#endif
2499#ifdef SEEK_HOLE
2500 if (vwhence == sym_HOLE)
2501 return SEEK_HOLE;
2502#endif
2503 return NUM2INT(vwhence);
2504}
2505
2506/*
2507 * call-seq:
2508 * seek(offset, whence = IO::SEEK_SET) -> 0
2509 *
2510 * Seeks to the position given by integer +offset+
2511 * (see {Position}[rdoc-ref:IO@Position])
2512 * and constant +whence+, which is one of:
2513 *
2514 * - +:CUR+ or <tt>IO::SEEK_CUR</tt>:
2515 * Repositions the stream to its current position plus the given +offset+:
2516 *
2517 * f = File.open('t.txt')
2518 * f.tell # => 0
2519 * f.seek(20, :CUR) # => 0
2520 * f.tell # => 20
2521 * f.seek(-10, :CUR) # => 0
2522 * f.tell # => 10
2523 * f.close
2524 *
2525 * - +:END+ or <tt>IO::SEEK_END</tt>:
2526 * Repositions the stream to its end plus the given +offset+:
2527 *
2528 * f = File.open('t.txt')
2529 * f.tell # => 0
2530 * f.seek(0, :END) # => 0 # Repositions to stream end.
2531 * f.tell # => 52
2532 * f.seek(-20, :END) # => 0
2533 * f.tell # => 32
2534 * f.seek(-40, :END) # => 0
2535 * f.tell # => 12
2536 * f.close
2537 *
2538 * - +:SET+ or <tt>IO:SEEK_SET</tt>:
2539 * Repositions the stream to the given +offset+:
2540 *
2541 * f = File.open('t.txt')
2542 * f.tell # => 0
2543 * f.seek(20, :SET) # => 0
2544 * f.tell # => 20
2545 * f.seek(40, :SET) # => 0
2546 * f.tell # => 40
2547 * f.close
2548 *
2549 * Related: IO#pos=, IO#tell.
2550 *
2551 */
2552
2553static VALUE
2554rb_io_seek_m(int argc, VALUE *argv, VALUE io)
2555{
2556 VALUE offset, ptrname;
2557 int whence = SEEK_SET;
2558
2559 if (rb_scan_args(argc, argv, "11", &offset, &ptrname) == 2) {
2560 whence = interpret_seek_whence(ptrname);
2561 }
2562
2563 return rb_io_seek(io, offset, whence);
2564}
2565
2566/*
2567 * call-seq:
2568 * pos = new_position -> new_position
2569 *
2570 * Seeks to the given +new_position+ (in bytes);
2571 * see {Position}[rdoc-ref:IO@Position]:
2572 *
2573 * f = File.open('t.txt')
2574 * f.tell # => 0
2575 * f.pos = 20 # => 20
2576 * f.tell # => 20
2577 * f.close
2578 *
2579 * Related: IO#seek, IO#tell.
2580 *
2581 */
2582
2583static VALUE
2584rb_io_set_pos(VALUE io, VALUE offset)
2585{
2586 rb_io_t *fptr;
2587 rb_off_t pos;
2588
2589 pos = NUM2OFFT(offset);
2590 GetOpenFile(io, fptr);
2591 pos = io_seek(fptr, pos, SEEK_SET);
2592 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2593
2594 return OFFT2NUM(pos);
2595}
2596
2597static void clear_readconv(rb_io_t *fptr);
2598
2599/*
2600 * call-seq:
2601 * rewind -> 0
2602 *
2603 * Repositions the stream to its beginning,
2604 * setting both the position and the line number to zero;
2605 * see {Position}[rdoc-ref:IO@Position]
2606 * and {Line Number}[rdoc-ref:IO@Line+Number]:
2607 *
2608 * f = File.open('t.txt')
2609 * f.tell # => 0
2610 * f.lineno # => 0
2611 * f.gets # => "First line\n"
2612 * f.tell # => 12
2613 * f.lineno # => 1
2614 * f.rewind # => 0
2615 * f.tell # => 0
2616 * f.lineno # => 0
2617 * f.close
2618 *
2619 * Note that this method cannot be used with streams such as pipes, ttys, and sockets.
2620 *
2621 */
2622
2623static VALUE
2624rb_io_rewind(VALUE io)
2625{
2626 rb_io_t *fptr;
2627
2628 GetOpenFile(io, fptr);
2629 if (io_seek(fptr, 0L, 0) < 0 && errno) rb_sys_fail_path(fptr->pathv);
2630 if (io == ARGF.current_file) {
2631 ARGF.lineno -= fptr->lineno;
2632 }
2633 fptr->lineno = 0;
2634 if (fptr->readconv) {
2635 clear_readconv(fptr);
2636 }
2637
2638 return INT2FIX(0);
2639}
2640
2641static int
2642fptr_wait_readable(rb_io_t *fptr)
2643{
2644 int result = rb_io_maybe_wait_readable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT);
2645
2646 if (result)
2647 rb_io_check_closed(fptr);
2648
2649 return result;
2650}
2651
2652static int
2653io_fillbuf(rb_io_t *fptr)
2654{
2655 ssize_t r;
2656
2657 if (fptr->rbuf.ptr == NULL) {
2658 fptr->rbuf.off = 0;
2659 fptr->rbuf.len = 0;
2660 fptr->rbuf.capa = IO_RBUF_CAPA_FOR(fptr);
2661 fptr->rbuf.ptr = ALLOC_N(char, fptr->rbuf.capa);
2662 }
2663 if (fptr->rbuf.len == 0) {
2664 retry:
2665 r = rb_io_read_memory(fptr, fptr->rbuf.ptr, fptr->rbuf.capa);
2666
2667 if (r < 0) {
2668 if (fptr_wait_readable(fptr))
2669 goto retry;
2670
2671 int e = errno;
2672 VALUE path = rb_sprintf("fd:%d ", fptr->fd);
2673 if (!NIL_P(fptr->pathv)) {
2674 rb_str_append(path, fptr->pathv);
2675 }
2676
2677 rb_syserr_fail_path(e, path);
2678 }
2679 if (r > 0) rb_io_check_closed(fptr);
2680 fptr->rbuf.off = 0;
2681 fptr->rbuf.len = (int)r; /* r should be <= rbuf_capa */
2682 if (r == 0)
2683 return -1; /* EOF */
2684 }
2685 return 0;
2686}
2687
2688/*
2689 * call-seq:
2690 * eof -> true or false
2691 *
2692 * Returns +true+ if the stream is positioned at its end, +false+ otherwise;
2693 * see {Position}[rdoc-ref:IO@Position]:
2694 *
2695 * f = File.open('t.txt')
2696 * f.eof # => false
2697 * f.seek(0, :END) # => 0
2698 * f.eof # => true
2699 * f.close
2700 *
2701 * Raises an exception unless the stream is opened for reading;
2702 * see {Mode}[rdoc-ref:File@Access+Modes].
2703 *
2704 * If +self+ is a stream such as pipe or socket, this method
2705 * blocks until the other end sends some data or closes it:
2706 *
2707 * r, w = IO.pipe
2708 * Thread.new { sleep 1; w.close }
2709 * r.eof? # => true # After 1-second wait.
2710 *
2711 * r, w = IO.pipe
2712 * Thread.new { sleep 1; w.puts "a" }
2713 * r.eof? # => false # After 1-second wait.
2714 *
2715 * r, w = IO.pipe
2716 * r.eof? # blocks forever
2717 *
2718 * Note that this method reads data to the input byte buffer. So
2719 * IO#sysread may not behave as you intend with IO#eof?, unless you
2720 * call IO#rewind first (which is not available for some streams).
2721 */
2722
2723VALUE
2725{
2726 rb_io_t *fptr;
2727
2728 GetOpenFile(io, fptr);
2730
2731 if (READ_CHAR_PENDING(fptr)) return Qfalse;
2732 if (READ_DATA_PENDING(fptr)) return Qfalse;
2733 READ_CHECK(fptr);
2734#if RUBY_CRLF_ENVIRONMENT
2735 if (!NEED_READCONV(fptr) && NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
2736 return RBOOL(eof(fptr->fd));
2737 }
2738#endif
2739 return RBOOL(io_fillbuf(fptr) < 0);
2740}
2741
2742/*
2743 * call-seq:
2744 * sync -> true or false
2745 *
2746 * Returns the current sync mode of the stream.
2747 * When sync mode is true, all output is immediately flushed to the underlying
2748 * operating system and is not buffered by Ruby internally. See also #fsync.
2749 *
2750 * f = File.open('t.tmp', 'w')
2751 * f.sync # => false
2752 * f.sync = true
2753 * f.sync # => true
2754 * f.close
2755 *
2756 */
2757
2758static VALUE
2759rb_io_sync(VALUE io)
2760{
2761 rb_io_t *fptr;
2762
2763 io = GetWriteIO(io);
2764 GetOpenFile(io, fptr);
2765 return RBOOL(fptr->mode & FMODE_SYNC);
2766}
2767
2768#ifdef HAVE_FSYNC
2769
2770/*
2771 * call-seq:
2772 * sync = boolean -> boolean
2773 *
2774 * Sets the _sync_ _mode_ for the stream to the given value;
2775 * returns the given value.
2776 *
2777 * Values for the sync mode:
2778 *
2779 * - +true+: All output is immediately flushed to the
2780 * underlying operating system and is not buffered internally.
2781 * - +false+: Output may be buffered internally.
2782 *
2783 * Example;
2784 *
2785 * f = File.open('t.tmp', 'w')
2786 * f.sync # => false
2787 * f.sync = true
2788 * f.sync # => true
2789 * f.close
2790 *
2791 * Related: IO#fsync.
2792 *
2793 */
2794
2795static VALUE
2796rb_io_set_sync(VALUE io, VALUE sync)
2797{
2798 rb_io_t *fptr;
2799
2800 io = GetWriteIO(io);
2801 GetOpenFile(io, fptr);
2802 if (RTEST(sync)) {
2803 fptr->mode |= FMODE_SYNC;
2804 }
2805 else {
2806 fptr->mode &= ~FMODE_SYNC;
2807 }
2808 return sync;
2809}
2810
2811/*
2812 * call-seq:
2813 * fsync -> 0
2814 *
2815 * Immediately writes to disk all data buffered in the stream,
2816 * via the operating system's <tt>fsync(2)</tt>.
2817
2818 * Note this difference:
2819 *
2820 * - IO#sync=: Ensures that data is flushed from the stream's internal buffers,
2821 * but does not guarantee that the operating system actually writes the data to disk.
2822 * - IO#fsync: Ensures both that data is flushed from internal buffers,
2823 * and that data is written to disk.
2824 *
2825 * Raises an exception if the operating system does not support <tt>fsync(2)</tt>.
2826 *
2827 */
2828
2829static VALUE
2830rb_io_fsync(VALUE io)
2831{
2832 rb_io_t *fptr;
2833
2834 io = GetWriteIO(io);
2835 GetOpenFile(io, fptr);
2836
2837 if (io_fflush(fptr) < 0)
2838 rb_sys_fail_on_write(fptr);
2839
2840 if ((int)rb_io_blocking_region(fptr, nogvl_fsync, fptr))
2841 rb_sys_fail_path(fptr->pathv);
2842
2843 return INT2FIX(0);
2844}
2845#else
2846# define rb_io_fsync rb_f_notimplement
2847# define rb_io_sync rb_f_notimplement
2848static VALUE
2849rb_io_set_sync(VALUE io, VALUE sync)
2850{
2853}
2854#endif
2855
2856#ifdef HAVE_FDATASYNC
2857static VALUE
2858nogvl_fdatasync(void *ptr)
2859{
2860 rb_io_t *fptr = ptr;
2861
2862#ifdef _WIN32
2863 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->fd)) != FILE_TYPE_DISK)
2864 return 0;
2865#endif
2866 return (VALUE)fdatasync(fptr->fd);
2867}
2868
2869/*
2870 * call-seq:
2871 * fdatasync -> 0
2872 *
2873 * Immediately writes to disk all data buffered in the stream,
2874 * via the operating system's: <tt>fdatasync(2)</tt>, if supported,
2875 * otherwise via <tt>fsync(2)</tt>, if supported;
2876 * otherwise raises an exception.
2877 *
2878 */
2879
2880static VALUE
2881rb_io_fdatasync(VALUE io)
2882{
2883 rb_io_t *fptr;
2884
2885 io = GetWriteIO(io);
2886 GetOpenFile(io, fptr);
2887
2888 if (io_fflush(fptr) < 0)
2889 rb_sys_fail_on_write(fptr);
2890
2891 if ((int)rb_io_blocking_region(fptr, nogvl_fdatasync, fptr) == 0)
2892 return INT2FIX(0);
2893
2894 /* fall back */
2895 return rb_io_fsync(io);
2896}
2897#else
2898#define rb_io_fdatasync rb_io_fsync
2899#endif
2900
2901/*
2902 * call-seq:
2903 * fileno -> integer
2904 *
2905 * Returns the integer file descriptor for the stream:
2906 *
2907 * $stdin.fileno # => 0
2908 * $stdout.fileno # => 1
2909 * $stderr.fileno # => 2
2910 * File.open('t.txt').fileno # => 10
2911 * f.close
2912 *
2913 */
2914
2915static VALUE
2916rb_io_fileno(VALUE io)
2917{
2918 rb_io_t *fptr = RFILE(io)->fptr;
2919 int fd;
2920
2921 rb_io_check_closed(fptr);
2922 fd = fptr->fd;
2923 return INT2FIX(fd);
2924}
2925
2926int
2928{
2929 if (RB_TYPE_P(io, T_FILE)) {
2930 rb_io_t *fptr = RFILE(io)->fptr;
2931 rb_io_check_closed(fptr);
2932 return fptr->fd;
2933 }
2934 else {
2935 VALUE fileno = rb_check_funcall(io, id_fileno, 0, NULL);
2936 if (!UNDEF_P(fileno)) {
2937 return RB_NUM2INT(fileno);
2938 }
2939 }
2940
2941 rb_raise(rb_eTypeError, "expected IO or #fileno, %"PRIsVALUE" given", rb_obj_class(io));
2942
2944}
2945
2946int
2947rb_io_mode(VALUE io)
2948{
2949 rb_io_t *fptr;
2950 GetOpenFile(io, fptr);
2951 return fptr->mode;
2952}
2953
2954/*
2955 * call-seq:
2956 * pid -> integer or nil
2957 *
2958 * Returns the process ID of a child process associated with the stream,
2959 * which will have been set by IO#popen, or +nil+ if the stream was not
2960 * created by IO#popen:
2961 *
2962 * pipe = IO.popen("-")
2963 * if pipe
2964 * $stderr.puts "In parent, child pid is #{pipe.pid}"
2965 * else
2966 * $stderr.puts "In child, pid is #{$$}"
2967 * end
2968 *
2969 * Output:
2970 *
2971 * In child, pid is 26209
2972 * In parent, child pid is 26209
2973 *
2974 */
2975
2976static VALUE
2977rb_io_pid(VALUE io)
2978{
2979 rb_io_t *fptr;
2980
2981 GetOpenFile(io, fptr);
2982 if (!fptr->pid)
2983 return Qnil;
2984 return PIDT2NUM(fptr->pid);
2985}
2986
2987/*
2988 * call-seq:
2989 * path -> string or nil
2990 *
2991 * Returns the path associated with the IO, or +nil+ if there is no path
2992 * associated with the IO. It is not guaranteed that the path exists on
2993 * the filesystem.
2994 *
2995 * $stdin.path # => "<STDIN>"
2996 *
2997 * File.open("testfile") {|f| f.path} # => "testfile"
2998 */
2999
3000VALUE
3002{
3003 rb_io_t *fptr = RFILE(io)->fptr;
3004
3005 if (!fptr)
3006 return Qnil;
3007
3008 return rb_obj_dup(fptr->pathv);
3009}
3010
3011/*
3012 * call-seq:
3013 * inspect -> string
3014 *
3015 * Returns a string representation of +self+:
3016 *
3017 * f = File.open('t.txt')
3018 * f.inspect # => "#<File:t.txt>"
3019 * f.close
3020 *
3021 */
3022
3023static VALUE
3024rb_io_inspect(VALUE obj)
3025{
3026 rb_io_t *fptr;
3027 VALUE result;
3028 static const char closed[] = " (closed)";
3029
3030 fptr = RFILE(obj)->fptr;
3031 if (!fptr) return rb_any_to_s(obj);
3032 result = rb_str_new_cstr("#<");
3033 rb_str_append(result, rb_class_name(CLASS_OF(obj)));
3034 rb_str_cat2(result, ":");
3035 if (NIL_P(fptr->pathv)) {
3036 if (fptr->fd < 0) {
3037 rb_str_cat(result, closed+1, strlen(closed)-1);
3038 }
3039 else {
3040 rb_str_catf(result, "fd %d", fptr->fd);
3041 }
3042 }
3043 else {
3044 rb_str_append(result, fptr->pathv);
3045 if (fptr->fd < 0) {
3046 rb_str_cat(result, closed, strlen(closed));
3047 }
3048 }
3049 return rb_str_cat2(result, ">");
3050}
3051
3052/*
3053 * call-seq:
3054 * to_io -> self
3055 *
3056 * Returns +self+.
3057 *
3058 */
3059
3060static VALUE
3061rb_io_to_io(VALUE io)
3062{
3063 return io;
3064}
3065
3066/* reading functions */
3067static long
3068read_buffered_data(char *ptr, long len, rb_io_t *fptr)
3069{
3070 int n;
3071
3072 n = READ_DATA_PENDING_COUNT(fptr);
3073 if (n <= 0) return 0;
3074 if (n > len) n = (int)len;
3075 MEMMOVE(ptr, fptr->rbuf.ptr+fptr->rbuf.off, char, n);
3076 fptr->rbuf.off += n;
3077 fptr->rbuf.len -= n;
3078 return n;
3079}
3080
3081static long
3082io_bufread(char *ptr, long len, rb_io_t *fptr)
3083{
3084 long offset = 0;
3085 long n = len;
3086 long c;
3087
3088 if (READ_DATA_PENDING(fptr) == 0) {
3089 while (n > 0) {
3090 again:
3091 rb_io_check_closed(fptr);
3092 c = rb_io_read_memory(fptr, ptr+offset, n);
3093 if (c == 0) break;
3094 if (c < 0) {
3095 if (fptr_wait_readable(fptr))
3096 goto again;
3097 return -1;
3098 }
3099 offset += c;
3100 if ((n -= c) <= 0) break;
3101 }
3102 return len - n;
3103 }
3104
3105 while (n > 0) {
3106 c = read_buffered_data(ptr+offset, n, fptr);
3107 if (c > 0) {
3108 offset += c;
3109 if ((n -= c) <= 0) break;
3110 }
3111 rb_io_check_closed(fptr);
3112 if (io_fillbuf(fptr) < 0) {
3113 break;
3114 }
3115 }
3116 return len - n;
3117}
3118
3119static int io_setstrbuf(VALUE *str, long len);
3120
3122 char *str_ptr;
3123 long len;
3124 rb_io_t *fptr;
3125};
3126
3127static VALUE
3128bufread_call(VALUE arg)
3129{
3130 struct bufread_arg *p = (struct bufread_arg *)arg;
3131 p->len = io_bufread(p->str_ptr, p->len, p->fptr);
3132 return Qundef;
3133}
3134
3135static long
3136io_fread(VALUE str, long offset, long size, rb_io_t *fptr)
3137{
3138 long len;
3139 struct bufread_arg arg;
3140
3141 io_setstrbuf(&str, offset + size);
3142 arg.str_ptr = RSTRING_PTR(str) + offset;
3143 arg.len = size;
3144 arg.fptr = fptr;
3145 rb_str_locktmp_ensure(str, bufread_call, (VALUE)&arg);
3146 len = arg.len;
3147 if (len < 0) rb_sys_fail_path(fptr->pathv);
3148 return len;
3149}
3150
3151static long
3152remain_size(rb_io_t *fptr)
3153{
3154 struct stat st;
3155 rb_off_t siz = READ_DATA_PENDING_COUNT(fptr);
3156 rb_off_t pos;
3157
3158 if (fstat(fptr->fd, &st) == 0 && S_ISREG(st.st_mode)
3159#if defined(__HAIKU__)
3160 && (st.st_dev > 3)
3161#endif
3162 )
3163 {
3164 if (io_fflush(fptr) < 0)
3165 rb_sys_fail_on_write(fptr);
3166 pos = lseek(fptr->fd, 0, SEEK_CUR);
3167 if (st.st_size >= pos && pos >= 0) {
3168 siz += st.st_size - pos;
3169 if (siz > LONG_MAX) {
3170 rb_raise(rb_eIOError, "file too big for single read");
3171 }
3172 }
3173 }
3174 else {
3175 siz += BUFSIZ;
3176 }
3177 return (long)siz;
3178}
3179
3180static VALUE
3181io_enc_str(VALUE str, rb_io_t *fptr)
3182{
3183 rb_enc_associate(str, io_read_encoding(fptr));
3184 return str;
3185}
3186
3187static void
3188make_readconv(rb_io_t *fptr, int size)
3189{
3190 if (!fptr->readconv) {
3191 int ecflags;
3192 VALUE ecopts;
3193 const char *sname, *dname;
3194 ecflags = fptr->encs.ecflags & ~ECONV_NEWLINE_DECORATOR_WRITE_MASK;
3195 ecopts = fptr->encs.ecopts;
3196 if (fptr->encs.enc2) {
3197 sname = rb_enc_name(fptr->encs.enc2);
3198 dname = rb_enc_name(io_read_encoding(fptr));
3199 }
3200 else {
3201 sname = dname = "";
3202 }
3203 fptr->readconv = rb_econv_open_opts(sname, dname, ecflags, ecopts);
3204 if (!fptr->readconv)
3205 rb_exc_raise(rb_econv_open_exc(sname, dname, ecflags));
3206 fptr->cbuf.off = 0;
3207 fptr->cbuf.len = 0;
3208 if (size < IO_CBUF_CAPA_MIN) size = IO_CBUF_CAPA_MIN;
3209 fptr->cbuf.capa = size;
3210 fptr->cbuf.ptr = ALLOC_N(char, fptr->cbuf.capa);
3211 }
3212}
3213
3214#define MORE_CHAR_SUSPENDED Qtrue
3215#define MORE_CHAR_FINISHED Qnil
3216static VALUE
3217fill_cbuf(rb_io_t *fptr, int ec_flags)
3218{
3219 const unsigned char *ss, *sp, *se;
3220 unsigned char *ds, *dp, *de;
3222 int putbackable;
3223 int cbuf_len0;
3224 VALUE exc;
3225
3226 ec_flags |= ECONV_PARTIAL_INPUT;
3227
3228 if (fptr->cbuf.len == fptr->cbuf.capa)
3229 return MORE_CHAR_SUSPENDED; /* cbuf full */
3230 if (fptr->cbuf.len == 0)
3231 fptr->cbuf.off = 0;
3232 else if (fptr->cbuf.off + fptr->cbuf.len == fptr->cbuf.capa) {
3233 memmove(fptr->cbuf.ptr, fptr->cbuf.ptr+fptr->cbuf.off, fptr->cbuf.len);
3234 fptr->cbuf.off = 0;
3235 }
3236
3237 cbuf_len0 = fptr->cbuf.len;
3238
3239 while (1) {
3240 ss = sp = (const unsigned char *)fptr->rbuf.ptr + fptr->rbuf.off;
3241 se = sp + fptr->rbuf.len;
3242 ds = dp = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.off + fptr->cbuf.len;
3243 de = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.capa;
3244 res = rb_econv_convert(fptr->readconv, &sp, se, &dp, de, ec_flags);
3245 fptr->rbuf.off += (int)(sp - ss);
3246 fptr->rbuf.len -= (int)(sp - ss);
3247 fptr->cbuf.len += (int)(dp - ds);
3248
3249 putbackable = rb_econv_putbackable(fptr->readconv);
3250 if (putbackable) {
3251 rb_econv_putback(fptr->readconv, (unsigned char *)fptr->rbuf.ptr + fptr->rbuf.off - putbackable, putbackable);
3252 fptr->rbuf.off -= putbackable;
3253 fptr->rbuf.len += putbackable;
3254 }
3255
3256 exc = rb_econv_make_exception(fptr->readconv);
3257 if (!NIL_P(exc))
3258 return exc;
3259
3260 if (cbuf_len0 != fptr->cbuf.len)
3261 return MORE_CHAR_SUSPENDED;
3262
3263 if (res == econv_finished) {
3264 return MORE_CHAR_FINISHED;
3265 }
3266
3267 if (res == econv_source_buffer_empty) {
3268 if (fptr->rbuf.len == 0) {
3269 READ_CHECK(fptr);
3270 if (io_fillbuf(fptr) < 0) {
3271 if (!fptr->readconv) {
3272 return MORE_CHAR_FINISHED;
3273 }
3274 ds = dp = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.off + fptr->cbuf.len;
3275 de = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.capa;
3276 res = rb_econv_convert(fptr->readconv, NULL, NULL, &dp, de, 0);
3277 fptr->cbuf.len += (int)(dp - ds);
3279 break;
3280 }
3281 }
3282 }
3283 }
3284 if (cbuf_len0 != fptr->cbuf.len)
3285 return MORE_CHAR_SUSPENDED;
3286
3287 return MORE_CHAR_FINISHED;
3288}
3289
3290static VALUE
3291more_char(rb_io_t *fptr)
3292{
3293 VALUE v;
3294 v = fill_cbuf(fptr, ECONV_AFTER_OUTPUT);
3295 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED)
3296 rb_exc_raise(v);
3297 return v;
3298}
3299
3300static VALUE
3301io_shift_cbuf(rb_io_t *fptr, int len, VALUE *strp)
3302{
3303 VALUE str = Qnil;
3304 if (strp) {
3305 str = *strp;
3306 if (NIL_P(str)) {
3307 *strp = str = rb_str_new(fptr->cbuf.ptr+fptr->cbuf.off, len);
3308 }
3309 else {
3310 rb_str_cat(str, fptr->cbuf.ptr+fptr->cbuf.off, len);
3311 }
3312 rb_enc_associate(str, fptr->encs.enc);
3313 }
3314 fptr->cbuf.off += len;
3315 fptr->cbuf.len -= len;
3316 /* xxx: set coderange */
3317 if (fptr->cbuf.len == 0)
3318 fptr->cbuf.off = 0;
3319 else if (fptr->cbuf.capa/2 < fptr->cbuf.off) {
3320 memmove(fptr->cbuf.ptr, fptr->cbuf.ptr+fptr->cbuf.off, fptr->cbuf.len);
3321 fptr->cbuf.off = 0;
3322 }
3323 return str;
3324}
3325
3326static int
3327io_setstrbuf(VALUE *str, long len)
3328{
3329 if (NIL_P(*str)) {
3330 *str = rb_str_new(0, len);
3331 return TRUE;
3332 }
3333 else {
3334 VALUE s = StringValue(*str);
3335 rb_str_modify(s);
3336
3337 long clen = RSTRING_LEN(s);
3338 if (clen >= len) {
3339 return FALSE;
3340 }
3341 len -= clen;
3342 }
3343 if ((rb_str_capacity(*str) - (size_t)RSTRING_LEN(*str)) < (size_t)len) {
3345 }
3346 return FALSE;
3347}
3348
3349#define MAX_REALLOC_GAP 4096
3350static void
3351io_shrink_read_string(VALUE str, long n)
3352{
3353 if (rb_str_capacity(str) - n > MAX_REALLOC_GAP) {
3354 rb_str_resize(str, n);
3355 }
3356}
3357
3358static void
3359io_set_read_length(VALUE str, long n, int shrinkable)
3360{
3361 if (RSTRING_LEN(str) != n) {
3362 rb_str_modify(str);
3363 rb_str_set_len(str, n);
3364 if (shrinkable) io_shrink_read_string(str, n);
3365 }
3366}
3367
3368static VALUE
3369read_all(rb_io_t *fptr, long siz, VALUE str)
3370{
3371 long bytes;
3372 long n;
3373 long pos;
3374 rb_encoding *enc;
3375 int cr;
3376 int shrinkable;
3377
3378 if (NEED_READCONV(fptr)) {
3379 int first = !NIL_P(str);
3380 SET_BINARY_MODE(fptr);
3381 shrinkable = io_setstrbuf(&str,0);
3382 make_readconv(fptr, 0);
3383 while (1) {
3384 VALUE v;
3385 if (fptr->cbuf.len) {
3386 if (first) rb_str_set_len(str, first = 0);
3387 io_shift_cbuf(fptr, fptr->cbuf.len, &str);
3388 }
3389 v = fill_cbuf(fptr, 0);
3390 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED) {
3391 if (fptr->cbuf.len) {
3392 if (first) rb_str_set_len(str, first = 0);
3393 io_shift_cbuf(fptr, fptr->cbuf.len, &str);
3394 }
3395 rb_exc_raise(v);
3396 }
3397 if (v == MORE_CHAR_FINISHED) {
3398 clear_readconv(fptr);
3399 if (first) rb_str_set_len(str, first = 0);
3400 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3401 return io_enc_str(str, fptr);
3402 }
3403 }
3404 }
3405
3406 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3407 bytes = 0;
3408 pos = 0;
3409
3410 enc = io_read_encoding(fptr);
3411 cr = 0;
3412
3413 if (siz == 0) siz = BUFSIZ;
3414 shrinkable = io_setstrbuf(&str, siz);
3415 for (;;) {
3416 READ_CHECK(fptr);
3417 n = io_fread(str, bytes, siz - bytes, fptr);
3418 if (n == 0 && bytes == 0) {
3419 rb_str_set_len(str, 0);
3420 break;
3421 }
3422 bytes += n;
3423 rb_str_set_len(str, bytes);
3424 if (cr != ENC_CODERANGE_BROKEN)
3425 pos += rb_str_coderange_scan_restartable(RSTRING_PTR(str) + pos, RSTRING_PTR(str) + bytes, enc, &cr);
3426 if (bytes < siz) break;
3427 siz += BUFSIZ;
3428
3429 size_t capa = rb_str_capacity(str);
3430 if (capa < (size_t)RSTRING_LEN(str) + BUFSIZ) {
3431 if (capa < BUFSIZ) {
3432 capa = BUFSIZ;
3433 }
3434 else if (capa > IO_MAX_BUFFER_GROWTH) {
3435 capa = IO_MAX_BUFFER_GROWTH;
3436 }
3438 }
3439 }
3440 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3441 str = io_enc_str(str, fptr);
3442 ENC_CODERANGE_SET(str, cr);
3443 return str;
3444}
3445
3446void
3448{
3449 if (rb_fd_set_nonblock(fptr->fd) != 0) {
3450 rb_sys_fail_path(fptr->pathv);
3451 }
3452}
3453
3454static VALUE
3455io_read_memory_call(VALUE arg)
3456{
3457 struct io_internal_read_struct *iis = (struct io_internal_read_struct *)arg;
3458
3459 VALUE scheduler = rb_fiber_scheduler_current();
3460 if (scheduler != Qnil) {
3461 VALUE result = rb_fiber_scheduler_io_read_memory(scheduler, iis->fptr->self, iis->buf, iis->capa, 0);
3462
3463 if (!UNDEF_P(result)) {
3464 // This is actually returned as a pseudo-VALUE and later cast to a long:
3466 }
3467 }
3468
3469 if (iis->nonblock) {
3470 return rb_io_blocking_region(iis->fptr, internal_read_func, iis);
3471 }
3472 else {
3473 return rb_io_blocking_region_wait(iis->fptr, internal_read_func, iis, RUBY_IO_READABLE);
3474 }
3475}
3476
3477static long
3478io_read_memory_locktmp(VALUE str, struct io_internal_read_struct *iis)
3479{
3480 return (long)rb_str_locktmp_ensure(str, io_read_memory_call, (VALUE)iis);
3481}
3482
3483#define no_exception_p(opts) !rb_opts_exception_p((opts), TRUE)
3484
3485static VALUE
3486io_getpartial(int argc, VALUE *argv, VALUE io, int no_exception, int nonblock)
3487{
3488 rb_io_t *fptr;
3489 VALUE length, str;
3490 long n, len;
3491 struct io_internal_read_struct iis;
3492 int shrinkable;
3493
3494 rb_scan_args(argc, argv, "11", &length, &str);
3495
3496 if ((len = NUM2LONG(length)) < 0) {
3497 rb_raise(rb_eArgError, "negative length %ld given", len);
3498 }
3499
3500 shrinkable = io_setstrbuf(&str, len);
3501
3502 GetOpenFile(io, fptr);
3504
3505 if (len == 0) {
3506 io_set_read_length(str, 0, shrinkable);
3507 return str;
3508 }
3509
3510 if (!nonblock)
3511 READ_CHECK(fptr);
3512 n = read_buffered_data(RSTRING_PTR(str), len, fptr);
3513 if (n <= 0) {
3514 again:
3515 if (nonblock) {
3516 rb_io_set_nonblock(fptr);
3517 }
3518 io_setstrbuf(&str, len);
3519 iis.th = rb_thread_current();
3520 iis.fptr = fptr;
3521 iis.nonblock = nonblock;
3522 iis.fd = fptr->fd;
3523 iis.buf = RSTRING_PTR(str);
3524 iis.capa = len;
3525 iis.timeout = NULL;
3526 n = io_read_memory_locktmp(str, &iis);
3527 if (n < 0) {
3528 int e = errno;
3529 if (!nonblock && fptr_wait_readable(fptr))
3530 goto again;
3531 if (nonblock && (io_again_p(e))) {
3532 if (no_exception)
3533 return sym_wait_readable;
3534 else
3535 rb_readwrite_syserr_fail(RB_IO_WAIT_READABLE,
3536 e, "read would block");
3537 }
3538 rb_syserr_fail_path(e, fptr->pathv);
3539 }
3540 }
3541 io_set_read_length(str, n, shrinkable);
3542
3543 if (n == 0)
3544 return Qnil;
3545 else
3546 return str;
3547}
3548
3549/*
3550 * call-seq:
3551 * readpartial(maxlen) -> string
3552 * readpartial(maxlen, out_string) -> out_string
3553 *
3554 * Reads up to +maxlen+ bytes from the stream;
3555 * returns a string (either a new string or the given +out_string+).
3556 * Its encoding is:
3557 *
3558 * - The unchanged encoding of +out_string+, if +out_string+ is given.
3559 * - ASCII-8BIT, otherwise.
3560 *
3561 * - Contains +maxlen+ bytes from the stream, if available.
3562 * - Otherwise contains all available bytes, if any available.
3563 * - Otherwise is an empty string.
3564 *
3565 * With the single non-negative integer argument +maxlen+ given,
3566 * returns a new string:
3567 *
3568 * f = File.new('t.txt')
3569 * f.readpartial(20) # => "First line\nSecond l"
3570 * f.readpartial(20) # => "ine\n\nFourth line\n"
3571 * f.readpartial(20) # => "Fifth line\n"
3572 * f.readpartial(20) # Raises EOFError.
3573 * f.close
3574 *
3575 * With both argument +maxlen+ and string argument +out_string+ given,
3576 * returns modified +out_string+:
3577 *
3578 * f = File.new('t.txt')
3579 * s = 'foo'
3580 * f.readpartial(20, s) # => "First line\nSecond l"
3581 * s = 'bar'
3582 * f.readpartial(0, s) # => ""
3583 * f.close
3584 *
3585 * This method is useful for a stream such as a pipe, a socket, or a tty.
3586 * It blocks only when no data is immediately available.
3587 * This means that it blocks only when _all_ of the following are true:
3588 *
3589 * - The byte buffer in the stream is empty.
3590 * - The content of the stream is empty.
3591 * - The stream is not at EOF.
3592 *
3593 * When blocked, the method waits for either more data or EOF on the stream:
3594 *
3595 * - If more data is read, the method returns the data.
3596 * - If EOF is reached, the method raises EOFError.
3597 *
3598 * When not blocked, the method responds immediately:
3599 *
3600 * - Returns data from the buffer if there is any.
3601 * - Otherwise returns data from the stream if there is any.
3602 * - Otherwise raises EOFError if the stream has reached EOF.
3603 *
3604 * Note that this method is similar to sysread. The differences are:
3605 *
3606 * - If the byte buffer is not empty, read from the byte buffer
3607 * instead of "sysread for buffered IO (IOError)".
3608 * - It doesn't cause Errno::EWOULDBLOCK and Errno::EINTR. When
3609 * readpartial meets EWOULDBLOCK and EINTR by read system call,
3610 * readpartial retries the system call.
3611 *
3612 * The latter means that readpartial is non-blocking-flag insensitive.
3613 * It blocks on the situation IO#sysread causes Errno::EWOULDBLOCK as
3614 * if the fd is blocking mode.
3615 *
3616 * Examples:
3617 *
3618 * # # Returned Buffer Content Pipe Content
3619 * r, w = IO.pipe #
3620 * w << 'abc' # "" "abc".
3621 * r.readpartial(4096) # => "abc" "" ""
3622 * r.readpartial(4096) # (Blocks because buffer and pipe are empty.)
3623 *
3624 * # # Returned Buffer Content Pipe Content
3625 * r, w = IO.pipe #
3626 * w << 'abc' # "" "abc"
3627 * w.close # "" "abc" EOF
3628 * r.readpartial(4096) # => "abc" "" EOF
3629 * r.readpartial(4096) # raises EOFError
3630 *
3631 * # # Returned Buffer Content Pipe Content
3632 * r, w = IO.pipe #
3633 * w << "abc\ndef\n" # "" "abc\ndef\n"
3634 * r.gets # => "abc\n" "def\n" ""
3635 * w << "ghi\n" # "def\n" "ghi\n"
3636 * r.readpartial(4096) # => "def\n" "" "ghi\n"
3637 * r.readpartial(4096) # => "ghi\n" "" ""
3638 *
3639 */
3640
3641static VALUE
3642io_readpartial(int argc, VALUE *argv, VALUE io)
3643{
3644 VALUE ret;
3645
3646 ret = io_getpartial(argc, argv, io, Qnil, 0);
3647 if (NIL_P(ret))
3648 rb_eof_error();
3649 return ret;
3650}
3651
3652static VALUE
3653io_nonblock_eof(int no_exception)
3654{
3655 if (!no_exception) {
3656 rb_eof_error();
3657 }
3658 return Qnil;
3659}
3660
3661/* :nodoc: */
3662static VALUE
3663io_read_nonblock(rb_execution_context_t *ec, VALUE io, VALUE length, VALUE str, VALUE ex)
3664{
3665 rb_io_t *fptr;
3666 long n, len;
3667 struct io_internal_read_struct iis;
3668 int shrinkable;
3669
3670 if ((len = NUM2LONG(length)) < 0) {
3671 rb_raise(rb_eArgError, "negative length %ld given", len);
3672 }
3673
3674 shrinkable = io_setstrbuf(&str, len);
3675 rb_bool_expected(ex, "exception", TRUE);
3676
3677 GetOpenFile(io, fptr);
3679
3680 if (len == 0) {
3681 io_set_read_length(str, 0, shrinkable);
3682 return str;
3683 }
3684
3685 n = read_buffered_data(RSTRING_PTR(str), len, fptr);
3686 if (n <= 0) {
3687 rb_fd_set_nonblock(fptr->fd);
3688 shrinkable |= io_setstrbuf(&str, len);
3689 iis.fptr = fptr;
3690 iis.nonblock = 1;
3691 iis.fd = fptr->fd;
3692 iis.buf = RSTRING_PTR(str);
3693 iis.capa = len;
3694 iis.timeout = NULL;
3695 n = io_read_memory_locktmp(str, &iis);
3696 if (n < 0) {
3697 int e = errno;
3698 if (io_again_p(e)) {
3699 if (!ex) return sym_wait_readable;
3700 rb_readwrite_syserr_fail(RB_IO_WAIT_READABLE,
3701 e, "read would block");
3702 }
3703 rb_syserr_fail_path(e, fptr->pathv);
3704 }
3705 }
3706 io_set_read_length(str, n, shrinkable);
3707
3708 if (n == 0) {
3709 if (!ex) return Qnil;
3710 rb_eof_error();
3711 }
3712
3713 return str;
3714}
3715
3716/* :nodoc: */
3717static VALUE
3718io_write_nonblock(rb_execution_context_t *ec, VALUE io, VALUE str, VALUE ex)
3719{
3720 rb_io_t *fptr;
3721 long n;
3722
3723 if (!RB_TYPE_P(str, T_STRING))
3724 str = rb_obj_as_string(str);
3725 rb_bool_expected(ex, "exception", TRUE);
3726
3727 io = GetWriteIO(io);
3728 GetOpenFile(io, fptr);
3730
3731 if (io_fflush(fptr) < 0)
3732 rb_sys_fail_on_write(fptr);
3733
3734 rb_fd_set_nonblock(fptr->fd);
3735 n = write(fptr->fd, RSTRING_PTR(str), RSTRING_LEN(str));
3736 RB_GC_GUARD(str);
3737
3738 if (n < 0) {
3739 int e = errno;
3740 if (io_again_p(e)) {
3741 if (!ex) {
3742 return sym_wait_writable;
3743 }
3744 else {
3745 rb_readwrite_syserr_fail(RB_IO_WAIT_WRITABLE, e, "write would block");
3746 }
3747 }
3748 rb_syserr_fail_path(e, fptr->pathv);
3749 }
3750
3751 return LONG2FIX(n);
3752}
3753
3754/*
3755 * call-seq:
3756 * read(maxlen = nil, out_string = nil) -> new_string, out_string, or nil
3757 *
3758 * Reads bytes from the stream; the stream must be opened for reading
3759 * (see {Access Modes}[rdoc-ref:File@Access+Modes]):
3760 *
3761 * - If +maxlen+ is +nil+, reads all bytes using the stream's data mode.
3762 * - Otherwise reads up to +maxlen+ bytes in binary mode.
3763 *
3764 * Returns a string (either a new string or the given +out_string+)
3765 * containing the bytes read.
3766 * The encoding of the string depends on both +maxLen+ and +out_string+:
3767 *
3768 * - +maxlen+ is +nil+: uses internal encoding of +self+
3769 * (regardless of whether +out_string+ was given).
3770 * - +maxlen+ not +nil+:
3771 *
3772 * - +out_string+ given: encoding of +out_string+ not modified.
3773 * - +out_string+ not given: ASCII-8BIT is used.
3774 *
3775 * <b>Without Argument +out_string+</b>
3776 *
3777 * When argument +out_string+ is omitted,
3778 * the returned value is a new string:
3779 *
3780 * f = File.new('t.txt')
3781 * f.read
3782 * # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3783 * f.rewind
3784 * f.read(30) # => "First line\r\nSecond line\r\n\r\nFou"
3785 * f.read(30) # => "rth line\r\nFifth line\r\n"
3786 * f.read(30) # => nil
3787 * f.close
3788 *
3789 * If +maxlen+ is zero, returns an empty string.
3790 *
3791 * <b> With Argument +out_string+</b>
3792 *
3793 * When argument +out_string+ is given,
3794 * the returned value is +out_string+, whose content is replaced:
3795 *
3796 * f = File.new('t.txt')
3797 * s = 'foo' # => "foo"
3798 * f.read(nil, s) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3799 * s # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3800 * f.rewind
3801 * s = 'bar'
3802 * f.read(30, s) # => "First line\r\nSecond line\r\n\r\nFou"
3803 * s # => "First line\r\nSecond line\r\n\r\nFou"
3804 * s = 'baz'
3805 * f.read(30, s) # => "rth line\r\nFifth line\r\n"
3806 * s # => "rth line\r\nFifth line\r\n"
3807 * s = 'bat'
3808 * f.read(30, s) # => nil
3809 * s # => ""
3810 * f.close
3811 *
3812 * Note that this method behaves like the fread() function in C.
3813 * This means it retries to invoke read(2) system calls to read data
3814 * with the specified maxlen (or until EOF).
3815 *
3816 * This behavior is preserved even if the stream is in non-blocking mode.
3817 * (This method is non-blocking-flag insensitive as other methods.)
3818 *
3819 * If you need the behavior like a single read(2) system call,
3820 * consider #readpartial, #read_nonblock, and #sysread.
3821 *
3822 * Related: IO#write.
3823 */
3824
3825static VALUE
3826io_read(int argc, VALUE *argv, VALUE io)
3827{
3828 rb_io_t *fptr;
3829 long n, len;
3830 VALUE length, str;
3831 int shrinkable;
3832#if RUBY_CRLF_ENVIRONMENT
3833 int previous_mode;
3834#endif
3835
3836 rb_scan_args(argc, argv, "02", &length, &str);
3837
3838 if (NIL_P(length)) {
3839 GetOpenFile(io, fptr);
3841 return read_all(fptr, remain_size(fptr), str);
3842 }
3843 len = NUM2LONG(length);
3844 if (len < 0) {
3845 rb_raise(rb_eArgError, "negative length %ld given", len);
3846 }
3847
3848 shrinkable = io_setstrbuf(&str,len);
3849
3850 GetOpenFile(io, fptr);
3852 if (len == 0) {
3853 io_set_read_length(str, 0, shrinkable);
3854 return str;
3855 }
3856
3857 READ_CHECK(fptr);
3858#if RUBY_CRLF_ENVIRONMENT
3859 previous_mode = set_binary_mode_with_seek_cur(fptr);
3860#endif
3861 n = io_fread(str, 0, len, fptr);
3862 io_set_read_length(str, n, shrinkable);
3863#if RUBY_CRLF_ENVIRONMENT
3864 if (previous_mode == O_TEXT) {
3865 setmode(fptr->fd, O_TEXT);
3866 }
3867#endif
3868 if (n == 0) return Qnil;
3869
3870 return str;
3871}
3872
3873static void
3874rscheck(const char *rsptr, long rslen, VALUE rs)
3875{
3876 if (!rs) return;
3877 if (RSTRING_PTR(rs) != rsptr && RSTRING_LEN(rs) != rslen)
3878 rb_raise(rb_eRuntimeError, "rs modified");
3879}
3880
3881static const char *
3882search_delim(const char *p, long len, int delim, rb_encoding *enc)
3883{
3884 if (rb_enc_mbminlen(enc) == 1) {
3885 p = memchr(p, delim, len);
3886 if (p) return p + 1;
3887 }
3888 else {
3889 const char *end = p + len;
3890 while (p < end) {
3891 int r = rb_enc_precise_mbclen(p, end, enc);
3892 if (!MBCLEN_CHARFOUND_P(r)) {
3893 p += rb_enc_mbminlen(enc);
3894 continue;
3895 }
3896 int n = MBCLEN_CHARFOUND_LEN(r);
3897 if (rb_enc_mbc_to_codepoint(p, end, enc) == (unsigned int)delim) {
3898 return p + n;
3899 }
3900 p += n;
3901 }
3902 }
3903 return NULL;
3904}
3905
3906static int
3907appendline(rb_io_t *fptr, int delim, VALUE *strp, long *lp, rb_encoding *enc)
3908{
3909 VALUE str = *strp;
3910 long limit = *lp;
3911
3912 if (NEED_READCONV(fptr)) {
3913 SET_BINARY_MODE(fptr);
3914 make_readconv(fptr, 0);
3915 do {
3916 const char *p, *e;
3917 int searchlen = READ_CHAR_PENDING_COUNT(fptr);
3918 if (searchlen) {
3919 p = READ_CHAR_PENDING_PTR(fptr);
3920 if (0 < limit && limit < searchlen)
3921 searchlen = (int)limit;
3922 e = search_delim(p, searchlen, delim, enc);
3923 if (e) {
3924 int len = (int)(e-p);
3925 if (NIL_P(str))
3926 *strp = str = rb_str_new(p, len);
3927 else
3928 rb_str_buf_cat(str, p, len);
3929 fptr->cbuf.off += len;
3930 fptr->cbuf.len -= len;
3931 limit -= len;
3932 *lp = limit;
3933 return delim;
3934 }
3935
3936 if (NIL_P(str))
3937 *strp = str = rb_str_new(p, searchlen);
3938 else
3939 rb_str_buf_cat(str, p, searchlen);
3940 fptr->cbuf.off += searchlen;
3941 fptr->cbuf.len -= searchlen;
3942 limit -= searchlen;
3943
3944 if (limit == 0) {
3945 *lp = limit;
3946 return (unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
3947 }
3948 }
3949 } while (more_char(fptr) != MORE_CHAR_FINISHED);
3950 clear_readconv(fptr);
3951 *lp = limit;
3952 return EOF;
3953 }
3954
3955 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3956 do {
3957 long pending = READ_DATA_PENDING_COUNT(fptr);
3958 if (pending > 0) {
3959 const char *p = READ_DATA_PENDING_PTR(fptr);
3960 const char *e;
3961 long last;
3962
3963 if (limit > 0 && pending > limit) pending = limit;
3964 e = search_delim(p, pending, delim, enc);
3965 if (e) pending = e - p;
3966 if (!NIL_P(str)) {
3967 last = RSTRING_LEN(str);
3968 rb_str_resize(str, last + pending);
3969 }
3970 else {
3971 last = 0;
3972 *strp = str = rb_str_buf_new(pending);
3973 rb_str_set_len(str, pending);
3974 }
3975 read_buffered_data(RSTRING_PTR(str) + last, pending, fptr); /* must not fail */
3976 limit -= pending;
3977 *lp = limit;
3978 if (e) return delim;
3979 if (limit == 0)
3980 return (unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
3981 }
3982 READ_CHECK(fptr);
3983 } while (io_fillbuf(fptr) >= 0);
3984 *lp = limit;
3985 return EOF;
3986}
3987
3988static inline int
3989swallow(rb_io_t *fptr, int term)
3990{
3991 if (NEED_READCONV(fptr)) {
3992 rb_encoding *enc = io_read_encoding(fptr);
3993 int needconv = rb_enc_mbminlen(enc) != 1;
3994 SET_BINARY_MODE(fptr);
3995 make_readconv(fptr, 0);
3996 do {
3997 size_t cnt;
3998 while ((cnt = READ_CHAR_PENDING_COUNT(fptr)) > 0) {
3999 const char *p = READ_CHAR_PENDING_PTR(fptr);
4000 int i;
4001 if (!needconv) {
4002 if (*p != term) return TRUE;
4003 i = (int)cnt;
4004 while (--i && *++p == term);
4005 }
4006 else {
4007 const char *e = p + cnt;
4008 if (rb_enc_ascget(p, e, &i, enc) != term) return TRUE;
4009 while ((p += i) < e && rb_enc_ascget(p, e, &i, enc) == term);
4010 i = (int)(e - p);
4011 }
4012 io_shift_cbuf(fptr, (int)cnt - i, NULL);
4013 }
4014 } while (more_char(fptr) != MORE_CHAR_FINISHED);
4015 return FALSE;
4016 }
4017
4018 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4019 do {
4020 size_t cnt;
4021 while ((cnt = READ_DATA_PENDING_COUNT(fptr)) > 0) {
4022 char buf[1024];
4023 const char *p = READ_DATA_PENDING_PTR(fptr);
4024 int i;
4025 if (cnt > sizeof buf) cnt = sizeof buf;
4026 if (*p != term) return TRUE;
4027 i = (int)cnt;
4028 while (--i && *++p == term);
4029 if (!read_buffered_data(buf, cnt - i, fptr)) /* must not fail */
4030 rb_sys_fail_path(fptr->pathv);
4031 }
4032 READ_CHECK(fptr);
4033 } while (io_fillbuf(fptr) == 0);
4034 return FALSE;
4035}
4036
4037static VALUE
4038rb_io_getline_fast(rb_io_t *fptr, rb_encoding *enc, int chomp)
4039{
4040 VALUE str = Qnil;
4041 int len = 0;
4042 long pos = 0;
4043 int cr = 0;
4044
4045 do {
4046 int pending = READ_DATA_PENDING_COUNT(fptr);
4047
4048 if (pending > 0) {
4049 const char *p = READ_DATA_PENDING_PTR(fptr);
4050 const char *e;
4051 int chomplen = 0;
4052
4053 e = memchr(p, '\n', pending);
4054 if (e) {
4055 pending = (int)(e - p + 1);
4056 if (chomp) {
4057 chomplen = (pending > 1 && *(e-1) == '\r') + 1;
4058 }
4059 }
4060 if (NIL_P(str)) {
4061 str = rb_str_new(p, pending - chomplen);
4062 fptr->rbuf.off += pending;
4063 fptr->rbuf.len -= pending;
4064 }
4065 else {
4066 rb_str_resize(str, len + pending - chomplen);
4067 read_buffered_data(RSTRING_PTR(str)+len, pending - chomplen, fptr);
4068 fptr->rbuf.off += chomplen;
4069 fptr->rbuf.len -= chomplen;
4070 if (pending == 1 && chomplen == 1 && len > 0) {
4071 if (RSTRING_PTR(str)[len-1] == '\r') {
4072 rb_str_resize(str, --len);
4073 break;
4074 }
4075 }
4076 }
4077 len += pending - chomplen;
4078 if (cr != ENC_CODERANGE_BROKEN)
4079 pos += rb_str_coderange_scan_restartable(RSTRING_PTR(str) + pos, RSTRING_PTR(str) + len, enc, &cr);
4080 if (e) break;
4081 }
4082 READ_CHECK(fptr);
4083 } while (io_fillbuf(fptr) >= 0);
4084 if (NIL_P(str)) return Qnil;
4085
4086 str = io_enc_str(str, fptr);
4087 ENC_CODERANGE_SET(str, cr);
4088 fptr->lineno++;
4089
4090 return str;
4091}
4092
4094 VALUE io;
4095 VALUE rs;
4096 long limit;
4097 unsigned int chomp: 1;
4098};
4099
4100static void
4101extract_getline_opts(VALUE opts, struct getline_arg *args)
4102{
4103 int chomp = FALSE;
4104 if (!NIL_P(opts)) {
4105 static ID kwds[1];
4106 VALUE vchomp;
4107 if (!kwds[0]) {
4108 kwds[0] = rb_intern_const("chomp");
4109 }
4110 rb_get_kwargs(opts, kwds, 0, -2, &vchomp);
4111 chomp = (!UNDEF_P(vchomp)) && RTEST(vchomp);
4112 }
4113 args->chomp = chomp;
4114}
4115
4116static void
4117extract_getline_args(int argc, VALUE *argv, struct getline_arg *args)
4118{
4119 VALUE rs = rb_rs, lim = Qnil;
4120
4121 if (argc == 1) {
4122 VALUE tmp = Qnil;
4123
4124 if (NIL_P(argv[0]) || !NIL_P(tmp = rb_check_string_type(argv[0]))) {
4125 rs = tmp;
4126 }
4127 else {
4128 lim = argv[0];
4129 }
4130 }
4131 else if (2 <= argc) {
4132 rs = argv[0], lim = argv[1];
4133 if (!NIL_P(rs))
4134 StringValue(rs);
4135 }
4136 args->rs = rs;
4137 args->limit = NIL_P(lim) ? -1L : NUM2LONG(lim);
4138}
4139
4140static void
4141check_getline_args(VALUE *rsp, long *limit, VALUE io)
4142{
4143 rb_io_t *fptr;
4144 VALUE rs = *rsp;
4145
4146 if (!NIL_P(rs)) {
4147 rb_encoding *enc_rs, *enc_io;
4148
4149 GetOpenFile(io, fptr);
4150 enc_rs = rb_enc_get(rs);
4151 enc_io = io_read_encoding(fptr);
4152 if (enc_io != enc_rs &&
4153 (!is_ascii_string(rs) ||
4154 (RSTRING_LEN(rs) > 0 && !rb_enc_asciicompat(enc_io)))) {
4155 if (rs == rb_default_rs) {
4156 rs = rb_enc_str_new(0, 0, enc_io);
4157 rb_str_buf_cat_ascii(rs, "\n");
4158 *rsp = rs;
4159 }
4160 else {
4161 rb_raise(rb_eArgError, "encoding mismatch: %s IO with %s RS",
4162 rb_enc_name(enc_io),
4163 rb_enc_name(enc_rs));
4164 }
4165 }
4166 }
4167}
4168
4169static void
4170prepare_getline_args(int argc, VALUE *argv, struct getline_arg *args, VALUE io)
4171{
4172 VALUE opts;
4173 argc = rb_scan_args(argc, argv, "02:", NULL, NULL, &opts);
4174 extract_getline_args(argc, argv, args);
4175 extract_getline_opts(opts, args);
4176 check_getline_args(&args->rs, &args->limit, io);
4177}
4178
4179static VALUE
4180rb_io_getline_0(VALUE rs, long limit, int chomp, rb_io_t *fptr)
4181{
4182 VALUE str = Qnil;
4183 int nolimit = 0;
4184 rb_encoding *enc;
4185
4187 if (NIL_P(rs) && limit < 0) {
4188 str = read_all(fptr, 0, Qnil);
4189 if (RSTRING_LEN(str) == 0) return Qnil;
4190 }
4191 else if (limit == 0) {
4192 return rb_enc_str_new(0, 0, io_read_encoding(fptr));
4193 }
4194 else if (rs == rb_default_rs && limit < 0 && !NEED_READCONV(fptr) &&
4195 rb_enc_asciicompat(enc = io_read_encoding(fptr))) {
4196 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4197 return rb_io_getline_fast(fptr, enc, chomp);
4198 }
4199 else {
4200 int c, newline = -1;
4201 const char *rsptr = 0;
4202 long rslen = 0;
4203 int rspara = 0;
4204 int extra_limit = 16;
4205 int chomp_cr = chomp;
4206
4207 SET_BINARY_MODE(fptr);
4208 enc = io_read_encoding(fptr);
4209
4210 if (!NIL_P(rs)) {
4211 rslen = RSTRING_LEN(rs);
4212 if (rslen == 0) {
4213 rsptr = "\n\n";
4214 rslen = 2;
4215 rspara = 1;
4216 swallow(fptr, '\n');
4217 rs = 0;
4218 if (!rb_enc_asciicompat(enc)) {
4219 rs = rb_usascii_str_new(rsptr, rslen);
4220 rs = rb_str_conv_enc(rs, 0, enc);
4221 OBJ_FREEZE(rs);
4222 rsptr = RSTRING_PTR(rs);
4223 rslen = RSTRING_LEN(rs);
4224 }
4225 newline = '\n';
4226 }
4227 else if (rb_enc_mbminlen(enc) == 1) {
4228 rsptr = RSTRING_PTR(rs);
4229 newline = (unsigned char)rsptr[rslen - 1];
4230 }
4231 else {
4232 rs = rb_str_conv_enc(rs, 0, enc);
4233 rsptr = RSTRING_PTR(rs);
4234 const char *e = rsptr + rslen;
4235 const char *last = rb_enc_prev_char(rsptr, e, e, enc);
4236 int n;
4237 newline = rb_enc_codepoint_len(last, e, &n, enc);
4238 if (last + n != e) rb_raise(rb_eArgError, "broken separator");
4239 }
4240 chomp_cr = chomp && newline == '\n' && rslen == rb_enc_mbminlen(enc);
4241 }
4242
4243 /* MS - Optimization */
4244 while ((c = appendline(fptr, newline, &str, &limit, enc)) != EOF) {
4245 const char *s, *p, *pp, *e;
4246
4247 if (c == newline) {
4248 if (RSTRING_LEN(str) < rslen) continue;
4249 s = RSTRING_PTR(str);
4250 e = RSTRING_END(str);
4251 p = e - rslen;
4252 if (!at_char_boundary(s, p, e, enc)) continue;
4253 if (!rspara) rscheck(rsptr, rslen, rs);
4254 if (memcmp(p, rsptr, rslen) == 0) {
4255 if (chomp) {
4256 if (chomp_cr && p > s && *(p-1) == '\r') --p;
4257 rb_str_set_len(str, p - s);
4258 }
4259 break;
4260 }
4261 }
4262 if (limit == 0) {
4263 s = RSTRING_PTR(str);
4264 p = RSTRING_END(str);
4265 pp = rb_enc_prev_char(s, p, p, enc);
4266 if (extra_limit && pp &&
4267 MBCLEN_NEEDMORE_P(rb_enc_precise_mbclen(pp, p, enc))) {
4268 /* relax the limit while incomplete character.
4269 * extra_limit limits the relax length */
4270 limit = 1;
4271 extra_limit--;
4272 }
4273 else {
4274 nolimit = 1;
4275 break;
4276 }
4277 }
4278 }
4279
4280 if (rspara && c != EOF)
4281 swallow(fptr, '\n');
4282 if (!NIL_P(str))
4283 str = io_enc_str(str, fptr);
4284 }
4285
4286 if (!NIL_P(str) && !nolimit) {
4287 fptr->lineno++;
4288 }
4289
4290 return str;
4291}
4292
4293static VALUE
4294rb_io_getline_1(VALUE rs, long limit, int chomp, VALUE io)
4295{
4296 rb_io_t *fptr;
4297 int old_lineno, new_lineno;
4298 VALUE str;
4299
4300 GetOpenFile(io, fptr);
4301 old_lineno = fptr->lineno;
4302 str = rb_io_getline_0(rs, limit, chomp, fptr);
4303 if (!NIL_P(str) && (new_lineno = fptr->lineno) != old_lineno) {
4304 if (io == ARGF.current_file) {
4305 ARGF.lineno += new_lineno - old_lineno;
4306 ARGF.last_lineno = ARGF.lineno;
4307 }
4308 else {
4309 ARGF.last_lineno = new_lineno;
4310 }
4311 }
4312
4313 return str;
4314}
4315
4316static VALUE
4317rb_io_getline(int argc, VALUE *argv, VALUE io)
4318{
4319 struct getline_arg args;
4320
4321 prepare_getline_args(argc, argv, &args, io);
4322 return rb_io_getline_1(args.rs, args.limit, args.chomp, io);
4323}
4324
4325VALUE
4327{
4328 return rb_io_getline_1(rb_default_rs, -1, FALSE, io);
4329}
4330
4331VALUE
4332rb_io_gets_limit_internal(VALUE io, long limit)
4333{
4334 rb_io_t *fptr;
4335 GetOpenFile(io, fptr);
4336 return rb_io_getline_0(rb_default_rs, limit, FALSE, fptr);
4337}
4338
4339VALUE
4340rb_io_gets_internal(VALUE io)
4341{
4342 return rb_io_gets_limit_internal(io, -1);
4343}
4344
4345/*
4346 * call-seq:
4347 * gets(sep = $/, chomp: false) -> string or nil
4348 * gets(limit, chomp: false) -> string or nil
4349 * gets(sep, limit, chomp: false) -> string or nil
4350 *
4351 * Reads and returns a line from the stream;
4352 * assigns the return value to <tt>$_</tt>.
4353 * See {Line IO}[rdoc-ref:IO@Line+IO].
4354 *
4355 * With no arguments given, returns the next line
4356 * as determined by line separator <tt>$/</tt>, or +nil+ if none:
4357 *
4358 * f = File.open('t.txt')
4359 * f.gets # => "First line\n"
4360 * $_ # => "First line\n"
4361 * f.gets # => "\n"
4362 * f.gets # => "Fourth line\n"
4363 * f.gets # => "Fifth line\n"
4364 * f.gets # => nil
4365 * f.close
4366 *
4367 * With only string argument +sep+ given,
4368 * returns the next line as determined by line separator +sep+,
4369 * or +nil+ if none;
4370 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4371 *
4372 * f = File.new('t.txt')
4373 * f.gets('l') # => "First l"
4374 * f.gets('li') # => "ine\nSecond li"
4375 * f.gets('lin') # => "ne\n\nFourth lin"
4376 * f.gets # => "e\n"
4377 * f.close
4378 *
4379 * The two special values for +sep+ are honored:
4380 *
4381 * f = File.new('t.txt')
4382 * # Get all.
4383 * f.gets(nil) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
4384 * f.rewind
4385 * # Get paragraph (up to two line separators).
4386 * f.gets('') # => "First line\nSecond line\n\n"
4387 * f.close
4388 *
4389 * With only integer argument +limit+ given,
4390 * limits the number of bytes in the line;
4391 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4392 *
4393 * # No more than one line.
4394 * File.open('t.txt') {|f| f.gets(10) } # => "First line"
4395 * File.open('t.txt') {|f| f.gets(11) } # => "First line\n"
4396 * File.open('t.txt') {|f| f.gets(12) } # => "First line\n"
4397 *
4398 * With arguments +sep+ and +limit+ given,
4399 * combines the two behaviors
4400 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
4401 *
4402 * Optional keyword argument +chomp+ specifies whether line separators
4403 * are to be omitted:
4404 *
4405 * f = File.open('t.txt')
4406 * # Chomp the lines.
4407 * f.gets(chomp: true) # => "First line"
4408 * f.gets(chomp: true) # => "Second line"
4409 * f.gets(chomp: true) # => ""
4410 * f.gets(chomp: true) # => "Fourth line"
4411 * f.gets(chomp: true) # => "Fifth line"
4412 * f.gets(chomp: true) # => nil
4413 * f.close
4414 *
4415 */
4416
4417static VALUE
4418rb_io_gets_m(int argc, VALUE *argv, VALUE io)
4419{
4420 VALUE str;
4421
4422 str = rb_io_getline(argc, argv, io);
4423 rb_lastline_set(str);
4424
4425 return str;
4426}
4427
4428/*
4429 * call-seq:
4430 * lineno -> integer
4431 *
4432 * Returns the current line number for the stream;
4433 * see {Line Number}[rdoc-ref:IO@Line+Number].
4434 *
4435 */
4436
4437static VALUE
4438rb_io_lineno(VALUE io)
4439{
4440 rb_io_t *fptr;
4441
4442 GetOpenFile(io, fptr);
4444 return INT2NUM(fptr->lineno);
4445}
4446
4447/*
4448 * call-seq:
4449 * lineno = integer -> integer
4450 *
4451 * Sets and returns the line number for the stream;
4452 * see {Line Number}[rdoc-ref:IO@Line+Number].
4453 *
4454 */
4455
4456static VALUE
4457rb_io_set_lineno(VALUE io, VALUE lineno)
4458{
4459 rb_io_t *fptr;
4460
4461 GetOpenFile(io, fptr);
4463 fptr->lineno = NUM2INT(lineno);
4464 return lineno;
4465}
4466
4467/* :nodoc: */
4468static VALUE
4469io_readline(rb_execution_context_t *ec, VALUE io, VALUE sep, VALUE lim, VALUE chomp)
4470{
4471 long limit = -1;
4472 if (NIL_P(lim)) {
4473 VALUE tmp = Qnil;
4474 // If sep is specified, but it's not a string and not nil, then assume
4475 // it's the limit (it should be an integer)
4476 if (!NIL_P(sep) && NIL_P(tmp = rb_check_string_type(sep))) {
4477 // If the user has specified a non-nil / non-string value
4478 // for the separator, we assume it's the limit and set the
4479 // separator to default: rb_rs.
4480 lim = sep;
4481 limit = NUM2LONG(lim);
4482 sep = rb_rs;
4483 }
4484 else {
4485 sep = tmp;
4486 }
4487 }
4488 else {
4489 if (!NIL_P(sep)) StringValue(sep);
4490 limit = NUM2LONG(lim);
4491 }
4492
4493 check_getline_args(&sep, &limit, io);
4494
4495 VALUE line = rb_io_getline_1(sep, limit, RTEST(chomp), io);
4496 rb_lastline_set_up(line, 1);
4497
4498 if (NIL_P(line)) {
4499 rb_eof_error();
4500 }
4501 return line;
4502}
4503
4504static VALUE io_readlines(const struct getline_arg *arg, VALUE io);
4505
4506/*
4507 * call-seq:
4508 * readlines(sep = $/, chomp: false) -> array
4509 * readlines(limit, chomp: false) -> array
4510 * readlines(sep, limit, chomp: false) -> array
4511 *
4512 * Reads and returns all remaining line from the stream;
4513 * does not modify <tt>$_</tt>.
4514 * See {Line IO}[rdoc-ref:IO@Line+IO].
4515 *
4516 * With no arguments given, returns lines
4517 * as determined by line separator <tt>$/</tt>, or +nil+ if none:
4518 *
4519 * f = File.new('t.txt')
4520 * f.readlines
4521 * # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
4522 * f.readlines # => []
4523 * f.close
4524 *
4525 * With only string argument +sep+ given,
4526 * returns lines as determined by line separator +sep+,
4527 * or +nil+ if none;
4528 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4529 *
4530 * f = File.new('t.txt')
4531 * f.readlines('li')
4532 * # => ["First li", "ne\nSecond li", "ne\n\nFourth li", "ne\nFifth li", "ne\n"]
4533 * f.close
4534 *
4535 * The two special values for +sep+ are honored:
4536 *
4537 * f = File.new('t.txt')
4538 * # Get all into one string.
4539 * f.readlines(nil)
4540 * # => ["First line\nSecond line\n\nFourth line\nFifth line\n"]
4541 * # Get paragraphs (up to two line separators).
4542 * f.rewind
4543 * f.readlines('')
4544 * # => ["First line\nSecond line\n\n", "Fourth line\nFifth line\n"]
4545 * f.close
4546 *
4547 * With only integer argument +limit+ given,
4548 * limits the number of bytes in each line;
4549 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4550 *
4551 * f = File.new('t.txt')
4552 * f.readlines(8)
4553 * # => ["First li", "ne\n", "Second l", "ine\n", "\n", "Fourth l", "ine\n", "Fifth li", "ne\n"]
4554 * f.close
4555 *
4556 * With arguments +sep+ and +limit+ given,
4557 * combines the two behaviors
4558 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
4559 *
4560 * Optional keyword argument +chomp+ specifies whether line separators
4561 * are to be omitted:
4562 *
4563 * f = File.new('t.txt')
4564 * f.readlines(chomp: true)
4565 * # => ["First line", "Second line", "", "Fourth line", "Fifth line"]
4566 * f.close
4567 *
4568 */
4569
4570static VALUE
4571rb_io_readlines(int argc, VALUE *argv, VALUE io)
4572{
4573 struct getline_arg args;
4574
4575 prepare_getline_args(argc, argv, &args, io);
4576 return io_readlines(&args, io);
4577}
4578
4579static VALUE
4580io_readlines(const struct getline_arg *arg, VALUE io)
4581{
4582 VALUE line, ary;
4583
4584 if (arg->limit == 0)
4585 rb_raise(rb_eArgError, "invalid limit: 0 for readlines");
4586 ary = rb_ary_new();
4587 while (!NIL_P(line = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, io))) {
4588 rb_ary_push(ary, line);
4589 }
4590 return ary;
4591}
4592
4593/*
4594 * call-seq:
4595 * each_line(sep = $/, chomp: false) {|line| ... } -> self
4596 * each_line(limit, chomp: false) {|line| ... } -> self
4597 * each_line(sep, limit, chomp: false) {|line| ... } -> self
4598 * each_line -> enumerator
4599 *
4600 * Calls the block with each remaining line read from the stream;
4601 * returns +self+.
4602 * Does nothing if already at end-of-stream;
4603 * See {Line IO}[rdoc-ref:IO@Line+IO].
4604 *
4605 * With no arguments given, reads lines
4606 * as determined by line separator <tt>$/</tt>:
4607 *
4608 * f = File.new('t.txt')
4609 * f.each_line {|line| p line }
4610 * f.each_line {|line| fail 'Cannot happen' }
4611 * f.close
4612 *
4613 * Output:
4614 *
4615 * "First line\n"
4616 * "Second line\n"
4617 * "\n"
4618 * "Fourth line\n"
4619 * "Fifth line\n"
4620 *
4621 * With only string argument +sep+ given,
4622 * reads lines as determined by line separator +sep+;
4623 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4624 *
4625 * f = File.new('t.txt')
4626 * f.each_line('li') {|line| p line }
4627 * f.close
4628 *
4629 * Output:
4630 *
4631 * "First li"
4632 * "ne\nSecond li"
4633 * "ne\n\nFourth li"
4634 * "ne\nFifth li"
4635 * "ne\n"
4636 *
4637 * The two special values for +sep+ are honored:
4638 *
4639 * f = File.new('t.txt')
4640 * # Get all into one string.
4641 * f.each_line(nil) {|line| p line }
4642 * f.close
4643 *
4644 * Output:
4645 *
4646 * "First line\nSecond line\n\nFourth line\nFifth line\n"
4647 *
4648 * f.rewind
4649 * # Get paragraphs (up to two line separators).
4650 * f.each_line('') {|line| p line }
4651 *
4652 * Output:
4653 *
4654 * "First line\nSecond line\n\n"
4655 * "Fourth line\nFifth line\n"
4656 *
4657 * With only integer argument +limit+ given,
4658 * limits the number of bytes in each line;
4659 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4660 *
4661 * f = File.new('t.txt')
4662 * f.each_line(8) {|line| p line }
4663 * f.close
4664 *
4665 * Output:
4666 *
4667 * "First li"
4668 * "ne\n"
4669 * "Second l"
4670 * "ine\n"
4671 * "\n"
4672 * "Fourth l"
4673 * "ine\n"
4674 * "Fifth li"
4675 * "ne\n"
4676 *
4677 * With arguments +sep+ and +limit+ given,
4678 * combines the two behaviors
4679 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
4680 *
4681 * Optional keyword argument +chomp+ specifies whether line separators
4682 * are to be omitted:
4683 *
4684 * f = File.new('t.txt')
4685 * f.each_line(chomp: true) {|line| p line }
4686 * f.close
4687 *
4688 * Output:
4689 *
4690 * "First line"
4691 * "Second line"
4692 * ""
4693 * "Fourth line"
4694 * "Fifth line"
4695 *
4696 * Returns an Enumerator if no block is given.
4697 */
4698
4699static VALUE
4700rb_io_each_line(int argc, VALUE *argv, VALUE io)
4701{
4702 VALUE str;
4703 struct getline_arg args;
4704
4705 RETURN_ENUMERATOR(io, argc, argv);
4706 prepare_getline_args(argc, argv, &args, io);
4707 if (args.limit == 0)
4708 rb_raise(rb_eArgError, "invalid limit: 0 for each_line");
4709 while (!NIL_P(str = rb_io_getline_1(args.rs, args.limit, args.chomp, io))) {
4710 rb_yield(str);
4711 }
4712 return io;
4713}
4714
4715/*
4716 * call-seq:
4717 * each_byte {|byte| ... } -> self
4718 * each_byte -> enumerator
4719 *
4720 * Calls the given block with each byte (0..255) in the stream; returns +self+.
4721 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
4722 *
4723 * File.read('t.ja') # => "こんにちは"
4724 * f = File.new('t.ja')
4725 * a = []
4726 * f.each_byte {|b| a << b }
4727 * a # => [227, 129, 147, 227, 130, 147, 227, 129, 171, 227, 129, 161, 227, 129, 175]
4728 * f.close
4729 *
4730 * Returns an Enumerator if no block is given.
4731 *
4732 * Related: IO#each_char, IO#each_codepoint.
4733 *
4734 */
4735
4736static VALUE
4737rb_io_each_byte(VALUE io)
4738{
4739 rb_io_t *fptr;
4740
4741 RETURN_ENUMERATOR(io, 0, 0);
4742 GetOpenFile(io, fptr);
4743
4744 do {
4745 while (fptr->rbuf.len > 0) {
4746 char *p = fptr->rbuf.ptr + fptr->rbuf.off++;
4747 fptr->rbuf.len--;
4748 rb_yield(INT2FIX(*p & 0xff));
4750 errno = 0;
4751 }
4752 READ_CHECK(fptr);
4753 } while (io_fillbuf(fptr) >= 0);
4754 return io;
4755}
4756
4757static VALUE
4758io_getc(rb_io_t *fptr, rb_encoding *enc)
4759{
4760 int r, n, cr = 0;
4761 VALUE str;
4762
4763 if (NEED_READCONV(fptr)) {
4764 rb_encoding *read_enc = io_read_encoding(fptr);
4765
4766 str = Qnil;
4767 SET_BINARY_MODE(fptr);
4768 make_readconv(fptr, 0);
4769
4770 while (1) {
4771 if (fptr->cbuf.len) {
4772 r = rb_enc_precise_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4773 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4774 read_enc);
4775 if (!MBCLEN_NEEDMORE_P(r))
4776 break;
4777 if (fptr->cbuf.len == fptr->cbuf.capa) {
4778 rb_raise(rb_eIOError, "too long character");
4779 }
4780 }
4781
4782 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4783 if (fptr->cbuf.len == 0) {
4784 clear_readconv(fptr);
4785 return Qnil;
4786 }
4787 /* return an unit of an incomplete character just before EOF */
4788 str = rb_enc_str_new(fptr->cbuf.ptr+fptr->cbuf.off, 1, read_enc);
4789 fptr->cbuf.off += 1;
4790 fptr->cbuf.len -= 1;
4791 if (fptr->cbuf.len == 0) clear_readconv(fptr);
4793 return str;
4794 }
4795 }
4796 if (MBCLEN_INVALID_P(r)) {
4797 r = rb_enc_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4798 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4799 read_enc);
4800 io_shift_cbuf(fptr, r, &str);
4802 }
4803 else {
4804 io_shift_cbuf(fptr, MBCLEN_CHARFOUND_LEN(r), &str);
4806 if (MBCLEN_CHARFOUND_LEN(r) == 1 && rb_enc_asciicompat(read_enc) &&
4807 ISASCII(RSTRING_PTR(str)[0])) {
4808 cr = ENC_CODERANGE_7BIT;
4809 }
4810 }
4811 str = io_enc_str(str, fptr);
4812 ENC_CODERANGE_SET(str, cr);
4813 return str;
4814 }
4815
4816 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4817 if (io_fillbuf(fptr) < 0) {
4818 return Qnil;
4819 }
4820 if (rb_enc_asciicompat(enc) && ISASCII(fptr->rbuf.ptr[fptr->rbuf.off])) {
4821 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, 1);
4822 fptr->rbuf.off += 1;
4823 fptr->rbuf.len -= 1;
4824 cr = ENC_CODERANGE_7BIT;
4825 }
4826 else {
4827 r = rb_enc_precise_mbclen(fptr->rbuf.ptr+fptr->rbuf.off, fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
4828 if (MBCLEN_CHARFOUND_P(r) &&
4829 (n = MBCLEN_CHARFOUND_LEN(r)) <= fptr->rbuf.len) {
4830 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, n);
4831 fptr->rbuf.off += n;
4832 fptr->rbuf.len -= n;
4834 }
4835 else if (MBCLEN_NEEDMORE_P(r)) {
4836 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, fptr->rbuf.len);
4837 fptr->rbuf.len = 0;
4838 getc_needmore:
4839 if (io_fillbuf(fptr) != -1) {
4840 rb_str_cat(str, fptr->rbuf.ptr+fptr->rbuf.off, 1);
4841 fptr->rbuf.off++;
4842 fptr->rbuf.len--;
4843 r = rb_enc_precise_mbclen(RSTRING_PTR(str), RSTRING_PTR(str)+RSTRING_LEN(str), enc);
4844 if (MBCLEN_NEEDMORE_P(r)) {
4845 goto getc_needmore;
4846 }
4847 else if (MBCLEN_CHARFOUND_P(r)) {
4849 }
4850 }
4851 }
4852 else {
4853 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, 1);
4854 fptr->rbuf.off++;
4855 fptr->rbuf.len--;
4856 }
4857 }
4858 if (!cr) cr = ENC_CODERANGE_BROKEN;
4859 str = io_enc_str(str, fptr);
4860 ENC_CODERANGE_SET(str, cr);
4861 return str;
4862}
4863
4864/*
4865 * call-seq:
4866 * each_char {|c| ... } -> self
4867 * each_char -> enumerator
4868 *
4869 * Calls the given block with each character in the stream; returns +self+.
4870 * See {Character IO}[rdoc-ref:IO@Character+IO].
4871 *
4872 * File.read('t.ja') # => "こんにちは"
4873 * f = File.new('t.ja')
4874 * a = []
4875 * f.each_char {|c| a << c.ord }
4876 * a # => [12371, 12435, 12395, 12385, 12399]
4877 * f.close
4878 *
4879 * Returns an Enumerator if no block is given.
4880 *
4881 * Related: IO#each_byte, IO#each_codepoint.
4882 *
4883 */
4884
4885static VALUE
4886rb_io_each_char(VALUE io)
4887{
4888 rb_io_t *fptr;
4889 rb_encoding *enc;
4890 VALUE c;
4891
4892 RETURN_ENUMERATOR(io, 0, 0);
4893 GetOpenFile(io, fptr);
4895
4896 enc = io_input_encoding(fptr);
4897 READ_CHECK(fptr);
4898 while (!NIL_P(c = io_getc(fptr, enc))) {
4899 rb_yield(c);
4900 }
4901 return io;
4902}
4903
4904/*
4905 * call-seq:
4906 * each_codepoint {|c| ... } -> self
4907 * each_codepoint -> enumerator
4908 *
4909 * Calls the given block with each codepoint in the stream; returns +self+:
4910 *
4911 * File.read('t.ja') # => "こんにちは"
4912 * f = File.new('t.ja')
4913 * a = []
4914 * f.each_codepoint {|c| a << c }
4915 * a # => [12371, 12435, 12395, 12385, 12399]
4916 * f.close
4917 *
4918 * Returns an Enumerator if no block is given.
4919 *
4920 * Related: IO#each_byte, IO#each_char.
4921 *
4922 */
4923
4924static VALUE
4925rb_io_each_codepoint(VALUE io)
4926{
4927 rb_io_t *fptr;
4928 rb_encoding *enc;
4929 unsigned int c;
4930 int r, n;
4931
4932 RETURN_ENUMERATOR(io, 0, 0);
4933 GetOpenFile(io, fptr);
4935
4936 READ_CHECK(fptr);
4937 enc = io_read_encoding(fptr);
4938 if (NEED_READCONV(fptr)) {
4939 SET_BINARY_MODE(fptr);
4940 r = 1; /* no invalid char yet */
4941 for (;;) {
4942 make_readconv(fptr, 0);
4943 for (;;) {
4944 if (fptr->cbuf.len) {
4945 r = rb_enc_precise_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4946 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4947 enc);
4948 if (!MBCLEN_NEEDMORE_P(r))
4949 break;
4950 if (fptr->cbuf.len == fptr->cbuf.capa) {
4951 rb_raise(rb_eIOError, "too long character");
4952 }
4953 }
4954 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4955 clear_readconv(fptr);
4956 if (!MBCLEN_CHARFOUND_P(r)) {
4957 goto invalid;
4958 }
4959 return io;
4960 }
4961 }
4962 if (MBCLEN_INVALID_P(r)) {
4963 goto invalid;
4964 }
4965 n = MBCLEN_CHARFOUND_LEN(r);
4966 c = rb_enc_codepoint(fptr->cbuf.ptr+fptr->cbuf.off,
4967 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4968 enc);
4969 fptr->cbuf.off += n;
4970 fptr->cbuf.len -= n;
4971 rb_yield(UINT2NUM(c));
4973 }
4974 }
4975 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4976 while (io_fillbuf(fptr) >= 0) {
4977 r = rb_enc_precise_mbclen(fptr->rbuf.ptr+fptr->rbuf.off,
4978 fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
4979 if (MBCLEN_CHARFOUND_P(r) &&
4980 (n = MBCLEN_CHARFOUND_LEN(r)) <= fptr->rbuf.len) {
4981 c = rb_enc_codepoint(fptr->rbuf.ptr+fptr->rbuf.off,
4982 fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
4983 fptr->rbuf.off += n;
4984 fptr->rbuf.len -= n;
4985 rb_yield(UINT2NUM(c));
4986 }
4987 else if (MBCLEN_INVALID_P(r)) {
4988 goto invalid;
4989 }
4990 else if (MBCLEN_NEEDMORE_P(r)) {
4991 char cbuf[8], *p = cbuf;
4992 int more = MBCLEN_NEEDMORE_LEN(r);
4993 if (more > numberof(cbuf)) goto invalid;
4994 more += n = fptr->rbuf.len;
4995 if (more > numberof(cbuf)) goto invalid;
4996 while ((n = (int)read_buffered_data(p, more, fptr)) > 0 &&
4997 (p += n, (more -= n) > 0)) {
4998 if (io_fillbuf(fptr) < 0) goto invalid;
4999 if ((n = fptr->rbuf.len) > more) n = more;
5000 }
5001 r = rb_enc_precise_mbclen(cbuf, p, enc);
5002 if (!MBCLEN_CHARFOUND_P(r)) goto invalid;
5003 c = rb_enc_codepoint(cbuf, p, enc);
5004 rb_yield(UINT2NUM(c));
5005 }
5006 else {
5007 continue;
5008 }
5010 }
5011 return io;
5012
5013 invalid:
5014 rb_raise(rb_eArgError, "invalid byte sequence in %s", rb_enc_name(enc));
5016}
5017
5018/*
5019 * call-seq:
5020 * getc -> character or nil
5021 *
5022 * Reads and returns the next 1-character string from the stream;
5023 * returns +nil+ if already at end-of-stream.
5024 * See {Character IO}[rdoc-ref:IO@Character+IO].
5025 *
5026 * f = File.open('t.txt')
5027 * f.getc # => "F"
5028 * f.close
5029 * File.read('t.ja') # => "こんにちは"
5030 * f = File.open('t.ja')
5031 * f.getc.ord # => 12371
5032 * f.close
5033 *
5034 * Related: IO#readchar (may raise EOFError).
5035 *
5036 */
5037
5038static VALUE
5039rb_io_getc(VALUE io)
5040{
5041 rb_io_t *fptr;
5042 rb_encoding *enc;
5043
5044 GetOpenFile(io, fptr);
5046
5047 enc = io_input_encoding(fptr);
5048 READ_CHECK(fptr);
5049 return io_getc(fptr, enc);
5050}
5051
5052/*
5053 * call-seq:
5054 * readchar -> string
5055 *
5056 * Reads and returns the next 1-character string from the stream;
5057 * raises EOFError if already at end-of-stream.
5058 * See {Character IO}[rdoc-ref:IO@Character+IO].
5059 *
5060 * f = File.open('t.txt')
5061 * f.readchar # => "F"
5062 * f.close
5063 * File.read('t.ja') # => "こんにちは"
5064 * f = File.open('t.ja')
5065 * f.readchar.ord # => 12371
5066 * f.close
5067 *
5068 * Related: IO#getc (will not raise EOFError).
5069 *
5070 */
5071
5072static VALUE
5073rb_io_readchar(VALUE io)
5074{
5075 VALUE c = rb_io_getc(io);
5076
5077 if (NIL_P(c)) {
5078 rb_eof_error();
5079 }
5080 return c;
5081}
5082
5083/*
5084 * call-seq:
5085 * getbyte -> integer or nil
5086 *
5087 * Reads and returns the next byte (in range 0..255) from the stream;
5088 * returns +nil+ if already at end-of-stream.
5089 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5090 *
5091 * f = File.open('t.txt')
5092 * f.getbyte # => 70
5093 * f.close
5094 * File.read('t.ja') # => "こんにちは"
5095 * f = File.open('t.ja')
5096 * f.getbyte # => 227
5097 * f.close
5098 *
5099 * Related: IO#readbyte (may raise EOFError).
5100 */
5101
5102VALUE
5104{
5105 rb_io_t *fptr;
5106 int c;
5107
5108 GetOpenFile(io, fptr);
5110 READ_CHECK(fptr);
5111 VALUE r_stdout = rb_ractor_stdout();
5112 if (fptr->fd == 0 && (fptr->mode & FMODE_TTY) && RB_TYPE_P(r_stdout, T_FILE)) {
5113 rb_io_t *ofp;
5114 GetOpenFile(r_stdout, ofp);
5115 if (ofp->mode & FMODE_TTY) {
5116 rb_io_flush(r_stdout);
5117 }
5118 }
5119 if (io_fillbuf(fptr) < 0) {
5120 return Qnil;
5121 }
5122 fptr->rbuf.off++;
5123 fptr->rbuf.len--;
5124 c = (unsigned char)fptr->rbuf.ptr[fptr->rbuf.off-1];
5125 return INT2FIX(c & 0xff);
5126}
5127
5128/*
5129 * call-seq:
5130 * readbyte -> integer
5131 *
5132 * Reads and returns the next byte (in range 0..255) from the stream;
5133 * raises EOFError if already at end-of-stream.
5134 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5135 *
5136 * f = File.open('t.txt')
5137 * f.readbyte # => 70
5138 * f.close
5139 * File.read('t.ja') # => "こんにちは"
5140 * f = File.open('t.ja')
5141 * f.readbyte # => 227
5142 * f.close
5143 *
5144 * Related: IO#getbyte (will not raise EOFError).
5145 *
5146 */
5147
5148static VALUE
5149rb_io_readbyte(VALUE io)
5150{
5151 VALUE c = rb_io_getbyte(io);
5152
5153 if (NIL_P(c)) {
5154 rb_eof_error();
5155 }
5156 return c;
5157}
5158
5159/*
5160 * call-seq:
5161 * ungetbyte(integer) -> nil
5162 * ungetbyte(string) -> nil
5163 *
5164 * Pushes back ("unshifts") the given data onto the stream's buffer,
5165 * placing the data so that it is next to be read; returns +nil+.
5166 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5167 *
5168 * Note that:
5169 *
5170 * - Calling the method has no effect with unbuffered reads (such as IO#sysread).
5171 * - Calling #rewind on the stream discards the pushed-back data.
5172 *
5173 * When argument +integer+ is given, uses only its low-order byte:
5174 *
5175 * File.write('t.tmp', '012')
5176 * f = File.open('t.tmp')
5177 * f.ungetbyte(0x41) # => nil
5178 * f.read # => "A012"
5179 * f.rewind
5180 * f.ungetbyte(0x4243) # => nil
5181 * f.read # => "C012"
5182 * f.close
5183 *
5184 * When argument +string+ is given, uses all bytes:
5185 *
5186 * File.write('t.tmp', '012')
5187 * f = File.open('t.tmp')
5188 * f.ungetbyte('A') # => nil
5189 * f.read # => "A012"
5190 * f.rewind
5191 * f.ungetbyte('BCDE') # => nil
5192 * f.read # => "BCDE012"
5193 * f.close
5194 *
5195 */
5196
5197VALUE
5199{
5200 rb_io_t *fptr;
5201
5202 GetOpenFile(io, fptr);
5204 switch (TYPE(b)) {
5205 case T_NIL:
5206 return Qnil;
5207 case T_FIXNUM:
5208 case T_BIGNUM: ;
5209 VALUE v = rb_int_modulo(b, INT2FIX(256));
5210 unsigned char c = NUM2INT(v) & 0xFF;
5211 b = rb_str_new((const char *)&c, 1);
5212 break;
5213 default:
5214 StringValue(b);
5215 }
5216 io_ungetbyte(b, fptr);
5217 return Qnil;
5218}
5219
5220/*
5221 * call-seq:
5222 * ungetc(integer) -> nil
5223 * ungetc(string) -> nil
5224 *
5225 * Pushes back ("unshifts") the given data onto the stream's buffer,
5226 * placing the data so that it is next to be read; returns +nil+.
5227 * See {Character IO}[rdoc-ref:IO@Character+IO].
5228 *
5229 * Note that:
5230 *
5231 * - Calling the method has no effect with unbuffered reads (such as IO#sysread).
5232 * - Calling #rewind on the stream discards the pushed-back data.
5233 *
5234 * When argument +integer+ is given, interprets the integer as a character:
5235 *
5236 * File.write('t.tmp', '012')
5237 * f = File.open('t.tmp')
5238 * f.ungetc(0x41) # => nil
5239 * f.read # => "A012"
5240 * f.rewind
5241 * f.ungetc(0x0442) # => nil
5242 * f.getc.ord # => 1090
5243 * f.close
5244 *
5245 * When argument +string+ is given, uses all characters:
5246 *
5247 * File.write('t.tmp', '012')
5248 * f = File.open('t.tmp')
5249 * f.ungetc('A') # => nil
5250 * f.read # => "A012"
5251 * f.rewind
5252 * f.ungetc("\u0442\u0435\u0441\u0442") # => nil
5253 * f.getc.ord # => 1090
5254 * f.getc.ord # => 1077
5255 * f.getc.ord # => 1089
5256 * f.getc.ord # => 1090
5257 * f.close
5258 *
5259 */
5260
5261VALUE
5263{
5264 rb_io_t *fptr;
5265 long len;
5266
5267 GetOpenFile(io, fptr);
5269 if (FIXNUM_P(c)) {
5270 c = rb_enc_uint_chr(FIX2UINT(c), io_read_encoding(fptr));
5271 }
5272 else if (RB_BIGNUM_TYPE_P(c)) {
5273 c = rb_enc_uint_chr(NUM2UINT(c), io_read_encoding(fptr));
5274 }
5275 else {
5276 StringValue(c);
5277 }
5278 if (NEED_READCONV(fptr)) {
5279 SET_BINARY_MODE(fptr);
5280 len = RSTRING_LEN(c);
5281#if SIZEOF_LONG > SIZEOF_INT
5282 if (len > INT_MAX)
5283 rb_raise(rb_eIOError, "ungetc failed");
5284#endif
5285 make_readconv(fptr, (int)len);
5286 if (fptr->cbuf.capa - fptr->cbuf.len < len)
5287 rb_raise(rb_eIOError, "ungetc failed");
5288 if (fptr->cbuf.off < len) {
5289 MEMMOVE(fptr->cbuf.ptr+fptr->cbuf.capa-fptr->cbuf.len,
5290 fptr->cbuf.ptr+fptr->cbuf.off,
5291 char, fptr->cbuf.len);
5292 fptr->cbuf.off = fptr->cbuf.capa-fptr->cbuf.len;
5293 }
5294 fptr->cbuf.off -= (int)len;
5295 fptr->cbuf.len += (int)len;
5296 MEMMOVE(fptr->cbuf.ptr+fptr->cbuf.off, RSTRING_PTR(c), char, len);
5297 }
5298 else {
5299 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
5300 io_ungetbyte(c, fptr);
5301 }
5302 return Qnil;
5303}
5304
5305/*
5306 * call-seq:
5307 * isatty -> true or false
5308 *
5309 * Returns +true+ if the stream is associated with a terminal device (tty),
5310 * +false+ otherwise:
5311 *
5312 * f = File.new('t.txt').isatty #=> false
5313 * f.close
5314 * f = File.new('/dev/tty').isatty #=> true
5315 * f.close
5316 *
5317 */
5318
5319static VALUE
5320rb_io_isatty(VALUE io)
5321{
5322 rb_io_t *fptr;
5323
5324 GetOpenFile(io, fptr);
5325 return RBOOL(isatty(fptr->fd) != 0);
5326}
5327
5328#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5329/*
5330 * call-seq:
5331 * close_on_exec? -> true or false
5332 *
5333 * Returns +true+ if the stream will be closed on exec, +false+ otherwise:
5334 *
5335 * f = File.open('t.txt')
5336 * f.close_on_exec? # => true
5337 * f.close_on_exec = false
5338 * f.close_on_exec? # => false
5339 * f.close
5340 *
5341 */
5342
5343static VALUE
5344rb_io_close_on_exec_p(VALUE io)
5345{
5346 rb_io_t *fptr;
5347 VALUE write_io;
5348 int fd, ret;
5349
5350 write_io = GetWriteIO(io);
5351 if (io != write_io) {
5352 GetOpenFile(write_io, fptr);
5353 if (fptr && 0 <= (fd = fptr->fd)) {
5354 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5355 if (!(ret & FD_CLOEXEC)) return Qfalse;
5356 }
5357 }
5358
5359 GetOpenFile(io, fptr);
5360 if (fptr && 0 <= (fd = fptr->fd)) {
5361 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5362 if (!(ret & FD_CLOEXEC)) return Qfalse;
5363 }
5364 return Qtrue;
5365}
5366#else
5367#define rb_io_close_on_exec_p rb_f_notimplement
5368#endif
5369
5370#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5371/*
5372 * call-seq:
5373 * self.close_on_exec = bool -> true or false
5374 *
5375 * Sets a close-on-exec flag.
5376 *
5377 * f = File.open(File::NULL)
5378 * f.close_on_exec = true
5379 * system("cat", "/proc/self/fd/#{f.fileno}") # cat: /proc/self/fd/3: No such file or directory
5380 * f.closed? #=> false
5381 *
5382 * Ruby sets close-on-exec flags of all file descriptors by default
5383 * since Ruby 2.0.0.
5384 * So you don't need to set by yourself.
5385 * Also, unsetting a close-on-exec flag can cause file descriptor leak
5386 * if another thread use fork() and exec() (via system() method for example).
5387 * If you really needs file descriptor inheritance to child process,
5388 * use spawn()'s argument such as fd=>fd.
5389 */
5390
5391static VALUE
5392rb_io_set_close_on_exec(VALUE io, VALUE arg)
5393{
5394 int flag = RTEST(arg) ? FD_CLOEXEC : 0;
5395 rb_io_t *fptr;
5396 VALUE write_io;
5397 int fd, ret;
5398
5399 write_io = GetWriteIO(io);
5400 if (io != write_io) {
5401 GetOpenFile(write_io, fptr);
5402 if (fptr && 0 <= (fd = fptr->fd)) {
5403 if ((ret = fcntl(fptr->fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5404 if ((ret & FD_CLOEXEC) != flag) {
5405 ret = (ret & ~FD_CLOEXEC) | flag;
5406 ret = fcntl(fd, F_SETFD, ret);
5407 if (ret != 0) rb_sys_fail_path(fptr->pathv);
5408 }
5409 }
5410
5411 }
5412
5413 GetOpenFile(io, fptr);
5414 if (fptr && 0 <= (fd = fptr->fd)) {
5415 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5416 if ((ret & FD_CLOEXEC) != flag) {
5417 ret = (ret & ~FD_CLOEXEC) | flag;
5418 ret = fcntl(fd, F_SETFD, ret);
5419 if (ret != 0) rb_sys_fail_path(fptr->pathv);
5420 }
5421 }
5422 return Qnil;
5423}
5424#else
5425#define rb_io_set_close_on_exec rb_f_notimplement
5426#endif
5427
5428#define RUBY_IO_EXTERNAL_P(f) ((f)->mode & FMODE_EXTERNAL)
5429#define PREP_STDIO_NAME(f) (RSTRING_PTR((f)->pathv))
5430
5431static VALUE
5432finish_writeconv(rb_io_t *fptr, int noalloc)
5433{
5434 unsigned char *ds, *dp, *de;
5436
5437 if (!fptr->wbuf.ptr) {
5438 unsigned char buf[1024];
5439
5441 while (res == econv_destination_buffer_full) {
5442 ds = dp = buf;
5443 de = buf + sizeof(buf);
5444 res = rb_econv_convert(fptr->writeconv, NULL, NULL, &dp, de, 0);
5445 while (dp-ds) {
5446 size_t remaining = dp-ds;
5447 long result = rb_io_write_memory(fptr, ds, remaining);
5448
5449 if (result > 0) {
5450 ds += result;
5451 if ((size_t)result == remaining) break;
5452 }
5453 else if (rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
5454 if (fptr->fd < 0)
5455 return noalloc ? Qtrue : rb_exc_new3(rb_eIOError, rb_str_new_cstr(closed_stream));
5456 }
5457 else {
5458 return noalloc ? Qtrue : INT2NUM(errno);
5459 }
5460 }
5461 if (res == econv_invalid_byte_sequence ||
5462 res == econv_incomplete_input ||
5464 return noalloc ? Qtrue : rb_econv_make_exception(fptr->writeconv);
5465 }
5466 }
5467
5468 return Qnil;
5469 }
5470
5472 while (res == econv_destination_buffer_full) {
5473 if (fptr->wbuf.len == fptr->wbuf.capa) {
5474 if (io_fflush(fptr) < 0) {
5475 return noalloc ? Qtrue : INT2NUM(errno);
5476 }
5477 }
5478
5479 ds = dp = (unsigned char *)fptr->wbuf.ptr + fptr->wbuf.off + fptr->wbuf.len;
5480 de = (unsigned char *)fptr->wbuf.ptr + fptr->wbuf.capa;
5481 res = rb_econv_convert(fptr->writeconv, NULL, NULL, &dp, de, 0);
5482 fptr->wbuf.len += (int)(dp - ds);
5483 if (res == econv_invalid_byte_sequence ||
5484 res == econv_incomplete_input ||
5486 return noalloc ? Qtrue : rb_econv_make_exception(fptr->writeconv);
5487 }
5488 }
5489 return Qnil;
5490}
5491
5493 rb_io_t *fptr;
5494 int noalloc;
5495};
5496
5497static VALUE
5498finish_writeconv_sync(VALUE arg)
5499{
5500 struct finish_writeconv_arg *p = (struct finish_writeconv_arg *)arg;
5501 return finish_writeconv(p->fptr, p->noalloc);
5502}
5503
5504static void*
5505nogvl_close(void *ptr)
5506{
5507 int *fd = ptr;
5508
5509 return (void*)(intptr_t)close(*fd);
5510}
5511
5512static int
5513maygvl_close(int fd, int keepgvl)
5514{
5515 if (keepgvl)
5516 return close(fd);
5517
5518 /*
5519 * close() may block for certain file types (NFS, SO_LINGER sockets,
5520 * inotify), so let other threads run.
5521 */
5522 return IO_WITHOUT_GVL_INT(nogvl_close, &fd);
5523}
5524
5525static void*
5526nogvl_fclose(void *ptr)
5527{
5528 FILE *file = ptr;
5529
5530 return (void*)(intptr_t)fclose(file);
5531}
5532
5533static int
5534maygvl_fclose(FILE *file, int keepgvl)
5535{
5536 if (keepgvl)
5537 return fclose(file);
5538
5539 return IO_WITHOUT_GVL_INT(nogvl_fclose, file);
5540}
5541
5542static void free_io_buffer(rb_io_buffer_t *buf);
5543
5544static void
5545fptr_finalize_flush(rb_io_t *fptr, int noraise, int keepgvl)
5546{
5547 VALUE error = Qnil;
5548 int fd = fptr->fd;
5549 FILE *stdio_file = fptr->stdio_file;
5550 int mode = fptr->mode;
5551
5552 if (fptr->writeconv) {
5553 if (!NIL_P(fptr->write_lock) && !noraise) {
5554 struct finish_writeconv_arg arg;
5555 arg.fptr = fptr;
5556 arg.noalloc = noraise;
5557 error = rb_mutex_synchronize(fptr->write_lock, finish_writeconv_sync, (VALUE)&arg);
5558 }
5559 else {
5560 error = finish_writeconv(fptr, noraise);
5561 }
5562 }
5563 if (fptr->wbuf.len) {
5564 if (noraise) {
5565 io_flush_buffer_sync(fptr);
5566 }
5567 else {
5568 if (io_fflush(fptr) < 0 && NIL_P(error)) {
5569 error = INT2NUM(errno);
5570 }
5571 }
5572 }
5573
5574 int done = 0;
5575
5576 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2) {
5577 // Need to keep FILE objects of stdin, stdout and stderr, so we are done:
5578 done = 1;
5579 }
5580
5581 fptr->fd = -1;
5582 fptr->stdio_file = 0;
5584
5585 // Wait for blocking operations to ensure they do not hit EBADF:
5586 rb_thread_io_close_wait(fptr);
5587
5588 if (!done && stdio_file) {
5589 // stdio_file is deallocated anyway even if fclose failed.
5590 if ((maygvl_fclose(stdio_file, noraise) < 0) && NIL_P(error)) {
5591 if (!noraise) {
5592 error = INT2NUM(errno);
5593 }
5594 }
5595
5596 done = 1;
5597 }
5598
5599 VALUE scheduler = rb_fiber_scheduler_current();
5600 if (!done && fd >= 0 && scheduler != Qnil) {
5601 VALUE result = rb_fiber_scheduler_io_close(scheduler, RB_INT2NUM(fd));
5602
5603 if (!UNDEF_P(result)) {
5604 done = RTEST(result);
5605 }
5606 }
5607
5608 if (!done && fd >= 0) {
5609 // fptr->fd may be closed even if close fails. POSIX doesn't specify it.
5610 // We assumes it is closed.
5611
5612 keepgvl |= !(mode & FMODE_WRITABLE);
5613 keepgvl |= noraise;
5614 if ((maygvl_close(fd, keepgvl) < 0) && NIL_P(error)) {
5615 if (!noraise) {
5616 error = INT2NUM(errno);
5617 }
5618 }
5619
5620 done = 1;
5621 }
5622
5623 if (!NIL_P(error) && !noraise) {
5624 if (RB_INTEGER_TYPE_P(error))
5625 rb_syserr_fail_path(NUM2INT(error), fptr->pathv);
5626 else
5627 rb_exc_raise(error);
5628 }
5629}
5630
5631static void
5632fptr_finalize(rb_io_t *fptr, int noraise)
5633{
5634 fptr_finalize_flush(fptr, noraise, FALSE);
5635 free_io_buffer(&fptr->rbuf);
5636 free_io_buffer(&fptr->wbuf);
5637 clear_codeconv(fptr);
5638}
5639
5640static void
5641rb_io_fptr_cleanup(rb_io_t *fptr, int noraise)
5642{
5643 if (fptr->finalize) {
5644 (*fptr->finalize)(fptr, noraise);
5645 }
5646 else {
5647 fptr_finalize(fptr, noraise);
5648 }
5649}
5650
5651static void
5652free_io_buffer(rb_io_buffer_t *buf)
5653{
5654 if (buf->ptr) {
5655 ruby_sized_xfree(buf->ptr, (size_t)buf->capa);
5656 buf->ptr = NULL;
5657 }
5658}
5659
5660static void
5661clear_readconv(rb_io_t *fptr)
5662{
5663 if (fptr->readconv) {
5664 rb_econv_close(fptr->readconv);
5665 fptr->readconv = NULL;
5666 }
5667 free_io_buffer(&fptr->cbuf);
5668}
5669
5670static void
5671clear_writeconv(rb_io_t *fptr)
5672{
5673 if (fptr->writeconv) {
5675 fptr->writeconv = NULL;
5676 }
5677 fptr->writeconv_initialized = 0;
5678}
5679
5680static void
5681clear_codeconv(rb_io_t *fptr)
5682{
5683 clear_readconv(fptr);
5684 clear_writeconv(fptr);
5685}
5686
5687static void
5688rb_io_fptr_cleanup_all(rb_io_t *fptr)
5689{
5690 fptr->pathv = Qnil;
5691 if (0 <= fptr->fd)
5692 rb_io_fptr_cleanup(fptr, TRUE);
5693 fptr->write_lock = Qnil;
5694 free_io_buffer(&fptr->rbuf);
5695 free_io_buffer(&fptr->wbuf);
5696 clear_codeconv(fptr);
5697}
5698
5699int
5701{
5702 if (!io) return 0;
5703 rb_io_fptr_cleanup_all(io);
5704 free(io);
5705
5706 return 1;
5707}
5708
5709size_t
5710rb_io_memsize(const rb_io_t *io)
5711{
5712 size_t size = sizeof(rb_io_t);
5713 size += io->rbuf.capa;
5714 size += io->wbuf.capa;
5715 size += io->cbuf.capa;
5716 if (io->readconv) size += rb_econv_memsize(io->readconv);
5717 if (io->writeconv) size += rb_econv_memsize(io->writeconv);
5718
5719 struct rb_io_blocking_operation *blocking_operation = 0;
5720
5721 // 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.
5722 rb_serial_t fork_generation = GET_VM()->fork_gen;
5723 if (io->fork_generation == fork_generation) {
5724 ccan_list_for_each(&io->blocking_operations, blocking_operation, list) {
5725 size += sizeof(struct rb_io_blocking_operation);
5726 }
5727 }
5728
5729 return size;
5730}
5731
5732#ifdef _WIN32
5733/* keep GVL while closing to prevent crash on Windows */
5734# define KEEPGVL TRUE
5735#else
5736# define KEEPGVL FALSE
5737#endif
5738
5739static rb_io_t *
5740io_close_fptr(VALUE io)
5741{
5742 rb_io_t *fptr;
5743 VALUE write_io;
5744 rb_io_t *write_fptr;
5745
5746 write_io = GetWriteIO(io);
5747 if (io != write_io) {
5748 write_fptr = RFILE(write_io)->fptr;
5749 if (write_fptr && 0 <= write_fptr->fd) {
5750 rb_io_fptr_cleanup(write_fptr, TRUE);
5751 }
5752 }
5753
5754 fptr = RFILE(io)->fptr;
5755 if (!fptr) return 0;
5756 if (fptr->fd < 0) return 0;
5757
5758 // This guards against multiple threads closing the same IO object:
5759 if (rb_thread_io_close_interrupt(fptr)) {
5760 /* calls close(fptr->fd): */
5761 fptr_finalize_flush(fptr, FALSE, KEEPGVL);
5762 }
5763
5764 rb_io_fptr_cleanup(fptr, FALSE);
5765 return fptr;
5766}
5767
5768static void
5769fptr_waitpid(rb_io_t *fptr, int nohang)
5770{
5771 int status;
5772 if (fptr->pid) {
5773 rb_last_status_clear();
5774 rb_waitpid(fptr->pid, &status, nohang ? WNOHANG : 0);
5775 fptr->pid = 0;
5776 }
5777}
5778
5779VALUE
5781{
5782 rb_io_t *fptr = io_close_fptr(io);
5783 if (fptr) fptr_waitpid(fptr, 0);
5784 return Qnil;
5785}
5786
5787/*
5788 * call-seq:
5789 * close -> nil
5790 *
5791 * Closes the stream for both reading and writing
5792 * if open for either or both; returns +nil+.
5793 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5794 *
5795 * If the stream is open for writing, flushes any buffered writes
5796 * to the operating system before closing.
5797 *
5798 * If the stream was opened by IO.popen, sets global variable <tt>$?</tt>
5799 * (child exit status).
5800 *
5801 * It is not an error to close an IO object that has already been closed.
5802 * It just returns nil.
5803 *
5804 * Example:
5805 *
5806 * IO.popen('ruby', 'r+') do |pipe|
5807 * puts pipe.closed?
5808 * pipe.close
5809 * puts $?
5810 * puts pipe.closed?
5811 * end
5812 *
5813 * Output:
5814 *
5815 * false
5816 * pid 13760 exit 0
5817 * true
5818 *
5819 * Related: IO#close_read, IO#close_write, IO#closed?.
5820 */
5821
5822static VALUE
5823rb_io_close_m(VALUE io)
5824{
5825 rb_io_t *fptr = rb_io_get_fptr(io);
5826 if (fptr->fd < 0) {
5827 return Qnil;
5828 }
5829 rb_io_close(io);
5830 return Qnil;
5831}
5832
5833static VALUE
5834io_call_close(VALUE io)
5835{
5836 rb_check_funcall(io, rb_intern("close"), 0, 0);
5837 return io;
5838}
5839
5840static VALUE
5841ignore_closed_stream(VALUE io, VALUE exc)
5842{
5843 enum {mesg_len = sizeof(closed_stream)-1};
5844 VALUE mesg = rb_attr_get(exc, idMesg);
5845 if (!RB_TYPE_P(mesg, T_STRING) ||
5846 RSTRING_LEN(mesg) != mesg_len ||
5847 memcmp(RSTRING_PTR(mesg), closed_stream, mesg_len)) {
5848 rb_exc_raise(exc);
5849 }
5850 return io;
5851}
5852
5853static VALUE
5854io_close(VALUE io)
5855{
5856 VALUE closed = rb_check_funcall(io, rb_intern("closed?"), 0, 0);
5857 if (!UNDEF_P(closed) && RTEST(closed)) return io;
5858 rb_rescue2(io_call_close, io, ignore_closed_stream, io,
5859 rb_eIOError, (VALUE)0);
5860 return io;
5861}
5862
5863/*
5864 * call-seq:
5865 * closed? -> true or false
5866 *
5867 * Returns +true+ if the stream is closed for both reading and writing,
5868 * +false+ otherwise.
5869 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5870 *
5871 * IO.popen('ruby', 'r+') do |pipe|
5872 * puts pipe.closed?
5873 * pipe.close_read
5874 * puts pipe.closed?
5875 * pipe.close_write
5876 * puts pipe.closed?
5877 * end
5878 *
5879 * Output:
5880 *
5881 * false
5882 * false
5883 * true
5884 *
5885 * Related: IO#close_read, IO#close_write, IO#close.
5886 */
5887VALUE
5889{
5890 rb_io_t *fptr;
5891 VALUE write_io;
5892 rb_io_t *write_fptr;
5893
5894 write_io = GetWriteIO(io);
5895 if (io != write_io) {
5896 write_fptr = RFILE(write_io)->fptr;
5897 if (write_fptr && 0 <= write_fptr->fd) {
5898 return Qfalse;
5899 }
5900 }
5901
5902 fptr = rb_io_get_fptr(io);
5903 return RBOOL(0 > fptr->fd);
5904}
5905
5906/*
5907 * call-seq:
5908 * close_read -> nil
5909 *
5910 * Closes the stream for reading if open for reading;
5911 * returns +nil+.
5912 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5913 *
5914 * If the stream was opened by IO.popen and is also closed for writing,
5915 * sets global variable <tt>$?</tt> (child exit status).
5916 *
5917 * Example:
5918 *
5919 * IO.popen('ruby', 'r+') do |pipe|
5920 * puts pipe.closed?
5921 * pipe.close_write
5922 * puts pipe.closed?
5923 * pipe.close_read
5924 * puts $?
5925 * puts pipe.closed?
5926 * end
5927 *
5928 * Output:
5929 *
5930 * false
5931 * false
5932 * pid 14748 exit 0
5933 * true
5934 *
5935 * Related: IO#close, IO#close_write, IO#closed?.
5936 */
5937
5938static VALUE
5939rb_io_close_read(VALUE io)
5940{
5941 rb_io_t *fptr;
5942 VALUE write_io;
5943
5944 fptr = rb_io_get_fptr(rb_io_taint_check(io));
5945 if (fptr->fd < 0) return Qnil;
5946 if (is_socket(fptr->fd, fptr->pathv)) {
5947#ifndef SHUT_RD
5948# define SHUT_RD 0
5949#endif
5950 if (shutdown(fptr->fd, SHUT_RD) < 0)
5951 rb_sys_fail_path(fptr->pathv);
5952 fptr->mode &= ~FMODE_READABLE;
5953 if (!(fptr->mode & FMODE_WRITABLE))
5954 return rb_io_close(io);
5955 return Qnil;
5956 }
5957
5958 write_io = GetWriteIO(io);
5959 if (io != write_io) {
5960 rb_io_t *wfptr;
5961 wfptr = rb_io_get_fptr(rb_io_taint_check(write_io));
5962 wfptr->pid = fptr->pid;
5963 fptr->pid = 0;
5964 RFILE(io)->fptr = wfptr;
5965 /* bind to write_io temporarily to get rid of memory/fd leak */
5966 fptr->tied_io_for_writing = 0;
5967 RFILE(write_io)->fptr = fptr;
5968 rb_io_fptr_cleanup(fptr, FALSE);
5969 /* should not finalize fptr because another thread may be reading it */
5970 return Qnil;
5971 }
5972
5973 if ((fptr->mode & (FMODE_DUPLEX|FMODE_WRITABLE)) == FMODE_WRITABLE) {
5974 rb_raise(rb_eIOError, "closing non-duplex IO for reading");
5975 }
5976 return rb_io_close(io);
5977}
5978
5979/*
5980 * call-seq:
5981 * close_write -> nil
5982 *
5983 * Closes the stream for writing if open for writing;
5984 * returns +nil+.
5985 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5986 *
5987 * Flushes any buffered writes to the operating system before closing.
5988 *
5989 * If the stream was opened by IO.popen and is also closed for reading,
5990 * sets global variable <tt>$?</tt> (child exit status).
5991 *
5992 * IO.popen('ruby', 'r+') do |pipe|
5993 * puts pipe.closed?
5994 * pipe.close_read
5995 * puts pipe.closed?
5996 * pipe.close_write
5997 * puts $?
5998 * puts pipe.closed?
5999 * end
6000 *
6001 * Output:
6002 *
6003 * false
6004 * false
6005 * pid 15044 exit 0
6006 * true
6007 *
6008 * Related: IO#close, IO#close_read, IO#closed?.
6009 */
6010
6011static VALUE
6012rb_io_close_write(VALUE io)
6013{
6014 rb_io_t *fptr;
6015 VALUE write_io;
6016
6017 write_io = GetWriteIO(io);
6018 fptr = rb_io_get_fptr(rb_io_taint_check(write_io));
6019 if (fptr->fd < 0) return Qnil;
6020 if (is_socket(fptr->fd, fptr->pathv)) {
6021#ifndef SHUT_WR
6022# define SHUT_WR 1
6023#endif
6024 if (shutdown(fptr->fd, SHUT_WR) < 0)
6025 rb_sys_fail_path(fptr->pathv);
6026 fptr->mode &= ~FMODE_WRITABLE;
6027 if (!(fptr->mode & FMODE_READABLE))
6028 return rb_io_close(write_io);
6029 return Qnil;
6030 }
6031
6032 if ((fptr->mode & (FMODE_DUPLEX|FMODE_READABLE)) == FMODE_READABLE) {
6033 rb_raise(rb_eIOError, "closing non-duplex IO for writing");
6034 }
6035
6036 if (io != write_io) {
6037 fptr = rb_io_get_fptr(rb_io_taint_check(io));
6038 fptr->tied_io_for_writing = 0;
6039 }
6040 rb_io_close(write_io);
6041 return Qnil;
6042}
6043
6044/*
6045 * call-seq:
6046 * sysseek(offset, whence = IO::SEEK_SET) -> integer
6047 *
6048 * Behaves like IO#seek, except that it:
6049 *
6050 * - Uses low-level system functions.
6051 * - Returns the new position.
6052 *
6053 */
6054
6055static VALUE
6056rb_io_sysseek(int argc, VALUE *argv, VALUE io)
6057{
6058 VALUE offset, ptrname;
6059 int whence = SEEK_SET;
6060 rb_io_t *fptr;
6061 rb_off_t pos;
6062
6063 if (rb_scan_args(argc, argv, "11", &offset, &ptrname) == 2) {
6064 whence = interpret_seek_whence(ptrname);
6065 }
6066 pos = NUM2OFFT(offset);
6067 GetOpenFile(io, fptr);
6068 if ((fptr->mode & FMODE_READABLE) &&
6069 (READ_DATA_BUFFERED(fptr) || READ_CHAR_PENDING(fptr))) {
6070 rb_raise(rb_eIOError, "sysseek for buffered IO");
6071 }
6072 if ((fptr->mode & FMODE_WRITABLE) && fptr->wbuf.len) {
6073 rb_warn("sysseek for buffered IO");
6074 }
6075 errno = 0;
6076 pos = lseek(fptr->fd, pos, whence);
6077 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
6078
6079 return OFFT2NUM(pos);
6080}
6081
6082/*
6083 * call-seq:
6084 * syswrite(object) -> integer
6085 *
6086 * Writes the given +object+ to self, which must be opened for writing (see Modes);
6087 * returns the number bytes written.
6088 * If +object+ is not a string is converted via method to_s:
6089 *
6090 * f = File.new('t.tmp', 'w')
6091 * f.syswrite('foo') # => 3
6092 * f.syswrite(30) # => 2
6093 * f.syswrite(:foo) # => 3
6094 * f.close
6095 *
6096 * This methods should not be used with other stream-writer methods.
6097 *
6098 */
6099
6100static VALUE
6101rb_io_syswrite(VALUE io, VALUE str)
6102{
6103 VALUE tmp;
6104 rb_io_t *fptr;
6105 long n, len;
6106 const char *ptr;
6107
6108 if (!RB_TYPE_P(str, T_STRING))
6109 str = rb_obj_as_string(str);
6110
6111 io = GetWriteIO(io);
6112 GetOpenFile(io, fptr);
6114
6115 if (fptr->wbuf.len) {
6116 rb_warn("syswrite for buffered IO");
6117 }
6118
6119 tmp = rb_str_tmp_frozen_acquire(str);
6120 RSTRING_GETMEM(tmp, ptr, len);
6121 n = rb_io_write_memory(fptr, ptr, len);
6122 if (n < 0) rb_sys_fail_path(fptr->pathv);
6123 rb_str_tmp_frozen_release(str, tmp);
6124
6125 return LONG2FIX(n);
6126}
6127
6128/*
6129 * call-seq:
6130 * sysread(maxlen) -> string
6131 * sysread(maxlen, out_string) -> string
6132 *
6133 * Behaves like IO#readpartial, except that it uses low-level system functions.
6134 *
6135 * This method should not be used with other stream-reader methods.
6136 *
6137 */
6138
6139static VALUE
6140rb_io_sysread(int argc, VALUE *argv, VALUE io)
6141{
6142 VALUE len, str;
6143 rb_io_t *fptr;
6144 long n, ilen;
6145 struct io_internal_read_struct iis;
6146 int shrinkable;
6147
6148 rb_scan_args(argc, argv, "11", &len, &str);
6149 ilen = NUM2LONG(len);
6150
6151 shrinkable = io_setstrbuf(&str, ilen);
6152 if (ilen == 0) return str;
6153
6154 GetOpenFile(io, fptr);
6156
6157 if (READ_DATA_BUFFERED(fptr)) {
6158 rb_raise(rb_eIOError, "sysread for buffered IO");
6159 }
6160
6161 rb_io_check_closed(fptr);
6162
6163 io_setstrbuf(&str, ilen);
6164 iis.th = rb_thread_current();
6165 iis.fptr = fptr;
6166 iis.nonblock = 0;
6167 iis.fd = fptr->fd;
6168 iis.buf = RSTRING_PTR(str);
6169 iis.capa = ilen;
6170 iis.timeout = NULL;
6171 n = io_read_memory_locktmp(str, &iis);
6172
6173 if (n < 0) {
6174 rb_sys_fail_path(fptr->pathv);
6175 }
6176
6177 io_set_read_length(str, n, shrinkable);
6178
6179 if (n == 0 && ilen > 0) {
6180 rb_eof_error();
6181 }
6182
6183 return str;
6184}
6185
6187 struct rb_io *io;
6188 int fd;
6189 void *buf;
6190 size_t count;
6191 rb_off_t offset;
6192};
6193
6194static VALUE
6195internal_pread_func(void *_arg)
6196{
6197 struct prdwr_internal_arg *arg = _arg;
6198
6199 return (VALUE)pread(arg->fd, arg->buf, arg->count, arg->offset);
6200}
6201
6202static VALUE
6203pread_internal_call(VALUE _arg)
6204{
6205 struct prdwr_internal_arg *arg = (struct prdwr_internal_arg *)_arg;
6206
6207 VALUE scheduler = rb_fiber_scheduler_current();
6208 if (scheduler != Qnil) {
6209 VALUE result = rb_fiber_scheduler_io_pread_memory(scheduler, arg->io->self, arg->offset, arg->buf, arg->count, 0);
6210
6211 if (!UNDEF_P(result)) {
6213 }
6214 }
6215
6216 return rb_io_blocking_region_wait(arg->io, internal_pread_func, arg, RUBY_IO_READABLE);
6217}
6218
6219/*
6220 * call-seq:
6221 * pread(maxlen, offset) -> string
6222 * pread(maxlen, offset, out_string) -> string
6223 *
6224 * Behaves like IO#readpartial, except that it:
6225 *
6226 * - Reads at the given +offset+ (in bytes).
6227 * - Disregards, and does not modify, the stream's position
6228 * (see {Position}[rdoc-ref:IO@Position]).
6229 * - Bypasses any user space buffering in the stream.
6230 *
6231 * Because this method does not disturb the stream's state
6232 * (its position, in particular), +pread+ allows multiple threads and processes
6233 * to use the same \IO object for reading at various offsets.
6234 *
6235 * f = File.open('t.txt')
6236 * f.read # => "First line\nSecond line\n\nFourth line\nFifth line\n"
6237 * f.pos # => 52
6238 * # Read 12 bytes at offset 0.
6239 * f.pread(12, 0) # => "First line\n"
6240 * # Read 9 bytes at offset 8.
6241 * f.pread(9, 8) # => "ne\nSecon"
6242 * f.close
6243 *
6244 * Not available on some platforms.
6245 *
6246 */
6247static VALUE
6248rb_io_pread(int argc, VALUE *argv, VALUE io)
6249{
6250 VALUE len, offset, str;
6251 rb_io_t *fptr;
6252 ssize_t n;
6253 struct prdwr_internal_arg arg;
6254 int shrinkable;
6255
6256 rb_scan_args(argc, argv, "21", &len, &offset, &str);
6257 arg.count = NUM2SIZET(len);
6258 arg.offset = NUM2OFFT(offset);
6259
6260 shrinkable = io_setstrbuf(&str, (long)arg.count);
6261 if (arg.count == 0) return str;
6262 arg.buf = RSTRING_PTR(str);
6263
6264 GetOpenFile(io, fptr);
6266
6267 arg.io = fptr;
6268 arg.fd = fptr->fd;
6269 rb_io_check_closed(fptr);
6270
6271 rb_str_locktmp(str);
6272 n = (ssize_t)rb_ensure(pread_internal_call, (VALUE)&arg, rb_str_unlocktmp, str);
6273
6274 if (n < 0) {
6275 rb_sys_fail_path(fptr->pathv);
6276 }
6277 io_set_read_length(str, n, shrinkable);
6278 if (n == 0 && arg.count > 0) {
6279 rb_eof_error();
6280 }
6281
6282 return str;
6283}
6284
6285static VALUE
6286internal_pwrite_func(void *_arg)
6287{
6288 struct prdwr_internal_arg *arg = _arg;
6289
6290 return (VALUE)pwrite(arg->fd, arg->buf, arg->count, arg->offset);
6291}
6292
6293static VALUE
6294pwrite_internal_call(VALUE _arg)
6295{
6296 struct prdwr_internal_arg *arg = (struct prdwr_internal_arg *)_arg;
6297
6298 VALUE scheduler = rb_fiber_scheduler_current();
6299 if (scheduler != Qnil) {
6300 VALUE result = rb_fiber_scheduler_io_pwrite_memory(scheduler, arg->io->self, arg->offset, arg->buf, arg->count, 0);
6301
6302 if (!UNDEF_P(result)) {
6304 }
6305 }
6306
6307 return rb_io_blocking_region_wait(arg->io, internal_pwrite_func, arg, RUBY_IO_WRITABLE);
6308}
6309
6310/*
6311 * call-seq:
6312 * pwrite(object, offset) -> integer
6313 *
6314 * Behaves like IO#write, except that it:
6315 *
6316 * - Writes at the given +offset+ (in bytes).
6317 * - Disregards, and does not modify, the stream's position
6318 * (see {Position}[rdoc-ref:IO@Position]).
6319 * - Bypasses any user space buffering in the stream.
6320 *
6321 * Because this method does not disturb the stream's state
6322 * (its position, in particular), +pwrite+ allows multiple threads and processes
6323 * to use the same \IO object for writing at various offsets.
6324 *
6325 * f = File.open('t.tmp', 'w+')
6326 * # Write 6 bytes at offset 3.
6327 * f.pwrite('ABCDEF', 3) # => 6
6328 * f.rewind
6329 * f.read # => "\u0000\u0000\u0000ABCDEF"
6330 * f.close
6331 *
6332 * Not available on some platforms.
6333 *
6334 */
6335static VALUE
6336rb_io_pwrite(VALUE io, VALUE str, VALUE offset)
6337{
6338 rb_io_t *fptr;
6339 ssize_t n;
6340 struct prdwr_internal_arg arg;
6341 VALUE tmp;
6342
6343 if (!RB_TYPE_P(str, T_STRING))
6344 str = rb_obj_as_string(str);
6345
6346 arg.offset = NUM2OFFT(offset);
6347
6348 io = GetWriteIO(io);
6349 GetOpenFile(io, fptr);
6351
6352 arg.io = fptr;
6353 arg.fd = fptr->fd;
6354
6355 tmp = rb_str_tmp_frozen_acquire(str);
6356 arg.buf = RSTRING_PTR(tmp);
6357 arg.count = (size_t)RSTRING_LEN(tmp);
6358
6359 n = (ssize_t)pwrite_internal_call((VALUE)&arg);
6360 if (n < 0) rb_sys_fail_path(fptr->pathv);
6361 rb_str_tmp_frozen_release(str, tmp);
6362
6363 return SSIZET2NUM(n);
6364}
6365
6366VALUE
6368{
6369 rb_io_t *fptr;
6370
6371 GetOpenFile(io, fptr);
6372 if (fptr->readconv)
6374 if (fptr->writeconv)
6376 fptr->mode |= FMODE_BINMODE;
6377 fptr->mode &= ~FMODE_TEXTMODE;
6378 fptr->writeconv_pre_ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
6379#ifdef O_BINARY
6380 if (!fptr->readconv) {
6381 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6382 }
6383 else {
6384 setmode(fptr->fd, O_BINARY);
6385 }
6386#endif
6387 return io;
6388}
6389
6390static void
6391io_ascii8bit_binmode(rb_io_t *fptr)
6392{
6393 if (fptr->readconv) {
6394 rb_econv_close(fptr->readconv);
6395 fptr->readconv = NULL;
6396 }
6397 if (fptr->writeconv) {
6399 fptr->writeconv = NULL;
6400 }
6401 fptr->mode |= FMODE_BINMODE;
6402 fptr->mode &= ~FMODE_TEXTMODE;
6403 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6404
6405 fptr->encs.enc = rb_ascii8bit_encoding();
6406 fptr->encs.enc2 = NULL;
6407 fptr->encs.ecflags = 0;
6408 fptr->encs.ecopts = Qnil;
6409 clear_codeconv(fptr);
6410}
6411
6412VALUE
6414{
6415 rb_io_t *fptr;
6416
6417 GetOpenFile(io, fptr);
6418 io_ascii8bit_binmode(fptr);
6419
6420 return io;
6421}
6422
6423/*
6424 * call-seq:
6425 * binmode -> self
6426 *
6427 * Sets the stream's data mode as binary
6428 * (see {Data Mode}[rdoc-ref:File@Data+Mode]).
6429 *
6430 * A stream's data mode may not be changed from binary to text.
6431 *
6432 */
6433
6434static VALUE
6435rb_io_binmode_m(VALUE io)
6436{
6437 VALUE write_io;
6438
6440
6441 write_io = GetWriteIO(io);
6442 if (write_io != io)
6443 rb_io_ascii8bit_binmode(write_io);
6444 return io;
6445}
6446
6447/*
6448 * call-seq:
6449 * binmode? -> true or false
6450 *
6451 * Returns +true+ if the stream is on binary mode, +false+ otherwise.
6452 * See {Data Mode}[rdoc-ref:File@Data+Mode].
6453 *
6454 */
6455static VALUE
6456rb_io_binmode_p(VALUE io)
6457{
6458 rb_io_t *fptr;
6459 GetOpenFile(io, fptr);
6460 return RBOOL(fptr->mode & FMODE_BINMODE);
6461}
6462
6463static const char*
6464rb_io_fmode_modestr(enum rb_io_mode fmode)
6465{
6466 if (fmode & FMODE_APPEND) {
6467 if ((fmode & FMODE_READWRITE) == FMODE_READWRITE) {
6468 return MODE_BTMODE("a+", "ab+", "at+");
6469 }
6470 return MODE_BTMODE("a", "ab", "at");
6471 }
6472 switch (fmode & FMODE_READWRITE) {
6473 default:
6474 rb_raise(rb_eArgError, "invalid access fmode 0x%x", fmode);
6475 case FMODE_READABLE:
6476 return MODE_BTMODE("r", "rb", "rt");
6477 case FMODE_WRITABLE:
6478 return MODE_BTXMODE("w", "wb", "wt", "wx", "wbx", "wtx");
6479 case FMODE_READWRITE:
6480 if (fmode & FMODE_CREATE) {
6481 return MODE_BTXMODE("w+", "wb+", "wt+", "w+x", "wb+x", "wt+x");
6482 }
6483 return MODE_BTMODE("r+", "rb+", "rt+");
6484 }
6485}
6486
6487static const char bom_prefix[] = "bom|";
6488static const char utf_prefix[] = "utf-";
6489enum {bom_prefix_len = (int)sizeof(bom_prefix) - 1};
6490enum {utf_prefix_len = (int)sizeof(utf_prefix) - 1};
6491
6492static int
6493io_encname_bom_p(const char *name, long len)
6494{
6495 return len > bom_prefix_len && STRNCASECMP(name, bom_prefix, bom_prefix_len) == 0;
6496}
6497
6498enum rb_io_mode
6499rb_io_modestr_fmode(const char *modestr)
6500{
6501 enum rb_io_mode fmode = 0;
6502 const char *m = modestr, *p = NULL;
6503
6504 switch (*m++) {
6505 case 'r':
6506 fmode |= FMODE_READABLE;
6507 break;
6508 case 'w':
6510 break;
6511 case 'a':
6513 break;
6514 default:
6515 goto error;
6516 }
6517
6518 while (*m) {
6519 switch (*m++) {
6520 case 'b':
6521 fmode |= FMODE_BINMODE;
6522 break;
6523 case 't':
6524 fmode |= FMODE_TEXTMODE;
6525 break;
6526 case '+':
6527 fmode |= FMODE_READWRITE;
6528 break;
6529 case 'x':
6530 if (modestr[0] != 'w')
6531 goto error;
6532 fmode |= FMODE_EXCL;
6533 break;
6534 default:
6535 goto error;
6536 case ':':
6537 p = strchr(m, ':');
6538 if (io_encname_bom_p(m, p ? (long)(p - m) : (long)strlen(m)))
6539 fmode |= FMODE_SETENC_BY_BOM;
6540 goto finished;
6541 }
6542 }
6543
6544 finished:
6545 if ((fmode & FMODE_BINMODE) && (fmode & FMODE_TEXTMODE))
6546 goto error;
6547
6548 return fmode;
6549
6550 error:
6551 rb_raise(rb_eArgError, "invalid access mode %s", modestr);
6553}
6554
6555int
6556rb_io_oflags_fmode(int oflags)
6557{
6558 enum rb_io_mode fmode = 0;
6559
6560 switch (oflags & O_ACCMODE) {
6561 case O_RDONLY:
6562 fmode = FMODE_READABLE;
6563 break;
6564 case O_WRONLY:
6565 fmode = FMODE_WRITABLE;
6566 break;
6567 case O_RDWR:
6568 fmode = FMODE_READWRITE;
6569 break;
6570 }
6571
6572 if (oflags & O_APPEND) {
6573 fmode |= FMODE_APPEND;
6574 }
6575 if (oflags & O_TRUNC) {
6576 fmode |= FMODE_TRUNC;
6577 }
6578 if (oflags & O_CREAT) {
6579 fmode |= FMODE_CREATE;
6580 }
6581 if (oflags & O_EXCL) {
6582 fmode |= FMODE_EXCL;
6583 }
6584#ifdef O_BINARY
6585 if (oflags & O_BINARY) {
6586 fmode |= FMODE_BINMODE;
6587 }
6588#endif
6589
6590 return fmode;
6591}
6592
6593static int
6594rb_io_fmode_oflags(enum rb_io_mode fmode)
6595{
6596 int oflags = 0;
6597
6598 switch (fmode & FMODE_READWRITE) {
6599 case FMODE_READABLE:
6600 oflags |= O_RDONLY;
6601 break;
6602 case FMODE_WRITABLE:
6603 oflags |= O_WRONLY;
6604 break;
6605 case FMODE_READWRITE:
6606 oflags |= O_RDWR;
6607 break;
6608 }
6609
6610 if (fmode & FMODE_APPEND) {
6611 oflags |= O_APPEND;
6612 }
6613 if (fmode & FMODE_TRUNC) {
6614 oflags |= O_TRUNC;
6615 }
6616 if (fmode & FMODE_CREATE) {
6617 oflags |= O_CREAT;
6618 }
6619 if (fmode & FMODE_EXCL) {
6620 oflags |= O_EXCL;
6621 }
6622#ifdef O_BINARY
6623 if (fmode & FMODE_BINMODE) {
6624 oflags |= O_BINARY;
6625 }
6626#endif
6627
6628 return oflags;
6629}
6630
6631int
6632rb_io_modestr_oflags(const char *modestr)
6633{
6634 return rb_io_fmode_oflags(rb_io_modestr_fmode(modestr));
6635}
6636
6637static const char*
6638rb_io_oflags_modestr(int oflags)
6639{
6640#ifdef O_BINARY
6641# define MODE_BINARY(a,b) ((oflags & O_BINARY) ? (b) : (a))
6642#else
6643# define MODE_BINARY(a,b) (a)
6644#endif
6645 int accmode;
6646 if (oflags & O_EXCL) {
6647 rb_raise(rb_eArgError, "exclusive access mode is not supported");
6648 }
6649 accmode = oflags & (O_RDONLY|O_WRONLY|O_RDWR);
6650 if (oflags & O_APPEND) {
6651 if (accmode == O_WRONLY) {
6652 return MODE_BINARY("a", "ab");
6653 }
6654 if (accmode == O_RDWR) {
6655 return MODE_BINARY("a+", "ab+");
6656 }
6657 }
6658 switch (accmode) {
6659 default:
6660 rb_raise(rb_eArgError, "invalid access oflags 0x%x", oflags);
6661 case O_RDONLY:
6662 return MODE_BINARY("r", "rb");
6663 case O_WRONLY:
6664 return MODE_BINARY("w", "wb");
6665 case O_RDWR:
6666 if (oflags & O_TRUNC) {
6667 return MODE_BINARY("w+", "wb+");
6668 }
6669 return MODE_BINARY("r+", "rb+");
6670 }
6671}
6672
6673/*
6674 * Convert external/internal encodings to enc/enc2
6675 * NULL => use default encoding
6676 * Qnil => no encoding specified (internal only)
6677 */
6678static void
6679rb_io_ext_int_to_encs(rb_encoding *ext, rb_encoding *intern, rb_encoding **enc, rb_encoding **enc2, enum rb_io_mode fmode)
6680{
6681 int default_ext = 0;
6682
6683 if (ext == NULL) {
6684 ext = rb_default_external_encoding();
6685 default_ext = 1;
6686 }
6687 if (rb_is_ascii8bit_enc(ext)) {
6688 /* If external is ASCII-8BIT, no transcoding */
6689 intern = NULL;
6690 }
6691 else if (intern == NULL) {
6692 intern = rb_default_internal_encoding();
6693 }
6694 if (intern == NULL || intern == (rb_encoding *)Qnil ||
6695 (!(fmode & FMODE_SETENC_BY_BOM) && (intern == ext))) {
6696 /* No internal encoding => use external + no transcoding */
6697 *enc = (default_ext && intern != ext) ? NULL : ext;
6698 *enc2 = NULL;
6699 }
6700 else {
6701 *enc = intern;
6702 *enc2 = ext;
6703 }
6704}
6705
6706static void
6707unsupported_encoding(const char *name, rb_encoding *enc)
6708{
6709 rb_enc_warn(enc, "Unsupported encoding %s ignored", name);
6710}
6711
6712static void
6713parse_mode_enc(const char *estr, rb_encoding *estr_enc,
6714 rb_encoding **enc_p, rb_encoding **enc2_p, enum rb_io_mode *fmode_p)
6715{
6716 const char *p;
6717 char encname[ENCODING_MAXNAMELEN+1];
6718 int idx, idx2;
6719 enum rb_io_mode fmode = fmode_p ? *fmode_p : 0;
6720 rb_encoding *ext_enc, *int_enc;
6721 long len;
6722
6723 /* parse estr as "enc" or "enc2:enc" or "enc:-" */
6724
6725 p = strrchr(estr, ':');
6726 len = p ? (p++ - estr) : (long)strlen(estr);
6727 if ((fmode & FMODE_SETENC_BY_BOM) || io_encname_bom_p(estr, len)) {
6728 estr += bom_prefix_len;
6729 len -= bom_prefix_len;
6730 if (!STRNCASECMP(estr, utf_prefix, utf_prefix_len)) {
6731 fmode |= FMODE_SETENC_BY_BOM;
6732 }
6733 else {
6734 rb_enc_warn(estr_enc, "BOM with non-UTF encoding %s is nonsense", estr);
6735 fmode &= ~FMODE_SETENC_BY_BOM;
6736 }
6737 }
6738 if (len == 0 || len > ENCODING_MAXNAMELEN) {
6739 idx = -1;
6740 }
6741 else {
6742 if (p) {
6743 memcpy(encname, estr, len);
6744 encname[len] = '\0';
6745 estr = encname;
6746 }
6747 idx = rb_enc_find_index(estr);
6748 }
6749 if (fmode_p) *fmode_p = fmode;
6750
6751 if (idx >= 0)
6752 ext_enc = rb_enc_from_index(idx);
6753 else {
6754 if (idx != -2)
6755 unsupported_encoding(estr, estr_enc);
6756 ext_enc = NULL;
6757 }
6758
6759 int_enc = NULL;
6760 if (p) {
6761 if (*p == '-' && *(p+1) == '\0') {
6762 /* Special case - "-" => no transcoding */
6763 int_enc = (rb_encoding *)Qnil;
6764 }
6765 else {
6766 idx2 = rb_enc_find_index(p);
6767 if (idx2 < 0)
6768 unsupported_encoding(p, estr_enc);
6769 else if (!(fmode & FMODE_SETENC_BY_BOM) && (idx2 == idx)) {
6770 int_enc = (rb_encoding *)Qnil;
6771 }
6772 else
6773 int_enc = rb_enc_from_index(idx2);
6774 }
6775 }
6776
6777 rb_io_ext_int_to_encs(ext_enc, int_enc, enc_p, enc2_p, fmode);
6778}
6779
6780int
6781rb_io_extract_encoding_option(VALUE opt, rb_encoding **enc_p, rb_encoding **enc2_p, enum rb_io_mode *fmode_p)
6782{
6783 VALUE encoding=Qnil, extenc=Qundef, intenc=Qundef, tmp;
6784 int extracted = 0;
6785 rb_encoding *extencoding = NULL;
6786 rb_encoding *intencoding = NULL;
6787
6788 if (!NIL_P(opt)) {
6789 VALUE v;
6790 v = rb_hash_lookup2(opt, sym_encoding, Qnil);
6791 if (v != Qnil) encoding = v;
6792 v = rb_hash_lookup2(opt, sym_extenc, Qundef);
6793 if (v != Qnil) extenc = v;
6794 v = rb_hash_lookup2(opt, sym_intenc, Qundef);
6795 if (!UNDEF_P(v)) intenc = v;
6796 }
6797 if ((!UNDEF_P(extenc) || !UNDEF_P(intenc)) && !NIL_P(encoding)) {
6798 if (!NIL_P(ruby_verbose)) {
6799 int idx = rb_to_encoding_index(encoding);
6800 if (idx >= 0) encoding = rb_enc_from_encoding(rb_enc_from_index(idx));
6801 rb_warn("Ignoring encoding parameter '%"PRIsVALUE"': %s_encoding is used",
6802 encoding, UNDEF_P(extenc) ? "internal" : "external");
6803 }
6804 encoding = Qnil;
6805 }
6806 if (!UNDEF_P(extenc) && !NIL_P(extenc)) {
6807 extencoding = rb_to_encoding(extenc);
6808 }
6809 if (!UNDEF_P(intenc)) {
6810 if (NIL_P(intenc)) {
6811 /* internal_encoding: nil => no transcoding */
6812 intencoding = (rb_encoding *)Qnil;
6813 }
6814 else if (!NIL_P(tmp = rb_check_string_type(intenc))) {
6815 char *p = StringValueCStr(tmp);
6816
6817 if (*p == '-' && *(p+1) == '\0') {
6818 /* Special case - "-" => no transcoding */
6819 intencoding = (rb_encoding *)Qnil;
6820 }
6821 else {
6822 intencoding = rb_to_encoding(intenc);
6823 }
6824 }
6825 else {
6826 intencoding = rb_to_encoding(intenc);
6827 }
6828 if (extencoding == intencoding) {
6829 intencoding = (rb_encoding *)Qnil;
6830 }
6831 }
6832 if (!NIL_P(encoding)) {
6833 extracted = 1;
6834 if (!NIL_P(tmp = rb_check_string_type(encoding))) {
6835 parse_mode_enc(StringValueCStr(tmp), rb_enc_get(tmp),
6836 enc_p, enc2_p, fmode_p);
6837 }
6838 else {
6839 rb_io_ext_int_to_encs(rb_to_encoding(encoding), NULL, enc_p, enc2_p, 0);
6840 }
6841 }
6842 else if (!UNDEF_P(extenc) || !UNDEF_P(intenc)) {
6843 extracted = 1;
6844 rb_io_ext_int_to_encs(extencoding, intencoding, enc_p, enc2_p, 0);
6845 }
6846 return extracted;
6847}
6848
6849static void
6850validate_enc_binmode(enum rb_io_mode *fmode_p, int ecflags, rb_encoding *enc, rb_encoding *enc2)
6851{
6852 enum rb_io_mode fmode = *fmode_p;
6853
6854 if ((fmode & FMODE_READABLE) &&
6855 !enc2 &&
6856 !(fmode & FMODE_BINMODE) &&
6857 !rb_enc_asciicompat(enc ? enc : rb_default_external_encoding()))
6858 rb_raise(rb_eArgError, "ASCII incompatible encoding needs binmode");
6859
6860 if ((fmode & FMODE_BINMODE) && (ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
6861 rb_raise(rb_eArgError, "newline decorator with binary mode");
6862 }
6863 if (!(fmode & FMODE_BINMODE) &&
6864 (DEFAULT_TEXTMODE || (ecflags & ECONV_NEWLINE_DECORATOR_MASK))) {
6865 fmode |= FMODE_TEXTMODE;
6866 *fmode_p = fmode;
6867 }
6868#if !DEFAULT_TEXTMODE
6869 else if (!(ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
6870 fmode &= ~FMODE_TEXTMODE;
6871 *fmode_p = fmode;
6872 }
6873#endif
6874}
6875
6876static void
6877extract_binmode(VALUE opthash, enum rb_io_mode *fmode)
6878{
6879 if (!NIL_P(opthash)) {
6880 VALUE v;
6881 v = rb_hash_aref(opthash, sym_textmode);
6882 if (!NIL_P(v)) {
6883 if (*fmode & FMODE_TEXTMODE)
6884 rb_raise(rb_eArgError, "textmode specified twice");
6885 if (*fmode & FMODE_BINMODE)
6886 rb_raise(rb_eArgError, "both textmode and binmode specified");
6887 if (RTEST(v))
6888 *fmode |= FMODE_TEXTMODE;
6889 }
6890 v = rb_hash_aref(opthash, sym_binmode);
6891 if (!NIL_P(v)) {
6892 if (*fmode & FMODE_BINMODE)
6893 rb_raise(rb_eArgError, "binmode specified twice");
6894 if (*fmode & FMODE_TEXTMODE)
6895 rb_raise(rb_eArgError, "both textmode and binmode specified");
6896 if (RTEST(v))
6897 *fmode |= FMODE_BINMODE;
6898 }
6899
6900 if ((*fmode & FMODE_BINMODE) && (*fmode & FMODE_TEXTMODE))
6901 rb_raise(rb_eArgError, "both textmode and binmode specified");
6902 }
6903}
6904
6905void
6906rb_io_extract_modeenc(VALUE *vmode_p, VALUE *vperm_p, VALUE opthash,
6907 int *oflags_p, enum rb_io_mode *fmode_p, struct rb_io_encoding *convconfig_p)
6908{
6909 VALUE vmode;
6910 int oflags;
6911 enum rb_io_mode fmode;
6912 rb_encoding *enc, *enc2;
6913 int ecflags;
6914 VALUE ecopts;
6915 int has_enc = 0, has_vmode = 0;
6916 VALUE intmode;
6917
6918 vmode = *vmode_p;
6919
6920 /* Set to defaults */
6921 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
6922
6923 vmode_handle:
6924 if (NIL_P(vmode)) {
6925 fmode = FMODE_READABLE;
6926 oflags = O_RDONLY;
6927 }
6928 else if (!NIL_P(intmode = rb_check_to_integer(vmode, "to_int"))) {
6929 vmode = intmode;
6930 oflags = NUM2INT(intmode);
6931 fmode = rb_io_oflags_fmode(oflags);
6932 }
6933 else {
6934 const char *p;
6935
6936 StringValue(vmode);
6937 p = StringValueCStr(vmode);
6938 fmode = rb_io_modestr_fmode(p);
6939 oflags = rb_io_fmode_oflags(fmode);
6940 p = strchr(p, ':');
6941 if (p) {
6942 has_enc = 1;
6943 parse_mode_enc(p+1, rb_enc_get(vmode), &enc, &enc2, &fmode);
6944 }
6945 else {
6946 rb_encoding *e;
6947
6948 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
6949 rb_io_ext_int_to_encs(e, NULL, &enc, &enc2, fmode);
6950 }
6951 }
6952
6953 if (NIL_P(opthash)) {
6954 ecflags = (fmode & FMODE_READABLE) ?
6957#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
6958 ecflags |= (fmode & FMODE_WRITABLE) ?
6959 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
6960 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
6961#endif
6962 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
6963 ecopts = Qnil;
6964 if (fmode & FMODE_BINMODE) {
6965#ifdef O_BINARY
6966 oflags |= O_BINARY;
6967#endif
6968 if (!has_enc)
6969 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
6970 }
6971#if DEFAULT_TEXTMODE
6972 else if (NIL_P(vmode)) {
6973 fmode |= DEFAULT_TEXTMODE;
6974 }
6975#endif
6976 }
6977 else {
6978 VALUE v;
6979 if (!has_vmode) {
6980 v = rb_hash_aref(opthash, sym_mode);
6981 if (!NIL_P(v)) {
6982 if (!NIL_P(vmode)) {
6983 rb_raise(rb_eArgError, "mode specified twice");
6984 }
6985 has_vmode = 1;
6986 vmode = v;
6987 goto vmode_handle;
6988 }
6989 }
6990 v = rb_hash_aref(opthash, sym_flags);
6991 if (!NIL_P(v)) {
6992 v = rb_to_int(v);
6993 oflags |= NUM2INT(v);
6994 vmode = INT2NUM(oflags);
6995 fmode = rb_io_oflags_fmode(oflags);
6996 }
6997 extract_binmode(opthash, &fmode);
6998 if (fmode & FMODE_BINMODE) {
6999#ifdef O_BINARY
7000 oflags |= O_BINARY;
7001#endif
7002 if (!has_enc)
7003 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
7004 }
7005#if DEFAULT_TEXTMODE
7006 else if (NIL_P(vmode)) {
7007 fmode |= DEFAULT_TEXTMODE;
7008 }
7009#endif
7010 v = rb_hash_aref(opthash, sym_perm);
7011 if (!NIL_P(v)) {
7012 if (vperm_p) {
7013 if (!NIL_P(*vperm_p)) {
7014 rb_raise(rb_eArgError, "perm specified twice");
7015 }
7016 *vperm_p = v;
7017 }
7018 else {
7019 /* perm no use, just ignore */
7020 }
7021 }
7022 ecflags = (fmode & FMODE_READABLE) ?
7025#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7026 ecflags |= (fmode & FMODE_WRITABLE) ?
7027 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7028 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7029#endif
7030
7031 if (rb_io_extract_encoding_option(opthash, &enc, &enc2, &fmode)) {
7032 if (has_enc) {
7033 rb_raise(rb_eArgError, "encoding specified twice");
7034 }
7035 }
7036 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
7037 ecflags = rb_econv_prepare_options(opthash, &ecopts, ecflags);
7038 }
7039
7040 validate_enc_binmode(&fmode, ecflags, enc, enc2);
7041
7042 *vmode_p = vmode;
7043
7044 *oflags_p = oflags;
7045 *fmode_p = fmode;
7046 convconfig_p->enc = enc;
7047 convconfig_p->enc2 = enc2;
7048 convconfig_p->ecflags = ecflags;
7049 convconfig_p->ecopts = ecopts;
7050}
7051
7053 VALUE fname;
7054 int oflags;
7055 mode_t perm;
7056};
7057
7058static void *
7059sysopen_func(void *ptr)
7060{
7061 const struct sysopen_struct *data = ptr;
7062 const char *fname = RSTRING_PTR(data->fname);
7063 return (void *)(VALUE)rb_cloexec_open(fname, data->oflags, data->perm);
7064}
7065
7066static inline int
7067rb_sysopen_internal(struct sysopen_struct *data)
7068{
7069 int fd;
7070 do {
7071 fd = IO_WITHOUT_GVL_INT(sysopen_func, data);
7072 } while (fd < 0 && errno == EINTR);
7073 if (0 <= fd)
7074 rb_update_max_fd(fd);
7075 return fd;
7076}
7077
7078static int
7079rb_sysopen(VALUE fname, int oflags, mode_t perm)
7080{
7081 int fd = -1;
7082 struct sysopen_struct data;
7083
7084 data.fname = rb_str_encode_ospath(fname);
7085 StringValueCStr(data.fname);
7086 data.oflags = oflags;
7087 data.perm = perm;
7088
7089 TRY_WITH_GC((fd = rb_sysopen_internal(&data)) >= 0) {
7090 rb_syserr_fail_path(first_errno, fname);
7091 }
7092 return fd;
7093}
7094
7095static inline FILE *
7096fdopen_internal(int fd, const char *modestr)
7097{
7098 FILE *file;
7099
7100#if defined(__sun)
7101 errno = 0;
7102#endif
7103 file = fdopen(fd, modestr);
7104 if (!file) {
7105#ifdef _WIN32
7106 if (errno == 0) errno = EINVAL;
7107#elif defined(__sun)
7108 if (errno == 0) errno = EMFILE;
7109#endif
7110 }
7111 return file;
7112}
7113
7114FILE *
7115rb_fdopen(int fd, const char *modestr)
7116{
7117 FILE *file = 0;
7118
7119 TRY_WITH_GC((file = fdopen_internal(fd, modestr)) != 0) {
7120 rb_syserr_fail(first_errno, 0);
7121 }
7122
7123 /* xxx: should be _IONBF? A buffer in FILE may have trouble. */
7124#ifdef USE_SETVBUF
7125 if (setvbuf(file, NULL, _IOFBF, 0) != 0)
7126 rb_warn("setvbuf() can't be honoured (fd=%d)", fd);
7127#endif
7128 return file;
7129}
7130
7131static int
7132io_check_tty(rb_io_t *fptr)
7133{
7134 int t = isatty(fptr->fd);
7135 if (t)
7136 fptr->mode |= FMODE_TTY|FMODE_DUPLEX;
7137 return t;
7138}
7139
7140static VALUE rb_io_internal_encoding(VALUE);
7141static void io_encoding_set(rb_io_t *, VALUE, VALUE, VALUE);
7142
7143static int
7144io_strip_bom(VALUE io)
7145{
7146 VALUE b1, b2, b3, b4;
7147 rb_io_t *fptr;
7148
7149 GetOpenFile(io, fptr);
7150 if (!(fptr->mode & FMODE_READABLE)) return 0;
7151 if (NIL_P(b1 = rb_io_getbyte(io))) return 0;
7152 switch (b1) {
7153 case INT2FIX(0xEF):
7154 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7155 if (b2 == INT2FIX(0xBB) && !NIL_P(b3 = rb_io_getbyte(io))) {
7156 if (b3 == INT2FIX(0xBF)) {
7157 return rb_utf8_encindex();
7158 }
7159 rb_io_ungetbyte(io, b3);
7160 }
7161 rb_io_ungetbyte(io, b2);
7162 break;
7163
7164 case INT2FIX(0xFE):
7165 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7166 if (b2 == INT2FIX(0xFF)) {
7167 return ENCINDEX_UTF_16BE;
7168 }
7169 rb_io_ungetbyte(io, b2);
7170 break;
7171
7172 case INT2FIX(0xFF):
7173 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7174 if (b2 == INT2FIX(0xFE)) {
7175 b3 = rb_io_getbyte(io);
7176 if (b3 == INT2FIX(0) && !NIL_P(b4 = rb_io_getbyte(io))) {
7177 if (b4 == INT2FIX(0)) {
7178 return ENCINDEX_UTF_32LE;
7179 }
7180 rb_io_ungetbyte(io, b4);
7181 }
7182 rb_io_ungetbyte(io, b3);
7183 return ENCINDEX_UTF_16LE;
7184 }
7185 rb_io_ungetbyte(io, b2);
7186 break;
7187
7188 case INT2FIX(0):
7189 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7190 if (b2 == INT2FIX(0) && !NIL_P(b3 = rb_io_getbyte(io))) {
7191 if (b3 == INT2FIX(0xFE) && !NIL_P(b4 = rb_io_getbyte(io))) {
7192 if (b4 == INT2FIX(0xFF)) {
7193 return ENCINDEX_UTF_32BE;
7194 }
7195 rb_io_ungetbyte(io, b4);
7196 }
7197 rb_io_ungetbyte(io, b3);
7198 }
7199 rb_io_ungetbyte(io, b2);
7200 break;
7201 }
7202 rb_io_ungetbyte(io, b1);
7203 return 0;
7204}
7205
7206static rb_encoding *
7207io_set_encoding_by_bom(VALUE io)
7208{
7209 int idx = io_strip_bom(io);
7210 rb_io_t *fptr;
7211 rb_encoding *extenc = NULL;
7212
7213 GetOpenFile(io, fptr);
7214 if (idx) {
7215 extenc = rb_enc_from_index(idx);
7216 io_encoding_set(fptr, rb_enc_from_encoding(extenc),
7217 rb_io_internal_encoding(io), Qnil);
7218 }
7219 else {
7220 fptr->encs.enc2 = NULL;
7221 }
7222 return extenc;
7223}
7224
7225static VALUE
7226rb_file_open_generic(VALUE io, VALUE filename, int oflags, enum rb_io_mode fmode,
7227 const struct rb_io_encoding *convconfig, mode_t perm)
7228{
7229 VALUE pathv;
7230 rb_io_t *fptr;
7231 struct rb_io_encoding cc;
7232 if (!convconfig) {
7233 /* Set to default encodings */
7234 rb_io_ext_int_to_encs(NULL, NULL, &cc.enc, &cc.enc2, fmode);
7235 cc.ecflags = 0;
7236 cc.ecopts = Qnil;
7237 convconfig = &cc;
7238 }
7239 validate_enc_binmode(&fmode, convconfig->ecflags,
7240 convconfig->enc, convconfig->enc2);
7241
7242 MakeOpenFile(io, fptr);
7243 fptr->mode = fmode;
7244 fptr->encs = *convconfig;
7245 pathv = rb_str_new_frozen(filename);
7246#ifdef O_TMPFILE
7247 if (!(oflags & O_TMPFILE)) {
7248 fptr->pathv = pathv;
7249 }
7250#else
7251 fptr->pathv = pathv;
7252#endif
7253 fptr->fd = rb_sysopen(pathv, oflags, perm);
7254 io_check_tty(fptr);
7255 if (fmode & FMODE_SETENC_BY_BOM) io_set_encoding_by_bom(io);
7256
7257 return io;
7258}
7259
7260static VALUE
7261rb_file_open_internal(VALUE io, VALUE filename, const char *modestr)
7262{
7263 enum rb_io_mode fmode = rb_io_modestr_fmode(modestr);
7264 const char *p = strchr(modestr, ':');
7265 struct rb_io_encoding convconfig;
7266
7267 if (p) {
7268 parse_mode_enc(p+1, rb_usascii_encoding(),
7269 &convconfig.enc, &convconfig.enc2, &fmode);
7270 }
7271 else {
7272 rb_encoding *e;
7273 /* Set to default encodings */
7274
7275 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
7276 rb_io_ext_int_to_encs(e, NULL, &convconfig.enc, &convconfig.enc2, fmode);
7277 }
7278
7279 convconfig.ecflags = (fmode & FMODE_READABLE) ?
7282#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7283 convconfig.ecflags |= (fmode & FMODE_WRITABLE) ?
7284 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7285 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7286#endif
7287 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.enc2, convconfig.ecflags);
7288 convconfig.ecopts = Qnil;
7289
7290 return rb_file_open_generic(io, filename,
7291 rb_io_fmode_oflags(fmode),
7292 fmode,
7293 &convconfig,
7294 0666);
7295}
7296
7297VALUE
7298rb_file_open_str(VALUE fname, const char *modestr)
7299{
7300 FilePathValue(fname);
7301 return rb_file_open_internal(io_alloc(rb_cFile), fname, modestr);
7302}
7303
7304VALUE
7305rb_file_open(const char *fname, const char *modestr)
7306{
7307 return rb_file_open_internal(io_alloc(rb_cFile), rb_str_new_cstr(fname), modestr);
7308}
7309
7310#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7311static struct pipe_list {
7312 rb_io_t *fptr;
7313 struct pipe_list *next;
7314} *pipe_list;
7315
7316static void
7317pipe_add_fptr(rb_io_t *fptr)
7318{
7319 struct pipe_list *list;
7320
7321 list = ALLOC(struct pipe_list);
7322 list->fptr = fptr;
7323 list->next = pipe_list;
7324 pipe_list = list;
7325}
7326
7327static void
7328pipe_del_fptr(rb_io_t *fptr)
7329{
7330 struct pipe_list **prev = &pipe_list;
7331 struct pipe_list *tmp;
7332
7333 while ((tmp = *prev) != 0) {
7334 if (tmp->fptr == fptr) {
7335 *prev = tmp->next;
7336 free(tmp);
7337 return;
7338 }
7339 prev = &tmp->next;
7340 }
7341}
7342
7343#if defined (_WIN32) || defined(__CYGWIN__)
7344static void
7345pipe_atexit(void)
7346{
7347 struct pipe_list *list = pipe_list;
7348 struct pipe_list *tmp;
7349
7350 while (list) {
7351 tmp = list->next;
7352 rb_io_fptr_finalize(list->fptr);
7353 list = tmp;
7354 }
7355}
7356#endif
7357
7358static void
7359pipe_finalize(rb_io_t *fptr, int noraise)
7360{
7361#if !defined(HAVE_WORKING_FORK) && !defined(_WIN32)
7362 int status = 0;
7363 if (fptr->stdio_file) {
7364 status = pclose(fptr->stdio_file);
7365 }
7366 fptr->fd = -1;
7367 fptr->stdio_file = 0;
7368 rb_last_status_set(status, fptr->pid);
7369#else
7370 fptr_finalize(fptr, noraise);
7371#endif
7372 pipe_del_fptr(fptr);
7373}
7374#endif
7375
7376static void
7377fptr_copy_finalizer(rb_io_t *fptr, const rb_io_t *orig)
7378{
7379#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7380 void (*const old_finalize)(struct rb_io*,int) = fptr->finalize;
7381
7382 if (old_finalize == orig->finalize) return;
7383#endif
7384
7385 fptr->finalize = orig->finalize;
7386
7387#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7388 if (old_finalize != pipe_finalize) {
7389 struct pipe_list *list;
7390 for (list = pipe_list; list; list = list->next) {
7391 if (list->fptr == fptr) break;
7392 }
7393 if (!list) pipe_add_fptr(fptr);
7394 }
7395 else {
7396 pipe_del_fptr(fptr);
7397 }
7398#endif
7399}
7400
7401void
7403{
7405 fptr->mode |= FMODE_SYNC;
7406}
7407
7408void
7409rb_io_unbuffered(rb_io_t *fptr)
7410{
7411 rb_io_synchronized(fptr);
7412}
7413
7414int
7415rb_pipe(int *pipes)
7416{
7417 int ret;
7418 TRY_WITH_GC((ret = rb_cloexec_pipe(pipes)) >= 0);
7419 if (ret == 0) {
7420 rb_update_max_fd(pipes[0]);
7421 rb_update_max_fd(pipes[1]);
7422 }
7423 return ret;
7424}
7425
7426#ifdef _WIN32
7427#define HAVE_SPAWNV 1
7428#define spawnv(mode, cmd, args) rb_w32_uaspawn((mode), (cmd), (args))
7429#define spawn(mode, cmd) rb_w32_uspawn((mode), (cmd), 0)
7430#endif
7431
7432#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7433struct popen_arg {
7434 VALUE execarg_obj;
7435 struct rb_execarg *eargp;
7436 int modef;
7437 int pair[2];
7438 int write_pair[2];
7439};
7440#endif
7441
7442#ifdef HAVE_WORKING_FORK
7443# ifndef __EMSCRIPTEN__
7444static void
7445popen_redirect(struct popen_arg *p)
7446{
7447 if ((p->modef & FMODE_READABLE) && (p->modef & FMODE_WRITABLE)) {
7448 close(p->write_pair[1]);
7449 if (p->write_pair[0] != 0) {
7450 dup2(p->write_pair[0], 0);
7451 close(p->write_pair[0]);
7452 }
7453 close(p->pair[0]);
7454 if (p->pair[1] != 1) {
7455 dup2(p->pair[1], 1);
7456 close(p->pair[1]);
7457 }
7458 }
7459 else if (p->modef & FMODE_READABLE) {
7460 close(p->pair[0]);
7461 if (p->pair[1] != 1) {
7462 dup2(p->pair[1], 1);
7463 close(p->pair[1]);
7464 }
7465 }
7466 else {
7467 close(p->pair[1]);
7468 if (p->pair[0] != 0) {
7469 dup2(p->pair[0], 0);
7470 close(p->pair[0]);
7471 }
7472 }
7473}
7474# endif
7475
7476#if defined(__linux__)
7477/* Linux /proc/self/status contains a line: "FDSize:\t<nnn>\n"
7478 * Since /proc may not be available, linux_get_maxfd is just a hint.
7479 * This function, linux_get_maxfd, must be async-signal-safe.
7480 * I.e. opendir() is not usable.
7481 *
7482 * Note that memchr() and memcmp is *not* async-signal-safe in POSIX.
7483 * However they are easy to re-implement in async-signal-safe manner.
7484 * (Also note that there is missing/memcmp.c.)
7485 */
7486static int
7487linux_get_maxfd(void)
7488{
7489 int fd;
7490 char buf[4096], *p, *np, *e;
7491 ssize_t ss;
7492 fd = rb_cloexec_open("/proc/self/status", O_RDONLY|O_NOCTTY, 0);
7493 if (fd < 0) return fd;
7494 ss = read(fd, buf, sizeof(buf));
7495 if (ss < 0) goto err;
7496 p = buf;
7497 e = buf + ss;
7498 while ((int)sizeof("FDSize:\t0\n")-1 <= e-p &&
7499 (np = memchr(p, '\n', e-p)) != NULL) {
7500 if (memcmp(p, "FDSize:", sizeof("FDSize:")-1) == 0) {
7501 int fdsize;
7502 p += sizeof("FDSize:")-1;
7503 *np = '\0';
7504 fdsize = (int)ruby_strtoul(p, (char **)NULL, 10);
7505 close(fd);
7506 return fdsize;
7507 }
7508 p = np+1;
7509 }
7510 /* fall through */
7511
7512 err:
7513 close(fd);
7514 return (int)ss;
7515}
7516#endif
7517
7518/* This function should be async-signal-safe. */
7519void
7520rb_close_before_exec(int lowfd, int maxhint, VALUE noclose_fds)
7521{
7522#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
7523 int fd, ret;
7524 int max = (int)max_file_descriptor;
7525# ifdef F_MAXFD
7526 /* F_MAXFD is available since NetBSD 2.0. */
7527 ret = fcntl(0, F_MAXFD); /* async-signal-safe */
7528 if (ret != -1)
7529 maxhint = max = ret;
7530# elif defined(__linux__)
7531 ret = linux_get_maxfd();
7532 if (maxhint < ret)
7533 maxhint = ret;
7534 /* maxhint = max = ret; if (ret == -1) abort(); // test */
7535# endif
7536 if (max < maxhint)
7537 max = maxhint;
7538 for (fd = lowfd; fd <= max; fd++) {
7539 if (!NIL_P(noclose_fds) &&
7540 RTEST(rb_hash_lookup(noclose_fds, INT2FIX(fd)))) /* async-signal-safe */
7541 continue;
7542 ret = fcntl(fd, F_GETFD); /* async-signal-safe */
7543 if (ret != -1 && !(ret & FD_CLOEXEC)) {
7544 fcntl(fd, F_SETFD, ret|FD_CLOEXEC); /* async-signal-safe */
7545 }
7546# define CONTIGUOUS_CLOSED_FDS 20
7547 if (ret != -1) {
7548 if (max < fd + CONTIGUOUS_CLOSED_FDS)
7549 max = fd + CONTIGUOUS_CLOSED_FDS;
7550 }
7551 }
7552#endif
7553}
7554
7555# ifndef __EMSCRIPTEN__
7556static int
7557popen_exec(void *pp, char *errmsg, size_t errmsg_len)
7558{
7559 struct popen_arg *p = (struct popen_arg*)pp;
7560
7561 return rb_exec_async_signal_safe(p->eargp, errmsg, errmsg_len);
7562}
7563# endif
7564#endif
7565
7566#if (defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)) && !defined __EMSCRIPTEN__
7567static VALUE
7568rb_execarg_fixup_v(VALUE execarg_obj)
7569{
7570 rb_execarg_parent_start(execarg_obj);
7571 return Qnil;
7572}
7573#else
7574char *rb_execarg_commandline(const struct rb_execarg *eargp, VALUE *prog);
7575#endif
7576
7577#ifndef __EMSCRIPTEN__
7578static VALUE
7579pipe_open(VALUE execarg_obj, const char *modestr, enum rb_io_mode fmode,
7580 const struct rb_io_encoding *convconfig)
7581{
7582 struct rb_execarg *eargp = NIL_P(execarg_obj) ? NULL : rb_execarg_get(execarg_obj);
7583 VALUE prog = eargp ? (eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name) : Qfalse ;
7584 rb_pid_t pid = 0;
7585 rb_io_t *fptr;
7586 VALUE port;
7587 rb_io_t *write_fptr;
7588 VALUE write_port;
7589#if defined(HAVE_WORKING_FORK)
7590 int status;
7591 char errmsg[80] = { '\0' };
7592#endif
7593#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7594 int state;
7595 struct popen_arg arg;
7596#endif
7597 int e = 0;
7598#if defined(HAVE_SPAWNV)
7599# if defined(HAVE_SPAWNVE)
7600# define DO_SPAWN(cmd, args, envp) ((args) ? \
7601 spawnve(P_NOWAIT, (cmd), (args), (envp)) : \
7602 spawne(P_NOWAIT, (cmd), (envp)))
7603# else
7604# define DO_SPAWN(cmd, args, envp) ((args) ? \
7605 spawnv(P_NOWAIT, (cmd), (args)) : \
7606 spawn(P_NOWAIT, (cmd)))
7607# endif
7608# if !defined(HAVE_WORKING_FORK)
7609 char **args = NULL;
7610# if defined(HAVE_SPAWNVE)
7611 char **envp = NULL;
7612# endif
7613# endif
7614#endif
7615#if !defined(HAVE_WORKING_FORK)
7616 struct rb_execarg sarg, *sargp = &sarg;
7617#endif
7618 FILE *fp = 0;
7619 int fd = -1;
7620 int write_fd = -1;
7621#if !defined(HAVE_WORKING_FORK)
7622 const char *cmd = 0;
7623
7624 if (prog)
7625 cmd = StringValueCStr(prog);
7626#endif
7627
7628#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7629 arg.execarg_obj = execarg_obj;
7630 arg.eargp = eargp;
7631 arg.modef = fmode;
7632 arg.pair[0] = arg.pair[1] = -1;
7633 arg.write_pair[0] = arg.write_pair[1] = -1;
7634# if !defined(HAVE_WORKING_FORK)
7635 if (eargp && !eargp->use_shell) {
7636 args = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
7637 }
7638# endif
7639 switch (fmode & (FMODE_READABLE|FMODE_WRITABLE)) {
7641 if (rb_pipe(arg.write_pair) < 0)
7642 rb_sys_fail_str(prog);
7643 if (rb_pipe(arg.pair) < 0) {
7644 e = errno;
7645 close(arg.write_pair[0]);
7646 close(arg.write_pair[1]);
7647 rb_syserr_fail_str(e, prog);
7648 }
7649 if (eargp) {
7650 rb_execarg_addopt(execarg_obj, INT2FIX(0), INT2FIX(arg.write_pair[0]));
7651 rb_execarg_addopt(execarg_obj, INT2FIX(1), INT2FIX(arg.pair[1]));
7652 }
7653 break;
7654 case FMODE_READABLE:
7655 if (rb_pipe(arg.pair) < 0)
7656 rb_sys_fail_str(prog);
7657 if (eargp)
7658 rb_execarg_addopt(execarg_obj, INT2FIX(1), INT2FIX(arg.pair[1]));
7659 break;
7660 case FMODE_WRITABLE:
7661 if (rb_pipe(arg.pair) < 0)
7662 rb_sys_fail_str(prog);
7663 if (eargp)
7664 rb_execarg_addopt(execarg_obj, INT2FIX(0), INT2FIX(arg.pair[0]));
7665 break;
7666 default:
7667 rb_sys_fail_str(prog);
7668 }
7669 if (!NIL_P(execarg_obj)) {
7670 rb_protect(rb_execarg_fixup_v, execarg_obj, &state);
7671 if (state) {
7672 if (0 <= arg.write_pair[0]) close(arg.write_pair[0]);
7673 if (0 <= arg.write_pair[1]) close(arg.write_pair[1]);
7674 if (0 <= arg.pair[0]) close(arg.pair[0]);
7675 if (0 <= arg.pair[1]) close(arg.pair[1]);
7676 rb_execarg_parent_end(execarg_obj);
7677 rb_jump_tag(state);
7678 }
7679
7680# if defined(HAVE_WORKING_FORK)
7681 pid = rb_fork_async_signal_safe(&status, popen_exec, &arg, arg.eargp->redirect_fds, errmsg, sizeof(errmsg));
7682# else
7683 rb_execarg_run_options(eargp, sargp, NULL, 0);
7684# if defined(HAVE_SPAWNVE)
7685 if (eargp->envp_str) envp = (char **)RSTRING_PTR(eargp->envp_str);
7686# endif
7687 while ((pid = DO_SPAWN(cmd, args, envp)) < 0) {
7688 /* exec failed */
7689 switch (e = errno) {
7690 case EAGAIN:
7691# if EWOULDBLOCK != EAGAIN
7692 case EWOULDBLOCK:
7693# endif
7694 rb_thread_sleep(1);
7695 continue;
7696 }
7697 break;
7698 }
7699 if (eargp)
7700 rb_execarg_run_options(sargp, NULL, NULL, 0);
7701# endif
7702 rb_execarg_parent_end(execarg_obj);
7703 }
7704 else {
7705# if defined(HAVE_WORKING_FORK)
7706 pid = rb_call_proc__fork();
7707 if (pid == 0) { /* child */
7708 popen_redirect(&arg);
7709 rb_io_synchronized(RFILE(orig_stdout)->fptr);
7710 rb_io_synchronized(RFILE(orig_stderr)->fptr);
7711 return Qnil;
7712 }
7713# else
7715# endif
7716 }
7717
7718 /* parent */
7719 if (pid < 0) {
7720# if defined(HAVE_WORKING_FORK)
7721 e = errno;
7722# endif
7723 close(arg.pair[0]);
7724 close(arg.pair[1]);
7726 close(arg.write_pair[0]);
7727 close(arg.write_pair[1]);
7728 }
7729# if defined(HAVE_WORKING_FORK)
7730 if (errmsg[0])
7731 rb_syserr_fail(e, errmsg);
7732# endif
7733 rb_syserr_fail_str(e, prog);
7734 }
7735 if ((fmode & FMODE_READABLE) && (fmode & FMODE_WRITABLE)) {
7736 close(arg.pair[1]);
7737 fd = arg.pair[0];
7738 close(arg.write_pair[0]);
7739 write_fd = arg.write_pair[1];
7740 }
7741 else if (fmode & FMODE_READABLE) {
7742 close(arg.pair[1]);
7743 fd = arg.pair[0];
7744 }
7745 else {
7746 close(arg.pair[0]);
7747 fd = arg.pair[1];
7748 }
7749#else
7750 cmd = rb_execarg_commandline(eargp, &prog);
7751 if (!NIL_P(execarg_obj)) {
7752 rb_execarg_parent_start(execarg_obj);
7753 rb_execarg_run_options(eargp, sargp, NULL, 0);
7754 }
7755 fp = popen(cmd, modestr);
7756 e = errno;
7757 if (eargp) {
7758 rb_execarg_parent_end(execarg_obj);
7759 rb_execarg_run_options(sargp, NULL, NULL, 0);
7760 }
7761 if (!fp) rb_syserr_fail_path(e, prog);
7762 fd = fileno(fp);
7763#endif
7764
7765 port = io_alloc(rb_cIO);
7766 MakeOpenFile(port, fptr);
7767 fptr->fd = fd;
7768 fptr->stdio_file = fp;
7769 fptr->mode = fmode | FMODE_SYNC|FMODE_DUPLEX;
7770 if (convconfig) {
7771 fptr->encs = *convconfig;
7772#if RUBY_CRLF_ENVIRONMENT
7775 }
7776#endif
7777 }
7778 else {
7779 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
7781 }
7782#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7783 if (NEED_NEWLINE_DECORATOR_ON_WRITE(fptr)) {
7784 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
7785 }
7786#endif
7787 }
7788 fptr->pid = pid;
7789
7790 if (0 <= write_fd) {
7791 write_port = io_alloc(rb_cIO);
7792 MakeOpenFile(write_port, write_fptr);
7793 write_fptr->fd = write_fd;
7794 write_fptr->mode = (fmode & ~FMODE_READABLE)| FMODE_SYNC|FMODE_DUPLEX;
7795 fptr->mode &= ~FMODE_WRITABLE;
7796 fptr->tied_io_for_writing = write_port;
7797 rb_ivar_set(port, rb_intern("@tied_io_for_writing"), write_port);
7798 }
7799
7800#if defined (__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7801 fptr->finalize = pipe_finalize;
7802 pipe_add_fptr(fptr);
7803#endif
7804 return port;
7805}
7806#else
7807static VALUE
7808pipe_open(VALUE execarg_obj, const char *modestr, enum rb_io_mode fmode,
7809 const struct rb_io_encoding *convconfig)
7810{
7811 rb_raise(rb_eNotImpError, "popen() is not available");
7812}
7813#endif
7814
7815static int
7816is_popen_fork(VALUE prog)
7817{
7818 if (RSTRING_LEN(prog) == 1 && RSTRING_PTR(prog)[0] == '-') {
7819#if !defined(HAVE_WORKING_FORK)
7820 rb_raise(rb_eNotImpError,
7821 "fork() function is unimplemented on this machine");
7822#else
7823 return TRUE;
7824#endif
7825 }
7826 return FALSE;
7827}
7828
7829static VALUE
7830pipe_open_s(VALUE prog, const char *modestr, enum rb_io_mode fmode,
7831 const struct rb_io_encoding *convconfig)
7832{
7833 int argc = 1;
7834 VALUE *argv = &prog;
7835 VALUE execarg_obj = Qnil;
7836
7837 if (!is_popen_fork(prog))
7838 execarg_obj = rb_execarg_new(argc, argv, TRUE, FALSE);
7839 return pipe_open(execarg_obj, modestr, fmode, convconfig);
7840}
7841
7842static VALUE
7843pipe_close(VALUE io)
7844{
7845 rb_io_t *fptr = io_close_fptr(io);
7846 if (fptr) {
7847 fptr_waitpid(fptr, rb_thread_to_be_killed(rb_thread_current()));
7848 }
7849 return Qnil;
7850}
7851
7852static VALUE popen_finish(VALUE port, VALUE klass);
7853
7854/*
7855 * call-seq:
7856 * IO.popen(env = {}, cmd, mode = 'r', **opts) -> io
7857 * IO.popen(env = {}, cmd, mode = 'r', **opts) {|io| ... } -> object
7858 *
7859 * Executes the given command +cmd+ as a subprocess
7860 * whose $stdin and $stdout are connected to a new stream +io+.
7861 *
7862 * This method has potential security vulnerabilities if called with untrusted input;
7863 * see {Command Injection}[rdoc-ref:security/command_injection.rdoc].
7864 *
7865 * If no block is given, returns the new stream,
7866 * which depending on given +mode+ may be open for reading, writing, or both.
7867 * The stream should be explicitly closed (eventually) to avoid resource leaks.
7868 *
7869 * If a block is given, the stream is passed to the block
7870 * (again, open for reading, writing, or both);
7871 * when the block exits, the stream is closed,
7872 * the block's value is returned,
7873 * and the global variable <tt>$?</tt> is set to the child's exit status.
7874 *
7875 * Optional argument +mode+ may be any valid \IO mode.
7876 * See {Access Modes}[rdoc-ref:File@Access+Modes].
7877 *
7878 * Required argument +cmd+ determines which of the following occurs:
7879 *
7880 * - The process forks.
7881 * - A specified program runs in a shell.
7882 * - A specified program runs with specified arguments.
7883 * - A specified program runs with specified arguments and a specified +argv0+.
7884 *
7885 * Each of these is detailed below.
7886 *
7887 * The optional hash argument +env+ specifies name/value pairs that are to be added
7888 * to the environment variables for the subprocess:
7889 *
7890 * IO.popen({'FOO' => 'bar'}, 'ruby', 'r+') do |pipe|
7891 * pipe.puts 'puts ENV["FOO"]'
7892 * pipe.close_write
7893 * pipe.gets
7894 * end => "bar\n"
7895 *
7896 * Optional keyword arguments +opts+ specify:
7897 *
7898 * - {Open options}[rdoc-ref:IO@Open+Options].
7899 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
7900 * - Options for Kernel#spawn.
7901 *
7902 * <b>Forked Process</b>
7903 *
7904 * When argument +cmd+ is the 1-character string <tt>'-'</tt>, causes the process to fork:
7905 * IO.popen('-') do |pipe|
7906 * if pipe
7907 * $stderr.puts "In parent, child pid is #{pipe.pid}\n"
7908 * else
7909 * $stderr.puts "In child, pid is #{$$}\n"
7910 * end
7911 * end
7912 *
7913 * Output:
7914 *
7915 * In parent, child pid is 26253
7916 * In child, pid is 26253
7917 *
7918 * Note that this is not supported on all platforms.
7919 *
7920 * <b>Shell Subprocess</b>
7921 *
7922 * When argument +cmd+ is a single string (but not <tt>'-'</tt>),
7923 * the program named +cmd+ is run as a shell command:
7924 *
7925 * IO.popen('uname') do |pipe|
7926 * pipe.readlines
7927 * end
7928 *
7929 * Output:
7930 *
7931 * ["Linux\n"]
7932 *
7933 * Another example:
7934 *
7935 * IO.popen('/bin/sh', 'r+') do |pipe|
7936 * pipe.puts('ls')
7937 * pipe.close_write
7938 * $stderr.puts pipe.readlines.size
7939 * end
7940 *
7941 * Output:
7942 *
7943 * 213
7944 *
7945 * <b>Program Subprocess</b>
7946 *
7947 * When argument +cmd+ is an array of strings,
7948 * the program named <tt>cmd[0]</tt> is run with all elements of +cmd+ as its arguments:
7949 *
7950 * IO.popen(['du', '..', '.']) do |pipe|
7951 * $stderr.puts pipe.readlines.size
7952 * end
7953 *
7954 * Output:
7955 *
7956 * 1111
7957 *
7958 * <b>Program Subprocess with <tt>argv0</tt></b>
7959 *
7960 * When argument +cmd+ is an array whose first element is a 2-element string array
7961 * and whose remaining elements (if any) are strings:
7962 *
7963 * - <tt>cmd[0][0]</tt> (the first string in the nested array) is the name of a program that is run.
7964 * - <tt>cmd[0][1]</tt> (the second string in the nested array) is set as the program's <tt>argv[0]</tt>.
7965 * - <tt>cmd[1..-1]</tt> (the strings in the outer array) are the program's arguments.
7966 *
7967 * Example (sets <tt>$0</tt> to 'foo'):
7968 *
7969 * IO.popen([['/bin/sh', 'foo'], '-c', 'echo $0']).read # => "foo\n"
7970 *
7971 * <b>Some Special Examples</b>
7972 *
7973 * # Set IO encoding.
7974 * IO.popen("nkf -e filename", :external_encoding=>"EUC-JP") {|nkf_io|
7975 * euc_jp_string = nkf_io.read
7976 * }
7977 *
7978 * # Merge standard output and standard error using Kernel#spawn option. See Kernel#spawn.
7979 * IO.popen(["ls", "/", :err=>[:child, :out]]) do |io|
7980 * ls_result_with_error = io.read
7981 * end
7982 *
7983 * # Use mixture of spawn options and IO options.
7984 * IO.popen(["ls", "/"], :err=>[:child, :out]) do |io|
7985 * ls_result_with_error = io.read
7986 * end
7987 *
7988 * f = IO.popen("uname")
7989 * p f.readlines
7990 * f.close
7991 * puts "Parent is #{Process.pid}"
7992 * IO.popen("date") {|f| puts f.gets }
7993 * IO.popen("-") {|f| $stderr.puts "#{Process.pid} is here, f is #{f.inspect}"}
7994 * p $?
7995 * IO.popen(%w"sed -e s|^|<foo>| -e s&$&;zot;&", "r+") {|f|
7996 * f.puts "bar"; f.close_write; puts f.gets
7997 * }
7998 *
7999 * Output (from last section):
8000 *
8001 * ["Linux\n"]
8002 * Parent is 21346
8003 * Thu Jan 15 22:41:19 JST 2009
8004 * 21346 is here, f is #<IO:fd 3>
8005 * 21352 is here, f is nil
8006 * #<Process::Status: pid 21352 exit 0>
8007 * <foo>bar;zot;
8008 *
8009 * Raises exceptions that IO.pipe and Kernel.spawn raise.
8010 *
8011 */
8012
8013static VALUE
8014rb_io_s_popen(int argc, VALUE *argv, VALUE klass)
8015{
8016 VALUE pname, pmode = Qnil, opt = Qnil, env = Qnil;
8017
8018 if (argc > 1 && !NIL_P(opt = rb_check_hash_type(argv[argc-1]))) --argc;
8019 if (argc > 1 && !NIL_P(env = rb_check_hash_type(argv[0]))) --argc, ++argv;
8020 switch (argc) {
8021 case 2:
8022 pmode = argv[1];
8023 case 1:
8024 pname = argv[0];
8025 break;
8026 default:
8027 {
8028 int ex = !NIL_P(opt);
8029 rb_error_arity(argc + ex, 1 + ex, 2 + ex);
8030 }
8031 }
8032 return popen_finish(rb_io_popen(pname, pmode, env, opt), klass);
8033}
8034
8035VALUE
8036rb_io_popen(VALUE pname, VALUE pmode, VALUE env, VALUE opt)
8037{
8038 const char *modestr;
8039 VALUE tmp, execarg_obj = Qnil;
8040 int oflags;
8041 enum rb_io_mode fmode;
8042 struct rb_io_encoding convconfig;
8043
8044 tmp = rb_check_array_type(pname);
8045 if (!NIL_P(tmp)) {
8046 long len = RARRAY_LEN(tmp);
8047#if SIZEOF_LONG > SIZEOF_INT
8048 if (len > INT_MAX) {
8049 rb_raise(rb_eArgError, "too many arguments");
8050 }
8051#endif
8052 execarg_obj = rb_execarg_new((int)len, RARRAY_CONST_PTR(tmp), FALSE, FALSE);
8053 RB_GC_GUARD(tmp);
8054 }
8055 else {
8056 StringValue(pname);
8057 execarg_obj = Qnil;
8058 if (!is_popen_fork(pname))
8059 execarg_obj = rb_execarg_new(1, &pname, TRUE, FALSE);
8060 }
8061 if (!NIL_P(execarg_obj)) {
8062 if (!NIL_P(opt))
8063 opt = rb_execarg_extract_options(execarg_obj, opt);
8064 if (!NIL_P(env))
8065 rb_execarg_setenv(execarg_obj, env);
8066 }
8067 rb_io_extract_modeenc(&pmode, 0, opt, &oflags, &fmode, &convconfig);
8068 modestr = rb_io_oflags_modestr(oflags);
8069
8070 return pipe_open(execarg_obj, modestr, fmode, &convconfig);
8071}
8072
8073static VALUE
8074popen_finish(VALUE port, VALUE klass)
8075{
8076 if (NIL_P(port)) {
8077 /* child */
8078 if (rb_block_given_p()) {
8079 rb_protect(rb_yield, Qnil, NULL);
8080 rb_io_flush(rb_ractor_stdout());
8081 rb_io_flush(rb_ractor_stderr());
8082 _exit(0);
8083 }
8084 return Qnil;
8085 }
8086 RBASIC_SET_CLASS(port, klass);
8087 if (rb_block_given_p()) {
8088 return rb_ensure(rb_yield, port, pipe_close, port);
8089 }
8090 return port;
8091}
8092
8093#if defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)
8094struct popen_writer_arg {
8095 char *const *argv;
8096 struct popen_arg popen;
8097};
8098
8099static int
8100exec_popen_writer(void *arg, char *errmsg, size_t buflen)
8101{
8102 struct popen_writer_arg *pw = arg;
8103 pw->popen.modef = FMODE_WRITABLE;
8104 popen_redirect(&pw->popen);
8105 execv(pw->argv[0], pw->argv);
8106 strlcpy(errmsg, strerror(errno), buflen);
8107 return -1;
8108}
8109#endif
8110
8111FILE *
8112ruby_popen_writer(char *const *argv, rb_pid_t *pid)
8113{
8114#if (defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)) || defined(_WIN32)
8115# ifdef HAVE_WORKING_FORK
8116 struct popen_writer_arg pw;
8117 int *const write_pair = pw.popen.pair;
8118# else
8119 int write_pair[2];
8120# endif
8121
8122#ifdef HAVE_PIPE2
8123 int result = pipe2(write_pair, O_CLOEXEC);
8124#else
8125 int result = pipe(write_pair);
8126#endif
8127
8128 *pid = -1;
8129 if (result == 0) {
8130# ifdef HAVE_WORKING_FORK
8131 pw.argv = argv;
8132 int status;
8133 char errmsg[80] = {'\0'};
8134 *pid = rb_fork_async_signal_safe(&status, exec_popen_writer, &pw, Qnil, errmsg, sizeof(errmsg));
8135# else
8136 *pid = rb_w32_uspawn_process(P_NOWAIT, argv[0], argv, write_pair[0], -1, -1, 0);
8137 const char *errmsg = (*pid < 0) ? strerror(errno) : NULL;
8138# endif
8139 close(write_pair[0]);
8140 if (*pid < 0) {
8141 close(write_pair[1]);
8142 fprintf(stderr, "ruby_popen_writer(%s): %s\n", argv[0], errmsg);
8143 }
8144 else {
8145 return fdopen(write_pair[1], "w");
8146 }
8147 }
8148#endif
8149 return NULL;
8150}
8151
8152static VALUE
8153rb_open_file(VALUE io, VALUE fname, VALUE vmode, VALUE vperm, VALUE opt)
8154{
8155 int oflags;
8156 enum rb_io_mode fmode;
8157 struct rb_io_encoding convconfig;
8158 mode_t perm;
8159
8160 FilePathValue(fname);
8161
8162 rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, &convconfig);
8163 perm = NIL_P(vperm) ? 0666 : NUM2MODET(vperm);
8164
8165 rb_file_open_generic(io, fname, oflags, fmode, &convconfig, perm);
8166
8167 return io;
8168}
8169
8170/*
8171 * Document-method: File::open
8172 *
8173 * call-seq:
8174 * File.open(path, mode = 'r', perm = 0666, **opts) -> file
8175 * File.open(path, mode = 'r', perm = 0666, **opts) {|f| ... } -> object
8176 *
8177 * Creates a new File object, via File.new with the given arguments.
8178 *
8179 * With no block given, returns the File object.
8180 *
8181 * With a block given, calls the block with the File object
8182 * and returns the block's value.
8183 *
8184 */
8185
8186/*
8187 * Document-method: IO::open
8188 *
8189 * call-seq:
8190 * IO.open(fd, mode = 'r', **opts) -> io
8191 * IO.open(fd, mode = 'r', **opts) {|io| ... } -> object
8192 *
8193 * Creates a new \IO object, via IO.new with the given arguments.
8194 *
8195 * With no block given, returns the \IO object.
8196 *
8197 * With a block given, calls the block with the \IO object
8198 * and returns the block's value.
8199 *
8200 */
8201
8202static VALUE
8203rb_io_s_open(int argc, VALUE *argv, VALUE klass)
8204{
8206
8207 if (rb_block_given_p()) {
8208 return rb_ensure(rb_yield, io, io_close, io);
8209 }
8210
8211 return io;
8212}
8213
8214/*
8215 * call-seq:
8216 * IO.sysopen(path, mode = 'r', perm = 0666) -> integer
8217 *
8218 * Opens the file at the given path with the given mode and permissions;
8219 * returns the integer file descriptor.
8220 *
8221 * If the file is to be readable, it must exist;
8222 * if the file is to be writable and does not exist,
8223 * it is created with the given permissions:
8224 *
8225 * File.write('t.tmp', '') # => 0
8226 * IO.sysopen('t.tmp') # => 8
8227 * IO.sysopen('t.tmp', 'w') # => 9
8228 *
8229 *
8230 */
8231
8232static VALUE
8233rb_io_s_sysopen(int argc, VALUE *argv, VALUE _)
8234{
8235 VALUE fname, vmode, vperm;
8236 VALUE intmode;
8237 int oflags, fd;
8238 mode_t perm;
8239
8240 rb_scan_args(argc, argv, "12", &fname, &vmode, &vperm);
8241 FilePathValue(fname);
8242
8243 if (NIL_P(vmode))
8244 oflags = O_RDONLY;
8245 else if (!NIL_P(intmode = rb_check_to_integer(vmode, "to_int")))
8246 oflags = NUM2INT(intmode);
8247 else {
8248 StringValue(vmode);
8249 oflags = rb_io_modestr_oflags(StringValueCStr(vmode));
8250 }
8251 if (NIL_P(vperm)) perm = 0666;
8252 else perm = NUM2MODET(vperm);
8253
8254 RB_GC_GUARD(fname) = rb_str_new4(fname);
8255 fd = rb_sysopen(fname, oflags, perm);
8256 return INT2NUM(fd);
8257}
8258
8259/*
8260 * call-seq:
8261 * open(path, mode = 'r', perm = 0666, **opts) -> io or nil
8262 * open(path, mode = 'r', perm = 0666, **opts) {|io| ... } -> obj
8263 *
8264 * Creates an IO object connected to the given file.
8265 *
8266 * With no block given, file stream is returned:
8267 *
8268 * open('t.txt') # => #<File:t.txt>
8269 *
8270 * With a block given, calls the block with the open file stream,
8271 * then closes the stream:
8272 *
8273 * open('t.txt') {|f| p f } # => #<File:t.txt (closed)>
8274 *
8275 * Output:
8276 *
8277 * #<File:t.txt>
8278 *
8279 * See File.open for details.
8280 *
8281 */
8282
8283static VALUE
8284rb_f_open(int argc, VALUE *argv, VALUE _)
8285{
8286 ID to_open = 0;
8287 int redirect = FALSE;
8288
8289 if (argc >= 1) {
8290 CONST_ID(to_open, "to_open");
8291 if (rb_respond_to(argv[0], to_open)) {
8292 redirect = TRUE;
8293 }
8294 else {
8295 VALUE tmp = argv[0];
8296 FilePathValue(tmp);
8297 if (NIL_P(tmp)) {
8298 redirect = TRUE;
8299 }
8300 else {
8301 argv[0] = tmp;
8302 }
8303 }
8304 }
8305 if (redirect) {
8306 VALUE io = rb_funcallv_kw(argv[0], to_open, argc-1, argv+1, RB_PASS_CALLED_KEYWORDS);
8307
8308 if (rb_block_given_p()) {
8309 return rb_ensure(rb_yield, io, io_close, io);
8310 }
8311 return io;
8312 }
8313 return rb_io_s_open(argc, argv, rb_cFile);
8314}
8315
8316static VALUE
8317rb_io_open_generic(VALUE klass, VALUE filename, int oflags, enum rb_io_mode fmode,
8318 const struct rb_io_encoding *convconfig, mode_t perm)
8319{
8320 return rb_file_open_generic(io_alloc(klass), filename,
8321 oflags, fmode, convconfig, perm);
8322}
8323
8324static VALUE
8325rb_io_open(VALUE io, VALUE filename, VALUE vmode, VALUE vperm, VALUE opt)
8326{
8327 int oflags;
8328 enum rb_io_mode fmode;
8329 struct rb_io_encoding convconfig;
8330 mode_t perm;
8331
8332 rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, &convconfig);
8333 perm = NIL_P(vperm) ? 0666 : NUM2MODET(vperm);
8334 return rb_io_open_generic(io, filename, oflags, fmode, &convconfig, perm);
8335}
8336
8337static VALUE
8338io_reopen(VALUE io, VALUE nfile)
8339{
8340 rb_io_t *fptr, *orig;
8341 int fd, fd2;
8342 rb_off_t pos = 0;
8343
8344 nfile = rb_io_get_io(nfile);
8345 GetOpenFile(io, fptr);
8346 GetOpenFile(nfile, orig);
8347
8348 if (fptr == orig) return io;
8349 if (RUBY_IO_EXTERNAL_P(fptr)) {
8350 if ((fptr->stdio_file == stdin && !(orig->mode & FMODE_READABLE)) ||
8351 (fptr->stdio_file == stdout && !(orig->mode & FMODE_WRITABLE)) ||
8352 (fptr->stdio_file == stderr && !(orig->mode & FMODE_WRITABLE))) {
8353 rb_raise(rb_eArgError,
8354 "%s can't change access mode from \"%s\" to \"%s\"",
8355 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->mode),
8356 rb_io_fmode_modestr(orig->mode));
8357 }
8358 }
8359 if (fptr->mode & FMODE_WRITABLE) {
8360 if (io_fflush(fptr) < 0)
8361 rb_sys_fail_on_write(fptr);
8362 }
8363 else {
8364 flush_before_seek(fptr, true);
8365 }
8366 if (orig->mode & FMODE_READABLE) {
8367 pos = io_tell(orig);
8368 }
8369 if (orig->mode & FMODE_WRITABLE) {
8370 if (io_fflush(orig) < 0)
8371 rb_sys_fail_on_write(fptr);
8372 }
8373
8374 /* copy rb_io_t structure */
8375 fptr->mode = orig->mode | (fptr->mode & FMODE_EXTERNAL);
8376 fptr->encs = orig->encs;
8377 fptr->pid = orig->pid;
8378 fptr->lineno = orig->lineno;
8379 if (RTEST(orig->pathv)) fptr->pathv = orig->pathv;
8380 else if (!RUBY_IO_EXTERNAL_P(fptr)) fptr->pathv = Qnil;
8381 fptr_copy_finalizer(fptr, orig);
8382
8383 fd = fptr->fd;
8384 fd2 = orig->fd;
8385 if (fd != fd2) {
8386 // Interrupt all usage of the old file descriptor:
8387 rb_thread_io_close_interrupt(fptr);
8388 rb_thread_io_close_wait(fptr);
8389
8390 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2 || !fptr->stdio_file) {
8391 /* need to keep FILE objects of stdin, stdout and stderr */
8392 if (rb_cloexec_dup2(fd2, fd) < 0)
8393 rb_sys_fail_path(orig->pathv);
8394 rb_update_max_fd(fd);
8395 }
8396 else {
8397 fclose(fptr->stdio_file);
8398 fptr->stdio_file = 0;
8399 fptr->fd = -1;
8400 if (rb_cloexec_dup2(fd2, fd) < 0)
8401 rb_sys_fail_path(orig->pathv);
8402 rb_update_max_fd(fd);
8403 fptr->fd = fd;
8404 }
8405
8406 if ((orig->mode & FMODE_READABLE) && pos >= 0) {
8407 if (io_seek(fptr, pos, SEEK_SET) < 0 && errno) {
8408 rb_sys_fail_path(fptr->pathv);
8409 }
8410 if (io_seek(orig, pos, SEEK_SET) < 0 && errno) {
8411 rb_sys_fail_path(orig->pathv);
8412 }
8413 }
8414 }
8415
8416 if (fptr->mode & FMODE_BINMODE) {
8417 rb_io_binmode(io);
8418 }
8419
8420 RBASIC_SET_CLASS(io, rb_obj_class(nfile));
8421 return io;
8422}
8423
8424#ifdef _WIN32
8425int rb_freopen(VALUE fname, const char *mode, FILE *fp);
8426#else
8427static int
8428rb_freopen(VALUE fname, const char *mode, FILE *fp)
8429{
8430 if (!freopen(RSTRING_PTR(fname), mode, fp)) {
8431 RB_GC_GUARD(fname);
8432 return errno;
8433 }
8434 return 0;
8435}
8436#endif
8437
8438/*
8439 * call-seq:
8440 * reopen(other_io) -> self
8441 * reopen(path, mode = 'r', **opts) -> self
8442 *
8443 * Reassociates the stream with another stream,
8444 * which may be of a different class.
8445 * This method may be used to redirect an existing stream
8446 * to a new destination.
8447 *
8448 * With argument +other_io+ given, reassociates with that stream:
8449 *
8450 * # Redirect $stdin from a file.
8451 * f = File.open('t.txt')
8452 * $stdin.reopen(f)
8453 * f.close
8454 *
8455 * # Redirect $stdout to a file.
8456 * f = File.open('t.tmp', 'w')
8457 * $stdout.reopen(f)
8458 * f.close
8459 *
8460 * With argument +path+ given, reassociates with a new stream to that file path:
8461 *
8462 * $stdin.reopen('t.txt')
8463 * $stdout.reopen('t.tmp', 'w')
8464 *
8465 * Optional keyword arguments +opts+ specify:
8466 *
8467 * - {Open Options}[rdoc-ref:IO@Open+Options].
8468 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
8469 *
8470 */
8471
8472static VALUE
8473rb_io_reopen(int argc, VALUE *argv, VALUE file)
8474{
8475 VALUE fname, nmode, opt;
8476 int oflags;
8477 rb_io_t *fptr;
8478
8479 if (rb_scan_args(argc, argv, "11:", &fname, &nmode, &opt) == 1) {
8480 VALUE tmp = rb_io_check_io(fname);
8481 if (!NIL_P(tmp)) {
8482 return io_reopen(file, tmp);
8483 }
8484 }
8485
8486 FilePathValue(fname);
8487 rb_io_taint_check(file);
8488 fptr = RFILE(file)->fptr;
8489 if (!fptr) {
8490 fptr = RFILE(file)->fptr = ZALLOC(rb_io_t);
8491 }
8492
8493 if (!NIL_P(nmode) || !NIL_P(opt)) {
8494 enum rb_io_mode fmode;
8495 struct rb_io_encoding convconfig;
8496
8497 rb_io_extract_modeenc(&nmode, 0, opt, &oflags, &fmode, &convconfig);
8498 if (RUBY_IO_EXTERNAL_P(fptr) &&
8499 ((fptr->mode & FMODE_READWRITE) & (fmode & FMODE_READWRITE)) !=
8500 (fptr->mode & FMODE_READWRITE)) {
8501 rb_raise(rb_eArgError,
8502 "%s can't change access mode from \"%s\" to \"%s\"",
8503 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->mode),
8504 rb_io_fmode_modestr(fmode));
8505 }
8506 fptr->mode = fmode;
8507 fptr->encs = convconfig;
8508 }
8509 else {
8510 oflags = rb_io_fmode_oflags(fptr->mode);
8511 }
8512
8513 fptr->pathv = fname;
8514 if (fptr->fd < 0) {
8515 fptr->fd = rb_sysopen(fptr->pathv, oflags, 0666);
8516 fptr->stdio_file = 0;
8517 return file;
8518 }
8519
8520 if (fptr->mode & FMODE_WRITABLE) {
8521 if (io_fflush(fptr) < 0)
8522 rb_sys_fail_on_write(fptr);
8523 }
8524 fptr->rbuf.off = fptr->rbuf.len = 0;
8525
8526 if (fptr->stdio_file) {
8527 int e = rb_freopen(rb_str_encode_ospath(fptr->pathv),
8528 rb_io_oflags_modestr(oflags),
8529 fptr->stdio_file);
8530 if (e) rb_syserr_fail_path(e, fptr->pathv);
8531 fptr->fd = fileno(fptr->stdio_file);
8532 rb_fd_fix_cloexec(fptr->fd);
8533#ifdef USE_SETVBUF
8534 if (setvbuf(fptr->stdio_file, NULL, _IOFBF, 0) != 0)
8535 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8536#endif
8537 if (fptr->stdio_file == stderr) {
8538 if (setvbuf(fptr->stdio_file, NULL, _IONBF, BUFSIZ) != 0)
8539 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8540 }
8541 else if (fptr->stdio_file == stdout && isatty(fptr->fd)) {
8542 if (setvbuf(fptr->stdio_file, NULL, _IOLBF, BUFSIZ) != 0)
8543 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8544 }
8545 }
8546 else {
8547 int tmpfd = rb_sysopen(fptr->pathv, oflags, 0666);
8548 int err = 0;
8549 if (rb_cloexec_dup2(tmpfd, fptr->fd) < 0)
8550 err = errno;
8551 (void)close(tmpfd);
8552 if (err) {
8553 rb_syserr_fail_path(err, fptr->pathv);
8554 }
8555 }
8556
8557 return file;
8558}
8559
8560/* :nodoc: */
8561static VALUE
8562rb_io_init_copy(VALUE dest, VALUE io)
8563{
8564 rb_io_t *fptr, *orig;
8565 int fd;
8566 VALUE write_io;
8567 rb_off_t pos;
8568
8569 io = rb_io_get_io(io);
8570 if (!OBJ_INIT_COPY(dest, io)) return dest;
8571 GetOpenFile(io, orig);
8572 MakeOpenFile(dest, fptr);
8573
8574 rb_io_flush(io);
8575
8576 /* copy rb_io_t structure */
8577 fptr->mode = orig->mode & ~FMODE_EXTERNAL;
8578 fptr->encs = orig->encs;
8579 fptr->pid = orig->pid;
8580 fptr->lineno = orig->lineno;
8581 fptr->timeout = orig->timeout;
8582
8583 ccan_list_head_init(&fptr->blocking_operations);
8584 fptr->closing_ec = NULL;
8585 fptr->wakeup_mutex = Qnil;
8586 fptr->fork_generation = GET_VM()->fork_gen;
8587
8588 if (!NIL_P(orig->pathv)) fptr->pathv = orig->pathv;
8589 fptr_copy_finalizer(fptr, orig);
8590
8591 fd = ruby_dup(orig->fd);
8592 fptr->fd = fd;
8593 pos = io_tell(orig);
8594 if (0 <= pos)
8595 io_seek(fptr, pos, SEEK_SET);
8596 if (fptr->mode & FMODE_BINMODE) {
8597 rb_io_binmode(dest);
8598 }
8599
8600 write_io = GetWriteIO(io);
8601 if (io != write_io) {
8602 write_io = rb_obj_dup(write_io);
8603 fptr->tied_io_for_writing = write_io;
8604 rb_ivar_set(dest, rb_intern("@tied_io_for_writing"), write_io);
8605 }
8606
8607 return dest;
8608}
8609
8610/*
8611 * call-seq:
8612 * printf(format_string, *objects) -> nil
8613 *
8614 * Formats and writes +objects+ to the stream.
8615 *
8616 * For details on +format_string+, see
8617 * {Format Specifications}[rdoc-ref:language/format_specifications.rdoc].
8618 *
8619 */
8620
8621VALUE
8622rb_io_printf(int argc, const VALUE *argv, VALUE out)
8623{
8624 rb_io_write(out, rb_f_sprintf(argc, argv));
8625 return Qnil;
8626}
8627
8628/*
8629 * call-seq:
8630 * printf(format_string, *objects) -> nil
8631 * printf(io, format_string, *objects) -> nil
8632 *
8633 * Equivalent to:
8634 *
8635 * io.write(sprintf(format_string, *objects))
8636 *
8637 * For details on +format_string+, see
8638 * {Format Specifications}[rdoc-ref:language/format_specifications.rdoc].
8639 *
8640 * With the single argument +format_string+, formats +objects+ into the string,
8641 * then writes the formatted string to $stdout:
8642 *
8643 * printf('%4.4d %10s %2.2f', 24, 24, 24.0)
8644 *
8645 * Output (on $stdout):
8646 *
8647 * 0024 24 24.00#
8648 *
8649 * With arguments +io+ and +format_string+, formats +objects+ into the string,
8650 * then writes the formatted string to +io+:
8651 *
8652 * printf($stderr, '%4.4d %10s %2.2f', 24, 24, 24.0)
8653 *
8654 * Output (on $stderr):
8655 *
8656 * 0024 24 24.00# => nil
8657 *
8658 * With no arguments, does nothing.
8659 *
8660 */
8661
8662static VALUE
8663rb_f_printf(int argc, VALUE *argv, VALUE _)
8664{
8665 VALUE out;
8666
8667 if (argc == 0) return Qnil;
8668 if (RB_TYPE_P(argv[0], T_STRING)) {
8669 out = rb_ractor_stdout();
8670 }
8671 else {
8672 out = argv[0];
8673 argv++;
8674 argc--;
8675 }
8676 rb_io_write(out, rb_f_sprintf(argc, argv));
8677
8678 return Qnil;
8679}
8680
8681extern void rb_deprecated_str_setter(VALUE val, ID id, VALUE *var);
8682
8683static void
8684deprecated_rs_setter(VALUE val, ID id, VALUE *var)
8685{
8686 rb_deprecated_str_setter(val, id, &val);
8687 if (!NIL_P(val)) {
8688 if (rb_str_equal(val, rb_default_rs)) {
8689 val = rb_default_rs;
8690 }
8691 else {
8692 val = rb_str_frozen_bare_string(val);
8693 }
8694 }
8695 *var = val;
8696}
8697
8698/*
8699 * call-seq:
8700 * print(*objects) -> nil
8701 *
8702 * Writes the given objects to the stream; returns +nil+.
8703 * Appends the output record separator <tt>$OUTPUT_RECORD_SEPARATOR</tt>
8704 * (<tt>$\</tt>), if it is not +nil+.
8705 * See {Line IO}[rdoc-ref:IO@Line+IO].
8706 *
8707 * With argument +objects+ given, for each object:
8708 *
8709 * - Converts via its method +to_s+ if not a string.
8710 * - Writes to the stream.
8711 * - If not the last object, writes the output field separator
8712 * <tt>$OUTPUT_FIELD_SEPARATOR</tt> (<tt>$,</tt>) if it is not +nil+.
8713 *
8714 * With default separators:
8715 *
8716 * f = File.open('t.tmp', 'w+')
8717 * objects = [0, 0.0, Rational(0, 1), Complex(0, 0), :zero, 'zero']
8718 * p $OUTPUT_RECORD_SEPARATOR
8719 * p $OUTPUT_FIELD_SEPARATOR
8720 * f.print(*objects)
8721 * f.rewind
8722 * p f.read
8723 * f.close
8724 *
8725 * Output:
8726 *
8727 * nil
8728 * nil
8729 * "00.00/10+0izerozero"
8730 *
8731 * With specified separators:
8732 *
8733 * $\ = "\n"
8734 * $, = ','
8735 * f.rewind
8736 * f.print(*objects)
8737 * f.rewind
8738 * p f.read
8739 *
8740 * Output:
8741 *
8742 * "0,0.0,0/1,0+0i,zero,zero\n"
8743 *
8744 * With no argument given, writes the content of <tt>$_</tt>
8745 * (which is usually the most recent user input):
8746 *
8747 * f = File.open('t.tmp', 'w+')
8748 * gets # Sets $_ to the most recent user input.
8749 * f.print
8750 * f.close
8751 *
8752 */
8753
8754VALUE
8755rb_io_print(int argc, const VALUE *argv, VALUE out)
8756{
8757 int i;
8758 VALUE line;
8759
8760 /* if no argument given, print `$_' */
8761 if (argc == 0) {
8762 argc = 1;
8763 line = rb_lastline_get();
8764 argv = &line;
8765 }
8766 if (argc > 1 && !NIL_P(rb_output_fs)) {
8767 rb_category_warn(RB_WARN_CATEGORY_DEPRECATED, "$, is set to non-nil value");
8768 }
8769 for (i=0; i<argc; i++) {
8770 if (!NIL_P(rb_output_fs) && i>0) {
8771 rb_io_write(out, rb_output_fs);
8772 }
8773 rb_io_write(out, argv[i]);
8774 }
8775 if (argc > 0 && !NIL_P(rb_output_rs)) {
8776 rb_io_write(out, rb_output_rs);
8777 }
8778
8779 return Qnil;
8780}
8781
8782/*
8783 * call-seq:
8784 * print(*objects) -> nil
8785 *
8786 * Equivalent to <tt>$stdout.print(*objects)</tt>,
8787 * this method is the straightforward way to write to <tt>$stdout</tt>.
8788 *
8789 * Writes the given objects to <tt>$stdout</tt>; returns +nil+.
8790 * Appends the output record separator <tt>$OUTPUT_RECORD_SEPARATOR</tt>
8791 * <tt>$\</tt>), if it is not +nil+.
8792 *
8793 * With argument +objects+ given, for each object:
8794 *
8795 * - Converts via its method +to_s+ if not a string.
8796 * - Writes to <tt>stdout</tt>.
8797 * - If not the last object, writes the output field separator
8798 * <tt>$OUTPUT_FIELD_SEPARATOR</tt> (<tt>$,</tt> if it is not +nil+.
8799 *
8800 * With default separators:
8801 *
8802 * objects = [0, 0.0, Rational(0, 1), Complex(0, 0), :zero, 'zero']
8803 * $OUTPUT_RECORD_SEPARATOR
8804 * $OUTPUT_FIELD_SEPARATOR
8805 * print(*objects)
8806 *
8807 * Output:
8808 *
8809 * nil
8810 * nil
8811 * 00.00/10+0izerozero
8812 *
8813 * With specified separators:
8814 *
8815 * $OUTPUT_RECORD_SEPARATOR = "\n"
8816 * $OUTPUT_FIELD_SEPARATOR = ','
8817 * print(*objects)
8818 *
8819 * Output:
8820 *
8821 * 0,0.0,0/1,0+0i,zero,zero
8822 *
8823 * With no argument given, writes the content of <tt>$_</tt>
8824 * (which is usually the most recent user input):
8825 *
8826 * gets # Sets $_ to the most recent user input.
8827 * print # Prints $_.
8828 *
8829 */
8830
8831static VALUE
8832rb_f_print(int argc, const VALUE *argv, VALUE _)
8833{
8834 rb_io_print(argc, argv, rb_ractor_stdout());
8835 return Qnil;
8836}
8837
8838/*
8839 * call-seq:
8840 * putc(object) -> object
8841 *
8842 * Writes a character to the stream.
8843 * See {Character IO}[rdoc-ref:IO@Character+IO].
8844 *
8845 * If +object+ is numeric, converts to integer if necessary,
8846 * then writes the character whose code is the
8847 * least significant byte;
8848 * if +object+ is a string, writes the first character:
8849 *
8850 * $stdout.putc "A"
8851 * $stdout.putc 65
8852 *
8853 * Output:
8854 *
8855 * AA
8856 *
8857 */
8858
8859static VALUE
8860rb_io_putc(VALUE io, VALUE ch)
8861{
8862 VALUE str;
8863 if (RB_TYPE_P(ch, T_STRING)) {
8864 str = rb_str_substr(ch, 0, 1);
8865 }
8866 else {
8867 char c = NUM2CHR(ch);
8868 str = rb_str_new(&c, 1);
8869 }
8870 rb_io_write(io, str);
8871 return ch;
8872}
8873
8874#define forward(obj, id, argc, argv) \
8875 rb_funcallv_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8876#define forward_public(obj, id, argc, argv) \
8877 rb_funcallv_public_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8878#define forward_current(id, argc, argv) \
8879 forward_public(ARGF.current_file, id, argc, argv)
8880
8881/*
8882 * call-seq:
8883 * putc(int) -> int
8884 *
8885 * Equivalent to:
8886 *
8887 * $stdout.putc(int)
8888 *
8889 * See IO#putc for important information regarding multi-byte characters.
8890 *
8891 */
8892
8893static VALUE
8894rb_f_putc(VALUE recv, VALUE ch)
8895{
8896 VALUE r_stdout = rb_ractor_stdout();
8897 if (recv == r_stdout) {
8898 return rb_io_putc(recv, ch);
8899 }
8900 return forward(r_stdout, rb_intern("putc"), 1, &ch);
8901}
8902
8903
8904int
8905rb_str_end_with_asciichar(VALUE str, int c)
8906{
8907 long len = RSTRING_LEN(str);
8908 const char *ptr = RSTRING_PTR(str);
8909 rb_encoding *enc = rb_enc_from_index(ENCODING_GET(str));
8910 int n;
8911
8912 if (len == 0) return 0;
8913 if ((n = rb_enc_mbminlen(enc)) == 1) {
8914 return ptr[len - 1] == c;
8915 }
8916 return rb_enc_ascget(ptr + ((len - 1) / n) * n, ptr + len, &n, enc) == c;
8917}
8918
8919static VALUE
8920io_puts_ary(VALUE ary, VALUE out, int recur)
8921{
8922 VALUE tmp;
8923 long i;
8924
8925 if (recur) {
8926 tmp = rb_str_new2("[...]");
8927 rb_io_puts(1, &tmp, out);
8928 return Qtrue;
8929 }
8930 ary = rb_check_array_type(ary);
8931 if (NIL_P(ary)) return Qfalse;
8932 for (i=0; i<RARRAY_LEN(ary); i++) {
8933 tmp = RARRAY_AREF(ary, i);
8934 rb_io_puts(1, &tmp, out);
8935 }
8936 return Qtrue;
8937}
8938
8939/*
8940 * call-seq:
8941 * puts(*objects) -> nil
8942 *
8943 * Writes the given +objects+ to the stream, which must be open for writing;
8944 * returns +nil+.\
8945 * Writes a newline after each that does not already end with a newline sequence.
8946 * If called without arguments, writes a newline.
8947 * See {Line IO}[rdoc-ref:IO@Line+IO].
8948 *
8949 * Note that each added newline is the character <tt>"\n"<//tt>,
8950 * not the output record separator (<tt>$\</tt>).
8951 *
8952 * Treatment for each object:
8953 *
8954 * - String: writes the string.
8955 * - Neither string nor array: writes <tt>object.to_s</tt>.
8956 * - Array: writes each element of the array; arrays may be nested.
8957 *
8958 * To keep these examples brief, we define this helper method:
8959 *
8960 * def show(*objects)
8961 * # Puts objects to file.
8962 * f = File.new('t.tmp', 'w+')
8963 * f.puts(objects)
8964 * # Return file content.
8965 * f.rewind
8966 * p f.read
8967 * f.close
8968 * end
8969 *
8970 * # Strings without newlines.
8971 * show('foo', 'bar', 'baz') # => "foo\nbar\nbaz\n"
8972 * # Strings, some with newlines.
8973 * show("foo\n", 'bar', "baz\n") # => "foo\nbar\nbaz\n"
8974 *
8975 * # Neither strings nor arrays:
8976 * show(0, 0.0, Rational(0, 1), Complex(9, 0), :zero)
8977 * # => "0\n0.0\n0/1\n9+0i\nzero\n"
8978 *
8979 * # Array of strings.
8980 * show(['foo', "bar\n", 'baz']) # => "foo\nbar\nbaz\n"
8981 * # Nested arrays.
8982 * show([[[0, 1], 2, 3], 4, 5]) # => "0\n1\n2\n3\n4\n5\n"
8983 *
8984 */
8985
8986VALUE
8987rb_io_puts(int argc, const VALUE *argv, VALUE out)
8988{
8989 VALUE line, args[2];
8990
8991 /* if no argument given, print newline. */
8992 if (argc == 0) {
8993 rb_io_write(out, rb_default_rs);
8994 return Qnil;
8995 }
8996 for (int i = 0; i < argc; i++) {
8997 // Convert the argument to a string:
8998 if (RB_TYPE_P(argv[i], T_STRING)) {
8999 line = argv[i];
9000 }
9001 else if (rb_exec_recursive(io_puts_ary, argv[i], out)) {
9002 continue;
9003 }
9004 else {
9005 line = rb_obj_as_string(argv[i]);
9006 }
9007
9008 // Write the line:
9009 int n = 0;
9010 if (RSTRING_LEN(line) == 0) {
9011 args[n++] = rb_default_rs;
9012 }
9013 else {
9014 args[n++] = line;
9015 if (!rb_str_end_with_asciichar(line, '\n')) {
9016 args[n++] = rb_default_rs;
9017 }
9018 }
9019
9020 rb_io_writev(out, n, args);
9021 }
9022
9023 return Qnil;
9024}
9025
9026/*
9027 * call-seq:
9028 * puts(*objects) -> nil
9029 *
9030 * Equivalent to
9031 *
9032 * $stdout.puts(objects)
9033 */
9034
9035static VALUE
9036rb_f_puts(int argc, VALUE *argv, VALUE recv)
9037{
9038 VALUE r_stdout = rb_ractor_stdout();
9039 if (recv == r_stdout) {
9040 return rb_io_puts(argc, argv, recv);
9041 }
9042 return forward(r_stdout, rb_intern("puts"), argc, argv);
9043}
9044
9045static VALUE
9046rb_p_write(VALUE str)
9047{
9048 VALUE args[2];
9049 args[0] = str;
9050 args[1] = rb_default_rs;
9051 VALUE r_stdout = rb_ractor_stdout();
9052 if (RB_TYPE_P(r_stdout, T_FILE) &&
9053 rb_method_basic_definition_p(CLASS_OF(r_stdout), id_write)) {
9054 io_writev(2, args, r_stdout);
9055 }
9056 else {
9057 rb_io_writev(r_stdout, 2, args);
9058 }
9059 return Qnil;
9060}
9061
9062void
9063rb_p(VALUE obj) /* for debug print within C code */
9064{
9065 rb_p_write(rb_obj_as_string(rb_inspect(obj)));
9066}
9067
9068static VALUE
9069rb_p_result(int argc, const VALUE *argv)
9070{
9071 VALUE ret = Qnil;
9072
9073 if (argc == 1) {
9074 ret = argv[0];
9075 }
9076 else if (argc > 1) {
9077 ret = rb_ary_new4(argc, argv);
9078 }
9079 VALUE r_stdout = rb_ractor_stdout();
9080 if (RB_TYPE_P(r_stdout, T_FILE)) {
9081 rb_uninterruptible(rb_io_flush, r_stdout);
9082 }
9083 return ret;
9084}
9085
9086/*
9087 * call-seq:
9088 * p(object) -> obj
9089 * p(*objects) -> array of objects
9090 * p -> nil
9091 *
9092 * For each object +obj+, executes:
9093 *
9094 * $stdout.write(obj.inspect, "\n")
9095 *
9096 * With one object given, returns the object;
9097 * with multiple objects given, returns an array containing the objects;
9098 * with no object given, returns +nil+.
9099 *
9100 * Examples:
9101 *
9102 * r = Range.new(0, 4)
9103 * p r # => 0..4
9104 * p [r, r, r] # => [0..4, 0..4, 0..4]
9105 * p # => nil
9106 *
9107 * Output:
9108 *
9109 * 0..4
9110 * [0..4, 0..4, 0..4]
9111 *
9112 * Kernel#p is designed for debugging purposes.
9113 * Ruby implementations may define Kernel#p to be uninterruptible
9114 * in whole or in part.
9115 * On CRuby, Kernel#p's writing of data is uninterruptible.
9116 */
9117
9118static VALUE
9119rb_f_p(int argc, VALUE *argv, VALUE self)
9120{
9121 int i;
9122 for (i=0; i<argc; i++) {
9123 VALUE inspected = rb_obj_as_string(rb_inspect(argv[i]));
9124 rb_uninterruptible(rb_p_write, inspected);
9125 }
9126 return rb_p_result(argc, argv);
9127}
9128
9129/*
9130 * call-seq:
9131 * display(port = $>) -> nil
9132 *
9133 * Writes +self+ on the given port:
9134 *
9135 * 1.display
9136 * "cat".display
9137 * [ 4, 5, 6 ].display
9138 * puts
9139 *
9140 * Output:
9141 *
9142 * 1cat[4, 5, 6]
9143 *
9144 */
9145
9146static VALUE
9147rb_obj_display(int argc, VALUE *argv, VALUE self)
9148{
9149 VALUE out;
9150
9151 out = (!rb_check_arity(argc, 0, 1) ? rb_ractor_stdout() : argv[0]);
9152 rb_io_write(out, self);
9153
9154 return Qnil;
9155}
9156
9157static int
9158rb_stderr_to_original_p(VALUE err)
9159{
9160 return (err == orig_stderr || RFILE(orig_stderr)->fptr->fd < 0);
9161}
9162
9163void
9164rb_write_error2(const char *mesg, long len)
9165{
9166 VALUE out = rb_ractor_stderr();
9167 if (rb_stderr_to_original_p(out)) {
9168#ifdef _WIN32
9169 if (isatty(fileno(stderr))) {
9170 if (rb_w32_write_console(rb_str_new(mesg, len), fileno(stderr)) > 0) return;
9171 }
9172#endif
9173 if (fwrite(mesg, sizeof(char), (size_t)len, stderr) < (size_t)len) {
9174 /* failed to write to stderr, what can we do? */
9175 return;
9176 }
9177 }
9178 else {
9179 rb_io_write(out, rb_str_new(mesg, len));
9180 }
9181}
9182
9183void
9184rb_write_error(const char *mesg)
9185{
9186 rb_write_error2(mesg, strlen(mesg));
9187}
9188
9189void
9190rb_write_error_str(VALUE mesg)
9191{
9192 VALUE out = rb_ractor_stderr();
9193 /* a stopgap measure for the time being */
9194 if (rb_stderr_to_original_p(out)) {
9195 size_t len = (size_t)RSTRING_LEN(mesg);
9196#ifdef _WIN32
9197 if (isatty(fileno(stderr))) {
9198 if (rb_w32_write_console(mesg, fileno(stderr)) > 0) return;
9199 }
9200#endif
9201 if (fwrite(RSTRING_PTR(mesg), sizeof(char), len, stderr) < len) {
9202 RB_GC_GUARD(mesg);
9203 return;
9204 }
9205 }
9206 else {
9207 /* may unlock GVL, and */
9208 rb_io_write(out, mesg);
9209 }
9210}
9211
9212int
9213rb_stderr_tty_p(void)
9214{
9215 if (rb_stderr_to_original_p(rb_ractor_stderr()))
9216 return isatty(fileno(stderr));
9217 return 0;
9218}
9219
9220static void
9221must_respond_to(ID mid, VALUE val, ID id)
9222{
9223 if (!rb_respond_to(val, mid)) {
9224 rb_raise(rb_eTypeError, "%"PRIsVALUE" must have %"PRIsVALUE" method, %"PRIsVALUE" given",
9225 rb_id2str(id), rb_id2str(mid),
9226 rb_obj_class(val));
9227 }
9228}
9229
9230static void
9231stdin_setter(VALUE val, ID id, VALUE *ptr)
9232{
9234}
9235
9236static VALUE
9237stdin_getter(ID id, VALUE *ptr)
9238{
9239 return rb_ractor_stdin();
9240}
9241
9242static void
9243stdout_setter(VALUE val, ID id, VALUE *ptr)
9244{
9245 must_respond_to(id_write, val, id);
9247}
9248
9249static VALUE
9250stdout_getter(ID id, VALUE *ptr)
9251{
9252 return rb_ractor_stdout();
9253}
9254
9255static void
9256stderr_setter(VALUE val, ID id, VALUE *ptr)
9257{
9258 must_respond_to(id_write, val, id);
9260}
9261
9262static VALUE
9263stderr_getter(ID id, VALUE *ptr)
9264{
9265 return rb_ractor_stderr();
9266}
9267
9268static VALUE
9269allocate_and_open_new_file(VALUE klass)
9270{
9271 VALUE self = io_alloc(klass);
9272 rb_io_make_open_file(self);
9273 return self;
9274}
9275
9276VALUE
9277rb_io_open_descriptor(VALUE klass, int descriptor, int mode, VALUE path, VALUE timeout, struct rb_io_encoding *encoding)
9278{
9279 int state;
9280 VALUE self = rb_protect(allocate_and_open_new_file, klass, &state);
9281 if (state) {
9282 /* if we raised an exception allocating an IO object, but the caller
9283 intended to transfer ownership of this FD to us, close the fd before
9284 raising the exception. Otherwise, we would leak a FD - the caller
9285 expects GC to close the file, but we never got around to assigning
9286 it to a rb_io. */
9287 if (!(mode & FMODE_EXTERNAL)) {
9288 maygvl_close(descriptor, 0);
9289 }
9290 rb_jump_tag(state);
9291 }
9292
9293
9294 rb_io_t *io = RFILE(self)->fptr;
9295 io->self = self;
9296 io->fd = descriptor;
9297 io->mode = mode;
9298
9299 /* At this point, Ruby fully owns the descriptor, and will close it when
9300 the IO gets GC'd (unless FMODE_EXTERNAL was set), no matter what happens
9301 in the rest of this method. */
9302
9303 if (NIL_P(path)) {
9304 io->pathv = Qnil;
9305 }
9306 else {
9307 StringValue(path);
9308 io->pathv = rb_str_new_frozen(path);
9309 }
9310
9311 io->timeout = timeout;
9312
9313 ccan_list_head_init(&io->blocking_operations);
9314 io->closing_ec = NULL;
9315 io->wakeup_mutex = Qnil;
9316 io->fork_generation = GET_VM()->fork_gen;
9317
9318 if (encoding) {
9319 io->encs = *encoding;
9320 }
9321
9322 rb_update_max_fd(descriptor);
9323
9324 return self;
9325}
9326
9327static VALUE
9328prep_io(int fd, enum rb_io_mode fmode, VALUE klass, const char *path)
9329{
9330 VALUE path_value = Qnil;
9331 rb_encoding *e;
9332 struct rb_io_encoding convconfig;
9333
9334 if (path) {
9335 path_value = rb_obj_freeze(rb_str_new_cstr(path));
9336 }
9337
9338 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
9339 rb_io_ext_int_to_encs(e, NULL, &convconfig.enc, &convconfig.enc2, fmode);
9340 convconfig.ecflags = (fmode & FMODE_READABLE) ?
9343#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9344 convconfig.ecflags |= (fmode & FMODE_WRITABLE) ?
9345 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
9346 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
9347#endif
9348 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.enc2, convconfig.ecflags);
9349 convconfig.ecopts = Qnil;
9350
9351 VALUE self = rb_io_open_descriptor(klass, fd, fmode, path_value, Qnil, &convconfig);
9352 rb_io_t*io = RFILE(self)->fptr;
9353
9354 if (!io_check_tty(io)) {
9355#ifdef __CYGWIN__
9356 io->mode |= FMODE_BINMODE;
9357 setmode(fd, O_BINARY);
9358#endif
9359 }
9360
9361 return self;
9362}
9363
9364VALUE
9365rb_io_fdopen(int fd, int oflags, const char *path)
9366{
9367 VALUE klass = rb_cIO;
9368
9369 if (path && strcmp(path, "-")) klass = rb_cFile;
9370 return prep_io(fd, rb_io_oflags_fmode(oflags), klass, path);
9371}
9372
9373static VALUE
9374prep_stdio(FILE *f, enum rb_io_mode fmode, VALUE klass, const char *path)
9375{
9376 rb_io_t *fptr;
9377 VALUE io = prep_io(fileno(f), fmode|FMODE_EXTERNAL|DEFAULT_TEXTMODE, klass, path);
9378
9379 GetOpenFile(io, fptr);
9381#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9382 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
9383 if (fmode & FMODE_READABLE) {
9385 }
9386#endif
9387 fptr->stdio_file = f;
9388
9389 return io;
9390}
9391
9392VALUE
9393rb_io_prep_stdin(void)
9394{
9395 return prep_stdio(stdin, FMODE_READABLE, rb_cIO, "<STDIN>");
9396}
9397
9398VALUE
9399rb_io_prep_stdout(void)
9400{
9401 return prep_stdio(stdout, FMODE_WRITABLE|FMODE_SIGNAL_ON_EPIPE, rb_cIO, "<STDOUT>");
9402}
9403
9404VALUE
9405rb_io_prep_stderr(void)
9406{
9407 return prep_stdio(stderr, FMODE_WRITABLE|FMODE_SYNC, rb_cIO, "<STDERR>");
9408}
9409
9410FILE *
9412{
9413 if (!fptr->stdio_file) {
9414 int oflags = rb_io_fmode_oflags(fptr->mode) & ~O_EXCL;
9415 fptr->stdio_file = rb_fdopen(fptr->fd, rb_io_oflags_modestr(oflags));
9416 }
9417 return fptr->stdio_file;
9418}
9419
9420static inline void
9421rb_io_buffer_init(struct rb_io_internal_buffer *buf)
9422{
9423 buf->ptr = NULL;
9424 buf->off = 0;
9425 buf->len = 0;
9426 buf->capa = 0;
9427}
9428
9429static inline rb_io_t *
9430rb_io_fptr_new(void)
9431{
9432 rb_io_t *fp = ALLOC(rb_io_t);
9433 fp->self = Qnil;
9434 fp->fd = -1;
9435 fp->stdio_file = NULL;
9436 fp->mode = 0;
9437 fp->pid = 0;
9438 fp->lineno = 0;
9439 fp->pathv = Qnil;
9440 fp->finalize = 0;
9441 rb_io_buffer_init(&fp->wbuf);
9442 rb_io_buffer_init(&fp->rbuf);
9443 rb_io_buffer_init(&fp->cbuf);
9444 fp->readconv = NULL;
9445 fp->writeconv = NULL;
9447 fp->writeconv_pre_ecflags = 0;
9449 fp->writeconv_initialized = 0;
9450 fp->tied_io_for_writing = 0;
9451 fp->encs.enc = NULL;
9452 fp->encs.enc2 = NULL;
9453 fp->encs.ecflags = 0;
9454 fp->encs.ecopts = Qnil;
9455 fp->write_lock = Qnil;
9456 fp->timeout = Qnil;
9457 ccan_list_head_init(&fp->blocking_operations);
9458 fp->closing_ec = NULL;
9459 fp->wakeup_mutex = Qnil;
9460 fp->fork_generation = GET_VM()->fork_gen;
9461 return fp;
9462}
9463
9464rb_io_t *
9465rb_io_make_open_file(VALUE obj)
9466{
9467 rb_io_t *fp = 0;
9468
9469 Check_Type(obj, T_FILE);
9470 if (RFILE(obj)->fptr) {
9471 rb_io_close(obj);
9472 rb_io_fptr_finalize(RFILE(obj)->fptr);
9473 RFILE(obj)->fptr = 0;
9474 }
9475 fp = rb_io_fptr_new();
9476 fp->self = obj;
9477 RFILE(obj)->fptr = fp;
9478 return fp;
9479}
9480
9481static VALUE io_initialize(VALUE io, VALUE fnum, VALUE vmode, VALUE opt);
9482
9483/*
9484 * call-seq:
9485 * IO.new(fd, mode = 'r', **opts) -> io
9486 *
9487 * Creates and returns a new \IO object (file stream) from a file descriptor.
9488 *
9489 * \IO.new may be useful for interaction with low-level libraries.
9490 * For higher-level interactions, it may be simpler to create
9491 * the file stream using File.open.
9492 *
9493 * Argument +fd+ must be a valid file descriptor (integer):
9494 *
9495 * path = 't.tmp'
9496 * fd = IO.sysopen(path) # => 3
9497 * IO.new(fd) # => #<IO:fd 3>
9498 *
9499 * The new \IO object does not inherit encoding
9500 * (because the integer file descriptor does not have an encoding):
9501 *
9502 * File.read('t.ja') # => "こんにちは"
9503 * fd = IO.sysopen('t.ja', 'rb')
9504 * io = IO.new(fd)
9505 * io.external_encoding # => #<Encoding:UTF-8> # Not ASCII-8BIT.
9506 *
9507 * Optional argument +mode+ (defaults to 'r') must specify a valid mode;
9508 * see {Access Modes}[rdoc-ref:File@Access+Modes]:
9509 *
9510 * IO.new(fd, 'w') # => #<IO:fd 3>
9511 * IO.new(fd, File::WRONLY) # => #<IO:fd 3>
9512 *
9513 * Optional keyword arguments +opts+ specify:
9514 *
9515 * - {Open Options}[rdoc-ref:IO@Open+Options].
9516 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
9517 *
9518 * Examples:
9519 *
9520 * IO.new(fd, internal_encoding: nil) # => #<IO:fd 3>
9521 * IO.new(fd, autoclose: true) # => #<IO:fd 3>
9522 *
9523 */
9524
9525static VALUE
9526rb_io_initialize(int argc, VALUE *argv, VALUE io)
9527{
9528 VALUE fnum, vmode;
9529 VALUE opt;
9530
9531 rb_scan_args(argc, argv, "11:", &fnum, &vmode, &opt);
9532 return io_initialize(io, fnum, vmode, opt);
9533}
9534
9535static VALUE
9536io_initialize(VALUE io, VALUE fnum, VALUE vmode, VALUE opt)
9537{
9538 rb_io_t *fp;
9539 int fd, oflags = O_RDONLY;
9540 enum rb_io_mode fmode;
9541 struct rb_io_encoding convconfig;
9542#if defined(HAVE_FCNTL) && defined(F_GETFL)
9543 int ofmode;
9544#else
9545 struct stat st;
9546#endif
9547
9548 rb_io_extract_modeenc(&vmode, 0, opt, &oflags, &fmode, &convconfig);
9549
9550 fd = NUM2INT(fnum);
9551 if (rb_reserved_fd_p(fd)) {
9552 rb_raise(rb_eArgError, "The given fd is not accessible because RubyVM reserves it");
9553 }
9554#if defined(HAVE_FCNTL) && defined(F_GETFL)
9555 oflags = fcntl(fd, F_GETFL);
9556 if (oflags == -1) rb_sys_fail(0);
9557#else
9558 if (fstat(fd, &st) < 0) rb_sys_fail(0);
9559#endif
9560 rb_update_max_fd(fd);
9561#if defined(HAVE_FCNTL) && defined(F_GETFL)
9562 ofmode = rb_io_oflags_fmode(oflags);
9563 if (NIL_P(vmode)) {
9564 fmode = ofmode;
9565 }
9566 else if ((~ofmode & fmode) & FMODE_READWRITE) {
9567 VALUE error = INT2FIX(EINVAL);
9569 }
9570#endif
9571 VALUE path = Qnil;
9572
9573 if (!NIL_P(opt)) {
9574 if (rb_hash_aref(opt, sym_autoclose) == Qfalse) {
9575 fmode |= FMODE_EXTERNAL;
9576 }
9577
9578 path = rb_hash_aref(opt, RB_ID2SYM(idPath));
9579 if (!NIL_P(path)) {
9580 StringValue(path);
9581 path = rb_str_new_frozen(path);
9582 }
9583 }
9584
9585 MakeOpenFile(io, fp);
9586 fp->self = io;
9587 fp->fd = fd;
9588 fp->mode = fmode;
9589 fp->encs = convconfig;
9590 fp->pathv = path;
9591 fp->timeout = Qnil;
9592 ccan_list_head_init(&fp->blocking_operations);
9593 fp->closing_ec = NULL;
9594 fp->wakeup_mutex = Qnil;
9595 fp->fork_generation = GET_VM()->fork_gen;
9596 clear_codeconv(fp);
9597 io_check_tty(fp);
9598 if (fileno(stdin) == fd)
9599 fp->stdio_file = stdin;
9600 else if (fileno(stdout) == fd)
9601 fp->stdio_file = stdout;
9602 else if (fileno(stderr) == fd)
9603 fp->stdio_file = stderr;
9604
9605 if (fmode & FMODE_SETENC_BY_BOM) io_set_encoding_by_bom(io);
9606 return io;
9607}
9608
9609/*
9610 * call-seq:
9611 * set_encoding_by_bom -> encoding or nil
9612 *
9613 * If the stream begins with a BOM
9614 * ({byte order marker}[https://en.wikipedia.org/wiki/Byte_order_mark]),
9615 * consumes the BOM and sets the external encoding accordingly;
9616 * returns the result encoding if found, or +nil+ otherwise:
9617 *
9618 * File.write('t.tmp', "\u{FEFF}abc")
9619 * io = File.open('t.tmp', 'rb')
9620 * io.set_encoding_by_bom # => #<Encoding:UTF-8>
9621 * io.close
9622 *
9623 * File.write('t.tmp', 'abc')
9624 * io = File.open('t.tmp', 'rb')
9625 * io.set_encoding_by_bom # => nil
9626 * io.close
9627 *
9628 * Raises an exception if the stream is not binmode
9629 * or its encoding has already been set.
9630 *
9631 */
9632
9633static VALUE
9634rb_io_set_encoding_by_bom(VALUE io)
9635{
9636 rb_io_t *fptr;
9637
9638 GetOpenFile(io, fptr);
9639 if (!(fptr->mode & FMODE_BINMODE)) {
9640 rb_raise(rb_eArgError, "ASCII incompatible encoding needs binmode");
9641 }
9642 if (fptr->encs.enc2) {
9643 rb_raise(rb_eArgError, "encoding conversion is set");
9644 }
9645 else if (fptr->encs.enc && fptr->encs.enc != rb_ascii8bit_encoding()) {
9646 rb_raise(rb_eArgError, "encoding is set to %s already",
9647 rb_enc_name(fptr->encs.enc));
9648 }
9649 if (!io_set_encoding_by_bom(io)) return Qnil;
9650 return rb_enc_from_encoding(fptr->encs.enc);
9651}
9652
9653/*
9654 * call-seq:
9655 * File.new(path, mode = 'r', perm = 0666, **opts) -> file
9656 *
9657 * Opens the file at the given +path+ according to the given +mode+;
9658 * creates and returns a new File object for that file.
9659 *
9660 * The new File object is buffered mode (or non-sync mode), unless
9661 * +filename+ is a tty.
9662 * See IO#flush, IO#fsync, IO#fdatasync, and IO#sync=.
9663 *
9664 * Argument +path+ must be a valid file path:
9665 *
9666 * f = File.new('/etc/fstab')
9667 * f.close
9668 * f = File.new('t.txt')
9669 * f.close
9670 *
9671 * Optional argument +mode+ (defaults to 'r') must specify a valid mode;
9672 * see {Access Modes}[rdoc-ref:File@Access+Modes]:
9673 *
9674 * f = File.new('t.tmp', 'w')
9675 * f.close
9676 * f = File.new('t.tmp', File::RDONLY)
9677 * f.close
9678 *
9679 * Optional argument +perm+ (defaults to 0666) must specify valid permissions
9680 * see {File Permissions}[rdoc-ref:File@File+Permissions]:
9681 *
9682 * f = File.new('t.tmp', File::CREAT, 0644)
9683 * f.close
9684 * f = File.new('t.tmp', File::CREAT, 0444)
9685 * f.close
9686 *
9687 * Optional keyword arguments +opts+ specify:
9688 *
9689 * - {Open Options}[rdoc-ref:IO@Open+Options].
9690 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
9691 *
9692 */
9693
9694static VALUE
9695rb_file_initialize(int argc, VALUE *argv, VALUE io)
9696{
9697 if (RFILE(io)->fptr) {
9698 rb_raise(rb_eRuntimeError, "reinitializing File");
9699 }
9700 VALUE fname, vmode, vperm, opt;
9701 int posargc = rb_scan_args(argc, argv, "12:", &fname, &vmode, &vperm, &opt);
9702 if (posargc < 3) { /* perm is File only */
9703 VALUE fd = rb_check_to_int(fname);
9704
9705 if (!NIL_P(fd)) {
9706 return io_initialize(io, fd, vmode, opt);
9707 }
9708 }
9709 return rb_open_file(io, fname, vmode, vperm, opt);
9710}
9711
9712/* :nodoc: */
9713static VALUE
9714rb_io_s_new(int argc, VALUE *argv, VALUE klass)
9715{
9716 if (rb_block_given_p()) {
9717 VALUE cname = rb_obj_as_string(klass);
9718
9719 rb_warn("%"PRIsVALUE"::new() does not take block; use %"PRIsVALUE"::open() instead",
9720 cname, cname);
9721 }
9722 return rb_class_new_instance_kw(argc, argv, klass, RB_PASS_CALLED_KEYWORDS);
9723}
9724
9725
9726/*
9727 * call-seq:
9728 * IO.for_fd(fd, mode = 'r', **opts) -> io
9729 *
9730 * Synonym for IO.new.
9731 *
9732 */
9733
9734static VALUE
9735rb_io_s_for_fd(int argc, VALUE *argv, VALUE klass)
9736{
9737 VALUE io = rb_obj_alloc(klass);
9738 rb_io_initialize(argc, argv, io);
9739 return io;
9740}
9741
9742/*
9743 * call-seq:
9744 * ios.autoclose? -> true or false
9745 *
9746 * Returns +true+ if the underlying file descriptor of _ios_ will be
9747 * closed at its finalization or at calling #close, otherwise +false+.
9748 */
9749
9750static VALUE
9751rb_io_autoclose_p(VALUE io)
9752{
9753 rb_io_t *fptr = RFILE(io)->fptr;
9754 rb_io_check_closed(fptr);
9755 return RBOOL(!(fptr->mode & FMODE_EXTERNAL));
9756}
9757
9758/*
9759 * call-seq:
9760 * io.autoclose = bool -> true or false
9761 *
9762 * Sets auto-close flag.
9763 *
9764 * f = File.open(File::NULL)
9765 * IO.for_fd(f.fileno).close
9766 * f.gets # raises Errno::EBADF
9767 *
9768 * f = File.open(File::NULL)
9769 * g = IO.for_fd(f.fileno)
9770 * g.autoclose = false
9771 * g.close
9772 * f.gets # won't cause Errno::EBADF
9773 */
9774
9775static VALUE
9776rb_io_set_autoclose(VALUE io, VALUE autoclose)
9777{
9778 rb_io_t *fptr;
9779 GetOpenFile(io, fptr);
9780 if (!RTEST(autoclose))
9781 fptr->mode |= FMODE_EXTERNAL;
9782 else
9783 fptr->mode &= ~FMODE_EXTERNAL;
9784 return autoclose;
9785}
9786
9787static VALUE
9788io_wait_event(VALUE io, int event, VALUE timeout, int return_io)
9789{
9790 VALUE result = rb_io_wait(io, RB_INT2NUM(event), timeout);
9791
9792 if (!RB_TEST(result)) {
9793 return Qnil;
9794 }
9795
9796 int mask = RB_NUM2INT(result);
9797
9798 if (mask & event) {
9799 if (return_io)
9800 return io;
9801 else
9802 return result;
9803 }
9804 else {
9805 return Qfalse;
9806 }
9807}
9808
9809/*
9810 * call-seq:
9811 * io.wait_readable -> truthy or falsy
9812 * io.wait_readable(timeout) -> truthy or falsy
9813 *
9814 * Waits until IO is readable and returns a truthy value, or a falsy
9815 * value when times out. Returns a truthy value immediately when
9816 * buffered data is available.
9817 */
9818
9819static VALUE
9820io_wait_readable(int argc, VALUE *argv, VALUE io)
9821{
9822 rb_io_t *fptr;
9823
9824 RB_IO_POINTER(io, fptr);
9826
9827 if (rb_io_read_pending(fptr)) return Qtrue;
9828
9829 rb_check_arity(argc, 0, 1);
9830 VALUE timeout = (argc == 1 ? argv[0] : Qnil);
9831
9832 return io_wait_event(io, RUBY_IO_READABLE, timeout, 1);
9833}
9834
9835/*
9836 * call-seq:
9837 * io.wait_writable -> truthy or falsy
9838 * io.wait_writable(timeout) -> truthy or falsy
9839 *
9840 * Waits until IO is writable and returns a truthy value or a falsy
9841 * value when times out.
9842 */
9843static VALUE
9844io_wait_writable(int argc, VALUE *argv, VALUE io)
9845{
9846 rb_io_t *fptr;
9847
9848 RB_IO_POINTER(io, fptr);
9850
9851 rb_check_arity(argc, 0, 1);
9852 VALUE timeout = (argc == 1 ? argv[0] : Qnil);
9853
9854 return io_wait_event(io, RUBY_IO_WRITABLE, timeout, 1);
9855}
9856
9857/*
9858 * call-seq:
9859 * io.wait_priority -> truthy or falsy
9860 * io.wait_priority(timeout) -> truthy or falsy
9861 *
9862 * Waits until IO is priority and returns a truthy value or a falsy
9863 * value when times out. Priority data is sent and received using
9864 * the Socket::MSG_OOB flag and is typically limited to streams.
9865 */
9866static VALUE
9867io_wait_priority(int argc, VALUE *argv, VALUE io)
9868{
9869 rb_io_t *fptr = NULL;
9870
9871 RB_IO_POINTER(io, fptr);
9873
9874 if (rb_io_read_pending(fptr)) return Qtrue;
9875
9876 rb_check_arity(argc, 0, 1);
9877 VALUE timeout = argc == 1 ? argv[0] : Qnil;
9878
9879 return io_wait_event(io, RUBY_IO_PRIORITY, timeout, 1);
9880}
9881
9882static int
9883wait_mode_sym(VALUE mode)
9884{
9885 if (mode == ID2SYM(rb_intern("r"))) {
9886 return RB_WAITFD_IN;
9887 }
9888 if (mode == ID2SYM(rb_intern("read"))) {
9889 return RB_WAITFD_IN;
9890 }
9891 if (mode == ID2SYM(rb_intern("readable"))) {
9892 return RB_WAITFD_IN;
9893 }
9894 if (mode == ID2SYM(rb_intern("w"))) {
9895 return RB_WAITFD_OUT;
9896 }
9897 if (mode == ID2SYM(rb_intern("write"))) {
9898 return RB_WAITFD_OUT;
9899 }
9900 if (mode == ID2SYM(rb_intern("writable"))) {
9901 return RB_WAITFD_OUT;
9902 }
9903 if (mode == ID2SYM(rb_intern("rw"))) {
9904 return RB_WAITFD_IN|RB_WAITFD_OUT;
9905 }
9906 if (mode == ID2SYM(rb_intern("read_write"))) {
9907 return RB_WAITFD_IN|RB_WAITFD_OUT;
9908 }
9909 if (mode == ID2SYM(rb_intern("readable_writable"))) {
9910 return RB_WAITFD_IN|RB_WAITFD_OUT;
9911 }
9912
9913 rb_raise(rb_eArgError, "unsupported mode: %"PRIsVALUE, mode);
9914}
9915
9916static inline enum rb_io_event
9917io_event_from_value(VALUE value)
9918{
9919 int events = RB_NUM2INT(value);
9920
9921 if (events <= 0) rb_raise(rb_eArgError, "Events must be positive integer!");
9922
9923 return events;
9924}
9925
9926/*
9927 * call-seq:
9928 * io.wait(events, timeout) -> event mask, false or nil
9929 * io.wait(*event_symbols[, timeout]) -> self, true, or false
9930 *
9931 * Waits until the IO becomes ready for the specified events and returns the
9932 * subset of events that become ready, or a falsy value when times out.
9933 *
9934 * The events can be a bit mask of +IO::READABLE+, +IO::WRITABLE+ or
9935 * +IO::PRIORITY+.
9936 *
9937 * Returns an event mask (truthy value) immediately when buffered data is
9938 * available.
9939 *
9940 * The second form: if one or more event symbols (+:read+, +:write+, or
9941 * +:read_write+) are passed, the event mask is the bit OR of the bitmask
9942 * corresponding to those symbols. In this form, +timeout+ is optional, the
9943 * order of the arguments is arbitrary, and returns +io+ if any of the
9944 * events is ready.
9945 */
9946
9947static VALUE
9948io_wait(int argc, VALUE *argv, VALUE io)
9949{
9950 VALUE timeout = Qundef;
9951 enum rb_io_event events = 0;
9952 int return_io = 0;
9953
9954 if (argc != 2 || (RB_SYMBOL_P(argv[0]) || RB_SYMBOL_P(argv[1]))) {
9955 // We'd prefer to return the actual mask, but this form would return the io itself:
9956 return_io = 1;
9957
9958 // Slow/messy path:
9959 for (int i = 0; i < argc; i += 1) {
9960 if (RB_SYMBOL_P(argv[i])) {
9961 events |= wait_mode_sym(argv[i]);
9962 }
9963 else if (UNDEF_P(timeout)) {
9964 rb_time_interval(timeout = argv[i]);
9965 }
9966 else {
9967 rb_raise(rb_eArgError, "timeout given more than once");
9968 }
9969 }
9970
9971 if (UNDEF_P(timeout)) timeout = Qnil;
9972
9973 if (events == 0) {
9974 events = RUBY_IO_READABLE;
9975 }
9976 }
9977 else /* argc == 2 and neither are symbols */ {
9978 // This is the fast path:
9979 events = io_event_from_value(argv[0]);
9980 timeout = argv[1];
9981 }
9982
9983 if (events & RUBY_IO_READABLE) {
9984 rb_io_t *fptr = NULL;
9985 RB_IO_POINTER(io, fptr);
9986
9987 if (rb_io_read_pending(fptr)) {
9988 // This was the original behaviour:
9989 if (return_io) return Qtrue;
9990 // New behaviour always returns an event mask:
9991 else return RB_INT2NUM(RUBY_IO_READABLE);
9992 }
9993 }
9994
9995 return io_wait_event(io, events, timeout, return_io);
9996}
9997
9998static void
9999argf_mark_and_move(void *ptr)
10000{
10001 struct argf *p = ptr;
10002 rb_gc_mark_and_move(&p->filename);
10003 rb_gc_mark_and_move(&p->current_file);
10004 rb_gc_mark_and_move(&p->argv);
10005 rb_gc_mark_and_move(&p->inplace);
10006 rb_gc_mark_and_move(&p->encs.ecopts);
10007}
10008
10009static size_t
10010argf_memsize(const void *ptr)
10011{
10012 const struct argf *p = ptr;
10013 size_t size = sizeof(*p);
10014 return size;
10015}
10016
10017static const rb_data_type_t argf_type = {
10018 "ARGF",
10019 {argf_mark_and_move, RUBY_TYPED_DEFAULT_FREE, argf_memsize, argf_mark_and_move},
10020 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
10021};
10022
10023static inline void
10024argf_init(struct argf *p, VALUE v)
10025{
10026 p->filename = Qnil;
10027 p->current_file = Qnil;
10028 p->lineno = 0;
10029 p->argv = v;
10030}
10031
10032static VALUE
10033argf_alloc(VALUE klass)
10034{
10035 struct argf *p;
10036 VALUE argf = TypedData_Make_Struct(klass, struct argf, &argf_type, p);
10037
10038 argf_init(p, Qnil);
10039 return argf;
10040}
10041
10042#undef rb_argv
10043
10044/* :nodoc: */
10045static VALUE
10046argf_initialize(VALUE argf, VALUE argv)
10047{
10048 memset(&ARGF, 0, sizeof(ARGF));
10049 argf_init(&ARGF, argv);
10050
10051 return argf;
10052}
10053
10054/* :nodoc: */
10055static VALUE
10056argf_initialize_copy(VALUE argf, VALUE orig)
10057{
10058 if (!OBJ_INIT_COPY(argf, orig)) return argf;
10059 ARGF = argf_of(orig);
10060 ARGF.argv = rb_obj_dup(ARGF.argv);
10061 return argf;
10062}
10063
10064/*
10065 * call-seq:
10066 * ARGF.lineno = integer -> integer
10067 *
10068 * Sets the line number of ARGF as a whole to the given Integer.
10069 *
10070 * ARGF sets the line number automatically as you read data, so normally
10071 * you will not need to set it explicitly. To access the current line number
10072 * use ARGF.lineno.
10073 *
10074 * For example:
10075 *
10076 * ARGF.lineno #=> 0
10077 * ARGF.readline #=> "This is line 1\n"
10078 * ARGF.lineno #=> 1
10079 * ARGF.lineno = 0 #=> 0
10080 * ARGF.lineno #=> 0
10081 */
10082static VALUE
10083argf_set_lineno(VALUE argf, VALUE val)
10084{
10085 ARGF.lineno = NUM2INT(val);
10086 ARGF.last_lineno = ARGF.lineno;
10087 return val;
10088}
10089
10090/*
10091 * call-seq:
10092 * ARGF.lineno -> integer
10093 *
10094 * Returns the current line number of ARGF as a whole. This value
10095 * can be set manually with ARGF.lineno=.
10096 *
10097 * For example:
10098 *
10099 * ARGF.lineno #=> 0
10100 * ARGF.readline #=> "This is line 1\n"
10101 * ARGF.lineno #=> 1
10102 */
10103static VALUE
10104argf_lineno(VALUE argf)
10105{
10106 return INT2FIX(ARGF.lineno);
10107}
10108
10109static VALUE
10110argf_forward(int argc, VALUE *argv, VALUE argf)
10111{
10112 return forward_current(rb_frame_this_func(), argc, argv);
10113}
10114
10115#define next_argv() argf_next_argv(argf)
10116#define ARGF_GENERIC_INPUT_P() \
10117 (ARGF.current_file == rb_stdin && !RB_TYPE_P(ARGF.current_file, T_FILE))
10118#define ARGF_FORWARD(argc, argv) do {\
10119 if (ARGF_GENERIC_INPUT_P())\
10120 return argf_forward((argc), (argv), argf);\
10121} while (0)
10122#define NEXT_ARGF_FORWARD(argc, argv) do {\
10123 if (!next_argv()) return Qnil;\
10124 ARGF_FORWARD((argc), (argv));\
10125} while (0)
10126
10127static void
10128argf_close(VALUE argf)
10129{
10130 VALUE file = ARGF.current_file;
10131 if (file == rb_stdin) return;
10132 if (RB_TYPE_P(file, T_FILE)) {
10133 rb_io_set_write_io(file, Qnil);
10134 }
10135 io_close(file);
10136 ARGF.init_p = -1;
10137}
10138
10139static int
10140argf_next_argv(VALUE argf)
10141{
10142 char *fn;
10143 rb_io_t *fptr;
10144 int stdout_binmode = 0;
10145 enum rb_io_mode fmode;
10146
10147 VALUE r_stdout = rb_ractor_stdout();
10148
10149 if (RB_TYPE_P(r_stdout, T_FILE)) {
10150 GetOpenFile(r_stdout, fptr);
10151 if (fptr->mode & FMODE_BINMODE)
10152 stdout_binmode = 1;
10153 }
10154
10155 if (ARGF.init_p == 0) {
10156 if (!NIL_P(ARGF.argv) && RARRAY_LEN(ARGF.argv) > 0) {
10157 ARGF.next_p = 1;
10158 }
10159 else {
10160 ARGF.next_p = -1;
10161 }
10162 ARGF.init_p = 1;
10163 }
10164 else {
10165 if (NIL_P(ARGF.argv)) {
10166 ARGF.next_p = -1;
10167 }
10168 else if (ARGF.next_p == -1 && RARRAY_LEN(ARGF.argv) > 0) {
10169 ARGF.next_p = 1;
10170 }
10171 }
10172
10173 if (ARGF.next_p == 1) {
10174 if (ARGF.init_p == 1) argf_close(argf);
10175 retry:
10176 if (RARRAY_LEN(ARGF.argv) > 0) {
10177 VALUE filename = rb_ary_shift(ARGF.argv);
10178 FilePathValue(filename);
10179 ARGF.filename = filename;
10180 filename = rb_str_encode_ospath(filename);
10181 fn = StringValueCStr(filename);
10182 if (RSTRING_LEN(filename) == 1 && fn[0] == '-') {
10183 ARGF.current_file = rb_stdin;
10184 if (ARGF.inplace) {
10185 rb_warn("Can't do inplace edit for stdio; skipping");
10186 goto retry;
10187 }
10188 }
10189 else {
10190 VALUE write_io = Qnil;
10191 int fr = rb_sysopen(filename, O_RDONLY, 0);
10192
10193 if (ARGF.inplace) {
10194 struct stat st;
10195#ifndef NO_SAFE_RENAME
10196 struct stat st2;
10197#endif
10198 VALUE str;
10199 int fw;
10200
10201 if (RB_TYPE_P(r_stdout, T_FILE) && r_stdout != orig_stdout) {
10202 rb_io_close(r_stdout);
10203 }
10204 fstat(fr, &st);
10205 str = filename;
10206 if (!NIL_P(ARGF.inplace)) {
10207 VALUE suffix = ARGF.inplace;
10208 str = rb_str_dup(str);
10209 if (NIL_P(rb_str_cat_conv_enc_opts(str, RSTRING_LEN(str),
10210 RSTRING_PTR(suffix), RSTRING_LEN(suffix),
10211 rb_enc_get(suffix), 0, Qnil))) {
10212 rb_str_append(str, suffix);
10213 }
10214#ifdef NO_SAFE_RENAME
10215 (void)close(fr);
10216 (void)unlink(RSTRING_PTR(str));
10217 if (rename(fn, RSTRING_PTR(str)) < 0) {
10218 rb_warn("Can't rename %"PRIsVALUE" to %"PRIsVALUE": %s, skipping file",
10219 filename, str, strerror(errno));
10220 goto retry;
10221 }
10222 fr = rb_sysopen(str, O_RDONLY, 0);
10223#else
10224 if (rename(fn, RSTRING_PTR(str)) < 0) {
10225 rb_warn("Can't rename %"PRIsVALUE" to %"PRIsVALUE": %s, skipping file",
10226 filename, str, strerror(errno));
10227 close(fr);
10228 goto retry;
10229 }
10230#endif
10231 }
10232 else {
10233#ifdef NO_SAFE_RENAME
10234 rb_fatal("Can't do inplace edit without backup");
10235#else
10236 if (unlink(fn) < 0) {
10237 rb_warn("Can't remove %"PRIsVALUE": %s, skipping file",
10238 filename, strerror(errno));
10239 close(fr);
10240 goto retry;
10241 }
10242#endif
10243 }
10244 fw = rb_sysopen(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666);
10245#ifndef NO_SAFE_RENAME
10246 fstat(fw, &st2);
10247#ifdef HAVE_FCHMOD
10248 fchmod(fw, st.st_mode);
10249#else
10250 chmod(fn, st.st_mode);
10251#endif
10252 if (st.st_uid!=st2.st_uid || st.st_gid!=st2.st_gid) {
10253 int err;
10254#ifdef HAVE_FCHOWN
10255 err = fchown(fw, st.st_uid, st.st_gid);
10256#else
10257 err = chown(fn, st.st_uid, st.st_gid);
10258#endif
10259 if (err && getuid() == 0 && st2.st_uid == 0) {
10260 const char *wkfn = RSTRING_PTR(filename);
10261 rb_warn("Can't set owner/group of %"PRIsVALUE" to same as %"PRIsVALUE": %s, skipping file",
10262 filename, str, strerror(errno));
10263 (void)close(fr);
10264 (void)close(fw);
10265 (void)unlink(wkfn);
10266 goto retry;
10267 }
10268 }
10269#endif
10270 write_io = prep_io(fw, FMODE_WRITABLE, rb_cFile, fn);
10271 rb_ractor_stdout_set(write_io);
10272 if (stdout_binmode) rb_io_binmode(rb_stdout);
10273 }
10274 fmode = FMODE_READABLE;
10275 if (!ARGF.binmode) {
10276 fmode |= DEFAULT_TEXTMODE;
10277 }
10278 ARGF.current_file = prep_io(fr, fmode, rb_cFile, fn);
10279 if (!NIL_P(write_io)) {
10280 rb_io_set_write_io(ARGF.current_file, write_io);
10281 }
10282 RB_GC_GUARD(filename);
10283 }
10284 if (ARGF.binmode) rb_io_ascii8bit_binmode(ARGF.current_file);
10285 GetOpenFile(ARGF.current_file, fptr);
10286 if (ARGF.encs.enc) {
10287 fptr->encs = ARGF.encs;
10288 clear_codeconv(fptr);
10289 }
10290 else {
10291 fptr->encs.ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
10292 if (!ARGF.binmode) {
10294#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
10295 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
10296#endif
10297 }
10298 }
10299 ARGF.next_p = 0;
10300 }
10301 else {
10302 ARGF.next_p = 1;
10303 return FALSE;
10304 }
10305 }
10306 else if (ARGF.next_p == -1) {
10307 ARGF.current_file = rb_stdin;
10308 ARGF.filename = rb_str_new2("-");
10309 if (ARGF.inplace) {
10310 rb_warn("Can't do inplace edit for stdio");
10311 rb_ractor_stdout_set(orig_stdout);
10312 }
10313 }
10314 if (ARGF.init_p == -1) ARGF.init_p = 1;
10315 return TRUE;
10316}
10317
10318static VALUE
10319argf_getline(int argc, VALUE *argv, VALUE argf)
10320{
10321 VALUE line;
10322 long lineno = ARGF.lineno;
10323
10324 retry:
10325 if (!next_argv()) return Qnil;
10326 if (ARGF_GENERIC_INPUT_P()) {
10327 line = forward_current(idGets, argc, argv);
10328 }
10329 else {
10330 if (argc == 0 && rb_rs == rb_default_rs) {
10331 line = rb_io_gets(ARGF.current_file);
10332 }
10333 else {
10334 line = rb_io_getline(argc, argv, ARGF.current_file);
10335 }
10336 if (NIL_P(line) && ARGF.next_p != -1) {
10337 argf_close(argf);
10338 ARGF.next_p = 1;
10339 goto retry;
10340 }
10341 }
10342 if (!NIL_P(line)) {
10343 ARGF.lineno = ++lineno;
10344 ARGF.last_lineno = ARGF.lineno;
10345 }
10346 return line;
10347}
10348
10349static VALUE
10350argf_lineno_getter(ID id, VALUE *var)
10351{
10352 VALUE argf = *var;
10353 return INT2FIX(ARGF.last_lineno);
10354}
10355
10356static void
10357argf_lineno_setter(VALUE val, ID id, VALUE *var)
10358{
10359 VALUE argf = *var;
10360 int n = NUM2INT(val);
10361 ARGF.last_lineno = ARGF.lineno = n;
10362}
10363
10364void
10365rb_reset_argf_lineno(long n)
10366{
10367 ARGF.last_lineno = ARGF.lineno = n;
10368}
10369
10370static VALUE argf_gets(int, VALUE *, VALUE);
10371
10372/*
10373 * call-seq:
10374 * gets(sep=$/ [, getline_args]) -> string or nil
10375 * gets(limit [, getline_args]) -> string or nil
10376 * gets(sep, limit [, getline_args]) -> string or nil
10377 *
10378 * Returns (and assigns to <code>$_</code>) the next line from the list
10379 * of files in +ARGV+ (or <code>$*</code>), or from standard input if
10380 * no files are present on the command line. Returns +nil+ at end of
10381 * file. The optional argument specifies the record separator. The
10382 * separator is included with the contents of each record. A separator
10383 * of +nil+ reads the entire contents, and a zero-length separator
10384 * reads the input one paragraph at a time, where paragraphs are
10385 * divided by two consecutive newlines. If the first argument is an
10386 * integer, or optional second argument is given, the returning string
10387 * would not be longer than the given value in bytes. If multiple
10388 * filenames are present in +ARGV+, <code>gets(nil)</code> will read
10389 * the contents one file at a time.
10390 *
10391 * ARGV << "testfile"
10392 * print while gets
10393 *
10394 * <em>produces:</em>
10395 *
10396 * This is line one
10397 * This is line two
10398 * This is line three
10399 * And so on...
10400 *
10401 * The style of programming using <code>$_</code> as an implicit
10402 * parameter is gradually losing favor in the Ruby community.
10403 */
10404
10405static VALUE
10406rb_f_gets(int argc, VALUE *argv, VALUE recv)
10407{
10408 if (recv == argf) {
10409 return argf_gets(argc, argv, argf);
10410 }
10411 return forward(argf, idGets, argc, argv);
10412}
10413
10414/*
10415 * call-seq:
10416 * ARGF.gets(sep=$/ [, getline_args]) -> string or nil
10417 * ARGF.gets(limit [, getline_args]) -> string or nil
10418 * ARGF.gets(sep, limit [, getline_args]) -> string or nil
10419 *
10420 * Returns the next line from the current file in ARGF.
10421 *
10422 * By default lines are assumed to be separated by <code>$/</code>;
10423 * to use a different character as a separator, supply it as a String
10424 * for the _sep_ argument.
10425 *
10426 * The optional _limit_ argument specifies how many characters of each line
10427 * to return. By default all characters are returned.
10428 *
10429 * See IO.readlines for details about getline_args.
10430 *
10431 */
10432static VALUE
10433argf_gets(int argc, VALUE *argv, VALUE argf)
10434{
10435 VALUE line;
10436
10437 line = argf_getline(argc, argv, argf);
10438 rb_lastline_set(line);
10439
10440 return line;
10441}
10442
10443VALUE
10445{
10446 VALUE line;
10447
10448 if (rb_rs != rb_default_rs) {
10449 return rb_f_gets(0, 0, argf);
10450 }
10451
10452 retry:
10453 if (!next_argv()) return Qnil;
10454 line = rb_io_gets(ARGF.current_file);
10455 if (NIL_P(line) && ARGF.next_p != -1) {
10456 rb_io_close(ARGF.current_file);
10457 ARGF.next_p = 1;
10458 goto retry;
10459 }
10460 rb_lastline_set(line);
10461 if (!NIL_P(line)) {
10462 ARGF.lineno++;
10463 ARGF.last_lineno = ARGF.lineno;
10464 }
10465
10466 return line;
10467}
10468
10469static VALUE argf_readline(int, VALUE *, VALUE);
10470
10471/*
10472 * call-seq:
10473 * readline(sep = $/, chomp: false) -> string
10474 * readline(limit, chomp: false) -> string
10475 * readline(sep, limit, chomp: false) -> string
10476 *
10477 * Equivalent to method Kernel#gets, except that it raises an exception
10478 * if called at end-of-stream:
10479 *
10480 * $ cat t.txt | ruby -e "p readlines; readline"
10481 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10482 * in `readline': end of file reached (EOFError)
10483 *
10484 * Optional keyword argument +chomp+ specifies whether line separators
10485 * are to be omitted.
10486 */
10487
10488static VALUE
10489rb_f_readline(int argc, VALUE *argv, VALUE recv)
10490{
10491 if (recv == argf) {
10492 return argf_readline(argc, argv, argf);
10493 }
10494 return forward(argf, rb_intern("readline"), argc, argv);
10495}
10496
10497
10498/*
10499 * call-seq:
10500 * ARGF.readline(sep=$/) -> string
10501 * ARGF.readline(limit) -> string
10502 * ARGF.readline(sep, limit) -> string
10503 *
10504 * Returns the next line from the current file in ARGF.
10505 *
10506 * By default lines are assumed to be separated by <code>$/</code>;
10507 * to use a different character as a separator, supply it as a String
10508 * for the _sep_ argument.
10509 *
10510 * The optional _limit_ argument specifies how many characters of each line
10511 * to return. By default all characters are returned.
10512 *
10513 * An EOFError is raised at the end of the file.
10514 */
10515static VALUE
10516argf_readline(int argc, VALUE *argv, VALUE argf)
10517{
10518 VALUE line;
10519
10520 if (!next_argv()) rb_eof_error();
10521 ARGF_FORWARD(argc, argv);
10522 line = argf_gets(argc, argv, argf);
10523 if (NIL_P(line)) {
10524 rb_eof_error();
10525 }
10526
10527 return line;
10528}
10529
10530static VALUE argf_readlines(int, VALUE *, VALUE);
10531
10532/*
10533 * call-seq:
10534 * readlines(sep = $/, chomp: false, **enc_opts) -> array
10535 * readlines(limit, chomp: false, **enc_opts) -> array
10536 * readlines(sep, limit, chomp: false, **enc_opts) -> array
10537 *
10538 * Returns an array containing the lines returned by calling
10539 * Kernel#gets until the end-of-stream is reached;
10540 * (see {Line IO}[rdoc-ref:IO@Line+IO]).
10541 *
10542 * With only string argument +sep+ given,
10543 * returns the remaining lines as determined by line separator +sep+,
10544 * or +nil+ if none;
10545 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
10546 *
10547 * # Default separator.
10548 * $ cat t.txt | ruby -e "p readlines"
10549 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10550 *
10551 * # Specified separator.
10552 * $ cat t.txt | ruby -e "p readlines 'li'"
10553 * ["First li", "ne\nSecond li", "ne\n\nFourth li", "ne\nFifth li", "ne\n"]
10554 *
10555 * # Get-all separator.
10556 * $ cat t.txt | ruby -e "p readlines nil"
10557 * ["First line\nSecond line\n\nFourth line\nFifth line\n"]
10558 *
10559 * # Get-paragraph separator.
10560 * $ cat t.txt | ruby -e "p readlines ''"
10561 * ["First line\nSecond line\n\n", "Fourth line\nFifth line\n"]
10562 *
10563 * With only integer argument +limit+ given,
10564 * limits the number of bytes in the line;
10565 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
10566 *
10567 * $cat t.txt | ruby -e "p readlines 10"
10568 * ["First line", "\n", "Second lin", "e\n", "\n", "Fourth lin", "e\n", "Fifth line", "\n"]
10569 *
10570 * $cat t.txt | ruby -e "p readlines 11"
10571 * ["First line\n", "Second line", "\n", "\n", "Fourth line", "\n", "Fifth line\n"]
10572 *
10573 * $cat t.txt | ruby -e "p readlines 12"
10574 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10575 *
10576 * With arguments +sep+ and +limit+ given,
10577 * combines the two behaviors
10578 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
10579 *
10580 * Optional keyword argument +chomp+ specifies whether line separators
10581 * are to be omitted:
10582 *
10583 * $ cat t.txt | ruby -e "p readlines(chomp: true)"
10584 * ["First line", "Second line", "", "Fourth line", "Fifth line"]
10585 *
10586 * Optional keyword arguments +enc_opts+ specify encoding options;
10587 * see {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
10588 *
10589 */
10590
10591static VALUE
10592rb_f_readlines(int argc, VALUE *argv, VALUE recv)
10593{
10594 if (recv == argf) {
10595 return argf_readlines(argc, argv, argf);
10596 }
10597 return forward(argf, rb_intern("readlines"), argc, argv);
10598}
10599
10600/*
10601 * call-seq:
10602 * ARGF.readlines(sep = $/, chomp: false) -> array
10603 * ARGF.readlines(limit, chomp: false) -> array
10604 * ARGF.readlines(sep, limit, chomp: false) -> array
10605 *
10606 * ARGF.to_a(sep = $/, chomp: false) -> array
10607 * ARGF.to_a(limit, chomp: false) -> array
10608 * ARGF.to_a(sep, limit, chomp: false) -> array
10609 *
10610 * Reads each file in ARGF in its entirety, returning an Array containing
10611 * lines from the files. Lines are assumed to be separated by _sep_.
10612 *
10613 * lines = ARGF.readlines
10614 * lines[0] #=> "This is line one\n"
10615 *
10616 * See +IO.readlines+ for a full description of all options.
10617 */
10618static VALUE
10619argf_readlines(int argc, VALUE *argv, VALUE argf)
10620{
10621 long lineno = ARGF.lineno;
10622 VALUE lines, ary;
10623
10624 ary = rb_ary_new();
10625 while (next_argv()) {
10626 if (ARGF_GENERIC_INPUT_P()) {
10627 lines = forward_current(rb_intern("readlines"), argc, argv);
10628 }
10629 else {
10630 lines = rb_io_readlines(argc, argv, ARGF.current_file);
10631 argf_close(argf);
10632 }
10633 ARGF.next_p = 1;
10634 rb_ary_concat(ary, lines);
10635 ARGF.lineno = lineno + RARRAY_LEN(ary);
10636 ARGF.last_lineno = ARGF.lineno;
10637 }
10638 ARGF.init_p = 0;
10639 return ary;
10640}
10641
10642/*
10643 * call-seq:
10644 * `command` -> string
10645 *
10646 * Returns the <tt>$stdout</tt> output from running +command+ in a subshell;
10647 * sets global variable <tt>$?</tt> to the process status.
10648 *
10649 * This method has potential security vulnerabilities if called with untrusted input;
10650 * see {Command Injection}[rdoc-ref:security/command_injection.rdoc].
10651 *
10652 * Examples:
10653 *
10654 * $ `date` # => "Wed Apr 9 08:56:30 CDT 2003\n"
10655 * $ `echo oops && exit 99` # => "oops\n"
10656 * $ $? # => #<Process::Status: pid 17088 exit 99>
10657 * $ $?.exitstatus # => 99
10658 *
10659 * The built-in syntax <tt>%x{...}</tt> uses this method.
10660 *
10661 */
10662
10663static VALUE
10664rb_f_backquote(VALUE obj, VALUE str)
10665{
10666 VALUE port;
10667 VALUE result;
10668 rb_io_t *fptr;
10669
10670 StringValue(str);
10671 rb_last_status_clear();
10672 port = pipe_open_s(str, "r", FMODE_READABLE|DEFAULT_TEXTMODE, NULL);
10673 if (NIL_P(port)) return rb_str_new(0,0);
10674
10675 GetOpenFile(port, fptr);
10676 result = read_all(fptr, remain_size(fptr), Qnil);
10677 rb_io_close(port);
10678 rb_io_fptr_cleanup_all(fptr);
10679 RB_GC_GUARD(port);
10680
10681 return result;
10682}
10683
10684#ifdef HAVE_SYS_SELECT_H
10685#include <sys/select.h>
10686#endif
10687
10688static VALUE
10689select_internal(VALUE read, VALUE write, VALUE except, struct timeval *tp, rb_fdset_t *fds)
10690{
10691 VALUE res, list;
10692 rb_fdset_t *rp, *wp, *ep;
10693 rb_io_t *fptr;
10694 long i;
10695 int max = 0, n;
10696 int pending = 0;
10697 struct timeval timerec;
10698
10699 if (!NIL_P(read)) {
10700 Check_Type(read, T_ARRAY);
10701 for (i=0; i<RARRAY_LEN(read); i++) {
10702 GetOpenFile(rb_io_get_io(RARRAY_AREF(read, i)), fptr);
10703 rb_fd_set(fptr->fd, &fds[0]);
10704 if (READ_DATA_PENDING(fptr) || READ_CHAR_PENDING(fptr)) { /* check for buffered data */
10705 pending++;
10706 rb_fd_set(fptr->fd, &fds[3]);
10707 }
10708 if (max < fptr->fd) max = fptr->fd;
10709 }
10710 if (pending) { /* no blocking if there's buffered data */
10711 timerec.tv_sec = timerec.tv_usec = 0;
10712 tp = &timerec;
10713 }
10714 rp = &fds[0];
10715 }
10716 else
10717 rp = 0;
10718
10719 if (!NIL_P(write)) {
10720 Check_Type(write, T_ARRAY);
10721 for (i=0; i<RARRAY_LEN(write); i++) {
10722 VALUE write_io = GetWriteIO(rb_io_get_io(RARRAY_AREF(write, i)));
10723 GetOpenFile(write_io, fptr);
10724 rb_fd_set(fptr->fd, &fds[1]);
10725 if (max < fptr->fd) max = fptr->fd;
10726 }
10727 wp = &fds[1];
10728 }
10729 else
10730 wp = 0;
10731
10732 if (!NIL_P(except)) {
10733 Check_Type(except, T_ARRAY);
10734 for (i=0; i<RARRAY_LEN(except); i++) {
10735 VALUE io = rb_io_get_io(RARRAY_AREF(except, i));
10736 VALUE write_io = GetWriteIO(io);
10737 GetOpenFile(io, fptr);
10738 rb_fd_set(fptr->fd, &fds[2]);
10739 if (max < fptr->fd) max = fptr->fd;
10740 if (io != write_io) {
10741 GetOpenFile(write_io, fptr);
10742 rb_fd_set(fptr->fd, &fds[2]);
10743 if (max < fptr->fd) max = fptr->fd;
10744 }
10745 }
10746 ep = &fds[2];
10747 }
10748 else {
10749 ep = 0;
10750 }
10751
10752 max++;
10753
10754 n = rb_thread_fd_select(max, rp, wp, ep, tp);
10755 if (n < 0) {
10756 rb_sys_fail(0);
10757 }
10758 if (!pending && n == 0) return Qnil; /* returns nil on timeout */
10759
10760 res = rb_ary_new2(3);
10761 rb_ary_push(res, rp?rb_ary_new():rb_ary_new2(0));
10762 rb_ary_push(res, wp?rb_ary_new():rb_ary_new2(0));
10763 rb_ary_push(res, ep?rb_ary_new():rb_ary_new2(0));
10764
10765 if (rp) {
10766 list = RARRAY_AREF(res, 0);
10767 for (i=0; i< RARRAY_LEN(read); i++) {
10768 VALUE obj = rb_ary_entry(read, i);
10769 VALUE io = rb_io_get_io(obj);
10770 GetOpenFile(io, fptr);
10771 if (rb_fd_isset(fptr->fd, &fds[0]) ||
10772 rb_fd_isset(fptr->fd, &fds[3])) {
10773 rb_ary_push(list, obj);
10774 }
10775 }
10776 }
10777
10778 if (wp) {
10779 list = RARRAY_AREF(res, 1);
10780 for (i=0; i< RARRAY_LEN(write); i++) {
10781 VALUE obj = rb_ary_entry(write, i);
10782 VALUE io = rb_io_get_io(obj);
10783 VALUE write_io = GetWriteIO(io);
10784 GetOpenFile(write_io, fptr);
10785 if (rb_fd_isset(fptr->fd, &fds[1])) {
10786 rb_ary_push(list, obj);
10787 }
10788 }
10789 }
10790
10791 if (ep) {
10792 list = RARRAY_AREF(res, 2);
10793 for (i=0; i< RARRAY_LEN(except); i++) {
10794 VALUE obj = rb_ary_entry(except, i);
10795 VALUE io = rb_io_get_io(obj);
10796 VALUE write_io = GetWriteIO(io);
10797 GetOpenFile(io, fptr);
10798 if (rb_fd_isset(fptr->fd, &fds[2])) {
10799 rb_ary_push(list, obj);
10800 }
10801 else if (io != write_io) {
10802 GetOpenFile(write_io, fptr);
10803 if (rb_fd_isset(fptr->fd, &fds[2])) {
10804 rb_ary_push(list, obj);
10805 }
10806 }
10807 }
10808 }
10809
10810 return res; /* returns an empty array on interrupt */
10811}
10812
10814 VALUE read, write, except;
10815 struct timeval *timeout;
10816 rb_fdset_t fdsets[4];
10817};
10818
10819static VALUE
10820select_call(VALUE arg)
10821{
10822 struct select_args *p = (struct select_args *)arg;
10823
10824 return select_internal(p->read, p->write, p->except, p->timeout, p->fdsets);
10825}
10826
10827static VALUE
10828select_end(VALUE arg)
10829{
10830 struct select_args *p = (struct select_args *)arg;
10831 int i;
10832
10833 for (i = 0; i < numberof(p->fdsets); ++i)
10834 rb_fd_term(&p->fdsets[i]);
10835 return Qnil;
10836}
10837
10838static VALUE sym_normal, sym_sequential, sym_random,
10839 sym_willneed, sym_dontneed, sym_noreuse;
10840
10841#ifdef HAVE_POSIX_FADVISE
10842struct io_advise_struct {
10843 int fd;
10844 int advice;
10845 rb_off_t offset;
10846 rb_off_t len;
10847};
10848
10849static VALUE
10850io_advise_internal(void *arg)
10851{
10852 struct io_advise_struct *ptr = arg;
10853 return posix_fadvise(ptr->fd, ptr->offset, ptr->len, ptr->advice);
10854}
10855
10856static VALUE
10857io_advise_sym_to_const(VALUE sym)
10858{
10859#ifdef POSIX_FADV_NORMAL
10860 if (sym == sym_normal)
10861 return INT2NUM(POSIX_FADV_NORMAL);
10862#endif
10863
10864#ifdef POSIX_FADV_RANDOM
10865 if (sym == sym_random)
10866 return INT2NUM(POSIX_FADV_RANDOM);
10867#endif
10868
10869#ifdef POSIX_FADV_SEQUENTIAL
10870 if (sym == sym_sequential)
10871 return INT2NUM(POSIX_FADV_SEQUENTIAL);
10872#endif
10873
10874#ifdef POSIX_FADV_WILLNEED
10875 if (sym == sym_willneed)
10876 return INT2NUM(POSIX_FADV_WILLNEED);
10877#endif
10878
10879#ifdef POSIX_FADV_DONTNEED
10880 if (sym == sym_dontneed)
10881 return INT2NUM(POSIX_FADV_DONTNEED);
10882#endif
10883
10884#ifdef POSIX_FADV_NOREUSE
10885 if (sym == sym_noreuse)
10886 return INT2NUM(POSIX_FADV_NOREUSE);
10887#endif
10888
10889 return Qnil;
10890}
10891
10892static VALUE
10893do_io_advise(rb_io_t *fptr, VALUE advice, rb_off_t offset, rb_off_t len)
10894{
10895 int rv;
10896 struct io_advise_struct ias;
10897 VALUE num_adv;
10898
10899 num_adv = io_advise_sym_to_const(advice);
10900
10901 /*
10902 * The platform doesn't support this hint. We don't raise exception, instead
10903 * silently ignore it. Because IO::advise is only hint.
10904 */
10905 if (NIL_P(num_adv))
10906 return Qnil;
10907
10908 ias.fd = fptr->fd;
10909 ias.advice = NUM2INT(num_adv);
10910 ias.offset = offset;
10911 ias.len = len;
10912
10913 rv = (int)rb_io_blocking_region(fptr, io_advise_internal, &ias);
10914 if (rv && rv != ENOSYS) {
10915 /* posix_fadvise(2) doesn't set errno. On success it returns 0; otherwise
10916 it returns the error code. */
10917 VALUE message = rb_sprintf("%"PRIsVALUE" "
10918 "(%"PRI_OFFT_PREFIX"d, "
10919 "%"PRI_OFFT_PREFIX"d, "
10920 "%"PRIsVALUE")",
10921 fptr->pathv, offset, len, advice);
10922 rb_syserr_fail_str(rv, message);
10923 }
10924
10925 return Qnil;
10926}
10927
10928#endif /* HAVE_POSIX_FADVISE */
10929
10930static void
10931advice_arg_check(VALUE advice)
10932{
10933 if (!SYMBOL_P(advice))
10934 rb_raise(rb_eTypeError, "advice must be a Symbol");
10935
10936 if (advice != sym_normal &&
10937 advice != sym_sequential &&
10938 advice != sym_random &&
10939 advice != sym_willneed &&
10940 advice != sym_dontneed &&
10941 advice != sym_noreuse) {
10942 rb_raise(rb_eNotImpError, "Unsupported advice: %+"PRIsVALUE, advice);
10943 }
10944}
10945
10946/*
10947 * call-seq:
10948 * advise(advice, offset = 0, len = 0) -> nil
10949 *
10950 * Invokes Posix system call
10951 * {posix_fadvise(2)}[https://linux.die.net/man/2/posix_fadvise],
10952 * which announces an intention to access data from the current file
10953 * in a particular manner.
10954 *
10955 * The arguments and results are platform-dependent.
10956 *
10957 * The relevant data is specified by:
10958 *
10959 * - +offset+: The offset of the first byte of data.
10960 * - +len+: The number of bytes to be accessed;
10961 * if +len+ is zero, or is larger than the number of bytes remaining,
10962 * all remaining bytes will be accessed.
10963 *
10964 * Argument +advice+ is one of the following symbols:
10965 *
10966 * - +:normal+: The application has no advice to give
10967 * about its access pattern for the specified data.
10968 * If no advice is given for an open file, this is the default assumption.
10969 * - +:sequential+: The application expects to access the specified data sequentially
10970 * (with lower offsets read before higher ones).
10971 * - +:random+: The specified data will be accessed in random order.
10972 * - +:noreuse+: The specified data will be accessed only once.
10973 * - +:willneed+: The specified data will be accessed in the near future.
10974 * - +:dontneed+: The specified data will not be accessed in the near future.
10975 *
10976 * Not implemented on all platforms.
10977 *
10978 */
10979static VALUE
10980rb_io_advise(int argc, VALUE *argv, VALUE io)
10981{
10982 VALUE advice, offset, len;
10983 rb_off_t off, l;
10984 rb_io_t *fptr;
10985
10986 rb_scan_args(argc, argv, "12", &advice, &offset, &len);
10987 advice_arg_check(advice);
10988
10989 io = GetWriteIO(io);
10990 GetOpenFile(io, fptr);
10991
10992 off = NIL_P(offset) ? 0 : NUM2OFFT(offset);
10993 l = NIL_P(len) ? 0 : NUM2OFFT(len);
10994
10995#ifdef HAVE_POSIX_FADVISE
10996 return do_io_advise(fptr, advice, off, l);
10997#else
10998 ((void)off, (void)l); /* Ignore all hint */
10999 return Qnil;
11000#endif
11001}
11002
11003static int
11004is_pos_inf(VALUE x)
11005{
11006 double f;
11007 if (!RB_FLOAT_TYPE_P(x))
11008 return 0;
11009 f = RFLOAT_VALUE(x);
11010 return isinf(f) && 0 < f;
11011}
11012
11013/*
11014 * call-seq:
11015 * IO.select(read_ios, write_ios = [], error_ios = [], timeout = nil) -> array or nil
11016 *
11017 * Invokes system call {select(2)}[https://linux.die.net/man/2/select],
11018 * which monitors multiple file descriptors,
11019 * waiting until one or more of the file descriptors
11020 * becomes ready for some class of I/O operation.
11021 *
11022 * Not implemented on all platforms.
11023 *
11024 * Each of the arguments +read_ios+, +write_ios+, and +error_ios+
11025 * is an array of IO objects.
11026 *
11027 * Argument +timeout+ is a numeric value (such as integer or float) timeout
11028 * interval in seconds.
11029 * +timeout+ can also be +nil+ or +Float::INFINITY+.
11030 * +nil+ and +Float::INFINITY+ means no timeout.
11031 *
11032 * The method monitors the \IO objects given in all three arrays,
11033 * waiting for some to be ready;
11034 * returns a 3-element array whose elements are:
11035 *
11036 * - An array of the objects in +read_ios+ that are ready for reading.
11037 * - An array of the objects in +write_ios+ that are ready for writing.
11038 * - An array of the objects in +error_ios+ have pending exceptions.
11039 *
11040 * If no object becomes ready within the given +timeout+, +nil+ is returned.
11041 *
11042 * \IO.select peeks the buffer of \IO objects for testing readability.
11043 * If the \IO buffer is not empty, \IO.select immediately notifies
11044 * readability. This "peek" only happens for \IO objects. It does not
11045 * happen for IO-like objects such as OpenSSL::SSL::SSLSocket.
11046 *
11047 * The best way to use \IO.select is invoking it after non-blocking
11048 * methods such as #read_nonblock, #write_nonblock, etc. The methods
11049 * raise an exception which is extended by IO::WaitReadable or
11050 * IO::WaitWritable. The modules notify how the caller should wait
11051 * with \IO.select. If IO::WaitReadable is raised, the caller should
11052 * wait for reading. If IO::WaitWritable is raised, the caller should
11053 * wait for writing.
11054 *
11055 * So, blocking read (#readpartial) can be emulated using
11056 * #read_nonblock and \IO.select as follows:
11057 *
11058 * begin
11059 * result = io_like.read_nonblock(maxlen)
11060 * rescue IO::WaitReadable
11061 * IO.select([io_like])
11062 * retry
11063 * rescue IO::WaitWritable
11064 * IO.select(nil, [io_like])
11065 * retry
11066 * end
11067 *
11068 * Especially, the combination of non-blocking methods and \IO.select is
11069 * preferred for IO like objects such as OpenSSL::SSL::SSLSocket. It
11070 * has #to_io method to return underlying IO object. IO.select calls
11071 * #to_io to obtain the file descriptor to wait.
11072 *
11073 * This means that readability notified by \IO.select doesn't mean
11074 * readability from OpenSSL::SSL::SSLSocket object.
11075 *
11076 * The most likely situation is that OpenSSL::SSL::SSLSocket buffers
11077 * some data. \IO.select doesn't see the buffer. So \IO.select can
11078 * block when OpenSSL::SSL::SSLSocket#readpartial doesn't block.
11079 *
11080 * However, several more complicated situations exist.
11081 *
11082 * SSL is a protocol which is sequence of records.
11083 * The record consists of multiple bytes.
11084 * So, the remote side of SSL sends a partial record, IO.select
11085 * notifies readability but OpenSSL::SSL::SSLSocket cannot decrypt a
11086 * byte and OpenSSL::SSL::SSLSocket#readpartial will block.
11087 *
11088 * Also, the remote side can request SSL renegotiation which forces
11089 * the local SSL engine to write some data.
11090 * This means OpenSSL::SSL::SSLSocket#readpartial may invoke #write
11091 * system call and it can block.
11092 * In such a situation, OpenSSL::SSL::SSLSocket#read_nonblock raises
11093 * IO::WaitWritable instead of blocking.
11094 * So, the caller should wait for ready for writability as above
11095 * example.
11096 *
11097 * The combination of non-blocking methods and \IO.select is also useful
11098 * for streams such as tty, pipe socket socket when multiple processes
11099 * read from a stream.
11100 *
11101 * Finally, Linux kernel developers don't guarantee that
11102 * readability of select(2) means readability of following read(2) even
11103 * for a single process;
11104 * see {select(2)}[https://linux.die.net/man/2/select]
11105 *
11106 * Invoking \IO.select before IO#readpartial works well as usual.
11107 * However it is not the best way to use \IO.select.
11108 *
11109 * The writability notified by select(2) doesn't show
11110 * how many bytes are writable.
11111 * IO#write method blocks until given whole string is written.
11112 * So, <tt>IO#write(two or more bytes)</tt> can block after
11113 * writability is notified by \IO.select. IO#write_nonblock is required
11114 * to avoid the blocking.
11115 *
11116 * Blocking write (#write) can be emulated using #write_nonblock and
11117 * IO.select as follows: IO::WaitReadable should also be rescued for
11118 * SSL renegotiation in OpenSSL::SSL::SSLSocket.
11119 *
11120 * while 0 < string.bytesize
11121 * begin
11122 * written = io_like.write_nonblock(string)
11123 * rescue IO::WaitReadable
11124 * IO.select([io_like])
11125 * retry
11126 * rescue IO::WaitWritable
11127 * IO.select(nil, [io_like])
11128 * retry
11129 * end
11130 * string = string.byteslice(written..-1)
11131 * end
11132 *
11133 * Example:
11134 *
11135 * rp, wp = IO.pipe
11136 * mesg = "ping "
11137 * 100.times {
11138 * # IO.select follows IO#read. Not the best way to use IO.select.
11139 * rs, ws, = IO.select([rp], [wp])
11140 * if r = rs[0]
11141 * ret = r.read(5)
11142 * print ret
11143 * case ret
11144 * when /ping/
11145 * mesg = "pong\n"
11146 * when /pong/
11147 * mesg = "ping "
11148 * end
11149 * end
11150 * if w = ws[0]
11151 * w.write(mesg)
11152 * end
11153 * }
11154 *
11155 * Output:
11156 *
11157 * ping pong
11158 * ping pong
11159 * ping pong
11160 * (snipped)
11161 * ping
11162 *
11163 */
11164
11165static VALUE
11166rb_f_select(int argc, VALUE *argv, VALUE obj)
11167{
11168 VALUE scheduler = rb_fiber_scheduler_current();
11169 if (scheduler != Qnil) {
11170 // It's optionally supported.
11171 VALUE result = rb_fiber_scheduler_io_selectv(scheduler, argc, argv);
11172 if (!UNDEF_P(result)) return result;
11173 }
11174
11175 VALUE timeout;
11176 struct select_args args;
11177 struct timeval timerec;
11178 int i;
11179
11180 rb_scan_args(argc, argv, "13", &args.read, &args.write, &args.except, &timeout);
11181 if (NIL_P(timeout) || is_pos_inf(timeout)) {
11182 args.timeout = 0;
11183 }
11184 else {
11185 timerec = rb_time_interval(timeout);
11186 args.timeout = &timerec;
11187 }
11188
11189 for (i = 0; i < numberof(args.fdsets); ++i)
11190 rb_fd_init(&args.fdsets[i]);
11191
11192 return rb_ensure(select_call, (VALUE)&args, select_end, (VALUE)&args);
11193}
11194
11195#ifdef IOCTL_REQ_TYPE
11196 typedef IOCTL_REQ_TYPE ioctl_req_t;
11197#else
11198 typedef int ioctl_req_t;
11199# define NUM2IOCTLREQ(num) ((int)NUM2LONG(num))
11200#endif
11201
11202#ifdef HAVE_IOCTL
11203struct ioctl_arg {
11204 int fd;
11205 ioctl_req_t cmd;
11206 long narg;
11207};
11208
11209static VALUE
11210nogvl_ioctl(void *ptr)
11211{
11212 struct ioctl_arg *arg = ptr;
11213
11214 return (VALUE)ioctl(arg->fd, arg->cmd, arg->narg);
11215}
11216
11217static int
11218do_ioctl(struct rb_io *io, ioctl_req_t cmd, long narg)
11219{
11220 int retval;
11221 struct ioctl_arg arg;
11222
11223 arg.fd = io->fd;
11224 arg.cmd = cmd;
11225 arg.narg = narg;
11226
11227 retval = (int)rb_io_blocking_region(io, nogvl_ioctl, &arg);
11228
11229 return retval;
11230}
11231#endif
11232
11233#define DEFAULT_IOCTL_NARG_LEN (256)
11234
11235#if defined(__linux__) && defined(_IOC_SIZE)
11236static long
11237linux_iocparm_len(ioctl_req_t cmd)
11238{
11239 long len;
11240
11241 if ((cmd & 0xFFFF0000) == 0) {
11242 /* legacy and unstructured ioctl number. */
11243 return DEFAULT_IOCTL_NARG_LEN;
11244 }
11245
11246 len = _IOC_SIZE(cmd);
11247
11248 /* paranoia check for silly drivers which don't keep ioctl convention */
11249 if (len < DEFAULT_IOCTL_NARG_LEN)
11250 len = DEFAULT_IOCTL_NARG_LEN;
11251
11252 return len;
11253}
11254#endif
11255
11256#ifdef HAVE_IOCTL
11257static long
11258ioctl_narg_len(ioctl_req_t cmd)
11259{
11260 long len;
11261
11262#ifdef IOCPARM_MASK
11263#ifndef IOCPARM_LEN
11264#define IOCPARM_LEN(x) (((x) >> 16) & IOCPARM_MASK)
11265#endif
11266#endif
11267#ifdef IOCPARM_LEN
11268 len = IOCPARM_LEN(cmd); /* on BSDish systems we're safe */
11269#elif defined(__linux__) && defined(_IOC_SIZE)
11270 len = linux_iocparm_len(cmd);
11271#else
11272 /* otherwise guess at what's safe */
11273 len = DEFAULT_IOCTL_NARG_LEN;
11274#endif
11275
11276 return len;
11277}
11278#endif
11279
11280#ifdef HAVE_FCNTL
11281#ifdef __linux__
11282typedef long fcntl_arg_t;
11283#else
11284/* posix */
11285typedef int fcntl_arg_t;
11286#endif
11287
11288static long
11289fcntl_narg_len(ioctl_req_t cmd)
11290{
11291 long len;
11292
11293 switch (cmd) {
11294#ifdef F_DUPFD
11295 case F_DUPFD:
11296 len = sizeof(fcntl_arg_t);
11297 break;
11298#endif
11299#ifdef F_DUP2FD /* bsd specific */
11300 case F_DUP2FD:
11301 len = sizeof(int);
11302 break;
11303#endif
11304#ifdef F_DUPFD_CLOEXEC /* linux specific */
11305 case F_DUPFD_CLOEXEC:
11306 len = sizeof(fcntl_arg_t);
11307 break;
11308#endif
11309#ifdef F_GETFD
11310 case F_GETFD:
11311 len = 1;
11312 break;
11313#endif
11314#ifdef F_SETFD
11315 case F_SETFD:
11316 len = sizeof(fcntl_arg_t);
11317 break;
11318#endif
11319#ifdef F_GETFL
11320 case F_GETFL:
11321 len = 1;
11322 break;
11323#endif
11324#ifdef F_SETFL
11325 case F_SETFL:
11326 len = sizeof(fcntl_arg_t);
11327 break;
11328#endif
11329#ifdef F_GETOWN
11330 case F_GETOWN:
11331 len = 1;
11332 break;
11333#endif
11334#ifdef F_SETOWN
11335 case F_SETOWN:
11336 len = sizeof(fcntl_arg_t);
11337 break;
11338#endif
11339#ifdef F_GETOWN_EX /* linux specific */
11340 case F_GETOWN_EX:
11341 len = sizeof(struct f_owner_ex);
11342 break;
11343#endif
11344#ifdef F_SETOWN_EX /* linux specific */
11345 case F_SETOWN_EX:
11346 len = sizeof(struct f_owner_ex);
11347 break;
11348#endif
11349#ifdef F_GETLK
11350 case F_GETLK:
11351 len = sizeof(struct flock);
11352 break;
11353#endif
11354#ifdef F_SETLK
11355 case F_SETLK:
11356 len = sizeof(struct flock);
11357 break;
11358#endif
11359#ifdef F_SETLKW
11360 case F_SETLKW:
11361 len = sizeof(struct flock);
11362 break;
11363#endif
11364#ifdef F_READAHEAD /* bsd specific */
11365 case F_READAHEAD:
11366 len = sizeof(int);
11367 break;
11368#endif
11369#ifdef F_RDAHEAD /* Darwin specific */
11370 case F_RDAHEAD:
11371 len = sizeof(int);
11372 break;
11373#endif
11374#ifdef F_GETSIG /* linux specific */
11375 case F_GETSIG:
11376 len = 1;
11377 break;
11378#endif
11379#ifdef F_SETSIG /* linux specific */
11380 case F_SETSIG:
11381 len = sizeof(fcntl_arg_t);
11382 break;
11383#endif
11384#ifdef F_GETLEASE /* linux specific */
11385 case F_GETLEASE:
11386 len = 1;
11387 break;
11388#endif
11389#ifdef F_SETLEASE /* linux specific */
11390 case F_SETLEASE:
11391 len = sizeof(fcntl_arg_t);
11392 break;
11393#endif
11394#ifdef F_NOTIFY /* linux specific */
11395 case F_NOTIFY:
11396 len = sizeof(fcntl_arg_t);
11397 break;
11398#endif
11399
11400 default:
11401 len = 256;
11402 break;
11403 }
11404
11405 return len;
11406}
11407#else /* HAVE_FCNTL */
11408static long
11409fcntl_narg_len(ioctl_req_t cmd)
11410{
11411 return 0;
11412}
11413#endif /* HAVE_FCNTL */
11414
11415#define NARG_SENTINEL 17
11416
11417static long
11418setup_narg(ioctl_req_t cmd, VALUE *argp, long (*narg_len)(ioctl_req_t))
11419{
11420 long narg = 0;
11421 VALUE arg = *argp;
11422
11423 if (!RTEST(arg)) {
11424 narg = 0;
11425 }
11426 else if (FIXNUM_P(arg)) {
11427 narg = FIX2LONG(arg);
11428 }
11429 else if (arg == Qtrue) {
11430 narg = 1;
11431 }
11432 else {
11433 VALUE tmp = rb_check_string_type(arg);
11434
11435 if (NIL_P(tmp)) {
11436 narg = NUM2LONG(arg);
11437 }
11438 else {
11439 char *ptr;
11440 long len, slen;
11441
11442 *argp = arg = tmp;
11443 len = narg_len(cmd);
11444 rb_str_modify(arg);
11445
11446 slen = RSTRING_LEN(arg);
11447 /* expand for data + sentinel. */
11448 if (slen < len+1) {
11449 rb_str_resize(arg, len+1);
11450 MEMZERO(RSTRING_PTR(arg)+slen, char, len-slen);
11451 slen = len+1;
11452 }
11453 /* a little sanity check here */
11454 ptr = RSTRING_PTR(arg);
11455 ptr[slen - 1] = NARG_SENTINEL;
11456 narg = (long)(SIGNED_VALUE)ptr;
11457 }
11458 }
11459
11460 return narg;
11461}
11462
11463static VALUE
11464finish_narg(int retval, VALUE arg, const rb_io_t *fptr)
11465{
11466 if (retval < 0) rb_sys_fail_path(fptr->pathv);
11467 if (RB_TYPE_P(arg, T_STRING)) {
11468 char *ptr;
11469 long slen;
11470 RSTRING_GETMEM(arg, ptr, slen);
11471 if (ptr[slen-1] != NARG_SENTINEL)
11472 rb_raise(rb_eArgError, "return value overflowed string");
11473 ptr[slen-1] = '\0';
11474 }
11475
11476 return INT2NUM(retval);
11477}
11478
11479#ifdef HAVE_IOCTL
11480static VALUE
11481rb_ioctl(VALUE io, VALUE req, VALUE arg)
11482{
11483 ioctl_req_t cmd = NUM2IOCTLREQ(req);
11484 rb_io_t *fptr;
11485 long narg;
11486 int retval;
11487
11488 narg = setup_narg(cmd, &arg, ioctl_narg_len);
11489 GetOpenFile(io, fptr);
11490 retval = do_ioctl(fptr, cmd, narg);
11491 return finish_narg(retval, arg, fptr);
11492}
11493
11494/*
11495 * call-seq:
11496 * ioctl(integer_cmd, argument) -> integer
11497 *
11498 * Invokes Posix system call {ioctl(2)}[https://linux.die.net/man/2/ioctl],
11499 * which issues a low-level command to an I/O device.
11500 *
11501 * Issues a low-level command to an I/O device.
11502 * The arguments and returned value are platform-dependent.
11503 * The effect of the call is platform-dependent.
11504 *
11505 * If argument +argument+ is an integer, it is passed directly;
11506 * if it is a string, it is interpreted as a binary sequence of bytes.
11507 *
11508 * Not implemented on all platforms.
11509 *
11510 */
11511
11512static VALUE
11513rb_io_ioctl(int argc, VALUE *argv, VALUE io)
11514{
11515 VALUE req, arg;
11516
11517 rb_scan_args(argc, argv, "11", &req, &arg);
11518 return rb_ioctl(io, req, arg);
11519}
11520#else
11521#define rb_io_ioctl rb_f_notimplement
11522#endif
11523
11524#ifdef HAVE_FCNTL
11525struct fcntl_arg {
11526 int fd;
11527 int cmd;
11528 long narg;
11529};
11530
11531static VALUE
11532nogvl_fcntl(void *ptr)
11533{
11534 struct fcntl_arg *arg = ptr;
11535
11536#if defined(F_DUPFD)
11537 if (arg->cmd == F_DUPFD)
11538 return (VALUE)rb_cloexec_fcntl_dupfd(arg->fd, (int)arg->narg);
11539#endif
11540 return (VALUE)fcntl(arg->fd, arg->cmd, arg->narg);
11541}
11542
11543static int
11544do_fcntl(struct rb_io *io, int cmd, long narg)
11545{
11546 int retval;
11547 struct fcntl_arg arg;
11548
11549 arg.fd = io->fd;
11550 arg.cmd = cmd;
11551 arg.narg = narg;
11552
11553 retval = (int)rb_io_blocking_region(io, nogvl_fcntl, &arg);
11554 if (retval != -1) {
11555 switch (cmd) {
11556#if defined(F_DUPFD)
11557 case F_DUPFD:
11558#endif
11559#if defined(F_DUPFD_CLOEXEC)
11560 case F_DUPFD_CLOEXEC:
11561#endif
11562 rb_update_max_fd(retval);
11563 }
11564 }
11565
11566 return retval;
11567}
11568
11569static VALUE
11570rb_fcntl(VALUE io, VALUE req, VALUE arg)
11571{
11572 int cmd = NUM2INT(req);
11573 rb_io_t *fptr;
11574 long narg;
11575 int retval;
11576
11577 narg = setup_narg(cmd, &arg, fcntl_narg_len);
11578 GetOpenFile(io, fptr);
11579 retval = do_fcntl(fptr, cmd, narg);
11580 return finish_narg(retval, arg, fptr);
11581}
11582
11583/*
11584 * call-seq:
11585 * fcntl(integer_cmd, argument) -> integer
11586 *
11587 * Invokes Posix system call {fcntl(2)}[https://linux.die.net/man/2/fcntl],
11588 * which provides a mechanism for issuing low-level commands to control or query
11589 * a file-oriented I/O stream. Arguments and results are platform
11590 * dependent.
11591 *
11592 * If +argument+ is a number, its value is passed directly;
11593 * if it is a string, it is interpreted as a binary sequence of bytes.
11594 * (Array#pack might be a useful way to build this string.)
11595 *
11596 * Not implemented on all platforms.
11597 *
11598 */
11599
11600static VALUE
11601rb_io_fcntl(int argc, VALUE *argv, VALUE io)
11602{
11603 VALUE req, arg;
11604
11605 rb_scan_args(argc, argv, "11", &req, &arg);
11606 return rb_fcntl(io, req, arg);
11607}
11608#else
11609#define rb_io_fcntl rb_f_notimplement
11610#endif
11611
11612#if defined(HAVE_SYSCALL) || defined(HAVE___SYSCALL)
11613/*
11614 * call-seq:
11615 * syscall(integer_callno, *arguments) -> integer
11616 *
11617 * Invokes Posix system call {syscall(2)}[https://linux.die.net/man/2/syscall],
11618 * which calls a specified function.
11619 *
11620 * Calls the operating system function identified by +integer_callno+;
11621 * returns the result of the function or raises SystemCallError if it failed.
11622 * The effect of the call is platform-dependent.
11623 * The arguments and returned value are platform-dependent.
11624 *
11625 * For each of +arguments+: if it is an integer, it is passed directly;
11626 * if it is a string, it is interpreted as a binary sequence of bytes.
11627 * There may be as many as nine such arguments.
11628 *
11629 * Arguments +integer_callno+ and +argument+, as well as the returned value,
11630 * are platform-dependent.
11631 *
11632 * Note: Method +syscall+ is essentially unsafe and unportable.
11633 * The DL (Fiddle) library is preferred for safer and a bit
11634 * more portable programming.
11635 *
11636 * Not implemented on all platforms.
11637 *
11638 */
11639
11640static VALUE
11641rb_f_syscall(int argc, VALUE *argv, VALUE _)
11642{
11643 VALUE arg[8];
11644#if SIZEOF_VOIDP == 8 && defined(HAVE___SYSCALL) && SIZEOF_INT != 8 /* mainly *BSD */
11645# define SYSCALL __syscall
11646# define NUM2SYSCALLID(x) NUM2LONG(x)
11647# define RETVAL2NUM(x) LONG2NUM(x)
11648# if SIZEOF_LONG == 8
11649 long num, retval = -1;
11650# elif SIZEOF_LONG_LONG == 8
11651 long long num, retval = -1;
11652# else
11653# error ---->> it is asserted that __syscall takes the first argument and returns retval in 64bit signed integer. <<----
11654# endif
11655#elif defined(__linux__)
11656# define SYSCALL syscall
11657# define NUM2SYSCALLID(x) NUM2LONG(x)
11658# define RETVAL2NUM(x) LONG2NUM(x)
11659 /*
11660 * Linux man page says, syscall(2) function prototype is below.
11661 *
11662 * int syscall(int number, ...);
11663 *
11664 * But, it's incorrect. Actual one takes and returned long. (see unistd.h)
11665 */
11666 long num, retval = -1;
11667#else
11668# define SYSCALL syscall
11669# define NUM2SYSCALLID(x) NUM2INT(x)
11670# define RETVAL2NUM(x) INT2NUM(x)
11671 int num, retval = -1;
11672#endif
11673 int i;
11674
11675 if (RTEST(ruby_verbose)) {
11677 "We plan to remove a syscall function at future release. DL(Fiddle) provides safer alternative.");
11678 }
11679
11680 if (argc == 0)
11681 rb_raise(rb_eArgError, "too few arguments for syscall");
11682 if (argc > numberof(arg))
11683 rb_raise(rb_eArgError, "too many arguments for syscall");
11684 num = NUM2SYSCALLID(argv[0]); ++argv;
11685 for (i = argc - 1; i--; ) {
11686 VALUE v = rb_check_string_type(argv[i]);
11687
11688 if (!NIL_P(v)) {
11689 StringValue(v);
11690 rb_str_modify(v);
11691 arg[i] = (VALUE)StringValueCStr(v);
11692 }
11693 else {
11694 arg[i] = (VALUE)NUM2LONG(argv[i]);
11695 }
11696 }
11697
11698 switch (argc) {
11699 case 1:
11700 retval = SYSCALL(num);
11701 break;
11702 case 2:
11703 retval = SYSCALL(num, arg[0]);
11704 break;
11705 case 3:
11706 retval = SYSCALL(num, arg[0],arg[1]);
11707 break;
11708 case 4:
11709 retval = SYSCALL(num, arg[0],arg[1],arg[2]);
11710 break;
11711 case 5:
11712 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3]);
11713 break;
11714 case 6:
11715 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4]);
11716 break;
11717 case 7:
11718 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5]);
11719 break;
11720 case 8:
11721 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6]);
11722 break;
11723 }
11724
11725 if (retval == -1)
11726 rb_sys_fail(0);
11727 return RETVAL2NUM(retval);
11728#undef SYSCALL
11729#undef NUM2SYSCALLID
11730#undef RETVAL2NUM
11731}
11732#else
11733#define rb_f_syscall rb_f_notimplement
11734#endif
11735
11736static VALUE
11737io_new_instance(VALUE args)
11738{
11739 return rb_class_new_instance(2, (VALUE*)args+1, *(VALUE*)args);
11740}
11741
11742static rb_encoding *
11743find_encoding(VALUE v)
11744{
11745 rb_encoding *enc = rb_find_encoding(v);
11746 if (!enc) rb_warn("Unsupported encoding %"PRIsVALUE" ignored", v);
11747 return enc;
11748}
11749
11750static void
11751io_encoding_set(rb_io_t *fptr, VALUE v1, VALUE v2, VALUE opt)
11752{
11753 rb_encoding *enc, *enc2;
11754 int ecflags = fptr->encs.ecflags;
11755 VALUE ecopts, tmp;
11756
11757 if (!NIL_P(v2)) {
11758 enc2 = find_encoding(v1);
11759 tmp = rb_check_string_type(v2);
11760 if (!NIL_P(tmp)) {
11761 if (RSTRING_LEN(tmp) == 1 && RSTRING_PTR(tmp)[0] == '-') {
11762 /* Special case - "-" => no transcoding */
11763 enc = enc2;
11764 enc2 = NULL;
11765 }
11766 else
11767 enc = find_encoding(v2);
11768 if (enc == enc2) {
11769 /* Special case - "-" => no transcoding */
11770 enc2 = NULL;
11771 }
11772 }
11773 else {
11774 enc = find_encoding(v2);
11775 if (enc == enc2) {
11776 /* Special case - "-" => no transcoding */
11777 enc2 = NULL;
11778 }
11779 }
11780 if (enc2 == rb_ascii8bit_encoding()) {
11781 /* If external is ASCII-8BIT, no transcoding */
11782 enc = enc2;
11783 enc2 = NULL;
11784 }
11785 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11786 ecflags = rb_econv_prepare_options(opt, &ecopts, ecflags);
11787 }
11788 else {
11789 if (NIL_P(v1)) {
11790 /* Set to default encodings */
11791 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
11792 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11793 ecopts = Qnil;
11794 }
11795 else {
11796 tmp = rb_check_string_type(v1);
11797 if (!NIL_P(tmp) && rb_enc_asciicompat(enc = rb_enc_get(tmp))) {
11798 parse_mode_enc(RSTRING_PTR(tmp), enc, &enc, &enc2, NULL);
11799 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11800 ecflags = rb_econv_prepare_options(opt, &ecopts, ecflags);
11801 }
11802 else {
11803 rb_io_ext_int_to_encs(find_encoding(v1), NULL, &enc, &enc2, 0);
11804 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11805 ecopts = Qnil;
11806 }
11807 }
11808 }
11809 validate_enc_binmode(&fptr->mode, ecflags, enc, enc2);
11810 fptr->encs.enc = enc;
11811 fptr->encs.enc2 = enc2;
11812 fptr->encs.ecflags = ecflags;
11813 fptr->encs.ecopts = ecopts;
11814 clear_codeconv(fptr);
11815
11816}
11817
11819 rb_io_t *fptr;
11820 VALUE v1;
11821 VALUE v2;
11822 VALUE opt;
11823};
11824
11825static VALUE
11826io_encoding_set_v(VALUE v)
11827{
11828 struct io_encoding_set_args *arg = (struct io_encoding_set_args *)v;
11829 io_encoding_set(arg->fptr, arg->v1, arg->v2, arg->opt);
11830 return Qnil;
11831}
11832
11833static VALUE
11834pipe_pair_close(VALUE rw)
11835{
11836 VALUE *rwp = (VALUE *)rw;
11837 return rb_ensure(io_close, rwp[0], io_close, rwp[1]);
11838}
11839
11840/*
11841 * call-seq:
11842 * IO.pipe(**opts) -> [read_io, write_io]
11843 * IO.pipe(enc, **opts) -> [read_io, write_io]
11844 * IO.pipe(ext_enc, int_enc, **opts) -> [read_io, write_io]
11845 * IO.pipe(**opts) {|read_io, write_io| ...} -> object
11846 * IO.pipe(enc, **opts) {|read_io, write_io| ...} -> object
11847 * IO.pipe(ext_enc, int_enc, **opts) {|read_io, write_io| ...} -> object
11848 *
11849 * Creates a pair of pipe endpoints, +read_io+ and +write_io+,
11850 * connected to each other.
11851 *
11852 * If argument +enc_string+ is given, it must be a string containing one of:
11853 *
11854 * - The name of the encoding to be used as the external encoding.
11855 * - The colon-separated names of two encodings to be used as the external
11856 * and internal encodings.
11857 *
11858 * If argument +int_enc+ is given, it must be an Encoding object
11859 * or encoding name string that specifies the internal encoding to be used;
11860 * if argument +ext_enc+ is also given, it must be an Encoding object
11861 * or encoding name string that specifies the external encoding to be used.
11862 *
11863 * The string read from +read_io+ is tagged with the external encoding;
11864 * if an internal encoding is also specified, the string is converted
11865 * to, and tagged with, that encoding.
11866 *
11867 * If any encoding is specified,
11868 * optional hash arguments specify the conversion option.
11869 *
11870 * Optional keyword arguments +opts+ specify:
11871 *
11872 * - {Open Options}[rdoc-ref:IO@Open+Options].
11873 * - {Encoding Options}[rdoc-ref:encodings.rdoc@Encoding+Options].
11874 *
11875 * With no block given, returns the two endpoints in an array:
11876 *
11877 * IO.pipe # => [#<IO:fd 4>, #<IO:fd 5>]
11878 *
11879 * With a block given, calls the block with the two endpoints;
11880 * closes both endpoints and returns the value of the block:
11881 *
11882 * IO.pipe {|read_io, write_io| p read_io; p write_io }
11883 *
11884 * Output:
11885 *
11886 * #<IO:fd 6>
11887 * #<IO:fd 7>
11888 *
11889 * Not available on all platforms.
11890 *
11891 * In the example below, the two processes close the ends of the pipe
11892 * that they are not using. This is not just a cosmetic nicety. The
11893 * read end of a pipe will not generate an end of file condition if
11894 * there are any writers with the pipe still open. In the case of the
11895 * parent process, the <tt>rd.read</tt> will never return if it
11896 * does not first issue a <tt>wr.close</tt>:
11897 *
11898 * rd, wr = IO.pipe
11899 *
11900 * if fork
11901 * wr.close
11902 * puts "Parent got: <#{rd.read}>"
11903 * rd.close
11904 * Process.wait
11905 * else
11906 * rd.close
11907 * puts 'Sending message to parent'
11908 * wr.write "Hi Dad"
11909 * wr.close
11910 * end
11911 *
11912 * <em>produces:</em>
11913 *
11914 * Sending message to parent
11915 * Parent got: <Hi Dad>
11916 *
11917 */
11918
11919static VALUE
11920rb_io_s_pipe(int argc, VALUE *argv, VALUE klass)
11921{
11922 int pipes[2], state;
11923 VALUE r, w, args[3], v1, v2;
11924 VALUE opt;
11925 rb_io_t *fptr, *fptr2;
11926 struct io_encoding_set_args ies_args;
11927 enum rb_io_mode fmode = 0;
11928 VALUE ret;
11929
11930 argc = rb_scan_args(argc, argv, "02:", &v1, &v2, &opt);
11931 if (rb_pipe(pipes) < 0)
11932 rb_sys_fail(0);
11933
11934 args[0] = klass;
11935 args[1] = INT2NUM(pipes[0]);
11936 args[2] = INT2FIX(O_RDONLY);
11937 r = rb_protect(io_new_instance, (VALUE)args, &state);
11938 if (state) {
11939 close(pipes[0]);
11940 close(pipes[1]);
11941 rb_jump_tag(state);
11942 }
11943 GetOpenFile(r, fptr);
11944
11945 ies_args.fptr = fptr;
11946 ies_args.v1 = v1;
11947 ies_args.v2 = v2;
11948 ies_args.opt = opt;
11949 rb_protect(io_encoding_set_v, (VALUE)&ies_args, &state);
11950 if (state) {
11951 close(pipes[1]);
11952 io_close(r);
11953 rb_jump_tag(state);
11954 }
11955
11956 args[1] = INT2NUM(pipes[1]);
11957 args[2] = INT2FIX(O_WRONLY);
11958 w = rb_protect(io_new_instance, (VALUE)args, &state);
11959 if (state) {
11960 close(pipes[1]);
11961 if (!NIL_P(r)) rb_io_close(r);
11962 rb_jump_tag(state);
11963 }
11964 GetOpenFile(w, fptr2);
11965 rb_io_synchronized(fptr2);
11966
11967 extract_binmode(opt, &fmode);
11968
11969 if ((fmode & FMODE_BINMODE) && NIL_P(v1)) {
11972 }
11973
11974#if DEFAULT_TEXTMODE
11975 if ((fptr->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
11976 fptr->mode &= ~FMODE_TEXTMODE;
11977 setmode(fptr->fd, O_BINARY);
11978 }
11979#if RUBY_CRLF_ENVIRONMENT
11982 }
11983#endif
11984#endif
11985 fptr->mode |= fmode;
11986#if DEFAULT_TEXTMODE
11987 if ((fptr2->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
11988 fptr2->mode &= ~FMODE_TEXTMODE;
11989 setmode(fptr2->fd, O_BINARY);
11990 }
11991#endif
11992 fptr2->mode |= fmode;
11993
11994 ret = rb_assoc_new(r, w);
11995 if (rb_block_given_p()) {
11996 VALUE rw[2];
11997 rw[0] = r;
11998 rw[1] = w;
11999 return rb_ensure(rb_yield, ret, pipe_pair_close, (VALUE)rw);
12000 }
12001 return ret;
12002}
12003
12005 int argc;
12006 VALUE *argv;
12007 VALUE io;
12008};
12009
12010static void
12011open_key_args(VALUE klass, int argc, VALUE *argv, VALUE opt, struct foreach_arg *arg)
12012{
12013 VALUE path, v;
12014 VALUE vmode = Qnil, vperm = Qnil;
12015
12016 path = *argv++;
12017 argc--;
12018 FilePathValue(path);
12019 arg->io = 0;
12020 arg->argc = argc;
12021 arg->argv = argv;
12022 if (NIL_P(opt)) {
12023 vmode = INT2NUM(O_RDONLY);
12024 vperm = INT2FIX(0666);
12025 }
12026 else if (!NIL_P(v = rb_hash_aref(opt, sym_open_args))) {
12027 int n;
12028
12029 v = rb_to_array_type(v);
12030 n = RARRAY_LENINT(v);
12031 rb_check_arity(n, 0, 3); /* rb_io_open */
12032 rb_scan_args_kw(RB_SCAN_ARGS_LAST_HASH_KEYWORDS, n, RARRAY_CONST_PTR(v), "02:", &vmode, &vperm, &opt);
12033 }
12034 arg->io = rb_io_open(klass, path, vmode, vperm, opt);
12035}
12036
12037static VALUE
12038io_s_foreach(VALUE v)
12039{
12040 struct getline_arg *arg = (void *)v;
12041 VALUE str;
12042
12043 if (arg->limit == 0)
12044 rb_raise(rb_eArgError, "invalid limit: 0 for foreach");
12045 while (!NIL_P(str = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, arg->io))) {
12046 rb_lastline_set(str);
12047 rb_yield(str);
12048 }
12050 return Qnil;
12051}
12052
12053/*
12054 * call-seq:
12055 * IO.foreach(path, sep = $/, **opts) {|line| block } -> nil
12056 * IO.foreach(path, limit, **opts) {|line| block } -> nil
12057 * IO.foreach(path, sep, limit, **opts) {|line| block } -> nil
12058 * IO.foreach(...) -> an_enumerator
12059 *
12060 * Calls the block with each successive line read from the stream.
12061 *
12062 * The first argument must be a string that is the path to a file.
12063 *
12064 * With only argument +path+ given, parses lines from the file at the given +path+,
12065 * as determined by the default line separator,
12066 * and calls the block with each successive line:
12067 *
12068 * File.foreach('t.txt') {|line| p line }
12069 *
12070 * Output: the same as above.
12071 *
12072 * For both forms, command and path, the remaining arguments are the same.
12073 *
12074 * With argument +sep+ given, parses lines as determined by that line separator
12075 * (see {Line Separator}[rdoc-ref:IO@Line+Separator]):
12076 *
12077 * File.foreach('t.txt', 'li') {|line| p line }
12078 *
12079 * Output:
12080 *
12081 * "First li"
12082 * "ne\nSecond li"
12083 * "ne\n\nThird li"
12084 * "ne\nFourth li"
12085 * "ne\n"
12086 *
12087 * Each paragraph:
12088 *
12089 * File.foreach('t.txt', '') {|paragraph| p paragraph }
12090 *
12091 * Output:
12092 *
12093 * "First line\nSecond line\n\n"
12094 * "Third line\nFourth line\n"
12095 *
12096 * With argument +limit+ given, parses lines as determined by the default
12097 * line separator and the given line-length limit
12098 * (see {Line Separator}[rdoc-ref:IO@Line+Separator] and {Line Limit}[rdoc-ref:IO@Line+Limit]):
12099 *
12100 * File.foreach('t.txt', 7) {|line| p line }
12101 *
12102 * Output:
12103 *
12104 * "First l"
12105 * "ine\n"
12106 * "Second "
12107 * "line\n"
12108 * "\n"
12109 * "Third l"
12110 * "ine\n"
12111 * "Fourth l"
12112 * "line\n"
12113 *
12114 * With arguments +sep+ and +limit+ given,
12115 * combines the two behaviors
12116 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
12117 *
12118 * Optional keyword arguments +opts+ specify:
12119 *
12120 * - {Open Options}[rdoc-ref:IO@Open+Options].
12121 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12122 * - {Line Options}[rdoc-ref:IO@Line+IO].
12123 *
12124 * Returns an Enumerator if no block is given.
12125 *
12126 */
12127
12128static VALUE
12129rb_io_s_foreach(int argc, VALUE *argv, VALUE self)
12130{
12131 VALUE opt;
12132 int orig_argc = argc;
12133 struct foreach_arg arg;
12134 struct getline_arg garg;
12135
12136 argc = rb_scan_args(argc, argv, "12:", NULL, NULL, NULL, &opt);
12137 RETURN_ENUMERATOR(self, orig_argc, argv);
12138 extract_getline_args(argc-1, argv+1, &garg);
12139 open_key_args(self, argc, argv, opt, &arg);
12140 if (NIL_P(arg.io)) return Qnil;
12141 extract_getline_opts(opt, &garg);
12142 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12143 return rb_ensure(io_s_foreach, (VALUE)&garg, rb_io_close, arg.io);
12144}
12145
12146static VALUE
12147io_s_readlines(VALUE v)
12148{
12149 struct getline_arg *arg = (void *)v;
12150 return io_readlines(arg, arg->io);
12151}
12152
12153/*
12154 * call-seq:
12155 * IO.readlines(path, sep = $/, **opts) -> array
12156 * IO.readlines(path, limit, **opts) -> array
12157 * IO.readlines(path, sep, limit, **opts) -> array
12158 *
12159 * Returns an array of all lines read from the stream.
12160 *
12161 * The first argument must be a string that is the path to a file.
12162 *
12163 * With only argument +path+ given, parses lines from the file at the given +path+,
12164 * as determined by the default line separator,
12165 * and returns those lines in an array:
12166 *
12167 * IO.readlines('t.txt')
12168 * # => ["First line\n", "Second line\n", "\n", "Third line\n", "Fourth line\n"]
12169 *
12170 * With argument +sep+ given, parses lines as determined by that line separator
12171 * (see {Line Separator}[rdoc-ref:IO@Line+Separator]):
12172 *
12173 * # Ordinary separator.
12174 * IO.readlines('t.txt', 'li')
12175 * # =>["First li", "ne\nSecond li", "ne\n\nThird li", "ne\nFourth li", "ne\n"]
12176 * # Get-paragraphs separator.
12177 * IO.readlines('t.txt', '')
12178 * # => ["First line\nSecond line\n\n", "Third line\nFourth line\n"]
12179 * # Get-all separator.
12180 * IO.readlines('t.txt', nil)
12181 * # => ["First line\nSecond line\n\nThird line\nFourth line\n"]
12182 *
12183 * With argument +limit+ given, parses lines as determined by the default
12184 * line separator and the given line-length limit
12185 * (see {Line Separator}[rdoc-ref:IO@Line+Separator] and {Line Limit}[rdoc-ref:IO@Line+Limit]:
12186 *
12187 * IO.readlines('t.txt', 7)
12188 * # => ["First l", "ine\n", "Second ", "line\n", "\n", "Third l", "ine\n", "Fourth ", "line\n"]
12189 *
12190 * With arguments +sep+ and +limit+ given,
12191 * combines the two behaviors
12192 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
12193 *
12194 * Optional keyword arguments +opts+ specify:
12195 *
12196 * - {Open Options}[rdoc-ref:IO@Open+Options].
12197 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12198 * - {Line Options}[rdoc-ref:IO@Line+IO].
12199 *
12200 */
12201
12202static VALUE
12203rb_io_s_readlines(int argc, VALUE *argv, VALUE io)
12204{
12205 VALUE opt;
12206 struct foreach_arg arg;
12207 struct getline_arg garg;
12208
12209 argc = rb_scan_args(argc, argv, "12:", NULL, NULL, NULL, &opt);
12210 extract_getline_args(argc-1, argv+1, &garg);
12211 open_key_args(io, argc, argv, opt, &arg);
12212 if (NIL_P(arg.io)) return Qnil;
12213 extract_getline_opts(opt, &garg);
12214 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12215 return rb_ensure(io_s_readlines, (VALUE)&garg, rb_io_close, arg.io);
12216}
12217
12218static VALUE
12219io_s_read(VALUE v)
12220{
12221 struct foreach_arg *arg = (void *)v;
12222 return io_read(arg->argc, arg->argv, arg->io);
12223}
12224
12225struct seek_arg {
12226 VALUE io;
12227 VALUE offset;
12228 int mode;
12229};
12230
12231static VALUE
12232seek_before_access(VALUE argp)
12233{
12234 struct seek_arg *arg = (struct seek_arg *)argp;
12235 rb_io_binmode(arg->io);
12236 return rb_io_seek(arg->io, arg->offset, arg->mode);
12237}
12238
12239/*
12240 * call-seq:
12241 * IO.read(path, length = nil, offset = 0, **opts) -> string or nil
12242 *
12243 * Opens the stream, reads and returns some or all of its content,
12244 * and closes the stream; returns +nil+ if no bytes were read.
12245 *
12246 * The first argument must be a string that is the path to a file.
12247 *
12248 * With only argument +path+ given, reads in text mode and returns the entire content
12249 * of the file at the given path:
12250 *
12251 * IO.read('t.txt')
12252 * # => "First line\nSecond line\n\nThird line\nFourth line\n"
12253 *
12254 * On Windows, text mode can terminate reading and leave bytes in the file
12255 * unread when encountering certain special bytes. Consider using
12256 * IO.binread if all bytes in the file should be read.
12257 *
12258 * With argument +length+, returns +length+ bytes if available:
12259 *
12260 * IO.read('t.txt', 7) # => "First l"
12261 * IO.read('t.txt', 700)
12262 * # => "First line\r\nSecond line\r\n\r\nFourth line\r\nFifth line\r\n"
12263 *
12264 * With arguments +length+ and +offset+, returns +length+ bytes
12265 * if available, beginning at the given +offset+:
12266 *
12267 * IO.read('t.txt', 10, 2) # => "rst line\nS"
12268 * IO.read('t.txt', 10, 200) # => nil
12269 *
12270 * Optional keyword arguments +opts+ specify:
12271 *
12272 * - {Open Options}[rdoc-ref:IO@Open+Options].
12273 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12274 *
12275 */
12276
12277static VALUE
12278rb_io_s_read(int argc, VALUE *argv, VALUE io)
12279{
12280 VALUE opt, offset;
12281 long off;
12282 struct foreach_arg arg;
12283
12284 argc = rb_scan_args(argc, argv, "13:", NULL, NULL, &offset, NULL, &opt);
12285 if (!NIL_P(offset) && (off = NUM2LONG(offset)) < 0) {
12286 rb_raise(rb_eArgError, "negative offset %ld given", off);
12287 }
12288 open_key_args(io, argc, argv, opt, &arg);
12289 if (NIL_P(arg.io)) return Qnil;
12290 if (!NIL_P(offset)) {
12291 struct seek_arg sarg;
12292 int state = 0;
12293 sarg.io = arg.io;
12294 sarg.offset = offset;
12295 sarg.mode = SEEK_SET;
12296 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12297 if (state) {
12298 rb_io_close(arg.io);
12299 rb_jump_tag(state);
12300 }
12301 if (arg.argc == 2) arg.argc = 1;
12302 }
12303 return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
12304}
12305
12306/*
12307 * call-seq:
12308 * IO.binread(path, length = nil, offset = 0) -> string or nil
12309 *
12310 * Behaves like IO.read, except that the stream is opened in binary mode
12311 * with ASCII-8BIT encoding.
12312 *
12313 */
12314
12315static VALUE
12316rb_io_s_binread(int argc, VALUE *argv, VALUE io)
12317{
12318 VALUE offset;
12319 struct foreach_arg arg;
12320 enum rb_io_mode fmode = FMODE_READABLE|FMODE_BINMODE;
12321 enum {
12322 oflags = O_RDONLY
12323#ifdef O_BINARY
12324 |O_BINARY
12325#endif
12326 };
12327 struct rb_io_encoding convconfig = {NULL, NULL, 0, Qnil};
12328
12329 rb_scan_args(argc, argv, "12", NULL, NULL, &offset);
12330 FilePathValue(argv[0]);
12331 convconfig.enc = rb_ascii8bit_encoding();
12332 arg.io = rb_io_open_generic(io, argv[0], oflags, fmode, &convconfig, 0);
12333 if (NIL_P(arg.io)) return Qnil;
12334 arg.argv = argv+1;
12335 arg.argc = (argc > 1) ? 1 : 0;
12336 if (!NIL_P(offset)) {
12337 struct seek_arg sarg;
12338 int state = 0;
12339 sarg.io = arg.io;
12340 sarg.offset = offset;
12341 sarg.mode = SEEK_SET;
12342 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12343 if (state) {
12344 rb_io_close(arg.io);
12345 rb_jump_tag(state);
12346 }
12347 }
12348 return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
12349}
12350
12351static VALUE
12352io_s_write0(VALUE v)
12353{
12354 struct write_arg *arg = (void *)v;
12355 return io_write(arg->io,arg->str,arg->nosync);
12356}
12357
12358static VALUE
12359io_s_write(int argc, VALUE *argv, VALUE klass, int binary)
12360{
12361 VALUE string, offset, opt;
12362 struct foreach_arg arg;
12363 struct write_arg warg;
12364
12365 rb_scan_args(argc, argv, "21:", NULL, &string, &offset, &opt);
12366
12367 if (NIL_P(opt)) opt = rb_hash_new();
12368 else opt = rb_hash_dup(opt);
12369
12370
12371 if (NIL_P(rb_hash_aref(opt,sym_mode))) {
12372 int mode = O_WRONLY|O_CREAT;
12373#ifdef O_BINARY
12374 if (binary) mode |= O_BINARY;
12375#endif
12376 if (NIL_P(offset)) mode |= O_TRUNC;
12377 rb_hash_aset(opt,sym_mode,INT2NUM(mode));
12378 }
12379 open_key_args(klass, argc, argv, opt, &arg);
12380
12381#ifndef O_BINARY
12382 if (binary) rb_io_binmode_m(arg.io);
12383#endif
12384
12385 if (NIL_P(arg.io)) return Qnil;
12386 if (!NIL_P(offset)) {
12387 struct seek_arg sarg;
12388 int state = 0;
12389 sarg.io = arg.io;
12390 sarg.offset = offset;
12391 sarg.mode = SEEK_SET;
12392 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12393 if (state) {
12394 rb_io_close(arg.io);
12395 rb_jump_tag(state);
12396 }
12397 }
12398
12399 warg.io = arg.io;
12400 warg.str = string;
12401 warg.nosync = 0;
12402
12403 return rb_ensure(io_s_write0, (VALUE)&warg, rb_io_close, arg.io);
12404}
12405
12406/*
12407 * call-seq:
12408 * IO.write(path, data, offset = 0, **opts) -> integer
12409 *
12410 * Opens the stream, writes the given +data+ to it,
12411 * and closes the stream; returns the number of bytes written.
12412 *
12413 * The first argument must be a string that is the path to a file.
12414 *
12415 * With only argument +path+ given, writes the given +data+ to the file at that path:
12416 *
12417 * IO.write('t.tmp', 'abc') # => 3
12418 * File.read('t.tmp') # => "abc"
12419 *
12420 * If +offset+ is zero (the default), the file is overwritten:
12421 *
12422 * IO.write('t.tmp', 'A') # => 1
12423 * File.read('t.tmp') # => "A"
12424 *
12425 * If +offset+ in within the file content, the file is partly overwritten:
12426 *
12427 * IO.write('t.tmp', 'abcdef') # => 3
12428 * File.read('t.tmp') # => "abcdef"
12429 * # Offset within content.
12430 * IO.write('t.tmp', '012', 2) # => 3
12431 * File.read('t.tmp') # => "ab012f"
12432 *
12433 * If +offset+ is outside the file content,
12434 * the file is padded with null characters <tt>"\u0000"</tt>:
12435 *
12436 * IO.write('t.tmp', 'xyz', 10) # => 3
12437 * File.read('t.tmp') # => "ab012f\u0000\u0000\u0000\u0000xyz"
12438 *
12439 * Optional keyword arguments +opts+ specify:
12440 *
12441 * - {Open Options}[rdoc-ref:IO@Open+Options].
12442 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12443 *
12444 */
12445
12446static VALUE
12447rb_io_s_write(int argc, VALUE *argv, VALUE io)
12448{
12449 return io_s_write(argc, argv, io, 0);
12450}
12451
12452/*
12453 * call-seq:
12454 * IO.binwrite(path, string, offset = 0) -> integer
12455 *
12456 * Behaves like IO.write, except that the stream is opened in binary mode
12457 * with ASCII-8BIT encoding.
12458 *
12459 */
12460
12461static VALUE
12462rb_io_s_binwrite(int argc, VALUE *argv, VALUE io)
12463{
12464 return io_s_write(argc, argv, io, 1);
12465}
12466
12468 VALUE src;
12469 VALUE dst;
12470 rb_off_t copy_length; /* (rb_off_t)-1 if not specified */
12471 rb_off_t src_offset; /* (rb_off_t)-1 if not specified */
12472
12473 rb_io_t *src_fptr;
12474 rb_io_t *dst_fptr;
12475 unsigned close_src : 1;
12476 unsigned close_dst : 1;
12477 int error_no;
12478 rb_off_t total;
12479 const char *syserr;
12480 const char *notimp;
12481 VALUE th;
12482 struct stat src_stat;
12483 struct stat dst_stat;
12484#ifdef HAVE_FCOPYFILE
12485 copyfile_state_t copyfile_state;
12486#endif
12487};
12488
12489static void *
12490exec_interrupts(void *arg)
12491{
12492 VALUE th = (VALUE)arg;
12493 rb_thread_execute_interrupts(th);
12494 return NULL;
12495}
12496
12497/*
12498 * returns TRUE if the preceding system call was interrupted
12499 * so we can continue. If the thread was interrupted, we
12500 * reacquire the GVL to execute interrupts before continuing.
12501 */
12502static int
12503maygvl_copy_stream_continue_p(int has_gvl, struct copy_stream_struct *stp)
12504{
12505 switch (errno) {
12506 case EINTR:
12507#if defined(ERESTART)
12508 case ERESTART:
12509#endif
12510 if (rb_thread_interrupted(stp->th)) {
12511 if (has_gvl)
12512 rb_thread_execute_interrupts(stp->th);
12513 else
12514 rb_thread_call_with_gvl(exec_interrupts, (void *)stp->th);
12515 }
12516 return TRUE;
12517 }
12518 return FALSE;
12519}
12520
12522 VALUE scheduler;
12523
12524 rb_io_t *fptr;
12525 short events;
12526
12527 VALUE result;
12528};
12529
12530static void *
12531fiber_scheduler_wait_for(void * _arguments)
12532{
12533 struct fiber_scheduler_wait_for_arguments *arguments = (struct fiber_scheduler_wait_for_arguments *)_arguments;
12534
12535 arguments->result = rb_fiber_scheduler_io_wait(arguments->scheduler, arguments->fptr->self, INT2NUM(arguments->events), RUBY_IO_TIMEOUT_DEFAULT);
12536
12537 return NULL;
12538}
12539
12540#if USE_POLL
12541# define IOWAIT_SYSCALL "poll"
12542STATIC_ASSERT(pollin_expected, POLLIN == RB_WAITFD_IN);
12543STATIC_ASSERT(pollout_expected, POLLOUT == RB_WAITFD_OUT);
12544static int
12545nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout)
12546{
12548 if (scheduler != Qnil) {
12549 struct fiber_scheduler_wait_for_arguments args = {.scheduler = scheduler, .fptr = fptr, .events = events};
12550 rb_thread_call_with_gvl(fiber_scheduler_wait_for, &args);
12551 return RTEST(args.result);
12552 }
12553
12554 int fd = fptr->fd;
12555 if (fd == -1) return 0;
12556
12557 struct pollfd fds;
12558
12559 fds.fd = fd;
12560 fds.events = events;
12561
12562 int timeout_milliseconds = -1;
12563
12564 if (timeout) {
12565 timeout_milliseconds = (int)(timeout->tv_sec * 1000) + (int)(timeout->tv_usec / 1000);
12566 }
12567
12568 return poll(&fds, 1, timeout_milliseconds);
12569}
12570#else /* !USE_POLL */
12571# define IOWAIT_SYSCALL "select"
12572static int
12573nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout)
12574{
12576 if (scheduler != Qnil) {
12577 struct fiber_scheduler_wait_for_arguments args = {.scheduler = scheduler, .fptr = fptr, .events = events};
12578 rb_thread_call_with_gvl(fiber_scheduler_wait_for, &args);
12579 return RTEST(args.result);
12580 }
12581
12582 int fd = fptr->fd;
12583
12584 if (fd == -1) {
12585 errno = EBADF;
12586 return -1;
12587 }
12588
12589 rb_fdset_t fds;
12590 int ret;
12591
12592 rb_fd_init(&fds);
12593 rb_fd_set(fd, &fds);
12594
12595 switch (events) {
12596 case RB_WAITFD_IN:
12597 ret = rb_fd_select(fd + 1, &fds, 0, 0, timeout);
12598 break;
12599 case RB_WAITFD_OUT:
12600 ret = rb_fd_select(fd + 1, 0, &fds, 0, timeout);
12601 break;
12602 default:
12603 VM_UNREACHABLE(nogvl_wait_for);
12604 }
12605
12606 rb_fd_term(&fds);
12607
12608 // On timeout, this returns 0.
12609 return ret;
12610}
12611#endif /* !USE_POLL */
12612
12613static int
12614maygvl_copy_stream_wait_read(int has_gvl, struct copy_stream_struct *stp)
12615{
12616 int ret;
12617
12618 do {
12619 if (has_gvl) {
12621 }
12622 else {
12623 ret = nogvl_wait_for(stp->th, stp->src_fptr, RB_WAITFD_IN, NULL);
12624 }
12625 } while (ret < 0 && maygvl_copy_stream_continue_p(has_gvl, stp));
12626
12627 if (ret < 0) {
12628 stp->syserr = IOWAIT_SYSCALL;
12629 stp->error_no = errno;
12630 return ret;
12631 }
12632 return 0;
12633}
12634
12635static int
12636nogvl_copy_stream_wait_write(struct copy_stream_struct *stp)
12637{
12638 int ret;
12639
12640 do {
12641 ret = nogvl_wait_for(stp->th, stp->dst_fptr, RB_WAITFD_OUT, NULL);
12642 } while (ret < 0 && maygvl_copy_stream_continue_p(0, stp));
12643
12644 if (ret < 0) {
12645 stp->syserr = IOWAIT_SYSCALL;
12646 stp->error_no = errno;
12647 return ret;
12648 }
12649 return 0;
12650}
12651
12652#ifdef USE_COPY_FILE_RANGE
12653
12654static ssize_t
12655simple_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)
12656{
12657#ifdef HAVE_COPY_FILE_RANGE
12658 return copy_file_range(in_fd, in_offset, out_fd, out_offset, count, flags);
12659#else
12660 return syscall(__NR_copy_file_range, in_fd, in_offset, out_fd, out_offset, count, flags);
12661#endif
12662}
12663
12664static int
12665nogvl_copy_file_range(struct copy_stream_struct *stp)
12666{
12667 ssize_t ss;
12668 rb_off_t src_size;
12669 rb_off_t copy_length, src_offset, *src_offset_ptr;
12670
12671 if (!S_ISREG(stp->src_stat.st_mode))
12672 return 0;
12673
12674 src_size = stp->src_stat.st_size;
12675 src_offset = stp->src_offset;
12676 if (src_offset >= (rb_off_t)0) {
12677 src_offset_ptr = &src_offset;
12678 }
12679 else {
12680 src_offset_ptr = NULL; /* if src_offset_ptr is NULL, then bytes are read from in_fd starting from the file offset */
12681 }
12682
12683 copy_length = stp->copy_length;
12684 if (copy_length < (rb_off_t)0) {
12685 if (src_offset < (rb_off_t)0) {
12686 rb_off_t current_offset;
12687 errno = 0;
12688 current_offset = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12689 if (current_offset < (rb_off_t)0 && errno) {
12690 stp->syserr = "lseek";
12691 stp->error_no = errno;
12692 return (int)current_offset;
12693 }
12694 copy_length = src_size - current_offset;
12695 }
12696 else {
12697 copy_length = src_size - src_offset;
12698 }
12699 }
12700
12701 retry_copy_file_range:
12702# if SIZEOF_OFF_T > SIZEOF_SIZE_T
12703 /* we are limited by the 32-bit ssize_t return value on 32-bit */
12704 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
12705# else
12706 ss = (ssize_t)copy_length;
12707# endif
12708 ss = simple_copy_file_range(stp->src_fptr->fd, src_offset_ptr, stp->dst_fptr->fd, NULL, ss, 0);
12709 if (0 < ss) {
12710 stp->total += ss;
12711 copy_length -= ss;
12712 if (0 < copy_length) {
12713 goto retry_copy_file_range;
12714 }
12715 }
12716 if (ss < 0) {
12717 if (maygvl_copy_stream_continue_p(0, stp)) {
12718 goto retry_copy_file_range;
12719 }
12720 switch (errno) {
12721 case EINVAL:
12722 case EPERM: /* copy_file_range(2) doesn't exist (may happen in
12723 docker container) */
12724#ifdef ENOSYS
12725 case ENOSYS:
12726#endif
12727#ifdef EXDEV
12728 case EXDEV: /* in_fd and out_fd are not on the same filesystem */
12729#endif
12730 return 0;
12731 case EAGAIN:
12732#if EWOULDBLOCK != EAGAIN
12733 case EWOULDBLOCK:
12734#endif
12735 {
12736 int ret = nogvl_copy_stream_wait_write(stp);
12737 if (ret < 0) return ret;
12738 }
12739 goto retry_copy_file_range;
12740 case EBADF:
12741 {
12742 int e = errno;
12743 int flags = fcntl(stp->dst_fptr->fd, F_GETFL);
12744
12745 if (flags != -1 && flags & O_APPEND) {
12746 return 0;
12747 }
12748 errno = e;
12749 }
12750 }
12751 stp->syserr = "copy_file_range";
12752 stp->error_no = errno;
12753 return (int)ss;
12754 }
12755 return 1;
12756}
12757#endif
12758
12759#ifdef HAVE_FCOPYFILE
12760static int
12761nogvl_fcopyfile(struct copy_stream_struct *stp)
12762{
12763 rb_off_t cur, ss = 0;
12764 const rb_off_t src_offset = stp->src_offset;
12765 int ret;
12766
12767 if (stp->copy_length >= (rb_off_t)0) {
12768 /* copy_length can't be specified in fcopyfile(3) */
12769 return 0;
12770 }
12771
12772 if (!S_ISREG(stp->src_stat.st_mode))
12773 return 0;
12774
12775 if (!S_ISREG(stp->dst_stat.st_mode))
12776 return 0;
12777 if (lseek(stp->dst_fptr->fd, 0, SEEK_CUR) > (rb_off_t)0) /* if dst IO was already written */
12778 return 0;
12779 if (fcntl(stp->dst_fptr->fd, F_GETFL) & O_APPEND) {
12780 /* fcopyfile(3) appends src IO to dst IO and then truncates
12781 * dst IO to src IO's original size. */
12782 rb_off_t end = lseek(stp->dst_fptr->fd, 0, SEEK_END);
12783 lseek(stp->dst_fptr->fd, 0, SEEK_SET);
12784 if (end > (rb_off_t)0) return 0;
12785 }
12786
12787 if (src_offset > (rb_off_t)0) {
12788 rb_off_t r;
12789
12790 /* get current offset */
12791 errno = 0;
12792 cur = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12793 if (cur < (rb_off_t)0 && errno) {
12794 stp->error_no = errno;
12795 return 1;
12796 }
12797
12798 errno = 0;
12799 r = lseek(stp->src_fptr->fd, src_offset, SEEK_SET);
12800 if (r < (rb_off_t)0 && errno) {
12801 stp->error_no = errno;
12802 return 1;
12803 }
12804 }
12805
12806 stp->copyfile_state = copyfile_state_alloc(); /* this will be freed by copy_stream_finalize() */
12807 ret = fcopyfile(stp->src_fptr->fd, stp->dst_fptr->fd, stp->copyfile_state, COPYFILE_DATA);
12808 copyfile_state_get(stp->copyfile_state, COPYFILE_STATE_COPIED, &ss); /* get copied bytes */
12809
12810 if (ret == 0) { /* success */
12811 stp->total = ss;
12812 if (src_offset > (rb_off_t)0) {
12813 rb_off_t r;
12814 errno = 0;
12815 /* reset offset */
12816 r = lseek(stp->src_fptr->fd, cur, SEEK_SET);
12817 if (r < (rb_off_t)0 && errno) {
12818 stp->error_no = errno;
12819 return 1;
12820 }
12821 }
12822 }
12823 else {
12824 switch (errno) {
12825 case ENOTSUP:
12826 case EPERM:
12827 case EINVAL:
12828 return 0;
12829 }
12830 stp->syserr = "fcopyfile";
12831 stp->error_no = errno;
12832 return (int)ret;
12833 }
12834 return 1;
12835}
12836#endif
12837
12838#ifdef HAVE_SENDFILE
12839
12840# ifdef __linux__
12841# define USE_SENDFILE
12842
12843# ifdef HAVE_SYS_SENDFILE_H
12844# include <sys/sendfile.h>
12845# endif
12846
12847static ssize_t
12848simple_sendfile(int out_fd, int in_fd, rb_off_t *offset, rb_off_t count)
12849{
12850 return sendfile(out_fd, in_fd, offset, (size_t)count);
12851}
12852
12853# elif 0 /* defined(__FreeBSD__) || defined(__DragonFly__) */ || defined(__APPLE__)
12854/* This runs on FreeBSD8.1 r30210, but sendfiles blocks its execution
12855 * without cpuset -l 0.
12856 */
12857# define USE_SENDFILE
12858
12859static ssize_t
12860simple_sendfile(int out_fd, int in_fd, rb_off_t *offset, rb_off_t count)
12861{
12862 int r;
12863 rb_off_t pos = offset ? *offset : lseek(in_fd, 0, SEEK_CUR);
12864 rb_off_t sbytes;
12865# ifdef __APPLE__
12866 r = sendfile(in_fd, out_fd, pos, &count, NULL, 0);
12867 sbytes = count;
12868# else
12869 r = sendfile(in_fd, out_fd, pos, (size_t)count, NULL, &sbytes, 0);
12870# endif
12871 if (r != 0 && sbytes == 0) return r;
12872 if (offset) {
12873 *offset += sbytes;
12874 }
12875 else {
12876 lseek(in_fd, sbytes, SEEK_CUR);
12877 }
12878 return (ssize_t)sbytes;
12879}
12880
12881# endif
12882
12883#endif
12884
12885#ifdef USE_SENDFILE
12886static int
12887nogvl_copy_stream_sendfile(struct copy_stream_struct *stp)
12888{
12889 ssize_t ss;
12890 rb_off_t src_size;
12891 rb_off_t copy_length;
12892 rb_off_t src_offset;
12893 int use_pread;
12894
12895 if (!S_ISREG(stp->src_stat.st_mode))
12896 return 0;
12897
12898 src_size = stp->src_stat.st_size;
12899#ifndef __linux__
12900 if ((stp->dst_stat.st_mode & S_IFMT) != S_IFSOCK)
12901 return 0;
12902#endif
12903
12904 src_offset = stp->src_offset;
12905 use_pread = src_offset >= (rb_off_t)0;
12906
12907 copy_length = stp->copy_length;
12908 if (copy_length < (rb_off_t)0) {
12909 if (use_pread)
12910 copy_length = src_size - src_offset;
12911 else {
12912 rb_off_t cur;
12913 errno = 0;
12914 cur = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12915 if (cur < (rb_off_t)0 && errno) {
12916 stp->syserr = "lseek";
12917 stp->error_no = errno;
12918 return (int)cur;
12919 }
12920 copy_length = src_size - cur;
12921 }
12922 }
12923
12924 retry_sendfile:
12925# if SIZEOF_OFF_T > SIZEOF_SIZE_T
12926 /* we are limited by the 32-bit ssize_t return value on 32-bit */
12927 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
12928# else
12929 ss = (ssize_t)copy_length;
12930# endif
12931 if (use_pread) {
12932 ss = simple_sendfile(stp->dst_fptr->fd, stp->src_fptr->fd, &src_offset, ss);
12933 }
12934 else {
12935 ss = simple_sendfile(stp->dst_fptr->fd, stp->src_fptr->fd, NULL, ss);
12936 }
12937 if (0 < ss) {
12938 stp->total += ss;
12939 copy_length -= ss;
12940 if (0 < copy_length) {
12941 goto retry_sendfile;
12942 }
12943 }
12944 if (ss < 0) {
12945 if (maygvl_copy_stream_continue_p(0, stp))
12946 goto retry_sendfile;
12947 switch (errno) {
12948 case EINVAL:
12949#ifdef ENOSYS
12950 case ENOSYS:
12951#endif
12952#ifdef EOPNOTSUP
12953 /* some RedHat kernels may return EOPNOTSUP on an NFS mount.
12954 see also: [Feature #16965] */
12955 case EOPNOTSUP:
12956#endif
12957 return 0;
12958 case EAGAIN:
12959#if EWOULDBLOCK != EAGAIN
12960 case EWOULDBLOCK:
12961#endif
12962 {
12963 int ret;
12964#ifndef __linux__
12965 /*
12966 * Linux requires stp->src_fptr->fd to be a mmap-able (regular) file,
12967 * select() reports regular files to always be "ready", so
12968 * there is no need to select() on it.
12969 * Other OSes may have the same limitation for sendfile() which
12970 * allow us to bypass maygvl_copy_stream_wait_read()...
12971 */
12972 ret = maygvl_copy_stream_wait_read(0, stp);
12973 if (ret < 0) return ret;
12974#endif
12975 ret = nogvl_copy_stream_wait_write(stp);
12976 if (ret < 0) return ret;
12977 }
12978 goto retry_sendfile;
12979 }
12980 stp->syserr = "sendfile";
12981 stp->error_no = errno;
12982 return (int)ss;
12983 }
12984 return 1;
12985}
12986#endif
12987
12988static ssize_t
12989maygvl_read(int has_gvl, rb_io_t *fptr, void *buf, size_t count)
12990{
12991 if (has_gvl)
12992 return rb_io_read_memory(fptr, buf, count);
12993 else
12994 return read(fptr->fd, buf, count);
12995}
12996
12997static ssize_t
12998maygvl_copy_stream_read(int has_gvl, struct copy_stream_struct *stp, char *buf, size_t len, rb_off_t offset)
12999{
13000 ssize_t ss;
13001 retry_read:
13002 if (offset < (rb_off_t)0) {
13003 ss = maygvl_read(has_gvl, stp->src_fptr, buf, len);
13004 }
13005 else {
13006 ss = pread(stp->src_fptr->fd, buf, len, offset);
13007 }
13008 if (ss == 0) {
13009 return 0;
13010 }
13011 if (ss < 0) {
13012 if (maygvl_copy_stream_continue_p(has_gvl, stp))
13013 goto retry_read;
13014 switch (errno) {
13015 case EAGAIN:
13016#if EWOULDBLOCK != EAGAIN
13017 case EWOULDBLOCK:
13018#endif
13019 {
13020 int ret = maygvl_copy_stream_wait_read(has_gvl, stp);
13021 if (ret < 0) return ret;
13022 }
13023 goto retry_read;
13024#ifdef ENOSYS
13025 case ENOSYS:
13026 stp->notimp = "pread";
13027 return ss;
13028#endif
13029 }
13030 stp->syserr = offset < (rb_off_t)0 ? "read" : "pread";
13031 stp->error_no = errno;
13032 }
13033 return ss;
13034}
13035
13036static int
13037nogvl_copy_stream_write(struct copy_stream_struct *stp, char *buf, size_t len)
13038{
13039 ssize_t ss;
13040 int off = 0;
13041 while (len) {
13042 ss = write(stp->dst_fptr->fd, buf+off, len);
13043 if (ss < 0) {
13044 if (maygvl_copy_stream_continue_p(0, stp))
13045 continue;
13046 if (io_again_p(errno)) {
13047 int ret = nogvl_copy_stream_wait_write(stp);
13048 if (ret < 0) return ret;
13049 continue;
13050 }
13051 stp->syserr = "write";
13052 stp->error_no = errno;
13053 return (int)ss;
13054 }
13055 off += (int)ss;
13056 len -= (int)ss;
13057 stp->total += ss;
13058 }
13059 return 0;
13060}
13061
13062static void
13063nogvl_copy_stream_read_write(struct copy_stream_struct *stp)
13064{
13065 char buf[1024*16];
13066 size_t len;
13067 ssize_t ss;
13068 int ret;
13069 rb_off_t copy_length;
13070 rb_off_t src_offset;
13071 int use_eof;
13072 int use_pread;
13073
13074 copy_length = stp->copy_length;
13075 use_eof = copy_length < (rb_off_t)0;
13076 src_offset = stp->src_offset;
13077 use_pread = src_offset >= (rb_off_t)0;
13078
13079 if (use_pread && stp->close_src) {
13080 rb_off_t r;
13081 errno = 0;
13082 r = lseek(stp->src_fptr->fd, src_offset, SEEK_SET);
13083 if (r < (rb_off_t)0 && errno) {
13084 stp->syserr = "lseek";
13085 stp->error_no = errno;
13086 return;
13087 }
13088 src_offset = (rb_off_t)-1;
13089 use_pread = 0;
13090 }
13091
13092 while (use_eof || 0 < copy_length) {
13093 if (!use_eof && copy_length < (rb_off_t)sizeof(buf)) {
13094 len = (size_t)copy_length;
13095 }
13096 else {
13097 len = sizeof(buf);
13098 }
13099 if (use_pread) {
13100 ss = maygvl_copy_stream_read(0, stp, buf, len, src_offset);
13101 if (0 < ss)
13102 src_offset += ss;
13103 }
13104 else {
13105 ss = maygvl_copy_stream_read(0, stp, buf, len, (rb_off_t)-1);
13106 }
13107 if (ss <= 0) /* EOF or error */
13108 return;
13109
13110 ret = nogvl_copy_stream_write(stp, buf, ss);
13111 if (ret < 0)
13112 return;
13113
13114 if (!use_eof)
13115 copy_length -= ss;
13116 }
13117}
13118
13119static void *
13120nogvl_copy_stream_func(void *arg)
13121{
13122 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13123#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13124 int ret;
13125#endif
13126
13127#ifdef USE_COPY_FILE_RANGE
13128 ret = nogvl_copy_file_range(stp);
13129 if (ret != 0)
13130 goto finish; /* error or success */
13131#endif
13132
13133#ifdef HAVE_FCOPYFILE
13134 ret = nogvl_fcopyfile(stp);
13135 if (ret != 0)
13136 goto finish; /* error or success */
13137#endif
13138
13139#ifdef USE_SENDFILE
13140 ret = nogvl_copy_stream_sendfile(stp);
13141 if (ret != 0)
13142 goto finish; /* error or success */
13143#endif
13144
13145 nogvl_copy_stream_read_write(stp);
13146
13147#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13148 finish:
13149#endif
13150 return 0;
13151}
13152
13153static VALUE
13154copy_stream_fallback_body(VALUE arg)
13155{
13156 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13157 const int buflen = 16*1024;
13158 VALUE n;
13159 VALUE buf = rb_str_buf_new(buflen);
13160 rb_off_t rest = stp->copy_length;
13161 rb_off_t off = stp->src_offset;
13162 ID read_method = id_readpartial;
13163
13164 if (!stp->src_fptr) {
13165 if (!rb_respond_to(stp->src, read_method)) {
13166 read_method = id_read;
13167 }
13168 }
13169
13170 while (1) {
13171 long numwrote;
13172 long l;
13173 rb_str_make_independent(buf);
13174 if (stp->copy_length < (rb_off_t)0) {
13175 l = buflen;
13176 }
13177 else {
13178 if (rest == 0) {
13179 rb_str_resize(buf, 0);
13180 break;
13181 }
13182 l = buflen < rest ? buflen : (long)rest;
13183 }
13184 if (!stp->src_fptr) {
13185 VALUE rc = rb_funcall(stp->src, read_method, 2, INT2FIX(l), buf);
13186
13187 if (read_method == id_read && NIL_P(rc))
13188 break;
13189 }
13190 else {
13191 ssize_t ss;
13192 rb_str_resize(buf, buflen);
13193 ss = maygvl_copy_stream_read(1, stp, RSTRING_PTR(buf), l, off);
13194 rb_str_resize(buf, ss > 0 ? ss : 0);
13195 if (ss < 0)
13196 return Qnil;
13197 if (ss == 0)
13198 rb_eof_error();
13199 if (off >= (rb_off_t)0)
13200 off += ss;
13201 }
13202 n = rb_io_write(stp->dst, buf);
13203 numwrote = NUM2LONG(n);
13204 stp->total += numwrote;
13205 rest -= numwrote;
13206 if (read_method == id_read && RSTRING_LEN(buf) == 0) {
13207 break;
13208 }
13209 }
13210
13211 return Qnil;
13212}
13213
13214static VALUE
13215copy_stream_fallback(struct copy_stream_struct *stp)
13216{
13217 if (!stp->src_fptr && stp->src_offset >= (rb_off_t)0) {
13218 rb_raise(rb_eArgError, "cannot specify src_offset for non-IO");
13219 }
13220 rb_rescue2(copy_stream_fallback_body, (VALUE)stp,
13221 (VALUE (*) (VALUE, VALUE))0, (VALUE)0,
13222 rb_eEOFError, (VALUE)0);
13223 return Qnil;
13224}
13225
13226static VALUE
13227copy_stream_body(VALUE arg)
13228{
13229 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13230 VALUE src_io = stp->src, dst_io = stp->dst;
13231 const int common_oflags = 0
13232#ifdef O_NOCTTY
13233 | O_NOCTTY
13234#endif
13235 ;
13236
13237 stp->th = rb_thread_current();
13238
13239 stp->total = 0;
13240
13241 if (src_io == argf ||
13242 !(RB_TYPE_P(src_io, T_FILE) ||
13243 RB_TYPE_P(src_io, T_STRING) ||
13244 rb_respond_to(src_io, rb_intern("to_path")))) {
13245 stp->src_fptr = NULL;
13246 }
13247 else {
13248 int stat_ret;
13249 VALUE tmp_io = rb_io_check_io(src_io);
13250 if (!NIL_P(tmp_io)) {
13251 src_io = tmp_io;
13252 }
13253 else if (!RB_TYPE_P(src_io, T_FILE)) {
13254 VALUE args[2];
13255 FilePathValue(src_io);
13256 args[0] = src_io;
13257 args[1] = INT2NUM(O_RDONLY|common_oflags);
13258 src_io = rb_class_new_instance(2, args, rb_cFile);
13259 stp->src = src_io;
13260 stp->close_src = 1;
13261 }
13262 RB_IO_POINTER(src_io, stp->src_fptr);
13263 rb_io_check_byte_readable(stp->src_fptr);
13264
13265 stat_ret = fstat(stp->src_fptr->fd, &stp->src_stat);
13266 if (stat_ret < 0) {
13267 stp->syserr = "fstat";
13268 stp->error_no = errno;
13269 return Qnil;
13270 }
13271 }
13272
13273 if (dst_io == argf ||
13274 !(RB_TYPE_P(dst_io, T_FILE) ||
13275 RB_TYPE_P(dst_io, T_STRING) ||
13276 rb_respond_to(dst_io, rb_intern("to_path")))) {
13277 stp->dst_fptr = NULL;
13278 }
13279 else {
13280 int stat_ret;
13281 VALUE tmp_io = rb_io_check_io(dst_io);
13282 if (!NIL_P(tmp_io)) {
13283 dst_io = GetWriteIO(tmp_io);
13284 }
13285 else if (!RB_TYPE_P(dst_io, T_FILE)) {
13286 VALUE args[3];
13287 FilePathValue(dst_io);
13288 args[0] = dst_io;
13289 args[1] = INT2NUM(O_WRONLY|O_CREAT|O_TRUNC|common_oflags);
13290 args[2] = INT2FIX(0666);
13291 dst_io = rb_class_new_instance(3, args, rb_cFile);
13292 stp->dst = dst_io;
13293 stp->close_dst = 1;
13294 }
13295 else {
13296 dst_io = GetWriteIO(dst_io);
13297 stp->dst = dst_io;
13298 }
13299 RB_IO_POINTER(dst_io, stp->dst_fptr);
13300 rb_io_check_writable(stp->dst_fptr);
13301
13302 stat_ret = fstat(stp->dst_fptr->fd, &stp->dst_stat);
13303 if (stat_ret < 0) {
13304 stp->syserr = "fstat";
13305 stp->error_no = errno;
13306 return Qnil;
13307 }
13308 }
13309
13310#ifdef O_BINARY
13311 if (stp->src_fptr)
13312 SET_BINARY_MODE_WITH_SEEK_CUR(stp->src_fptr);
13313#endif
13314 if (stp->dst_fptr)
13315 io_ascii8bit_binmode(stp->dst_fptr);
13316
13317 if (stp->src_offset < (rb_off_t)0 && stp->src_fptr && stp->src_fptr->rbuf.len) {
13318 size_t len = stp->src_fptr->rbuf.len;
13319 VALUE str;
13320 if (stp->copy_length >= (rb_off_t)0 && stp->copy_length < (rb_off_t)len) {
13321 len = (size_t)stp->copy_length;
13322 }
13323 str = rb_str_buf_new(len);
13324 rb_str_resize(str,len);
13325 read_buffered_data(RSTRING_PTR(str), len, stp->src_fptr);
13326 if (stp->dst_fptr) { /* IO or filename */
13327 if (io_binwrite(RSTRING_PTR(str), RSTRING_LEN(str), stp->dst_fptr, 0) < 0)
13328 rb_sys_fail_on_write(stp->dst_fptr);
13329 }
13330 else /* others such as StringIO */
13331 rb_io_write(dst_io, str);
13332 rb_str_resize(str, 0);
13333 stp->total += len;
13334 if (stp->copy_length >= (rb_off_t)0)
13335 stp->copy_length -= len;
13336 }
13337
13338 if (stp->dst_fptr && io_fflush(stp->dst_fptr) < 0) {
13339 rb_raise(rb_eIOError, "flush failed");
13340 }
13341
13342 if (stp->copy_length == 0)
13343 return Qnil;
13344
13345 if (stp->src_fptr == NULL || stp->dst_fptr == NULL) {
13346 return copy_stream_fallback(stp);
13347 }
13348
13349 IO_WITHOUT_GVL(nogvl_copy_stream_func, stp);
13350 return Qnil;
13351}
13352
13353static VALUE
13354copy_stream_finalize(VALUE arg)
13355{
13356 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13357
13358#ifdef HAVE_FCOPYFILE
13359 if (stp->copyfile_state) {
13360 copyfile_state_free(stp->copyfile_state);
13361 }
13362#endif
13363
13364 if (stp->close_src) {
13365 rb_io_close_m(stp->src);
13366 }
13367 if (stp->close_dst) {
13368 rb_io_close_m(stp->dst);
13369 }
13370 if (stp->syserr) {
13371 rb_syserr_fail(stp->error_no, stp->syserr);
13372 }
13373 if (stp->notimp) {
13374 rb_raise(rb_eNotImpError, "%s() not implemented", stp->notimp);
13375 }
13376 return Qnil;
13377}
13378
13379/*
13380 * call-seq:
13381 * IO.copy_stream(src, dst, src_length = nil, src_offset = 0) -> integer
13382 *
13383 * Copies from the given +src+ to the given +dst+,
13384 * returning the number of bytes copied.
13385 *
13386 * - The given +src+ must be one of the following:
13387 *
13388 * - The path to a readable file, from which source data is to be read.
13389 * - An \IO-like object, opened for reading and capable of responding
13390 * to method +:readpartial+ or method +:read+.
13391 *
13392 * - The given +dst+ must be one of the following:
13393 *
13394 * - The path to a writable file, to which data is to be written.
13395 * - An \IO-like object, opened for writing and capable of responding
13396 * to method +:write+.
13397 *
13398 * The examples here use file <tt>t.txt</tt> as source:
13399 *
13400 * File.read('t.txt')
13401 * # => "First line\nSecond line\n\nThird line\nFourth line\n"
13402 * File.read('t.txt').size # => 47
13403 *
13404 * If only arguments +src+ and +dst+ are given,
13405 * the entire source stream is copied:
13406 *
13407 * # Paths.
13408 * IO.copy_stream('t.txt', 't.tmp') # => 47
13409 *
13410 * # IOs (recall that a File is also an IO).
13411 * src_io = File.open('t.txt', 'r') # => #<File:t.txt>
13412 * dst_io = File.open('t.tmp', 'w') # => #<File:t.tmp>
13413 * IO.copy_stream(src_io, dst_io) # => 47
13414 * src_io.close
13415 * dst_io.close
13416 *
13417 * With argument +src_length+ a non-negative integer,
13418 * no more than that many bytes are copied:
13419 *
13420 * IO.copy_stream('t.txt', 't.tmp', 10) # => 10
13421 * File.read('t.tmp') # => "First line"
13422 *
13423 * With argument +src_offset+ also given,
13424 * the source stream is read beginning at that offset:
13425 *
13426 * IO.copy_stream('t.txt', 't.tmp', 11, 11) # => 11
13427 * IO.read('t.tmp') # => "Second line"
13428 *
13429 */
13430static VALUE
13431rb_io_s_copy_stream(int argc, VALUE *argv, VALUE io)
13432{
13433 VALUE src, dst, length, src_offset;
13434 struct copy_stream_struct st;
13435
13436 MEMZERO(&st, struct copy_stream_struct, 1);
13437
13438 rb_scan_args(argc, argv, "22", &src, &dst, &length, &src_offset);
13439
13440 st.src = src;
13441 st.dst = dst;
13442
13443 st.src_fptr = NULL;
13444 st.dst_fptr = NULL;
13445
13446 if (NIL_P(length))
13447 st.copy_length = (rb_off_t)-1;
13448 else
13449 st.copy_length = NUM2OFFT(length);
13450
13451 if (NIL_P(src_offset))
13452 st.src_offset = (rb_off_t)-1;
13453 else
13454 st.src_offset = NUM2OFFT(src_offset);
13455
13456 rb_ensure(copy_stream_body, (VALUE)&st, copy_stream_finalize, (VALUE)&st);
13457
13458 return OFFT2NUM(st.total);
13459}
13460
13461/*
13462 * call-seq:
13463 * external_encoding -> encoding or nil
13464 *
13465 * Returns the Encoding object that represents the encoding of the stream,
13466 * or +nil+ if the stream is in write mode and no encoding is specified.
13467 *
13468 * See {Encodings}[rdoc-ref:File@Encodings].
13469 *
13470 */
13471
13472static VALUE
13473rb_io_external_encoding(VALUE io)
13474{
13475 rb_io_t *fptr = RFILE(rb_io_taint_check(io))->fptr;
13476
13477 if (fptr->encs.enc2) {
13478 return rb_enc_from_encoding(fptr->encs.enc2);
13479 }
13480 if (fptr->mode & FMODE_WRITABLE) {
13481 if (fptr->encs.enc)
13482 return rb_enc_from_encoding(fptr->encs.enc);
13483 return Qnil;
13484 }
13485 return rb_enc_from_encoding(io_read_encoding(fptr));
13486}
13487
13488/*
13489 * call-seq:
13490 * internal_encoding -> encoding or nil
13491 *
13492 * Returns the Encoding object that represents the encoding of the internal string,
13493 * if conversion is specified,
13494 * or +nil+ otherwise.
13495 *
13496 * See {Encodings}[rdoc-ref:File@Encodings].
13497 *
13498 */
13499
13500static VALUE
13501rb_io_internal_encoding(VALUE io)
13502{
13503 rb_io_t *fptr = RFILE(rb_io_taint_check(io))->fptr;
13504
13505 if (!fptr->encs.enc2) return Qnil;
13506 return rb_enc_from_encoding(io_read_encoding(fptr));
13507}
13508
13509/*
13510 * call-seq:
13511 * set_encoding(ext_enc) -> self
13512 * set_encoding(ext_enc, int_enc, **enc_opts) -> self
13513 * set_encoding('ext_enc:int_enc', **enc_opts) -> self
13514 *
13515 * See {Encodings}[rdoc-ref:File@Encodings].
13516 *
13517 * Argument +ext_enc+, if given, must be an Encoding object
13518 * or a String with the encoding name;
13519 * it is assigned as the encoding for the stream.
13520 *
13521 * Argument +int_enc+, if given, must be an Encoding object
13522 * or a String with the encoding name;
13523 * it is assigned as the encoding for the internal string.
13524 *
13525 * Argument <tt>'ext_enc:int_enc'</tt>, if given, is a string
13526 * containing two colon-separated encoding names;
13527 * corresponding Encoding objects are assigned as the external
13528 * and internal encodings for the stream.
13529 *
13530 * If the external encoding of a string is binary/ASCII-8BIT,
13531 * the internal encoding of the string is set to nil, since no
13532 * transcoding is needed.
13533 *
13534 * Optional keyword arguments +enc_opts+ specify
13535 * {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
13536 *
13537 */
13538
13539static VALUE
13540rb_io_set_encoding(int argc, VALUE *argv, VALUE io)
13541{
13542 rb_io_t *fptr;
13543 VALUE v1, v2, opt;
13544
13545 if (!RB_TYPE_P(io, T_FILE)) {
13546 return forward(io, id_set_encoding, argc, argv);
13547 }
13548
13549 argc = rb_scan_args(argc, argv, "11:", &v1, &v2, &opt);
13550 GetOpenFile(io, fptr);
13551 io_encoding_set(fptr, v1, v2, opt);
13552 return io;
13553}
13554
13555void
13556rb_stdio_set_default_encoding(void)
13557{
13558 VALUE val = Qnil;
13559
13560#ifdef _WIN32
13561 if (isatty(fileno(stdin))) {
13562 rb_encoding *external = rb_locale_encoding();
13563 rb_encoding *internal = rb_default_internal_encoding();
13564 if (!internal) internal = rb_default_external_encoding();
13565 io_encoding_set(RFILE(rb_stdin)->fptr,
13566 rb_enc_from_encoding(external),
13567 rb_enc_from_encoding(internal),
13568 Qnil);
13569 }
13570 else
13571#endif
13572 rb_io_set_encoding(1, &val, rb_stdin);
13573 rb_io_set_encoding(1, &val, rb_stdout);
13574 rb_io_set_encoding(1, &val, rb_stderr);
13575}
13576
13577static inline int
13578global_argf_p(VALUE arg)
13579{
13580 return arg == argf;
13581}
13582
13583typedef VALUE (*argf_encoding_func)(VALUE io);
13584
13585static VALUE
13586argf_encoding(VALUE argf, argf_encoding_func func)
13587{
13588 if (!RTEST(ARGF.current_file)) {
13589 return rb_enc_default_external();
13590 }
13591 return func(rb_io_check_io(ARGF.current_file));
13592}
13593
13594/*
13595 * call-seq:
13596 * ARGF.external_encoding -> encoding
13597 *
13598 * Returns the external encoding for files read from ARGF as an Encoding
13599 * object. The external encoding is the encoding of the text as stored in a
13600 * file. Contrast with ARGF.internal_encoding, which is the encoding used to
13601 * represent this text within Ruby.
13602 *
13603 * To set the external encoding use ARGF.set_encoding.
13604 *
13605 * For example:
13606 *
13607 * ARGF.external_encoding #=> #<Encoding:UTF-8>
13608 *
13609 */
13610static VALUE
13611argf_external_encoding(VALUE argf)
13612{
13613 return argf_encoding(argf, rb_io_external_encoding);
13614}
13615
13616/*
13617 * call-seq:
13618 * ARGF.internal_encoding -> encoding
13619 *
13620 * Returns the internal encoding for strings read from ARGF as an
13621 * Encoding object.
13622 *
13623 * If ARGF.set_encoding has been called with two encoding names, the second
13624 * is returned. Otherwise, if +Encoding.default_external+ has been set, that
13625 * value is returned. Failing that, if a default external encoding was
13626 * specified on the command-line, that value is used. If the encoding is
13627 * unknown, +nil+ is returned.
13628 */
13629static VALUE
13630argf_internal_encoding(VALUE argf)
13631{
13632 return argf_encoding(argf, rb_io_internal_encoding);
13633}
13634
13635/*
13636 * call-seq:
13637 * ARGF.set_encoding(ext_enc) -> ARGF
13638 * ARGF.set_encoding("ext_enc:int_enc") -> ARGF
13639 * ARGF.set_encoding(ext_enc, int_enc) -> ARGF
13640 * ARGF.set_encoding("ext_enc:int_enc", opt) -> ARGF
13641 * ARGF.set_encoding(ext_enc, int_enc, opt) -> ARGF
13642 *
13643 * If single argument is specified, strings read from ARGF are tagged with
13644 * the encoding specified.
13645 *
13646 * If two encoding names separated by a colon are given, e.g. "ascii:utf-8",
13647 * the read string is converted from the first encoding (external encoding)
13648 * to the second encoding (internal encoding), then tagged with the second
13649 * encoding.
13650 *
13651 * If two arguments are specified, they must be encoding objects or encoding
13652 * names. Again, the first specifies the external encoding; the second
13653 * specifies the internal encoding.
13654 *
13655 * If the external encoding and the internal encoding are specified, the
13656 * optional Hash argument can be used to adjust the conversion process. The
13657 * structure of this hash is explained in the String#encode documentation.
13658 *
13659 * For example:
13660 *
13661 * ARGF.set_encoding('ascii') # Tag the input as US-ASCII text
13662 * ARGF.set_encoding(Encoding::UTF_8) # Tag the input as UTF-8 text
13663 * ARGF.set_encoding('utf-8','ascii') # Transcode the input from US-ASCII
13664 * # to UTF-8.
13665 */
13666static VALUE
13667argf_set_encoding(int argc, VALUE *argv, VALUE argf)
13668{
13669 rb_io_t *fptr;
13670
13671 if (!next_argv()) {
13672 rb_raise(rb_eArgError, "no stream to set encoding");
13673 }
13674 rb_io_set_encoding(argc, argv, ARGF.current_file);
13675 GetOpenFile(ARGF.current_file, fptr);
13676 ARGF.encs = fptr->encs;
13677 return argf;
13678}
13679
13680/*
13681 * call-seq:
13682 * ARGF.tell -> Integer
13683 * ARGF.pos -> Integer
13684 *
13685 * Returns the current offset (in bytes) of the current file in ARGF.
13686 *
13687 * ARGF.pos #=> 0
13688 * ARGF.gets #=> "This is line one\n"
13689 * ARGF.pos #=> 17
13690 *
13691 */
13692static VALUE
13693argf_tell(VALUE argf)
13694{
13695 if (!next_argv()) {
13696 rb_raise(rb_eArgError, "no stream to tell");
13697 }
13698 ARGF_FORWARD(0, 0);
13699 return rb_io_tell(ARGF.current_file);
13700}
13701
13702/*
13703 * call-seq:
13704 * ARGF.seek(amount, whence=IO::SEEK_SET) -> 0
13705 *
13706 * Seeks to offset _amount_ (an Integer) in the ARGF stream according to
13707 * the value of _whence_. See IO#seek for further details.
13708 */
13709static VALUE
13710argf_seek_m(int argc, VALUE *argv, VALUE argf)
13711{
13712 if (!next_argv()) {
13713 rb_raise(rb_eArgError, "no stream to seek");
13714 }
13715 ARGF_FORWARD(argc, argv);
13716 return rb_io_seek_m(argc, argv, ARGF.current_file);
13717}
13718
13719/*
13720 * call-seq:
13721 * ARGF.pos = position -> Integer
13722 *
13723 * Seeks to the position given by _position_ (in bytes) in ARGF.
13724 *
13725 * For example:
13726 *
13727 * ARGF.pos = 17
13728 * ARGF.gets #=> "This is line two\n"
13729 */
13730static VALUE
13731argf_set_pos(VALUE argf, VALUE offset)
13732{
13733 if (!next_argv()) {
13734 rb_raise(rb_eArgError, "no stream to set position");
13735 }
13736 ARGF_FORWARD(1, &offset);
13737 return rb_io_set_pos(ARGF.current_file, offset);
13738}
13739
13740/*
13741 * call-seq:
13742 * ARGF.rewind -> 0
13743 *
13744 * Positions the current file to the beginning of input, resetting
13745 * ARGF.lineno to zero.
13746 *
13747 * ARGF.readline #=> "This is line one\n"
13748 * ARGF.rewind #=> 0
13749 * ARGF.lineno #=> 0
13750 * ARGF.readline #=> "This is line one\n"
13751 */
13752static VALUE
13753argf_rewind(VALUE argf)
13754{
13755 VALUE ret;
13756 int old_lineno;
13757
13758 if (!next_argv()) {
13759 rb_raise(rb_eArgError, "no stream to rewind");
13760 }
13761 ARGF_FORWARD(0, 0);
13762 old_lineno = RFILE(ARGF.current_file)->fptr->lineno;
13763 ret = rb_io_rewind(ARGF.current_file);
13764 if (!global_argf_p(argf)) {
13765 ARGF.last_lineno = ARGF.lineno -= old_lineno;
13766 }
13767 return ret;
13768}
13769
13770/*
13771 * call-seq:
13772 * ARGF.fileno -> integer
13773 * ARGF.to_i -> integer
13774 *
13775 * Returns an integer representing the numeric file descriptor for
13776 * the current file. Raises an ArgumentError if there isn't a current file.
13777 *
13778 * ARGF.fileno #=> 3
13779 */
13780static VALUE
13781argf_fileno(VALUE argf)
13782{
13783 if (!next_argv()) {
13784 rb_raise(rb_eArgError, "no stream");
13785 }
13786 ARGF_FORWARD(0, 0);
13787 return rb_io_fileno(ARGF.current_file);
13788}
13789
13790/*
13791 * call-seq:
13792 * ARGF.to_io -> IO
13793 *
13794 * Returns an IO object representing the current file. This will be a
13795 * File object unless the current file is a stream such as STDIN.
13796 *
13797 * For example:
13798 *
13799 * ARGF.to_io #=> #<File:glark.txt>
13800 * ARGF.to_io #=> #<IO:<STDIN>>
13801 */
13802static VALUE
13803argf_to_io(VALUE argf)
13804{
13805 next_argv();
13806 ARGF_FORWARD(0, 0);
13807 return ARGF.current_file;
13808}
13809
13810/*
13811 * call-seq:
13812 * ARGF.eof? -> true or false
13813 * ARGF.eof -> true or false
13814 *
13815 * Returns true if the current file in ARGF is at end of file, i.e. it has
13816 * no data to read. The stream must be opened for reading or an IOError
13817 * will be raised.
13818 *
13819 * $ echo "eof" | ruby argf.rb
13820 *
13821 * ARGF.eof? #=> false
13822 * 3.times { ARGF.readchar }
13823 * ARGF.eof? #=> false
13824 * ARGF.readchar #=> "\n"
13825 * ARGF.eof? #=> true
13826 */
13827
13828static VALUE
13829argf_eof(VALUE argf)
13830{
13831 next_argv();
13832 if (RTEST(ARGF.current_file)) {
13833 if (ARGF.init_p == 0) return Qtrue;
13834 next_argv();
13835 ARGF_FORWARD(0, 0);
13836 if (rb_io_eof(ARGF.current_file)) {
13837 return Qtrue;
13838 }
13839 }
13840 return Qfalse;
13841}
13842
13843/*
13844 * call-seq:
13845 * ARGF.read([length [, outbuf]]) -> string, outbuf, or nil
13846 *
13847 * Reads _length_ bytes from ARGF. The files named on the command line
13848 * are concatenated and treated as a single file by this method, so when
13849 * called without arguments the contents of this pseudo file are returned in
13850 * their entirety.
13851 *
13852 * _length_ must be a non-negative integer or +nil+.
13853 *
13854 * If _length_ is a positive integer, +read+ tries to read
13855 * _length_ bytes without any conversion (binary mode).
13856 * It returns +nil+ if an EOF is encountered before anything can be read.
13857 * Fewer than _length_ bytes are returned if an EOF is encountered during
13858 * the read.
13859 * In the case of an integer _length_, the resulting string is always
13860 * in ASCII-8BIT encoding.
13861 *
13862 * If _length_ is omitted or is +nil+, it reads until EOF
13863 * and the encoding conversion is applied, if applicable.
13864 * A string is returned even if EOF is encountered before any data is read.
13865 *
13866 * If _length_ is zero, it returns an empty string (<code>""</code>).
13867 *
13868 * If the optional _outbuf_ argument is present,
13869 * it must reference a String, which will receive the data.
13870 * The _outbuf_ will contain only the received data after the method call
13871 * even if it is not empty at the beginning.
13872 *
13873 * For example:
13874 *
13875 * $ echo "small" > small.txt
13876 * $ echo "large" > large.txt
13877 * $ ./glark.rb small.txt large.txt
13878 *
13879 * ARGF.read #=> "small\nlarge"
13880 * ARGF.read(200) #=> "small\nlarge"
13881 * ARGF.read(2) #=> "sm"
13882 * ARGF.read(0) #=> ""
13883 *
13884 * Note that this method behaves like the fread() function in C.
13885 * This means it retries to invoke read(2) system calls to read data
13886 * with the specified length.
13887 * If you need the behavior like a single read(2) system call,
13888 * consider ARGF#readpartial or ARGF#read_nonblock.
13889 */
13890
13891static VALUE
13892argf_read(int argc, VALUE *argv, VALUE argf)
13893{
13894 VALUE tmp, str, length;
13895 long len = 0;
13896
13897 rb_scan_args(argc, argv, "02", &length, &str);
13898 if (!NIL_P(length)) {
13899 len = NUM2LONG(argv[0]);
13900 }
13901 if (!NIL_P(str)) {
13902 StringValue(str);
13903 rb_str_resize(str,0);
13904 argv[1] = Qnil;
13905 }
13906
13907 retry:
13908 if (!next_argv()) {
13909 return str;
13910 }
13911 if (ARGF_GENERIC_INPUT_P()) {
13912 tmp = argf_forward(argc, argv, argf);
13913 }
13914 else {
13915 tmp = io_read(argc, argv, ARGF.current_file);
13916 }
13917 if (NIL_P(str)) str = tmp;
13918 else if (!NIL_P(tmp)) rb_str_append(str, tmp);
13919 if (NIL_P(tmp) || NIL_P(length)) {
13920 if (ARGF.next_p != -1) {
13921 argf_close(argf);
13922 ARGF.next_p = 1;
13923 goto retry;
13924 }
13925 }
13926 else if (argc >= 1) {
13927 long slen = RSTRING_LEN(str);
13928 if (slen < len) {
13929 argv[0] = LONG2NUM(len - slen);
13930 goto retry;
13931 }
13932 }
13933 return str;
13934}
13935
13937 int argc;
13938 VALUE *argv;
13939 VALUE argf;
13940};
13941
13942static VALUE
13943argf_forward_call(VALUE arg)
13944{
13945 struct argf_call_arg *p = (struct argf_call_arg *)arg;
13946 argf_forward(p->argc, p->argv, p->argf);
13947 return Qnil;
13948}
13949
13950static VALUE argf_getpartial(int argc, VALUE *argv, VALUE argf, VALUE opts,
13951 int nonblock);
13952
13953/*
13954 * call-seq:
13955 * ARGF.readpartial(maxlen) -> string
13956 * ARGF.readpartial(maxlen, outbuf) -> outbuf
13957 *
13958 * Reads at most _maxlen_ bytes from the ARGF stream.
13959 *
13960 * If the optional _outbuf_ argument is present,
13961 * it must reference a String, which will receive the data.
13962 * The _outbuf_ will contain only the received data after the method call
13963 * even if it is not empty at the beginning.
13964 *
13965 * It raises EOFError on end of ARGF stream.
13966 * Since ARGF stream is a concatenation of multiple files,
13967 * internally EOF is occur for each file.
13968 * ARGF.readpartial returns empty strings for EOFs except the last one and
13969 * raises EOFError for the last one.
13970 *
13971 */
13972
13973static VALUE
13974argf_readpartial(int argc, VALUE *argv, VALUE argf)
13975{
13976 return argf_getpartial(argc, argv, argf, Qnil, 0);
13977}
13978
13979/*
13980 * call-seq:
13981 * ARGF.read_nonblock(maxlen[, options]) -> string
13982 * ARGF.read_nonblock(maxlen, outbuf[, options]) -> outbuf
13983 *
13984 * Reads at most _maxlen_ bytes from the ARGF stream in non-blocking mode.
13985 */
13986
13987static VALUE
13988argf_read_nonblock(int argc, VALUE *argv, VALUE argf)
13989{
13990 VALUE opts;
13991
13992 rb_scan_args(argc, argv, "11:", NULL, NULL, &opts);
13993
13994 if (!NIL_P(opts))
13995 argc--;
13996
13997 return argf_getpartial(argc, argv, argf, opts, 1);
13998}
13999
14000static VALUE
14001argf_getpartial(int argc, VALUE *argv, VALUE argf, VALUE opts, int nonblock)
14002{
14003 VALUE tmp, str, length;
14004 int no_exception;
14005
14006 rb_scan_args(argc, argv, "11", &length, &str);
14007 if (!NIL_P(str)) {
14008 StringValue(str);
14009 argv[1] = str;
14010 }
14011 no_exception = no_exception_p(opts);
14012
14013 if (!next_argv()) {
14014 if (!NIL_P(str)) {
14015 rb_str_resize(str, 0);
14016 }
14017 rb_eof_error();
14018 }
14019 if (ARGF_GENERIC_INPUT_P()) {
14020 VALUE (*const rescue_does_nothing)(VALUE, VALUE) = 0;
14021 struct argf_call_arg arg;
14022 arg.argc = argc;
14023 arg.argv = argv;
14024 arg.argf = argf;
14025 tmp = rb_rescue2(argf_forward_call, (VALUE)&arg,
14026 rescue_does_nothing, Qnil, rb_eEOFError, (VALUE)0);
14027 }
14028 else {
14029 tmp = io_getpartial(argc, argv, ARGF.current_file, no_exception, nonblock);
14030 }
14031 if (NIL_P(tmp)) {
14032 if (ARGF.next_p == -1) {
14033 return io_nonblock_eof(no_exception);
14034 }
14035 argf_close(argf);
14036 ARGF.next_p = 1;
14037 if (RARRAY_LEN(ARGF.argv) == 0) {
14038 return io_nonblock_eof(no_exception);
14039 }
14040 if (NIL_P(str))
14041 str = rb_str_new(NULL, 0);
14042 return str;
14043 }
14044 return tmp;
14045}
14046
14047/*
14048 * call-seq:
14049 * ARGF.getc -> String or nil
14050 *
14051 * Reads the next character from ARGF and returns it as a String. Returns
14052 * +nil+ at the end of the stream.
14053 *
14054 * ARGF treats the files named on the command line as a single file created
14055 * by concatenating their contents. After returning the last character of the
14056 * first file, it returns the first character of the second file, and so on.
14057 *
14058 * For example:
14059 *
14060 * $ echo "foo" > file
14061 * $ ruby argf.rb file
14062 *
14063 * ARGF.getc #=> "f"
14064 * ARGF.getc #=> "o"
14065 * ARGF.getc #=> "o"
14066 * ARGF.getc #=> "\n"
14067 * ARGF.getc #=> nil
14068 * ARGF.getc #=> nil
14069 */
14070static VALUE
14071argf_getc(VALUE argf)
14072{
14073 VALUE ch;
14074
14075 retry:
14076 if (!next_argv()) return Qnil;
14077 if (ARGF_GENERIC_INPUT_P()) {
14078 ch = forward_current(rb_intern("getc"), 0, 0);
14079 }
14080 else {
14081 ch = rb_io_getc(ARGF.current_file);
14082 }
14083 if (NIL_P(ch) && ARGF.next_p != -1) {
14084 argf_close(argf);
14085 ARGF.next_p = 1;
14086 goto retry;
14087 }
14088
14089 return ch;
14090}
14091
14092/*
14093 * call-seq:
14094 * ARGF.getbyte -> Integer or nil
14095 *
14096 * Gets the next 8-bit byte (0..255) from ARGF. Returns +nil+ if called at
14097 * the end of the stream.
14098 *
14099 * For example:
14100 *
14101 * $ echo "foo" > file
14102 * $ ruby argf.rb file
14103 *
14104 * ARGF.getbyte #=> 102
14105 * ARGF.getbyte #=> 111
14106 * ARGF.getbyte #=> 111
14107 * ARGF.getbyte #=> 10
14108 * ARGF.getbyte #=> nil
14109 */
14110static VALUE
14111argf_getbyte(VALUE argf)
14112{
14113 VALUE ch;
14114
14115 retry:
14116 if (!next_argv()) return Qnil;
14117 if (!RB_TYPE_P(ARGF.current_file, T_FILE)) {
14118 ch = forward_current(rb_intern("getbyte"), 0, 0);
14119 }
14120 else {
14121 ch = rb_io_getbyte(ARGF.current_file);
14122 }
14123 if (NIL_P(ch) && ARGF.next_p != -1) {
14124 argf_close(argf);
14125 ARGF.next_p = 1;
14126 goto retry;
14127 }
14128
14129 return ch;
14130}
14131
14132/*
14133 * call-seq:
14134 * ARGF.readchar -> String or nil
14135 *
14136 * Reads the next character from ARGF and returns it as a String. Raises
14137 * an EOFError after the last character of the last file has been read.
14138 *
14139 * For example:
14140 *
14141 * $ echo "foo" > file
14142 * $ ruby argf.rb file
14143 *
14144 * ARGF.readchar #=> "f"
14145 * ARGF.readchar #=> "o"
14146 * ARGF.readchar #=> "o"
14147 * ARGF.readchar #=> "\n"
14148 * ARGF.readchar #=> end of file reached (EOFError)
14149 */
14150static VALUE
14151argf_readchar(VALUE argf)
14152{
14153 VALUE ch;
14154
14155 retry:
14156 if (!next_argv()) rb_eof_error();
14157 if (!RB_TYPE_P(ARGF.current_file, T_FILE)) {
14158 ch = forward_current(rb_intern("getc"), 0, 0);
14159 }
14160 else {
14161 ch = rb_io_getc(ARGF.current_file);
14162 }
14163 if (NIL_P(ch) && ARGF.next_p != -1) {
14164 argf_close(argf);
14165 ARGF.next_p = 1;
14166 goto retry;
14167 }
14168
14169 return ch;
14170}
14171
14172/*
14173 * call-seq:
14174 * ARGF.readbyte -> Integer
14175 *
14176 * Reads the next 8-bit byte from ARGF and returns it as an Integer. Raises
14177 * an EOFError after the last byte of the last file has been read.
14178 *
14179 * For example:
14180 *
14181 * $ echo "foo" > file
14182 * $ ruby argf.rb file
14183 *
14184 * ARGF.readbyte #=> 102
14185 * ARGF.readbyte #=> 111
14186 * ARGF.readbyte #=> 111
14187 * ARGF.readbyte #=> 10
14188 * ARGF.readbyte #=> end of file reached (EOFError)
14189 */
14190static VALUE
14191argf_readbyte(VALUE argf)
14192{
14193 VALUE c;
14194
14195 NEXT_ARGF_FORWARD(0, 0);
14196 c = argf_getbyte(argf);
14197 if (NIL_P(c)) {
14198 rb_eof_error();
14199 }
14200 return c;
14201}
14202
14203#define FOREACH_ARGF() while (next_argv())
14204
14205static VALUE
14206argf_block_call_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, argf))
14207{
14208 const VALUE current = ARGF.current_file;
14209 rb_yield_values2(argc, argv);
14210 if (ARGF.init_p == -1 || current != ARGF.current_file) {
14212 }
14213 return Qnil;
14214}
14215
14216#define ARGF_block_call(mid, argc, argv, func, argf) \
14217 rb_block_call_kw(ARGF.current_file, mid, argc, argv, \
14218 func, argf, rb_keyword_given_p())
14219
14220static void
14221argf_block_call(ID mid, int argc, VALUE *argv, VALUE argf)
14222{
14223 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_i, argf);
14224 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14225}
14226
14227static VALUE
14228argf_block_call_line_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, argf))
14229{
14230 if (!global_argf_p(argf)) {
14231 ARGF.last_lineno = ++ARGF.lineno;
14232 }
14233 return argf_block_call_i(i, argf, argc, argv, blockarg);
14234}
14235
14236static void
14237argf_block_call_line(ID mid, int argc, VALUE *argv, VALUE argf)
14238{
14239 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_line_i, argf);
14240 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14241}
14242
14243/*
14244 * call-seq:
14245 * ARGF.each(sep=$/) {|line| block } -> ARGF
14246 * ARGF.each(sep=$/, limit) {|line| block } -> ARGF
14247 * ARGF.each(...) -> an_enumerator
14248 *
14249 * ARGF.each_line(sep=$/) {|line| block } -> ARGF
14250 * ARGF.each_line(sep=$/, limit) {|line| block } -> ARGF
14251 * ARGF.each_line(...) -> an_enumerator
14252 *
14253 * Returns an enumerator which iterates over each line (separated by _sep_,
14254 * which defaults to your platform's newline character) of each file in
14255 * +ARGV+. If a block is supplied, each line in turn will be yielded to the
14256 * block, otherwise an enumerator is returned.
14257 * The optional _limit_ argument is an Integer specifying the maximum
14258 * length of each line; longer lines will be split according to this limit.
14259 *
14260 * This method allows you to treat the files supplied on the command line as
14261 * a single file consisting of the concatenation of each named file. After
14262 * the last line of the first file has been returned, the first line of the
14263 * second file is returned. The ARGF.filename and ARGF.lineno methods can be
14264 * used to determine the filename of the current line and line number of the
14265 * whole input, respectively.
14266 *
14267 * For example, the following code prints out each line of each named file
14268 * prefixed with its line number, displaying the filename once per file:
14269 *
14270 * ARGF.each_line do |line|
14271 * puts ARGF.filename if ARGF.file.lineno == 1
14272 * puts "#{ARGF.file.lineno}: #{line}"
14273 * end
14274 *
14275 * While the following code prints only the first file's name at first, and
14276 * the contents with line number counted through all named files.
14277 *
14278 * ARGF.each_line do |line|
14279 * puts ARGF.filename if ARGF.lineno == 1
14280 * puts "#{ARGF.lineno}: #{line}"
14281 * end
14282 */
14283static VALUE
14284argf_each_line(int argc, VALUE *argv, VALUE argf)
14285{
14286 RETURN_ENUMERATOR(argf, argc, argv);
14287 FOREACH_ARGF() {
14288 argf_block_call_line(rb_intern("each_line"), argc, argv, argf);
14289 }
14290 return argf;
14291}
14292
14293/*
14294 * call-seq:
14295 * ARGF.each_byte {|byte| block } -> ARGF
14296 * ARGF.each_byte -> an_enumerator
14297 *
14298 * Iterates over each byte of each file in +ARGV+.
14299 * A byte is returned as an Integer in the range 0..255.
14300 *
14301 * This method allows you to treat the files supplied on the command line as
14302 * a single file consisting of the concatenation of each named file. After
14303 * the last byte of the first file has been returned, the first byte of the
14304 * second file is returned. The ARGF.filename method can be used to
14305 * determine the filename of the current byte.
14306 *
14307 * If no block is given, an enumerator is returned instead.
14308 *
14309 * For example:
14310 *
14311 * ARGF.bytes.to_a #=> [35, 32, ... 95, 10]
14312 *
14313 */
14314static VALUE
14315argf_each_byte(VALUE argf)
14316{
14317 RETURN_ENUMERATOR(argf, 0, 0);
14318 FOREACH_ARGF() {
14319 argf_block_call(rb_intern("each_byte"), 0, 0, argf);
14320 }
14321 return argf;
14322}
14323
14324/*
14325 * call-seq:
14326 * ARGF.each_char {|char| block } -> ARGF
14327 * ARGF.each_char -> an_enumerator
14328 *
14329 * Iterates over each character of each file in ARGF.
14330 *
14331 * This method allows you to treat the files supplied on the command line as
14332 * a single file consisting of the concatenation of each named file. After
14333 * the last character of the first file has been returned, the first
14334 * character of the second file is returned. The ARGF.filename method can
14335 * be used to determine the name of the file in which the current character
14336 * appears.
14337 *
14338 * If no block is given, an enumerator is returned instead.
14339 */
14340static VALUE
14341argf_each_char(VALUE argf)
14342{
14343 RETURN_ENUMERATOR(argf, 0, 0);
14344 FOREACH_ARGF() {
14345 argf_block_call(rb_intern("each_char"), 0, 0, argf);
14346 }
14347 return argf;
14348}
14349
14350/*
14351 * call-seq:
14352 * ARGF.each_codepoint {|codepoint| block } -> ARGF
14353 * ARGF.each_codepoint -> an_enumerator
14354 *
14355 * Iterates over each codepoint of each file in ARGF.
14356 *
14357 * This method allows you to treat the files supplied on the command line as
14358 * a single file consisting of the concatenation of each named file. After
14359 * the last codepoint of the first file has been returned, the first
14360 * codepoint of the second file is returned. The ARGF.filename method can
14361 * be used to determine the name of the file in which the current codepoint
14362 * appears.
14363 *
14364 * If no block is given, an enumerator is returned instead.
14365 */
14366static VALUE
14367argf_each_codepoint(VALUE argf)
14368{
14369 RETURN_ENUMERATOR(argf, 0, 0);
14370 FOREACH_ARGF() {
14371 argf_block_call(rb_intern("each_codepoint"), 0, 0, argf);
14372 }
14373 return argf;
14374}
14375
14376/*
14377 * call-seq:
14378 * ARGF.filename -> String
14379 * ARGF.path -> String
14380 *
14381 * Returns the current filename. "-" is returned when the current file is
14382 * STDIN.
14383 *
14384 * For example:
14385 *
14386 * $ echo "foo" > foo
14387 * $ echo "bar" > bar
14388 * $ echo "glark" > glark
14389 *
14390 * $ ruby argf.rb foo bar glark
14391 *
14392 * ARGF.filename #=> "foo"
14393 * ARGF.read(5) #=> "foo\nb"
14394 * ARGF.filename #=> "bar"
14395 * ARGF.skip
14396 * ARGF.filename #=> "glark"
14397 */
14398static VALUE
14399argf_filename(VALUE argf)
14400{
14401 next_argv();
14402 return ARGF.filename;
14403}
14404
14405static VALUE
14406argf_filename_getter(ID id, VALUE *var)
14407{
14408 return argf_filename(*var);
14409}
14410
14411/*
14412 * call-seq:
14413 * ARGF.file -> IO or File object
14414 *
14415 * Returns the current file as an IO or File object.
14416 * <code>$stdin</code> is returned when the current file is STDIN.
14417 *
14418 * For example:
14419 *
14420 * $ echo "foo" > foo
14421 * $ echo "bar" > bar
14422 *
14423 * $ ruby argf.rb foo bar
14424 *
14425 * ARGF.file #=> #<File:foo>
14426 * ARGF.read(5) #=> "foo\nb"
14427 * ARGF.file #=> #<File:bar>
14428 */
14429static VALUE
14430argf_file(VALUE argf)
14431{
14432 next_argv();
14433 return ARGF.current_file;
14434}
14435
14436/*
14437 * call-seq:
14438 * ARGF.binmode -> ARGF
14439 *
14440 * Puts ARGF into binary mode. Once a stream is in binary mode, it cannot
14441 * be reset to non-binary mode. This option has the following effects:
14442 *
14443 * * Newline conversion is disabled.
14444 * * Encoding conversion is disabled.
14445 * * Content is treated as ASCII-8BIT.
14446 */
14447static VALUE
14448argf_binmode_m(VALUE argf)
14449{
14450 ARGF.binmode = 1;
14451 next_argv();
14452 ARGF_FORWARD(0, 0);
14453 rb_io_ascii8bit_binmode(ARGF.current_file);
14454 return argf;
14455}
14456
14457/*
14458 * call-seq:
14459 * ARGF.binmode? -> true or false
14460 *
14461 * Returns true if ARGF is being read in binary mode; false otherwise.
14462 * To enable binary mode use ARGF.binmode.
14463 *
14464 * For example:
14465 *
14466 * ARGF.binmode? #=> false
14467 * ARGF.binmode
14468 * ARGF.binmode? #=> true
14469 */
14470static VALUE
14471argf_binmode_p(VALUE argf)
14472{
14473 return RBOOL(ARGF.binmode);
14474}
14475
14476/*
14477 * call-seq:
14478 * ARGF.skip -> ARGF
14479 *
14480 * Sets the current file to the next file in ARGV. If there aren't any more
14481 * files it has no effect.
14482 *
14483 * For example:
14484 *
14485 * $ ruby argf.rb foo bar
14486 * ARGF.filename #=> "foo"
14487 * ARGF.skip
14488 * ARGF.filename #=> "bar"
14489 */
14490static VALUE
14491argf_skip(VALUE argf)
14492{
14493 if (ARGF.init_p && ARGF.next_p == 0) {
14494 argf_close(argf);
14495 ARGF.next_p = 1;
14496 }
14497 return argf;
14498}
14499
14500/*
14501 * call-seq:
14502 * ARGF.close -> ARGF
14503 *
14504 * Closes the current file and skips to the next file in ARGV. If there are
14505 * no more files to open, just closes the current file. STDIN will not be
14506 * closed.
14507 *
14508 * For example:
14509 *
14510 * $ ruby argf.rb foo bar
14511 *
14512 * ARGF.filename #=> "foo"
14513 * ARGF.close
14514 * ARGF.filename #=> "bar"
14515 * ARGF.close
14516 */
14517static VALUE
14518argf_close_m(VALUE argf)
14519{
14520 next_argv();
14521 argf_close(argf);
14522 if (ARGF.next_p != -1) {
14523 ARGF.next_p = 1;
14524 }
14525 ARGF.lineno = 0;
14526 return argf;
14527}
14528
14529/*
14530 * call-seq:
14531 * ARGF.closed? -> true or false
14532 *
14533 * Returns _true_ if the current file has been closed; _false_ otherwise. Use
14534 * ARGF.close to actually close the current file.
14535 */
14536static VALUE
14537argf_closed(VALUE argf)
14538{
14539 next_argv();
14540 ARGF_FORWARD(0, 0);
14541 return rb_io_closed_p(ARGF.current_file);
14542}
14543
14544/*
14545 * call-seq:
14546 * ARGF.to_s -> String
14547 *
14548 * Returns "ARGF".
14549 */
14550static VALUE
14551argf_to_s(VALUE argf)
14552{
14553 return rb_str_new2("ARGF");
14554}
14555
14556/*
14557 * call-seq:
14558 * ARGF.inplace_mode -> String
14559 *
14560 * Returns the file extension appended to the names of backup copies of
14561 * modified files under in-place edit mode. This value can be set using
14562 * ARGF.inplace_mode= or passing the +-i+ switch to the Ruby binary.
14563 */
14564static VALUE
14565argf_inplace_mode_get(VALUE argf)
14566{
14567 if (!ARGF.inplace) return Qnil;
14568 if (NIL_P(ARGF.inplace)) return rb_str_new(0, 0);
14569 return rb_str_dup(ARGF.inplace);
14570}
14571
14572static VALUE
14573opt_i_get(ID id, VALUE *var)
14574{
14575 return argf_inplace_mode_get(*var);
14576}
14577
14578/*
14579 * call-seq:
14580 * ARGF.inplace_mode = ext -> ARGF
14581 *
14582 * Sets the filename extension for in-place editing mode to the given String.
14583 * The backup copy of each file being edited has this value appended to its
14584 * filename.
14585 *
14586 * For example:
14587 *
14588 * $ ruby argf.rb file.txt
14589 *
14590 * ARGF.inplace_mode = '.bak'
14591 * ARGF.each_line do |line|
14592 * print line.sub("foo","bar")
14593 * end
14594 *
14595 * First, _file.txt.bak_ is created as a backup copy of _file.txt_.
14596 * Then, each line of _file.txt_ has the first occurrence of "foo" replaced with
14597 * "bar".
14598 */
14599static VALUE
14600argf_inplace_mode_set(VALUE argf, VALUE val)
14601{
14602 if (!RTEST(val)) {
14603 ARGF.inplace = Qfalse;
14604 }
14605 else if (StringValueCStr(val), !RSTRING_LEN(val)) {
14606 ARGF.inplace = Qnil;
14607 }
14608 else {
14609 ARGF.inplace = rb_str_new_frozen(val);
14610 }
14611 return argf;
14612}
14613
14614static void
14615opt_i_set(VALUE val, ID id, VALUE *var)
14616{
14617 argf_inplace_mode_set(*var, val);
14618}
14619
14620void
14621ruby_set_inplace_mode(const char *suffix)
14622{
14623 ARGF.inplace = !suffix ? Qfalse : !*suffix ? Qnil : rb_str_new(suffix, strlen(suffix));
14624}
14625
14626/*
14627 * call-seq:
14628 * ARGF.argv -> ARGV
14629 *
14630 * Returns the +ARGV+ array, which contains the arguments passed to your
14631 * script, one per element.
14632 *
14633 * For example:
14634 *
14635 * $ ruby argf.rb -v glark.txt
14636 *
14637 * ARGF.argv #=> ["-v", "glark.txt"]
14638 *
14639 */
14640static VALUE
14641argf_argv(VALUE argf)
14642{
14643 return ARGF.argv;
14644}
14645
14646static VALUE
14647argf_argv_getter(ID id, VALUE *var)
14648{
14649 return argf_argv(*var);
14650}
14651
14652VALUE
14654{
14655 return ARGF.argv;
14656}
14657
14658/*
14659 * call-seq:
14660 * ARGF.to_write_io -> io
14661 *
14662 * Returns IO instance tied to _ARGF_ for writing if inplace mode is
14663 * enabled.
14664 */
14665static VALUE
14666argf_write_io(VALUE argf)
14667{
14668 if (!RTEST(ARGF.current_file)) {
14669 rb_raise(rb_eIOError, "not opened for writing");
14670 }
14671 return GetWriteIO(ARGF.current_file);
14672}
14673
14674/*
14675 * call-seq:
14676 * ARGF.write(*objects) -> integer
14677 *
14678 * Writes each of the given +objects+ if inplace mode.
14679 */
14680static VALUE
14681argf_write(int argc, VALUE *argv, VALUE argf)
14682{
14683 return rb_io_writev(argf_write_io(argf), argc, argv);
14684}
14685
14686void
14687rb_readwrite_sys_fail(enum rb_io_wait_readwrite waiting, const char *mesg)
14688{
14689 rb_readwrite_syserr_fail(waiting, errno, mesg);
14690}
14691
14692void
14693rb_readwrite_syserr_fail(enum rb_io_wait_readwrite waiting, int n, const char *mesg)
14694{
14695 VALUE arg, c = Qnil;
14696 arg = mesg ? rb_str_new2(mesg) : Qnil;
14697 switch (waiting) {
14698 case RB_IO_WAIT_WRITABLE:
14699 switch (n) {
14700 case EAGAIN:
14701 c = rb_eEAGAINWaitWritable;
14702 break;
14703#if EAGAIN != EWOULDBLOCK
14704 case EWOULDBLOCK:
14705 c = rb_eEWOULDBLOCKWaitWritable;
14706 break;
14707#endif
14708 case EINPROGRESS:
14709 c = rb_eEINPROGRESSWaitWritable;
14710 break;
14711 default:
14713 }
14714 break;
14715 case RB_IO_WAIT_READABLE:
14716 switch (n) {
14717 case EAGAIN:
14718 c = rb_eEAGAINWaitReadable;
14719 break;
14720#if EAGAIN != EWOULDBLOCK
14721 case EWOULDBLOCK:
14722 c = rb_eEWOULDBLOCKWaitReadable;
14723 break;
14724#endif
14725 case EINPROGRESS:
14726 c = rb_eEINPROGRESSWaitReadable;
14727 break;
14728 default:
14730 }
14731 break;
14732 default:
14733 rb_bug("invalid read/write type passed to rb_readwrite_sys_fail: %d", waiting);
14734 }
14736}
14737
14738static VALUE
14739get_LAST_READ_LINE(ID _x, VALUE *_y)
14740{
14741 return rb_lastline_get();
14742}
14743
14744static void
14745set_LAST_READ_LINE(VALUE val, ID _x, VALUE *_y)
14746{
14747 rb_lastline_set(val);
14748}
14749
14750/*
14751 * Document-class: IOError
14752 *
14753 * Raised when an IO operation fails.
14754 *
14755 * File.open("/etc/hosts") {|f| f << "example"}
14756 * #=> IOError: not opened for writing
14757 *
14758 * File.open("/etc/hosts") {|f| f.close; f.read }
14759 * #=> IOError: closed stream
14760 *
14761 * Note that some IO failures raise <code>SystemCallError</code>s
14762 * and these are not subclasses of IOError:
14763 *
14764 * File.open("does/not/exist")
14765 * #=> Errno::ENOENT: No such file or directory - does/not/exist
14766 */
14767
14768/*
14769 * Document-class: EOFError
14770 *
14771 * Raised by some IO operations when reaching the end of file. Many IO
14772 * methods exist in two forms,
14773 *
14774 * one that returns +nil+ when the end of file is reached, the other
14775 * raises EOFError.
14776 *
14777 * EOFError is a subclass of IOError.
14778 *
14779 * file = File.open("/etc/hosts")
14780 * file.read
14781 * file.gets #=> nil
14782 * file.readline #=> EOFError: end of file reached
14783 * file.close
14784 */
14785
14786/*
14787 * Document-class: ARGF
14788 *
14789 * == \ARGF and +ARGV+
14790 *
14791 * The \ARGF object works with the array at global variable +ARGV+
14792 * to make <tt>$stdin</tt> and file streams available in the Ruby program:
14793 *
14794 * - **ARGV** may be thought of as the <b>argument vector</b> array.
14795 *
14796 * Initially, it contains the command-line arguments and options
14797 * that are passed to the Ruby program;
14798 * the program can modify that array as it likes.
14799 *
14800 * - **ARGF** may be thought of as the <b>argument files</b> object.
14801 *
14802 * It can access file streams and/or the <tt>$stdin</tt> stream,
14803 * based on what it finds in +ARGV+.
14804 * This provides a convenient way for the command line
14805 * to specify streams for a Ruby program to read.
14806 *
14807 * == Reading
14808 *
14809 * \ARGF may read from _source_ streams,
14810 * which at any particular time are determined by the content of +ARGV+.
14811 *
14812 * === Simplest Case
14813 *
14814 * When the <i>very first</i> \ARGF read occurs with an empty +ARGV+ (<tt>[]</tt>),
14815 * the source is <tt>$stdin</tt>:
14816 *
14817 * - \File +t.rb+:
14818 *
14819 * p ['ARGV', ARGV]
14820 * p ['ARGF.read', ARGF.read]
14821 *
14822 * - Commands and outputs
14823 * (see below for the content of files +foo.txt+ and +bar.txt+):
14824 *
14825 * $ echo "Open the pod bay doors, Hal." | ruby t.rb
14826 * ["ARGV", []]
14827 * ["ARGF.read", "Open the pod bay doors, Hal.\n"]
14828 *
14829 * $ cat foo.txt bar.txt | ruby t.rb
14830 * ["ARGV", []]
14831 * ["ARGF.read", "Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"]
14832 *
14833 * === About the Examples
14834 *
14835 * Many examples here assume the existence of files +foo.txt+ and +bar.txt+:
14836 *
14837 * $ cat foo.txt
14838 * Foo 0
14839 * Foo 1
14840 * $ cat bar.txt
14841 * Bar 0
14842 * Bar 1
14843 * Bar 2
14844 * Bar 3
14845 *
14846 * === Sources in +ARGV+
14847 *
14848 * For any \ARGF read _except_ the {simplest case}[rdoc-ref:ARGF@Simplest+Case]
14849 * (that is, _except_ for the <i>very first</i> \ARGF read with an empty +ARGV+),
14850 * the sources are found in +ARGV+.
14851 *
14852 * \ARGF assumes that each element in array +ARGV+ is a potential source,
14853 * and is one of:
14854 *
14855 * - The string path to a file that may be opened as a stream.
14856 * - The character <tt>'-'</tt>, meaning stream <tt>$stdin</tt>.
14857 *
14858 * Each element that is _not_ one of these
14859 * should be removed from +ARGV+ before \ARGF accesses that source.
14860 *
14861 * In the following example:
14862 *
14863 * - Filepaths +foo.txt+ and +bar.txt+ may be retained as potential sources.
14864 * - Options <tt>--xyzzy</tt> and <tt>--mojo</tt> should be removed.
14865 *
14866 * Example:
14867 *
14868 * - \File +t.rb+:
14869 *
14870 * # Print arguments (and options, if any) found on command line.
14871 * p ['ARGV', ARGV]
14872 *
14873 * - Command and output:
14874 *
14875 * $ ruby t.rb --xyzzy --mojo foo.txt bar.txt
14876 * ["ARGV", ["--xyzzy", "--mojo", "foo.txt", "bar.txt"]]
14877 *
14878 * \ARGF's stream access considers the elements of +ARGV+, left to right:
14879 *
14880 * - \File +t.rb+:
14881 *
14882 * p "ARGV: #{ARGV}"
14883 * p "Read: #{ARGF.read}" # Read everything from all specified streams.
14884 *
14885 * - Command and output:
14886 *
14887 * $ ruby t.rb foo.txt bar.txt
14888 * "ARGV: [\"foo.txt\", \"bar.txt\"]"
14889 * "Read: Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"
14890 *
14891 * Because the value at +ARGV+ is an ordinary array,
14892 * you can manipulate it to control which sources \ARGF considers:
14893 *
14894 * - If you remove an element from +ARGV+, \ARGF will not consider the corresponding source.
14895 * - If you add an element to +ARGV+, \ARGF will consider the corresponding source.
14896 *
14897 * Each element in +ARGV+ is removed when its corresponding source is accessed;
14898 * when all sources have been accessed, the array is empty:
14899 *
14900 * - \File +t.rb+:
14901 *
14902 * until ARGV.empty? && ARGF.eof?
14903 * p "ARGV: #{ARGV}"
14904 * p "Line: #{ARGF.readline}" # Read each line from each specified stream.
14905 * end
14906 *
14907 * - Command and output:
14908 *
14909 * $ ruby t.rb foo.txt bar.txt
14910 * "ARGV: [\"foo.txt\", \"bar.txt\"]"
14911 * "Line: Foo 0\n"
14912 * "ARGV: [\"bar.txt\"]"
14913 * "Line: Foo 1\n"
14914 * "ARGV: [\"bar.txt\"]"
14915 * "Line: Bar 0\n"
14916 * "ARGV: []"
14917 * "Line: Bar 1\n"
14918 * "ARGV: []"
14919 * "Line: Bar 2\n"
14920 * "ARGV: []"
14921 * "Line: Bar 3\n"
14922 *
14923 * ==== Filepaths in +ARGV+
14924 *
14925 * The +ARGV+ array may contain filepaths the specify sources for \ARGF reading.
14926 *
14927 * This program prints what it reads from files at the paths specified
14928 * on the command line:
14929 *
14930 * - \File +t.rb+:
14931 *
14932 * p ['ARGV', ARGV]
14933 * # Read and print all content from the specified sources.
14934 * p ['ARGF.read', ARGF.read]
14935 *
14936 * - Command and output:
14937 *
14938 * $ ruby t.rb foo.txt bar.txt
14939 * ["ARGV", [foo.txt, bar.txt]
14940 * ["ARGF.read", "Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"]
14941 *
14942 * ==== Specifying <tt>$stdin</tt> in +ARGV+
14943 *
14944 * To specify stream <tt>$stdin</tt> in +ARGV+, us the character <tt>'-'</tt>:
14945 *
14946 * - \File +t.rb+:
14947 *
14948 * p ['ARGV', ARGV]
14949 * p ['ARGF.read', ARGF.read]
14950 *
14951 * - Command and output:
14952 *
14953 * $ echo "Open the pod bay doors, Hal." | ruby t.rb -
14954 * ["ARGV", ["-"]]
14955 * ["ARGF.read", "Open the pod bay doors, Hal.\n"]
14956 *
14957 * When no character <tt>'-'</tt> is given, stream <tt>$stdin</tt> is ignored
14958 * (exception:
14959 * see {Specifying $stdin in ARGV}[rdoc-ref:ARGF@Specifying+-24stdin+in+ARGV]):
14960 *
14961 * - Command and output:
14962 *
14963 * $ echo "Open the pod bay doors, Hal." | ruby t.rb foo.txt bar.txt
14964 * "ARGV: [\"foo.txt\", \"bar.txt\"]"
14965 * "Read: Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"
14966 *
14967 * ==== Mixtures and Repetitions in +ARGV+
14968 *
14969 * For an \ARGF reader, +ARGV+ may contain any mixture of filepaths
14970 * and character <tt>'-'</tt>, including repetitions.
14971 *
14972 * ==== Modifications to +ARGV+
14973 *
14974 * The running Ruby program may make any modifications to the +ARGV+ array;
14975 * the current value of +ARGV+ affects \ARGF reading.
14976 *
14977 * ==== Empty +ARGV+
14978 *
14979 * For an empty +ARGV+, an \ARGF read method either returns +nil+
14980 * or raises an exception, depending on the specific method.
14981 *
14982 * === More Read Methods
14983 *
14984 * As seen above, method ARGF#read reads the content of all sources
14985 * into a single string.
14986 * Other \ARGF methods provide other ways to access that content;
14987 * these include:
14988 *
14989 * - Byte access: #each_byte, #getbyte, #readbyte.
14990 * - Character access: #each_char, #getc, #readchar.
14991 * - Codepoint access: #each_codepoint.
14992 * - Line access: #each_line, #gets, #readline, #readlines.
14993 * - Source access: #read, #read_nonblock, #readpartial.
14994 *
14995 * === About \Enumerable
14996 *
14997 * \ARGF includes module Enumerable.
14998 * Virtually all methods in \Enumerable call method <tt>#each</tt> in the including class.
14999 *
15000 * <b>Note well</b>: In \ARGF, method #each returns data from the _sources_,
15001 * _not_ from +ARGV+;
15002 * therefore, for example, <tt>ARGF#entries</tt> returns an array of lines from the sources,
15003 * not an array of the strings from +ARGV+:
15004 *
15005 * - \File +t.rb+:
15006 *
15007 * p ['ARGV', ARGV]
15008 * p ['ARGF.entries', ARGF.entries]
15009 *
15010 * - Command and output:
15011 *
15012 * $ ruby t.rb foo.txt bar.txt
15013 * ["ARGV", ["foo.txt", "bar.txt"]]
15014 * ["ARGF.entries", ["Foo 0\n", "Foo 1\n", "Bar 0\n", "Bar 1\n", "Bar 2\n", "Bar 3\n"]]
15015 *
15016 * == Writing
15017 *
15018 * If <i>inplace mode</i> is in effect,
15019 * \ARGF may write to target streams,
15020 * which at any particular time are determined by the content of ARGV.
15021 *
15022 * Methods about inplace mode:
15023 *
15024 * - #inplace_mode
15025 * - #inplace_mode=
15026 * - #to_write_io
15027 *
15028 * Methods for writing:
15029 *
15030 * - #print
15031 * - #printf
15032 * - #putc
15033 * - #puts
15034 * - #write
15035 *
15036 */
15037
15038/*
15039 * An instance of class \IO (commonly called a _stream_)
15040 * represents an input/output stream in the underlying operating system.
15041 * Class \IO is the basis for input and output in Ruby.
15042 *
15043 * Class File is the only class in the Ruby core that is a subclass of \IO.
15044 * Some classes in the Ruby standard library are also subclasses of \IO;
15045 * these include TCPSocket and UDPSocket.
15046 *
15047 * The global constant ARGF (also accessible as <tt>$<</tt>)
15048 * provides an IO-like stream that allows access to all file paths
15049 * found in ARGV (or found in STDIN if ARGV is empty).
15050 * ARGF is not itself a subclass of \IO.
15051 *
15052 * Class StringIO provides an IO-like stream that handles a String.
15053 * StringIO is not itself a subclass of \IO.
15054 *
15055 * Important objects based on \IO include:
15056 *
15057 * - $stdin.
15058 * - $stdout.
15059 * - $stderr.
15060 * - Instances of class File.
15061 *
15062 * An instance of \IO may be created using:
15063 *
15064 * - IO.new: returns a new \IO object for the given integer file descriptor.
15065 * - IO.open: passes a new \IO object to the given block.
15066 * - IO.popen: returns a new \IO object that is connected to the $stdin and $stdout
15067 * of a newly-launched subprocess.
15068 * - Kernel#open: Returns a new \IO object connected to a given source:
15069 * stream, file, or subprocess.
15070 *
15071 * Like a File stream, an \IO stream has:
15072 *
15073 * - A read/write mode, which may be read-only, write-only, or read/write;
15074 * see {Read/Write Mode}[rdoc-ref:File@Read-2FWrite+Mode].
15075 * - A data mode, which may be text-only or binary;
15076 * see {Data Mode}[rdoc-ref:File@Data+Mode].
15077 * - Internal and external encodings;
15078 * see {Encodings}[rdoc-ref:File@Encodings].
15079 *
15080 * And like other \IO streams, it has:
15081 *
15082 * - A position, which determines where in the stream the next
15083 * read or write is to occur;
15084 * see {Position}[rdoc-ref:IO@Position].
15085 * - A line number, which is a special, line-oriented, "position"
15086 * (different from the position mentioned above);
15087 * see {Line Number}[rdoc-ref:IO@Line+Number].
15088 *
15089 * == Extension <tt>io/console</tt>
15090 *
15091 * Extension <tt>io/console</tt> provides numerous methods
15092 * for interacting with the console;
15093 * requiring it adds numerous methods to class \IO.
15094 *
15095 * == Example Files
15096 *
15097 * Many examples here use these variables:
15098 *
15099 * :include: doc/examples/files.rdoc
15100 *
15101 * == Open Options
15102 *
15103 * A number of \IO methods accept optional keyword arguments
15104 * that determine how a new stream is to be opened:
15105 *
15106 * - +:mode+: Stream mode.
15107 * - +:flags+: Integer file open flags;
15108 * If +mode+ is also given, the two are bitwise-ORed.
15109 * - +:external_encoding+: External encoding for the stream.
15110 * - +:internal_encoding+: Internal encoding for the stream.
15111 * <tt>'-'</tt> is a synonym for the default internal encoding.
15112 * If the value is +nil+ no conversion occurs.
15113 * - +:encoding+: Specifies external and internal encodings as <tt>'extern:intern'</tt>.
15114 * - +:textmode+: If a truthy value, specifies the mode as text-only, binary otherwise.
15115 * - +:binmode+: If a truthy value, specifies the mode as binary, text-only otherwise.
15116 * - +:autoclose+: If a truthy value, specifies that the +fd+ will close
15117 * when the stream closes; otherwise it remains open.
15118 * - +:path:+ If a string value is provided, it is used in #inspect and is available as
15119 * #path method.
15120 *
15121 * Also available are the options offered in String#encode,
15122 * which may control conversion between external and internal encoding.
15123 *
15124 * == Basic \IO
15125 *
15126 * You can perform basic stream \IO with these methods,
15127 * which typically operate on multi-byte strings:
15128 *
15129 * - IO#read: Reads and returns some or all of the remaining bytes from the stream.
15130 * - IO#write: Writes zero or more strings to the stream;
15131 * each given object that is not already a string is converted via +to_s+.
15132 *
15133 * === Position
15134 *
15135 * An \IO stream has a nonnegative integer _position_,
15136 * which is the byte offset at which the next read or write is to occur.
15137 * A new stream has position zero (and line number zero);
15138 * method +rewind+ resets the position (and line number) to zero.
15139 *
15140 * These methods discard {buffers}[rdoc-ref:IO@Buffering] and the
15141 * Encoding::Converter instances used for that \IO.
15142 *
15143 * The relevant methods:
15144 *
15145 * - IO#tell (aliased as +#pos+): Returns the current position (in bytes) in the stream.
15146 * - IO#pos=: Sets the position of the stream to a given integer +new_position+ (in bytes).
15147 * - IO#seek: Sets the position of the stream to a given integer +offset+ (in bytes),
15148 * relative to a given position +whence+
15149 * (indicating the beginning, end, or current position).
15150 * - IO#rewind: Positions the stream at the beginning (also resetting the line number).
15151 *
15152 * === Open and Closed Streams
15153 *
15154 * A new \IO stream may be open for reading, open for writing, or both.
15155 *
15156 * A stream is automatically closed when claimed by the garbage collector.
15157 *
15158 * Attempted reading or writing on a closed stream raises an exception.
15159 *
15160 * The relevant methods:
15161 *
15162 * - IO#close: Closes the stream for both reading and writing.
15163 * - IO#close_read: Closes the stream for reading.
15164 * - IO#close_write: Closes the stream for writing.
15165 * - IO#closed?: Returns whether the stream is closed.
15166 *
15167 * === End-of-Stream
15168 *
15169 * You can query whether a stream is positioned at its end:
15170 *
15171 * - IO#eof? (also aliased as +#eof+): Returns whether the stream is at end-of-stream.
15172 *
15173 * You can reposition to end-of-stream by using method IO#seek:
15174 *
15175 * f = File.new('t.txt')
15176 * f.eof? # => false
15177 * f.seek(0, :END)
15178 * f.eof? # => true
15179 * f.close
15180 *
15181 * Or by reading all stream content (which is slower than using IO#seek):
15182 *
15183 * f.rewind
15184 * f.eof? # => false
15185 * f.read # => "First line\nSecond line\n\nFourth line\nFifth line\n"
15186 * f.eof? # => true
15187 *
15188 * == Line \IO
15189 *
15190 * Class \IO supports line-oriented
15191 * {input}[rdoc-ref:IO@Line+Input] and {output}[rdoc-ref:IO@Line+Output]
15192 *
15193 * === Line Input
15194 *
15195 * Class \IO supports line-oriented input for
15196 * {files}[rdoc-ref:IO@File+Line+Input] and {IO streams}[rdoc-ref:IO@Stream+Line+Input]
15197 *
15198 * ==== \File Line Input
15199 *
15200 * You can read lines from a file using these methods:
15201 *
15202 * - IO.foreach: Reads each line and passes it to the given block.
15203 * - IO.readlines: Reads and returns all lines in an array.
15204 *
15205 * For each of these methods:
15206 *
15207 * - You can specify {open options}[rdoc-ref:IO@Open+Options].
15208 * - Line parsing depends on the effective <i>line separator</i>;
15209 * see {Line Separator}[rdoc-ref:IO@Line+Separator].
15210 * - The length of each returned line depends on the effective <i>line limit</i>;
15211 * see {Line Limit}[rdoc-ref:IO@Line+Limit].
15212 *
15213 * ==== Stream Line Input
15214 *
15215 * You can read lines from an \IO stream using these methods:
15216 *
15217 * - IO#each_line: Reads each remaining line, passing it to the given block.
15218 * - IO#gets: Returns the next line.
15219 * - IO#readline: Like #gets, but raises an exception at end-of-stream.
15220 * - IO#readlines: Returns all remaining lines in an array.
15221 *
15222 * For each of these methods:
15223 *
15224 * - Reading may begin mid-line,
15225 * depending on the stream's _position_;
15226 * see {Position}[rdoc-ref:IO@Position].
15227 * - Line parsing depends on the effective <i>line separator</i>;
15228 * see {Line Separator}[rdoc-ref:IO@Line+Separator].
15229 * - The length of each returned line depends on the effective <i>line limit</i>;
15230 * see {Line Limit}[rdoc-ref:IO@Line+Limit].
15231 *
15232 * ===== Line Separator
15233 *
15234 * Each of the {line input methods}[rdoc-ref:IO@Line+Input] uses a <i>line separator</i>:
15235 * the string that determines what is considered a line;
15236 * it is sometimes called the <i>input record separator</i>.
15237 *
15238 * The default line separator is taken from global variable <tt>$/</tt>,
15239 * whose initial value is <tt>"\n"</tt>.
15240 *
15241 * Generally, the line to be read next is all data
15242 * from the current {position}[rdoc-ref:IO@Position]
15243 * to the next line separator
15244 * (but see {Special Line Separator Values}[rdoc-ref:IO@Special+Line+Separator+Values]):
15245 *
15246 * f = File.new('t.txt')
15247 * # Method gets with no sep argument returns the next line, according to $/.
15248 * f.gets # => "First line\n"
15249 * f.gets # => "Second line\n"
15250 * f.gets # => "\n"
15251 * f.gets # => "Fourth line\n"
15252 * f.gets # => "Fifth line\n"
15253 * f.close
15254 *
15255 * You can use a different line separator by passing argument +sep+:
15256 *
15257 * f = File.new('t.txt')
15258 * f.gets('l') # => "First l"
15259 * f.gets('li') # => "ine\nSecond li"
15260 * f.gets('lin') # => "ne\n\nFourth lin"
15261 * f.gets # => "e\n"
15262 * f.close
15263 *
15264 * Or by setting global variable <tt>$/</tt>:
15265 *
15266 * f = File.new('t.txt')
15267 * $/ = 'l'
15268 * f.gets # => "First l"
15269 * f.gets # => "ine\nSecond l"
15270 * f.gets # => "ine\n\nFourth l"
15271 * f.close
15272 *
15273 * ===== Special Line Separator Values
15274 *
15275 * Each of the {line input methods}[rdoc-ref:IO@Line+Input]
15276 * accepts two special values for parameter +sep+:
15277 *
15278 * - +nil+: The entire stream is to be read ("slurped") into a single string:
15279 *
15280 * f = File.new('t.txt')
15281 * f.gets(nil) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
15282 * f.close
15283 *
15284 * - <tt>''</tt> (the empty string): The next "paragraph" is to be read
15285 * (paragraphs being separated by two consecutive line separators):
15286 *
15287 * f = File.new('t.txt')
15288 * f.gets('') # => "First line\nSecond line\n\n"
15289 * f.gets('') # => "Fourth line\nFifth line\n"
15290 * f.close
15291 *
15292 * ===== Line Limit
15293 *
15294 * Each of the {line input methods}[rdoc-ref:IO@Line+Input]
15295 * uses an integer <i>line limit</i>,
15296 * which restricts the number of bytes that may be returned.
15297 * (A multi-byte character will not be split, and so a returned line may be slightly longer
15298 * than the limit).
15299 *
15300 * The default limit value is <tt>-1</tt>;
15301 * any negative limit value means that there is no limit.
15302 *
15303 * If there is no limit, the line is determined only by +sep+.
15304 *
15305 * # Text with 1-byte characters.
15306 * File.open('t.txt') {|f| f.gets(1) } # => "F"
15307 * File.open('t.txt') {|f| f.gets(2) } # => "Fi"
15308 * File.open('t.txt') {|f| f.gets(3) } # => "Fir"
15309 * File.open('t.txt') {|f| f.gets(4) } # => "Firs"
15310 * # No more than one line.
15311 * File.open('t.txt') {|f| f.gets(10) } # => "First line"
15312 * File.open('t.txt') {|f| f.gets(11) } # => "First line\n"
15313 * File.open('t.txt') {|f| f.gets(12) } # => "First line\n"
15314 *
15315 * # Text with 3-byte characters, which will not be split.
15316 * File.read('t.ja') # => "こんにちは"
15317 * File.open('t.ja') {|f| f.gets(1).size } # => 1
15318 * File.open('t.ja') {|f| f.gets(2).size } # => 1
15319 * File.open('t.ja') {|f| f.gets(3).size } # => 1
15320 * File.open('t.ja') {|f| f.gets(4).size } # => 2
15321 * File.open('t.ja') {|f| f.gets(5).size } # => 2
15322 *
15323 * ===== Line Separator and Line Limit
15324 *
15325 * With arguments +sep+ and +limit+ given, combines the two behaviors:
15326 *
15327 * - Returns the next line as determined by line separator +sep+.
15328 * - But returns no more bytes than are allowed by the limit +limit+.
15329 *
15330 * Example:
15331 *
15332 * File.open('t.txt') {|f| f.gets('li', 20) } # => "First li"
15333 * File.open('t.txt') {|f| f.gets('li', 2) } # => "Fi"
15334 *
15335 * ===== Line Number
15336 *
15337 * A readable \IO stream has a non-negative integer <i>line number</i>:
15338 *
15339 * - IO#lineno: Returns the line number.
15340 * - IO#lineno=: Resets and returns the line number.
15341 *
15342 * Unless modified by a call to method IO#lineno=,
15343 * the line number is the number of lines read
15344 * by certain line-oriented methods,
15345 * according to the effective {line separator}[rdoc-ref:IO@Line+Separator]:
15346 *
15347 * - IO.foreach: Increments the line number on each call to the block.
15348 * - IO#each_line: Increments the line number on each call to the block.
15349 * - IO#gets: Increments the line number.
15350 * - IO#readline: Increments the line number.
15351 * - IO#readlines: Increments the line number for each line read.
15352 *
15353 * A new stream is initially has line number zero (and position zero);
15354 * method +rewind+ resets the line number (and position) to zero:
15355 *
15356 * f = File.new('t.txt')
15357 * f.lineno # => 0
15358 * f.gets # => "First line\n"
15359 * f.lineno # => 1
15360 * f.rewind
15361 * f.lineno # => 0
15362 * f.close
15363 *
15364 * Reading lines from a stream usually changes its line number:
15365 *
15366 * f = File.new('t.txt', 'r')
15367 * f.lineno # => 0
15368 * f.readline # => "This is line one.\n"
15369 * f.lineno # => 1
15370 * f.readline # => "This is the second line.\n"
15371 * f.lineno # => 2
15372 * f.readline # => "Here's the third line.\n"
15373 * f.lineno # => 3
15374 * f.eof? # => true
15375 * f.close
15376 *
15377 * Iterating over lines in a stream usually changes its line number:
15378 *
15379 * File.open('t.txt') do |f|
15380 * f.each_line do |line|
15381 * p "position=#{f.pos} eof?=#{f.eof?} lineno=#{f.lineno}"
15382 * end
15383 * end
15384 *
15385 * Output:
15386 *
15387 * "position=11 eof?=false lineno=1"
15388 * "position=23 eof?=false lineno=2"
15389 * "position=24 eof?=false lineno=3"
15390 * "position=36 eof?=false lineno=4"
15391 * "position=47 eof?=true lineno=5"
15392 *
15393 * Unlike the stream's {position}[rdoc-ref:IO@Position],
15394 * the line number does not affect where the next read or write will occur:
15395 *
15396 * f = File.new('t.txt')
15397 * f.lineno = 1000
15398 * f.lineno # => 1000
15399 * f.gets # => "First line\n"
15400 * f.lineno # => 1001
15401 * f.close
15402 *
15403 * Associated with the line number is the global variable <tt>$.</tt>:
15404 *
15405 * - When a stream is opened, <tt>$.</tt> is not set;
15406 * its value is left over from previous activity in the process:
15407 *
15408 * $. = 41
15409 * f = File.new('t.txt')
15410 * $. = 41
15411 * # => 41
15412 * f.close
15413 *
15414 * - When a stream is read, <tt>$.</tt> is set to the line number for that stream:
15415 *
15416 * f0 = File.new('t.txt')
15417 * f1 = File.new('t.dat')
15418 * f0.readlines # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
15419 * $. # => 5
15420 * f1.readlines # => ["\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"]
15421 * $. # => 1
15422 * f0.close
15423 * f1.close
15424 *
15425 * - Methods IO#rewind and IO#seek do not affect <tt>$.</tt>:
15426 *
15427 * f = File.new('t.txt')
15428 * f.readlines # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
15429 * $. # => 5
15430 * f.rewind
15431 * f.seek(0, :SET)
15432 * $. # => 5
15433 * f.close
15434 *
15435 * === Line Output
15436 *
15437 * You can write to an \IO stream line-by-line using this method:
15438 *
15439 * - IO#puts: Writes objects to the stream.
15440 *
15441 * == Character \IO
15442 *
15443 * You can process an \IO stream character-by-character using these methods:
15444 *
15445 * - IO#getc: Reads and returns the next character from the stream.
15446 * - IO#readchar: Like #getc, but raises an exception at end-of-stream.
15447 * - IO#ungetc: Pushes back ("unshifts") a character or integer onto the stream.
15448 * - IO#putc: Writes a character to the stream.
15449 * - IO#each_char: Reads each remaining character in the stream,
15450 * passing the character to the given block.
15451 *
15452 * == Byte \IO
15453 *
15454 * You can process an \IO stream byte-by-byte using these methods:
15455 *
15456 * - IO#getbyte: Returns the next 8-bit byte as an integer in range 0..255.
15457 * - IO#readbyte: Like #getbyte, but raises an exception if at end-of-stream.
15458 * - IO#ungetbyte: Pushes back ("unshifts") a byte back onto the stream.
15459 * - IO#each_byte: Reads each remaining byte in the stream,
15460 * passing the byte to the given block.
15461 *
15462 * == Codepoint \IO
15463 *
15464 * You can process an \IO stream codepoint-by-codepoint:
15465 *
15466 * - IO#each_codepoint: Reads each remaining codepoint, passing it to the given block.
15467 *
15468 * == What's Here
15469 *
15470 * First, what's elsewhere. Class \IO:
15471 *
15472 * - Inherits from {class Object}[rdoc-ref:Object@What-27s+Here].
15473 * - Includes {module Enumerable}[rdoc-ref:Enumerable@What-27s+Here],
15474 * which provides dozens of additional methods.
15475 *
15476 * Here, class \IO provides methods that are useful for:
15477 *
15478 * - {Creating}[rdoc-ref:IO@Creating]
15479 * - {Reading}[rdoc-ref:IO@Reading]
15480 * - {Writing}[rdoc-ref:IO@Writing]
15481 * - {Positioning}[rdoc-ref:IO@Positioning]
15482 * - {Iterating}[rdoc-ref:IO@Iterating]
15483 * - {Settings}[rdoc-ref:IO@Settings]
15484 * - {Querying}[rdoc-ref:IO@Querying]
15485 * - {Buffering}[rdoc-ref:IO@Buffering]
15486 * - {Low-Level Access}[rdoc-ref:IO@Low-Level+Access]
15487 * - {Other}[rdoc-ref:IO@Other]
15488 *
15489 * === Creating
15490 *
15491 * - ::new (aliased as ::for_fd): Creates and returns a new \IO object for the given
15492 * integer file descriptor.
15493 * - ::open: Creates a new \IO object.
15494 * - ::pipe: Creates a connected pair of reader and writer \IO objects.
15495 * - ::popen: Creates an \IO object to interact with a subprocess.
15496 * - ::select: Selects which given \IO instances are ready for reading,
15497 * writing, or have pending exceptions.
15498 *
15499 * === Reading
15500 *
15501 * - ::binread: Returns a binary string with all or a subset of bytes
15502 * from the given file.
15503 * - ::read: Returns a string with all or a subset of bytes from the given file.
15504 * - ::readlines: Returns an array of strings, which are the lines from the given file.
15505 * - #getbyte: Returns the next 8-bit byte read from +self+ as an integer.
15506 * - #getc: Returns the next character read from +self+ as a string.
15507 * - #gets: Returns the line read from +self+.
15508 * - #pread: Returns all or the next _n_ bytes read from +self+,
15509 * not updating the receiver's offset.
15510 * - #read: Returns all remaining or the next _n_ bytes read from +self+
15511 * for a given _n_.
15512 * - #read_nonblock: the next _n_ bytes read from +self+ for a given _n_,
15513 * in non-block mode.
15514 * - #readbyte: Returns the next byte read from +self+;
15515 * same as #getbyte, but raises an exception on end-of-stream.
15516 * - #readchar: Returns the next character read from +self+;
15517 * same as #getc, but raises an exception on end-of-stream.
15518 * - #readline: Returns the next line read from +self+;
15519 * same as #getline, but raises an exception of end-of-stream.
15520 * - #readlines: Returns an array of all lines read read from +self+.
15521 * - #readpartial: Returns up to the given number of bytes from +self+.
15522 *
15523 * === Writing
15524 *
15525 * - ::binwrite: Writes the given string to the file at the given filepath,
15526 * in binary mode.
15527 * - ::write: Writes the given string to +self+.
15528 * - #<<: Appends the given string to +self+.
15529 * - #print: Prints last read line or given objects to +self+.
15530 * - #printf: Writes to +self+ based on the given format string and objects.
15531 * - #putc: Writes a character to +self+.
15532 * - #puts: Writes lines to +self+, making sure line ends with a newline.
15533 * - #pwrite: Writes the given string at the given offset,
15534 * not updating the receiver's offset.
15535 * - #write: Writes one or more given strings to +self+.
15536 * - #write_nonblock: Writes one or more given strings to +self+ in non-blocking mode.
15537 *
15538 * === Positioning
15539 *
15540 * - #lineno: Returns the current line number in +self+.
15541 * - #lineno=: Sets the line number is +self+.
15542 * - #pos (aliased as #tell): Returns the current byte offset in +self+.
15543 * - #pos=: Sets the byte offset in +self+.
15544 * - #reopen: Reassociates +self+ with a new or existing \IO stream.
15545 * - #rewind: Positions +self+ to the beginning of input.
15546 * - #seek: Sets the offset for +self+ relative to given position.
15547 *
15548 * === Iterating
15549 *
15550 * - ::foreach: Yields each line of given file to the block.
15551 * - #each (aliased as #each_line): Calls the given block
15552 * with each successive line in +self+.
15553 * - #each_byte: Calls the given block with each successive byte in +self+
15554 * as an integer.
15555 * - #each_char: Calls the given block with each successive character in +self+
15556 * as a string.
15557 * - #each_codepoint: Calls the given block with each successive codepoint in +self+
15558 * as an integer.
15559 *
15560 * === Settings
15561 *
15562 * - #autoclose=: Sets whether +self+ auto-closes.
15563 * - #binmode: Sets +self+ to binary mode.
15564 * - #close: Closes +self+.
15565 * - #close_on_exec=: Sets the close-on-exec flag.
15566 * - #close_read: Closes +self+ for reading.
15567 * - #close_write: Closes +self+ for writing.
15568 * - #set_encoding: Sets the encoding for +self+.
15569 * - #set_encoding_by_bom: Sets the encoding for +self+, based on its
15570 * Unicode byte-order-mark.
15571 * - #sync=: Sets the sync-mode to the given value.
15572 *
15573 * === Querying
15574 *
15575 * - #autoclose?: Returns whether +self+ auto-closes.
15576 * - #binmode?: Returns whether +self+ is in binary mode.
15577 * - #close_on_exec?: Returns the close-on-exec flag for +self+.
15578 * - #closed?: Returns whether +self+ is closed.
15579 * - #eof? (aliased as #eof): Returns whether +self+ is at end-of-stream.
15580 * - #external_encoding: Returns the external encoding object for +self+.
15581 * - #fileno (aliased as #to_i): Returns the integer file descriptor for +self+
15582 * - #internal_encoding: Returns the internal encoding object for +self+.
15583 * - #pid: Returns the process ID of a child process associated with +self+,
15584 * if +self+ was created by ::popen.
15585 * - #stat: Returns the File::Stat object containing status information for +self+.
15586 * - #sync: Returns whether +self+ is in sync-mode.
15587 * - #tty? (aliased as #isatty): Returns whether +self+ is a terminal.
15588 *
15589 * === Buffering
15590 *
15591 * - #fdatasync: Immediately writes all buffered data in +self+ to disk.
15592 * - #flush: Flushes any buffered data within +self+ to the underlying
15593 * operating system.
15594 * - #fsync: Immediately writes all buffered data and attributes in +self+ to disk.
15595 * - #ungetbyte: Prepends buffer for +self+ with given integer byte or string.
15596 * - #ungetc: Prepends buffer for +self+ with given string.
15597 *
15598 * === Low-Level Access
15599 *
15600 * - ::sysopen: Opens the file given by its path,
15601 * returning the integer file descriptor.
15602 * - #advise: Announces the intention to access data from +self+ in a specific way.
15603 * - #fcntl: Passes a low-level command to the file specified
15604 * by the given file descriptor.
15605 * - #ioctl: Passes a low-level command to the device specified
15606 * by the given file descriptor.
15607 * - #sysread: Returns up to the next _n_ bytes read from self using a low-level read.
15608 * - #sysseek: Sets the offset for +self+.
15609 * - #syswrite: Writes the given string to +self+ using a low-level write.
15610 *
15611 * === Other
15612 *
15613 * - ::copy_stream: Copies data from a source to a destination,
15614 * each of which is a filepath or an \IO-like object.
15615 * - ::try_convert: Returns a new \IO object resulting from converting
15616 * the given object.
15617 * - #inspect: Returns the string representation of +self+.
15618 *
15619 */
15620
15621void
15622Init_IO(void)
15623{
15624 VALUE rb_cARGF;
15625#ifdef __CYGWIN__
15626#include <sys/cygwin.h>
15627 static struct __cygwin_perfile pf[] =
15628 {
15629 {"", O_RDONLY | O_BINARY},
15630 {"", O_WRONLY | O_BINARY},
15631 {"", O_RDWR | O_BINARY},
15632 {"", O_APPEND | O_BINARY},
15633 {NULL, 0}
15634 };
15635 cygwin_internal(CW_PERFILE, pf);
15636#endif
15637
15640
15641 id_write = rb_intern_const("write");
15642 id_read = rb_intern_const("read");
15643 id_getc = rb_intern_const("getc");
15644 id_flush = rb_intern_const("flush");
15645 id_readpartial = rb_intern_const("readpartial");
15646 id_set_encoding = rb_intern_const("set_encoding");
15647 id_fileno = rb_intern_const("fileno");
15648
15649 rb_define_global_function("syscall", rb_f_syscall, -1);
15650
15651 rb_define_global_function("open", rb_f_open, -1);
15652 rb_define_global_function("printf", rb_f_printf, -1);
15653 rb_define_global_function("print", rb_f_print, -1);
15654 rb_define_global_function("putc", rb_f_putc, 1);
15655 rb_define_global_function("puts", rb_f_puts, -1);
15656 rb_define_global_function("gets", rb_f_gets, -1);
15657 rb_define_global_function("readline", rb_f_readline, -1);
15658 rb_define_global_function("select", rb_f_select, -1);
15659
15660 rb_define_global_function("readlines", rb_f_readlines, -1);
15661
15662 rb_define_global_function("`", rb_f_backquote, 1);
15663
15664 rb_define_global_function("p", rb_f_p, -1);
15665 rb_define_method(rb_mKernel, "display", rb_obj_display, -1);
15666
15667 rb_cIO = rb_define_class("IO", rb_cObject);
15669
15670 /* Can be raised by IO operations when IO#timeout= is set. */
15672
15673 /* Readable event mask for IO#wait. */
15674 rb_define_const(rb_cIO, "READABLE", INT2NUM(RUBY_IO_READABLE));
15675 /* Writable event mask for IO#wait. */
15676 rb_define_const(rb_cIO, "WRITABLE", INT2NUM(RUBY_IO_WRITABLE));
15677 /* Priority event mask for IO#wait. */
15678 rb_define_const(rb_cIO, "PRIORITY", INT2NUM(RUBY_IO_PRIORITY));
15679
15680 /* exception to wait for reading. see IO.select. */
15682 /* exception to wait for writing. see IO.select. */
15684 /* exception to wait for reading by EAGAIN. see IO.select. */
15685 rb_eEAGAINWaitReadable = rb_define_class_under(rb_cIO, "EAGAINWaitReadable", rb_eEAGAIN);
15686 rb_include_module(rb_eEAGAINWaitReadable, rb_mWaitReadable);
15687 /* exception to wait for writing by EAGAIN. see IO.select. */
15688 rb_eEAGAINWaitWritable = rb_define_class_under(rb_cIO, "EAGAINWaitWritable", rb_eEAGAIN);
15689 rb_include_module(rb_eEAGAINWaitWritable, rb_mWaitWritable);
15690#if EAGAIN == EWOULDBLOCK
15691 rb_eEWOULDBLOCKWaitReadable = rb_eEAGAINWaitReadable;
15692 /* same as IO::EAGAINWaitReadable */
15693 rb_define_const(rb_cIO, "EWOULDBLOCKWaitReadable", rb_eEAGAINWaitReadable);
15694 rb_eEWOULDBLOCKWaitWritable = rb_eEAGAINWaitWritable;
15695 /* same as IO::EAGAINWaitWritable */
15696 rb_define_const(rb_cIO, "EWOULDBLOCKWaitWritable", rb_eEAGAINWaitWritable);
15697#else
15698 /* exception to wait for reading by EWOULDBLOCK. see IO.select. */
15699 rb_eEWOULDBLOCKWaitReadable = rb_define_class_under(rb_cIO, "EWOULDBLOCKWaitReadable", rb_eEWOULDBLOCK);
15700 rb_include_module(rb_eEWOULDBLOCKWaitReadable, rb_mWaitReadable);
15701 /* exception to wait for writing by EWOULDBLOCK. see IO.select. */
15702 rb_eEWOULDBLOCKWaitWritable = rb_define_class_under(rb_cIO, "EWOULDBLOCKWaitWritable", rb_eEWOULDBLOCK);
15703 rb_include_module(rb_eEWOULDBLOCKWaitWritable, rb_mWaitWritable);
15704#endif
15705 /* exception to wait for reading by EINPROGRESS. see IO.select. */
15706 rb_eEINPROGRESSWaitReadable = rb_define_class_under(rb_cIO, "EINPROGRESSWaitReadable", rb_eEINPROGRESS);
15707 rb_include_module(rb_eEINPROGRESSWaitReadable, rb_mWaitReadable);
15708 /* exception to wait for writing by EINPROGRESS. see IO.select. */
15709 rb_eEINPROGRESSWaitWritable = rb_define_class_under(rb_cIO, "EINPROGRESSWaitWritable", rb_eEINPROGRESS);
15710 rb_include_module(rb_eEINPROGRESSWaitWritable, rb_mWaitWritable);
15711
15712#if 0
15713 /* This is necessary only for forcing rdoc handle File::open */
15714 rb_define_singleton_method(rb_cFile, "open", rb_io_s_open, -1);
15715#endif
15716
15717 rb_define_alloc_func(rb_cIO, io_alloc);
15718 rb_define_singleton_method(rb_cIO, "new", rb_io_s_new, -1);
15719 rb_define_singleton_method(rb_cIO, "open", rb_io_s_open, -1);
15720 rb_define_singleton_method(rb_cIO, "sysopen", rb_io_s_sysopen, -1);
15721 rb_define_singleton_method(rb_cIO, "for_fd", rb_io_s_for_fd, -1);
15722 rb_define_singleton_method(rb_cIO, "popen", rb_io_s_popen, -1);
15723 rb_define_singleton_method(rb_cIO, "foreach", rb_io_s_foreach, -1);
15724 rb_define_singleton_method(rb_cIO, "readlines", rb_io_s_readlines, -1);
15725 rb_define_singleton_method(rb_cIO, "read", rb_io_s_read, -1);
15726 rb_define_singleton_method(rb_cIO, "binread", rb_io_s_binread, -1);
15727 rb_define_singleton_method(rb_cIO, "write", rb_io_s_write, -1);
15728 rb_define_singleton_method(rb_cIO, "binwrite", rb_io_s_binwrite, -1);
15729 rb_define_singleton_method(rb_cIO, "select", rb_f_select, -1);
15730 rb_define_singleton_method(rb_cIO, "pipe", rb_io_s_pipe, -1);
15731 rb_define_singleton_method(rb_cIO, "try_convert", rb_io_s_try_convert, 1);
15732 rb_define_singleton_method(rb_cIO, "copy_stream", rb_io_s_copy_stream, -1);
15733
15734 rb_define_method(rb_cIO, "initialize", rb_io_initialize, -1);
15735
15737 rb_define_hooked_variable("$,", &rb_output_fs, 0, rb_deprecated_str_setter);
15738
15739 rb_default_rs = rb_fstring_lit("\n"); /* avoid modifying RS_default */
15740 rb_vm_register_global_object(rb_default_rs);
15741 rb_rs = rb_default_rs;
15743 rb_define_hooked_variable("$/", &rb_rs, 0, deprecated_rs_setter);
15744 rb_gvar_ractor_local("$/"); // not local but ractor safe
15745 rb_define_hooked_variable("$-0", &rb_rs, 0, deprecated_rs_setter);
15746 rb_gvar_ractor_local("$-0"); // not local but ractor safe
15747 rb_define_hooked_variable("$\\", &rb_output_rs, 0, rb_deprecated_str_setter);
15748
15749 rb_define_virtual_variable("$_", get_LAST_READ_LINE, set_LAST_READ_LINE);
15750 rb_gvar_ractor_local("$_");
15751
15752 rb_define_method(rb_cIO, "initialize_copy", rb_io_init_copy, 1);
15753 rb_define_method(rb_cIO, "reopen", rb_io_reopen, -1);
15754
15755 rb_define_method(rb_cIO, "print", rb_io_print, -1);
15756 rb_define_method(rb_cIO, "putc", rb_io_putc, 1);
15757 rb_define_method(rb_cIO, "puts", rb_io_puts, -1);
15758 rb_define_method(rb_cIO, "printf", rb_io_printf, -1);
15759
15760 rb_define_method(rb_cIO, "each", rb_io_each_line, -1);
15761 rb_define_method(rb_cIO, "each_line", rb_io_each_line, -1);
15762 rb_define_method(rb_cIO, "each_byte", rb_io_each_byte, 0);
15763 rb_define_method(rb_cIO, "each_char", rb_io_each_char, 0);
15764 rb_define_method(rb_cIO, "each_codepoint", rb_io_each_codepoint, 0);
15765
15766 rb_define_method(rb_cIO, "syswrite", rb_io_syswrite, 1);
15767 rb_define_method(rb_cIO, "sysread", rb_io_sysread, -1);
15768
15769 rb_define_method(rb_cIO, "pread", rb_io_pread, -1);
15770 rb_define_method(rb_cIO, "pwrite", rb_io_pwrite, 2);
15771
15772 rb_define_method(rb_cIO, "fileno", rb_io_fileno, 0);
15773 rb_define_alias(rb_cIO, "to_i", "fileno");
15774 rb_define_method(rb_cIO, "to_io", rb_io_to_io, 0);
15775
15776 rb_define_method(rb_cIO, "timeout", rb_io_timeout, 0);
15777 rb_define_method(rb_cIO, "timeout=", rb_io_set_timeout, 1);
15778
15779 rb_define_method(rb_cIO, "fsync", rb_io_fsync, 0);
15780 rb_define_method(rb_cIO, "fdatasync", rb_io_fdatasync, 0);
15781 rb_define_method(rb_cIO, "sync", rb_io_sync, 0);
15782 rb_define_method(rb_cIO, "sync=", rb_io_set_sync, 1);
15783
15784 rb_define_method(rb_cIO, "lineno", rb_io_lineno, 0);
15785 rb_define_method(rb_cIO, "lineno=", rb_io_set_lineno, 1);
15786
15787 rb_define_method(rb_cIO, "readlines", rb_io_readlines, -1);
15788
15789 rb_define_method(rb_cIO, "readpartial", io_readpartial, -1);
15790 rb_define_method(rb_cIO, "read", io_read, -1);
15791 rb_define_method(rb_cIO, "write", io_write_m, -1);
15792 rb_define_method(rb_cIO, "gets", rb_io_gets_m, -1);
15793 rb_define_method(rb_cIO, "getc", rb_io_getc, 0);
15794 rb_define_method(rb_cIO, "getbyte", rb_io_getbyte, 0);
15795 rb_define_method(rb_cIO, "readchar", rb_io_readchar, 0);
15796 rb_define_method(rb_cIO, "readbyte", rb_io_readbyte, 0);
15797 rb_define_method(rb_cIO, "ungetbyte",rb_io_ungetbyte, 1);
15798 rb_define_method(rb_cIO, "ungetc",rb_io_ungetc, 1);
15800 rb_define_method(rb_cIO, "flush", rb_io_flush, 0);
15801 rb_define_method(rb_cIO, "tell", rb_io_tell, 0);
15802 rb_define_method(rb_cIO, "seek", rb_io_seek_m, -1);
15803 /* Set I/O position from the beginning */
15804 rb_define_const(rb_cIO, "SEEK_SET", INT2FIX(SEEK_SET));
15805 /* Set I/O position from the current position */
15806 rb_define_const(rb_cIO, "SEEK_CUR", INT2FIX(SEEK_CUR));
15807 /* Set I/O position from the end */
15808 rb_define_const(rb_cIO, "SEEK_END", INT2FIX(SEEK_END));
15809#ifdef SEEK_DATA
15810 /* Set I/O position to the next location containing data */
15811 rb_define_const(rb_cIO, "SEEK_DATA", INT2FIX(SEEK_DATA));
15812#endif
15813#ifdef SEEK_HOLE
15814 /* Set I/O position to the next hole */
15815 rb_define_const(rb_cIO, "SEEK_HOLE", INT2FIX(SEEK_HOLE));
15816#endif
15817 rb_define_method(rb_cIO, "rewind", rb_io_rewind, 0);
15818 rb_define_method(rb_cIO, "pos", rb_io_tell, 0);
15819 rb_define_method(rb_cIO, "pos=", rb_io_set_pos, 1);
15820 rb_define_method(rb_cIO, "eof", rb_io_eof, 0);
15821 rb_define_method(rb_cIO, "eof?", rb_io_eof, 0);
15822
15823 rb_define_method(rb_cIO, "close_on_exec?", rb_io_close_on_exec_p, 0);
15824 rb_define_method(rb_cIO, "close_on_exec=", rb_io_set_close_on_exec, 1);
15825
15826 rb_define_method(rb_cIO, "close", rb_io_close_m, 0);
15827 rb_define_method(rb_cIO, "closed?", rb_io_closed_p, 0);
15828 rb_define_method(rb_cIO, "close_read", rb_io_close_read, 0);
15829 rb_define_method(rb_cIO, "close_write", rb_io_close_write, 0);
15830
15831 rb_define_method(rb_cIO, "isatty", rb_io_isatty, 0);
15832 rb_define_method(rb_cIO, "tty?", rb_io_isatty, 0);
15833 rb_define_method(rb_cIO, "binmode", rb_io_binmode_m, 0);
15834 rb_define_method(rb_cIO, "binmode?", rb_io_binmode_p, 0);
15835 rb_define_method(rb_cIO, "sysseek", rb_io_sysseek, -1);
15836 rb_define_method(rb_cIO, "advise", rb_io_advise, -1);
15837
15838 rb_define_method(rb_cIO, "ioctl", rb_io_ioctl, -1);
15839 rb_define_method(rb_cIO, "fcntl", rb_io_fcntl, -1);
15840 rb_define_method(rb_cIO, "pid", rb_io_pid, 0);
15841
15842 rb_define_method(rb_cIO, "path", rb_io_path, 0);
15843 rb_define_method(rb_cIO, "to_path", rb_io_path, 0);
15844
15845 rb_define_method(rb_cIO, "inspect", rb_io_inspect, 0);
15846
15847 rb_define_method(rb_cIO, "external_encoding", rb_io_external_encoding, 0);
15848 rb_define_method(rb_cIO, "internal_encoding", rb_io_internal_encoding, 0);
15849 rb_define_method(rb_cIO, "set_encoding", rb_io_set_encoding, -1);
15850 rb_define_method(rb_cIO, "set_encoding_by_bom", rb_io_set_encoding_by_bom, 0);
15851
15852 rb_define_method(rb_cIO, "autoclose?", rb_io_autoclose_p, 0);
15853 rb_define_method(rb_cIO, "autoclose=", rb_io_set_autoclose, 1);
15854
15855 rb_define_method(rb_cIO, "wait", io_wait, -1);
15856
15857 rb_define_method(rb_cIO, "wait_readable", io_wait_readable, -1);
15858 rb_define_method(rb_cIO, "wait_writable", io_wait_writable, -1);
15859 rb_define_method(rb_cIO, "wait_priority", io_wait_priority, -1);
15860
15861 rb_define_virtual_variable("$stdin", stdin_getter, stdin_setter);
15862 rb_define_virtual_variable("$stdout", stdout_getter, stdout_setter);
15863 rb_define_virtual_variable("$>", stdout_getter, stdout_setter);
15864 rb_define_virtual_variable("$stderr", stderr_getter, stderr_setter);
15865
15866 rb_gvar_ractor_local("$stdin");
15867 rb_gvar_ractor_local("$stdout");
15868 rb_gvar_ractor_local("$>");
15869 rb_gvar_ractor_local("$stderr");
15870
15872 rb_stdin = rb_io_prep_stdin();
15874 rb_stdout = rb_io_prep_stdout();
15876 rb_stderr = rb_io_prep_stderr();
15877
15878 orig_stdout = rb_stdout;
15879 orig_stderr = rb_stderr;
15880
15881 /* Holds the original stdin */
15883 /* Holds the original stdout */
15885 /* Holds the original stderr */
15887
15888#if 0
15889 /* Hack to get rdoc to regard ARGF as a class: */
15890 rb_cARGF = rb_define_class("ARGF", rb_cObject);
15891#endif
15892
15893 rb_cARGF = rb_class_new(rb_cObject);
15894 rb_set_class_path(rb_cARGF, rb_cObject, "ARGF.class");
15895 rb_define_alloc_func(rb_cARGF, argf_alloc);
15896
15898
15899 rb_define_method(rb_cARGF, "initialize", argf_initialize, -2);
15900 rb_define_method(rb_cARGF, "initialize_copy", argf_initialize_copy, 1);
15901 rb_define_method(rb_cARGF, "to_s", argf_to_s, 0);
15902 rb_define_alias(rb_cARGF, "inspect", "to_s");
15903 rb_define_method(rb_cARGF, "argv", argf_argv, 0);
15904
15905 rb_define_method(rb_cARGF, "fileno", argf_fileno, 0);
15906 rb_define_method(rb_cARGF, "to_i", argf_fileno, 0);
15907 rb_define_method(rb_cARGF, "to_io", argf_to_io, 0);
15908 rb_define_method(rb_cARGF, "to_write_io", argf_write_io, 0);
15909 rb_define_method(rb_cARGF, "each", argf_each_line, -1);
15910 rb_define_method(rb_cARGF, "each_line", argf_each_line, -1);
15911 rb_define_method(rb_cARGF, "each_byte", argf_each_byte, 0);
15912 rb_define_method(rb_cARGF, "each_char", argf_each_char, 0);
15913 rb_define_method(rb_cARGF, "each_codepoint", argf_each_codepoint, 0);
15914
15915 rb_define_method(rb_cARGF, "read", argf_read, -1);
15916 rb_define_method(rb_cARGF, "readpartial", argf_readpartial, -1);
15917 rb_define_method(rb_cARGF, "read_nonblock", argf_read_nonblock, -1);
15918 rb_define_method(rb_cARGF, "readlines", argf_readlines, -1);
15919 rb_define_method(rb_cARGF, "to_a", argf_readlines, -1);
15920 rb_define_method(rb_cARGF, "gets", argf_gets, -1);
15921 rb_define_method(rb_cARGF, "readline", argf_readline, -1);
15922 rb_define_method(rb_cARGF, "getc", argf_getc, 0);
15923 rb_define_method(rb_cARGF, "getbyte", argf_getbyte, 0);
15924 rb_define_method(rb_cARGF, "readchar", argf_readchar, 0);
15925 rb_define_method(rb_cARGF, "readbyte", argf_readbyte, 0);
15926 rb_define_method(rb_cARGF, "tell", argf_tell, 0);
15927 rb_define_method(rb_cARGF, "seek", argf_seek_m, -1);
15928 rb_define_method(rb_cARGF, "rewind", argf_rewind, 0);
15929 rb_define_method(rb_cARGF, "pos", argf_tell, 0);
15930 rb_define_method(rb_cARGF, "pos=", argf_set_pos, 1);
15931 rb_define_method(rb_cARGF, "eof", argf_eof, 0);
15932 rb_define_method(rb_cARGF, "eof?", argf_eof, 0);
15933 rb_define_method(rb_cARGF, "binmode", argf_binmode_m, 0);
15934 rb_define_method(rb_cARGF, "binmode?", argf_binmode_p, 0);
15935
15936 rb_define_method(rb_cARGF, "write", argf_write, -1);
15937 rb_define_method(rb_cARGF, "print", rb_io_print, -1);
15938 rb_define_method(rb_cARGF, "putc", rb_io_putc, 1);
15939 rb_define_method(rb_cARGF, "puts", rb_io_puts, -1);
15940 rb_define_method(rb_cARGF, "printf", rb_io_printf, -1);
15941
15942 rb_define_method(rb_cARGF, "filename", argf_filename, 0);
15943 rb_define_method(rb_cARGF, "path", argf_filename, 0);
15944 rb_define_method(rb_cARGF, "file", argf_file, 0);
15945 rb_define_method(rb_cARGF, "skip", argf_skip, 0);
15946 rb_define_method(rb_cARGF, "close", argf_close_m, 0);
15947 rb_define_method(rb_cARGF, "closed?", argf_closed, 0);
15948
15949 rb_define_method(rb_cARGF, "lineno", argf_lineno, 0);
15950 rb_define_method(rb_cARGF, "lineno=", argf_set_lineno, 1);
15951
15952 rb_define_method(rb_cARGF, "inplace_mode", argf_inplace_mode_get, 0);
15953 rb_define_method(rb_cARGF, "inplace_mode=", argf_inplace_mode_set, 1);
15954
15955 rb_define_method(rb_cARGF, "external_encoding", argf_external_encoding, 0);
15956 rb_define_method(rb_cARGF, "internal_encoding", argf_internal_encoding, 0);
15957 rb_define_method(rb_cARGF, "set_encoding", argf_set_encoding, -1);
15958
15959 argf = rb_class_new_instance(0, 0, rb_cARGF);
15960
15962 /*
15963 * ARGF is a stream designed for use in scripts that process files given
15964 * as command-line arguments or passed in via STDIN.
15965 *
15966 * See ARGF (the class) for more details.
15967 */
15969
15970 rb_define_hooked_variable("$.", &argf, argf_lineno_getter, argf_lineno_setter);
15971 rb_define_hooked_variable("$FILENAME", &argf, argf_filename_getter, rb_gvar_readonly_setter);
15972 ARGF.filename = rb_str_new2("-");
15973
15974 rb_define_hooked_variable("$-i", &argf, opt_i_get, opt_i_set);
15975 rb_gvar_ractor_local("$-i");
15976
15977 rb_define_hooked_variable("$*", &argf, argf_argv_getter, rb_gvar_readonly_setter);
15978
15979#if defined (_WIN32) || defined(__CYGWIN__)
15980 atexit(pipe_atexit);
15981#endif
15982
15983 Init_File();
15984
15985 rb_define_method(rb_cFile, "initialize", rb_file_initialize, -1);
15986
15987 sym_mode = ID2SYM(rb_intern_const("mode"));
15988 sym_perm = ID2SYM(rb_intern_const("perm"));
15989 sym_flags = ID2SYM(rb_intern_const("flags"));
15990 sym_extenc = ID2SYM(rb_intern_const("external_encoding"));
15991 sym_intenc = ID2SYM(rb_intern_const("internal_encoding"));
15992 sym_encoding = ID2SYM(rb_id_encoding());
15993 sym_open_args = ID2SYM(rb_intern_const("open_args"));
15994 sym_textmode = ID2SYM(rb_intern_const("textmode"));
15995 sym_binmode = ID2SYM(rb_intern_const("binmode"));
15996 sym_autoclose = ID2SYM(rb_intern_const("autoclose"));
15997 sym_normal = ID2SYM(rb_intern_const("normal"));
15998 sym_sequential = ID2SYM(rb_intern_const("sequential"));
15999 sym_random = ID2SYM(rb_intern_const("random"));
16000 sym_willneed = ID2SYM(rb_intern_const("willneed"));
16001 sym_dontneed = ID2SYM(rb_intern_const("dontneed"));
16002 sym_noreuse = ID2SYM(rb_intern_const("noreuse"));
16003 sym_SET = ID2SYM(rb_intern_const("SET"));
16004 sym_CUR = ID2SYM(rb_intern_const("CUR"));
16005 sym_END = ID2SYM(rb_intern_const("END"));
16006#ifdef SEEK_DATA
16007 sym_DATA = ID2SYM(rb_intern_const("DATA"));
16008#endif
16009#ifdef SEEK_HOLE
16010 sym_HOLE = ID2SYM(rb_intern_const("HOLE"));
16011#endif
16012 sym_wait_readable = ID2SYM(rb_intern_const("wait_readable"));
16013 sym_wait_writable = ID2SYM(rb_intern_const("wait_writable"));
16014}
16015
16016#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:1796
VALUE rb_define_class(const char *name, VALUE super)
Defines a top-level class.
Definition class.c:1589
VALUE rb_class_new(VALUE super)
Creates a new, anonymous class.
Definition class.c:969
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
Definition class.c:1620
VALUE rb_define_module_under(VALUE outer, const char *name)
Defines a module under the namespace of outer.
Definition class.c:1725
void rb_define_alias(VALUE klass, const char *name1, const char *name2)
Defines an alias of a method.
Definition class.c:2956
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:3259
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:3246
int rb_block_given_p(void)
Determines if the current method is given a block.
Definition eval.c:1010
int rb_get_kwargs(VALUE keyword_hash, const ID *table, int required, int optional, VALUE *values)
Keyword argument deconstructor.
Definition class.c:3035
#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:133
#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:205
#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:3827
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:1428
void rb_exc_raise(VALUE mesg)
Raises an exception in the current thread.
Definition eval.c:653
void rb_syserr_fail(int e, const char *mesg)
Raises appropriate exception that represents a C errno.
Definition error.c:3896
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:14693
VALUE rb_eIOError
IOError exception.
Definition io.c:189
VALUE rb_eStandardError
StandardError exception.
Definition error.c:1415
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:3986
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:3902
#define ruby_verbose
This variable controls whether the interpreter is in debug mode.
Definition error.h:476
VALUE rb_eTypeError
TypeError exception.
Definition error.c:1418
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:14687
void rb_iter_break_value(VALUE val)
Identical to rb_iter_break(), except it additionally takes the "value" of this breakage.
Definition vm.c:2286
rb_io_wait_readwrite
for rb_readwrite_sys_fail first argument
Definition error.h:73
VALUE rb_eRuntimeError
RuntimeError exception.
Definition error.c:1416
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:1438
@ 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:3312
VALUE rb_any_to_s(VALUE obj)
Generates a textual representation of the given object.
Definition object.c:675
VALUE rb_obj_alloc(VALUE klass)
Allocates an instance of the given class.
Definition object.c:2208
VALUE rb_class_new_instance(int argc, const VALUE *argv, VALUE klass)
Allocates, then initialises an instance of the given class.
Definition object.c:2249
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:2237
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:264
VALUE rb_obj_dup(VALUE obj)
Duplicates the given object.
Definition object.c:582
VALUE rb_inspect(VALUE obj)
Generates a human-readable textual representation of the given object.
Definition object.c:686
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:1342
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:3293
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:3306
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:1343
VALUE rb_enc_uint_chr(unsigned int code, rb_encoding *enc)
Encodes the passed code point into a series of bytes.
Definition numeric.c:3932
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:832
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:2660
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:2711
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:2974
VALUE rb_econv_make_exception(rb_econv_t *ec)
This function makes sense right after rb_econv_convert() returns.
Definition transcode.c:4340
void rb_econv_check_error(rb_econv_t *ec)
This is a rb_econv_make_exception() + rb_exc_raise() combo.
Definition transcode.c:4346
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:242
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:8622
VALUE rb_io_gets(VALUE io)
Reads a "line" from the given IO.
Definition io.c:4326
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:8755
VALUE rb_io_addstr(VALUE io, VALUE str)
Identical to rb_io_write(), except it always returns the passed IO.
Definition io.c:2382
void rb_write_error(const char *str)
Writes the given error message to somewhere applicable.
Definition io.c:9184
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:5198
VALUE rb_io_getbyte(VALUE io)
Reads a byte from the given IO.
Definition io.c:5103
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:9365
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:2724
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:9164
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:6413
VALUE rb_io_binmode(VALUE io)
Sets the binmode.
Definition io.c:6367
VALUE rb_io_ungetc(VALUE io, VALUE c)
"Unget"s a string.
Definition io.c:5262
int rb_pipe(int *pipes)
This is an rb_cloexec_pipe() + rb_update_max_fd() combo.
Definition io.c:7415
VALUE rb_gets(void)
Much like rb_io_gets(), but it reads from the mysterious ARGF object.
Definition io.c:10444
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:7298
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:7305
VALUE rb_io_close(VALUE io)
Closes the IO.
Definition io.c:5780
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:2048
VALUE rb_lastline_get(void)
Queries the last line, or the $_.
Definition vm.c:2042
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:3098
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:3798
#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:1002
VALUE rb_str_new_frozen(VALUE str)
Creates a frozen copy of the string, if necessary.
Definition string.c:1519
VALUE rb_str_dup(VALUE str)
Duplicates a string.
Definition string.c:1997
VALUE rb_str_cat(VALUE dst, const char *src, long srclen)
Destructively appends the passed contents to the string.
Definition string.c:3566
VALUE rb_str_locktmp(VALUE str)
Obtains a "temporary lock" of the string.
VALUE rb_str_equal(VALUE str1, VALUE str2)
Equality of two strings.
Definition string.c:4268
void rb_str_set_len(VALUE str, long len)
Overwrites the length of the string.
Definition string.c:3388
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:3740
VALUE rb_check_string_type(VALUE obj)
Try converting an object to its stringised representation using its to_str method,...
Definition string.c:2951
VALUE rb_str_substr(VALUE str, long beg, long len)
This is the implementation of two-argumented String#slice.
Definition string.c:3251
VALUE rb_str_unlocktmp(VALUE str)
Releases a lock formerly obtained by rb_str_locktmp().
Definition string.c:3370
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:2745
VALUE rb_str_buf_new(long capa)
Allocates a "string buffer".
Definition string.c:1719
#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:1851
int rb_thread_interrupted(VALUE thval)
Checks if the thread's execution was recently interrupted.
Definition thread.c:1482
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:1635
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:1465
VALUE rb_thread_current(void)
Obtains the "current" thread.
Definition thread.c:3178
int rb_thread_wait_fd(int fd)
Blocks the current thread until the given file descriptor is ready to be read.
Definition io.c:1629
void rb_thread_sleep(int sec)
Blocks for the given period of time.
Definition thread.c:1488
struct timeval rb_time_interval(VALUE num)
Creates a "time interval".
Definition time.c:2949
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:2017
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:3399
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:285
#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:4035
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:6499
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:6632
#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:1621
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:7115
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:6781
int rb_io_descriptor(VALUE io)
Returns an integer representing the numeric file descriptor for io.
Definition io.c:2927
#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:9411
#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:1682
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:1641
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:3001
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:6906
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:5700
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:5888
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:2047
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:3447
int rb_io_wait_writable(int fd)
Blocks until the passed file descriptor gets writable.
Definition io.c:1577
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:9277
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:1697
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:1542
void rb_io_synchronized(rb_io_t *fptr)
Sets FMODE_SYNC.
Definition io.c:7402
VALUE rb_io_wait(VALUE io, VALUE events, VALUE timeout)
Blocks until the passed IO is ready for the passed events.
Definition io.c:1482
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:1081
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:1141
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:1129
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:1117
void * rb_thread_call_with_gvl(void *(*func)(void *), void *data1)
(Re-)acquires the GVL.
Definition thread.c:2062
#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:1417
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:409
#define RSTRING_GETMEM(str, ptrvar, lenvar)
Convenient macro to obtain the contents and length at once.
Definition rstring.h:450
#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:542
VALUE rb_get_argv(void)
Queries the arguments passed to the current process that you can access from Ruby as ARGV.
Definition io.c:14653
void rb_p(VALUE obj)
Inspects an object.
Definition io.c:9063
#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:471
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:1006
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:522
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:756
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:982
VALUE rb_fiber_scheduler_io_wait(VALUE scheduler, VALUE io, VALUE events, VALUE timeout)
Non-blocking version of rb_io_wait().
Definition scheduler.c:742
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:72
VALUE rb_fiber_scheduler_io_selectv(VALUE scheduler, int argc, VALUE *argv)
Non-blocking version of IO.select, argv variant.
Definition scheduler.c:786
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:1018
VALUE rb_fiber_scheduler_current_for_thread(VALUE thread)
Identical to rb_fiber_scheduler_current(), except it queries for that of the passed thread value inst...
Definition scheduler.c:479
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:994
VALUE rb_fiber_scheduler_current_for_threadptr(struct rb_thread_struct *thread)
Identical to rb_fiber_scheduler_current_for_thread(), except it expects a threadptr instead of a thre...
Definition scheduler.c:484
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:762
VALUE rb_fiber_scheduler_io_close(VALUE scheduler, VALUE io)
Non-blocking close the given IO.
Definition scheduler.c:1038
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:4531
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:230
This is the struct that holds necessary info for a struct.
Definition rtypeddata.h:208
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