Ruby 4.0.0dev (2025-12-24 revision ab683d56bc625c83d815741b3bfd9c606b14517f)
io.c (ab683d56bc625c83d815741b3bfd9c606b14517f)
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 * f = File.new('t.rus')
4724 * a = []
4725 * f.each_byte {|b| a << b }
4726 * a # => [209, 130, 208, 181, 209, 129, 209, 130]
4727 * f.close
4728 *
4729 * Returns an Enumerator if no block is given.
4730 *
4731 * Related: IO#each_char, IO#each_codepoint.
4732 *
4733 */
4734
4735static VALUE
4736rb_io_each_byte(VALUE io)
4737{
4738 rb_io_t *fptr;
4739
4740 RETURN_ENUMERATOR(io, 0, 0);
4741 GetOpenFile(io, fptr);
4742
4743 do {
4744 while (fptr->rbuf.len > 0) {
4745 char *p = fptr->rbuf.ptr + fptr->rbuf.off++;
4746 fptr->rbuf.len--;
4747 rb_yield(INT2FIX(*p & 0xff));
4749 errno = 0;
4750 }
4751 READ_CHECK(fptr);
4752 } while (io_fillbuf(fptr) >= 0);
4753 return io;
4754}
4755
4756static VALUE
4757io_getc(rb_io_t *fptr, rb_encoding *enc)
4758{
4759 int r, n, cr = 0;
4760 VALUE str;
4761
4762 if (NEED_READCONV(fptr)) {
4763 rb_encoding *read_enc = io_read_encoding(fptr);
4764
4765 str = Qnil;
4766 SET_BINARY_MODE(fptr);
4767 make_readconv(fptr, 0);
4768
4769 while (1) {
4770 if (fptr->cbuf.len) {
4771 r = rb_enc_precise_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4772 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4773 read_enc);
4774 if (!MBCLEN_NEEDMORE_P(r))
4775 break;
4776 if (fptr->cbuf.len == fptr->cbuf.capa) {
4777 rb_raise(rb_eIOError, "too long character");
4778 }
4779 }
4780
4781 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4782 if (fptr->cbuf.len == 0) {
4783 clear_readconv(fptr);
4784 return Qnil;
4785 }
4786 /* return an unit of an incomplete character just before EOF */
4787 str = rb_enc_str_new(fptr->cbuf.ptr+fptr->cbuf.off, 1, read_enc);
4788 fptr->cbuf.off += 1;
4789 fptr->cbuf.len -= 1;
4790 if (fptr->cbuf.len == 0) clear_readconv(fptr);
4792 return str;
4793 }
4794 }
4795 if (MBCLEN_INVALID_P(r)) {
4796 r = rb_enc_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4797 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4798 read_enc);
4799 io_shift_cbuf(fptr, r, &str);
4801 }
4802 else {
4803 io_shift_cbuf(fptr, MBCLEN_CHARFOUND_LEN(r), &str);
4805 if (MBCLEN_CHARFOUND_LEN(r) == 1 && rb_enc_asciicompat(read_enc) &&
4806 ISASCII(RSTRING_PTR(str)[0])) {
4807 cr = ENC_CODERANGE_7BIT;
4808 }
4809 }
4810 str = io_enc_str(str, fptr);
4811 ENC_CODERANGE_SET(str, cr);
4812 return str;
4813 }
4814
4815 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4816 if (io_fillbuf(fptr) < 0) {
4817 return Qnil;
4818 }
4819 if (rb_enc_asciicompat(enc) && ISASCII(fptr->rbuf.ptr[fptr->rbuf.off])) {
4820 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, 1);
4821 fptr->rbuf.off += 1;
4822 fptr->rbuf.len -= 1;
4823 cr = ENC_CODERANGE_7BIT;
4824 }
4825 else {
4826 r = rb_enc_precise_mbclen(fptr->rbuf.ptr+fptr->rbuf.off, fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
4827 if (MBCLEN_CHARFOUND_P(r) &&
4828 (n = MBCLEN_CHARFOUND_LEN(r)) <= fptr->rbuf.len) {
4829 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, n);
4830 fptr->rbuf.off += n;
4831 fptr->rbuf.len -= n;
4833 }
4834 else if (MBCLEN_NEEDMORE_P(r)) {
4835 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, fptr->rbuf.len);
4836 fptr->rbuf.len = 0;
4837 getc_needmore:
4838 if (io_fillbuf(fptr) != -1) {
4839 rb_str_cat(str, fptr->rbuf.ptr+fptr->rbuf.off, 1);
4840 fptr->rbuf.off++;
4841 fptr->rbuf.len--;
4842 r = rb_enc_precise_mbclen(RSTRING_PTR(str), RSTRING_PTR(str)+RSTRING_LEN(str), enc);
4843 if (MBCLEN_NEEDMORE_P(r)) {
4844 goto getc_needmore;
4845 }
4846 else if (MBCLEN_CHARFOUND_P(r)) {
4848 }
4849 }
4850 }
4851 else {
4852 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, 1);
4853 fptr->rbuf.off++;
4854 fptr->rbuf.len--;
4855 }
4856 }
4857 if (!cr) cr = ENC_CODERANGE_BROKEN;
4858 str = io_enc_str(str, fptr);
4859 ENC_CODERANGE_SET(str, cr);
4860 return str;
4861}
4862
4863/*
4864 * call-seq:
4865 * each_char {|c| ... } -> self
4866 * each_char -> enumerator
4867 *
4868 * Calls the given block with each character in the stream; returns +self+.
4869 * See {Character IO}[rdoc-ref:IO@Character+IO].
4870 *
4871 * f = File.new('t.rus')
4872 * a = []
4873 * f.each_char {|c| a << c.ord }
4874 * a # => [1090, 1077, 1089, 1090]
4875 * f.close
4876 *
4877 * Returns an Enumerator if no block is given.
4878 *
4879 * Related: IO#each_byte, IO#each_codepoint.
4880 *
4881 */
4882
4883static VALUE
4884rb_io_each_char(VALUE io)
4885{
4886 rb_io_t *fptr;
4887 rb_encoding *enc;
4888 VALUE c;
4889
4890 RETURN_ENUMERATOR(io, 0, 0);
4891 GetOpenFile(io, fptr);
4893
4894 enc = io_input_encoding(fptr);
4895 READ_CHECK(fptr);
4896 while (!NIL_P(c = io_getc(fptr, enc))) {
4897 rb_yield(c);
4898 }
4899 return io;
4900}
4901
4902/*
4903 * call-seq:
4904 * each_codepoint {|c| ... } -> self
4905 * each_codepoint -> enumerator
4906 *
4907 * Calls the given block with each codepoint in the stream; returns +self+:
4908 *
4909 * f = File.new('t.rus')
4910 * a = []
4911 * f.each_codepoint {|c| a << c }
4912 * a # => [1090, 1077, 1089, 1090]
4913 * f.close
4914 *
4915 * Returns an Enumerator if no block is given.
4916 *
4917 * Related: IO#each_byte, IO#each_char.
4918 *
4919 */
4920
4921static VALUE
4922rb_io_each_codepoint(VALUE io)
4923{
4924 rb_io_t *fptr;
4925 rb_encoding *enc;
4926 unsigned int c;
4927 int r, n;
4928
4929 RETURN_ENUMERATOR(io, 0, 0);
4930 GetOpenFile(io, fptr);
4932
4933 READ_CHECK(fptr);
4934 enc = io_read_encoding(fptr);
4935 if (NEED_READCONV(fptr)) {
4936 SET_BINARY_MODE(fptr);
4937 r = 1; /* no invalid char yet */
4938 for (;;) {
4939 make_readconv(fptr, 0);
4940 for (;;) {
4941 if (fptr->cbuf.len) {
4942 r = rb_enc_precise_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4943 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4944 enc);
4945 if (!MBCLEN_NEEDMORE_P(r))
4946 break;
4947 if (fptr->cbuf.len == fptr->cbuf.capa) {
4948 rb_raise(rb_eIOError, "too long character");
4949 }
4950 }
4951 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4952 clear_readconv(fptr);
4953 if (!MBCLEN_CHARFOUND_P(r)) {
4954 goto invalid;
4955 }
4956 return io;
4957 }
4958 }
4959 if (MBCLEN_INVALID_P(r)) {
4960 goto invalid;
4961 }
4962 n = MBCLEN_CHARFOUND_LEN(r);
4963 c = rb_enc_codepoint(fptr->cbuf.ptr+fptr->cbuf.off,
4964 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4965 enc);
4966 fptr->cbuf.off += n;
4967 fptr->cbuf.len -= n;
4968 rb_yield(UINT2NUM(c));
4970 }
4971 }
4972 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4973 while (io_fillbuf(fptr) >= 0) {
4974 r = rb_enc_precise_mbclen(fptr->rbuf.ptr+fptr->rbuf.off,
4975 fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
4976 if (MBCLEN_CHARFOUND_P(r) &&
4977 (n = MBCLEN_CHARFOUND_LEN(r)) <= fptr->rbuf.len) {
4978 c = rb_enc_codepoint(fptr->rbuf.ptr+fptr->rbuf.off,
4979 fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
4980 fptr->rbuf.off += n;
4981 fptr->rbuf.len -= n;
4982 rb_yield(UINT2NUM(c));
4983 }
4984 else if (MBCLEN_INVALID_P(r)) {
4985 goto invalid;
4986 }
4987 else if (MBCLEN_NEEDMORE_P(r)) {
4988 char cbuf[8], *p = cbuf;
4989 int more = MBCLEN_NEEDMORE_LEN(r);
4990 if (more > numberof(cbuf)) goto invalid;
4991 more += n = fptr->rbuf.len;
4992 if (more > numberof(cbuf)) goto invalid;
4993 while ((n = (int)read_buffered_data(p, more, fptr)) > 0 &&
4994 (p += n, (more -= n) > 0)) {
4995 if (io_fillbuf(fptr) < 0) goto invalid;
4996 if ((n = fptr->rbuf.len) > more) n = more;
4997 }
4998 r = rb_enc_precise_mbclen(cbuf, p, enc);
4999 if (!MBCLEN_CHARFOUND_P(r)) goto invalid;
5000 c = rb_enc_codepoint(cbuf, p, enc);
5001 rb_yield(UINT2NUM(c));
5002 }
5003 else {
5004 continue;
5005 }
5007 }
5008 return io;
5009
5010 invalid:
5011 rb_raise(rb_eArgError, "invalid byte sequence in %s", rb_enc_name(enc));
5013}
5014
5015/*
5016 * call-seq:
5017 * getc -> character or nil
5018 *
5019 * Reads and returns the next 1-character string from the stream;
5020 * returns +nil+ if already at end-of-stream.
5021 * See {Character IO}[rdoc-ref:IO@Character+IO].
5022 *
5023 * f = File.open('t.txt')
5024 * f.getc # => "F"
5025 * f.close
5026 * f = File.open('t.rus')
5027 * f.getc.ord # => 1090
5028 * f.close
5029 *
5030 * Related: IO#readchar (may raise EOFError).
5031 *
5032 */
5033
5034static VALUE
5035rb_io_getc(VALUE io)
5036{
5037 rb_io_t *fptr;
5038 rb_encoding *enc;
5039
5040 GetOpenFile(io, fptr);
5042
5043 enc = io_input_encoding(fptr);
5044 READ_CHECK(fptr);
5045 return io_getc(fptr, enc);
5046}
5047
5048/*
5049 * call-seq:
5050 * readchar -> string
5051 *
5052 * Reads and returns the next 1-character string from the stream;
5053 * raises EOFError if already at end-of-stream.
5054 * See {Character IO}[rdoc-ref:IO@Character+IO].
5055 *
5056 * f = File.open('t.txt')
5057 * f.readchar # => "F"
5058 * f.close
5059 * f = File.open('t.rus')
5060 * f.readchar.ord # => 1090
5061 * f.close
5062 *
5063 * Related: IO#getc (will not raise EOFError).
5064 *
5065 */
5066
5067static VALUE
5068rb_io_readchar(VALUE io)
5069{
5070 VALUE c = rb_io_getc(io);
5071
5072 if (NIL_P(c)) {
5073 rb_eof_error();
5074 }
5075 return c;
5076}
5077
5078/*
5079 * call-seq:
5080 * getbyte -> integer or nil
5081 *
5082 * Reads and returns the next byte (in range 0..255) from the stream;
5083 * returns +nil+ if already at end-of-stream.
5084 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5085 *
5086 * f = File.open('t.txt')
5087 * f.getbyte # => 70
5088 * f.close
5089 * f = File.open('t.rus')
5090 * f.getbyte # => 209
5091 * f.close
5092 *
5093 * Related: IO#readbyte (may raise EOFError).
5094 */
5095
5096VALUE
5098{
5099 rb_io_t *fptr;
5100 int c;
5101
5102 GetOpenFile(io, fptr);
5104 READ_CHECK(fptr);
5105 VALUE r_stdout = rb_ractor_stdout();
5106 if (fptr->fd == 0 && (fptr->mode & FMODE_TTY) && RB_TYPE_P(r_stdout, T_FILE)) {
5107 rb_io_t *ofp;
5108 GetOpenFile(r_stdout, ofp);
5109 if (ofp->mode & FMODE_TTY) {
5110 rb_io_flush(r_stdout);
5111 }
5112 }
5113 if (io_fillbuf(fptr) < 0) {
5114 return Qnil;
5115 }
5116 fptr->rbuf.off++;
5117 fptr->rbuf.len--;
5118 c = (unsigned char)fptr->rbuf.ptr[fptr->rbuf.off-1];
5119 return INT2FIX(c & 0xff);
5120}
5121
5122/*
5123 * call-seq:
5124 * readbyte -> integer
5125 *
5126 * Reads and returns the next byte (in range 0..255) from the stream;
5127 * raises EOFError if already at end-of-stream.
5128 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5129 *
5130 * f = File.open('t.txt')
5131 * f.readbyte # => 70
5132 * f.close
5133 * f = File.open('t.rus')
5134 * f.readbyte # => 209
5135 * f.close
5136 *
5137 * Related: IO#getbyte (will not raise EOFError).
5138 *
5139 */
5140
5141static VALUE
5142rb_io_readbyte(VALUE io)
5143{
5144 VALUE c = rb_io_getbyte(io);
5145
5146 if (NIL_P(c)) {
5147 rb_eof_error();
5148 }
5149 return c;
5150}
5151
5152/*
5153 * call-seq:
5154 * ungetbyte(integer) -> nil
5155 * ungetbyte(string) -> nil
5156 *
5157 * Pushes back ("unshifts") the given data onto the stream's buffer,
5158 * placing the data so that it is next to be read; returns +nil+.
5159 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5160 *
5161 * Note that:
5162 *
5163 * - Calling the method has no effect with unbuffered reads (such as IO#sysread).
5164 * - Calling #rewind on the stream discards the pushed-back data.
5165 *
5166 * When argument +integer+ is given, uses only its low-order byte:
5167 *
5168 * File.write('t.tmp', '012')
5169 * f = File.open('t.tmp')
5170 * f.ungetbyte(0x41) # => nil
5171 * f.read # => "A012"
5172 * f.rewind
5173 * f.ungetbyte(0x4243) # => nil
5174 * f.read # => "C012"
5175 * f.close
5176 *
5177 * When argument +string+ is given, uses all bytes:
5178 *
5179 * File.write('t.tmp', '012')
5180 * f = File.open('t.tmp')
5181 * f.ungetbyte('A') # => nil
5182 * f.read # => "A012"
5183 * f.rewind
5184 * f.ungetbyte('BCDE') # => nil
5185 * f.read # => "BCDE012"
5186 * f.close
5187 *
5188 */
5189
5190VALUE
5192{
5193 rb_io_t *fptr;
5194
5195 GetOpenFile(io, fptr);
5197 switch (TYPE(b)) {
5198 case T_NIL:
5199 return Qnil;
5200 case T_FIXNUM:
5201 case T_BIGNUM: ;
5202 VALUE v = rb_int_modulo(b, INT2FIX(256));
5203 unsigned char c = NUM2INT(v) & 0xFF;
5204 b = rb_str_new((const char *)&c, 1);
5205 break;
5206 default:
5207 StringValue(b);
5208 }
5209 io_ungetbyte(b, fptr);
5210 return Qnil;
5211}
5212
5213/*
5214 * call-seq:
5215 * ungetc(integer) -> nil
5216 * ungetc(string) -> nil
5217 *
5218 * Pushes back ("unshifts") the given data onto the stream's buffer,
5219 * placing the data so that it is next to be read; returns +nil+.
5220 * See {Character IO}[rdoc-ref:IO@Character+IO].
5221 *
5222 * Note that:
5223 *
5224 * - Calling the method has no effect with unbuffered reads (such as IO#sysread).
5225 * - Calling #rewind on the stream discards the pushed-back data.
5226 *
5227 * When argument +integer+ is given, interprets the integer as a character:
5228 *
5229 * File.write('t.tmp', '012')
5230 * f = File.open('t.tmp')
5231 * f.ungetc(0x41) # => nil
5232 * f.read # => "A012"
5233 * f.rewind
5234 * f.ungetc(0x0442) # => nil
5235 * f.getc.ord # => 1090
5236 * f.close
5237 *
5238 * When argument +string+ is given, uses all characters:
5239 *
5240 * File.write('t.tmp', '012')
5241 * f = File.open('t.tmp')
5242 * f.ungetc('A') # => nil
5243 * f.read # => "A012"
5244 * f.rewind
5245 * f.ungetc("\u0442\u0435\u0441\u0442") # => nil
5246 * f.getc.ord # => 1090
5247 * f.getc.ord # => 1077
5248 * f.getc.ord # => 1089
5249 * f.getc.ord # => 1090
5250 * f.close
5251 *
5252 */
5253
5254VALUE
5256{
5257 rb_io_t *fptr;
5258 long len;
5259
5260 GetOpenFile(io, fptr);
5262 if (FIXNUM_P(c)) {
5263 c = rb_enc_uint_chr(FIX2UINT(c), io_read_encoding(fptr));
5264 }
5265 else if (RB_BIGNUM_TYPE_P(c)) {
5266 c = rb_enc_uint_chr(NUM2UINT(c), io_read_encoding(fptr));
5267 }
5268 else {
5269 StringValue(c);
5270 }
5271 if (NEED_READCONV(fptr)) {
5272 SET_BINARY_MODE(fptr);
5273 len = RSTRING_LEN(c);
5274#if SIZEOF_LONG > SIZEOF_INT
5275 if (len > INT_MAX)
5276 rb_raise(rb_eIOError, "ungetc failed");
5277#endif
5278 make_readconv(fptr, (int)len);
5279 if (fptr->cbuf.capa - fptr->cbuf.len < len)
5280 rb_raise(rb_eIOError, "ungetc failed");
5281 if (fptr->cbuf.off < len) {
5282 MEMMOVE(fptr->cbuf.ptr+fptr->cbuf.capa-fptr->cbuf.len,
5283 fptr->cbuf.ptr+fptr->cbuf.off,
5284 char, fptr->cbuf.len);
5285 fptr->cbuf.off = fptr->cbuf.capa-fptr->cbuf.len;
5286 }
5287 fptr->cbuf.off -= (int)len;
5288 fptr->cbuf.len += (int)len;
5289 MEMMOVE(fptr->cbuf.ptr+fptr->cbuf.off, RSTRING_PTR(c), char, len);
5290 }
5291 else {
5292 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
5293 io_ungetbyte(c, fptr);
5294 }
5295 return Qnil;
5296}
5297
5298/*
5299 * call-seq:
5300 * isatty -> true or false
5301 *
5302 * Returns +true+ if the stream is associated with a terminal device (tty),
5303 * +false+ otherwise:
5304 *
5305 * f = File.new('t.txt').isatty #=> false
5306 * f.close
5307 * f = File.new('/dev/tty').isatty #=> true
5308 * f.close
5309 *
5310 */
5311
5312static VALUE
5313rb_io_isatty(VALUE io)
5314{
5315 rb_io_t *fptr;
5316
5317 GetOpenFile(io, fptr);
5318 return RBOOL(isatty(fptr->fd) != 0);
5319}
5320
5321#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5322/*
5323 * call-seq:
5324 * close_on_exec? -> true or false
5325 *
5326 * Returns +true+ if the stream will be closed on exec, +false+ otherwise:
5327 *
5328 * f = File.open('t.txt')
5329 * f.close_on_exec? # => true
5330 * f.close_on_exec = false
5331 * f.close_on_exec? # => false
5332 * f.close
5333 *
5334 */
5335
5336static VALUE
5337rb_io_close_on_exec_p(VALUE io)
5338{
5339 rb_io_t *fptr;
5340 VALUE write_io;
5341 int fd, ret;
5342
5343 write_io = GetWriteIO(io);
5344 if (io != write_io) {
5345 GetOpenFile(write_io, fptr);
5346 if (fptr && 0 <= (fd = fptr->fd)) {
5347 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5348 if (!(ret & FD_CLOEXEC)) return Qfalse;
5349 }
5350 }
5351
5352 GetOpenFile(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 return Qtrue;
5358}
5359#else
5360#define rb_io_close_on_exec_p rb_f_notimplement
5361#endif
5362
5363#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5364/*
5365 * call-seq:
5366 * self.close_on_exec = bool -> true or false
5367 *
5368 * Sets a close-on-exec flag.
5369 *
5370 * f = File.open(File::NULL)
5371 * f.close_on_exec = true
5372 * system("cat", "/proc/self/fd/#{f.fileno}") # cat: /proc/self/fd/3: No such file or directory
5373 * f.closed? #=> false
5374 *
5375 * Ruby sets close-on-exec flags of all file descriptors by default
5376 * since Ruby 2.0.0.
5377 * So you don't need to set by yourself.
5378 * Also, unsetting a close-on-exec flag can cause file descriptor leak
5379 * if another thread use fork() and exec() (via system() method for example).
5380 * If you really needs file descriptor inheritance to child process,
5381 * use spawn()'s argument such as fd=>fd.
5382 */
5383
5384static VALUE
5385rb_io_set_close_on_exec(VALUE io, VALUE arg)
5386{
5387 int flag = RTEST(arg) ? FD_CLOEXEC : 0;
5388 rb_io_t *fptr;
5389 VALUE write_io;
5390 int fd, ret;
5391
5392 write_io = GetWriteIO(io);
5393 if (io != write_io) {
5394 GetOpenFile(write_io, fptr);
5395 if (fptr && 0 <= (fd = fptr->fd)) {
5396 if ((ret = fcntl(fptr->fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5397 if ((ret & FD_CLOEXEC) != flag) {
5398 ret = (ret & ~FD_CLOEXEC) | flag;
5399 ret = fcntl(fd, F_SETFD, ret);
5400 if (ret != 0) rb_sys_fail_path(fptr->pathv);
5401 }
5402 }
5403
5404 }
5405
5406 GetOpenFile(io, fptr);
5407 if (fptr && 0 <= (fd = fptr->fd)) {
5408 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5409 if ((ret & FD_CLOEXEC) != flag) {
5410 ret = (ret & ~FD_CLOEXEC) | flag;
5411 ret = fcntl(fd, F_SETFD, ret);
5412 if (ret != 0) rb_sys_fail_path(fptr->pathv);
5413 }
5414 }
5415 return Qnil;
5416}
5417#else
5418#define rb_io_set_close_on_exec rb_f_notimplement
5419#endif
5420
5421#define RUBY_IO_EXTERNAL_P(f) ((f)->mode & FMODE_EXTERNAL)
5422#define PREP_STDIO_NAME(f) (RSTRING_PTR((f)->pathv))
5423
5424static VALUE
5425finish_writeconv(rb_io_t *fptr, int noalloc)
5426{
5427 unsigned char *ds, *dp, *de;
5429
5430 if (!fptr->wbuf.ptr) {
5431 unsigned char buf[1024];
5432
5434 while (res == econv_destination_buffer_full) {
5435 ds = dp = buf;
5436 de = buf + sizeof(buf);
5437 res = rb_econv_convert(fptr->writeconv, NULL, NULL, &dp, de, 0);
5438 while (dp-ds) {
5439 size_t remaining = dp-ds;
5440 long result = rb_io_write_memory(fptr, ds, remaining);
5441
5442 if (result > 0) {
5443 ds += result;
5444 if ((size_t)result == remaining) break;
5445 }
5446 else if (rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
5447 if (fptr->fd < 0)
5448 return noalloc ? Qtrue : rb_exc_new3(rb_eIOError, rb_str_new_cstr(closed_stream));
5449 }
5450 else {
5451 return noalloc ? Qtrue : INT2NUM(errno);
5452 }
5453 }
5454 if (res == econv_invalid_byte_sequence ||
5455 res == econv_incomplete_input ||
5457 return noalloc ? Qtrue : rb_econv_make_exception(fptr->writeconv);
5458 }
5459 }
5460
5461 return Qnil;
5462 }
5463
5465 while (res == econv_destination_buffer_full) {
5466 if (fptr->wbuf.len == fptr->wbuf.capa) {
5467 if (io_fflush(fptr) < 0) {
5468 return noalloc ? Qtrue : INT2NUM(errno);
5469 }
5470 }
5471
5472 ds = dp = (unsigned char *)fptr->wbuf.ptr + fptr->wbuf.off + fptr->wbuf.len;
5473 de = (unsigned char *)fptr->wbuf.ptr + fptr->wbuf.capa;
5474 res = rb_econv_convert(fptr->writeconv, NULL, NULL, &dp, de, 0);
5475 fptr->wbuf.len += (int)(dp - ds);
5476 if (res == econv_invalid_byte_sequence ||
5477 res == econv_incomplete_input ||
5479 return noalloc ? Qtrue : rb_econv_make_exception(fptr->writeconv);
5480 }
5481 }
5482 return Qnil;
5483}
5484
5486 rb_io_t *fptr;
5487 int noalloc;
5488};
5489
5490static VALUE
5491finish_writeconv_sync(VALUE arg)
5492{
5493 struct finish_writeconv_arg *p = (struct finish_writeconv_arg *)arg;
5494 return finish_writeconv(p->fptr, p->noalloc);
5495}
5496
5497static void*
5498nogvl_close(void *ptr)
5499{
5500 int *fd = ptr;
5501
5502 return (void*)(intptr_t)close(*fd);
5503}
5504
5505static int
5506maygvl_close(int fd, int keepgvl)
5507{
5508 if (keepgvl)
5509 return close(fd);
5510
5511 /*
5512 * close() may block for certain file types (NFS, SO_LINGER sockets,
5513 * inotify), so let other threads run.
5514 */
5515 return IO_WITHOUT_GVL_INT(nogvl_close, &fd);
5516}
5517
5518static void*
5519nogvl_fclose(void *ptr)
5520{
5521 FILE *file = ptr;
5522
5523 return (void*)(intptr_t)fclose(file);
5524}
5525
5526static int
5527maygvl_fclose(FILE *file, int keepgvl)
5528{
5529 if (keepgvl)
5530 return fclose(file);
5531
5532 return IO_WITHOUT_GVL_INT(nogvl_fclose, file);
5533}
5534
5535static void free_io_buffer(rb_io_buffer_t *buf);
5536
5537static void
5538fptr_finalize_flush(rb_io_t *fptr, int noraise, int keepgvl)
5539{
5540 VALUE error = Qnil;
5541 int fd = fptr->fd;
5542 FILE *stdio_file = fptr->stdio_file;
5543 int mode = fptr->mode;
5544
5545 if (fptr->writeconv) {
5546 if (!NIL_P(fptr->write_lock) && !noraise) {
5547 struct finish_writeconv_arg arg;
5548 arg.fptr = fptr;
5549 arg.noalloc = noraise;
5550 error = rb_mutex_synchronize(fptr->write_lock, finish_writeconv_sync, (VALUE)&arg);
5551 }
5552 else {
5553 error = finish_writeconv(fptr, noraise);
5554 }
5555 }
5556 if (fptr->wbuf.len) {
5557 if (noraise) {
5558 io_flush_buffer_sync(fptr);
5559 }
5560 else {
5561 if (io_fflush(fptr) < 0 && NIL_P(error)) {
5562 error = INT2NUM(errno);
5563 }
5564 }
5565 }
5566
5567 int done = 0;
5568
5569 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2) {
5570 // Need to keep FILE objects of stdin, stdout and stderr, so we are done:
5571 done = 1;
5572 }
5573
5574 fptr->fd = -1;
5575 fptr->stdio_file = 0;
5577
5578 // Wait for blocking operations to ensure they do not hit EBADF:
5579 rb_thread_io_close_wait(fptr);
5580
5581 if (!done && stdio_file) {
5582 // stdio_file is deallocated anyway even if fclose failed.
5583 if ((maygvl_fclose(stdio_file, noraise) < 0) && NIL_P(error)) {
5584 if (!noraise) {
5585 error = INT2NUM(errno);
5586 }
5587 }
5588
5589 done = 1;
5590 }
5591
5592 VALUE scheduler = rb_fiber_scheduler_current();
5593 if (!done && fd >= 0 && scheduler != Qnil) {
5594 VALUE result = rb_fiber_scheduler_io_close(scheduler, RB_INT2NUM(fd));
5595
5596 if (!UNDEF_P(result)) {
5597 done = RTEST(result);
5598 }
5599 }
5600
5601 if (!done && fd >= 0) {
5602 // fptr->fd may be closed even if close fails. POSIX doesn't specify it.
5603 // We assumes it is closed.
5604
5605 keepgvl |= !(mode & FMODE_WRITABLE);
5606 keepgvl |= noraise;
5607 if ((maygvl_close(fd, keepgvl) < 0) && NIL_P(error)) {
5608 if (!noraise) {
5609 error = INT2NUM(errno);
5610 }
5611 }
5612
5613 done = 1;
5614 }
5615
5616 if (!NIL_P(error) && !noraise) {
5617 if (RB_INTEGER_TYPE_P(error))
5618 rb_syserr_fail_path(NUM2INT(error), fptr->pathv);
5619 else
5620 rb_exc_raise(error);
5621 }
5622}
5623
5624static void
5625fptr_finalize(rb_io_t *fptr, int noraise)
5626{
5627 fptr_finalize_flush(fptr, noraise, FALSE);
5628 free_io_buffer(&fptr->rbuf);
5629 free_io_buffer(&fptr->wbuf);
5630 clear_codeconv(fptr);
5631}
5632
5633static void
5634rb_io_fptr_cleanup(rb_io_t *fptr, int noraise)
5635{
5636 if (fptr->finalize) {
5637 (*fptr->finalize)(fptr, noraise);
5638 }
5639 else {
5640 fptr_finalize(fptr, noraise);
5641 }
5642}
5643
5644static void
5645free_io_buffer(rb_io_buffer_t *buf)
5646{
5647 if (buf->ptr) {
5648 ruby_sized_xfree(buf->ptr, (size_t)buf->capa);
5649 buf->ptr = NULL;
5650 }
5651}
5652
5653static void
5654clear_readconv(rb_io_t *fptr)
5655{
5656 if (fptr->readconv) {
5657 rb_econv_close(fptr->readconv);
5658 fptr->readconv = NULL;
5659 }
5660 free_io_buffer(&fptr->cbuf);
5661}
5662
5663static void
5664clear_writeconv(rb_io_t *fptr)
5665{
5666 if (fptr->writeconv) {
5668 fptr->writeconv = NULL;
5669 }
5670 fptr->writeconv_initialized = 0;
5671}
5672
5673static void
5674clear_codeconv(rb_io_t *fptr)
5675{
5676 clear_readconv(fptr);
5677 clear_writeconv(fptr);
5678}
5679
5680static void
5681rb_io_fptr_cleanup_all(rb_io_t *fptr)
5682{
5683 fptr->pathv = Qnil;
5684 if (0 <= fptr->fd)
5685 rb_io_fptr_cleanup(fptr, TRUE);
5686 fptr->write_lock = Qnil;
5687 free_io_buffer(&fptr->rbuf);
5688 free_io_buffer(&fptr->wbuf);
5689 clear_codeconv(fptr);
5690}
5691
5692int
5694{
5695 if (!io) return 0;
5696 rb_io_fptr_cleanup_all(io);
5697 free(io);
5698
5699 return 1;
5700}
5701
5702size_t
5703rb_io_memsize(const rb_io_t *io)
5704{
5705 size_t size = sizeof(rb_io_t);
5706 size += io->rbuf.capa;
5707 size += io->wbuf.capa;
5708 size += io->cbuf.capa;
5709 if (io->readconv) size += rb_econv_memsize(io->readconv);
5710 if (io->writeconv) size += rb_econv_memsize(io->writeconv);
5711
5712 struct rb_io_blocking_operation *blocking_operation = 0;
5713
5714 // 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.
5715 rb_serial_t fork_generation = GET_VM()->fork_gen;
5716 if (io->fork_generation == fork_generation) {
5717 ccan_list_for_each(&io->blocking_operations, blocking_operation, list) {
5718 size += sizeof(struct rb_io_blocking_operation);
5719 }
5720 }
5721
5722 return size;
5723}
5724
5725#ifdef _WIN32
5726/* keep GVL while closing to prevent crash on Windows */
5727# define KEEPGVL TRUE
5728#else
5729# define KEEPGVL FALSE
5730#endif
5731
5732static rb_io_t *
5733io_close_fptr(VALUE io)
5734{
5735 rb_io_t *fptr;
5736 VALUE write_io;
5737 rb_io_t *write_fptr;
5738
5739 write_io = GetWriteIO(io);
5740 if (io != write_io) {
5741 write_fptr = RFILE(write_io)->fptr;
5742 if (write_fptr && 0 <= write_fptr->fd) {
5743 rb_io_fptr_cleanup(write_fptr, TRUE);
5744 }
5745 }
5746
5747 fptr = RFILE(io)->fptr;
5748 if (!fptr) return 0;
5749 if (fptr->fd < 0) return 0;
5750
5751 // This guards against multiple threads closing the same IO object:
5752 if (rb_thread_io_close_interrupt(fptr)) {
5753 /* calls close(fptr->fd): */
5754 fptr_finalize_flush(fptr, FALSE, KEEPGVL);
5755 }
5756
5757 rb_io_fptr_cleanup(fptr, FALSE);
5758 return fptr;
5759}
5760
5761static void
5762fptr_waitpid(rb_io_t *fptr, int nohang)
5763{
5764 int status;
5765 if (fptr->pid) {
5766 rb_last_status_clear();
5767 rb_waitpid(fptr->pid, &status, nohang ? WNOHANG : 0);
5768 fptr->pid = 0;
5769 }
5770}
5771
5772VALUE
5774{
5775 rb_io_t *fptr = io_close_fptr(io);
5776 if (fptr) fptr_waitpid(fptr, 0);
5777 return Qnil;
5778}
5779
5780/*
5781 * call-seq:
5782 * close -> nil
5783 *
5784 * Closes the stream for both reading and writing
5785 * if open for either or both; returns +nil+.
5786 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5787 *
5788 * If the stream is open for writing, flushes any buffered writes
5789 * to the operating system before closing.
5790 *
5791 * If the stream was opened by IO.popen, sets global variable <tt>$?</tt>
5792 * (child exit status).
5793 *
5794 * It is not an error to close an IO object that has already been closed.
5795 * It just returns nil.
5796 *
5797 * Example:
5798 *
5799 * IO.popen('ruby', 'r+') do |pipe|
5800 * puts pipe.closed?
5801 * pipe.close
5802 * puts $?
5803 * puts pipe.closed?
5804 * end
5805 *
5806 * Output:
5807 *
5808 * false
5809 * pid 13760 exit 0
5810 * true
5811 *
5812 * Related: IO#close_read, IO#close_write, IO#closed?.
5813 */
5814
5815static VALUE
5816rb_io_close_m(VALUE io)
5817{
5818 rb_io_t *fptr = rb_io_get_fptr(io);
5819 if (fptr->fd < 0) {
5820 return Qnil;
5821 }
5822 rb_io_close(io);
5823 return Qnil;
5824}
5825
5826static VALUE
5827io_call_close(VALUE io)
5828{
5829 rb_check_funcall(io, rb_intern("close"), 0, 0);
5830 return io;
5831}
5832
5833static VALUE
5834ignore_closed_stream(VALUE io, VALUE exc)
5835{
5836 enum {mesg_len = sizeof(closed_stream)-1};
5837 VALUE mesg = rb_attr_get(exc, idMesg);
5838 if (!RB_TYPE_P(mesg, T_STRING) ||
5839 RSTRING_LEN(mesg) != mesg_len ||
5840 memcmp(RSTRING_PTR(mesg), closed_stream, mesg_len)) {
5841 rb_exc_raise(exc);
5842 }
5843 return io;
5844}
5845
5846static VALUE
5847io_close(VALUE io)
5848{
5849 VALUE closed = rb_check_funcall(io, rb_intern("closed?"), 0, 0);
5850 if (!UNDEF_P(closed) && RTEST(closed)) return io;
5851 rb_rescue2(io_call_close, io, ignore_closed_stream, io,
5852 rb_eIOError, (VALUE)0);
5853 return io;
5854}
5855
5856/*
5857 * call-seq:
5858 * closed? -> true or false
5859 *
5860 * Returns +true+ if the stream is closed for both reading and writing,
5861 * +false+ otherwise.
5862 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5863 *
5864 * IO.popen('ruby', 'r+') do |pipe|
5865 * puts pipe.closed?
5866 * pipe.close_read
5867 * puts pipe.closed?
5868 * pipe.close_write
5869 * puts pipe.closed?
5870 * end
5871 *
5872 * Output:
5873 *
5874 * false
5875 * false
5876 * true
5877 *
5878 * Related: IO#close_read, IO#close_write, IO#close.
5879 */
5880VALUE
5882{
5883 rb_io_t *fptr;
5884 VALUE write_io;
5885 rb_io_t *write_fptr;
5886
5887 write_io = GetWriteIO(io);
5888 if (io != write_io) {
5889 write_fptr = RFILE(write_io)->fptr;
5890 if (write_fptr && 0 <= write_fptr->fd) {
5891 return Qfalse;
5892 }
5893 }
5894
5895 fptr = rb_io_get_fptr(io);
5896 return RBOOL(0 > fptr->fd);
5897}
5898
5899/*
5900 * call-seq:
5901 * close_read -> nil
5902 *
5903 * Closes the stream for reading if open for reading;
5904 * returns +nil+.
5905 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5906 *
5907 * If the stream was opened by IO.popen and is also closed for writing,
5908 * sets global variable <tt>$?</tt> (child exit status).
5909 *
5910 * Example:
5911 *
5912 * IO.popen('ruby', 'r+') do |pipe|
5913 * puts pipe.closed?
5914 * pipe.close_write
5915 * puts pipe.closed?
5916 * pipe.close_read
5917 * puts $?
5918 * puts pipe.closed?
5919 * end
5920 *
5921 * Output:
5922 *
5923 * false
5924 * false
5925 * pid 14748 exit 0
5926 * true
5927 *
5928 * Related: IO#close, IO#close_write, IO#closed?.
5929 */
5930
5931static VALUE
5932rb_io_close_read(VALUE io)
5933{
5934 rb_io_t *fptr;
5935 VALUE write_io;
5936
5937 fptr = rb_io_get_fptr(rb_io_taint_check(io));
5938 if (fptr->fd < 0) return Qnil;
5939 if (is_socket(fptr->fd, fptr->pathv)) {
5940#ifndef SHUT_RD
5941# define SHUT_RD 0
5942#endif
5943 if (shutdown(fptr->fd, SHUT_RD) < 0)
5944 rb_sys_fail_path(fptr->pathv);
5945 fptr->mode &= ~FMODE_READABLE;
5946 if (!(fptr->mode & FMODE_WRITABLE))
5947 return rb_io_close(io);
5948 return Qnil;
5949 }
5950
5951 write_io = GetWriteIO(io);
5952 if (io != write_io) {
5953 rb_io_t *wfptr;
5954 wfptr = rb_io_get_fptr(rb_io_taint_check(write_io));
5955 wfptr->pid = fptr->pid;
5956 fptr->pid = 0;
5957 RFILE(io)->fptr = wfptr;
5958 /* bind to write_io temporarily to get rid of memory/fd leak */
5959 fptr->tied_io_for_writing = 0;
5960 RFILE(write_io)->fptr = fptr;
5961 rb_io_fptr_cleanup(fptr, FALSE);
5962 /* should not finalize fptr because another thread may be reading it */
5963 return Qnil;
5964 }
5965
5966 if ((fptr->mode & (FMODE_DUPLEX|FMODE_WRITABLE)) == FMODE_WRITABLE) {
5967 rb_raise(rb_eIOError, "closing non-duplex IO for reading");
5968 }
5969 return rb_io_close(io);
5970}
5971
5972/*
5973 * call-seq:
5974 * close_write -> nil
5975 *
5976 * Closes the stream for writing if open for writing;
5977 * returns +nil+.
5978 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5979 *
5980 * Flushes any buffered writes to the operating system before closing.
5981 *
5982 * If the stream was opened by IO.popen and is also closed for reading,
5983 * sets global variable <tt>$?</tt> (child exit status).
5984 *
5985 * IO.popen('ruby', 'r+') do |pipe|
5986 * puts pipe.closed?
5987 * pipe.close_read
5988 * puts pipe.closed?
5989 * pipe.close_write
5990 * puts $?
5991 * puts pipe.closed?
5992 * end
5993 *
5994 * Output:
5995 *
5996 * false
5997 * false
5998 * pid 15044 exit 0
5999 * true
6000 *
6001 * Related: IO#close, IO#close_read, IO#closed?.
6002 */
6003
6004static VALUE
6005rb_io_close_write(VALUE io)
6006{
6007 rb_io_t *fptr;
6008 VALUE write_io;
6009
6010 write_io = GetWriteIO(io);
6011 fptr = rb_io_get_fptr(rb_io_taint_check(write_io));
6012 if (fptr->fd < 0) return Qnil;
6013 if (is_socket(fptr->fd, fptr->pathv)) {
6014#ifndef SHUT_WR
6015# define SHUT_WR 1
6016#endif
6017 if (shutdown(fptr->fd, SHUT_WR) < 0)
6018 rb_sys_fail_path(fptr->pathv);
6019 fptr->mode &= ~FMODE_WRITABLE;
6020 if (!(fptr->mode & FMODE_READABLE))
6021 return rb_io_close(write_io);
6022 return Qnil;
6023 }
6024
6025 if ((fptr->mode & (FMODE_DUPLEX|FMODE_READABLE)) == FMODE_READABLE) {
6026 rb_raise(rb_eIOError, "closing non-duplex IO for writing");
6027 }
6028
6029 if (io != write_io) {
6030 fptr = rb_io_get_fptr(rb_io_taint_check(io));
6031 fptr->tied_io_for_writing = 0;
6032 }
6033 rb_io_close(write_io);
6034 return Qnil;
6035}
6036
6037/*
6038 * call-seq:
6039 * sysseek(offset, whence = IO::SEEK_SET) -> integer
6040 *
6041 * Behaves like IO#seek, except that it:
6042 *
6043 * - Uses low-level system functions.
6044 * - Returns the new position.
6045 *
6046 */
6047
6048static VALUE
6049rb_io_sysseek(int argc, VALUE *argv, VALUE io)
6050{
6051 VALUE offset, ptrname;
6052 int whence = SEEK_SET;
6053 rb_io_t *fptr;
6054 rb_off_t pos;
6055
6056 if (rb_scan_args(argc, argv, "11", &offset, &ptrname) == 2) {
6057 whence = interpret_seek_whence(ptrname);
6058 }
6059 pos = NUM2OFFT(offset);
6060 GetOpenFile(io, fptr);
6061 if ((fptr->mode & FMODE_READABLE) &&
6062 (READ_DATA_BUFFERED(fptr) || READ_CHAR_PENDING(fptr))) {
6063 rb_raise(rb_eIOError, "sysseek for buffered IO");
6064 }
6065 if ((fptr->mode & FMODE_WRITABLE) && fptr->wbuf.len) {
6066 rb_warn("sysseek for buffered IO");
6067 }
6068 errno = 0;
6069 pos = lseek(fptr->fd, pos, whence);
6070 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
6071
6072 return OFFT2NUM(pos);
6073}
6074
6075/*
6076 * call-seq:
6077 * syswrite(object) -> integer
6078 *
6079 * Writes the given +object+ to self, which must be opened for writing (see Modes);
6080 * returns the number bytes written.
6081 * If +object+ is not a string is converted via method to_s:
6082 *
6083 * f = File.new('t.tmp', 'w')
6084 * f.syswrite('foo') # => 3
6085 * f.syswrite(30) # => 2
6086 * f.syswrite(:foo) # => 3
6087 * f.close
6088 *
6089 * This methods should not be used with other stream-writer methods.
6090 *
6091 */
6092
6093static VALUE
6094rb_io_syswrite(VALUE io, VALUE str)
6095{
6096 VALUE tmp;
6097 rb_io_t *fptr;
6098 long n, len;
6099 const char *ptr;
6100
6101 if (!RB_TYPE_P(str, T_STRING))
6102 str = rb_obj_as_string(str);
6103
6104 io = GetWriteIO(io);
6105 GetOpenFile(io, fptr);
6107
6108 if (fptr->wbuf.len) {
6109 rb_warn("syswrite for buffered IO");
6110 }
6111
6112 tmp = rb_str_tmp_frozen_acquire(str);
6113 RSTRING_GETMEM(tmp, ptr, len);
6114 n = rb_io_write_memory(fptr, ptr, len);
6115 if (n < 0) rb_sys_fail_path(fptr->pathv);
6116 rb_str_tmp_frozen_release(str, tmp);
6117
6118 return LONG2FIX(n);
6119}
6120
6121/*
6122 * call-seq:
6123 * sysread(maxlen) -> string
6124 * sysread(maxlen, out_string) -> string
6125 *
6126 * Behaves like IO#readpartial, except that it uses low-level system functions.
6127 *
6128 * This method should not be used with other stream-reader methods.
6129 *
6130 */
6131
6132static VALUE
6133rb_io_sysread(int argc, VALUE *argv, VALUE io)
6134{
6135 VALUE len, str;
6136 rb_io_t *fptr;
6137 long n, ilen;
6138 struct io_internal_read_struct iis;
6139 int shrinkable;
6140
6141 rb_scan_args(argc, argv, "11", &len, &str);
6142 ilen = NUM2LONG(len);
6143
6144 shrinkable = io_setstrbuf(&str, ilen);
6145 if (ilen == 0) return str;
6146
6147 GetOpenFile(io, fptr);
6149
6150 if (READ_DATA_BUFFERED(fptr)) {
6151 rb_raise(rb_eIOError, "sysread for buffered IO");
6152 }
6153
6154 rb_io_check_closed(fptr);
6155
6156 io_setstrbuf(&str, ilen);
6157 iis.th = rb_thread_current();
6158 iis.fptr = fptr;
6159 iis.nonblock = 0;
6160 iis.fd = fptr->fd;
6161 iis.buf = RSTRING_PTR(str);
6162 iis.capa = ilen;
6163 iis.timeout = NULL;
6164 n = io_read_memory_locktmp(str, &iis);
6165
6166 if (n < 0) {
6167 rb_sys_fail_path(fptr->pathv);
6168 }
6169
6170 io_set_read_length(str, n, shrinkable);
6171
6172 if (n == 0 && ilen > 0) {
6173 rb_eof_error();
6174 }
6175
6176 return str;
6177}
6178
6180 struct rb_io *io;
6181 int fd;
6182 void *buf;
6183 size_t count;
6184 rb_off_t offset;
6185};
6186
6187static VALUE
6188internal_pread_func(void *_arg)
6189{
6190 struct prdwr_internal_arg *arg = _arg;
6191
6192 return (VALUE)pread(arg->fd, arg->buf, arg->count, arg->offset);
6193}
6194
6195static VALUE
6196pread_internal_call(VALUE _arg)
6197{
6198 struct prdwr_internal_arg *arg = (struct prdwr_internal_arg *)_arg;
6199
6200 VALUE scheduler = rb_fiber_scheduler_current();
6201 if (scheduler != Qnil) {
6202 VALUE result = rb_fiber_scheduler_io_pread_memory(scheduler, arg->io->self, arg->offset, arg->buf, arg->count, 0);
6203
6204 if (!UNDEF_P(result)) {
6206 }
6207 }
6208
6209 return rb_io_blocking_region_wait(arg->io, internal_pread_func, arg, RUBY_IO_READABLE);
6210}
6211
6212/*
6213 * call-seq:
6214 * pread(maxlen, offset) -> string
6215 * pread(maxlen, offset, out_string) -> string
6216 *
6217 * Behaves like IO#readpartial, except that it:
6218 *
6219 * - Reads at the given +offset+ (in bytes).
6220 * - Disregards, and does not modify, the stream's position
6221 * (see {Position}[rdoc-ref:IO@Position]).
6222 * - Bypasses any user space buffering in the stream.
6223 *
6224 * Because this method does not disturb the stream's state
6225 * (its position, in particular), +pread+ allows multiple threads and processes
6226 * to use the same \IO object for reading at various offsets.
6227 *
6228 * f = File.open('t.txt')
6229 * f.read # => "First line\nSecond line\n\nFourth line\nFifth line\n"
6230 * f.pos # => 52
6231 * # Read 12 bytes at offset 0.
6232 * f.pread(12, 0) # => "First line\n"
6233 * # Read 9 bytes at offset 8.
6234 * f.pread(9, 8) # => "ne\nSecon"
6235 * f.close
6236 *
6237 * Not available on some platforms.
6238 *
6239 */
6240static VALUE
6241rb_io_pread(int argc, VALUE *argv, VALUE io)
6242{
6243 VALUE len, offset, str;
6244 rb_io_t *fptr;
6245 ssize_t n;
6246 struct prdwr_internal_arg arg;
6247 int shrinkable;
6248
6249 rb_scan_args(argc, argv, "21", &len, &offset, &str);
6250 arg.count = NUM2SIZET(len);
6251 arg.offset = NUM2OFFT(offset);
6252
6253 shrinkable = io_setstrbuf(&str, (long)arg.count);
6254 if (arg.count == 0) return str;
6255 arg.buf = RSTRING_PTR(str);
6256
6257 GetOpenFile(io, fptr);
6259
6260 arg.io = fptr;
6261 arg.fd = fptr->fd;
6262 rb_io_check_closed(fptr);
6263
6264 rb_str_locktmp(str);
6265 n = (ssize_t)rb_ensure(pread_internal_call, (VALUE)&arg, rb_str_unlocktmp, str);
6266
6267 if (n < 0) {
6268 rb_sys_fail_path(fptr->pathv);
6269 }
6270 io_set_read_length(str, n, shrinkable);
6271 if (n == 0 && arg.count > 0) {
6272 rb_eof_error();
6273 }
6274
6275 return str;
6276}
6277
6278static VALUE
6279internal_pwrite_func(void *_arg)
6280{
6281 struct prdwr_internal_arg *arg = _arg;
6282
6283 return (VALUE)pwrite(arg->fd, arg->buf, arg->count, arg->offset);
6284}
6285
6286static VALUE
6287pwrite_internal_call(VALUE _arg)
6288{
6289 struct prdwr_internal_arg *arg = (struct prdwr_internal_arg *)_arg;
6290
6291 VALUE scheduler = rb_fiber_scheduler_current();
6292 if (scheduler != Qnil) {
6293 VALUE result = rb_fiber_scheduler_io_pwrite_memory(scheduler, arg->io->self, arg->offset, arg->buf, arg->count, 0);
6294
6295 if (!UNDEF_P(result)) {
6297 }
6298 }
6299
6300 return rb_io_blocking_region_wait(arg->io, internal_pwrite_func, arg, RUBY_IO_WRITABLE);
6301}
6302
6303/*
6304 * call-seq:
6305 * pwrite(object, offset) -> integer
6306 *
6307 * Behaves like IO#write, except that it:
6308 *
6309 * - Writes at the given +offset+ (in bytes).
6310 * - Disregards, and does not modify, the stream's position
6311 * (see {Position}[rdoc-ref:IO@Position]).
6312 * - Bypasses any user space buffering in the stream.
6313 *
6314 * Because this method does not disturb the stream's state
6315 * (its position, in particular), +pwrite+ allows multiple threads and processes
6316 * to use the same \IO object for writing at various offsets.
6317 *
6318 * f = File.open('t.tmp', 'w+')
6319 * # Write 6 bytes at offset 3.
6320 * f.pwrite('ABCDEF', 3) # => 6
6321 * f.rewind
6322 * f.read # => "\u0000\u0000\u0000ABCDEF"
6323 * f.close
6324 *
6325 * Not available on some platforms.
6326 *
6327 */
6328static VALUE
6329rb_io_pwrite(VALUE io, VALUE str, VALUE offset)
6330{
6331 rb_io_t *fptr;
6332 ssize_t n;
6333 struct prdwr_internal_arg arg;
6334 VALUE tmp;
6335
6336 if (!RB_TYPE_P(str, T_STRING))
6337 str = rb_obj_as_string(str);
6338
6339 arg.offset = NUM2OFFT(offset);
6340
6341 io = GetWriteIO(io);
6342 GetOpenFile(io, fptr);
6344
6345 arg.io = fptr;
6346 arg.fd = fptr->fd;
6347
6348 tmp = rb_str_tmp_frozen_acquire(str);
6349 arg.buf = RSTRING_PTR(tmp);
6350 arg.count = (size_t)RSTRING_LEN(tmp);
6351
6352 n = (ssize_t)pwrite_internal_call((VALUE)&arg);
6353 if (n < 0) rb_sys_fail_path(fptr->pathv);
6354 rb_str_tmp_frozen_release(str, tmp);
6355
6356 return SSIZET2NUM(n);
6357}
6358
6359VALUE
6361{
6362 rb_io_t *fptr;
6363
6364 GetOpenFile(io, fptr);
6365 if (fptr->readconv)
6367 if (fptr->writeconv)
6369 fptr->mode |= FMODE_BINMODE;
6370 fptr->mode &= ~FMODE_TEXTMODE;
6371 fptr->writeconv_pre_ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
6372#ifdef O_BINARY
6373 if (!fptr->readconv) {
6374 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6375 }
6376 else {
6377 setmode(fptr->fd, O_BINARY);
6378 }
6379#endif
6380 return io;
6381}
6382
6383static void
6384io_ascii8bit_binmode(rb_io_t *fptr)
6385{
6386 if (fptr->readconv) {
6387 rb_econv_close(fptr->readconv);
6388 fptr->readconv = NULL;
6389 }
6390 if (fptr->writeconv) {
6392 fptr->writeconv = NULL;
6393 }
6394 fptr->mode |= FMODE_BINMODE;
6395 fptr->mode &= ~FMODE_TEXTMODE;
6396 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6397
6398 fptr->encs.enc = rb_ascii8bit_encoding();
6399 fptr->encs.enc2 = NULL;
6400 fptr->encs.ecflags = 0;
6401 fptr->encs.ecopts = Qnil;
6402 clear_codeconv(fptr);
6403}
6404
6405VALUE
6407{
6408 rb_io_t *fptr;
6409
6410 GetOpenFile(io, fptr);
6411 io_ascii8bit_binmode(fptr);
6412
6413 return io;
6414}
6415
6416/*
6417 * call-seq:
6418 * binmode -> self
6419 *
6420 * Sets the stream's data mode as binary
6421 * (see {Data Mode}[rdoc-ref:File@Data+Mode]).
6422 *
6423 * A stream's data mode may not be changed from binary to text.
6424 *
6425 */
6426
6427static VALUE
6428rb_io_binmode_m(VALUE io)
6429{
6430 VALUE write_io;
6431
6433
6434 write_io = GetWriteIO(io);
6435 if (write_io != io)
6436 rb_io_ascii8bit_binmode(write_io);
6437 return io;
6438}
6439
6440/*
6441 * call-seq:
6442 * binmode? -> true or false
6443 *
6444 * Returns +true+ if the stream is on binary mode, +false+ otherwise.
6445 * See {Data Mode}[rdoc-ref:File@Data+Mode].
6446 *
6447 */
6448static VALUE
6449rb_io_binmode_p(VALUE io)
6450{
6451 rb_io_t *fptr;
6452 GetOpenFile(io, fptr);
6453 return RBOOL(fptr->mode & FMODE_BINMODE);
6454}
6455
6456static const char*
6457rb_io_fmode_modestr(enum rb_io_mode fmode)
6458{
6459 if (fmode & FMODE_APPEND) {
6460 if ((fmode & FMODE_READWRITE) == FMODE_READWRITE) {
6461 return MODE_BTMODE("a+", "ab+", "at+");
6462 }
6463 return MODE_BTMODE("a", "ab", "at");
6464 }
6465 switch (fmode & FMODE_READWRITE) {
6466 default:
6467 rb_raise(rb_eArgError, "invalid access fmode 0x%x", fmode);
6468 case FMODE_READABLE:
6469 return MODE_BTMODE("r", "rb", "rt");
6470 case FMODE_WRITABLE:
6471 return MODE_BTXMODE("w", "wb", "wt", "wx", "wbx", "wtx");
6472 case FMODE_READWRITE:
6473 if (fmode & FMODE_CREATE) {
6474 return MODE_BTXMODE("w+", "wb+", "wt+", "w+x", "wb+x", "wt+x");
6475 }
6476 return MODE_BTMODE("r+", "rb+", "rt+");
6477 }
6478}
6479
6480static const char bom_prefix[] = "bom|";
6481static const char utf_prefix[] = "utf-";
6482enum {bom_prefix_len = (int)sizeof(bom_prefix) - 1};
6483enum {utf_prefix_len = (int)sizeof(utf_prefix) - 1};
6484
6485static int
6486io_encname_bom_p(const char *name, long len)
6487{
6488 return len > bom_prefix_len && STRNCASECMP(name, bom_prefix, bom_prefix_len) == 0;
6489}
6490
6491enum rb_io_mode
6492rb_io_modestr_fmode(const char *modestr)
6493{
6494 enum rb_io_mode fmode = 0;
6495 const char *m = modestr, *p = NULL;
6496
6497 switch (*m++) {
6498 case 'r':
6499 fmode |= FMODE_READABLE;
6500 break;
6501 case 'w':
6503 break;
6504 case 'a':
6506 break;
6507 default:
6508 goto error;
6509 }
6510
6511 while (*m) {
6512 switch (*m++) {
6513 case 'b':
6514 fmode |= FMODE_BINMODE;
6515 break;
6516 case 't':
6517 fmode |= FMODE_TEXTMODE;
6518 break;
6519 case '+':
6520 fmode |= FMODE_READWRITE;
6521 break;
6522 case 'x':
6523 if (modestr[0] != 'w')
6524 goto error;
6525 fmode |= FMODE_EXCL;
6526 break;
6527 default:
6528 goto error;
6529 case ':':
6530 p = strchr(m, ':');
6531 if (io_encname_bom_p(m, p ? (long)(p - m) : (long)strlen(m)))
6532 fmode |= FMODE_SETENC_BY_BOM;
6533 goto finished;
6534 }
6535 }
6536
6537 finished:
6538 if ((fmode & FMODE_BINMODE) && (fmode & FMODE_TEXTMODE))
6539 goto error;
6540
6541 return fmode;
6542
6543 error:
6544 rb_raise(rb_eArgError, "invalid access mode %s", modestr);
6546}
6547
6548int
6549rb_io_oflags_fmode(int oflags)
6550{
6551 enum rb_io_mode fmode = 0;
6552
6553 switch (oflags & O_ACCMODE) {
6554 case O_RDONLY:
6555 fmode = FMODE_READABLE;
6556 break;
6557 case O_WRONLY:
6558 fmode = FMODE_WRITABLE;
6559 break;
6560 case O_RDWR:
6561 fmode = FMODE_READWRITE;
6562 break;
6563 }
6564
6565 if (oflags & O_APPEND) {
6566 fmode |= FMODE_APPEND;
6567 }
6568 if (oflags & O_TRUNC) {
6569 fmode |= FMODE_TRUNC;
6570 }
6571 if (oflags & O_CREAT) {
6572 fmode |= FMODE_CREATE;
6573 }
6574 if (oflags & O_EXCL) {
6575 fmode |= FMODE_EXCL;
6576 }
6577#ifdef O_BINARY
6578 if (oflags & O_BINARY) {
6579 fmode |= FMODE_BINMODE;
6580 }
6581#endif
6582
6583 return fmode;
6584}
6585
6586static int
6587rb_io_fmode_oflags(enum rb_io_mode fmode)
6588{
6589 int oflags = 0;
6590
6591 switch (fmode & FMODE_READWRITE) {
6592 case FMODE_READABLE:
6593 oflags |= O_RDONLY;
6594 break;
6595 case FMODE_WRITABLE:
6596 oflags |= O_WRONLY;
6597 break;
6598 case FMODE_READWRITE:
6599 oflags |= O_RDWR;
6600 break;
6601 }
6602
6603 if (fmode & FMODE_APPEND) {
6604 oflags |= O_APPEND;
6605 }
6606 if (fmode & FMODE_TRUNC) {
6607 oflags |= O_TRUNC;
6608 }
6609 if (fmode & FMODE_CREATE) {
6610 oflags |= O_CREAT;
6611 }
6612 if (fmode & FMODE_EXCL) {
6613 oflags |= O_EXCL;
6614 }
6615#ifdef O_BINARY
6616 if (fmode & FMODE_BINMODE) {
6617 oflags |= O_BINARY;
6618 }
6619#endif
6620
6621 return oflags;
6622}
6623
6624int
6625rb_io_modestr_oflags(const char *modestr)
6626{
6627 return rb_io_fmode_oflags(rb_io_modestr_fmode(modestr));
6628}
6629
6630static const char*
6631rb_io_oflags_modestr(int oflags)
6632{
6633#ifdef O_BINARY
6634# define MODE_BINARY(a,b) ((oflags & O_BINARY) ? (b) : (a))
6635#else
6636# define MODE_BINARY(a,b) (a)
6637#endif
6638 int accmode;
6639 if (oflags & O_EXCL) {
6640 rb_raise(rb_eArgError, "exclusive access mode is not supported");
6641 }
6642 accmode = oflags & (O_RDONLY|O_WRONLY|O_RDWR);
6643 if (oflags & O_APPEND) {
6644 if (accmode == O_WRONLY) {
6645 return MODE_BINARY("a", "ab");
6646 }
6647 if (accmode == O_RDWR) {
6648 return MODE_BINARY("a+", "ab+");
6649 }
6650 }
6651 switch (accmode) {
6652 default:
6653 rb_raise(rb_eArgError, "invalid access oflags 0x%x", oflags);
6654 case O_RDONLY:
6655 return MODE_BINARY("r", "rb");
6656 case O_WRONLY:
6657 return MODE_BINARY("w", "wb");
6658 case O_RDWR:
6659 if (oflags & O_TRUNC) {
6660 return MODE_BINARY("w+", "wb+");
6661 }
6662 return MODE_BINARY("r+", "rb+");
6663 }
6664}
6665
6666/*
6667 * Convert external/internal encodings to enc/enc2
6668 * NULL => use default encoding
6669 * Qnil => no encoding specified (internal only)
6670 */
6671static void
6672rb_io_ext_int_to_encs(rb_encoding *ext, rb_encoding *intern, rb_encoding **enc, rb_encoding **enc2, enum rb_io_mode fmode)
6673{
6674 int default_ext = 0;
6675
6676 if (ext == NULL) {
6677 ext = rb_default_external_encoding();
6678 default_ext = 1;
6679 }
6680 if (rb_is_ascii8bit_enc(ext)) {
6681 /* If external is ASCII-8BIT, no transcoding */
6682 intern = NULL;
6683 }
6684 else if (intern == NULL) {
6685 intern = rb_default_internal_encoding();
6686 }
6687 if (intern == NULL || intern == (rb_encoding *)Qnil ||
6688 (!(fmode & FMODE_SETENC_BY_BOM) && (intern == ext))) {
6689 /* No internal encoding => use external + no transcoding */
6690 *enc = (default_ext && intern != ext) ? NULL : ext;
6691 *enc2 = NULL;
6692 }
6693 else {
6694 *enc = intern;
6695 *enc2 = ext;
6696 }
6697}
6698
6699static void
6700unsupported_encoding(const char *name, rb_encoding *enc)
6701{
6702 rb_enc_warn(enc, "Unsupported encoding %s ignored", name);
6703}
6704
6705static void
6706parse_mode_enc(const char *estr, rb_encoding *estr_enc,
6707 rb_encoding **enc_p, rb_encoding **enc2_p, enum rb_io_mode *fmode_p)
6708{
6709 const char *p;
6710 char encname[ENCODING_MAXNAMELEN+1];
6711 int idx, idx2;
6712 enum rb_io_mode fmode = fmode_p ? *fmode_p : 0;
6713 rb_encoding *ext_enc, *int_enc;
6714 long len;
6715
6716 /* parse estr as "enc" or "enc2:enc" or "enc:-" */
6717
6718 p = strrchr(estr, ':');
6719 len = p ? (p++ - estr) : (long)strlen(estr);
6720 if ((fmode & FMODE_SETENC_BY_BOM) || io_encname_bom_p(estr, len)) {
6721 estr += bom_prefix_len;
6722 len -= bom_prefix_len;
6723 if (!STRNCASECMP(estr, utf_prefix, utf_prefix_len)) {
6724 fmode |= FMODE_SETENC_BY_BOM;
6725 }
6726 else {
6727 rb_enc_warn(estr_enc, "BOM with non-UTF encoding %s is nonsense", estr);
6728 fmode &= ~FMODE_SETENC_BY_BOM;
6729 }
6730 }
6731 if (len == 0 || len > ENCODING_MAXNAMELEN) {
6732 idx = -1;
6733 }
6734 else {
6735 if (p) {
6736 memcpy(encname, estr, len);
6737 encname[len] = '\0';
6738 estr = encname;
6739 }
6740 idx = rb_enc_find_index(estr);
6741 }
6742 if (fmode_p) *fmode_p = fmode;
6743
6744 if (idx >= 0)
6745 ext_enc = rb_enc_from_index(idx);
6746 else {
6747 if (idx != -2)
6748 unsupported_encoding(estr, estr_enc);
6749 ext_enc = NULL;
6750 }
6751
6752 int_enc = NULL;
6753 if (p) {
6754 if (*p == '-' && *(p+1) == '\0') {
6755 /* Special case - "-" => no transcoding */
6756 int_enc = (rb_encoding *)Qnil;
6757 }
6758 else {
6759 idx2 = rb_enc_find_index(p);
6760 if (idx2 < 0)
6761 unsupported_encoding(p, estr_enc);
6762 else if (!(fmode & FMODE_SETENC_BY_BOM) && (idx2 == idx)) {
6763 int_enc = (rb_encoding *)Qnil;
6764 }
6765 else
6766 int_enc = rb_enc_from_index(idx2);
6767 }
6768 }
6769
6770 rb_io_ext_int_to_encs(ext_enc, int_enc, enc_p, enc2_p, fmode);
6771}
6772
6773int
6774rb_io_extract_encoding_option(VALUE opt, rb_encoding **enc_p, rb_encoding **enc2_p, enum rb_io_mode *fmode_p)
6775{
6776 VALUE encoding=Qnil, extenc=Qundef, intenc=Qundef, tmp;
6777 int extracted = 0;
6778 rb_encoding *extencoding = NULL;
6779 rb_encoding *intencoding = NULL;
6780
6781 if (!NIL_P(opt)) {
6782 VALUE v;
6783 v = rb_hash_lookup2(opt, sym_encoding, Qnil);
6784 if (v != Qnil) encoding = v;
6785 v = rb_hash_lookup2(opt, sym_extenc, Qundef);
6786 if (v != Qnil) extenc = v;
6787 v = rb_hash_lookup2(opt, sym_intenc, Qundef);
6788 if (!UNDEF_P(v)) intenc = v;
6789 }
6790 if ((!UNDEF_P(extenc) || !UNDEF_P(intenc)) && !NIL_P(encoding)) {
6791 if (!NIL_P(ruby_verbose)) {
6792 int idx = rb_to_encoding_index(encoding);
6793 if (idx >= 0) encoding = rb_enc_from_encoding(rb_enc_from_index(idx));
6794 rb_warn("Ignoring encoding parameter '%"PRIsVALUE"': %s_encoding is used",
6795 encoding, UNDEF_P(extenc) ? "internal" : "external");
6796 }
6797 encoding = Qnil;
6798 }
6799 if (!UNDEF_P(extenc) && !NIL_P(extenc)) {
6800 extencoding = rb_to_encoding(extenc);
6801 }
6802 if (!UNDEF_P(intenc)) {
6803 if (NIL_P(intenc)) {
6804 /* internal_encoding: nil => no transcoding */
6805 intencoding = (rb_encoding *)Qnil;
6806 }
6807 else if (!NIL_P(tmp = rb_check_string_type(intenc))) {
6808 char *p = StringValueCStr(tmp);
6809
6810 if (*p == '-' && *(p+1) == '\0') {
6811 /* Special case - "-" => no transcoding */
6812 intencoding = (rb_encoding *)Qnil;
6813 }
6814 else {
6815 intencoding = rb_to_encoding(intenc);
6816 }
6817 }
6818 else {
6819 intencoding = rb_to_encoding(intenc);
6820 }
6821 if (extencoding == intencoding) {
6822 intencoding = (rb_encoding *)Qnil;
6823 }
6824 }
6825 if (!NIL_P(encoding)) {
6826 extracted = 1;
6827 if (!NIL_P(tmp = rb_check_string_type(encoding))) {
6828 parse_mode_enc(StringValueCStr(tmp), rb_enc_get(tmp),
6829 enc_p, enc2_p, fmode_p);
6830 }
6831 else {
6832 rb_io_ext_int_to_encs(rb_to_encoding(encoding), NULL, enc_p, enc2_p, 0);
6833 }
6834 }
6835 else if (!UNDEF_P(extenc) || !UNDEF_P(intenc)) {
6836 extracted = 1;
6837 rb_io_ext_int_to_encs(extencoding, intencoding, enc_p, enc2_p, 0);
6838 }
6839 return extracted;
6840}
6841
6842static void
6843validate_enc_binmode(enum rb_io_mode *fmode_p, int ecflags, rb_encoding *enc, rb_encoding *enc2)
6844{
6845 enum rb_io_mode fmode = *fmode_p;
6846
6847 if ((fmode & FMODE_READABLE) &&
6848 !enc2 &&
6849 !(fmode & FMODE_BINMODE) &&
6850 !rb_enc_asciicompat(enc ? enc : rb_default_external_encoding()))
6851 rb_raise(rb_eArgError, "ASCII incompatible encoding needs binmode");
6852
6853 if ((fmode & FMODE_BINMODE) && (ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
6854 rb_raise(rb_eArgError, "newline decorator with binary mode");
6855 }
6856 if (!(fmode & FMODE_BINMODE) &&
6857 (DEFAULT_TEXTMODE || (ecflags & ECONV_NEWLINE_DECORATOR_MASK))) {
6858 fmode |= FMODE_TEXTMODE;
6859 *fmode_p = fmode;
6860 }
6861#if !DEFAULT_TEXTMODE
6862 else if (!(ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
6863 fmode &= ~FMODE_TEXTMODE;
6864 *fmode_p = fmode;
6865 }
6866#endif
6867}
6868
6869static void
6870extract_binmode(VALUE opthash, enum rb_io_mode *fmode)
6871{
6872 if (!NIL_P(opthash)) {
6873 VALUE v;
6874 v = rb_hash_aref(opthash, sym_textmode);
6875 if (!NIL_P(v)) {
6876 if (*fmode & FMODE_TEXTMODE)
6877 rb_raise(rb_eArgError, "textmode specified twice");
6878 if (*fmode & FMODE_BINMODE)
6879 rb_raise(rb_eArgError, "both textmode and binmode specified");
6880 if (RTEST(v))
6881 *fmode |= FMODE_TEXTMODE;
6882 }
6883 v = rb_hash_aref(opthash, sym_binmode);
6884 if (!NIL_P(v)) {
6885 if (*fmode & FMODE_BINMODE)
6886 rb_raise(rb_eArgError, "binmode specified twice");
6887 if (*fmode & FMODE_TEXTMODE)
6888 rb_raise(rb_eArgError, "both textmode and binmode specified");
6889 if (RTEST(v))
6890 *fmode |= FMODE_BINMODE;
6891 }
6892
6893 if ((*fmode & FMODE_BINMODE) && (*fmode & FMODE_TEXTMODE))
6894 rb_raise(rb_eArgError, "both textmode and binmode specified");
6895 }
6896}
6897
6898void
6899rb_io_extract_modeenc(VALUE *vmode_p, VALUE *vperm_p, VALUE opthash,
6900 int *oflags_p, enum rb_io_mode *fmode_p, struct rb_io_encoding *convconfig_p)
6901{
6902 VALUE vmode;
6903 int oflags;
6904 enum rb_io_mode fmode;
6905 rb_encoding *enc, *enc2;
6906 int ecflags;
6907 VALUE ecopts;
6908 int has_enc = 0, has_vmode = 0;
6909 VALUE intmode;
6910
6911 vmode = *vmode_p;
6912
6913 /* Set to defaults */
6914 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
6915
6916 vmode_handle:
6917 if (NIL_P(vmode)) {
6918 fmode = FMODE_READABLE;
6919 oflags = O_RDONLY;
6920 }
6921 else if (!NIL_P(intmode = rb_check_to_integer(vmode, "to_int"))) {
6922 vmode = intmode;
6923 oflags = NUM2INT(intmode);
6924 fmode = rb_io_oflags_fmode(oflags);
6925 }
6926 else {
6927 const char *p;
6928
6929 StringValue(vmode);
6930 p = StringValueCStr(vmode);
6931 fmode = rb_io_modestr_fmode(p);
6932 oflags = rb_io_fmode_oflags(fmode);
6933 p = strchr(p, ':');
6934 if (p) {
6935 has_enc = 1;
6936 parse_mode_enc(p+1, rb_enc_get(vmode), &enc, &enc2, &fmode);
6937 }
6938 else {
6939 rb_encoding *e;
6940
6941 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
6942 rb_io_ext_int_to_encs(e, NULL, &enc, &enc2, fmode);
6943 }
6944 }
6945
6946 if (NIL_P(opthash)) {
6947 ecflags = (fmode & FMODE_READABLE) ?
6950#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
6951 ecflags |= (fmode & FMODE_WRITABLE) ?
6952 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
6953 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
6954#endif
6955 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
6956 ecopts = Qnil;
6957 if (fmode & FMODE_BINMODE) {
6958#ifdef O_BINARY
6959 oflags |= O_BINARY;
6960#endif
6961 if (!has_enc)
6962 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
6963 }
6964#if DEFAULT_TEXTMODE
6965 else if (NIL_P(vmode)) {
6966 fmode |= DEFAULT_TEXTMODE;
6967 }
6968#endif
6969 }
6970 else {
6971 VALUE v;
6972 if (!has_vmode) {
6973 v = rb_hash_aref(opthash, sym_mode);
6974 if (!NIL_P(v)) {
6975 if (!NIL_P(vmode)) {
6976 rb_raise(rb_eArgError, "mode specified twice");
6977 }
6978 has_vmode = 1;
6979 vmode = v;
6980 goto vmode_handle;
6981 }
6982 }
6983 v = rb_hash_aref(opthash, sym_flags);
6984 if (!NIL_P(v)) {
6985 v = rb_to_int(v);
6986 oflags |= NUM2INT(v);
6987 vmode = INT2NUM(oflags);
6988 fmode = rb_io_oflags_fmode(oflags);
6989 }
6990 extract_binmode(opthash, &fmode);
6991 if (fmode & FMODE_BINMODE) {
6992#ifdef O_BINARY
6993 oflags |= O_BINARY;
6994#endif
6995 if (!has_enc)
6996 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
6997 }
6998#if DEFAULT_TEXTMODE
6999 else if (NIL_P(vmode)) {
7000 fmode |= DEFAULT_TEXTMODE;
7001 }
7002#endif
7003 v = rb_hash_aref(opthash, sym_perm);
7004 if (!NIL_P(v)) {
7005 if (vperm_p) {
7006 if (!NIL_P(*vperm_p)) {
7007 rb_raise(rb_eArgError, "perm specified twice");
7008 }
7009 *vperm_p = v;
7010 }
7011 else {
7012 /* perm no use, just ignore */
7013 }
7014 }
7015 ecflags = (fmode & FMODE_READABLE) ?
7018#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7019 ecflags |= (fmode & FMODE_WRITABLE) ?
7020 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7021 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7022#endif
7023
7024 if (rb_io_extract_encoding_option(opthash, &enc, &enc2, &fmode)) {
7025 if (has_enc) {
7026 rb_raise(rb_eArgError, "encoding specified twice");
7027 }
7028 }
7029 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
7030 ecflags = rb_econv_prepare_options(opthash, &ecopts, ecflags);
7031 }
7032
7033 validate_enc_binmode(&fmode, ecflags, enc, enc2);
7034
7035 *vmode_p = vmode;
7036
7037 *oflags_p = oflags;
7038 *fmode_p = fmode;
7039 convconfig_p->enc = enc;
7040 convconfig_p->enc2 = enc2;
7041 convconfig_p->ecflags = ecflags;
7042 convconfig_p->ecopts = ecopts;
7043}
7044
7046 VALUE fname;
7047 int oflags;
7048 mode_t perm;
7049};
7050
7051static void *
7052sysopen_func(void *ptr)
7053{
7054 const struct sysopen_struct *data = ptr;
7055 const char *fname = RSTRING_PTR(data->fname);
7056 return (void *)(VALUE)rb_cloexec_open(fname, data->oflags, data->perm);
7057}
7058
7059static inline int
7060rb_sysopen_internal(struct sysopen_struct *data)
7061{
7062 int fd;
7063 do {
7064 fd = IO_WITHOUT_GVL_INT(sysopen_func, data);
7065 } while (fd < 0 && errno == EINTR);
7066 if (0 <= fd)
7067 rb_update_max_fd(fd);
7068 return fd;
7069}
7070
7071static int
7072rb_sysopen(VALUE fname, int oflags, mode_t perm)
7073{
7074 int fd = -1;
7075 struct sysopen_struct data;
7076
7077 data.fname = rb_str_encode_ospath(fname);
7078 StringValueCStr(data.fname);
7079 data.oflags = oflags;
7080 data.perm = perm;
7081
7082 TRY_WITH_GC((fd = rb_sysopen_internal(&data)) >= 0) {
7083 rb_syserr_fail_path(first_errno, fname);
7084 }
7085 return fd;
7086}
7087
7088static inline FILE *
7089fdopen_internal(int fd, const char *modestr)
7090{
7091 FILE *file;
7092
7093#if defined(__sun)
7094 errno = 0;
7095#endif
7096 file = fdopen(fd, modestr);
7097 if (!file) {
7098#ifdef _WIN32
7099 if (errno == 0) errno = EINVAL;
7100#elif defined(__sun)
7101 if (errno == 0) errno = EMFILE;
7102#endif
7103 }
7104 return file;
7105}
7106
7107FILE *
7108rb_fdopen(int fd, const char *modestr)
7109{
7110 FILE *file = 0;
7111
7112 TRY_WITH_GC((file = fdopen_internal(fd, modestr)) != 0) {
7113 rb_syserr_fail(first_errno, 0);
7114 }
7115
7116 /* xxx: should be _IONBF? A buffer in FILE may have trouble. */
7117#ifdef USE_SETVBUF
7118 if (setvbuf(file, NULL, _IOFBF, 0) != 0)
7119 rb_warn("setvbuf() can't be honoured (fd=%d)", fd);
7120#endif
7121 return file;
7122}
7123
7124static int
7125io_check_tty(rb_io_t *fptr)
7126{
7127 int t = isatty(fptr->fd);
7128 if (t)
7129 fptr->mode |= FMODE_TTY|FMODE_DUPLEX;
7130 return t;
7131}
7132
7133static VALUE rb_io_internal_encoding(VALUE);
7134static void io_encoding_set(rb_io_t *, VALUE, VALUE, VALUE);
7135
7136static int
7137io_strip_bom(VALUE io)
7138{
7139 VALUE b1, b2, b3, b4;
7140 rb_io_t *fptr;
7141
7142 GetOpenFile(io, fptr);
7143 if (!(fptr->mode & FMODE_READABLE)) return 0;
7144 if (NIL_P(b1 = rb_io_getbyte(io))) return 0;
7145 switch (b1) {
7146 case INT2FIX(0xEF):
7147 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7148 if (b2 == INT2FIX(0xBB) && !NIL_P(b3 = rb_io_getbyte(io))) {
7149 if (b3 == INT2FIX(0xBF)) {
7150 return rb_utf8_encindex();
7151 }
7152 rb_io_ungetbyte(io, b3);
7153 }
7154 rb_io_ungetbyte(io, b2);
7155 break;
7156
7157 case INT2FIX(0xFE):
7158 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7159 if (b2 == INT2FIX(0xFF)) {
7160 return ENCINDEX_UTF_16BE;
7161 }
7162 rb_io_ungetbyte(io, b2);
7163 break;
7164
7165 case INT2FIX(0xFF):
7166 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7167 if (b2 == INT2FIX(0xFE)) {
7168 b3 = rb_io_getbyte(io);
7169 if (b3 == INT2FIX(0) && !NIL_P(b4 = rb_io_getbyte(io))) {
7170 if (b4 == INT2FIX(0)) {
7171 return ENCINDEX_UTF_32LE;
7172 }
7173 rb_io_ungetbyte(io, b4);
7174 }
7175 rb_io_ungetbyte(io, b3);
7176 return ENCINDEX_UTF_16LE;
7177 }
7178 rb_io_ungetbyte(io, b2);
7179 break;
7180
7181 case INT2FIX(0):
7182 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7183 if (b2 == INT2FIX(0) && !NIL_P(b3 = rb_io_getbyte(io))) {
7184 if (b3 == INT2FIX(0xFE) && !NIL_P(b4 = rb_io_getbyte(io))) {
7185 if (b4 == INT2FIX(0xFF)) {
7186 return ENCINDEX_UTF_32BE;
7187 }
7188 rb_io_ungetbyte(io, b4);
7189 }
7190 rb_io_ungetbyte(io, b3);
7191 }
7192 rb_io_ungetbyte(io, b2);
7193 break;
7194 }
7195 rb_io_ungetbyte(io, b1);
7196 return 0;
7197}
7198
7199static rb_encoding *
7200io_set_encoding_by_bom(VALUE io)
7201{
7202 int idx = io_strip_bom(io);
7203 rb_io_t *fptr;
7204 rb_encoding *extenc = NULL;
7205
7206 GetOpenFile(io, fptr);
7207 if (idx) {
7208 extenc = rb_enc_from_index(idx);
7209 io_encoding_set(fptr, rb_enc_from_encoding(extenc),
7210 rb_io_internal_encoding(io), Qnil);
7211 }
7212 else {
7213 fptr->encs.enc2 = NULL;
7214 }
7215 return extenc;
7216}
7217
7218static VALUE
7219rb_file_open_generic(VALUE io, VALUE filename, int oflags, enum rb_io_mode fmode,
7220 const struct rb_io_encoding *convconfig, mode_t perm)
7221{
7222 VALUE pathv;
7223 rb_io_t *fptr;
7224 struct rb_io_encoding cc;
7225 if (!convconfig) {
7226 /* Set to default encodings */
7227 rb_io_ext_int_to_encs(NULL, NULL, &cc.enc, &cc.enc2, fmode);
7228 cc.ecflags = 0;
7229 cc.ecopts = Qnil;
7230 convconfig = &cc;
7231 }
7232 validate_enc_binmode(&fmode, convconfig->ecflags,
7233 convconfig->enc, convconfig->enc2);
7234
7235 MakeOpenFile(io, fptr);
7236 fptr->mode = fmode;
7237 fptr->encs = *convconfig;
7238 pathv = rb_str_new_frozen(filename);
7239#ifdef O_TMPFILE
7240 if (!(oflags & O_TMPFILE)) {
7241 fptr->pathv = pathv;
7242 }
7243#else
7244 fptr->pathv = pathv;
7245#endif
7246 fptr->fd = rb_sysopen(pathv, oflags, perm);
7247 io_check_tty(fptr);
7248 if (fmode & FMODE_SETENC_BY_BOM) io_set_encoding_by_bom(io);
7249
7250 return io;
7251}
7252
7253static VALUE
7254rb_file_open_internal(VALUE io, VALUE filename, const char *modestr)
7255{
7256 enum rb_io_mode fmode = rb_io_modestr_fmode(modestr);
7257 const char *p = strchr(modestr, ':');
7258 struct rb_io_encoding convconfig;
7259
7260 if (p) {
7261 parse_mode_enc(p+1, rb_usascii_encoding(),
7262 &convconfig.enc, &convconfig.enc2, &fmode);
7263 }
7264 else {
7265 rb_encoding *e;
7266 /* Set to default encodings */
7267
7268 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
7269 rb_io_ext_int_to_encs(e, NULL, &convconfig.enc, &convconfig.enc2, fmode);
7270 }
7271
7272 convconfig.ecflags = (fmode & FMODE_READABLE) ?
7275#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7276 convconfig.ecflags |= (fmode & FMODE_WRITABLE) ?
7277 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7278 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7279#endif
7280 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.enc2, convconfig.ecflags);
7281 convconfig.ecopts = Qnil;
7282
7283 return rb_file_open_generic(io, filename,
7284 rb_io_fmode_oflags(fmode),
7285 fmode,
7286 &convconfig,
7287 0666);
7288}
7289
7290VALUE
7291rb_file_open_str(VALUE fname, const char *modestr)
7292{
7293 FilePathValue(fname);
7294 return rb_file_open_internal(io_alloc(rb_cFile), fname, modestr);
7295}
7296
7297VALUE
7298rb_file_open(const char *fname, const char *modestr)
7299{
7300 return rb_file_open_internal(io_alloc(rb_cFile), rb_str_new_cstr(fname), modestr);
7301}
7302
7303#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7304static struct pipe_list {
7305 rb_io_t *fptr;
7306 struct pipe_list *next;
7307} *pipe_list;
7308
7309static void
7310pipe_add_fptr(rb_io_t *fptr)
7311{
7312 struct pipe_list *list;
7313
7314 list = ALLOC(struct pipe_list);
7315 list->fptr = fptr;
7316 list->next = pipe_list;
7317 pipe_list = list;
7318}
7319
7320static void
7321pipe_del_fptr(rb_io_t *fptr)
7322{
7323 struct pipe_list **prev = &pipe_list;
7324 struct pipe_list *tmp;
7325
7326 while ((tmp = *prev) != 0) {
7327 if (tmp->fptr == fptr) {
7328 *prev = tmp->next;
7329 free(tmp);
7330 return;
7331 }
7332 prev = &tmp->next;
7333 }
7334}
7335
7336#if defined (_WIN32) || defined(__CYGWIN__)
7337static void
7338pipe_atexit(void)
7339{
7340 struct pipe_list *list = pipe_list;
7341 struct pipe_list *tmp;
7342
7343 while (list) {
7344 tmp = list->next;
7345 rb_io_fptr_finalize(list->fptr);
7346 list = tmp;
7347 }
7348}
7349#endif
7350
7351static void
7352pipe_finalize(rb_io_t *fptr, int noraise)
7353{
7354#if !defined(HAVE_WORKING_FORK) && !defined(_WIN32)
7355 int status = 0;
7356 if (fptr->stdio_file) {
7357 status = pclose(fptr->stdio_file);
7358 }
7359 fptr->fd = -1;
7360 fptr->stdio_file = 0;
7361 rb_last_status_set(status, fptr->pid);
7362#else
7363 fptr_finalize(fptr, noraise);
7364#endif
7365 pipe_del_fptr(fptr);
7366}
7367#endif
7368
7369static void
7370fptr_copy_finalizer(rb_io_t *fptr, const rb_io_t *orig)
7371{
7372#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7373 void (*const old_finalize)(struct rb_io*,int) = fptr->finalize;
7374
7375 if (old_finalize == orig->finalize) return;
7376#endif
7377
7378 fptr->finalize = orig->finalize;
7379
7380#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7381 if (old_finalize != pipe_finalize) {
7382 struct pipe_list *list;
7383 for (list = pipe_list; list; list = list->next) {
7384 if (list->fptr == fptr) break;
7385 }
7386 if (!list) pipe_add_fptr(fptr);
7387 }
7388 else {
7389 pipe_del_fptr(fptr);
7390 }
7391#endif
7392}
7393
7394void
7396{
7398 fptr->mode |= FMODE_SYNC;
7399}
7400
7401void
7402rb_io_unbuffered(rb_io_t *fptr)
7403{
7404 rb_io_synchronized(fptr);
7405}
7406
7407int
7408rb_pipe(int *pipes)
7409{
7410 int ret;
7411 TRY_WITH_GC((ret = rb_cloexec_pipe(pipes)) >= 0);
7412 if (ret == 0) {
7413 rb_update_max_fd(pipes[0]);
7414 rb_update_max_fd(pipes[1]);
7415 }
7416 return ret;
7417}
7418
7419#ifdef _WIN32
7420#define HAVE_SPAWNV 1
7421#define spawnv(mode, cmd, args) rb_w32_uaspawn((mode), (cmd), (args))
7422#define spawn(mode, cmd) rb_w32_uspawn((mode), (cmd), 0)
7423#endif
7424
7425#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7426struct popen_arg {
7427 VALUE execarg_obj;
7428 struct rb_execarg *eargp;
7429 int modef;
7430 int pair[2];
7431 int write_pair[2];
7432};
7433#endif
7434
7435#ifdef HAVE_WORKING_FORK
7436# ifndef __EMSCRIPTEN__
7437static void
7438popen_redirect(struct popen_arg *p)
7439{
7440 if ((p->modef & FMODE_READABLE) && (p->modef & FMODE_WRITABLE)) {
7441 close(p->write_pair[1]);
7442 if (p->write_pair[0] != 0) {
7443 dup2(p->write_pair[0], 0);
7444 close(p->write_pair[0]);
7445 }
7446 close(p->pair[0]);
7447 if (p->pair[1] != 1) {
7448 dup2(p->pair[1], 1);
7449 close(p->pair[1]);
7450 }
7451 }
7452 else if (p->modef & FMODE_READABLE) {
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 {
7460 close(p->pair[1]);
7461 if (p->pair[0] != 0) {
7462 dup2(p->pair[0], 0);
7463 close(p->pair[0]);
7464 }
7465 }
7466}
7467# endif
7468
7469#if defined(__linux__)
7470/* Linux /proc/self/status contains a line: "FDSize:\t<nnn>\n"
7471 * Since /proc may not be available, linux_get_maxfd is just a hint.
7472 * This function, linux_get_maxfd, must be async-signal-safe.
7473 * I.e. opendir() is not usable.
7474 *
7475 * Note that memchr() and memcmp is *not* async-signal-safe in POSIX.
7476 * However they are easy to re-implement in async-signal-safe manner.
7477 * (Also note that there is missing/memcmp.c.)
7478 */
7479static int
7480linux_get_maxfd(void)
7481{
7482 int fd;
7483 char buf[4096], *p, *np, *e;
7484 ssize_t ss;
7485 fd = rb_cloexec_open("/proc/self/status", O_RDONLY|O_NOCTTY, 0);
7486 if (fd < 0) return fd;
7487 ss = read(fd, buf, sizeof(buf));
7488 if (ss < 0) goto err;
7489 p = buf;
7490 e = buf + ss;
7491 while ((int)sizeof("FDSize:\t0\n")-1 <= e-p &&
7492 (np = memchr(p, '\n', e-p)) != NULL) {
7493 if (memcmp(p, "FDSize:", sizeof("FDSize:")-1) == 0) {
7494 int fdsize;
7495 p += sizeof("FDSize:")-1;
7496 *np = '\0';
7497 fdsize = (int)ruby_strtoul(p, (char **)NULL, 10);
7498 close(fd);
7499 return fdsize;
7500 }
7501 p = np+1;
7502 }
7503 /* fall through */
7504
7505 err:
7506 close(fd);
7507 return (int)ss;
7508}
7509#endif
7510
7511/* This function should be async-signal-safe. */
7512void
7513rb_close_before_exec(int lowfd, int maxhint, VALUE noclose_fds)
7514{
7515#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
7516 int fd, ret;
7517 int max = (int)max_file_descriptor;
7518# ifdef F_MAXFD
7519 /* F_MAXFD is available since NetBSD 2.0. */
7520 ret = fcntl(0, F_MAXFD); /* async-signal-safe */
7521 if (ret != -1)
7522 maxhint = max = ret;
7523# elif defined(__linux__)
7524 ret = linux_get_maxfd();
7525 if (maxhint < ret)
7526 maxhint = ret;
7527 /* maxhint = max = ret; if (ret == -1) abort(); // test */
7528# endif
7529 if (max < maxhint)
7530 max = maxhint;
7531 for (fd = lowfd; fd <= max; fd++) {
7532 if (!NIL_P(noclose_fds) &&
7533 RTEST(rb_hash_lookup(noclose_fds, INT2FIX(fd)))) /* async-signal-safe */
7534 continue;
7535 ret = fcntl(fd, F_GETFD); /* async-signal-safe */
7536 if (ret != -1 && !(ret & FD_CLOEXEC)) {
7537 fcntl(fd, F_SETFD, ret|FD_CLOEXEC); /* async-signal-safe */
7538 }
7539# define CONTIGUOUS_CLOSED_FDS 20
7540 if (ret != -1) {
7541 if (max < fd + CONTIGUOUS_CLOSED_FDS)
7542 max = fd + CONTIGUOUS_CLOSED_FDS;
7543 }
7544 }
7545#endif
7546}
7547
7548# ifndef __EMSCRIPTEN__
7549static int
7550popen_exec(void *pp, char *errmsg, size_t errmsg_len)
7551{
7552 struct popen_arg *p = (struct popen_arg*)pp;
7553
7554 return rb_exec_async_signal_safe(p->eargp, errmsg, errmsg_len);
7555}
7556# endif
7557#endif
7558
7559#if (defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)) && !defined __EMSCRIPTEN__
7560static VALUE
7561rb_execarg_fixup_v(VALUE execarg_obj)
7562{
7563 rb_execarg_parent_start(execarg_obj);
7564 return Qnil;
7565}
7566#else
7567char *rb_execarg_commandline(const struct rb_execarg *eargp, VALUE *prog);
7568#endif
7569
7570#ifndef __EMSCRIPTEN__
7571static VALUE
7572pipe_open(VALUE execarg_obj, const char *modestr, enum rb_io_mode fmode,
7573 const struct rb_io_encoding *convconfig)
7574{
7575 struct rb_execarg *eargp = NIL_P(execarg_obj) ? NULL : rb_execarg_get(execarg_obj);
7576 VALUE prog = eargp ? (eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name) : Qfalse ;
7577 rb_pid_t pid = 0;
7578 rb_io_t *fptr;
7579 VALUE port;
7580 rb_io_t *write_fptr;
7581 VALUE write_port;
7582#if defined(HAVE_WORKING_FORK)
7583 int status;
7584 char errmsg[80] = { '\0' };
7585#endif
7586#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7587 int state;
7588 struct popen_arg arg;
7589#endif
7590 int e = 0;
7591#if defined(HAVE_SPAWNV)
7592# if defined(HAVE_SPAWNVE)
7593# define DO_SPAWN(cmd, args, envp) ((args) ? \
7594 spawnve(P_NOWAIT, (cmd), (args), (envp)) : \
7595 spawne(P_NOWAIT, (cmd), (envp)))
7596# else
7597# define DO_SPAWN(cmd, args, envp) ((args) ? \
7598 spawnv(P_NOWAIT, (cmd), (args)) : \
7599 spawn(P_NOWAIT, (cmd)))
7600# endif
7601# if !defined(HAVE_WORKING_FORK)
7602 char **args = NULL;
7603# if defined(HAVE_SPAWNVE)
7604 char **envp = NULL;
7605# endif
7606# endif
7607#endif
7608#if !defined(HAVE_WORKING_FORK)
7609 struct rb_execarg sarg, *sargp = &sarg;
7610#endif
7611 FILE *fp = 0;
7612 int fd = -1;
7613 int write_fd = -1;
7614#if !defined(HAVE_WORKING_FORK)
7615 const char *cmd = 0;
7616
7617 if (prog)
7618 cmd = StringValueCStr(prog);
7619#endif
7620
7621#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7622 arg.execarg_obj = execarg_obj;
7623 arg.eargp = eargp;
7624 arg.modef = fmode;
7625 arg.pair[0] = arg.pair[1] = -1;
7626 arg.write_pair[0] = arg.write_pair[1] = -1;
7627# if !defined(HAVE_WORKING_FORK)
7628 if (eargp && !eargp->use_shell) {
7629 args = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
7630 }
7631# endif
7632 switch (fmode & (FMODE_READABLE|FMODE_WRITABLE)) {
7634 if (rb_pipe(arg.write_pair) < 0)
7635 rb_sys_fail_str(prog);
7636 if (rb_pipe(arg.pair) < 0) {
7637 e = errno;
7638 close(arg.write_pair[0]);
7639 close(arg.write_pair[1]);
7640 rb_syserr_fail_str(e, prog);
7641 }
7642 if (eargp) {
7643 rb_execarg_addopt(execarg_obj, INT2FIX(0), INT2FIX(arg.write_pair[0]));
7644 rb_execarg_addopt(execarg_obj, INT2FIX(1), INT2FIX(arg.pair[1]));
7645 }
7646 break;
7647 case FMODE_READABLE:
7648 if (rb_pipe(arg.pair) < 0)
7649 rb_sys_fail_str(prog);
7650 if (eargp)
7651 rb_execarg_addopt(execarg_obj, INT2FIX(1), INT2FIX(arg.pair[1]));
7652 break;
7653 case FMODE_WRITABLE:
7654 if (rb_pipe(arg.pair) < 0)
7655 rb_sys_fail_str(prog);
7656 if (eargp)
7657 rb_execarg_addopt(execarg_obj, INT2FIX(0), INT2FIX(arg.pair[0]));
7658 break;
7659 default:
7660 rb_sys_fail_str(prog);
7661 }
7662 if (!NIL_P(execarg_obj)) {
7663 rb_protect(rb_execarg_fixup_v, execarg_obj, &state);
7664 if (state) {
7665 if (0 <= arg.write_pair[0]) close(arg.write_pair[0]);
7666 if (0 <= arg.write_pair[1]) close(arg.write_pair[1]);
7667 if (0 <= arg.pair[0]) close(arg.pair[0]);
7668 if (0 <= arg.pair[1]) close(arg.pair[1]);
7669 rb_execarg_parent_end(execarg_obj);
7670 rb_jump_tag(state);
7671 }
7672
7673# if defined(HAVE_WORKING_FORK)
7674 pid = rb_fork_async_signal_safe(&status, popen_exec, &arg, arg.eargp->redirect_fds, errmsg, sizeof(errmsg));
7675# else
7676 rb_execarg_run_options(eargp, sargp, NULL, 0);
7677# if defined(HAVE_SPAWNVE)
7678 if (eargp->envp_str) envp = (char **)RSTRING_PTR(eargp->envp_str);
7679# endif
7680 while ((pid = DO_SPAWN(cmd, args, envp)) < 0) {
7681 /* exec failed */
7682 switch (e = errno) {
7683 case EAGAIN:
7684# if EWOULDBLOCK != EAGAIN
7685 case EWOULDBLOCK:
7686# endif
7687 rb_thread_sleep(1);
7688 continue;
7689 }
7690 break;
7691 }
7692 if (eargp)
7693 rb_execarg_run_options(sargp, NULL, NULL, 0);
7694# endif
7695 rb_execarg_parent_end(execarg_obj);
7696 }
7697 else {
7698# if defined(HAVE_WORKING_FORK)
7699 pid = rb_call_proc__fork();
7700 if (pid == 0) { /* child */
7701 popen_redirect(&arg);
7702 rb_io_synchronized(RFILE(orig_stdout)->fptr);
7703 rb_io_synchronized(RFILE(orig_stderr)->fptr);
7704 return Qnil;
7705 }
7706# else
7708# endif
7709 }
7710
7711 /* parent */
7712 if (pid < 0) {
7713# if defined(HAVE_WORKING_FORK)
7714 e = errno;
7715# endif
7716 close(arg.pair[0]);
7717 close(arg.pair[1]);
7719 close(arg.write_pair[0]);
7720 close(arg.write_pair[1]);
7721 }
7722# if defined(HAVE_WORKING_FORK)
7723 if (errmsg[0])
7724 rb_syserr_fail(e, errmsg);
7725# endif
7726 rb_syserr_fail_str(e, prog);
7727 }
7728 if ((fmode & FMODE_READABLE) && (fmode & FMODE_WRITABLE)) {
7729 close(arg.pair[1]);
7730 fd = arg.pair[0];
7731 close(arg.write_pair[0]);
7732 write_fd = arg.write_pair[1];
7733 }
7734 else if (fmode & FMODE_READABLE) {
7735 close(arg.pair[1]);
7736 fd = arg.pair[0];
7737 }
7738 else {
7739 close(arg.pair[0]);
7740 fd = arg.pair[1];
7741 }
7742#else
7743 cmd = rb_execarg_commandline(eargp, &prog);
7744 if (!NIL_P(execarg_obj)) {
7745 rb_execarg_parent_start(execarg_obj);
7746 rb_execarg_run_options(eargp, sargp, NULL, 0);
7747 }
7748 fp = popen(cmd, modestr);
7749 e = errno;
7750 if (eargp) {
7751 rb_execarg_parent_end(execarg_obj);
7752 rb_execarg_run_options(sargp, NULL, NULL, 0);
7753 }
7754 if (!fp) rb_syserr_fail_path(e, prog);
7755 fd = fileno(fp);
7756#endif
7757
7758 port = io_alloc(rb_cIO);
7759 MakeOpenFile(port, fptr);
7760 fptr->fd = fd;
7761 fptr->stdio_file = fp;
7762 fptr->mode = fmode | FMODE_SYNC|FMODE_DUPLEX;
7763 if (convconfig) {
7764 fptr->encs = *convconfig;
7765#if RUBY_CRLF_ENVIRONMENT
7768 }
7769#endif
7770 }
7771 else {
7772 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
7774 }
7775#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7776 if (NEED_NEWLINE_DECORATOR_ON_WRITE(fptr)) {
7777 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
7778 }
7779#endif
7780 }
7781 fptr->pid = pid;
7782
7783 if (0 <= write_fd) {
7784 write_port = io_alloc(rb_cIO);
7785 MakeOpenFile(write_port, write_fptr);
7786 write_fptr->fd = write_fd;
7787 write_fptr->mode = (fmode & ~FMODE_READABLE)| FMODE_SYNC|FMODE_DUPLEX;
7788 fptr->mode &= ~FMODE_WRITABLE;
7789 fptr->tied_io_for_writing = write_port;
7790 rb_ivar_set(port, rb_intern("@tied_io_for_writing"), write_port);
7791 }
7792
7793#if defined (__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7794 fptr->finalize = pipe_finalize;
7795 pipe_add_fptr(fptr);
7796#endif
7797 return port;
7798}
7799#else
7800static VALUE
7801pipe_open(VALUE execarg_obj, const char *modestr, enum rb_io_mode fmode,
7802 const struct rb_io_encoding *convconfig)
7803{
7804 rb_raise(rb_eNotImpError, "popen() is not available");
7805}
7806#endif
7807
7808static int
7809is_popen_fork(VALUE prog)
7810{
7811 if (RSTRING_LEN(prog) == 1 && RSTRING_PTR(prog)[0] == '-') {
7812#if !defined(HAVE_WORKING_FORK)
7813 rb_raise(rb_eNotImpError,
7814 "fork() function is unimplemented on this machine");
7815#else
7816 return TRUE;
7817#endif
7818 }
7819 return FALSE;
7820}
7821
7822static VALUE
7823pipe_open_s(VALUE prog, const char *modestr, enum rb_io_mode fmode,
7824 const struct rb_io_encoding *convconfig)
7825{
7826 int argc = 1;
7827 VALUE *argv = &prog;
7828 VALUE execarg_obj = Qnil;
7829
7830 if (!is_popen_fork(prog))
7831 execarg_obj = rb_execarg_new(argc, argv, TRUE, FALSE);
7832 return pipe_open(execarg_obj, modestr, fmode, convconfig);
7833}
7834
7835static VALUE
7836pipe_close(VALUE io)
7837{
7838 rb_io_t *fptr = io_close_fptr(io);
7839 if (fptr) {
7840 fptr_waitpid(fptr, rb_thread_to_be_killed(rb_thread_current()));
7841 }
7842 return Qnil;
7843}
7844
7845static VALUE popen_finish(VALUE port, VALUE klass);
7846
7847/*
7848 * call-seq:
7849 * IO.popen(env = {}, cmd, mode = 'r', **opts) -> io
7850 * IO.popen(env = {}, cmd, mode = 'r', **opts) {|io| ... } -> object
7851 *
7852 * Executes the given command +cmd+ as a subprocess
7853 * whose $stdin and $stdout are connected to a new stream +io+.
7854 *
7855 * This method has potential security vulnerabilities if called with untrusted input;
7856 * see {Command Injection}[rdoc-ref:security/command_injection.rdoc].
7857 *
7858 * If no block is given, returns the new stream,
7859 * which depending on given +mode+ may be open for reading, writing, or both.
7860 * The stream should be explicitly closed (eventually) to avoid resource leaks.
7861 *
7862 * If a block is given, the stream is passed to the block
7863 * (again, open for reading, writing, or both);
7864 * when the block exits, the stream is closed,
7865 * the block's value is returned,
7866 * and the global variable <tt>$?</tt> is set to the child's exit status.
7867 *
7868 * Optional argument +mode+ may be any valid \IO mode.
7869 * See {Access Modes}[rdoc-ref:File@Access+Modes].
7870 *
7871 * Required argument +cmd+ determines which of the following occurs:
7872 *
7873 * - The process forks.
7874 * - A specified program runs in a shell.
7875 * - A specified program runs with specified arguments.
7876 * - A specified program runs with specified arguments and a specified +argv0+.
7877 *
7878 * Each of these is detailed below.
7879 *
7880 * The optional hash argument +env+ specifies name/value pairs that are to be added
7881 * to the environment variables for the subprocess:
7882 *
7883 * IO.popen({'FOO' => 'bar'}, 'ruby', 'r+') do |pipe|
7884 * pipe.puts 'puts ENV["FOO"]'
7885 * pipe.close_write
7886 * pipe.gets
7887 * end => "bar\n"
7888 *
7889 * Optional keyword arguments +opts+ specify:
7890 *
7891 * - {Open options}[rdoc-ref:IO@Open+Options].
7892 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
7893 * - Options for Kernel#spawn.
7894 *
7895 * <b>Forked Process</b>
7896 *
7897 * When argument +cmd+ is the 1-character string <tt>'-'</tt>, causes the process to fork:
7898 * IO.popen('-') do |pipe|
7899 * if pipe
7900 * $stderr.puts "In parent, child pid is #{pipe.pid}\n"
7901 * else
7902 * $stderr.puts "In child, pid is #{$$}\n"
7903 * end
7904 * end
7905 *
7906 * Output:
7907 *
7908 * In parent, child pid is 26253
7909 * In child, pid is 26253
7910 *
7911 * Note that this is not supported on all platforms.
7912 *
7913 * <b>Shell Subprocess</b>
7914 *
7915 * When argument +cmd+ is a single string (but not <tt>'-'</tt>),
7916 * the program named +cmd+ is run as a shell command:
7917 *
7918 * IO.popen('uname') do |pipe|
7919 * pipe.readlines
7920 * end
7921 *
7922 * Output:
7923 *
7924 * ["Linux\n"]
7925 *
7926 * Another example:
7927 *
7928 * IO.popen('/bin/sh', 'r+') do |pipe|
7929 * pipe.puts('ls')
7930 * pipe.close_write
7931 * $stderr.puts pipe.readlines.size
7932 * end
7933 *
7934 * Output:
7935 *
7936 * 213
7937 *
7938 * <b>Program Subprocess</b>
7939 *
7940 * When argument +cmd+ is an array of strings,
7941 * the program named <tt>cmd[0]</tt> is run with all elements of +cmd+ as its arguments:
7942 *
7943 * IO.popen(['du', '..', '.']) do |pipe|
7944 * $stderr.puts pipe.readlines.size
7945 * end
7946 *
7947 * Output:
7948 *
7949 * 1111
7950 *
7951 * <b>Program Subprocess with <tt>argv0</tt></b>
7952 *
7953 * When argument +cmd+ is an array whose first element is a 2-element string array
7954 * and whose remaining elements (if any) are strings:
7955 *
7956 * - <tt>cmd[0][0]</tt> (the first string in the nested array) is the name of a program that is run.
7957 * - <tt>cmd[0][1]</tt> (the second string in the nested array) is set as the program's <tt>argv[0]</tt>.
7958 * - <tt>cmd[1..-1]</tt> (the strings in the outer array) are the program's arguments.
7959 *
7960 * Example (sets <tt>$0</tt> to 'foo'):
7961 *
7962 * IO.popen([['/bin/sh', 'foo'], '-c', 'echo $0']).read # => "foo\n"
7963 *
7964 * <b>Some Special Examples</b>
7965 *
7966 * # Set IO encoding.
7967 * IO.popen("nkf -e filename", :external_encoding=>"EUC-JP") {|nkf_io|
7968 * euc_jp_string = nkf_io.read
7969 * }
7970 *
7971 * # Merge standard output and standard error using Kernel#spawn option. See Kernel#spawn.
7972 * IO.popen(["ls", "/", :err=>[:child, :out]]) do |io|
7973 * ls_result_with_error = io.read
7974 * end
7975 *
7976 * # Use mixture of spawn options and IO options.
7977 * IO.popen(["ls", "/"], :err=>[:child, :out]) do |io|
7978 * ls_result_with_error = io.read
7979 * end
7980 *
7981 * f = IO.popen("uname")
7982 * p f.readlines
7983 * f.close
7984 * puts "Parent is #{Process.pid}"
7985 * IO.popen("date") {|f| puts f.gets }
7986 * IO.popen("-") {|f| $stderr.puts "#{Process.pid} is here, f is #{f.inspect}"}
7987 * p $?
7988 * IO.popen(%w"sed -e s|^|<foo>| -e s&$&;zot;&", "r+") {|f|
7989 * f.puts "bar"; f.close_write; puts f.gets
7990 * }
7991 *
7992 * Output (from last section):
7993 *
7994 * ["Linux\n"]
7995 * Parent is 21346
7996 * Thu Jan 15 22:41:19 JST 2009
7997 * 21346 is here, f is #<IO:fd 3>
7998 * 21352 is here, f is nil
7999 * #<Process::Status: pid 21352 exit 0>
8000 * <foo>bar;zot;
8001 *
8002 * Raises exceptions that IO.pipe and Kernel.spawn raise.
8003 *
8004 */
8005
8006static VALUE
8007rb_io_s_popen(int argc, VALUE *argv, VALUE klass)
8008{
8009 VALUE pname, pmode = Qnil, opt = Qnil, env = Qnil;
8010
8011 if (argc > 1 && !NIL_P(opt = rb_check_hash_type(argv[argc-1]))) --argc;
8012 if (argc > 1 && !NIL_P(env = rb_check_hash_type(argv[0]))) --argc, ++argv;
8013 switch (argc) {
8014 case 2:
8015 pmode = argv[1];
8016 case 1:
8017 pname = argv[0];
8018 break;
8019 default:
8020 {
8021 int ex = !NIL_P(opt);
8022 rb_error_arity(argc + ex, 1 + ex, 2 + ex);
8023 }
8024 }
8025 return popen_finish(rb_io_popen(pname, pmode, env, opt), klass);
8026}
8027
8028VALUE
8029rb_io_popen(VALUE pname, VALUE pmode, VALUE env, VALUE opt)
8030{
8031 const char *modestr;
8032 VALUE tmp, execarg_obj = Qnil;
8033 int oflags;
8034 enum rb_io_mode fmode;
8035 struct rb_io_encoding convconfig;
8036
8037 tmp = rb_check_array_type(pname);
8038 if (!NIL_P(tmp)) {
8039 long len = RARRAY_LEN(tmp);
8040#if SIZEOF_LONG > SIZEOF_INT
8041 if (len > INT_MAX) {
8042 rb_raise(rb_eArgError, "too many arguments");
8043 }
8044#endif
8045 execarg_obj = rb_execarg_new((int)len, RARRAY_CONST_PTR(tmp), FALSE, FALSE);
8046 RB_GC_GUARD(tmp);
8047 }
8048 else {
8049 StringValue(pname);
8050 execarg_obj = Qnil;
8051 if (!is_popen_fork(pname))
8052 execarg_obj = rb_execarg_new(1, &pname, TRUE, FALSE);
8053 }
8054 if (!NIL_P(execarg_obj)) {
8055 if (!NIL_P(opt))
8056 opt = rb_execarg_extract_options(execarg_obj, opt);
8057 if (!NIL_P(env))
8058 rb_execarg_setenv(execarg_obj, env);
8059 }
8060 rb_io_extract_modeenc(&pmode, 0, opt, &oflags, &fmode, &convconfig);
8061 modestr = rb_io_oflags_modestr(oflags);
8062
8063 return pipe_open(execarg_obj, modestr, fmode, &convconfig);
8064}
8065
8066static VALUE
8067popen_finish(VALUE port, VALUE klass)
8068{
8069 if (NIL_P(port)) {
8070 /* child */
8071 if (rb_block_given_p()) {
8072 rb_protect(rb_yield, Qnil, NULL);
8073 rb_io_flush(rb_ractor_stdout());
8074 rb_io_flush(rb_ractor_stderr());
8075 _exit(0);
8076 }
8077 return Qnil;
8078 }
8079 RBASIC_SET_CLASS(port, klass);
8080 if (rb_block_given_p()) {
8081 return rb_ensure(rb_yield, port, pipe_close, port);
8082 }
8083 return port;
8084}
8085
8086#if defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)
8087struct popen_writer_arg {
8088 char *const *argv;
8089 struct popen_arg popen;
8090};
8091
8092static int
8093exec_popen_writer(void *arg, char *errmsg, size_t buflen)
8094{
8095 struct popen_writer_arg *pw = arg;
8096 pw->popen.modef = FMODE_WRITABLE;
8097 popen_redirect(&pw->popen);
8098 execv(pw->argv[0], pw->argv);
8099 strlcpy(errmsg, strerror(errno), buflen);
8100 return -1;
8101}
8102#endif
8103
8104FILE *
8105ruby_popen_writer(char *const *argv, rb_pid_t *pid)
8106{
8107#if (defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)) || defined(_WIN32)
8108# ifdef HAVE_WORKING_FORK
8109 struct popen_writer_arg pw;
8110 int *const write_pair = pw.popen.pair;
8111# else
8112 int write_pair[2];
8113# endif
8114
8115#ifdef HAVE_PIPE2
8116 int result = pipe2(write_pair, O_CLOEXEC);
8117#else
8118 int result = pipe(write_pair);
8119#endif
8120
8121 *pid = -1;
8122 if (result == 0) {
8123# ifdef HAVE_WORKING_FORK
8124 pw.argv = argv;
8125 int status;
8126 char errmsg[80] = {'\0'};
8127 *pid = rb_fork_async_signal_safe(&status, exec_popen_writer, &pw, Qnil, errmsg, sizeof(errmsg));
8128# else
8129 *pid = rb_w32_uspawn_process(P_NOWAIT, argv[0], argv, write_pair[0], -1, -1, 0);
8130 const char *errmsg = (*pid < 0) ? strerror(errno) : NULL;
8131# endif
8132 close(write_pair[0]);
8133 if (*pid < 0) {
8134 close(write_pair[1]);
8135 fprintf(stderr, "ruby_popen_writer(%s): %s\n", argv[0], errmsg);
8136 }
8137 else {
8138 return fdopen(write_pair[1], "w");
8139 }
8140 }
8141#endif
8142 return NULL;
8143}
8144
8145static VALUE
8146rb_open_file(VALUE io, VALUE fname, VALUE vmode, VALUE vperm, VALUE opt)
8147{
8148 int oflags;
8149 enum rb_io_mode fmode;
8150 struct rb_io_encoding convconfig;
8151 mode_t perm;
8152
8153 FilePathValue(fname);
8154
8155 rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, &convconfig);
8156 perm = NIL_P(vperm) ? 0666 : NUM2MODET(vperm);
8157
8158 rb_file_open_generic(io, fname, oflags, fmode, &convconfig, perm);
8159
8160 return io;
8161}
8162
8163/*
8164 * Document-method: File::open
8165 *
8166 * call-seq:
8167 * File.open(path, mode = 'r', perm = 0666, **opts) -> file
8168 * File.open(path, mode = 'r', perm = 0666, **opts) {|f| ... } -> object
8169 *
8170 * Creates a new File object, via File.new with the given arguments.
8171 *
8172 * With no block given, returns the File object.
8173 *
8174 * With a block given, calls the block with the File object
8175 * and returns the block's value.
8176 *
8177 */
8178
8179/*
8180 * Document-method: IO::open
8181 *
8182 * call-seq:
8183 * IO.open(fd, mode = 'r', **opts) -> io
8184 * IO.open(fd, mode = 'r', **opts) {|io| ... } -> object
8185 *
8186 * Creates a new \IO object, via IO.new with the given arguments.
8187 *
8188 * With no block given, returns the \IO object.
8189 *
8190 * With a block given, calls the block with the \IO object
8191 * and returns the block's value.
8192 *
8193 */
8194
8195static VALUE
8196rb_io_s_open(int argc, VALUE *argv, VALUE klass)
8197{
8199
8200 if (rb_block_given_p()) {
8201 return rb_ensure(rb_yield, io, io_close, io);
8202 }
8203
8204 return io;
8205}
8206
8207/*
8208 * call-seq:
8209 * IO.sysopen(path, mode = 'r', perm = 0666) -> integer
8210 *
8211 * Opens the file at the given path with the given mode and permissions;
8212 * returns the integer file descriptor.
8213 *
8214 * If the file is to be readable, it must exist;
8215 * if the file is to be writable and does not exist,
8216 * it is created with the given permissions:
8217 *
8218 * File.write('t.tmp', '') # => 0
8219 * IO.sysopen('t.tmp') # => 8
8220 * IO.sysopen('t.tmp', 'w') # => 9
8221 *
8222 *
8223 */
8224
8225static VALUE
8226rb_io_s_sysopen(int argc, VALUE *argv, VALUE _)
8227{
8228 VALUE fname, vmode, vperm;
8229 VALUE intmode;
8230 int oflags, fd;
8231 mode_t perm;
8232
8233 rb_scan_args(argc, argv, "12", &fname, &vmode, &vperm);
8234 FilePathValue(fname);
8235
8236 if (NIL_P(vmode))
8237 oflags = O_RDONLY;
8238 else if (!NIL_P(intmode = rb_check_to_integer(vmode, "to_int")))
8239 oflags = NUM2INT(intmode);
8240 else {
8241 StringValue(vmode);
8242 oflags = rb_io_modestr_oflags(StringValueCStr(vmode));
8243 }
8244 if (NIL_P(vperm)) perm = 0666;
8245 else perm = NUM2MODET(vperm);
8246
8247 RB_GC_GUARD(fname) = rb_str_new4(fname);
8248 fd = rb_sysopen(fname, oflags, perm);
8249 return INT2NUM(fd);
8250}
8251
8252/*
8253 * call-seq:
8254 * open(path, mode = 'r', perm = 0666, **opts) -> io or nil
8255 * open(path, mode = 'r', perm = 0666, **opts) {|io| ... } -> obj
8256 *
8257 * Creates an IO object connected to the given file.
8258 *
8259 * This method has potential security vulnerabilities if called with untrusted input;
8260 * see {Command Injection}[rdoc-ref:security/command_injection.rdoc].
8261 *
8262 * With no block given, file stream is returned:
8263 *
8264 * open('t.txt') # => #<File:t.txt>
8265 *
8266 * With a block given, calls the block with the open file stream,
8267 * then closes the stream:
8268 *
8269 * open('t.txt') {|f| p f } # => #<File:t.txt (closed)>
8270 *
8271 * Output:
8272 *
8273 * #<File:t.txt>
8274 *
8275 * See File.open for details.
8276 *
8277 */
8278
8279static VALUE
8280rb_f_open(int argc, VALUE *argv, VALUE _)
8281{
8282 ID to_open = 0;
8283 int redirect = FALSE;
8284
8285 if (argc >= 1) {
8286 CONST_ID(to_open, "to_open");
8287 if (rb_respond_to(argv[0], to_open)) {
8288 redirect = TRUE;
8289 }
8290 else {
8291 VALUE tmp = argv[0];
8292 FilePathValue(tmp);
8293 if (NIL_P(tmp)) {
8294 redirect = TRUE;
8295 }
8296 else {
8297 argv[0] = tmp;
8298 }
8299 }
8300 }
8301 if (redirect) {
8302 VALUE io = rb_funcallv_kw(argv[0], to_open, argc-1, argv+1, RB_PASS_CALLED_KEYWORDS);
8303
8304 if (rb_block_given_p()) {
8305 return rb_ensure(rb_yield, io, io_close, io);
8306 }
8307 return io;
8308 }
8309 return rb_io_s_open(argc, argv, rb_cFile);
8310}
8311
8312static VALUE
8313rb_io_open_generic(VALUE klass, VALUE filename, int oflags, enum rb_io_mode fmode,
8314 const struct rb_io_encoding *convconfig, mode_t perm)
8315{
8316 return rb_file_open_generic(io_alloc(klass), filename,
8317 oflags, fmode, convconfig, perm);
8318}
8319
8320static VALUE
8321rb_io_open(VALUE io, VALUE filename, VALUE vmode, VALUE vperm, VALUE opt)
8322{
8323 int oflags;
8324 enum rb_io_mode fmode;
8325 struct rb_io_encoding convconfig;
8326 mode_t perm;
8327
8328 rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, &convconfig);
8329 perm = NIL_P(vperm) ? 0666 : NUM2MODET(vperm);
8330 return rb_io_open_generic(io, filename, oflags, fmode, &convconfig, perm);
8331}
8332
8333static VALUE
8334io_reopen(VALUE io, VALUE nfile)
8335{
8336 rb_io_t *fptr, *orig;
8337 int fd, fd2;
8338 rb_off_t pos = 0;
8339
8340 nfile = rb_io_get_io(nfile);
8341 GetOpenFile(io, fptr);
8342 GetOpenFile(nfile, orig);
8343
8344 if (fptr == orig) return io;
8345 if (RUBY_IO_EXTERNAL_P(fptr)) {
8346 if ((fptr->stdio_file == stdin && !(orig->mode & FMODE_READABLE)) ||
8347 (fptr->stdio_file == stdout && !(orig->mode & FMODE_WRITABLE)) ||
8348 (fptr->stdio_file == stderr && !(orig->mode & FMODE_WRITABLE))) {
8349 rb_raise(rb_eArgError,
8350 "%s can't change access mode from \"%s\" to \"%s\"",
8351 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->mode),
8352 rb_io_fmode_modestr(orig->mode));
8353 }
8354 }
8355 if (fptr->mode & FMODE_WRITABLE) {
8356 if (io_fflush(fptr) < 0)
8357 rb_sys_fail_on_write(fptr);
8358 }
8359 else {
8360 flush_before_seek(fptr, true);
8361 }
8362 if (orig->mode & FMODE_READABLE) {
8363 pos = io_tell(orig);
8364 }
8365 if (orig->mode & FMODE_WRITABLE) {
8366 if (io_fflush(orig) < 0)
8367 rb_sys_fail_on_write(fptr);
8368 }
8369
8370 /* copy rb_io_t structure */
8371 fptr->mode = orig->mode | (fptr->mode & FMODE_EXTERNAL);
8372 fptr->encs = orig->encs;
8373 fptr->pid = orig->pid;
8374 fptr->lineno = orig->lineno;
8375 if (RTEST(orig->pathv)) fptr->pathv = orig->pathv;
8376 else if (!RUBY_IO_EXTERNAL_P(fptr)) fptr->pathv = Qnil;
8377 fptr_copy_finalizer(fptr, orig);
8378
8379 fd = fptr->fd;
8380 fd2 = orig->fd;
8381 if (fd != fd2) {
8382 // Interrupt all usage of the old file descriptor:
8383 rb_thread_io_close_interrupt(fptr);
8384 rb_thread_io_close_wait(fptr);
8385
8386 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2 || !fptr->stdio_file) {
8387 /* need to keep FILE objects of stdin, stdout and stderr */
8388 if (rb_cloexec_dup2(fd2, fd) < 0)
8389 rb_sys_fail_path(orig->pathv);
8390 rb_update_max_fd(fd);
8391 }
8392 else {
8393 fclose(fptr->stdio_file);
8394 fptr->stdio_file = 0;
8395 fptr->fd = -1;
8396 if (rb_cloexec_dup2(fd2, fd) < 0)
8397 rb_sys_fail_path(orig->pathv);
8398 rb_update_max_fd(fd);
8399 fptr->fd = fd;
8400 }
8401
8402 if ((orig->mode & FMODE_READABLE) && pos >= 0) {
8403 if (io_seek(fptr, pos, SEEK_SET) < 0 && errno) {
8404 rb_sys_fail_path(fptr->pathv);
8405 }
8406 if (io_seek(orig, pos, SEEK_SET) < 0 && errno) {
8407 rb_sys_fail_path(orig->pathv);
8408 }
8409 }
8410 }
8411
8412 if (fptr->mode & FMODE_BINMODE) {
8413 rb_io_binmode(io);
8414 }
8415
8416 RBASIC_SET_CLASS(io, rb_obj_class(nfile));
8417 return io;
8418}
8419
8420#ifdef _WIN32
8421int rb_freopen(VALUE fname, const char *mode, FILE *fp);
8422#else
8423static int
8424rb_freopen(VALUE fname, const char *mode, FILE *fp)
8425{
8426 if (!freopen(RSTRING_PTR(fname), mode, fp)) {
8427 RB_GC_GUARD(fname);
8428 return errno;
8429 }
8430 return 0;
8431}
8432#endif
8433
8434/*
8435 * call-seq:
8436 * reopen(other_io) -> self
8437 * reopen(path, mode = 'r', **opts) -> self
8438 *
8439 * Reassociates the stream with another stream,
8440 * which may be of a different class.
8441 * This method may be used to redirect an existing stream
8442 * to a new destination.
8443 *
8444 * With argument +other_io+ given, reassociates with that stream:
8445 *
8446 * # Redirect $stdin from a file.
8447 * f = File.open('t.txt')
8448 * $stdin.reopen(f)
8449 * f.close
8450 *
8451 * # Redirect $stdout to a file.
8452 * f = File.open('t.tmp', 'w')
8453 * $stdout.reopen(f)
8454 * f.close
8455 *
8456 * With argument +path+ given, reassociates with a new stream to that file path:
8457 *
8458 * $stdin.reopen('t.txt')
8459 * $stdout.reopen('t.tmp', 'w')
8460 *
8461 * Optional keyword arguments +opts+ specify:
8462 *
8463 * - {Open Options}[rdoc-ref:IO@Open+Options].
8464 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
8465 *
8466 */
8467
8468static VALUE
8469rb_io_reopen(int argc, VALUE *argv, VALUE file)
8470{
8471 VALUE fname, nmode, opt;
8472 int oflags;
8473 rb_io_t *fptr;
8474
8475 if (rb_scan_args(argc, argv, "11:", &fname, &nmode, &opt) == 1) {
8476 VALUE tmp = rb_io_check_io(fname);
8477 if (!NIL_P(tmp)) {
8478 return io_reopen(file, tmp);
8479 }
8480 }
8481
8482 FilePathValue(fname);
8483 rb_io_taint_check(file);
8484 fptr = RFILE(file)->fptr;
8485 if (!fptr) {
8486 fptr = RFILE(file)->fptr = ZALLOC(rb_io_t);
8487 }
8488
8489 if (!NIL_P(nmode) || !NIL_P(opt)) {
8490 enum rb_io_mode fmode;
8491 struct rb_io_encoding convconfig;
8492
8493 rb_io_extract_modeenc(&nmode, 0, opt, &oflags, &fmode, &convconfig);
8494 if (RUBY_IO_EXTERNAL_P(fptr) &&
8495 ((fptr->mode & FMODE_READWRITE) & (fmode & FMODE_READWRITE)) !=
8496 (fptr->mode & FMODE_READWRITE)) {
8497 rb_raise(rb_eArgError,
8498 "%s can't change access mode from \"%s\" to \"%s\"",
8499 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->mode),
8500 rb_io_fmode_modestr(fmode));
8501 }
8502 fptr->mode = fmode;
8503 fptr->encs = convconfig;
8504 }
8505 else {
8506 oflags = rb_io_fmode_oflags(fptr->mode);
8507 }
8508
8509 fptr->pathv = fname;
8510 if (fptr->fd < 0) {
8511 fptr->fd = rb_sysopen(fptr->pathv, oflags, 0666);
8512 fptr->stdio_file = 0;
8513 return file;
8514 }
8515
8516 if (fptr->mode & FMODE_WRITABLE) {
8517 if (io_fflush(fptr) < 0)
8518 rb_sys_fail_on_write(fptr);
8519 }
8520 fptr->rbuf.off = fptr->rbuf.len = 0;
8521
8522 if (fptr->stdio_file) {
8523 int e = rb_freopen(rb_str_encode_ospath(fptr->pathv),
8524 rb_io_oflags_modestr(oflags),
8525 fptr->stdio_file);
8526 if (e) rb_syserr_fail_path(e, fptr->pathv);
8527 fptr->fd = fileno(fptr->stdio_file);
8528 rb_fd_fix_cloexec(fptr->fd);
8529#ifdef USE_SETVBUF
8530 if (setvbuf(fptr->stdio_file, NULL, _IOFBF, 0) != 0)
8531 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8532#endif
8533 if (fptr->stdio_file == stderr) {
8534 if (setvbuf(fptr->stdio_file, NULL, _IONBF, BUFSIZ) != 0)
8535 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8536 }
8537 else if (fptr->stdio_file == stdout && isatty(fptr->fd)) {
8538 if (setvbuf(fptr->stdio_file, NULL, _IOLBF, BUFSIZ) != 0)
8539 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8540 }
8541 }
8542 else {
8543 int tmpfd = rb_sysopen(fptr->pathv, oflags, 0666);
8544 int err = 0;
8545 if (rb_cloexec_dup2(tmpfd, fptr->fd) < 0)
8546 err = errno;
8547 (void)close(tmpfd);
8548 if (err) {
8549 rb_syserr_fail_path(err, fptr->pathv);
8550 }
8551 }
8552
8553 return file;
8554}
8555
8556/* :nodoc: */
8557static VALUE
8558rb_io_init_copy(VALUE dest, VALUE io)
8559{
8560 rb_io_t *fptr, *orig;
8561 int fd;
8562 VALUE write_io;
8563 rb_off_t pos;
8564
8565 io = rb_io_get_io(io);
8566 if (!OBJ_INIT_COPY(dest, io)) return dest;
8567 GetOpenFile(io, orig);
8568 MakeOpenFile(dest, fptr);
8569
8570 rb_io_flush(io);
8571
8572 /* copy rb_io_t structure */
8573 fptr->mode = orig->mode & ~FMODE_EXTERNAL;
8574 fptr->encs = orig->encs;
8575 fptr->pid = orig->pid;
8576 fptr->lineno = orig->lineno;
8577 fptr->timeout = orig->timeout;
8578
8579 ccan_list_head_init(&fptr->blocking_operations);
8580 fptr->closing_ec = NULL;
8581 fptr->wakeup_mutex = Qnil;
8582 fptr->fork_generation = GET_VM()->fork_gen;
8583
8584 if (!NIL_P(orig->pathv)) fptr->pathv = orig->pathv;
8585 fptr_copy_finalizer(fptr, orig);
8586
8587 fd = ruby_dup(orig->fd);
8588 fptr->fd = fd;
8589 pos = io_tell(orig);
8590 if (0 <= pos)
8591 io_seek(fptr, pos, SEEK_SET);
8592 if (fptr->mode & FMODE_BINMODE) {
8593 rb_io_binmode(dest);
8594 }
8595
8596 write_io = GetWriteIO(io);
8597 if (io != write_io) {
8598 write_io = rb_obj_dup(write_io);
8599 fptr->tied_io_for_writing = write_io;
8600 rb_ivar_set(dest, rb_intern("@tied_io_for_writing"), write_io);
8601 }
8602
8603 return dest;
8604}
8605
8606/*
8607 * call-seq:
8608 * printf(format_string, *objects) -> nil
8609 *
8610 * Formats and writes +objects+ to the stream.
8611 *
8612 * For details on +format_string+, see
8613 * {Format Specifications}[rdoc-ref:language/format_specifications.rdoc].
8614 *
8615 */
8616
8617VALUE
8618rb_io_printf(int argc, const VALUE *argv, VALUE out)
8619{
8620 rb_io_write(out, rb_f_sprintf(argc, argv));
8621 return Qnil;
8622}
8623
8624/*
8625 * call-seq:
8626 * printf(format_string, *objects) -> nil
8627 * printf(io, format_string, *objects) -> nil
8628 *
8629 * Equivalent to:
8630 *
8631 * io.write(sprintf(format_string, *objects))
8632 *
8633 * For details on +format_string+, see
8634 * {Format Specifications}[rdoc-ref:language/format_specifications.rdoc].
8635 *
8636 * With the single argument +format_string+, formats +objects+ into the string,
8637 * then writes the formatted string to $stdout:
8638 *
8639 * printf('%4.4d %10s %2.2f', 24, 24, 24.0)
8640 *
8641 * Output (on $stdout):
8642 *
8643 * 0024 24 24.00#
8644 *
8645 * With arguments +io+ and +format_string+, formats +objects+ into the string,
8646 * then writes the formatted string to +io+:
8647 *
8648 * printf($stderr, '%4.4d %10s %2.2f', 24, 24, 24.0)
8649 *
8650 * Output (on $stderr):
8651 *
8652 * 0024 24 24.00# => nil
8653 *
8654 * With no arguments, does nothing.
8655 *
8656 */
8657
8658static VALUE
8659rb_f_printf(int argc, VALUE *argv, VALUE _)
8660{
8661 VALUE out;
8662
8663 if (argc == 0) return Qnil;
8664 if (RB_TYPE_P(argv[0], T_STRING)) {
8665 out = rb_ractor_stdout();
8666 }
8667 else {
8668 out = argv[0];
8669 argv++;
8670 argc--;
8671 }
8672 rb_io_write(out, rb_f_sprintf(argc, argv));
8673
8674 return Qnil;
8675}
8676
8677extern void rb_deprecated_str_setter(VALUE val, ID id, VALUE *var);
8678
8679static void
8680deprecated_rs_setter(VALUE val, ID id, VALUE *var)
8681{
8682 rb_deprecated_str_setter(val, id, &val);
8683 if (!NIL_P(val)) {
8684 if (rb_str_equal(val, rb_default_rs)) {
8685 val = rb_default_rs;
8686 }
8687 else {
8688 val = rb_str_frozen_bare_string(val);
8689 }
8690 }
8691 *var = val;
8692}
8693
8694/*
8695 * call-seq:
8696 * print(*objects) -> nil
8697 *
8698 * Writes the given objects to the stream; returns +nil+.
8699 * Appends the output record separator <tt>$OUTPUT_RECORD_SEPARATOR</tt>
8700 * (<tt>$\</tt>), if it is not +nil+.
8701 * See {Line IO}[rdoc-ref:IO@Line+IO].
8702 *
8703 * With argument +objects+ given, for each object:
8704 *
8705 * - Converts via its method +to_s+ if not a string.
8706 * - Writes to the stream.
8707 * - If not the last object, writes the output field separator
8708 * <tt>$OUTPUT_FIELD_SEPARATOR</tt> (<tt>$,</tt>) if it is not +nil+.
8709 *
8710 * With default separators:
8711 *
8712 * f = File.open('t.tmp', 'w+')
8713 * objects = [0, 0.0, Rational(0, 1), Complex(0, 0), :zero, 'zero']
8714 * p $OUTPUT_RECORD_SEPARATOR
8715 * p $OUTPUT_FIELD_SEPARATOR
8716 * f.print(*objects)
8717 * f.rewind
8718 * p f.read
8719 * f.close
8720 *
8721 * Output:
8722 *
8723 * nil
8724 * nil
8725 * "00.00/10+0izerozero"
8726 *
8727 * With specified separators:
8728 *
8729 * $\ = "\n"
8730 * $, = ','
8731 * f.rewind
8732 * f.print(*objects)
8733 * f.rewind
8734 * p f.read
8735 *
8736 * Output:
8737 *
8738 * "0,0.0,0/1,0+0i,zero,zero\n"
8739 *
8740 * With no argument given, writes the content of <tt>$_</tt>
8741 * (which is usually the most recent user input):
8742 *
8743 * f = File.open('t.tmp', 'w+')
8744 * gets # Sets $_ to the most recent user input.
8745 * f.print
8746 * f.close
8747 *
8748 */
8749
8750VALUE
8751rb_io_print(int argc, const VALUE *argv, VALUE out)
8752{
8753 int i;
8754 VALUE line;
8755
8756 /* if no argument given, print `$_' */
8757 if (argc == 0) {
8758 argc = 1;
8759 line = rb_lastline_get();
8760 argv = &line;
8761 }
8762 if (argc > 1 && !NIL_P(rb_output_fs)) {
8763 rb_category_warn(RB_WARN_CATEGORY_DEPRECATED, "$, is set to non-nil value");
8764 }
8765 for (i=0; i<argc; i++) {
8766 if (!NIL_P(rb_output_fs) && i>0) {
8767 rb_io_write(out, rb_output_fs);
8768 }
8769 rb_io_write(out, argv[i]);
8770 }
8771 if (argc > 0 && !NIL_P(rb_output_rs)) {
8772 rb_io_write(out, rb_output_rs);
8773 }
8774
8775 return Qnil;
8776}
8777
8778/*
8779 * call-seq:
8780 * print(*objects) -> nil
8781 *
8782 * Equivalent to <tt>$stdout.print(*objects)</tt>,
8783 * this method is the straightforward way to write to <tt>$stdout</tt>.
8784 *
8785 * Writes the given objects to <tt>$stdout</tt>; returns +nil+.
8786 * Appends the output record separator <tt>$OUTPUT_RECORD_SEPARATOR</tt>
8787 * <tt>$\</tt>), if it is not +nil+.
8788 *
8789 * With argument +objects+ given, for each object:
8790 *
8791 * - Converts via its method +to_s+ if not a string.
8792 * - Writes to <tt>stdout</tt>.
8793 * - If not the last object, writes the output field separator
8794 * <tt>$OUTPUT_FIELD_SEPARATOR</tt> (<tt>$,</tt> if it is not +nil+.
8795 *
8796 * With default separators:
8797 *
8798 * objects = [0, 0.0, Rational(0, 1), Complex(0, 0), :zero, 'zero']
8799 * $OUTPUT_RECORD_SEPARATOR
8800 * $OUTPUT_FIELD_SEPARATOR
8801 * print(*objects)
8802 *
8803 * Output:
8804 *
8805 * nil
8806 * nil
8807 * 00.00/10+0izerozero
8808 *
8809 * With specified separators:
8810 *
8811 * $OUTPUT_RECORD_SEPARATOR = "\n"
8812 * $OUTPUT_FIELD_SEPARATOR = ','
8813 * print(*objects)
8814 *
8815 * Output:
8816 *
8817 * 0,0.0,0/1,0+0i,zero,zero
8818 *
8819 * With no argument given, writes the content of <tt>$_</tt>
8820 * (which is usually the most recent user input):
8821 *
8822 * gets # Sets $_ to the most recent user input.
8823 * print # Prints $_.
8824 *
8825 */
8826
8827static VALUE
8828rb_f_print(int argc, const VALUE *argv, VALUE _)
8829{
8830 rb_io_print(argc, argv, rb_ractor_stdout());
8831 return Qnil;
8832}
8833
8834/*
8835 * call-seq:
8836 * putc(object) -> object
8837 *
8838 * Writes a character to the stream.
8839 * See {Character IO}[rdoc-ref:IO@Character+IO].
8840 *
8841 * If +object+ is numeric, converts to integer if necessary,
8842 * then writes the character whose code is the
8843 * least significant byte;
8844 * if +object+ is a string, writes the first character:
8845 *
8846 * $stdout.putc "A"
8847 * $stdout.putc 65
8848 *
8849 * Output:
8850 *
8851 * AA
8852 *
8853 */
8854
8855static VALUE
8856rb_io_putc(VALUE io, VALUE ch)
8857{
8858 VALUE str;
8859 if (RB_TYPE_P(ch, T_STRING)) {
8860 str = rb_str_substr(ch, 0, 1);
8861 }
8862 else {
8863 char c = NUM2CHR(ch);
8864 str = rb_str_new(&c, 1);
8865 }
8866 rb_io_write(io, str);
8867 return ch;
8868}
8869
8870#define forward(obj, id, argc, argv) \
8871 rb_funcallv_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8872#define forward_public(obj, id, argc, argv) \
8873 rb_funcallv_public_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8874#define forward_current(id, argc, argv) \
8875 forward_public(ARGF.current_file, id, argc, argv)
8876
8877/*
8878 * call-seq:
8879 * putc(int) -> int
8880 *
8881 * Equivalent to:
8882 *
8883 * $stdout.putc(int)
8884 *
8885 * See IO#putc for important information regarding multi-byte characters.
8886 *
8887 */
8888
8889static VALUE
8890rb_f_putc(VALUE recv, VALUE ch)
8891{
8892 VALUE r_stdout = rb_ractor_stdout();
8893 if (recv == r_stdout) {
8894 return rb_io_putc(recv, ch);
8895 }
8896 return forward(r_stdout, rb_intern("putc"), 1, &ch);
8897}
8898
8899
8900int
8901rb_str_end_with_asciichar(VALUE str, int c)
8902{
8903 long len = RSTRING_LEN(str);
8904 const char *ptr = RSTRING_PTR(str);
8905 rb_encoding *enc = rb_enc_from_index(ENCODING_GET(str));
8906 int n;
8907
8908 if (len == 0) return 0;
8909 if ((n = rb_enc_mbminlen(enc)) == 1) {
8910 return ptr[len - 1] == c;
8911 }
8912 return rb_enc_ascget(ptr + ((len - 1) / n) * n, ptr + len, &n, enc) == c;
8913}
8914
8915static VALUE
8916io_puts_ary(VALUE ary, VALUE out, int recur)
8917{
8918 VALUE tmp;
8919 long i;
8920
8921 if (recur) {
8922 tmp = rb_str_new2("[...]");
8923 rb_io_puts(1, &tmp, out);
8924 return Qtrue;
8925 }
8926 ary = rb_check_array_type(ary);
8927 if (NIL_P(ary)) return Qfalse;
8928 for (i=0; i<RARRAY_LEN(ary); i++) {
8929 tmp = RARRAY_AREF(ary, i);
8930 rb_io_puts(1, &tmp, out);
8931 }
8932 return Qtrue;
8933}
8934
8935/*
8936 * call-seq:
8937 * puts(*objects) -> nil
8938 *
8939 * Writes the given +objects+ to the stream, which must be open for writing;
8940 * returns +nil+.\
8941 * Writes a newline after each that does not already end with a newline sequence.
8942 * If called without arguments, writes a newline.
8943 * See {Line IO}[rdoc-ref:IO@Line+IO].
8944 *
8945 * Note that each added newline is the character <tt>"\n"<//tt>,
8946 * not the output record separator (<tt>$\</tt>).
8947 *
8948 * Treatment for each object:
8949 *
8950 * - String: writes the string.
8951 * - Neither string nor array: writes <tt>object.to_s</tt>.
8952 * - Array: writes each element of the array; arrays may be nested.
8953 *
8954 * To keep these examples brief, we define this helper method:
8955 *
8956 * def show(*objects)
8957 * # Puts objects to file.
8958 * f = File.new('t.tmp', 'w+')
8959 * f.puts(objects)
8960 * # Return file content.
8961 * f.rewind
8962 * p f.read
8963 * f.close
8964 * end
8965 *
8966 * # Strings without newlines.
8967 * show('foo', 'bar', 'baz') # => "foo\nbar\nbaz\n"
8968 * # Strings, some with newlines.
8969 * show("foo\n", 'bar', "baz\n") # => "foo\nbar\nbaz\n"
8970 *
8971 * # Neither strings nor arrays:
8972 * show(0, 0.0, Rational(0, 1), Complex(9, 0), :zero)
8973 * # => "0\n0.0\n0/1\n9+0i\nzero\n"
8974 *
8975 * # Array of strings.
8976 * show(['foo', "bar\n", 'baz']) # => "foo\nbar\nbaz\n"
8977 * # Nested arrays.
8978 * show([[[0, 1], 2, 3], 4, 5]) # => "0\n1\n2\n3\n4\n5\n"
8979 *
8980 */
8981
8982VALUE
8983rb_io_puts(int argc, const VALUE *argv, VALUE out)
8984{
8985 VALUE line, args[2];
8986
8987 /* if no argument given, print newline. */
8988 if (argc == 0) {
8989 rb_io_write(out, rb_default_rs);
8990 return Qnil;
8991 }
8992 for (int i = 0; i < argc; i++) {
8993 // Convert the argument to a string:
8994 if (RB_TYPE_P(argv[i], T_STRING)) {
8995 line = argv[i];
8996 }
8997 else if (rb_exec_recursive(io_puts_ary, argv[i], out)) {
8998 continue;
8999 }
9000 else {
9001 line = rb_obj_as_string(argv[i]);
9002 }
9003
9004 // Write the line:
9005 int n = 0;
9006 if (RSTRING_LEN(line) == 0) {
9007 args[n++] = rb_default_rs;
9008 }
9009 else {
9010 args[n++] = line;
9011 if (!rb_str_end_with_asciichar(line, '\n')) {
9012 args[n++] = rb_default_rs;
9013 }
9014 }
9015
9016 rb_io_writev(out, n, args);
9017 }
9018
9019 return Qnil;
9020}
9021
9022/*
9023 * call-seq:
9024 * puts(*objects) -> nil
9025 *
9026 * Equivalent to
9027 *
9028 * $stdout.puts(objects)
9029 */
9030
9031static VALUE
9032rb_f_puts(int argc, VALUE *argv, VALUE recv)
9033{
9034 VALUE r_stdout = rb_ractor_stdout();
9035 if (recv == r_stdout) {
9036 return rb_io_puts(argc, argv, recv);
9037 }
9038 return forward(r_stdout, rb_intern("puts"), argc, argv);
9039}
9040
9041static VALUE
9042rb_p_write(VALUE str)
9043{
9044 VALUE args[2];
9045 args[0] = str;
9046 args[1] = rb_default_rs;
9047 VALUE r_stdout = rb_ractor_stdout();
9048 if (RB_TYPE_P(r_stdout, T_FILE) &&
9049 rb_method_basic_definition_p(CLASS_OF(r_stdout), id_write)) {
9050 io_writev(2, args, r_stdout);
9051 }
9052 else {
9053 rb_io_writev(r_stdout, 2, args);
9054 }
9055 return Qnil;
9056}
9057
9058void
9059rb_p(VALUE obj) /* for debug print within C code */
9060{
9061 rb_p_write(rb_obj_as_string(rb_inspect(obj)));
9062}
9063
9064static VALUE
9065rb_p_result(int argc, const VALUE *argv)
9066{
9067 VALUE ret = Qnil;
9068
9069 if (argc == 1) {
9070 ret = argv[0];
9071 }
9072 else if (argc > 1) {
9073 ret = rb_ary_new4(argc, argv);
9074 }
9075 VALUE r_stdout = rb_ractor_stdout();
9076 if (RB_TYPE_P(r_stdout, T_FILE)) {
9077 rb_uninterruptible(rb_io_flush, r_stdout);
9078 }
9079 return ret;
9080}
9081
9082/*
9083 * call-seq:
9084 * p(object) -> obj
9085 * p(*objects) -> array of objects
9086 * p -> nil
9087 *
9088 * For each object +obj+, executes:
9089 *
9090 * $stdout.write(obj.inspect, "\n")
9091 *
9092 * With one object given, returns the object;
9093 * with multiple objects given, returns an array containing the objects;
9094 * with no object given, returns +nil+.
9095 *
9096 * Examples:
9097 *
9098 * r = Range.new(0, 4)
9099 * p r # => 0..4
9100 * p [r, r, r] # => [0..4, 0..4, 0..4]
9101 * p # => nil
9102 *
9103 * Output:
9104 *
9105 * 0..4
9106 * [0..4, 0..4, 0..4]
9107 *
9108 * Kernel#p is designed for debugging purposes.
9109 * Ruby implementations may define Kernel#p to be uninterruptible
9110 * in whole or in part.
9111 * On CRuby, Kernel#p's writing of data is uninterruptible.
9112 */
9113
9114static VALUE
9115rb_f_p(int argc, VALUE *argv, VALUE self)
9116{
9117 int i;
9118 for (i=0; i<argc; i++) {
9119 VALUE inspected = rb_obj_as_string(rb_inspect(argv[i]));
9120 rb_uninterruptible(rb_p_write, inspected);
9121 }
9122 return rb_p_result(argc, argv);
9123}
9124
9125/*
9126 * call-seq:
9127 * display(port = $>) -> nil
9128 *
9129 * Writes +self+ on the given port:
9130 *
9131 * 1.display
9132 * "cat".display
9133 * [ 4, 5, 6 ].display
9134 * puts
9135 *
9136 * Output:
9137 *
9138 * 1cat[4, 5, 6]
9139 *
9140 */
9141
9142static VALUE
9143rb_obj_display(int argc, VALUE *argv, VALUE self)
9144{
9145 VALUE out;
9146
9147 out = (!rb_check_arity(argc, 0, 1) ? rb_ractor_stdout() : argv[0]);
9148 rb_io_write(out, self);
9149
9150 return Qnil;
9151}
9152
9153static int
9154rb_stderr_to_original_p(VALUE err)
9155{
9156 return (err == orig_stderr || RFILE(orig_stderr)->fptr->fd < 0);
9157}
9158
9159void
9160rb_write_error2(const char *mesg, long len)
9161{
9162 VALUE out = rb_ractor_stderr();
9163 if (rb_stderr_to_original_p(out)) {
9164#ifdef _WIN32
9165 if (isatty(fileno(stderr))) {
9166 if (rb_w32_write_console(rb_str_new(mesg, len), fileno(stderr)) > 0) return;
9167 }
9168#endif
9169 if (fwrite(mesg, sizeof(char), (size_t)len, stderr) < (size_t)len) {
9170 /* failed to write to stderr, what can we do? */
9171 return;
9172 }
9173 }
9174 else {
9175 rb_io_write(out, rb_str_new(mesg, len));
9176 }
9177}
9178
9179void
9180rb_write_error(const char *mesg)
9181{
9182 rb_write_error2(mesg, strlen(mesg));
9183}
9184
9185void
9186rb_write_error_str(VALUE mesg)
9187{
9188 VALUE out = rb_ractor_stderr();
9189 /* a stopgap measure for the time being */
9190 if (rb_stderr_to_original_p(out)) {
9191 size_t len = (size_t)RSTRING_LEN(mesg);
9192#ifdef _WIN32
9193 if (isatty(fileno(stderr))) {
9194 if (rb_w32_write_console(mesg, fileno(stderr)) > 0) return;
9195 }
9196#endif
9197 if (fwrite(RSTRING_PTR(mesg), sizeof(char), len, stderr) < len) {
9198 RB_GC_GUARD(mesg);
9199 return;
9200 }
9201 }
9202 else {
9203 /* may unlock GVL, and */
9204 rb_io_write(out, mesg);
9205 }
9206}
9207
9208int
9209rb_stderr_tty_p(void)
9210{
9211 if (rb_stderr_to_original_p(rb_ractor_stderr()))
9212 return isatty(fileno(stderr));
9213 return 0;
9214}
9215
9216static void
9217must_respond_to(ID mid, VALUE val, ID id)
9218{
9219 if (!rb_respond_to(val, mid)) {
9220 rb_raise(rb_eTypeError, "%"PRIsVALUE" must have %"PRIsVALUE" method, %"PRIsVALUE" given",
9221 rb_id2str(id), rb_id2str(mid),
9222 rb_obj_class(val));
9223 }
9224}
9225
9226static void
9227stdin_setter(VALUE val, ID id, VALUE *ptr)
9228{
9230}
9231
9232static VALUE
9233stdin_getter(ID id, VALUE *ptr)
9234{
9235 return rb_ractor_stdin();
9236}
9237
9238static void
9239stdout_setter(VALUE val, ID id, VALUE *ptr)
9240{
9241 must_respond_to(id_write, val, id);
9243}
9244
9245static VALUE
9246stdout_getter(ID id, VALUE *ptr)
9247{
9248 return rb_ractor_stdout();
9249}
9250
9251static void
9252stderr_setter(VALUE val, ID id, VALUE *ptr)
9253{
9254 must_respond_to(id_write, val, id);
9256}
9257
9258static VALUE
9259stderr_getter(ID id, VALUE *ptr)
9260{
9261 return rb_ractor_stderr();
9262}
9263
9264static VALUE
9265allocate_and_open_new_file(VALUE klass)
9266{
9267 VALUE self = io_alloc(klass);
9268 rb_io_make_open_file(self);
9269 return self;
9270}
9271
9272VALUE
9273rb_io_open_descriptor(VALUE klass, int descriptor, int mode, VALUE path, VALUE timeout, struct rb_io_encoding *encoding)
9274{
9275 int state;
9276 VALUE self = rb_protect(allocate_and_open_new_file, klass, &state);
9277 if (state) {
9278 /* if we raised an exception allocating an IO object, but the caller
9279 intended to transfer ownership of this FD to us, close the fd before
9280 raising the exception. Otherwise, we would leak a FD - the caller
9281 expects GC to close the file, but we never got around to assigning
9282 it to a rb_io. */
9283 if (!(mode & FMODE_EXTERNAL)) {
9284 maygvl_close(descriptor, 0);
9285 }
9286 rb_jump_tag(state);
9287 }
9288
9289
9290 rb_io_t *io = RFILE(self)->fptr;
9291 io->self = self;
9292 io->fd = descriptor;
9293 io->mode = mode;
9294
9295 /* At this point, Ruby fully owns the descriptor, and will close it when
9296 the IO gets GC'd (unless FMODE_EXTERNAL was set), no matter what happens
9297 in the rest of this method. */
9298
9299 if (NIL_P(path)) {
9300 io->pathv = Qnil;
9301 }
9302 else {
9303 StringValue(path);
9304 io->pathv = rb_str_new_frozen(path);
9305 }
9306
9307 io->timeout = timeout;
9308
9309 ccan_list_head_init(&io->blocking_operations);
9310 io->closing_ec = NULL;
9311 io->wakeup_mutex = Qnil;
9312 io->fork_generation = GET_VM()->fork_gen;
9313
9314 if (encoding) {
9315 io->encs = *encoding;
9316 }
9317
9318 rb_update_max_fd(descriptor);
9319
9320 return self;
9321}
9322
9323static VALUE
9324prep_io(int fd, enum rb_io_mode fmode, VALUE klass, const char *path)
9325{
9326 VALUE path_value = Qnil;
9327 rb_encoding *e;
9328 struct rb_io_encoding convconfig;
9329
9330 if (path) {
9331 path_value = rb_obj_freeze(rb_str_new_cstr(path));
9332 }
9333
9334 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
9335 rb_io_ext_int_to_encs(e, NULL, &convconfig.enc, &convconfig.enc2, fmode);
9336 convconfig.ecflags = (fmode & FMODE_READABLE) ?
9339#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9340 convconfig.ecflags |= (fmode & FMODE_WRITABLE) ?
9341 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
9342 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
9343#endif
9344 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.enc2, convconfig.ecflags);
9345 convconfig.ecopts = Qnil;
9346
9347 VALUE self = rb_io_open_descriptor(klass, fd, fmode, path_value, Qnil, &convconfig);
9348 rb_io_t*io = RFILE(self)->fptr;
9349
9350 if (!io_check_tty(io)) {
9351#ifdef __CYGWIN__
9352 io->mode |= FMODE_BINMODE;
9353 setmode(fd, O_BINARY);
9354#endif
9355 }
9356
9357 return self;
9358}
9359
9360VALUE
9361rb_io_fdopen(int fd, int oflags, const char *path)
9362{
9363 VALUE klass = rb_cIO;
9364
9365 if (path && strcmp(path, "-")) klass = rb_cFile;
9366 return prep_io(fd, rb_io_oflags_fmode(oflags), klass, path);
9367}
9368
9369static VALUE
9370prep_stdio(FILE *f, enum rb_io_mode fmode, VALUE klass, const char *path)
9371{
9372 rb_io_t *fptr;
9373 VALUE io = prep_io(fileno(f), fmode|FMODE_EXTERNAL|DEFAULT_TEXTMODE, klass, path);
9374
9375 GetOpenFile(io, fptr);
9377#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9378 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
9379 if (fmode & FMODE_READABLE) {
9381 }
9382#endif
9383 fptr->stdio_file = f;
9384
9385 return io;
9386}
9387
9388VALUE
9389rb_io_prep_stdin(void)
9390{
9391 return prep_stdio(stdin, FMODE_READABLE, rb_cIO, "<STDIN>");
9392}
9393
9394VALUE
9395rb_io_prep_stdout(void)
9396{
9397 return prep_stdio(stdout, FMODE_WRITABLE|FMODE_SIGNAL_ON_EPIPE, rb_cIO, "<STDOUT>");
9398}
9399
9400VALUE
9401rb_io_prep_stderr(void)
9402{
9403 return prep_stdio(stderr, FMODE_WRITABLE|FMODE_SYNC, rb_cIO, "<STDERR>");
9404}
9405
9406FILE *
9408{
9409 if (!fptr->stdio_file) {
9410 int oflags = rb_io_fmode_oflags(fptr->mode) & ~O_EXCL;
9411 fptr->stdio_file = rb_fdopen(fptr->fd, rb_io_oflags_modestr(oflags));
9412 }
9413 return fptr->stdio_file;
9414}
9415
9416static inline void
9417rb_io_buffer_init(struct rb_io_internal_buffer *buf)
9418{
9419 buf->ptr = NULL;
9420 buf->off = 0;
9421 buf->len = 0;
9422 buf->capa = 0;
9423}
9424
9425static inline rb_io_t *
9426rb_io_fptr_new(void)
9427{
9428 rb_io_t *fp = ALLOC(rb_io_t);
9429 fp->self = Qnil;
9430 fp->fd = -1;
9431 fp->stdio_file = NULL;
9432 fp->mode = 0;
9433 fp->pid = 0;
9434 fp->lineno = 0;
9435 fp->pathv = Qnil;
9436 fp->finalize = 0;
9437 rb_io_buffer_init(&fp->wbuf);
9438 rb_io_buffer_init(&fp->rbuf);
9439 rb_io_buffer_init(&fp->cbuf);
9440 fp->readconv = NULL;
9441 fp->writeconv = NULL;
9443 fp->writeconv_pre_ecflags = 0;
9445 fp->writeconv_initialized = 0;
9446 fp->tied_io_for_writing = 0;
9447 fp->encs.enc = NULL;
9448 fp->encs.enc2 = NULL;
9449 fp->encs.ecflags = 0;
9450 fp->encs.ecopts = Qnil;
9451 fp->write_lock = Qnil;
9452 fp->timeout = Qnil;
9453 ccan_list_head_init(&fp->blocking_operations);
9454 fp->closing_ec = NULL;
9455 fp->wakeup_mutex = Qnil;
9456 fp->fork_generation = GET_VM()->fork_gen;
9457 return fp;
9458}
9459
9460rb_io_t *
9461rb_io_make_open_file(VALUE obj)
9462{
9463 rb_io_t *fp = 0;
9464
9465 Check_Type(obj, T_FILE);
9466 if (RFILE(obj)->fptr) {
9467 rb_io_close(obj);
9468 rb_io_fptr_finalize(RFILE(obj)->fptr);
9469 RFILE(obj)->fptr = 0;
9470 }
9471 fp = rb_io_fptr_new();
9472 fp->self = obj;
9473 RFILE(obj)->fptr = fp;
9474 return fp;
9475}
9476
9477static VALUE io_initialize(VALUE io, VALUE fnum, VALUE vmode, VALUE opt);
9478
9479/*
9480 * call-seq:
9481 * IO.new(fd, mode = 'r', **opts) -> io
9482 *
9483 * Creates and returns a new \IO object (file stream) from a file descriptor.
9484 *
9485 * \IO.new may be useful for interaction with low-level libraries.
9486 * For higher-level interactions, it may be simpler to create
9487 * the file stream using File.open.
9488 *
9489 * Argument +fd+ must be a valid file descriptor (integer):
9490 *
9491 * path = 't.tmp'
9492 * fd = IO.sysopen(path) # => 3
9493 * IO.new(fd) # => #<IO:fd 3>
9494 *
9495 * The new \IO object does not inherit encoding
9496 * (because the integer file descriptor does not have an encoding):
9497 *
9498 * fd = IO.sysopen('t.rus', 'rb')
9499 * io = IO.new(fd)
9500 * io.external_encoding # => #<Encoding:UTF-8> # Not ASCII-8BIT.
9501 *
9502 * Optional argument +mode+ (defaults to 'r') must specify a valid mode;
9503 * see {Access Modes}[rdoc-ref:File@Access+Modes]:
9504 *
9505 * IO.new(fd, 'w') # => #<IO:fd 3>
9506 * IO.new(fd, File::WRONLY) # => #<IO:fd 3>
9507 *
9508 * Optional keyword arguments +opts+ specify:
9509 *
9510 * - {Open Options}[rdoc-ref:IO@Open+Options].
9511 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
9512 *
9513 * Examples:
9514 *
9515 * IO.new(fd, internal_encoding: nil) # => #<IO:fd 3>
9516 * IO.new(fd, autoclose: true) # => #<IO:fd 3>
9517 *
9518 */
9519
9520static VALUE
9521rb_io_initialize(int argc, VALUE *argv, VALUE io)
9522{
9523 VALUE fnum, vmode;
9524 VALUE opt;
9525
9526 rb_scan_args(argc, argv, "11:", &fnum, &vmode, &opt);
9527 return io_initialize(io, fnum, vmode, opt);
9528}
9529
9530static VALUE
9531io_initialize(VALUE io, VALUE fnum, VALUE vmode, VALUE opt)
9532{
9533 rb_io_t *fp;
9534 int fd, oflags = O_RDONLY;
9535 enum rb_io_mode fmode;
9536 struct rb_io_encoding convconfig;
9537#if defined(HAVE_FCNTL) && defined(F_GETFL)
9538 int ofmode;
9539#else
9540 struct stat st;
9541#endif
9542
9543 rb_io_extract_modeenc(&vmode, 0, opt, &oflags, &fmode, &convconfig);
9544
9545 fd = NUM2INT(fnum);
9546 if (rb_reserved_fd_p(fd)) {
9547 rb_raise(rb_eArgError, "The given fd is not accessible because RubyVM reserves it");
9548 }
9549#if defined(HAVE_FCNTL) && defined(F_GETFL)
9550 oflags = fcntl(fd, F_GETFL);
9551 if (oflags == -1) rb_sys_fail(0);
9552#else
9553 if (fstat(fd, &st) < 0) rb_sys_fail(0);
9554#endif
9555 rb_update_max_fd(fd);
9556#if defined(HAVE_FCNTL) && defined(F_GETFL)
9557 ofmode = rb_io_oflags_fmode(oflags);
9558 if (NIL_P(vmode)) {
9559 fmode = ofmode;
9560 }
9561 else if ((~ofmode & fmode) & FMODE_READWRITE) {
9562 VALUE error = INT2FIX(EINVAL);
9564 }
9565#endif
9566 VALUE path = Qnil;
9567
9568 if (!NIL_P(opt)) {
9569 if (rb_hash_aref(opt, sym_autoclose) == Qfalse) {
9570 fmode |= FMODE_EXTERNAL;
9571 }
9572
9573 path = rb_hash_aref(opt, RB_ID2SYM(idPath));
9574 if (!NIL_P(path)) {
9575 StringValue(path);
9576 path = rb_str_new_frozen(path);
9577 }
9578 }
9579
9580 MakeOpenFile(io, fp);
9581 fp->self = io;
9582 fp->fd = fd;
9583 fp->mode = fmode;
9584 fp->encs = convconfig;
9585 fp->pathv = path;
9586 fp->timeout = Qnil;
9587 ccan_list_head_init(&fp->blocking_operations);
9588 fp->closing_ec = NULL;
9589 fp->wakeup_mutex = Qnil;
9590 fp->fork_generation = GET_VM()->fork_gen;
9591 clear_codeconv(fp);
9592 io_check_tty(fp);
9593 if (fileno(stdin) == fd)
9594 fp->stdio_file = stdin;
9595 else if (fileno(stdout) == fd)
9596 fp->stdio_file = stdout;
9597 else if (fileno(stderr) == fd)
9598 fp->stdio_file = stderr;
9599
9600 if (fmode & FMODE_SETENC_BY_BOM) io_set_encoding_by_bom(io);
9601 return io;
9602}
9603
9604/*
9605 * call-seq:
9606 * set_encoding_by_bom -> encoding or nil
9607 *
9608 * If the stream begins with a BOM
9609 * ({byte order marker}[https://en.wikipedia.org/wiki/Byte_order_mark]),
9610 * consumes the BOM and sets the external encoding accordingly;
9611 * returns the result encoding if found, or +nil+ otherwise:
9612 *
9613 * File.write('t.tmp', "\u{FEFF}abc")
9614 * io = File.open('t.tmp', 'rb')
9615 * io.set_encoding_by_bom # => #<Encoding:UTF-8>
9616 * io.close
9617 *
9618 * File.write('t.tmp', 'abc')
9619 * io = File.open('t.tmp', 'rb')
9620 * io.set_encoding_by_bom # => nil
9621 * io.close
9622 *
9623 * Raises an exception if the stream is not binmode
9624 * or its encoding has already been set.
9625 *
9626 */
9627
9628static VALUE
9629rb_io_set_encoding_by_bom(VALUE io)
9630{
9631 rb_io_t *fptr;
9632
9633 GetOpenFile(io, fptr);
9634 if (!(fptr->mode & FMODE_BINMODE)) {
9635 rb_raise(rb_eArgError, "ASCII incompatible encoding needs binmode");
9636 }
9637 if (fptr->encs.enc2) {
9638 rb_raise(rb_eArgError, "encoding conversion is set");
9639 }
9640 else if (fptr->encs.enc && fptr->encs.enc != rb_ascii8bit_encoding()) {
9641 rb_raise(rb_eArgError, "encoding is set to %s already",
9642 rb_enc_name(fptr->encs.enc));
9643 }
9644 if (!io_set_encoding_by_bom(io)) return Qnil;
9645 return rb_enc_from_encoding(fptr->encs.enc);
9646}
9647
9648/*
9649 * call-seq:
9650 * File.new(path, mode = 'r', perm = 0666, **opts) -> file
9651 *
9652 * Opens the file at the given +path+ according to the given +mode+;
9653 * creates and returns a new File object for that file.
9654 *
9655 * The new File object is buffered mode (or non-sync mode), unless
9656 * +filename+ is a tty.
9657 * See IO#flush, IO#fsync, IO#fdatasync, and IO#sync=.
9658 *
9659 * Argument +path+ must be a valid file path:
9660 *
9661 * f = File.new('/etc/fstab')
9662 * f.close
9663 * f = File.new('t.txt')
9664 * f.close
9665 *
9666 * Optional argument +mode+ (defaults to 'r') must specify a valid mode;
9667 * see {Access Modes}[rdoc-ref:File@Access+Modes]:
9668 *
9669 * f = File.new('t.tmp', 'w')
9670 * f.close
9671 * f = File.new('t.tmp', File::RDONLY)
9672 * f.close
9673 *
9674 * Optional argument +perm+ (defaults to 0666) must specify valid permissions
9675 * see {File Permissions}[rdoc-ref:File@File+Permissions]:
9676 *
9677 * f = File.new('t.tmp', File::CREAT, 0644)
9678 * f.close
9679 * f = File.new('t.tmp', File::CREAT, 0444)
9680 * f.close
9681 *
9682 * Optional keyword arguments +opts+ specify:
9683 *
9684 * - {Open Options}[rdoc-ref:IO@Open+Options].
9685 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
9686 *
9687 */
9688
9689static VALUE
9690rb_file_initialize(int argc, VALUE *argv, VALUE io)
9691{
9692 if (RFILE(io)->fptr) {
9693 rb_raise(rb_eRuntimeError, "reinitializing File");
9694 }
9695 VALUE fname, vmode, vperm, opt;
9696 int posargc = rb_scan_args(argc, argv, "12:", &fname, &vmode, &vperm, &opt);
9697 if (posargc < 3) { /* perm is File only */
9698 VALUE fd = rb_check_to_int(fname);
9699
9700 if (!NIL_P(fd)) {
9701 return io_initialize(io, fd, vmode, opt);
9702 }
9703 }
9704 return rb_open_file(io, fname, vmode, vperm, opt);
9705}
9706
9707/* :nodoc: */
9708static VALUE
9709rb_io_s_new(int argc, VALUE *argv, VALUE klass)
9710{
9711 if (rb_block_given_p()) {
9712 VALUE cname = rb_obj_as_string(klass);
9713
9714 rb_warn("%"PRIsVALUE"::new() does not take block; use %"PRIsVALUE"::open() instead",
9715 cname, cname);
9716 }
9717 return rb_class_new_instance_kw(argc, argv, klass, RB_PASS_CALLED_KEYWORDS);
9718}
9719
9720
9721/*
9722 * call-seq:
9723 * IO.for_fd(fd, mode = 'r', **opts) -> io
9724 *
9725 * Synonym for IO.new.
9726 *
9727 */
9728
9729static VALUE
9730rb_io_s_for_fd(int argc, VALUE *argv, VALUE klass)
9731{
9732 VALUE io = rb_obj_alloc(klass);
9733 rb_io_initialize(argc, argv, io);
9734 return io;
9735}
9736
9737/*
9738 * call-seq:
9739 * ios.autoclose? -> true or false
9740 *
9741 * Returns +true+ if the underlying file descriptor of _ios_ will be
9742 * closed at its finalization or at calling #close, otherwise +false+.
9743 */
9744
9745static VALUE
9746rb_io_autoclose_p(VALUE io)
9747{
9748 rb_io_t *fptr = RFILE(io)->fptr;
9749 rb_io_check_closed(fptr);
9750 return RBOOL(!(fptr->mode & FMODE_EXTERNAL));
9751}
9752
9753/*
9754 * call-seq:
9755 * io.autoclose = bool -> true or false
9756 *
9757 * Sets auto-close flag.
9758 *
9759 * f = File.open(File::NULL)
9760 * IO.for_fd(f.fileno).close
9761 * f.gets # raises Errno::EBADF
9762 *
9763 * f = File.open(File::NULL)
9764 * g = IO.for_fd(f.fileno)
9765 * g.autoclose = false
9766 * g.close
9767 * f.gets # won't cause Errno::EBADF
9768 */
9769
9770static VALUE
9771rb_io_set_autoclose(VALUE io, VALUE autoclose)
9772{
9773 rb_io_t *fptr;
9774 GetOpenFile(io, fptr);
9775 if (!RTEST(autoclose))
9776 fptr->mode |= FMODE_EXTERNAL;
9777 else
9778 fptr->mode &= ~FMODE_EXTERNAL;
9779 return autoclose;
9780}
9781
9782static VALUE
9783io_wait_event(VALUE io, int event, VALUE timeout, int return_io)
9784{
9785 VALUE result = rb_io_wait(io, RB_INT2NUM(event), timeout);
9786
9787 if (!RB_TEST(result)) {
9788 return Qnil;
9789 }
9790
9791 int mask = RB_NUM2INT(result);
9792
9793 if (mask & event) {
9794 if (return_io)
9795 return io;
9796 else
9797 return result;
9798 }
9799 else {
9800 return Qfalse;
9801 }
9802}
9803
9804/*
9805 * call-seq:
9806 * io.wait_readable -> truthy or falsy
9807 * io.wait_readable(timeout) -> truthy or falsy
9808 *
9809 * Waits until IO is readable and returns a truthy value, or a falsy
9810 * value when times out. Returns a truthy value immediately when
9811 * buffered data is available.
9812 */
9813
9814static VALUE
9815io_wait_readable(int argc, VALUE *argv, VALUE io)
9816{
9817 rb_io_t *fptr;
9818
9819 RB_IO_POINTER(io, fptr);
9821
9822 if (rb_io_read_pending(fptr)) return Qtrue;
9823
9824 rb_check_arity(argc, 0, 1);
9825 VALUE timeout = (argc == 1 ? argv[0] : Qnil);
9826
9827 return io_wait_event(io, RUBY_IO_READABLE, timeout, 1);
9828}
9829
9830/*
9831 * call-seq:
9832 * io.wait_writable -> truthy or falsy
9833 * io.wait_writable(timeout) -> truthy or falsy
9834 *
9835 * Waits until IO is writable and returns a truthy value or a falsy
9836 * value when times out.
9837 */
9838static VALUE
9839io_wait_writable(int argc, VALUE *argv, VALUE io)
9840{
9841 rb_io_t *fptr;
9842
9843 RB_IO_POINTER(io, fptr);
9845
9846 rb_check_arity(argc, 0, 1);
9847 VALUE timeout = (argc == 1 ? argv[0] : Qnil);
9848
9849 return io_wait_event(io, RUBY_IO_WRITABLE, timeout, 1);
9850}
9851
9852/*
9853 * call-seq:
9854 * io.wait_priority -> truthy or falsy
9855 * io.wait_priority(timeout) -> truthy or falsy
9856 *
9857 * Waits until IO is priority and returns a truthy value or a falsy
9858 * value when times out. Priority data is sent and received using
9859 * the Socket::MSG_OOB flag and is typically limited to streams.
9860 */
9861static VALUE
9862io_wait_priority(int argc, VALUE *argv, VALUE io)
9863{
9864 rb_io_t *fptr = NULL;
9865
9866 RB_IO_POINTER(io, fptr);
9868
9869 if (rb_io_read_pending(fptr)) return Qtrue;
9870
9871 rb_check_arity(argc, 0, 1);
9872 VALUE timeout = argc == 1 ? argv[0] : Qnil;
9873
9874 return io_wait_event(io, RUBY_IO_PRIORITY, timeout, 1);
9875}
9876
9877static int
9878wait_mode_sym(VALUE mode)
9879{
9880 if (mode == ID2SYM(rb_intern("r"))) {
9881 return RB_WAITFD_IN;
9882 }
9883 if (mode == ID2SYM(rb_intern("read"))) {
9884 return RB_WAITFD_IN;
9885 }
9886 if (mode == ID2SYM(rb_intern("readable"))) {
9887 return RB_WAITFD_IN;
9888 }
9889 if (mode == ID2SYM(rb_intern("w"))) {
9890 return RB_WAITFD_OUT;
9891 }
9892 if (mode == ID2SYM(rb_intern("write"))) {
9893 return RB_WAITFD_OUT;
9894 }
9895 if (mode == ID2SYM(rb_intern("writable"))) {
9896 return RB_WAITFD_OUT;
9897 }
9898 if (mode == ID2SYM(rb_intern("rw"))) {
9899 return RB_WAITFD_IN|RB_WAITFD_OUT;
9900 }
9901 if (mode == ID2SYM(rb_intern("read_write"))) {
9902 return RB_WAITFD_IN|RB_WAITFD_OUT;
9903 }
9904 if (mode == ID2SYM(rb_intern("readable_writable"))) {
9905 return RB_WAITFD_IN|RB_WAITFD_OUT;
9906 }
9907
9908 rb_raise(rb_eArgError, "unsupported mode: %"PRIsVALUE, mode);
9909}
9910
9911static inline enum rb_io_event
9912io_event_from_value(VALUE value)
9913{
9914 int events = RB_NUM2INT(value);
9915
9916 if (events <= 0) rb_raise(rb_eArgError, "Events must be positive integer!");
9917
9918 return events;
9919}
9920
9921/*
9922 * call-seq:
9923 * io.wait(events, timeout) -> event mask, false or nil
9924 * io.wait(*event_symbols[, timeout]) -> self, true, or false
9925 *
9926 * Waits until the IO becomes ready for the specified events and returns the
9927 * subset of events that become ready, or a falsy value when times out.
9928 *
9929 * The events can be a bit mask of +IO::READABLE+, +IO::WRITABLE+ or
9930 * +IO::PRIORITY+.
9931 *
9932 * Returns an event mask (truthy value) immediately when buffered data is
9933 * available.
9934 *
9935 * The second form: if one or more event symbols (+:read+, +:write+, or
9936 * +:read_write+) are passed, the event mask is the bit OR of the bitmask
9937 * corresponding to those symbols. In this form, +timeout+ is optional, the
9938 * order of the arguments is arbitrary, and returns +io+ if any of the
9939 * events is ready.
9940 */
9941
9942static VALUE
9943io_wait(int argc, VALUE *argv, VALUE io)
9944{
9945 VALUE timeout = Qundef;
9946 enum rb_io_event events = 0;
9947 int return_io = 0;
9948
9949 if (argc != 2 || (RB_SYMBOL_P(argv[0]) || RB_SYMBOL_P(argv[1]))) {
9950 // We'd prefer to return the actual mask, but this form would return the io itself:
9951 return_io = 1;
9952
9953 // Slow/messy path:
9954 for (int i = 0; i < argc; i += 1) {
9955 if (RB_SYMBOL_P(argv[i])) {
9956 events |= wait_mode_sym(argv[i]);
9957 }
9958 else if (UNDEF_P(timeout)) {
9959 rb_time_interval(timeout = argv[i]);
9960 }
9961 else {
9962 rb_raise(rb_eArgError, "timeout given more than once");
9963 }
9964 }
9965
9966 if (UNDEF_P(timeout)) timeout = Qnil;
9967
9968 if (events == 0) {
9969 events = RUBY_IO_READABLE;
9970 }
9971 }
9972 else /* argc == 2 and neither are symbols */ {
9973 // This is the fast path:
9974 events = io_event_from_value(argv[0]);
9975 timeout = argv[1];
9976 }
9977
9978 if (events & RUBY_IO_READABLE) {
9979 rb_io_t *fptr = NULL;
9980 RB_IO_POINTER(io, fptr);
9981
9982 if (rb_io_read_pending(fptr)) {
9983 // This was the original behaviour:
9984 if (return_io) return Qtrue;
9985 // New behaviour always returns an event mask:
9986 else return RB_INT2NUM(RUBY_IO_READABLE);
9987 }
9988 }
9989
9990 return io_wait_event(io, events, timeout, return_io);
9991}
9992
9993static void
9994argf_mark_and_move(void *ptr)
9995{
9996 struct argf *p = ptr;
9997 rb_gc_mark_and_move(&p->filename);
9998 rb_gc_mark_and_move(&p->current_file);
9999 rb_gc_mark_and_move(&p->argv);
10000 rb_gc_mark_and_move(&p->inplace);
10001 rb_gc_mark_and_move(&p->encs.ecopts);
10002}
10003
10004static size_t
10005argf_memsize(const void *ptr)
10006{
10007 const struct argf *p = ptr;
10008 size_t size = sizeof(*p);
10009 return size;
10010}
10011
10012static const rb_data_type_t argf_type = {
10013 "ARGF",
10014 {argf_mark_and_move, RUBY_TYPED_DEFAULT_FREE, argf_memsize, argf_mark_and_move},
10015 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
10016};
10017
10018static inline void
10019argf_init(struct argf *p, VALUE v)
10020{
10021 p->filename = Qnil;
10022 p->current_file = Qnil;
10023 p->lineno = 0;
10024 p->argv = v;
10025}
10026
10027static VALUE
10028argf_alloc(VALUE klass)
10029{
10030 struct argf *p;
10031 VALUE argf = TypedData_Make_Struct(klass, struct argf, &argf_type, p);
10032
10033 argf_init(p, Qnil);
10034 return argf;
10035}
10036
10037#undef rb_argv
10038
10039/* :nodoc: */
10040static VALUE
10041argf_initialize(VALUE argf, VALUE argv)
10042{
10043 memset(&ARGF, 0, sizeof(ARGF));
10044 argf_init(&ARGF, argv);
10045
10046 return argf;
10047}
10048
10049/* :nodoc: */
10050static VALUE
10051argf_initialize_copy(VALUE argf, VALUE orig)
10052{
10053 if (!OBJ_INIT_COPY(argf, orig)) return argf;
10054 ARGF = argf_of(orig);
10055 ARGF.argv = rb_obj_dup(ARGF.argv);
10056 return argf;
10057}
10058
10059/*
10060 * call-seq:
10061 * ARGF.lineno = integer -> integer
10062 *
10063 * Sets the line number of ARGF as a whole to the given Integer.
10064 *
10065 * ARGF sets the line number automatically as you read data, so normally
10066 * you will not need to set it explicitly. To access the current line number
10067 * use ARGF.lineno.
10068 *
10069 * For example:
10070 *
10071 * ARGF.lineno #=> 0
10072 * ARGF.readline #=> "This is line 1\n"
10073 * ARGF.lineno #=> 1
10074 * ARGF.lineno = 0 #=> 0
10075 * ARGF.lineno #=> 0
10076 */
10077static VALUE
10078argf_set_lineno(VALUE argf, VALUE val)
10079{
10080 ARGF.lineno = NUM2INT(val);
10081 ARGF.last_lineno = ARGF.lineno;
10082 return val;
10083}
10084
10085/*
10086 * call-seq:
10087 * ARGF.lineno -> integer
10088 *
10089 * Returns the current line number of ARGF as a whole. This value
10090 * can be set manually with ARGF.lineno=.
10091 *
10092 * For example:
10093 *
10094 * ARGF.lineno #=> 0
10095 * ARGF.readline #=> "This is line 1\n"
10096 * ARGF.lineno #=> 1
10097 */
10098static VALUE
10099argf_lineno(VALUE argf)
10100{
10101 return INT2FIX(ARGF.lineno);
10102}
10103
10104static VALUE
10105argf_forward(int argc, VALUE *argv, VALUE argf)
10106{
10107 return forward_current(rb_frame_this_func(), argc, argv);
10108}
10109
10110#define next_argv() argf_next_argv(argf)
10111#define ARGF_GENERIC_INPUT_P() \
10112 (ARGF.current_file == rb_stdin && !RB_TYPE_P(ARGF.current_file, T_FILE))
10113#define ARGF_FORWARD(argc, argv) do {\
10114 if (ARGF_GENERIC_INPUT_P())\
10115 return argf_forward((argc), (argv), argf);\
10116} while (0)
10117#define NEXT_ARGF_FORWARD(argc, argv) do {\
10118 if (!next_argv()) return Qnil;\
10119 ARGF_FORWARD((argc), (argv));\
10120} while (0)
10121
10122static void
10123argf_close(VALUE argf)
10124{
10125 VALUE file = ARGF.current_file;
10126 if (file == rb_stdin) return;
10127 if (RB_TYPE_P(file, T_FILE)) {
10128 rb_io_set_write_io(file, Qnil);
10129 }
10130 io_close(file);
10131 ARGF.init_p = -1;
10132}
10133
10134static int
10135argf_next_argv(VALUE argf)
10136{
10137 char *fn;
10138 rb_io_t *fptr;
10139 int stdout_binmode = 0;
10140 enum rb_io_mode fmode;
10141
10142 VALUE r_stdout = rb_ractor_stdout();
10143
10144 if (RB_TYPE_P(r_stdout, T_FILE)) {
10145 GetOpenFile(r_stdout, fptr);
10146 if (fptr->mode & FMODE_BINMODE)
10147 stdout_binmode = 1;
10148 }
10149
10150 if (ARGF.init_p == 0) {
10151 if (!NIL_P(ARGF.argv) && RARRAY_LEN(ARGF.argv) > 0) {
10152 ARGF.next_p = 1;
10153 }
10154 else {
10155 ARGF.next_p = -1;
10156 }
10157 ARGF.init_p = 1;
10158 }
10159 else {
10160 if (NIL_P(ARGF.argv)) {
10161 ARGF.next_p = -1;
10162 }
10163 else if (ARGF.next_p == -1 && RARRAY_LEN(ARGF.argv) > 0) {
10164 ARGF.next_p = 1;
10165 }
10166 }
10167
10168 if (ARGF.next_p == 1) {
10169 if (ARGF.init_p == 1) argf_close(argf);
10170 retry:
10171 if (RARRAY_LEN(ARGF.argv) > 0) {
10172 VALUE filename = rb_ary_shift(ARGF.argv);
10173 FilePathValue(filename);
10174 ARGF.filename = filename;
10175 filename = rb_str_encode_ospath(filename);
10176 fn = StringValueCStr(filename);
10177 if (RSTRING_LEN(filename) == 1 && fn[0] == '-') {
10178 ARGF.current_file = rb_stdin;
10179 if (ARGF.inplace) {
10180 rb_warn("Can't do inplace edit for stdio; skipping");
10181 goto retry;
10182 }
10183 }
10184 else {
10185 VALUE write_io = Qnil;
10186 int fr = rb_sysopen(filename, O_RDONLY, 0);
10187
10188 if (ARGF.inplace) {
10189 struct stat st;
10190#ifndef NO_SAFE_RENAME
10191 struct stat st2;
10192#endif
10193 VALUE str;
10194 int fw;
10195
10196 if (RB_TYPE_P(r_stdout, T_FILE) && r_stdout != orig_stdout) {
10197 rb_io_close(r_stdout);
10198 }
10199 fstat(fr, &st);
10200 str = filename;
10201 if (!NIL_P(ARGF.inplace)) {
10202 VALUE suffix = ARGF.inplace;
10203 str = rb_str_dup(str);
10204 if (NIL_P(rb_str_cat_conv_enc_opts(str, RSTRING_LEN(str),
10205 RSTRING_PTR(suffix), RSTRING_LEN(suffix),
10206 rb_enc_get(suffix), 0, Qnil))) {
10207 rb_str_append(str, suffix);
10208 }
10209#ifdef NO_SAFE_RENAME
10210 (void)close(fr);
10211 (void)unlink(RSTRING_PTR(str));
10212 if (rename(fn, RSTRING_PTR(str)) < 0) {
10213 rb_warn("Can't rename %"PRIsVALUE" to %"PRIsVALUE": %s, skipping file",
10214 filename, str, strerror(errno));
10215 goto retry;
10216 }
10217 fr = rb_sysopen(str, O_RDONLY, 0);
10218#else
10219 if (rename(fn, RSTRING_PTR(str)) < 0) {
10220 rb_warn("Can't rename %"PRIsVALUE" to %"PRIsVALUE": %s, skipping file",
10221 filename, str, strerror(errno));
10222 close(fr);
10223 goto retry;
10224 }
10225#endif
10226 }
10227 else {
10228#ifdef NO_SAFE_RENAME
10229 rb_fatal("Can't do inplace edit without backup");
10230#else
10231 if (unlink(fn) < 0) {
10232 rb_warn("Can't remove %"PRIsVALUE": %s, skipping file",
10233 filename, strerror(errno));
10234 close(fr);
10235 goto retry;
10236 }
10237#endif
10238 }
10239 fw = rb_sysopen(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666);
10240#ifndef NO_SAFE_RENAME
10241 fstat(fw, &st2);
10242#ifdef HAVE_FCHMOD
10243 fchmod(fw, st.st_mode);
10244#else
10245 chmod(fn, st.st_mode);
10246#endif
10247 if (st.st_uid!=st2.st_uid || st.st_gid!=st2.st_gid) {
10248 int err;
10249#ifdef HAVE_FCHOWN
10250 err = fchown(fw, st.st_uid, st.st_gid);
10251#else
10252 err = chown(fn, st.st_uid, st.st_gid);
10253#endif
10254 if (err && getuid() == 0 && st2.st_uid == 0) {
10255 const char *wkfn = RSTRING_PTR(filename);
10256 rb_warn("Can't set owner/group of %"PRIsVALUE" to same as %"PRIsVALUE": %s, skipping file",
10257 filename, str, strerror(errno));
10258 (void)close(fr);
10259 (void)close(fw);
10260 (void)unlink(wkfn);
10261 goto retry;
10262 }
10263 }
10264#endif
10265 write_io = prep_io(fw, FMODE_WRITABLE, rb_cFile, fn);
10266 rb_ractor_stdout_set(write_io);
10267 if (stdout_binmode) rb_io_binmode(rb_stdout);
10268 }
10269 fmode = FMODE_READABLE;
10270 if (!ARGF.binmode) {
10271 fmode |= DEFAULT_TEXTMODE;
10272 }
10273 ARGF.current_file = prep_io(fr, fmode, rb_cFile, fn);
10274 if (!NIL_P(write_io)) {
10275 rb_io_set_write_io(ARGF.current_file, write_io);
10276 }
10277 RB_GC_GUARD(filename);
10278 }
10279 if (ARGF.binmode) rb_io_ascii8bit_binmode(ARGF.current_file);
10280 GetOpenFile(ARGF.current_file, fptr);
10281 if (ARGF.encs.enc) {
10282 fptr->encs = ARGF.encs;
10283 clear_codeconv(fptr);
10284 }
10285 else {
10286 fptr->encs.ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
10287 if (!ARGF.binmode) {
10289#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
10290 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
10291#endif
10292 }
10293 }
10294 ARGF.next_p = 0;
10295 }
10296 else {
10297 ARGF.next_p = 1;
10298 return FALSE;
10299 }
10300 }
10301 else if (ARGF.next_p == -1) {
10302 ARGF.current_file = rb_stdin;
10303 ARGF.filename = rb_str_new2("-");
10304 if (ARGF.inplace) {
10305 rb_warn("Can't do inplace edit for stdio");
10306 rb_ractor_stdout_set(orig_stdout);
10307 }
10308 }
10309 if (ARGF.init_p == -1) ARGF.init_p = 1;
10310 return TRUE;
10311}
10312
10313static VALUE
10314argf_getline(int argc, VALUE *argv, VALUE argf)
10315{
10316 VALUE line;
10317 long lineno = ARGF.lineno;
10318
10319 retry:
10320 if (!next_argv()) return Qnil;
10321 if (ARGF_GENERIC_INPUT_P()) {
10322 line = forward_current(idGets, argc, argv);
10323 }
10324 else {
10325 if (argc == 0 && rb_rs == rb_default_rs) {
10326 line = rb_io_gets(ARGF.current_file);
10327 }
10328 else {
10329 line = rb_io_getline(argc, argv, ARGF.current_file);
10330 }
10331 if (NIL_P(line) && ARGF.next_p != -1) {
10332 argf_close(argf);
10333 ARGF.next_p = 1;
10334 goto retry;
10335 }
10336 }
10337 if (!NIL_P(line)) {
10338 ARGF.lineno = ++lineno;
10339 ARGF.last_lineno = ARGF.lineno;
10340 }
10341 return line;
10342}
10343
10344static VALUE
10345argf_lineno_getter(ID id, VALUE *var)
10346{
10347 VALUE argf = *var;
10348 return INT2FIX(ARGF.last_lineno);
10349}
10350
10351static void
10352argf_lineno_setter(VALUE val, ID id, VALUE *var)
10353{
10354 VALUE argf = *var;
10355 int n = NUM2INT(val);
10356 ARGF.last_lineno = ARGF.lineno = n;
10357}
10358
10359void
10360rb_reset_argf_lineno(long n)
10361{
10362 ARGF.last_lineno = ARGF.lineno = n;
10363}
10364
10365static VALUE argf_gets(int, VALUE *, VALUE);
10366
10367/*
10368 * call-seq:
10369 * gets(sep=$/ [, getline_args]) -> string or nil
10370 * gets(limit [, getline_args]) -> string or nil
10371 * gets(sep, limit [, getline_args]) -> string or nil
10372 *
10373 * Returns (and assigns to <code>$_</code>) the next line from the list
10374 * of files in +ARGV+ (or <code>$*</code>), or from standard input if
10375 * no files are present on the command line. Returns +nil+ at end of
10376 * file. The optional argument specifies the record separator. The
10377 * separator is included with the contents of each record. A separator
10378 * of +nil+ reads the entire contents, and a zero-length separator
10379 * reads the input one paragraph at a time, where paragraphs are
10380 * divided by two consecutive newlines. If the first argument is an
10381 * integer, or optional second argument is given, the returning string
10382 * would not be longer than the given value in bytes. If multiple
10383 * filenames are present in +ARGV+, <code>gets(nil)</code> will read
10384 * the contents one file at a time.
10385 *
10386 * ARGV << "testfile"
10387 * print while gets
10388 *
10389 * <em>produces:</em>
10390 *
10391 * This is line one
10392 * This is line two
10393 * This is line three
10394 * And so on...
10395 *
10396 * The style of programming using <code>$_</code> as an implicit
10397 * parameter is gradually losing favor in the Ruby community.
10398 */
10399
10400static VALUE
10401rb_f_gets(int argc, VALUE *argv, VALUE recv)
10402{
10403 if (recv == argf) {
10404 return argf_gets(argc, argv, argf);
10405 }
10406 return forward(argf, idGets, argc, argv);
10407}
10408
10409/*
10410 * call-seq:
10411 * ARGF.gets(sep=$/ [, getline_args]) -> string or nil
10412 * ARGF.gets(limit [, getline_args]) -> string or nil
10413 * ARGF.gets(sep, limit [, getline_args]) -> string or nil
10414 *
10415 * Returns the next line from the current file in ARGF.
10416 *
10417 * By default lines are assumed to be separated by <code>$/</code>;
10418 * to use a different character as a separator, supply it as a String
10419 * for the _sep_ argument.
10420 *
10421 * The optional _limit_ argument specifies how many characters of each line
10422 * to return. By default all characters are returned.
10423 *
10424 * See IO.readlines for details about getline_args.
10425 *
10426 */
10427static VALUE
10428argf_gets(int argc, VALUE *argv, VALUE argf)
10429{
10430 VALUE line;
10431
10432 line = argf_getline(argc, argv, argf);
10433 rb_lastline_set(line);
10434
10435 return line;
10436}
10437
10438VALUE
10440{
10441 VALUE line;
10442
10443 if (rb_rs != rb_default_rs) {
10444 return rb_f_gets(0, 0, argf);
10445 }
10446
10447 retry:
10448 if (!next_argv()) return Qnil;
10449 line = rb_io_gets(ARGF.current_file);
10450 if (NIL_P(line) && ARGF.next_p != -1) {
10451 rb_io_close(ARGF.current_file);
10452 ARGF.next_p = 1;
10453 goto retry;
10454 }
10455 rb_lastline_set(line);
10456 if (!NIL_P(line)) {
10457 ARGF.lineno++;
10458 ARGF.last_lineno = ARGF.lineno;
10459 }
10460
10461 return line;
10462}
10463
10464static VALUE argf_readline(int, VALUE *, VALUE);
10465
10466/*
10467 * call-seq:
10468 * readline(sep = $/, chomp: false) -> string
10469 * readline(limit, chomp: false) -> string
10470 * readline(sep, limit, chomp: false) -> string
10471 *
10472 * Equivalent to method Kernel#gets, except that it raises an exception
10473 * if called at end-of-stream:
10474 *
10475 * $ cat t.txt | ruby -e "p readlines; readline"
10476 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10477 * in `readline': end of file reached (EOFError)
10478 *
10479 * Optional keyword argument +chomp+ specifies whether line separators
10480 * are to be omitted.
10481 */
10482
10483static VALUE
10484rb_f_readline(int argc, VALUE *argv, VALUE recv)
10485{
10486 if (recv == argf) {
10487 return argf_readline(argc, argv, argf);
10488 }
10489 return forward(argf, rb_intern("readline"), argc, argv);
10490}
10491
10492
10493/*
10494 * call-seq:
10495 * ARGF.readline(sep=$/) -> string
10496 * ARGF.readline(limit) -> string
10497 * ARGF.readline(sep, limit) -> string
10498 *
10499 * Returns the next line from the current file in ARGF.
10500 *
10501 * By default lines are assumed to be separated by <code>$/</code>;
10502 * to use a different character as a separator, supply it as a String
10503 * for the _sep_ argument.
10504 *
10505 * The optional _limit_ argument specifies how many characters of each line
10506 * to return. By default all characters are returned.
10507 *
10508 * An EOFError is raised at the end of the file.
10509 */
10510static VALUE
10511argf_readline(int argc, VALUE *argv, VALUE argf)
10512{
10513 VALUE line;
10514
10515 if (!next_argv()) rb_eof_error();
10516 ARGF_FORWARD(argc, argv);
10517 line = argf_gets(argc, argv, argf);
10518 if (NIL_P(line)) {
10519 rb_eof_error();
10520 }
10521
10522 return line;
10523}
10524
10525static VALUE argf_readlines(int, VALUE *, VALUE);
10526
10527/*
10528 * call-seq:
10529 * readlines(sep = $/, chomp: false, **enc_opts) -> array
10530 * readlines(limit, chomp: false, **enc_opts) -> array
10531 * readlines(sep, limit, chomp: false, **enc_opts) -> array
10532 *
10533 * Returns an array containing the lines returned by calling
10534 * Kernel#gets until the end-of-stream is reached;
10535 * (see {Line IO}[rdoc-ref:IO@Line+IO]).
10536 *
10537 * With only string argument +sep+ given,
10538 * returns the remaining lines as determined by line separator +sep+,
10539 * or +nil+ if none;
10540 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
10541 *
10542 * # Default separator.
10543 * $ cat t.txt | ruby -e "p readlines"
10544 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10545 *
10546 * # Specified separator.
10547 * $ cat t.txt | ruby -e "p readlines 'li'"
10548 * ["First li", "ne\nSecond li", "ne\n\nFourth li", "ne\nFifth li", "ne\n"]
10549 *
10550 * # Get-all separator.
10551 * $ cat t.txt | ruby -e "p readlines nil"
10552 * ["First line\nSecond line\n\nFourth line\nFifth line\n"]
10553 *
10554 * # Get-paragraph separator.
10555 * $ cat t.txt | ruby -e "p readlines ''"
10556 * ["First line\nSecond line\n\n", "Fourth line\nFifth line\n"]
10557 *
10558 * With only integer argument +limit+ given,
10559 * limits the number of bytes in the line;
10560 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
10561 *
10562 * $cat t.txt | ruby -e "p readlines 10"
10563 * ["First line", "\n", "Second lin", "e\n", "\n", "Fourth lin", "e\n", "Fifth line", "\n"]
10564 *
10565 * $cat t.txt | ruby -e "p readlines 11"
10566 * ["First line\n", "Second line", "\n", "\n", "Fourth line", "\n", "Fifth line\n"]
10567 *
10568 * $cat t.txt | ruby -e "p readlines 12"
10569 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10570 *
10571 * With arguments +sep+ and +limit+ given,
10572 * combines the two behaviors
10573 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
10574 *
10575 * Optional keyword argument +chomp+ specifies whether line separators
10576 * are to be omitted:
10577 *
10578 * $ cat t.txt | ruby -e "p readlines(chomp: true)"
10579 * ["First line", "Second line", "", "Fourth line", "Fifth line"]
10580 *
10581 * Optional keyword arguments +enc_opts+ specify encoding options;
10582 * see {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
10583 *
10584 */
10585
10586static VALUE
10587rb_f_readlines(int argc, VALUE *argv, VALUE recv)
10588{
10589 if (recv == argf) {
10590 return argf_readlines(argc, argv, argf);
10591 }
10592 return forward(argf, rb_intern("readlines"), argc, argv);
10593}
10594
10595/*
10596 * call-seq:
10597 * ARGF.readlines(sep = $/, chomp: false) -> array
10598 * ARGF.readlines(limit, chomp: false) -> array
10599 * ARGF.readlines(sep, limit, chomp: false) -> array
10600 *
10601 * ARGF.to_a(sep = $/, chomp: false) -> array
10602 * ARGF.to_a(limit, chomp: false) -> array
10603 * ARGF.to_a(sep, limit, chomp: false) -> array
10604 *
10605 * Reads each file in ARGF in its entirety, returning an Array containing
10606 * lines from the files. Lines are assumed to be separated by _sep_.
10607 *
10608 * lines = ARGF.readlines
10609 * lines[0] #=> "This is line one\n"
10610 *
10611 * See +IO.readlines+ for a full description of all options.
10612 */
10613static VALUE
10614argf_readlines(int argc, VALUE *argv, VALUE argf)
10615{
10616 long lineno = ARGF.lineno;
10617 VALUE lines, ary;
10618
10619 ary = rb_ary_new();
10620 while (next_argv()) {
10621 if (ARGF_GENERIC_INPUT_P()) {
10622 lines = forward_current(rb_intern("readlines"), argc, argv);
10623 }
10624 else {
10625 lines = rb_io_readlines(argc, argv, ARGF.current_file);
10626 argf_close(argf);
10627 }
10628 ARGF.next_p = 1;
10629 rb_ary_concat(ary, lines);
10630 ARGF.lineno = lineno + RARRAY_LEN(ary);
10631 ARGF.last_lineno = ARGF.lineno;
10632 }
10633 ARGF.init_p = 0;
10634 return ary;
10635}
10636
10637/*
10638 * call-seq:
10639 * `command` -> string
10640 *
10641 * Returns the <tt>$stdout</tt> output from running +command+ in a subshell;
10642 * sets global variable <tt>$?</tt> to the process status.
10643 *
10644 * This method has potential security vulnerabilities if called with untrusted input;
10645 * see {Command Injection}[rdoc-ref:security/command_injection.rdoc].
10646 *
10647 * Examples:
10648 *
10649 * $ `date` # => "Wed Apr 9 08:56:30 CDT 2003\n"
10650 * $ `echo oops && exit 99` # => "oops\n"
10651 * $ $? # => #<Process::Status: pid 17088 exit 99>
10652 * $ $?.exitstatus # => 99
10653 *
10654 * The built-in syntax <tt>%x{...}</tt> uses this method.
10655 *
10656 */
10657
10658static VALUE
10659rb_f_backquote(VALUE obj, VALUE str)
10660{
10661 VALUE port;
10662 VALUE result;
10663 rb_io_t *fptr;
10664
10665 StringValue(str);
10666 rb_last_status_clear();
10667 port = pipe_open_s(str, "r", FMODE_READABLE|DEFAULT_TEXTMODE, NULL);
10668 if (NIL_P(port)) return rb_str_new(0,0);
10669
10670 GetOpenFile(port, fptr);
10671 result = read_all(fptr, remain_size(fptr), Qnil);
10672 rb_io_close(port);
10673 rb_io_fptr_cleanup_all(fptr);
10674 RB_GC_GUARD(port);
10675
10676 return result;
10677}
10678
10679#ifdef HAVE_SYS_SELECT_H
10680#include <sys/select.h>
10681#endif
10682
10683static VALUE
10684select_internal(VALUE read, VALUE write, VALUE except, struct timeval *tp, rb_fdset_t *fds)
10685{
10686 VALUE res, list;
10687 rb_fdset_t *rp, *wp, *ep;
10688 rb_io_t *fptr;
10689 long i;
10690 int max = 0, n;
10691 int pending = 0;
10692 struct timeval timerec;
10693
10694 if (!NIL_P(read)) {
10695 Check_Type(read, T_ARRAY);
10696 for (i=0; i<RARRAY_LEN(read); i++) {
10697 GetOpenFile(rb_io_get_io(RARRAY_AREF(read, i)), fptr);
10698 rb_fd_set(fptr->fd, &fds[0]);
10699 if (READ_DATA_PENDING(fptr) || READ_CHAR_PENDING(fptr)) { /* check for buffered data */
10700 pending++;
10701 rb_fd_set(fptr->fd, &fds[3]);
10702 }
10703 if (max < fptr->fd) max = fptr->fd;
10704 }
10705 if (pending) { /* no blocking if there's buffered data */
10706 timerec.tv_sec = timerec.tv_usec = 0;
10707 tp = &timerec;
10708 }
10709 rp = &fds[0];
10710 }
10711 else
10712 rp = 0;
10713
10714 if (!NIL_P(write)) {
10715 Check_Type(write, T_ARRAY);
10716 for (i=0; i<RARRAY_LEN(write); i++) {
10717 VALUE write_io = GetWriteIO(rb_io_get_io(RARRAY_AREF(write, i)));
10718 GetOpenFile(write_io, fptr);
10719 rb_fd_set(fptr->fd, &fds[1]);
10720 if (max < fptr->fd) max = fptr->fd;
10721 }
10722 wp = &fds[1];
10723 }
10724 else
10725 wp = 0;
10726
10727 if (!NIL_P(except)) {
10728 Check_Type(except, T_ARRAY);
10729 for (i=0; i<RARRAY_LEN(except); i++) {
10730 VALUE io = rb_io_get_io(RARRAY_AREF(except, i));
10731 VALUE write_io = GetWriteIO(io);
10732 GetOpenFile(io, fptr);
10733 rb_fd_set(fptr->fd, &fds[2]);
10734 if (max < fptr->fd) max = fptr->fd;
10735 if (io != write_io) {
10736 GetOpenFile(write_io, fptr);
10737 rb_fd_set(fptr->fd, &fds[2]);
10738 if (max < fptr->fd) max = fptr->fd;
10739 }
10740 }
10741 ep = &fds[2];
10742 }
10743 else {
10744 ep = 0;
10745 }
10746
10747 max++;
10748
10749 n = rb_thread_fd_select(max, rp, wp, ep, tp);
10750 if (n < 0) {
10751 rb_sys_fail(0);
10752 }
10753 if (!pending && n == 0) return Qnil; /* returns nil on timeout */
10754
10755 res = rb_ary_new2(3);
10756 rb_ary_push(res, rp?rb_ary_new():rb_ary_new2(0));
10757 rb_ary_push(res, wp?rb_ary_new():rb_ary_new2(0));
10758 rb_ary_push(res, ep?rb_ary_new():rb_ary_new2(0));
10759
10760 if (rp) {
10761 list = RARRAY_AREF(res, 0);
10762 for (i=0; i< RARRAY_LEN(read); i++) {
10763 VALUE obj = rb_ary_entry(read, i);
10764 VALUE io = rb_io_get_io(obj);
10765 GetOpenFile(io, fptr);
10766 if (rb_fd_isset(fptr->fd, &fds[0]) ||
10767 rb_fd_isset(fptr->fd, &fds[3])) {
10768 rb_ary_push(list, obj);
10769 }
10770 }
10771 }
10772
10773 if (wp) {
10774 list = RARRAY_AREF(res, 1);
10775 for (i=0; i< RARRAY_LEN(write); i++) {
10776 VALUE obj = rb_ary_entry(write, i);
10777 VALUE io = rb_io_get_io(obj);
10778 VALUE write_io = GetWriteIO(io);
10779 GetOpenFile(write_io, fptr);
10780 if (rb_fd_isset(fptr->fd, &fds[1])) {
10781 rb_ary_push(list, obj);
10782 }
10783 }
10784 }
10785
10786 if (ep) {
10787 list = RARRAY_AREF(res, 2);
10788 for (i=0; i< RARRAY_LEN(except); i++) {
10789 VALUE obj = rb_ary_entry(except, i);
10790 VALUE io = rb_io_get_io(obj);
10791 VALUE write_io = GetWriteIO(io);
10792 GetOpenFile(io, fptr);
10793 if (rb_fd_isset(fptr->fd, &fds[2])) {
10794 rb_ary_push(list, obj);
10795 }
10796 else if (io != write_io) {
10797 GetOpenFile(write_io, fptr);
10798 if (rb_fd_isset(fptr->fd, &fds[2])) {
10799 rb_ary_push(list, obj);
10800 }
10801 }
10802 }
10803 }
10804
10805 return res; /* returns an empty array on interrupt */
10806}
10807
10809 VALUE read, write, except;
10810 struct timeval *timeout;
10811 rb_fdset_t fdsets[4];
10812};
10813
10814static VALUE
10815select_call(VALUE arg)
10816{
10817 struct select_args *p = (struct select_args *)arg;
10818
10819 return select_internal(p->read, p->write, p->except, p->timeout, p->fdsets);
10820}
10821
10822static VALUE
10823select_end(VALUE arg)
10824{
10825 struct select_args *p = (struct select_args *)arg;
10826 int i;
10827
10828 for (i = 0; i < numberof(p->fdsets); ++i)
10829 rb_fd_term(&p->fdsets[i]);
10830 return Qnil;
10831}
10832
10833static VALUE sym_normal, sym_sequential, sym_random,
10834 sym_willneed, sym_dontneed, sym_noreuse;
10835
10836#ifdef HAVE_POSIX_FADVISE
10837struct io_advise_struct {
10838 int fd;
10839 int advice;
10840 rb_off_t offset;
10841 rb_off_t len;
10842};
10843
10844static VALUE
10845io_advise_internal(void *arg)
10846{
10847 struct io_advise_struct *ptr = arg;
10848 return posix_fadvise(ptr->fd, ptr->offset, ptr->len, ptr->advice);
10849}
10850
10851static VALUE
10852io_advise_sym_to_const(VALUE sym)
10853{
10854#ifdef POSIX_FADV_NORMAL
10855 if (sym == sym_normal)
10856 return INT2NUM(POSIX_FADV_NORMAL);
10857#endif
10858
10859#ifdef POSIX_FADV_RANDOM
10860 if (sym == sym_random)
10861 return INT2NUM(POSIX_FADV_RANDOM);
10862#endif
10863
10864#ifdef POSIX_FADV_SEQUENTIAL
10865 if (sym == sym_sequential)
10866 return INT2NUM(POSIX_FADV_SEQUENTIAL);
10867#endif
10868
10869#ifdef POSIX_FADV_WILLNEED
10870 if (sym == sym_willneed)
10871 return INT2NUM(POSIX_FADV_WILLNEED);
10872#endif
10873
10874#ifdef POSIX_FADV_DONTNEED
10875 if (sym == sym_dontneed)
10876 return INT2NUM(POSIX_FADV_DONTNEED);
10877#endif
10878
10879#ifdef POSIX_FADV_NOREUSE
10880 if (sym == sym_noreuse)
10881 return INT2NUM(POSIX_FADV_NOREUSE);
10882#endif
10883
10884 return Qnil;
10885}
10886
10887static VALUE
10888do_io_advise(rb_io_t *fptr, VALUE advice, rb_off_t offset, rb_off_t len)
10889{
10890 int rv;
10891 struct io_advise_struct ias;
10892 VALUE num_adv;
10893
10894 num_adv = io_advise_sym_to_const(advice);
10895
10896 /*
10897 * The platform doesn't support this hint. We don't raise exception, instead
10898 * silently ignore it. Because IO::advise is only hint.
10899 */
10900 if (NIL_P(num_adv))
10901 return Qnil;
10902
10903 ias.fd = fptr->fd;
10904 ias.advice = NUM2INT(num_adv);
10905 ias.offset = offset;
10906 ias.len = len;
10907
10908 rv = (int)rb_io_blocking_region(fptr, io_advise_internal, &ias);
10909 if (rv && rv != ENOSYS) {
10910 /* posix_fadvise(2) doesn't set errno. On success it returns 0; otherwise
10911 it returns the error code. */
10912 VALUE message = rb_sprintf("%"PRIsVALUE" "
10913 "(%"PRI_OFFT_PREFIX"d, "
10914 "%"PRI_OFFT_PREFIX"d, "
10915 "%"PRIsVALUE")",
10916 fptr->pathv, offset, len, advice);
10917 rb_syserr_fail_str(rv, message);
10918 }
10919
10920 return Qnil;
10921}
10922
10923#endif /* HAVE_POSIX_FADVISE */
10924
10925static void
10926advice_arg_check(VALUE advice)
10927{
10928 if (!SYMBOL_P(advice))
10929 rb_raise(rb_eTypeError, "advice must be a Symbol");
10930
10931 if (advice != sym_normal &&
10932 advice != sym_sequential &&
10933 advice != sym_random &&
10934 advice != sym_willneed &&
10935 advice != sym_dontneed &&
10936 advice != sym_noreuse) {
10937 rb_raise(rb_eNotImpError, "Unsupported advice: %+"PRIsVALUE, advice);
10938 }
10939}
10940
10941/*
10942 * call-seq:
10943 * advise(advice, offset = 0, len = 0) -> nil
10944 *
10945 * Invokes Posix system call
10946 * {posix_fadvise(2)}[https://linux.die.net/man/2/posix_fadvise],
10947 * which announces an intention to access data from the current file
10948 * in a particular manner.
10949 *
10950 * The arguments and results are platform-dependent.
10951 *
10952 * The relevant data is specified by:
10953 *
10954 * - +offset+: The offset of the first byte of data.
10955 * - +len+: The number of bytes to be accessed;
10956 * if +len+ is zero, or is larger than the number of bytes remaining,
10957 * all remaining bytes will be accessed.
10958 *
10959 * Argument +advice+ is one of the following symbols:
10960 *
10961 * - +:normal+: The application has no advice to give
10962 * about its access pattern for the specified data.
10963 * If no advice is given for an open file, this is the default assumption.
10964 * - +:sequential+: The application expects to access the specified data sequentially
10965 * (with lower offsets read before higher ones).
10966 * - +:random+: The specified data will be accessed in random order.
10967 * - +:noreuse+: The specified data will be accessed only once.
10968 * - +:willneed+: The specified data will be accessed in the near future.
10969 * - +:dontneed+: The specified data will not be accessed in the near future.
10970 *
10971 * Not implemented on all platforms.
10972 *
10973 */
10974static VALUE
10975rb_io_advise(int argc, VALUE *argv, VALUE io)
10976{
10977 VALUE advice, offset, len;
10978 rb_off_t off, l;
10979 rb_io_t *fptr;
10980
10981 rb_scan_args(argc, argv, "12", &advice, &offset, &len);
10982 advice_arg_check(advice);
10983
10984 io = GetWriteIO(io);
10985 GetOpenFile(io, fptr);
10986
10987 off = NIL_P(offset) ? 0 : NUM2OFFT(offset);
10988 l = NIL_P(len) ? 0 : NUM2OFFT(len);
10989
10990#ifdef HAVE_POSIX_FADVISE
10991 return do_io_advise(fptr, advice, off, l);
10992#else
10993 ((void)off, (void)l); /* Ignore all hint */
10994 return Qnil;
10995#endif
10996}
10997
10998static int
10999is_pos_inf(VALUE x)
11000{
11001 double f;
11002 if (!RB_FLOAT_TYPE_P(x))
11003 return 0;
11004 f = RFLOAT_VALUE(x);
11005 return isinf(f) && 0 < f;
11006}
11007
11008/*
11009 * call-seq:
11010 * IO.select(read_ios, write_ios = [], error_ios = [], timeout = nil) -> array or nil
11011 *
11012 * Invokes system call {select(2)}[https://linux.die.net/man/2/select],
11013 * which monitors multiple file descriptors,
11014 * waiting until one or more of the file descriptors
11015 * becomes ready for some class of I/O operation.
11016 *
11017 * Not implemented on all platforms.
11018 *
11019 * Each of the arguments +read_ios+, +write_ios+, and +error_ios+
11020 * is an array of IO objects.
11021 *
11022 * Argument +timeout+ is a numeric value (such as integer or float) timeout
11023 * interval in seconds.
11024 * +timeout+ can also be +nil+ or +Float::INFINITY+.
11025 * +nil+ and +Float::INFINITY+ means no timeout.
11026 *
11027 * The method monitors the \IO objects given in all three arrays,
11028 * waiting for some to be ready;
11029 * returns a 3-element array whose elements are:
11030 *
11031 * - An array of the objects in +read_ios+ that are ready for reading.
11032 * - An array of the objects in +write_ios+ that are ready for writing.
11033 * - An array of the objects in +error_ios+ have pending exceptions.
11034 *
11035 * If no object becomes ready within the given +timeout+, +nil+ is returned.
11036 *
11037 * \IO.select peeks the buffer of \IO objects for testing readability.
11038 * If the \IO buffer is not empty, \IO.select immediately notifies
11039 * readability. This "peek" only happens for \IO objects. It does not
11040 * happen for IO-like objects such as OpenSSL::SSL::SSLSocket.
11041 *
11042 * The best way to use \IO.select is invoking it after non-blocking
11043 * methods such as #read_nonblock, #write_nonblock, etc. The methods
11044 * raise an exception which is extended by IO::WaitReadable or
11045 * IO::WaitWritable. The modules notify how the caller should wait
11046 * with \IO.select. If IO::WaitReadable is raised, the caller should
11047 * wait for reading. If IO::WaitWritable is raised, the caller should
11048 * wait for writing.
11049 *
11050 * So, blocking read (#readpartial) can be emulated using
11051 * #read_nonblock and \IO.select as follows:
11052 *
11053 * begin
11054 * result = io_like.read_nonblock(maxlen)
11055 * rescue IO::WaitReadable
11056 * IO.select([io_like])
11057 * retry
11058 * rescue IO::WaitWritable
11059 * IO.select(nil, [io_like])
11060 * retry
11061 * end
11062 *
11063 * Especially, the combination of non-blocking methods and \IO.select is
11064 * preferred for IO like objects such as OpenSSL::SSL::SSLSocket. It
11065 * has #to_io method to return underlying IO object. IO.select calls
11066 * #to_io to obtain the file descriptor to wait.
11067 *
11068 * This means that readability notified by \IO.select doesn't mean
11069 * readability from OpenSSL::SSL::SSLSocket object.
11070 *
11071 * The most likely situation is that OpenSSL::SSL::SSLSocket buffers
11072 * some data. \IO.select doesn't see the buffer. So \IO.select can
11073 * block when OpenSSL::SSL::SSLSocket#readpartial doesn't block.
11074 *
11075 * However, several more complicated situations exist.
11076 *
11077 * SSL is a protocol which is sequence of records.
11078 * The record consists of multiple bytes.
11079 * So, the remote side of SSL sends a partial record, IO.select
11080 * notifies readability but OpenSSL::SSL::SSLSocket cannot decrypt a
11081 * byte and OpenSSL::SSL::SSLSocket#readpartial will block.
11082 *
11083 * Also, the remote side can request SSL renegotiation which forces
11084 * the local SSL engine to write some data.
11085 * This means OpenSSL::SSL::SSLSocket#readpartial may invoke #write
11086 * system call and it can block.
11087 * In such a situation, OpenSSL::SSL::SSLSocket#read_nonblock raises
11088 * IO::WaitWritable instead of blocking.
11089 * So, the caller should wait for ready for writability as above
11090 * example.
11091 *
11092 * The combination of non-blocking methods and \IO.select is also useful
11093 * for streams such as tty, pipe socket socket when multiple processes
11094 * read from a stream.
11095 *
11096 * Finally, Linux kernel developers don't guarantee that
11097 * readability of select(2) means readability of following read(2) even
11098 * for a single process;
11099 * see {select(2)}[https://linux.die.net/man/2/select]
11100 *
11101 * Invoking \IO.select before IO#readpartial works well as usual.
11102 * However it is not the best way to use \IO.select.
11103 *
11104 * The writability notified by select(2) doesn't show
11105 * how many bytes are writable.
11106 * IO#write method blocks until given whole string is written.
11107 * So, <tt>IO#write(two or more bytes)</tt> can block after
11108 * writability is notified by \IO.select. IO#write_nonblock is required
11109 * to avoid the blocking.
11110 *
11111 * Blocking write (#write) can be emulated using #write_nonblock and
11112 * IO.select as follows: IO::WaitReadable should also be rescued for
11113 * SSL renegotiation in OpenSSL::SSL::SSLSocket.
11114 *
11115 * while 0 < string.bytesize
11116 * begin
11117 * written = io_like.write_nonblock(string)
11118 * rescue IO::WaitReadable
11119 * IO.select([io_like])
11120 * retry
11121 * rescue IO::WaitWritable
11122 * IO.select(nil, [io_like])
11123 * retry
11124 * end
11125 * string = string.byteslice(written..-1)
11126 * end
11127 *
11128 * Example:
11129 *
11130 * rp, wp = IO.pipe
11131 * mesg = "ping "
11132 * 100.times {
11133 * # IO.select follows IO#read. Not the best way to use IO.select.
11134 * rs, ws, = IO.select([rp], [wp])
11135 * if r = rs[0]
11136 * ret = r.read(5)
11137 * print ret
11138 * case ret
11139 * when /ping/
11140 * mesg = "pong\n"
11141 * when /pong/
11142 * mesg = "ping "
11143 * end
11144 * end
11145 * if w = ws[0]
11146 * w.write(mesg)
11147 * end
11148 * }
11149 *
11150 * Output:
11151 *
11152 * ping pong
11153 * ping pong
11154 * ping pong
11155 * (snipped)
11156 * ping
11157 *
11158 */
11159
11160static VALUE
11161rb_f_select(int argc, VALUE *argv, VALUE obj)
11162{
11163 VALUE scheduler = rb_fiber_scheduler_current();
11164 if (scheduler != Qnil) {
11165 // It's optionally supported.
11166 VALUE result = rb_fiber_scheduler_io_selectv(scheduler, argc, argv);
11167 if (!UNDEF_P(result)) return result;
11168 }
11169
11170 VALUE timeout;
11171 struct select_args args;
11172 struct timeval timerec;
11173 int i;
11174
11175 rb_scan_args(argc, argv, "13", &args.read, &args.write, &args.except, &timeout);
11176 if (NIL_P(timeout) || is_pos_inf(timeout)) {
11177 args.timeout = 0;
11178 }
11179 else {
11180 timerec = rb_time_interval(timeout);
11181 args.timeout = &timerec;
11182 }
11183
11184 for (i = 0; i < numberof(args.fdsets); ++i)
11185 rb_fd_init(&args.fdsets[i]);
11186
11187 return rb_ensure(select_call, (VALUE)&args, select_end, (VALUE)&args);
11188}
11189
11190#ifdef IOCTL_REQ_TYPE
11191 typedef IOCTL_REQ_TYPE ioctl_req_t;
11192#else
11193 typedef int ioctl_req_t;
11194# define NUM2IOCTLREQ(num) ((int)NUM2LONG(num))
11195#endif
11196
11197#ifdef HAVE_IOCTL
11198struct ioctl_arg {
11199 int fd;
11200 ioctl_req_t cmd;
11201 long narg;
11202};
11203
11204static VALUE
11205nogvl_ioctl(void *ptr)
11206{
11207 struct ioctl_arg *arg = ptr;
11208
11209 return (VALUE)ioctl(arg->fd, arg->cmd, arg->narg);
11210}
11211
11212static int
11213do_ioctl(struct rb_io *io, ioctl_req_t cmd, long narg)
11214{
11215 int retval;
11216 struct ioctl_arg arg;
11217
11218 arg.fd = io->fd;
11219 arg.cmd = cmd;
11220 arg.narg = narg;
11221
11222 retval = (int)rb_io_blocking_region(io, nogvl_ioctl, &arg);
11223
11224 return retval;
11225}
11226#endif
11227
11228#define DEFAULT_IOCTL_NARG_LEN (256)
11229
11230#if defined(__linux__) && defined(_IOC_SIZE)
11231static long
11232linux_iocparm_len(ioctl_req_t cmd)
11233{
11234 long len;
11235
11236 if ((cmd & 0xFFFF0000) == 0) {
11237 /* legacy and unstructured ioctl number. */
11238 return DEFAULT_IOCTL_NARG_LEN;
11239 }
11240
11241 len = _IOC_SIZE(cmd);
11242
11243 /* paranoia check for silly drivers which don't keep ioctl convention */
11244 if (len < DEFAULT_IOCTL_NARG_LEN)
11245 len = DEFAULT_IOCTL_NARG_LEN;
11246
11247 return len;
11248}
11249#endif
11250
11251#ifdef HAVE_IOCTL
11252static long
11253ioctl_narg_len(ioctl_req_t cmd)
11254{
11255 long len;
11256
11257#ifdef IOCPARM_MASK
11258#ifndef IOCPARM_LEN
11259#define IOCPARM_LEN(x) (((x) >> 16) & IOCPARM_MASK)
11260#endif
11261#endif
11262#ifdef IOCPARM_LEN
11263 len = IOCPARM_LEN(cmd); /* on BSDish systems we're safe */
11264#elif defined(__linux__) && defined(_IOC_SIZE)
11265 len = linux_iocparm_len(cmd);
11266#else
11267 /* otherwise guess at what's safe */
11268 len = DEFAULT_IOCTL_NARG_LEN;
11269#endif
11270
11271 return len;
11272}
11273#endif
11274
11275#ifdef HAVE_FCNTL
11276#ifdef __linux__
11277typedef long fcntl_arg_t;
11278#else
11279/* posix */
11280typedef int fcntl_arg_t;
11281#endif
11282
11283static long
11284fcntl_narg_len(ioctl_req_t cmd)
11285{
11286 long len;
11287
11288 switch (cmd) {
11289#ifdef F_DUPFD
11290 case F_DUPFD:
11291 len = sizeof(fcntl_arg_t);
11292 break;
11293#endif
11294#ifdef F_DUP2FD /* bsd specific */
11295 case F_DUP2FD:
11296 len = sizeof(int);
11297 break;
11298#endif
11299#ifdef F_DUPFD_CLOEXEC /* linux specific */
11300 case F_DUPFD_CLOEXEC:
11301 len = sizeof(fcntl_arg_t);
11302 break;
11303#endif
11304#ifdef F_GETFD
11305 case F_GETFD:
11306 len = 1;
11307 break;
11308#endif
11309#ifdef F_SETFD
11310 case F_SETFD:
11311 len = sizeof(fcntl_arg_t);
11312 break;
11313#endif
11314#ifdef F_GETFL
11315 case F_GETFL:
11316 len = 1;
11317 break;
11318#endif
11319#ifdef F_SETFL
11320 case F_SETFL:
11321 len = sizeof(fcntl_arg_t);
11322 break;
11323#endif
11324#ifdef F_GETOWN
11325 case F_GETOWN:
11326 len = 1;
11327 break;
11328#endif
11329#ifdef F_SETOWN
11330 case F_SETOWN:
11331 len = sizeof(fcntl_arg_t);
11332 break;
11333#endif
11334#ifdef F_GETOWN_EX /* linux specific */
11335 case F_GETOWN_EX:
11336 len = sizeof(struct f_owner_ex);
11337 break;
11338#endif
11339#ifdef F_SETOWN_EX /* linux specific */
11340 case F_SETOWN_EX:
11341 len = sizeof(struct f_owner_ex);
11342 break;
11343#endif
11344#ifdef F_GETLK
11345 case F_GETLK:
11346 len = sizeof(struct flock);
11347 break;
11348#endif
11349#ifdef F_SETLK
11350 case F_SETLK:
11351 len = sizeof(struct flock);
11352 break;
11353#endif
11354#ifdef F_SETLKW
11355 case F_SETLKW:
11356 len = sizeof(struct flock);
11357 break;
11358#endif
11359#ifdef F_READAHEAD /* bsd specific */
11360 case F_READAHEAD:
11361 len = sizeof(int);
11362 break;
11363#endif
11364#ifdef F_RDAHEAD /* Darwin specific */
11365 case F_RDAHEAD:
11366 len = sizeof(int);
11367 break;
11368#endif
11369#ifdef F_GETSIG /* linux specific */
11370 case F_GETSIG:
11371 len = 1;
11372 break;
11373#endif
11374#ifdef F_SETSIG /* linux specific */
11375 case F_SETSIG:
11376 len = sizeof(fcntl_arg_t);
11377 break;
11378#endif
11379#ifdef F_GETLEASE /* linux specific */
11380 case F_GETLEASE:
11381 len = 1;
11382 break;
11383#endif
11384#ifdef F_SETLEASE /* linux specific */
11385 case F_SETLEASE:
11386 len = sizeof(fcntl_arg_t);
11387 break;
11388#endif
11389#ifdef F_NOTIFY /* linux specific */
11390 case F_NOTIFY:
11391 len = sizeof(fcntl_arg_t);
11392 break;
11393#endif
11394
11395 default:
11396 len = 256;
11397 break;
11398 }
11399
11400 return len;
11401}
11402#else /* HAVE_FCNTL */
11403static long
11404fcntl_narg_len(ioctl_req_t cmd)
11405{
11406 return 0;
11407}
11408#endif /* HAVE_FCNTL */
11409
11410#define NARG_SENTINEL 17
11411
11412static long
11413setup_narg(ioctl_req_t cmd, VALUE *argp, long (*narg_len)(ioctl_req_t))
11414{
11415 long narg = 0;
11416 VALUE arg = *argp;
11417
11418 if (!RTEST(arg)) {
11419 narg = 0;
11420 }
11421 else if (FIXNUM_P(arg)) {
11422 narg = FIX2LONG(arg);
11423 }
11424 else if (arg == Qtrue) {
11425 narg = 1;
11426 }
11427 else {
11428 VALUE tmp = rb_check_string_type(arg);
11429
11430 if (NIL_P(tmp)) {
11431 narg = NUM2LONG(arg);
11432 }
11433 else {
11434 char *ptr;
11435 long len, slen;
11436
11437 *argp = arg = tmp;
11438 len = narg_len(cmd);
11439 rb_str_modify(arg);
11440
11441 slen = RSTRING_LEN(arg);
11442 /* expand for data + sentinel. */
11443 if (slen < len+1) {
11444 rb_str_resize(arg, len+1);
11445 MEMZERO(RSTRING_PTR(arg)+slen, char, len-slen);
11446 slen = len+1;
11447 }
11448 /* a little sanity check here */
11449 ptr = RSTRING_PTR(arg);
11450 ptr[slen - 1] = NARG_SENTINEL;
11451 narg = (long)(SIGNED_VALUE)ptr;
11452 }
11453 }
11454
11455 return narg;
11456}
11457
11458static VALUE
11459finish_narg(int retval, VALUE arg, const rb_io_t *fptr)
11460{
11461 if (retval < 0) rb_sys_fail_path(fptr->pathv);
11462 if (RB_TYPE_P(arg, T_STRING)) {
11463 char *ptr;
11464 long slen;
11465 RSTRING_GETMEM(arg, ptr, slen);
11466 if (ptr[slen-1] != NARG_SENTINEL)
11467 rb_raise(rb_eArgError, "return value overflowed string");
11468 ptr[slen-1] = '\0';
11469 }
11470
11471 return INT2NUM(retval);
11472}
11473
11474#ifdef HAVE_IOCTL
11475static VALUE
11476rb_ioctl(VALUE io, VALUE req, VALUE arg)
11477{
11478 ioctl_req_t cmd = NUM2IOCTLREQ(req);
11479 rb_io_t *fptr;
11480 long narg;
11481 int retval;
11482
11483 narg = setup_narg(cmd, &arg, ioctl_narg_len);
11484 GetOpenFile(io, fptr);
11485 retval = do_ioctl(fptr, cmd, narg);
11486 return finish_narg(retval, arg, fptr);
11487}
11488
11489/*
11490 * call-seq:
11491 * ioctl(integer_cmd, argument) -> integer
11492 *
11493 * Invokes Posix system call {ioctl(2)}[https://linux.die.net/man/2/ioctl],
11494 * which issues a low-level command to an I/O device.
11495 *
11496 * Issues a low-level command to an I/O device.
11497 * The arguments and returned value are platform-dependent.
11498 * The effect of the call is platform-dependent.
11499 *
11500 * If argument +argument+ is an integer, it is passed directly;
11501 * if it is a string, it is interpreted as a binary sequence of bytes.
11502 *
11503 * Not implemented on all platforms.
11504 *
11505 */
11506
11507static VALUE
11508rb_io_ioctl(int argc, VALUE *argv, VALUE io)
11509{
11510 VALUE req, arg;
11511
11512 rb_scan_args(argc, argv, "11", &req, &arg);
11513 return rb_ioctl(io, req, arg);
11514}
11515#else
11516#define rb_io_ioctl rb_f_notimplement
11517#endif
11518
11519#ifdef HAVE_FCNTL
11520struct fcntl_arg {
11521 int fd;
11522 int cmd;
11523 long narg;
11524};
11525
11526static VALUE
11527nogvl_fcntl(void *ptr)
11528{
11529 struct fcntl_arg *arg = ptr;
11530
11531#if defined(F_DUPFD)
11532 if (arg->cmd == F_DUPFD)
11533 return (VALUE)rb_cloexec_fcntl_dupfd(arg->fd, (int)arg->narg);
11534#endif
11535 return (VALUE)fcntl(arg->fd, arg->cmd, arg->narg);
11536}
11537
11538static int
11539do_fcntl(struct rb_io *io, int cmd, long narg)
11540{
11541 int retval;
11542 struct fcntl_arg arg;
11543
11544 arg.fd = io->fd;
11545 arg.cmd = cmd;
11546 arg.narg = narg;
11547
11548 retval = (int)rb_io_blocking_region(io, nogvl_fcntl, &arg);
11549 if (retval != -1) {
11550 switch (cmd) {
11551#if defined(F_DUPFD)
11552 case F_DUPFD:
11553#endif
11554#if defined(F_DUPFD_CLOEXEC)
11555 case F_DUPFD_CLOEXEC:
11556#endif
11557 rb_update_max_fd(retval);
11558 }
11559 }
11560
11561 return retval;
11562}
11563
11564static VALUE
11565rb_fcntl(VALUE io, VALUE req, VALUE arg)
11566{
11567 int cmd = NUM2INT(req);
11568 rb_io_t *fptr;
11569 long narg;
11570 int retval;
11571
11572 narg = setup_narg(cmd, &arg, fcntl_narg_len);
11573 GetOpenFile(io, fptr);
11574 retval = do_fcntl(fptr, cmd, narg);
11575 return finish_narg(retval, arg, fptr);
11576}
11577
11578/*
11579 * call-seq:
11580 * fcntl(integer_cmd, argument) -> integer
11581 *
11582 * Invokes Posix system call {fcntl(2)}[https://linux.die.net/man/2/fcntl],
11583 * which provides a mechanism for issuing low-level commands to control or query
11584 * a file-oriented I/O stream. Arguments and results are platform
11585 * dependent.
11586 *
11587 * If +argument+ is a number, its value is passed directly;
11588 * if it is a string, it is interpreted as a binary sequence of bytes.
11589 * (Array#pack might be a useful way to build this string.)
11590 *
11591 * Not implemented on all platforms.
11592 *
11593 */
11594
11595static VALUE
11596rb_io_fcntl(int argc, VALUE *argv, VALUE io)
11597{
11598 VALUE req, arg;
11599
11600 rb_scan_args(argc, argv, "11", &req, &arg);
11601 return rb_fcntl(io, req, arg);
11602}
11603#else
11604#define rb_io_fcntl rb_f_notimplement
11605#endif
11606
11607#if defined(HAVE_SYSCALL) || defined(HAVE___SYSCALL)
11608/*
11609 * call-seq:
11610 * syscall(integer_callno, *arguments) -> integer
11611 *
11612 * Invokes Posix system call {syscall(2)}[https://linux.die.net/man/2/syscall],
11613 * which calls a specified function.
11614 *
11615 * Calls the operating system function identified by +integer_callno+;
11616 * returns the result of the function or raises SystemCallError if it failed.
11617 * The effect of the call is platform-dependent.
11618 * The arguments and returned value are platform-dependent.
11619 *
11620 * For each of +arguments+: if it is an integer, it is passed directly;
11621 * if it is a string, it is interpreted as a binary sequence of bytes.
11622 * There may be as many as nine such arguments.
11623 *
11624 * Arguments +integer_callno+ and +argument+, as well as the returned value,
11625 * are platform-dependent.
11626 *
11627 * Note: Method +syscall+ is essentially unsafe and unportable.
11628 * The DL (Fiddle) library is preferred for safer and a bit
11629 * more portable programming.
11630 *
11631 * Not implemented on all platforms.
11632 *
11633 */
11634
11635static VALUE
11636rb_f_syscall(int argc, VALUE *argv, VALUE _)
11637{
11638 VALUE arg[8];
11639#if SIZEOF_VOIDP == 8 && defined(HAVE___SYSCALL) && SIZEOF_INT != 8 /* mainly *BSD */
11640# define SYSCALL __syscall
11641# define NUM2SYSCALLID(x) NUM2LONG(x)
11642# define RETVAL2NUM(x) LONG2NUM(x)
11643# if SIZEOF_LONG == 8
11644 long num, retval = -1;
11645# elif SIZEOF_LONG_LONG == 8
11646 long long num, retval = -1;
11647# else
11648# error ---->> it is asserted that __syscall takes the first argument and returns retval in 64bit signed integer. <<----
11649# endif
11650#elif defined(__linux__)
11651# define SYSCALL syscall
11652# define NUM2SYSCALLID(x) NUM2LONG(x)
11653# define RETVAL2NUM(x) LONG2NUM(x)
11654 /*
11655 * Linux man page says, syscall(2) function prototype is below.
11656 *
11657 * int syscall(int number, ...);
11658 *
11659 * But, it's incorrect. Actual one takes and returned long. (see unistd.h)
11660 */
11661 long num, retval = -1;
11662#else
11663# define SYSCALL syscall
11664# define NUM2SYSCALLID(x) NUM2INT(x)
11665# define RETVAL2NUM(x) INT2NUM(x)
11666 int num, retval = -1;
11667#endif
11668 int i;
11669
11670 if (RTEST(ruby_verbose)) {
11672 "We plan to remove a syscall function at future release. DL(Fiddle) provides safer alternative.");
11673 }
11674
11675 if (argc == 0)
11676 rb_raise(rb_eArgError, "too few arguments for syscall");
11677 if (argc > numberof(arg))
11678 rb_raise(rb_eArgError, "too many arguments for syscall");
11679 num = NUM2SYSCALLID(argv[0]); ++argv;
11680 for (i = argc - 1; i--; ) {
11681 VALUE v = rb_check_string_type(argv[i]);
11682
11683 if (!NIL_P(v)) {
11684 StringValue(v);
11685 rb_str_modify(v);
11686 arg[i] = (VALUE)StringValueCStr(v);
11687 }
11688 else {
11689 arg[i] = (VALUE)NUM2LONG(argv[i]);
11690 }
11691 }
11692
11693 switch (argc) {
11694 case 1:
11695 retval = SYSCALL(num);
11696 break;
11697 case 2:
11698 retval = SYSCALL(num, arg[0]);
11699 break;
11700 case 3:
11701 retval = SYSCALL(num, arg[0],arg[1]);
11702 break;
11703 case 4:
11704 retval = SYSCALL(num, arg[0],arg[1],arg[2]);
11705 break;
11706 case 5:
11707 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3]);
11708 break;
11709 case 6:
11710 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4]);
11711 break;
11712 case 7:
11713 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5]);
11714 break;
11715 case 8:
11716 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6]);
11717 break;
11718 }
11719
11720 if (retval == -1)
11721 rb_sys_fail(0);
11722 return RETVAL2NUM(retval);
11723#undef SYSCALL
11724#undef NUM2SYSCALLID
11725#undef RETVAL2NUM
11726}
11727#else
11728#define rb_f_syscall rb_f_notimplement
11729#endif
11730
11731static VALUE
11732io_new_instance(VALUE args)
11733{
11734 return rb_class_new_instance(2, (VALUE*)args+1, *(VALUE*)args);
11735}
11736
11737static rb_encoding *
11738find_encoding(VALUE v)
11739{
11740 rb_encoding *enc = rb_find_encoding(v);
11741 if (!enc) rb_warn("Unsupported encoding %"PRIsVALUE" ignored", v);
11742 return enc;
11743}
11744
11745static void
11746io_encoding_set(rb_io_t *fptr, VALUE v1, VALUE v2, VALUE opt)
11747{
11748 rb_encoding *enc, *enc2;
11749 int ecflags = fptr->encs.ecflags;
11750 VALUE ecopts, tmp;
11751
11752 if (!NIL_P(v2)) {
11753 enc2 = find_encoding(v1);
11754 tmp = rb_check_string_type(v2);
11755 if (!NIL_P(tmp)) {
11756 if (RSTRING_LEN(tmp) == 1 && RSTRING_PTR(tmp)[0] == '-') {
11757 /* Special case - "-" => no transcoding */
11758 enc = enc2;
11759 enc2 = NULL;
11760 }
11761 else
11762 enc = find_encoding(v2);
11763 if (enc == enc2) {
11764 /* Special case - "-" => no transcoding */
11765 enc2 = NULL;
11766 }
11767 }
11768 else {
11769 enc = find_encoding(v2);
11770 if (enc == enc2) {
11771 /* Special case - "-" => no transcoding */
11772 enc2 = NULL;
11773 }
11774 }
11775 if (enc2 == rb_ascii8bit_encoding()) {
11776 /* If external is ASCII-8BIT, no transcoding */
11777 enc = enc2;
11778 enc2 = NULL;
11779 }
11780 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11781 ecflags = rb_econv_prepare_options(opt, &ecopts, ecflags);
11782 }
11783 else {
11784 if (NIL_P(v1)) {
11785 /* Set to default encodings */
11786 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
11787 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11788 ecopts = Qnil;
11789 }
11790 else {
11791 tmp = rb_check_string_type(v1);
11792 if (!NIL_P(tmp) && rb_enc_asciicompat(enc = rb_enc_get(tmp))) {
11793 parse_mode_enc(RSTRING_PTR(tmp), enc, &enc, &enc2, NULL);
11794 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11795 ecflags = rb_econv_prepare_options(opt, &ecopts, ecflags);
11796 }
11797 else {
11798 rb_io_ext_int_to_encs(find_encoding(v1), NULL, &enc, &enc2, 0);
11799 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11800 ecopts = Qnil;
11801 }
11802 }
11803 }
11804 validate_enc_binmode(&fptr->mode, ecflags, enc, enc2);
11805 fptr->encs.enc = enc;
11806 fptr->encs.enc2 = enc2;
11807 fptr->encs.ecflags = ecflags;
11808 fptr->encs.ecopts = ecopts;
11809 clear_codeconv(fptr);
11810
11811}
11812
11814 rb_io_t *fptr;
11815 VALUE v1;
11816 VALUE v2;
11817 VALUE opt;
11818};
11819
11820static VALUE
11821io_encoding_set_v(VALUE v)
11822{
11823 struct io_encoding_set_args *arg = (struct io_encoding_set_args *)v;
11824 io_encoding_set(arg->fptr, arg->v1, arg->v2, arg->opt);
11825 return Qnil;
11826}
11827
11828static VALUE
11829pipe_pair_close(VALUE rw)
11830{
11831 VALUE *rwp = (VALUE *)rw;
11832 return rb_ensure(io_close, rwp[0], io_close, rwp[1]);
11833}
11834
11835/*
11836 * call-seq:
11837 * IO.pipe(**opts) -> [read_io, write_io]
11838 * IO.pipe(enc, **opts) -> [read_io, write_io]
11839 * IO.pipe(ext_enc, int_enc, **opts) -> [read_io, write_io]
11840 * IO.pipe(**opts) {|read_io, write_io| ...} -> object
11841 * IO.pipe(enc, **opts) {|read_io, write_io| ...} -> object
11842 * IO.pipe(ext_enc, int_enc, **opts) {|read_io, write_io| ...} -> object
11843 *
11844 * Creates a pair of pipe endpoints, +read_io+ and +write_io+,
11845 * connected to each other.
11846 *
11847 * If argument +enc_string+ is given, it must be a string containing one of:
11848 *
11849 * - The name of the encoding to be used as the external encoding.
11850 * - The colon-separated names of two encodings to be used as the external
11851 * and internal encodings.
11852 *
11853 * If argument +int_enc+ is given, it must be an Encoding object
11854 * or encoding name string that specifies the internal encoding to be used;
11855 * if argument +ext_enc+ is also given, it must be an Encoding object
11856 * or encoding name string that specifies the external encoding to be used.
11857 *
11858 * The string read from +read_io+ is tagged with the external encoding;
11859 * if an internal encoding is also specified, the string is converted
11860 * to, and tagged with, that encoding.
11861 *
11862 * If any encoding is specified,
11863 * optional hash arguments specify the conversion option.
11864 *
11865 * Optional keyword arguments +opts+ specify:
11866 *
11867 * - {Open Options}[rdoc-ref:IO@Open+Options].
11868 * - {Encoding Options}[rdoc-ref:encodings.rdoc@Encoding+Options].
11869 *
11870 * With no block given, returns the two endpoints in an array:
11871 *
11872 * IO.pipe # => [#<IO:fd 4>, #<IO:fd 5>]
11873 *
11874 * With a block given, calls the block with the two endpoints;
11875 * closes both endpoints and returns the value of the block:
11876 *
11877 * IO.pipe {|read_io, write_io| p read_io; p write_io }
11878 *
11879 * Output:
11880 *
11881 * #<IO:fd 6>
11882 * #<IO:fd 7>
11883 *
11884 * Not available on all platforms.
11885 *
11886 * In the example below, the two processes close the ends of the pipe
11887 * that they are not using. This is not just a cosmetic nicety. The
11888 * read end of a pipe will not generate an end of file condition if
11889 * there are any writers with the pipe still open. In the case of the
11890 * parent process, the <tt>rd.read</tt> will never return if it
11891 * does not first issue a <tt>wr.close</tt>:
11892 *
11893 * rd, wr = IO.pipe
11894 *
11895 * if fork
11896 * wr.close
11897 * puts "Parent got: <#{rd.read}>"
11898 * rd.close
11899 * Process.wait
11900 * else
11901 * rd.close
11902 * puts 'Sending message to parent'
11903 * wr.write "Hi Dad"
11904 * wr.close
11905 * end
11906 *
11907 * <em>produces:</em>
11908 *
11909 * Sending message to parent
11910 * Parent got: <Hi Dad>
11911 *
11912 */
11913
11914static VALUE
11915rb_io_s_pipe(int argc, VALUE *argv, VALUE klass)
11916{
11917 int pipes[2], state;
11918 VALUE r, w, args[3], v1, v2;
11919 VALUE opt;
11920 rb_io_t *fptr, *fptr2;
11921 struct io_encoding_set_args ies_args;
11922 enum rb_io_mode fmode = 0;
11923 VALUE ret;
11924
11925 argc = rb_scan_args(argc, argv, "02:", &v1, &v2, &opt);
11926 if (rb_pipe(pipes) < 0)
11927 rb_sys_fail(0);
11928
11929 args[0] = klass;
11930 args[1] = INT2NUM(pipes[0]);
11931 args[2] = INT2FIX(O_RDONLY);
11932 r = rb_protect(io_new_instance, (VALUE)args, &state);
11933 if (state) {
11934 close(pipes[0]);
11935 close(pipes[1]);
11936 rb_jump_tag(state);
11937 }
11938 GetOpenFile(r, fptr);
11939
11940 ies_args.fptr = fptr;
11941 ies_args.v1 = v1;
11942 ies_args.v2 = v2;
11943 ies_args.opt = opt;
11944 rb_protect(io_encoding_set_v, (VALUE)&ies_args, &state);
11945 if (state) {
11946 close(pipes[1]);
11947 io_close(r);
11948 rb_jump_tag(state);
11949 }
11950
11951 args[1] = INT2NUM(pipes[1]);
11952 args[2] = INT2FIX(O_WRONLY);
11953 w = rb_protect(io_new_instance, (VALUE)args, &state);
11954 if (state) {
11955 close(pipes[1]);
11956 if (!NIL_P(r)) rb_io_close(r);
11957 rb_jump_tag(state);
11958 }
11959 GetOpenFile(w, fptr2);
11960 rb_io_synchronized(fptr2);
11961
11962 extract_binmode(opt, &fmode);
11963
11964 if ((fmode & FMODE_BINMODE) && NIL_P(v1)) {
11967 }
11968
11969#if DEFAULT_TEXTMODE
11970 if ((fptr->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
11971 fptr->mode &= ~FMODE_TEXTMODE;
11972 setmode(fptr->fd, O_BINARY);
11973 }
11974#if RUBY_CRLF_ENVIRONMENT
11977 }
11978#endif
11979#endif
11980 fptr->mode |= fmode;
11981#if DEFAULT_TEXTMODE
11982 if ((fptr2->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
11983 fptr2->mode &= ~FMODE_TEXTMODE;
11984 setmode(fptr2->fd, O_BINARY);
11985 }
11986#endif
11987 fptr2->mode |= fmode;
11988
11989 ret = rb_assoc_new(r, w);
11990 if (rb_block_given_p()) {
11991 VALUE rw[2];
11992 rw[0] = r;
11993 rw[1] = w;
11994 return rb_ensure(rb_yield, ret, pipe_pair_close, (VALUE)rw);
11995 }
11996 return ret;
11997}
11998
12000 int argc;
12001 VALUE *argv;
12002 VALUE io;
12003};
12004
12005static void
12006open_key_args(VALUE klass, int argc, VALUE *argv, VALUE opt, struct foreach_arg *arg)
12007{
12008 VALUE path, v;
12009 VALUE vmode = Qnil, vperm = Qnil;
12010
12011 path = *argv++;
12012 argc--;
12013 FilePathValue(path);
12014 arg->io = 0;
12015 arg->argc = argc;
12016 arg->argv = argv;
12017 if (NIL_P(opt)) {
12018 vmode = INT2NUM(O_RDONLY);
12019 vperm = INT2FIX(0666);
12020 }
12021 else if (!NIL_P(v = rb_hash_aref(opt, sym_open_args))) {
12022 int n;
12023
12024 v = rb_to_array_type(v);
12025 n = RARRAY_LENINT(v);
12026 rb_check_arity(n, 0, 3); /* rb_io_open */
12027 rb_scan_args_kw(RB_SCAN_ARGS_LAST_HASH_KEYWORDS, n, RARRAY_CONST_PTR(v), "02:", &vmode, &vperm, &opt);
12028 }
12029 arg->io = rb_io_open(klass, path, vmode, vperm, opt);
12030}
12031
12032static VALUE
12033io_s_foreach(VALUE v)
12034{
12035 struct getline_arg *arg = (void *)v;
12036 VALUE str;
12037
12038 if (arg->limit == 0)
12039 rb_raise(rb_eArgError, "invalid limit: 0 for foreach");
12040 while (!NIL_P(str = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, arg->io))) {
12041 rb_lastline_set(str);
12042 rb_yield(str);
12043 }
12045 return Qnil;
12046}
12047
12048/*
12049 * call-seq:
12050 * IO.foreach(path, sep = $/, **opts) {|line| block } -> nil
12051 * IO.foreach(path, limit, **opts) {|line| block } -> nil
12052 * IO.foreach(path, sep, limit, **opts) {|line| block } -> nil
12053 * IO.foreach(...) -> an_enumerator
12054 *
12055 * Calls the block with each successive line read from the stream.
12056 *
12057 * When called from class \IO (but not subclasses of \IO),
12058 * this method has potential security vulnerabilities if called with untrusted input;
12059 * see {Command Injection}[rdoc-ref:security/command_injection.rdoc].
12060 *
12061 * The first argument must be a string that is the path to a file.
12062 *
12063 * With only argument +path+ given, parses lines from the file at the given +path+,
12064 * as determined by the default line separator,
12065 * and calls the block with each successive line:
12066 *
12067 * File.foreach('t.txt') {|line| p line }
12068 *
12069 * Output: the same as above.
12070 *
12071 * For both forms, command and path, the remaining arguments are the same.
12072 *
12073 * With argument +sep+ given, parses lines as determined by that line separator
12074 * (see {Line Separator}[rdoc-ref:IO@Line+Separator]):
12075 *
12076 * File.foreach('t.txt', 'li') {|line| p line }
12077 *
12078 * Output:
12079 *
12080 * "First li"
12081 * "ne\nSecond li"
12082 * "ne\n\nThird li"
12083 * "ne\nFourth li"
12084 * "ne\n"
12085 *
12086 * Each paragraph:
12087 *
12088 * File.foreach('t.txt', '') {|paragraph| p paragraph }
12089 *
12090 * Output:
12091 *
12092 * "First line\nSecond line\n\n"
12093 * "Third line\nFourth line\n"
12094 *
12095 * With argument +limit+ given, parses lines as determined by the default
12096 * line separator and the given line-length limit
12097 * (see {Line Separator}[rdoc-ref:IO@Line+Separator] and {Line Limit}[rdoc-ref:IO@Line+Limit]):
12098 *
12099 * File.foreach('t.txt', 7) {|line| p line }
12100 *
12101 * Output:
12102 *
12103 * "First l"
12104 * "ine\n"
12105 * "Second "
12106 * "line\n"
12107 * "\n"
12108 * "Third l"
12109 * "ine\n"
12110 * "Fourth l"
12111 * "line\n"
12112 *
12113 * With arguments +sep+ and +limit+ given,
12114 * combines the two behaviors
12115 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
12116 *
12117 * Optional keyword arguments +opts+ specify:
12118 *
12119 * - {Open Options}[rdoc-ref:IO@Open+Options].
12120 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12121 * - {Line Options}[rdoc-ref:IO@Line+IO].
12122 *
12123 * Returns an Enumerator if no block is given.
12124 *
12125 */
12126
12127static VALUE
12128rb_io_s_foreach(int argc, VALUE *argv, VALUE self)
12129{
12130 VALUE opt;
12131 int orig_argc = argc;
12132 struct foreach_arg arg;
12133 struct getline_arg garg;
12134
12135 argc = rb_scan_args(argc, argv, "12:", NULL, NULL, NULL, &opt);
12136 RETURN_ENUMERATOR(self, orig_argc, argv);
12137 extract_getline_args(argc-1, argv+1, &garg);
12138 open_key_args(self, argc, argv, opt, &arg);
12139 if (NIL_P(arg.io)) return Qnil;
12140 extract_getline_opts(opt, &garg);
12141 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12142 return rb_ensure(io_s_foreach, (VALUE)&garg, rb_io_close, arg.io);
12143}
12144
12145static VALUE
12146io_s_readlines(VALUE v)
12147{
12148 struct getline_arg *arg = (void *)v;
12149 return io_readlines(arg, arg->io);
12150}
12151
12152/*
12153 * call-seq:
12154 * IO.readlines(path, sep = $/, **opts) -> array
12155 * IO.readlines(path, limit, **opts) -> array
12156 * IO.readlines(path, sep, limit, **opts) -> array
12157 *
12158 * Returns an array of all lines read from the stream.
12159 *
12160 * When called from class \IO (but not subclasses of \IO),
12161 * this method has potential security vulnerabilities if called with untrusted input;
12162 * see {Command Injection}[rdoc-ref:security/command_injection.rdoc].
12163 *
12164 * The first argument must be a string that is the path to a file.
12165 *
12166 * With only argument +path+ given, parses lines from the file at the given +path+,
12167 * as determined by the default line separator,
12168 * and returns those lines in an array:
12169 *
12170 * IO.readlines('t.txt')
12171 * # => ["First line\n", "Second line\n", "\n", "Third line\n", "Fourth line\n"]
12172 *
12173 * With argument +sep+ given, parses lines as determined by that line separator
12174 * (see {Line Separator}[rdoc-ref:IO@Line+Separator]):
12175 *
12176 * # Ordinary separator.
12177 * IO.readlines('t.txt', 'li')
12178 * # =>["First li", "ne\nSecond li", "ne\n\nThird li", "ne\nFourth li", "ne\n"]
12179 * # Get-paragraphs separator.
12180 * IO.readlines('t.txt', '')
12181 * # => ["First line\nSecond line\n\n", "Third line\nFourth line\n"]
12182 * # Get-all separator.
12183 * IO.readlines('t.txt', nil)
12184 * # => ["First line\nSecond line\n\nThird line\nFourth line\n"]
12185 *
12186 * With argument +limit+ given, parses lines as determined by the default
12187 * line separator and the given line-length limit
12188 * (see {Line Separator}[rdoc-ref:IO@Line+Separator] and {Line Limit}[rdoc-ref:IO@Line+Limit]:
12189 *
12190 * IO.readlines('t.txt', 7)
12191 * # => ["First l", "ine\n", "Second ", "line\n", "\n", "Third l", "ine\n", "Fourth ", "line\n"]
12192 *
12193 * With arguments +sep+ and +limit+ given,
12194 * combines the two behaviors
12195 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
12196 *
12197 * Optional keyword arguments +opts+ specify:
12198 *
12199 * - {Open Options}[rdoc-ref:IO@Open+Options].
12200 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12201 * - {Line Options}[rdoc-ref:IO@Line+IO].
12202 *
12203 */
12204
12205static VALUE
12206rb_io_s_readlines(int argc, VALUE *argv, VALUE io)
12207{
12208 VALUE opt;
12209 struct foreach_arg arg;
12210 struct getline_arg garg;
12211
12212 argc = rb_scan_args(argc, argv, "12:", NULL, NULL, NULL, &opt);
12213 extract_getline_args(argc-1, argv+1, &garg);
12214 open_key_args(io, argc, argv, opt, &arg);
12215 if (NIL_P(arg.io)) return Qnil;
12216 extract_getline_opts(opt, &garg);
12217 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12218 return rb_ensure(io_s_readlines, (VALUE)&garg, rb_io_close, arg.io);
12219}
12220
12221static VALUE
12222io_s_read(VALUE v)
12223{
12224 struct foreach_arg *arg = (void *)v;
12225 return io_read(arg->argc, arg->argv, arg->io);
12226}
12227
12228struct seek_arg {
12229 VALUE io;
12230 VALUE offset;
12231 int mode;
12232};
12233
12234static VALUE
12235seek_before_access(VALUE argp)
12236{
12237 struct seek_arg *arg = (struct seek_arg *)argp;
12238 rb_io_binmode(arg->io);
12239 return rb_io_seek(arg->io, arg->offset, arg->mode);
12240}
12241
12242/*
12243 * call-seq:
12244 * IO.read(path, length = nil, offset = 0, **opts) -> string or nil
12245 *
12246 * Opens the stream, reads and returns some or all of its content,
12247 * and closes the stream; returns +nil+ if no bytes were read.
12248 *
12249 * When called from class \IO (but not subclasses of \IO),
12250 * this method has potential security vulnerabilities if called with untrusted input;
12251 * see {Command Injection}[rdoc-ref:security/command_injection.rdoc].
12252 *
12253 * The first argument must be a string that is the path to a file.
12254 *
12255 * With only argument +path+ given, reads in text mode and returns the entire content
12256 * of the file at the given path:
12257 *
12258 * IO.read('t.txt')
12259 * # => "First line\nSecond line\n\nThird line\nFourth line\n"
12260 *
12261 * On Windows, text mode can terminate reading and leave bytes in the file
12262 * unread when encountering certain special bytes. Consider using
12263 * IO.binread if all bytes in the file should be read.
12264 *
12265 * With argument +length+, returns +length+ bytes if available:
12266 *
12267 * IO.read('t.txt', 7) # => "First l"
12268 * IO.read('t.txt', 700)
12269 * # => "First line\r\nSecond line\r\n\r\nFourth line\r\nFifth line\r\n"
12270 *
12271 * With arguments +length+ and +offset+, returns +length+ bytes
12272 * if available, beginning at the given +offset+:
12273 *
12274 * IO.read('t.txt', 10, 2) # => "rst line\nS"
12275 * IO.read('t.txt', 10, 200) # => nil
12276 *
12277 * Optional keyword arguments +opts+ specify:
12278 *
12279 * - {Open Options}[rdoc-ref:IO@Open+Options].
12280 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12281 *
12282 */
12283
12284static VALUE
12285rb_io_s_read(int argc, VALUE *argv, VALUE io)
12286{
12287 VALUE opt, offset;
12288 long off;
12289 struct foreach_arg arg;
12290
12291 argc = rb_scan_args(argc, argv, "13:", NULL, NULL, &offset, NULL, &opt);
12292 if (!NIL_P(offset) && (off = NUM2LONG(offset)) < 0) {
12293 rb_raise(rb_eArgError, "negative offset %ld given", off);
12294 }
12295 open_key_args(io, argc, argv, opt, &arg);
12296 if (NIL_P(arg.io)) return Qnil;
12297 if (!NIL_P(offset)) {
12298 struct seek_arg sarg;
12299 int state = 0;
12300 sarg.io = arg.io;
12301 sarg.offset = offset;
12302 sarg.mode = SEEK_SET;
12303 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12304 if (state) {
12305 rb_io_close(arg.io);
12306 rb_jump_tag(state);
12307 }
12308 if (arg.argc == 2) arg.argc = 1;
12309 }
12310 return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
12311}
12312
12313/*
12314 * call-seq:
12315 * IO.binread(path, length = nil, offset = 0) -> string or nil
12316 *
12317 * Behaves like IO.read, except that the stream is opened in binary mode
12318 * with ASCII-8BIT encoding.
12319 *
12320 * When called from class \IO (but not subclasses of \IO),
12321 * this method has potential security vulnerabilities if called with untrusted input;
12322 * see {Command Injection}[rdoc-ref:security/command_injection.rdoc].
12323 *
12324 */
12325
12326static VALUE
12327rb_io_s_binread(int argc, VALUE *argv, VALUE io)
12328{
12329 VALUE offset;
12330 struct foreach_arg arg;
12331 enum rb_io_mode fmode = FMODE_READABLE|FMODE_BINMODE;
12332 enum {
12333 oflags = O_RDONLY
12334#ifdef O_BINARY
12335 |O_BINARY
12336#endif
12337 };
12338 struct rb_io_encoding convconfig = {NULL, NULL, 0, Qnil};
12339
12340 rb_scan_args(argc, argv, "12", NULL, NULL, &offset);
12341 FilePathValue(argv[0]);
12342 convconfig.enc = rb_ascii8bit_encoding();
12343 arg.io = rb_io_open_generic(io, argv[0], oflags, fmode, &convconfig, 0);
12344 if (NIL_P(arg.io)) return Qnil;
12345 arg.argv = argv+1;
12346 arg.argc = (argc > 1) ? 1 : 0;
12347 if (!NIL_P(offset)) {
12348 struct seek_arg sarg;
12349 int state = 0;
12350 sarg.io = arg.io;
12351 sarg.offset = offset;
12352 sarg.mode = SEEK_SET;
12353 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12354 if (state) {
12355 rb_io_close(arg.io);
12356 rb_jump_tag(state);
12357 }
12358 }
12359 return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
12360}
12361
12362static VALUE
12363io_s_write0(VALUE v)
12364{
12365 struct write_arg *arg = (void *)v;
12366 return io_write(arg->io,arg->str,arg->nosync);
12367}
12368
12369static VALUE
12370io_s_write(int argc, VALUE *argv, VALUE klass, int binary)
12371{
12372 VALUE string, offset, opt;
12373 struct foreach_arg arg;
12374 struct write_arg warg;
12375
12376 rb_scan_args(argc, argv, "21:", NULL, &string, &offset, &opt);
12377
12378 if (NIL_P(opt)) opt = rb_hash_new();
12379 else opt = rb_hash_dup(opt);
12380
12381
12382 if (NIL_P(rb_hash_aref(opt,sym_mode))) {
12383 int mode = O_WRONLY|O_CREAT;
12384#ifdef O_BINARY
12385 if (binary) mode |= O_BINARY;
12386#endif
12387 if (NIL_P(offset)) mode |= O_TRUNC;
12388 rb_hash_aset(opt,sym_mode,INT2NUM(mode));
12389 }
12390 open_key_args(klass, argc, argv, opt, &arg);
12391
12392#ifndef O_BINARY
12393 if (binary) rb_io_binmode_m(arg.io);
12394#endif
12395
12396 if (NIL_P(arg.io)) return Qnil;
12397 if (!NIL_P(offset)) {
12398 struct seek_arg sarg;
12399 int state = 0;
12400 sarg.io = arg.io;
12401 sarg.offset = offset;
12402 sarg.mode = SEEK_SET;
12403 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12404 if (state) {
12405 rb_io_close(arg.io);
12406 rb_jump_tag(state);
12407 }
12408 }
12409
12410 warg.io = arg.io;
12411 warg.str = string;
12412 warg.nosync = 0;
12413
12414 return rb_ensure(io_s_write0, (VALUE)&warg, rb_io_close, arg.io);
12415}
12416
12417/*
12418 * call-seq:
12419 * IO.write(path, data, offset = 0, **opts) -> integer
12420 *
12421 * Opens the stream, writes the given +data+ to it,
12422 * and closes the stream; returns the number of bytes written.
12423 *
12424 * When called from class \IO (but not subclasses of \IO),
12425 * this method has potential security vulnerabilities if called with untrusted input;
12426 * see {Command Injection}[rdoc-ref:security/command_injection.rdoc].
12427 *
12428 * The first argument must be a string that is the path to a file.
12429 *
12430 * With only argument +path+ given, writes the given +data+ to the file at that path:
12431 *
12432 * IO.write('t.tmp', 'abc') # => 3
12433 * File.read('t.tmp') # => "abc"
12434 *
12435 * If +offset+ is zero (the default), the file is overwritten:
12436 *
12437 * IO.write('t.tmp', 'A') # => 1
12438 * File.read('t.tmp') # => "A"
12439 *
12440 * If +offset+ in within the file content, the file is partly overwritten:
12441 *
12442 * IO.write('t.tmp', 'abcdef') # => 3
12443 * File.read('t.tmp') # => "abcdef"
12444 * # Offset within content.
12445 * IO.write('t.tmp', '012', 2) # => 3
12446 * File.read('t.tmp') # => "ab012f"
12447 *
12448 * If +offset+ is outside the file content,
12449 * the file is padded with null characters <tt>"\u0000"</tt>:
12450 *
12451 * IO.write('t.tmp', 'xyz', 10) # => 3
12452 * File.read('t.tmp') # => "ab012f\u0000\u0000\u0000\u0000xyz"
12453 *
12454 * Optional keyword arguments +opts+ specify:
12455 *
12456 * - {Open Options}[rdoc-ref:IO@Open+Options].
12457 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12458 *
12459 */
12460
12461static VALUE
12462rb_io_s_write(int argc, VALUE *argv, VALUE io)
12463{
12464 return io_s_write(argc, argv, io, 0);
12465}
12466
12467/*
12468 * call-seq:
12469 * IO.binwrite(path, string, offset = 0) -> integer
12470 *
12471 * Behaves like IO.write, except that the stream is opened in binary mode
12472 * with ASCII-8BIT encoding.
12473 *
12474 * When called from class \IO (but not subclasses of \IO),
12475 * this method has potential security vulnerabilities if called with untrusted input;
12476 * see {Command Injection}[rdoc-ref:security/command_injection.rdoc].
12477 *
12478 */
12479
12480static VALUE
12481rb_io_s_binwrite(int argc, VALUE *argv, VALUE io)
12482{
12483 return io_s_write(argc, argv, io, 1);
12484}
12485
12487 VALUE src;
12488 VALUE dst;
12489 rb_off_t copy_length; /* (rb_off_t)-1 if not specified */
12490 rb_off_t src_offset; /* (rb_off_t)-1 if not specified */
12491
12492 rb_io_t *src_fptr;
12493 rb_io_t *dst_fptr;
12494 unsigned close_src : 1;
12495 unsigned close_dst : 1;
12496 int error_no;
12497 rb_off_t total;
12498 const char *syserr;
12499 const char *notimp;
12500 VALUE th;
12501 struct stat src_stat;
12502 struct stat dst_stat;
12503#ifdef HAVE_FCOPYFILE
12504 copyfile_state_t copyfile_state;
12505#endif
12506};
12507
12508static void *
12509exec_interrupts(void *arg)
12510{
12511 VALUE th = (VALUE)arg;
12512 rb_thread_execute_interrupts(th);
12513 return NULL;
12514}
12515
12516/*
12517 * returns TRUE if the preceding system call was interrupted
12518 * so we can continue. If the thread was interrupted, we
12519 * reacquire the GVL to execute interrupts before continuing.
12520 */
12521static int
12522maygvl_copy_stream_continue_p(int has_gvl, struct copy_stream_struct *stp)
12523{
12524 switch (errno) {
12525 case EINTR:
12526#if defined(ERESTART)
12527 case ERESTART:
12528#endif
12529 if (rb_thread_interrupted(stp->th)) {
12530 if (has_gvl)
12531 rb_thread_execute_interrupts(stp->th);
12532 else
12533 rb_thread_call_with_gvl(exec_interrupts, (void *)stp->th);
12534 }
12535 return TRUE;
12536 }
12537 return FALSE;
12538}
12539
12541 VALUE scheduler;
12542
12543 rb_io_t *fptr;
12544 short events;
12545
12546 VALUE result;
12547};
12548
12549static void *
12550fiber_scheduler_wait_for(void * _arguments)
12551{
12552 struct fiber_scheduler_wait_for_arguments *arguments = (struct fiber_scheduler_wait_for_arguments *)_arguments;
12553
12554 arguments->result = rb_fiber_scheduler_io_wait(arguments->scheduler, arguments->fptr->self, INT2NUM(arguments->events), RUBY_IO_TIMEOUT_DEFAULT);
12555
12556 return NULL;
12557}
12558
12559#if USE_POLL
12560# define IOWAIT_SYSCALL "poll"
12561STATIC_ASSERT(pollin_expected, POLLIN == RB_WAITFD_IN);
12562STATIC_ASSERT(pollout_expected, POLLOUT == RB_WAITFD_OUT);
12563static int
12564nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout)
12565{
12567 if (scheduler != Qnil) {
12568 struct fiber_scheduler_wait_for_arguments args = {.scheduler = scheduler, .fptr = fptr, .events = events};
12569 rb_thread_call_with_gvl(fiber_scheduler_wait_for, &args);
12570 return RTEST(args.result);
12571 }
12572
12573 int fd = fptr->fd;
12574 if (fd == -1) return 0;
12575
12576 struct pollfd fds;
12577
12578 fds.fd = fd;
12579 fds.events = events;
12580
12581 int timeout_milliseconds = -1;
12582
12583 if (timeout) {
12584 timeout_milliseconds = (int)(timeout->tv_sec * 1000) + (int)(timeout->tv_usec / 1000);
12585 }
12586
12587 return poll(&fds, 1, timeout_milliseconds);
12588}
12589#else /* !USE_POLL */
12590# define IOWAIT_SYSCALL "select"
12591static int
12592nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout)
12593{
12595 if (scheduler != Qnil) {
12596 struct fiber_scheduler_wait_for_arguments args = {.scheduler = scheduler, .fptr = fptr, .events = events};
12597 rb_thread_call_with_gvl(fiber_scheduler_wait_for, &args);
12598 return RTEST(args.result);
12599 }
12600
12601 int fd = fptr->fd;
12602
12603 if (fd == -1) {
12604 errno = EBADF;
12605 return -1;
12606 }
12607
12608 rb_fdset_t fds;
12609 int ret;
12610
12611 rb_fd_init(&fds);
12612 rb_fd_set(fd, &fds);
12613
12614 switch (events) {
12615 case RB_WAITFD_IN:
12616 ret = rb_fd_select(fd + 1, &fds, 0, 0, timeout);
12617 break;
12618 case RB_WAITFD_OUT:
12619 ret = rb_fd_select(fd + 1, 0, &fds, 0, timeout);
12620 break;
12621 default:
12622 VM_UNREACHABLE(nogvl_wait_for);
12623 }
12624
12625 rb_fd_term(&fds);
12626
12627 // On timeout, this returns 0.
12628 return ret;
12629}
12630#endif /* !USE_POLL */
12631
12632static int
12633maygvl_copy_stream_wait_read(int has_gvl, struct copy_stream_struct *stp)
12634{
12635 int ret;
12636
12637 do {
12638 if (has_gvl) {
12640 }
12641 else {
12642 ret = nogvl_wait_for(stp->th, stp->src_fptr, RB_WAITFD_IN, NULL);
12643 }
12644 } while (ret < 0 && maygvl_copy_stream_continue_p(has_gvl, stp));
12645
12646 if (ret < 0) {
12647 stp->syserr = IOWAIT_SYSCALL;
12648 stp->error_no = errno;
12649 return ret;
12650 }
12651 return 0;
12652}
12653
12654static int
12655nogvl_copy_stream_wait_write(struct copy_stream_struct *stp)
12656{
12657 int ret;
12658
12659 do {
12660 ret = nogvl_wait_for(stp->th, stp->dst_fptr, RB_WAITFD_OUT, NULL);
12661 } while (ret < 0 && maygvl_copy_stream_continue_p(0, stp));
12662
12663 if (ret < 0) {
12664 stp->syserr = IOWAIT_SYSCALL;
12665 stp->error_no = errno;
12666 return ret;
12667 }
12668 return 0;
12669}
12670
12671#ifdef USE_COPY_FILE_RANGE
12672
12673static ssize_t
12674simple_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)
12675{
12676#ifdef HAVE_COPY_FILE_RANGE
12677 return copy_file_range(in_fd, in_offset, out_fd, out_offset, count, flags);
12678#else
12679 return syscall(__NR_copy_file_range, in_fd, in_offset, out_fd, out_offset, count, flags);
12680#endif
12681}
12682
12683static int
12684nogvl_copy_file_range(struct copy_stream_struct *stp)
12685{
12686 ssize_t ss;
12687 rb_off_t src_size;
12688 rb_off_t copy_length, src_offset, *src_offset_ptr;
12689
12690 if (!S_ISREG(stp->src_stat.st_mode))
12691 return 0;
12692
12693 src_size = stp->src_stat.st_size;
12694 src_offset = stp->src_offset;
12695 if (src_offset >= (rb_off_t)0) {
12696 src_offset_ptr = &src_offset;
12697 }
12698 else {
12699 src_offset_ptr = NULL; /* if src_offset_ptr is NULL, then bytes are read from in_fd starting from the file offset */
12700 }
12701
12702 copy_length = stp->copy_length;
12703 if (copy_length < (rb_off_t)0) {
12704 if (src_offset < (rb_off_t)0) {
12705 rb_off_t current_offset;
12706 errno = 0;
12707 current_offset = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12708 if (current_offset < (rb_off_t)0 && errno) {
12709 stp->syserr = "lseek";
12710 stp->error_no = errno;
12711 return (int)current_offset;
12712 }
12713 copy_length = src_size - current_offset;
12714 }
12715 else {
12716 copy_length = src_size - src_offset;
12717 }
12718 }
12719
12720 retry_copy_file_range:
12721# if SIZEOF_OFF_T > SIZEOF_SIZE_T
12722 /* we are limited by the 32-bit ssize_t return value on 32-bit */
12723 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
12724# else
12725 ss = (ssize_t)copy_length;
12726# endif
12727 ss = simple_copy_file_range(stp->src_fptr->fd, src_offset_ptr, stp->dst_fptr->fd, NULL, ss, 0);
12728 if (0 < ss) {
12729 stp->total += ss;
12730 copy_length -= ss;
12731 if (0 < copy_length) {
12732 goto retry_copy_file_range;
12733 }
12734 }
12735 if (ss < 0) {
12736 if (maygvl_copy_stream_continue_p(0, stp)) {
12737 goto retry_copy_file_range;
12738 }
12739 switch (errno) {
12740 case EINVAL:
12741 case EPERM: /* copy_file_range(2) doesn't exist (may happen in
12742 docker container) */
12743#ifdef ENOSYS
12744 case ENOSYS:
12745#endif
12746#ifdef EXDEV
12747 case EXDEV: /* in_fd and out_fd are not on the same filesystem */
12748#endif
12749 return 0;
12750 case EAGAIN:
12751#if EWOULDBLOCK != EAGAIN
12752 case EWOULDBLOCK:
12753#endif
12754 {
12755 int ret = nogvl_copy_stream_wait_write(stp);
12756 if (ret < 0) return ret;
12757 }
12758 goto retry_copy_file_range;
12759 case EBADF:
12760 {
12761 int e = errno;
12762 int flags = fcntl(stp->dst_fptr->fd, F_GETFL);
12763
12764 if (flags != -1 && flags & O_APPEND) {
12765 return 0;
12766 }
12767 errno = e;
12768 }
12769 }
12770 stp->syserr = "copy_file_range";
12771 stp->error_no = errno;
12772 return (int)ss;
12773 }
12774 return 1;
12775}
12776#endif
12777
12778#ifdef HAVE_FCOPYFILE
12779static int
12780nogvl_fcopyfile(struct copy_stream_struct *stp)
12781{
12782 rb_off_t cur, ss = 0;
12783 const rb_off_t src_offset = stp->src_offset;
12784 int ret;
12785
12786 if (stp->copy_length >= (rb_off_t)0) {
12787 /* copy_length can't be specified in fcopyfile(3) */
12788 return 0;
12789 }
12790
12791 if (!S_ISREG(stp->src_stat.st_mode))
12792 return 0;
12793
12794 if (!S_ISREG(stp->dst_stat.st_mode))
12795 return 0;
12796 if (lseek(stp->dst_fptr->fd, 0, SEEK_CUR) > (rb_off_t)0) /* if dst IO was already written */
12797 return 0;
12798 if (fcntl(stp->dst_fptr->fd, F_GETFL) & O_APPEND) {
12799 /* fcopyfile(3) appends src IO to dst IO and then truncates
12800 * dst IO to src IO's original size. */
12801 rb_off_t end = lseek(stp->dst_fptr->fd, 0, SEEK_END);
12802 lseek(stp->dst_fptr->fd, 0, SEEK_SET);
12803 if (end > (rb_off_t)0) return 0;
12804 }
12805
12806 if (src_offset > (rb_off_t)0) {
12807 rb_off_t r;
12808
12809 /* get current offset */
12810 errno = 0;
12811 cur = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12812 if (cur < (rb_off_t)0 && errno) {
12813 stp->error_no = errno;
12814 return 1;
12815 }
12816
12817 errno = 0;
12818 r = lseek(stp->src_fptr->fd, src_offset, SEEK_SET);
12819 if (r < (rb_off_t)0 && errno) {
12820 stp->error_no = errno;
12821 return 1;
12822 }
12823 }
12824
12825 stp->copyfile_state = copyfile_state_alloc(); /* this will be freed by copy_stream_finalize() */
12826 ret = fcopyfile(stp->src_fptr->fd, stp->dst_fptr->fd, stp->copyfile_state, COPYFILE_DATA);
12827 copyfile_state_get(stp->copyfile_state, COPYFILE_STATE_COPIED, &ss); /* get copied bytes */
12828
12829 if (ret == 0) { /* success */
12830 stp->total = ss;
12831 if (src_offset > (rb_off_t)0) {
12832 rb_off_t r;
12833 errno = 0;
12834 /* reset offset */
12835 r = lseek(stp->src_fptr->fd, cur, SEEK_SET);
12836 if (r < (rb_off_t)0 && errno) {
12837 stp->error_no = errno;
12838 return 1;
12839 }
12840 }
12841 }
12842 else {
12843 switch (errno) {
12844 case ENOTSUP:
12845 case EPERM:
12846 case EINVAL:
12847 return 0;
12848 }
12849 stp->syserr = "fcopyfile";
12850 stp->error_no = errno;
12851 return (int)ret;
12852 }
12853 return 1;
12854}
12855#endif
12856
12857#ifdef HAVE_SENDFILE
12858
12859# ifdef __linux__
12860# define USE_SENDFILE
12861
12862# ifdef HAVE_SYS_SENDFILE_H
12863# include <sys/sendfile.h>
12864# endif
12865
12866static ssize_t
12867simple_sendfile(int out_fd, int in_fd, rb_off_t *offset, rb_off_t count)
12868{
12869 return sendfile(out_fd, in_fd, offset, (size_t)count);
12870}
12871
12872# elif 0 /* defined(__FreeBSD__) || defined(__DragonFly__) */ || defined(__APPLE__)
12873/* This runs on FreeBSD8.1 r30210, but sendfiles blocks its execution
12874 * without cpuset -l 0.
12875 */
12876# define USE_SENDFILE
12877
12878static ssize_t
12879simple_sendfile(int out_fd, int in_fd, rb_off_t *offset, rb_off_t count)
12880{
12881 int r;
12882 rb_off_t pos = offset ? *offset : lseek(in_fd, 0, SEEK_CUR);
12883 rb_off_t sbytes;
12884# ifdef __APPLE__
12885 r = sendfile(in_fd, out_fd, pos, &count, NULL, 0);
12886 sbytes = count;
12887# else
12888 r = sendfile(in_fd, out_fd, pos, (size_t)count, NULL, &sbytes, 0);
12889# endif
12890 if (r != 0 && sbytes == 0) return r;
12891 if (offset) {
12892 *offset += sbytes;
12893 }
12894 else {
12895 lseek(in_fd, sbytes, SEEK_CUR);
12896 }
12897 return (ssize_t)sbytes;
12898}
12899
12900# endif
12901
12902#endif
12903
12904#ifdef USE_SENDFILE
12905static int
12906nogvl_copy_stream_sendfile(struct copy_stream_struct *stp)
12907{
12908 ssize_t ss;
12909 rb_off_t src_size;
12910 rb_off_t copy_length;
12911 rb_off_t src_offset;
12912 int use_pread;
12913
12914 if (!S_ISREG(stp->src_stat.st_mode))
12915 return 0;
12916
12917 src_size = stp->src_stat.st_size;
12918#ifndef __linux__
12919 if ((stp->dst_stat.st_mode & S_IFMT) != S_IFSOCK)
12920 return 0;
12921#endif
12922
12923 src_offset = stp->src_offset;
12924 use_pread = src_offset >= (rb_off_t)0;
12925
12926 copy_length = stp->copy_length;
12927 if (copy_length < (rb_off_t)0) {
12928 if (use_pread)
12929 copy_length = src_size - src_offset;
12930 else {
12931 rb_off_t cur;
12932 errno = 0;
12933 cur = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12934 if (cur < (rb_off_t)0 && errno) {
12935 stp->syserr = "lseek";
12936 stp->error_no = errno;
12937 return (int)cur;
12938 }
12939 copy_length = src_size - cur;
12940 }
12941 }
12942
12943 retry_sendfile:
12944# if SIZEOF_OFF_T > SIZEOF_SIZE_T
12945 /* we are limited by the 32-bit ssize_t return value on 32-bit */
12946 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
12947# else
12948 ss = (ssize_t)copy_length;
12949# endif
12950 if (use_pread) {
12951 ss = simple_sendfile(stp->dst_fptr->fd, stp->src_fptr->fd, &src_offset, ss);
12952 }
12953 else {
12954 ss = simple_sendfile(stp->dst_fptr->fd, stp->src_fptr->fd, NULL, ss);
12955 }
12956 if (0 < ss) {
12957 stp->total += ss;
12958 copy_length -= ss;
12959 if (0 < copy_length) {
12960 goto retry_sendfile;
12961 }
12962 }
12963 if (ss < 0) {
12964 if (maygvl_copy_stream_continue_p(0, stp))
12965 goto retry_sendfile;
12966 switch (errno) {
12967 case EINVAL:
12968#ifdef ENOSYS
12969 case ENOSYS:
12970#endif
12971#ifdef EOPNOTSUP
12972 /* some RedHat kernels may return EOPNOTSUP on an NFS mount.
12973 see also: [Feature #16965] */
12974 case EOPNOTSUP:
12975#endif
12976 return 0;
12977 case EAGAIN:
12978#if EWOULDBLOCK != EAGAIN
12979 case EWOULDBLOCK:
12980#endif
12981 {
12982 int ret;
12983#ifndef __linux__
12984 /*
12985 * Linux requires stp->src_fptr->fd to be a mmap-able (regular) file,
12986 * select() reports regular files to always be "ready", so
12987 * there is no need to select() on it.
12988 * Other OSes may have the same limitation for sendfile() which
12989 * allow us to bypass maygvl_copy_stream_wait_read()...
12990 */
12991 ret = maygvl_copy_stream_wait_read(0, stp);
12992 if (ret < 0) return ret;
12993#endif
12994 ret = nogvl_copy_stream_wait_write(stp);
12995 if (ret < 0) return ret;
12996 }
12997 goto retry_sendfile;
12998 }
12999 stp->syserr = "sendfile";
13000 stp->error_no = errno;
13001 return (int)ss;
13002 }
13003 return 1;
13004}
13005#endif
13006
13007static ssize_t
13008maygvl_read(int has_gvl, rb_io_t *fptr, void *buf, size_t count)
13009{
13010 if (has_gvl)
13011 return rb_io_read_memory(fptr, buf, count);
13012 else
13013 return read(fptr->fd, buf, count);
13014}
13015
13016static ssize_t
13017maygvl_copy_stream_read(int has_gvl, struct copy_stream_struct *stp, char *buf, size_t len, rb_off_t offset)
13018{
13019 ssize_t ss;
13020 retry_read:
13021 if (offset < (rb_off_t)0) {
13022 ss = maygvl_read(has_gvl, stp->src_fptr, buf, len);
13023 }
13024 else {
13025 ss = pread(stp->src_fptr->fd, buf, len, offset);
13026 }
13027 if (ss == 0) {
13028 return 0;
13029 }
13030 if (ss < 0) {
13031 if (maygvl_copy_stream_continue_p(has_gvl, stp))
13032 goto retry_read;
13033 switch (errno) {
13034 case EAGAIN:
13035#if EWOULDBLOCK != EAGAIN
13036 case EWOULDBLOCK:
13037#endif
13038 {
13039 int ret = maygvl_copy_stream_wait_read(has_gvl, stp);
13040 if (ret < 0) return ret;
13041 }
13042 goto retry_read;
13043#ifdef ENOSYS
13044 case ENOSYS:
13045 stp->notimp = "pread";
13046 return ss;
13047#endif
13048 }
13049 stp->syserr = offset < (rb_off_t)0 ? "read" : "pread";
13050 stp->error_no = errno;
13051 }
13052 return ss;
13053}
13054
13055static int
13056nogvl_copy_stream_write(struct copy_stream_struct *stp, char *buf, size_t len)
13057{
13058 ssize_t ss;
13059 int off = 0;
13060 while (len) {
13061 ss = write(stp->dst_fptr->fd, buf+off, len);
13062 if (ss < 0) {
13063 if (maygvl_copy_stream_continue_p(0, stp))
13064 continue;
13065 if (io_again_p(errno)) {
13066 int ret = nogvl_copy_stream_wait_write(stp);
13067 if (ret < 0) return ret;
13068 continue;
13069 }
13070 stp->syserr = "write";
13071 stp->error_no = errno;
13072 return (int)ss;
13073 }
13074 off += (int)ss;
13075 len -= (int)ss;
13076 stp->total += ss;
13077 }
13078 return 0;
13079}
13080
13081static void
13082nogvl_copy_stream_read_write(struct copy_stream_struct *stp)
13083{
13084 char buf[1024*16];
13085 size_t len;
13086 ssize_t ss;
13087 int ret;
13088 rb_off_t copy_length;
13089 rb_off_t src_offset;
13090 int use_eof;
13091 int use_pread;
13092
13093 copy_length = stp->copy_length;
13094 use_eof = copy_length < (rb_off_t)0;
13095 src_offset = stp->src_offset;
13096 use_pread = src_offset >= (rb_off_t)0;
13097
13098 if (use_pread && stp->close_src) {
13099 rb_off_t r;
13100 errno = 0;
13101 r = lseek(stp->src_fptr->fd, src_offset, SEEK_SET);
13102 if (r < (rb_off_t)0 && errno) {
13103 stp->syserr = "lseek";
13104 stp->error_no = errno;
13105 return;
13106 }
13107 src_offset = (rb_off_t)-1;
13108 use_pread = 0;
13109 }
13110
13111 while (use_eof || 0 < copy_length) {
13112 if (!use_eof && copy_length < (rb_off_t)sizeof(buf)) {
13113 len = (size_t)copy_length;
13114 }
13115 else {
13116 len = sizeof(buf);
13117 }
13118 if (use_pread) {
13119 ss = maygvl_copy_stream_read(0, stp, buf, len, src_offset);
13120 if (0 < ss)
13121 src_offset += ss;
13122 }
13123 else {
13124 ss = maygvl_copy_stream_read(0, stp, buf, len, (rb_off_t)-1);
13125 }
13126 if (ss <= 0) /* EOF or error */
13127 return;
13128
13129 ret = nogvl_copy_stream_write(stp, buf, ss);
13130 if (ret < 0)
13131 return;
13132
13133 if (!use_eof)
13134 copy_length -= ss;
13135 }
13136}
13137
13138static void *
13139nogvl_copy_stream_func(void *arg)
13140{
13141 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13142#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13143 int ret;
13144#endif
13145
13146#ifdef USE_COPY_FILE_RANGE
13147 ret = nogvl_copy_file_range(stp);
13148 if (ret != 0)
13149 goto finish; /* error or success */
13150#endif
13151
13152#ifdef HAVE_FCOPYFILE
13153 ret = nogvl_fcopyfile(stp);
13154 if (ret != 0)
13155 goto finish; /* error or success */
13156#endif
13157
13158#ifdef USE_SENDFILE
13159 ret = nogvl_copy_stream_sendfile(stp);
13160 if (ret != 0)
13161 goto finish; /* error or success */
13162#endif
13163
13164 nogvl_copy_stream_read_write(stp);
13165
13166#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13167 finish:
13168#endif
13169 return 0;
13170}
13171
13172static VALUE
13173copy_stream_fallback_body(VALUE arg)
13174{
13175 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13176 const int buflen = 16*1024;
13177 VALUE n;
13178 VALUE buf = rb_str_buf_new(buflen);
13179 rb_off_t rest = stp->copy_length;
13180 rb_off_t off = stp->src_offset;
13181 ID read_method = id_readpartial;
13182
13183 if (!stp->src_fptr) {
13184 if (!rb_respond_to(stp->src, read_method)) {
13185 read_method = id_read;
13186 }
13187 }
13188
13189 while (1) {
13190 long numwrote;
13191 long l;
13192 rb_str_make_independent(buf);
13193 if (stp->copy_length < (rb_off_t)0) {
13194 l = buflen;
13195 }
13196 else {
13197 if (rest == 0) {
13198 rb_str_resize(buf, 0);
13199 break;
13200 }
13201 l = buflen < rest ? buflen : (long)rest;
13202 }
13203 if (!stp->src_fptr) {
13204 VALUE rc = rb_funcall(stp->src, read_method, 2, INT2FIX(l), buf);
13205
13206 if (read_method == id_read && NIL_P(rc))
13207 break;
13208 }
13209 else {
13210 ssize_t ss;
13211 rb_str_resize(buf, buflen);
13212 ss = maygvl_copy_stream_read(1, stp, RSTRING_PTR(buf), l, off);
13213 rb_str_resize(buf, ss > 0 ? ss : 0);
13214 if (ss < 0)
13215 return Qnil;
13216 if (ss == 0)
13217 rb_eof_error();
13218 if (off >= (rb_off_t)0)
13219 off += ss;
13220 }
13221 n = rb_io_write(stp->dst, buf);
13222 numwrote = NUM2LONG(n);
13223 stp->total += numwrote;
13224 rest -= numwrote;
13225 if (read_method == id_read && RSTRING_LEN(buf) == 0) {
13226 break;
13227 }
13228 }
13229
13230 return Qnil;
13231}
13232
13233static VALUE
13234copy_stream_fallback(struct copy_stream_struct *stp)
13235{
13236 if (!stp->src_fptr && stp->src_offset >= (rb_off_t)0) {
13237 rb_raise(rb_eArgError, "cannot specify src_offset for non-IO");
13238 }
13239 rb_rescue2(copy_stream_fallback_body, (VALUE)stp,
13240 (VALUE (*) (VALUE, VALUE))0, (VALUE)0,
13241 rb_eEOFError, (VALUE)0);
13242 return Qnil;
13243}
13244
13245static VALUE
13246copy_stream_body(VALUE arg)
13247{
13248 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13249 VALUE src_io = stp->src, dst_io = stp->dst;
13250 const int common_oflags = 0
13251#ifdef O_NOCTTY
13252 | O_NOCTTY
13253#endif
13254 ;
13255
13256 stp->th = rb_thread_current();
13257
13258 stp->total = 0;
13259
13260 if (src_io == argf ||
13261 !(RB_TYPE_P(src_io, T_FILE) ||
13262 RB_TYPE_P(src_io, T_STRING) ||
13263 rb_respond_to(src_io, rb_intern("to_path")))) {
13264 stp->src_fptr = NULL;
13265 }
13266 else {
13267 int stat_ret;
13268 VALUE tmp_io = rb_io_check_io(src_io);
13269 if (!NIL_P(tmp_io)) {
13270 src_io = tmp_io;
13271 }
13272 else if (!RB_TYPE_P(src_io, T_FILE)) {
13273 VALUE args[2];
13274 FilePathValue(src_io);
13275 args[0] = src_io;
13276 args[1] = INT2NUM(O_RDONLY|common_oflags);
13277 src_io = rb_class_new_instance(2, args, rb_cFile);
13278 stp->src = src_io;
13279 stp->close_src = 1;
13280 }
13281 RB_IO_POINTER(src_io, stp->src_fptr);
13282 rb_io_check_byte_readable(stp->src_fptr);
13283
13284 stat_ret = fstat(stp->src_fptr->fd, &stp->src_stat);
13285 if (stat_ret < 0) {
13286 stp->syserr = "fstat";
13287 stp->error_no = errno;
13288 return Qnil;
13289 }
13290 }
13291
13292 if (dst_io == argf ||
13293 !(RB_TYPE_P(dst_io, T_FILE) ||
13294 RB_TYPE_P(dst_io, T_STRING) ||
13295 rb_respond_to(dst_io, rb_intern("to_path")))) {
13296 stp->dst_fptr = NULL;
13297 }
13298 else {
13299 int stat_ret;
13300 VALUE tmp_io = rb_io_check_io(dst_io);
13301 if (!NIL_P(tmp_io)) {
13302 dst_io = GetWriteIO(tmp_io);
13303 }
13304 else if (!RB_TYPE_P(dst_io, T_FILE)) {
13305 VALUE args[3];
13306 FilePathValue(dst_io);
13307 args[0] = dst_io;
13308 args[1] = INT2NUM(O_WRONLY|O_CREAT|O_TRUNC|common_oflags);
13309 args[2] = INT2FIX(0666);
13310 dst_io = rb_class_new_instance(3, args, rb_cFile);
13311 stp->dst = dst_io;
13312 stp->close_dst = 1;
13313 }
13314 else {
13315 dst_io = GetWriteIO(dst_io);
13316 stp->dst = dst_io;
13317 }
13318 RB_IO_POINTER(dst_io, stp->dst_fptr);
13319 rb_io_check_writable(stp->dst_fptr);
13320
13321 stat_ret = fstat(stp->dst_fptr->fd, &stp->dst_stat);
13322 if (stat_ret < 0) {
13323 stp->syserr = "fstat";
13324 stp->error_no = errno;
13325 return Qnil;
13326 }
13327 }
13328
13329#ifdef O_BINARY
13330 if (stp->src_fptr)
13331 SET_BINARY_MODE_WITH_SEEK_CUR(stp->src_fptr);
13332#endif
13333 if (stp->dst_fptr)
13334 io_ascii8bit_binmode(stp->dst_fptr);
13335
13336 if (stp->src_offset < (rb_off_t)0 && stp->src_fptr && stp->src_fptr->rbuf.len) {
13337 size_t len = stp->src_fptr->rbuf.len;
13338 VALUE str;
13339 if (stp->copy_length >= (rb_off_t)0 && stp->copy_length < (rb_off_t)len) {
13340 len = (size_t)stp->copy_length;
13341 }
13342 str = rb_str_buf_new(len);
13343 rb_str_resize(str,len);
13344 read_buffered_data(RSTRING_PTR(str), len, stp->src_fptr);
13345 if (stp->dst_fptr) { /* IO or filename */
13346 if (io_binwrite(RSTRING_PTR(str), RSTRING_LEN(str), stp->dst_fptr, 0) < 0)
13347 rb_sys_fail_on_write(stp->dst_fptr);
13348 }
13349 else /* others such as StringIO */
13350 rb_io_write(dst_io, str);
13351 rb_str_resize(str, 0);
13352 stp->total += len;
13353 if (stp->copy_length >= (rb_off_t)0)
13354 stp->copy_length -= len;
13355 }
13356
13357 if (stp->dst_fptr && io_fflush(stp->dst_fptr) < 0) {
13358 rb_raise(rb_eIOError, "flush failed");
13359 }
13360
13361 if (stp->copy_length == 0)
13362 return Qnil;
13363
13364 if (stp->src_fptr == NULL || stp->dst_fptr == NULL) {
13365 return copy_stream_fallback(stp);
13366 }
13367
13368 IO_WITHOUT_GVL(nogvl_copy_stream_func, stp);
13369 return Qnil;
13370}
13371
13372static VALUE
13373copy_stream_finalize(VALUE arg)
13374{
13375 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13376
13377#ifdef HAVE_FCOPYFILE
13378 if (stp->copyfile_state) {
13379 copyfile_state_free(stp->copyfile_state);
13380 }
13381#endif
13382
13383 if (stp->close_src) {
13384 rb_io_close_m(stp->src);
13385 }
13386 if (stp->close_dst) {
13387 rb_io_close_m(stp->dst);
13388 }
13389 if (stp->syserr) {
13390 rb_syserr_fail(stp->error_no, stp->syserr);
13391 }
13392 if (stp->notimp) {
13393 rb_raise(rb_eNotImpError, "%s() not implemented", stp->notimp);
13394 }
13395 return Qnil;
13396}
13397
13398/*
13399 * call-seq:
13400 * IO.copy_stream(src, dst, src_length = nil, src_offset = 0) -> integer
13401 *
13402 * Copies from the given +src+ to the given +dst+,
13403 * returning the number of bytes copied.
13404 *
13405 * - The given +src+ must be one of the following:
13406 *
13407 * - The path to a readable file, from which source data is to be read.
13408 * - An \IO-like object, opened for reading and capable of responding
13409 * to method +:readpartial+ or method +:read+.
13410 *
13411 * - The given +dst+ must be one of the following:
13412 *
13413 * - The path to a writable file, to which data is to be written.
13414 * - An \IO-like object, opened for writing and capable of responding
13415 * to method +:write+.
13416 *
13417 * The examples here use file <tt>t.txt</tt> as source:
13418 *
13419 * File.read('t.txt')
13420 * # => "First line\nSecond line\n\nThird line\nFourth line\n"
13421 * File.read('t.txt').size # => 47
13422 *
13423 * If only arguments +src+ and +dst+ are given,
13424 * the entire source stream is copied:
13425 *
13426 * # Paths.
13427 * IO.copy_stream('t.txt', 't.tmp') # => 47
13428 *
13429 * # IOs (recall that a File is also an IO).
13430 * src_io = File.open('t.txt', 'r') # => #<File:t.txt>
13431 * dst_io = File.open('t.tmp', 'w') # => #<File:t.tmp>
13432 * IO.copy_stream(src_io, dst_io) # => 47
13433 * src_io.close
13434 * dst_io.close
13435 *
13436 * With argument +src_length+ a non-negative integer,
13437 * no more than that many bytes are copied:
13438 *
13439 * IO.copy_stream('t.txt', 't.tmp', 10) # => 10
13440 * File.read('t.tmp') # => "First line"
13441 *
13442 * With argument +src_offset+ also given,
13443 * the source stream is read beginning at that offset:
13444 *
13445 * IO.copy_stream('t.txt', 't.tmp', 11, 11) # => 11
13446 * IO.read('t.tmp') # => "Second line"
13447 *
13448 */
13449static VALUE
13450rb_io_s_copy_stream(int argc, VALUE *argv, VALUE io)
13451{
13452 VALUE src, dst, length, src_offset;
13453 struct copy_stream_struct st;
13454
13455 MEMZERO(&st, struct copy_stream_struct, 1);
13456
13457 rb_scan_args(argc, argv, "22", &src, &dst, &length, &src_offset);
13458
13459 st.src = src;
13460 st.dst = dst;
13461
13462 st.src_fptr = NULL;
13463 st.dst_fptr = NULL;
13464
13465 if (NIL_P(length))
13466 st.copy_length = (rb_off_t)-1;
13467 else
13468 st.copy_length = NUM2OFFT(length);
13469
13470 if (NIL_P(src_offset))
13471 st.src_offset = (rb_off_t)-1;
13472 else
13473 st.src_offset = NUM2OFFT(src_offset);
13474
13475 rb_ensure(copy_stream_body, (VALUE)&st, copy_stream_finalize, (VALUE)&st);
13476
13477 return OFFT2NUM(st.total);
13478}
13479
13480/*
13481 * call-seq:
13482 * external_encoding -> encoding or nil
13483 *
13484 * Returns the Encoding object that represents the encoding of the stream,
13485 * or +nil+ if the stream is in write mode and no encoding is specified.
13486 *
13487 * See {Encodings}[rdoc-ref:File@Encodings].
13488 *
13489 */
13490
13491static VALUE
13492rb_io_external_encoding(VALUE io)
13493{
13494 rb_io_t *fptr = RFILE(rb_io_taint_check(io))->fptr;
13495
13496 if (fptr->encs.enc2) {
13497 return rb_enc_from_encoding(fptr->encs.enc2);
13498 }
13499 if (fptr->mode & FMODE_WRITABLE) {
13500 if (fptr->encs.enc)
13501 return rb_enc_from_encoding(fptr->encs.enc);
13502 return Qnil;
13503 }
13504 return rb_enc_from_encoding(io_read_encoding(fptr));
13505}
13506
13507/*
13508 * call-seq:
13509 * internal_encoding -> encoding or nil
13510 *
13511 * Returns the Encoding object that represents the encoding of the internal string,
13512 * if conversion is specified,
13513 * or +nil+ otherwise.
13514 *
13515 * See {Encodings}[rdoc-ref:File@Encodings].
13516 *
13517 */
13518
13519static VALUE
13520rb_io_internal_encoding(VALUE io)
13521{
13522 rb_io_t *fptr = RFILE(rb_io_taint_check(io))->fptr;
13523
13524 if (!fptr->encs.enc2) return Qnil;
13525 return rb_enc_from_encoding(io_read_encoding(fptr));
13526}
13527
13528/*
13529 * call-seq:
13530 * set_encoding(ext_enc) -> self
13531 * set_encoding(ext_enc, int_enc, **enc_opts) -> self
13532 * set_encoding('ext_enc:int_enc', **enc_opts) -> self
13533 *
13534 * See {Encodings}[rdoc-ref:File@Encodings].
13535 *
13536 * Argument +ext_enc+, if given, must be an Encoding object
13537 * or a String with the encoding name;
13538 * it is assigned as the encoding for the stream.
13539 *
13540 * Argument +int_enc+, if given, must be an Encoding object
13541 * or a String with the encoding name;
13542 * it is assigned as the encoding for the internal string.
13543 *
13544 * Argument <tt>'ext_enc:int_enc'</tt>, if given, is a string
13545 * containing two colon-separated encoding names;
13546 * corresponding Encoding objects are assigned as the external
13547 * and internal encodings for the stream.
13548 *
13549 * If the external encoding of a string is binary/ASCII-8BIT,
13550 * the internal encoding of the string is set to nil, since no
13551 * transcoding is needed.
13552 *
13553 * Optional keyword arguments +enc_opts+ specify
13554 * {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
13555 *
13556 */
13557
13558static VALUE
13559rb_io_set_encoding(int argc, VALUE *argv, VALUE io)
13560{
13561 rb_io_t *fptr;
13562 VALUE v1, v2, opt;
13563
13564 if (!RB_TYPE_P(io, T_FILE)) {
13565 return forward(io, id_set_encoding, argc, argv);
13566 }
13567
13568 argc = rb_scan_args(argc, argv, "11:", &v1, &v2, &opt);
13569 GetOpenFile(io, fptr);
13570 io_encoding_set(fptr, v1, v2, opt);
13571 return io;
13572}
13573
13574void
13575rb_stdio_set_default_encoding(void)
13576{
13577 VALUE val = Qnil;
13578
13579#ifdef _WIN32
13580 if (isatty(fileno(stdin))) {
13581 rb_encoding *external = rb_locale_encoding();
13582 rb_encoding *internal = rb_default_internal_encoding();
13583 if (!internal) internal = rb_default_external_encoding();
13584 io_encoding_set(RFILE(rb_stdin)->fptr,
13585 rb_enc_from_encoding(external),
13586 rb_enc_from_encoding(internal),
13587 Qnil);
13588 }
13589 else
13590#endif
13591 rb_io_set_encoding(1, &val, rb_stdin);
13592 rb_io_set_encoding(1, &val, rb_stdout);
13593 rb_io_set_encoding(1, &val, rb_stderr);
13594}
13595
13596static inline int
13597global_argf_p(VALUE arg)
13598{
13599 return arg == argf;
13600}
13601
13602typedef VALUE (*argf_encoding_func)(VALUE io);
13603
13604static VALUE
13605argf_encoding(VALUE argf, argf_encoding_func func)
13606{
13607 if (!RTEST(ARGF.current_file)) {
13608 return rb_enc_default_external();
13609 }
13610 return func(rb_io_check_io(ARGF.current_file));
13611}
13612
13613/*
13614 * call-seq:
13615 * ARGF.external_encoding -> encoding
13616 *
13617 * Returns the external encoding for files read from ARGF as an Encoding
13618 * object. The external encoding is the encoding of the text as stored in a
13619 * file. Contrast with ARGF.internal_encoding, which is the encoding used to
13620 * represent this text within Ruby.
13621 *
13622 * To set the external encoding use ARGF.set_encoding.
13623 *
13624 * For example:
13625 *
13626 * ARGF.external_encoding #=> #<Encoding:UTF-8>
13627 *
13628 */
13629static VALUE
13630argf_external_encoding(VALUE argf)
13631{
13632 return argf_encoding(argf, rb_io_external_encoding);
13633}
13634
13635/*
13636 * call-seq:
13637 * ARGF.internal_encoding -> encoding
13638 *
13639 * Returns the internal encoding for strings read from ARGF as an
13640 * Encoding object.
13641 *
13642 * If ARGF.set_encoding has been called with two encoding names, the second
13643 * is returned. Otherwise, if +Encoding.default_external+ has been set, that
13644 * value is returned. Failing that, if a default external encoding was
13645 * specified on the command-line, that value is used. If the encoding is
13646 * unknown, +nil+ is returned.
13647 */
13648static VALUE
13649argf_internal_encoding(VALUE argf)
13650{
13651 return argf_encoding(argf, rb_io_internal_encoding);
13652}
13653
13654/*
13655 * call-seq:
13656 * ARGF.set_encoding(ext_enc) -> ARGF
13657 * ARGF.set_encoding("ext_enc:int_enc") -> ARGF
13658 * ARGF.set_encoding(ext_enc, int_enc) -> ARGF
13659 * ARGF.set_encoding("ext_enc:int_enc", opt) -> ARGF
13660 * ARGF.set_encoding(ext_enc, int_enc, opt) -> ARGF
13661 *
13662 * If single argument is specified, strings read from ARGF are tagged with
13663 * the encoding specified.
13664 *
13665 * If two encoding names separated by a colon are given, e.g. "ascii:utf-8",
13666 * the read string is converted from the first encoding (external encoding)
13667 * to the second encoding (internal encoding), then tagged with the second
13668 * encoding.
13669 *
13670 * If two arguments are specified, they must be encoding objects or encoding
13671 * names. Again, the first specifies the external encoding; the second
13672 * specifies the internal encoding.
13673 *
13674 * If the external encoding and the internal encoding are specified, the
13675 * optional Hash argument can be used to adjust the conversion process. The
13676 * structure of this hash is explained in the String#encode documentation.
13677 *
13678 * For example:
13679 *
13680 * ARGF.set_encoding('ascii') # Tag the input as US-ASCII text
13681 * ARGF.set_encoding(Encoding::UTF_8) # Tag the input as UTF-8 text
13682 * ARGF.set_encoding('utf-8','ascii') # Transcode the input from US-ASCII
13683 * # to UTF-8.
13684 */
13685static VALUE
13686argf_set_encoding(int argc, VALUE *argv, VALUE argf)
13687{
13688 rb_io_t *fptr;
13689
13690 if (!next_argv()) {
13691 rb_raise(rb_eArgError, "no stream to set encoding");
13692 }
13693 rb_io_set_encoding(argc, argv, ARGF.current_file);
13694 GetOpenFile(ARGF.current_file, fptr);
13695 ARGF.encs = fptr->encs;
13696 return argf;
13697}
13698
13699/*
13700 * call-seq:
13701 * ARGF.tell -> Integer
13702 * ARGF.pos -> Integer
13703 *
13704 * Returns the current offset (in bytes) of the current file in ARGF.
13705 *
13706 * ARGF.pos #=> 0
13707 * ARGF.gets #=> "This is line one\n"
13708 * ARGF.pos #=> 17
13709 *
13710 */
13711static VALUE
13712argf_tell(VALUE argf)
13713{
13714 if (!next_argv()) {
13715 rb_raise(rb_eArgError, "no stream to tell");
13716 }
13717 ARGF_FORWARD(0, 0);
13718 return rb_io_tell(ARGF.current_file);
13719}
13720
13721/*
13722 * call-seq:
13723 * ARGF.seek(amount, whence=IO::SEEK_SET) -> 0
13724 *
13725 * Seeks to offset _amount_ (an Integer) in the ARGF stream according to
13726 * the value of _whence_. See IO#seek for further details.
13727 */
13728static VALUE
13729argf_seek_m(int argc, VALUE *argv, VALUE argf)
13730{
13731 if (!next_argv()) {
13732 rb_raise(rb_eArgError, "no stream to seek");
13733 }
13734 ARGF_FORWARD(argc, argv);
13735 return rb_io_seek_m(argc, argv, ARGF.current_file);
13736}
13737
13738/*
13739 * call-seq:
13740 * ARGF.pos = position -> Integer
13741 *
13742 * Seeks to the position given by _position_ (in bytes) in ARGF.
13743 *
13744 * For example:
13745 *
13746 * ARGF.pos = 17
13747 * ARGF.gets #=> "This is line two\n"
13748 */
13749static VALUE
13750argf_set_pos(VALUE argf, VALUE offset)
13751{
13752 if (!next_argv()) {
13753 rb_raise(rb_eArgError, "no stream to set position");
13754 }
13755 ARGF_FORWARD(1, &offset);
13756 return rb_io_set_pos(ARGF.current_file, offset);
13757}
13758
13759/*
13760 * call-seq:
13761 * ARGF.rewind -> 0
13762 *
13763 * Positions the current file to the beginning of input, resetting
13764 * ARGF.lineno to zero.
13765 *
13766 * ARGF.readline #=> "This is line one\n"
13767 * ARGF.rewind #=> 0
13768 * ARGF.lineno #=> 0
13769 * ARGF.readline #=> "This is line one\n"
13770 */
13771static VALUE
13772argf_rewind(VALUE argf)
13773{
13774 VALUE ret;
13775 int old_lineno;
13776
13777 if (!next_argv()) {
13778 rb_raise(rb_eArgError, "no stream to rewind");
13779 }
13780 ARGF_FORWARD(0, 0);
13781 old_lineno = RFILE(ARGF.current_file)->fptr->lineno;
13782 ret = rb_io_rewind(ARGF.current_file);
13783 if (!global_argf_p(argf)) {
13784 ARGF.last_lineno = ARGF.lineno -= old_lineno;
13785 }
13786 return ret;
13787}
13788
13789/*
13790 * call-seq:
13791 * ARGF.fileno -> integer
13792 * ARGF.to_i -> integer
13793 *
13794 * Returns an integer representing the numeric file descriptor for
13795 * the current file. Raises an ArgumentError if there isn't a current file.
13796 *
13797 * ARGF.fileno #=> 3
13798 */
13799static VALUE
13800argf_fileno(VALUE argf)
13801{
13802 if (!next_argv()) {
13803 rb_raise(rb_eArgError, "no stream");
13804 }
13805 ARGF_FORWARD(0, 0);
13806 return rb_io_fileno(ARGF.current_file);
13807}
13808
13809/*
13810 * call-seq:
13811 * ARGF.to_io -> IO
13812 *
13813 * Returns an IO object representing the current file. This will be a
13814 * File object unless the current file is a stream such as STDIN.
13815 *
13816 * For example:
13817 *
13818 * ARGF.to_io #=> #<File:glark.txt>
13819 * ARGF.to_io #=> #<IO:<STDIN>>
13820 */
13821static VALUE
13822argf_to_io(VALUE argf)
13823{
13824 next_argv();
13825 ARGF_FORWARD(0, 0);
13826 return ARGF.current_file;
13827}
13828
13829/*
13830 * call-seq:
13831 * ARGF.eof? -> true or false
13832 * ARGF.eof -> true or false
13833 *
13834 * Returns true if the current file in ARGF is at end of file, i.e. it has
13835 * no data to read. The stream must be opened for reading or an IOError
13836 * will be raised.
13837 *
13838 * $ echo "eof" | ruby argf.rb
13839 *
13840 * ARGF.eof? #=> false
13841 * 3.times { ARGF.readchar }
13842 * ARGF.eof? #=> false
13843 * ARGF.readchar #=> "\n"
13844 * ARGF.eof? #=> true
13845 */
13846
13847static VALUE
13848argf_eof(VALUE argf)
13849{
13850 next_argv();
13851 if (RTEST(ARGF.current_file)) {
13852 if (ARGF.init_p == 0) return Qtrue;
13853 next_argv();
13854 ARGF_FORWARD(0, 0);
13855 if (rb_io_eof(ARGF.current_file)) {
13856 return Qtrue;
13857 }
13858 }
13859 return Qfalse;
13860}
13861
13862/*
13863 * call-seq:
13864 * ARGF.read([length [, outbuf]]) -> string, outbuf, or nil
13865 *
13866 * Reads _length_ bytes from ARGF. The files named on the command line
13867 * are concatenated and treated as a single file by this method, so when
13868 * called without arguments the contents of this pseudo file are returned in
13869 * their entirety.
13870 *
13871 * _length_ must be a non-negative integer or +nil+.
13872 *
13873 * If _length_ is a positive integer, +read+ tries to read
13874 * _length_ bytes without any conversion (binary mode).
13875 * It returns +nil+ if an EOF is encountered before anything can be read.
13876 * Fewer than _length_ bytes are returned if an EOF is encountered during
13877 * the read.
13878 * In the case of an integer _length_, the resulting string is always
13879 * in ASCII-8BIT encoding.
13880 *
13881 * If _length_ is omitted or is +nil+, it reads until EOF
13882 * and the encoding conversion is applied, if applicable.
13883 * A string is returned even if EOF is encountered before any data is read.
13884 *
13885 * If _length_ is zero, it returns an empty string (<code>""</code>).
13886 *
13887 * If the optional _outbuf_ argument is present,
13888 * it must reference a String, which will receive the data.
13889 * The _outbuf_ will contain only the received data after the method call
13890 * even if it is not empty at the beginning.
13891 *
13892 * For example:
13893 *
13894 * $ echo "small" > small.txt
13895 * $ echo "large" > large.txt
13896 * $ ./glark.rb small.txt large.txt
13897 *
13898 * ARGF.read #=> "small\nlarge"
13899 * ARGF.read(200) #=> "small\nlarge"
13900 * ARGF.read(2) #=> "sm"
13901 * ARGF.read(0) #=> ""
13902 *
13903 * Note that this method behaves like the fread() function in C.
13904 * This means it retries to invoke read(2) system calls to read data
13905 * with the specified length.
13906 * If you need the behavior like a single read(2) system call,
13907 * consider ARGF#readpartial or ARGF#read_nonblock.
13908 */
13909
13910static VALUE
13911argf_read(int argc, VALUE *argv, VALUE argf)
13912{
13913 VALUE tmp, str, length;
13914 long len = 0;
13915
13916 rb_scan_args(argc, argv, "02", &length, &str);
13917 if (!NIL_P(length)) {
13918 len = NUM2LONG(argv[0]);
13919 }
13920 if (!NIL_P(str)) {
13921 StringValue(str);
13922 rb_str_resize(str,0);
13923 argv[1] = Qnil;
13924 }
13925
13926 retry:
13927 if (!next_argv()) {
13928 return str;
13929 }
13930 if (ARGF_GENERIC_INPUT_P()) {
13931 tmp = argf_forward(argc, argv, argf);
13932 }
13933 else {
13934 tmp = io_read(argc, argv, ARGF.current_file);
13935 }
13936 if (NIL_P(str)) str = tmp;
13937 else if (!NIL_P(tmp)) rb_str_append(str, tmp);
13938 if (NIL_P(tmp) || NIL_P(length)) {
13939 if (ARGF.next_p != -1) {
13940 argf_close(argf);
13941 ARGF.next_p = 1;
13942 goto retry;
13943 }
13944 }
13945 else if (argc >= 1) {
13946 long slen = RSTRING_LEN(str);
13947 if (slen < len) {
13948 argv[0] = LONG2NUM(len - slen);
13949 goto retry;
13950 }
13951 }
13952 return str;
13953}
13954
13956 int argc;
13957 VALUE *argv;
13958 VALUE argf;
13959};
13960
13961static VALUE
13962argf_forward_call(VALUE arg)
13963{
13964 struct argf_call_arg *p = (struct argf_call_arg *)arg;
13965 argf_forward(p->argc, p->argv, p->argf);
13966 return Qnil;
13967}
13968
13969static VALUE argf_getpartial(int argc, VALUE *argv, VALUE argf, VALUE opts,
13970 int nonblock);
13971
13972/*
13973 * call-seq:
13974 * ARGF.readpartial(maxlen) -> string
13975 * ARGF.readpartial(maxlen, outbuf) -> outbuf
13976 *
13977 * Reads at most _maxlen_ bytes from the ARGF stream.
13978 *
13979 * If the optional _outbuf_ argument is present,
13980 * it must reference a String, which will receive the data.
13981 * The _outbuf_ will contain only the received data after the method call
13982 * even if it is not empty at the beginning.
13983 *
13984 * It raises EOFError on end of ARGF stream.
13985 * Since ARGF stream is a concatenation of multiple files,
13986 * internally EOF is occur for each file.
13987 * ARGF.readpartial returns empty strings for EOFs except the last one and
13988 * raises EOFError for the last one.
13989 *
13990 */
13991
13992static VALUE
13993argf_readpartial(int argc, VALUE *argv, VALUE argf)
13994{
13995 return argf_getpartial(argc, argv, argf, Qnil, 0);
13996}
13997
13998/*
13999 * call-seq:
14000 * ARGF.read_nonblock(maxlen[, options]) -> string
14001 * ARGF.read_nonblock(maxlen, outbuf[, options]) -> outbuf
14002 *
14003 * Reads at most _maxlen_ bytes from the ARGF stream in non-blocking mode.
14004 */
14005
14006static VALUE
14007argf_read_nonblock(int argc, VALUE *argv, VALUE argf)
14008{
14009 VALUE opts;
14010
14011 rb_scan_args(argc, argv, "11:", NULL, NULL, &opts);
14012
14013 if (!NIL_P(opts))
14014 argc--;
14015
14016 return argf_getpartial(argc, argv, argf, opts, 1);
14017}
14018
14019static VALUE
14020argf_getpartial(int argc, VALUE *argv, VALUE argf, VALUE opts, int nonblock)
14021{
14022 VALUE tmp, str, length;
14023 int no_exception;
14024
14025 rb_scan_args(argc, argv, "11", &length, &str);
14026 if (!NIL_P(str)) {
14027 StringValue(str);
14028 argv[1] = str;
14029 }
14030 no_exception = no_exception_p(opts);
14031
14032 if (!next_argv()) {
14033 if (!NIL_P(str)) {
14034 rb_str_resize(str, 0);
14035 }
14036 rb_eof_error();
14037 }
14038 if (ARGF_GENERIC_INPUT_P()) {
14039 VALUE (*const rescue_does_nothing)(VALUE, VALUE) = 0;
14040 struct argf_call_arg arg;
14041 arg.argc = argc;
14042 arg.argv = argv;
14043 arg.argf = argf;
14044 tmp = rb_rescue2(argf_forward_call, (VALUE)&arg,
14045 rescue_does_nothing, Qnil, rb_eEOFError, (VALUE)0);
14046 }
14047 else {
14048 tmp = io_getpartial(argc, argv, ARGF.current_file, no_exception, nonblock);
14049 }
14050 if (NIL_P(tmp)) {
14051 if (ARGF.next_p == -1) {
14052 return io_nonblock_eof(no_exception);
14053 }
14054 argf_close(argf);
14055 ARGF.next_p = 1;
14056 if (RARRAY_LEN(ARGF.argv) == 0) {
14057 return io_nonblock_eof(no_exception);
14058 }
14059 if (NIL_P(str))
14060 str = rb_str_new(NULL, 0);
14061 return str;
14062 }
14063 return tmp;
14064}
14065
14066/*
14067 * call-seq:
14068 * ARGF.getc -> String or nil
14069 *
14070 * Reads the next character from ARGF and returns it as a String. Returns
14071 * +nil+ at the end of the stream.
14072 *
14073 * ARGF treats the files named on the command line as a single file created
14074 * by concatenating their contents. After returning the last character of the
14075 * first file, it returns the first character of the second file, and so on.
14076 *
14077 * For example:
14078 *
14079 * $ echo "foo" > file
14080 * $ ruby argf.rb file
14081 *
14082 * ARGF.getc #=> "f"
14083 * ARGF.getc #=> "o"
14084 * ARGF.getc #=> "o"
14085 * ARGF.getc #=> "\n"
14086 * ARGF.getc #=> nil
14087 * ARGF.getc #=> nil
14088 */
14089static VALUE
14090argf_getc(VALUE argf)
14091{
14092 VALUE ch;
14093
14094 retry:
14095 if (!next_argv()) return Qnil;
14096 if (ARGF_GENERIC_INPUT_P()) {
14097 ch = forward_current(rb_intern("getc"), 0, 0);
14098 }
14099 else {
14100 ch = rb_io_getc(ARGF.current_file);
14101 }
14102 if (NIL_P(ch) && ARGF.next_p != -1) {
14103 argf_close(argf);
14104 ARGF.next_p = 1;
14105 goto retry;
14106 }
14107
14108 return ch;
14109}
14110
14111/*
14112 * call-seq:
14113 * ARGF.getbyte -> Integer or nil
14114 *
14115 * Gets the next 8-bit byte (0..255) from ARGF. Returns +nil+ if called at
14116 * the end of the stream.
14117 *
14118 * For example:
14119 *
14120 * $ echo "foo" > file
14121 * $ ruby argf.rb file
14122 *
14123 * ARGF.getbyte #=> 102
14124 * ARGF.getbyte #=> 111
14125 * ARGF.getbyte #=> 111
14126 * ARGF.getbyte #=> 10
14127 * ARGF.getbyte #=> nil
14128 */
14129static VALUE
14130argf_getbyte(VALUE argf)
14131{
14132 VALUE ch;
14133
14134 retry:
14135 if (!next_argv()) return Qnil;
14136 if (!RB_TYPE_P(ARGF.current_file, T_FILE)) {
14137 ch = forward_current(rb_intern("getbyte"), 0, 0);
14138 }
14139 else {
14140 ch = rb_io_getbyte(ARGF.current_file);
14141 }
14142 if (NIL_P(ch) && ARGF.next_p != -1) {
14143 argf_close(argf);
14144 ARGF.next_p = 1;
14145 goto retry;
14146 }
14147
14148 return ch;
14149}
14150
14151/*
14152 * call-seq:
14153 * ARGF.readchar -> String or nil
14154 *
14155 * Reads the next character from ARGF and returns it as a String. Raises
14156 * an EOFError after the last character of the last file has been read.
14157 *
14158 * For example:
14159 *
14160 * $ echo "foo" > file
14161 * $ ruby argf.rb file
14162 *
14163 * ARGF.readchar #=> "f"
14164 * ARGF.readchar #=> "o"
14165 * ARGF.readchar #=> "o"
14166 * ARGF.readchar #=> "\n"
14167 * ARGF.readchar #=> end of file reached (EOFError)
14168 */
14169static VALUE
14170argf_readchar(VALUE argf)
14171{
14172 VALUE ch;
14173
14174 retry:
14175 if (!next_argv()) rb_eof_error();
14176 if (!RB_TYPE_P(ARGF.current_file, T_FILE)) {
14177 ch = forward_current(rb_intern("getc"), 0, 0);
14178 }
14179 else {
14180 ch = rb_io_getc(ARGF.current_file);
14181 }
14182 if (NIL_P(ch) && ARGF.next_p != -1) {
14183 argf_close(argf);
14184 ARGF.next_p = 1;
14185 goto retry;
14186 }
14187
14188 return ch;
14189}
14190
14191/*
14192 * call-seq:
14193 * ARGF.readbyte -> Integer
14194 *
14195 * Reads the next 8-bit byte from ARGF and returns it as an Integer. Raises
14196 * an EOFError after the last byte of the last file has been read.
14197 *
14198 * For example:
14199 *
14200 * $ echo "foo" > file
14201 * $ ruby argf.rb file
14202 *
14203 * ARGF.readbyte #=> 102
14204 * ARGF.readbyte #=> 111
14205 * ARGF.readbyte #=> 111
14206 * ARGF.readbyte #=> 10
14207 * ARGF.readbyte #=> end of file reached (EOFError)
14208 */
14209static VALUE
14210argf_readbyte(VALUE argf)
14211{
14212 VALUE c;
14213
14214 NEXT_ARGF_FORWARD(0, 0);
14215 c = argf_getbyte(argf);
14216 if (NIL_P(c)) {
14217 rb_eof_error();
14218 }
14219 return c;
14220}
14221
14222#define FOREACH_ARGF() while (next_argv())
14223
14224static VALUE
14225argf_block_call_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, argf))
14226{
14227 const VALUE current = ARGF.current_file;
14228 rb_yield_values2(argc, argv);
14229 if (ARGF.init_p == -1 || current != ARGF.current_file) {
14231 }
14232 return Qnil;
14233}
14234
14235#define ARGF_block_call(mid, argc, argv, func, argf) \
14236 rb_block_call_kw(ARGF.current_file, mid, argc, argv, \
14237 func, argf, rb_keyword_given_p())
14238
14239static void
14240argf_block_call(ID mid, int argc, VALUE *argv, VALUE argf)
14241{
14242 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_i, argf);
14243 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14244}
14245
14246static VALUE
14247argf_block_call_line_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, argf))
14248{
14249 if (!global_argf_p(argf)) {
14250 ARGF.last_lineno = ++ARGF.lineno;
14251 }
14252 return argf_block_call_i(i, argf, argc, argv, blockarg);
14253}
14254
14255static void
14256argf_block_call_line(ID mid, int argc, VALUE *argv, VALUE argf)
14257{
14258 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_line_i, argf);
14259 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14260}
14261
14262/*
14263 * call-seq:
14264 * ARGF.each(sep=$/) {|line| block } -> ARGF
14265 * ARGF.each(sep=$/, limit) {|line| block } -> ARGF
14266 * ARGF.each(...) -> an_enumerator
14267 *
14268 * ARGF.each_line(sep=$/) {|line| block } -> ARGF
14269 * ARGF.each_line(sep=$/, limit) {|line| block } -> ARGF
14270 * ARGF.each_line(...) -> an_enumerator
14271 *
14272 * Returns an enumerator which iterates over each line (separated by _sep_,
14273 * which defaults to your platform's newline character) of each file in
14274 * +ARGV+. If a block is supplied, each line in turn will be yielded to the
14275 * block, otherwise an enumerator is returned.
14276 * The optional _limit_ argument is an Integer specifying the maximum
14277 * length of each line; longer lines will be split according to this limit.
14278 *
14279 * This method allows you to treat the files supplied on the command line as
14280 * a single file consisting of the concatenation of each named file. After
14281 * the last line of the first file has been returned, the first line of the
14282 * second file is returned. The ARGF.filename and ARGF.lineno methods can be
14283 * used to determine the filename of the current line and line number of the
14284 * whole input, respectively.
14285 *
14286 * For example, the following code prints out each line of each named file
14287 * prefixed with its line number, displaying the filename once per file:
14288 *
14289 * ARGF.each_line do |line|
14290 * puts ARGF.filename if ARGF.file.lineno == 1
14291 * puts "#{ARGF.file.lineno}: #{line}"
14292 * end
14293 *
14294 * While the following code prints only the first file's name at first, and
14295 * the contents with line number counted through all named files.
14296 *
14297 * ARGF.each_line do |line|
14298 * puts ARGF.filename if ARGF.lineno == 1
14299 * puts "#{ARGF.lineno}: #{line}"
14300 * end
14301 */
14302static VALUE
14303argf_each_line(int argc, VALUE *argv, VALUE argf)
14304{
14305 RETURN_ENUMERATOR(argf, argc, argv);
14306 FOREACH_ARGF() {
14307 argf_block_call_line(rb_intern("each_line"), argc, argv, argf);
14308 }
14309 return argf;
14310}
14311
14312/*
14313 * call-seq:
14314 * ARGF.each_byte {|byte| block } -> ARGF
14315 * ARGF.each_byte -> an_enumerator
14316 *
14317 * Iterates over each byte of each file in +ARGV+.
14318 * A byte is returned as an Integer in the range 0..255.
14319 *
14320 * This method allows you to treat the files supplied on the command line as
14321 * a single file consisting of the concatenation of each named file. After
14322 * the last byte of the first file has been returned, the first byte of the
14323 * second file is returned. The ARGF.filename method can be used to
14324 * determine the filename of the current byte.
14325 *
14326 * If no block is given, an enumerator is returned instead.
14327 *
14328 * For example:
14329 *
14330 * ARGF.bytes.to_a #=> [35, 32, ... 95, 10]
14331 *
14332 */
14333static VALUE
14334argf_each_byte(VALUE argf)
14335{
14336 RETURN_ENUMERATOR(argf, 0, 0);
14337 FOREACH_ARGF() {
14338 argf_block_call(rb_intern("each_byte"), 0, 0, argf);
14339 }
14340 return argf;
14341}
14342
14343/*
14344 * call-seq:
14345 * ARGF.each_char {|char| block } -> ARGF
14346 * ARGF.each_char -> an_enumerator
14347 *
14348 * Iterates over each character of each file in ARGF.
14349 *
14350 * This method allows you to treat the files supplied on the command line as
14351 * a single file consisting of the concatenation of each named file. After
14352 * the last character of the first file has been returned, the first
14353 * character of the second file is returned. The ARGF.filename method can
14354 * be used to determine the name of the file in which the current character
14355 * appears.
14356 *
14357 * If no block is given, an enumerator is returned instead.
14358 */
14359static VALUE
14360argf_each_char(VALUE argf)
14361{
14362 RETURN_ENUMERATOR(argf, 0, 0);
14363 FOREACH_ARGF() {
14364 argf_block_call(rb_intern("each_char"), 0, 0, argf);
14365 }
14366 return argf;
14367}
14368
14369/*
14370 * call-seq:
14371 * ARGF.each_codepoint {|codepoint| block } -> ARGF
14372 * ARGF.each_codepoint -> an_enumerator
14373 *
14374 * Iterates over each codepoint of each file in ARGF.
14375 *
14376 * This method allows you to treat the files supplied on the command line as
14377 * a single file consisting of the concatenation of each named file. After
14378 * the last codepoint of the first file has been returned, the first
14379 * codepoint of the second file is returned. The ARGF.filename method can
14380 * be used to determine the name of the file in which the current codepoint
14381 * appears.
14382 *
14383 * If no block is given, an enumerator is returned instead.
14384 */
14385static VALUE
14386argf_each_codepoint(VALUE argf)
14387{
14388 RETURN_ENUMERATOR(argf, 0, 0);
14389 FOREACH_ARGF() {
14390 argf_block_call(rb_intern("each_codepoint"), 0, 0, argf);
14391 }
14392 return argf;
14393}
14394
14395/*
14396 * call-seq:
14397 * ARGF.filename -> String
14398 * ARGF.path -> String
14399 *
14400 * Returns the current filename. "-" is returned when the current file is
14401 * STDIN.
14402 *
14403 * For example:
14404 *
14405 * $ echo "foo" > foo
14406 * $ echo "bar" > bar
14407 * $ echo "glark" > glark
14408 *
14409 * $ ruby argf.rb foo bar glark
14410 *
14411 * ARGF.filename #=> "foo"
14412 * ARGF.read(5) #=> "foo\nb"
14413 * ARGF.filename #=> "bar"
14414 * ARGF.skip
14415 * ARGF.filename #=> "glark"
14416 */
14417static VALUE
14418argf_filename(VALUE argf)
14419{
14420 next_argv();
14421 return ARGF.filename;
14422}
14423
14424static VALUE
14425argf_filename_getter(ID id, VALUE *var)
14426{
14427 return argf_filename(*var);
14428}
14429
14430/*
14431 * call-seq:
14432 * ARGF.file -> IO or File object
14433 *
14434 * Returns the current file as an IO or File object.
14435 * <code>$stdin</code> is returned when the current file is STDIN.
14436 *
14437 * For example:
14438 *
14439 * $ echo "foo" > foo
14440 * $ echo "bar" > bar
14441 *
14442 * $ ruby argf.rb foo bar
14443 *
14444 * ARGF.file #=> #<File:foo>
14445 * ARGF.read(5) #=> "foo\nb"
14446 * ARGF.file #=> #<File:bar>
14447 */
14448static VALUE
14449argf_file(VALUE argf)
14450{
14451 next_argv();
14452 return ARGF.current_file;
14453}
14454
14455/*
14456 * call-seq:
14457 * ARGF.binmode -> ARGF
14458 *
14459 * Puts ARGF into binary mode. Once a stream is in binary mode, it cannot
14460 * be reset to non-binary mode. This option has the following effects:
14461 *
14462 * * Newline conversion is disabled.
14463 * * Encoding conversion is disabled.
14464 * * Content is treated as ASCII-8BIT.
14465 */
14466static VALUE
14467argf_binmode_m(VALUE argf)
14468{
14469 ARGF.binmode = 1;
14470 next_argv();
14471 ARGF_FORWARD(0, 0);
14472 rb_io_ascii8bit_binmode(ARGF.current_file);
14473 return argf;
14474}
14475
14476/*
14477 * call-seq:
14478 * ARGF.binmode? -> true or false
14479 *
14480 * Returns true if ARGF is being read in binary mode; false otherwise.
14481 * To enable binary mode use ARGF.binmode.
14482 *
14483 * For example:
14484 *
14485 * ARGF.binmode? #=> false
14486 * ARGF.binmode
14487 * ARGF.binmode? #=> true
14488 */
14489static VALUE
14490argf_binmode_p(VALUE argf)
14491{
14492 return RBOOL(ARGF.binmode);
14493}
14494
14495/*
14496 * call-seq:
14497 * ARGF.skip -> ARGF
14498 *
14499 * Sets the current file to the next file in ARGV. If there aren't any more
14500 * files it has no effect.
14501 *
14502 * For example:
14503 *
14504 * $ ruby argf.rb foo bar
14505 * ARGF.filename #=> "foo"
14506 * ARGF.skip
14507 * ARGF.filename #=> "bar"
14508 */
14509static VALUE
14510argf_skip(VALUE argf)
14511{
14512 if (ARGF.init_p && ARGF.next_p == 0) {
14513 argf_close(argf);
14514 ARGF.next_p = 1;
14515 }
14516 return argf;
14517}
14518
14519/*
14520 * call-seq:
14521 * ARGF.close -> ARGF
14522 *
14523 * Closes the current file and skips to the next file in ARGV. If there are
14524 * no more files to open, just closes the current file. STDIN will not be
14525 * closed.
14526 *
14527 * For example:
14528 *
14529 * $ ruby argf.rb foo bar
14530 *
14531 * ARGF.filename #=> "foo"
14532 * ARGF.close
14533 * ARGF.filename #=> "bar"
14534 * ARGF.close
14535 */
14536static VALUE
14537argf_close_m(VALUE argf)
14538{
14539 next_argv();
14540 argf_close(argf);
14541 if (ARGF.next_p != -1) {
14542 ARGF.next_p = 1;
14543 }
14544 ARGF.lineno = 0;
14545 return argf;
14546}
14547
14548/*
14549 * call-seq:
14550 * ARGF.closed? -> true or false
14551 *
14552 * Returns _true_ if the current file has been closed; _false_ otherwise. Use
14553 * ARGF.close to actually close the current file.
14554 */
14555static VALUE
14556argf_closed(VALUE argf)
14557{
14558 next_argv();
14559 ARGF_FORWARD(0, 0);
14560 return rb_io_closed_p(ARGF.current_file);
14561}
14562
14563/*
14564 * call-seq:
14565 * ARGF.to_s -> String
14566 *
14567 * Returns "ARGF".
14568 */
14569static VALUE
14570argf_to_s(VALUE argf)
14571{
14572 return rb_str_new2("ARGF");
14573}
14574
14575/*
14576 * call-seq:
14577 * ARGF.inplace_mode -> String
14578 *
14579 * Returns the file extension appended to the names of backup copies of
14580 * modified files under in-place edit mode. This value can be set using
14581 * ARGF.inplace_mode= or passing the +-i+ switch to the Ruby binary.
14582 */
14583static VALUE
14584argf_inplace_mode_get(VALUE argf)
14585{
14586 if (!ARGF.inplace) return Qnil;
14587 if (NIL_P(ARGF.inplace)) return rb_str_new(0, 0);
14588 return rb_str_dup(ARGF.inplace);
14589}
14590
14591static VALUE
14592opt_i_get(ID id, VALUE *var)
14593{
14594 return argf_inplace_mode_get(*var);
14595}
14596
14597/*
14598 * call-seq:
14599 * ARGF.inplace_mode = ext -> ARGF
14600 *
14601 * Sets the filename extension for in-place editing mode to the given String.
14602 * The backup copy of each file being edited has this value appended to its
14603 * filename.
14604 *
14605 * For example:
14606 *
14607 * $ ruby argf.rb file.txt
14608 *
14609 * ARGF.inplace_mode = '.bak'
14610 * ARGF.each_line do |line|
14611 * print line.sub("foo","bar")
14612 * end
14613 *
14614 * First, _file.txt.bak_ is created as a backup copy of _file.txt_.
14615 * Then, each line of _file.txt_ has the first occurrence of "foo" replaced with
14616 * "bar".
14617 */
14618static VALUE
14619argf_inplace_mode_set(VALUE argf, VALUE val)
14620{
14621 if (!RTEST(val)) {
14622 ARGF.inplace = Qfalse;
14623 }
14624 else if (StringValueCStr(val), !RSTRING_LEN(val)) {
14625 ARGF.inplace = Qnil;
14626 }
14627 else {
14628 ARGF.inplace = rb_str_new_frozen(val);
14629 }
14630 return argf;
14631}
14632
14633static void
14634opt_i_set(VALUE val, ID id, VALUE *var)
14635{
14636 argf_inplace_mode_set(*var, val);
14637}
14638
14639void
14640ruby_set_inplace_mode(const char *suffix)
14641{
14642 ARGF.inplace = !suffix ? Qfalse : !*suffix ? Qnil : rb_str_new(suffix, strlen(suffix));
14643}
14644
14645/*
14646 * call-seq:
14647 * ARGF.argv -> ARGV
14648 *
14649 * Returns the +ARGV+ array, which contains the arguments passed to your
14650 * script, one per element.
14651 *
14652 * For example:
14653 *
14654 * $ ruby argf.rb -v glark.txt
14655 *
14656 * ARGF.argv #=> ["-v", "glark.txt"]
14657 *
14658 */
14659static VALUE
14660argf_argv(VALUE argf)
14661{
14662 return ARGF.argv;
14663}
14664
14665static VALUE
14666argf_argv_getter(ID id, VALUE *var)
14667{
14668 return argf_argv(*var);
14669}
14670
14671VALUE
14673{
14674 return ARGF.argv;
14675}
14676
14677/*
14678 * call-seq:
14679 * ARGF.to_write_io -> io
14680 *
14681 * Returns IO instance tied to _ARGF_ for writing if inplace mode is
14682 * enabled.
14683 */
14684static VALUE
14685argf_write_io(VALUE argf)
14686{
14687 if (!RTEST(ARGF.current_file)) {
14688 rb_raise(rb_eIOError, "not opened for writing");
14689 }
14690 return GetWriteIO(ARGF.current_file);
14691}
14692
14693/*
14694 * call-seq:
14695 * ARGF.write(*objects) -> integer
14696 *
14697 * Writes each of the given +objects+ if inplace mode.
14698 */
14699static VALUE
14700argf_write(int argc, VALUE *argv, VALUE argf)
14701{
14702 return rb_io_writev(argf_write_io(argf), argc, argv);
14703}
14704
14705void
14706rb_readwrite_sys_fail(enum rb_io_wait_readwrite waiting, const char *mesg)
14707{
14708 rb_readwrite_syserr_fail(waiting, errno, mesg);
14709}
14710
14711void
14712rb_readwrite_syserr_fail(enum rb_io_wait_readwrite waiting, int n, const char *mesg)
14713{
14714 VALUE arg, c = Qnil;
14715 arg = mesg ? rb_str_new2(mesg) : Qnil;
14716 switch (waiting) {
14717 case RB_IO_WAIT_WRITABLE:
14718 switch (n) {
14719 case EAGAIN:
14720 c = rb_eEAGAINWaitWritable;
14721 break;
14722#if EAGAIN != EWOULDBLOCK
14723 case EWOULDBLOCK:
14724 c = rb_eEWOULDBLOCKWaitWritable;
14725 break;
14726#endif
14727 case EINPROGRESS:
14728 c = rb_eEINPROGRESSWaitWritable;
14729 break;
14730 default:
14732 }
14733 break;
14734 case RB_IO_WAIT_READABLE:
14735 switch (n) {
14736 case EAGAIN:
14737 c = rb_eEAGAINWaitReadable;
14738 break;
14739#if EAGAIN != EWOULDBLOCK
14740 case EWOULDBLOCK:
14741 c = rb_eEWOULDBLOCKWaitReadable;
14742 break;
14743#endif
14744 case EINPROGRESS:
14745 c = rb_eEINPROGRESSWaitReadable;
14746 break;
14747 default:
14749 }
14750 break;
14751 default:
14752 rb_bug("invalid read/write type passed to rb_readwrite_sys_fail: %d", waiting);
14753 }
14755}
14756
14757static VALUE
14758get_LAST_READ_LINE(ID _x, VALUE *_y)
14759{
14760 return rb_lastline_get();
14761}
14762
14763static void
14764set_LAST_READ_LINE(VALUE val, ID _x, VALUE *_y)
14765{
14766 rb_lastline_set(val);
14767}
14768
14769/*
14770 * Document-class: IOError
14771 *
14772 * Raised when an IO operation fails.
14773 *
14774 * File.open("/etc/hosts") {|f| f << "example"}
14775 * #=> IOError: not opened for writing
14776 *
14777 * File.open("/etc/hosts") {|f| f.close; f.read }
14778 * #=> IOError: closed stream
14779 *
14780 * Note that some IO failures raise <code>SystemCallError</code>s
14781 * and these are not subclasses of IOError:
14782 *
14783 * File.open("does/not/exist")
14784 * #=> Errno::ENOENT: No such file or directory - does/not/exist
14785 */
14786
14787/*
14788 * Document-class: EOFError
14789 *
14790 * Raised by some IO operations when reaching the end of file. Many IO
14791 * methods exist in two forms,
14792 *
14793 * one that returns +nil+ when the end of file is reached, the other
14794 * raises EOFError.
14795 *
14796 * EOFError is a subclass of IOError.
14797 *
14798 * file = File.open("/etc/hosts")
14799 * file.read
14800 * file.gets #=> nil
14801 * file.readline #=> EOFError: end of file reached
14802 * file.close
14803 */
14804
14805/*
14806 * Document-class: ARGF
14807 *
14808 * == \ARGF and +ARGV+
14809 *
14810 * The \ARGF object works with the array at global variable +ARGV+
14811 * to make <tt>$stdin</tt> and file streams available in the Ruby program:
14812 *
14813 * - **ARGV** may be thought of as the <b>argument vector</b> array.
14814 *
14815 * Initially, it contains the command-line arguments and options
14816 * that are passed to the Ruby program;
14817 * the program can modify that array as it likes.
14818 *
14819 * - **ARGF** may be thought of as the <b>argument files</b> object.
14820 *
14821 * It can access file streams and/or the <tt>$stdin</tt> stream,
14822 * based on what it finds in +ARGV+.
14823 * This provides a convenient way for the command line
14824 * to specify streams for a Ruby program to read.
14825 *
14826 * == Reading
14827 *
14828 * \ARGF may read from _source_ streams,
14829 * which at any particular time are determined by the content of +ARGV+.
14830 *
14831 * === Simplest Case
14832 *
14833 * When the <i>very first</i> \ARGF read occurs with an empty +ARGV+ (<tt>[]</tt>),
14834 * the source is <tt>$stdin</tt>:
14835 *
14836 * - \File +t.rb+:
14837 *
14838 * p ['ARGV', ARGV]
14839 * p ['ARGF.read', ARGF.read]
14840 *
14841 * - Commands and outputs
14842 * (see below for the content of files +foo.txt+ and +bar.txt+):
14843 *
14844 * $ echo "Open the pod bay doors, Hal." | ruby t.rb
14845 * ["ARGV", []]
14846 * ["ARGF.read", "Open the pod bay doors, Hal.\n"]
14847 *
14848 * $ cat foo.txt bar.txt | ruby t.rb
14849 * ["ARGV", []]
14850 * ["ARGF.read", "Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"]
14851 *
14852 * === About the Examples
14853 *
14854 * Many examples here assume the existence of files +foo.txt+ and +bar.txt+:
14855 *
14856 * $ cat foo.txt
14857 * Foo 0
14858 * Foo 1
14859 * $ cat bar.txt
14860 * Bar 0
14861 * Bar 1
14862 * Bar 2
14863 * Bar 3
14864 *
14865 * === Sources in +ARGV+
14866 *
14867 * For any \ARGF read _except_ the {simplest case}[rdoc-ref:ARGF@Simplest+Case]
14868 * (that is, _except_ for the <i>very first</i> \ARGF read with an empty +ARGV+),
14869 * the sources are found in +ARGV+.
14870 *
14871 * \ARGF assumes that each element in array +ARGV+ is a potential source,
14872 * and is one of:
14873 *
14874 * - The string path to a file that may be opened as a stream.
14875 * - The character <tt>'-'</tt>, meaning stream <tt>$stdin</tt>.
14876 *
14877 * Each element that is _not_ one of these
14878 * should be removed from +ARGV+ before \ARGF accesses that source.
14879 *
14880 * In the following example:
14881 *
14882 * - Filepaths +foo.txt+ and +bar.txt+ may be retained as potential sources.
14883 * - Options <tt>--xyzzy</tt> and <tt>--mojo</tt> should be removed.
14884 *
14885 * Example:
14886 *
14887 * - \File +t.rb+:
14888 *
14889 * # Print arguments (and options, if any) found on command line.
14890 * p ['ARGV', ARGV]
14891 *
14892 * - Command and output:
14893 *
14894 * $ ruby t.rb --xyzzy --mojo foo.txt bar.txt
14895 * ["ARGV", ["--xyzzy", "--mojo", "foo.txt", "bar.txt"]]
14896 *
14897 * \ARGF's stream access considers the elements of +ARGV+, left to right:
14898 *
14899 * - \File +t.rb+:
14900 *
14901 * p "ARGV: #{ARGV}"
14902 * p "Read: #{ARGF.read}" # Read everything from all specified streams.
14903 *
14904 * - Command and output:
14905 *
14906 * $ ruby t.rb foo.txt bar.txt
14907 * "ARGV: [\"foo.txt\", \"bar.txt\"]"
14908 * "Read: Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"
14909 *
14910 * Because the value at +ARGV+ is an ordinary array,
14911 * you can manipulate it to control which sources \ARGF considers:
14912 *
14913 * - If you remove an element from +ARGV+, \ARGF will not consider the corresponding source.
14914 * - If you add an element to +ARGV+, \ARGF will consider the corresponding source.
14915 *
14916 * Each element in +ARGV+ is removed when its corresponding source is accessed;
14917 * when all sources have been accessed, the array is empty:
14918 *
14919 * - \File +t.rb+:
14920 *
14921 * until ARGV.empty? && ARGF.eof?
14922 * p "ARGV: #{ARGV}"
14923 * p "Line: #{ARGF.readline}" # Read each line from each specified stream.
14924 * end
14925 *
14926 * - Command and output:
14927 *
14928 * $ ruby t.rb foo.txt bar.txt
14929 * "ARGV: [\"foo.txt\", \"bar.txt\"]"
14930 * "Line: Foo 0\n"
14931 * "ARGV: [\"bar.txt\"]"
14932 * "Line: Foo 1\n"
14933 * "ARGV: [\"bar.txt\"]"
14934 * "Line: Bar 0\n"
14935 * "ARGV: []"
14936 * "Line: Bar 1\n"
14937 * "ARGV: []"
14938 * "Line: Bar 2\n"
14939 * "ARGV: []"
14940 * "Line: Bar 3\n"
14941 *
14942 * ==== Filepaths in +ARGV+
14943 *
14944 * The +ARGV+ array may contain filepaths the specify sources for \ARGF reading.
14945 *
14946 * This program prints what it reads from files at the paths specified
14947 * on the command line:
14948 *
14949 * - \File +t.rb+:
14950 *
14951 * p ['ARGV', ARGV]
14952 * # Read and print all content from the specified sources.
14953 * p ['ARGF.read', ARGF.read]
14954 *
14955 * - Command and output:
14956 *
14957 * $ ruby t.rb foo.txt bar.txt
14958 * ["ARGV", [foo.txt, bar.txt]
14959 * ["ARGF.read", "Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"]
14960 *
14961 * ==== Specifying <tt>$stdin</tt> in +ARGV+
14962 *
14963 * To specify stream <tt>$stdin</tt> in +ARGV+, us the character <tt>'-'</tt>:
14964 *
14965 * - \File +t.rb+:
14966 *
14967 * p ['ARGV', ARGV]
14968 * p ['ARGF.read', ARGF.read]
14969 *
14970 * - Command and output:
14971 *
14972 * $ echo "Open the pod bay doors, Hal." | ruby t.rb -
14973 * ["ARGV", ["-"]]
14974 * ["ARGF.read", "Open the pod bay doors, Hal.\n"]
14975 *
14976 * When no character <tt>'-'</tt> is given, stream <tt>$stdin</tt> is ignored
14977 * (exception:
14978 * see {Specifying $stdin in ARGV}[rdoc-ref:ARGF@Specifying+-24stdin+in+ARGV]):
14979 *
14980 * - Command and output:
14981 *
14982 * $ echo "Open the pod bay doors, Hal." | ruby t.rb foo.txt bar.txt
14983 * "ARGV: [\"foo.txt\", \"bar.txt\"]"
14984 * "Read: Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"
14985 *
14986 * ==== Mixtures and Repetitions in +ARGV+
14987 *
14988 * For an \ARGF reader, +ARGV+ may contain any mixture of filepaths
14989 * and character <tt>'-'</tt>, including repetitions.
14990 *
14991 * ==== Modifications to +ARGV+
14992 *
14993 * The running Ruby program may make any modifications to the +ARGV+ array;
14994 * the current value of +ARGV+ affects \ARGF reading.
14995 *
14996 * ==== Empty +ARGV+
14997 *
14998 * For an empty +ARGV+, an \ARGF read method either returns +nil+
14999 * or raises an exception, depending on the specific method.
15000 *
15001 * === More Read Methods
15002 *
15003 * As seen above, method ARGF#read reads the content of all sources
15004 * into a single string.
15005 * Other \ARGF methods provide other ways to access that content;
15006 * these include:
15007 *
15008 * - Byte access: #each_byte, #getbyte, #readbyte.
15009 * - Character access: #each_char, #getc, #readchar.
15010 * - Codepoint access: #each_codepoint.
15011 * - Line access: #each_line, #gets, #readline, #readlines.
15012 * - Source access: #read, #read_nonblock, #readpartial.
15013 *
15014 * === About \Enumerable
15015 *
15016 * \ARGF includes module Enumerable.
15017 * Virtually all methods in \Enumerable call method <tt>#each</tt> in the including class.
15018 *
15019 * <b>Note well</b>: In \ARGF, method #each returns data from the _sources_,
15020 * _not_ from +ARGV+;
15021 * therefore, for example, <tt>ARGF#entries</tt> returns an array of lines from the sources,
15022 * not an array of the strings from +ARGV+:
15023 *
15024 * - \File +t.rb+:
15025 *
15026 * p ['ARGV', ARGV]
15027 * p ['ARGF.entries', ARGF.entries]
15028 *
15029 * - Command and output:
15030 *
15031 * $ ruby t.rb foo.txt bar.txt
15032 * ["ARGV", ["foo.txt", "bar.txt"]]
15033 * ["ARGF.entries", ["Foo 0\n", "Foo 1\n", "Bar 0\n", "Bar 1\n", "Bar 2\n", "Bar 3\n"]]
15034 *
15035 * == Writing
15036 *
15037 * If <i>inplace mode</i> is in effect,
15038 * \ARGF may write to target streams,
15039 * which at any particular time are determined by the content of ARGV.
15040 *
15041 * Methods about inplace mode:
15042 *
15043 * - #inplace_mode
15044 * - #inplace_mode=
15045 * - #to_write_io
15046 *
15047 * Methods for writing:
15048 *
15049 * - #print
15050 * - #printf
15051 * - #putc
15052 * - #puts
15053 * - #write
15054 *
15055 */
15056
15057/*
15058 * An instance of class \IO (commonly called a _stream_)
15059 * represents an input/output stream in the underlying operating system.
15060 * Class \IO is the basis for input and output in Ruby.
15061 *
15062 * Class File is the only class in the Ruby core that is a subclass of \IO.
15063 * Some classes in the Ruby standard library are also subclasses of \IO;
15064 * these include TCPSocket and UDPSocket.
15065 *
15066 * The global constant ARGF (also accessible as <tt>$<</tt>)
15067 * provides an IO-like stream that allows access to all file paths
15068 * found in ARGV (or found in STDIN if ARGV is empty).
15069 * ARGF is not itself a subclass of \IO.
15070 *
15071 * Class StringIO provides an IO-like stream that handles a String.
15072 * StringIO is not itself a subclass of \IO.
15073 *
15074 * Important objects based on \IO include:
15075 *
15076 * - $stdin.
15077 * - $stdout.
15078 * - $stderr.
15079 * - Instances of class File.
15080 *
15081 * An instance of \IO may be created using:
15082 *
15083 * - IO.new: returns a new \IO object for the given integer file descriptor.
15084 * - IO.open: passes a new \IO object to the given block.
15085 * - IO.popen: returns a new \IO object that is connected to the $stdin and $stdout
15086 * of a newly-launched subprocess.
15087 * - Kernel#open: Returns a new \IO object connected to a given source:
15088 * stream, file, or subprocess.
15089 *
15090 * Like a File stream, an \IO stream has:
15091 *
15092 * - A read/write mode, which may be read-only, write-only, or read/write;
15093 * see {Read/Write Mode}[rdoc-ref:File@Read-2FWrite+Mode].
15094 * - A data mode, which may be text-only or binary;
15095 * see {Data Mode}[rdoc-ref:File@Data+Mode].
15096 * - Internal and external encodings;
15097 * see {Encodings}[rdoc-ref:File@Encodings].
15098 *
15099 * And like other \IO streams, it has:
15100 *
15101 * - A position, which determines where in the stream the next
15102 * read or write is to occur;
15103 * see {Position}[rdoc-ref:IO@Position].
15104 * - A line number, which is a special, line-oriented, "position"
15105 * (different from the position mentioned above);
15106 * see {Line Number}[rdoc-ref:IO@Line+Number].
15107 *
15108 * == Extension <tt>io/console</tt>
15109 *
15110 * Extension <tt>io/console</tt> provides numerous methods
15111 * for interacting with the console;
15112 * requiring it adds numerous methods to class \IO.
15113 *
15114 * == Example Files
15115 *
15116 * Many examples here use these variables:
15117 *
15118 * :include: doc/examples/files.rdoc
15119 *
15120 * == Open Options
15121 *
15122 * A number of \IO methods accept optional keyword arguments
15123 * that determine how a new stream is to be opened:
15124 *
15125 * - +:mode+: Stream mode.
15126 * - +:flags+: Integer file open flags;
15127 * If +mode+ is also given, the two are bitwise-ORed.
15128 * - +:external_encoding+: External encoding for the stream.
15129 * - +:internal_encoding+: Internal encoding for the stream.
15130 * <tt>'-'</tt> is a synonym for the default internal encoding.
15131 * If the value is +nil+ no conversion occurs.
15132 * - +:encoding+: Specifies external and internal encodings as <tt>'extern:intern'</tt>.
15133 * - +:textmode+: If a truthy value, specifies the mode as text-only, binary otherwise.
15134 * - +:binmode+: If a truthy value, specifies the mode as binary, text-only otherwise.
15135 * - +:autoclose+: If a truthy value, specifies that the +fd+ will close
15136 * when the stream closes; otherwise it remains open.
15137 * - +:path:+ If a string value is provided, it is used in #inspect and is available as
15138 * #path method.
15139 *
15140 * Also available are the options offered in String#encode,
15141 * which may control conversion between external and internal encoding.
15142 *
15143 * == Basic \IO
15144 *
15145 * You can perform basic stream \IO with these methods,
15146 * which typically operate on multi-byte strings:
15147 *
15148 * - IO#read: Reads and returns some or all of the remaining bytes from the stream.
15149 * - IO#write: Writes zero or more strings to the stream;
15150 * each given object that is not already a string is converted via +to_s+.
15151 *
15152 * === Position
15153 *
15154 * An \IO stream has a nonnegative integer _position_,
15155 * which is the byte offset at which the next read or write is to occur.
15156 * A new stream has position zero (and line number zero);
15157 * method +rewind+ resets the position (and line number) to zero.
15158 *
15159 * These methods discard {buffers}[rdoc-ref:IO@Buffering] and the
15160 * Encoding::Converter instances used for that \IO.
15161 *
15162 * The relevant methods:
15163 *
15164 * - IO#tell (aliased as +#pos+): Returns the current position (in bytes) in the stream.
15165 * - IO#pos=: Sets the position of the stream to a given integer +new_position+ (in bytes).
15166 * - IO#seek: Sets the position of the stream to a given integer +offset+ (in bytes),
15167 * relative to a given position +whence+
15168 * (indicating the beginning, end, or current position).
15169 * - IO#rewind: Positions the stream at the beginning (also resetting the line number).
15170 *
15171 * === Open and Closed Streams
15172 *
15173 * A new \IO stream may be open for reading, open for writing, or both.
15174 *
15175 * A stream is automatically closed when claimed by the garbage collector.
15176 *
15177 * Attempted reading or writing on a closed stream raises an exception.
15178 *
15179 * The relevant methods:
15180 *
15181 * - IO#close: Closes the stream for both reading and writing.
15182 * - IO#close_read: Closes the stream for reading.
15183 * - IO#close_write: Closes the stream for writing.
15184 * - IO#closed?: Returns whether the stream is closed.
15185 *
15186 * === End-of-Stream
15187 *
15188 * You can query whether a stream is positioned at its end:
15189 *
15190 * - IO#eof? (also aliased as +#eof+): Returns whether the stream is at end-of-stream.
15191 *
15192 * You can reposition to end-of-stream by using method IO#seek:
15193 *
15194 * f = File.new('t.txt')
15195 * f.eof? # => false
15196 * f.seek(0, :END)
15197 * f.eof? # => true
15198 * f.close
15199 *
15200 * Or by reading all stream content (which is slower than using IO#seek):
15201 *
15202 * f.rewind
15203 * f.eof? # => false
15204 * f.read # => "First line\nSecond line\n\nFourth line\nFifth line\n"
15205 * f.eof? # => true
15206 *
15207 * == Line \IO
15208 *
15209 * Class \IO supports line-oriented
15210 * {input}[rdoc-ref:IO@Line+Input] and {output}[rdoc-ref:IO@Line+Output]
15211 *
15212 * === Line Input
15213 *
15214 * Class \IO supports line-oriented input for
15215 * {files}[rdoc-ref:IO@File+Line+Input] and {IO streams}[rdoc-ref:IO@Stream+Line+Input]
15216 *
15217 * ==== \File Line Input
15218 *
15219 * You can read lines from a file using these methods:
15220 *
15221 * - IO.foreach: Reads each line and passes it to the given block.
15222 * - IO.readlines: Reads and returns all lines in an array.
15223 *
15224 * For each of these methods:
15225 *
15226 * - You can specify {open options}[rdoc-ref:IO@Open+Options].
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 * ==== Stream Line Input
15233 *
15234 * You can read lines from an \IO stream using these methods:
15235 *
15236 * - IO#each_line: Reads each remaining line, passing it to the given block.
15237 * - IO#gets: Returns the next line.
15238 * - IO#readline: Like #gets, but raises an exception at end-of-stream.
15239 * - IO#readlines: Returns all remaining lines in an array.
15240 *
15241 * For each of these methods:
15242 *
15243 * - Reading may begin mid-line,
15244 * depending on the stream's _position_;
15245 * see {Position}[rdoc-ref:IO@Position].
15246 * - Line parsing depends on the effective <i>line separator</i>;
15247 * see {Line Separator}[rdoc-ref:IO@Line+Separator].
15248 * - The length of each returned line depends on the effective <i>line limit</i>;
15249 * see {Line Limit}[rdoc-ref:IO@Line+Limit].
15250 *
15251 * ===== Line Separator
15252 *
15253 * Each of the {line input methods}[rdoc-ref:IO@Line+Input] uses a <i>line separator</i>:
15254 * the string that determines what is considered a line;
15255 * it is sometimes called the <i>input record separator</i>.
15256 *
15257 * The default line separator is taken from global variable <tt>$/</tt>,
15258 * whose initial value is <tt>"\n"</tt>.
15259 *
15260 * Generally, the line to be read next is all data
15261 * from the current {position}[rdoc-ref:IO@Position]
15262 * to the next line separator
15263 * (but see {Special Line Separator Values}[rdoc-ref:IO@Special+Line+Separator+Values]):
15264 *
15265 * f = File.new('t.txt')
15266 * # Method gets with no sep argument returns the next line, according to $/.
15267 * f.gets # => "First line\n"
15268 * f.gets # => "Second line\n"
15269 * f.gets # => "\n"
15270 * f.gets # => "Fourth line\n"
15271 * f.gets # => "Fifth line\n"
15272 * f.close
15273 *
15274 * You can use a different line separator by passing argument +sep+:
15275 *
15276 * f = File.new('t.txt')
15277 * f.gets('l') # => "First l"
15278 * f.gets('li') # => "ine\nSecond li"
15279 * f.gets('lin') # => "ne\n\nFourth lin"
15280 * f.gets # => "e\n"
15281 * f.close
15282 *
15283 * Or by setting global variable <tt>$/</tt>:
15284 *
15285 * f = File.new('t.txt')
15286 * $/ = 'l'
15287 * f.gets # => "First l"
15288 * f.gets # => "ine\nSecond l"
15289 * f.gets # => "ine\n\nFourth l"
15290 * f.close
15291 *
15292 * ===== Special Line Separator Values
15293 *
15294 * Each of the {line input methods}[rdoc-ref:IO@Line+Input]
15295 * accepts two special values for parameter +sep+:
15296 *
15297 * - +nil+: The entire stream is to be read ("slurped") into a single string:
15298 *
15299 * f = File.new('t.txt')
15300 * f.gets(nil) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
15301 * f.close
15302 *
15303 * - <tt>''</tt> (the empty string): The next "paragraph" is to be read
15304 * (paragraphs being separated by two consecutive line separators):
15305 *
15306 * f = File.new('t.txt')
15307 * f.gets('') # => "First line\nSecond line\n\n"
15308 * f.gets('') # => "Fourth line\nFifth line\n"
15309 * f.close
15310 *
15311 * ===== Line Limit
15312 *
15313 * Each of the {line input methods}[rdoc-ref:IO@Line+Input]
15314 * uses an integer <i>line limit</i>,
15315 * which restricts the number of bytes that may be returned.
15316 * (A multi-byte character will not be split, and so a returned line may be slightly longer
15317 * than the limit).
15318 *
15319 * The default limit value is <tt>-1</tt>;
15320 * any negative limit value means that there is no limit.
15321 *
15322 * If there is no limit, the line is determined only by +sep+.
15323 *
15324 * # Text with 1-byte characters.
15325 * File.open('t.txt') {|f| f.gets(1) } # => "F"
15326 * File.open('t.txt') {|f| f.gets(2) } # => "Fi"
15327 * File.open('t.txt') {|f| f.gets(3) } # => "Fir"
15328 * File.open('t.txt') {|f| f.gets(4) } # => "Firs"
15329 * # No more than one line.
15330 * File.open('t.txt') {|f| f.gets(10) } # => "First line"
15331 * File.open('t.txt') {|f| f.gets(11) } # => "First line\n"
15332 * File.open('t.txt') {|f| f.gets(12) } # => "First line\n"
15333 *
15334 * # Text with 2-byte characters, which will not be split.
15335 * File.open('t.rus') {|f| f.gets(1).size } # => 1
15336 * File.open('t.rus') {|f| f.gets(2).size } # => 1
15337 * File.open('t.rus') {|f| f.gets(3).size } # => 2
15338 * File.open('t.rus') {|f| f.gets(4).size } # => 2
15339 *
15340 * ===== Line Separator and Line Limit
15341 *
15342 * With arguments +sep+ and +limit+ given, combines the two behaviors:
15343 *
15344 * - Returns the next line as determined by line separator +sep+.
15345 * - But returns no more bytes than are allowed by the limit +limit+.
15346 *
15347 * Example:
15348 *
15349 * File.open('t.txt') {|f| f.gets('li', 20) } # => "First li"
15350 * File.open('t.txt') {|f| f.gets('li', 2) } # => "Fi"
15351 *
15352 * ===== Line Number
15353 *
15354 * A readable \IO stream has a non-negative integer <i>line number</i>:
15355 *
15356 * - IO#lineno: Returns the line number.
15357 * - IO#lineno=: Resets and returns the line number.
15358 *
15359 * Unless modified by a call to method IO#lineno=,
15360 * the line number is the number of lines read
15361 * by certain line-oriented methods,
15362 * according to the effective {line separator}[rdoc-ref:IO@Line+Separator]:
15363 *
15364 * - IO.foreach: Increments the line number on each call to the block.
15365 * - IO#each_line: Increments the line number on each call to the block.
15366 * - IO#gets: Increments the line number.
15367 * - IO#readline: Increments the line number.
15368 * - IO#readlines: Increments the line number for each line read.
15369 *
15370 * A new stream is initially has line number zero (and position zero);
15371 * method +rewind+ resets the line number (and position) to zero:
15372 *
15373 * f = File.new('t.txt')
15374 * f.lineno # => 0
15375 * f.gets # => "First line\n"
15376 * f.lineno # => 1
15377 * f.rewind
15378 * f.lineno # => 0
15379 * f.close
15380 *
15381 * Reading lines from a stream usually changes its line number:
15382 *
15383 * f = File.new('t.txt', 'r')
15384 * f.lineno # => 0
15385 * f.readline # => "This is line one.\n"
15386 * f.lineno # => 1
15387 * f.readline # => "This is the second line.\n"
15388 * f.lineno # => 2
15389 * f.readline # => "Here's the third line.\n"
15390 * f.lineno # => 3
15391 * f.eof? # => true
15392 * f.close
15393 *
15394 * Iterating over lines in a stream usually changes its line number:
15395 *
15396 * File.open('t.txt') do |f|
15397 * f.each_line do |line|
15398 * p "position=#{f.pos} eof?=#{f.eof?} lineno=#{f.lineno}"
15399 * end
15400 * end
15401 *
15402 * Output:
15403 *
15404 * "position=11 eof?=false lineno=1"
15405 * "position=23 eof?=false lineno=2"
15406 * "position=24 eof?=false lineno=3"
15407 * "position=36 eof?=false lineno=4"
15408 * "position=47 eof?=true lineno=5"
15409 *
15410 * Unlike the stream's {position}[rdoc-ref:IO@Position],
15411 * the line number does not affect where the next read or write will occur:
15412 *
15413 * f = File.new('t.txt')
15414 * f.lineno = 1000
15415 * f.lineno # => 1000
15416 * f.gets # => "First line\n"
15417 * f.lineno # => 1001
15418 * f.close
15419 *
15420 * Associated with the line number is the global variable <tt>$.</tt>:
15421 *
15422 * - When a stream is opened, <tt>$.</tt> is not set;
15423 * its value is left over from previous activity in the process:
15424 *
15425 * $. = 41
15426 * f = File.new('t.txt')
15427 * $. = 41
15428 * # => 41
15429 * f.close
15430 *
15431 * - When a stream is read, <tt>$.</tt> is set to the line number for that stream:
15432 *
15433 * f0 = File.new('t.txt')
15434 * f1 = File.new('t.dat')
15435 * f0.readlines # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
15436 * $. # => 5
15437 * f1.readlines # => ["\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"]
15438 * $. # => 1
15439 * f0.close
15440 * f1.close
15441 *
15442 * - Methods IO#rewind and IO#seek do not affect <tt>$.</tt>:
15443 *
15444 * f = File.new('t.txt')
15445 * f.readlines # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
15446 * $. # => 5
15447 * f.rewind
15448 * f.seek(0, :SET)
15449 * $. # => 5
15450 * f.close
15451 *
15452 * === Line Output
15453 *
15454 * You can write to an \IO stream line-by-line using this method:
15455 *
15456 * - IO#puts: Writes objects to the stream.
15457 *
15458 * == Character \IO
15459 *
15460 * You can process an \IO stream character-by-character using these methods:
15461 *
15462 * - IO#getc: Reads and returns the next character from the stream.
15463 * - IO#readchar: Like #getc, but raises an exception at end-of-stream.
15464 * - IO#ungetc: Pushes back ("unshifts") a character or integer onto the stream.
15465 * - IO#putc: Writes a character to the stream.
15466 * - IO#each_char: Reads each remaining character in the stream,
15467 * passing the character to the given block.
15468 *
15469 * == Byte \IO
15470 *
15471 * You can process an \IO stream byte-by-byte using these methods:
15472 *
15473 * - IO#getbyte: Returns the next 8-bit byte as an integer in range 0..255.
15474 * - IO#readbyte: Like #getbyte, but raises an exception if at end-of-stream.
15475 * - IO#ungetbyte: Pushes back ("unshifts") a byte back onto the stream.
15476 * - IO#each_byte: Reads each remaining byte in the stream,
15477 * passing the byte to the given block.
15478 *
15479 * == Codepoint \IO
15480 *
15481 * You can process an \IO stream codepoint-by-codepoint:
15482 *
15483 * - IO#each_codepoint: Reads each remaining codepoint, passing it to the given block.
15484 *
15485 * == What's Here
15486 *
15487 * First, what's elsewhere. Class \IO:
15488 *
15489 * - Inherits from {class Object}[rdoc-ref:Object@What-27s+Here].
15490 * - Includes {module Enumerable}[rdoc-ref:Enumerable@What-27s+Here],
15491 * which provides dozens of additional methods.
15492 *
15493 * Here, class \IO provides methods that are useful for:
15494 *
15495 * - {Creating}[rdoc-ref:IO@Creating]
15496 * - {Reading}[rdoc-ref:IO@Reading]
15497 * - {Writing}[rdoc-ref:IO@Writing]
15498 * - {Positioning}[rdoc-ref:IO@Positioning]
15499 * - {Iterating}[rdoc-ref:IO@Iterating]
15500 * - {Settings}[rdoc-ref:IO@Settings]
15501 * - {Querying}[rdoc-ref:IO@Querying]
15502 * - {Buffering}[rdoc-ref:IO@Buffering]
15503 * - {Low-Level Access}[rdoc-ref:IO@Low-Level+Access]
15504 * - {Other}[rdoc-ref:IO@Other]
15505 *
15506 * === Creating
15507 *
15508 * - ::new (aliased as ::for_fd): Creates and returns a new \IO object for the given
15509 * integer file descriptor.
15510 * - ::open: Creates a new \IO object.
15511 * - ::pipe: Creates a connected pair of reader and writer \IO objects.
15512 * - ::popen: Creates an \IO object to interact with a subprocess.
15513 * - ::select: Selects which given \IO instances are ready for reading,
15514 * writing, or have pending exceptions.
15515 *
15516 * === Reading
15517 *
15518 * - ::binread: Returns a binary string with all or a subset of bytes
15519 * from the given file.
15520 * - ::read: Returns a string with all or a subset of bytes from the given file.
15521 * - ::readlines: Returns an array of strings, which are the lines from the given file.
15522 * - #getbyte: Returns the next 8-bit byte read from +self+ as an integer.
15523 * - #getc: Returns the next character read from +self+ as a string.
15524 * - #gets: Returns the line read from +self+.
15525 * - #pread: Returns all or the next _n_ bytes read from +self+,
15526 * not updating the receiver's offset.
15527 * - #read: Returns all remaining or the next _n_ bytes read from +self+
15528 * for a given _n_.
15529 * - #read_nonblock: the next _n_ bytes read from +self+ for a given _n_,
15530 * in non-block mode.
15531 * - #readbyte: Returns the next byte read from +self+;
15532 * same as #getbyte, but raises an exception on end-of-stream.
15533 * - #readchar: Returns the next character read from +self+;
15534 * same as #getc, but raises an exception on end-of-stream.
15535 * - #readline: Returns the next line read from +self+;
15536 * same as #getline, but raises an exception of end-of-stream.
15537 * - #readlines: Returns an array of all lines read read from +self+.
15538 * - #readpartial: Returns up to the given number of bytes from +self+.
15539 *
15540 * === Writing
15541 *
15542 * - ::binwrite: Writes the given string to the file at the given filepath,
15543 * in binary mode.
15544 * - ::write: Writes the given string to +self+.
15545 * - #<<: Appends the given string to +self+.
15546 * - #print: Prints last read line or given objects to +self+.
15547 * - #printf: Writes to +self+ based on the given format string and objects.
15548 * - #putc: Writes a character to +self+.
15549 * - #puts: Writes lines to +self+, making sure line ends with a newline.
15550 * - #pwrite: Writes the given string at the given offset,
15551 * not updating the receiver's offset.
15552 * - #write: Writes one or more given strings to +self+.
15553 * - #write_nonblock: Writes one or more given strings to +self+ in non-blocking mode.
15554 *
15555 * === Positioning
15556 *
15557 * - #lineno: Returns the current line number in +self+.
15558 * - #lineno=: Sets the line number is +self+.
15559 * - #pos (aliased as #tell): Returns the current byte offset in +self+.
15560 * - #pos=: Sets the byte offset in +self+.
15561 * - #reopen: Reassociates +self+ with a new or existing \IO stream.
15562 * - #rewind: Positions +self+ to the beginning of input.
15563 * - #seek: Sets the offset for +self+ relative to given position.
15564 *
15565 * === Iterating
15566 *
15567 * - ::foreach: Yields each line of given file to the block.
15568 * - #each (aliased as #each_line): Calls the given block
15569 * with each successive line in +self+.
15570 * - #each_byte: Calls the given block with each successive byte in +self+
15571 * as an integer.
15572 * - #each_char: Calls the given block with each successive character in +self+
15573 * as a string.
15574 * - #each_codepoint: Calls the given block with each successive codepoint in +self+
15575 * as an integer.
15576 *
15577 * === Settings
15578 *
15579 * - #autoclose=: Sets whether +self+ auto-closes.
15580 * - #binmode: Sets +self+ to binary mode.
15581 * - #close: Closes +self+.
15582 * - #close_on_exec=: Sets the close-on-exec flag.
15583 * - #close_read: Closes +self+ for reading.
15584 * - #close_write: Closes +self+ for writing.
15585 * - #set_encoding: Sets the encoding for +self+.
15586 * - #set_encoding_by_bom: Sets the encoding for +self+, based on its
15587 * Unicode byte-order-mark.
15588 * - #sync=: Sets the sync-mode to the given value.
15589 *
15590 * === Querying
15591 *
15592 * - #autoclose?: Returns whether +self+ auto-closes.
15593 * - #binmode?: Returns whether +self+ is in binary mode.
15594 * - #close_on_exec?: Returns the close-on-exec flag for +self+.
15595 * - #closed?: Returns whether +self+ is closed.
15596 * - #eof? (aliased as #eof): Returns whether +self+ is at end-of-stream.
15597 * - #external_encoding: Returns the external encoding object for +self+.
15598 * - #fileno (aliased as #to_i): Returns the integer file descriptor for +self+
15599 * - #internal_encoding: Returns the internal encoding object for +self+.
15600 * - #pid: Returns the process ID of a child process associated with +self+,
15601 * if +self+ was created by ::popen.
15602 * - #stat: Returns the File::Stat object containing status information for +self+.
15603 * - #sync: Returns whether +self+ is in sync-mode.
15604 * - #tty? (aliased as #isatty): Returns whether +self+ is a terminal.
15605 *
15606 * === Buffering
15607 *
15608 * - #fdatasync: Immediately writes all buffered data in +self+ to disk.
15609 * - #flush: Flushes any buffered data within +self+ to the underlying
15610 * operating system.
15611 * - #fsync: Immediately writes all buffered data and attributes in +self+ to disk.
15612 * - #ungetbyte: Prepends buffer for +self+ with given integer byte or string.
15613 * - #ungetc: Prepends buffer for +self+ with given string.
15614 *
15615 * === Low-Level Access
15616 *
15617 * - ::sysopen: Opens the file given by its path,
15618 * returning the integer file descriptor.
15619 * - #advise: Announces the intention to access data from +self+ in a specific way.
15620 * - #fcntl: Passes a low-level command to the file specified
15621 * by the given file descriptor.
15622 * - #ioctl: Passes a low-level command to the device specified
15623 * by the given file descriptor.
15624 * - #sysread: Returns up to the next _n_ bytes read from self using a low-level read.
15625 * - #sysseek: Sets the offset for +self+.
15626 * - #syswrite: Writes the given string to +self+ using a low-level write.
15627 *
15628 * === Other
15629 *
15630 * - ::copy_stream: Copies data from a source to a destination,
15631 * each of which is a filepath or an \IO-like object.
15632 * - ::try_convert: Returns a new \IO object resulting from converting
15633 * the given object.
15634 * - #inspect: Returns the string representation of +self+.
15635 *
15636 */
15637
15638void
15639Init_IO(void)
15640{
15641 VALUE rb_cARGF;
15642#ifdef __CYGWIN__
15643#include <sys/cygwin.h>
15644 static struct __cygwin_perfile pf[] =
15645 {
15646 {"", O_RDONLY | O_BINARY},
15647 {"", O_WRONLY | O_BINARY},
15648 {"", O_RDWR | O_BINARY},
15649 {"", O_APPEND | O_BINARY},
15650 {NULL, 0}
15651 };
15652 cygwin_internal(CW_PERFILE, pf);
15653#endif
15654
15657
15658 id_write = rb_intern_const("write");
15659 id_read = rb_intern_const("read");
15660 id_getc = rb_intern_const("getc");
15661 id_flush = rb_intern_const("flush");
15662 id_readpartial = rb_intern_const("readpartial");
15663 id_set_encoding = rb_intern_const("set_encoding");
15664 id_fileno = rb_intern_const("fileno");
15665
15666 rb_define_global_function("syscall", rb_f_syscall, -1);
15667
15668 rb_define_global_function("open", rb_f_open, -1);
15669 rb_define_global_function("printf", rb_f_printf, -1);
15670 rb_define_global_function("print", rb_f_print, -1);
15671 rb_define_global_function("putc", rb_f_putc, 1);
15672 rb_define_global_function("puts", rb_f_puts, -1);
15673 rb_define_global_function("gets", rb_f_gets, -1);
15674 rb_define_global_function("readline", rb_f_readline, -1);
15675 rb_define_global_function("select", rb_f_select, -1);
15676
15677 rb_define_global_function("readlines", rb_f_readlines, -1);
15678
15679 rb_define_global_function("`", rb_f_backquote, 1);
15680
15681 rb_define_global_function("p", rb_f_p, -1);
15682 rb_define_method(rb_mKernel, "display", rb_obj_display, -1);
15683
15684 rb_cIO = rb_define_class("IO", rb_cObject);
15686
15687 /* Can be raised by IO operations when IO#timeout= is set. */
15689
15690 /* Readable event mask for IO#wait. */
15691 rb_define_const(rb_cIO, "READABLE", INT2NUM(RUBY_IO_READABLE));
15692 /* Writable event mask for IO#wait. */
15693 rb_define_const(rb_cIO, "WRITABLE", INT2NUM(RUBY_IO_WRITABLE));
15694 /* Priority event mask for IO#wait. */
15695 rb_define_const(rb_cIO, "PRIORITY", INT2NUM(RUBY_IO_PRIORITY));
15696
15697 /* exception to wait for reading. see IO.select. */
15699 /* exception to wait for writing. see IO.select. */
15701 /* exception to wait for reading by EAGAIN. see IO.select. */
15702 rb_eEAGAINWaitReadable = rb_define_class_under(rb_cIO, "EAGAINWaitReadable", rb_eEAGAIN);
15703 rb_include_module(rb_eEAGAINWaitReadable, rb_mWaitReadable);
15704 /* exception to wait for writing by EAGAIN. see IO.select. */
15705 rb_eEAGAINWaitWritable = rb_define_class_under(rb_cIO, "EAGAINWaitWritable", rb_eEAGAIN);
15706 rb_include_module(rb_eEAGAINWaitWritable, rb_mWaitWritable);
15707#if EAGAIN == EWOULDBLOCK
15708 rb_eEWOULDBLOCKWaitReadable = rb_eEAGAINWaitReadable;
15709 /* same as IO::EAGAINWaitReadable */
15710 rb_define_const(rb_cIO, "EWOULDBLOCKWaitReadable", rb_eEAGAINWaitReadable);
15711 rb_eEWOULDBLOCKWaitWritable = rb_eEAGAINWaitWritable;
15712 /* same as IO::EAGAINWaitWritable */
15713 rb_define_const(rb_cIO, "EWOULDBLOCKWaitWritable", rb_eEAGAINWaitWritable);
15714#else
15715 /* exception to wait for reading by EWOULDBLOCK. see IO.select. */
15716 rb_eEWOULDBLOCKWaitReadable = rb_define_class_under(rb_cIO, "EWOULDBLOCKWaitReadable", rb_eEWOULDBLOCK);
15717 rb_include_module(rb_eEWOULDBLOCKWaitReadable, rb_mWaitReadable);
15718 /* exception to wait for writing by EWOULDBLOCK. see IO.select. */
15719 rb_eEWOULDBLOCKWaitWritable = rb_define_class_under(rb_cIO, "EWOULDBLOCKWaitWritable", rb_eEWOULDBLOCK);
15720 rb_include_module(rb_eEWOULDBLOCKWaitWritable, rb_mWaitWritable);
15721#endif
15722 /* exception to wait for reading by EINPROGRESS. see IO.select. */
15723 rb_eEINPROGRESSWaitReadable = rb_define_class_under(rb_cIO, "EINPROGRESSWaitReadable", rb_eEINPROGRESS);
15724 rb_include_module(rb_eEINPROGRESSWaitReadable, rb_mWaitReadable);
15725 /* exception to wait for writing by EINPROGRESS. see IO.select. */
15726 rb_eEINPROGRESSWaitWritable = rb_define_class_under(rb_cIO, "EINPROGRESSWaitWritable", rb_eEINPROGRESS);
15727 rb_include_module(rb_eEINPROGRESSWaitWritable, rb_mWaitWritable);
15728
15729#if 0
15730 /* This is necessary only for forcing rdoc handle File::open */
15731 rb_define_singleton_method(rb_cFile, "open", rb_io_s_open, -1);
15732#endif
15733
15734 rb_define_alloc_func(rb_cIO, io_alloc);
15735 rb_define_singleton_method(rb_cIO, "new", rb_io_s_new, -1);
15736 rb_define_singleton_method(rb_cIO, "open", rb_io_s_open, -1);
15737 rb_define_singleton_method(rb_cIO, "sysopen", rb_io_s_sysopen, -1);
15738 rb_define_singleton_method(rb_cIO, "for_fd", rb_io_s_for_fd, -1);
15739 rb_define_singleton_method(rb_cIO, "popen", rb_io_s_popen, -1);
15740 rb_define_singleton_method(rb_cIO, "foreach", rb_io_s_foreach, -1);
15741 rb_define_singleton_method(rb_cIO, "readlines", rb_io_s_readlines, -1);
15742 rb_define_singleton_method(rb_cIO, "read", rb_io_s_read, -1);
15743 rb_define_singleton_method(rb_cIO, "binread", rb_io_s_binread, -1);
15744 rb_define_singleton_method(rb_cIO, "write", rb_io_s_write, -1);
15745 rb_define_singleton_method(rb_cIO, "binwrite", rb_io_s_binwrite, -1);
15746 rb_define_singleton_method(rb_cIO, "select", rb_f_select, -1);
15747 rb_define_singleton_method(rb_cIO, "pipe", rb_io_s_pipe, -1);
15748 rb_define_singleton_method(rb_cIO, "try_convert", rb_io_s_try_convert, 1);
15749 rb_define_singleton_method(rb_cIO, "copy_stream", rb_io_s_copy_stream, -1);
15750
15751 rb_define_method(rb_cIO, "initialize", rb_io_initialize, -1);
15752
15754 rb_define_hooked_variable("$,", &rb_output_fs, 0, rb_deprecated_str_setter);
15755
15756 rb_default_rs = rb_fstring_lit("\n"); /* avoid modifying RS_default */
15757 rb_vm_register_global_object(rb_default_rs);
15758 rb_rs = rb_default_rs;
15760 rb_define_hooked_variable("$/", &rb_rs, 0, deprecated_rs_setter);
15761 rb_gvar_ractor_local("$/"); // not local but ractor safe
15762 rb_define_hooked_variable("$-0", &rb_rs, 0, deprecated_rs_setter);
15763 rb_gvar_ractor_local("$-0"); // not local but ractor safe
15764 rb_define_hooked_variable("$\\", &rb_output_rs, 0, rb_deprecated_str_setter);
15765
15766 rb_define_virtual_variable("$_", get_LAST_READ_LINE, set_LAST_READ_LINE);
15767 rb_gvar_ractor_local("$_");
15768
15769 rb_define_method(rb_cIO, "initialize_copy", rb_io_init_copy, 1);
15770 rb_define_method(rb_cIO, "reopen", rb_io_reopen, -1);
15771
15772 rb_define_method(rb_cIO, "print", rb_io_print, -1);
15773 rb_define_method(rb_cIO, "putc", rb_io_putc, 1);
15774 rb_define_method(rb_cIO, "puts", rb_io_puts, -1);
15775 rb_define_method(rb_cIO, "printf", rb_io_printf, -1);
15776
15777 rb_define_method(rb_cIO, "each", rb_io_each_line, -1);
15778 rb_define_method(rb_cIO, "each_line", rb_io_each_line, -1);
15779 rb_define_method(rb_cIO, "each_byte", rb_io_each_byte, 0);
15780 rb_define_method(rb_cIO, "each_char", rb_io_each_char, 0);
15781 rb_define_method(rb_cIO, "each_codepoint", rb_io_each_codepoint, 0);
15782
15783 rb_define_method(rb_cIO, "syswrite", rb_io_syswrite, 1);
15784 rb_define_method(rb_cIO, "sysread", rb_io_sysread, -1);
15785
15786 rb_define_method(rb_cIO, "pread", rb_io_pread, -1);
15787 rb_define_method(rb_cIO, "pwrite", rb_io_pwrite, 2);
15788
15789 rb_define_method(rb_cIO, "fileno", rb_io_fileno, 0);
15790 rb_define_alias(rb_cIO, "to_i", "fileno");
15791 rb_define_method(rb_cIO, "to_io", rb_io_to_io, 0);
15792
15793 rb_define_method(rb_cIO, "timeout", rb_io_timeout, 0);
15794 rb_define_method(rb_cIO, "timeout=", rb_io_set_timeout, 1);
15795
15796 rb_define_method(rb_cIO, "fsync", rb_io_fsync, 0);
15797 rb_define_method(rb_cIO, "fdatasync", rb_io_fdatasync, 0);
15798 rb_define_method(rb_cIO, "sync", rb_io_sync, 0);
15799 rb_define_method(rb_cIO, "sync=", rb_io_set_sync, 1);
15800
15801 rb_define_method(rb_cIO, "lineno", rb_io_lineno, 0);
15802 rb_define_method(rb_cIO, "lineno=", rb_io_set_lineno, 1);
15803
15804 rb_define_method(rb_cIO, "readlines", rb_io_readlines, -1);
15805
15806 rb_define_method(rb_cIO, "readpartial", io_readpartial, -1);
15807 rb_define_method(rb_cIO, "read", io_read, -1);
15808 rb_define_method(rb_cIO, "write", io_write_m, -1);
15809 rb_define_method(rb_cIO, "gets", rb_io_gets_m, -1);
15810 rb_define_method(rb_cIO, "getc", rb_io_getc, 0);
15811 rb_define_method(rb_cIO, "getbyte", rb_io_getbyte, 0);
15812 rb_define_method(rb_cIO, "readchar", rb_io_readchar, 0);
15813 rb_define_method(rb_cIO, "readbyte", rb_io_readbyte, 0);
15814 rb_define_method(rb_cIO, "ungetbyte",rb_io_ungetbyte, 1);
15815 rb_define_method(rb_cIO, "ungetc",rb_io_ungetc, 1);
15817 rb_define_method(rb_cIO, "flush", rb_io_flush, 0);
15818 rb_define_method(rb_cIO, "tell", rb_io_tell, 0);
15819 rb_define_method(rb_cIO, "seek", rb_io_seek_m, -1);
15820 /* Set I/O position from the beginning */
15821 rb_define_const(rb_cIO, "SEEK_SET", INT2FIX(SEEK_SET));
15822 /* Set I/O position from the current position */
15823 rb_define_const(rb_cIO, "SEEK_CUR", INT2FIX(SEEK_CUR));
15824 /* Set I/O position from the end */
15825 rb_define_const(rb_cIO, "SEEK_END", INT2FIX(SEEK_END));
15826#ifdef SEEK_DATA
15827 /* Set I/O position to the next location containing data */
15828 rb_define_const(rb_cIO, "SEEK_DATA", INT2FIX(SEEK_DATA));
15829#endif
15830#ifdef SEEK_HOLE
15831 /* Set I/O position to the next hole */
15832 rb_define_const(rb_cIO, "SEEK_HOLE", INT2FIX(SEEK_HOLE));
15833#endif
15834 rb_define_method(rb_cIO, "rewind", rb_io_rewind, 0);
15835 rb_define_method(rb_cIO, "pos", rb_io_tell, 0);
15836 rb_define_method(rb_cIO, "pos=", rb_io_set_pos, 1);
15837 rb_define_method(rb_cIO, "eof", rb_io_eof, 0);
15838 rb_define_method(rb_cIO, "eof?", rb_io_eof, 0);
15839
15840 rb_define_method(rb_cIO, "close_on_exec?", rb_io_close_on_exec_p, 0);
15841 rb_define_method(rb_cIO, "close_on_exec=", rb_io_set_close_on_exec, 1);
15842
15843 rb_define_method(rb_cIO, "close", rb_io_close_m, 0);
15844 rb_define_method(rb_cIO, "closed?", rb_io_closed_p, 0);
15845 rb_define_method(rb_cIO, "close_read", rb_io_close_read, 0);
15846 rb_define_method(rb_cIO, "close_write", rb_io_close_write, 0);
15847
15848 rb_define_method(rb_cIO, "isatty", rb_io_isatty, 0);
15849 rb_define_method(rb_cIO, "tty?", rb_io_isatty, 0);
15850 rb_define_method(rb_cIO, "binmode", rb_io_binmode_m, 0);
15851 rb_define_method(rb_cIO, "binmode?", rb_io_binmode_p, 0);
15852 rb_define_method(rb_cIO, "sysseek", rb_io_sysseek, -1);
15853 rb_define_method(rb_cIO, "advise", rb_io_advise, -1);
15854
15855 rb_define_method(rb_cIO, "ioctl", rb_io_ioctl, -1);
15856 rb_define_method(rb_cIO, "fcntl", rb_io_fcntl, -1);
15857 rb_define_method(rb_cIO, "pid", rb_io_pid, 0);
15858
15859 rb_define_method(rb_cIO, "path", rb_io_path, 0);
15860 rb_define_method(rb_cIO, "to_path", rb_io_path, 0);
15861
15862 rb_define_method(rb_cIO, "inspect", rb_io_inspect, 0);
15863
15864 rb_define_method(rb_cIO, "external_encoding", rb_io_external_encoding, 0);
15865 rb_define_method(rb_cIO, "internal_encoding", rb_io_internal_encoding, 0);
15866 rb_define_method(rb_cIO, "set_encoding", rb_io_set_encoding, -1);
15867 rb_define_method(rb_cIO, "set_encoding_by_bom", rb_io_set_encoding_by_bom, 0);
15868
15869 rb_define_method(rb_cIO, "autoclose?", rb_io_autoclose_p, 0);
15870 rb_define_method(rb_cIO, "autoclose=", rb_io_set_autoclose, 1);
15871
15872 rb_define_method(rb_cIO, "wait", io_wait, -1);
15873
15874 rb_define_method(rb_cIO, "wait_readable", io_wait_readable, -1);
15875 rb_define_method(rb_cIO, "wait_writable", io_wait_writable, -1);
15876 rb_define_method(rb_cIO, "wait_priority", io_wait_priority, -1);
15877
15878 rb_define_virtual_variable("$stdin", stdin_getter, stdin_setter);
15879 rb_define_virtual_variable("$stdout", stdout_getter, stdout_setter);
15880 rb_define_virtual_variable("$>", stdout_getter, stdout_setter);
15881 rb_define_virtual_variable("$stderr", stderr_getter, stderr_setter);
15882
15883 rb_gvar_ractor_local("$stdin");
15884 rb_gvar_ractor_local("$stdout");
15885 rb_gvar_ractor_local("$>");
15886 rb_gvar_ractor_local("$stderr");
15887
15889 rb_stdin = rb_io_prep_stdin();
15891 rb_stdout = rb_io_prep_stdout();
15893 rb_stderr = rb_io_prep_stderr();
15894
15895 orig_stdout = rb_stdout;
15896 orig_stderr = rb_stderr;
15897
15898 /* Holds the original stdin */
15900 /* Holds the original stdout */
15902 /* Holds the original stderr */
15904
15905#if 0
15906 /* Hack to get rdoc to regard ARGF as a class: */
15907 rb_cARGF = rb_define_class("ARGF", rb_cObject);
15908#endif
15909
15910 rb_cARGF = rb_class_new(rb_cObject);
15911 rb_set_class_path(rb_cARGF, rb_cObject, "ARGF.class");
15912 rb_define_alloc_func(rb_cARGF, argf_alloc);
15913
15915
15916 rb_define_method(rb_cARGF, "initialize", argf_initialize, -2);
15917 rb_define_method(rb_cARGF, "initialize_copy", argf_initialize_copy, 1);
15918 rb_define_method(rb_cARGF, "to_s", argf_to_s, 0);
15919 rb_define_alias(rb_cARGF, "inspect", "to_s");
15920 rb_define_method(rb_cARGF, "argv", argf_argv, 0);
15921
15922 rb_define_method(rb_cARGF, "fileno", argf_fileno, 0);
15923 rb_define_method(rb_cARGF, "to_i", argf_fileno, 0);
15924 rb_define_method(rb_cARGF, "to_io", argf_to_io, 0);
15925 rb_define_method(rb_cARGF, "to_write_io", argf_write_io, 0);
15926 rb_define_method(rb_cARGF, "each", argf_each_line, -1);
15927 rb_define_method(rb_cARGF, "each_line", argf_each_line, -1);
15928 rb_define_method(rb_cARGF, "each_byte", argf_each_byte, 0);
15929 rb_define_method(rb_cARGF, "each_char", argf_each_char, 0);
15930 rb_define_method(rb_cARGF, "each_codepoint", argf_each_codepoint, 0);
15931
15932 rb_define_method(rb_cARGF, "read", argf_read, -1);
15933 rb_define_method(rb_cARGF, "readpartial", argf_readpartial, -1);
15934 rb_define_method(rb_cARGF, "read_nonblock", argf_read_nonblock, -1);
15935 rb_define_method(rb_cARGF, "readlines", argf_readlines, -1);
15936 rb_define_method(rb_cARGF, "to_a", argf_readlines, -1);
15937 rb_define_method(rb_cARGF, "gets", argf_gets, -1);
15938 rb_define_method(rb_cARGF, "readline", argf_readline, -1);
15939 rb_define_method(rb_cARGF, "getc", argf_getc, 0);
15940 rb_define_method(rb_cARGF, "getbyte", argf_getbyte, 0);
15941 rb_define_method(rb_cARGF, "readchar", argf_readchar, 0);
15942 rb_define_method(rb_cARGF, "readbyte", argf_readbyte, 0);
15943 rb_define_method(rb_cARGF, "tell", argf_tell, 0);
15944 rb_define_method(rb_cARGF, "seek", argf_seek_m, -1);
15945 rb_define_method(rb_cARGF, "rewind", argf_rewind, 0);
15946 rb_define_method(rb_cARGF, "pos", argf_tell, 0);
15947 rb_define_method(rb_cARGF, "pos=", argf_set_pos, 1);
15948 rb_define_method(rb_cARGF, "eof", argf_eof, 0);
15949 rb_define_method(rb_cARGF, "eof?", argf_eof, 0);
15950 rb_define_method(rb_cARGF, "binmode", argf_binmode_m, 0);
15951 rb_define_method(rb_cARGF, "binmode?", argf_binmode_p, 0);
15952
15953 rb_define_method(rb_cARGF, "write", argf_write, -1);
15954 rb_define_method(rb_cARGF, "print", rb_io_print, -1);
15955 rb_define_method(rb_cARGF, "putc", rb_io_putc, 1);
15956 rb_define_method(rb_cARGF, "puts", rb_io_puts, -1);
15957 rb_define_method(rb_cARGF, "printf", rb_io_printf, -1);
15958
15959 rb_define_method(rb_cARGF, "filename", argf_filename, 0);
15960 rb_define_method(rb_cARGF, "path", argf_filename, 0);
15961 rb_define_method(rb_cARGF, "file", argf_file, 0);
15962 rb_define_method(rb_cARGF, "skip", argf_skip, 0);
15963 rb_define_method(rb_cARGF, "close", argf_close_m, 0);
15964 rb_define_method(rb_cARGF, "closed?", argf_closed, 0);
15965
15966 rb_define_method(rb_cARGF, "lineno", argf_lineno, 0);
15967 rb_define_method(rb_cARGF, "lineno=", argf_set_lineno, 1);
15968
15969 rb_define_method(rb_cARGF, "inplace_mode", argf_inplace_mode_get, 0);
15970 rb_define_method(rb_cARGF, "inplace_mode=", argf_inplace_mode_set, 1);
15971
15972 rb_define_method(rb_cARGF, "external_encoding", argf_external_encoding, 0);
15973 rb_define_method(rb_cARGF, "internal_encoding", argf_internal_encoding, 0);
15974 rb_define_method(rb_cARGF, "set_encoding", argf_set_encoding, -1);
15975
15976 argf = rb_class_new_instance(0, 0, rb_cARGF);
15977
15979 /*
15980 * ARGF is a stream designed for use in scripts that process files given
15981 * as command-line arguments or passed in via STDIN.
15982 *
15983 * See ARGF (the class) for more details.
15984 */
15986
15987 rb_define_hooked_variable("$.", &argf, argf_lineno_getter, argf_lineno_setter);
15988 rb_define_hooked_variable("$FILENAME", &argf, argf_filename_getter, rb_gvar_readonly_setter);
15989 ARGF.filename = rb_str_new2("-");
15990
15991 rb_define_hooked_variable("$-i", &argf, opt_i_get, opt_i_set);
15992 rb_gvar_ractor_local("$-i");
15993
15994 rb_define_hooked_variable("$*", &argf, argf_argv_getter, rb_gvar_readonly_setter);
15995
15996#if defined (_WIN32) || defined(__CYGWIN__)
15997 atexit(pipe_atexit);
15998#endif
15999
16000 Init_File();
16001
16002 rb_define_method(rb_cFile, "initialize", rb_file_initialize, -1);
16003
16004 sym_mode = ID2SYM(rb_intern_const("mode"));
16005 sym_perm = ID2SYM(rb_intern_const("perm"));
16006 sym_flags = ID2SYM(rb_intern_const("flags"));
16007 sym_extenc = ID2SYM(rb_intern_const("external_encoding"));
16008 sym_intenc = ID2SYM(rb_intern_const("internal_encoding"));
16009 sym_encoding = ID2SYM(rb_id_encoding());
16010 sym_open_args = ID2SYM(rb_intern_const("open_args"));
16011 sym_textmode = ID2SYM(rb_intern_const("textmode"));
16012 sym_binmode = ID2SYM(rb_intern_const("binmode"));
16013 sym_autoclose = ID2SYM(rb_intern_const("autoclose"));
16014 sym_normal = ID2SYM(rb_intern_const("normal"));
16015 sym_sequential = ID2SYM(rb_intern_const("sequential"));
16016 sym_random = ID2SYM(rb_intern_const("random"));
16017 sym_willneed = ID2SYM(rb_intern_const("willneed"));
16018 sym_dontneed = ID2SYM(rb_intern_const("dontneed"));
16019 sym_noreuse = ID2SYM(rb_intern_const("noreuse"));
16020 sym_SET = ID2SYM(rb_intern_const("SET"));
16021 sym_CUR = ID2SYM(rb_intern_const("CUR"));
16022 sym_END = ID2SYM(rb_intern_const("END"));
16023#ifdef SEEK_DATA
16024 sym_DATA = ID2SYM(rb_intern_const("DATA"));
16025#endif
16026#ifdef SEEK_HOLE
16027 sym_HOLE = ID2SYM(rb_intern_const("HOLE"));
16028#endif
16029 sym_wait_readable = ID2SYM(rb_intern_const("wait_readable"));
16030 sym_wait_writable = ID2SYM(rb_intern_const("wait_writable"));
16031}
16032
16033#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:134
#define T_FIXNUM
Old name of RUBY_T_FIXNUM.
Definition value_type.h:63
#define UNREACHABLE_RETURN
Old name of RBIMPL_UNREACHABLE_RETURN.
Definition assume.h:29
#define FIX2UINT
Old name of RB_FIX2UINT.
Definition int.h:42
#define SSIZET2NUM
Old name of RB_SSIZE2NUM.
Definition size_t.h:64
#define ZALLOC
Old name of RB_ZALLOC.
Definition memory.h:402
#define CLASS_OF
Old name of rb_class_of.
Definition globals.h: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:3840
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:1441
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:3909
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:14712
VALUE rb_eIOError
IOError exception.
Definition io.c:189
VALUE rb_eStandardError
StandardError exception.
Definition error.c:1428
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:3999
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:3915
#define ruby_verbose
This variable controls whether the interpreter is in debug mode.
Definition error.h:475
VALUE rb_eTypeError
TypeError exception.
Definition error.c:1431
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:14706
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:1429
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:1451
@ 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:1342
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:831
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:8618
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:8751
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:9180
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:5191
VALUE rb_io_getbyte(VALUE io)
Reads a byte from the given IO.
Definition io.c:5097
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:9361
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:9160
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:6406
VALUE rb_io_binmode(VALUE io)
Sets the binmode.
Definition io.c:6360
VALUE rb_io_ungetc(VALUE io, VALUE c)
"Unget"s a string.
Definition io.c:5255
int rb_pipe(int *pipes)
This is an rb_cloexec_pipe() + rb_update_max_fd() combo.
Definition io.c:7408
VALUE rb_gets(void)
Much like rb_io_gets(), but it reads from the mysterious ARGF object.
Definition io.c:10439
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:7291
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:7298
VALUE rb_io_close(VALUE io)
Closes the IO.
Definition io.c:5773
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:3095
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:3797
#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:1001
VALUE rb_str_new_frozen(VALUE str)
Creates a frozen copy of the string, if necessary.
Definition string.c:1518
VALUE rb_str_dup(VALUE str)
Duplicates a string.
Definition string.c:1996
VALUE rb_str_cat(VALUE dst, const char *src, long srclen)
Destructively appends the passed contents to the string.
Definition string.c:3565
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:4267
void rb_str_set_len(VALUE str, long len)
Overwrites the length of the string.
Definition string.c:3387
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:3739
VALUE rb_check_string_type(VALUE obj)
Try converting an object to its stringised representation using its to_str method,...
Definition string.c:2950
VALUE rb_str_substr(VALUE str, long beg, long len)
This is the implementation of two-argumented String#slice.
Definition string.c:3250
VALUE rb_str_unlocktmp(VALUE str)
Releases a lock formerly obtained by rb_str_locktmp().
Definition string.c:3369
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:2744
VALUE rb_str_buf_new(long capa)
Allocates a "string buffer".
Definition string.c:1718
#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:1850
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:3402
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:6492
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:6625
#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:7108
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:6774
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:9407
#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:6899
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:5693
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:5881
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:9273
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:7395
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:508
VALUE rb_get_argv(void)
Queries the arguments passed to the current process that you can access from Ruby as ARGV.
Definition io.c:14672
void rb_p(VALUE obj)
Inspects an object.
Definition io.c:9059
#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