Ruby 3.5.0dev (2025-04-25 revision 71166f60d95f0d78de5f151205ef6060de5e054e)
io.c (71166f60d95f0d78de5f151205ef6060de5e054e)
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
204VALUE rb_output_fs;
205VALUE rb_rs;
208
209static VALUE argf;
210
211static ID id_write, id_read, id_getc, id_flush, id_readpartial, id_set_encoding, id_fileno;
212static VALUE sym_mode, sym_perm, sym_flags, sym_extenc, sym_intenc, sym_encoding, sym_open_args;
213static VALUE sym_textmode, sym_binmode, sym_autoclose;
214static VALUE sym_SET, sym_CUR, sym_END;
215static VALUE sym_wait_readable, sym_wait_writable;
216#ifdef SEEK_DATA
217static VALUE sym_DATA;
218#endif
219#ifdef SEEK_HOLE
220static VALUE sym_HOLE;
221#endif
222
223static VALUE prep_io(int fd, enum rb_io_mode fmode, VALUE klass, const char *path);
224
225VALUE
226rb_io_blocking_region_wait(struct rb_io *io, rb_blocking_function_t *function, void *argument, enum rb_io_event events)
227{
228 return rb_thread_io_blocking_call(io, function, argument, events);
229}
230
231VALUE rb_io_blocking_region(struct rb_io *io, rb_blocking_function_t *function, void *argument)
232{
233 return rb_io_blocking_region_wait(io, function, argument, 0);
234}
235
236struct argf {
237 VALUE filename, current_file;
238 long last_lineno; /* $. */
239 long lineno;
240 VALUE argv;
241 VALUE inplace;
242 struct rb_io_encoding encs;
243 int8_t init_p, next_p, binmode;
244};
245
246static rb_atomic_t max_file_descriptor = NOFILE;
247void
249{
250 rb_atomic_t afd = (rb_atomic_t)fd;
251 rb_atomic_t max_fd = max_file_descriptor;
252 int err;
253
254 if (fd < 0 || afd <= max_fd)
255 return;
256
257#if defined(HAVE_FCNTL) && defined(F_GETFL)
258 err = fcntl(fd, F_GETFL) == -1;
259#else
260 {
261 struct stat buf;
262 err = fstat(fd, &buf) != 0;
263 }
264#endif
265 if (err && errno == EBADF) {
266 rb_bug("rb_update_max_fd: invalid fd (%d) given.", fd);
267 }
268
269 while (max_fd < afd) {
270 max_fd = ATOMIC_CAS(max_file_descriptor, max_fd, afd);
271 }
272}
273
274void
275rb_maygvl_fd_fix_cloexec(int fd)
276{
277 /* MinGW don't have F_GETFD and FD_CLOEXEC. [ruby-core:40281] */
278#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
279 int flags, flags2, ret;
280 flags = fcntl(fd, F_GETFD); /* should not fail except EBADF. */
281 if (flags == -1) {
282 rb_bug("rb_maygvl_fd_fix_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(errno));
283 }
284 if (fd <= 2)
285 flags2 = flags & ~FD_CLOEXEC; /* Clear CLOEXEC for standard file descriptors: 0, 1, 2. */
286 else
287 flags2 = flags | FD_CLOEXEC; /* Set CLOEXEC for non-standard file descriptors: 3, 4, 5, ... */
288 if (flags != flags2) {
289 ret = fcntl(fd, F_SETFD, flags2);
290 if (ret != 0) {
291 rb_bug("rb_maygvl_fd_fix_cloexec: fcntl(%d, F_SETFD, %d) failed: %s", fd, flags2, strerror(errno));
292 }
293 }
294#endif
295}
296
297void
299{
300 rb_maygvl_fd_fix_cloexec(fd);
302}
303
304/* this is only called once */
305static int
306rb_fix_detect_o_cloexec(int fd)
307{
308#if defined(O_CLOEXEC) && defined(F_GETFD)
309 int flags = fcntl(fd, F_GETFD);
310
311 if (flags == -1)
312 rb_bug("rb_fix_detect_o_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(errno));
313
314 if (flags & FD_CLOEXEC)
315 return 1;
316#endif /* fall through if O_CLOEXEC does not work: */
317 rb_maygvl_fd_fix_cloexec(fd);
318 return 0;
319}
320
321static inline bool
322io_again_p(int e)
323{
324 return (e == EWOULDBLOCK) || (e == EAGAIN);
325}
326
327int
328rb_cloexec_open(const char *pathname, int flags, mode_t mode)
329{
330 int ret;
331 static int o_cloexec_state = -1; /* <0: unknown, 0: ignored, >0: working */
332
333 static const int retry_interval = 0;
334 static const int retry_max_count = 10000;
335
336 int retry_count = 0;
337
338#ifdef O_CLOEXEC
339 /* O_CLOEXEC is available since Linux 2.6.23. Linux 2.6.18 silently ignore it. */
340 flags |= O_CLOEXEC;
341#elif defined O_NOINHERIT
342 flags |= O_NOINHERIT;
343#endif
344
345 while ((ret = open(pathname, flags, mode)) == -1) {
346 int e = errno;
347 if (!io_again_p(e)) break;
348 if (retry_count++ >= retry_max_count) break;
349
350 sleep(retry_interval);
351 }
352
353 if (ret < 0) return ret;
354 if (ret <= 2 || o_cloexec_state == 0) {
355 rb_maygvl_fd_fix_cloexec(ret);
356 }
357 else if (o_cloexec_state > 0) {
358 return ret;
359 }
360 else {
361 o_cloexec_state = rb_fix_detect_o_cloexec(ret);
362 }
363 return ret;
364}
365
366int
368{
369 /* Don't allocate standard file descriptors: 0, 1, 2 */
370 return rb_cloexec_fcntl_dupfd(oldfd, 3);
371}
372
373int
374rb_cloexec_dup2(int oldfd, int newfd)
375{
376 int ret;
377
378 /* When oldfd == newfd, dup2 succeeds but dup3 fails with EINVAL.
379 * rb_cloexec_dup2 succeeds as dup2. */
380 if (oldfd == newfd) {
381 ret = newfd;
382 }
383 else {
384#if defined(HAVE_DUP3) && defined(O_CLOEXEC)
385 static int try_dup3 = 1;
386 if (2 < newfd && try_dup3) {
387 ret = dup3(oldfd, newfd, O_CLOEXEC);
388 if (ret != -1)
389 return ret;
390 /* dup3 is available since Linux 2.6.27, glibc 2.9. */
391 if (errno == ENOSYS) {
392 try_dup3 = 0;
393 ret = dup2(oldfd, newfd);
394 }
395 }
396 else {
397 ret = dup2(oldfd, newfd);
398 }
399#else
400 ret = dup2(oldfd, newfd);
401#endif
402 if (ret < 0) return ret;
403 }
404 rb_maygvl_fd_fix_cloexec(ret);
405 return ret;
406}
407
408static int
409rb_fd_set_nonblock(int fd)
410{
411#ifdef _WIN32
412 return rb_w32_set_nonblock(fd);
413#elif defined(F_GETFL)
414 int oflags = fcntl(fd, F_GETFL);
415
416 if (oflags == -1)
417 return -1;
418 if (oflags & O_NONBLOCK)
419 return 0;
420 oflags |= O_NONBLOCK;
421 return fcntl(fd, F_SETFL, oflags);
422#endif
423 return 0;
424}
425
426int
427rb_cloexec_pipe(int descriptors[2])
428{
429#ifdef HAVE_PIPE2
430 int result = pipe2(descriptors, O_CLOEXEC | O_NONBLOCK);
431#else
432 int result = pipe(descriptors);
433#endif
434
435 if (result < 0)
436 return result;
437
438#ifdef __CYGWIN__
439 if (result == 0 && descriptors[1] == -1) {
440 close(descriptors[0]);
441 descriptors[0] = -1;
442 errno = ENFILE;
443 return -1;
444 }
445#endif
446
447#ifndef HAVE_PIPE2
448 rb_maygvl_fd_fix_cloexec(descriptors[0]);
449 rb_maygvl_fd_fix_cloexec(descriptors[1]);
450
451#ifndef _WIN32
452 rb_fd_set_nonblock(descriptors[0]);
453 rb_fd_set_nonblock(descriptors[1]);
454#endif
455#endif
456
457 return result;
458}
459
460int
461rb_cloexec_fcntl_dupfd(int fd, int minfd)
462{
463 int ret;
464
465#if defined(HAVE_FCNTL) && defined(F_DUPFD_CLOEXEC) && defined(F_DUPFD)
466 static int try_dupfd_cloexec = 1;
467 if (try_dupfd_cloexec) {
468 ret = fcntl(fd, F_DUPFD_CLOEXEC, minfd);
469 if (ret != -1) {
470 if (ret <= 2)
471 rb_maygvl_fd_fix_cloexec(ret);
472 return ret;
473 }
474 /* F_DUPFD_CLOEXEC is available since Linux 2.6.24. Linux 2.6.18 fails with EINVAL */
475 if (errno == EINVAL) {
476 ret = fcntl(fd, F_DUPFD, minfd);
477 if (ret != -1) {
478 try_dupfd_cloexec = 0;
479 }
480 }
481 }
482 else {
483 ret = fcntl(fd, F_DUPFD, minfd);
484 }
485#elif defined(HAVE_FCNTL) && defined(F_DUPFD)
486 ret = fcntl(fd, F_DUPFD, minfd);
487#else
488 ret = dup(fd);
489 if (ret >= 0 && ret < minfd) {
490 const int prev_fd = ret;
491 ret = rb_cloexec_fcntl_dupfd(fd, minfd);
492 close(prev_fd);
493 }
494 return ret;
495#endif
496 if (ret < 0) return ret;
497 rb_maygvl_fd_fix_cloexec(ret);
498 return ret;
499}
500
501#define argf_of(obj) (*(struct argf *)DATA_PTR(obj))
502#define ARGF argf_of(argf)
503
504#define GetWriteIO(io) rb_io_get_write_io(io)
505
506#define READ_DATA_PENDING(fptr) ((fptr)->rbuf.len)
507#define READ_DATA_PENDING_COUNT(fptr) ((fptr)->rbuf.len)
508#define READ_DATA_PENDING_PTR(fptr) ((fptr)->rbuf.ptr+(fptr)->rbuf.off)
509#define READ_DATA_BUFFERED(fptr) READ_DATA_PENDING(fptr)
510
511#define READ_CHAR_PENDING(fptr) ((fptr)->cbuf.len)
512#define READ_CHAR_PENDING_COUNT(fptr) ((fptr)->cbuf.len)
513#define READ_CHAR_PENDING_PTR(fptr) ((fptr)->cbuf.ptr+(fptr)->cbuf.off)
514
515#if defined(_WIN32)
516#define WAIT_FD_IN_WIN32(fptr) \
517 (rb_w32_io_cancelable_p((fptr)->fd) ? Qnil : rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_READABLE), RUBY_IO_TIMEOUT_DEFAULT))
518#else
519#define WAIT_FD_IN_WIN32(fptr)
520#endif
521
522#define READ_CHECK(fptr) do {\
523 if (!READ_DATA_PENDING(fptr)) {\
524 WAIT_FD_IN_WIN32(fptr);\
525 rb_io_check_closed(fptr);\
526 }\
527} while(0)
528
529#ifndef S_ISSOCK
530# ifdef _S_ISSOCK
531# define S_ISSOCK(m) _S_ISSOCK(m)
532# else
533# ifdef _S_IFSOCK
534# define S_ISSOCK(m) (((m) & S_IFMT) == _S_IFSOCK)
535# else
536# ifdef S_IFSOCK
537# define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
538# endif
539# endif
540# endif
541#endif
542
543static int io_fflush(rb_io_t *);
544static rb_io_t *flush_before_seek(rb_io_t *fptr, bool discard_rbuf);
545static void clear_codeconv(rb_io_t *fptr);
546
547#define FMODE_SIGNAL_ON_EPIPE (1<<17)
548
549#define fptr_signal_on_epipe(fptr) \
550 (((fptr)->mode & FMODE_SIGNAL_ON_EPIPE) != 0)
551
552#define fptr_set_signal_on_epipe(fptr, flag) \
553 ((flag) ? \
554 (fptr)->mode |= FMODE_SIGNAL_ON_EPIPE : \
555 (fptr)->mode &= ~FMODE_SIGNAL_ON_EPIPE)
556
557extern ID ruby_static_id_signo;
558
559NORETURN(static void rb_sys_fail_on_write(rb_io_t *fptr));
560static void
561rb_sys_fail_on_write(rb_io_t *fptr)
562{
563 int e = errno;
564 VALUE errinfo = rb_syserr_new_path(e, (fptr)->pathv);
565#if defined EPIPE
566 if (fptr_signal_on_epipe(fptr) && (e == EPIPE)) {
567 const VALUE sig =
568# if defined SIGPIPE
569 INT2FIX(SIGPIPE) - INT2FIX(0) +
570# endif
571 INT2FIX(0);
572 rb_ivar_set(errinfo, ruby_static_id_signo, sig);
573 }
574#endif
575 rb_exc_raise(errinfo);
576}
577
578#define NEED_NEWLINE_DECORATOR_ON_READ(fptr) ((fptr)->mode & FMODE_TEXTMODE)
579#define NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) ((fptr)->mode & FMODE_TEXTMODE)
580#if defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32)
581# define RUBY_CRLF_ENVIRONMENT 1
582#else
583# define RUBY_CRLF_ENVIRONMENT 0
584#endif
585
586#if RUBY_CRLF_ENVIRONMENT
587/* Windows */
588# define DEFAULT_TEXTMODE FMODE_TEXTMODE
589# define TEXTMODE_NEWLINE_DECORATOR_ON_WRITE ECONV_CRLF_NEWLINE_DECORATOR
590/*
591 * CRLF newline is set as default newline decorator.
592 * If only CRLF newline conversion is needed, we use binary IO process
593 * with OS's text mode for IO performance improvement.
594 * If encoding conversion is needed or a user sets text mode, we use encoding
595 * conversion IO process and universal newline decorator by default.
596 */
597#define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || (fptr)->encs.ecflags & ~ECONV_CRLF_NEWLINE_DECORATOR)
598#define WRITECONV_MASK ( \
599 (ECONV_DECORATOR_MASK & ~ECONV_CRLF_NEWLINE_DECORATOR)|\
600 ECONV_STATEFUL_DECORATOR_MASK|\
601 0)
602#define NEED_WRITECONV(fptr) ( \
603 ((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || \
604 ((fptr)->encs.ecflags & WRITECONV_MASK) || \
605 0)
606#define SET_BINARY_MODE(fptr) setmode((fptr)->fd, O_BINARY)
607
608#define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) do {\
609 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {\
610 if (((fptr)->mode & FMODE_READABLE) &&\
611 !((fptr)->encs.ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {\
612 setmode((fptr)->fd, O_BINARY);\
613 }\
614 else {\
615 setmode((fptr)->fd, O_TEXT);\
616 }\
617 }\
618} while(0)
619
620#define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) do {\
621 if ((enc2) && ((ecflags) & ECONV_DEFAULT_NEWLINE_DECORATOR)) {\
622 (ecflags) |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;\
623 }\
624} while(0)
625
626/*
627 * IO unread with taking care of removed '\r' in text mode.
628 */
629static void
630io_unread(rb_io_t *fptr, bool discard_rbuf)
631{
632 rb_off_t r, pos;
633 ssize_t read_size;
634 long i;
635 long newlines = 0;
636 long extra_max;
637 char *p;
638 char *buf;
639
640 rb_io_check_closed(fptr);
641 if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX) {
642 return;
643 }
644
645 errno = 0;
646 if (!rb_w32_fd_is_text(fptr->fd)) {
647 r = lseek(fptr->fd, -fptr->rbuf.len, SEEK_CUR);
648 if (r < 0 && errno) {
649 if (errno == ESPIPE)
650 fptr->mode |= FMODE_DUPLEX;
651 if (!discard_rbuf) return;
652 }
653
654 goto end;
655 }
656
657 pos = lseek(fptr->fd, 0, SEEK_CUR);
658 if (pos < 0 && errno) {
659 if (errno == ESPIPE)
660 fptr->mode |= FMODE_DUPLEX;
661 if (!discard_rbuf) goto end;
662 }
663
664 /* add extra offset for removed '\r' in rbuf */
665 extra_max = (long)(pos - fptr->rbuf.len);
666 p = fptr->rbuf.ptr + fptr->rbuf.off;
667
668 /* if the end of rbuf is '\r', rbuf doesn't have '\r' within rbuf.len */
669 if (*(fptr->rbuf.ptr + fptr->rbuf.capa - 1) == '\r') {
670 newlines++;
671 }
672
673 for (i = 0; i < fptr->rbuf.len; i++) {
674 if (*p == '\n') newlines++;
675 if (extra_max == newlines) break;
676 p++;
677 }
678
679 buf = ALLOC_N(char, fptr->rbuf.len + newlines);
680 while (newlines >= 0) {
681 r = lseek(fptr->fd, pos - fptr->rbuf.len - newlines, SEEK_SET);
682 if (newlines == 0) break;
683 if (r < 0) {
684 newlines--;
685 continue;
686 }
687 read_size = _read(fptr->fd, buf, fptr->rbuf.len + newlines);
688 if (read_size < 0) {
689 int e = errno;
690 free(buf);
691 rb_syserr_fail_path(e, fptr->pathv);
692 }
693 if (read_size == fptr->rbuf.len) {
694 lseek(fptr->fd, r, SEEK_SET);
695 break;
696 }
697 else {
698 newlines--;
699 }
700 }
701 free(buf);
702 end:
703 fptr->rbuf.off = 0;
704 fptr->rbuf.len = 0;
705 clear_codeconv(fptr);
706 return;
707}
708
709/*
710 * We use io_seek to back cursor position when changing mode from text to binary,
711 * but stdin and pipe cannot seek back. Stdin and pipe read should use encoding
712 * conversion for working properly with mode change.
713 *
714 * Return previous translation mode.
715 */
716static inline int
717set_binary_mode_with_seek_cur(rb_io_t *fptr)
718{
719 if (!rb_w32_fd_is_text(fptr->fd)) return O_BINARY;
720
721 if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX) {
722 return setmode(fptr->fd, O_BINARY);
723 }
724 flush_before_seek(fptr, false);
725 return setmode(fptr->fd, O_BINARY);
726}
727#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) set_binary_mode_with_seek_cur(fptr)
728
729#else
730/* Unix */
731# define DEFAULT_TEXTMODE 0
732#define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || NEED_NEWLINE_DECORATOR_ON_READ(fptr))
733#define NEED_WRITECONV(fptr) ( \
734 ((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || \
735 NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) || \
736 ((fptr)->encs.ecflags & (ECONV_DECORATOR_MASK|ECONV_STATEFUL_DECORATOR_MASK)) || \
737 0)
738#define SET_BINARY_MODE(fptr) (void)(fptr)
739#define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) (void)(fptr)
740#define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) ((void)(enc2), (void)(ecflags))
741#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) (void)(fptr)
742#endif
743
744#if !defined HAVE_SHUTDOWN && !defined shutdown
745#define shutdown(a,b) 0
746#endif
747
748#if defined(_WIN32)
749#define is_socket(fd, path) rb_w32_is_socket(fd)
750#elif !defined(S_ISSOCK)
751#define is_socket(fd, path) 0
752#else
753static int
754is_socket(int fd, VALUE path)
755{
756 struct stat sbuf;
757 if (fstat(fd, &sbuf) < 0)
758 rb_sys_fail_path(path);
759 return S_ISSOCK(sbuf.st_mode);
760}
761#endif
762
763static const char closed_stream[] = "closed stream";
764
765static void
766io_fd_check_closed(int fd)
767{
768 if (fd < 0) {
769 rb_thread_check_ints(); /* check for ruby_error_stream_closed */
770 rb_raise(rb_eIOError, closed_stream);
771 }
772}
773
774void
775rb_eof_error(void)
776{
777 rb_raise(rb_eEOFError, "end of file reached");
778}
779
780VALUE
782{
783 rb_check_frozen(io);
784 return io;
785}
786
787void
789{
790 if (!fptr) {
791 rb_raise(rb_eIOError, "uninitialized stream");
792 }
793}
794
795void
797{
799 io_fd_check_closed(fptr->fd);
800}
801
802static rb_io_t *
803rb_io_get_fptr(VALUE io)
804{
805 rb_io_t *fptr = RFILE(io)->fptr;
807 return fptr;
808}
809
810VALUE
812{
813 return rb_convert_type_with_id(io, T_FILE, "IO", idTo_io);
814}
815
816VALUE
818{
819 return rb_check_convert_type_with_id(io, T_FILE, "IO", idTo_io);
820}
821
822VALUE
824{
825 VALUE write_io;
826 write_io = rb_io_get_fptr(io)->tied_io_for_writing;
827 if (write_io) {
828 return write_io;
829 }
830 return io;
831}
832
833VALUE
835{
836 VALUE write_io;
837 rb_io_t *fptr = rb_io_get_fptr(io);
838 if (!RTEST(w)) {
839 w = 0;
840 }
841 else {
842 GetWriteIO(w);
843 }
844 write_io = fptr->tied_io_for_writing;
845 fptr->tied_io_for_writing = w;
846 return write_io ? write_io : Qnil;
847}
848
849/*
850 * call-seq:
851 * timeout -> duration or nil
852 *
853 * Get the internal timeout duration or nil if it was not set.
854 *
855 */
856VALUE
858{
859 rb_io_t *fptr = rb_io_get_fptr(self);
860
861 return fptr->timeout;
862}
863
864/*
865 * call-seq:
866 * timeout = duration -> duration
867 * timeout = nil -> nil
868 *
869 * Sets the internal timeout to the specified duration or nil. The timeout
870 * applies to all blocking operations where possible.
871 *
872 * When the operation performs longer than the timeout set, IO::TimeoutError
873 * is raised.
874 *
875 * This affects the following methods (but is not limited to): #gets, #puts,
876 * #read, #write, #wait_readable and #wait_writable. This also affects
877 * blocking socket operations like Socket#accept and Socket#connect.
878 *
879 * Some operations like File#open and IO#close are not affected by the
880 * timeout. A timeout during a write operation may leave the IO in an
881 * inconsistent state, e.g. data was partially written. Generally speaking, a
882 * timeout is a last ditch effort to prevent an application from hanging on
883 * slow I/O operations, such as those that occur during a slowloris attack.
884 */
885VALUE
887{
888 // Validate it:
889 if (RTEST(timeout)) {
890 rb_time_interval(timeout);
891 }
892
893 rb_io_t *fptr = rb_io_get_fptr(self);
894
895 fptr->timeout = timeout;
896
897 return self;
898}
899
900/*
901 * call-seq:
902 * IO.try_convert(object) -> new_io or nil
903 *
904 * Attempts to convert +object+ into an \IO object via method +to_io+;
905 * returns the new \IO object if successful, or +nil+ otherwise:
906 *
907 * IO.try_convert(STDOUT) # => #<IO:<STDOUT>>
908 * IO.try_convert(ARGF) # => #<IO:<STDIN>>
909 * IO.try_convert('STDOUT') # => nil
910 *
911 */
912static VALUE
913rb_io_s_try_convert(VALUE dummy, VALUE io)
914{
915 return rb_io_check_io(io);
916}
917
918#if !RUBY_CRLF_ENVIRONMENT
919static void
920io_unread(rb_io_t *fptr, bool discard_rbuf)
921{
922 rb_off_t r;
923 rb_io_check_closed(fptr);
924 if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX)
925 return;
926 /* xxx: target position may be negative if buffer is filled by ungetc */
927 errno = 0;
928 r = lseek(fptr->fd, -fptr->rbuf.len, SEEK_CUR);
929 if (r < 0 && errno) {
930 if (errno == ESPIPE)
931 fptr->mode |= FMODE_DUPLEX;
932 if (!discard_rbuf) return;
933 }
934 fptr->rbuf.off = 0;
935 fptr->rbuf.len = 0;
936 clear_codeconv(fptr);
937 return;
938}
939#endif
940
941static rb_encoding *io_input_encoding(rb_io_t *fptr);
942
943static void
944io_ungetbyte(VALUE str, rb_io_t *fptr)
945{
946 long len = RSTRING_LEN(str);
947
948 if (fptr->rbuf.ptr == NULL) {
949 const int min_capa = IO_RBUF_CAPA_FOR(fptr);
950 fptr->rbuf.off = 0;
951 fptr->rbuf.len = 0;
952#if SIZEOF_LONG > SIZEOF_INT
953 if (len > INT_MAX)
954 rb_raise(rb_eIOError, "ungetbyte failed");
955#endif
956 if (len > min_capa)
957 fptr->rbuf.capa = (int)len;
958 else
959 fptr->rbuf.capa = min_capa;
960 fptr->rbuf.ptr = ALLOC_N(char, fptr->rbuf.capa);
961 }
962 if (fptr->rbuf.capa < len + fptr->rbuf.len) {
963 rb_raise(rb_eIOError, "ungetbyte failed");
964 }
965 if (fptr->rbuf.off < len) {
966 MEMMOVE(fptr->rbuf.ptr+fptr->rbuf.capa-fptr->rbuf.len,
967 fptr->rbuf.ptr+fptr->rbuf.off,
968 char, fptr->rbuf.len);
969 fptr->rbuf.off = fptr->rbuf.capa-fptr->rbuf.len;
970 }
971 fptr->rbuf.off-=(int)len;
972 fptr->rbuf.len+=(int)len;
973 MEMMOVE(fptr->rbuf.ptr+fptr->rbuf.off, RSTRING_PTR(str), char, len);
974}
975
976static rb_io_t *
977flush_before_seek(rb_io_t *fptr, bool discard_rbuf)
978{
979 if (io_fflush(fptr) < 0)
980 rb_sys_fail_on_write(fptr);
981 io_unread(fptr, discard_rbuf);
982 errno = 0;
983 return fptr;
984}
985
986#define io_seek(fptr, ofs, whence) (errno = 0, lseek(flush_before_seek(fptr, true)->fd, (ofs), (whence)))
987#define io_tell(fptr) lseek(flush_before_seek(fptr, false)->fd, 0, SEEK_CUR)
988
989#ifndef SEEK_CUR
990# define SEEK_SET 0
991# define SEEK_CUR 1
992# define SEEK_END 2
993#endif
994
995void
997{
998 rb_io_check_closed(fptr);
999 if (!(fptr->mode & FMODE_READABLE)) {
1000 rb_raise(rb_eIOError, "not opened for reading");
1001 }
1002 if (fptr->wbuf.len) {
1003 if (io_fflush(fptr) < 0)
1004 rb_sys_fail_on_write(fptr);
1005 }
1006 if (fptr->tied_io_for_writing) {
1007 rb_io_t *wfptr;
1008 GetOpenFile(fptr->tied_io_for_writing, wfptr);
1009 if (io_fflush(wfptr) < 0)
1010 rb_sys_fail_on_write(wfptr);
1011 }
1012}
1013
1014void
1016{
1018 if (READ_CHAR_PENDING(fptr)) {
1019 rb_raise(rb_eIOError, "byte oriented read for character buffered IO");
1020 }
1021}
1022
1023void
1028
1029static rb_encoding*
1030io_read_encoding(rb_io_t *fptr)
1031{
1032 if (fptr->encs.enc) {
1033 return fptr->encs.enc;
1034 }
1035 return rb_default_external_encoding();
1036}
1037
1038static rb_encoding*
1039io_input_encoding(rb_io_t *fptr)
1040{
1041 if (fptr->encs.enc2) {
1042 return fptr->encs.enc2;
1043 }
1044 return io_read_encoding(fptr);
1045}
1046
1047void
1049{
1050 rb_io_check_closed(fptr);
1051 if (!(fptr->mode & FMODE_WRITABLE)) {
1052 rb_raise(rb_eIOError, "not opened for writing");
1053 }
1054 if (fptr->rbuf.len) {
1055 io_unread(fptr, true);
1056 }
1057}
1058
1059int
1060rb_io_read_pending(rb_io_t *fptr)
1061{
1062 /* This function is used for bytes and chars. Confusing. */
1063 if (READ_CHAR_PENDING(fptr))
1064 return 1; /* should raise? */
1065 return READ_DATA_PENDING(fptr);
1066}
1067
1068void
1070{
1071 if (!READ_DATA_PENDING(fptr)) {
1072 rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_READABLE), RUBY_IO_TIMEOUT_DEFAULT);
1073 }
1074 return;
1075}
1076
1077int
1078rb_gc_for_fd(int err)
1079{
1080 if (err == EMFILE || err == ENFILE || err == ENOMEM) {
1081 rb_gc();
1082 return 1;
1083 }
1084 return 0;
1085}
1086
1087/* try `expr` upto twice while it returns false and `errno`
1088 * is to GC. Each `errno`s are available as `first_errno` and
1089 * `retried_errno` respectively */
1090#define TRY_WITH_GC(expr) \
1091 for (int first_errno, retried_errno = 0, retried = 0; \
1092 (!retried && \
1093 !(expr) && \
1094 (!rb_gc_for_fd(first_errno = errno) || !(expr)) && \
1095 (retried_errno = errno, 1)); \
1096 (void)retried_errno, retried = 1)
1097
1098static int
1099ruby_dup(int orig)
1100{
1101 int fd = -1;
1102
1103 TRY_WITH_GC((fd = rb_cloexec_dup(orig)) >= 0) {
1104 rb_syserr_fail(first_errno, 0);
1105 }
1106 rb_update_max_fd(fd);
1107 return fd;
1108}
1109
1110static VALUE
1111io_alloc(VALUE klass)
1112{
1113 NEWOBJ_OF(io, struct RFile, klass, T_FILE, sizeof(struct RFile), 0);
1114
1115 io->fptr = 0;
1116
1117 return (VALUE)io;
1118}
1119
1120#ifndef S_ISREG
1121# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
1122#endif
1123
1125 VALUE th;
1126 rb_io_t *fptr;
1127 int nonblock;
1128 int fd;
1129
1130 void *buf;
1131 size_t capa;
1132 struct timeval *timeout;
1133};
1134
1136 VALUE th;
1137 rb_io_t *fptr;
1138 int nonblock;
1139 int fd;
1140
1141 const void *buf;
1142 size_t capa;
1143 struct timeval *timeout;
1144};
1145
1146#ifdef HAVE_WRITEV
1147struct io_internal_writev_struct {
1148 VALUE th;
1149 rb_io_t *fptr;
1150 int nonblock;
1151 int fd;
1152
1153 int iovcnt;
1154 const struct iovec *iov;
1155 struct timeval *timeout;
1156};
1157#endif
1158
1159static int nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout);
1160
1166static inline int
1167io_internal_wait(VALUE thread, rb_io_t *fptr, int error, int events, struct timeval *timeout)
1168{
1169 if (!timeout && rb_thread_mn_schedulable(thread)) {
1170 RUBY_ASSERT(errno == EWOULDBLOCK || errno == EAGAIN);
1171 return -1;
1172 }
1173
1174 int ready = nogvl_wait_for(thread, fptr, events, timeout);
1175
1176 if (ready > 0) {
1177 return ready;
1178 }
1179 else if (ready == 0) {
1180 errno = ETIMEDOUT;
1181 return -1;
1182 }
1183
1184 // If there was an error BEFORE we started waiting, return it:
1185 if (error) {
1186 errno = error;
1187 return -1;
1188 }
1189 else {
1190 // Otherwise, whatever error was generated by `nogvl_wait_for` is the one we want:
1191 return ready;
1192 }
1193}
1194
1195static VALUE
1196internal_read_func(void *ptr)
1197{
1198 struct io_internal_read_struct *iis = ptr;
1199 ssize_t result;
1200
1201 if (iis->timeout && !iis->nonblock) {
1202 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_IN, iis->timeout) == -1) {
1203 return -1;
1204 }
1205 }
1206
1207 retry:
1208 result = read(iis->fd, iis->buf, iis->capa);
1209
1210 if (result < 0 && !iis->nonblock) {
1211 if (io_again_p(errno)) {
1212 if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_IN, iis->timeout) == -1) {
1213 return -1;
1214 }
1215 else {
1216 goto retry;
1217 }
1218 }
1219 }
1220
1221 return result;
1222}
1223
1224#if defined __APPLE__
1225# define do_write_retry(code) do {result = code;} while (result == -1 && errno == EPROTOTYPE)
1226#else
1227# define do_write_retry(code) result = code
1228#endif
1229
1230static VALUE
1231internal_write_func(void *ptr)
1232{
1233 struct io_internal_write_struct *iis = ptr;
1234 ssize_t result;
1235
1236 if (iis->timeout && !iis->nonblock) {
1237 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1238 return -1;
1239 }
1240 }
1241
1242 retry:
1243 do_write_retry(write(iis->fd, iis->buf, iis->capa));
1244
1245 if (result < 0 && !iis->nonblock) {
1246 int e = errno;
1247 if (io_again_p(e)) {
1248 if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1249 return -1;
1250 }
1251 else {
1252 goto retry;
1253 }
1254 }
1255 }
1256
1257 return result;
1258}
1259
1260#ifdef HAVE_WRITEV
1261static VALUE
1262internal_writev_func(void *ptr)
1263{
1264 struct io_internal_writev_struct *iis = ptr;
1265 ssize_t result;
1266
1267 if (iis->timeout && !iis->nonblock) {
1268 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1269 return -1;
1270 }
1271 }
1272
1273 retry:
1274 do_write_retry(writev(iis->fd, iis->iov, iis->iovcnt));
1275
1276 if (result < 0 && !iis->nonblock) {
1277 if (io_again_p(errno)) {
1278 if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1279 return -1;
1280 }
1281 else {
1282 goto retry;
1283 }
1284 }
1285 }
1286
1287 return result;
1288}
1289#endif
1290
1291static ssize_t
1292rb_io_read_memory(rb_io_t *fptr, void *buf, size_t count)
1293{
1294 VALUE scheduler = rb_fiber_scheduler_current();
1295 if (scheduler != Qnil) {
1296 VALUE result = rb_fiber_scheduler_io_read_memory(scheduler, fptr->self, buf, count, 0);
1297
1298 if (!UNDEF_P(result)) {
1300 }
1301 }
1302
1303 struct io_internal_read_struct iis = {
1304 .th = rb_thread_current(),
1305 .fptr = fptr,
1306 .nonblock = 0,
1307 .fd = fptr->fd,
1308
1309 .buf = buf,
1310 .capa = count,
1311 .timeout = NULL,
1312 };
1313
1314 struct timeval timeout_storage;
1315
1316 if (fptr->timeout != Qnil) {
1317 timeout_storage = rb_time_interval(fptr->timeout);
1318 iis.timeout = &timeout_storage;
1319 }
1320
1321 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_read_func, &iis, RUBY_IO_READABLE);
1322}
1323
1324static ssize_t
1325rb_io_write_memory(rb_io_t *fptr, const void *buf, size_t count)
1326{
1327 VALUE scheduler = rb_fiber_scheduler_current();
1328 if (scheduler != Qnil) {
1329 VALUE result = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, buf, count, 0);
1330
1331 if (!UNDEF_P(result)) {
1333 }
1334 }
1335
1336 struct io_internal_write_struct iis = {
1337 .th = rb_thread_current(),
1338 .fptr = fptr,
1339 .nonblock = 0,
1340 .fd = fptr->fd,
1341
1342 .buf = buf,
1343 .capa = count,
1344 .timeout = NULL
1345 };
1346
1347 struct timeval timeout_storage;
1348
1349 if (fptr->timeout != Qnil) {
1350 timeout_storage = rb_time_interval(fptr->timeout);
1351 iis.timeout = &timeout_storage;
1352 }
1353
1354 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_write_func, &iis, RUBY_IO_WRITABLE);
1355}
1356
1357#ifdef HAVE_WRITEV
1358static ssize_t
1359rb_writev_internal(rb_io_t *fptr, const struct iovec *iov, int iovcnt)
1360{
1361 if (!iovcnt) return 0;
1362
1363 VALUE scheduler = rb_fiber_scheduler_current();
1364 if (scheduler != Qnil) {
1365 // This path assumes at least one `iov`:
1366 VALUE result = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, iov[0].iov_base, iov[0].iov_len, 0);
1367
1368 if (!UNDEF_P(result)) {
1370 }
1371 }
1372
1373 struct io_internal_writev_struct iis = {
1374 .th = rb_thread_current(),
1375 .fptr = fptr,
1376 .nonblock = 0,
1377 .fd = fptr->fd,
1378
1379 .iov = iov,
1380 .iovcnt = iovcnt,
1381 .timeout = NULL
1382 };
1383
1384 struct timeval timeout_storage;
1385
1386 if (fptr->timeout != Qnil) {
1387 timeout_storage = rb_time_interval(fptr->timeout);
1388 iis.timeout = &timeout_storage;
1389 }
1390
1391 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_writev_func, &iis, RUBY_IO_WRITABLE);
1392}
1393#endif
1394
1395static VALUE
1396io_flush_buffer_sync(void *arg)
1397{
1398 rb_io_t *fptr = arg;
1399 long l = fptr->wbuf.len;
1400 ssize_t r = write(fptr->fd, fptr->wbuf.ptr+fptr->wbuf.off, (size_t)l);
1401
1402 if (fptr->wbuf.len <= r) {
1403 fptr->wbuf.off = 0;
1404 fptr->wbuf.len = 0;
1405 return 0;
1406 }
1407
1408 if (0 <= r) {
1409 fptr->wbuf.off += (int)r;
1410 fptr->wbuf.len -= (int)r;
1411 errno = EAGAIN;
1412 }
1413
1414 return (VALUE)-1;
1415}
1416
1417static VALUE
1418io_flush_buffer_async(VALUE arg)
1419{
1420 rb_io_t *fptr = (rb_io_t *)arg;
1421 return rb_io_blocking_region_wait(fptr, io_flush_buffer_sync, fptr, RUBY_IO_WRITABLE);
1422}
1423
1424static inline int
1425io_flush_buffer(rb_io_t *fptr)
1426{
1427 if (!NIL_P(fptr->write_lock) && rb_mutex_owned_p(fptr->write_lock)) {
1428 return (int)io_flush_buffer_async((VALUE)fptr);
1429 }
1430 else {
1431 return (int)rb_mutex_synchronize(fptr->write_lock, io_flush_buffer_async, (VALUE)fptr);
1432 }
1433}
1434
1435static int
1436io_fflush(rb_io_t *fptr)
1437{
1438 rb_io_check_closed(fptr);
1439
1440 if (fptr->wbuf.len == 0)
1441 return 0;
1442
1443 while (fptr->wbuf.len > 0 && io_flush_buffer(fptr) != 0) {
1444 if (!rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT))
1445 return -1;
1446
1447 rb_io_check_closed(fptr);
1448 }
1449
1450 return 0;
1451}
1452
1453VALUE
1454rb_io_wait(VALUE io, VALUE events, VALUE timeout)
1455{
1456 VALUE scheduler = rb_fiber_scheduler_current();
1457
1458 if (scheduler != Qnil) {
1459 return rb_fiber_scheduler_io_wait(scheduler, io, events, timeout);
1460 }
1461
1462 rb_io_t * fptr = NULL;
1463 RB_IO_POINTER(io, fptr);
1464
1465 struct timeval tv_storage;
1466 struct timeval *tv = NULL;
1467
1468 if (NIL_OR_UNDEF_P(timeout)) {
1469 timeout = fptr->timeout;
1470 }
1471
1472 if (timeout != Qnil) {
1473 tv_storage = rb_time_interval(timeout);
1474 tv = &tv_storage;
1475 }
1476
1477 int ready = rb_thread_io_wait(fptr, RB_NUM2INT(events), tv);
1478
1479 if (ready < 0) {
1480 rb_sys_fail(0);
1481 }
1482
1483 // Not sure if this is necessary:
1484 rb_io_check_closed(fptr);
1485
1486 if (ready) {
1487 return RB_INT2NUM(ready);
1488 }
1489 else {
1490 return Qfalse;
1491 }
1492}
1493
1494static VALUE
1495io_from_fd(int fd)
1496{
1497 return prep_io(fd, FMODE_EXTERNAL, rb_cIO, NULL);
1498}
1499
1500static int
1501io_wait_for_single_fd(int fd, int events, struct timeval *timeout)
1502{
1503 VALUE scheduler = rb_fiber_scheduler_current();
1504
1505 if (scheduler != Qnil) {
1506 return RTEST(
1507 rb_fiber_scheduler_io_wait(scheduler, io_from_fd(fd), RB_INT2NUM(events), rb_fiber_scheduler_make_timeout(timeout))
1508 );
1509 }
1510
1511 return rb_thread_wait_for_single_fd(fd, events, timeout);
1512}
1513
1514int
1516{
1517 io_fd_check_closed(f);
1518
1519 VALUE scheduler = rb_fiber_scheduler_current();
1520
1521 switch (errno) {
1522 case EINTR:
1523#if defined(ERESTART)
1524 case ERESTART:
1525#endif
1527 return TRUE;
1528
1529 case EAGAIN:
1530#if EWOULDBLOCK != EAGAIN
1531 case EWOULDBLOCK:
1532#endif
1533 if (scheduler != Qnil) {
1534 return RTEST(
1535 rb_fiber_scheduler_io_wait_readable(scheduler, io_from_fd(f))
1536 );
1537 }
1538 else {
1539 io_wait_for_single_fd(f, RUBY_IO_READABLE, NULL);
1540 }
1541 return TRUE;
1542
1543 default:
1544 return FALSE;
1545 }
1546}
1547
1548int
1550{
1551 io_fd_check_closed(f);
1552
1553 VALUE scheduler = rb_fiber_scheduler_current();
1554
1555 switch (errno) {
1556 case EINTR:
1557#if defined(ERESTART)
1558 case ERESTART:
1559#endif
1560 /*
1561 * In old Linux, several special files under /proc and /sys don't handle
1562 * select properly. Thus we need avoid to call if don't use O_NONBLOCK.
1563 * Otherwise, we face nasty hang up. Sigh.
1564 * e.g. https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1565 * https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1566 * In EINTR case, we only need to call RUBY_VM_CHECK_INTS_BLOCKING().
1567 * Then rb_thread_check_ints() is enough.
1568 */
1570 return TRUE;
1571
1572 case EAGAIN:
1573#if EWOULDBLOCK != EAGAIN
1574 case EWOULDBLOCK:
1575#endif
1576 if (scheduler != Qnil) {
1577 return RTEST(
1578 rb_fiber_scheduler_io_wait_writable(scheduler, io_from_fd(f))
1579 );
1580 }
1581 else {
1582 io_wait_for_single_fd(f, RUBY_IO_WRITABLE, NULL);
1583 }
1584 return TRUE;
1585
1586 default:
1587 return FALSE;
1588 }
1589}
1590
1591int
1592rb_wait_for_single_fd(int fd, int events, struct timeval *timeout)
1593{
1594 return io_wait_for_single_fd(fd, events, timeout);
1595}
1596
1597int
1599{
1600 return rb_wait_for_single_fd(fd, RUBY_IO_READABLE, NULL);
1601}
1602
1603int
1605{
1606 return rb_wait_for_single_fd(fd, RUBY_IO_WRITABLE, NULL);
1607}
1608
1609VALUE
1610rb_io_maybe_wait(int error, VALUE io, VALUE events, VALUE timeout)
1611{
1612 // fptr->fd can be set to -1 at any time by another thread when the GVL is
1613 // released. Many code, e.g. `io_bufread` didn't check this correctly and
1614 // instead relies on `read(-1) -> -1` which causes this code path. We then
1615 // check here whether the IO was in fact closed. Probably it's better to
1616 // check that `fptr->fd != -1` before using it in syscall.
1617 rb_io_check_closed(RFILE(io)->fptr);
1618
1619 switch (error) {
1620 // In old Linux, several special files under /proc and /sys don't handle
1621 // select properly. Thus we need avoid to call if don't use O_NONBLOCK.
1622 // Otherwise, we face nasty hang up. Sigh.
1623 // e.g. https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1624 // https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1625 // In EINTR case, we only need to call RUBY_VM_CHECK_INTS_BLOCKING().
1626 // Then rb_thread_check_ints() is enough.
1627 case EINTR:
1628#if defined(ERESTART)
1629 case ERESTART:
1630#endif
1631 // We might have pending interrupts since the previous syscall was interrupted:
1633
1634 // The operation was interrupted, so retry it immediately:
1635 return events;
1636
1637 case EAGAIN:
1638#if EWOULDBLOCK != EAGAIN
1639 case EWOULDBLOCK:
1640#endif
1641 // The operation would block, so wait for the specified events:
1642 return rb_io_wait(io, events, timeout);
1643
1644 default:
1645 // Non-specific error, no event is ready:
1646 return Qnil;
1647 }
1648}
1649
1650int
1652{
1653 VALUE result = rb_io_maybe_wait(error, io, RB_INT2NUM(RUBY_IO_READABLE), timeout);
1654
1655 if (RTEST(result)) {
1656 return RB_NUM2INT(result);
1657 }
1658 else if (result == RUBY_Qfalse) {
1659 rb_raise(rb_eIOTimeoutError, "Timed out waiting for IO to become readable!");
1660 }
1661
1662 return 0;
1663}
1664
1665int
1667{
1668 VALUE result = rb_io_maybe_wait(error, io, RB_INT2NUM(RUBY_IO_WRITABLE), timeout);
1669
1670 if (RTEST(result)) {
1671 return RB_NUM2INT(result);
1672 }
1673 else if (result == RUBY_Qfalse) {
1674 rb_raise(rb_eIOTimeoutError, "Timed out waiting for IO to become writable!");
1675 }
1676
1677 return 0;
1678}
1679
1680static void
1681make_writeconv(rb_io_t *fptr)
1682{
1683 if (!fptr->writeconv_initialized) {
1684 const char *senc, *denc;
1685 rb_encoding *enc;
1686 int ecflags;
1687 VALUE ecopts;
1688
1689 fptr->writeconv_initialized = 1;
1690
1691 ecflags = fptr->encs.ecflags & ~ECONV_NEWLINE_DECORATOR_READ_MASK;
1692 ecopts = fptr->encs.ecopts;
1693
1694 if (!fptr->encs.enc || (rb_is_ascii8bit_enc(fptr->encs.enc) && !fptr->encs.enc2)) {
1695 /* no encoding conversion */
1696 fptr->writeconv_pre_ecflags = 0;
1697 fptr->writeconv_pre_ecopts = Qnil;
1698 fptr->writeconv = rb_econv_open_opts("", "", ecflags, ecopts);
1699 if (!fptr->writeconv)
1700 rb_exc_raise(rb_econv_open_exc("", "", ecflags));
1702 }
1703 else {
1704 enc = fptr->encs.enc2 ? fptr->encs.enc2 : fptr->encs.enc;
1705 senc = rb_econv_asciicompat_encoding(rb_enc_name(enc));
1706 if (!senc && !(fptr->encs.ecflags & ECONV_STATEFUL_DECORATOR_MASK)) {
1707 /* single conversion */
1708 fptr->writeconv_pre_ecflags = ecflags;
1709 fptr->writeconv_pre_ecopts = ecopts;
1710 fptr->writeconv = NULL;
1712 }
1713 else {
1714 /* double conversion */
1715 fptr->writeconv_pre_ecflags = ecflags & ~ECONV_STATEFUL_DECORATOR_MASK;
1716 fptr->writeconv_pre_ecopts = ecopts;
1717 if (senc) {
1718 denc = rb_enc_name(enc);
1719 fptr->writeconv_asciicompat = rb_str_new2(senc);
1720 }
1721 else {
1722 senc = denc = "";
1723 fptr->writeconv_asciicompat = rb_str_new2(rb_enc_name(enc));
1724 }
1726 ecopts = fptr->encs.ecopts;
1727 fptr->writeconv = rb_econv_open_opts(senc, denc, ecflags, ecopts);
1728 if (!fptr->writeconv)
1729 rb_exc_raise(rb_econv_open_exc(senc, denc, ecflags));
1730 }
1731 }
1732 }
1733}
1734
1735/* writing functions */
1737 rb_io_t *fptr;
1738 const char *ptr;
1739 long length;
1740};
1741
1743 VALUE io;
1744 VALUE str;
1745 int nosync;
1746};
1747
1748#ifdef HAVE_WRITEV
1749static ssize_t
1750io_binwrite_string_internal(rb_io_t *fptr, const char *ptr, long length)
1751{
1752 if (fptr->wbuf.len) {
1753 struct iovec iov[2];
1754
1755 iov[0].iov_base = fptr->wbuf.ptr+fptr->wbuf.off;
1756 iov[0].iov_len = fptr->wbuf.len;
1757 iov[1].iov_base = (void*)ptr;
1758 iov[1].iov_len = length;
1759
1760 ssize_t result = rb_writev_internal(fptr, iov, 2);
1761
1762 if (result < 0)
1763 return result;
1764
1765 if (result >= fptr->wbuf.len) {
1766 // We wrote more than the internal buffer:
1767 result -= fptr->wbuf.len;
1768 fptr->wbuf.off = 0;
1769 fptr->wbuf.len = 0;
1770 }
1771 else {
1772 // We only wrote less data than the internal buffer:
1773 fptr->wbuf.off += (int)result;
1774 fptr->wbuf.len -= (int)result;
1775
1776 result = 0;
1777 }
1778
1779 return result;
1780 }
1781 else {
1782 return rb_io_write_memory(fptr, ptr, length);
1783 }
1784}
1785#else
1786static ssize_t
1787io_binwrite_string_internal(rb_io_t *fptr, const char *ptr, long length)
1788{
1789 long remaining = length;
1790
1791 if (fptr->wbuf.len) {
1792 if (fptr->wbuf.len+length <= fptr->wbuf.capa) {
1793 if (fptr->wbuf.capa < fptr->wbuf.off+fptr->wbuf.len+length) {
1794 MEMMOVE(fptr->wbuf.ptr, fptr->wbuf.ptr+fptr->wbuf.off, char, fptr->wbuf.len);
1795 fptr->wbuf.off = 0;
1796 }
1797
1798 MEMMOVE(fptr->wbuf.ptr+fptr->wbuf.off+fptr->wbuf.len, ptr, char, length);
1799 fptr->wbuf.len += (int)length;
1800
1801 // We copied the entire incoming data to the internal buffer:
1802 remaining = 0;
1803 }
1804
1805 // Flush the internal buffer:
1806 if (io_fflush(fptr) < 0) {
1807 return -1;
1808 }
1809
1810 // If all the data was buffered, we are done:
1811 if (remaining == 0) {
1812 return length;
1813 }
1814 }
1815
1816 // Otherwise, we should write the data directly:
1817 return rb_io_write_memory(fptr, ptr, length);
1818}
1819#endif
1820
1821static VALUE
1822io_binwrite_string(VALUE arg)
1823{
1824 struct binwrite_arg *p = (struct binwrite_arg *)arg;
1825
1826 const char *ptr = p->ptr;
1827 size_t remaining = p->length;
1828
1829 while (remaining) {
1830 // Write as much as possible:
1831 ssize_t result = io_binwrite_string_internal(p->fptr, ptr, remaining);
1832
1833 if (result == 0) {
1834 // If only the internal buffer is written, result will be zero [bytes of given data written]. This means we
1835 // should try again immediately.
1836 }
1837 else if (result > 0) {
1838 if ((size_t)result == remaining) break;
1839 ptr += result;
1840 remaining -= result;
1841 }
1842 // Wait for it to become writable:
1843 else if (rb_io_maybe_wait_writable(errno, p->fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
1844 rb_io_check_closed(p->fptr);
1845 }
1846 else {
1847 // The error was unrelated to waiting for it to become writable, so we fail:
1848 return -1;
1849 }
1850 }
1851
1852 return p->length;
1853}
1854
1855inline static void
1856io_allocate_write_buffer(rb_io_t *fptr, int sync)
1857{
1858 if (fptr->wbuf.ptr == NULL && !(sync && (fptr->mode & FMODE_SYNC))) {
1859 fptr->wbuf.off = 0;
1860 fptr->wbuf.len = 0;
1861 fptr->wbuf.capa = IO_WBUF_CAPA_MIN;
1862 fptr->wbuf.ptr = ALLOC_N(char, fptr->wbuf.capa);
1863 }
1864
1865 if (NIL_P(fptr->write_lock)) {
1866 fptr->write_lock = rb_mutex_new();
1867 rb_mutex_allow_trap(fptr->write_lock, 1);
1868 }
1869}
1870
1871static inline int
1872io_binwrite_requires_flush_write(rb_io_t *fptr, long len, int nosync)
1873{
1874 // If the requested operation was synchronous and the output mode is synchronous or a TTY:
1875 if (!nosync && (fptr->mode & (FMODE_SYNC|FMODE_TTY)))
1876 return 1;
1877
1878 // If the amount of data we want to write exceeds the internal buffer:
1879 if (fptr->wbuf.ptr && fptr->wbuf.capa <= fptr->wbuf.len + len)
1880 return 1;
1881
1882 // Otherwise, we can append to the internal buffer:
1883 return 0;
1884}
1885
1886static long
1887io_binwrite(const char *ptr, long len, rb_io_t *fptr, int nosync)
1888{
1889 if (len <= 0) return len;
1890
1891 // Don't write anything if current thread has a pending interrupt:
1893
1894 io_allocate_write_buffer(fptr, !nosync);
1895
1896 if (io_binwrite_requires_flush_write(fptr, len, nosync)) {
1897 struct binwrite_arg arg;
1898
1899 arg.fptr = fptr;
1900 arg.ptr = ptr;
1901 arg.length = len;
1902
1903 if (!NIL_P(fptr->write_lock)) {
1904 return rb_mutex_synchronize(fptr->write_lock, io_binwrite_string, (VALUE)&arg);
1905 }
1906 else {
1907 return io_binwrite_string((VALUE)&arg);
1908 }
1909 }
1910 else {
1911 if (fptr->wbuf.off) {
1912 if (fptr->wbuf.len)
1913 MEMMOVE(fptr->wbuf.ptr, fptr->wbuf.ptr+fptr->wbuf.off, char, fptr->wbuf.len);
1914 fptr->wbuf.off = 0;
1915 }
1916
1917 MEMMOVE(fptr->wbuf.ptr+fptr->wbuf.off+fptr->wbuf.len, ptr, char, len);
1918 fptr->wbuf.len += (int)len;
1919
1920 return len;
1921 }
1922}
1923
1924# define MODE_BTMODE(a,b,c) ((fmode & FMODE_BINMODE) ? (b) : \
1925 (fmode & FMODE_TEXTMODE) ? (c) : (a))
1926
1927#define MODE_BTXMODE(a, b, c, d, e, f) ((fmode & FMODE_EXCL) ? \
1928 MODE_BTMODE(d, e, f) : \
1929 MODE_BTMODE(a, b, c))
1930
1931static VALUE
1932do_writeconv(VALUE str, rb_io_t *fptr, int *converted)
1933{
1934 if (NEED_WRITECONV(fptr)) {
1935 VALUE common_encoding = Qnil;
1936 SET_BINARY_MODE(fptr);
1937
1938 make_writeconv(fptr);
1939
1940 if (fptr->writeconv) {
1941#define fmode (fptr->mode)
1942 if (!NIL_P(fptr->writeconv_asciicompat))
1943 common_encoding = fptr->writeconv_asciicompat;
1944 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1) && !rb_enc_asciicompat(rb_enc_get(str))) {
1945 rb_raise(rb_eArgError, "ASCII incompatible string written for text mode IO without encoding conversion: %s",
1946 rb_enc_name(rb_enc_get(str)));
1947 }
1948#undef fmode
1949 }
1950 else {
1951 if (fptr->encs.enc2)
1952 common_encoding = rb_enc_from_encoding(fptr->encs.enc2);
1953 else if (fptr->encs.enc != rb_ascii8bit_encoding())
1954 common_encoding = rb_enc_from_encoding(fptr->encs.enc);
1955 }
1956
1957 if (!NIL_P(common_encoding)) {
1958 str = rb_str_encode(str, common_encoding,
1960 *converted = 1;
1961 }
1962
1963 if (fptr->writeconv) {
1965 *converted = 1;
1966 }
1967 }
1968#if RUBY_CRLF_ENVIRONMENT
1969#define fmode (fptr->mode)
1970 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1)) {
1971 if ((fptr->mode & FMODE_READABLE) &&
1973 setmode(fptr->fd, O_BINARY);
1974 }
1975 else {
1976 setmode(fptr->fd, O_TEXT);
1977 }
1978 if (!rb_enc_asciicompat(rb_enc_get(str))) {
1979 rb_raise(rb_eArgError, "ASCII incompatible string written for text mode IO without encoding conversion: %s",
1980 rb_enc_name(rb_enc_get(str)));
1981 }
1982 }
1983#undef fmode
1984#endif
1985 return str;
1986}
1987
1988static long
1989io_fwrite(VALUE str, rb_io_t *fptr, int nosync)
1990{
1991 int converted = 0;
1992 VALUE tmp;
1993 long n, len;
1994 const char *ptr;
1995
1996#ifdef _WIN32
1997 if (fptr->mode & FMODE_TTY) {
1998 long len = rb_w32_write_console(str, fptr->fd);
1999 if (len > 0) return len;
2000 }
2001#endif
2002
2003 str = do_writeconv(str, fptr, &converted);
2004 if (converted)
2005 OBJ_FREEZE(str);
2006
2007 tmp = rb_str_tmp_frozen_no_embed_acquire(str);
2008 RSTRING_GETMEM(tmp, ptr, len);
2009 n = io_binwrite(ptr, len, fptr, nosync);
2010 rb_str_tmp_frozen_release(str, tmp);
2011
2012 return n;
2013}
2014
2015ssize_t
2016rb_io_bufwrite(VALUE io, const void *buf, size_t size)
2017{
2018 rb_io_t *fptr;
2019
2020 GetOpenFile(io, fptr);
2022 return (ssize_t)io_binwrite(buf, (long)size, fptr, 0);
2023}
2024
2025static VALUE
2026io_write(VALUE io, VALUE str, int nosync)
2027{
2028 rb_io_t *fptr;
2029 long n;
2030 VALUE tmp;
2031
2032 io = GetWriteIO(io);
2033 str = rb_obj_as_string(str);
2034 tmp = rb_io_check_io(io);
2035
2036 if (NIL_P(tmp)) {
2037 /* port is not IO, call write method for it. */
2038 return rb_funcall(io, id_write, 1, str);
2039 }
2040
2041 io = tmp;
2042 if (RSTRING_LEN(str) == 0) return INT2FIX(0);
2043
2044 GetOpenFile(io, fptr);
2046
2047 n = io_fwrite(str, fptr, nosync);
2048 if (n < 0L) rb_sys_fail_on_write(fptr);
2049
2050 return LONG2FIX(n);
2051}
2052
2053#ifdef HAVE_WRITEV
2054struct binwritev_arg {
2055 rb_io_t *fptr;
2056 struct iovec *iov;
2057 int iovcnt;
2058 size_t total;
2059};
2060
2061static VALUE
2062io_binwritev_internal(VALUE arg)
2063{
2064 struct binwritev_arg *p = (struct binwritev_arg *)arg;
2065
2066 size_t remaining = p->total;
2067 size_t offset = 0;
2068
2069 rb_io_t *fptr = p->fptr;
2070 struct iovec *iov = p->iov;
2071 int iovcnt = p->iovcnt;
2072
2073 while (remaining) {
2074 long result = rb_writev_internal(fptr, iov, iovcnt);
2075
2076 if (result >= 0) {
2077 offset += result;
2078 if (fptr->wbuf.ptr && fptr->wbuf.len) {
2079 if (offset < (size_t)fptr->wbuf.len) {
2080 fptr->wbuf.off += result;
2081 fptr->wbuf.len -= result;
2082 }
2083 else {
2084 offset -= (size_t)fptr->wbuf.len;
2085 fptr->wbuf.off = 0;
2086 fptr->wbuf.len = 0;
2087 }
2088 }
2089
2090 if (offset == p->total) {
2091 return p->total;
2092 }
2093
2094 while (result >= (ssize_t)iov->iov_len) {
2095 /* iovcnt > 0 */
2096 result -= iov->iov_len;
2097 iov->iov_len = 0;
2098 iov++;
2099
2100 if (!--iovcnt) {
2101 // I don't believe this code path can ever occur.
2102 return offset;
2103 }
2104 }
2105
2106 iov->iov_base = (char *)iov->iov_base + result;
2107 iov->iov_len -= result;
2108 }
2109 else if (rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
2110 rb_io_check_closed(fptr);
2111 }
2112 else {
2113 return -1;
2114 }
2115 }
2116
2117 return offset;
2118}
2119
2120static long
2121io_binwritev(struct iovec *iov, int iovcnt, rb_io_t *fptr)
2122{
2123 // Don't write anything if current thread has a pending interrupt:
2125
2126 if (iovcnt == 0) return 0;
2127
2128 size_t total = 0;
2129 for (int i = 1; i < iovcnt; i++) total += iov[i].iov_len;
2130
2131 io_allocate_write_buffer(fptr, 1);
2132
2133 if (fptr->wbuf.ptr && fptr->wbuf.len) {
2134 // The end of the buffered data:
2135 size_t offset = fptr->wbuf.off + fptr->wbuf.len;
2136
2137 if (offset + total <= (size_t)fptr->wbuf.capa) {
2138 for (int i = 1; i < iovcnt; i++) {
2139 memcpy(fptr->wbuf.ptr+offset, iov[i].iov_base, iov[i].iov_len);
2140 offset += iov[i].iov_len;
2141 }
2142
2143 fptr->wbuf.len += total;
2144
2145 return total;
2146 }
2147 else {
2148 iov[0].iov_base = fptr->wbuf.ptr + fptr->wbuf.off;
2149 iov[0].iov_len = fptr->wbuf.len;
2150 }
2151 }
2152 else {
2153 // The first iov is reserved for the internal buffer, and it's empty.
2154 iov++;
2155
2156 if (!--iovcnt) {
2157 // If there are no other io vectors we are done.
2158 return 0;
2159 }
2160 }
2161
2162 struct binwritev_arg arg;
2163 arg.fptr = fptr;
2164 arg.iov = iov;
2165 arg.iovcnt = iovcnt;
2166 arg.total = total;
2167
2168 if (!NIL_P(fptr->write_lock)) {
2169 return rb_mutex_synchronize(fptr->write_lock, io_binwritev_internal, (VALUE)&arg);
2170 }
2171 else {
2172 return io_binwritev_internal((VALUE)&arg);
2173 }
2174}
2175
2176static long
2177io_fwritev(int argc, const VALUE *argv, rb_io_t *fptr)
2178{
2179 int i, converted, iovcnt = argc + 1;
2180 long n;
2181 VALUE v1, v2, str, tmp, *tmp_array;
2182 struct iovec *iov;
2183
2184 iov = ALLOCV_N(struct iovec, v1, iovcnt);
2185 tmp_array = ALLOCV_N(VALUE, v2, argc);
2186
2187 for (i = 0; i < argc; i++) {
2188 str = rb_obj_as_string(argv[i]);
2189 converted = 0;
2190 str = do_writeconv(str, fptr, &converted);
2191
2192 if (converted)
2193 OBJ_FREEZE(str);
2194
2195 tmp = rb_str_tmp_frozen_acquire(str);
2196 tmp_array[i] = tmp;
2197
2198 /* iov[0] is reserved for buffer of fptr */
2199 iov[i+1].iov_base = RSTRING_PTR(tmp);
2200 iov[i+1].iov_len = RSTRING_LEN(tmp);
2201 }
2202
2203 n = io_binwritev(iov, iovcnt, fptr);
2204 if (v1) ALLOCV_END(v1);
2205
2206 for (i = 0; i < argc; i++) {
2207 rb_str_tmp_frozen_release(argv[i], tmp_array[i]);
2208 }
2209
2210 if (v2) ALLOCV_END(v2);
2211
2212 return n;
2213}
2214
2215static int
2216iovcnt_ok(int iovcnt)
2217{
2218#ifdef IOV_MAX
2219 return iovcnt < IOV_MAX;
2220#else /* GNU/Hurd has writev, but no IOV_MAX */
2221 return 1;
2222#endif
2223}
2224#endif /* HAVE_WRITEV */
2225
2226static VALUE
2227io_writev(int argc, const VALUE *argv, VALUE io)
2228{
2229 rb_io_t *fptr;
2230 long n;
2231 VALUE tmp, total = INT2FIX(0);
2232 int i, cnt = 1;
2233
2234 io = GetWriteIO(io);
2235 tmp = rb_io_check_io(io);
2236
2237 if (NIL_P(tmp)) {
2238 /* port is not IO, call write method for it. */
2239 return rb_funcallv(io, id_write, argc, argv);
2240 }
2241
2242 io = tmp;
2243
2244 GetOpenFile(io, fptr);
2246
2247 for (i = 0; i < argc; i += cnt) {
2248#ifdef HAVE_WRITEV
2249 if ((fptr->mode & (FMODE_SYNC|FMODE_TTY)) && iovcnt_ok(cnt = argc - i)) {
2250 n = io_fwritev(cnt, &argv[i], fptr);
2251 }
2252 else
2253#endif
2254 {
2255 cnt = 1;
2256 /* sync at last item */
2257 n = io_fwrite(rb_obj_as_string(argv[i]), fptr, (i < argc-1));
2258 }
2259
2260 if (n < 0L)
2261 rb_sys_fail_on_write(fptr);
2262
2263 total = rb_fix_plus(LONG2FIX(n), total);
2264 }
2265
2266 return total;
2267}
2268
2269/*
2270 * call-seq:
2271 * write(*objects) -> integer
2272 *
2273 * Writes each of the given +objects+ to +self+,
2274 * which must be opened for writing
2275 * (see {Access Modes}[rdoc-ref:File@Access+Modes]);
2276 * returns the total number bytes written;
2277 * each of +objects+ that is not a string is converted via method +to_s+:
2278 *
2279 * $stdout.write('Hello', ', ', 'World!', "\n") # => 14
2280 * $stdout.write('foo', :bar, 2, "\n") # => 8
2281 *
2282 * Output:
2283 *
2284 * Hello, World!
2285 * foobar2
2286 *
2287 * Related: IO#read.
2288 */
2289
2290static VALUE
2291io_write_m(int argc, VALUE *argv, VALUE io)
2292{
2293 if (argc != 1) {
2294 return io_writev(argc, argv, io);
2295 }
2296 else {
2297 VALUE str = argv[0];
2298 return io_write(io, str, 0);
2299 }
2300}
2301
2302VALUE
2303rb_io_write(VALUE io, VALUE str)
2304{
2305 return rb_funcallv(io, id_write, 1, &str);
2306}
2307
2308static VALUE
2309rb_io_writev(VALUE io, int argc, const VALUE *argv)
2310{
2311 if (argc > 1 && rb_obj_method_arity(io, id_write) == 1) {
2312 if (io != rb_ractor_stderr() && RTEST(ruby_verbose)) {
2313 VALUE klass = CLASS_OF(io);
2314 char sep = RCLASS_SINGLETON_P(klass) ? (klass = io, '.') : '#';
2316 RB_WARN_CATEGORY_DEPRECATED, "%+"PRIsVALUE"%c""write is outdated interface"
2317 " which accepts just one argument",
2318 klass, sep
2319 );
2320 }
2321
2322 do rb_io_write(io, *argv++); while (--argc);
2323
2324 return Qnil;
2325 }
2326
2327 return rb_funcallv(io, id_write, argc, argv);
2328}
2329
2330/*
2331 * call-seq:
2332 * self << object -> self
2333 *
2334 * Writes the given +object+ to +self+,
2335 * which must be opened for writing (see {Access Modes}[rdoc-ref:File@Access+Modes]);
2336 * returns +self+;
2337 * if +object+ is not a string, it is converted via method +to_s+:
2338 *
2339 * $stdout << 'Hello' << ', ' << 'World!' << "\n"
2340 * $stdout << 'foo' << :bar << 2 << "\n"
2341 *
2342 * Output:
2343 *
2344 * Hello, World!
2345 * foobar2
2346 *
2347 */
2348
2349
2350VALUE
2352{
2353 rb_io_write(io, str);
2354 return io;
2355}
2356
2357#ifdef HAVE_FSYNC
2358static VALUE
2359nogvl_fsync(void *ptr)
2360{
2361 rb_io_t *fptr = ptr;
2362
2363#ifdef _WIN32
2364 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->fd)) != FILE_TYPE_DISK)
2365 return 0;
2366#endif
2367 return (VALUE)fsync(fptr->fd);
2368}
2369#endif
2370
2371VALUE
2372rb_io_flush_raw(VALUE io, int sync)
2373{
2374 rb_io_t *fptr;
2375
2376 if (!RB_TYPE_P(io, T_FILE)) {
2377 return rb_funcall(io, id_flush, 0);
2378 }
2379
2380 io = GetWriteIO(io);
2381 GetOpenFile(io, fptr);
2382
2383 if (fptr->mode & FMODE_WRITABLE) {
2384 if (io_fflush(fptr) < 0)
2385 rb_sys_fail_on_write(fptr);
2386 }
2387 if (fptr->mode & FMODE_READABLE) {
2388 io_unread(fptr, true);
2389 }
2390
2391 return io;
2392}
2393
2394/*
2395 * call-seq:
2396 * flush -> self
2397 *
2398 * Flushes data buffered in +self+ to the operating system
2399 * (but does not necessarily flush data buffered in the operating system):
2400 *
2401 * $stdout.print 'no newline' # Not necessarily flushed.
2402 * $stdout.flush # Flushed.
2403 *
2404 */
2405
2406VALUE
2407rb_io_flush(VALUE io)
2408{
2409 return rb_io_flush_raw(io, 1);
2410}
2411
2412/*
2413 * call-seq:
2414 * tell -> integer
2415 *
2416 * Returns the current position (in bytes) in +self+
2417 * (see {Position}[rdoc-ref:IO@Position]):
2418 *
2419 * f = File.open('t.txt')
2420 * f.tell # => 0
2421 * f.gets # => "First line\n"
2422 * f.tell # => 12
2423 * f.close
2424 *
2425 * Related: IO#pos=, IO#seek.
2426 */
2427
2428static VALUE
2429rb_io_tell(VALUE io)
2430{
2431 rb_io_t *fptr;
2432 rb_off_t pos;
2433
2434 GetOpenFile(io, fptr);
2435 pos = io_tell(fptr);
2436 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2437 pos -= fptr->rbuf.len;
2438 return OFFT2NUM(pos);
2439}
2440
2441static VALUE
2442rb_io_seek(VALUE io, VALUE offset, int whence)
2443{
2444 rb_io_t *fptr;
2445 rb_off_t pos;
2446
2447 pos = NUM2OFFT(offset);
2448 GetOpenFile(io, fptr);
2449 pos = io_seek(fptr, pos, whence);
2450 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2451
2452 return INT2FIX(0);
2453}
2454
2455static int
2456interpret_seek_whence(VALUE vwhence)
2457{
2458 if (vwhence == sym_SET)
2459 return SEEK_SET;
2460 if (vwhence == sym_CUR)
2461 return SEEK_CUR;
2462 if (vwhence == sym_END)
2463 return SEEK_END;
2464#ifdef SEEK_DATA
2465 if (vwhence == sym_DATA)
2466 return SEEK_DATA;
2467#endif
2468#ifdef SEEK_HOLE
2469 if (vwhence == sym_HOLE)
2470 return SEEK_HOLE;
2471#endif
2472 return NUM2INT(vwhence);
2473}
2474
2475/*
2476 * call-seq:
2477 * seek(offset, whence = IO::SEEK_SET) -> 0
2478 *
2479 * Seeks to the position given by integer +offset+
2480 * (see {Position}[rdoc-ref:IO@Position])
2481 * and constant +whence+, which is one of:
2482 *
2483 * - +:CUR+ or <tt>IO::SEEK_CUR</tt>:
2484 * Repositions the stream to its current position plus the given +offset+:
2485 *
2486 * f = File.open('t.txt')
2487 * f.tell # => 0
2488 * f.seek(20, :CUR) # => 0
2489 * f.tell # => 20
2490 * f.seek(-10, :CUR) # => 0
2491 * f.tell # => 10
2492 * f.close
2493 *
2494 * - +:END+ or <tt>IO::SEEK_END</tt>:
2495 * Repositions the stream to its end plus the given +offset+:
2496 *
2497 * f = File.open('t.txt')
2498 * f.tell # => 0
2499 * f.seek(0, :END) # => 0 # Repositions to stream end.
2500 * f.tell # => 52
2501 * f.seek(-20, :END) # => 0
2502 * f.tell # => 32
2503 * f.seek(-40, :END) # => 0
2504 * f.tell # => 12
2505 * f.close
2506 *
2507 * - +:SET+ or <tt>IO:SEEK_SET</tt>:
2508 * Repositions the stream to the given +offset+:
2509 *
2510 * f = File.open('t.txt')
2511 * f.tell # => 0
2512 * f.seek(20, :SET) # => 0
2513 * f.tell # => 20
2514 * f.seek(40, :SET) # => 0
2515 * f.tell # => 40
2516 * f.close
2517 *
2518 * Related: IO#pos=, IO#tell.
2519 *
2520 */
2521
2522static VALUE
2523rb_io_seek_m(int argc, VALUE *argv, VALUE io)
2524{
2525 VALUE offset, ptrname;
2526 int whence = SEEK_SET;
2527
2528 if (rb_scan_args(argc, argv, "11", &offset, &ptrname) == 2) {
2529 whence = interpret_seek_whence(ptrname);
2530 }
2531
2532 return rb_io_seek(io, offset, whence);
2533}
2534
2535/*
2536 * call-seq:
2537 * pos = new_position -> new_position
2538 *
2539 * Seeks to the given +new_position+ (in bytes);
2540 * see {Position}[rdoc-ref:IO@Position]:
2541 *
2542 * f = File.open('t.txt')
2543 * f.tell # => 0
2544 * f.pos = 20 # => 20
2545 * f.tell # => 20
2546 * f.close
2547 *
2548 * Related: IO#seek, IO#tell.
2549 *
2550 */
2551
2552static VALUE
2553rb_io_set_pos(VALUE io, VALUE offset)
2554{
2555 rb_io_t *fptr;
2556 rb_off_t pos;
2557
2558 pos = NUM2OFFT(offset);
2559 GetOpenFile(io, fptr);
2560 pos = io_seek(fptr, pos, SEEK_SET);
2561 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2562
2563 return OFFT2NUM(pos);
2564}
2565
2566static void clear_readconv(rb_io_t *fptr);
2567
2568/*
2569 * call-seq:
2570 * rewind -> 0
2571 *
2572 * Repositions the stream to its beginning,
2573 * setting both the position and the line number to zero;
2574 * see {Position}[rdoc-ref:IO@Position]
2575 * and {Line Number}[rdoc-ref:IO@Line+Number]:
2576 *
2577 * f = File.open('t.txt')
2578 * f.tell # => 0
2579 * f.lineno # => 0
2580 * f.gets # => "First line\n"
2581 * f.tell # => 12
2582 * f.lineno # => 1
2583 * f.rewind # => 0
2584 * f.tell # => 0
2585 * f.lineno # => 0
2586 * f.close
2587 *
2588 * Note that this method cannot be used with streams such as pipes, ttys, and sockets.
2589 *
2590 */
2591
2592static VALUE
2593rb_io_rewind(VALUE io)
2594{
2595 rb_io_t *fptr;
2596
2597 GetOpenFile(io, fptr);
2598 if (io_seek(fptr, 0L, 0) < 0 && errno) rb_sys_fail_path(fptr->pathv);
2599 if (io == ARGF.current_file) {
2600 ARGF.lineno -= fptr->lineno;
2601 }
2602 fptr->lineno = 0;
2603 if (fptr->readconv) {
2604 clear_readconv(fptr);
2605 }
2606
2607 return INT2FIX(0);
2608}
2609
2610static int
2611fptr_wait_readable(rb_io_t *fptr)
2612{
2613 int result = rb_io_maybe_wait_readable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT);
2614
2615 if (result)
2616 rb_io_check_closed(fptr);
2617
2618 return result;
2619}
2620
2621static int
2622io_fillbuf(rb_io_t *fptr)
2623{
2624 ssize_t r;
2625
2626 if (fptr->rbuf.ptr == NULL) {
2627 fptr->rbuf.off = 0;
2628 fptr->rbuf.len = 0;
2629 fptr->rbuf.capa = IO_RBUF_CAPA_FOR(fptr);
2630 fptr->rbuf.ptr = ALLOC_N(char, fptr->rbuf.capa);
2631#ifdef _WIN32
2632 fptr->rbuf.capa--;
2633#endif
2634 }
2635 if (fptr->rbuf.len == 0) {
2636 retry:
2637 r = rb_io_read_memory(fptr, fptr->rbuf.ptr, fptr->rbuf.capa);
2638
2639 if (r < 0) {
2640 if (fptr_wait_readable(fptr))
2641 goto retry;
2642
2643 int e = errno;
2644 VALUE path = rb_sprintf("fd:%d ", fptr->fd);
2645 if (!NIL_P(fptr->pathv)) {
2646 rb_str_append(path, fptr->pathv);
2647 }
2648
2649 rb_syserr_fail_path(e, path);
2650 }
2651 if (r > 0) rb_io_check_closed(fptr);
2652 fptr->rbuf.off = 0;
2653 fptr->rbuf.len = (int)r; /* r should be <= rbuf_capa */
2654 if (r == 0)
2655 return -1; /* EOF */
2656 }
2657 return 0;
2658}
2659
2660/*
2661 * call-seq:
2662 * eof -> true or false
2663 *
2664 * Returns +true+ if the stream is positioned at its end, +false+ otherwise;
2665 * see {Position}[rdoc-ref:IO@Position]:
2666 *
2667 * f = File.open('t.txt')
2668 * f.eof # => false
2669 * f.seek(0, :END) # => 0
2670 * f.eof # => true
2671 * f.close
2672 *
2673 * Raises an exception unless the stream is opened for reading;
2674 * see {Mode}[rdoc-ref:File@Access+Modes].
2675 *
2676 * If +self+ is a stream such as pipe or socket, this method
2677 * blocks until the other end sends some data or closes it:
2678 *
2679 * r, w = IO.pipe
2680 * Thread.new { sleep 1; w.close }
2681 * r.eof? # => true # After 1-second wait.
2682 *
2683 * r, w = IO.pipe
2684 * Thread.new { sleep 1; w.puts "a" }
2685 * r.eof? # => false # After 1-second wait.
2686 *
2687 * r, w = IO.pipe
2688 * r.eof? # blocks forever
2689 *
2690 * Note that this method reads data to the input byte buffer. So
2691 * IO#sysread may not behave as you intend with IO#eof?, unless you
2692 * call IO#rewind first (which is not available for some streams).
2693 */
2694
2695VALUE
2697{
2698 rb_io_t *fptr;
2699
2700 GetOpenFile(io, fptr);
2702
2703 if (READ_CHAR_PENDING(fptr)) return Qfalse;
2704 if (READ_DATA_PENDING(fptr)) return Qfalse;
2705 READ_CHECK(fptr);
2706#if RUBY_CRLF_ENVIRONMENT
2707 if (!NEED_READCONV(fptr) && NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
2708 return RBOOL(eof(fptr->fd));
2709 }
2710#endif
2711 return RBOOL(io_fillbuf(fptr) < 0);
2712}
2713
2714/*
2715 * call-seq:
2716 * sync -> true or false
2717 *
2718 * Returns the current sync mode of the stream.
2719 * When sync mode is true, all output is immediately flushed to the underlying
2720 * operating system and is not buffered by Ruby internally. See also #fsync.
2721 *
2722 * f = File.open('t.tmp', 'w')
2723 * f.sync # => false
2724 * f.sync = true
2725 * f.sync # => true
2726 * f.close
2727 *
2728 */
2729
2730static VALUE
2731rb_io_sync(VALUE io)
2732{
2733 rb_io_t *fptr;
2734
2735 io = GetWriteIO(io);
2736 GetOpenFile(io, fptr);
2737 return RBOOL(fptr->mode & FMODE_SYNC);
2738}
2739
2740#ifdef HAVE_FSYNC
2741
2742/*
2743 * call-seq:
2744 * sync = boolean -> boolean
2745 *
2746 * Sets the _sync_ _mode_ for the stream to the given value;
2747 * returns the given value.
2748 *
2749 * Values for the sync mode:
2750 *
2751 * - +true+: All output is immediately flushed to the
2752 * underlying operating system and is not buffered internally.
2753 * - +false+: Output may be buffered internally.
2754 *
2755 * Example;
2756 *
2757 * f = File.open('t.tmp', 'w')
2758 * f.sync # => false
2759 * f.sync = true
2760 * f.sync # => true
2761 * f.close
2762 *
2763 * Related: IO#fsync.
2764 *
2765 */
2766
2767static VALUE
2768rb_io_set_sync(VALUE io, VALUE sync)
2769{
2770 rb_io_t *fptr;
2771
2772 io = GetWriteIO(io);
2773 GetOpenFile(io, fptr);
2774 if (RTEST(sync)) {
2775 fptr->mode |= FMODE_SYNC;
2776 }
2777 else {
2778 fptr->mode &= ~FMODE_SYNC;
2779 }
2780 return sync;
2781}
2782
2783/*
2784 * call-seq:
2785 * fsync -> 0
2786 *
2787 * Immediately writes to disk all data buffered in the stream,
2788 * via the operating system's <tt>fsync(2)</tt>.
2789
2790 * Note this difference:
2791 *
2792 * - IO#sync=: Ensures that data is flushed from the stream's internal buffers,
2793 * but does not guarantee that the operating system actually writes the data to disk.
2794 * - IO#fsync: Ensures both that data is flushed from internal buffers,
2795 * and that data is written to disk.
2796 *
2797 * Raises an exception if the operating system does not support <tt>fsync(2)</tt>.
2798 *
2799 */
2800
2801static VALUE
2802rb_io_fsync(VALUE io)
2803{
2804 rb_io_t *fptr;
2805
2806 io = GetWriteIO(io);
2807 GetOpenFile(io, fptr);
2808
2809 if (io_fflush(fptr) < 0)
2810 rb_sys_fail_on_write(fptr);
2811
2812 if ((int)rb_io_blocking_region(fptr, nogvl_fsync, fptr))
2813 rb_sys_fail_path(fptr->pathv);
2814
2815 return INT2FIX(0);
2816}
2817#else
2818# define rb_io_fsync rb_f_notimplement
2819# define rb_io_sync rb_f_notimplement
2820static VALUE
2821rb_io_set_sync(VALUE io, VALUE sync)
2822{
2825}
2826#endif
2827
2828#ifdef HAVE_FDATASYNC
2829static VALUE
2830nogvl_fdatasync(void *ptr)
2831{
2832 rb_io_t *fptr = ptr;
2833
2834#ifdef _WIN32
2835 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->fd)) != FILE_TYPE_DISK)
2836 return 0;
2837#endif
2838 return (VALUE)fdatasync(fptr->fd);
2839}
2840
2841/*
2842 * call-seq:
2843 * fdatasync -> 0
2844 *
2845 * Immediately writes to disk all data buffered in the stream,
2846 * via the operating system's: <tt>fdatasync(2)</tt>, if supported,
2847 * otherwise via <tt>fsync(2)</tt>, if supported;
2848 * otherwise raises an exception.
2849 *
2850 */
2851
2852static VALUE
2853rb_io_fdatasync(VALUE io)
2854{
2855 rb_io_t *fptr;
2856
2857 io = GetWriteIO(io);
2858 GetOpenFile(io, fptr);
2859
2860 if (io_fflush(fptr) < 0)
2861 rb_sys_fail_on_write(fptr);
2862
2863 if ((int)rb_io_blocking_region(fptr, nogvl_fdatasync, fptr) == 0)
2864 return INT2FIX(0);
2865
2866 /* fall back */
2867 return rb_io_fsync(io);
2868}
2869#else
2870#define rb_io_fdatasync rb_io_fsync
2871#endif
2872
2873/*
2874 * call-seq:
2875 * fileno -> integer
2876 *
2877 * Returns the integer file descriptor for the stream:
2878 *
2879 * $stdin.fileno # => 0
2880 * $stdout.fileno # => 1
2881 * $stderr.fileno # => 2
2882 * File.open('t.txt').fileno # => 10
2883 * f.close
2884 *
2885 */
2886
2887static VALUE
2888rb_io_fileno(VALUE io)
2889{
2890 rb_io_t *fptr = RFILE(io)->fptr;
2891 int fd;
2892
2893 rb_io_check_closed(fptr);
2894 fd = fptr->fd;
2895 return INT2FIX(fd);
2896}
2897
2898int
2900{
2901 if (RB_TYPE_P(io, T_FILE)) {
2902 rb_io_t *fptr = RFILE(io)->fptr;
2903 rb_io_check_closed(fptr);
2904 return fptr->fd;
2905 }
2906 else {
2907 VALUE fileno = rb_check_funcall(io, id_fileno, 0, NULL);
2908 if (!UNDEF_P(fileno)) {
2909 return RB_NUM2INT(fileno);
2910 }
2911 }
2912
2913 rb_raise(rb_eTypeError, "expected IO or #fileno, %"PRIsVALUE" given", rb_obj_class(io));
2914
2916}
2917
2918int
2919rb_io_mode(VALUE io)
2920{
2921 rb_io_t *fptr;
2922 GetOpenFile(io, fptr);
2923 return fptr->mode;
2924}
2925
2926/*
2927 * call-seq:
2928 * pid -> integer or nil
2929 *
2930 * Returns the process ID of a child process associated with the stream,
2931 * which will have been set by IO#popen, or +nil+ if the stream was not
2932 * created by IO#popen:
2933 *
2934 * pipe = IO.popen("-")
2935 * if pipe
2936 * $stderr.puts "In parent, child pid is #{pipe.pid}"
2937 * else
2938 * $stderr.puts "In child, pid is #{$$}"
2939 * end
2940 *
2941 * Output:
2942 *
2943 * In child, pid is 26209
2944 * In parent, child pid is 26209
2945 *
2946 */
2947
2948static VALUE
2949rb_io_pid(VALUE io)
2950{
2951 rb_io_t *fptr;
2952
2953 GetOpenFile(io, fptr);
2954 if (!fptr->pid)
2955 return Qnil;
2956 return PIDT2NUM(fptr->pid);
2957}
2958
2959/*
2960 * call-seq:
2961 * path -> string or nil
2962 *
2963 * Returns the path associated with the IO, or +nil+ if there is no path
2964 * associated with the IO. It is not guaranteed that the path exists on
2965 * the filesystem.
2966 *
2967 * $stdin.path # => "<STDIN>"
2968 *
2969 * File.open("testfile") {|f| f.path} # => "testfile"
2970 */
2971
2972VALUE
2974{
2975 rb_io_t *fptr = RFILE(io)->fptr;
2976
2977 if (!fptr)
2978 return Qnil;
2979
2980 return rb_obj_dup(fptr->pathv);
2981}
2982
2983/*
2984 * call-seq:
2985 * inspect -> string
2986 *
2987 * Returns a string representation of +self+:
2988 *
2989 * f = File.open('t.txt')
2990 * f.inspect # => "#<File:t.txt>"
2991 * f.close
2992 *
2993 */
2994
2995static VALUE
2996rb_io_inspect(VALUE obj)
2997{
2998 rb_io_t *fptr;
2999 VALUE result;
3000 static const char closed[] = " (closed)";
3001
3002 fptr = RFILE(obj)->fptr;
3003 if (!fptr) return rb_any_to_s(obj);
3004 result = rb_str_new_cstr("#<");
3005 rb_str_append(result, rb_class_name(CLASS_OF(obj)));
3006 rb_str_cat2(result, ":");
3007 if (NIL_P(fptr->pathv)) {
3008 if (fptr->fd < 0) {
3009 rb_str_cat(result, closed+1, strlen(closed)-1);
3010 }
3011 else {
3012 rb_str_catf(result, "fd %d", fptr->fd);
3013 }
3014 }
3015 else {
3016 rb_str_append(result, fptr->pathv);
3017 if (fptr->fd < 0) {
3018 rb_str_cat(result, closed, strlen(closed));
3019 }
3020 }
3021 return rb_str_cat2(result, ">");
3022}
3023
3024/*
3025 * call-seq:
3026 * to_io -> self
3027 *
3028 * Returns +self+.
3029 *
3030 */
3031
3032static VALUE
3033rb_io_to_io(VALUE io)
3034{
3035 return io;
3036}
3037
3038/* reading functions */
3039static long
3040read_buffered_data(char *ptr, long len, rb_io_t *fptr)
3041{
3042 int n;
3043
3044 n = READ_DATA_PENDING_COUNT(fptr);
3045 if (n <= 0) return 0;
3046 if (n > len) n = (int)len;
3047 MEMMOVE(ptr, fptr->rbuf.ptr+fptr->rbuf.off, char, n);
3048 fptr->rbuf.off += n;
3049 fptr->rbuf.len -= n;
3050 return n;
3051}
3052
3053static long
3054io_bufread(char *ptr, long len, rb_io_t *fptr)
3055{
3056 long offset = 0;
3057 long n = len;
3058 long c;
3059
3060 if (READ_DATA_PENDING(fptr) == 0) {
3061 while (n > 0) {
3062 again:
3063 rb_io_check_closed(fptr);
3064 c = rb_io_read_memory(fptr, ptr+offset, n);
3065 if (c == 0) break;
3066 if (c < 0) {
3067 if (fptr_wait_readable(fptr))
3068 goto again;
3069 return -1;
3070 }
3071 offset += c;
3072 if ((n -= c) <= 0) break;
3073 }
3074 return len - n;
3075 }
3076
3077 while (n > 0) {
3078 c = read_buffered_data(ptr+offset, n, fptr);
3079 if (c > 0) {
3080 offset += c;
3081 if ((n -= c) <= 0) break;
3082 }
3083 rb_io_check_closed(fptr);
3084 if (io_fillbuf(fptr) < 0) {
3085 break;
3086 }
3087 }
3088 return len - n;
3089}
3090
3091static int io_setstrbuf(VALUE *str, long len);
3092
3094 char *str_ptr;
3095 long len;
3096 rb_io_t *fptr;
3097};
3098
3099static VALUE
3100bufread_call(VALUE arg)
3101{
3102 struct bufread_arg *p = (struct bufread_arg *)arg;
3103 p->len = io_bufread(p->str_ptr, p->len, p->fptr);
3104 return Qundef;
3105}
3106
3107static long
3108io_fread(VALUE str, long offset, long size, rb_io_t *fptr)
3109{
3110 long len;
3111 struct bufread_arg arg;
3112
3113 io_setstrbuf(&str, offset + size);
3114 arg.str_ptr = RSTRING_PTR(str) + offset;
3115 arg.len = size;
3116 arg.fptr = fptr;
3117 rb_str_locktmp_ensure(str, bufread_call, (VALUE)&arg);
3118 len = arg.len;
3119 if (len < 0) rb_sys_fail_path(fptr->pathv);
3120 return len;
3121}
3122
3123static long
3124remain_size(rb_io_t *fptr)
3125{
3126 struct stat st;
3127 rb_off_t siz = READ_DATA_PENDING_COUNT(fptr);
3128 rb_off_t pos;
3129
3130 if (fstat(fptr->fd, &st) == 0 && S_ISREG(st.st_mode)
3131#if defined(__HAIKU__)
3132 && (st.st_dev > 3)
3133#endif
3134 )
3135 {
3136 if (io_fflush(fptr) < 0)
3137 rb_sys_fail_on_write(fptr);
3138 pos = lseek(fptr->fd, 0, SEEK_CUR);
3139 if (st.st_size >= pos && pos >= 0) {
3140 siz += st.st_size - pos;
3141 if (siz > LONG_MAX) {
3142 rb_raise(rb_eIOError, "file too big for single read");
3143 }
3144 }
3145 }
3146 else {
3147 siz += BUFSIZ;
3148 }
3149 return (long)siz;
3150}
3151
3152static VALUE
3153io_enc_str(VALUE str, rb_io_t *fptr)
3154{
3155 rb_enc_associate(str, io_read_encoding(fptr));
3156 return str;
3157}
3158
3159static rb_encoding *io_read_encoding(rb_io_t *fptr);
3160
3161static void
3162make_readconv(rb_io_t *fptr, int size)
3163{
3164 if (!fptr->readconv) {
3165 int ecflags;
3166 VALUE ecopts;
3167 const char *sname, *dname;
3168 ecflags = fptr->encs.ecflags & ~ECONV_NEWLINE_DECORATOR_WRITE_MASK;
3169 ecopts = fptr->encs.ecopts;
3170 if (fptr->encs.enc2) {
3171 sname = rb_enc_name(fptr->encs.enc2);
3172 dname = rb_enc_name(io_read_encoding(fptr));
3173 }
3174 else {
3175 sname = dname = "";
3176 }
3177 fptr->readconv = rb_econv_open_opts(sname, dname, ecflags, ecopts);
3178 if (!fptr->readconv)
3179 rb_exc_raise(rb_econv_open_exc(sname, dname, ecflags));
3180 fptr->cbuf.off = 0;
3181 fptr->cbuf.len = 0;
3182 if (size < IO_CBUF_CAPA_MIN) size = IO_CBUF_CAPA_MIN;
3183 fptr->cbuf.capa = size;
3184 fptr->cbuf.ptr = ALLOC_N(char, fptr->cbuf.capa);
3185 }
3186}
3187
3188#define MORE_CHAR_SUSPENDED Qtrue
3189#define MORE_CHAR_FINISHED Qnil
3190static VALUE
3191fill_cbuf(rb_io_t *fptr, int ec_flags)
3192{
3193 const unsigned char *ss, *sp, *se;
3194 unsigned char *ds, *dp, *de;
3196 int putbackable;
3197 int cbuf_len0;
3198 VALUE exc;
3199
3200 ec_flags |= ECONV_PARTIAL_INPUT;
3201
3202 if (fptr->cbuf.len == fptr->cbuf.capa)
3203 return MORE_CHAR_SUSPENDED; /* cbuf full */
3204 if (fptr->cbuf.len == 0)
3205 fptr->cbuf.off = 0;
3206 else if (fptr->cbuf.off + fptr->cbuf.len == fptr->cbuf.capa) {
3207 memmove(fptr->cbuf.ptr, fptr->cbuf.ptr+fptr->cbuf.off, fptr->cbuf.len);
3208 fptr->cbuf.off = 0;
3209 }
3210
3211 cbuf_len0 = fptr->cbuf.len;
3212
3213 while (1) {
3214 ss = sp = (const unsigned char *)fptr->rbuf.ptr + fptr->rbuf.off;
3215 se = sp + fptr->rbuf.len;
3216 ds = dp = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.off + fptr->cbuf.len;
3217 de = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.capa;
3218 res = rb_econv_convert(fptr->readconv, &sp, se, &dp, de, ec_flags);
3219 fptr->rbuf.off += (int)(sp - ss);
3220 fptr->rbuf.len -= (int)(sp - ss);
3221 fptr->cbuf.len += (int)(dp - ds);
3222
3223 putbackable = rb_econv_putbackable(fptr->readconv);
3224 if (putbackable) {
3225 rb_econv_putback(fptr->readconv, (unsigned char *)fptr->rbuf.ptr + fptr->rbuf.off - putbackable, putbackable);
3226 fptr->rbuf.off -= putbackable;
3227 fptr->rbuf.len += putbackable;
3228 }
3229
3230 exc = rb_econv_make_exception(fptr->readconv);
3231 if (!NIL_P(exc))
3232 return exc;
3233
3234 if (cbuf_len0 != fptr->cbuf.len)
3235 return MORE_CHAR_SUSPENDED;
3236
3237 if (res == econv_finished) {
3238 return MORE_CHAR_FINISHED;
3239 }
3240
3241 if (res == econv_source_buffer_empty) {
3242 if (fptr->rbuf.len == 0) {
3243 READ_CHECK(fptr);
3244 if (io_fillbuf(fptr) < 0) {
3245 if (!fptr->readconv) {
3246 return MORE_CHAR_FINISHED;
3247 }
3248 ds = dp = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.off + fptr->cbuf.len;
3249 de = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.capa;
3250 res = rb_econv_convert(fptr->readconv, NULL, NULL, &dp, de, 0);
3251 fptr->cbuf.len += (int)(dp - ds);
3253 break;
3254 }
3255 }
3256 }
3257 }
3258 if (cbuf_len0 != fptr->cbuf.len)
3259 return MORE_CHAR_SUSPENDED;
3260
3261 return MORE_CHAR_FINISHED;
3262}
3263
3264static VALUE
3265more_char(rb_io_t *fptr)
3266{
3267 VALUE v;
3268 v = fill_cbuf(fptr, ECONV_AFTER_OUTPUT);
3269 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED)
3270 rb_exc_raise(v);
3271 return v;
3272}
3273
3274static VALUE
3275io_shift_cbuf(rb_io_t *fptr, int len, VALUE *strp)
3276{
3277 VALUE str = Qnil;
3278 if (strp) {
3279 str = *strp;
3280 if (NIL_P(str)) {
3281 *strp = str = rb_str_new(fptr->cbuf.ptr+fptr->cbuf.off, len);
3282 }
3283 else {
3284 rb_str_cat(str, fptr->cbuf.ptr+fptr->cbuf.off, len);
3285 }
3286 rb_enc_associate(str, fptr->encs.enc);
3287 }
3288 fptr->cbuf.off += len;
3289 fptr->cbuf.len -= len;
3290 /* xxx: set coderange */
3291 if (fptr->cbuf.len == 0)
3292 fptr->cbuf.off = 0;
3293 else if (fptr->cbuf.capa/2 < fptr->cbuf.off) {
3294 memmove(fptr->cbuf.ptr, fptr->cbuf.ptr+fptr->cbuf.off, fptr->cbuf.len);
3295 fptr->cbuf.off = 0;
3296 }
3297 return str;
3298}
3299
3300static int
3301io_setstrbuf(VALUE *str, long len)
3302{
3303#ifdef _WIN32
3304 if (len > 0)
3305 len = (len + 1) & ~1L; /* round up for wide char */
3306#endif
3307 if (NIL_P(*str)) {
3308 *str = rb_str_new(0, len);
3309 return TRUE;
3310 }
3311 else {
3312 VALUE s = StringValue(*str);
3313 rb_str_modify(s);
3314
3315 long clen = RSTRING_LEN(s);
3316 if (clen >= len) {
3317 return FALSE;
3318 }
3319 len -= clen;
3320 }
3321 if ((rb_str_capacity(*str) - (size_t)RSTRING_LEN(*str)) < (size_t)len) {
3323 }
3324 return FALSE;
3325}
3326
3327#define MAX_REALLOC_GAP 4096
3328static void
3329io_shrink_read_string(VALUE str, long n)
3330{
3331 if (rb_str_capacity(str) - n > MAX_REALLOC_GAP) {
3332 rb_str_resize(str, n);
3333 }
3334}
3335
3336static void
3337io_set_read_length(VALUE str, long n, int shrinkable)
3338{
3339 if (RSTRING_LEN(str) != n) {
3340 rb_str_modify(str);
3341 rb_str_set_len(str, n);
3342 if (shrinkable) io_shrink_read_string(str, n);
3343 }
3344}
3345
3346static VALUE
3347read_all(rb_io_t *fptr, long siz, VALUE str)
3348{
3349 long bytes;
3350 long n;
3351 long pos;
3352 rb_encoding *enc;
3353 int cr;
3354 int shrinkable;
3355
3356 if (NEED_READCONV(fptr)) {
3357 int first = !NIL_P(str);
3358 SET_BINARY_MODE(fptr);
3359 shrinkable = io_setstrbuf(&str,0);
3360 make_readconv(fptr, 0);
3361 while (1) {
3362 VALUE v;
3363 if (fptr->cbuf.len) {
3364 if (first) rb_str_set_len(str, first = 0);
3365 io_shift_cbuf(fptr, fptr->cbuf.len, &str);
3366 }
3367 v = fill_cbuf(fptr, 0);
3368 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED) {
3369 if (fptr->cbuf.len) {
3370 if (first) rb_str_set_len(str, first = 0);
3371 io_shift_cbuf(fptr, fptr->cbuf.len, &str);
3372 }
3373 rb_exc_raise(v);
3374 }
3375 if (v == MORE_CHAR_FINISHED) {
3376 clear_readconv(fptr);
3377 if (first) rb_str_set_len(str, first = 0);
3378 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3379 return io_enc_str(str, fptr);
3380 }
3381 }
3382 }
3383
3384 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3385 bytes = 0;
3386 pos = 0;
3387
3388 enc = io_read_encoding(fptr);
3389 cr = 0;
3390
3391 if (siz == 0) siz = BUFSIZ;
3392 shrinkable = io_setstrbuf(&str, siz);
3393 for (;;) {
3394 READ_CHECK(fptr);
3395 n = io_fread(str, bytes, siz - bytes, fptr);
3396 if (n == 0 && bytes == 0) {
3397 rb_str_set_len(str, 0);
3398 break;
3399 }
3400 bytes += n;
3401 rb_str_set_len(str, bytes);
3402 if (cr != ENC_CODERANGE_BROKEN)
3403 pos += rb_str_coderange_scan_restartable(RSTRING_PTR(str) + pos, RSTRING_PTR(str) + bytes, enc, &cr);
3404 if (bytes < siz) break;
3405 siz += BUFSIZ;
3406
3407 size_t capa = rb_str_capacity(str);
3408 if (capa < (size_t)RSTRING_LEN(str) + BUFSIZ) {
3409 if (capa < BUFSIZ) {
3410 capa = BUFSIZ;
3411 }
3412 else if (capa > IO_MAX_BUFFER_GROWTH) {
3413 capa = IO_MAX_BUFFER_GROWTH;
3414 }
3416 }
3417 }
3418 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3419 str = io_enc_str(str, fptr);
3420 ENC_CODERANGE_SET(str, cr);
3421 return str;
3422}
3423
3424void
3426{
3427 if (rb_fd_set_nonblock(fptr->fd) != 0) {
3428 rb_sys_fail_path(fptr->pathv);
3429 }
3430}
3431
3432static VALUE
3433io_read_memory_call(VALUE arg)
3434{
3435 struct io_internal_read_struct *iis = (struct io_internal_read_struct *)arg;
3436
3437 VALUE scheduler = rb_fiber_scheduler_current();
3438 if (scheduler != Qnil) {
3439 VALUE result = rb_fiber_scheduler_io_read_memory(scheduler, iis->fptr->self, iis->buf, iis->capa, 0);
3440
3441 if (!UNDEF_P(result)) {
3442 // This is actually returned as a pseudo-VALUE and later cast to a long:
3444 }
3445 }
3446
3447 if (iis->nonblock) {
3448 return rb_io_blocking_region(iis->fptr, internal_read_func, iis);
3449 }
3450 else {
3451 return rb_io_blocking_region_wait(iis->fptr, internal_read_func, iis, RUBY_IO_READABLE);
3452 }
3453}
3454
3455static long
3456io_read_memory_locktmp(VALUE str, struct io_internal_read_struct *iis)
3457{
3458 return (long)rb_str_locktmp_ensure(str, io_read_memory_call, (VALUE)iis);
3459}
3460
3461#define no_exception_p(opts) !rb_opts_exception_p((opts), TRUE)
3462
3463static VALUE
3464io_getpartial(int argc, VALUE *argv, VALUE io, int no_exception, int nonblock)
3465{
3466 rb_io_t *fptr;
3467 VALUE length, str;
3468 long n, len;
3469 struct io_internal_read_struct iis;
3470 int shrinkable;
3471
3472 rb_scan_args(argc, argv, "11", &length, &str);
3473
3474 if ((len = NUM2LONG(length)) < 0) {
3475 rb_raise(rb_eArgError, "negative length %ld given", len);
3476 }
3477
3478 shrinkable = io_setstrbuf(&str, len);
3479
3480 GetOpenFile(io, fptr);
3482
3483 if (len == 0) {
3484 io_set_read_length(str, 0, shrinkable);
3485 return str;
3486 }
3487
3488 if (!nonblock)
3489 READ_CHECK(fptr);
3490 n = read_buffered_data(RSTRING_PTR(str), len, fptr);
3491 if (n <= 0) {
3492 again:
3493 if (nonblock) {
3494 rb_io_set_nonblock(fptr);
3495 }
3496 io_setstrbuf(&str, len);
3497 iis.th = rb_thread_current();
3498 iis.fptr = fptr;
3499 iis.nonblock = nonblock;
3500 iis.fd = fptr->fd;
3501 iis.buf = RSTRING_PTR(str);
3502 iis.capa = len;
3503 iis.timeout = NULL;
3504 n = io_read_memory_locktmp(str, &iis);
3505 if (n < 0) {
3506 int e = errno;
3507 if (!nonblock && fptr_wait_readable(fptr))
3508 goto again;
3509 if (nonblock && (io_again_p(e))) {
3510 if (no_exception)
3511 return sym_wait_readable;
3512 else
3513 rb_readwrite_syserr_fail(RB_IO_WAIT_READABLE,
3514 e, "read would block");
3515 }
3516 rb_syserr_fail_path(e, fptr->pathv);
3517 }
3518 }
3519 io_set_read_length(str, n, shrinkable);
3520
3521 if (n == 0)
3522 return Qnil;
3523 else
3524 return str;
3525}
3526
3527/*
3528 * call-seq:
3529 * readpartial(maxlen) -> string
3530 * readpartial(maxlen, out_string) -> out_string
3531 *
3532 * Reads up to +maxlen+ bytes from the stream;
3533 * returns a string (either a new string or the given +out_string+).
3534 * Its encoding is:
3535 *
3536 * - The unchanged encoding of +out_string+, if +out_string+ is given.
3537 * - ASCII-8BIT, otherwise.
3538 *
3539 * - Contains +maxlen+ bytes from the stream, if available.
3540 * - Otherwise contains all available bytes, if any available.
3541 * - Otherwise is an empty string.
3542 *
3543 * With the single non-negative integer argument +maxlen+ given,
3544 * returns a new string:
3545 *
3546 * f = File.new('t.txt')
3547 * f.readpartial(20) # => "First line\nSecond l"
3548 * f.readpartial(20) # => "ine\n\nFourth line\n"
3549 * f.readpartial(20) # => "Fifth line\n"
3550 * f.readpartial(20) # Raises EOFError.
3551 * f.close
3552 *
3553 * With both argument +maxlen+ and string argument +out_string+ given,
3554 * returns modified +out_string+:
3555 *
3556 * f = File.new('t.txt')
3557 * s = 'foo'
3558 * f.readpartial(20, s) # => "First line\nSecond l"
3559 * s = 'bar'
3560 * f.readpartial(0, s) # => ""
3561 * f.close
3562 *
3563 * This method is useful for a stream such as a pipe, a socket, or a tty.
3564 * It blocks only when no data is immediately available.
3565 * This means that it blocks only when _all_ of the following are true:
3566 *
3567 * - The byte buffer in the stream is empty.
3568 * - The content of the stream is empty.
3569 * - The stream is not at EOF.
3570 *
3571 * When blocked, the method waits for either more data or EOF on the stream:
3572 *
3573 * - If more data is read, the method returns the data.
3574 * - If EOF is reached, the method raises EOFError.
3575 *
3576 * When not blocked, the method responds immediately:
3577 *
3578 * - Returns data from the buffer if there is any.
3579 * - Otherwise returns data from the stream if there is any.
3580 * - Otherwise raises EOFError if the stream has reached EOF.
3581 *
3582 * Note that this method is similar to sysread. The differences are:
3583 *
3584 * - If the byte buffer is not empty, read from the byte buffer
3585 * instead of "sysread for buffered IO (IOError)".
3586 * - It doesn't cause Errno::EWOULDBLOCK and Errno::EINTR. When
3587 * readpartial meets EWOULDBLOCK and EINTR by read system call,
3588 * readpartial retries the system call.
3589 *
3590 * The latter means that readpartial is non-blocking-flag insensitive.
3591 * It blocks on the situation IO#sysread causes Errno::EWOULDBLOCK as
3592 * if the fd is blocking mode.
3593 *
3594 * Examples:
3595 *
3596 * # # Returned Buffer Content Pipe Content
3597 * r, w = IO.pipe #
3598 * w << 'abc' # "" "abc".
3599 * r.readpartial(4096) # => "abc" "" ""
3600 * r.readpartial(4096) # (Blocks because buffer and pipe are empty.)
3601 *
3602 * # # Returned Buffer Content Pipe Content
3603 * r, w = IO.pipe #
3604 * w << 'abc' # "" "abc"
3605 * w.close # "" "abc" EOF
3606 * r.readpartial(4096) # => "abc" "" EOF
3607 * r.readpartial(4096) # raises EOFError
3608 *
3609 * # # Returned Buffer Content Pipe Content
3610 * r, w = IO.pipe #
3611 * w << "abc\ndef\n" # "" "abc\ndef\n"
3612 * r.gets # => "abc\n" "def\n" ""
3613 * w << "ghi\n" # "def\n" "ghi\n"
3614 * r.readpartial(4096) # => "def\n" "" "ghi\n"
3615 * r.readpartial(4096) # => "ghi\n" "" ""
3616 *
3617 */
3618
3619static VALUE
3620io_readpartial(int argc, VALUE *argv, VALUE io)
3621{
3622 VALUE ret;
3623
3624 ret = io_getpartial(argc, argv, io, Qnil, 0);
3625 if (NIL_P(ret))
3626 rb_eof_error();
3627 return ret;
3628}
3629
3630static VALUE
3631io_nonblock_eof(int no_exception)
3632{
3633 if (!no_exception) {
3634 rb_eof_error();
3635 }
3636 return Qnil;
3637}
3638
3639/* :nodoc: */
3640static VALUE
3641io_read_nonblock(rb_execution_context_t *ec, VALUE io, VALUE length, VALUE str, VALUE ex)
3642{
3643 rb_io_t *fptr;
3644 long n, len;
3645 struct io_internal_read_struct iis;
3646 int shrinkable;
3647
3648 if ((len = NUM2LONG(length)) < 0) {
3649 rb_raise(rb_eArgError, "negative length %ld given", len);
3650 }
3651
3652 shrinkable = io_setstrbuf(&str, len);
3653 rb_bool_expected(ex, "exception", TRUE);
3654
3655 GetOpenFile(io, fptr);
3657
3658 if (len == 0) {
3659 io_set_read_length(str, 0, shrinkable);
3660 return str;
3661 }
3662
3663 n = read_buffered_data(RSTRING_PTR(str), len, fptr);
3664 if (n <= 0) {
3665 rb_fd_set_nonblock(fptr->fd);
3666 shrinkable |= io_setstrbuf(&str, len);
3667 iis.fptr = fptr;
3668 iis.nonblock = 1;
3669 iis.fd = fptr->fd;
3670 iis.buf = RSTRING_PTR(str);
3671 iis.capa = len;
3672 iis.timeout = NULL;
3673 n = io_read_memory_locktmp(str, &iis);
3674 if (n < 0) {
3675 int e = errno;
3676 if (io_again_p(e)) {
3677 if (!ex) return sym_wait_readable;
3678 rb_readwrite_syserr_fail(RB_IO_WAIT_READABLE,
3679 e, "read would block");
3680 }
3681 rb_syserr_fail_path(e, fptr->pathv);
3682 }
3683 }
3684 io_set_read_length(str, n, shrinkable);
3685
3686 if (n == 0) {
3687 if (!ex) return Qnil;
3688 rb_eof_error();
3689 }
3690
3691 return str;
3692}
3693
3694/* :nodoc: */
3695static VALUE
3696io_write_nonblock(rb_execution_context_t *ec, VALUE io, VALUE str, VALUE ex)
3697{
3698 rb_io_t *fptr;
3699 long n;
3700
3701 if (!RB_TYPE_P(str, T_STRING))
3702 str = rb_obj_as_string(str);
3703 rb_bool_expected(ex, "exception", TRUE);
3704
3705 io = GetWriteIO(io);
3706 GetOpenFile(io, fptr);
3708
3709 if (io_fflush(fptr) < 0)
3710 rb_sys_fail_on_write(fptr);
3711
3712 rb_fd_set_nonblock(fptr->fd);
3713 n = write(fptr->fd, RSTRING_PTR(str), RSTRING_LEN(str));
3714 RB_GC_GUARD(str);
3715
3716 if (n < 0) {
3717 int e = errno;
3718 if (io_again_p(e)) {
3719 if (!ex) {
3720 return sym_wait_writable;
3721 }
3722 else {
3723 rb_readwrite_syserr_fail(RB_IO_WAIT_WRITABLE, e, "write would block");
3724 }
3725 }
3726 rb_syserr_fail_path(e, fptr->pathv);
3727 }
3728
3729 return LONG2FIX(n);
3730}
3731
3732/*
3733 * call-seq:
3734 * read(maxlen = nil, out_string = nil) -> new_string, out_string, or nil
3735 *
3736 * Reads bytes from the stream; the stream must be opened for reading
3737 * (see {Access Modes}[rdoc-ref:File@Access+Modes]):
3738 *
3739 * - If +maxlen+ is +nil+, reads all bytes using the stream's data mode.
3740 * - Otherwise reads up to +maxlen+ bytes in binary mode.
3741 *
3742 * Returns a string (either a new string or the given +out_string+)
3743 * containing the bytes read.
3744 * The encoding of the string depends on both +maxLen+ and +out_string+:
3745 *
3746 * - +maxlen+ is +nil+: uses internal encoding of +self+
3747 * (regardless of whether +out_string+ was given).
3748 * - +maxlen+ not +nil+:
3749 *
3750 * - +out_string+ given: encoding of +out_string+ not modified.
3751 * - +out_string+ not given: ASCII-8BIT is used.
3752 *
3753 * <b>Without Argument +out_string+</b>
3754 *
3755 * When argument +out_string+ is omitted,
3756 * the returned value is a new string:
3757 *
3758 * f = File.new('t.txt')
3759 * f.read
3760 * # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3761 * f.rewind
3762 * f.read(30) # => "First line\r\nSecond line\r\n\r\nFou"
3763 * f.read(30) # => "rth line\r\nFifth line\r\n"
3764 * f.read(30) # => nil
3765 * f.close
3766 *
3767 * If +maxlen+ is zero, returns an empty string.
3768 *
3769 * <b> With Argument +out_string+</b>
3770 *
3771 * When argument +out_string+ is given,
3772 * the returned value is +out_string+, whose content is replaced:
3773 *
3774 * f = File.new('t.txt')
3775 * s = 'foo' # => "foo"
3776 * f.read(nil, s) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3777 * s # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3778 * f.rewind
3779 * s = 'bar'
3780 * f.read(30, s) # => "First line\r\nSecond line\r\n\r\nFou"
3781 * s # => "First line\r\nSecond line\r\n\r\nFou"
3782 * s = 'baz'
3783 * f.read(30, s) # => "rth line\r\nFifth line\r\n"
3784 * s # => "rth line\r\nFifth line\r\n"
3785 * s = 'bat'
3786 * f.read(30, s) # => nil
3787 * s # => ""
3788 * f.close
3789 *
3790 * Note that this method behaves like the fread() function in C.
3791 * This means it retries to invoke read(2) system calls to read data
3792 * with the specified maxlen (or until EOF).
3793 *
3794 * This behavior is preserved even if the stream is in non-blocking mode.
3795 * (This method is non-blocking-flag insensitive as other methods.)
3796 *
3797 * If you need the behavior like a single read(2) system call,
3798 * consider #readpartial, #read_nonblock, and #sysread.
3799 *
3800 * Related: IO#write.
3801 */
3802
3803static VALUE
3804io_read(int argc, VALUE *argv, VALUE io)
3805{
3806 rb_io_t *fptr;
3807 long n, len;
3808 VALUE length, str;
3809 int shrinkable;
3810#if RUBY_CRLF_ENVIRONMENT
3811 int previous_mode;
3812#endif
3813
3814 rb_scan_args(argc, argv, "02", &length, &str);
3815
3816 if (NIL_P(length)) {
3817 GetOpenFile(io, fptr);
3819 return read_all(fptr, remain_size(fptr), str);
3820 }
3821 len = NUM2LONG(length);
3822 if (len < 0) {
3823 rb_raise(rb_eArgError, "negative length %ld given", len);
3824 }
3825
3826 shrinkable = io_setstrbuf(&str,len);
3827
3828 GetOpenFile(io, fptr);
3830 if (len == 0) {
3831 io_set_read_length(str, 0, shrinkable);
3832 return str;
3833 }
3834
3835 READ_CHECK(fptr);
3836#if RUBY_CRLF_ENVIRONMENT
3837 previous_mode = set_binary_mode_with_seek_cur(fptr);
3838#endif
3839 n = io_fread(str, 0, len, fptr);
3840 io_set_read_length(str, n, shrinkable);
3841#if RUBY_CRLF_ENVIRONMENT
3842 if (previous_mode == O_TEXT) {
3843 setmode(fptr->fd, O_TEXT);
3844 }
3845#endif
3846 if (n == 0) return Qnil;
3847
3848 return str;
3849}
3850
3851static void
3852rscheck(const char *rsptr, long rslen, VALUE rs)
3853{
3854 if (!rs) return;
3855 if (RSTRING_PTR(rs) != rsptr && RSTRING_LEN(rs) != rslen)
3856 rb_raise(rb_eRuntimeError, "rs modified");
3857}
3858
3859static const char *
3860search_delim(const char *p, long len, int delim, rb_encoding *enc)
3861{
3862 if (rb_enc_mbminlen(enc) == 1) {
3863 p = memchr(p, delim, len);
3864 if (p) return p + 1;
3865 }
3866 else {
3867 const char *end = p + len;
3868 while (p < end) {
3869 int r = rb_enc_precise_mbclen(p, end, enc);
3870 if (!MBCLEN_CHARFOUND_P(r)) {
3871 p += rb_enc_mbminlen(enc);
3872 continue;
3873 }
3874 int n = MBCLEN_CHARFOUND_LEN(r);
3875 if (rb_enc_mbc_to_codepoint(p, end, enc) == (unsigned int)delim) {
3876 return p + n;
3877 }
3878 p += n;
3879 }
3880 }
3881 return NULL;
3882}
3883
3884static int
3885appendline(rb_io_t *fptr, int delim, VALUE *strp, long *lp, rb_encoding *enc)
3886{
3887 VALUE str = *strp;
3888 long limit = *lp;
3889
3890 if (NEED_READCONV(fptr)) {
3891 SET_BINARY_MODE(fptr);
3892 make_readconv(fptr, 0);
3893 do {
3894 const char *p, *e;
3895 int searchlen = READ_CHAR_PENDING_COUNT(fptr);
3896 if (searchlen) {
3897 p = READ_CHAR_PENDING_PTR(fptr);
3898 if (0 < limit && limit < searchlen)
3899 searchlen = (int)limit;
3900 e = search_delim(p, searchlen, delim, enc);
3901 if (e) {
3902 int len = (int)(e-p);
3903 if (NIL_P(str))
3904 *strp = str = rb_str_new(p, len);
3905 else
3906 rb_str_buf_cat(str, p, len);
3907 fptr->cbuf.off += len;
3908 fptr->cbuf.len -= len;
3909 limit -= len;
3910 *lp = limit;
3911 return delim;
3912 }
3913
3914 if (NIL_P(str))
3915 *strp = str = rb_str_new(p, searchlen);
3916 else
3917 rb_str_buf_cat(str, p, searchlen);
3918 fptr->cbuf.off += searchlen;
3919 fptr->cbuf.len -= searchlen;
3920 limit -= searchlen;
3921
3922 if (limit == 0) {
3923 *lp = limit;
3924 return (unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
3925 }
3926 }
3927 } while (more_char(fptr) != MORE_CHAR_FINISHED);
3928 clear_readconv(fptr);
3929 *lp = limit;
3930 return EOF;
3931 }
3932
3933 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3934 do {
3935 long pending = READ_DATA_PENDING_COUNT(fptr);
3936 if (pending > 0) {
3937 const char *p = READ_DATA_PENDING_PTR(fptr);
3938 const char *e;
3939 long last;
3940
3941 if (limit > 0 && pending > limit) pending = limit;
3942 e = search_delim(p, pending, delim, enc);
3943 if (e) pending = e - p;
3944 if (!NIL_P(str)) {
3945 last = RSTRING_LEN(str);
3946 rb_str_resize(str, last + pending);
3947 }
3948 else {
3949 last = 0;
3950 *strp = str = rb_str_buf_new(pending);
3951 rb_str_set_len(str, pending);
3952 }
3953 read_buffered_data(RSTRING_PTR(str) + last, pending, fptr); /* must not fail */
3954 limit -= pending;
3955 *lp = limit;
3956 if (e) return delim;
3957 if (limit == 0)
3958 return (unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
3959 }
3960 READ_CHECK(fptr);
3961 } while (io_fillbuf(fptr) >= 0);
3962 *lp = limit;
3963 return EOF;
3964}
3965
3966static inline int
3967swallow(rb_io_t *fptr, int term)
3968{
3969 if (NEED_READCONV(fptr)) {
3970 rb_encoding *enc = io_read_encoding(fptr);
3971 int needconv = rb_enc_mbminlen(enc) != 1;
3972 SET_BINARY_MODE(fptr);
3973 make_readconv(fptr, 0);
3974 do {
3975 size_t cnt;
3976 while ((cnt = READ_CHAR_PENDING_COUNT(fptr)) > 0) {
3977 const char *p = READ_CHAR_PENDING_PTR(fptr);
3978 int i;
3979 if (!needconv) {
3980 if (*p != term) return TRUE;
3981 i = (int)cnt;
3982 while (--i && *++p == term);
3983 }
3984 else {
3985 const char *e = p + cnt;
3986 if (rb_enc_ascget(p, e, &i, enc) != term) return TRUE;
3987 while ((p += i) < e && rb_enc_ascget(p, e, &i, enc) == term);
3988 i = (int)(e - p);
3989 }
3990 io_shift_cbuf(fptr, (int)cnt - i, NULL);
3991 }
3992 } while (more_char(fptr) != MORE_CHAR_FINISHED);
3993 return FALSE;
3994 }
3995
3996 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3997 do {
3998 size_t cnt;
3999 while ((cnt = READ_DATA_PENDING_COUNT(fptr)) > 0) {
4000 char buf[1024];
4001 const char *p = READ_DATA_PENDING_PTR(fptr);
4002 int i;
4003 if (cnt > sizeof buf) cnt = sizeof buf;
4004 if (*p != term) return TRUE;
4005 i = (int)cnt;
4006 while (--i && *++p == term);
4007 if (!read_buffered_data(buf, cnt - i, fptr)) /* must not fail */
4008 rb_sys_fail_path(fptr->pathv);
4009 }
4010 READ_CHECK(fptr);
4011 } while (io_fillbuf(fptr) == 0);
4012 return FALSE;
4013}
4014
4015static VALUE
4016rb_io_getline_fast(rb_io_t *fptr, rb_encoding *enc, int chomp)
4017{
4018 VALUE str = Qnil;
4019 int len = 0;
4020 long pos = 0;
4021 int cr = 0;
4022
4023 do {
4024 int pending = READ_DATA_PENDING_COUNT(fptr);
4025
4026 if (pending > 0) {
4027 const char *p = READ_DATA_PENDING_PTR(fptr);
4028 const char *e;
4029 int chomplen = 0;
4030
4031 e = memchr(p, '\n', pending);
4032 if (e) {
4033 pending = (int)(e - p + 1);
4034 if (chomp) {
4035 chomplen = (pending > 1 && *(e-1) == '\r') + 1;
4036 }
4037 }
4038 if (NIL_P(str)) {
4039 str = rb_str_new(p, pending - chomplen);
4040 fptr->rbuf.off += pending;
4041 fptr->rbuf.len -= pending;
4042 }
4043 else {
4044 rb_str_resize(str, len + pending - chomplen);
4045 read_buffered_data(RSTRING_PTR(str)+len, pending - chomplen, fptr);
4046 fptr->rbuf.off += chomplen;
4047 fptr->rbuf.len -= chomplen;
4048 if (pending == 1 && chomplen == 1 && len > 0) {
4049 if (RSTRING_PTR(str)[len-1] == '\r') {
4050 rb_str_resize(str, --len);
4051 break;
4052 }
4053 }
4054 }
4055 len += pending - chomplen;
4056 if (cr != ENC_CODERANGE_BROKEN)
4057 pos += rb_str_coderange_scan_restartable(RSTRING_PTR(str) + pos, RSTRING_PTR(str) + len, enc, &cr);
4058 if (e) break;
4059 }
4060 READ_CHECK(fptr);
4061 } while (io_fillbuf(fptr) >= 0);
4062 if (NIL_P(str)) return Qnil;
4063
4064 str = io_enc_str(str, fptr);
4065 ENC_CODERANGE_SET(str, cr);
4066 fptr->lineno++;
4067
4068 return str;
4069}
4070
4072 VALUE io;
4073 VALUE rs;
4074 long limit;
4075 unsigned int chomp: 1;
4076};
4077
4078static void
4079extract_getline_opts(VALUE opts, struct getline_arg *args)
4080{
4081 int chomp = FALSE;
4082 if (!NIL_P(opts)) {
4083 static ID kwds[1];
4084 VALUE vchomp;
4085 if (!kwds[0]) {
4086 kwds[0] = rb_intern_const("chomp");
4087 }
4088 rb_get_kwargs(opts, kwds, 0, -2, &vchomp);
4089 chomp = (!UNDEF_P(vchomp)) && RTEST(vchomp);
4090 }
4091 args->chomp = chomp;
4092}
4093
4094static void
4095extract_getline_args(int argc, VALUE *argv, struct getline_arg *args)
4096{
4097 VALUE rs = rb_rs, lim = Qnil;
4098
4099 if (argc == 1) {
4100 VALUE tmp = Qnil;
4101
4102 if (NIL_P(argv[0]) || !NIL_P(tmp = rb_check_string_type(argv[0]))) {
4103 rs = tmp;
4104 }
4105 else {
4106 lim = argv[0];
4107 }
4108 }
4109 else if (2 <= argc) {
4110 rs = argv[0], lim = argv[1];
4111 if (!NIL_P(rs))
4112 StringValue(rs);
4113 }
4114 args->rs = rs;
4115 args->limit = NIL_P(lim) ? -1L : NUM2LONG(lim);
4116}
4117
4118static void
4119check_getline_args(VALUE *rsp, long *limit, VALUE io)
4120{
4121 rb_io_t *fptr;
4122 VALUE rs = *rsp;
4123
4124 if (!NIL_P(rs)) {
4125 rb_encoding *enc_rs, *enc_io;
4126
4127 GetOpenFile(io, fptr);
4128 enc_rs = rb_enc_get(rs);
4129 enc_io = io_read_encoding(fptr);
4130 if (enc_io != enc_rs &&
4131 (!is_ascii_string(rs) ||
4132 (RSTRING_LEN(rs) > 0 && !rb_enc_asciicompat(enc_io)))) {
4133 if (rs == rb_default_rs) {
4134 rs = rb_enc_str_new(0, 0, enc_io);
4135 rb_str_buf_cat_ascii(rs, "\n");
4136 *rsp = rs;
4137 }
4138 else {
4139 rb_raise(rb_eArgError, "encoding mismatch: %s IO with %s RS",
4140 rb_enc_name(enc_io),
4141 rb_enc_name(enc_rs));
4142 }
4143 }
4144 }
4145}
4146
4147static void
4148prepare_getline_args(int argc, VALUE *argv, struct getline_arg *args, VALUE io)
4149{
4150 VALUE opts;
4151 argc = rb_scan_args(argc, argv, "02:", NULL, NULL, &opts);
4152 extract_getline_args(argc, argv, args);
4153 extract_getline_opts(opts, args);
4154 check_getline_args(&args->rs, &args->limit, io);
4155}
4156
4157static VALUE
4158rb_io_getline_0(VALUE rs, long limit, int chomp, rb_io_t *fptr)
4159{
4160 VALUE str = Qnil;
4161 int nolimit = 0;
4162 rb_encoding *enc;
4163
4165 if (NIL_P(rs) && limit < 0) {
4166 str = read_all(fptr, 0, Qnil);
4167 if (RSTRING_LEN(str) == 0) return Qnil;
4168 }
4169 else if (limit == 0) {
4170 return rb_enc_str_new(0, 0, io_read_encoding(fptr));
4171 }
4172 else if (rs == rb_default_rs && limit < 0 && !NEED_READCONV(fptr) &&
4173 rb_enc_asciicompat(enc = io_read_encoding(fptr))) {
4174 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4175 return rb_io_getline_fast(fptr, enc, chomp);
4176 }
4177 else {
4178 int c, newline = -1;
4179 const char *rsptr = 0;
4180 long rslen = 0;
4181 int rspara = 0;
4182 int extra_limit = 16;
4183 int chomp_cr = chomp;
4184
4185 SET_BINARY_MODE(fptr);
4186 enc = io_read_encoding(fptr);
4187
4188 if (!NIL_P(rs)) {
4189 rslen = RSTRING_LEN(rs);
4190 if (rslen == 0) {
4191 rsptr = "\n\n";
4192 rslen = 2;
4193 rspara = 1;
4194 swallow(fptr, '\n');
4195 rs = 0;
4196 if (!rb_enc_asciicompat(enc)) {
4197 rs = rb_usascii_str_new(rsptr, rslen);
4198 rs = rb_str_conv_enc(rs, 0, enc);
4199 OBJ_FREEZE(rs);
4200 rsptr = RSTRING_PTR(rs);
4201 rslen = RSTRING_LEN(rs);
4202 }
4203 newline = '\n';
4204 }
4205 else if (rb_enc_mbminlen(enc) == 1) {
4206 rsptr = RSTRING_PTR(rs);
4207 newline = (unsigned char)rsptr[rslen - 1];
4208 }
4209 else {
4210 rs = rb_str_conv_enc(rs, 0, enc);
4211 rsptr = RSTRING_PTR(rs);
4212 const char *e = rsptr + rslen;
4213 const char *last = rb_enc_prev_char(rsptr, e, e, enc);
4214 int n;
4215 newline = rb_enc_codepoint_len(last, e, &n, enc);
4216 if (last + n != e) rb_raise(rb_eArgError, "broken separator");
4217 }
4218 chomp_cr = chomp && newline == '\n' && rslen == rb_enc_mbminlen(enc);
4219 }
4220
4221 /* MS - Optimization */
4222 while ((c = appendline(fptr, newline, &str, &limit, enc)) != EOF) {
4223 const char *s, *p, *pp, *e;
4224
4225 if (c == newline) {
4226 if (RSTRING_LEN(str) < rslen) continue;
4227 s = RSTRING_PTR(str);
4228 e = RSTRING_END(str);
4229 p = e - rslen;
4230 if (!at_char_boundary(s, p, e, enc)) continue;
4231 if (!rspara) rscheck(rsptr, rslen, rs);
4232 if (memcmp(p, rsptr, rslen) == 0) {
4233 if (chomp) {
4234 if (chomp_cr && p > s && *(p-1) == '\r') --p;
4235 rb_str_set_len(str, p - s);
4236 }
4237 break;
4238 }
4239 }
4240 if (limit == 0) {
4241 s = RSTRING_PTR(str);
4242 p = RSTRING_END(str);
4243 pp = rb_enc_prev_char(s, p, p, enc);
4244 if (extra_limit && pp &&
4245 MBCLEN_NEEDMORE_P(rb_enc_precise_mbclen(pp, p, enc))) {
4246 /* relax the limit while incomplete character.
4247 * extra_limit limits the relax length */
4248 limit = 1;
4249 extra_limit--;
4250 }
4251 else {
4252 nolimit = 1;
4253 break;
4254 }
4255 }
4256 }
4257
4258 if (rspara && c != EOF)
4259 swallow(fptr, '\n');
4260 if (!NIL_P(str))
4261 str = io_enc_str(str, fptr);
4262 }
4263
4264 if (!NIL_P(str) && !nolimit) {
4265 fptr->lineno++;
4266 }
4267
4268 return str;
4269}
4270
4271static VALUE
4272rb_io_getline_1(VALUE rs, long limit, int chomp, VALUE io)
4273{
4274 rb_io_t *fptr;
4275 int old_lineno, new_lineno;
4276 VALUE str;
4277
4278 GetOpenFile(io, fptr);
4279 old_lineno = fptr->lineno;
4280 str = rb_io_getline_0(rs, limit, chomp, fptr);
4281 if (!NIL_P(str) && (new_lineno = fptr->lineno) != old_lineno) {
4282 if (io == ARGF.current_file) {
4283 ARGF.lineno += new_lineno - old_lineno;
4284 ARGF.last_lineno = ARGF.lineno;
4285 }
4286 else {
4287 ARGF.last_lineno = new_lineno;
4288 }
4289 }
4290
4291 return str;
4292}
4293
4294static VALUE
4295rb_io_getline(int argc, VALUE *argv, VALUE io)
4296{
4297 struct getline_arg args;
4298
4299 prepare_getline_args(argc, argv, &args, io);
4300 return rb_io_getline_1(args.rs, args.limit, args.chomp, io);
4301}
4302
4303VALUE
4305{
4306 return rb_io_getline_1(rb_default_rs, -1, FALSE, io);
4307}
4308
4309VALUE
4310rb_io_gets_internal(VALUE io)
4311{
4312 rb_io_t *fptr;
4313 GetOpenFile(io, fptr);
4314 return rb_io_getline_0(rb_default_rs, -1, FALSE, fptr);
4315}
4316
4317/*
4318 * call-seq:
4319 * gets(sep = $/, chomp: false) -> string or nil
4320 * gets(limit, chomp: false) -> string or nil
4321 * gets(sep, limit, chomp: false) -> string or nil
4322 *
4323 * Reads and returns a line from the stream;
4324 * assigns the return value to <tt>$_</tt>.
4325 * See {Line IO}[rdoc-ref:IO@Line+IO].
4326 *
4327 * With no arguments given, returns the next line
4328 * as determined by line separator <tt>$/</tt>, or +nil+ if none:
4329 *
4330 * f = File.open('t.txt')
4331 * f.gets # => "First line\n"
4332 * $_ # => "First line\n"
4333 * f.gets # => "\n"
4334 * f.gets # => "Fourth line\n"
4335 * f.gets # => "Fifth line\n"
4336 * f.gets # => nil
4337 * f.close
4338 *
4339 * With only string argument +sep+ given,
4340 * returns the next line as determined by line separator +sep+,
4341 * or +nil+ if none;
4342 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4343 *
4344 * f = File.new('t.txt')
4345 * f.gets('l') # => "First l"
4346 * f.gets('li') # => "ine\nSecond li"
4347 * f.gets('lin') # => "ne\n\nFourth lin"
4348 * f.gets # => "e\n"
4349 * f.close
4350 *
4351 * The two special values for +sep+ are honored:
4352 *
4353 * f = File.new('t.txt')
4354 * # Get all.
4355 * f.gets(nil) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
4356 * f.rewind
4357 * # Get paragraph (up to two line separators).
4358 * f.gets('') # => "First line\nSecond line\n\n"
4359 * f.close
4360 *
4361 * With only integer argument +limit+ given,
4362 * limits the number of bytes in the line;
4363 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4364 *
4365 * # No more than one line.
4366 * File.open('t.txt') {|f| f.gets(10) } # => "First line"
4367 * File.open('t.txt') {|f| f.gets(11) } # => "First line\n"
4368 * File.open('t.txt') {|f| f.gets(12) } # => "First line\n"
4369 *
4370 * With arguments +sep+ and +limit+ given,
4371 * combines the two behaviors
4372 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
4373 *
4374 * Optional keyword argument +chomp+ specifies whether line separators
4375 * are to be omitted:
4376 *
4377 * f = File.open('t.txt')
4378 * # Chomp the lines.
4379 * f.gets(chomp: true) # => "First line"
4380 * f.gets(chomp: true) # => "Second line"
4381 * f.gets(chomp: true) # => ""
4382 * f.gets(chomp: true) # => "Fourth line"
4383 * f.gets(chomp: true) # => "Fifth line"
4384 * f.gets(chomp: true) # => nil
4385 * f.close
4386 *
4387 */
4388
4389static VALUE
4390rb_io_gets_m(int argc, VALUE *argv, VALUE io)
4391{
4392 VALUE str;
4393
4394 str = rb_io_getline(argc, argv, io);
4395 rb_lastline_set(str);
4396
4397 return str;
4398}
4399
4400/*
4401 * call-seq:
4402 * lineno -> integer
4403 *
4404 * Returns the current line number for the stream;
4405 * see {Line Number}[rdoc-ref:IO@Line+Number].
4406 *
4407 */
4408
4409static VALUE
4410rb_io_lineno(VALUE io)
4411{
4412 rb_io_t *fptr;
4413
4414 GetOpenFile(io, fptr);
4416 return INT2NUM(fptr->lineno);
4417}
4418
4419/*
4420 * call-seq:
4421 * lineno = integer -> integer
4422 *
4423 * Sets and returns the line number for the stream;
4424 * see {Line Number}[rdoc-ref:IO@Line+Number].
4425 *
4426 */
4427
4428static VALUE
4429rb_io_set_lineno(VALUE io, VALUE lineno)
4430{
4431 rb_io_t *fptr;
4432
4433 GetOpenFile(io, fptr);
4435 fptr->lineno = NUM2INT(lineno);
4436 return lineno;
4437}
4438
4439/* :nodoc: */
4440static VALUE
4441io_readline(rb_execution_context_t *ec, VALUE io, VALUE sep, VALUE lim, VALUE chomp)
4442{
4443 long limit = -1;
4444 if (NIL_P(lim)) {
4445 VALUE tmp = Qnil;
4446 // If sep is specified, but it's not a string and not nil, then assume
4447 // it's the limit (it should be an integer)
4448 if (!NIL_P(sep) && NIL_P(tmp = rb_check_string_type(sep))) {
4449 // If the user has specified a non-nil / non-string value
4450 // for the separator, we assume it's the limit and set the
4451 // separator to default: rb_rs.
4452 lim = sep;
4453 limit = NUM2LONG(lim);
4454 sep = rb_rs;
4455 }
4456 else {
4457 sep = tmp;
4458 }
4459 }
4460 else {
4461 if (!NIL_P(sep)) StringValue(sep);
4462 limit = NUM2LONG(lim);
4463 }
4464
4465 check_getline_args(&sep, &limit, io);
4466
4467 VALUE line = rb_io_getline_1(sep, limit, RTEST(chomp), io);
4468 rb_lastline_set_up(line, 1);
4469
4470 if (NIL_P(line)) {
4471 rb_eof_error();
4472 }
4473 return line;
4474}
4475
4476static VALUE io_readlines(const struct getline_arg *arg, VALUE io);
4477
4478/*
4479 * call-seq:
4480 * readlines(sep = $/, chomp: false) -> array
4481 * readlines(limit, chomp: false) -> array
4482 * readlines(sep, limit, chomp: false) -> array
4483 *
4484 * Reads and returns all remaining line from the stream;
4485 * does not modify <tt>$_</tt>.
4486 * See {Line IO}[rdoc-ref:IO@Line+IO].
4487 *
4488 * With no arguments given, returns lines
4489 * as determined by line separator <tt>$/</tt>, or +nil+ if none:
4490 *
4491 * f = File.new('t.txt')
4492 * f.readlines
4493 * # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
4494 * f.readlines # => []
4495 * f.close
4496 *
4497 * With only string argument +sep+ given,
4498 * returns lines as determined by line separator +sep+,
4499 * or +nil+ if none;
4500 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4501 *
4502 * f = File.new('t.txt')
4503 * f.readlines('li')
4504 * # => ["First li", "ne\nSecond li", "ne\n\nFourth li", "ne\nFifth li", "ne\n"]
4505 * f.close
4506 *
4507 * The two special values for +sep+ are honored:
4508 *
4509 * f = File.new('t.txt')
4510 * # Get all into one string.
4511 * f.readlines(nil)
4512 * # => ["First line\nSecond line\n\nFourth line\nFifth line\n"]
4513 * # Get paragraphs (up to two line separators).
4514 * f.rewind
4515 * f.readlines('')
4516 * # => ["First line\nSecond line\n\n", "Fourth line\nFifth line\n"]
4517 * f.close
4518 *
4519 * With only integer argument +limit+ given,
4520 * limits the number of bytes in each line;
4521 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4522 *
4523 * f = File.new('t.txt')
4524 * f.readlines(8)
4525 * # => ["First li", "ne\n", "Second l", "ine\n", "\n", "Fourth l", "ine\n", "Fifth li", "ne\n"]
4526 * f.close
4527 *
4528 * With arguments +sep+ and +limit+ given,
4529 * combines the two behaviors
4530 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
4531 *
4532 * Optional keyword argument +chomp+ specifies whether line separators
4533 * are to be omitted:
4534 *
4535 * f = File.new('t.txt')
4536 * f.readlines(chomp: true)
4537 * # => ["First line", "Second line", "", "Fourth line", "Fifth line"]
4538 * f.close
4539 *
4540 */
4541
4542static VALUE
4543rb_io_readlines(int argc, VALUE *argv, VALUE io)
4544{
4545 struct getline_arg args;
4546
4547 prepare_getline_args(argc, argv, &args, io);
4548 return io_readlines(&args, io);
4549}
4550
4551static VALUE
4552io_readlines(const struct getline_arg *arg, VALUE io)
4553{
4554 VALUE line, ary;
4555
4556 if (arg->limit == 0)
4557 rb_raise(rb_eArgError, "invalid limit: 0 for readlines");
4558 ary = rb_ary_new();
4559 while (!NIL_P(line = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, io))) {
4560 rb_ary_push(ary, line);
4561 }
4562 return ary;
4563}
4564
4565/*
4566 * call-seq:
4567 * each_line(sep = $/, chomp: false) {|line| ... } -> self
4568 * each_line(limit, chomp: false) {|line| ... } -> self
4569 * each_line(sep, limit, chomp: false) {|line| ... } -> self
4570 * each_line -> enumerator
4571 *
4572 * Calls the block with each remaining line read from the stream;
4573 * returns +self+.
4574 * Does nothing if already at end-of-stream;
4575 * See {Line IO}[rdoc-ref:IO@Line+IO].
4576 *
4577 * With no arguments given, reads lines
4578 * as determined by line separator <tt>$/</tt>:
4579 *
4580 * f = File.new('t.txt')
4581 * f.each_line {|line| p line }
4582 * f.each_line {|line| fail 'Cannot happen' }
4583 * f.close
4584 *
4585 * Output:
4586 *
4587 * "First line\n"
4588 * "Second line\n"
4589 * "\n"
4590 * "Fourth line\n"
4591 * "Fifth line\n"
4592 *
4593 * With only string argument +sep+ given,
4594 * reads lines as determined by line separator +sep+;
4595 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
4596 *
4597 * f = File.new('t.txt')
4598 * f.each_line('li') {|line| p line }
4599 * f.close
4600 *
4601 * Output:
4602 *
4603 * "First li"
4604 * "ne\nSecond li"
4605 * "ne\n\nFourth li"
4606 * "ne\nFifth li"
4607 * "ne\n"
4608 *
4609 * The two special values for +sep+ are honored:
4610 *
4611 * f = File.new('t.txt')
4612 * # Get all into one string.
4613 * f.each_line(nil) {|line| p line }
4614 * f.close
4615 *
4616 * Output:
4617 *
4618 * "First line\nSecond line\n\nFourth line\nFifth line\n"
4619 *
4620 * f.rewind
4621 * # Get paragraphs (up to two line separators).
4622 * f.each_line('') {|line| p line }
4623 *
4624 * Output:
4625 *
4626 * "First line\nSecond line\n\n"
4627 * "Fourth line\nFifth line\n"
4628 *
4629 * With only integer argument +limit+ given,
4630 * limits the number of bytes in each line;
4631 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
4632 *
4633 * f = File.new('t.txt')
4634 * f.each_line(8) {|line| p line }
4635 * f.close
4636 *
4637 * Output:
4638 *
4639 * "First li"
4640 * "ne\n"
4641 * "Second l"
4642 * "ine\n"
4643 * "\n"
4644 * "Fourth l"
4645 * "ine\n"
4646 * "Fifth li"
4647 * "ne\n"
4648 *
4649 * With arguments +sep+ and +limit+ given,
4650 * combines the two behaviors
4651 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
4652 *
4653 * Optional keyword argument +chomp+ specifies whether line separators
4654 * are to be omitted:
4655 *
4656 * f = File.new('t.txt')
4657 * f.each_line(chomp: true) {|line| p line }
4658 * f.close
4659 *
4660 * Output:
4661 *
4662 * "First line"
4663 * "Second line"
4664 * ""
4665 * "Fourth line"
4666 * "Fifth line"
4667 *
4668 * Returns an Enumerator if no block is given.
4669 */
4670
4671static VALUE
4672rb_io_each_line(int argc, VALUE *argv, VALUE io)
4673{
4674 VALUE str;
4675 struct getline_arg args;
4676
4677 RETURN_ENUMERATOR(io, argc, argv);
4678 prepare_getline_args(argc, argv, &args, io);
4679 if (args.limit == 0)
4680 rb_raise(rb_eArgError, "invalid limit: 0 for each_line");
4681 while (!NIL_P(str = rb_io_getline_1(args.rs, args.limit, args.chomp, io))) {
4682 rb_yield(str);
4683 }
4684 return io;
4685}
4686
4687/*
4688 * call-seq:
4689 * each_byte {|byte| ... } -> self
4690 * each_byte -> enumerator
4691 *
4692 * Calls the given block with each byte (0..255) in the stream; returns +self+.
4693 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
4694 *
4695 * f = File.new('t.rus')
4696 * a = []
4697 * f.each_byte {|b| a << b }
4698 * a # => [209, 130, 208, 181, 209, 129, 209, 130]
4699 * f.close
4700 *
4701 * Returns an Enumerator if no block is given.
4702 *
4703 * Related: IO#each_char, IO#each_codepoint.
4704 *
4705 */
4706
4707static VALUE
4708rb_io_each_byte(VALUE io)
4709{
4710 rb_io_t *fptr;
4711
4712 RETURN_ENUMERATOR(io, 0, 0);
4713 GetOpenFile(io, fptr);
4714
4715 do {
4716 while (fptr->rbuf.len > 0) {
4717 char *p = fptr->rbuf.ptr + fptr->rbuf.off++;
4718 fptr->rbuf.len--;
4719 rb_yield(INT2FIX(*p & 0xff));
4721 errno = 0;
4722 }
4723 READ_CHECK(fptr);
4724 } while (io_fillbuf(fptr) >= 0);
4725 return io;
4726}
4727
4728static VALUE
4729io_getc(rb_io_t *fptr, rb_encoding *enc)
4730{
4731 int r, n, cr = 0;
4732 VALUE str;
4733
4734 if (NEED_READCONV(fptr)) {
4735 rb_encoding *read_enc = io_read_encoding(fptr);
4736
4737 str = Qnil;
4738 SET_BINARY_MODE(fptr);
4739 make_readconv(fptr, 0);
4740
4741 while (1) {
4742 if (fptr->cbuf.len) {
4743 r = rb_enc_precise_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4744 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4745 read_enc);
4746 if (!MBCLEN_NEEDMORE_P(r))
4747 break;
4748 if (fptr->cbuf.len == fptr->cbuf.capa) {
4749 rb_raise(rb_eIOError, "too long character");
4750 }
4751 }
4752
4753 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4754 if (fptr->cbuf.len == 0) {
4755 clear_readconv(fptr);
4756 return Qnil;
4757 }
4758 /* return an unit of an incomplete character just before EOF */
4759 str = rb_enc_str_new(fptr->cbuf.ptr+fptr->cbuf.off, 1, read_enc);
4760 fptr->cbuf.off += 1;
4761 fptr->cbuf.len -= 1;
4762 if (fptr->cbuf.len == 0) clear_readconv(fptr);
4764 return str;
4765 }
4766 }
4767 if (MBCLEN_INVALID_P(r)) {
4768 r = rb_enc_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4769 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4770 read_enc);
4771 io_shift_cbuf(fptr, r, &str);
4773 }
4774 else {
4775 io_shift_cbuf(fptr, MBCLEN_CHARFOUND_LEN(r), &str);
4777 if (MBCLEN_CHARFOUND_LEN(r) == 1 && rb_enc_asciicompat(read_enc) &&
4778 ISASCII(RSTRING_PTR(str)[0])) {
4779 cr = ENC_CODERANGE_7BIT;
4780 }
4781 }
4782 str = io_enc_str(str, fptr);
4783 ENC_CODERANGE_SET(str, cr);
4784 return str;
4785 }
4786
4787 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4788 if (io_fillbuf(fptr) < 0) {
4789 return Qnil;
4790 }
4791 if (rb_enc_asciicompat(enc) && ISASCII(fptr->rbuf.ptr[fptr->rbuf.off])) {
4792 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, 1);
4793 fptr->rbuf.off += 1;
4794 fptr->rbuf.len -= 1;
4795 cr = ENC_CODERANGE_7BIT;
4796 }
4797 else {
4798 r = rb_enc_precise_mbclen(fptr->rbuf.ptr+fptr->rbuf.off, fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
4799 if (MBCLEN_CHARFOUND_P(r) &&
4800 (n = MBCLEN_CHARFOUND_LEN(r)) <= fptr->rbuf.len) {
4801 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, n);
4802 fptr->rbuf.off += n;
4803 fptr->rbuf.len -= n;
4805 }
4806 else if (MBCLEN_NEEDMORE_P(r)) {
4807 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, fptr->rbuf.len);
4808 fptr->rbuf.len = 0;
4809 getc_needmore:
4810 if (io_fillbuf(fptr) != -1) {
4811 rb_str_cat(str, fptr->rbuf.ptr+fptr->rbuf.off, 1);
4812 fptr->rbuf.off++;
4813 fptr->rbuf.len--;
4814 r = rb_enc_precise_mbclen(RSTRING_PTR(str), RSTRING_PTR(str)+RSTRING_LEN(str), enc);
4815 if (MBCLEN_NEEDMORE_P(r)) {
4816 goto getc_needmore;
4817 }
4818 else if (MBCLEN_CHARFOUND_P(r)) {
4820 }
4821 }
4822 }
4823 else {
4824 str = rb_str_new(fptr->rbuf.ptr+fptr->rbuf.off, 1);
4825 fptr->rbuf.off++;
4826 fptr->rbuf.len--;
4827 }
4828 }
4829 if (!cr) cr = ENC_CODERANGE_BROKEN;
4830 str = io_enc_str(str, fptr);
4831 ENC_CODERANGE_SET(str, cr);
4832 return str;
4833}
4834
4835/*
4836 * call-seq:
4837 * each_char {|c| ... } -> self
4838 * each_char -> enumerator
4839 *
4840 * Calls the given block with each character in the stream; returns +self+.
4841 * See {Character IO}[rdoc-ref:IO@Character+IO].
4842 *
4843 * f = File.new('t.rus')
4844 * a = []
4845 * f.each_char {|c| a << c.ord }
4846 * a # => [1090, 1077, 1089, 1090]
4847 * f.close
4848 *
4849 * Returns an Enumerator if no block is given.
4850 *
4851 * Related: IO#each_byte, IO#each_codepoint.
4852 *
4853 */
4854
4855static VALUE
4856rb_io_each_char(VALUE io)
4857{
4858 rb_io_t *fptr;
4859 rb_encoding *enc;
4860 VALUE c;
4861
4862 RETURN_ENUMERATOR(io, 0, 0);
4863 GetOpenFile(io, fptr);
4865
4866 enc = io_input_encoding(fptr);
4867 READ_CHECK(fptr);
4868 while (!NIL_P(c = io_getc(fptr, enc))) {
4869 rb_yield(c);
4870 }
4871 return io;
4872}
4873
4874/*
4875 * call-seq:
4876 * each_codepoint {|c| ... } -> self
4877 * each_codepoint -> enumerator
4878 *
4879 * Calls the given block with each codepoint in the stream; returns +self+:
4880 *
4881 * f = File.new('t.rus')
4882 * a = []
4883 * f.each_codepoint {|c| a << c }
4884 * a # => [1090, 1077, 1089, 1090]
4885 * f.close
4886 *
4887 * Returns an Enumerator if no block is given.
4888 *
4889 * Related: IO#each_byte, IO#each_char.
4890 *
4891 */
4892
4893static VALUE
4894rb_io_each_codepoint(VALUE io)
4895{
4896 rb_io_t *fptr;
4897 rb_encoding *enc;
4898 unsigned int c;
4899 int r, n;
4900
4901 RETURN_ENUMERATOR(io, 0, 0);
4902 GetOpenFile(io, fptr);
4904
4905 READ_CHECK(fptr);
4906 if (NEED_READCONV(fptr)) {
4907 SET_BINARY_MODE(fptr);
4908 r = 1; /* no invalid char yet */
4909 for (;;) {
4910 make_readconv(fptr, 0);
4911 for (;;) {
4912 if (fptr->cbuf.len) {
4913 if (fptr->encs.enc)
4914 r = rb_enc_precise_mbclen(fptr->cbuf.ptr+fptr->cbuf.off,
4915 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4916 fptr->encs.enc);
4917 else
4918 r = ONIGENC_CONSTRUCT_MBCLEN_CHARFOUND(1);
4919 if (!MBCLEN_NEEDMORE_P(r))
4920 break;
4921 if (fptr->cbuf.len == fptr->cbuf.capa) {
4922 rb_raise(rb_eIOError, "too long character");
4923 }
4924 }
4925 if (more_char(fptr) == MORE_CHAR_FINISHED) {
4926 clear_readconv(fptr);
4927 if (!MBCLEN_CHARFOUND_P(r)) {
4928 enc = fptr->encs.enc;
4929 goto invalid;
4930 }
4931 return io;
4932 }
4933 }
4934 if (MBCLEN_INVALID_P(r)) {
4935 enc = fptr->encs.enc;
4936 goto invalid;
4937 }
4938 n = MBCLEN_CHARFOUND_LEN(r);
4939 if (fptr->encs.enc) {
4940 c = rb_enc_codepoint(fptr->cbuf.ptr+fptr->cbuf.off,
4941 fptr->cbuf.ptr+fptr->cbuf.off+fptr->cbuf.len,
4942 fptr->encs.enc);
4943 }
4944 else {
4945 c = (unsigned char)fptr->cbuf.ptr[fptr->cbuf.off];
4946 }
4947 fptr->cbuf.off += n;
4948 fptr->cbuf.len -= n;
4949 rb_yield(UINT2NUM(c));
4951 }
4952 }
4953 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4954 enc = io_input_encoding(fptr);
4955 while (io_fillbuf(fptr) >= 0) {
4956 r = rb_enc_precise_mbclen(fptr->rbuf.ptr+fptr->rbuf.off,
4957 fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
4958 if (MBCLEN_CHARFOUND_P(r) &&
4959 (n = MBCLEN_CHARFOUND_LEN(r)) <= fptr->rbuf.len) {
4960 c = rb_enc_codepoint(fptr->rbuf.ptr+fptr->rbuf.off,
4961 fptr->rbuf.ptr+fptr->rbuf.off+fptr->rbuf.len, enc);
4962 fptr->rbuf.off += n;
4963 fptr->rbuf.len -= n;
4964 rb_yield(UINT2NUM(c));
4965 }
4966 else if (MBCLEN_INVALID_P(r)) {
4967 goto invalid;
4968 }
4969 else if (MBCLEN_NEEDMORE_P(r)) {
4970 char cbuf[8], *p = cbuf;
4971 int more = MBCLEN_NEEDMORE_LEN(r);
4972 if (more > numberof(cbuf)) goto invalid;
4973 more += n = fptr->rbuf.len;
4974 if (more > numberof(cbuf)) goto invalid;
4975 while ((n = (int)read_buffered_data(p, more, fptr)) > 0 &&
4976 (p += n, (more -= n) > 0)) {
4977 if (io_fillbuf(fptr) < 0) goto invalid;
4978 if ((n = fptr->rbuf.len) > more) n = more;
4979 }
4980 r = rb_enc_precise_mbclen(cbuf, p, enc);
4981 if (!MBCLEN_CHARFOUND_P(r)) goto invalid;
4982 c = rb_enc_codepoint(cbuf, p, enc);
4983 rb_yield(UINT2NUM(c));
4984 }
4985 else {
4986 continue;
4987 }
4989 }
4990 return io;
4991
4992 invalid:
4993 rb_raise(rb_eArgError, "invalid byte sequence in %s", rb_enc_name(enc));
4995}
4996
4997/*
4998 * call-seq:
4999 * getc -> character or nil
5000 *
5001 * Reads and returns the next 1-character string from the stream;
5002 * returns +nil+ if already at end-of-stream.
5003 * See {Character IO}[rdoc-ref:IO@Character+IO].
5004 *
5005 * f = File.open('t.txt')
5006 * f.getc # => "F"
5007 * f.close
5008 * f = File.open('t.rus')
5009 * f.getc.ord # => 1090
5010 * f.close
5011 *
5012 * Related: IO#readchar (may raise EOFError).
5013 *
5014 */
5015
5016static VALUE
5017rb_io_getc(VALUE io)
5018{
5019 rb_io_t *fptr;
5020 rb_encoding *enc;
5021
5022 GetOpenFile(io, fptr);
5024
5025 enc = io_input_encoding(fptr);
5026 READ_CHECK(fptr);
5027 return io_getc(fptr, enc);
5028}
5029
5030/*
5031 * call-seq:
5032 * readchar -> string
5033 *
5034 * Reads and returns the next 1-character string from the stream;
5035 * raises EOFError if already at end-of-stream.
5036 * See {Character IO}[rdoc-ref:IO@Character+IO].
5037 *
5038 * f = File.open('t.txt')
5039 * f.readchar # => "F"
5040 * f.close
5041 * f = File.open('t.rus')
5042 * f.readchar.ord # => 1090
5043 * f.close
5044 *
5045 * Related: IO#getc (will not raise EOFError).
5046 *
5047 */
5048
5049static VALUE
5050rb_io_readchar(VALUE io)
5051{
5052 VALUE c = rb_io_getc(io);
5053
5054 if (NIL_P(c)) {
5055 rb_eof_error();
5056 }
5057 return c;
5058}
5059
5060/*
5061 * call-seq:
5062 * getbyte -> integer or nil
5063 *
5064 * Reads and returns the next byte (in range 0..255) from the stream;
5065 * returns +nil+ if already at end-of-stream.
5066 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5067 *
5068 * f = File.open('t.txt')
5069 * f.getbyte # => 70
5070 * f.close
5071 * f = File.open('t.rus')
5072 * f.getbyte # => 209
5073 * f.close
5074 *
5075 * Related: IO#readbyte (may raise EOFError).
5076 */
5077
5078VALUE
5080{
5081 rb_io_t *fptr;
5082 int c;
5083
5084 GetOpenFile(io, fptr);
5086 READ_CHECK(fptr);
5087 VALUE r_stdout = rb_ractor_stdout();
5088 if (fptr->fd == 0 && (fptr->mode & FMODE_TTY) && RB_TYPE_P(r_stdout, T_FILE)) {
5089 rb_io_t *ofp;
5090 GetOpenFile(r_stdout, ofp);
5091 if (ofp->mode & FMODE_TTY) {
5092 rb_io_flush(r_stdout);
5093 }
5094 }
5095 if (io_fillbuf(fptr) < 0) {
5096 return Qnil;
5097 }
5098 fptr->rbuf.off++;
5099 fptr->rbuf.len--;
5100 c = (unsigned char)fptr->rbuf.ptr[fptr->rbuf.off-1];
5101 return INT2FIX(c & 0xff);
5102}
5103
5104/*
5105 * call-seq:
5106 * readbyte -> integer
5107 *
5108 * Reads and returns the next byte (in range 0..255) from the stream;
5109 * raises EOFError if already at end-of-stream.
5110 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5111 *
5112 * f = File.open('t.txt')
5113 * f.readbyte # => 70
5114 * f.close
5115 * f = File.open('t.rus')
5116 * f.readbyte # => 209
5117 * f.close
5118 *
5119 * Related: IO#getbyte (will not raise EOFError).
5120 *
5121 */
5122
5123static VALUE
5124rb_io_readbyte(VALUE io)
5125{
5126 VALUE c = rb_io_getbyte(io);
5127
5128 if (NIL_P(c)) {
5129 rb_eof_error();
5130 }
5131 return c;
5132}
5133
5134/*
5135 * call-seq:
5136 * ungetbyte(integer) -> nil
5137 * ungetbyte(string) -> nil
5138 *
5139 * Pushes back ("unshifts") the given data onto the stream's buffer,
5140 * placing the data so that it is next to be read; returns +nil+.
5141 * See {Byte IO}[rdoc-ref:IO@Byte+IO].
5142 *
5143 * Note that:
5144 *
5145 * - Calling the method has no effect with unbuffered reads (such as IO#sysread).
5146 * - Calling #rewind on the stream discards the pushed-back data.
5147 *
5148 * When argument +integer+ is given, uses only its low-order byte:
5149 *
5150 * File.write('t.tmp', '012')
5151 * f = File.open('t.tmp')
5152 * f.ungetbyte(0x41) # => nil
5153 * f.read # => "A012"
5154 * f.rewind
5155 * f.ungetbyte(0x4243) # => nil
5156 * f.read # => "C012"
5157 * f.close
5158 *
5159 * When argument +string+ is given, uses all bytes:
5160 *
5161 * File.write('t.tmp', '012')
5162 * f = File.open('t.tmp')
5163 * f.ungetbyte('A') # => nil
5164 * f.read # => "A012"
5165 * f.rewind
5166 * f.ungetbyte('BCDE') # => nil
5167 * f.read # => "BCDE012"
5168 * f.close
5169 *
5170 */
5171
5172VALUE
5174{
5175 rb_io_t *fptr;
5176
5177 GetOpenFile(io, fptr);
5179 switch (TYPE(b)) {
5180 case T_NIL:
5181 return Qnil;
5182 case T_FIXNUM:
5183 case T_BIGNUM: ;
5184 VALUE v = rb_int_modulo(b, INT2FIX(256));
5185 unsigned char c = NUM2INT(v) & 0xFF;
5186 b = rb_str_new((const char *)&c, 1);
5187 break;
5188 default:
5189 StringValue(b);
5190 }
5191 io_ungetbyte(b, fptr);
5192 return Qnil;
5193}
5194
5195/*
5196 * call-seq:
5197 * ungetc(integer) -> nil
5198 * ungetc(string) -> nil
5199 *
5200 * Pushes back ("unshifts") the given data onto the stream's buffer,
5201 * placing the data so that it is next to be read; returns +nil+.
5202 * See {Character IO}[rdoc-ref:IO@Character+IO].
5203 *
5204 * Note that:
5205 *
5206 * - Calling the method has no effect with unbuffered reads (such as IO#sysread).
5207 * - Calling #rewind on the stream discards the pushed-back data.
5208 *
5209 * When argument +integer+ is given, interprets the integer as a character:
5210 *
5211 * File.write('t.tmp', '012')
5212 * f = File.open('t.tmp')
5213 * f.ungetc(0x41) # => nil
5214 * f.read # => "A012"
5215 * f.rewind
5216 * f.ungetc(0x0442) # => nil
5217 * f.getc.ord # => 1090
5218 * f.close
5219 *
5220 * When argument +string+ is given, uses all characters:
5221 *
5222 * File.write('t.tmp', '012')
5223 * f = File.open('t.tmp')
5224 * f.ungetc('A') # => nil
5225 * f.read # => "A012"
5226 * f.rewind
5227 * f.ungetc("\u0442\u0435\u0441\u0442") # => nil
5228 * f.getc.ord # => 1090
5229 * f.getc.ord # => 1077
5230 * f.getc.ord # => 1089
5231 * f.getc.ord # => 1090
5232 * f.close
5233 *
5234 */
5235
5236VALUE
5238{
5239 rb_io_t *fptr;
5240 long len;
5241
5242 GetOpenFile(io, fptr);
5244 if (FIXNUM_P(c)) {
5245 c = rb_enc_uint_chr(FIX2UINT(c), io_read_encoding(fptr));
5246 }
5247 else if (RB_BIGNUM_TYPE_P(c)) {
5248 c = rb_enc_uint_chr(NUM2UINT(c), io_read_encoding(fptr));
5249 }
5250 else {
5251 StringValue(c);
5252 }
5253 if (NEED_READCONV(fptr)) {
5254 SET_BINARY_MODE(fptr);
5255 len = RSTRING_LEN(c);
5256#if SIZEOF_LONG > SIZEOF_INT
5257 if (len > INT_MAX)
5258 rb_raise(rb_eIOError, "ungetc failed");
5259#endif
5260 make_readconv(fptr, (int)len);
5261 if (fptr->cbuf.capa - fptr->cbuf.len < len)
5262 rb_raise(rb_eIOError, "ungetc failed");
5263 if (fptr->cbuf.off < len) {
5264 MEMMOVE(fptr->cbuf.ptr+fptr->cbuf.capa-fptr->cbuf.len,
5265 fptr->cbuf.ptr+fptr->cbuf.off,
5266 char, fptr->cbuf.len);
5267 fptr->cbuf.off = fptr->cbuf.capa-fptr->cbuf.len;
5268 }
5269 fptr->cbuf.off -= (int)len;
5270 fptr->cbuf.len += (int)len;
5271 MEMMOVE(fptr->cbuf.ptr+fptr->cbuf.off, RSTRING_PTR(c), char, len);
5272 }
5273 else {
5274 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
5275 io_ungetbyte(c, fptr);
5276 }
5277 return Qnil;
5278}
5279
5280/*
5281 * call-seq:
5282 * isatty -> true or false
5283 *
5284 * Returns +true+ if the stream is associated with a terminal device (tty),
5285 * +false+ otherwise:
5286 *
5287 * f = File.new('t.txt').isatty #=> false
5288 * f.close
5289 * f = File.new('/dev/tty').isatty #=> true
5290 * f.close
5291 *
5292 */
5293
5294static VALUE
5295rb_io_isatty(VALUE io)
5296{
5297 rb_io_t *fptr;
5298
5299 GetOpenFile(io, fptr);
5300 return RBOOL(isatty(fptr->fd) != 0);
5301}
5302
5303#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5304/*
5305 * call-seq:
5306 * close_on_exec? -> true or false
5307 *
5308 * Returns +true+ if the stream will be closed on exec, +false+ otherwise:
5309 *
5310 * f = File.open('t.txt')
5311 * f.close_on_exec? # => true
5312 * f.close_on_exec = false
5313 * f.close_on_exec? # => false
5314 * f.close
5315 *
5316 */
5317
5318static VALUE
5319rb_io_close_on_exec_p(VALUE io)
5320{
5321 rb_io_t *fptr;
5322 VALUE write_io;
5323 int fd, ret;
5324
5325 write_io = GetWriteIO(io);
5326 if (io != write_io) {
5327 GetOpenFile(write_io, fptr);
5328 if (fptr && 0 <= (fd = fptr->fd)) {
5329 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5330 if (!(ret & FD_CLOEXEC)) return Qfalse;
5331 }
5332 }
5333
5334 GetOpenFile(io, fptr);
5335 if (fptr && 0 <= (fd = fptr->fd)) {
5336 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5337 if (!(ret & FD_CLOEXEC)) return Qfalse;
5338 }
5339 return Qtrue;
5340}
5341#else
5342#define rb_io_close_on_exec_p rb_f_notimplement
5343#endif
5344
5345#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
5346/*
5347 * call-seq:
5348 * self.close_on_exec = bool -> true or false
5349 *
5350 * Sets a close-on-exec flag.
5351 *
5352 * f = File.open(File::NULL)
5353 * f.close_on_exec = true
5354 * system("cat", "/proc/self/fd/#{f.fileno}") # cat: /proc/self/fd/3: No such file or directory
5355 * f.closed? #=> false
5356 *
5357 * Ruby sets close-on-exec flags of all file descriptors by default
5358 * since Ruby 2.0.0.
5359 * So you don't need to set by yourself.
5360 * Also, unsetting a close-on-exec flag can cause file descriptor leak
5361 * if another thread use fork() and exec() (via system() method for example).
5362 * If you really needs file descriptor inheritance to child process,
5363 * use spawn()'s argument such as fd=>fd.
5364 */
5365
5366static VALUE
5367rb_io_set_close_on_exec(VALUE io, VALUE arg)
5368{
5369 int flag = RTEST(arg) ? FD_CLOEXEC : 0;
5370 rb_io_t *fptr;
5371 VALUE write_io;
5372 int fd, ret;
5373
5374 write_io = GetWriteIO(io);
5375 if (io != write_io) {
5376 GetOpenFile(write_io, fptr);
5377 if (fptr && 0 <= (fd = fptr->fd)) {
5378 if ((ret = fcntl(fptr->fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5379 if ((ret & FD_CLOEXEC) != flag) {
5380 ret = (ret & ~FD_CLOEXEC) | flag;
5381 ret = fcntl(fd, F_SETFD, ret);
5382 if (ret != 0) rb_sys_fail_path(fptr->pathv);
5383 }
5384 }
5385
5386 }
5387
5388 GetOpenFile(io, fptr);
5389 if (fptr && 0 <= (fd = fptr->fd)) {
5390 if ((ret = fcntl(fd, F_GETFD)) == -1) rb_sys_fail_path(fptr->pathv);
5391 if ((ret & FD_CLOEXEC) != flag) {
5392 ret = (ret & ~FD_CLOEXEC) | flag;
5393 ret = fcntl(fd, F_SETFD, ret);
5394 if (ret != 0) rb_sys_fail_path(fptr->pathv);
5395 }
5396 }
5397 return Qnil;
5398}
5399#else
5400#define rb_io_set_close_on_exec rb_f_notimplement
5401#endif
5402
5403#define RUBY_IO_EXTERNAL_P(f) ((f)->mode & FMODE_EXTERNAL)
5404#define PREP_STDIO_NAME(f) (RSTRING_PTR((f)->pathv))
5405
5406static VALUE
5407finish_writeconv(rb_io_t *fptr, int noalloc)
5408{
5409 unsigned char *ds, *dp, *de;
5411
5412 if (!fptr->wbuf.ptr) {
5413 unsigned char buf[1024];
5414
5416 while (res == econv_destination_buffer_full) {
5417 ds = dp = buf;
5418 de = buf + sizeof(buf);
5419 res = rb_econv_convert(fptr->writeconv, NULL, NULL, &dp, de, 0);
5420 while (dp-ds) {
5421 size_t remaining = dp-ds;
5422 long result = rb_io_write_memory(fptr, ds, remaining);
5423
5424 if (result > 0) {
5425 ds += result;
5426 if ((size_t)result == remaining) break;
5427 }
5428 else if (rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
5429 if (fptr->fd < 0)
5430 return noalloc ? Qtrue : rb_exc_new3(rb_eIOError, rb_str_new_cstr(closed_stream));
5431 }
5432 else {
5433 return noalloc ? Qtrue : INT2NUM(errno);
5434 }
5435 }
5436 if (res == econv_invalid_byte_sequence ||
5437 res == econv_incomplete_input ||
5439 return noalloc ? Qtrue : rb_econv_make_exception(fptr->writeconv);
5440 }
5441 }
5442
5443 return Qnil;
5444 }
5445
5447 while (res == econv_destination_buffer_full) {
5448 if (fptr->wbuf.len == fptr->wbuf.capa) {
5449 if (io_fflush(fptr) < 0) {
5450 return noalloc ? Qtrue : INT2NUM(errno);
5451 }
5452 }
5453
5454 ds = dp = (unsigned char *)fptr->wbuf.ptr + fptr->wbuf.off + fptr->wbuf.len;
5455 de = (unsigned char *)fptr->wbuf.ptr + fptr->wbuf.capa;
5456 res = rb_econv_convert(fptr->writeconv, NULL, NULL, &dp, de, 0);
5457 fptr->wbuf.len += (int)(dp - ds);
5458 if (res == econv_invalid_byte_sequence ||
5459 res == econv_incomplete_input ||
5461 return noalloc ? Qtrue : rb_econv_make_exception(fptr->writeconv);
5462 }
5463 }
5464 return Qnil;
5465}
5466
5468 rb_io_t *fptr;
5469 int noalloc;
5470};
5471
5472static VALUE
5473finish_writeconv_sync(VALUE arg)
5474{
5475 struct finish_writeconv_arg *p = (struct finish_writeconv_arg *)arg;
5476 return finish_writeconv(p->fptr, p->noalloc);
5477}
5478
5479static void*
5480nogvl_close(void *ptr)
5481{
5482 int *fd = ptr;
5483
5484 return (void*)(intptr_t)close(*fd);
5485}
5486
5487static int
5488maygvl_close(int fd, int keepgvl)
5489{
5490 if (keepgvl)
5491 return close(fd);
5492
5493 /*
5494 * close() may block for certain file types (NFS, SO_LINGER sockets,
5495 * inotify), so let other threads run.
5496 */
5497 return IO_WITHOUT_GVL_INT(nogvl_close, &fd);
5498}
5499
5500static void*
5501nogvl_fclose(void *ptr)
5502{
5503 FILE *file = ptr;
5504
5505 return (void*)(intptr_t)fclose(file);
5506}
5507
5508static int
5509maygvl_fclose(FILE *file, int keepgvl)
5510{
5511 if (keepgvl)
5512 return fclose(file);
5513
5514 return IO_WITHOUT_GVL_INT(nogvl_fclose, file);
5515}
5516
5517static void free_io_buffer(rb_io_buffer_t *buf);
5518
5519static void
5520fptr_finalize_flush(rb_io_t *fptr, int noraise, int keepgvl,
5521 struct rb_io_close_wait_list *busy)
5522{
5523 VALUE error = Qnil;
5524 int fd = fptr->fd;
5525 FILE *stdio_file = fptr->stdio_file;
5526 int mode = fptr->mode;
5527
5528 if (fptr->writeconv) {
5529 if (!NIL_P(fptr->write_lock) && !noraise) {
5530 struct finish_writeconv_arg arg;
5531 arg.fptr = fptr;
5532 arg.noalloc = noraise;
5533 error = rb_mutex_synchronize(fptr->write_lock, finish_writeconv_sync, (VALUE)&arg);
5534 }
5535 else {
5536 error = finish_writeconv(fptr, noraise);
5537 }
5538 }
5539 if (fptr->wbuf.len) {
5540 if (noraise) {
5541 io_flush_buffer_sync(fptr);
5542 }
5543 else {
5544 if (io_fflush(fptr) < 0 && NIL_P(error)) {
5545 error = INT2NUM(errno);
5546 }
5547 }
5548 }
5549
5550 int done = 0;
5551
5552 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2) {
5553 // Need to keep FILE objects of stdin, stdout and stderr, so we are done:
5554 done = 1;
5555 }
5556
5557 fptr->fd = -1;
5558 fptr->stdio_file = 0;
5560
5561 // Ensure waiting_fd users do not hit EBADF.
5562 if (busy) {
5563 // Wait for them to exit before we call close().
5564 rb_notify_fd_close_wait(busy);
5565 }
5566
5567 // Disable for now.
5568 // if (!done && fd >= 0) {
5569 // VALUE scheduler = rb_fiber_scheduler_current();
5570 // if (scheduler != Qnil) {
5571 // VALUE result = rb_fiber_scheduler_io_close(scheduler, fptr->self);
5572 // if (!UNDEF_P(result)) done = 1;
5573 // }
5574 // }
5575
5576 if (!done && stdio_file) {
5577 // stdio_file is deallocated anyway even if fclose failed.
5578 if ((maygvl_fclose(stdio_file, noraise) < 0) && NIL_P(error)) {
5579 if (!noraise) {
5580 error = INT2NUM(errno);
5581 }
5582 }
5583
5584 done = 1;
5585 }
5586
5587 if (!done && fd >= 0) {
5588 // fptr->fd may be closed even if close fails. POSIX doesn't specify it.
5589 // We assumes it is closed.
5590
5591 keepgvl |= !(mode & FMODE_WRITABLE);
5592 keepgvl |= noraise;
5593 if ((maygvl_close(fd, keepgvl) < 0) && NIL_P(error)) {
5594 if (!noraise) {
5595 error = INT2NUM(errno);
5596 }
5597 }
5598
5599 done = 1;
5600 }
5601
5602 if (!NIL_P(error) && !noraise) {
5603 if (RB_INTEGER_TYPE_P(error))
5604 rb_syserr_fail_path(NUM2INT(error), fptr->pathv);
5605 else
5606 rb_exc_raise(error);
5607 }
5608}
5609
5610static void
5611fptr_finalize(rb_io_t *fptr, int noraise)
5612{
5613 fptr_finalize_flush(fptr, noraise, FALSE, 0);
5614 free_io_buffer(&fptr->rbuf);
5615 free_io_buffer(&fptr->wbuf);
5616 clear_codeconv(fptr);
5617}
5618
5619static void
5620rb_io_fptr_cleanup(rb_io_t *fptr, int noraise)
5621{
5622 if (fptr->finalize) {
5623 (*fptr->finalize)(fptr, noraise);
5624 }
5625 else {
5626 fptr_finalize(fptr, noraise);
5627 }
5628}
5629
5630static void
5631free_io_buffer(rb_io_buffer_t *buf)
5632{
5633 if (buf->ptr) {
5634 ruby_sized_xfree(buf->ptr, (size_t)buf->capa);
5635 buf->ptr = NULL;
5636 }
5637}
5638
5639static void
5640clear_readconv(rb_io_t *fptr)
5641{
5642 if (fptr->readconv) {
5643 rb_econv_close(fptr->readconv);
5644 fptr->readconv = NULL;
5645 }
5646 free_io_buffer(&fptr->cbuf);
5647}
5648
5649static void
5650clear_writeconv(rb_io_t *fptr)
5651{
5652 if (fptr->writeconv) {
5654 fptr->writeconv = NULL;
5655 }
5656 fptr->writeconv_initialized = 0;
5657}
5658
5659static void
5660clear_codeconv(rb_io_t *fptr)
5661{
5662 clear_readconv(fptr);
5663 clear_writeconv(fptr);
5664}
5665
5666static void
5667rb_io_fptr_cleanup_all(rb_io_t *fptr)
5668{
5669 fptr->pathv = Qnil;
5670 if (0 <= fptr->fd)
5671 rb_io_fptr_cleanup(fptr, TRUE);
5672 fptr->write_lock = Qnil;
5673 free_io_buffer(&fptr->rbuf);
5674 free_io_buffer(&fptr->wbuf);
5675 clear_codeconv(fptr);
5676}
5677
5678int
5680{
5681 if (!io) return 0;
5682 rb_io_fptr_cleanup_all(io);
5683 free(io);
5684
5685 return 1;
5686}
5687
5688size_t
5689rb_io_memsize(const rb_io_t *fptr)
5690{
5691 size_t size = sizeof(rb_io_t);
5692 size += fptr->rbuf.capa;
5693 size += fptr->wbuf.capa;
5694 size += fptr->cbuf.capa;
5695 if (fptr->readconv) size += rb_econv_memsize(fptr->readconv);
5696 if (fptr->writeconv) size += rb_econv_memsize(fptr->writeconv);
5697 return size;
5698}
5699
5700#ifdef _WIN32
5701/* keep GVL while closing to prevent crash on Windows */
5702# define KEEPGVL TRUE
5703#else
5704# define KEEPGVL FALSE
5705#endif
5706
5707static rb_io_t *
5708io_close_fptr(VALUE io)
5709{
5710 rb_io_t *fptr;
5711 VALUE write_io;
5712 rb_io_t *write_fptr;
5713 struct rb_io_close_wait_list busy;
5714
5715 write_io = GetWriteIO(io);
5716 if (io != write_io) {
5717 write_fptr = RFILE(write_io)->fptr;
5718 if (write_fptr && 0 <= write_fptr->fd) {
5719 rb_io_fptr_cleanup(write_fptr, TRUE);
5720 }
5721 }
5722
5723 fptr = RFILE(io)->fptr;
5724 if (!fptr) return 0;
5725 if (fptr->fd < 0) return 0;
5726
5727 if (rb_notify_fd_close(fptr->fd, &busy)) {
5728 /* calls close(fptr->fd): */
5729 fptr_finalize_flush(fptr, FALSE, KEEPGVL, &busy);
5730 }
5731 rb_io_fptr_cleanup(fptr, FALSE);
5732 return fptr;
5733}
5734
5735static void
5736fptr_waitpid(rb_io_t *fptr, int nohang)
5737{
5738 int status;
5739 if (fptr->pid) {
5740 rb_last_status_clear();
5741 rb_waitpid(fptr->pid, &status, nohang ? WNOHANG : 0);
5742 fptr->pid = 0;
5743 }
5744}
5745
5746VALUE
5748{
5749 rb_io_t *fptr = io_close_fptr(io);
5750 if (fptr) fptr_waitpid(fptr, 0);
5751 return Qnil;
5752}
5753
5754/*
5755 * call-seq:
5756 * close -> nil
5757 *
5758 * Closes the stream for both reading and writing
5759 * if open for either or both; returns +nil+.
5760 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5761 *
5762 * If the stream is open for writing, flushes any buffered writes
5763 * to the operating system before closing.
5764 *
5765 * If the stream was opened by IO.popen, sets global variable <tt>$?</tt>
5766 * (child exit status).
5767 *
5768 * It is not an error to close an IO object that has already been closed.
5769 * It just returns nil.
5770 *
5771 * Example:
5772 *
5773 * IO.popen('ruby', 'r+') do |pipe|
5774 * puts pipe.closed?
5775 * pipe.close
5776 * puts $?
5777 * puts pipe.closed?
5778 * end
5779 *
5780 * Output:
5781 *
5782 * false
5783 * pid 13760 exit 0
5784 * true
5785 *
5786 * Related: IO#close_read, IO#close_write, IO#closed?.
5787 */
5788
5789static VALUE
5790rb_io_close_m(VALUE io)
5791{
5792 rb_io_t *fptr = rb_io_get_fptr(io);
5793 if (fptr->fd < 0) {
5794 return Qnil;
5795 }
5796 rb_io_close(io);
5797 return Qnil;
5798}
5799
5800static VALUE
5801io_call_close(VALUE io)
5802{
5803 rb_check_funcall(io, rb_intern("close"), 0, 0);
5804 return io;
5805}
5806
5807static VALUE
5808ignore_closed_stream(VALUE io, VALUE exc)
5809{
5810 enum {mesg_len = sizeof(closed_stream)-1};
5811 VALUE mesg = rb_attr_get(exc, idMesg);
5812 if (!RB_TYPE_P(mesg, T_STRING) ||
5813 RSTRING_LEN(mesg) != mesg_len ||
5814 memcmp(RSTRING_PTR(mesg), closed_stream, mesg_len)) {
5815 rb_exc_raise(exc);
5816 }
5817 return io;
5818}
5819
5820static VALUE
5821io_close(VALUE io)
5822{
5823 VALUE closed = rb_check_funcall(io, rb_intern("closed?"), 0, 0);
5824 if (!UNDEF_P(closed) && RTEST(closed)) return io;
5825 rb_rescue2(io_call_close, io, ignore_closed_stream, io,
5826 rb_eIOError, (VALUE)0);
5827 return io;
5828}
5829
5830/*
5831 * call-seq:
5832 * closed? -> true or false
5833 *
5834 * Returns +true+ if the stream is closed for both reading and writing,
5835 * +false+ otherwise.
5836 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5837 *
5838 * IO.popen('ruby', 'r+') do |pipe|
5839 * puts pipe.closed?
5840 * pipe.close_read
5841 * puts pipe.closed?
5842 * pipe.close_write
5843 * puts pipe.closed?
5844 * end
5845 *
5846 * Output:
5847 *
5848 * false
5849 * false
5850 * true
5851 *
5852 * Related: IO#close_read, IO#close_write, IO#close.
5853 */
5854VALUE
5856{
5857 rb_io_t *fptr;
5858 VALUE write_io;
5859 rb_io_t *write_fptr;
5860
5861 write_io = GetWriteIO(io);
5862 if (io != write_io) {
5863 write_fptr = RFILE(write_io)->fptr;
5864 if (write_fptr && 0 <= write_fptr->fd) {
5865 return Qfalse;
5866 }
5867 }
5868
5869 fptr = rb_io_get_fptr(io);
5870 return RBOOL(0 > fptr->fd);
5871}
5872
5873/*
5874 * call-seq:
5875 * close_read -> nil
5876 *
5877 * Closes the stream for reading if open for reading;
5878 * returns +nil+.
5879 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5880 *
5881 * If the stream was opened by IO.popen and is also closed for writing,
5882 * sets global variable <tt>$?</tt> (child exit status).
5883 *
5884 * Example:
5885 *
5886 * IO.popen('ruby', 'r+') do |pipe|
5887 * puts pipe.closed?
5888 * pipe.close_write
5889 * puts pipe.closed?
5890 * pipe.close_read
5891 * puts $?
5892 * puts pipe.closed?
5893 * end
5894 *
5895 * Output:
5896 *
5897 * false
5898 * false
5899 * pid 14748 exit 0
5900 * true
5901 *
5902 * Related: IO#close, IO#close_write, IO#closed?.
5903 */
5904
5905static VALUE
5906rb_io_close_read(VALUE io)
5907{
5908 rb_io_t *fptr;
5909 VALUE write_io;
5910
5911 fptr = rb_io_get_fptr(rb_io_taint_check(io));
5912 if (fptr->fd < 0) return Qnil;
5913 if (is_socket(fptr->fd, fptr->pathv)) {
5914#ifndef SHUT_RD
5915# define SHUT_RD 0
5916#endif
5917 if (shutdown(fptr->fd, SHUT_RD) < 0)
5918 rb_sys_fail_path(fptr->pathv);
5919 fptr->mode &= ~FMODE_READABLE;
5920 if (!(fptr->mode & FMODE_WRITABLE))
5921 return rb_io_close(io);
5922 return Qnil;
5923 }
5924
5925 write_io = GetWriteIO(io);
5926 if (io != write_io) {
5927 rb_io_t *wfptr;
5928 wfptr = rb_io_get_fptr(rb_io_taint_check(write_io));
5929 wfptr->pid = fptr->pid;
5930 fptr->pid = 0;
5931 RFILE(io)->fptr = wfptr;
5932 /* bind to write_io temporarily to get rid of memory/fd leak */
5933 fptr->tied_io_for_writing = 0;
5934 RFILE(write_io)->fptr = fptr;
5935 rb_io_fptr_cleanup(fptr, FALSE);
5936 /* should not finalize fptr because another thread may be reading it */
5937 return Qnil;
5938 }
5939
5940 if ((fptr->mode & (FMODE_DUPLEX|FMODE_WRITABLE)) == FMODE_WRITABLE) {
5941 rb_raise(rb_eIOError, "closing non-duplex IO for reading");
5942 }
5943 return rb_io_close(io);
5944}
5945
5946/*
5947 * call-seq:
5948 * close_write -> nil
5949 *
5950 * Closes the stream for writing if open for writing;
5951 * returns +nil+.
5952 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5953 *
5954 * Flushes any buffered writes to the operating system before closing.
5955 *
5956 * If the stream was opened by IO.popen and is also closed for reading,
5957 * sets global variable <tt>$?</tt> (child exit status).
5958 *
5959 * IO.popen('ruby', 'r+') do |pipe|
5960 * puts pipe.closed?
5961 * pipe.close_read
5962 * puts pipe.closed?
5963 * pipe.close_write
5964 * puts $?
5965 * puts pipe.closed?
5966 * end
5967 *
5968 * Output:
5969 *
5970 * false
5971 * false
5972 * pid 15044 exit 0
5973 * true
5974 *
5975 * Related: IO#close, IO#close_read, IO#closed?.
5976 */
5977
5978static VALUE
5979rb_io_close_write(VALUE io)
5980{
5981 rb_io_t *fptr;
5982 VALUE write_io;
5983
5984 write_io = GetWriteIO(io);
5985 fptr = rb_io_get_fptr(rb_io_taint_check(write_io));
5986 if (fptr->fd < 0) return Qnil;
5987 if (is_socket(fptr->fd, fptr->pathv)) {
5988#ifndef SHUT_WR
5989# define SHUT_WR 1
5990#endif
5991 if (shutdown(fptr->fd, SHUT_WR) < 0)
5992 rb_sys_fail_path(fptr->pathv);
5993 fptr->mode &= ~FMODE_WRITABLE;
5994 if (!(fptr->mode & FMODE_READABLE))
5995 return rb_io_close(write_io);
5996 return Qnil;
5997 }
5998
5999 if ((fptr->mode & (FMODE_DUPLEX|FMODE_READABLE)) == FMODE_READABLE) {
6000 rb_raise(rb_eIOError, "closing non-duplex IO for writing");
6001 }
6002
6003 if (io != write_io) {
6004 fptr = rb_io_get_fptr(rb_io_taint_check(io));
6005 fptr->tied_io_for_writing = 0;
6006 }
6007 rb_io_close(write_io);
6008 return Qnil;
6009}
6010
6011/*
6012 * call-seq:
6013 * sysseek(offset, whence = IO::SEEK_SET) -> integer
6014 *
6015 * Behaves like IO#seek, except that it:
6016 *
6017 * - Uses low-level system functions.
6018 * - Returns the new position.
6019 *
6020 */
6021
6022static VALUE
6023rb_io_sysseek(int argc, VALUE *argv, VALUE io)
6024{
6025 VALUE offset, ptrname;
6026 int whence = SEEK_SET;
6027 rb_io_t *fptr;
6028 rb_off_t pos;
6029
6030 if (rb_scan_args(argc, argv, "11", &offset, &ptrname) == 2) {
6031 whence = interpret_seek_whence(ptrname);
6032 }
6033 pos = NUM2OFFT(offset);
6034 GetOpenFile(io, fptr);
6035 if ((fptr->mode & FMODE_READABLE) &&
6036 (READ_DATA_BUFFERED(fptr) || READ_CHAR_PENDING(fptr))) {
6037 rb_raise(rb_eIOError, "sysseek for buffered IO");
6038 }
6039 if ((fptr->mode & FMODE_WRITABLE) && fptr->wbuf.len) {
6040 rb_warn("sysseek for buffered IO");
6041 }
6042 errno = 0;
6043 pos = lseek(fptr->fd, pos, whence);
6044 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
6045
6046 return OFFT2NUM(pos);
6047}
6048
6049/*
6050 * call-seq:
6051 * syswrite(object) -> integer
6052 *
6053 * Writes the given +object+ to self, which must be opened for writing (see Modes);
6054 * returns the number bytes written.
6055 * If +object+ is not a string is converted via method to_s:
6056 *
6057 * f = File.new('t.tmp', 'w')
6058 * f.syswrite('foo') # => 3
6059 * f.syswrite(30) # => 2
6060 * f.syswrite(:foo) # => 3
6061 * f.close
6062 *
6063 * This methods should not be used with other stream-writer methods.
6064 *
6065 */
6066
6067static VALUE
6068rb_io_syswrite(VALUE io, VALUE str)
6069{
6070 VALUE tmp;
6071 rb_io_t *fptr;
6072 long n, len;
6073 const char *ptr;
6074
6075 if (!RB_TYPE_P(str, T_STRING))
6076 str = rb_obj_as_string(str);
6077
6078 io = GetWriteIO(io);
6079 GetOpenFile(io, fptr);
6081
6082 if (fptr->wbuf.len) {
6083 rb_warn("syswrite for buffered IO");
6084 }
6085
6086 tmp = rb_str_tmp_frozen_acquire(str);
6087 RSTRING_GETMEM(tmp, ptr, len);
6088 n = rb_io_write_memory(fptr, ptr, len);
6089 if (n < 0) rb_sys_fail_path(fptr->pathv);
6090 rb_str_tmp_frozen_release(str, tmp);
6091
6092 return LONG2FIX(n);
6093}
6094
6095/*
6096 * call-seq:
6097 * sysread(maxlen) -> string
6098 * sysread(maxlen, out_string) -> string
6099 *
6100 * Behaves like IO#readpartial, except that it uses low-level system functions.
6101 *
6102 * This method should not be used with other stream-reader methods.
6103 *
6104 */
6105
6106static VALUE
6107rb_io_sysread(int argc, VALUE *argv, VALUE io)
6108{
6109 VALUE len, str;
6110 rb_io_t *fptr;
6111 long n, ilen;
6112 struct io_internal_read_struct iis;
6113 int shrinkable;
6114
6115 rb_scan_args(argc, argv, "11", &len, &str);
6116 ilen = NUM2LONG(len);
6117
6118 shrinkable = io_setstrbuf(&str, ilen);
6119 if (ilen == 0) return str;
6120
6121 GetOpenFile(io, fptr);
6123
6124 if (READ_DATA_BUFFERED(fptr)) {
6125 rb_raise(rb_eIOError, "sysread for buffered IO");
6126 }
6127
6128 rb_io_check_closed(fptr);
6129
6130 io_setstrbuf(&str, ilen);
6131 iis.th = rb_thread_current();
6132 iis.fptr = fptr;
6133 iis.nonblock = 0;
6134 iis.fd = fptr->fd;
6135 iis.buf = RSTRING_PTR(str);
6136 iis.capa = ilen;
6137 iis.timeout = NULL;
6138 n = io_read_memory_locktmp(str, &iis);
6139
6140 if (n < 0) {
6141 rb_sys_fail_path(fptr->pathv);
6142 }
6143
6144 io_set_read_length(str, n, shrinkable);
6145
6146 if (n == 0 && ilen > 0) {
6147 rb_eof_error();
6148 }
6149
6150 return str;
6151}
6152
6154 struct rb_io *io;
6155 int fd;
6156 void *buf;
6157 size_t count;
6158 rb_off_t offset;
6159};
6160
6161static VALUE
6162internal_pread_func(void *_arg)
6163{
6164 struct prdwr_internal_arg *arg = _arg;
6165
6166 return (VALUE)pread(arg->fd, arg->buf, arg->count, arg->offset);
6167}
6168
6169static VALUE
6170pread_internal_call(VALUE _arg)
6171{
6172 struct prdwr_internal_arg *arg = (struct prdwr_internal_arg *)_arg;
6173
6174 VALUE scheduler = rb_fiber_scheduler_current();
6175 if (scheduler != Qnil) {
6176 VALUE result = rb_fiber_scheduler_io_pread_memory(scheduler, arg->io->self, arg->offset, arg->buf, arg->count, 0);
6177
6178 if (!UNDEF_P(result)) {
6180 }
6181 }
6182
6183 return rb_io_blocking_region_wait(arg->io, internal_pread_func, arg, RUBY_IO_READABLE);
6184}
6185
6186/*
6187 * call-seq:
6188 * pread(maxlen, offset) -> string
6189 * pread(maxlen, offset, out_string) -> string
6190 *
6191 * Behaves like IO#readpartial, except that it:
6192 *
6193 * - Reads at the given +offset+ (in bytes).
6194 * - Disregards, and does not modify, the stream's position
6195 * (see {Position}[rdoc-ref:IO@Position]).
6196 * - Bypasses any user space buffering in the stream.
6197 *
6198 * Because this method does not disturb the stream's state
6199 * (its position, in particular), +pread+ allows multiple threads and processes
6200 * to use the same \IO object for reading at various offsets.
6201 *
6202 * f = File.open('t.txt')
6203 * f.read # => "First line\nSecond line\n\nFourth line\nFifth line\n"
6204 * f.pos # => 52
6205 * # Read 12 bytes at offset 0.
6206 * f.pread(12, 0) # => "First line\n"
6207 * # Read 9 bytes at offset 8.
6208 * f.pread(9, 8) # => "ne\nSecon"
6209 * f.close
6210 *
6211 * Not available on some platforms.
6212 *
6213 */
6214static VALUE
6215rb_io_pread(int argc, VALUE *argv, VALUE io)
6216{
6217 VALUE len, offset, str;
6218 rb_io_t *fptr;
6219 ssize_t n;
6220 struct prdwr_internal_arg arg;
6221 int shrinkable;
6222
6223 rb_scan_args(argc, argv, "21", &len, &offset, &str);
6224 arg.count = NUM2SIZET(len);
6225 arg.offset = NUM2OFFT(offset);
6226
6227 shrinkable = io_setstrbuf(&str, (long)arg.count);
6228 if (arg.count == 0) return str;
6229 arg.buf = RSTRING_PTR(str);
6230
6231 GetOpenFile(io, fptr);
6233
6234 arg.io = fptr;
6235 arg.fd = fptr->fd;
6236 rb_io_check_closed(fptr);
6237
6238 rb_str_locktmp(str);
6239 n = (ssize_t)rb_ensure(pread_internal_call, (VALUE)&arg, rb_str_unlocktmp, str);
6240
6241 if (n < 0) {
6242 rb_sys_fail_path(fptr->pathv);
6243 }
6244 io_set_read_length(str, n, shrinkable);
6245 if (n == 0 && arg.count > 0) {
6246 rb_eof_error();
6247 }
6248
6249 return str;
6250}
6251
6252static VALUE
6253internal_pwrite_func(void *_arg)
6254{
6255 struct prdwr_internal_arg *arg = _arg;
6256
6257 VALUE scheduler = rb_fiber_scheduler_current();
6258 if (scheduler != Qnil) {
6259 VALUE result = rb_fiber_scheduler_io_pwrite_memory(scheduler, arg->io->self, arg->offset, arg->buf, arg->count, 0);
6260
6261 if (!UNDEF_P(result)) {
6263 }
6264 }
6265
6266
6267 return (VALUE)pwrite(arg->fd, arg->buf, arg->count, arg->offset);
6268}
6269
6270/*
6271 * call-seq:
6272 * pwrite(object, offset) -> integer
6273 *
6274 * Behaves like IO#write, except that it:
6275 *
6276 * - Writes at the given +offset+ (in bytes).
6277 * - Disregards, and does not modify, the stream's position
6278 * (see {Position}[rdoc-ref:IO@Position]).
6279 * - Bypasses any user space buffering in the stream.
6280 *
6281 * Because this method does not disturb the stream's state
6282 * (its position, in particular), +pwrite+ allows multiple threads and processes
6283 * to use the same \IO object for writing at various offsets.
6284 *
6285 * f = File.open('t.tmp', 'w+')
6286 * # Write 6 bytes at offset 3.
6287 * f.pwrite('ABCDEF', 3) # => 6
6288 * f.rewind
6289 * f.read # => "\u0000\u0000\u0000ABCDEF"
6290 * f.close
6291 *
6292 * Not available on some platforms.
6293 *
6294 */
6295static VALUE
6296rb_io_pwrite(VALUE io, VALUE str, VALUE offset)
6297{
6298 rb_io_t *fptr;
6299 ssize_t n;
6300 struct prdwr_internal_arg arg;
6301 VALUE tmp;
6302
6303 if (!RB_TYPE_P(str, T_STRING))
6304 str = rb_obj_as_string(str);
6305
6306 arg.offset = NUM2OFFT(offset);
6307
6308 io = GetWriteIO(io);
6309 GetOpenFile(io, fptr);
6311
6312 arg.io = fptr;
6313 arg.fd = fptr->fd;
6314
6315 tmp = rb_str_tmp_frozen_acquire(str);
6316 arg.buf = RSTRING_PTR(tmp);
6317 arg.count = (size_t)RSTRING_LEN(tmp);
6318
6319 n = (ssize_t)rb_io_blocking_region_wait(fptr, internal_pwrite_func, &arg, RUBY_IO_WRITABLE);
6320 if (n < 0) rb_sys_fail_path(fptr->pathv);
6321 rb_str_tmp_frozen_release(str, tmp);
6322
6323 return SSIZET2NUM(n);
6324}
6325
6326VALUE
6328{
6329 rb_io_t *fptr;
6330
6331 GetOpenFile(io, fptr);
6332 if (fptr->readconv)
6334 if (fptr->writeconv)
6336 fptr->mode |= FMODE_BINMODE;
6337 fptr->mode &= ~FMODE_TEXTMODE;
6338 fptr->writeconv_pre_ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
6339#ifdef O_BINARY
6340 if (!fptr->readconv) {
6341 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6342 }
6343 else {
6344 setmode(fptr->fd, O_BINARY);
6345 }
6346#endif
6347 return io;
6348}
6349
6350static void
6351io_ascii8bit_binmode(rb_io_t *fptr)
6352{
6353 if (fptr->readconv) {
6354 rb_econv_close(fptr->readconv);
6355 fptr->readconv = NULL;
6356 }
6357 if (fptr->writeconv) {
6359 fptr->writeconv = NULL;
6360 }
6361 fptr->mode |= FMODE_BINMODE;
6362 fptr->mode &= ~FMODE_TEXTMODE;
6363 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6364
6365 fptr->encs.enc = rb_ascii8bit_encoding();
6366 fptr->encs.enc2 = NULL;
6367 fptr->encs.ecflags = 0;
6368 fptr->encs.ecopts = Qnil;
6369 clear_codeconv(fptr);
6370}
6371
6372VALUE
6374{
6375 rb_io_t *fptr;
6376
6377 GetOpenFile(io, fptr);
6378 io_ascii8bit_binmode(fptr);
6379
6380 return io;
6381}
6382
6383/*
6384 * call-seq:
6385 * binmode -> self
6386 *
6387 * Sets the stream's data mode as binary
6388 * (see {Data Mode}[rdoc-ref:File@Data+Mode]).
6389 *
6390 * A stream's data mode may not be changed from binary to text.
6391 *
6392 */
6393
6394static VALUE
6395rb_io_binmode_m(VALUE io)
6396{
6397 VALUE write_io;
6398
6400
6401 write_io = GetWriteIO(io);
6402 if (write_io != io)
6403 rb_io_ascii8bit_binmode(write_io);
6404 return io;
6405}
6406
6407/*
6408 * call-seq:
6409 * binmode? -> true or false
6410 *
6411 * Returns +true+ if the stream is on binary mode, +false+ otherwise.
6412 * See {Data Mode}[rdoc-ref:File@Data+Mode].
6413 *
6414 */
6415static VALUE
6416rb_io_binmode_p(VALUE io)
6417{
6418 rb_io_t *fptr;
6419 GetOpenFile(io, fptr);
6420 return RBOOL(fptr->mode & FMODE_BINMODE);
6421}
6422
6423static const char*
6424rb_io_fmode_modestr(enum rb_io_mode fmode)
6425{
6426 if (fmode & FMODE_APPEND) {
6427 if ((fmode & FMODE_READWRITE) == FMODE_READWRITE) {
6428 return MODE_BTMODE("a+", "ab+", "at+");
6429 }
6430 return MODE_BTMODE("a", "ab", "at");
6431 }
6432 switch (fmode & FMODE_READWRITE) {
6433 default:
6434 rb_raise(rb_eArgError, "invalid access fmode 0x%x", fmode);
6435 case FMODE_READABLE:
6436 return MODE_BTMODE("r", "rb", "rt");
6437 case FMODE_WRITABLE:
6438 return MODE_BTXMODE("w", "wb", "wt", "wx", "wbx", "wtx");
6439 case FMODE_READWRITE:
6440 if (fmode & FMODE_CREATE) {
6441 return MODE_BTXMODE("w+", "wb+", "wt+", "w+x", "wb+x", "wt+x");
6442 }
6443 return MODE_BTMODE("r+", "rb+", "rt+");
6444 }
6445}
6446
6447static const char bom_prefix[] = "bom|";
6448static const char utf_prefix[] = "utf-";
6449enum {bom_prefix_len = (int)sizeof(bom_prefix) - 1};
6450enum {utf_prefix_len = (int)sizeof(utf_prefix) - 1};
6451
6452static int
6453io_encname_bom_p(const char *name, long len)
6454{
6455 return len > bom_prefix_len && STRNCASECMP(name, bom_prefix, bom_prefix_len) == 0;
6456}
6457
6458enum rb_io_mode
6459rb_io_modestr_fmode(const char *modestr)
6460{
6461 enum rb_io_mode fmode = 0;
6462 const char *m = modestr, *p = NULL;
6463
6464 switch (*m++) {
6465 case 'r':
6466 fmode |= FMODE_READABLE;
6467 break;
6468 case 'w':
6470 break;
6471 case 'a':
6473 break;
6474 default:
6475 goto error;
6476 }
6477
6478 while (*m) {
6479 switch (*m++) {
6480 case 'b':
6481 fmode |= FMODE_BINMODE;
6482 break;
6483 case 't':
6484 fmode |= FMODE_TEXTMODE;
6485 break;
6486 case '+':
6487 fmode |= FMODE_READWRITE;
6488 break;
6489 case 'x':
6490 if (modestr[0] != 'w')
6491 goto error;
6492 fmode |= FMODE_EXCL;
6493 break;
6494 default:
6495 goto error;
6496 case ':':
6497 p = strchr(m, ':');
6498 if (io_encname_bom_p(m, p ? (long)(p - m) : (long)strlen(m)))
6499 fmode |= FMODE_SETENC_BY_BOM;
6500 goto finished;
6501 }
6502 }
6503
6504 finished:
6505 if ((fmode & FMODE_BINMODE) && (fmode & FMODE_TEXTMODE))
6506 goto error;
6507
6508 return fmode;
6509
6510 error:
6511 rb_raise(rb_eArgError, "invalid access mode %s", modestr);
6513}
6514
6515int
6516rb_io_oflags_fmode(int oflags)
6517{
6518 enum rb_io_mode fmode = 0;
6519
6520 switch (oflags & O_ACCMODE) {
6521 case O_RDONLY:
6522 fmode = FMODE_READABLE;
6523 break;
6524 case O_WRONLY:
6525 fmode = FMODE_WRITABLE;
6526 break;
6527 case O_RDWR:
6528 fmode = FMODE_READWRITE;
6529 break;
6530 }
6531
6532 if (oflags & O_APPEND) {
6533 fmode |= FMODE_APPEND;
6534 }
6535 if (oflags & O_TRUNC) {
6536 fmode |= FMODE_TRUNC;
6537 }
6538 if (oflags & O_CREAT) {
6539 fmode |= FMODE_CREATE;
6540 }
6541 if (oflags & O_EXCL) {
6542 fmode |= FMODE_EXCL;
6543 }
6544#ifdef O_BINARY
6545 if (oflags & O_BINARY) {
6546 fmode |= FMODE_BINMODE;
6547 }
6548#endif
6549
6550 return fmode;
6551}
6552
6553static int
6554rb_io_fmode_oflags(enum rb_io_mode fmode)
6555{
6556 int oflags = 0;
6557
6558 switch (fmode & FMODE_READWRITE) {
6559 case FMODE_READABLE:
6560 oflags |= O_RDONLY;
6561 break;
6562 case FMODE_WRITABLE:
6563 oflags |= O_WRONLY;
6564 break;
6565 case FMODE_READWRITE:
6566 oflags |= O_RDWR;
6567 break;
6568 }
6569
6570 if (fmode & FMODE_APPEND) {
6571 oflags |= O_APPEND;
6572 }
6573 if (fmode & FMODE_TRUNC) {
6574 oflags |= O_TRUNC;
6575 }
6576 if (fmode & FMODE_CREATE) {
6577 oflags |= O_CREAT;
6578 }
6579 if (fmode & FMODE_EXCL) {
6580 oflags |= O_EXCL;
6581 }
6582#ifdef O_BINARY
6583 if (fmode & FMODE_BINMODE) {
6584 oflags |= O_BINARY;
6585 }
6586#endif
6587
6588 return oflags;
6589}
6590
6591int
6592rb_io_modestr_oflags(const char *modestr)
6593{
6594 return rb_io_fmode_oflags(rb_io_modestr_fmode(modestr));
6595}
6596
6597static const char*
6598rb_io_oflags_modestr(int oflags)
6599{
6600#ifdef O_BINARY
6601# define MODE_BINARY(a,b) ((oflags & O_BINARY) ? (b) : (a))
6602#else
6603# define MODE_BINARY(a,b) (a)
6604#endif
6605 int accmode;
6606 if (oflags & O_EXCL) {
6607 rb_raise(rb_eArgError, "exclusive access mode is not supported");
6608 }
6609 accmode = oflags & (O_RDONLY|O_WRONLY|O_RDWR);
6610 if (oflags & O_APPEND) {
6611 if (accmode == O_WRONLY) {
6612 return MODE_BINARY("a", "ab");
6613 }
6614 if (accmode == O_RDWR) {
6615 return MODE_BINARY("a+", "ab+");
6616 }
6617 }
6618 switch (accmode) {
6619 default:
6620 rb_raise(rb_eArgError, "invalid access oflags 0x%x", oflags);
6621 case O_RDONLY:
6622 return MODE_BINARY("r", "rb");
6623 case O_WRONLY:
6624 return MODE_BINARY("w", "wb");
6625 case O_RDWR:
6626 if (oflags & O_TRUNC) {
6627 return MODE_BINARY("w+", "wb+");
6628 }
6629 return MODE_BINARY("r+", "rb+");
6630 }
6631}
6632
6633/*
6634 * Convert external/internal encodings to enc/enc2
6635 * NULL => use default encoding
6636 * Qnil => no encoding specified (internal only)
6637 */
6638static void
6639rb_io_ext_int_to_encs(rb_encoding *ext, rb_encoding *intern, rb_encoding **enc, rb_encoding **enc2, enum rb_io_mode fmode)
6640{
6641 int default_ext = 0;
6642
6643 if (ext == NULL) {
6644 ext = rb_default_external_encoding();
6645 default_ext = 1;
6646 }
6647 if (rb_is_ascii8bit_enc(ext)) {
6648 /* If external is ASCII-8BIT, no transcoding */
6649 intern = NULL;
6650 }
6651 else if (intern == NULL) {
6652 intern = rb_default_internal_encoding();
6653 }
6654 if (intern == NULL || intern == (rb_encoding *)Qnil ||
6655 (!(fmode & FMODE_SETENC_BY_BOM) && (intern == ext))) {
6656 /* No internal encoding => use external + no transcoding */
6657 *enc = (default_ext && intern != ext) ? NULL : ext;
6658 *enc2 = NULL;
6659 }
6660 else {
6661 *enc = intern;
6662 *enc2 = ext;
6663 }
6664}
6665
6666static void
6667unsupported_encoding(const char *name, rb_encoding *enc)
6668{
6669 rb_enc_warn(enc, "Unsupported encoding %s ignored", name);
6670}
6671
6672static void
6673parse_mode_enc(const char *estr, rb_encoding *estr_enc,
6674 rb_encoding **enc_p, rb_encoding **enc2_p, enum rb_io_mode *fmode_p)
6675{
6676 const char *p;
6677 char encname[ENCODING_MAXNAMELEN+1];
6678 int idx, idx2;
6679 enum rb_io_mode fmode = fmode_p ? *fmode_p : 0;
6680 rb_encoding *ext_enc, *int_enc;
6681 long len;
6682
6683 /* parse estr as "enc" or "enc2:enc" or "enc:-" */
6684
6685 p = strrchr(estr, ':');
6686 len = p ? (p++ - estr) : (long)strlen(estr);
6687 if ((fmode & FMODE_SETENC_BY_BOM) || io_encname_bom_p(estr, len)) {
6688 estr += bom_prefix_len;
6689 len -= bom_prefix_len;
6690 if (!STRNCASECMP(estr, utf_prefix, utf_prefix_len)) {
6691 fmode |= FMODE_SETENC_BY_BOM;
6692 }
6693 else {
6694 rb_enc_warn(estr_enc, "BOM with non-UTF encoding %s is nonsense", estr);
6695 fmode &= ~FMODE_SETENC_BY_BOM;
6696 }
6697 }
6698 if (len == 0 || len > ENCODING_MAXNAMELEN) {
6699 idx = -1;
6700 }
6701 else {
6702 if (p) {
6703 memcpy(encname, estr, len);
6704 encname[len] = '\0';
6705 estr = encname;
6706 }
6707 idx = rb_enc_find_index(estr);
6708 }
6709 if (fmode_p) *fmode_p = fmode;
6710
6711 if (idx >= 0)
6712 ext_enc = rb_enc_from_index(idx);
6713 else {
6714 if (idx != -2)
6715 unsupported_encoding(estr, estr_enc);
6716 ext_enc = NULL;
6717 }
6718
6719 int_enc = NULL;
6720 if (p) {
6721 if (*p == '-' && *(p+1) == '\0') {
6722 /* Special case - "-" => no transcoding */
6723 int_enc = (rb_encoding *)Qnil;
6724 }
6725 else {
6726 idx2 = rb_enc_find_index(p);
6727 if (idx2 < 0)
6728 unsupported_encoding(p, estr_enc);
6729 else if (!(fmode & FMODE_SETENC_BY_BOM) && (idx2 == idx)) {
6730 int_enc = (rb_encoding *)Qnil;
6731 }
6732 else
6733 int_enc = rb_enc_from_index(idx2);
6734 }
6735 }
6736
6737 rb_io_ext_int_to_encs(ext_enc, int_enc, enc_p, enc2_p, fmode);
6738}
6739
6740int
6741rb_io_extract_encoding_option(VALUE opt, rb_encoding **enc_p, rb_encoding **enc2_p, enum rb_io_mode *fmode_p)
6742{
6743 VALUE encoding=Qnil, extenc=Qundef, intenc=Qundef, tmp;
6744 int extracted = 0;
6745 rb_encoding *extencoding = NULL;
6746 rb_encoding *intencoding = NULL;
6747
6748 if (!NIL_P(opt)) {
6749 VALUE v;
6750 v = rb_hash_lookup2(opt, sym_encoding, Qnil);
6751 if (v != Qnil) encoding = v;
6752 v = rb_hash_lookup2(opt, sym_extenc, Qundef);
6753 if (v != Qnil) extenc = v;
6754 v = rb_hash_lookup2(opt, sym_intenc, Qundef);
6755 if (!UNDEF_P(v)) intenc = v;
6756 }
6757 if ((!UNDEF_P(extenc) || !UNDEF_P(intenc)) && !NIL_P(encoding)) {
6758 if (!NIL_P(ruby_verbose)) {
6759 int idx = rb_to_encoding_index(encoding);
6760 if (idx >= 0) encoding = rb_enc_from_encoding(rb_enc_from_index(idx));
6761 rb_warn("Ignoring encoding parameter '%"PRIsVALUE"': %s_encoding is used",
6762 encoding, UNDEF_P(extenc) ? "internal" : "external");
6763 }
6764 encoding = Qnil;
6765 }
6766 if (!UNDEF_P(extenc) && !NIL_P(extenc)) {
6767 extencoding = rb_to_encoding(extenc);
6768 }
6769 if (!UNDEF_P(intenc)) {
6770 if (NIL_P(intenc)) {
6771 /* internal_encoding: nil => no transcoding */
6772 intencoding = (rb_encoding *)Qnil;
6773 }
6774 else if (!NIL_P(tmp = rb_check_string_type(intenc))) {
6775 char *p = StringValueCStr(tmp);
6776
6777 if (*p == '-' && *(p+1) == '\0') {
6778 /* Special case - "-" => no transcoding */
6779 intencoding = (rb_encoding *)Qnil;
6780 }
6781 else {
6782 intencoding = rb_to_encoding(intenc);
6783 }
6784 }
6785 else {
6786 intencoding = rb_to_encoding(intenc);
6787 }
6788 if (extencoding == intencoding) {
6789 intencoding = (rb_encoding *)Qnil;
6790 }
6791 }
6792 if (!NIL_P(encoding)) {
6793 extracted = 1;
6794 if (!NIL_P(tmp = rb_check_string_type(encoding))) {
6795 parse_mode_enc(StringValueCStr(tmp), rb_enc_get(tmp),
6796 enc_p, enc2_p, fmode_p);
6797 }
6798 else {
6799 rb_io_ext_int_to_encs(rb_to_encoding(encoding), NULL, enc_p, enc2_p, 0);
6800 }
6801 }
6802 else if (!UNDEF_P(extenc) || !UNDEF_P(intenc)) {
6803 extracted = 1;
6804 rb_io_ext_int_to_encs(extencoding, intencoding, enc_p, enc2_p, 0);
6805 }
6806 return extracted;
6807}
6808
6809static void
6810validate_enc_binmode(enum rb_io_mode *fmode_p, int ecflags, rb_encoding *enc, rb_encoding *enc2)
6811{
6812 enum rb_io_mode fmode = *fmode_p;
6813
6814 if ((fmode & FMODE_READABLE) &&
6815 !enc2 &&
6816 !(fmode & FMODE_BINMODE) &&
6817 !rb_enc_asciicompat(enc ? enc : rb_default_external_encoding()))
6818 rb_raise(rb_eArgError, "ASCII incompatible encoding needs binmode");
6819
6820 if ((fmode & FMODE_BINMODE) && (ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
6821 rb_raise(rb_eArgError, "newline decorator with binary mode");
6822 }
6823 if (!(fmode & FMODE_BINMODE) &&
6824 (DEFAULT_TEXTMODE || (ecflags & ECONV_NEWLINE_DECORATOR_MASK))) {
6825 fmode |= FMODE_TEXTMODE;
6826 *fmode_p = fmode;
6827 }
6828#if !DEFAULT_TEXTMODE
6829 else if (!(ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
6830 fmode &= ~FMODE_TEXTMODE;
6831 *fmode_p = fmode;
6832 }
6833#endif
6834}
6835
6836static void
6837extract_binmode(VALUE opthash, enum rb_io_mode *fmode)
6838{
6839 if (!NIL_P(opthash)) {
6840 VALUE v;
6841 v = rb_hash_aref(opthash, sym_textmode);
6842 if (!NIL_P(v)) {
6843 if (*fmode & FMODE_TEXTMODE)
6844 rb_raise(rb_eArgError, "textmode specified twice");
6845 if (*fmode & FMODE_BINMODE)
6846 rb_raise(rb_eArgError, "both textmode and binmode specified");
6847 if (RTEST(v))
6848 *fmode |= FMODE_TEXTMODE;
6849 }
6850 v = rb_hash_aref(opthash, sym_binmode);
6851 if (!NIL_P(v)) {
6852 if (*fmode & FMODE_BINMODE)
6853 rb_raise(rb_eArgError, "binmode specified twice");
6854 if (*fmode & FMODE_TEXTMODE)
6855 rb_raise(rb_eArgError, "both textmode and binmode specified");
6856 if (RTEST(v))
6857 *fmode |= FMODE_BINMODE;
6858 }
6859
6860 if ((*fmode & FMODE_BINMODE) && (*fmode & FMODE_TEXTMODE))
6861 rb_raise(rb_eArgError, "both textmode and binmode specified");
6862 }
6863}
6864
6865void
6866rb_io_extract_modeenc(VALUE *vmode_p, VALUE *vperm_p, VALUE opthash,
6867 int *oflags_p, enum rb_io_mode *fmode_p, struct rb_io_encoding *convconfig_p)
6868{
6869 VALUE vmode;
6870 int oflags;
6871 enum rb_io_mode fmode;
6872 rb_encoding *enc, *enc2;
6873 int ecflags;
6874 VALUE ecopts;
6875 int has_enc = 0, has_vmode = 0;
6876 VALUE intmode;
6877
6878 vmode = *vmode_p;
6879
6880 /* Set to defaults */
6881 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
6882
6883 vmode_handle:
6884 if (NIL_P(vmode)) {
6885 fmode = FMODE_READABLE;
6886 oflags = O_RDONLY;
6887 }
6888 else if (!NIL_P(intmode = rb_check_to_integer(vmode, "to_int"))) {
6889 vmode = intmode;
6890 oflags = NUM2INT(intmode);
6891 fmode = rb_io_oflags_fmode(oflags);
6892 }
6893 else {
6894 const char *p;
6895
6896 StringValue(vmode);
6897 p = StringValueCStr(vmode);
6898 fmode = rb_io_modestr_fmode(p);
6899 oflags = rb_io_fmode_oflags(fmode);
6900 p = strchr(p, ':');
6901 if (p) {
6902 has_enc = 1;
6903 parse_mode_enc(p+1, rb_enc_get(vmode), &enc, &enc2, &fmode);
6904 }
6905 else {
6906 rb_encoding *e;
6907
6908 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
6909 rb_io_ext_int_to_encs(e, NULL, &enc, &enc2, fmode);
6910 }
6911 }
6912
6913 if (NIL_P(opthash)) {
6914 ecflags = (fmode & FMODE_READABLE) ?
6917#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
6918 ecflags |= (fmode & FMODE_WRITABLE) ?
6919 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
6920 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
6921#endif
6922 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
6923 ecopts = Qnil;
6924 if (fmode & FMODE_BINMODE) {
6925#ifdef O_BINARY
6926 oflags |= O_BINARY;
6927#endif
6928 if (!has_enc)
6929 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
6930 }
6931#if DEFAULT_TEXTMODE
6932 else if (NIL_P(vmode)) {
6933 fmode |= DEFAULT_TEXTMODE;
6934 }
6935#endif
6936 }
6937 else {
6938 VALUE v;
6939 if (!has_vmode) {
6940 v = rb_hash_aref(opthash, sym_mode);
6941 if (!NIL_P(v)) {
6942 if (!NIL_P(vmode)) {
6943 rb_raise(rb_eArgError, "mode specified twice");
6944 }
6945 has_vmode = 1;
6946 vmode = v;
6947 goto vmode_handle;
6948 }
6949 }
6950 v = rb_hash_aref(opthash, sym_flags);
6951 if (!NIL_P(v)) {
6952 v = rb_to_int(v);
6953 oflags |= NUM2INT(v);
6954 vmode = INT2NUM(oflags);
6955 fmode = rb_io_oflags_fmode(oflags);
6956 }
6957 extract_binmode(opthash, &fmode);
6958 if (fmode & FMODE_BINMODE) {
6959#ifdef O_BINARY
6960 oflags |= O_BINARY;
6961#endif
6962 if (!has_enc)
6963 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
6964 }
6965#if DEFAULT_TEXTMODE
6966 else if (NIL_P(vmode)) {
6967 fmode |= DEFAULT_TEXTMODE;
6968 }
6969#endif
6970 v = rb_hash_aref(opthash, sym_perm);
6971 if (!NIL_P(v)) {
6972 if (vperm_p) {
6973 if (!NIL_P(*vperm_p)) {
6974 rb_raise(rb_eArgError, "perm specified twice");
6975 }
6976 *vperm_p = v;
6977 }
6978 else {
6979 /* perm no use, just ignore */
6980 }
6981 }
6982 ecflags = (fmode & FMODE_READABLE) ?
6985#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
6986 ecflags |= (fmode & FMODE_WRITABLE) ?
6987 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
6988 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
6989#endif
6990
6991 if (rb_io_extract_encoding_option(opthash, &enc, &enc2, &fmode)) {
6992 if (has_enc) {
6993 rb_raise(rb_eArgError, "encoding specified twice");
6994 }
6995 }
6996 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
6997 ecflags = rb_econv_prepare_options(opthash, &ecopts, ecflags);
6998 }
6999
7000 validate_enc_binmode(&fmode, ecflags, enc, enc2);
7001
7002 *vmode_p = vmode;
7003
7004 *oflags_p = oflags;
7005 *fmode_p = fmode;
7006 convconfig_p->enc = enc;
7007 convconfig_p->enc2 = enc2;
7008 convconfig_p->ecflags = ecflags;
7009 convconfig_p->ecopts = ecopts;
7010}
7011
7013 VALUE fname;
7014 int oflags;
7015 mode_t perm;
7016};
7017
7018static void *
7019sysopen_func(void *ptr)
7020{
7021 const struct sysopen_struct *data = ptr;
7022 const char *fname = RSTRING_PTR(data->fname);
7023 return (void *)(VALUE)rb_cloexec_open(fname, data->oflags, data->perm);
7024}
7025
7026static inline int
7027rb_sysopen_internal(struct sysopen_struct *data)
7028{
7029 int fd;
7030 do {
7031 fd = IO_WITHOUT_GVL_INT(sysopen_func, data);
7032 } while (fd < 0 && errno == EINTR);
7033 if (0 <= fd)
7034 rb_update_max_fd(fd);
7035 return fd;
7036}
7037
7038static int
7039rb_sysopen(VALUE fname, int oflags, mode_t perm)
7040{
7041 int fd = -1;
7042 struct sysopen_struct data;
7043
7044 data.fname = rb_str_encode_ospath(fname);
7045 StringValueCStr(data.fname);
7046 data.oflags = oflags;
7047 data.perm = perm;
7048
7049 TRY_WITH_GC((fd = rb_sysopen_internal(&data)) >= 0) {
7050 rb_syserr_fail_path(first_errno, fname);
7051 }
7052 return fd;
7053}
7054
7055static inline FILE *
7056fdopen_internal(int fd, const char *modestr)
7057{
7058 FILE *file;
7059
7060#if defined(__sun)
7061 errno = 0;
7062#endif
7063 file = fdopen(fd, modestr);
7064 if (!file) {
7065#ifdef _WIN32
7066 if (errno == 0) errno = EINVAL;
7067#elif defined(__sun)
7068 if (errno == 0) errno = EMFILE;
7069#endif
7070 }
7071 return file;
7072}
7073
7074FILE *
7075rb_fdopen(int fd, const char *modestr)
7076{
7077 FILE *file = 0;
7078
7079 TRY_WITH_GC((file = fdopen_internal(fd, modestr)) != 0) {
7080 rb_syserr_fail(first_errno, 0);
7081 }
7082
7083 /* xxx: should be _IONBF? A buffer in FILE may have trouble. */
7084#ifdef USE_SETVBUF
7085 if (setvbuf(file, NULL, _IOFBF, 0) != 0)
7086 rb_warn("setvbuf() can't be honoured (fd=%d)", fd);
7087#endif
7088 return file;
7089}
7090
7091static int
7092io_check_tty(rb_io_t *fptr)
7093{
7094 int t = isatty(fptr->fd);
7095 if (t)
7096 fptr->mode |= FMODE_TTY|FMODE_DUPLEX;
7097 return t;
7098}
7099
7100static VALUE rb_io_internal_encoding(VALUE);
7101static void io_encoding_set(rb_io_t *, VALUE, VALUE, VALUE);
7102
7103static int
7104io_strip_bom(VALUE io)
7105{
7106 VALUE b1, b2, b3, b4;
7107 rb_io_t *fptr;
7108
7109 GetOpenFile(io, fptr);
7110 if (!(fptr->mode & FMODE_READABLE)) return 0;
7111 if (NIL_P(b1 = rb_io_getbyte(io))) return 0;
7112 switch (b1) {
7113 case INT2FIX(0xEF):
7114 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7115 if (b2 == INT2FIX(0xBB) && !NIL_P(b3 = rb_io_getbyte(io))) {
7116 if (b3 == INT2FIX(0xBF)) {
7117 return rb_utf8_encindex();
7118 }
7119 rb_io_ungetbyte(io, b3);
7120 }
7121 rb_io_ungetbyte(io, b2);
7122 break;
7123
7124 case INT2FIX(0xFE):
7125 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7126 if (b2 == INT2FIX(0xFF)) {
7127 return ENCINDEX_UTF_16BE;
7128 }
7129 rb_io_ungetbyte(io, b2);
7130 break;
7131
7132 case INT2FIX(0xFF):
7133 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7134 if (b2 == INT2FIX(0xFE)) {
7135 b3 = rb_io_getbyte(io);
7136 if (b3 == INT2FIX(0) && !NIL_P(b4 = rb_io_getbyte(io))) {
7137 if (b4 == INT2FIX(0)) {
7138 return ENCINDEX_UTF_32LE;
7139 }
7140 rb_io_ungetbyte(io, b4);
7141 }
7142 rb_io_ungetbyte(io, b3);
7143 return ENCINDEX_UTF_16LE;
7144 }
7145 rb_io_ungetbyte(io, b2);
7146 break;
7147
7148 case INT2FIX(0):
7149 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7150 if (b2 == INT2FIX(0) && !NIL_P(b3 = rb_io_getbyte(io))) {
7151 if (b3 == INT2FIX(0xFE) && !NIL_P(b4 = rb_io_getbyte(io))) {
7152 if (b4 == INT2FIX(0xFF)) {
7153 return ENCINDEX_UTF_32BE;
7154 }
7155 rb_io_ungetbyte(io, b4);
7156 }
7157 rb_io_ungetbyte(io, b3);
7158 }
7159 rb_io_ungetbyte(io, b2);
7160 break;
7161 }
7162 rb_io_ungetbyte(io, b1);
7163 return 0;
7164}
7165
7166static rb_encoding *
7167io_set_encoding_by_bom(VALUE io)
7168{
7169 int idx = io_strip_bom(io);
7170 rb_io_t *fptr;
7171 rb_encoding *extenc = NULL;
7172
7173 GetOpenFile(io, fptr);
7174 if (idx) {
7175 extenc = rb_enc_from_index(idx);
7176 io_encoding_set(fptr, rb_enc_from_encoding(extenc),
7177 rb_io_internal_encoding(io), Qnil);
7178 }
7179 else {
7180 fptr->encs.enc2 = NULL;
7181 }
7182 return extenc;
7183}
7184
7185static VALUE
7186rb_file_open_generic(VALUE io, VALUE filename, int oflags, enum rb_io_mode fmode,
7187 const struct rb_io_encoding *convconfig, mode_t perm)
7188{
7189 VALUE pathv;
7190 rb_io_t *fptr;
7191 struct rb_io_encoding cc;
7192 if (!convconfig) {
7193 /* Set to default encodings */
7194 rb_io_ext_int_to_encs(NULL, NULL, &cc.enc, &cc.enc2, fmode);
7195 cc.ecflags = 0;
7196 cc.ecopts = Qnil;
7197 convconfig = &cc;
7198 }
7199 validate_enc_binmode(&fmode, convconfig->ecflags,
7200 convconfig->enc, convconfig->enc2);
7201
7202 MakeOpenFile(io, fptr);
7203 fptr->mode = fmode;
7204 fptr->encs = *convconfig;
7205 pathv = rb_str_new_frozen(filename);
7206#ifdef O_TMPFILE
7207 if (!(oflags & O_TMPFILE)) {
7208 fptr->pathv = pathv;
7209 }
7210#else
7211 fptr->pathv = pathv;
7212#endif
7213 fptr->fd = rb_sysopen(pathv, oflags, perm);
7214 io_check_tty(fptr);
7215 if (fmode & FMODE_SETENC_BY_BOM) io_set_encoding_by_bom(io);
7216
7217 return io;
7218}
7219
7220static VALUE
7221rb_file_open_internal(VALUE io, VALUE filename, const char *modestr)
7222{
7223 enum rb_io_mode fmode = rb_io_modestr_fmode(modestr);
7224 const char *p = strchr(modestr, ':');
7225 struct rb_io_encoding convconfig;
7226
7227 if (p) {
7228 parse_mode_enc(p+1, rb_usascii_encoding(),
7229 &convconfig.enc, &convconfig.enc2, &fmode);
7230 }
7231 else {
7232 rb_encoding *e;
7233 /* Set to default encodings */
7234
7235 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
7236 rb_io_ext_int_to_encs(e, NULL, &convconfig.enc, &convconfig.enc2, fmode);
7237 }
7238
7239 convconfig.ecflags = (fmode & FMODE_READABLE) ?
7242#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7243 convconfig.ecflags |= (fmode & FMODE_WRITABLE) ?
7244 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7245 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7246#endif
7247 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.enc2, convconfig.ecflags);
7248 convconfig.ecopts = Qnil;
7249
7250 return rb_file_open_generic(io, filename,
7251 rb_io_fmode_oflags(fmode),
7252 fmode,
7253 &convconfig,
7254 0666);
7255}
7256
7257VALUE
7258rb_file_open_str(VALUE fname, const char *modestr)
7259{
7260 FilePathValue(fname);
7261 return rb_file_open_internal(io_alloc(rb_cFile), fname, modestr);
7262}
7263
7264VALUE
7265rb_file_open(const char *fname, const char *modestr)
7266{
7267 return rb_file_open_internal(io_alloc(rb_cFile), rb_str_new_cstr(fname), modestr);
7268}
7269
7270#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7271static struct pipe_list {
7272 rb_io_t *fptr;
7273 struct pipe_list *next;
7274} *pipe_list;
7275
7276static void
7277pipe_add_fptr(rb_io_t *fptr)
7278{
7279 struct pipe_list *list;
7280
7281 list = ALLOC(struct pipe_list);
7282 list->fptr = fptr;
7283 list->next = pipe_list;
7284 pipe_list = list;
7285}
7286
7287static void
7288pipe_del_fptr(rb_io_t *fptr)
7289{
7290 struct pipe_list **prev = &pipe_list;
7291 struct pipe_list *tmp;
7292
7293 while ((tmp = *prev) != 0) {
7294 if (tmp->fptr == fptr) {
7295 *prev = tmp->next;
7296 free(tmp);
7297 return;
7298 }
7299 prev = &tmp->next;
7300 }
7301}
7302
7303#if defined (_WIN32) || defined(__CYGWIN__)
7304static void
7305pipe_atexit(void)
7306{
7307 struct pipe_list *list = pipe_list;
7308 struct pipe_list *tmp;
7309
7310 while (list) {
7311 tmp = list->next;
7312 rb_io_fptr_finalize(list->fptr);
7313 list = tmp;
7314 }
7315}
7316#endif
7317
7318static void
7319pipe_finalize(rb_io_t *fptr, int noraise)
7320{
7321#if !defined(HAVE_WORKING_FORK) && !defined(_WIN32)
7322 int status = 0;
7323 if (fptr->stdio_file) {
7324 status = pclose(fptr->stdio_file);
7325 }
7326 fptr->fd = -1;
7327 fptr->stdio_file = 0;
7328 rb_last_status_set(status, fptr->pid);
7329#else
7330 fptr_finalize(fptr, noraise);
7331#endif
7332 pipe_del_fptr(fptr);
7333}
7334#endif
7335
7336static void
7337fptr_copy_finalizer(rb_io_t *fptr, const rb_io_t *orig)
7338{
7339#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7340 void (*const old_finalize)(struct rb_io*,int) = fptr->finalize;
7341
7342 if (old_finalize == orig->finalize) return;
7343#endif
7344
7345 fptr->finalize = orig->finalize;
7346
7347#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7348 if (old_finalize != pipe_finalize) {
7349 struct pipe_list *list;
7350 for (list = pipe_list; list; list = list->next) {
7351 if (list->fptr == fptr) break;
7352 }
7353 if (!list) pipe_add_fptr(fptr);
7354 }
7355 else {
7356 pipe_del_fptr(fptr);
7357 }
7358#endif
7359}
7360
7361void
7363{
7365 fptr->mode |= FMODE_SYNC;
7366}
7367
7368void
7369rb_io_unbuffered(rb_io_t *fptr)
7370{
7371 rb_io_synchronized(fptr);
7372}
7373
7374int
7375rb_pipe(int *pipes)
7376{
7377 int ret;
7378 TRY_WITH_GC((ret = rb_cloexec_pipe(pipes)) >= 0);
7379 if (ret == 0) {
7380 rb_update_max_fd(pipes[0]);
7381 rb_update_max_fd(pipes[1]);
7382 }
7383 return ret;
7384}
7385
7386#ifdef _WIN32
7387#define HAVE_SPAWNV 1
7388#define spawnv(mode, cmd, args) rb_w32_uaspawn((mode), (cmd), (args))
7389#define spawn(mode, cmd) rb_w32_uspawn((mode), (cmd), 0)
7390#endif
7391
7392#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7393struct popen_arg {
7394 VALUE execarg_obj;
7395 struct rb_execarg *eargp;
7396 int modef;
7397 int pair[2];
7398 int write_pair[2];
7399};
7400#endif
7401
7402#ifdef HAVE_WORKING_FORK
7403# ifndef __EMSCRIPTEN__
7404static void
7405popen_redirect(struct popen_arg *p)
7406{
7407 if ((p->modef & FMODE_READABLE) && (p->modef & FMODE_WRITABLE)) {
7408 close(p->write_pair[1]);
7409 if (p->write_pair[0] != 0) {
7410 dup2(p->write_pair[0], 0);
7411 close(p->write_pair[0]);
7412 }
7413 close(p->pair[0]);
7414 if (p->pair[1] != 1) {
7415 dup2(p->pair[1], 1);
7416 close(p->pair[1]);
7417 }
7418 }
7419 else if (p->modef & FMODE_READABLE) {
7420 close(p->pair[0]);
7421 if (p->pair[1] != 1) {
7422 dup2(p->pair[1], 1);
7423 close(p->pair[1]);
7424 }
7425 }
7426 else {
7427 close(p->pair[1]);
7428 if (p->pair[0] != 0) {
7429 dup2(p->pair[0], 0);
7430 close(p->pair[0]);
7431 }
7432 }
7433}
7434# endif
7435
7436#if defined(__linux__)
7437/* Linux /proc/self/status contains a line: "FDSize:\t<nnn>\n"
7438 * Since /proc may not be available, linux_get_maxfd is just a hint.
7439 * This function, linux_get_maxfd, must be async-signal-safe.
7440 * I.e. opendir() is not usable.
7441 *
7442 * Note that memchr() and memcmp is *not* async-signal-safe in POSIX.
7443 * However they are easy to re-implement in async-signal-safe manner.
7444 * (Also note that there is missing/memcmp.c.)
7445 */
7446static int
7447linux_get_maxfd(void)
7448{
7449 int fd;
7450 char buf[4096], *p, *np, *e;
7451 ssize_t ss;
7452 fd = rb_cloexec_open("/proc/self/status", O_RDONLY|O_NOCTTY, 0);
7453 if (fd < 0) return fd;
7454 ss = read(fd, buf, sizeof(buf));
7455 if (ss < 0) goto err;
7456 p = buf;
7457 e = buf + ss;
7458 while ((int)sizeof("FDSize:\t0\n")-1 <= e-p &&
7459 (np = memchr(p, '\n', e-p)) != NULL) {
7460 if (memcmp(p, "FDSize:", sizeof("FDSize:")-1) == 0) {
7461 int fdsize;
7462 p += sizeof("FDSize:")-1;
7463 *np = '\0';
7464 fdsize = (int)ruby_strtoul(p, (char **)NULL, 10);
7465 close(fd);
7466 return fdsize;
7467 }
7468 p = np+1;
7469 }
7470 /* fall through */
7471
7472 err:
7473 close(fd);
7474 return (int)ss;
7475}
7476#endif
7477
7478/* This function should be async-signal-safe. */
7479void
7480rb_close_before_exec(int lowfd, int maxhint, VALUE noclose_fds)
7481{
7482#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
7483 int fd, ret;
7484 int max = (int)max_file_descriptor;
7485# ifdef F_MAXFD
7486 /* F_MAXFD is available since NetBSD 2.0. */
7487 ret = fcntl(0, F_MAXFD); /* async-signal-safe */
7488 if (ret != -1)
7489 maxhint = max = ret;
7490# elif defined(__linux__)
7491 ret = linux_get_maxfd();
7492 if (maxhint < ret)
7493 maxhint = ret;
7494 /* maxhint = max = ret; if (ret == -1) abort(); // test */
7495# endif
7496 if (max < maxhint)
7497 max = maxhint;
7498 for (fd = lowfd; fd <= max; fd++) {
7499 if (!NIL_P(noclose_fds) &&
7500 RTEST(rb_hash_lookup(noclose_fds, INT2FIX(fd)))) /* async-signal-safe */
7501 continue;
7502 ret = fcntl(fd, F_GETFD); /* async-signal-safe */
7503 if (ret != -1 && !(ret & FD_CLOEXEC)) {
7504 fcntl(fd, F_SETFD, ret|FD_CLOEXEC); /* async-signal-safe */
7505 }
7506# define CONTIGUOUS_CLOSED_FDS 20
7507 if (ret != -1) {
7508 if (max < fd + CONTIGUOUS_CLOSED_FDS)
7509 max = fd + CONTIGUOUS_CLOSED_FDS;
7510 }
7511 }
7512#endif
7513}
7514
7515# ifndef __EMSCRIPTEN__
7516static int
7517popen_exec(void *pp, char *errmsg, size_t errmsg_len)
7518{
7519 struct popen_arg *p = (struct popen_arg*)pp;
7520
7521 return rb_exec_async_signal_safe(p->eargp, errmsg, errmsg_len);
7522}
7523# endif
7524#endif
7525
7526#if (defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)) && !defined __EMSCRIPTEN__
7527static VALUE
7528rb_execarg_fixup_v(VALUE execarg_obj)
7529{
7530 rb_execarg_parent_start(execarg_obj);
7531 return Qnil;
7532}
7533#else
7534char *rb_execarg_commandline(const struct rb_execarg *eargp, VALUE *prog);
7535#endif
7536
7537#ifndef __EMSCRIPTEN__
7538static VALUE
7539pipe_open(VALUE execarg_obj, const char *modestr, enum rb_io_mode fmode,
7540 const struct rb_io_encoding *convconfig)
7541{
7542 struct rb_execarg *eargp = NIL_P(execarg_obj) ? NULL : rb_execarg_get(execarg_obj);
7543 VALUE prog = eargp ? (eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name) : Qfalse ;
7544 rb_pid_t pid = 0;
7545 rb_io_t *fptr;
7546 VALUE port;
7547 rb_io_t *write_fptr;
7548 VALUE write_port;
7549#if defined(HAVE_WORKING_FORK)
7550 int status;
7551 char errmsg[80] = { '\0' };
7552#endif
7553#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7554 int state;
7555 struct popen_arg arg;
7556#endif
7557 int e = 0;
7558#if defined(HAVE_SPAWNV)
7559# if defined(HAVE_SPAWNVE)
7560# define DO_SPAWN(cmd, args, envp) ((args) ? \
7561 spawnve(P_NOWAIT, (cmd), (args), (envp)) : \
7562 spawne(P_NOWAIT, (cmd), (envp)))
7563# else
7564# define DO_SPAWN(cmd, args, envp) ((args) ? \
7565 spawnv(P_NOWAIT, (cmd), (args)) : \
7566 spawn(P_NOWAIT, (cmd)))
7567# endif
7568# if !defined(HAVE_WORKING_FORK)
7569 char **args = NULL;
7570# if defined(HAVE_SPAWNVE)
7571 char **envp = NULL;
7572# endif
7573# endif
7574#endif
7575#if !defined(HAVE_WORKING_FORK)
7576 struct rb_execarg sarg, *sargp = &sarg;
7577#endif
7578 FILE *fp = 0;
7579 int fd = -1;
7580 int write_fd = -1;
7581#if !defined(HAVE_WORKING_FORK)
7582 const char *cmd = 0;
7583
7584 if (prog)
7585 cmd = StringValueCStr(prog);
7586#endif
7587
7588#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7589 arg.execarg_obj = execarg_obj;
7590 arg.eargp = eargp;
7591 arg.modef = fmode;
7592 arg.pair[0] = arg.pair[1] = -1;
7593 arg.write_pair[0] = arg.write_pair[1] = -1;
7594# if !defined(HAVE_WORKING_FORK)
7595 if (eargp && !eargp->use_shell) {
7596 args = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
7597 }
7598# endif
7599 switch (fmode & (FMODE_READABLE|FMODE_WRITABLE)) {
7601 if (rb_pipe(arg.write_pair) < 0)
7602 rb_sys_fail_str(prog);
7603 if (rb_pipe(arg.pair) < 0) {
7604 e = errno;
7605 close(arg.write_pair[0]);
7606 close(arg.write_pair[1]);
7607 rb_syserr_fail_str(e, prog);
7608 }
7609 if (eargp) {
7610 rb_execarg_addopt(execarg_obj, INT2FIX(0), INT2FIX(arg.write_pair[0]));
7611 rb_execarg_addopt(execarg_obj, INT2FIX(1), INT2FIX(arg.pair[1]));
7612 }
7613 break;
7614 case FMODE_READABLE:
7615 if (rb_pipe(arg.pair) < 0)
7616 rb_sys_fail_str(prog);
7617 if (eargp)
7618 rb_execarg_addopt(execarg_obj, INT2FIX(1), INT2FIX(arg.pair[1]));
7619 break;
7620 case FMODE_WRITABLE:
7621 if (rb_pipe(arg.pair) < 0)
7622 rb_sys_fail_str(prog);
7623 if (eargp)
7624 rb_execarg_addopt(execarg_obj, INT2FIX(0), INT2FIX(arg.pair[0]));
7625 break;
7626 default:
7627 rb_sys_fail_str(prog);
7628 }
7629 if (!NIL_P(execarg_obj)) {
7630 rb_protect(rb_execarg_fixup_v, execarg_obj, &state);
7631 if (state) {
7632 if (0 <= arg.write_pair[0]) close(arg.write_pair[0]);
7633 if (0 <= arg.write_pair[1]) close(arg.write_pair[1]);
7634 if (0 <= arg.pair[0]) close(arg.pair[0]);
7635 if (0 <= arg.pair[1]) close(arg.pair[1]);
7636 rb_execarg_parent_end(execarg_obj);
7637 rb_jump_tag(state);
7638 }
7639
7640# if defined(HAVE_WORKING_FORK)
7641 pid = rb_fork_async_signal_safe(&status, popen_exec, &arg, arg.eargp->redirect_fds, errmsg, sizeof(errmsg));
7642# else
7643 rb_execarg_run_options(eargp, sargp, NULL, 0);
7644# if defined(HAVE_SPAWNVE)
7645 if (eargp->envp_str) envp = (char **)RSTRING_PTR(eargp->envp_str);
7646# endif
7647 while ((pid = DO_SPAWN(cmd, args, envp)) < 0) {
7648 /* exec failed */
7649 switch (e = errno) {
7650 case EAGAIN:
7651# if EWOULDBLOCK != EAGAIN
7652 case EWOULDBLOCK:
7653# endif
7654 rb_thread_sleep(1);
7655 continue;
7656 }
7657 break;
7658 }
7659 if (eargp)
7660 rb_execarg_run_options(sargp, NULL, NULL, 0);
7661# endif
7662 rb_execarg_parent_end(execarg_obj);
7663 }
7664 else {
7665# if defined(HAVE_WORKING_FORK)
7666 pid = rb_call_proc__fork();
7667 if (pid == 0) { /* child */
7668 popen_redirect(&arg);
7669 rb_io_synchronized(RFILE(orig_stdout)->fptr);
7670 rb_io_synchronized(RFILE(orig_stderr)->fptr);
7671 return Qnil;
7672 }
7673# else
7675# endif
7676 }
7677
7678 /* parent */
7679 if (pid < 0) {
7680# if defined(HAVE_WORKING_FORK)
7681 e = errno;
7682# endif
7683 close(arg.pair[0]);
7684 close(arg.pair[1]);
7686 close(arg.write_pair[0]);
7687 close(arg.write_pair[1]);
7688 }
7689# if defined(HAVE_WORKING_FORK)
7690 if (errmsg[0])
7691 rb_syserr_fail(e, errmsg);
7692# endif
7693 rb_syserr_fail_str(e, prog);
7694 }
7695 if ((fmode & FMODE_READABLE) && (fmode & FMODE_WRITABLE)) {
7696 close(arg.pair[1]);
7697 fd = arg.pair[0];
7698 close(arg.write_pair[0]);
7699 write_fd = arg.write_pair[1];
7700 }
7701 else if (fmode & FMODE_READABLE) {
7702 close(arg.pair[1]);
7703 fd = arg.pair[0];
7704 }
7705 else {
7706 close(arg.pair[0]);
7707 fd = arg.pair[1];
7708 }
7709#else
7710 cmd = rb_execarg_commandline(eargp, &prog);
7711 if (!NIL_P(execarg_obj)) {
7712 rb_execarg_parent_start(execarg_obj);
7713 rb_execarg_run_options(eargp, sargp, NULL, 0);
7714 }
7715 fp = popen(cmd, modestr);
7716 e = errno;
7717 if (eargp) {
7718 rb_execarg_parent_end(execarg_obj);
7719 rb_execarg_run_options(sargp, NULL, NULL, 0);
7720 }
7721 if (!fp) rb_syserr_fail_path(e, prog);
7722 fd = fileno(fp);
7723#endif
7724
7725 port = io_alloc(rb_cIO);
7726 MakeOpenFile(port, fptr);
7727 fptr->fd = fd;
7728 fptr->stdio_file = fp;
7729 fptr->mode = fmode | FMODE_SYNC|FMODE_DUPLEX;
7730 if (convconfig) {
7731 fptr->encs = *convconfig;
7732#if RUBY_CRLF_ENVIRONMENT
7735 }
7736#endif
7737 }
7738 else {
7739 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
7741 }
7742#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7743 if (NEED_NEWLINE_DECORATOR_ON_WRITE(fptr)) {
7744 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
7745 }
7746#endif
7747 }
7748 fptr->pid = pid;
7749
7750 if (0 <= write_fd) {
7751 write_port = io_alloc(rb_cIO);
7752 MakeOpenFile(write_port, write_fptr);
7753 write_fptr->fd = write_fd;
7754 write_fptr->mode = (fmode & ~FMODE_READABLE)| FMODE_SYNC|FMODE_DUPLEX;
7755 fptr->mode &= ~FMODE_WRITABLE;
7756 fptr->tied_io_for_writing = write_port;
7757 rb_ivar_set(port, rb_intern("@tied_io_for_writing"), write_port);
7758 }
7759
7760#if defined (__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7761 fptr->finalize = pipe_finalize;
7762 pipe_add_fptr(fptr);
7763#endif
7764 return port;
7765}
7766#else
7767static VALUE
7768pipe_open(VALUE execarg_obj, const char *modestr, enum rb_io_mode fmode,
7769 const struct rb_io_encoding *convconfig)
7770{
7771 rb_raise(rb_eNotImpError, "popen() is not available");
7772}
7773#endif
7774
7775static int
7776is_popen_fork(VALUE prog)
7777{
7778 if (RSTRING_LEN(prog) == 1 && RSTRING_PTR(prog)[0] == '-') {
7779#if !defined(HAVE_WORKING_FORK)
7780 rb_raise(rb_eNotImpError,
7781 "fork() function is unimplemented on this machine");
7782#else
7783 return TRUE;
7784#endif
7785 }
7786 return FALSE;
7787}
7788
7789static VALUE
7790pipe_open_s(VALUE prog, const char *modestr, enum rb_io_mode fmode,
7791 const struct rb_io_encoding *convconfig)
7792{
7793 int argc = 1;
7794 VALUE *argv = &prog;
7795 VALUE execarg_obj = Qnil;
7796
7797 if (!is_popen_fork(prog))
7798 execarg_obj = rb_execarg_new(argc, argv, TRUE, FALSE);
7799 return pipe_open(execarg_obj, modestr, fmode, convconfig);
7800}
7801
7802static VALUE
7803pipe_close(VALUE io)
7804{
7805 rb_io_t *fptr = io_close_fptr(io);
7806 if (fptr) {
7807 fptr_waitpid(fptr, rb_thread_to_be_killed(rb_thread_current()));
7808 }
7809 return Qnil;
7810}
7811
7812static VALUE popen_finish(VALUE port, VALUE klass);
7813
7814/*
7815 * call-seq:
7816 * IO.popen(env = {}, cmd, mode = 'r', **opts) -> io
7817 * IO.popen(env = {}, cmd, mode = 'r', **opts) {|io| ... } -> object
7818 *
7819 * Executes the given command +cmd+ as a subprocess
7820 * whose $stdin and $stdout are connected to a new stream +io+.
7821 *
7822 * This method has potential security vulnerabilities if called with untrusted input;
7823 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
7824 *
7825 * If no block is given, returns the new stream,
7826 * which depending on given +mode+ may be open for reading, writing, or both.
7827 * The stream should be explicitly closed (eventually) to avoid resource leaks.
7828 *
7829 * If a block is given, the stream is passed to the block
7830 * (again, open for reading, writing, or both);
7831 * when the block exits, the stream is closed,
7832 * and the block's value is assigned to global variable <tt>$?</tt> and returned.
7833 *
7834 * Optional argument +mode+ may be any valid \IO mode.
7835 * See {Access Modes}[rdoc-ref:File@Access+Modes].
7836 *
7837 * Required argument +cmd+ determines which of the following occurs:
7838 *
7839 * - The process forks.
7840 * - A specified program runs in a shell.
7841 * - A specified program runs with specified arguments.
7842 * - A specified program runs with specified arguments and a specified +argv0+.
7843 *
7844 * Each of these is detailed below.
7845 *
7846 * The optional hash argument +env+ specifies name/value pairs that are to be added
7847 * to the environment variables for the subprocess:
7848 *
7849 * IO.popen({'FOO' => 'bar'}, 'ruby', 'r+') do |pipe|
7850 * pipe.puts 'puts ENV["FOO"]'
7851 * pipe.close_write
7852 * pipe.gets
7853 * end => "bar\n"
7854 *
7855 * Optional keyword arguments +opts+ specify:
7856 *
7857 * - {Open options}[rdoc-ref:IO@Open+Options].
7858 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
7859 * - Options for Kernel#spawn.
7860 *
7861 * <b>Forked Process</b>
7862 *
7863 * When argument +cmd+ is the 1-character string <tt>'-'</tt>, causes the process to fork:
7864 * IO.popen('-') do |pipe|
7865 * if pipe
7866 * $stderr.puts "In parent, child pid is #{pipe.pid}\n"
7867 * else
7868 * $stderr.puts "In child, pid is #{$$}\n"
7869 * end
7870 * end
7871 *
7872 * Output:
7873 *
7874 * In parent, child pid is 26253
7875 * In child, pid is 26253
7876 *
7877 * Note that this is not supported on all platforms.
7878 *
7879 * <b>Shell Subprocess</b>
7880 *
7881 * When argument +cmd+ is a single string (but not <tt>'-'</tt>),
7882 * the program named +cmd+ is run as a shell command:
7883 *
7884 * IO.popen('uname') do |pipe|
7885 * pipe.readlines
7886 * end
7887 *
7888 * Output:
7889 *
7890 * ["Linux\n"]
7891 *
7892 * Another example:
7893 *
7894 * IO.popen('/bin/sh', 'r+') do |pipe|
7895 * pipe.puts('ls')
7896 * pipe.close_write
7897 * $stderr.puts pipe.readlines.size
7898 * end
7899 *
7900 * Output:
7901 *
7902 * 213
7903 *
7904 * <b>Program Subprocess</b>
7905 *
7906 * When argument +cmd+ is an array of strings,
7907 * the program named <tt>cmd[0]</tt> is run with all elements of +cmd+ as its arguments:
7908 *
7909 * IO.popen(['du', '..', '.']) do |pipe|
7910 * $stderr.puts pipe.readlines.size
7911 * end
7912 *
7913 * Output:
7914 *
7915 * 1111
7916 *
7917 * <b>Program Subprocess with <tt>argv0</tt></b>
7918 *
7919 * When argument +cmd+ is an array whose first element is a 2-element string array
7920 * and whose remaining elements (if any) are strings:
7921 *
7922 * - <tt>cmd[0][0]</tt> (the first string in the nested array) is the name of a program that is run.
7923 * - <tt>cmd[0][1]</tt> (the second string in the nested array) is set as the program's <tt>argv[0]</tt>.
7924 * - <tt>cmd[1..-1]</tt> (the strings in the outer array) are the program's arguments.
7925 *
7926 * Example (sets <tt>$0</tt> to 'foo'):
7927 *
7928 * IO.popen([['/bin/sh', 'foo'], '-c', 'echo $0']).read # => "foo\n"
7929 *
7930 * <b>Some Special Examples</b>
7931 *
7932 * # Set IO encoding.
7933 * IO.popen("nkf -e filename", :external_encoding=>"EUC-JP") {|nkf_io|
7934 * euc_jp_string = nkf_io.read
7935 * }
7936 *
7937 * # Merge standard output and standard error using Kernel#spawn option. See Kernel#spawn.
7938 * IO.popen(["ls", "/", :err=>[:child, :out]]) do |io|
7939 * ls_result_with_error = io.read
7940 * end
7941 *
7942 * # Use mixture of spawn options and IO options.
7943 * IO.popen(["ls", "/"], :err=>[:child, :out]) do |io|
7944 * ls_result_with_error = io.read
7945 * end
7946 *
7947 * f = IO.popen("uname")
7948 * p f.readlines
7949 * f.close
7950 * puts "Parent is #{Process.pid}"
7951 * IO.popen("date") {|f| puts f.gets }
7952 * IO.popen("-") {|f| $stderr.puts "#{Process.pid} is here, f is #{f.inspect}"}
7953 * p $?
7954 * IO.popen(%w"sed -e s|^|<foo>| -e s&$&;zot;&", "r+") {|f|
7955 * f.puts "bar"; f.close_write; puts f.gets
7956 * }
7957 *
7958 * Output (from last section):
7959 *
7960 * ["Linux\n"]
7961 * Parent is 21346
7962 * Thu Jan 15 22:41:19 JST 2009
7963 * 21346 is here, f is #<IO:fd 3>
7964 * 21352 is here, f is nil
7965 * #<Process::Status: pid 21352 exit 0>
7966 * <foo>bar;zot;
7967 *
7968 * Raises exceptions that IO.pipe and Kernel.spawn raise.
7969 *
7970 */
7971
7972static VALUE
7973rb_io_s_popen(int argc, VALUE *argv, VALUE klass)
7974{
7975 VALUE pname, pmode = Qnil, opt = Qnil, env = Qnil;
7976
7977 if (argc > 1 && !NIL_P(opt = rb_check_hash_type(argv[argc-1]))) --argc;
7978 if (argc > 1 && !NIL_P(env = rb_check_hash_type(argv[0]))) --argc, ++argv;
7979 switch (argc) {
7980 case 2:
7981 pmode = argv[1];
7982 case 1:
7983 pname = argv[0];
7984 break;
7985 default:
7986 {
7987 int ex = !NIL_P(opt);
7988 rb_error_arity(argc + ex, 1 + ex, 2 + ex);
7989 }
7990 }
7991 return popen_finish(rb_io_popen(pname, pmode, env, opt), klass);
7992}
7993
7994VALUE
7995rb_io_popen(VALUE pname, VALUE pmode, VALUE env, VALUE opt)
7996{
7997 const char *modestr;
7998 VALUE tmp, execarg_obj = Qnil;
7999 int oflags;
8000 enum rb_io_mode fmode;
8001 struct rb_io_encoding convconfig;
8002
8003 tmp = rb_check_array_type(pname);
8004 if (!NIL_P(tmp)) {
8005 long len = RARRAY_LEN(tmp);
8006#if SIZEOF_LONG > SIZEOF_INT
8007 if (len > INT_MAX) {
8008 rb_raise(rb_eArgError, "too many arguments");
8009 }
8010#endif
8011 execarg_obj = rb_execarg_new((int)len, RARRAY_CONST_PTR(tmp), FALSE, FALSE);
8012 RB_GC_GUARD(tmp);
8013 }
8014 else {
8015 StringValue(pname);
8016 execarg_obj = Qnil;
8017 if (!is_popen_fork(pname))
8018 execarg_obj = rb_execarg_new(1, &pname, TRUE, FALSE);
8019 }
8020 if (!NIL_P(execarg_obj)) {
8021 if (!NIL_P(opt))
8022 opt = rb_execarg_extract_options(execarg_obj, opt);
8023 if (!NIL_P(env))
8024 rb_execarg_setenv(execarg_obj, env);
8025 }
8026 rb_io_extract_modeenc(&pmode, 0, opt, &oflags, &fmode, &convconfig);
8027 modestr = rb_io_oflags_modestr(oflags);
8028
8029 return pipe_open(execarg_obj, modestr, fmode, &convconfig);
8030}
8031
8032static VALUE
8033popen_finish(VALUE port, VALUE klass)
8034{
8035 if (NIL_P(port)) {
8036 /* child */
8037 if (rb_block_given_p()) {
8038 rb_protect(rb_yield, Qnil, NULL);
8039 rb_io_flush(rb_ractor_stdout());
8040 rb_io_flush(rb_ractor_stderr());
8041 _exit(0);
8042 }
8043 return Qnil;
8044 }
8045 RBASIC_SET_CLASS(port, klass);
8046 if (rb_block_given_p()) {
8047 return rb_ensure(rb_yield, port, pipe_close, port);
8048 }
8049 return port;
8050}
8051
8052#if defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)
8053struct popen_writer_arg {
8054 char *const *argv;
8055 struct popen_arg popen;
8056};
8057
8058static int
8059exec_popen_writer(void *arg, char *errmsg, size_t buflen)
8060{
8061 struct popen_writer_arg *pw = arg;
8062 pw->popen.modef = FMODE_WRITABLE;
8063 popen_redirect(&pw->popen);
8064 execv(pw->argv[0], pw->argv);
8065 strlcpy(errmsg, strerror(errno), buflen);
8066 return -1;
8067}
8068#endif
8069
8070FILE *
8071ruby_popen_writer(char *const *argv, rb_pid_t *pid)
8072{
8073#if (defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)) || defined(_WIN32)
8074# ifdef HAVE_WORKING_FORK
8075 struct popen_writer_arg pw;
8076 int *const write_pair = pw.popen.pair;
8077# else
8078 int write_pair[2];
8079# endif
8080
8081 int result = rb_cloexec_pipe(write_pair);
8082 *pid = -1;
8083 if (result == 0) {
8084# ifdef HAVE_WORKING_FORK
8085 pw.argv = argv;
8086 int status;
8087 char errmsg[80] = {'\0'};
8088 *pid = rb_fork_async_signal_safe(&status, exec_popen_writer, &pw, Qnil, errmsg, sizeof(errmsg));
8089# else
8090 *pid = rb_w32_uspawn_process(P_NOWAIT, argv[0], argv, write_pair[0], -1, -1, 0);
8091 const char *errmsg = (*pid < 0) ? strerror(errno) : NULL;
8092# endif
8093 close(write_pair[0]);
8094 if (*pid < 0) {
8095 close(write_pair[1]);
8096 fprintf(stderr, "ruby_popen_writer(%s): %s\n", argv[0], errmsg);
8097 }
8098 else {
8099 return fdopen(write_pair[1], "w");
8100 }
8101 }
8102#endif
8103 return NULL;
8104}
8105
8106static VALUE
8107rb_open_file(VALUE io, VALUE fname, VALUE vmode, VALUE vperm, VALUE opt)
8108{
8109 int oflags;
8110 enum rb_io_mode fmode;
8111 struct rb_io_encoding convconfig;
8112 mode_t perm;
8113
8114 FilePathValue(fname);
8115
8116 rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, &convconfig);
8117 perm = NIL_P(vperm) ? 0666 : NUM2MODET(vperm);
8118
8119 rb_file_open_generic(io, fname, oflags, fmode, &convconfig, perm);
8120
8121 return io;
8122}
8123
8124/*
8125 * Document-method: File::open
8126 *
8127 * call-seq:
8128 * File.open(path, mode = 'r', perm = 0666, **opts) -> file
8129 * File.open(path, mode = 'r', perm = 0666, **opts) {|f| ... } -> object
8130 *
8131 * Creates a new File object, via File.new with the given arguments.
8132 *
8133 * With no block given, returns the File object.
8134 *
8135 * With a block given, calls the block with the File object
8136 * and returns the block's value.
8137 *
8138 */
8139
8140/*
8141 * Document-method: IO::open
8142 *
8143 * call-seq:
8144 * IO.open(fd, mode = 'r', **opts) -> io
8145 * IO.open(fd, mode = 'r', **opts) {|io| ... } -> object
8146 *
8147 * Creates a new \IO object, via IO.new with the given arguments.
8148 *
8149 * With no block given, returns the \IO object.
8150 *
8151 * With a block given, calls the block with the \IO object
8152 * and returns the block's value.
8153 *
8154 */
8155
8156static VALUE
8157rb_io_s_open(int argc, VALUE *argv, VALUE klass)
8158{
8160
8161 if (rb_block_given_p()) {
8162 return rb_ensure(rb_yield, io, io_close, io);
8163 }
8164
8165 return io;
8166}
8167
8168/*
8169 * call-seq:
8170 * IO.sysopen(path, mode = 'r', perm = 0666) -> integer
8171 *
8172 * Opens the file at the given path with the given mode and permissions;
8173 * returns the integer file descriptor.
8174 *
8175 * If the file is to be readable, it must exist;
8176 * if the file is to be writable and does not exist,
8177 * it is created with the given permissions:
8178 *
8179 * File.write('t.tmp', '') # => 0
8180 * IO.sysopen('t.tmp') # => 8
8181 * IO.sysopen('t.tmp', 'w') # => 9
8182 *
8183 *
8184 */
8185
8186static VALUE
8187rb_io_s_sysopen(int argc, VALUE *argv, VALUE _)
8188{
8189 VALUE fname, vmode, vperm;
8190 VALUE intmode;
8191 int oflags, fd;
8192 mode_t perm;
8193
8194 rb_scan_args(argc, argv, "12", &fname, &vmode, &vperm);
8195 FilePathValue(fname);
8196
8197 if (NIL_P(vmode))
8198 oflags = O_RDONLY;
8199 else if (!NIL_P(intmode = rb_check_to_integer(vmode, "to_int")))
8200 oflags = NUM2INT(intmode);
8201 else {
8202 StringValue(vmode);
8203 oflags = rb_io_modestr_oflags(StringValueCStr(vmode));
8204 }
8205 if (NIL_P(vperm)) perm = 0666;
8206 else perm = NUM2MODET(vperm);
8207
8208 RB_GC_GUARD(fname) = rb_str_new4(fname);
8209 fd = rb_sysopen(fname, oflags, perm);
8210 return INT2NUM(fd);
8211}
8212
8213static VALUE
8214check_pipe_command(VALUE filename_or_command)
8215{
8216 char *s = RSTRING_PTR(filename_or_command);
8217 long l = RSTRING_LEN(filename_or_command);
8218 char *e = s + l;
8219 int chlen;
8220
8221 if (rb_enc_ascget(s, e, &chlen, rb_enc_get(filename_or_command)) == '|') {
8222 VALUE cmd = rb_str_new(s+chlen, l-chlen);
8223 return cmd;
8224 }
8225 return Qnil;
8226}
8227
8228/*
8229 * call-seq:
8230 * open(path, mode = 'r', perm = 0666, **opts) -> io or nil
8231 * open(path, mode = 'r', perm = 0666, **opts) {|io| ... } -> obj
8232 *
8233 * Creates an IO object connected to the given file.
8234 *
8235 * This method has potential security vulnerabilities if called with untrusted input;
8236 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
8237 *
8238 * With no block given, file stream is returned:
8239 *
8240 * open('t.txt') # => #<File:t.txt>
8241 *
8242 * With a block given, calls the block with the open file stream,
8243 * then closes the stream:
8244 *
8245 * open('t.txt') {|f| p f } # => #<File:t.txt (closed)>
8246 *
8247 * Output:
8248 *
8249 * #<File:t.txt>
8250 *
8251 * See File.open for details.
8252 *
8253 */
8254
8255static VALUE
8256rb_f_open(int argc, VALUE *argv, VALUE _)
8257{
8258 ID to_open = 0;
8259 int redirect = FALSE;
8260
8261 if (argc >= 1) {
8262 CONST_ID(to_open, "to_open");
8263 if (rb_respond_to(argv[0], to_open)) {
8264 redirect = TRUE;
8265 }
8266 else {
8267 VALUE tmp = argv[0];
8268 FilePathValue(tmp);
8269 if (NIL_P(tmp)) {
8270 redirect = TRUE;
8271 }
8272 else {
8273 VALUE cmd = check_pipe_command(tmp);
8274 if (!NIL_P(cmd)) {
8275 // TODO: when removed in 4.0, update command_injection.rdoc
8276 rb_warn_deprecated_to_remove_at(4.0, "Calling Kernel#open with a leading '|'", "IO.popen");
8277 argv[0] = cmd;
8278 return rb_io_s_popen(argc, argv, rb_cIO);
8279 }
8280 }
8281 }
8282 }
8283 if (redirect) {
8284 VALUE io = rb_funcallv_kw(argv[0], to_open, argc-1, argv+1, RB_PASS_CALLED_KEYWORDS);
8285
8286 if (rb_block_given_p()) {
8287 return rb_ensure(rb_yield, io, io_close, io);
8288 }
8289 return io;
8290 }
8291 return rb_io_s_open(argc, argv, rb_cFile);
8292}
8293
8294static VALUE
8295rb_io_open_generic(VALUE klass, VALUE filename, int oflags, enum rb_io_mode fmode,
8296 const struct rb_io_encoding *convconfig, mode_t perm)
8297{
8298 VALUE cmd;
8299 if (klass == rb_cIO && !NIL_P(cmd = check_pipe_command(filename))) {
8300 // TODO: when removed in 4.0, update command_injection.rdoc
8301 rb_warn_deprecated_to_remove_at(4.0, "IO process creation with a leading '|'", "IO.popen");
8302 return pipe_open_s(cmd, rb_io_oflags_modestr(oflags), fmode, convconfig);
8303 }
8304 else {
8305 return rb_file_open_generic(io_alloc(klass), filename,
8306 oflags, fmode, convconfig, perm);
8307 }
8308}
8309
8310static VALUE
8311rb_io_open(VALUE io, VALUE filename, VALUE vmode, VALUE vperm, VALUE opt)
8312{
8313 int oflags;
8314 enum rb_io_mode fmode;
8315 struct rb_io_encoding convconfig;
8316 mode_t perm;
8317
8318 rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, &convconfig);
8319 perm = NIL_P(vperm) ? 0666 : NUM2MODET(vperm);
8320 return rb_io_open_generic(io, filename, oflags, fmode, &convconfig, perm);
8321}
8322
8323static VALUE
8324io_reopen(VALUE io, VALUE nfile)
8325{
8326 rb_io_t *fptr, *orig;
8327 int fd, fd2;
8328 rb_off_t pos = 0;
8329
8330 nfile = rb_io_get_io(nfile);
8331 GetOpenFile(io, fptr);
8332 GetOpenFile(nfile, orig);
8333
8334 if (fptr == orig) return io;
8335 if (RUBY_IO_EXTERNAL_P(fptr)) {
8336 if ((fptr->stdio_file == stdin && !(orig->mode & FMODE_READABLE)) ||
8337 (fptr->stdio_file == stdout && !(orig->mode & FMODE_WRITABLE)) ||
8338 (fptr->stdio_file == stderr && !(orig->mode & FMODE_WRITABLE))) {
8339 rb_raise(rb_eArgError,
8340 "%s can't change access mode from \"%s\" to \"%s\"",
8341 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->mode),
8342 rb_io_fmode_modestr(orig->mode));
8343 }
8344 }
8345 if (fptr->mode & FMODE_WRITABLE) {
8346 if (io_fflush(fptr) < 0)
8347 rb_sys_fail_on_write(fptr);
8348 }
8349 else {
8350 flush_before_seek(fptr, true);
8351 }
8352 if (orig->mode & FMODE_READABLE) {
8353 pos = io_tell(orig);
8354 }
8355 if (orig->mode & FMODE_WRITABLE) {
8356 if (io_fflush(orig) < 0)
8357 rb_sys_fail_on_write(fptr);
8358 }
8359
8360 /* copy rb_io_t structure */
8361 fptr->mode = orig->mode | (fptr->mode & FMODE_EXTERNAL);
8362 fptr->encs = orig->encs;
8363 fptr->pid = orig->pid;
8364 fptr->lineno = orig->lineno;
8365 if (RTEST(orig->pathv)) fptr->pathv = orig->pathv;
8366 else if (!RUBY_IO_EXTERNAL_P(fptr)) fptr->pathv = Qnil;
8367 fptr_copy_finalizer(fptr, orig);
8368
8369 fd = fptr->fd;
8370 fd2 = orig->fd;
8371 if (fd != fd2) {
8372 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2 || !fptr->stdio_file) {
8373 /* need to keep FILE objects of stdin, stdout and stderr */
8374 if (rb_cloexec_dup2(fd2, fd) < 0)
8375 rb_sys_fail_path(orig->pathv);
8376 rb_update_max_fd(fd);
8377 }
8378 else {
8379 fclose(fptr->stdio_file);
8380 fptr->stdio_file = 0;
8381 fptr->fd = -1;
8382 if (rb_cloexec_dup2(fd2, fd) < 0)
8383 rb_sys_fail_path(orig->pathv);
8384 rb_update_max_fd(fd);
8385 fptr->fd = fd;
8386 }
8388 if ((orig->mode & FMODE_READABLE) && pos >= 0) {
8389 if (io_seek(fptr, pos, SEEK_SET) < 0 && errno) {
8390 rb_sys_fail_path(fptr->pathv);
8391 }
8392 if (io_seek(orig, pos, SEEK_SET) < 0 && errno) {
8393 rb_sys_fail_path(orig->pathv);
8394 }
8395 }
8396 }
8397
8398 if (fptr->mode & FMODE_BINMODE) {
8399 rb_io_binmode(io);
8400 }
8401
8402 RBASIC_SET_CLASS(io, rb_obj_class(nfile));
8403 return io;
8404}
8405
8406#ifdef _WIN32
8407int rb_freopen(VALUE fname, const char *mode, FILE *fp);
8408#else
8409static int
8410rb_freopen(VALUE fname, const char *mode, FILE *fp)
8411{
8412 if (!freopen(RSTRING_PTR(fname), mode, fp)) {
8413 RB_GC_GUARD(fname);
8414 return errno;
8415 }
8416 return 0;
8417}
8418#endif
8419
8420/*
8421 * call-seq:
8422 * reopen(other_io) -> self
8423 * reopen(path, mode = 'r', **opts) -> self
8424 *
8425 * Reassociates the stream with another stream,
8426 * which may be of a different class.
8427 * This method may be used to redirect an existing stream
8428 * to a new destination.
8429 *
8430 * With argument +other_io+ given, reassociates with that stream:
8431 *
8432 * # Redirect $stdin from a file.
8433 * f = File.open('t.txt')
8434 * $stdin.reopen(f)
8435 * f.close
8436 *
8437 * # Redirect $stdout to a file.
8438 * f = File.open('t.tmp', 'w')
8439 * $stdout.reopen(f)
8440 * f.close
8441 *
8442 * With argument +path+ given, reassociates with a new stream to that file path:
8443 *
8444 * $stdin.reopen('t.txt')
8445 * $stdout.reopen('t.tmp', 'w')
8446 *
8447 * Optional keyword arguments +opts+ specify:
8448 *
8449 * - {Open Options}[rdoc-ref:IO@Open+Options].
8450 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
8451 *
8452 */
8453
8454static VALUE
8455rb_io_reopen(int argc, VALUE *argv, VALUE file)
8456{
8457 VALUE fname, nmode, opt;
8458 int oflags;
8459 rb_io_t *fptr;
8460
8461 if (rb_scan_args(argc, argv, "11:", &fname, &nmode, &opt) == 1) {
8462 VALUE tmp = rb_io_check_io(fname);
8463 if (!NIL_P(tmp)) {
8464 return io_reopen(file, tmp);
8465 }
8466 }
8467
8468 FilePathValue(fname);
8469 rb_io_taint_check(file);
8470 fptr = RFILE(file)->fptr;
8471 if (!fptr) {
8472 fptr = RFILE(file)->fptr = ZALLOC(rb_io_t);
8473 }
8474
8475 if (!NIL_P(nmode) || !NIL_P(opt)) {
8476 enum rb_io_mode fmode;
8477 struct rb_io_encoding convconfig;
8478
8479 rb_io_extract_modeenc(&nmode, 0, opt, &oflags, &fmode, &convconfig);
8480 if (RUBY_IO_EXTERNAL_P(fptr) &&
8481 ((fptr->mode & FMODE_READWRITE) & (fmode & FMODE_READWRITE)) !=
8482 (fptr->mode & FMODE_READWRITE)) {
8483 rb_raise(rb_eArgError,
8484 "%s can't change access mode from \"%s\" to \"%s\"",
8485 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->mode),
8486 rb_io_fmode_modestr(fmode));
8487 }
8488 fptr->mode = fmode;
8489 fptr->encs = convconfig;
8490 }
8491 else {
8492 oflags = rb_io_fmode_oflags(fptr->mode);
8493 }
8494
8495 fptr->pathv = fname;
8496 if (fptr->fd < 0) {
8497 fptr->fd = rb_sysopen(fptr->pathv, oflags, 0666);
8498 fptr->stdio_file = 0;
8499 return file;
8500 }
8501
8502 if (fptr->mode & FMODE_WRITABLE) {
8503 if (io_fflush(fptr) < 0)
8504 rb_sys_fail_on_write(fptr);
8505 }
8506 fptr->rbuf.off = fptr->rbuf.len = 0;
8507
8508 if (fptr->stdio_file) {
8509 int e = rb_freopen(rb_str_encode_ospath(fptr->pathv),
8510 rb_io_oflags_modestr(oflags),
8511 fptr->stdio_file);
8512 if (e) rb_syserr_fail_path(e, fptr->pathv);
8513 fptr->fd = fileno(fptr->stdio_file);
8514 rb_fd_fix_cloexec(fptr->fd);
8515#ifdef USE_SETVBUF
8516 if (setvbuf(fptr->stdio_file, NULL, _IOFBF, 0) != 0)
8517 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8518#endif
8519 if (fptr->stdio_file == stderr) {
8520 if (setvbuf(fptr->stdio_file, NULL, _IONBF, BUFSIZ) != 0)
8521 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8522 }
8523 else if (fptr->stdio_file == stdout && isatty(fptr->fd)) {
8524 if (setvbuf(fptr->stdio_file, NULL, _IOLBF, BUFSIZ) != 0)
8525 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8526 }
8527 }
8528 else {
8529 int tmpfd = rb_sysopen(fptr->pathv, oflags, 0666);
8530 int err = 0;
8531 if (rb_cloexec_dup2(tmpfd, fptr->fd) < 0)
8532 err = errno;
8533 (void)close(tmpfd);
8534 if (err) {
8535 rb_syserr_fail_path(err, fptr->pathv);
8536 }
8537 }
8538
8539 return file;
8540}
8541
8542/* :nodoc: */
8543static VALUE
8544rb_io_init_copy(VALUE dest, VALUE io)
8545{
8546 rb_io_t *fptr, *orig;
8547 int fd;
8548 VALUE write_io;
8549 rb_off_t pos;
8550
8551 io = rb_io_get_io(io);
8552 if (!OBJ_INIT_COPY(dest, io)) return dest;
8553 GetOpenFile(io, orig);
8554 MakeOpenFile(dest, fptr);
8555
8556 rb_io_flush(io);
8557
8558 /* copy rb_io_t structure */
8559 fptr->mode = orig->mode & ~FMODE_EXTERNAL;
8560 fptr->encs = orig->encs;
8561 fptr->pid = orig->pid;
8562 fptr->lineno = orig->lineno;
8563 fptr->timeout = orig->timeout;
8564 if (!NIL_P(orig->pathv)) fptr->pathv = orig->pathv;
8565 fptr_copy_finalizer(fptr, orig);
8566
8567 fd = ruby_dup(orig->fd);
8568 fptr->fd = fd;
8569 pos = io_tell(orig);
8570 if (0 <= pos)
8571 io_seek(fptr, pos, SEEK_SET);
8572 if (fptr->mode & FMODE_BINMODE) {
8573 rb_io_binmode(dest);
8574 }
8575
8576 write_io = GetWriteIO(io);
8577 if (io != write_io) {
8578 write_io = rb_obj_dup(write_io);
8579 fptr->tied_io_for_writing = write_io;
8580 rb_ivar_set(dest, rb_intern("@tied_io_for_writing"), write_io);
8581 }
8582
8583 return dest;
8584}
8585
8586/*
8587 * call-seq:
8588 * printf(format_string, *objects) -> nil
8589 *
8590 * Formats and writes +objects+ to the stream.
8591 *
8592 * For details on +format_string+, see
8593 * {Format Specifications}[rdoc-ref:format_specifications.rdoc].
8594 *
8595 */
8596
8597VALUE
8598rb_io_printf(int argc, const VALUE *argv, VALUE out)
8599{
8600 rb_io_write(out, rb_f_sprintf(argc, argv));
8601 return Qnil;
8602}
8603
8604/*
8605 * call-seq:
8606 * printf(format_string, *objects) -> nil
8607 * printf(io, format_string, *objects) -> nil
8608 *
8609 * Equivalent to:
8610 *
8611 * io.write(sprintf(format_string, *objects))
8612 *
8613 * For details on +format_string+, see
8614 * {Format Specifications}[rdoc-ref:format_specifications.rdoc].
8615 *
8616 * With the single argument +format_string+, formats +objects+ into the string,
8617 * then writes the formatted string to $stdout:
8618 *
8619 * printf('%4.4d %10s %2.2f', 24, 24, 24.0)
8620 *
8621 * Output (on $stdout):
8622 *
8623 * 0024 24 24.00#
8624 *
8625 * With arguments +io+ and +format_string+, formats +objects+ into the string,
8626 * then writes the formatted string to +io+:
8627 *
8628 * printf($stderr, '%4.4d %10s %2.2f', 24, 24, 24.0)
8629 *
8630 * Output (on $stderr):
8631 *
8632 * 0024 24 24.00# => nil
8633 *
8634 * With no arguments, does nothing.
8635 *
8636 */
8637
8638static VALUE
8639rb_f_printf(int argc, VALUE *argv, VALUE _)
8640{
8641 VALUE out;
8642
8643 if (argc == 0) return Qnil;
8644 if (RB_TYPE_P(argv[0], T_STRING)) {
8645 out = rb_ractor_stdout();
8646 }
8647 else {
8648 out = argv[0];
8649 argv++;
8650 argc--;
8651 }
8652 rb_io_write(out, rb_f_sprintf(argc, argv));
8653
8654 return Qnil;
8655}
8656
8657static void
8658deprecated_str_setter(VALUE val, ID id, VALUE *var)
8659{
8660 rb_str_setter(val, id, &val);
8661 if (!NIL_P(val)) {
8662 rb_warn_deprecated("'%s'", NULL, rb_id2name(id));
8663 }
8664 *var = val;
8665}
8666
8667static void
8668deprecated_rs_setter(VALUE val, ID id, VALUE *var)
8669{
8670 if (!NIL_P(val)) {
8671 if (!RB_TYPE_P(val, T_STRING)) {
8672 rb_raise(rb_eTypeError, "value of %"PRIsVALUE" must be String", rb_id2str(id));
8673 }
8674 if (rb_str_equal(val, rb_default_rs)) {
8675 val = rb_default_rs;
8676 }
8677 else {
8678 val = rb_str_frozen_bare_string(val);
8679 }
8681 rb_warn_deprecated("'%s'", NULL, rb_id2name(id));
8682 }
8683 *var = val;
8684}
8685
8686/*
8687 * call-seq:
8688 * print(*objects) -> nil
8689 *
8690 * Writes the given objects to the stream; returns +nil+.
8691 * Appends the output record separator <tt>$OUTPUT_RECORD_SEPARATOR</tt>
8692 * (<tt>$\</tt>), if it is not +nil+.
8693 * See {Line IO}[rdoc-ref:IO@Line+IO].
8694 *
8695 * With argument +objects+ given, for each object:
8696 *
8697 * - Converts via its method +to_s+ if not a string.
8698 * - Writes to the stream.
8699 * - If not the last object, writes the output field separator
8700 * <tt>$OUTPUT_FIELD_SEPARATOR</tt> (<tt>$,</tt>) if it is not +nil+.
8701 *
8702 * With default separators:
8703 *
8704 * f = File.open('t.tmp', 'w+')
8705 * objects = [0, 0.0, Rational(0, 1), Complex(0, 0), :zero, 'zero']
8706 * p $OUTPUT_RECORD_SEPARATOR
8707 * p $OUTPUT_FIELD_SEPARATOR
8708 * f.print(*objects)
8709 * f.rewind
8710 * p f.read
8711 * f.close
8712 *
8713 * Output:
8714 *
8715 * nil
8716 * nil
8717 * "00.00/10+0izerozero"
8718 *
8719 * With specified separators:
8720 *
8721 * $\ = "\n"
8722 * $, = ','
8723 * f.rewind
8724 * f.print(*objects)
8725 * f.rewind
8726 * p f.read
8727 *
8728 * Output:
8729 *
8730 * "0,0.0,0/1,0+0i,zero,zero\n"
8731 *
8732 * With no argument given, writes the content of <tt>$_</tt>
8733 * (which is usually the most recent user input):
8734 *
8735 * f = File.open('t.tmp', 'w+')
8736 * gets # Sets $_ to the most recent user input.
8737 * f.print
8738 * f.close
8739 *
8740 */
8741
8742VALUE
8743rb_io_print(int argc, const VALUE *argv, VALUE out)
8744{
8745 int i;
8746 VALUE line;
8747
8748 /* if no argument given, print `$_' */
8749 if (argc == 0) {
8750 argc = 1;
8751 line = rb_lastline_get();
8752 argv = &line;
8753 }
8754 if (argc > 1 && !NIL_P(rb_output_fs)) {
8755 rb_category_warn(RB_WARN_CATEGORY_DEPRECATED, "$, is set to non-nil value");
8756 }
8757 for (i=0; i<argc; i++) {
8758 if (!NIL_P(rb_output_fs) && i>0) {
8759 rb_io_write(out, rb_output_fs);
8760 }
8761 rb_io_write(out, argv[i]);
8762 }
8763 if (argc > 0 && !NIL_P(rb_output_rs)) {
8764 rb_io_write(out, rb_output_rs);
8765 }
8766
8767 return Qnil;
8768}
8769
8770/*
8771 * call-seq:
8772 * print(*objects) -> nil
8773 *
8774 * Equivalent to <tt>$stdout.print(*objects)</tt>,
8775 * this method is the straightforward way to write to <tt>$stdout</tt>.
8776 *
8777 * Writes the given objects to <tt>$stdout</tt>; returns +nil+.
8778 * Appends the output record separator <tt>$OUTPUT_RECORD_SEPARATOR</tt>
8779 * <tt>$\</tt>), if it is not +nil+.
8780 *
8781 * With argument +objects+ given, for each object:
8782 *
8783 * - Converts via its method +to_s+ if not a string.
8784 * - Writes to <tt>stdout</tt>.
8785 * - If not the last object, writes the output field separator
8786 * <tt>$OUTPUT_FIELD_SEPARATOR</tt> (<tt>$,</tt> if it is not +nil+.
8787 *
8788 * With default separators:
8789 *
8790 * objects = [0, 0.0, Rational(0, 1), Complex(0, 0), :zero, 'zero']
8791 * $OUTPUT_RECORD_SEPARATOR
8792 * $OUTPUT_FIELD_SEPARATOR
8793 * print(*objects)
8794 *
8795 * Output:
8796 *
8797 * nil
8798 * nil
8799 * 00.00/10+0izerozero
8800 *
8801 * With specified separators:
8802 *
8803 * $OUTPUT_RECORD_SEPARATOR = "\n"
8804 * $OUTPUT_FIELD_SEPARATOR = ','
8805 * print(*objects)
8806 *
8807 * Output:
8808 *
8809 * 0,0.0,0/1,0+0i,zero,zero
8810 *
8811 * With no argument given, writes the content of <tt>$_</tt>
8812 * (which is usually the most recent user input):
8813 *
8814 * gets # Sets $_ to the most recent user input.
8815 * print # Prints $_.
8816 *
8817 */
8818
8819static VALUE
8820rb_f_print(int argc, const VALUE *argv, VALUE _)
8821{
8822 rb_io_print(argc, argv, rb_ractor_stdout());
8823 return Qnil;
8824}
8825
8826/*
8827 * call-seq:
8828 * putc(object) -> object
8829 *
8830 * Writes a character to the stream.
8831 * See {Character IO}[rdoc-ref:IO@Character+IO].
8832 *
8833 * If +object+ is numeric, converts to integer if necessary,
8834 * then writes the character whose code is the
8835 * least significant byte;
8836 * if +object+ is a string, writes the first character:
8837 *
8838 * $stdout.putc "A"
8839 * $stdout.putc 65
8840 *
8841 * Output:
8842 *
8843 * AA
8844 *
8845 */
8846
8847static VALUE
8848rb_io_putc(VALUE io, VALUE ch)
8849{
8850 VALUE str;
8851 if (RB_TYPE_P(ch, T_STRING)) {
8852 str = rb_str_substr(ch, 0, 1);
8853 }
8854 else {
8855 char c = NUM2CHR(ch);
8856 str = rb_str_new(&c, 1);
8857 }
8858 rb_io_write(io, str);
8859 return ch;
8860}
8861
8862#define forward(obj, id, argc, argv) \
8863 rb_funcallv_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8864#define forward_public(obj, id, argc, argv) \
8865 rb_funcallv_public_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8866#define forward_current(id, argc, argv) \
8867 forward_public(ARGF.current_file, id, argc, argv)
8868
8869/*
8870 * call-seq:
8871 * putc(int) -> int
8872 *
8873 * Equivalent to:
8874 *
8875 * $stdout.putc(int)
8876 *
8877 * See IO#putc for important information regarding multi-byte characters.
8878 *
8879 */
8880
8881static VALUE
8882rb_f_putc(VALUE recv, VALUE ch)
8883{
8884 VALUE r_stdout = rb_ractor_stdout();
8885 if (recv == r_stdout) {
8886 return rb_io_putc(recv, ch);
8887 }
8888 return forward(r_stdout, rb_intern("putc"), 1, &ch);
8889}
8890
8891
8892int
8893rb_str_end_with_asciichar(VALUE str, int c)
8894{
8895 long len = RSTRING_LEN(str);
8896 const char *ptr = RSTRING_PTR(str);
8897 rb_encoding *enc = rb_enc_from_index(ENCODING_GET(str));
8898 int n;
8899
8900 if (len == 0) return 0;
8901 if ((n = rb_enc_mbminlen(enc)) == 1) {
8902 return ptr[len - 1] == c;
8903 }
8904 return rb_enc_ascget(ptr + ((len - 1) / n) * n, ptr + len, &n, enc) == c;
8905}
8906
8907static VALUE
8908io_puts_ary(VALUE ary, VALUE out, int recur)
8909{
8910 VALUE tmp;
8911 long i;
8912
8913 if (recur) {
8914 tmp = rb_str_new2("[...]");
8915 rb_io_puts(1, &tmp, out);
8916 return Qtrue;
8917 }
8918 ary = rb_check_array_type(ary);
8919 if (NIL_P(ary)) return Qfalse;
8920 for (i=0; i<RARRAY_LEN(ary); i++) {
8921 tmp = RARRAY_AREF(ary, i);
8922 rb_io_puts(1, &tmp, out);
8923 }
8924 return Qtrue;
8925}
8926
8927/*
8928 * call-seq:
8929 * puts(*objects) -> nil
8930 *
8931 * Writes the given +objects+ to the stream, which must be open for writing;
8932 * returns +nil+.\
8933 * Writes a newline after each that does not already end with a newline sequence.
8934 * If called without arguments, writes a newline.
8935 * See {Line IO}[rdoc-ref:IO@Line+IO].
8936 *
8937 * Note that each added newline is the character <tt>"\n"<//tt>,
8938 * not the output record separator (<tt>$\</tt>).
8939 *
8940 * Treatment for each object:
8941 *
8942 * - String: writes the string.
8943 * - Neither string nor array: writes <tt>object.to_s</tt>.
8944 * - Array: writes each element of the array; arrays may be nested.
8945 *
8946 * To keep these examples brief, we define this helper method:
8947 *
8948 * def show(*objects)
8949 * # Puts objects to file.
8950 * f = File.new('t.tmp', 'w+')
8951 * f.puts(objects)
8952 * # Return file content.
8953 * f.rewind
8954 * p f.read
8955 * f.close
8956 * end
8957 *
8958 * # Strings without newlines.
8959 * show('foo', 'bar', 'baz') # => "foo\nbar\nbaz\n"
8960 * # Strings, some with newlines.
8961 * show("foo\n", 'bar', "baz\n") # => "foo\nbar\nbaz\n"
8962 *
8963 * # Neither strings nor arrays:
8964 * show(0, 0.0, Rational(0, 1), Complex(9, 0), :zero)
8965 * # => "0\n0.0\n0/1\n9+0i\nzero\n"
8966 *
8967 * # Array of strings.
8968 * show(['foo', "bar\n", 'baz']) # => "foo\nbar\nbaz\n"
8969 * # Nested arrays.
8970 * show([[[0, 1], 2, 3], 4, 5]) # => "0\n1\n2\n3\n4\n5\n"
8971 *
8972 */
8973
8974VALUE
8975rb_io_puts(int argc, const VALUE *argv, VALUE out)
8976{
8977 VALUE line, args[2];
8978
8979 /* if no argument given, print newline. */
8980 if (argc == 0) {
8981 rb_io_write(out, rb_default_rs);
8982 return Qnil;
8983 }
8984 for (int i = 0; i < argc; i++) {
8985 // Convert the argument to a string:
8986 if (RB_TYPE_P(argv[i], T_STRING)) {
8987 line = argv[i];
8988 }
8989 else if (rb_exec_recursive(io_puts_ary, argv[i], out)) {
8990 continue;
8991 }
8992 else {
8993 line = rb_obj_as_string(argv[i]);
8994 }
8995
8996 // Write the line:
8997 int n = 0;
8998 if (RSTRING_LEN(line) == 0) {
8999 args[n++] = rb_default_rs;
9000 }
9001 else {
9002 args[n++] = line;
9003 if (!rb_str_end_with_asciichar(line, '\n')) {
9004 args[n++] = rb_default_rs;
9005 }
9006 }
9007
9008 rb_io_writev(out, n, args);
9009 }
9010
9011 return Qnil;
9012}
9013
9014/*
9015 * call-seq:
9016 * puts(*objects) -> nil
9017 *
9018 * Equivalent to
9019 *
9020 * $stdout.puts(objects)
9021 */
9022
9023static VALUE
9024rb_f_puts(int argc, VALUE *argv, VALUE recv)
9025{
9026 VALUE r_stdout = rb_ractor_stdout();
9027 if (recv == r_stdout) {
9028 return rb_io_puts(argc, argv, recv);
9029 }
9030 return forward(r_stdout, rb_intern("puts"), argc, argv);
9031}
9032
9033static VALUE
9034rb_p_write(VALUE str)
9035{
9036 VALUE args[2];
9037 args[0] = str;
9038 args[1] = rb_default_rs;
9039 VALUE r_stdout = rb_ractor_stdout();
9040 if (RB_TYPE_P(r_stdout, T_FILE) &&
9041 rb_method_basic_definition_p(CLASS_OF(r_stdout), id_write)) {
9042 io_writev(2, args, r_stdout);
9043 }
9044 else {
9045 rb_io_writev(r_stdout, 2, args);
9046 }
9047 return Qnil;
9048}
9049
9050void
9051rb_p(VALUE obj) /* for debug print within C code */
9052{
9053 rb_p_write(rb_obj_as_string(rb_inspect(obj)));
9054}
9055
9056static VALUE
9057rb_p_result(int argc, const VALUE *argv)
9058{
9059 VALUE ret = Qnil;
9060
9061 if (argc == 1) {
9062 ret = argv[0];
9063 }
9064 else if (argc > 1) {
9065 ret = rb_ary_new4(argc, argv);
9066 }
9067 VALUE r_stdout = rb_ractor_stdout();
9068 if (RB_TYPE_P(r_stdout, T_FILE)) {
9069 rb_uninterruptible(rb_io_flush, r_stdout);
9070 }
9071 return ret;
9072}
9073
9074/*
9075 * call-seq:
9076 * p(object) -> obj
9077 * p(*objects) -> array of objects
9078 * p -> nil
9079 *
9080 * For each object +obj+, executes:
9081 *
9082 * $stdout.write(obj.inspect, "\n")
9083 *
9084 * With one object given, returns the object;
9085 * with multiple objects given, returns an array containing the objects;
9086 * with no object given, returns +nil+.
9087 *
9088 * Examples:
9089 *
9090 * r = Range.new(0, 4)
9091 * p r # => 0..4
9092 * p [r, r, r] # => [0..4, 0..4, 0..4]
9093 * p # => nil
9094 *
9095 * Output:
9096 *
9097 * 0..4
9098 * [0..4, 0..4, 0..4]
9099 *
9100 * Kernel#p is designed for debugging purposes.
9101 * Ruby implementations may define Kernel#p to be uninterruptible
9102 * in whole or in part.
9103 * On CRuby, Kernel#p's writing of data is uninterruptible.
9104 */
9105
9106static VALUE
9107rb_f_p(int argc, VALUE *argv, VALUE self)
9108{
9109 int i;
9110 for (i=0; i<argc; i++) {
9111 VALUE inspected = rb_obj_as_string(rb_inspect(argv[i]));
9112 rb_uninterruptible(rb_p_write, inspected);
9113 }
9114 return rb_p_result(argc, argv);
9115}
9116
9117/*
9118 * call-seq:
9119 * display(port = $>) -> nil
9120 *
9121 * Writes +self+ on the given port:
9122 *
9123 * 1.display
9124 * "cat".display
9125 * [ 4, 5, 6 ].display
9126 * puts
9127 *
9128 * Output:
9129 *
9130 * 1cat[4, 5, 6]
9131 *
9132 */
9133
9134static VALUE
9135rb_obj_display(int argc, VALUE *argv, VALUE self)
9136{
9137 VALUE out;
9138
9139 out = (!rb_check_arity(argc, 0, 1) ? rb_ractor_stdout() : argv[0]);
9140 rb_io_write(out, self);
9141
9142 return Qnil;
9143}
9144
9145static int
9146rb_stderr_to_original_p(VALUE err)
9147{
9148 return (err == orig_stderr || RFILE(orig_stderr)->fptr->fd < 0);
9149}
9150
9151void
9152rb_write_error2(const char *mesg, long len)
9153{
9154 VALUE out = rb_ractor_stderr();
9155 if (rb_stderr_to_original_p(out)) {
9156#ifdef _WIN32
9157 if (isatty(fileno(stderr))) {
9158 if (rb_w32_write_console(rb_str_new(mesg, len), fileno(stderr)) > 0) return;
9159 }
9160#endif
9161 if (fwrite(mesg, sizeof(char), (size_t)len, stderr) < (size_t)len) {
9162 /* failed to write to stderr, what can we do? */
9163 return;
9164 }
9165 }
9166 else {
9167 rb_io_write(out, rb_str_new(mesg, len));
9168 }
9169}
9170
9171void
9172rb_write_error(const char *mesg)
9173{
9174 rb_write_error2(mesg, strlen(mesg));
9175}
9176
9177void
9178rb_write_error_str(VALUE mesg)
9179{
9180 VALUE out = rb_ractor_stderr();
9181 /* a stopgap measure for the time being */
9182 if (rb_stderr_to_original_p(out)) {
9183 size_t len = (size_t)RSTRING_LEN(mesg);
9184#ifdef _WIN32
9185 if (isatty(fileno(stderr))) {
9186 if (rb_w32_write_console(mesg, fileno(stderr)) > 0) return;
9187 }
9188#endif
9189 if (fwrite(RSTRING_PTR(mesg), sizeof(char), len, stderr) < len) {
9190 RB_GC_GUARD(mesg);
9191 return;
9192 }
9193 }
9194 else {
9195 /* may unlock GVL, and */
9196 rb_io_write(out, mesg);
9197 }
9198}
9199
9200int
9201rb_stderr_tty_p(void)
9202{
9203 if (rb_stderr_to_original_p(rb_ractor_stderr()))
9204 return isatty(fileno(stderr));
9205 return 0;
9206}
9207
9208static void
9209must_respond_to(ID mid, VALUE val, ID id)
9210{
9211 if (!rb_respond_to(val, mid)) {
9212 rb_raise(rb_eTypeError, "%"PRIsVALUE" must have %"PRIsVALUE" method, %"PRIsVALUE" given",
9213 rb_id2str(id), rb_id2str(mid),
9214 rb_obj_class(val));
9215 }
9216}
9217
9218static void
9219stdin_setter(VALUE val, ID id, VALUE *ptr)
9220{
9222}
9223
9224static VALUE
9225stdin_getter(ID id, VALUE *ptr)
9226{
9227 return rb_ractor_stdin();
9228}
9229
9230static void
9231stdout_setter(VALUE val, ID id, VALUE *ptr)
9232{
9233 must_respond_to(id_write, val, id);
9235}
9236
9237static VALUE
9238stdout_getter(ID id, VALUE *ptr)
9239{
9240 return rb_ractor_stdout();
9241}
9242
9243static void
9244stderr_setter(VALUE val, ID id, VALUE *ptr)
9245{
9246 must_respond_to(id_write, val, id);
9248}
9249
9250static VALUE
9251stderr_getter(ID id, VALUE *ptr)
9252{
9253 return rb_ractor_stderr();
9254}
9255
9256static VALUE
9257allocate_and_open_new_file(VALUE klass)
9258{
9259 VALUE self = io_alloc(klass);
9260 rb_io_make_open_file(self);
9261 return self;
9262}
9263
9264VALUE
9265rb_io_open_descriptor(VALUE klass, int descriptor, int mode, VALUE path, VALUE timeout, struct rb_io_encoding *encoding)
9266{
9267 int state;
9268 VALUE self = rb_protect(allocate_and_open_new_file, klass, &state);
9269 if (state) {
9270 /* if we raised an exception allocating an IO object, but the caller
9271 intended to transfer ownership of this FD to us, close the fd before
9272 raising the exception. Otherwise, we would leak a FD - the caller
9273 expects GC to close the file, but we never got around to assigning
9274 it to a rb_io. */
9275 if (!(mode & FMODE_EXTERNAL)) {
9276 maygvl_close(descriptor, 0);
9277 }
9278 rb_jump_tag(state);
9279 }
9280
9281
9282 rb_io_t *io = RFILE(self)->fptr;
9283 io->self = self;
9284 io->fd = descriptor;
9285 io->mode = mode;
9286
9287 /* At this point, Ruby fully owns the descriptor, and will close it when
9288 the IO gets GC'd (unless FMODE_EXTERNAL was set), no matter what happens
9289 in the rest of this method. */
9290
9291 if (NIL_P(path)) {
9292 io->pathv = Qnil;
9293 }
9294 else {
9295 StringValue(path);
9296 io->pathv = rb_str_new_frozen(path);
9297 }
9298
9299 io->timeout = timeout;
9300
9301 if (encoding) {
9302 io->encs = *encoding;
9303 }
9304
9305 rb_update_max_fd(descriptor);
9306
9307 return self;
9308}
9309
9310static VALUE
9311prep_io(int fd, enum rb_io_mode fmode, VALUE klass, const char *path)
9312{
9313 VALUE path_value = Qnil;
9314 rb_encoding *e;
9315 struct rb_io_encoding convconfig;
9316
9317 if (path) {
9318 path_value = rb_obj_freeze(rb_str_new_cstr(path));
9319 }
9320
9321 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
9322 rb_io_ext_int_to_encs(e, NULL, &convconfig.enc, &convconfig.enc2, fmode);
9323 convconfig.ecflags = (fmode & FMODE_READABLE) ?
9326#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9327 convconfig.ecflags |= (fmode & FMODE_WRITABLE) ?
9328 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
9329 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
9330#endif
9331 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.enc2, convconfig.ecflags);
9332 convconfig.ecopts = Qnil;
9333
9334 VALUE self = rb_io_open_descriptor(klass, fd, fmode, path_value, Qnil, &convconfig);
9335 rb_io_t*io = RFILE(self)->fptr;
9336
9337 if (!io_check_tty(io)) {
9338#ifdef __CYGWIN__
9339 io->mode |= FMODE_BINMODE;
9340 setmode(fd, O_BINARY);
9341#endif
9342 }
9343
9344 return self;
9345}
9346
9347VALUE
9348rb_io_fdopen(int fd, int oflags, const char *path)
9349{
9350 VALUE klass = rb_cIO;
9351
9352 if (path && strcmp(path, "-")) klass = rb_cFile;
9353 return prep_io(fd, rb_io_oflags_fmode(oflags), klass, path);
9354}
9355
9356static VALUE
9357prep_stdio(FILE *f, enum rb_io_mode fmode, VALUE klass, const char *path)
9358{
9359 rb_io_t *fptr;
9360 VALUE io = prep_io(fileno(f), fmode|FMODE_EXTERNAL|DEFAULT_TEXTMODE, klass, path);
9361
9362 GetOpenFile(io, fptr);
9364#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9365 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
9366 if (fmode & FMODE_READABLE) {
9368 }
9369#endif
9370 fptr->stdio_file = f;
9371
9372 return io;
9373}
9374
9375VALUE
9376rb_io_prep_stdin(void)
9377{
9378 return prep_stdio(stdin, FMODE_READABLE, rb_cIO, "<STDIN>");
9379}
9380
9381VALUE
9382rb_io_prep_stdout(void)
9383{
9384 return prep_stdio(stdout, FMODE_WRITABLE|FMODE_SIGNAL_ON_EPIPE, rb_cIO, "<STDOUT>");
9385}
9386
9387VALUE
9388rb_io_prep_stderr(void)
9389{
9390 return prep_stdio(stderr, FMODE_WRITABLE|FMODE_SYNC, rb_cIO, "<STDERR>");
9391}
9392
9393FILE *
9395{
9396 if (!fptr->stdio_file) {
9397 int oflags = rb_io_fmode_oflags(fptr->mode) & ~O_EXCL;
9398 fptr->stdio_file = rb_fdopen(fptr->fd, rb_io_oflags_modestr(oflags));
9399 }
9400 return fptr->stdio_file;
9401}
9402
9403static inline void
9404rb_io_buffer_init(struct rb_io_internal_buffer *buf)
9405{
9406 buf->ptr = NULL;
9407 buf->off = 0;
9408 buf->len = 0;
9409 buf->capa = 0;
9410}
9411
9412static inline rb_io_t *
9413rb_io_fptr_new(void)
9414{
9415 rb_io_t *fp = ALLOC(rb_io_t);
9416 fp->self = Qnil;
9417 fp->fd = -1;
9418 fp->stdio_file = NULL;
9419 fp->mode = 0;
9420 fp->pid = 0;
9421 fp->lineno = 0;
9422 fp->pathv = Qnil;
9423 fp->finalize = 0;
9424 rb_io_buffer_init(&fp->wbuf);
9425 rb_io_buffer_init(&fp->rbuf);
9426 rb_io_buffer_init(&fp->cbuf);
9427 fp->readconv = NULL;
9428 fp->writeconv = NULL;
9430 fp->writeconv_pre_ecflags = 0;
9432 fp->writeconv_initialized = 0;
9433 fp->tied_io_for_writing = 0;
9434 fp->encs.enc = NULL;
9435 fp->encs.enc2 = NULL;
9436 fp->encs.ecflags = 0;
9437 fp->encs.ecopts = Qnil;
9438 fp->write_lock = Qnil;
9439 fp->timeout = Qnil;
9440 return fp;
9441}
9442
9443rb_io_t *
9444rb_io_make_open_file(VALUE obj)
9445{
9446 rb_io_t *fp = 0;
9447
9448 Check_Type(obj, T_FILE);
9449 if (RFILE(obj)->fptr) {
9450 rb_io_close(obj);
9451 rb_io_fptr_finalize(RFILE(obj)->fptr);
9452 RFILE(obj)->fptr = 0;
9453 }
9454 fp = rb_io_fptr_new();
9455 fp->self = obj;
9456 RFILE(obj)->fptr = fp;
9457 return fp;
9458}
9459
9460static VALUE io_initialize(VALUE io, VALUE fnum, VALUE vmode, VALUE opt);
9461
9462/*
9463 * call-seq:
9464 * IO.new(fd, mode = 'r', **opts) -> io
9465 *
9466 * Creates and returns a new \IO object (file stream) from a file descriptor.
9467 *
9468 * \IO.new may be useful for interaction with low-level libraries.
9469 * For higher-level interactions, it may be simpler to create
9470 * the file stream using File.open.
9471 *
9472 * Argument +fd+ must be a valid file descriptor (integer):
9473 *
9474 * path = 't.tmp'
9475 * fd = IO.sysopen(path) # => 3
9476 * IO.new(fd) # => #<IO:fd 3>
9477 *
9478 * The new \IO object does not inherit encoding
9479 * (because the integer file descriptor does not have an encoding):
9480 *
9481 * fd = IO.sysopen('t.rus', 'rb')
9482 * io = IO.new(fd)
9483 * io.external_encoding # => #<Encoding:UTF-8> # Not ASCII-8BIT.
9484 *
9485 * Optional argument +mode+ (defaults to 'r') must specify a valid mode;
9486 * see {Access Modes}[rdoc-ref:File@Access+Modes]:
9487 *
9488 * IO.new(fd, 'w') # => #<IO:fd 3>
9489 * IO.new(fd, File::WRONLY) # => #<IO:fd 3>
9490 *
9491 * Optional keyword arguments +opts+ specify:
9492 *
9493 * - {Open Options}[rdoc-ref:IO@Open+Options].
9494 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
9495 *
9496 * Examples:
9497 *
9498 * IO.new(fd, internal_encoding: nil) # => #<IO:fd 3>
9499 * IO.new(fd, autoclose: true) # => #<IO:fd 3>
9500 *
9501 */
9502
9503static VALUE
9504rb_io_initialize(int argc, VALUE *argv, VALUE io)
9505{
9506 VALUE fnum, vmode;
9507 VALUE opt;
9508
9509 rb_scan_args(argc, argv, "11:", &fnum, &vmode, &opt);
9510 return io_initialize(io, fnum, vmode, opt);
9511}
9512
9513static VALUE
9514io_initialize(VALUE io, VALUE fnum, VALUE vmode, VALUE opt)
9515{
9516 rb_io_t *fp;
9517 int fd, oflags = O_RDONLY;
9518 enum rb_io_mode fmode;
9519 struct rb_io_encoding convconfig;
9520#if defined(HAVE_FCNTL) && defined(F_GETFL)
9521 int ofmode;
9522#else
9523 struct stat st;
9524#endif
9525
9526 rb_io_extract_modeenc(&vmode, 0, opt, &oflags, &fmode, &convconfig);
9527
9528 fd = NUM2INT(fnum);
9529 if (rb_reserved_fd_p(fd)) {
9530 rb_raise(rb_eArgError, "The given fd is not accessible because RubyVM reserves it");
9531 }
9532#if defined(HAVE_FCNTL) && defined(F_GETFL)
9533 oflags = fcntl(fd, F_GETFL);
9534 if (oflags == -1) rb_sys_fail(0);
9535#else
9536 if (fstat(fd, &st) < 0) rb_sys_fail(0);
9537#endif
9538 rb_update_max_fd(fd);
9539#if defined(HAVE_FCNTL) && defined(F_GETFL)
9540 ofmode = rb_io_oflags_fmode(oflags);
9541 if (NIL_P(vmode)) {
9542 fmode = ofmode;
9543 }
9544 else if ((~ofmode & fmode) & FMODE_READWRITE) {
9545 VALUE error = INT2FIX(EINVAL);
9547 }
9548#endif
9549 VALUE path = Qnil;
9550
9551 if (!NIL_P(opt)) {
9552 if (rb_hash_aref(opt, sym_autoclose) == Qfalse) {
9553 fmode |= FMODE_EXTERNAL;
9554 }
9555
9556 path = rb_hash_aref(opt, RB_ID2SYM(idPath));
9557 if (!NIL_P(path)) {
9558 StringValue(path);
9559 path = rb_str_new_frozen(path);
9560 }
9561 }
9562
9563 MakeOpenFile(io, fp);
9564 fp->self = io;
9565 fp->fd = fd;
9566 fp->mode = fmode;
9567 fp->encs = convconfig;
9568 fp->pathv = path;
9569 fp->timeout = Qnil;
9570 clear_codeconv(fp);
9571 io_check_tty(fp);
9572 if (fileno(stdin) == fd)
9573 fp->stdio_file = stdin;
9574 else if (fileno(stdout) == fd)
9575 fp->stdio_file = stdout;
9576 else if (fileno(stderr) == fd)
9577 fp->stdio_file = stderr;
9578
9579 if (fmode & FMODE_SETENC_BY_BOM) io_set_encoding_by_bom(io);
9580 return io;
9581}
9582
9583/*
9584 * call-seq:
9585 * set_encoding_by_bom -> encoding or nil
9586 *
9587 * If the stream begins with a BOM
9588 * ({byte order marker}[https://en.wikipedia.org/wiki/Byte_order_mark]),
9589 * consumes the BOM and sets the external encoding accordingly;
9590 * returns the result encoding if found, or +nil+ otherwise:
9591 *
9592 * File.write('t.tmp', "\u{FEFF}abc")
9593 * io = File.open('t.tmp', 'rb')
9594 * io.set_encoding_by_bom # => #<Encoding:UTF-8>
9595 * io.close
9596 *
9597 * File.write('t.tmp', 'abc')
9598 * io = File.open('t.tmp', 'rb')
9599 * io.set_encoding_by_bom # => nil
9600 * io.close
9601 *
9602 * Raises an exception if the stream is not binmode
9603 * or its encoding has already been set.
9604 *
9605 */
9606
9607static VALUE
9608rb_io_set_encoding_by_bom(VALUE io)
9609{
9610 rb_io_t *fptr;
9611
9612 GetOpenFile(io, fptr);
9613 if (!(fptr->mode & FMODE_BINMODE)) {
9614 rb_raise(rb_eArgError, "ASCII incompatible encoding needs binmode");
9615 }
9616 if (fptr->encs.enc2) {
9617 rb_raise(rb_eArgError, "encoding conversion is set");
9618 }
9619 else if (fptr->encs.enc && fptr->encs.enc != rb_ascii8bit_encoding()) {
9620 rb_raise(rb_eArgError, "encoding is set to %s already",
9621 rb_enc_name(fptr->encs.enc));
9622 }
9623 if (!io_set_encoding_by_bom(io)) return Qnil;
9624 return rb_enc_from_encoding(fptr->encs.enc);
9625}
9626
9627/*
9628 * call-seq:
9629 * File.new(path, mode = 'r', perm = 0666, **opts) -> file
9630 *
9631 * Opens the file at the given +path+ according to the given +mode+;
9632 * creates and returns a new File object for that file.
9633 *
9634 * The new File object is buffered mode (or non-sync mode), unless
9635 * +filename+ is a tty.
9636 * See IO#flush, IO#fsync, IO#fdatasync, and IO#sync=.
9637 *
9638 * Argument +path+ must be a valid file path:
9639 *
9640 * f = File.new('/etc/fstab')
9641 * f.close
9642 * f = File.new('t.txt')
9643 * f.close
9644 *
9645 * Optional argument +mode+ (defaults to 'r') must specify a valid mode;
9646 * see {Access Modes}[rdoc-ref:File@Access+Modes]:
9647 *
9648 * f = File.new('t.tmp', 'w')
9649 * f.close
9650 * f = File.new('t.tmp', File::RDONLY)
9651 * f.close
9652 *
9653 * Optional argument +perm+ (defaults to 0666) must specify valid permissions
9654 * see {File Permissions}[rdoc-ref:File@File+Permissions]:
9655 *
9656 * f = File.new('t.tmp', File::CREAT, 0644)
9657 * f.close
9658 * f = File.new('t.tmp', File::CREAT, 0444)
9659 * f.close
9660 *
9661 * Optional keyword arguments +opts+ specify:
9662 *
9663 * - {Open Options}[rdoc-ref:IO@Open+Options].
9664 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
9665 *
9666 */
9667
9668static VALUE
9669rb_file_initialize(int argc, VALUE *argv, VALUE io)
9670{
9671 if (RFILE(io)->fptr) {
9672 rb_raise(rb_eRuntimeError, "reinitializing File");
9673 }
9674 VALUE fname, vmode, vperm, opt;
9675 int posargc = rb_scan_args(argc, argv, "12:", &fname, &vmode, &vperm, &opt);
9676 if (posargc < 3) { /* perm is File only */
9677 VALUE fd = rb_check_to_int(fname);
9678
9679 if (!NIL_P(fd)) {
9680 return io_initialize(io, fd, vmode, opt);
9681 }
9682 }
9683 return rb_open_file(io, fname, vmode, vperm, opt);
9684}
9685
9686/* :nodoc: */
9687static VALUE
9688rb_io_s_new(int argc, VALUE *argv, VALUE klass)
9689{
9690 if (rb_block_given_p()) {
9691 VALUE cname = rb_obj_as_string(klass);
9692
9693 rb_warn("%"PRIsVALUE"::new() does not take block; use %"PRIsVALUE"::open() instead",
9694 cname, cname);
9695 }
9696 return rb_class_new_instance_kw(argc, argv, klass, RB_PASS_CALLED_KEYWORDS);
9697}
9698
9699
9700/*
9701 * call-seq:
9702 * IO.for_fd(fd, mode = 'r', **opts) -> io
9703 *
9704 * Synonym for IO.new.
9705 *
9706 */
9707
9708static VALUE
9709rb_io_s_for_fd(int argc, VALUE *argv, VALUE klass)
9710{
9711 VALUE io = rb_obj_alloc(klass);
9712 rb_io_initialize(argc, argv, io);
9713 return io;
9714}
9715
9716/*
9717 * call-seq:
9718 * ios.autoclose? -> true or false
9719 *
9720 * Returns +true+ if the underlying file descriptor of _ios_ will be
9721 * closed at its finalization or at calling #close, otherwise +false+.
9722 */
9723
9724static VALUE
9725rb_io_autoclose_p(VALUE io)
9726{
9727 rb_io_t *fptr = RFILE(io)->fptr;
9728 rb_io_check_closed(fptr);
9729 return RBOOL(!(fptr->mode & FMODE_EXTERNAL));
9730}
9731
9732/*
9733 * call-seq:
9734 * io.autoclose = bool -> true or false
9735 *
9736 * Sets auto-close flag.
9737 *
9738 * f = File.open(File::NULL)
9739 * IO.for_fd(f.fileno).close
9740 * f.gets # raises Errno::EBADF
9741 *
9742 * f = File.open(File::NULL)
9743 * g = IO.for_fd(f.fileno)
9744 * g.autoclose = false
9745 * g.close
9746 * f.gets # won't cause Errno::EBADF
9747 */
9748
9749static VALUE
9750rb_io_set_autoclose(VALUE io, VALUE autoclose)
9751{
9752 rb_io_t *fptr;
9753 GetOpenFile(io, fptr);
9754 if (!RTEST(autoclose))
9755 fptr->mode |= FMODE_EXTERNAL;
9756 else
9757 fptr->mode &= ~FMODE_EXTERNAL;
9758 return autoclose;
9759}
9760
9761static VALUE
9762io_wait_event(VALUE io, int event, VALUE timeout, int return_io)
9763{
9764 VALUE result = rb_io_wait(io, RB_INT2NUM(event), timeout);
9765
9766 if (!RB_TEST(result)) {
9767 return Qnil;
9768 }
9769
9770 int mask = RB_NUM2INT(result);
9771
9772 if (mask & event) {
9773 if (return_io)
9774 return io;
9775 else
9776 return result;
9777 }
9778 else {
9779 return Qfalse;
9780 }
9781}
9782
9783/*
9784 * call-seq:
9785 * io.wait_readable -> truthy or falsy
9786 * io.wait_readable(timeout) -> truthy or falsy
9787 *
9788 * Waits until IO is readable and returns a truthy value, or a falsy
9789 * value when times out. Returns a truthy value immediately when
9790 * buffered data is available.
9791 */
9792
9793static VALUE
9794io_wait_readable(int argc, VALUE *argv, VALUE io)
9795{
9796 rb_io_t *fptr;
9797
9798 RB_IO_POINTER(io, fptr);
9800
9801 if (rb_io_read_pending(fptr)) return Qtrue;
9802
9803 rb_check_arity(argc, 0, 1);
9804 VALUE timeout = (argc == 1 ? argv[0] : Qnil);
9805
9806 return io_wait_event(io, RUBY_IO_READABLE, timeout, 1);
9807}
9808
9809/*
9810 * call-seq:
9811 * io.wait_writable -> truthy or falsy
9812 * io.wait_writable(timeout) -> truthy or falsy
9813 *
9814 * Waits until IO is writable and returns a truthy value or a falsy
9815 * value when times out.
9816 */
9817static VALUE
9818io_wait_writable(int argc, VALUE *argv, VALUE io)
9819{
9820 rb_io_t *fptr;
9821
9822 RB_IO_POINTER(io, fptr);
9824
9825 rb_check_arity(argc, 0, 1);
9826 VALUE timeout = (argc == 1 ? argv[0] : Qnil);
9827
9828 return io_wait_event(io, RUBY_IO_WRITABLE, timeout, 1);
9829}
9830
9831/*
9832 * call-seq:
9833 * io.wait_priority -> truthy or falsy
9834 * io.wait_priority(timeout) -> truthy or falsy
9835 *
9836 * Waits until IO is priority and returns a truthy value or a falsy
9837 * value when times out. Priority data is sent and received using
9838 * the Socket::MSG_OOB flag and is typically limited to streams.
9839 */
9840static VALUE
9841io_wait_priority(int argc, VALUE *argv, VALUE io)
9842{
9843 rb_io_t *fptr = NULL;
9844
9845 RB_IO_POINTER(io, fptr);
9847
9848 if (rb_io_read_pending(fptr)) return Qtrue;
9849
9850 rb_check_arity(argc, 0, 1);
9851 VALUE timeout = argc == 1 ? argv[0] : Qnil;
9852
9853 return io_wait_event(io, RUBY_IO_PRIORITY, timeout, 1);
9854}
9855
9856static int
9857wait_mode_sym(VALUE mode)
9858{
9859 if (mode == ID2SYM(rb_intern("r"))) {
9860 return RB_WAITFD_IN;
9861 }
9862 if (mode == ID2SYM(rb_intern("read"))) {
9863 return RB_WAITFD_IN;
9864 }
9865 if (mode == ID2SYM(rb_intern("readable"))) {
9866 return RB_WAITFD_IN;
9867 }
9868 if (mode == ID2SYM(rb_intern("w"))) {
9869 return RB_WAITFD_OUT;
9870 }
9871 if (mode == ID2SYM(rb_intern("write"))) {
9872 return RB_WAITFD_OUT;
9873 }
9874 if (mode == ID2SYM(rb_intern("writable"))) {
9875 return RB_WAITFD_OUT;
9876 }
9877 if (mode == ID2SYM(rb_intern("rw"))) {
9878 return RB_WAITFD_IN|RB_WAITFD_OUT;
9879 }
9880 if (mode == ID2SYM(rb_intern("read_write"))) {
9881 return RB_WAITFD_IN|RB_WAITFD_OUT;
9882 }
9883 if (mode == ID2SYM(rb_intern("readable_writable"))) {
9884 return RB_WAITFD_IN|RB_WAITFD_OUT;
9885 }
9886
9887 rb_raise(rb_eArgError, "unsupported mode: %"PRIsVALUE, mode);
9888}
9889
9890static inline enum rb_io_event
9891io_event_from_value(VALUE value)
9892{
9893 int events = RB_NUM2INT(value);
9894
9895 if (events <= 0) rb_raise(rb_eArgError, "Events must be positive integer!");
9896
9897 return events;
9898}
9899
9900/*
9901 * call-seq:
9902 * io.wait(events, timeout) -> event mask, false or nil
9903 * io.wait(timeout = nil, mode = :read) -> self, true, or false
9904 *
9905 * Waits until the IO becomes ready for the specified events and returns the
9906 * subset of events that become ready, or a falsy value when times out.
9907 *
9908 * The events can be a bit mask of +IO::READABLE+, +IO::WRITABLE+ or
9909 * +IO::PRIORITY+.
9910 *
9911 * Returns an event mask (truthy value) immediately when buffered data is available.
9912 *
9913 * Optional parameter +mode+ is one of +:read+, +:write+, or
9914 * +:read_write+.
9915 */
9916
9917static VALUE
9918io_wait(int argc, VALUE *argv, VALUE io)
9919{
9920 VALUE timeout = Qundef;
9921 enum rb_io_event events = 0;
9922 int return_io = 0;
9923
9924 // The documented signature for this method is actually incorrect.
9925 // A single timeout is allowed in any position, and multiple symbols can be given.
9926 // Whether this is intentional or not, I don't know, and as such I consider this to
9927 // be a legacy/slow path.
9928 if (argc != 2 || (RB_SYMBOL_P(argv[0]) || RB_SYMBOL_P(argv[1]))) {
9929 // We'd prefer to return the actual mask, but this form would return the io itself:
9930 return_io = 1;
9931
9932 // Slow/messy path:
9933 for (int i = 0; i < argc; i += 1) {
9934 if (RB_SYMBOL_P(argv[i])) {
9935 events |= wait_mode_sym(argv[i]);
9936 }
9937 else if (UNDEF_P(timeout)) {
9938 rb_time_interval(timeout = argv[i]);
9939 }
9940 else {
9941 rb_raise(rb_eArgError, "timeout given more than once");
9942 }
9943 }
9944
9945 if (UNDEF_P(timeout)) timeout = Qnil;
9946
9947 if (events == 0) {
9948 events = RUBY_IO_READABLE;
9949 }
9950 }
9951 else /* argc == 2 and neither are symbols */ {
9952 // This is the fast path:
9953 events = io_event_from_value(argv[0]);
9954 timeout = argv[1];
9955 }
9956
9957 if (events & RUBY_IO_READABLE) {
9958 rb_io_t *fptr = NULL;
9959 RB_IO_POINTER(io, fptr);
9960
9961 if (rb_io_read_pending(fptr)) {
9962 // This was the original behaviour:
9963 if (return_io) return Qtrue;
9964 // New behaviour always returns an event mask:
9965 else return RB_INT2NUM(RUBY_IO_READABLE);
9966 }
9967 }
9968
9969 return io_wait_event(io, events, timeout, return_io);
9970}
9971
9972static void
9973argf_mark(void *ptr)
9974{
9975 struct argf *p = ptr;
9976 rb_gc_mark(p->filename);
9977 rb_gc_mark(p->current_file);
9978 rb_gc_mark(p->argv);
9979 rb_gc_mark(p->inplace);
9980 rb_gc_mark(p->encs.ecopts);
9981}
9982
9983static size_t
9984argf_memsize(const void *ptr)
9985{
9986 const struct argf *p = ptr;
9987 size_t size = sizeof(*p);
9988 return size;
9989}
9990
9991static void
9992argf_compact(void *ptr)
9993{
9994 struct argf *p = ptr;
9995 p->filename = rb_gc_location(p->filename);
9996 p->current_file = rb_gc_location(p->current_file);
9997 p->argv = rb_gc_location(p->argv);
9998 p->inplace = rb_gc_location(p->inplace);
9999 p->encs.ecopts = rb_gc_location(p->encs.ecopts);
10000}
10001
10002static const rb_data_type_t argf_type = {
10003 "ARGF",
10004 {argf_mark, RUBY_TYPED_DEFAULT_FREE, argf_memsize, argf_compact},
10005 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
10006};
10007
10008static inline void
10009argf_init(struct argf *p, VALUE v)
10010{
10011 p->filename = Qnil;
10012 p->current_file = Qnil;
10013 p->lineno = 0;
10014 p->argv = v;
10015}
10016
10017static VALUE
10018argf_alloc(VALUE klass)
10019{
10020 struct argf *p;
10021 VALUE argf = TypedData_Make_Struct(klass, struct argf, &argf_type, p);
10022
10023 argf_init(p, Qnil);
10024 return argf;
10025}
10026
10027#undef rb_argv
10028
10029/* :nodoc: */
10030static VALUE
10031argf_initialize(VALUE argf, VALUE argv)
10032{
10033 memset(&ARGF, 0, sizeof(ARGF));
10034 argf_init(&ARGF, argv);
10035
10036 return argf;
10037}
10038
10039/* :nodoc: */
10040static VALUE
10041argf_initialize_copy(VALUE argf, VALUE orig)
10042{
10043 if (!OBJ_INIT_COPY(argf, orig)) return argf;
10044 ARGF = argf_of(orig);
10045 ARGF.argv = rb_obj_dup(ARGF.argv);
10046 return argf;
10047}
10048
10049/*
10050 * call-seq:
10051 * ARGF.lineno = integer -> integer
10052 *
10053 * Sets the line number of ARGF as a whole to the given Integer.
10054 *
10055 * ARGF sets the line number automatically as you read data, so normally
10056 * you will not need to set it explicitly. To access the current line number
10057 * use ARGF.lineno.
10058 *
10059 * For example:
10060 *
10061 * ARGF.lineno #=> 0
10062 * ARGF.readline #=> "This is line 1\n"
10063 * ARGF.lineno #=> 1
10064 * ARGF.lineno = 0 #=> 0
10065 * ARGF.lineno #=> 0
10066 */
10067static VALUE
10068argf_set_lineno(VALUE argf, VALUE val)
10069{
10070 ARGF.lineno = NUM2INT(val);
10071 ARGF.last_lineno = ARGF.lineno;
10072 return val;
10073}
10074
10075/*
10076 * call-seq:
10077 * ARGF.lineno -> integer
10078 *
10079 * Returns the current line number of ARGF as a whole. This value
10080 * can be set manually with ARGF.lineno=.
10081 *
10082 * For example:
10083 *
10084 * ARGF.lineno #=> 0
10085 * ARGF.readline #=> "This is line 1\n"
10086 * ARGF.lineno #=> 1
10087 */
10088static VALUE
10089argf_lineno(VALUE argf)
10090{
10091 return INT2FIX(ARGF.lineno);
10092}
10093
10094static VALUE
10095argf_forward(int argc, VALUE *argv, VALUE argf)
10096{
10097 return forward_current(rb_frame_this_func(), argc, argv);
10098}
10099
10100#define next_argv() argf_next_argv(argf)
10101#define ARGF_GENERIC_INPUT_P() \
10102 (ARGF.current_file == rb_stdin && !RB_TYPE_P(ARGF.current_file, T_FILE))
10103#define ARGF_FORWARD(argc, argv) do {\
10104 if (ARGF_GENERIC_INPUT_P())\
10105 return argf_forward((argc), (argv), argf);\
10106} while (0)
10107#define NEXT_ARGF_FORWARD(argc, argv) do {\
10108 if (!next_argv()) return Qnil;\
10109 ARGF_FORWARD((argc), (argv));\
10110} while (0)
10111
10112static void
10113argf_close(VALUE argf)
10114{
10115 VALUE file = ARGF.current_file;
10116 if (file == rb_stdin) return;
10117 if (RB_TYPE_P(file, T_FILE)) {
10118 rb_io_set_write_io(file, Qnil);
10119 }
10120 io_close(file);
10121 ARGF.init_p = -1;
10122}
10123
10124static int
10125argf_next_argv(VALUE argf)
10126{
10127 char *fn;
10128 rb_io_t *fptr;
10129 int stdout_binmode = 0;
10130 enum rb_io_mode fmode;
10131
10132 VALUE r_stdout = rb_ractor_stdout();
10133
10134 if (RB_TYPE_P(r_stdout, T_FILE)) {
10135 GetOpenFile(r_stdout, fptr);
10136 if (fptr->mode & FMODE_BINMODE)
10137 stdout_binmode = 1;
10138 }
10139
10140 if (ARGF.init_p == 0) {
10141 if (!NIL_P(ARGF.argv) && RARRAY_LEN(ARGF.argv) > 0) {
10142 ARGF.next_p = 1;
10143 }
10144 else {
10145 ARGF.next_p = -1;
10146 }
10147 ARGF.init_p = 1;
10148 }
10149 else {
10150 if (NIL_P(ARGF.argv)) {
10151 ARGF.next_p = -1;
10152 }
10153 else if (ARGF.next_p == -1 && RARRAY_LEN(ARGF.argv) > 0) {
10154 ARGF.next_p = 1;
10155 }
10156 }
10157
10158 if (ARGF.next_p == 1) {
10159 if (ARGF.init_p == 1) argf_close(argf);
10160 retry:
10161 if (RARRAY_LEN(ARGF.argv) > 0) {
10162 VALUE filename = rb_ary_shift(ARGF.argv);
10163 FilePathValue(filename);
10164 ARGF.filename = filename;
10165 filename = rb_str_encode_ospath(filename);
10166 fn = StringValueCStr(filename);
10167 if (RSTRING_LEN(filename) == 1 && fn[0] == '-') {
10168 ARGF.current_file = rb_stdin;
10169 if (ARGF.inplace) {
10170 rb_warn("Can't do inplace edit for stdio; skipping");
10171 goto retry;
10172 }
10173 }
10174 else {
10175 VALUE write_io = Qnil;
10176 int fr = rb_sysopen(filename, O_RDONLY, 0);
10177
10178 if (ARGF.inplace) {
10179 struct stat st;
10180#ifndef NO_SAFE_RENAME
10181 struct stat st2;
10182#endif
10183 VALUE str;
10184 int fw;
10185
10186 if (RB_TYPE_P(r_stdout, T_FILE) && r_stdout != orig_stdout) {
10187 rb_io_close(r_stdout);
10188 }
10189 fstat(fr, &st);
10190 str = filename;
10191 if (!NIL_P(ARGF.inplace)) {
10192 VALUE suffix = ARGF.inplace;
10193 str = rb_str_dup(str);
10194 if (NIL_P(rb_str_cat_conv_enc_opts(str, RSTRING_LEN(str),
10195 RSTRING_PTR(suffix), RSTRING_LEN(suffix),
10196 rb_enc_get(suffix), 0, Qnil))) {
10197 rb_str_append(str, suffix);
10198 }
10199#ifdef NO_SAFE_RENAME
10200 (void)close(fr);
10201 (void)unlink(RSTRING_PTR(str));
10202 if (rename(fn, RSTRING_PTR(str)) < 0) {
10203 rb_warn("Can't rename %"PRIsVALUE" to %"PRIsVALUE": %s, skipping file",
10204 filename, str, strerror(errno));
10205 goto retry;
10206 }
10207 fr = rb_sysopen(str, O_RDONLY, 0);
10208#else
10209 if (rename(fn, RSTRING_PTR(str)) < 0) {
10210 rb_warn("Can't rename %"PRIsVALUE" to %"PRIsVALUE": %s, skipping file",
10211 filename, str, strerror(errno));
10212 close(fr);
10213 goto retry;
10214 }
10215#endif
10216 }
10217 else {
10218#ifdef NO_SAFE_RENAME
10219 rb_fatal("Can't do inplace edit without backup");
10220#else
10221 if (unlink(fn) < 0) {
10222 rb_warn("Can't remove %"PRIsVALUE": %s, skipping file",
10223 filename, strerror(errno));
10224 close(fr);
10225 goto retry;
10226 }
10227#endif
10228 }
10229 fw = rb_sysopen(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666);
10230#ifndef NO_SAFE_RENAME
10231 fstat(fw, &st2);
10232#ifdef HAVE_FCHMOD
10233 fchmod(fw, st.st_mode);
10234#else
10235 chmod(fn, st.st_mode);
10236#endif
10237 if (st.st_uid!=st2.st_uid || st.st_gid!=st2.st_gid) {
10238 int err;
10239#ifdef HAVE_FCHOWN
10240 err = fchown(fw, st.st_uid, st.st_gid);
10241#else
10242 err = chown(fn, st.st_uid, st.st_gid);
10243#endif
10244 if (err && getuid() == 0 && st2.st_uid == 0) {
10245 const char *wkfn = RSTRING_PTR(filename);
10246 rb_warn("Can't set owner/group of %"PRIsVALUE" to same as %"PRIsVALUE": %s, skipping file",
10247 filename, str, strerror(errno));
10248 (void)close(fr);
10249 (void)close(fw);
10250 (void)unlink(wkfn);
10251 goto retry;
10252 }
10253 }
10254#endif
10255 write_io = prep_io(fw, FMODE_WRITABLE, rb_cFile, fn);
10256 rb_ractor_stdout_set(write_io);
10257 if (stdout_binmode) rb_io_binmode(rb_stdout);
10258 }
10259 fmode = FMODE_READABLE;
10260 if (!ARGF.binmode) {
10261 fmode |= DEFAULT_TEXTMODE;
10262 }
10263 ARGF.current_file = prep_io(fr, fmode, rb_cFile, fn);
10264 if (!NIL_P(write_io)) {
10265 rb_io_set_write_io(ARGF.current_file, write_io);
10266 }
10267 RB_GC_GUARD(filename);
10268 }
10269 if (ARGF.binmode) rb_io_ascii8bit_binmode(ARGF.current_file);
10270 GetOpenFile(ARGF.current_file, fptr);
10271 if (ARGF.encs.enc) {
10272 fptr->encs = ARGF.encs;
10273 clear_codeconv(fptr);
10274 }
10275 else {
10276 fptr->encs.ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
10277 if (!ARGF.binmode) {
10279#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
10280 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
10281#endif
10282 }
10283 }
10284 ARGF.next_p = 0;
10285 }
10286 else {
10287 ARGF.next_p = 1;
10288 return FALSE;
10289 }
10290 }
10291 else if (ARGF.next_p == -1) {
10292 ARGF.current_file = rb_stdin;
10293 ARGF.filename = rb_str_new2("-");
10294 if (ARGF.inplace) {
10295 rb_warn("Can't do inplace edit for stdio");
10296 rb_ractor_stdout_set(orig_stdout);
10297 }
10298 }
10299 if (ARGF.init_p == -1) ARGF.init_p = 1;
10300 return TRUE;
10301}
10302
10303static VALUE
10304argf_getline(int argc, VALUE *argv, VALUE argf)
10305{
10306 VALUE line;
10307 long lineno = ARGF.lineno;
10308
10309 retry:
10310 if (!next_argv()) return Qnil;
10311 if (ARGF_GENERIC_INPUT_P()) {
10312 line = forward_current(idGets, argc, argv);
10313 }
10314 else {
10315 if (argc == 0 && rb_rs == rb_default_rs) {
10316 line = rb_io_gets(ARGF.current_file);
10317 }
10318 else {
10319 line = rb_io_getline(argc, argv, ARGF.current_file);
10320 }
10321 if (NIL_P(line) && ARGF.next_p != -1) {
10322 argf_close(argf);
10323 ARGF.next_p = 1;
10324 goto retry;
10325 }
10326 }
10327 if (!NIL_P(line)) {
10328 ARGF.lineno = ++lineno;
10329 ARGF.last_lineno = ARGF.lineno;
10330 }
10331 return line;
10332}
10333
10334static VALUE
10335argf_lineno_getter(ID id, VALUE *var)
10336{
10337 VALUE argf = *var;
10338 return INT2FIX(ARGF.last_lineno);
10339}
10340
10341static void
10342argf_lineno_setter(VALUE val, ID id, VALUE *var)
10343{
10344 VALUE argf = *var;
10345 int n = NUM2INT(val);
10346 ARGF.last_lineno = ARGF.lineno = n;
10347}
10348
10349void
10350rb_reset_argf_lineno(long n)
10351{
10352 ARGF.last_lineno = ARGF.lineno = n;
10353}
10354
10355static VALUE argf_gets(int, VALUE *, VALUE);
10356
10357/*
10358 * call-seq:
10359 * gets(sep=$/ [, getline_args]) -> string or nil
10360 * gets(limit [, getline_args]) -> string or nil
10361 * gets(sep, limit [, getline_args]) -> string or nil
10362 *
10363 * Returns (and assigns to <code>$_</code>) the next line from the list
10364 * of files in +ARGV+ (or <code>$*</code>), or from standard input if
10365 * no files are present on the command line. Returns +nil+ at end of
10366 * file. The optional argument specifies the record separator. The
10367 * separator is included with the contents of each record. A separator
10368 * of +nil+ reads the entire contents, and a zero-length separator
10369 * reads the input one paragraph at a time, where paragraphs are
10370 * divided by two consecutive newlines. If the first argument is an
10371 * integer, or optional second argument is given, the returning string
10372 * would not be longer than the given value in bytes. If multiple
10373 * filenames are present in +ARGV+, <code>gets(nil)</code> will read
10374 * the contents one file at a time.
10375 *
10376 * ARGV << "testfile"
10377 * print while gets
10378 *
10379 * <em>produces:</em>
10380 *
10381 * This is line one
10382 * This is line two
10383 * This is line three
10384 * And so on...
10385 *
10386 * The style of programming using <code>$_</code> as an implicit
10387 * parameter is gradually losing favor in the Ruby community.
10388 */
10389
10390static VALUE
10391rb_f_gets(int argc, VALUE *argv, VALUE recv)
10392{
10393 if (recv == argf) {
10394 return argf_gets(argc, argv, argf);
10395 }
10396 return forward(argf, idGets, argc, argv);
10397}
10398
10399/*
10400 * call-seq:
10401 * ARGF.gets(sep=$/ [, getline_args]) -> string or nil
10402 * ARGF.gets(limit [, getline_args]) -> string or nil
10403 * ARGF.gets(sep, limit [, getline_args]) -> string or nil
10404 *
10405 * Returns the next line from the current file in ARGF.
10406 *
10407 * By default lines are assumed to be separated by <code>$/</code>;
10408 * to use a different character as a separator, supply it as a String
10409 * for the _sep_ argument.
10410 *
10411 * The optional _limit_ argument specifies how many characters of each line
10412 * to return. By default all characters are returned.
10413 *
10414 * See IO.readlines for details about getline_args.
10415 *
10416 */
10417static VALUE
10418argf_gets(int argc, VALUE *argv, VALUE argf)
10419{
10420 VALUE line;
10421
10422 line = argf_getline(argc, argv, argf);
10423 rb_lastline_set(line);
10424
10425 return line;
10426}
10427
10428VALUE
10430{
10431 VALUE line;
10432
10433 if (rb_rs != rb_default_rs) {
10434 return rb_f_gets(0, 0, argf);
10435 }
10436
10437 retry:
10438 if (!next_argv()) return Qnil;
10439 line = rb_io_gets(ARGF.current_file);
10440 if (NIL_P(line) && ARGF.next_p != -1) {
10441 rb_io_close(ARGF.current_file);
10442 ARGF.next_p = 1;
10443 goto retry;
10444 }
10445 rb_lastline_set(line);
10446 if (!NIL_P(line)) {
10447 ARGF.lineno++;
10448 ARGF.last_lineno = ARGF.lineno;
10449 }
10450
10451 return line;
10452}
10453
10454static VALUE argf_readline(int, VALUE *, VALUE);
10455
10456/*
10457 * call-seq:
10458 * readline(sep = $/, chomp: false) -> string
10459 * readline(limit, chomp: false) -> string
10460 * readline(sep, limit, chomp: false) -> string
10461 *
10462 * Equivalent to method Kernel#gets, except that it raises an exception
10463 * if called at end-of-stream:
10464 *
10465 * $ cat t.txt | ruby -e "p readlines; readline"
10466 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10467 * in `readline': end of file reached (EOFError)
10468 *
10469 * Optional keyword argument +chomp+ specifies whether line separators
10470 * are to be omitted.
10471 */
10472
10473static VALUE
10474rb_f_readline(int argc, VALUE *argv, VALUE recv)
10475{
10476 if (recv == argf) {
10477 return argf_readline(argc, argv, argf);
10478 }
10479 return forward(argf, rb_intern("readline"), argc, argv);
10480}
10481
10482
10483/*
10484 * call-seq:
10485 * ARGF.readline(sep=$/) -> string
10486 * ARGF.readline(limit) -> string
10487 * ARGF.readline(sep, limit) -> string
10488 *
10489 * Returns the next line from the current file in ARGF.
10490 *
10491 * By default lines are assumed to be separated by <code>$/</code>;
10492 * to use a different character as a separator, supply it as a String
10493 * for the _sep_ argument.
10494 *
10495 * The optional _limit_ argument specifies how many characters of each line
10496 * to return. By default all characters are returned.
10497 *
10498 * An EOFError is raised at the end of the file.
10499 */
10500static VALUE
10501argf_readline(int argc, VALUE *argv, VALUE argf)
10502{
10503 VALUE line;
10504
10505 if (!next_argv()) rb_eof_error();
10506 ARGF_FORWARD(argc, argv);
10507 line = argf_gets(argc, argv, argf);
10508 if (NIL_P(line)) {
10509 rb_eof_error();
10510 }
10511
10512 return line;
10513}
10514
10515static VALUE argf_readlines(int, VALUE *, VALUE);
10516
10517/*
10518 * call-seq:
10519 * readlines(sep = $/, chomp: false, **enc_opts) -> array
10520 * readlines(limit, chomp: false, **enc_opts) -> array
10521 * readlines(sep, limit, chomp: false, **enc_opts) -> array
10522 *
10523 * Returns an array containing the lines returned by calling
10524 * Kernel#gets until the end-of-stream is reached;
10525 * (see {Line IO}[rdoc-ref:IO@Line+IO]).
10526 *
10527 * With only string argument +sep+ given,
10528 * returns the remaining lines as determined by line separator +sep+,
10529 * or +nil+ if none;
10530 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
10531 *
10532 * # Default separator.
10533 * $ cat t.txt | ruby -e "p readlines"
10534 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10535 *
10536 * # Specified separator.
10537 * $ cat t.txt | ruby -e "p readlines 'li'"
10538 * ["First li", "ne\nSecond li", "ne\n\nFourth li", "ne\nFifth li", "ne\n"]
10539 *
10540 * # Get-all separator.
10541 * $ cat t.txt | ruby -e "p readlines nil"
10542 * ["First line\nSecond line\n\nFourth line\nFifth line\n"]
10543 *
10544 * # Get-paragraph separator.
10545 * $ cat t.txt | ruby -e "p readlines ''"
10546 * ["First line\nSecond line\n\n", "Fourth line\nFifth line\n"]
10547 *
10548 * With only integer argument +limit+ given,
10549 * limits the number of bytes in the line;
10550 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
10551 *
10552 * $cat t.txt | ruby -e "p readlines 10"
10553 * ["First line", "\n", "Second lin", "e\n", "\n", "Fourth lin", "e\n", "Fifth line", "\n"]
10554 *
10555 * $cat t.txt | ruby -e "p readlines 11"
10556 * ["First line\n", "Second line", "\n", "\n", "Fourth line", "\n", "Fifth line\n"]
10557 *
10558 * $cat t.txt | ruby -e "p readlines 12"
10559 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10560 *
10561 * With arguments +sep+ and +limit+ given,
10562 * combines the two behaviors
10563 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
10564 *
10565 * Optional keyword argument +chomp+ specifies whether line separators
10566 * are to be omitted:
10567 *
10568 * $ cat t.txt | ruby -e "p readlines(chomp: true)"
10569 * ["First line", "Second line", "", "Fourth line", "Fifth line"]
10570 *
10571 * Optional keyword arguments +enc_opts+ specify encoding options;
10572 * see {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
10573 *
10574 */
10575
10576static VALUE
10577rb_f_readlines(int argc, VALUE *argv, VALUE recv)
10578{
10579 if (recv == argf) {
10580 return argf_readlines(argc, argv, argf);
10581 }
10582 return forward(argf, rb_intern("readlines"), argc, argv);
10583}
10584
10585/*
10586 * call-seq:
10587 * ARGF.readlines(sep = $/, chomp: false) -> array
10588 * ARGF.readlines(limit, chomp: false) -> array
10589 * ARGF.readlines(sep, limit, chomp: false) -> array
10590 *
10591 * ARGF.to_a(sep = $/, chomp: false) -> array
10592 * ARGF.to_a(limit, chomp: false) -> array
10593 * ARGF.to_a(sep, limit, chomp: false) -> array
10594 *
10595 * Reads each file in ARGF in its entirety, returning an Array containing
10596 * lines from the files. Lines are assumed to be separated by _sep_.
10597 *
10598 * lines = ARGF.readlines
10599 * lines[0] #=> "This is line one\n"
10600 *
10601 * See +IO.readlines+ for a full description of all options.
10602 */
10603static VALUE
10604argf_readlines(int argc, VALUE *argv, VALUE argf)
10605{
10606 long lineno = ARGF.lineno;
10607 VALUE lines, ary;
10608
10609 ary = rb_ary_new();
10610 while (next_argv()) {
10611 if (ARGF_GENERIC_INPUT_P()) {
10612 lines = forward_current(rb_intern("readlines"), argc, argv);
10613 }
10614 else {
10615 lines = rb_io_readlines(argc, argv, ARGF.current_file);
10616 argf_close(argf);
10617 }
10618 ARGF.next_p = 1;
10619 rb_ary_concat(ary, lines);
10620 ARGF.lineno = lineno + RARRAY_LEN(ary);
10621 ARGF.last_lineno = ARGF.lineno;
10622 }
10623 ARGF.init_p = 0;
10624 return ary;
10625}
10626
10627/*
10628 * call-seq:
10629 * `command` -> string
10630 *
10631 * Returns the <tt>$stdout</tt> output from running +command+ in a subshell;
10632 * sets global variable <tt>$?</tt> to the process status.
10633 *
10634 * This method has potential security vulnerabilities if called with untrusted input;
10635 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
10636 *
10637 * Examples:
10638 *
10639 * $ `date` # => "Wed Apr 9 08:56:30 CDT 2003\n"
10640 * $ `echo oops && exit 99` # => "oops\n"
10641 * $ $? # => #<Process::Status: pid 17088 exit 99>
10642 * $ $?.status # => 99>
10643 *
10644 * The built-in syntax <tt>%x{...}</tt> uses this method.
10645 *
10646 */
10647
10648static VALUE
10649rb_f_backquote(VALUE obj, VALUE str)
10650{
10651 VALUE port;
10652 VALUE result;
10653 rb_io_t *fptr;
10654
10655 StringValue(str);
10656 rb_last_status_clear();
10657 port = pipe_open_s(str, "r", FMODE_READABLE|DEFAULT_TEXTMODE, NULL);
10658 if (NIL_P(port)) return rb_str_new(0,0);
10659
10660 GetOpenFile(port, fptr);
10661 result = read_all(fptr, remain_size(fptr), Qnil);
10662 rb_io_close(port);
10663 rb_io_fptr_cleanup_all(fptr);
10664 RB_GC_GUARD(port);
10665
10666 return result;
10667}
10668
10669#ifdef HAVE_SYS_SELECT_H
10670#include <sys/select.h>
10671#endif
10672
10673static VALUE
10674select_internal(VALUE read, VALUE write, VALUE except, struct timeval *tp, rb_fdset_t *fds)
10675{
10676 VALUE res, list;
10677 rb_fdset_t *rp, *wp, *ep;
10678 rb_io_t *fptr;
10679 long i;
10680 int max = 0, n;
10681 int pending = 0;
10682 struct timeval timerec;
10683
10684 if (!NIL_P(read)) {
10685 Check_Type(read, T_ARRAY);
10686 for (i=0; i<RARRAY_LEN(read); i++) {
10687 GetOpenFile(rb_io_get_io(RARRAY_AREF(read, i)), fptr);
10688 rb_fd_set(fptr->fd, &fds[0]);
10689 if (READ_DATA_PENDING(fptr) || READ_CHAR_PENDING(fptr)) { /* check for buffered data */
10690 pending++;
10691 rb_fd_set(fptr->fd, &fds[3]);
10692 }
10693 if (max < fptr->fd) max = fptr->fd;
10694 }
10695 if (pending) { /* no blocking if there's buffered data */
10696 timerec.tv_sec = timerec.tv_usec = 0;
10697 tp = &timerec;
10698 }
10699 rp = &fds[0];
10700 }
10701 else
10702 rp = 0;
10703
10704 if (!NIL_P(write)) {
10705 Check_Type(write, T_ARRAY);
10706 for (i=0; i<RARRAY_LEN(write); i++) {
10707 VALUE write_io = GetWriteIO(rb_io_get_io(RARRAY_AREF(write, i)));
10708 GetOpenFile(write_io, fptr);
10709 rb_fd_set(fptr->fd, &fds[1]);
10710 if (max < fptr->fd) max = fptr->fd;
10711 }
10712 wp = &fds[1];
10713 }
10714 else
10715 wp = 0;
10716
10717 if (!NIL_P(except)) {
10718 Check_Type(except, T_ARRAY);
10719 for (i=0; i<RARRAY_LEN(except); i++) {
10720 VALUE io = rb_io_get_io(RARRAY_AREF(except, i));
10721 VALUE write_io = GetWriteIO(io);
10722 GetOpenFile(io, fptr);
10723 rb_fd_set(fptr->fd, &fds[2]);
10724 if (max < fptr->fd) max = fptr->fd;
10725 if (io != write_io) {
10726 GetOpenFile(write_io, fptr);
10727 rb_fd_set(fptr->fd, &fds[2]);
10728 if (max < fptr->fd) max = fptr->fd;
10729 }
10730 }
10731 ep = &fds[2];
10732 }
10733 else {
10734 ep = 0;
10735 }
10736
10737 max++;
10738
10739 n = rb_thread_fd_select(max, rp, wp, ep, tp);
10740 if (n < 0) {
10741 rb_sys_fail(0);
10742 }
10743 if (!pending && n == 0) return Qnil; /* returns nil on timeout */
10744
10745 res = rb_ary_new2(3);
10746 rb_ary_push(res, rp?rb_ary_new():rb_ary_new2(0));
10747 rb_ary_push(res, wp?rb_ary_new():rb_ary_new2(0));
10748 rb_ary_push(res, ep?rb_ary_new():rb_ary_new2(0));
10749
10750 if (rp) {
10751 list = RARRAY_AREF(res, 0);
10752 for (i=0; i< RARRAY_LEN(read); i++) {
10753 VALUE obj = rb_ary_entry(read, i);
10754 VALUE io = rb_io_get_io(obj);
10755 GetOpenFile(io, fptr);
10756 if (rb_fd_isset(fptr->fd, &fds[0]) ||
10757 rb_fd_isset(fptr->fd, &fds[3])) {
10758 rb_ary_push(list, obj);
10759 }
10760 }
10761 }
10762
10763 if (wp) {
10764 list = RARRAY_AREF(res, 1);
10765 for (i=0; i< RARRAY_LEN(write); i++) {
10766 VALUE obj = rb_ary_entry(write, i);
10767 VALUE io = rb_io_get_io(obj);
10768 VALUE write_io = GetWriteIO(io);
10769 GetOpenFile(write_io, fptr);
10770 if (rb_fd_isset(fptr->fd, &fds[1])) {
10771 rb_ary_push(list, obj);
10772 }
10773 }
10774 }
10775
10776 if (ep) {
10777 list = RARRAY_AREF(res, 2);
10778 for (i=0; i< RARRAY_LEN(except); i++) {
10779 VALUE obj = rb_ary_entry(except, i);
10780 VALUE io = rb_io_get_io(obj);
10781 VALUE write_io = GetWriteIO(io);
10782 GetOpenFile(io, fptr);
10783 if (rb_fd_isset(fptr->fd, &fds[2])) {
10784 rb_ary_push(list, obj);
10785 }
10786 else if (io != write_io) {
10787 GetOpenFile(write_io, fptr);
10788 if (rb_fd_isset(fptr->fd, &fds[2])) {
10789 rb_ary_push(list, obj);
10790 }
10791 }
10792 }
10793 }
10794
10795 return res; /* returns an empty array on interrupt */
10796}
10797
10799 VALUE read, write, except;
10800 struct timeval *timeout;
10801 rb_fdset_t fdsets[4];
10802};
10803
10804static VALUE
10805select_call(VALUE arg)
10806{
10807 struct select_args *p = (struct select_args *)arg;
10808
10809 return select_internal(p->read, p->write, p->except, p->timeout, p->fdsets);
10810}
10811
10812static VALUE
10813select_end(VALUE arg)
10814{
10815 struct select_args *p = (struct select_args *)arg;
10816 int i;
10817
10818 for (i = 0; i < numberof(p->fdsets); ++i)
10819 rb_fd_term(&p->fdsets[i]);
10820 return Qnil;
10821}
10822
10823static VALUE sym_normal, sym_sequential, sym_random,
10824 sym_willneed, sym_dontneed, sym_noreuse;
10825
10826#ifdef HAVE_POSIX_FADVISE
10827struct io_advise_struct {
10828 int fd;
10829 int advice;
10830 rb_off_t offset;
10831 rb_off_t len;
10832};
10833
10834static VALUE
10835io_advise_internal(void *arg)
10836{
10837 struct io_advise_struct *ptr = arg;
10838 return posix_fadvise(ptr->fd, ptr->offset, ptr->len, ptr->advice);
10839}
10840
10841static VALUE
10842io_advise_sym_to_const(VALUE sym)
10843{
10844#ifdef POSIX_FADV_NORMAL
10845 if (sym == sym_normal)
10846 return INT2NUM(POSIX_FADV_NORMAL);
10847#endif
10848
10849#ifdef POSIX_FADV_RANDOM
10850 if (sym == sym_random)
10851 return INT2NUM(POSIX_FADV_RANDOM);
10852#endif
10853
10854#ifdef POSIX_FADV_SEQUENTIAL
10855 if (sym == sym_sequential)
10856 return INT2NUM(POSIX_FADV_SEQUENTIAL);
10857#endif
10858
10859#ifdef POSIX_FADV_WILLNEED
10860 if (sym == sym_willneed)
10861 return INT2NUM(POSIX_FADV_WILLNEED);
10862#endif
10863
10864#ifdef POSIX_FADV_DONTNEED
10865 if (sym == sym_dontneed)
10866 return INT2NUM(POSIX_FADV_DONTNEED);
10867#endif
10868
10869#ifdef POSIX_FADV_NOREUSE
10870 if (sym == sym_noreuse)
10871 return INT2NUM(POSIX_FADV_NOREUSE);
10872#endif
10873
10874 return Qnil;
10875}
10876
10877static VALUE
10878do_io_advise(rb_io_t *fptr, VALUE advice, rb_off_t offset, rb_off_t len)
10879{
10880 int rv;
10881 struct io_advise_struct ias;
10882 VALUE num_adv;
10883
10884 num_adv = io_advise_sym_to_const(advice);
10885
10886 /*
10887 * The platform doesn't support this hint. We don't raise exception, instead
10888 * silently ignore it. Because IO::advise is only hint.
10889 */
10890 if (NIL_P(num_adv))
10891 return Qnil;
10892
10893 ias.fd = fptr->fd;
10894 ias.advice = NUM2INT(num_adv);
10895 ias.offset = offset;
10896 ias.len = len;
10897
10898 rv = (int)rb_io_blocking_region(fptr, io_advise_internal, &ias);
10899 if (rv && rv != ENOSYS) {
10900 /* posix_fadvise(2) doesn't set errno. On success it returns 0; otherwise
10901 it returns the error code. */
10902 VALUE message = rb_sprintf("%"PRIsVALUE" "
10903 "(%"PRI_OFFT_PREFIX"d, "
10904 "%"PRI_OFFT_PREFIX"d, "
10905 "%"PRIsVALUE")",
10906 fptr->pathv, offset, len, advice);
10907 rb_syserr_fail_str(rv, message);
10908 }
10909
10910 return Qnil;
10911}
10912
10913#endif /* HAVE_POSIX_FADVISE */
10914
10915static void
10916advice_arg_check(VALUE advice)
10917{
10918 if (!SYMBOL_P(advice))
10919 rb_raise(rb_eTypeError, "advice must be a Symbol");
10920
10921 if (advice != sym_normal &&
10922 advice != sym_sequential &&
10923 advice != sym_random &&
10924 advice != sym_willneed &&
10925 advice != sym_dontneed &&
10926 advice != sym_noreuse) {
10927 rb_raise(rb_eNotImpError, "Unsupported advice: %+"PRIsVALUE, advice);
10928 }
10929}
10930
10931/*
10932 * call-seq:
10933 * advise(advice, offset = 0, len = 0) -> nil
10934 *
10935 * Invokes Posix system call
10936 * {posix_fadvise(2)}[https://linux.die.net/man/2/posix_fadvise],
10937 * which announces an intention to access data from the current file
10938 * in a particular manner.
10939 *
10940 * The arguments and results are platform-dependent.
10941 *
10942 * The relevant data is specified by:
10943 *
10944 * - +offset+: The offset of the first byte of data.
10945 * - +len+: The number of bytes to be accessed;
10946 * if +len+ is zero, or is larger than the number of bytes remaining,
10947 * all remaining bytes will be accessed.
10948 *
10949 * Argument +advice+ is one of the following symbols:
10950 *
10951 * - +:normal+: The application has no advice to give
10952 * about its access pattern for the specified data.
10953 * If no advice is given for an open file, this is the default assumption.
10954 * - +:sequential+: The application expects to access the specified data sequentially
10955 * (with lower offsets read before higher ones).
10956 * - +:random+: The specified data will be accessed in random order.
10957 * - +:noreuse+: The specified data will be accessed only once.
10958 * - +:willneed+: The specified data will be accessed in the near future.
10959 * - +:dontneed+: The specified data will not be accessed in the near future.
10960 *
10961 * Not implemented on all platforms.
10962 *
10963 */
10964static VALUE
10965rb_io_advise(int argc, VALUE *argv, VALUE io)
10966{
10967 VALUE advice, offset, len;
10968 rb_off_t off, l;
10969 rb_io_t *fptr;
10970
10971 rb_scan_args(argc, argv, "12", &advice, &offset, &len);
10972 advice_arg_check(advice);
10973
10974 io = GetWriteIO(io);
10975 GetOpenFile(io, fptr);
10976
10977 off = NIL_P(offset) ? 0 : NUM2OFFT(offset);
10978 l = NIL_P(len) ? 0 : NUM2OFFT(len);
10979
10980#ifdef HAVE_POSIX_FADVISE
10981 return do_io_advise(fptr, advice, off, l);
10982#else
10983 ((void)off, (void)l); /* Ignore all hint */
10984 return Qnil;
10985#endif
10986}
10987
10988static int
10989is_pos_inf(VALUE x)
10990{
10991 double f;
10992 if (!RB_FLOAT_TYPE_P(x))
10993 return 0;
10994 f = RFLOAT_VALUE(x);
10995 return isinf(f) && 0 < f;
10996}
10997
10998/*
10999 * call-seq:
11000 * IO.select(read_ios, write_ios = [], error_ios = [], timeout = nil) -> array or nil
11001 *
11002 * Invokes system call {select(2)}[https://linux.die.net/man/2/select],
11003 * which monitors multiple file descriptors,
11004 * waiting until one or more of the file descriptors
11005 * becomes ready for some class of I/O operation.
11006 *
11007 * Not implemented on all platforms.
11008 *
11009 * Each of the arguments +read_ios+, +write_ios+, and +error_ios+
11010 * is an array of IO objects.
11011 *
11012 * Argument +timeout+ is a numeric value (such as integer or float) timeout
11013 * interval in seconds.
11014 * +timeout+ can also be +nil+ or +Float::INFINITY+.
11015 * +nil+ and +Float::INFINITY+ means no timeout.
11016 *
11017 * The method monitors the \IO objects given in all three arrays,
11018 * waiting for some to be ready;
11019 * returns a 3-element array whose elements are:
11020 *
11021 * - An array of the objects in +read_ios+ that are ready for reading.
11022 * - An array of the objects in +write_ios+ that are ready for writing.
11023 * - An array of the objects in +error_ios+ have pending exceptions.
11024 *
11025 * If no object becomes ready within the given +timeout+, +nil+ is returned.
11026 *
11027 * \IO.select peeks the buffer of \IO objects for testing readability.
11028 * If the \IO buffer is not empty, \IO.select immediately notifies
11029 * readability. This "peek" only happens for \IO objects. It does not
11030 * happen for IO-like objects such as OpenSSL::SSL::SSLSocket.
11031 *
11032 * The best way to use \IO.select is invoking it after non-blocking
11033 * methods such as #read_nonblock, #write_nonblock, etc. The methods
11034 * raise an exception which is extended by IO::WaitReadable or
11035 * IO::WaitWritable. The modules notify how the caller should wait
11036 * with \IO.select. If IO::WaitReadable is raised, the caller should
11037 * wait for reading. If IO::WaitWritable is raised, the caller should
11038 * wait for writing.
11039 *
11040 * So, blocking read (#readpartial) can be emulated using
11041 * #read_nonblock and \IO.select as follows:
11042 *
11043 * begin
11044 * result = io_like.read_nonblock(maxlen)
11045 * rescue IO::WaitReadable
11046 * IO.select([io_like])
11047 * retry
11048 * rescue IO::WaitWritable
11049 * IO.select(nil, [io_like])
11050 * retry
11051 * end
11052 *
11053 * Especially, the combination of non-blocking methods and \IO.select is
11054 * preferred for IO like objects such as OpenSSL::SSL::SSLSocket. It
11055 * has #to_io method to return underlying IO object. IO.select calls
11056 * #to_io to obtain the file descriptor to wait.
11057 *
11058 * This means that readability notified by \IO.select doesn't mean
11059 * readability from OpenSSL::SSL::SSLSocket object.
11060 *
11061 * The most likely situation is that OpenSSL::SSL::SSLSocket buffers
11062 * some data. \IO.select doesn't see the buffer. So \IO.select can
11063 * block when OpenSSL::SSL::SSLSocket#readpartial doesn't block.
11064 *
11065 * However, several more complicated situations exist.
11066 *
11067 * SSL is a protocol which is sequence of records.
11068 * The record consists of multiple bytes.
11069 * So, the remote side of SSL sends a partial record, IO.select
11070 * notifies readability but OpenSSL::SSL::SSLSocket cannot decrypt a
11071 * byte and OpenSSL::SSL::SSLSocket#readpartial will block.
11072 *
11073 * Also, the remote side can request SSL renegotiation which forces
11074 * the local SSL engine to write some data.
11075 * This means OpenSSL::SSL::SSLSocket#readpartial may invoke #write
11076 * system call and it can block.
11077 * In such a situation, OpenSSL::SSL::SSLSocket#read_nonblock raises
11078 * IO::WaitWritable instead of blocking.
11079 * So, the caller should wait for ready for writability as above
11080 * example.
11081 *
11082 * The combination of non-blocking methods and \IO.select is also useful
11083 * for streams such as tty, pipe socket socket when multiple processes
11084 * read from a stream.
11085 *
11086 * Finally, Linux kernel developers don't guarantee that
11087 * readability of select(2) means readability of following read(2) even
11088 * for a single process;
11089 * see {select(2)}[https://linux.die.net/man/2/select]
11090 *
11091 * Invoking \IO.select before IO#readpartial works well as usual.
11092 * However it is not the best way to use \IO.select.
11093 *
11094 * The writability notified by select(2) doesn't show
11095 * how many bytes are writable.
11096 * IO#write method blocks until given whole string is written.
11097 * So, <tt>IO#write(two or more bytes)</tt> can block after
11098 * writability is notified by \IO.select. IO#write_nonblock is required
11099 * to avoid the blocking.
11100 *
11101 * Blocking write (#write) can be emulated using #write_nonblock and
11102 * IO.select as follows: IO::WaitReadable should also be rescued for
11103 * SSL renegotiation in OpenSSL::SSL::SSLSocket.
11104 *
11105 * while 0 < string.bytesize
11106 * begin
11107 * written = io_like.write_nonblock(string)
11108 * rescue IO::WaitReadable
11109 * IO.select([io_like])
11110 * retry
11111 * rescue IO::WaitWritable
11112 * IO.select(nil, [io_like])
11113 * retry
11114 * end
11115 * string = string.byteslice(written..-1)
11116 * end
11117 *
11118 * Example:
11119 *
11120 * rp, wp = IO.pipe
11121 * mesg = "ping "
11122 * 100.times {
11123 * # IO.select follows IO#read. Not the best way to use IO.select.
11124 * rs, ws, = IO.select([rp], [wp])
11125 * if r = rs[0]
11126 * ret = r.read(5)
11127 * print ret
11128 * case ret
11129 * when /ping/
11130 * mesg = "pong\n"
11131 * when /pong/
11132 * mesg = "ping "
11133 * end
11134 * end
11135 * if w = ws[0]
11136 * w.write(mesg)
11137 * end
11138 * }
11139 *
11140 * Output:
11141 *
11142 * ping pong
11143 * ping pong
11144 * ping pong
11145 * (snipped)
11146 * ping
11147 *
11148 */
11149
11150static VALUE
11151rb_f_select(int argc, VALUE *argv, VALUE obj)
11152{
11153 VALUE scheduler = rb_fiber_scheduler_current();
11154 if (scheduler != Qnil) {
11155 // It's optionally supported.
11156 VALUE result = rb_fiber_scheduler_io_selectv(scheduler, argc, argv);
11157 if (!UNDEF_P(result)) return result;
11158 }
11159
11160 VALUE timeout;
11161 struct select_args args;
11162 struct timeval timerec;
11163 int i;
11164
11165 rb_scan_args(argc, argv, "13", &args.read, &args.write, &args.except, &timeout);
11166 if (NIL_P(timeout) || is_pos_inf(timeout)) {
11167 args.timeout = 0;
11168 }
11169 else {
11170 timerec = rb_time_interval(timeout);
11171 args.timeout = &timerec;
11172 }
11173
11174 for (i = 0; i < numberof(args.fdsets); ++i)
11175 rb_fd_init(&args.fdsets[i]);
11176
11177 return rb_ensure(select_call, (VALUE)&args, select_end, (VALUE)&args);
11178}
11179
11180#ifdef IOCTL_REQ_TYPE
11181 typedef IOCTL_REQ_TYPE ioctl_req_t;
11182#else
11183 typedef int ioctl_req_t;
11184# define NUM2IOCTLREQ(num) ((int)NUM2LONG(num))
11185#endif
11186
11187#ifdef HAVE_IOCTL
11188struct ioctl_arg {
11189 int fd;
11190 ioctl_req_t cmd;
11191 long narg;
11192};
11193
11194static VALUE
11195nogvl_ioctl(void *ptr)
11196{
11197 struct ioctl_arg *arg = ptr;
11198
11199 return (VALUE)ioctl(arg->fd, arg->cmd, arg->narg);
11200}
11201
11202static int
11203do_ioctl(struct rb_io *io, ioctl_req_t cmd, long narg)
11204{
11205 int retval;
11206 struct ioctl_arg arg;
11207
11208 arg.fd = io->fd;
11209 arg.cmd = cmd;
11210 arg.narg = narg;
11211
11212 retval = (int)rb_io_blocking_region(io, nogvl_ioctl, &arg);
11213
11214 return retval;
11215}
11216#endif
11217
11218#define DEFAULT_IOCTL_NARG_LEN (256)
11219
11220#if defined(__linux__) && defined(_IOC_SIZE)
11221static long
11222linux_iocparm_len(ioctl_req_t cmd)
11223{
11224 long len;
11225
11226 if ((cmd & 0xFFFF0000) == 0) {
11227 /* legacy and unstructured ioctl number. */
11228 return DEFAULT_IOCTL_NARG_LEN;
11229 }
11230
11231 len = _IOC_SIZE(cmd);
11232
11233 /* paranoia check for silly drivers which don't keep ioctl convention */
11234 if (len < DEFAULT_IOCTL_NARG_LEN)
11235 len = DEFAULT_IOCTL_NARG_LEN;
11236
11237 return len;
11238}
11239#endif
11240
11241#ifdef HAVE_IOCTL
11242static long
11243ioctl_narg_len(ioctl_req_t cmd)
11244{
11245 long len;
11246
11247#ifdef IOCPARM_MASK
11248#ifndef IOCPARM_LEN
11249#define IOCPARM_LEN(x) (((x) >> 16) & IOCPARM_MASK)
11250#endif
11251#endif
11252#ifdef IOCPARM_LEN
11253 len = IOCPARM_LEN(cmd); /* on BSDish systems we're safe */
11254#elif defined(__linux__) && defined(_IOC_SIZE)
11255 len = linux_iocparm_len(cmd);
11256#else
11257 /* otherwise guess at what's safe */
11258 len = DEFAULT_IOCTL_NARG_LEN;
11259#endif
11260
11261 return len;
11262}
11263#endif
11264
11265#ifdef HAVE_FCNTL
11266#ifdef __linux__
11267typedef long fcntl_arg_t;
11268#else
11269/* posix */
11270typedef int fcntl_arg_t;
11271#endif
11272
11273static long
11274fcntl_narg_len(ioctl_req_t cmd)
11275{
11276 long len;
11277
11278 switch (cmd) {
11279#ifdef F_DUPFD
11280 case F_DUPFD:
11281 len = sizeof(fcntl_arg_t);
11282 break;
11283#endif
11284#ifdef F_DUP2FD /* bsd specific */
11285 case F_DUP2FD:
11286 len = sizeof(int);
11287 break;
11288#endif
11289#ifdef F_DUPFD_CLOEXEC /* linux specific */
11290 case F_DUPFD_CLOEXEC:
11291 len = sizeof(fcntl_arg_t);
11292 break;
11293#endif
11294#ifdef F_GETFD
11295 case F_GETFD:
11296 len = 1;
11297 break;
11298#endif
11299#ifdef F_SETFD
11300 case F_SETFD:
11301 len = sizeof(fcntl_arg_t);
11302 break;
11303#endif
11304#ifdef F_GETFL
11305 case F_GETFL:
11306 len = 1;
11307 break;
11308#endif
11309#ifdef F_SETFL
11310 case F_SETFL:
11311 len = sizeof(fcntl_arg_t);
11312 break;
11313#endif
11314#ifdef F_GETOWN
11315 case F_GETOWN:
11316 len = 1;
11317 break;
11318#endif
11319#ifdef F_SETOWN
11320 case F_SETOWN:
11321 len = sizeof(fcntl_arg_t);
11322 break;
11323#endif
11324#ifdef F_GETOWN_EX /* linux specific */
11325 case F_GETOWN_EX:
11326 len = sizeof(struct f_owner_ex);
11327 break;
11328#endif
11329#ifdef F_SETOWN_EX /* linux specific */
11330 case F_SETOWN_EX:
11331 len = sizeof(struct f_owner_ex);
11332 break;
11333#endif
11334#ifdef F_GETLK
11335 case F_GETLK:
11336 len = sizeof(struct flock);
11337 break;
11338#endif
11339#ifdef F_SETLK
11340 case F_SETLK:
11341 len = sizeof(struct flock);
11342 break;
11343#endif
11344#ifdef F_SETLKW
11345 case F_SETLKW:
11346 len = sizeof(struct flock);
11347 break;
11348#endif
11349#ifdef F_READAHEAD /* bsd specific */
11350 case F_READAHEAD:
11351 len = sizeof(int);
11352 break;
11353#endif
11354#ifdef F_RDAHEAD /* Darwin specific */
11355 case F_RDAHEAD:
11356 len = sizeof(int);
11357 break;
11358#endif
11359#ifdef F_GETSIG /* linux specific */
11360 case F_GETSIG:
11361 len = 1;
11362 break;
11363#endif
11364#ifdef F_SETSIG /* linux specific */
11365 case F_SETSIG:
11366 len = sizeof(fcntl_arg_t);
11367 break;
11368#endif
11369#ifdef F_GETLEASE /* linux specific */
11370 case F_GETLEASE:
11371 len = 1;
11372 break;
11373#endif
11374#ifdef F_SETLEASE /* linux specific */
11375 case F_SETLEASE:
11376 len = sizeof(fcntl_arg_t);
11377 break;
11378#endif
11379#ifdef F_NOTIFY /* linux specific */
11380 case F_NOTIFY:
11381 len = sizeof(fcntl_arg_t);
11382 break;
11383#endif
11384
11385 default:
11386 len = 256;
11387 break;
11388 }
11389
11390 return len;
11391}
11392#else /* HAVE_FCNTL */
11393static long
11394fcntl_narg_len(ioctl_req_t cmd)
11395{
11396 return 0;
11397}
11398#endif /* HAVE_FCNTL */
11399
11400#define NARG_SENTINEL 17
11401
11402static long
11403setup_narg(ioctl_req_t cmd, VALUE *argp, long (*narg_len)(ioctl_req_t))
11404{
11405 long narg = 0;
11406 VALUE arg = *argp;
11407
11408 if (!RTEST(arg)) {
11409 narg = 0;
11410 }
11411 else if (FIXNUM_P(arg)) {
11412 narg = FIX2LONG(arg);
11413 }
11414 else if (arg == Qtrue) {
11415 narg = 1;
11416 }
11417 else {
11418 VALUE tmp = rb_check_string_type(arg);
11419
11420 if (NIL_P(tmp)) {
11421 narg = NUM2LONG(arg);
11422 }
11423 else {
11424 char *ptr;
11425 long len, slen;
11426
11427 *argp = arg = tmp;
11428 len = narg_len(cmd);
11429 rb_str_modify(arg);
11430
11431 slen = RSTRING_LEN(arg);
11432 /* expand for data + sentinel. */
11433 if (slen < len+1) {
11434 rb_str_resize(arg, len+1);
11435 MEMZERO(RSTRING_PTR(arg)+slen, char, len-slen);
11436 slen = len+1;
11437 }
11438 /* a little sanity check here */
11439 ptr = RSTRING_PTR(arg);
11440 ptr[slen - 1] = NARG_SENTINEL;
11441 narg = (long)(SIGNED_VALUE)ptr;
11442 }
11443 }
11444
11445 return narg;
11446}
11447
11448static VALUE
11449finish_narg(int retval, VALUE arg, const rb_io_t *fptr)
11450{
11451 if (retval < 0) rb_sys_fail_path(fptr->pathv);
11452 if (RB_TYPE_P(arg, T_STRING)) {
11453 char *ptr;
11454 long slen;
11455 RSTRING_GETMEM(arg, ptr, slen);
11456 if (ptr[slen-1] != NARG_SENTINEL)
11457 rb_raise(rb_eArgError, "return value overflowed string");
11458 ptr[slen-1] = '\0';
11459 }
11460
11461 return INT2NUM(retval);
11462}
11463
11464#ifdef HAVE_IOCTL
11465static VALUE
11466rb_ioctl(VALUE io, VALUE req, VALUE arg)
11467{
11468 ioctl_req_t cmd = NUM2IOCTLREQ(req);
11469 rb_io_t *fptr;
11470 long narg;
11471 int retval;
11472
11473 narg = setup_narg(cmd, &arg, ioctl_narg_len);
11474 GetOpenFile(io, fptr);
11475 retval = do_ioctl(fptr, cmd, narg);
11476 return finish_narg(retval, arg, fptr);
11477}
11478
11479/*
11480 * call-seq:
11481 * ioctl(integer_cmd, argument) -> integer
11482 *
11483 * Invokes Posix system call {ioctl(2)}[https://linux.die.net/man/2/ioctl],
11484 * which issues a low-level command to an I/O device.
11485 *
11486 * Issues a low-level command to an I/O device.
11487 * The arguments and returned value are platform-dependent.
11488 * The effect of the call is platform-dependent.
11489 *
11490 * If argument +argument+ is an integer, it is passed directly;
11491 * if it is a string, it is interpreted as a binary sequence of bytes.
11492 *
11493 * Not implemented on all platforms.
11494 *
11495 */
11496
11497static VALUE
11498rb_io_ioctl(int argc, VALUE *argv, VALUE io)
11499{
11500 VALUE req, arg;
11501
11502 rb_scan_args(argc, argv, "11", &req, &arg);
11503 return rb_ioctl(io, req, arg);
11504}
11505#else
11506#define rb_io_ioctl rb_f_notimplement
11507#endif
11508
11509#ifdef HAVE_FCNTL
11510struct fcntl_arg {
11511 int fd;
11512 int cmd;
11513 long narg;
11514};
11515
11516static VALUE
11517nogvl_fcntl(void *ptr)
11518{
11519 struct fcntl_arg *arg = ptr;
11520
11521#if defined(F_DUPFD)
11522 if (arg->cmd == F_DUPFD)
11523 return (VALUE)rb_cloexec_fcntl_dupfd(arg->fd, (int)arg->narg);
11524#endif
11525 return (VALUE)fcntl(arg->fd, arg->cmd, arg->narg);
11526}
11527
11528static int
11529do_fcntl(struct rb_io *io, int cmd, long narg)
11530{
11531 int retval;
11532 struct fcntl_arg arg;
11533
11534 arg.fd = io->fd;
11535 arg.cmd = cmd;
11536 arg.narg = narg;
11537
11538 retval = (int)rb_io_blocking_region(io, nogvl_fcntl, &arg);
11539 if (retval != -1) {
11540 switch (cmd) {
11541#if defined(F_DUPFD)
11542 case F_DUPFD:
11543#endif
11544#if defined(F_DUPFD_CLOEXEC)
11545 case F_DUPFD_CLOEXEC:
11546#endif
11547 rb_update_max_fd(retval);
11548 }
11549 }
11550
11551 return retval;
11552}
11553
11554static VALUE
11555rb_fcntl(VALUE io, VALUE req, VALUE arg)
11556{
11557 int cmd = NUM2INT(req);
11558 rb_io_t *fptr;
11559 long narg;
11560 int retval;
11561
11562 narg = setup_narg(cmd, &arg, fcntl_narg_len);
11563 GetOpenFile(io, fptr);
11564 retval = do_fcntl(fptr, cmd, narg);
11565 return finish_narg(retval, arg, fptr);
11566}
11567
11568/*
11569 * call-seq:
11570 * fcntl(integer_cmd, argument) -> integer
11571 *
11572 * Invokes Posix system call {fcntl(2)}[https://linux.die.net/man/2/fcntl],
11573 * which provides a mechanism for issuing low-level commands to control or query
11574 * a file-oriented I/O stream. Arguments and results are platform
11575 * dependent.
11576 *
11577 * If +argument+ is a number, its value is passed directly;
11578 * if it is a string, it is interpreted as a binary sequence of bytes.
11579 * (Array#pack might be a useful way to build this string.)
11580 *
11581 * Not implemented on all platforms.
11582 *
11583 */
11584
11585static VALUE
11586rb_io_fcntl(int argc, VALUE *argv, VALUE io)
11587{
11588 VALUE req, arg;
11589
11590 rb_scan_args(argc, argv, "11", &req, &arg);
11591 return rb_fcntl(io, req, arg);
11592}
11593#else
11594#define rb_io_fcntl rb_f_notimplement
11595#endif
11596
11597#if defined(HAVE_SYSCALL) || defined(HAVE___SYSCALL)
11598/*
11599 * call-seq:
11600 * syscall(integer_callno, *arguments) -> integer
11601 *
11602 * Invokes Posix system call {syscall(2)}[https://linux.die.net/man/2/syscall],
11603 * which calls a specified function.
11604 *
11605 * Calls the operating system function identified by +integer_callno+;
11606 * returns the result of the function or raises SystemCallError if it failed.
11607 * The effect of the call is platform-dependent.
11608 * The arguments and returned value are platform-dependent.
11609 *
11610 * For each of +arguments+: if it is an integer, it is passed directly;
11611 * if it is a string, it is interpreted as a binary sequence of bytes.
11612 * There may be as many as nine such arguments.
11613 *
11614 * Arguments +integer_callno+ and +argument+, as well as the returned value,
11615 * are platform-dependent.
11616 *
11617 * Note: Method +syscall+ is essentially unsafe and unportable.
11618 * The DL (Fiddle) library is preferred for safer and a bit
11619 * more portable programming.
11620 *
11621 * Not implemented on all platforms.
11622 *
11623 */
11624
11625static VALUE
11626rb_f_syscall(int argc, VALUE *argv, VALUE _)
11627{
11628 VALUE arg[8];
11629#if SIZEOF_VOIDP == 8 && defined(HAVE___SYSCALL) && SIZEOF_INT != 8 /* mainly *BSD */
11630# define SYSCALL __syscall
11631# define NUM2SYSCALLID(x) NUM2LONG(x)
11632# define RETVAL2NUM(x) LONG2NUM(x)
11633# if SIZEOF_LONG == 8
11634 long num, retval = -1;
11635# elif SIZEOF_LONG_LONG == 8
11636 long long num, retval = -1;
11637# else
11638# error ---->> it is asserted that __syscall takes the first argument and returns retval in 64bit signed integer. <<----
11639# endif
11640#elif defined(__linux__)
11641# define SYSCALL syscall
11642# define NUM2SYSCALLID(x) NUM2LONG(x)
11643# define RETVAL2NUM(x) LONG2NUM(x)
11644 /*
11645 * Linux man page says, syscall(2) function prototype is below.
11646 *
11647 * int syscall(int number, ...);
11648 *
11649 * But, it's incorrect. Actual one takes and returned long. (see unistd.h)
11650 */
11651 long num, retval = -1;
11652#else
11653# define SYSCALL syscall
11654# define NUM2SYSCALLID(x) NUM2INT(x)
11655# define RETVAL2NUM(x) INT2NUM(x)
11656 int num, retval = -1;
11657#endif
11658 int i;
11659
11660 if (RTEST(ruby_verbose)) {
11662 "We plan to remove a syscall function at future release. DL(Fiddle) provides safer alternative.");
11663 }
11664
11665 if (argc == 0)
11666 rb_raise(rb_eArgError, "too few arguments for syscall");
11667 if (argc > numberof(arg))
11668 rb_raise(rb_eArgError, "too many arguments for syscall");
11669 num = NUM2SYSCALLID(argv[0]); ++argv;
11670 for (i = argc - 1; i--; ) {
11671 VALUE v = rb_check_string_type(argv[i]);
11672
11673 if (!NIL_P(v)) {
11674 StringValue(v);
11675 rb_str_modify(v);
11676 arg[i] = (VALUE)StringValueCStr(v);
11677 }
11678 else {
11679 arg[i] = (VALUE)NUM2LONG(argv[i]);
11680 }
11681 }
11682
11683 switch (argc) {
11684 case 1:
11685 retval = SYSCALL(num);
11686 break;
11687 case 2:
11688 retval = SYSCALL(num, arg[0]);
11689 break;
11690 case 3:
11691 retval = SYSCALL(num, arg[0],arg[1]);
11692 break;
11693 case 4:
11694 retval = SYSCALL(num, arg[0],arg[1],arg[2]);
11695 break;
11696 case 5:
11697 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3]);
11698 break;
11699 case 6:
11700 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4]);
11701 break;
11702 case 7:
11703 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5]);
11704 break;
11705 case 8:
11706 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6]);
11707 break;
11708 }
11709
11710 if (retval == -1)
11711 rb_sys_fail(0);
11712 return RETVAL2NUM(retval);
11713#undef SYSCALL
11714#undef NUM2SYSCALLID
11715#undef RETVAL2NUM
11716}
11717#else
11718#define rb_f_syscall rb_f_notimplement
11719#endif
11720
11721static VALUE
11722io_new_instance(VALUE args)
11723{
11724 return rb_class_new_instance(2, (VALUE*)args+1, *(VALUE*)args);
11725}
11726
11727static rb_encoding *
11728find_encoding(VALUE v)
11729{
11730 rb_encoding *enc = rb_find_encoding(v);
11731 if (!enc) rb_warn("Unsupported encoding %"PRIsVALUE" ignored", v);
11732 return enc;
11733}
11734
11735static void
11736io_encoding_set(rb_io_t *fptr, VALUE v1, VALUE v2, VALUE opt)
11737{
11738 rb_encoding *enc, *enc2;
11739 int ecflags = fptr->encs.ecflags;
11740 VALUE ecopts, tmp;
11741
11742 if (!NIL_P(v2)) {
11743 enc2 = find_encoding(v1);
11744 tmp = rb_check_string_type(v2);
11745 if (!NIL_P(tmp)) {
11746 if (RSTRING_LEN(tmp) == 1 && RSTRING_PTR(tmp)[0] == '-') {
11747 /* Special case - "-" => no transcoding */
11748 enc = enc2;
11749 enc2 = NULL;
11750 }
11751 else
11752 enc = find_encoding(v2);
11753 if (enc == enc2) {
11754 /* Special case - "-" => no transcoding */
11755 enc2 = NULL;
11756 }
11757 }
11758 else {
11759 enc = find_encoding(v2);
11760 if (enc == enc2) {
11761 /* Special case - "-" => no transcoding */
11762 enc2 = NULL;
11763 }
11764 }
11765 if (enc2 == rb_ascii8bit_encoding()) {
11766 /* If external is ASCII-8BIT, no transcoding */
11767 enc = enc2;
11768 enc2 = NULL;
11769 }
11770 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11771 ecflags = rb_econv_prepare_options(opt, &ecopts, ecflags);
11772 }
11773 else {
11774 if (NIL_P(v1)) {
11775 /* Set to default encodings */
11776 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
11777 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11778 ecopts = Qnil;
11779 }
11780 else {
11781 tmp = rb_check_string_type(v1);
11782 if (!NIL_P(tmp) && rb_enc_asciicompat(enc = rb_enc_get(tmp))) {
11783 parse_mode_enc(RSTRING_PTR(tmp), enc, &enc, &enc2, NULL);
11784 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11785 ecflags = rb_econv_prepare_options(opt, &ecopts, ecflags);
11786 }
11787 else {
11788 rb_io_ext_int_to_encs(find_encoding(v1), NULL, &enc, &enc2, 0);
11789 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11790 ecopts = Qnil;
11791 }
11792 }
11793 }
11794 validate_enc_binmode(&fptr->mode, ecflags, enc, enc2);
11795 fptr->encs.enc = enc;
11796 fptr->encs.enc2 = enc2;
11797 fptr->encs.ecflags = ecflags;
11798 fptr->encs.ecopts = ecopts;
11799 clear_codeconv(fptr);
11800
11801}
11802
11804 rb_io_t *fptr;
11805 VALUE v1;
11806 VALUE v2;
11807 VALUE opt;
11808};
11809
11810static VALUE
11811io_encoding_set_v(VALUE v)
11812{
11813 struct io_encoding_set_args *arg = (struct io_encoding_set_args *)v;
11814 io_encoding_set(arg->fptr, arg->v1, arg->v2, arg->opt);
11815 return Qnil;
11816}
11817
11818static VALUE
11819pipe_pair_close(VALUE rw)
11820{
11821 VALUE *rwp = (VALUE *)rw;
11822 return rb_ensure(io_close, rwp[0], io_close, rwp[1]);
11823}
11824
11825/*
11826 * call-seq:
11827 * IO.pipe(**opts) -> [read_io, write_io]
11828 * IO.pipe(enc, **opts) -> [read_io, write_io]
11829 * IO.pipe(ext_enc, int_enc, **opts) -> [read_io, write_io]
11830 * IO.pipe(**opts) {|read_io, write_io| ...} -> object
11831 * IO.pipe(enc, **opts) {|read_io, write_io| ...} -> object
11832 * IO.pipe(ext_enc, int_enc, **opts) {|read_io, write_io| ...} -> object
11833 *
11834 * Creates a pair of pipe endpoints, +read_io+ and +write_io+,
11835 * connected to each other.
11836 *
11837 * If argument +enc_string+ is given, it must be a string containing one of:
11838 *
11839 * - The name of the encoding to be used as the external encoding.
11840 * - The colon-separated names of two encodings to be used as the external
11841 * and internal encodings.
11842 *
11843 * If argument +int_enc+ is given, it must be an Encoding object
11844 * or encoding name string that specifies the internal encoding to be used;
11845 * if argument +ext_enc+ is also given, it must be an Encoding object
11846 * or encoding name string that specifies the external encoding to be used.
11847 *
11848 * The string read from +read_io+ is tagged with the external encoding;
11849 * if an internal encoding is also specified, the string is converted
11850 * to, and tagged with, that encoding.
11851 *
11852 * If any encoding is specified,
11853 * optional hash arguments specify the conversion option.
11854 *
11855 * Optional keyword arguments +opts+ specify:
11856 *
11857 * - {Open Options}[rdoc-ref:IO@Open+Options].
11858 * - {Encoding Options}[rdoc-ref:encodings.rdoc@Encoding+Options].
11859 *
11860 * With no block given, returns the two endpoints in an array:
11861 *
11862 * IO.pipe # => [#<IO:fd 4>, #<IO:fd 5>]
11863 *
11864 * With a block given, calls the block with the two endpoints;
11865 * closes both endpoints and returns the value of the block:
11866 *
11867 * IO.pipe {|read_io, write_io| p read_io; p write_io }
11868 *
11869 * Output:
11870 *
11871 * #<IO:fd 6>
11872 * #<IO:fd 7>
11873 *
11874 * Not available on all platforms.
11875 *
11876 * In the example below, the two processes close the ends of the pipe
11877 * that they are not using. This is not just a cosmetic nicety. The
11878 * read end of a pipe will not generate an end of file condition if
11879 * there are any writers with the pipe still open. In the case of the
11880 * parent process, the <tt>rd.read</tt> will never return if it
11881 * does not first issue a <tt>wr.close</tt>:
11882 *
11883 * rd, wr = IO.pipe
11884 *
11885 * if fork
11886 * wr.close
11887 * puts "Parent got: <#{rd.read}>"
11888 * rd.close
11889 * Process.wait
11890 * else
11891 * rd.close
11892 * puts 'Sending message to parent'
11893 * wr.write "Hi Dad"
11894 * wr.close
11895 * end
11896 *
11897 * <em>produces:</em>
11898 *
11899 * Sending message to parent
11900 * Parent got: <Hi Dad>
11901 *
11902 */
11903
11904static VALUE
11905rb_io_s_pipe(int argc, VALUE *argv, VALUE klass)
11906{
11907 int pipes[2], state;
11908 VALUE r, w, args[3], v1, v2;
11909 VALUE opt;
11910 rb_io_t *fptr, *fptr2;
11911 struct io_encoding_set_args ies_args;
11912 enum rb_io_mode fmode = 0;
11913 VALUE ret;
11914
11915 argc = rb_scan_args(argc, argv, "02:", &v1, &v2, &opt);
11916 if (rb_pipe(pipes) < 0)
11917 rb_sys_fail(0);
11918
11919 args[0] = klass;
11920 args[1] = INT2NUM(pipes[0]);
11921 args[2] = INT2FIX(O_RDONLY);
11922 r = rb_protect(io_new_instance, (VALUE)args, &state);
11923 if (state) {
11924 close(pipes[0]);
11925 close(pipes[1]);
11926 rb_jump_tag(state);
11927 }
11928 GetOpenFile(r, fptr);
11929
11930 ies_args.fptr = fptr;
11931 ies_args.v1 = v1;
11932 ies_args.v2 = v2;
11933 ies_args.opt = opt;
11934 rb_protect(io_encoding_set_v, (VALUE)&ies_args, &state);
11935 if (state) {
11936 close(pipes[1]);
11937 io_close(r);
11938 rb_jump_tag(state);
11939 }
11940
11941 args[1] = INT2NUM(pipes[1]);
11942 args[2] = INT2FIX(O_WRONLY);
11943 w = rb_protect(io_new_instance, (VALUE)args, &state);
11944 if (state) {
11945 close(pipes[1]);
11946 if (!NIL_P(r)) rb_io_close(r);
11947 rb_jump_tag(state);
11948 }
11949 GetOpenFile(w, fptr2);
11950 rb_io_synchronized(fptr2);
11951
11952 extract_binmode(opt, &fmode);
11953
11954 if ((fmode & FMODE_BINMODE) && NIL_P(v1)) {
11957 }
11958
11959#if DEFAULT_TEXTMODE
11960 if ((fptr->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
11961 fptr->mode &= ~FMODE_TEXTMODE;
11962 setmode(fptr->fd, O_BINARY);
11963 }
11964#if RUBY_CRLF_ENVIRONMENT
11967 }
11968#endif
11969#endif
11970 fptr->mode |= fmode;
11971#if DEFAULT_TEXTMODE
11972 if ((fptr2->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
11973 fptr2->mode &= ~FMODE_TEXTMODE;
11974 setmode(fptr2->fd, O_BINARY);
11975 }
11976#endif
11977 fptr2->mode |= fmode;
11978
11979 ret = rb_assoc_new(r, w);
11980 if (rb_block_given_p()) {
11981 VALUE rw[2];
11982 rw[0] = r;
11983 rw[1] = w;
11984 return rb_ensure(rb_yield, ret, pipe_pair_close, (VALUE)rw);
11985 }
11986 return ret;
11987}
11988
11990 int argc;
11991 VALUE *argv;
11992 VALUE io;
11993};
11994
11995static void
11996open_key_args(VALUE klass, int argc, VALUE *argv, VALUE opt, struct foreach_arg *arg)
11997{
11998 VALUE path, v;
11999 VALUE vmode = Qnil, vperm = Qnil;
12000
12001 path = *argv++;
12002 argc--;
12003 FilePathValue(path);
12004 arg->io = 0;
12005 arg->argc = argc;
12006 arg->argv = argv;
12007 if (NIL_P(opt)) {
12008 vmode = INT2NUM(O_RDONLY);
12009 vperm = INT2FIX(0666);
12010 }
12011 else if (!NIL_P(v = rb_hash_aref(opt, sym_open_args))) {
12012 int n;
12013
12014 v = rb_to_array_type(v);
12015 n = RARRAY_LENINT(v);
12016 rb_check_arity(n, 0, 3); /* rb_io_open */
12017 rb_scan_args_kw(RB_SCAN_ARGS_LAST_HASH_KEYWORDS, n, RARRAY_CONST_PTR(v), "02:", &vmode, &vperm, &opt);
12018 }
12019 arg->io = rb_io_open(klass, path, vmode, vperm, opt);
12020}
12021
12022static VALUE
12023io_s_foreach(VALUE v)
12024{
12025 struct getline_arg *arg = (void *)v;
12026 VALUE str;
12027
12028 if (arg->limit == 0)
12029 rb_raise(rb_eArgError, "invalid limit: 0 for foreach");
12030 while (!NIL_P(str = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, arg->io))) {
12031 rb_lastline_set(str);
12032 rb_yield(str);
12033 }
12035 return Qnil;
12036}
12037
12038/*
12039 * call-seq:
12040 * IO.foreach(path, sep = $/, **opts) {|line| block } -> nil
12041 * IO.foreach(path, limit, **opts) {|line| block } -> nil
12042 * IO.foreach(path, sep, limit, **opts) {|line| block } -> nil
12043 * IO.foreach(...) -> an_enumerator
12044 *
12045 * Calls the block with each successive line read from the stream.
12046 *
12047 * When called from class \IO (but not subclasses of \IO),
12048 * this method has potential security vulnerabilities if called with untrusted input;
12049 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12050 *
12051 * The first argument must be a string that is the path to a file.
12052 *
12053 * With only argument +path+ given, parses lines from the file at the given +path+,
12054 * as determined by the default line separator,
12055 * and calls the block with each successive line:
12056 *
12057 * File.foreach('t.txt') {|line| p line }
12058 *
12059 * Output: the same as above.
12060 *
12061 * For both forms, command and path, the remaining arguments are the same.
12062 *
12063 * With argument +sep+ given, parses lines as determined by that line separator
12064 * (see {Line Separator}[rdoc-ref:IO@Line+Separator]):
12065 *
12066 * File.foreach('t.txt', 'li') {|line| p line }
12067 *
12068 * Output:
12069 *
12070 * "First li"
12071 * "ne\nSecond li"
12072 * "ne\n\nThird li"
12073 * "ne\nFourth li"
12074 * "ne\n"
12075 *
12076 * Each paragraph:
12077 *
12078 * File.foreach('t.txt', '') {|paragraph| p paragraph }
12079 *
12080 * Output:
12081 *
12082 * "First line\nSecond line\n\n"
12083 * "Third line\nFourth line\n"
12084 *
12085 * With argument +limit+ given, parses lines as determined by the default
12086 * line separator and the given line-length limit
12087 * (see {Line Separator}[rdoc-ref:IO@Line+Separator] and {Line Limit}[rdoc-ref:IO@Line+Limit]):
12088 *
12089 * File.foreach('t.txt', 7) {|line| p line }
12090 *
12091 * Output:
12092 *
12093 * "First l"
12094 * "ine\n"
12095 * "Second "
12096 * "line\n"
12097 * "\n"
12098 * "Third l"
12099 * "ine\n"
12100 * "Fourth l"
12101 * "line\n"
12102 *
12103 * With arguments +sep+ and +limit+ given,
12104 * combines the two behaviors
12105 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
12106 *
12107 * Optional keyword arguments +opts+ specify:
12108 *
12109 * - {Open Options}[rdoc-ref:IO@Open+Options].
12110 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12111 * - {Line Options}[rdoc-ref:IO@Line+IO].
12112 *
12113 * Returns an Enumerator if no block is given.
12114 *
12115 */
12116
12117static VALUE
12118rb_io_s_foreach(int argc, VALUE *argv, VALUE self)
12119{
12120 VALUE opt;
12121 int orig_argc = argc;
12122 struct foreach_arg arg;
12123 struct getline_arg garg;
12124
12125 argc = rb_scan_args(argc, argv, "12:", NULL, NULL, NULL, &opt);
12126 RETURN_ENUMERATOR(self, orig_argc, argv);
12127 extract_getline_args(argc-1, argv+1, &garg);
12128 open_key_args(self, argc, argv, opt, &arg);
12129 if (NIL_P(arg.io)) return Qnil;
12130 extract_getline_opts(opt, &garg);
12131 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12132 return rb_ensure(io_s_foreach, (VALUE)&garg, rb_io_close, arg.io);
12133}
12134
12135static VALUE
12136io_s_readlines(VALUE v)
12137{
12138 struct getline_arg *arg = (void *)v;
12139 return io_readlines(arg, arg->io);
12140}
12141
12142/*
12143 * call-seq:
12144 * IO.readlines(path, sep = $/, **opts) -> array
12145 * IO.readlines(path, limit, **opts) -> array
12146 * IO.readlines(path, sep, limit, **opts) -> array
12147 *
12148 * Returns an array of all lines read from the stream.
12149 *
12150 * When called from class \IO (but not subclasses of \IO),
12151 * this method has potential security vulnerabilities if called with untrusted input;
12152 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12153 *
12154 * The first argument must be a string that is the path to a file.
12155 *
12156 * With only argument +path+ given, parses lines from the file at the given +path+,
12157 * as determined by the default line separator,
12158 * and returns those lines in an array:
12159 *
12160 * IO.readlines('t.txt')
12161 * # => ["First line\n", "Second line\n", "\n", "Third line\n", "Fourth line\n"]
12162 *
12163 * With argument +sep+ given, parses lines as determined by that line separator
12164 * (see {Line Separator}[rdoc-ref:IO@Line+Separator]):
12165 *
12166 * # Ordinary separator.
12167 * IO.readlines('t.txt', 'li')
12168 * # =>["First li", "ne\nSecond li", "ne\n\nThird li", "ne\nFourth li", "ne\n"]
12169 * # Get-paragraphs separator.
12170 * IO.readlines('t.txt', '')
12171 * # => ["First line\nSecond line\n\n", "Third line\nFourth line\n"]
12172 * # Get-all separator.
12173 * IO.readlines('t.txt', nil)
12174 * # => ["First line\nSecond line\n\nThird line\nFourth line\n"]
12175 *
12176 * With argument +limit+ given, parses lines as determined by the default
12177 * line separator and the given line-length limit
12178 * (see {Line Separator}[rdoc-ref:IO@Line+Separator] and {Line Limit}[rdoc-ref:IO@Line+Limit]:
12179 *
12180 * IO.readlines('t.txt', 7)
12181 * # => ["First l", "ine\n", "Second ", "line\n", "\n", "Third l", "ine\n", "Fourth ", "line\n"]
12182 *
12183 * With arguments +sep+ and +limit+ given,
12184 * combines the two behaviors
12185 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
12186 *
12187 * Optional keyword arguments +opts+ specify:
12188 *
12189 * - {Open Options}[rdoc-ref:IO@Open+Options].
12190 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12191 * - {Line Options}[rdoc-ref:IO@Line+IO].
12192 *
12193 */
12194
12195static VALUE
12196rb_io_s_readlines(int argc, VALUE *argv, VALUE io)
12197{
12198 VALUE opt;
12199 struct foreach_arg arg;
12200 struct getline_arg garg;
12201
12202 argc = rb_scan_args(argc, argv, "12:", NULL, NULL, NULL, &opt);
12203 extract_getline_args(argc-1, argv+1, &garg);
12204 open_key_args(io, argc, argv, opt, &arg);
12205 if (NIL_P(arg.io)) return Qnil;
12206 extract_getline_opts(opt, &garg);
12207 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12208 return rb_ensure(io_s_readlines, (VALUE)&garg, rb_io_close, arg.io);
12209}
12210
12211static VALUE
12212io_s_read(VALUE v)
12213{
12214 struct foreach_arg *arg = (void *)v;
12215 return io_read(arg->argc, arg->argv, arg->io);
12216}
12217
12218struct seek_arg {
12219 VALUE io;
12220 VALUE offset;
12221 int mode;
12222};
12223
12224static VALUE
12225seek_before_access(VALUE argp)
12226{
12227 struct seek_arg *arg = (struct seek_arg *)argp;
12228 rb_io_binmode(arg->io);
12229 return rb_io_seek(arg->io, arg->offset, arg->mode);
12230}
12231
12232/*
12233 * call-seq:
12234 * IO.read(path, length = nil, offset = 0, **opts) -> string or nil
12235 *
12236 * Opens the stream, reads and returns some or all of its content,
12237 * and closes the stream; returns +nil+ if no bytes were read.
12238 *
12239 * When called from class \IO (but not subclasses of \IO),
12240 * this method has potential security vulnerabilities if called with untrusted input;
12241 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12242 *
12243 * The first argument must be a string that is the path to a file.
12244 *
12245 * With only argument +path+ given, reads in text mode and returns the entire content
12246 * of the file at the given path:
12247 *
12248 * IO.read('t.txt')
12249 * # => "First line\nSecond line\n\nThird line\nFourth line\n"
12250 *
12251 * On Windows, text mode can terminate reading and leave bytes in the file
12252 * unread when encountering certain special bytes. Consider using
12253 * IO.binread if all bytes in the file should be read.
12254 *
12255 * With argument +length+, returns +length+ bytes if available:
12256 *
12257 * IO.read('t.txt', 7) # => "First l"
12258 * IO.read('t.txt', 700)
12259 * # => "First line\r\nSecond line\r\n\r\nFourth line\r\nFifth line\r\n"
12260 *
12261 * With arguments +length+ and +offset+, returns +length+ bytes
12262 * if available, beginning at the given +offset+:
12263 *
12264 * IO.read('t.txt', 10, 2) # => "rst line\nS"
12265 * IO.read('t.txt', 10, 200) # => nil
12266 *
12267 * Optional keyword arguments +opts+ specify:
12268 *
12269 * - {Open Options}[rdoc-ref:IO@Open+Options].
12270 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12271 *
12272 */
12273
12274static VALUE
12275rb_io_s_read(int argc, VALUE *argv, VALUE io)
12276{
12277 VALUE opt, offset;
12278 long off;
12279 struct foreach_arg arg;
12280
12281 argc = rb_scan_args(argc, argv, "13:", NULL, NULL, &offset, NULL, &opt);
12282 if (!NIL_P(offset) && (off = NUM2LONG(offset)) < 0) {
12283 rb_raise(rb_eArgError, "negative offset %ld given", off);
12284 }
12285 open_key_args(io, argc, argv, opt, &arg);
12286 if (NIL_P(arg.io)) return Qnil;
12287 if (!NIL_P(offset)) {
12288 struct seek_arg sarg;
12289 int state = 0;
12290 sarg.io = arg.io;
12291 sarg.offset = offset;
12292 sarg.mode = SEEK_SET;
12293 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12294 if (state) {
12295 rb_io_close(arg.io);
12296 rb_jump_tag(state);
12297 }
12298 if (arg.argc == 2) arg.argc = 1;
12299 }
12300 return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
12301}
12302
12303/*
12304 * call-seq:
12305 * IO.binread(path, length = nil, offset = 0) -> string or nil
12306 *
12307 * Behaves like IO.read, except that the stream is opened in binary mode
12308 * with ASCII-8BIT encoding.
12309 *
12310 * When called from class \IO (but not subclasses of \IO),
12311 * this method has potential security vulnerabilities if called with untrusted input;
12312 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12313 *
12314 */
12315
12316static VALUE
12317rb_io_s_binread(int argc, VALUE *argv, VALUE io)
12318{
12319 VALUE offset;
12320 struct foreach_arg arg;
12321 enum rb_io_mode fmode = FMODE_READABLE|FMODE_BINMODE;
12322 enum {
12323 oflags = O_RDONLY
12324#ifdef O_BINARY
12325 |O_BINARY
12326#endif
12327 };
12328 struct rb_io_encoding convconfig = {NULL, NULL, 0, Qnil};
12329
12330 rb_scan_args(argc, argv, "12", NULL, NULL, &offset);
12331 FilePathValue(argv[0]);
12332 convconfig.enc = rb_ascii8bit_encoding();
12333 arg.io = rb_io_open_generic(io, argv[0], oflags, fmode, &convconfig, 0);
12334 if (NIL_P(arg.io)) return Qnil;
12335 arg.argv = argv+1;
12336 arg.argc = (argc > 1) ? 1 : 0;
12337 if (!NIL_P(offset)) {
12338 struct seek_arg sarg;
12339 int state = 0;
12340 sarg.io = arg.io;
12341 sarg.offset = offset;
12342 sarg.mode = SEEK_SET;
12343 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12344 if (state) {
12345 rb_io_close(arg.io);
12346 rb_jump_tag(state);
12347 }
12348 }
12349 return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
12350}
12351
12352static VALUE
12353io_s_write0(VALUE v)
12354{
12355 struct write_arg *arg = (void *)v;
12356 return io_write(arg->io,arg->str,arg->nosync);
12357}
12358
12359static VALUE
12360io_s_write(int argc, VALUE *argv, VALUE klass, int binary)
12361{
12362 VALUE string, offset, opt;
12363 struct foreach_arg arg;
12364 struct write_arg warg;
12365
12366 rb_scan_args(argc, argv, "21:", NULL, &string, &offset, &opt);
12367
12368 if (NIL_P(opt)) opt = rb_hash_new();
12369 else opt = rb_hash_dup(opt);
12370
12371
12372 if (NIL_P(rb_hash_aref(opt,sym_mode))) {
12373 int mode = O_WRONLY|O_CREAT;
12374#ifdef O_BINARY
12375 if (binary) mode |= O_BINARY;
12376#endif
12377 if (NIL_P(offset)) mode |= O_TRUNC;
12378 rb_hash_aset(opt,sym_mode,INT2NUM(mode));
12379 }
12380 open_key_args(klass, argc, argv, opt, &arg);
12381
12382#ifndef O_BINARY
12383 if (binary) rb_io_binmode_m(arg.io);
12384#endif
12385
12386 if (NIL_P(arg.io)) return Qnil;
12387 if (!NIL_P(offset)) {
12388 struct seek_arg sarg;
12389 int state = 0;
12390 sarg.io = arg.io;
12391 sarg.offset = offset;
12392 sarg.mode = SEEK_SET;
12393 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12394 if (state) {
12395 rb_io_close(arg.io);
12396 rb_jump_tag(state);
12397 }
12398 }
12399
12400 warg.io = arg.io;
12401 warg.str = string;
12402 warg.nosync = 0;
12403
12404 return rb_ensure(io_s_write0, (VALUE)&warg, rb_io_close, arg.io);
12405}
12406
12407/*
12408 * call-seq:
12409 * IO.write(path, data, offset = 0, **opts) -> integer
12410 *
12411 * Opens the stream, writes the given +data+ to it,
12412 * and closes the stream; returns the number of bytes written.
12413 *
12414 * When called from class \IO (but not subclasses of \IO),
12415 * this method has potential security vulnerabilities if called with untrusted input;
12416 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12417 *
12418 * The first argument must be a string that is the path to a file.
12419 *
12420 * With only argument +path+ given, writes the given +data+ to the file at that path:
12421 *
12422 * IO.write('t.tmp', 'abc') # => 3
12423 * File.read('t.tmp') # => "abc"
12424 *
12425 * If +offset+ is zero (the default), the file is overwritten:
12426 *
12427 * IO.write('t.tmp', 'A') # => 1
12428 * File.read('t.tmp') # => "A"
12429 *
12430 * If +offset+ in within the file content, the file is partly overwritten:
12431 *
12432 * IO.write('t.tmp', 'abcdef') # => 3
12433 * File.read('t.tmp') # => "abcdef"
12434 * # Offset within content.
12435 * IO.write('t.tmp', '012', 2) # => 3
12436 * File.read('t.tmp') # => "ab012f"
12437 *
12438 * If +offset+ is outside the file content,
12439 * the file is padded with null characters <tt>"\u0000"</tt>:
12440 *
12441 * IO.write('t.tmp', 'xyz', 10) # => 3
12442 * File.read('t.tmp') # => "ab012f\u0000\u0000\u0000\u0000xyz"
12443 *
12444 * Optional keyword arguments +opts+ specify:
12445 *
12446 * - {Open Options}[rdoc-ref:IO@Open+Options].
12447 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12448 *
12449 */
12450
12451static VALUE
12452rb_io_s_write(int argc, VALUE *argv, VALUE io)
12453{
12454 return io_s_write(argc, argv, io, 0);
12455}
12456
12457/*
12458 * call-seq:
12459 * IO.binwrite(path, string, offset = 0) -> integer
12460 *
12461 * Behaves like IO.write, except that the stream is opened in binary mode
12462 * with ASCII-8BIT encoding.
12463 *
12464 * When called from class \IO (but not subclasses of \IO),
12465 * this method has potential security vulnerabilities if called with untrusted input;
12466 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12467 *
12468 */
12469
12470static VALUE
12471rb_io_s_binwrite(int argc, VALUE *argv, VALUE io)
12472{
12473 return io_s_write(argc, argv, io, 1);
12474}
12475
12477 VALUE src;
12478 VALUE dst;
12479 rb_off_t copy_length; /* (rb_off_t)-1 if not specified */
12480 rb_off_t src_offset; /* (rb_off_t)-1 if not specified */
12481
12482 rb_io_t *src_fptr;
12483 rb_io_t *dst_fptr;
12484 unsigned close_src : 1;
12485 unsigned close_dst : 1;
12486 int error_no;
12487 rb_off_t total;
12488 const char *syserr;
12489 const char *notimp;
12490 VALUE th;
12491 struct stat src_stat;
12492 struct stat dst_stat;
12493#ifdef HAVE_FCOPYFILE
12494 copyfile_state_t copyfile_state;
12495#endif
12496};
12497
12498static void *
12499exec_interrupts(void *arg)
12500{
12501 VALUE th = (VALUE)arg;
12502 rb_thread_execute_interrupts(th);
12503 return NULL;
12504}
12505
12506/*
12507 * returns TRUE if the preceding system call was interrupted
12508 * so we can continue. If the thread was interrupted, we
12509 * reacquire the GVL to execute interrupts before continuing.
12510 */
12511static int
12512maygvl_copy_stream_continue_p(int has_gvl, struct copy_stream_struct *stp)
12513{
12514 switch (errno) {
12515 case EINTR:
12516#if defined(ERESTART)
12517 case ERESTART:
12518#endif
12519 if (rb_thread_interrupted(stp->th)) {
12520 if (has_gvl)
12521 rb_thread_execute_interrupts(stp->th);
12522 else
12523 rb_thread_call_with_gvl(exec_interrupts, (void *)stp->th);
12524 }
12525 return TRUE;
12526 }
12527 return FALSE;
12528}
12529
12531 VALUE scheduler;
12532
12533 rb_io_t *fptr;
12534 short events;
12535
12536 VALUE result;
12537};
12538
12539static void *
12540fiber_scheduler_wait_for(void * _arguments)
12541{
12542 struct fiber_scheduler_wait_for_arguments *arguments = (struct fiber_scheduler_wait_for_arguments *)_arguments;
12543
12544 arguments->result = rb_fiber_scheduler_io_wait(arguments->scheduler, arguments->fptr->self, INT2NUM(arguments->events), RUBY_IO_TIMEOUT_DEFAULT);
12545
12546 return NULL;
12547}
12548
12549#if USE_POLL
12550# define IOWAIT_SYSCALL "poll"
12551STATIC_ASSERT(pollin_expected, POLLIN == RB_WAITFD_IN);
12552STATIC_ASSERT(pollout_expected, POLLOUT == RB_WAITFD_OUT);
12553static int
12554nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout)
12555{
12557 if (scheduler != Qnil) {
12558 struct fiber_scheduler_wait_for_arguments args = {.scheduler = scheduler, .fptr = fptr, .events = events};
12559 rb_thread_call_with_gvl(fiber_scheduler_wait_for, &args);
12560 return RTEST(args.result);
12561 }
12562
12563 int fd = fptr->fd;
12564 if (fd == -1) return 0;
12565
12566 struct pollfd fds;
12567
12568 fds.fd = fd;
12569 fds.events = events;
12570
12571 int timeout_milliseconds = -1;
12572
12573 if (timeout) {
12574 timeout_milliseconds = (int)(timeout->tv_sec * 1000) + (int)(timeout->tv_usec / 1000);
12575 }
12576
12577 return poll(&fds, 1, timeout_milliseconds);
12578}
12579#else /* !USE_POLL */
12580# define IOWAIT_SYSCALL "select"
12581static int
12582nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout)
12583{
12585 if (scheduler != Qnil) {
12586 struct fiber_scheduler_wait_for_arguments args = {.scheduler = scheduler, .fptr = fptr, .events = events};
12587 rb_thread_call_with_gvl(fiber_scheduler_wait_for, &args);
12588 return RTEST(args.result);
12589 }
12590
12591 int fd = fptr->fd;
12592
12593 if (fd == -1) {
12594 errno = EBADF;
12595 return -1;
12596 }
12597
12598 rb_fdset_t fds;
12599 int ret;
12600
12601 rb_fd_init(&fds);
12602 rb_fd_set(fd, &fds);
12603
12604 switch (events) {
12605 case RB_WAITFD_IN:
12606 ret = rb_fd_select(fd + 1, &fds, 0, 0, timeout);
12607 break;
12608 case RB_WAITFD_OUT:
12609 ret = rb_fd_select(fd + 1, 0, &fds, 0, timeout);
12610 break;
12611 default:
12612 VM_UNREACHABLE(nogvl_wait_for);
12613 }
12614
12615 rb_fd_term(&fds);
12616
12617 // On timeout, this returns 0.
12618 return ret;
12619}
12620#endif /* !USE_POLL */
12621
12622static int
12623maygvl_copy_stream_wait_read(int has_gvl, struct copy_stream_struct *stp)
12624{
12625 int ret;
12626
12627 do {
12628 if (has_gvl) {
12630 }
12631 else {
12632 ret = nogvl_wait_for(stp->th, stp->src_fptr, RB_WAITFD_IN, NULL);
12633 }
12634 } while (ret < 0 && maygvl_copy_stream_continue_p(has_gvl, stp));
12635
12636 if (ret < 0) {
12637 stp->syserr = IOWAIT_SYSCALL;
12638 stp->error_no = errno;
12639 return ret;
12640 }
12641 return 0;
12642}
12643
12644static int
12645nogvl_copy_stream_wait_write(struct copy_stream_struct *stp)
12646{
12647 int ret;
12648
12649 do {
12650 ret = nogvl_wait_for(stp->th, stp->dst_fptr, RB_WAITFD_OUT, NULL);
12651 } while (ret < 0 && maygvl_copy_stream_continue_p(0, stp));
12652
12653 if (ret < 0) {
12654 stp->syserr = IOWAIT_SYSCALL;
12655 stp->error_no = errno;
12656 return ret;
12657 }
12658 return 0;
12659}
12660
12661#ifdef USE_COPY_FILE_RANGE
12662
12663static ssize_t
12664simple_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)
12665{
12666#ifdef HAVE_COPY_FILE_RANGE
12667 return copy_file_range(in_fd, in_offset, out_fd, out_offset, count, flags);
12668#else
12669 return syscall(__NR_copy_file_range, in_fd, in_offset, out_fd, out_offset, count, flags);
12670#endif
12671}
12672
12673static int
12674nogvl_copy_file_range(struct copy_stream_struct *stp)
12675{
12676 ssize_t ss;
12677 rb_off_t src_size;
12678 rb_off_t copy_length, src_offset, *src_offset_ptr;
12679
12680 if (!S_ISREG(stp->src_stat.st_mode))
12681 return 0;
12682
12683 src_size = stp->src_stat.st_size;
12684 src_offset = stp->src_offset;
12685 if (src_offset >= (rb_off_t)0) {
12686 src_offset_ptr = &src_offset;
12687 }
12688 else {
12689 src_offset_ptr = NULL; /* if src_offset_ptr is NULL, then bytes are read from in_fd starting from the file offset */
12690 }
12691
12692 copy_length = stp->copy_length;
12693 if (copy_length < (rb_off_t)0) {
12694 if (src_offset < (rb_off_t)0) {
12695 rb_off_t current_offset;
12696 errno = 0;
12697 current_offset = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12698 if (current_offset < (rb_off_t)0 && errno) {
12699 stp->syserr = "lseek";
12700 stp->error_no = errno;
12701 return (int)current_offset;
12702 }
12703 copy_length = src_size - current_offset;
12704 }
12705 else {
12706 copy_length = src_size - src_offset;
12707 }
12708 }
12709
12710 retry_copy_file_range:
12711# if SIZEOF_OFF_T > SIZEOF_SIZE_T
12712 /* we are limited by the 32-bit ssize_t return value on 32-bit */
12713 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
12714# else
12715 ss = (ssize_t)copy_length;
12716# endif
12717 ss = simple_copy_file_range(stp->src_fptr->fd, src_offset_ptr, stp->dst_fptr->fd, NULL, ss, 0);
12718 if (0 < ss) {
12719 stp->total += ss;
12720 copy_length -= ss;
12721 if (0 < copy_length) {
12722 goto retry_copy_file_range;
12723 }
12724 }
12725 if (ss < 0) {
12726 if (maygvl_copy_stream_continue_p(0, stp)) {
12727 goto retry_copy_file_range;
12728 }
12729 switch (errno) {
12730 case EINVAL:
12731 case EPERM: /* copy_file_range(2) doesn't exist (may happen in
12732 docker container) */
12733#ifdef ENOSYS
12734 case ENOSYS:
12735#endif
12736#ifdef EXDEV
12737 case EXDEV: /* in_fd and out_fd are not on the same filesystem */
12738#endif
12739 return 0;
12740 case EAGAIN:
12741#if EWOULDBLOCK != EAGAIN
12742 case EWOULDBLOCK:
12743#endif
12744 {
12745 int ret = nogvl_copy_stream_wait_write(stp);
12746 if (ret < 0) return ret;
12747 }
12748 goto retry_copy_file_range;
12749 case EBADF:
12750 {
12751 int e = errno;
12752 int flags = fcntl(stp->dst_fptr->fd, F_GETFL);
12753
12754 if (flags != -1 && flags & O_APPEND) {
12755 return 0;
12756 }
12757 errno = e;
12758 }
12759 }
12760 stp->syserr = "copy_file_range";
12761 stp->error_no = errno;
12762 return (int)ss;
12763 }
12764 return 1;
12765}
12766#endif
12767
12768#ifdef HAVE_FCOPYFILE
12769static int
12770nogvl_fcopyfile(struct copy_stream_struct *stp)
12771{
12772 rb_off_t cur, ss = 0;
12773 const rb_off_t src_offset = stp->src_offset;
12774 int ret;
12775
12776 if (stp->copy_length >= (rb_off_t)0) {
12777 /* copy_length can't be specified in fcopyfile(3) */
12778 return 0;
12779 }
12780
12781 if (!S_ISREG(stp->src_stat.st_mode))
12782 return 0;
12783
12784 if (!S_ISREG(stp->dst_stat.st_mode))
12785 return 0;
12786 if (lseek(stp->dst_fptr->fd, 0, SEEK_CUR) > (rb_off_t)0) /* if dst IO was already written */
12787 return 0;
12788 if (fcntl(stp->dst_fptr->fd, F_GETFL) & O_APPEND) {
12789 /* fcopyfile(3) appends src IO to dst IO and then truncates
12790 * dst IO to src IO's original size. */
12791 rb_off_t end = lseek(stp->dst_fptr->fd, 0, SEEK_END);
12792 lseek(stp->dst_fptr->fd, 0, SEEK_SET);
12793 if (end > (rb_off_t)0) return 0;
12794 }
12795
12796 if (src_offset > (rb_off_t)0) {
12797 rb_off_t r;
12798
12799 /* get current offset */
12800 errno = 0;
12801 cur = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12802 if (cur < (rb_off_t)0 && errno) {
12803 stp->error_no = errno;
12804 return 1;
12805 }
12806
12807 errno = 0;
12808 r = lseek(stp->src_fptr->fd, src_offset, SEEK_SET);
12809 if (r < (rb_off_t)0 && errno) {
12810 stp->error_no = errno;
12811 return 1;
12812 }
12813 }
12814
12815 stp->copyfile_state = copyfile_state_alloc(); /* this will be freed by copy_stream_finalize() */
12816 ret = fcopyfile(stp->src_fptr->fd, stp->dst_fptr->fd, stp->copyfile_state, COPYFILE_DATA);
12817 copyfile_state_get(stp->copyfile_state, COPYFILE_STATE_COPIED, &ss); /* get copied bytes */
12818
12819 if (ret == 0) { /* success */
12820 stp->total = ss;
12821 if (src_offset > (rb_off_t)0) {
12822 rb_off_t r;
12823 errno = 0;
12824 /* reset offset */
12825 r = lseek(stp->src_fptr->fd, cur, SEEK_SET);
12826 if (r < (rb_off_t)0 && errno) {
12827 stp->error_no = errno;
12828 return 1;
12829 }
12830 }
12831 }
12832 else {
12833 switch (errno) {
12834 case ENOTSUP:
12835 case EPERM:
12836 case EINVAL:
12837 return 0;
12838 }
12839 stp->syserr = "fcopyfile";
12840 stp->error_no = errno;
12841 return (int)ret;
12842 }
12843 return 1;
12844}
12845#endif
12846
12847#ifdef HAVE_SENDFILE
12848
12849# ifdef __linux__
12850# define USE_SENDFILE
12851
12852# ifdef HAVE_SYS_SENDFILE_H
12853# include <sys/sendfile.h>
12854# endif
12855
12856static ssize_t
12857simple_sendfile(int out_fd, int in_fd, rb_off_t *offset, rb_off_t count)
12858{
12859 return sendfile(out_fd, in_fd, offset, (size_t)count);
12860}
12861
12862# elif 0 /* defined(__FreeBSD__) || defined(__DragonFly__) */ || defined(__APPLE__)
12863/* This runs on FreeBSD8.1 r30210, but sendfiles blocks its execution
12864 * without cpuset -l 0.
12865 */
12866# define USE_SENDFILE
12867
12868static ssize_t
12869simple_sendfile(int out_fd, int in_fd, rb_off_t *offset, rb_off_t count)
12870{
12871 int r;
12872 rb_off_t pos = offset ? *offset : lseek(in_fd, 0, SEEK_CUR);
12873 rb_off_t sbytes;
12874# ifdef __APPLE__
12875 r = sendfile(in_fd, out_fd, pos, &count, NULL, 0);
12876 sbytes = count;
12877# else
12878 r = sendfile(in_fd, out_fd, pos, (size_t)count, NULL, &sbytes, 0);
12879# endif
12880 if (r != 0 && sbytes == 0) return r;
12881 if (offset) {
12882 *offset += sbytes;
12883 }
12884 else {
12885 lseek(in_fd, sbytes, SEEK_CUR);
12886 }
12887 return (ssize_t)sbytes;
12888}
12889
12890# endif
12891
12892#endif
12893
12894#ifdef USE_SENDFILE
12895static int
12896nogvl_copy_stream_sendfile(struct copy_stream_struct *stp)
12897{
12898 ssize_t ss;
12899 rb_off_t src_size;
12900 rb_off_t copy_length;
12901 rb_off_t src_offset;
12902 int use_pread;
12903
12904 if (!S_ISREG(stp->src_stat.st_mode))
12905 return 0;
12906
12907 src_size = stp->src_stat.st_size;
12908#ifndef __linux__
12909 if ((stp->dst_stat.st_mode & S_IFMT) != S_IFSOCK)
12910 return 0;
12911#endif
12912
12913 src_offset = stp->src_offset;
12914 use_pread = src_offset >= (rb_off_t)0;
12915
12916 copy_length = stp->copy_length;
12917 if (copy_length < (rb_off_t)0) {
12918 if (use_pread)
12919 copy_length = src_size - src_offset;
12920 else {
12921 rb_off_t cur;
12922 errno = 0;
12923 cur = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12924 if (cur < (rb_off_t)0 && errno) {
12925 stp->syserr = "lseek";
12926 stp->error_no = errno;
12927 return (int)cur;
12928 }
12929 copy_length = src_size - cur;
12930 }
12931 }
12932
12933 retry_sendfile:
12934# if SIZEOF_OFF_T > SIZEOF_SIZE_T
12935 /* we are limited by the 32-bit ssize_t return value on 32-bit */
12936 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
12937# else
12938 ss = (ssize_t)copy_length;
12939# endif
12940 if (use_pread) {
12941 ss = simple_sendfile(stp->dst_fptr->fd, stp->src_fptr->fd, &src_offset, ss);
12942 }
12943 else {
12944 ss = simple_sendfile(stp->dst_fptr->fd, stp->src_fptr->fd, NULL, ss);
12945 }
12946 if (0 < ss) {
12947 stp->total += ss;
12948 copy_length -= ss;
12949 if (0 < copy_length) {
12950 goto retry_sendfile;
12951 }
12952 }
12953 if (ss < 0) {
12954 if (maygvl_copy_stream_continue_p(0, stp))
12955 goto retry_sendfile;
12956 switch (errno) {
12957 case EINVAL:
12958#ifdef ENOSYS
12959 case ENOSYS:
12960#endif
12961#ifdef EOPNOTSUP
12962 /* some RedHat kernels may return EOPNOTSUP on an NFS mount.
12963 see also: [Feature #16965] */
12964 case EOPNOTSUP:
12965#endif
12966 return 0;
12967 case EAGAIN:
12968#if EWOULDBLOCK != EAGAIN
12969 case EWOULDBLOCK:
12970#endif
12971 {
12972 int ret;
12973#ifndef __linux__
12974 /*
12975 * Linux requires stp->src_fptr->fd to be a mmap-able (regular) file,
12976 * select() reports regular files to always be "ready", so
12977 * there is no need to select() on it.
12978 * Other OSes may have the same limitation for sendfile() which
12979 * allow us to bypass maygvl_copy_stream_wait_read()...
12980 */
12981 ret = maygvl_copy_stream_wait_read(0, stp);
12982 if (ret < 0) return ret;
12983#endif
12984 ret = nogvl_copy_stream_wait_write(stp);
12985 if (ret < 0) return ret;
12986 }
12987 goto retry_sendfile;
12988 }
12989 stp->syserr = "sendfile";
12990 stp->error_no = errno;
12991 return (int)ss;
12992 }
12993 return 1;
12994}
12995#endif
12996
12997static ssize_t
12998maygvl_read(int has_gvl, rb_io_t *fptr, void *buf, size_t count)
12999{
13000 if (has_gvl)
13001 return rb_io_read_memory(fptr, buf, count);
13002 else
13003 return read(fptr->fd, buf, count);
13004}
13005
13006static ssize_t
13007maygvl_copy_stream_read(int has_gvl, struct copy_stream_struct *stp, char *buf, size_t len, rb_off_t offset)
13008{
13009 ssize_t ss;
13010 retry_read:
13011 if (offset < (rb_off_t)0) {
13012 ss = maygvl_read(has_gvl, stp->src_fptr, buf, len);
13013 }
13014 else {
13015 ss = pread(stp->src_fptr->fd, buf, len, offset);
13016 }
13017 if (ss == 0) {
13018 return 0;
13019 }
13020 if (ss < 0) {
13021 if (maygvl_copy_stream_continue_p(has_gvl, stp))
13022 goto retry_read;
13023 switch (errno) {
13024 case EAGAIN:
13025#if EWOULDBLOCK != EAGAIN
13026 case EWOULDBLOCK:
13027#endif
13028 {
13029 int ret = maygvl_copy_stream_wait_read(has_gvl, stp);
13030 if (ret < 0) return ret;
13031 }
13032 goto retry_read;
13033#ifdef ENOSYS
13034 case ENOSYS:
13035 stp->notimp = "pread";
13036 return ss;
13037#endif
13038 }
13039 stp->syserr = offset < (rb_off_t)0 ? "read" : "pread";
13040 stp->error_no = errno;
13041 }
13042 return ss;
13043}
13044
13045static int
13046nogvl_copy_stream_write(struct copy_stream_struct *stp, char *buf, size_t len)
13047{
13048 ssize_t ss;
13049 int off = 0;
13050 while (len) {
13051 ss = write(stp->dst_fptr->fd, buf+off, len);
13052 if (ss < 0) {
13053 if (maygvl_copy_stream_continue_p(0, stp))
13054 continue;
13055 if (io_again_p(errno)) {
13056 int ret = nogvl_copy_stream_wait_write(stp);
13057 if (ret < 0) return ret;
13058 continue;
13059 }
13060 stp->syserr = "write";
13061 stp->error_no = errno;
13062 return (int)ss;
13063 }
13064 off += (int)ss;
13065 len -= (int)ss;
13066 stp->total += ss;
13067 }
13068 return 0;
13069}
13070
13071static void
13072nogvl_copy_stream_read_write(struct copy_stream_struct *stp)
13073{
13074 char buf[1024*16];
13075 size_t len;
13076 ssize_t ss;
13077 int ret;
13078 rb_off_t copy_length;
13079 rb_off_t src_offset;
13080 int use_eof;
13081 int use_pread;
13082
13083 copy_length = stp->copy_length;
13084 use_eof = copy_length < (rb_off_t)0;
13085 src_offset = stp->src_offset;
13086 use_pread = src_offset >= (rb_off_t)0;
13087
13088 if (use_pread && stp->close_src) {
13089 rb_off_t r;
13090 errno = 0;
13091 r = lseek(stp->src_fptr->fd, src_offset, SEEK_SET);
13092 if (r < (rb_off_t)0 && errno) {
13093 stp->syserr = "lseek";
13094 stp->error_no = errno;
13095 return;
13096 }
13097 src_offset = (rb_off_t)-1;
13098 use_pread = 0;
13099 }
13100
13101 while (use_eof || 0 < copy_length) {
13102 if (!use_eof && copy_length < (rb_off_t)sizeof(buf)) {
13103 len = (size_t)copy_length;
13104 }
13105 else {
13106 len = sizeof(buf);
13107 }
13108 if (use_pread) {
13109 ss = maygvl_copy_stream_read(0, stp, buf, len, src_offset);
13110 if (0 < ss)
13111 src_offset += ss;
13112 }
13113 else {
13114 ss = maygvl_copy_stream_read(0, stp, buf, len, (rb_off_t)-1);
13115 }
13116 if (ss <= 0) /* EOF or error */
13117 return;
13118
13119 ret = nogvl_copy_stream_write(stp, buf, ss);
13120 if (ret < 0)
13121 return;
13122
13123 if (!use_eof)
13124 copy_length -= ss;
13125 }
13126}
13127
13128static void *
13129nogvl_copy_stream_func(void *arg)
13130{
13131 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13132#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13133 int ret;
13134#endif
13135
13136#ifdef USE_COPY_FILE_RANGE
13137 ret = nogvl_copy_file_range(stp);
13138 if (ret != 0)
13139 goto finish; /* error or success */
13140#endif
13141
13142#ifdef HAVE_FCOPYFILE
13143 ret = nogvl_fcopyfile(stp);
13144 if (ret != 0)
13145 goto finish; /* error or success */
13146#endif
13147
13148#ifdef USE_SENDFILE
13149 ret = nogvl_copy_stream_sendfile(stp);
13150 if (ret != 0)
13151 goto finish; /* error or success */
13152#endif
13153
13154 nogvl_copy_stream_read_write(stp);
13155
13156#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13157 finish:
13158#endif
13159 return 0;
13160}
13161
13162static VALUE
13163copy_stream_fallback_body(VALUE arg)
13164{
13165 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13166 const int buflen = 16*1024;
13167 VALUE n;
13168 VALUE buf = rb_str_buf_new(buflen);
13169 rb_off_t rest = stp->copy_length;
13170 rb_off_t off = stp->src_offset;
13171 ID read_method = id_readpartial;
13172
13173 if (!stp->src_fptr) {
13174 if (!rb_respond_to(stp->src, read_method)) {
13175 read_method = id_read;
13176 }
13177 }
13178
13179 while (1) {
13180 long numwrote;
13181 long l;
13182 rb_str_make_independent(buf);
13183 if (stp->copy_length < (rb_off_t)0) {
13184 l = buflen;
13185 }
13186 else {
13187 if (rest == 0) {
13188 rb_str_resize(buf, 0);
13189 break;
13190 }
13191 l = buflen < rest ? buflen : (long)rest;
13192 }
13193 if (!stp->src_fptr) {
13194 VALUE rc = rb_funcall(stp->src, read_method, 2, INT2FIX(l), buf);
13195
13196 if (read_method == id_read && NIL_P(rc))
13197 break;
13198 }
13199 else {
13200 ssize_t ss;
13201 rb_str_resize(buf, buflen);
13202 ss = maygvl_copy_stream_read(1, stp, RSTRING_PTR(buf), l, off);
13203 rb_str_resize(buf, ss > 0 ? ss : 0);
13204 if (ss < 0)
13205 return Qnil;
13206 if (ss == 0)
13207 rb_eof_error();
13208 if (off >= (rb_off_t)0)
13209 off += ss;
13210 }
13211 n = rb_io_write(stp->dst, buf);
13212 numwrote = NUM2LONG(n);
13213 stp->total += numwrote;
13214 rest -= numwrote;
13215 if (read_method == id_read && RSTRING_LEN(buf) == 0) {
13216 break;
13217 }
13218 }
13219
13220 return Qnil;
13221}
13222
13223static VALUE
13224copy_stream_fallback(struct copy_stream_struct *stp)
13225{
13226 if (!stp->src_fptr && stp->src_offset >= (rb_off_t)0) {
13227 rb_raise(rb_eArgError, "cannot specify src_offset for non-IO");
13228 }
13229 rb_rescue2(copy_stream_fallback_body, (VALUE)stp,
13230 (VALUE (*) (VALUE, VALUE))0, (VALUE)0,
13231 rb_eEOFError, (VALUE)0);
13232 return Qnil;
13233}
13234
13235static VALUE
13236copy_stream_body(VALUE arg)
13237{
13238 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13239 VALUE src_io = stp->src, dst_io = stp->dst;
13240 const int common_oflags = 0
13241#ifdef O_NOCTTY
13242 | O_NOCTTY
13243#endif
13244 ;
13245
13246 stp->th = rb_thread_current();
13247
13248 stp->total = 0;
13249
13250 if (src_io == argf ||
13251 !(RB_TYPE_P(src_io, T_FILE) ||
13252 RB_TYPE_P(src_io, T_STRING) ||
13253 rb_respond_to(src_io, rb_intern("to_path")))) {
13254 stp->src_fptr = NULL;
13255 }
13256 else {
13257 int stat_ret;
13258 VALUE tmp_io = rb_io_check_io(src_io);
13259 if (!NIL_P(tmp_io)) {
13260 src_io = tmp_io;
13261 }
13262 else if (!RB_TYPE_P(src_io, T_FILE)) {
13263 VALUE args[2];
13264 FilePathValue(src_io);
13265 args[0] = src_io;
13266 args[1] = INT2NUM(O_RDONLY|common_oflags);
13267 src_io = rb_class_new_instance(2, args, rb_cFile);
13268 stp->src = src_io;
13269 stp->close_src = 1;
13270 }
13271 RB_IO_POINTER(src_io, stp->src_fptr);
13272 rb_io_check_byte_readable(stp->src_fptr);
13273
13274 stat_ret = fstat(stp->src_fptr->fd, &stp->src_stat);
13275 if (stat_ret < 0) {
13276 stp->syserr = "fstat";
13277 stp->error_no = errno;
13278 return Qnil;
13279 }
13280 }
13281
13282 if (dst_io == argf ||
13283 !(RB_TYPE_P(dst_io, T_FILE) ||
13284 RB_TYPE_P(dst_io, T_STRING) ||
13285 rb_respond_to(dst_io, rb_intern("to_path")))) {
13286 stp->dst_fptr = NULL;
13287 }
13288 else {
13289 int stat_ret;
13290 VALUE tmp_io = rb_io_check_io(dst_io);
13291 if (!NIL_P(tmp_io)) {
13292 dst_io = GetWriteIO(tmp_io);
13293 }
13294 else if (!RB_TYPE_P(dst_io, T_FILE)) {
13295 VALUE args[3];
13296 FilePathValue(dst_io);
13297 args[0] = dst_io;
13298 args[1] = INT2NUM(O_WRONLY|O_CREAT|O_TRUNC|common_oflags);
13299 args[2] = INT2FIX(0666);
13300 dst_io = rb_class_new_instance(3, args, rb_cFile);
13301 stp->dst = dst_io;
13302 stp->close_dst = 1;
13303 }
13304 else {
13305 dst_io = GetWriteIO(dst_io);
13306 stp->dst = dst_io;
13307 }
13308 RB_IO_POINTER(dst_io, stp->dst_fptr);
13309 rb_io_check_writable(stp->dst_fptr);
13310
13311 stat_ret = fstat(stp->dst_fptr->fd, &stp->dst_stat);
13312 if (stat_ret < 0) {
13313 stp->syserr = "fstat";
13314 stp->error_no = errno;
13315 return Qnil;
13316 }
13317 }
13318
13319#ifdef O_BINARY
13320 if (stp->src_fptr)
13321 SET_BINARY_MODE_WITH_SEEK_CUR(stp->src_fptr);
13322#endif
13323 if (stp->dst_fptr)
13324 io_ascii8bit_binmode(stp->dst_fptr);
13325
13326 if (stp->src_offset < (rb_off_t)0 && stp->src_fptr && stp->src_fptr->rbuf.len) {
13327 size_t len = stp->src_fptr->rbuf.len;
13328 VALUE str;
13329 if (stp->copy_length >= (rb_off_t)0 && stp->copy_length < (rb_off_t)len) {
13330 len = (size_t)stp->copy_length;
13331 }
13332 str = rb_str_buf_new(len);
13333 rb_str_resize(str,len);
13334 read_buffered_data(RSTRING_PTR(str), len, stp->src_fptr);
13335 if (stp->dst_fptr) { /* IO or filename */
13336 if (io_binwrite(RSTRING_PTR(str), RSTRING_LEN(str), stp->dst_fptr, 0) < 0)
13337 rb_sys_fail_on_write(stp->dst_fptr);
13338 }
13339 else /* others such as StringIO */
13340 rb_io_write(dst_io, str);
13341 rb_str_resize(str, 0);
13342 stp->total += len;
13343 if (stp->copy_length >= (rb_off_t)0)
13344 stp->copy_length -= len;
13345 }
13346
13347 if (stp->dst_fptr && io_fflush(stp->dst_fptr) < 0) {
13348 rb_raise(rb_eIOError, "flush failed");
13349 }
13350
13351 if (stp->copy_length == 0)
13352 return Qnil;
13353
13354 if (stp->src_fptr == NULL || stp->dst_fptr == NULL) {
13355 return copy_stream_fallback(stp);
13356 }
13357
13358 IO_WITHOUT_GVL(nogvl_copy_stream_func, stp);
13359 return Qnil;
13360}
13361
13362static VALUE
13363copy_stream_finalize(VALUE arg)
13364{
13365 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13366
13367#ifdef HAVE_FCOPYFILE
13368 if (stp->copyfile_state) {
13369 copyfile_state_free(stp->copyfile_state);
13370 }
13371#endif
13372
13373 if (stp->close_src) {
13374 rb_io_close_m(stp->src);
13375 }
13376 if (stp->close_dst) {
13377 rb_io_close_m(stp->dst);
13378 }
13379 if (stp->syserr) {
13380 rb_syserr_fail(stp->error_no, stp->syserr);
13381 }
13382 if (stp->notimp) {
13383 rb_raise(rb_eNotImpError, "%s() not implemented", stp->notimp);
13384 }
13385 return Qnil;
13386}
13387
13388/*
13389 * call-seq:
13390 * IO.copy_stream(src, dst, src_length = nil, src_offset = 0) -> integer
13391 *
13392 * Copies from the given +src+ to the given +dst+,
13393 * returning the number of bytes copied.
13394 *
13395 * - The given +src+ must be one of the following:
13396 *
13397 * - The path to a readable file, from which source data is to be read.
13398 * - An \IO-like object, opened for reading and capable of responding
13399 * to method +:readpartial+ or method +:read+.
13400 *
13401 * - The given +dst+ must be one of the following:
13402 *
13403 * - The path to a writable file, to which data is to be written.
13404 * - An \IO-like object, opened for writing and capable of responding
13405 * to method +:write+.
13406 *
13407 * The examples here use file <tt>t.txt</tt> as source:
13408 *
13409 * File.read('t.txt')
13410 * # => "First line\nSecond line\n\nThird line\nFourth line\n"
13411 * File.read('t.txt').size # => 47
13412 *
13413 * If only arguments +src+ and +dst+ are given,
13414 * the entire source stream is copied:
13415 *
13416 * # Paths.
13417 * IO.copy_stream('t.txt', 't.tmp') # => 47
13418 *
13419 * # IOs (recall that a File is also an IO).
13420 * src_io = File.open('t.txt', 'r') # => #<File:t.txt>
13421 * dst_io = File.open('t.tmp', 'w') # => #<File:t.tmp>
13422 * IO.copy_stream(src_io, dst_io) # => 47
13423 * src_io.close
13424 * dst_io.close
13425 *
13426 * With argument +src_length+ a non-negative integer,
13427 * no more than that many bytes are copied:
13428 *
13429 * IO.copy_stream('t.txt', 't.tmp', 10) # => 10
13430 * File.read('t.tmp') # => "First line"
13431 *
13432 * With argument +src_offset+ also given,
13433 * the source stream is read beginning at that offset:
13434 *
13435 * IO.copy_stream('t.txt', 't.tmp', 11, 11) # => 11
13436 * IO.read('t.tmp') # => "Second line"
13437 *
13438 */
13439static VALUE
13440rb_io_s_copy_stream(int argc, VALUE *argv, VALUE io)
13441{
13442 VALUE src, dst, length, src_offset;
13443 struct copy_stream_struct st;
13444
13445 MEMZERO(&st, struct copy_stream_struct, 1);
13446
13447 rb_scan_args(argc, argv, "22", &src, &dst, &length, &src_offset);
13448
13449 st.src = src;
13450 st.dst = dst;
13451
13452 st.src_fptr = NULL;
13453 st.dst_fptr = NULL;
13454
13455 if (NIL_P(length))
13456 st.copy_length = (rb_off_t)-1;
13457 else
13458 st.copy_length = NUM2OFFT(length);
13459
13460 if (NIL_P(src_offset))
13461 st.src_offset = (rb_off_t)-1;
13462 else
13463 st.src_offset = NUM2OFFT(src_offset);
13464
13465 rb_ensure(copy_stream_body, (VALUE)&st, copy_stream_finalize, (VALUE)&st);
13466
13467 return OFFT2NUM(st.total);
13468}
13469
13470/*
13471 * call-seq:
13472 * external_encoding -> encoding or nil
13473 *
13474 * Returns the Encoding object that represents the encoding of the stream,
13475 * or +nil+ if the stream is in write mode and no encoding is specified.
13476 *
13477 * See {Encodings}[rdoc-ref:File@Encodings].
13478 *
13479 */
13480
13481static VALUE
13482rb_io_external_encoding(VALUE io)
13483{
13484 rb_io_t *fptr = RFILE(rb_io_taint_check(io))->fptr;
13485
13486 if (fptr->encs.enc2) {
13487 return rb_enc_from_encoding(fptr->encs.enc2);
13488 }
13489 if (fptr->mode & FMODE_WRITABLE) {
13490 if (fptr->encs.enc)
13491 return rb_enc_from_encoding(fptr->encs.enc);
13492 return Qnil;
13493 }
13494 return rb_enc_from_encoding(io_read_encoding(fptr));
13495}
13496
13497/*
13498 * call-seq:
13499 * internal_encoding -> encoding or nil
13500 *
13501 * Returns the Encoding object that represents the encoding of the internal string,
13502 * if conversion is specified,
13503 * or +nil+ otherwise.
13504 *
13505 * See {Encodings}[rdoc-ref:File@Encodings].
13506 *
13507 */
13508
13509static VALUE
13510rb_io_internal_encoding(VALUE io)
13511{
13512 rb_io_t *fptr = RFILE(rb_io_taint_check(io))->fptr;
13513
13514 if (!fptr->encs.enc2) return Qnil;
13515 return rb_enc_from_encoding(io_read_encoding(fptr));
13516}
13517
13518/*
13519 * call-seq:
13520 * set_encoding(ext_enc) -> self
13521 * set_encoding(ext_enc, int_enc, **enc_opts) -> self
13522 * set_encoding('ext_enc:int_enc', **enc_opts) -> self
13523 *
13524 * See {Encodings}[rdoc-ref:File@Encodings].
13525 *
13526 * Argument +ext_enc+, if given, must be an Encoding object
13527 * or a String with the encoding name;
13528 * it is assigned as the encoding for the stream.
13529 *
13530 * Argument +int_enc+, if given, must be an Encoding object
13531 * or a String with the encoding name;
13532 * it is assigned as the encoding for the internal string.
13533 *
13534 * Argument <tt>'ext_enc:int_enc'</tt>, if given, is a string
13535 * containing two colon-separated encoding names;
13536 * corresponding Encoding objects are assigned as the external
13537 * and internal encodings for the stream.
13538 *
13539 * If the external encoding of a string is binary/ASCII-8BIT,
13540 * the internal encoding of the string is set to nil, since no
13541 * transcoding is needed.
13542 *
13543 * Optional keyword arguments +enc_opts+ specify
13544 * {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
13545 *
13546 */
13547
13548static VALUE
13549rb_io_set_encoding(int argc, VALUE *argv, VALUE io)
13550{
13551 rb_io_t *fptr;
13552 VALUE v1, v2, opt;
13553
13554 if (!RB_TYPE_P(io, T_FILE)) {
13555 return forward(io, id_set_encoding, argc, argv);
13556 }
13557
13558 argc = rb_scan_args(argc, argv, "11:", &v1, &v2, &opt);
13559 GetOpenFile(io, fptr);
13560 io_encoding_set(fptr, v1, v2, opt);
13561 return io;
13562}
13563
13564void
13565rb_stdio_set_default_encoding(void)
13566{
13567 VALUE val = Qnil;
13568
13569#ifdef _WIN32
13570 if (isatty(fileno(stdin))) {
13571 rb_encoding *external = rb_locale_encoding();
13572 rb_encoding *internal = rb_default_internal_encoding();
13573 if (!internal) internal = rb_default_external_encoding();
13574 io_encoding_set(RFILE(rb_stdin)->fptr,
13575 rb_enc_from_encoding(external),
13576 rb_enc_from_encoding(internal),
13577 Qnil);
13578 }
13579 else
13580#endif
13581 rb_io_set_encoding(1, &val, rb_stdin);
13582 rb_io_set_encoding(1, &val, rb_stdout);
13583 rb_io_set_encoding(1, &val, rb_stderr);
13584}
13585
13586static inline int
13587global_argf_p(VALUE arg)
13588{
13589 return arg == argf;
13590}
13591
13592typedef VALUE (*argf_encoding_func)(VALUE io);
13593
13594static VALUE
13595argf_encoding(VALUE argf, argf_encoding_func func)
13596{
13597 if (!RTEST(ARGF.current_file)) {
13598 return rb_enc_default_external();
13599 }
13600 return func(rb_io_check_io(ARGF.current_file));
13601}
13602
13603/*
13604 * call-seq:
13605 * ARGF.external_encoding -> encoding
13606 *
13607 * Returns the external encoding for files read from ARGF as an Encoding
13608 * object. The external encoding is the encoding of the text as stored in a
13609 * file. Contrast with ARGF.internal_encoding, which is the encoding used to
13610 * represent this text within Ruby.
13611 *
13612 * To set the external encoding use ARGF.set_encoding.
13613 *
13614 * For example:
13615 *
13616 * ARGF.external_encoding #=> #<Encoding:UTF-8>
13617 *
13618 */
13619static VALUE
13620argf_external_encoding(VALUE argf)
13621{
13622 return argf_encoding(argf, rb_io_external_encoding);
13623}
13624
13625/*
13626 * call-seq:
13627 * ARGF.internal_encoding -> encoding
13628 *
13629 * Returns the internal encoding for strings read from ARGF as an
13630 * Encoding object.
13631 *
13632 * If ARGF.set_encoding has been called with two encoding names, the second
13633 * is returned. Otherwise, if +Encoding.default_external+ has been set, that
13634 * value is returned. Failing that, if a default external encoding was
13635 * specified on the command-line, that value is used. If the encoding is
13636 * unknown, +nil+ is returned.
13637 */
13638static VALUE
13639argf_internal_encoding(VALUE argf)
13640{
13641 return argf_encoding(argf, rb_io_internal_encoding);
13642}
13643
13644/*
13645 * call-seq:
13646 * ARGF.set_encoding(ext_enc) -> ARGF
13647 * ARGF.set_encoding("ext_enc:int_enc") -> ARGF
13648 * ARGF.set_encoding(ext_enc, int_enc) -> ARGF
13649 * ARGF.set_encoding("ext_enc:int_enc", opt) -> ARGF
13650 * ARGF.set_encoding(ext_enc, int_enc, opt) -> ARGF
13651 *
13652 * If single argument is specified, strings read from ARGF are tagged with
13653 * the encoding specified.
13654 *
13655 * If two encoding names separated by a colon are given, e.g. "ascii:utf-8",
13656 * the read string is converted from the first encoding (external encoding)
13657 * to the second encoding (internal encoding), then tagged with the second
13658 * encoding.
13659 *
13660 * If two arguments are specified, they must be encoding objects or encoding
13661 * names. Again, the first specifies the external encoding; the second
13662 * specifies the internal encoding.
13663 *
13664 * If the external encoding and the internal encoding are specified, the
13665 * optional Hash argument can be used to adjust the conversion process. The
13666 * structure of this hash is explained in the String#encode documentation.
13667 *
13668 * For example:
13669 *
13670 * ARGF.set_encoding('ascii') # Tag the input as US-ASCII text
13671 * ARGF.set_encoding(Encoding::UTF_8) # Tag the input as UTF-8 text
13672 * ARGF.set_encoding('utf-8','ascii') # Transcode the input from US-ASCII
13673 * # to UTF-8.
13674 */
13675static VALUE
13676argf_set_encoding(int argc, VALUE *argv, VALUE argf)
13677{
13678 rb_io_t *fptr;
13679
13680 if (!next_argv()) {
13681 rb_raise(rb_eArgError, "no stream to set encoding");
13682 }
13683 rb_io_set_encoding(argc, argv, ARGF.current_file);
13684 GetOpenFile(ARGF.current_file, fptr);
13685 ARGF.encs = fptr->encs;
13686 return argf;
13687}
13688
13689/*
13690 * call-seq:
13691 * ARGF.tell -> Integer
13692 * ARGF.pos -> Integer
13693 *
13694 * Returns the current offset (in bytes) of the current file in ARGF.
13695 *
13696 * ARGF.pos #=> 0
13697 * ARGF.gets #=> "This is line one\n"
13698 * ARGF.pos #=> 17
13699 *
13700 */
13701static VALUE
13702argf_tell(VALUE argf)
13703{
13704 if (!next_argv()) {
13705 rb_raise(rb_eArgError, "no stream to tell");
13706 }
13707 ARGF_FORWARD(0, 0);
13708 return rb_io_tell(ARGF.current_file);
13709}
13710
13711/*
13712 * call-seq:
13713 * ARGF.seek(amount, whence=IO::SEEK_SET) -> 0
13714 *
13715 * Seeks to offset _amount_ (an Integer) in the ARGF stream according to
13716 * the value of _whence_. See IO#seek for further details.
13717 */
13718static VALUE
13719argf_seek_m(int argc, VALUE *argv, VALUE argf)
13720{
13721 if (!next_argv()) {
13722 rb_raise(rb_eArgError, "no stream to seek");
13723 }
13724 ARGF_FORWARD(argc, argv);
13725 return rb_io_seek_m(argc, argv, ARGF.current_file);
13726}
13727
13728/*
13729 * call-seq:
13730 * ARGF.pos = position -> Integer
13731 *
13732 * Seeks to the position given by _position_ (in bytes) in ARGF.
13733 *
13734 * For example:
13735 *
13736 * ARGF.pos = 17
13737 * ARGF.gets #=> "This is line two\n"
13738 */
13739static VALUE
13740argf_set_pos(VALUE argf, VALUE offset)
13741{
13742 if (!next_argv()) {
13743 rb_raise(rb_eArgError, "no stream to set position");
13744 }
13745 ARGF_FORWARD(1, &offset);
13746 return rb_io_set_pos(ARGF.current_file, offset);
13747}
13748
13749/*
13750 * call-seq:
13751 * ARGF.rewind -> 0
13752 *
13753 * Positions the current file to the beginning of input, resetting
13754 * ARGF.lineno to zero.
13755 *
13756 * ARGF.readline #=> "This is line one\n"
13757 * ARGF.rewind #=> 0
13758 * ARGF.lineno #=> 0
13759 * ARGF.readline #=> "This is line one\n"
13760 */
13761static VALUE
13762argf_rewind(VALUE argf)
13763{
13764 VALUE ret;
13765 int old_lineno;
13766
13767 if (!next_argv()) {
13768 rb_raise(rb_eArgError, "no stream to rewind");
13769 }
13770 ARGF_FORWARD(0, 0);
13771 old_lineno = RFILE(ARGF.current_file)->fptr->lineno;
13772 ret = rb_io_rewind(ARGF.current_file);
13773 if (!global_argf_p(argf)) {
13774 ARGF.last_lineno = ARGF.lineno -= old_lineno;
13775 }
13776 return ret;
13777}
13778
13779/*
13780 * call-seq:
13781 * ARGF.fileno -> integer
13782 * ARGF.to_i -> integer
13783 *
13784 * Returns an integer representing the numeric file descriptor for
13785 * the current file. Raises an ArgumentError if there isn't a current file.
13786 *
13787 * ARGF.fileno #=> 3
13788 */
13789static VALUE
13790argf_fileno(VALUE argf)
13791{
13792 if (!next_argv()) {
13793 rb_raise(rb_eArgError, "no stream");
13794 }
13795 ARGF_FORWARD(0, 0);
13796 return rb_io_fileno(ARGF.current_file);
13797}
13798
13799/*
13800 * call-seq:
13801 * ARGF.to_io -> IO
13802 *
13803 * Returns an IO object representing the current file. This will be a
13804 * File object unless the current file is a stream such as STDIN.
13805 *
13806 * For example:
13807 *
13808 * ARGF.to_io #=> #<File:glark.txt>
13809 * ARGF.to_io #=> #<IO:<STDIN>>
13810 */
13811static VALUE
13812argf_to_io(VALUE argf)
13813{
13814 next_argv();
13815 ARGF_FORWARD(0, 0);
13816 return ARGF.current_file;
13817}
13818
13819/*
13820 * call-seq:
13821 * ARGF.eof? -> true or false
13822 * ARGF.eof -> true or false
13823 *
13824 * Returns true if the current file in ARGF is at end of file, i.e. it has
13825 * no data to read. The stream must be opened for reading or an IOError
13826 * will be raised.
13827 *
13828 * $ echo "eof" | ruby argf.rb
13829 *
13830 * ARGF.eof? #=> false
13831 * 3.times { ARGF.readchar }
13832 * ARGF.eof? #=> false
13833 * ARGF.readchar #=> "\n"
13834 * ARGF.eof? #=> true
13835 */
13836
13837static VALUE
13838argf_eof(VALUE argf)
13839{
13840 next_argv();
13841 if (RTEST(ARGF.current_file)) {
13842 if (ARGF.init_p == 0) return Qtrue;
13843 next_argv();
13844 ARGF_FORWARD(0, 0);
13845 if (rb_io_eof(ARGF.current_file)) {
13846 return Qtrue;
13847 }
13848 }
13849 return Qfalse;
13850}
13851
13852/*
13853 * call-seq:
13854 * ARGF.read([length [, outbuf]]) -> string, outbuf, or nil
13855 *
13856 * Reads _length_ bytes from ARGF. The files named on the command line
13857 * are concatenated and treated as a single file by this method, so when
13858 * called without arguments the contents of this pseudo file are returned in
13859 * their entirety.
13860 *
13861 * _length_ must be a non-negative integer or +nil+.
13862 *
13863 * If _length_ is a positive integer, +read+ tries to read
13864 * _length_ bytes without any conversion (binary mode).
13865 * It returns +nil+ if an EOF is encountered before anything can be read.
13866 * Fewer than _length_ bytes are returned if an EOF is encountered during
13867 * the read.
13868 * In the case of an integer _length_, the resulting string is always
13869 * in ASCII-8BIT encoding.
13870 *
13871 * If _length_ is omitted or is +nil+, it reads until EOF
13872 * and the encoding conversion is applied, if applicable.
13873 * A string is returned even if EOF is encountered before any data is read.
13874 *
13875 * If _length_ is zero, it returns an empty string (<code>""</code>).
13876 *
13877 * If the optional _outbuf_ argument is present,
13878 * it must reference a String, which will receive the data.
13879 * The _outbuf_ will contain only the received data after the method call
13880 * even if it is not empty at the beginning.
13881 *
13882 * For example:
13883 *
13884 * $ echo "small" > small.txt
13885 * $ echo "large" > large.txt
13886 * $ ./glark.rb small.txt large.txt
13887 *
13888 * ARGF.read #=> "small\nlarge"
13889 * ARGF.read(200) #=> "small\nlarge"
13890 * ARGF.read(2) #=> "sm"
13891 * ARGF.read(0) #=> ""
13892 *
13893 * Note that this method behaves like the fread() function in C.
13894 * This means it retries to invoke read(2) system calls to read data
13895 * with the specified length.
13896 * If you need the behavior like a single read(2) system call,
13897 * consider ARGF#readpartial or ARGF#read_nonblock.
13898 */
13899
13900static VALUE
13901argf_read(int argc, VALUE *argv, VALUE argf)
13902{
13903 VALUE tmp, str, length;
13904 long len = 0;
13905
13906 rb_scan_args(argc, argv, "02", &length, &str);
13907 if (!NIL_P(length)) {
13908 len = NUM2LONG(argv[0]);
13909 }
13910 if (!NIL_P(str)) {
13911 StringValue(str);
13912 rb_str_resize(str,0);
13913 argv[1] = Qnil;
13914 }
13915
13916 retry:
13917 if (!next_argv()) {
13918 return str;
13919 }
13920 if (ARGF_GENERIC_INPUT_P()) {
13921 tmp = argf_forward(argc, argv, argf);
13922 }
13923 else {
13924 tmp = io_read(argc, argv, ARGF.current_file);
13925 }
13926 if (NIL_P(str)) str = tmp;
13927 else if (!NIL_P(tmp)) rb_str_append(str, tmp);
13928 if (NIL_P(tmp) || NIL_P(length)) {
13929 if (ARGF.next_p != -1) {
13930 argf_close(argf);
13931 ARGF.next_p = 1;
13932 goto retry;
13933 }
13934 }
13935 else if (argc >= 1) {
13936 long slen = RSTRING_LEN(str);
13937 if (slen < len) {
13938 argv[0] = LONG2NUM(len - slen);
13939 goto retry;
13940 }
13941 }
13942 return str;
13943}
13944
13946 int argc;
13947 VALUE *argv;
13948 VALUE argf;
13949};
13950
13951static VALUE
13952argf_forward_call(VALUE arg)
13953{
13954 struct argf_call_arg *p = (struct argf_call_arg *)arg;
13955 argf_forward(p->argc, p->argv, p->argf);
13956 return Qnil;
13957}
13958
13959static VALUE argf_getpartial(int argc, VALUE *argv, VALUE argf, VALUE opts,
13960 int nonblock);
13961
13962/*
13963 * call-seq:
13964 * ARGF.readpartial(maxlen) -> string
13965 * ARGF.readpartial(maxlen, outbuf) -> outbuf
13966 *
13967 * Reads at most _maxlen_ bytes from the ARGF stream.
13968 *
13969 * If the optional _outbuf_ argument is present,
13970 * it must reference a String, which will receive the data.
13971 * The _outbuf_ will contain only the received data after the method call
13972 * even if it is not empty at the beginning.
13973 *
13974 * It raises EOFError on end of ARGF stream.
13975 * Since ARGF stream is a concatenation of multiple files,
13976 * internally EOF is occur for each file.
13977 * ARGF.readpartial returns empty strings for EOFs except the last one and
13978 * raises EOFError for the last one.
13979 *
13980 */
13981
13982static VALUE
13983argf_readpartial(int argc, VALUE *argv, VALUE argf)
13984{
13985 return argf_getpartial(argc, argv, argf, Qnil, 0);
13986}
13987
13988/*
13989 * call-seq:
13990 * ARGF.read_nonblock(maxlen[, options]) -> string
13991 * ARGF.read_nonblock(maxlen, outbuf[, options]) -> outbuf
13992 *
13993 * Reads at most _maxlen_ bytes from the ARGF stream in non-blocking mode.
13994 */
13995
13996static VALUE
13997argf_read_nonblock(int argc, VALUE *argv, VALUE argf)
13998{
13999 VALUE opts;
14000
14001 rb_scan_args(argc, argv, "11:", NULL, NULL, &opts);
14002
14003 if (!NIL_P(opts))
14004 argc--;
14005
14006 return argf_getpartial(argc, argv, argf, opts, 1);
14007}
14008
14009static VALUE
14010argf_getpartial(int argc, VALUE *argv, VALUE argf, VALUE opts, int nonblock)
14011{
14012 VALUE tmp, str, length;
14013 int no_exception;
14014
14015 rb_scan_args(argc, argv, "11", &length, &str);
14016 if (!NIL_P(str)) {
14017 StringValue(str);
14018 argv[1] = str;
14019 }
14020 no_exception = no_exception_p(opts);
14021
14022 if (!next_argv()) {
14023 if (!NIL_P(str)) {
14024 rb_str_resize(str, 0);
14025 }
14026 rb_eof_error();
14027 }
14028 if (ARGF_GENERIC_INPUT_P()) {
14029 VALUE (*const rescue_does_nothing)(VALUE, VALUE) = 0;
14030 struct argf_call_arg arg;
14031 arg.argc = argc;
14032 arg.argv = argv;
14033 arg.argf = argf;
14034 tmp = rb_rescue2(argf_forward_call, (VALUE)&arg,
14035 rescue_does_nothing, Qnil, rb_eEOFError, (VALUE)0);
14036 }
14037 else {
14038 tmp = io_getpartial(argc, argv, ARGF.current_file, no_exception, nonblock);
14039 }
14040 if (NIL_P(tmp)) {
14041 if (ARGF.next_p == -1) {
14042 return io_nonblock_eof(no_exception);
14043 }
14044 argf_close(argf);
14045 ARGF.next_p = 1;
14046 if (RARRAY_LEN(ARGF.argv) == 0) {
14047 return io_nonblock_eof(no_exception);
14048 }
14049 if (NIL_P(str))
14050 str = rb_str_new(NULL, 0);
14051 return str;
14052 }
14053 return tmp;
14054}
14055
14056/*
14057 * call-seq:
14058 * ARGF.getc -> String or nil
14059 *
14060 * Reads the next character from ARGF and returns it as a String. Returns
14061 * +nil+ at the end of the stream.
14062 *
14063 * ARGF treats the files named on the command line as a single file created
14064 * by concatenating their contents. After returning the last character of the
14065 * first file, it returns the first character of the second file, and so on.
14066 *
14067 * For example:
14068 *
14069 * $ echo "foo" > file
14070 * $ ruby argf.rb file
14071 *
14072 * ARGF.getc #=> "f"
14073 * ARGF.getc #=> "o"
14074 * ARGF.getc #=> "o"
14075 * ARGF.getc #=> "\n"
14076 * ARGF.getc #=> nil
14077 * ARGF.getc #=> nil
14078 */
14079static VALUE
14080argf_getc(VALUE argf)
14081{
14082 VALUE ch;
14083
14084 retry:
14085 if (!next_argv()) return Qnil;
14086 if (ARGF_GENERIC_INPUT_P()) {
14087 ch = forward_current(rb_intern("getc"), 0, 0);
14088 }
14089 else {
14090 ch = rb_io_getc(ARGF.current_file);
14091 }
14092 if (NIL_P(ch) && ARGF.next_p != -1) {
14093 argf_close(argf);
14094 ARGF.next_p = 1;
14095 goto retry;
14096 }
14097
14098 return ch;
14099}
14100
14101/*
14102 * call-seq:
14103 * ARGF.getbyte -> Integer or nil
14104 *
14105 * Gets the next 8-bit byte (0..255) from ARGF. Returns +nil+ if called at
14106 * the end of the stream.
14107 *
14108 * For example:
14109 *
14110 * $ echo "foo" > file
14111 * $ ruby argf.rb file
14112 *
14113 * ARGF.getbyte #=> 102
14114 * ARGF.getbyte #=> 111
14115 * ARGF.getbyte #=> 111
14116 * ARGF.getbyte #=> 10
14117 * ARGF.getbyte #=> nil
14118 */
14119static VALUE
14120argf_getbyte(VALUE argf)
14121{
14122 VALUE ch;
14123
14124 retry:
14125 if (!next_argv()) return Qnil;
14126 if (!RB_TYPE_P(ARGF.current_file, T_FILE)) {
14127 ch = forward_current(rb_intern("getbyte"), 0, 0);
14128 }
14129 else {
14130 ch = rb_io_getbyte(ARGF.current_file);
14131 }
14132 if (NIL_P(ch) && ARGF.next_p != -1) {
14133 argf_close(argf);
14134 ARGF.next_p = 1;
14135 goto retry;
14136 }
14137
14138 return ch;
14139}
14140
14141/*
14142 * call-seq:
14143 * ARGF.readchar -> String or nil
14144 *
14145 * Reads the next character from ARGF and returns it as a String. Raises
14146 * an EOFError after the last character of the last file has been read.
14147 *
14148 * For example:
14149 *
14150 * $ echo "foo" > file
14151 * $ ruby argf.rb file
14152 *
14153 * ARGF.readchar #=> "f"
14154 * ARGF.readchar #=> "o"
14155 * ARGF.readchar #=> "o"
14156 * ARGF.readchar #=> "\n"
14157 * ARGF.readchar #=> end of file reached (EOFError)
14158 */
14159static VALUE
14160argf_readchar(VALUE argf)
14161{
14162 VALUE ch;
14163
14164 retry:
14165 if (!next_argv()) rb_eof_error();
14166 if (!RB_TYPE_P(ARGF.current_file, T_FILE)) {
14167 ch = forward_current(rb_intern("getc"), 0, 0);
14168 }
14169 else {
14170 ch = rb_io_getc(ARGF.current_file);
14171 }
14172 if (NIL_P(ch) && ARGF.next_p != -1) {
14173 argf_close(argf);
14174 ARGF.next_p = 1;
14175 goto retry;
14176 }
14177
14178 return ch;
14179}
14180
14181/*
14182 * call-seq:
14183 * ARGF.readbyte -> Integer
14184 *
14185 * Reads the next 8-bit byte from ARGF and returns it as an Integer. Raises
14186 * an EOFError after the last byte of the last file has been read.
14187 *
14188 * For example:
14189 *
14190 * $ echo "foo" > file
14191 * $ ruby argf.rb file
14192 *
14193 * ARGF.readbyte #=> 102
14194 * ARGF.readbyte #=> 111
14195 * ARGF.readbyte #=> 111
14196 * ARGF.readbyte #=> 10
14197 * ARGF.readbyte #=> end of file reached (EOFError)
14198 */
14199static VALUE
14200argf_readbyte(VALUE argf)
14201{
14202 VALUE c;
14203
14204 NEXT_ARGF_FORWARD(0, 0);
14205 c = argf_getbyte(argf);
14206 if (NIL_P(c)) {
14207 rb_eof_error();
14208 }
14209 return c;
14210}
14211
14212#define FOREACH_ARGF() while (next_argv())
14213
14214static VALUE
14215argf_block_call_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, argf))
14216{
14217 const VALUE current = ARGF.current_file;
14218 rb_yield_values2(argc, argv);
14219 if (ARGF.init_p == -1 || current != ARGF.current_file) {
14221 }
14222 return Qnil;
14223}
14224
14225#define ARGF_block_call(mid, argc, argv, func, argf) \
14226 rb_block_call_kw(ARGF.current_file, mid, argc, argv, \
14227 func, argf, rb_keyword_given_p())
14228
14229static void
14230argf_block_call(ID mid, int argc, VALUE *argv, VALUE argf)
14231{
14232 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_i, argf);
14233 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14234}
14235
14236static VALUE
14237argf_block_call_line_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, argf))
14238{
14239 if (!global_argf_p(argf)) {
14240 ARGF.last_lineno = ++ARGF.lineno;
14241 }
14242 return argf_block_call_i(i, argf, argc, argv, blockarg);
14243}
14244
14245static void
14246argf_block_call_line(ID mid, int argc, VALUE *argv, VALUE argf)
14247{
14248 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_line_i, argf);
14249 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14250}
14251
14252/*
14253 * call-seq:
14254 * ARGF.each(sep=$/) {|line| block } -> ARGF
14255 * ARGF.each(sep=$/, limit) {|line| block } -> ARGF
14256 * ARGF.each(...) -> an_enumerator
14257 *
14258 * ARGF.each_line(sep=$/) {|line| block } -> ARGF
14259 * ARGF.each_line(sep=$/, limit) {|line| block } -> ARGF
14260 * ARGF.each_line(...) -> an_enumerator
14261 *
14262 * Returns an enumerator which iterates over each line (separated by _sep_,
14263 * which defaults to your platform's newline character) of each file in
14264 * +ARGV+. If a block is supplied, each line in turn will be yielded to the
14265 * block, otherwise an enumerator is returned.
14266 * The optional _limit_ argument is an Integer specifying the maximum
14267 * length of each line; longer lines will be split according to this limit.
14268 *
14269 * This method allows you to treat the files supplied on the command line as
14270 * a single file consisting of the concatenation of each named file. After
14271 * the last line of the first file has been returned, the first line of the
14272 * second file is returned. The ARGF.filename and ARGF.lineno methods can be
14273 * used to determine the filename of the current line and line number of the
14274 * whole input, respectively.
14275 *
14276 * For example, the following code prints out each line of each named file
14277 * prefixed with its line number, displaying the filename once per file:
14278 *
14279 * ARGF.each_line do |line|
14280 * puts ARGF.filename if ARGF.file.lineno == 1
14281 * puts "#{ARGF.file.lineno}: #{line}"
14282 * end
14283 *
14284 * While the following code prints only the first file's name at first, and
14285 * the contents with line number counted through all named files.
14286 *
14287 * ARGF.each_line do |line|
14288 * puts ARGF.filename if ARGF.lineno == 1
14289 * puts "#{ARGF.lineno}: #{line}"
14290 * end
14291 */
14292static VALUE
14293argf_each_line(int argc, VALUE *argv, VALUE argf)
14294{
14295 RETURN_ENUMERATOR(argf, argc, argv);
14296 FOREACH_ARGF() {
14297 argf_block_call_line(rb_intern("each_line"), argc, argv, argf);
14298 }
14299 return argf;
14300}
14301
14302/*
14303 * call-seq:
14304 * ARGF.each_byte {|byte| block } -> ARGF
14305 * ARGF.each_byte -> an_enumerator
14306 *
14307 * Iterates over each byte of each file in +ARGV+.
14308 * A byte is returned as an Integer in the range 0..255.
14309 *
14310 * This method allows you to treat the files supplied on the command line as
14311 * a single file consisting of the concatenation of each named file. After
14312 * the last byte of the first file has been returned, the first byte of the
14313 * second file is returned. The ARGF.filename method can be used to
14314 * determine the filename of the current byte.
14315 *
14316 * If no block is given, an enumerator is returned instead.
14317 *
14318 * For example:
14319 *
14320 * ARGF.bytes.to_a #=> [35, 32, ... 95, 10]
14321 *
14322 */
14323static VALUE
14324argf_each_byte(VALUE argf)
14325{
14326 RETURN_ENUMERATOR(argf, 0, 0);
14327 FOREACH_ARGF() {
14328 argf_block_call(rb_intern("each_byte"), 0, 0, argf);
14329 }
14330 return argf;
14331}
14332
14333/*
14334 * call-seq:
14335 * ARGF.each_char {|char| block } -> ARGF
14336 * ARGF.each_char -> an_enumerator
14337 *
14338 * Iterates over each character of each file in ARGF.
14339 *
14340 * This method allows you to treat the files supplied on the command line as
14341 * a single file consisting of the concatenation of each named file. After
14342 * the last character of the first file has been returned, the first
14343 * character of the second file is returned. The ARGF.filename method can
14344 * be used to determine the name of the file in which the current character
14345 * appears.
14346 *
14347 * If no block is given, an enumerator is returned instead.
14348 */
14349static VALUE
14350argf_each_char(VALUE argf)
14351{
14352 RETURN_ENUMERATOR(argf, 0, 0);
14353 FOREACH_ARGF() {
14354 argf_block_call(rb_intern("each_char"), 0, 0, argf);
14355 }
14356 return argf;
14357}
14358
14359/*
14360 * call-seq:
14361 * ARGF.each_codepoint {|codepoint| block } -> ARGF
14362 * ARGF.each_codepoint -> an_enumerator
14363 *
14364 * Iterates over each codepoint of each file in ARGF.
14365 *
14366 * This method allows you to treat the files supplied on the command line as
14367 * a single file consisting of the concatenation of each named file. After
14368 * the last codepoint of the first file has been returned, the first
14369 * codepoint of the second file is returned. The ARGF.filename method can
14370 * be used to determine the name of the file in which the current codepoint
14371 * appears.
14372 *
14373 * If no block is given, an enumerator is returned instead.
14374 */
14375static VALUE
14376argf_each_codepoint(VALUE argf)
14377{
14378 RETURN_ENUMERATOR(argf, 0, 0);
14379 FOREACH_ARGF() {
14380 argf_block_call(rb_intern("each_codepoint"), 0, 0, argf);
14381 }
14382 return argf;
14383}
14384
14385/*
14386 * call-seq:
14387 * ARGF.filename -> String
14388 * ARGF.path -> String
14389 *
14390 * Returns the current filename. "-" is returned when the current file is
14391 * STDIN.
14392 *
14393 * For example:
14394 *
14395 * $ echo "foo" > foo
14396 * $ echo "bar" > bar
14397 * $ echo "glark" > glark
14398 *
14399 * $ ruby argf.rb foo bar glark
14400 *
14401 * ARGF.filename #=> "foo"
14402 * ARGF.read(5) #=> "foo\nb"
14403 * ARGF.filename #=> "bar"
14404 * ARGF.skip
14405 * ARGF.filename #=> "glark"
14406 */
14407static VALUE
14408argf_filename(VALUE argf)
14409{
14410 next_argv();
14411 return ARGF.filename;
14412}
14413
14414static VALUE
14415argf_filename_getter(ID id, VALUE *var)
14416{
14417 return argf_filename(*var);
14418}
14419
14420/*
14421 * call-seq:
14422 * ARGF.file -> IO or File object
14423 *
14424 * Returns the current file as an IO or File object.
14425 * <code>$stdin</code> is returned when the current file is STDIN.
14426 *
14427 * For example:
14428 *
14429 * $ echo "foo" > foo
14430 * $ echo "bar" > bar
14431 *
14432 * $ ruby argf.rb foo bar
14433 *
14434 * ARGF.file #=> #<File:foo>
14435 * ARGF.read(5) #=> "foo\nb"
14436 * ARGF.file #=> #<File:bar>
14437 */
14438static VALUE
14439argf_file(VALUE argf)
14440{
14441 next_argv();
14442 return ARGF.current_file;
14443}
14444
14445/*
14446 * call-seq:
14447 * ARGF.binmode -> ARGF
14448 *
14449 * Puts ARGF into binary mode. Once a stream is in binary mode, it cannot
14450 * be reset to non-binary mode. This option has the following effects:
14451 *
14452 * * Newline conversion is disabled.
14453 * * Encoding conversion is disabled.
14454 * * Content is treated as ASCII-8BIT.
14455 */
14456static VALUE
14457argf_binmode_m(VALUE argf)
14458{
14459 ARGF.binmode = 1;
14460 next_argv();
14461 ARGF_FORWARD(0, 0);
14462 rb_io_ascii8bit_binmode(ARGF.current_file);
14463 return argf;
14464}
14465
14466/*
14467 * call-seq:
14468 * ARGF.binmode? -> true or false
14469 *
14470 * Returns true if ARGF is being read in binary mode; false otherwise.
14471 * To enable binary mode use ARGF.binmode.
14472 *
14473 * For example:
14474 *
14475 * ARGF.binmode? #=> false
14476 * ARGF.binmode
14477 * ARGF.binmode? #=> true
14478 */
14479static VALUE
14480argf_binmode_p(VALUE argf)
14481{
14482 return RBOOL(ARGF.binmode);
14483}
14484
14485/*
14486 * call-seq:
14487 * ARGF.skip -> ARGF
14488 *
14489 * Sets the current file to the next file in ARGV. If there aren't any more
14490 * files it has no effect.
14491 *
14492 * For example:
14493 *
14494 * $ ruby argf.rb foo bar
14495 * ARGF.filename #=> "foo"
14496 * ARGF.skip
14497 * ARGF.filename #=> "bar"
14498 */
14499static VALUE
14500argf_skip(VALUE argf)
14501{
14502 if (ARGF.init_p && ARGF.next_p == 0) {
14503 argf_close(argf);
14504 ARGF.next_p = 1;
14505 }
14506 return argf;
14507}
14508
14509/*
14510 * call-seq:
14511 * ARGF.close -> ARGF
14512 *
14513 * Closes the current file and skips to the next file in ARGV. If there are
14514 * no more files to open, just closes the current file. STDIN will not be
14515 * closed.
14516 *
14517 * For example:
14518 *
14519 * $ ruby argf.rb foo bar
14520 *
14521 * ARGF.filename #=> "foo"
14522 * ARGF.close
14523 * ARGF.filename #=> "bar"
14524 * ARGF.close
14525 */
14526static VALUE
14527argf_close_m(VALUE argf)
14528{
14529 next_argv();
14530 argf_close(argf);
14531 if (ARGF.next_p != -1) {
14532 ARGF.next_p = 1;
14533 }
14534 ARGF.lineno = 0;
14535 return argf;
14536}
14537
14538/*
14539 * call-seq:
14540 * ARGF.closed? -> true or false
14541 *
14542 * Returns _true_ if the current file has been closed; _false_ otherwise. Use
14543 * ARGF.close to actually close the current file.
14544 */
14545static VALUE
14546argf_closed(VALUE argf)
14547{
14548 next_argv();
14549 ARGF_FORWARD(0, 0);
14550 return rb_io_closed_p(ARGF.current_file);
14551}
14552
14553/*
14554 * call-seq:
14555 * ARGF.to_s -> String
14556 *
14557 * Returns "ARGF".
14558 */
14559static VALUE
14560argf_to_s(VALUE argf)
14561{
14562 return rb_str_new2("ARGF");
14563}
14564
14565/*
14566 * call-seq:
14567 * ARGF.inplace_mode -> String
14568 *
14569 * Returns the file extension appended to the names of backup copies of
14570 * modified files under in-place edit mode. This value can be set using
14571 * ARGF.inplace_mode= or passing the +-i+ switch to the Ruby binary.
14572 */
14573static VALUE
14574argf_inplace_mode_get(VALUE argf)
14575{
14576 if (!ARGF.inplace) return Qnil;
14577 if (NIL_P(ARGF.inplace)) return rb_str_new(0, 0);
14578 return rb_str_dup(ARGF.inplace);
14579}
14580
14581static VALUE
14582opt_i_get(ID id, VALUE *var)
14583{
14584 return argf_inplace_mode_get(*var);
14585}
14586
14587/*
14588 * call-seq:
14589 * ARGF.inplace_mode = ext -> ARGF
14590 *
14591 * Sets the filename extension for in-place editing mode to the given String.
14592 * The backup copy of each file being edited has this value appended to its
14593 * filename.
14594 *
14595 * For example:
14596 *
14597 * $ ruby argf.rb file.txt
14598 *
14599 * ARGF.inplace_mode = '.bak'
14600 * ARGF.each_line do |line|
14601 * print line.sub("foo","bar")
14602 * end
14603 *
14604 * First, _file.txt.bak_ is created as a backup copy of _file.txt_.
14605 * Then, each line of _file.txt_ has the first occurrence of "foo" replaced with
14606 * "bar".
14607 */
14608static VALUE
14609argf_inplace_mode_set(VALUE argf, VALUE val)
14610{
14611 if (!RTEST(val)) {
14612 ARGF.inplace = Qfalse;
14613 }
14614 else if (StringValueCStr(val), !RSTRING_LEN(val)) {
14615 ARGF.inplace = Qnil;
14616 }
14617 else {
14618 ARGF.inplace = rb_str_new_frozen(val);
14619 }
14620 return argf;
14621}
14622
14623static void
14624opt_i_set(VALUE val, ID id, VALUE *var)
14625{
14626 argf_inplace_mode_set(*var, val);
14627}
14628
14629void
14630ruby_set_inplace_mode(const char *suffix)
14631{
14632 ARGF.inplace = !suffix ? Qfalse : !*suffix ? Qnil : rb_str_new(suffix, strlen(suffix));
14633}
14634
14635/*
14636 * call-seq:
14637 * ARGF.argv -> ARGV
14638 *
14639 * Returns the +ARGV+ array, which contains the arguments passed to your
14640 * script, one per element.
14641 *
14642 * For example:
14643 *
14644 * $ ruby argf.rb -v glark.txt
14645 *
14646 * ARGF.argv #=> ["-v", "glark.txt"]
14647 *
14648 */
14649static VALUE
14650argf_argv(VALUE argf)
14651{
14652 return ARGF.argv;
14653}
14654
14655static VALUE
14656argf_argv_getter(ID id, VALUE *var)
14657{
14658 return argf_argv(*var);
14659}
14660
14661VALUE
14663{
14664 return ARGF.argv;
14665}
14666
14667/*
14668 * call-seq:
14669 * ARGF.to_write_io -> io
14670 *
14671 * Returns IO instance tied to _ARGF_ for writing if inplace mode is
14672 * enabled.
14673 */
14674static VALUE
14675argf_write_io(VALUE argf)
14676{
14677 if (!RTEST(ARGF.current_file)) {
14678 rb_raise(rb_eIOError, "not opened for writing");
14679 }
14680 return GetWriteIO(ARGF.current_file);
14681}
14682
14683/*
14684 * call-seq:
14685 * ARGF.write(*objects) -> integer
14686 *
14687 * Writes each of the given +objects+ if inplace mode.
14688 */
14689static VALUE
14690argf_write(int argc, VALUE *argv, VALUE argf)
14691{
14692 return rb_io_writev(argf_write_io(argf), argc, argv);
14693}
14694
14695void
14696rb_readwrite_sys_fail(enum rb_io_wait_readwrite waiting, const char *mesg)
14697{
14698 rb_readwrite_syserr_fail(waiting, errno, mesg);
14699}
14700
14701void
14702rb_readwrite_syserr_fail(enum rb_io_wait_readwrite waiting, int n, const char *mesg)
14703{
14704 VALUE arg, c = Qnil;
14705 arg = mesg ? rb_str_new2(mesg) : Qnil;
14706 switch (waiting) {
14707 case RB_IO_WAIT_WRITABLE:
14708 switch (n) {
14709 case EAGAIN:
14710 c = rb_eEAGAINWaitWritable;
14711 break;
14712#if EAGAIN != EWOULDBLOCK
14713 case EWOULDBLOCK:
14714 c = rb_eEWOULDBLOCKWaitWritable;
14715 break;
14716#endif
14717 case EINPROGRESS:
14718 c = rb_eEINPROGRESSWaitWritable;
14719 break;
14720 default:
14722 }
14723 break;
14724 case RB_IO_WAIT_READABLE:
14725 switch (n) {
14726 case EAGAIN:
14727 c = rb_eEAGAINWaitReadable;
14728 break;
14729#if EAGAIN != EWOULDBLOCK
14730 case EWOULDBLOCK:
14731 c = rb_eEWOULDBLOCKWaitReadable;
14732 break;
14733#endif
14734 case EINPROGRESS:
14735 c = rb_eEINPROGRESSWaitReadable;
14736 break;
14737 default:
14739 }
14740 break;
14741 default:
14742 rb_bug("invalid read/write type passed to rb_readwrite_sys_fail: %d", waiting);
14743 }
14745}
14746
14747static VALUE
14748get_LAST_READ_LINE(ID _x, VALUE *_y)
14749{
14750 return rb_lastline_get();
14751}
14752
14753static void
14754set_LAST_READ_LINE(VALUE val, ID _x, VALUE *_y)
14755{
14756 rb_lastline_set(val);
14757}
14758
14759/*
14760 * Document-class: IOError
14761 *
14762 * Raised when an IO operation fails.
14763 *
14764 * File.open("/etc/hosts") {|f| f << "example"}
14765 * #=> IOError: not opened for writing
14766 *
14767 * File.open("/etc/hosts") {|f| f.close; f.read }
14768 * #=> IOError: closed stream
14769 *
14770 * Note that some IO failures raise <code>SystemCallError</code>s
14771 * and these are not subclasses of IOError:
14772 *
14773 * File.open("does/not/exist")
14774 * #=> Errno::ENOENT: No such file or directory - does/not/exist
14775 */
14776
14777/*
14778 * Document-class: EOFError
14779 *
14780 * Raised by some IO operations when reaching the end of file. Many IO
14781 * methods exist in two forms,
14782 *
14783 * one that returns +nil+ when the end of file is reached, the other
14784 * raises EOFError.
14785 *
14786 * EOFError is a subclass of IOError.
14787 *
14788 * file = File.open("/etc/hosts")
14789 * file.read
14790 * file.gets #=> nil
14791 * file.readline #=> EOFError: end of file reached
14792 * file.close
14793 */
14794
14795/*
14796 * Document-class: ARGF
14797 *
14798 * == \ARGF and +ARGV+
14799 *
14800 * The \ARGF object works with the array at global variable +ARGV+
14801 * to make <tt>$stdin</tt> and file streams available in the Ruby program:
14802 *
14803 * - **ARGV** may be thought of as the <b>argument vector</b> array.
14804 *
14805 * Initially, it contains the command-line arguments and options
14806 * that are passed to the Ruby program;
14807 * the program can modify that array as it likes.
14808 *
14809 * - **ARGF** may be thought of as the <b>argument files</b> object.
14810 *
14811 * It can access file streams and/or the <tt>$stdin</tt> stream,
14812 * based on what it finds in +ARGV+.
14813 * This provides a convenient way for the command line
14814 * to specify streams for a Ruby program to read.
14815 *
14816 * == Reading
14817 *
14818 * \ARGF may read from _source_ streams,
14819 * which at any particular time are determined by the content of +ARGV+.
14820 *
14821 * === Simplest Case
14822 *
14823 * When the <i>very first</i> \ARGF read occurs with an empty +ARGV+ (<tt>[]</tt>),
14824 * the source is <tt>$stdin</tt>:
14825 *
14826 * - \File +t.rb+:
14827 *
14828 * p ['ARGV', ARGV]
14829 * p ['ARGF.read', ARGF.read]
14830 *
14831 * - Commands and outputs
14832 * (see below for the content of files +foo.txt+ and +bar.txt+):
14833 *
14834 * $ echo "Open the pod bay doors, Hal." | ruby t.rb
14835 * ["ARGV", []]
14836 * ["ARGF.read", "Open the pod bay doors, Hal.\n"]
14837 *
14838 * $ cat foo.txt bar.txt | ruby t.rb
14839 * ["ARGV", []]
14840 * ["ARGF.read", "Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"]
14841 *
14842 * === About the Examples
14843 *
14844 * Many examples here assume the existence of files +foo.txt+ and +bar.txt+:
14845 *
14846 * $ cat foo.txt
14847 * Foo 0
14848 * Foo 1
14849 * $ cat bar.txt
14850 * Bar 0
14851 * Bar 1
14852 * Bar 2
14853 * Bar 3
14854 *
14855 * === Sources in +ARGV+
14856 *
14857 * For any \ARGF read _except_ the {simplest case}[rdoc-ref:ARGF@Simplest+Case]
14858 * (that is, _except_ for the <i>very first</i> \ARGF read with an empty +ARGV+),
14859 * the sources are found in +ARGV+.
14860 *
14861 * \ARGF assumes that each element in array +ARGV+ is a potential source,
14862 * and is one of:
14863 *
14864 * - The string path to a file that may be opened as a stream.
14865 * - The character <tt>'-'</tt>, meaning stream <tt>$stdin</tt>.
14866 *
14867 * Each element that is _not_ one of these
14868 * should be removed from +ARGV+ before \ARGF accesses that source.
14869 *
14870 * In the following example:
14871 *
14872 * - Filepaths +foo.txt+ and +bar.txt+ may be retained as potential sources.
14873 * - Options <tt>--xyzzy</tt> and <tt>--mojo</tt> should be removed.
14874 *
14875 * Example:
14876 *
14877 * - \File +t.rb+:
14878 *
14879 * # Print arguments (and options, if any) found on command line.
14880 * p ['ARGV', ARGV]
14881 *
14882 * - Command and output:
14883 *
14884 * $ ruby t.rb --xyzzy --mojo foo.txt bar.txt
14885 * ["ARGV", ["--xyzzy", "--mojo", "foo.txt", "bar.txt"]]
14886 *
14887 * \ARGF's stream access considers the elements of +ARGV+, left to right:
14888 *
14889 * - \File +t.rb+:
14890 *
14891 * p "ARGV: #{ARGV}"
14892 * p "Line: #{ARGF.read}" # Read everything from all specified streams.
14893 *
14894 * - Command and output:
14895 *
14896 * $ ruby t.rb foo.txt bar.txt
14897 * "ARGV: [\"foo.txt\", \"bar.txt\"]"
14898 * "Read: Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"
14899 *
14900 * Because the value at +ARGV+ is an ordinary array,
14901 * you can manipulate it to control which sources \ARGF considers:
14902 *
14903 * - If you remove an element from +ARGV+, \ARGF will not consider the corresponding source.
14904 * - If you add an element to +ARGV+, \ARGF will consider the corresponding source.
14905 *
14906 * Each element in +ARGV+ is removed when its corresponding source is accessed;
14907 * when all sources have been accessed, the array is empty:
14908 *
14909 * - \File +t.rb+:
14910 *
14911 * until ARGV.empty? && ARGF.eof?
14912 * p "ARGV: #{ARGV}"
14913 * p "Line: #{ARGF.readline}" # Read each line from each specified stream.
14914 * end
14915 *
14916 * - Command and output:
14917 *
14918 * $ ruby t.rb foo.txt bar.txt
14919 * "ARGV: [\"foo.txt\", \"bar.txt\"]"
14920 * "Line: Foo 0\n"
14921 * "ARGV: [\"bar.txt\"]"
14922 * "Line: Foo 1\n"
14923 * "ARGV: [\"bar.txt\"]"
14924 * "Line: Bar 0\n"
14925 * "ARGV: []"
14926 * "Line: Bar 1\n"
14927 * "ARGV: []"
14928 * "Line: Bar 2\n"
14929 * "ARGV: []"
14930 * "Line: Bar 3\n"
14931 *
14932 * ==== Filepaths in +ARGV+
14933 *
14934 * The +ARGV+ array may contain filepaths the specify sources for \ARGF reading.
14935 *
14936 * This program prints what it reads from files at the paths specified
14937 * on the command line:
14938 *
14939 * - \File +t.rb+:
14940 *
14941 * p ['ARGV', ARGV]
14942 * # Read and print all content from the specified sources.
14943 * p ['ARGF.read', ARGF.read]
14944 *
14945 * - Command and output:
14946 *
14947 * $ ruby t.rb foo.txt bar.txt
14948 * ["ARGV", [foo.txt, bar.txt]
14949 * ["ARGF.read", "Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"]
14950 *
14951 * ==== Specifying <tt>$stdin</tt> in +ARGV+
14952 *
14953 * To specify stream <tt>$stdin</tt> in +ARGV+, us the character <tt>'-'</tt>:
14954 *
14955 * - \File +t.rb+:
14956 *
14957 * p ['ARGV', ARGV]
14958 * p ['ARGF.read', ARGF.read]
14959 *
14960 * - Command and output:
14961 *
14962 * $ echo "Open the pod bay doors, Hal." | ruby t.rb -
14963 * ["ARGV", ["-"]]
14964 * ["ARGF.read", "Open the pod bay doors, Hal.\n"]
14965 *
14966 * When no character <tt>'-'</tt> is given, stream <tt>$stdin</tt> is ignored
14967 * (exception:
14968 * see {Specifying $stdin in ARGV}[rdoc-ref:ARGF@Specifying+-24stdin+in+ARGV]):
14969 *
14970 * - Command and output:
14971 *
14972 * $ echo "Open the pod bay doors, Hal." | ruby t.rb foo.txt bar.txt
14973 * "ARGV: [\"foo.txt\", \"bar.txt\"]"
14974 * "Read: Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"
14975 *
14976 * ==== Mixtures and Repetitions in +ARGV+
14977 *
14978 * For an \ARGF reader, +ARGV+ may contain any mixture of filepaths
14979 * and character <tt>'-'</tt>, including repetitions.
14980 *
14981 * ==== Modifications to +ARGV+
14982 *
14983 * The running Ruby program may make any modifications to the +ARGV+ array;
14984 * the current value of +ARGV+ affects \ARGF reading.
14985 *
14986 * ==== Empty +ARGV+
14987 *
14988 * For an empty +ARGV+, an \ARGF read method either returns +nil+
14989 * or raises an exception, depending on the specific method.
14990 *
14991 * === More Read Methods
14992 *
14993 * As seen above, method ARGF#read reads the content of all sources
14994 * into a single string.
14995 * Other \ARGF methods provide other ways to access that content;
14996 * these include:
14997 *
14998 * - Byte access: #each_byte, #getbyte, #readbyte.
14999 * - Character access: #each_char, #getc, #readchar.
15000 * - Codepoint access: #each_codepoint.
15001 * - Line access: #each_line, #gets, #readline, #readlines.
15002 * - Source access: #read, #read_nonblock, #readpartial.
15003 *
15004 * === About \Enumerable
15005 *
15006 * \ARGF includes module Enumerable.
15007 * Virtually all methods in \Enumerable call method <tt>#each</tt> in the including class.
15008 *
15009 * <b>Note well</b>: In \ARGF, method #each returns data from the _sources_,
15010 * _not_ from +ARGV+;
15011 * therefore, for example, <tt>ARGF#entries</tt> returns an array of lines from the sources,
15012 * not an array of the strings from +ARGV+:
15013 *
15014 * - \File +t.rb+:
15015 *
15016 * p ['ARGV', ARGV]
15017 * p ['ARGF.entries', ARGF.entries]
15018 *
15019 * - Command and output:
15020 *
15021 * $ ruby t.rb foo.txt bar.txt
15022 * ["ARGV", ["foo.txt", "bar.txt"]]
15023 * ["ARGF.entries", ["Foo 0\n", "Foo 1\n", "Bar 0\n", "Bar 1\n", "Bar 2\n", "Bar 3\n"]]
15024 *
15025 * == Writing
15026 *
15027 * If <i>inplace mode</i> is in effect,
15028 * \ARGF may write to target streams,
15029 * which at any particular time are determined by the content of ARGV.
15030 *
15031 * Methods about inplace mode:
15032 *
15033 * - #inplace_mode
15034 * - #inplace_mode=
15035 * - #to_write_io
15036 *
15037 * Methods for writing:
15038 *
15039 * - #print
15040 * - #printf
15041 * - #putc
15042 * - #puts
15043 * - #write
15044 *
15045 */
15046
15047/*
15048 * An instance of class \IO (commonly called a _stream_)
15049 * represents an input/output stream in the underlying operating system.
15050 * Class \IO is the basis for input and output in Ruby.
15051 *
15052 * Class File is the only class in the Ruby core that is a subclass of \IO.
15053 * Some classes in the Ruby standard library are also subclasses of \IO;
15054 * these include TCPSocket and UDPSocket.
15055 *
15056 * The global constant ARGF (also accessible as <tt>$<</tt>)
15057 * provides an IO-like stream that allows access to all file paths
15058 * found in ARGV (or found in STDIN if ARGV is empty).
15059 * ARGF is not itself a subclass of \IO.
15060 *
15061 * Class StringIO provides an IO-like stream that handles a String.
15062 * StringIO is not itself a subclass of \IO.
15063 *
15064 * Important objects based on \IO include:
15065 *
15066 * - $stdin.
15067 * - $stdout.
15068 * - $stderr.
15069 * - Instances of class File.
15070 *
15071 * An instance of \IO may be created using:
15072 *
15073 * - IO.new: returns a new \IO object for the given integer file descriptor.
15074 * - IO.open: passes a new \IO object to the given block.
15075 * - IO.popen: returns a new \IO object that is connected to the $stdin and $stdout
15076 * of a newly-launched subprocess.
15077 * - Kernel#open: Returns a new \IO object connected to a given source:
15078 * stream, file, or subprocess.
15079 *
15080 * Like a File stream, an \IO stream has:
15081 *
15082 * - A read/write mode, which may be read-only, write-only, or read/write;
15083 * see {Read/Write Mode}[rdoc-ref:File@Read-2FWrite+Mode].
15084 * - A data mode, which may be text-only or binary;
15085 * see {Data Mode}[rdoc-ref:File@Data+Mode].
15086 * - Internal and external encodings;
15087 * see {Encodings}[rdoc-ref:File@Encodings].
15088 *
15089 * And like other \IO streams, it has:
15090 *
15091 * - A position, which determines where in the stream the next
15092 * read or write is to occur;
15093 * see {Position}[rdoc-ref:IO@Position].
15094 * - A line number, which is a special, line-oriented, "position"
15095 * (different from the position mentioned above);
15096 * see {Line Number}[rdoc-ref:IO@Line+Number].
15097 *
15098 * == Extension <tt>io/console</tt>
15099 *
15100 * Extension <tt>io/console</tt> provides numerous methods
15101 * for interacting with the console;
15102 * requiring it adds numerous methods to class \IO.
15103 *
15104 * == Example Files
15105 *
15106 * Many examples here use these variables:
15107 *
15108 * :include: doc/examples/files.rdoc
15109 *
15110 * == Open Options
15111 *
15112 * A number of \IO methods accept optional keyword arguments
15113 * that determine how a new stream is to be opened:
15114 *
15115 * - +:mode+: Stream mode.
15116 * - +:flags+: Integer file open flags;
15117 * If +mode+ is also given, the two are bitwise-ORed.
15118 * - +:external_encoding+: External encoding for the stream.
15119 * - +:internal_encoding+: Internal encoding for the stream.
15120 * <tt>'-'</tt> is a synonym for the default internal encoding.
15121 * If the value is +nil+ no conversion occurs.
15122 * - +:encoding+: Specifies external and internal encodings as <tt>'extern:intern'</tt>.
15123 * - +:textmode+: If a truthy value, specifies the mode as text-only, binary otherwise.
15124 * - +:binmode+: If a truthy value, specifies the mode as binary, text-only otherwise.
15125 * - +:autoclose+: If a truthy value, specifies that the +fd+ will close
15126 * when the stream closes; otherwise it remains open.
15127 * - +:path:+ If a string value is provided, it is used in #inspect and is available as
15128 * #path method.
15129 *
15130 * Also available are the options offered in String#encode,
15131 * which may control conversion between external and internal encoding.
15132 *
15133 * == Basic \IO
15134 *
15135 * You can perform basic stream \IO with these methods,
15136 * which typically operate on multi-byte strings:
15137 *
15138 * - IO#read: Reads and returns some or all of the remaining bytes from the stream.
15139 * - IO#write: Writes zero or more strings to the stream;
15140 * each given object that is not already a string is converted via +to_s+.
15141 *
15142 * === Position
15143 *
15144 * An \IO stream has a nonnegative integer _position_,
15145 * which is the byte offset at which the next read or write is to occur.
15146 * A new stream has position zero (and line number zero);
15147 * method +rewind+ resets the position (and line number) to zero.
15148 *
15149 * These methods discard {buffers}[rdoc-ref:IO@Buffering] and the
15150 * Encoding::Converter instances used for that \IO.
15151 *
15152 * The relevant methods:
15153 *
15154 * - IO#tell (aliased as +#pos+): Returns the current position (in bytes) in the stream.
15155 * - IO#pos=: Sets the position of the stream to a given integer +new_position+ (in bytes).
15156 * - IO#seek: Sets the position of the stream to a given integer +offset+ (in bytes),
15157 * relative to a given position +whence+
15158 * (indicating the beginning, end, or current position).
15159 * - IO#rewind: Positions the stream at the beginning (also resetting the line number).
15160 *
15161 * === Open and Closed Streams
15162 *
15163 * A new \IO stream may be open for reading, open for writing, or both.
15164 *
15165 * A stream is automatically closed when claimed by the garbage collector.
15166 *
15167 * Attempted reading or writing on a closed stream raises an exception.
15168 *
15169 * The relevant methods:
15170 *
15171 * - IO#close: Closes the stream for both reading and writing.
15172 * - IO#close_read: Closes the stream for reading.
15173 * - IO#close_write: Closes the stream for writing.
15174 * - IO#closed?: Returns whether the stream is closed.
15175 *
15176 * === End-of-Stream
15177 *
15178 * You can query whether a stream is positioned at its end:
15179 *
15180 * - IO#eof? (also aliased as +#eof+): Returns whether the stream is at end-of-stream.
15181 *
15182 * You can reposition to end-of-stream by using method IO#seek:
15183 *
15184 * f = File.new('t.txt')
15185 * f.eof? # => false
15186 * f.seek(0, :END)
15187 * f.eof? # => true
15188 * f.close
15189 *
15190 * Or by reading all stream content (which is slower than using IO#seek):
15191 *
15192 * f.rewind
15193 * f.eof? # => false
15194 * f.read # => "First line\nSecond line\n\nFourth line\nFifth line\n"
15195 * f.eof? # => true
15196 *
15197 * == Line \IO
15198 *
15199 * Class \IO supports line-oriented
15200 * {input}[rdoc-ref:IO@Line+Input] and {output}[rdoc-ref:IO@Line+Output]
15201 *
15202 * === Line Input
15203 *
15204 * Class \IO supports line-oriented input for
15205 * {files}[rdoc-ref:IO@File+Line+Input] and {IO streams}[rdoc-ref:IO@Stream+Line+Input]
15206 *
15207 * ==== \File Line Input
15208 *
15209 * You can read lines from a file using these methods:
15210 *
15211 * - IO.foreach: Reads each line and passes it to the given block.
15212 * - IO.readlines: Reads and returns all lines in an array.
15213 *
15214 * For each of these methods:
15215 *
15216 * - You can specify {open options}[rdoc-ref:IO@Open+Options].
15217 * - Line parsing depends on the effective <i>line separator</i>;
15218 * see {Line Separator}[rdoc-ref:IO@Line+Separator].
15219 * - The length of each returned line depends on the effective <i>line limit</i>;
15220 * see {Line Limit}[rdoc-ref:IO@Line+Limit].
15221 *
15222 * ==== Stream Line Input
15223 *
15224 * You can read lines from an \IO stream using these methods:
15225 *
15226 * - IO#each_line: Reads each remaining line, passing it to the given block.
15227 * - IO#gets: Returns the next line.
15228 * - IO#readline: Like #gets, but raises an exception at end-of-stream.
15229 * - IO#readlines: Returns all remaining lines in an array.
15230 *
15231 * For each of these methods:
15232 *
15233 * - Reading may begin mid-line,
15234 * depending on the stream's _position_;
15235 * see {Position}[rdoc-ref:IO@Position].
15236 * - Line parsing depends on the effective <i>line separator</i>;
15237 * see {Line Separator}[rdoc-ref:IO@Line+Separator].
15238 * - The length of each returned line depends on the effective <i>line limit</i>;
15239 * see {Line Limit}[rdoc-ref:IO@Line+Limit].
15240 *
15241 * ===== Line Separator
15242 *
15243 * Each of the {line input methods}[rdoc-ref:IO@Line+Input] uses a <i>line separator</i>:
15244 * the string that determines what is considered a line;
15245 * it is sometimes called the <i>input record separator</i>.
15246 *
15247 * The default line separator is taken from global variable <tt>$/</tt>,
15248 * whose initial value is <tt>"\n"</tt>.
15249 *
15250 * Generally, the line to be read next is all data
15251 * from the current {position}[rdoc-ref:IO@Position]
15252 * to the next line separator
15253 * (but see {Special Line Separator Values}[rdoc-ref:IO@Special+Line+Separator+Values]):
15254 *
15255 * f = File.new('t.txt')
15256 * # Method gets with no sep argument returns the next line, according to $/.
15257 * f.gets # => "First line\n"
15258 * f.gets # => "Second line\n"
15259 * f.gets # => "\n"
15260 * f.gets # => "Fourth line\n"
15261 * f.gets # => "Fifth line\n"
15262 * f.close
15263 *
15264 * You can use a different line separator by passing argument +sep+:
15265 *
15266 * f = File.new('t.txt')
15267 * f.gets('l') # => "First l"
15268 * f.gets('li') # => "ine\nSecond li"
15269 * f.gets('lin') # => "ne\n\nFourth lin"
15270 * f.gets # => "e\n"
15271 * f.close
15272 *
15273 * Or by setting global variable <tt>$/</tt>:
15274 *
15275 * f = File.new('t.txt')
15276 * $/ = 'l'
15277 * f.gets # => "First l"
15278 * f.gets # => "ine\nSecond l"
15279 * f.gets # => "ine\n\nFourth l"
15280 * f.close
15281 *
15282 * ===== Special Line Separator Values
15283 *
15284 * Each of the {line input methods}[rdoc-ref:IO@Line+Input]
15285 * accepts two special values for parameter +sep+:
15286 *
15287 * - +nil+: The entire stream is to be read ("slurped") into a single string:
15288 *
15289 * f = File.new('t.txt')
15290 * f.gets(nil) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
15291 * f.close
15292 *
15293 * - <tt>''</tt> (the empty string): The next "paragraph" is to be read
15294 * (paragraphs being separated by two consecutive line separators):
15295 *
15296 * f = File.new('t.txt')
15297 * f.gets('') # => "First line\nSecond line\n\n"
15298 * f.gets('') # => "Fourth line\nFifth line\n"
15299 * f.close
15300 *
15301 * ===== Line Limit
15302 *
15303 * Each of the {line input methods}[rdoc-ref:IO@Line+Input]
15304 * uses an integer <i>line limit</i>,
15305 * which restricts the number of bytes that may be returned.
15306 * (A multi-byte character will not be split, and so a returned line may be slightly longer
15307 * than the limit).
15308 *
15309 * The default limit value is <tt>-1</tt>;
15310 * any negative limit value means that there is no limit.
15311 *
15312 * If there is no limit, the line is determined only by +sep+.
15313 *
15314 * # Text with 1-byte characters.
15315 * File.open('t.txt') {|f| f.gets(1) } # => "F"
15316 * File.open('t.txt') {|f| f.gets(2) } # => "Fi"
15317 * File.open('t.txt') {|f| f.gets(3) } # => "Fir"
15318 * File.open('t.txt') {|f| f.gets(4) } # => "Firs"
15319 * # No more than one line.
15320 * File.open('t.txt') {|f| f.gets(10) } # => "First line"
15321 * File.open('t.txt') {|f| f.gets(11) } # => "First line\n"
15322 * File.open('t.txt') {|f| f.gets(12) } # => "First line\n"
15323 *
15324 * # Text with 2-byte characters, which will not be split.
15325 * File.open('t.rus') {|f| f.gets(1).size } # => 1
15326 * File.open('t.rus') {|f| f.gets(2).size } # => 1
15327 * File.open('t.rus') {|f| f.gets(3).size } # => 2
15328 * File.open('t.rus') {|f| f.gets(4).size } # => 2
15329 *
15330 * ===== Line Separator and Line Limit
15331 *
15332 * With arguments +sep+ and +limit+ given, combines the two behaviors:
15333 *
15334 * - Returns the next line as determined by line separator +sep+.
15335 * - But returns no more bytes than are allowed by the limit +limit+.
15336 *
15337 * Example:
15338 *
15339 * File.open('t.txt') {|f| f.gets('li', 20) } # => "First li"
15340 * File.open('t.txt') {|f| f.gets('li', 2) } # => "Fi"
15341 *
15342 * ===== Line Number
15343 *
15344 * A readable \IO stream has a non-negative integer <i>line number</i>:
15345 *
15346 * - IO#lineno: Returns the line number.
15347 * - IO#lineno=: Resets and returns the line number.
15348 *
15349 * Unless modified by a call to method IO#lineno=,
15350 * the line number is the number of lines read
15351 * by certain line-oriented methods,
15352 * according to the effective {line separator}[rdoc-ref:IO@Line+Separator]:
15353 *
15354 * - IO.foreach: Increments the line number on each call to the block.
15355 * - IO#each_line: Increments the line number on each call to the block.
15356 * - IO#gets: Increments the line number.
15357 * - IO#readline: Increments the line number.
15358 * - IO#readlines: Increments the line number for each line read.
15359 *
15360 * A new stream is initially has line number zero (and position zero);
15361 * method +rewind+ resets the line number (and position) to zero:
15362 *
15363 * f = File.new('t.txt')
15364 * f.lineno # => 0
15365 * f.gets # => "First line\n"
15366 * f.lineno # => 1
15367 * f.rewind
15368 * f.lineno # => 0
15369 * f.close
15370 *
15371 * Reading lines from a stream usually changes its line number:
15372 *
15373 * f = File.new('t.txt', 'r')
15374 * f.lineno # => 0
15375 * f.readline # => "This is line one.\n"
15376 * f.lineno # => 1
15377 * f.readline # => "This is the second line.\n"
15378 * f.lineno # => 2
15379 * f.readline # => "Here's the third line.\n"
15380 * f.lineno # => 3
15381 * f.eof? # => true
15382 * f.close
15383 *
15384 * Iterating over lines in a stream usually changes its line number:
15385 *
15386 * File.open('t.txt') do |f|
15387 * f.each_line do |line|
15388 * p "position=#{f.pos} eof?=#{f.eof?} lineno=#{f.lineno}"
15389 * end
15390 * end
15391 *
15392 * Output:
15393 *
15394 * "position=11 eof?=false lineno=1"
15395 * "position=23 eof?=false lineno=2"
15396 * "position=24 eof?=false lineno=3"
15397 * "position=36 eof?=false lineno=4"
15398 * "position=47 eof?=true lineno=5"
15399 *
15400 * Unlike the stream's {position}[rdoc-ref:IO@Position],
15401 * the line number does not affect where the next read or write will occur:
15402 *
15403 * f = File.new('t.txt')
15404 * f.lineno = 1000
15405 * f.lineno # => 1000
15406 * f.gets # => "First line\n"
15407 * f.lineno # => 1001
15408 * f.close
15409 *
15410 * Associated with the line number is the global variable <tt>$.</tt>:
15411 *
15412 * - When a stream is opened, <tt>$.</tt> is not set;
15413 * its value is left over from previous activity in the process:
15414 *
15415 * $. = 41
15416 * f = File.new('t.txt')
15417 * $. = 41
15418 * # => 41
15419 * f.close
15420 *
15421 * - When a stream is read, <tt>$.</tt> is set to the line number for that stream:
15422 *
15423 * f0 = File.new('t.txt')
15424 * f1 = File.new('t.dat')
15425 * f0.readlines # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
15426 * $. # => 5
15427 * f1.readlines # => ["\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"]
15428 * $. # => 1
15429 * f0.close
15430 * f1.close
15431 *
15432 * - Methods IO#rewind and IO#seek do not affect <tt>$.</tt>:
15433 *
15434 * f = File.new('t.txt')
15435 * f.readlines # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
15436 * $. # => 5
15437 * f.rewind
15438 * f.seek(0, :SET)
15439 * $. # => 5
15440 * f.close
15441 *
15442 * === Line Output
15443 *
15444 * You can write to an \IO stream line-by-line using this method:
15445 *
15446 * - IO#puts: Writes objects to the stream.
15447 *
15448 * == Character \IO
15449 *
15450 * You can process an \IO stream character-by-character using these methods:
15451 *
15452 * - IO#getc: Reads and returns the next character from the stream.
15453 * - IO#readchar: Like #getc, but raises an exception at end-of-stream.
15454 * - IO#ungetc: Pushes back ("unshifts") a character or integer onto the stream.
15455 * - IO#putc: Writes a character to the stream.
15456 * - IO#each_char: Reads each remaining character in the stream,
15457 * passing the character to the given block.
15458 *
15459 * == Byte \IO
15460 *
15461 * You can process an \IO stream byte-by-byte using these methods:
15462 *
15463 * - IO#getbyte: Returns the next 8-bit byte as an integer in range 0..255.
15464 * - IO#readbyte: Like #getbyte, but raises an exception if at end-of-stream.
15465 * - IO#ungetbyte: Pushes back ("unshifts") a byte back onto the stream.
15466 * - IO#each_byte: Reads each remaining byte in the stream,
15467 * passing the byte to the given block.
15468 *
15469 * == Codepoint \IO
15470 *
15471 * You can process an \IO stream codepoint-by-codepoint:
15472 *
15473 * - IO#each_codepoint: Reads each remaining codepoint, passing it to the given block.
15474 *
15475 * == What's Here
15476 *
15477 * First, what's elsewhere. Class \IO:
15478 *
15479 * - Inherits from {class Object}[rdoc-ref:Object@What-27s+Here].
15480 * - Includes {module Enumerable}[rdoc-ref:Enumerable@What-27s+Here],
15481 * which provides dozens of additional methods.
15482 *
15483 * Here, class \IO provides methods that are useful for:
15484 *
15485 * - {Creating}[rdoc-ref:IO@Creating]
15486 * - {Reading}[rdoc-ref:IO@Reading]
15487 * - {Writing}[rdoc-ref:IO@Writing]
15488 * - {Positioning}[rdoc-ref:IO@Positioning]
15489 * - {Iterating}[rdoc-ref:IO@Iterating]
15490 * - {Settings}[rdoc-ref:IO@Settings]
15491 * - {Querying}[rdoc-ref:IO@Querying]
15492 * - {Buffering}[rdoc-ref:IO@Buffering]
15493 * - {Low-Level Access}[rdoc-ref:IO@Low-Level+Access]
15494 * - {Other}[rdoc-ref:IO@Other]
15495 *
15496 * === Creating
15497 *
15498 * - ::new (aliased as ::for_fd): Creates and returns a new \IO object for the given
15499 * integer file descriptor.
15500 * - ::open: Creates a new \IO object.
15501 * - ::pipe: Creates a connected pair of reader and writer \IO objects.
15502 * - ::popen: Creates an \IO object to interact with a subprocess.
15503 * - ::select: Selects which given \IO instances are ready for reading,
15504 * writing, or have pending exceptions.
15505 *
15506 * === Reading
15507 *
15508 * - ::binread: Returns a binary string with all or a subset of bytes
15509 * from the given file.
15510 * - ::read: Returns a string with all or a subset of bytes from the given file.
15511 * - ::readlines: Returns an array of strings, which are the lines from the given file.
15512 * - #getbyte: Returns the next 8-bit byte read from +self+ as an integer.
15513 * - #getc: Returns the next character read from +self+ as a string.
15514 * - #gets: Returns the line read from +self+.
15515 * - #pread: Returns all or the next _n_ bytes read from +self+,
15516 * not updating the receiver's offset.
15517 * - #read: Returns all remaining or the next _n_ bytes read from +self+
15518 * for a given _n_.
15519 * - #read_nonblock: the next _n_ bytes read from +self+ for a given _n_,
15520 * in non-block mode.
15521 * - #readbyte: Returns the next byte read from +self+;
15522 * same as #getbyte, but raises an exception on end-of-stream.
15523 * - #readchar: Returns the next character read from +self+;
15524 * same as #getc, but raises an exception on end-of-stream.
15525 * - #readline: Returns the next line read from +self+;
15526 * same as #getline, but raises an exception of end-of-stream.
15527 * - #readlines: Returns an array of all lines read read from +self+.
15528 * - #readpartial: Returns up to the given number of bytes from +self+.
15529 *
15530 * === Writing
15531 *
15532 * - ::binwrite: Writes the given string to the file at the given filepath,
15533 * in binary mode.
15534 * - ::write: Writes the given string to +self+.
15535 * - #<<: Appends the given string to +self+.
15536 * - #print: Prints last read line or given objects to +self+.
15537 * - #printf: Writes to +self+ based on the given format string and objects.
15538 * - #putc: Writes a character to +self+.
15539 * - #puts: Writes lines to +self+, making sure line ends with a newline.
15540 * - #pwrite: Writes the given string at the given offset,
15541 * not updating the receiver's offset.
15542 * - #write: Writes one or more given strings to +self+.
15543 * - #write_nonblock: Writes one or more given strings to +self+ in non-blocking mode.
15544 *
15545 * === Positioning
15546 *
15547 * - #lineno: Returns the current line number in +self+.
15548 * - #lineno=: Sets the line number is +self+.
15549 * - #pos (aliased as #tell): Returns the current byte offset in +self+.
15550 * - #pos=: Sets the byte offset in +self+.
15551 * - #reopen: Reassociates +self+ with a new or existing \IO stream.
15552 * - #rewind: Positions +self+ to the beginning of input.
15553 * - #seek: Sets the offset for +self+ relative to given position.
15554 *
15555 * === Iterating
15556 *
15557 * - ::foreach: Yields each line of given file to the block.
15558 * - #each (aliased as #each_line): Calls the given block
15559 * with each successive line in +self+.
15560 * - #each_byte: Calls the given block with each successive byte in +self+
15561 * as an integer.
15562 * - #each_char: Calls the given block with each successive character in +self+
15563 * as a string.
15564 * - #each_codepoint: Calls the given block with each successive codepoint in +self+
15565 * as an integer.
15566 *
15567 * === Settings
15568 *
15569 * - #autoclose=: Sets whether +self+ auto-closes.
15570 * - #binmode: Sets +self+ to binary mode.
15571 * - #close: Closes +self+.
15572 * - #close_on_exec=: Sets the close-on-exec flag.
15573 * - #close_read: Closes +self+ for reading.
15574 * - #close_write: Closes +self+ for writing.
15575 * - #set_encoding: Sets the encoding for +self+.
15576 * - #set_encoding_by_bom: Sets the encoding for +self+, based on its
15577 * Unicode byte-order-mark.
15578 * - #sync=: Sets the sync-mode to the given value.
15579 *
15580 * === Querying
15581 *
15582 * - #autoclose?: Returns whether +self+ auto-closes.
15583 * - #binmode?: Returns whether +self+ is in binary mode.
15584 * - #close_on_exec?: Returns the close-on-exec flag for +self+.
15585 * - #closed?: Returns whether +self+ is closed.
15586 * - #eof? (aliased as #eof): Returns whether +self+ is at end-of-stream.
15587 * - #external_encoding: Returns the external encoding object for +self+.
15588 * - #fileno (aliased as #to_i): Returns the integer file descriptor for +self+
15589 * - #internal_encoding: Returns the internal encoding object for +self+.
15590 * - #pid: Returns the process ID of a child process associated with +self+,
15591 * if +self+ was created by ::popen.
15592 * - #stat: Returns the File::Stat object containing status information for +self+.
15593 * - #sync: Returns whether +self+ is in sync-mode.
15594 * - #tty? (aliased as #isatty): Returns whether +self+ is a terminal.
15595 *
15596 * === Buffering
15597 *
15598 * - #fdatasync: Immediately writes all buffered data in +self+ to disk.
15599 * - #flush: Flushes any buffered data within +self+ to the underlying
15600 * operating system.
15601 * - #fsync: Immediately writes all buffered data and attributes in +self+ to disk.
15602 * - #ungetbyte: Prepends buffer for +self+ with given integer byte or string.
15603 * - #ungetc: Prepends buffer for +self+ with given string.
15604 *
15605 * === Low-Level Access
15606 *
15607 * - ::sysopen: Opens the file given by its path,
15608 * returning the integer file descriptor.
15609 * - #advise: Announces the intention to access data from +self+ in a specific way.
15610 * - #fcntl: Passes a low-level command to the file specified
15611 * by the given file descriptor.
15612 * - #ioctl: Passes a low-level command to the device specified
15613 * by the given file descriptor.
15614 * - #sysread: Returns up to the next _n_ bytes read from self using a low-level read.
15615 * - #sysseek: Sets the offset for +self+.
15616 * - #syswrite: Writes the given string to +self+ using a low-level write.
15617 *
15618 * === Other
15619 *
15620 * - ::copy_stream: Copies data from a source to a destination,
15621 * each of which is a filepath or an \IO-like object.
15622 * - ::try_convert: Returns a new \IO object resulting from converting
15623 * the given object.
15624 * - #inspect: Returns the string representation of +self+.
15625 *
15626 */
15627
15628void
15629Init_IO(void)
15630{
15631 VALUE rb_cARGF;
15632#ifdef __CYGWIN__
15633#include <sys/cygwin.h>
15634 static struct __cygwin_perfile pf[] =
15635 {
15636 {"", O_RDONLY | O_BINARY},
15637 {"", O_WRONLY | O_BINARY},
15638 {"", O_RDWR | O_BINARY},
15639 {"", O_APPEND | O_BINARY},
15640 {NULL, 0}
15641 };
15642 cygwin_internal(CW_PERFILE, pf);
15643#endif
15644
15647
15648 id_write = rb_intern_const("write");
15649 id_read = rb_intern_const("read");
15650 id_getc = rb_intern_const("getc");
15651 id_flush = rb_intern_const("flush");
15652 id_readpartial = rb_intern_const("readpartial");
15653 id_set_encoding = rb_intern_const("set_encoding");
15654 id_fileno = rb_intern_const("fileno");
15655
15656 rb_define_global_function("syscall", rb_f_syscall, -1);
15657
15658 rb_define_global_function("open", rb_f_open, -1);
15659 rb_define_global_function("printf", rb_f_printf, -1);
15660 rb_define_global_function("print", rb_f_print, -1);
15661 rb_define_global_function("putc", rb_f_putc, 1);
15662 rb_define_global_function("puts", rb_f_puts, -1);
15663 rb_define_global_function("gets", rb_f_gets, -1);
15664 rb_define_global_function("readline", rb_f_readline, -1);
15665 rb_define_global_function("select", rb_f_select, -1);
15666
15667 rb_define_global_function("readlines", rb_f_readlines, -1);
15668
15669 rb_define_global_function("`", rb_f_backquote, 1);
15670
15671 rb_define_global_function("p", rb_f_p, -1);
15672 rb_define_method(rb_mKernel, "display", rb_obj_display, -1);
15673
15674 rb_cIO = rb_define_class("IO", rb_cObject);
15676
15677 /* Can be raised by IO operations when IO#timeout= is set. */
15679
15680 /* Readable event mask for IO#wait. */
15681 rb_define_const(rb_cIO, "READABLE", INT2NUM(RUBY_IO_READABLE));
15682 /* Writable event mask for IO#wait. */
15683 rb_define_const(rb_cIO, "WRITABLE", INT2NUM(RUBY_IO_WRITABLE));
15684 /* Priority event mask for IO#wait. */
15685 rb_define_const(rb_cIO, "PRIORITY", INT2NUM(RUBY_IO_PRIORITY));
15686
15687 /* exception to wait for reading. see IO.select. */
15689 /* exception to wait for writing. see IO.select. */
15691 /* exception to wait for reading by EAGAIN. see IO.select. */
15692 rb_eEAGAINWaitReadable = rb_define_class_under(rb_cIO, "EAGAINWaitReadable", rb_eEAGAIN);
15693 rb_include_module(rb_eEAGAINWaitReadable, rb_mWaitReadable);
15694 /* exception to wait for writing by EAGAIN. see IO.select. */
15695 rb_eEAGAINWaitWritable = rb_define_class_under(rb_cIO, "EAGAINWaitWritable", rb_eEAGAIN);
15696 rb_include_module(rb_eEAGAINWaitWritable, rb_mWaitWritable);
15697#if EAGAIN == EWOULDBLOCK
15698 rb_eEWOULDBLOCKWaitReadable = rb_eEAGAINWaitReadable;
15699 /* same as IO::EAGAINWaitReadable */
15700 rb_define_const(rb_cIO, "EWOULDBLOCKWaitReadable", rb_eEAGAINWaitReadable);
15701 rb_eEWOULDBLOCKWaitWritable = rb_eEAGAINWaitWritable;
15702 /* same as IO::EAGAINWaitWritable */
15703 rb_define_const(rb_cIO, "EWOULDBLOCKWaitWritable", rb_eEAGAINWaitWritable);
15704#else
15705 /* exception to wait for reading by EWOULDBLOCK. see IO.select. */
15706 rb_eEWOULDBLOCKWaitReadable = rb_define_class_under(rb_cIO, "EWOULDBLOCKWaitReadable", rb_eEWOULDBLOCK);
15707 rb_include_module(rb_eEWOULDBLOCKWaitReadable, rb_mWaitReadable);
15708 /* exception to wait for writing by EWOULDBLOCK. see IO.select. */
15709 rb_eEWOULDBLOCKWaitWritable = rb_define_class_under(rb_cIO, "EWOULDBLOCKWaitWritable", rb_eEWOULDBLOCK);
15710 rb_include_module(rb_eEWOULDBLOCKWaitWritable, rb_mWaitWritable);
15711#endif
15712 /* exception to wait for reading by EINPROGRESS. see IO.select. */
15713 rb_eEINPROGRESSWaitReadable = rb_define_class_under(rb_cIO, "EINPROGRESSWaitReadable", rb_eEINPROGRESS);
15714 rb_include_module(rb_eEINPROGRESSWaitReadable, rb_mWaitReadable);
15715 /* exception to wait for writing by EINPROGRESS. see IO.select. */
15716 rb_eEINPROGRESSWaitWritable = rb_define_class_under(rb_cIO, "EINPROGRESSWaitWritable", rb_eEINPROGRESS);
15717 rb_include_module(rb_eEINPROGRESSWaitWritable, rb_mWaitWritable);
15718
15719#if 0
15720 /* This is necessary only for forcing rdoc handle File::open */
15721 rb_define_singleton_method(rb_cFile, "open", rb_io_s_open, -1);
15722#endif
15723
15724 rb_define_alloc_func(rb_cIO, io_alloc);
15725 rb_define_singleton_method(rb_cIO, "new", rb_io_s_new, -1);
15726 rb_define_singleton_method(rb_cIO, "open", rb_io_s_open, -1);
15727 rb_define_singleton_method(rb_cIO, "sysopen", rb_io_s_sysopen, -1);
15728 rb_define_singleton_method(rb_cIO, "for_fd", rb_io_s_for_fd, -1);
15729 rb_define_singleton_method(rb_cIO, "popen", rb_io_s_popen, -1);
15730 rb_define_singleton_method(rb_cIO, "foreach", rb_io_s_foreach, -1);
15731 rb_define_singleton_method(rb_cIO, "readlines", rb_io_s_readlines, -1);
15732 rb_define_singleton_method(rb_cIO, "read", rb_io_s_read, -1);
15733 rb_define_singleton_method(rb_cIO, "binread", rb_io_s_binread, -1);
15734 rb_define_singleton_method(rb_cIO, "write", rb_io_s_write, -1);
15735 rb_define_singleton_method(rb_cIO, "binwrite", rb_io_s_binwrite, -1);
15736 rb_define_singleton_method(rb_cIO, "select", rb_f_select, -1);
15737 rb_define_singleton_method(rb_cIO, "pipe", rb_io_s_pipe, -1);
15738 rb_define_singleton_method(rb_cIO, "try_convert", rb_io_s_try_convert, 1);
15739 rb_define_singleton_method(rb_cIO, "copy_stream", rb_io_s_copy_stream, -1);
15740
15741 rb_define_method(rb_cIO, "initialize", rb_io_initialize, -1);
15742
15743 rb_output_fs = Qnil;
15744 rb_define_hooked_variable("$,", &rb_output_fs, 0, deprecated_str_setter);
15745
15746 rb_default_rs = rb_fstring_lit("\n"); /* avoid modifying RS_default */
15747 rb_vm_register_global_object(rb_default_rs);
15748 rb_rs = rb_default_rs;
15750 rb_define_hooked_variable("$/", &rb_rs, 0, deprecated_rs_setter);
15751 rb_gvar_ractor_local("$/"); // not local but ractor safe
15752 rb_define_hooked_variable("$-0", &rb_rs, 0, deprecated_rs_setter);
15753 rb_gvar_ractor_local("$-0"); // not local but ractor safe
15754 rb_define_hooked_variable("$\\", &rb_output_rs, 0, deprecated_str_setter);
15755
15756 rb_define_virtual_variable("$_", get_LAST_READ_LINE, set_LAST_READ_LINE);
15757 rb_gvar_ractor_local("$_");
15758
15759 rb_define_method(rb_cIO, "initialize_copy", rb_io_init_copy, 1);
15760 rb_define_method(rb_cIO, "reopen", rb_io_reopen, -1);
15761
15762 rb_define_method(rb_cIO, "print", rb_io_print, -1);
15763 rb_define_method(rb_cIO, "putc", rb_io_putc, 1);
15764 rb_define_method(rb_cIO, "puts", rb_io_puts, -1);
15765 rb_define_method(rb_cIO, "printf", rb_io_printf, -1);
15766
15767 rb_define_method(rb_cIO, "each", rb_io_each_line, -1);
15768 rb_define_method(rb_cIO, "each_line", rb_io_each_line, -1);
15769 rb_define_method(rb_cIO, "each_byte", rb_io_each_byte, 0);
15770 rb_define_method(rb_cIO, "each_char", rb_io_each_char, 0);
15771 rb_define_method(rb_cIO, "each_codepoint", rb_io_each_codepoint, 0);
15772
15773 rb_define_method(rb_cIO, "syswrite", rb_io_syswrite, 1);
15774 rb_define_method(rb_cIO, "sysread", rb_io_sysread, -1);
15775
15776 rb_define_method(rb_cIO, "pread", rb_io_pread, -1);
15777 rb_define_method(rb_cIO, "pwrite", rb_io_pwrite, 2);
15778
15779 rb_define_method(rb_cIO, "fileno", rb_io_fileno, 0);
15780 rb_define_alias(rb_cIO, "to_i", "fileno");
15781 rb_define_method(rb_cIO, "to_io", rb_io_to_io, 0);
15782
15783 rb_define_method(rb_cIO, "timeout", rb_io_timeout, 0);
15784 rb_define_method(rb_cIO, "timeout=", rb_io_set_timeout, 1);
15785
15786 rb_define_method(rb_cIO, "fsync", rb_io_fsync, 0);
15787 rb_define_method(rb_cIO, "fdatasync", rb_io_fdatasync, 0);
15788 rb_define_method(rb_cIO, "sync", rb_io_sync, 0);
15789 rb_define_method(rb_cIO, "sync=", rb_io_set_sync, 1);
15790
15791 rb_define_method(rb_cIO, "lineno", rb_io_lineno, 0);
15792 rb_define_method(rb_cIO, "lineno=", rb_io_set_lineno, 1);
15793
15794 rb_define_method(rb_cIO, "readlines", rb_io_readlines, -1);
15795
15796 rb_define_method(rb_cIO, "readpartial", io_readpartial, -1);
15797 rb_define_method(rb_cIO, "read", io_read, -1);
15798 rb_define_method(rb_cIO, "write", io_write_m, -1);
15799 rb_define_method(rb_cIO, "gets", rb_io_gets_m, -1);
15800 rb_define_method(rb_cIO, "getc", rb_io_getc, 0);
15801 rb_define_method(rb_cIO, "getbyte", rb_io_getbyte, 0);
15802 rb_define_method(rb_cIO, "readchar", rb_io_readchar, 0);
15803 rb_define_method(rb_cIO, "readbyte", rb_io_readbyte, 0);
15804 rb_define_method(rb_cIO, "ungetbyte",rb_io_ungetbyte, 1);
15805 rb_define_method(rb_cIO, "ungetc",rb_io_ungetc, 1);
15807 rb_define_method(rb_cIO, "flush", rb_io_flush, 0);
15808 rb_define_method(rb_cIO, "tell", rb_io_tell, 0);
15809 rb_define_method(rb_cIO, "seek", rb_io_seek_m, -1);
15810 /* Set I/O position from the beginning */
15811 rb_define_const(rb_cIO, "SEEK_SET", INT2FIX(SEEK_SET));
15812 /* Set I/O position from the current position */
15813 rb_define_const(rb_cIO, "SEEK_CUR", INT2FIX(SEEK_CUR));
15814 /* Set I/O position from the end */
15815 rb_define_const(rb_cIO, "SEEK_END", INT2FIX(SEEK_END));
15816#ifdef SEEK_DATA
15817 /* Set I/O position to the next location containing data */
15818 rb_define_const(rb_cIO, "SEEK_DATA", INT2FIX(SEEK_DATA));
15819#endif
15820#ifdef SEEK_HOLE
15821 /* Set I/O position to the next hole */
15822 rb_define_const(rb_cIO, "SEEK_HOLE", INT2FIX(SEEK_HOLE));
15823#endif
15824 rb_define_method(rb_cIO, "rewind", rb_io_rewind, 0);
15825 rb_define_method(rb_cIO, "pos", rb_io_tell, 0);
15826 rb_define_method(rb_cIO, "pos=", rb_io_set_pos, 1);
15827 rb_define_method(rb_cIO, "eof", rb_io_eof, 0);
15828 rb_define_method(rb_cIO, "eof?", rb_io_eof, 0);
15829
15830 rb_define_method(rb_cIO, "close_on_exec?", rb_io_close_on_exec_p, 0);
15831 rb_define_method(rb_cIO, "close_on_exec=", rb_io_set_close_on_exec, 1);
15832
15833 rb_define_method(rb_cIO, "close", rb_io_close_m, 0);
15834 rb_define_method(rb_cIO, "closed?", rb_io_closed_p, 0);
15835 rb_define_method(rb_cIO, "close_read", rb_io_close_read, 0);
15836 rb_define_method(rb_cIO, "close_write", rb_io_close_write, 0);
15837
15838 rb_define_method(rb_cIO, "isatty", rb_io_isatty, 0);
15839 rb_define_method(rb_cIO, "tty?", rb_io_isatty, 0);
15840 rb_define_method(rb_cIO, "binmode", rb_io_binmode_m, 0);
15841 rb_define_method(rb_cIO, "binmode?", rb_io_binmode_p, 0);
15842 rb_define_method(rb_cIO, "sysseek", rb_io_sysseek, -1);
15843 rb_define_method(rb_cIO, "advise", rb_io_advise, -1);
15844
15845 rb_define_method(rb_cIO, "ioctl", rb_io_ioctl, -1);
15846 rb_define_method(rb_cIO, "fcntl", rb_io_fcntl, -1);
15847 rb_define_method(rb_cIO, "pid", rb_io_pid, 0);
15848
15849 rb_define_method(rb_cIO, "path", rb_io_path, 0);
15850 rb_define_method(rb_cIO, "to_path", rb_io_path, 0);
15851
15852 rb_define_method(rb_cIO, "inspect", rb_io_inspect, 0);
15853
15854 rb_define_method(rb_cIO, "external_encoding", rb_io_external_encoding, 0);
15855 rb_define_method(rb_cIO, "internal_encoding", rb_io_internal_encoding, 0);
15856 rb_define_method(rb_cIO, "set_encoding", rb_io_set_encoding, -1);
15857 rb_define_method(rb_cIO, "set_encoding_by_bom", rb_io_set_encoding_by_bom, 0);
15858
15859 rb_define_method(rb_cIO, "autoclose?", rb_io_autoclose_p, 0);
15860 rb_define_method(rb_cIO, "autoclose=", rb_io_set_autoclose, 1);
15861
15862 rb_define_method(rb_cIO, "wait", io_wait, -1);
15863
15864 rb_define_method(rb_cIO, "wait_readable", io_wait_readable, -1);
15865 rb_define_method(rb_cIO, "wait_writable", io_wait_writable, -1);
15866 rb_define_method(rb_cIO, "wait_priority", io_wait_priority, -1);
15867
15868 rb_define_virtual_variable("$stdin", stdin_getter, stdin_setter);
15869 rb_define_virtual_variable("$stdout", stdout_getter, stdout_setter);
15870 rb_define_virtual_variable("$>", stdout_getter, stdout_setter);
15871 rb_define_virtual_variable("$stderr", stderr_getter, stderr_setter);
15872
15873 rb_gvar_ractor_local("$stdin");
15874 rb_gvar_ractor_local("$stdout");
15875 rb_gvar_ractor_local("$>");
15876 rb_gvar_ractor_local("$stderr");
15877
15879 rb_stdin = rb_io_prep_stdin();
15881 rb_stdout = rb_io_prep_stdout();
15883 rb_stderr = rb_io_prep_stderr();
15884
15885 orig_stdout = rb_stdout;
15886 orig_stderr = rb_stderr;
15887
15888 /* Holds the original stdin */
15890 /* Holds the original stdout */
15892 /* Holds the original stderr */
15894
15895#if 0
15896 /* Hack to get rdoc to regard ARGF as a class: */
15897 rb_cARGF = rb_define_class("ARGF", rb_cObject);
15898#endif
15899
15900 rb_cARGF = rb_class_new(rb_cObject);
15901 rb_set_class_path(rb_cARGF, rb_cObject, "ARGF.class");
15902 rb_define_alloc_func(rb_cARGF, argf_alloc);
15903
15905
15906 rb_define_method(rb_cARGF, "initialize", argf_initialize, -2);
15907 rb_define_method(rb_cARGF, "initialize_copy", argf_initialize_copy, 1);
15908 rb_define_method(rb_cARGF, "to_s", argf_to_s, 0);
15909 rb_define_alias(rb_cARGF, "inspect", "to_s");
15910 rb_define_method(rb_cARGF, "argv", argf_argv, 0);
15911
15912 rb_define_method(rb_cARGF, "fileno", argf_fileno, 0);
15913 rb_define_method(rb_cARGF, "to_i", argf_fileno, 0);
15914 rb_define_method(rb_cARGF, "to_io", argf_to_io, 0);
15915 rb_define_method(rb_cARGF, "to_write_io", argf_write_io, 0);
15916 rb_define_method(rb_cARGF, "each", argf_each_line, -1);
15917 rb_define_method(rb_cARGF, "each_line", argf_each_line, -1);
15918 rb_define_method(rb_cARGF, "each_byte", argf_each_byte, 0);
15919 rb_define_method(rb_cARGF, "each_char", argf_each_char, 0);
15920 rb_define_method(rb_cARGF, "each_codepoint", argf_each_codepoint, 0);
15921
15922 rb_define_method(rb_cARGF, "read", argf_read, -1);
15923 rb_define_method(rb_cARGF, "readpartial", argf_readpartial, -1);
15924 rb_define_method(rb_cARGF, "read_nonblock", argf_read_nonblock, -1);
15925 rb_define_method(rb_cARGF, "readlines", argf_readlines, -1);
15926 rb_define_method(rb_cARGF, "to_a", argf_readlines, -1);
15927 rb_define_method(rb_cARGF, "gets", argf_gets, -1);
15928 rb_define_method(rb_cARGF, "readline", argf_readline, -1);
15929 rb_define_method(rb_cARGF, "getc", argf_getc, 0);
15930 rb_define_method(rb_cARGF, "getbyte", argf_getbyte, 0);
15931 rb_define_method(rb_cARGF, "readchar", argf_readchar, 0);
15932 rb_define_method(rb_cARGF, "readbyte", argf_readbyte, 0);
15933 rb_define_method(rb_cARGF, "tell", argf_tell, 0);
15934 rb_define_method(rb_cARGF, "seek", argf_seek_m, -1);
15935 rb_define_method(rb_cARGF, "rewind", argf_rewind, 0);
15936 rb_define_method(rb_cARGF, "pos", argf_tell, 0);
15937 rb_define_method(rb_cARGF, "pos=", argf_set_pos, 1);
15938 rb_define_method(rb_cARGF, "eof", argf_eof, 0);
15939 rb_define_method(rb_cARGF, "eof?", argf_eof, 0);
15940 rb_define_method(rb_cARGF, "binmode", argf_binmode_m, 0);
15941 rb_define_method(rb_cARGF, "binmode?", argf_binmode_p, 0);
15942
15943 rb_define_method(rb_cARGF, "write", argf_write, -1);
15944 rb_define_method(rb_cARGF, "print", rb_io_print, -1);
15945 rb_define_method(rb_cARGF, "putc", rb_io_putc, 1);
15946 rb_define_method(rb_cARGF, "puts", rb_io_puts, -1);
15947 rb_define_method(rb_cARGF, "printf", rb_io_printf, -1);
15948
15949 rb_define_method(rb_cARGF, "filename", argf_filename, 0);
15950 rb_define_method(rb_cARGF, "path", argf_filename, 0);
15951 rb_define_method(rb_cARGF, "file", argf_file, 0);
15952 rb_define_method(rb_cARGF, "skip", argf_skip, 0);
15953 rb_define_method(rb_cARGF, "close", argf_close_m, 0);
15954 rb_define_method(rb_cARGF, "closed?", argf_closed, 0);
15955
15956 rb_define_method(rb_cARGF, "lineno", argf_lineno, 0);
15957 rb_define_method(rb_cARGF, "lineno=", argf_set_lineno, 1);
15958
15959 rb_define_method(rb_cARGF, "inplace_mode", argf_inplace_mode_get, 0);
15960 rb_define_method(rb_cARGF, "inplace_mode=", argf_inplace_mode_set, 1);
15961
15962 rb_define_method(rb_cARGF, "external_encoding", argf_external_encoding, 0);
15963 rb_define_method(rb_cARGF, "internal_encoding", argf_internal_encoding, 0);
15964 rb_define_method(rb_cARGF, "set_encoding", argf_set_encoding, -1);
15965
15966 argf = rb_class_new_instance(0, 0, rb_cARGF);
15967
15969 /*
15970 * ARGF is a stream designed for use in scripts that process files given
15971 * as command-line arguments or passed in via STDIN.
15972 *
15973 * See ARGF (the class) for more details.
15974 */
15976
15977 rb_define_hooked_variable("$.", &argf, argf_lineno_getter, argf_lineno_setter);
15978 rb_define_hooked_variable("$FILENAME", &argf, argf_filename_getter, rb_gvar_readonly_setter);
15979 ARGF.filename = rb_str_new2("-");
15980
15981 rb_define_hooked_variable("$-i", &argf, opt_i_get, opt_i_set);
15982 rb_gvar_ractor_local("$-i");
15983
15984 rb_define_hooked_variable("$*", &argf, argf_argv_getter, rb_gvar_readonly_setter);
15985
15986#if defined (_WIN32) || defined(__CYGWIN__)
15987 atexit(pipe_atexit);
15988#endif
15989
15990 Init_File();
15991
15992 rb_define_method(rb_cFile, "initialize", rb_file_initialize, -1);
15993
15994 sym_mode = ID2SYM(rb_intern_const("mode"));
15995 sym_perm = ID2SYM(rb_intern_const("perm"));
15996 sym_flags = ID2SYM(rb_intern_const("flags"));
15997 sym_extenc = ID2SYM(rb_intern_const("external_encoding"));
15998 sym_intenc = ID2SYM(rb_intern_const("internal_encoding"));
15999 sym_encoding = ID2SYM(rb_id_encoding());
16000 sym_open_args = ID2SYM(rb_intern_const("open_args"));
16001 sym_textmode = ID2SYM(rb_intern_const("textmode"));
16002 sym_binmode = ID2SYM(rb_intern_const("binmode"));
16003 sym_autoclose = ID2SYM(rb_intern_const("autoclose"));
16004 sym_normal = ID2SYM(rb_intern_const("normal"));
16005 sym_sequential = ID2SYM(rb_intern_const("sequential"));
16006 sym_random = ID2SYM(rb_intern_const("random"));
16007 sym_willneed = ID2SYM(rb_intern_const("willneed"));
16008 sym_dontneed = ID2SYM(rb_intern_const("dontneed"));
16009 sym_noreuse = ID2SYM(rb_intern_const("noreuse"));
16010 sym_SET = ID2SYM(rb_intern_const("SET"));
16011 sym_CUR = ID2SYM(rb_intern_const("CUR"));
16012 sym_END = ID2SYM(rb_intern_const("END"));
16013#ifdef SEEK_DATA
16014 sym_DATA = ID2SYM(rb_intern_const("DATA"));
16015#endif
16016#ifdef SEEK_HOLE
16017 sym_HOLE = ID2SYM(rb_intern_const("HOLE"));
16018#endif
16019 sym_wait_readable = ID2SYM(rb_intern_const("wait_readable"));
16020 sym_wait_writable = ID2SYM(rb_intern_const("wait_writable"));
16021}
16022
16023#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:138
#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:1187
VALUE rb_define_class(const char *name, VALUE super)
Defines a top-level class.
Definition class.c:980
VALUE rb_class_new(VALUE super)
Creates a new, anonymous class.
Definition class.c:359
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
Definition class.c:1012
VALUE rb_define_module_under(VALUE outer, const char *name)
Defines a module under the namespace of outer.
Definition class.c:1119
void rb_define_alias(VALUE klass, const char *name1, const char *name2)
Defines an alias of a method.
Definition class.c:2345
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:2648
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:2635
int rb_block_given_p(void)
Determines if the current method is given a block.
Definition eval.c:937
int rb_get_kwargs(VALUE keyword_hash, const ID *table, int required, int optional, VALUE *values)
Keyword argument deconstructor.
Definition class.c:2424
#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:1675
#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:1683
#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:135
#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:203
#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:1677
#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:3836
void rb_category_warn(rb_warning_category_t category, const char *fmt,...)
Identical to rb_category_warning(), except it reports unless $VERBOSE is nil.
Definition error.c:476
void rb_category_warning(rb_warning_category_t category, const char *fmt,...)
Identical to rb_warning(), except it takes additional "category" parameter.
Definition error.c:508
VALUE rb_eNotImpError
NotImplementedError exception.
Definition error.c:1440
void rb_exc_raise(VALUE mesg)
Raises an exception in the current thread.
Definition eval.c:676
void rb_syserr_fail(int e, const char *mesg)
Raises appropriate exception that represents a C errno.
Definition error.c:3905
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:14702
VALUE rb_eIOError
IOError exception.
Definition io.c:189
VALUE rb_eStandardError
StandardError exception.
Definition error.c:1427
void rb_mod_syserr_fail_str(VALUE mod, int e, VALUE mesg)
Identical to rb_mod_syserr_fail(), except it takes the message in Ruby's String instead of C's.
Definition error.c:3995
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:3911
#define ruby_verbose
This variable controls whether the interpreter is in debug mode.
Definition error.h:475
VALUE rb_eTypeError
TypeError exception.
Definition error.c:1430
VALUE rb_eEOFError
EOFError exception.
Definition io.c:188
void rb_readwrite_sys_fail(enum rb_io_wait_readwrite waiting, const char *mesg)
Raises appropriate exception using the parameters.
Definition io.c:14696
void rb_iter_break_value(VALUE val)
Identical to rb_iter_break(), except it additionally takes the "value" of this breakage.
Definition vm.c:2114
rb_io_wait_readwrite
for rb_readwrite_sys_fail first argument
Definition error.h:73
VALUE rb_eRuntimeError
RuntimeError exception.
Definition error.c:1428
void rb_warn(const char *fmt,...)
Identical to rb_warning(), except it reports unless $VERBOSE is nil.
Definition error.c:466
VALUE rb_eSystemCallError
SystemCallError exception.
Definition error.c:1450
@ RB_WARN_CATEGORY_DEPRECATED
Warning is for deprecated features.
Definition error.h:48
VALUE rb_mKernel
Kernel module.
Definition object.c:65
VALUE rb_check_to_int(VALUE val)
Identical to rb_check_to_integer(), except it uses #to_int for conversion.
Definition object.c:3222
VALUE rb_any_to_s(VALUE obj)
Generates a textual representation of the given object.
Definition object.c:669
VALUE rb_obj_alloc(VALUE klass)
Allocates an instance of the given class.
Definition object.c:2121
VALUE rb_class_new_instance(int argc, const VALUE *argv, VALUE klass)
Allocates, then initialises an instance of the given class.
Definition object.c:2162
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:2150
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:247
VALUE rb_obj_dup(VALUE obj)
Duplicates the given object.
Definition object.c:576
VALUE rb_inspect(VALUE obj)
Generates a human-readable textual representation of the given object.
Definition object.c:680
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:1284
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:3203
VALUE rb_cFile
File class.
Definition file.c:175
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:3216
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:1655
int rb_enc_str_coderange(VALUE str)
Scans the passed string to collect its code range.
Definition string.c:1270
VALUE rb_enc_uint_chr(unsigned int code, rb_encoding *enc)
Encodes the passed code point into a series of bytes.
Definition numeric.c:3803
long rb_str_coderange_scan_restartable(const char *str, const char *end, rb_encoding *enc, int *cr)
Scans the passed string until it finds something odd.
Definition string.c:1154
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:2600
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:2097
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:1475
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:1770
const char * rb_econv_asciicompat_encoding(const char *encname)
Queries the passed encoding's corresponding ASCII compatible encoding.
Definition transcode.c:1814
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:1931
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:2651
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:1996
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:2914
VALUE rb_econv_make_exception(rb_econv_t *ec)
This function makes sense right after rb_econv_convert() returns.
Definition transcode.c:4272
void rb_econv_check_error(rb_econv_t *ec)
This is a rb_econv_make_exception() + rb_exc_raise() combo.
Definition transcode.c:4278
void rb_econv_close(rb_econv_t *ec)
Destructs a converter.
Definition transcode.c:1731
void rb_econv_putback(rb_econv_t *ec, unsigned char *p, int n)
Puts back the bytes.
Definition transcode.c:1781
VALUE rb_funcall(VALUE recv, ID mid, int n,...)
Calls a method.
Definition vm_eval.c:1099
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:1066
Defines RBIMPL_HAS_BUILTIN.
#define RETURN_ENUMERATOR(obj, argc, argv)
Identical to RETURN_SIZED_ENUMERATOR(), except its size is unknown.
Definition enumerator.h:239
static int rb_check_arity(int argc, int min, int max)
Ensures that the passed integer is in the passed range.
Definition error.h:284
VALUE rb_io_printf(int argc, const VALUE *argv, VALUE io)
This is a rb_f_sprintf() + rb_io_write() combo.
Definition io.c:8598
VALUE rb_io_gets(VALUE io)
Reads a "line" from the given IO.
Definition io.c:4304
int rb_cloexec_pipe(int fildes[2])
Opens a pipe with closing on exec.
Definition io.c:427
VALUE rb_io_print(int argc, const VALUE *argv, VALUE io)
Iterates over the passed array to apply rb_io_write() individually.
Definition io.c:8743
VALUE rb_io_addstr(VALUE io, VALUE str)
Identical to rb_io_write(), except it always returns the passed IO.
Definition io.c:2351
void rb_write_error(const char *str)
Writes the given error message to somewhere applicable.
Definition io.c:9172
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:5173
VALUE rb_io_getbyte(VALUE io)
Reads a byte from the given IO.
Definition io.c:5079
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:9348
void rb_update_max_fd(int fd)
Informs the interpreter that the passed fd can be the max.
Definition io.c:248
int rb_cloexec_open(const char *pathname, int flags, mode_t mode)
Opens a file that closes on exec.
Definition io.c:328
VALUE rb_output_rs
The record separator character for outputs, or the $\.
Definition io.c:206
VALUE rb_io_eof(VALUE io)
Queries if the passed IO is at the end of file.
Definition io.c:2696
void rb_write_error2(const char *str, long len)
Identical to rb_write_error(), except it additionally takes the message's length.
Definition io.c:9152
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:6373
VALUE rb_io_binmode(VALUE io)
Sets the binmode.
Definition io.c:6327
VALUE rb_io_ungetc(VALUE io, VALUE c)
"Unget"s a string.
Definition io.c:5237
int rb_pipe(int *pipes)
This is an rb_cloexec_pipe() + rb_update_max_fd() combo.
Definition io.c:7375
VALUE rb_gets(void)
Much like rb_io_gets(), but it reads from the mysterious ARGF object.
Definition io.c:10429
int rb_cloexec_fcntl_dupfd(int fd, int minfd)
Duplicates a file descriptor with closing on exec.
Definition io.c:461
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:7258
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:7265
VALUE rb_io_close(VALUE io)
Closes the IO.
Definition io.c:5747
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:1876
VALUE rb_lastline_get(void)
Queries the last line, or the $_.
Definition vm.c:1870
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:2945
rb_pid_t rb_waitpid(rb_pid_t pid, int *status, int flags)
Waits for a process, with releasing GVL.
Definition process.c:1167
void rb_last_status_set(int status, rb_pid_t pid)
Sets the "last status", or the $?.
Definition process.c:681
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:4068
#define rb_str_new(str, len)
Allocates an instance of rb_cString.
Definition string.h:1498
#define rb_str_buf_cat
Just another name of rb_str_cat.
Definition string.h:1681
#define rb_usascii_str_new(str, len)
Identical to rb_str_new, except it generates a string of "US ASCII" encoding.
Definition string.h:1532
size_t rb_str_capacity(VALUE str)
Queries the capacity of the given string.
Definition string.c:1324
VALUE rb_str_new_frozen(VALUE str)
Creates a frozen copy of the string, if necessary.
Definition string.c:1831
VALUE rb_str_dup(VALUE str)
Duplicates a string.
Definition string.c:2294
VALUE rb_str_cat(VALUE dst, const char *src, long srclen)
Destructively appends the passed contents to the string.
Definition string.c:3836
VALUE rb_str_locktmp(VALUE str)
Obtains a "temporary lock" of the string.
rb_gvar_setter_t rb_str_setter
This is a rb_gvar_setter_t that refutes non-string assignments.
Definition string.h:1146
VALUE rb_str_equal(VALUE str1, VALUE str2)
Equality of two strings.
Definition string.c:4539
void rb_str_set_len(VALUE str, long len)
Overwrites the length of the string.
Definition string.c:3658
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:4010
VALUE rb_check_string_type(VALUE obj)
Try converting an object to its stringised representation using its to_str method,...
Definition string.c:3238
VALUE rb_str_substr(VALUE str, long beg, long len)
This is the implementation of two-argumented String#slice.
Definition string.c:3538
VALUE rb_str_unlocktmp(VALUE str)
Releases a lock formerly obtained by rb_str_locktmp().
Definition string.c:3641
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:3032
VALUE rb_str_buf_new(long capa)
Allocates a "string buffer".
Definition string.c:2021
#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:1514
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:2153
int rb_thread_interrupted(VALUE thval)
Checks if the thread's execution was recently interrupted.
Definition thread.c:1450
VALUE rb_mutex_new(void)
Creates a mutex.
int rb_thread_fd_writable(int fd)
Identical to rb_thread_wait_fd(), except it blocks the current thread until the given file descriptor...
Definition io.c:1604
VALUE rb_exec_recursive(VALUE(*f)(VALUE g, VALUE h, int r), VALUE g, VALUE h)
"Recursion" API entry point.
void rb_thread_fd_close(int fd)
Notifies a closing of a file descriptor to other threads.
Definition thread.c:2704
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:1433
VALUE rb_thread_current(void)
Obtains the "current" thread.
Definition thread.c:2981
int rb_thread_wait_fd(int fd)
Blocks the current thread until the given file descriptor is ready to be read.
Definition io.c:1598
void rb_thread_sleep(int sec)
Blocks for the given period of time.
Definition thread.c:1456
struct timeval rb_time_interval(VALUE num)
Creates a "time interval".
Definition time.c:2958
void rb_set_class_path(VALUE klass, VALUE space, const char *name)
Names a class.
Definition variable.c:433
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:1924
VALUE rb_class_name(VALUE obj)
Queries the name of the given object's class.
Definition variable.c:492
int rb_respond_to(VALUE obj, ID mid)
Queries if the object responds to the method.
Definition vm_method.c:2958
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:668
void rb_define_alloc_func(VALUE klass, rb_alloc_func_t func)
Sets the allocator function of a class.
static ID rb_intern_const(const char *str)
This is a "tiny optimisation" over rb_intern().
Definition symbol.h:284
#define RB_ID2SYM
Just another name of rb_id2sym.
Definition symbol.h:42
void rb_define_global_const(const char *name, VALUE val)
Identical to rb_define_const(), except it defines that of "global", i.e.
Definition variable.c:3792
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:824
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:147
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:6459
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:6592
#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:245
rb_io_event
Type of events that an IO can wait.
Definition io.h:81
@ RUBY_IO_READABLE
IO::READABLE
Definition io.h:82
@ RUBY_IO_PRIORITY
IO::PRIORITY
Definition io.h:84
@ RUBY_IO_WRITABLE
IO::WRITABLE
Definition io.h:83
#define FMODE_READWRITE
The IO is opened for both read/write.
Definition io.h:153
#define FMODE_EXTERNAL
This flag means that an IO object is wrapping an "external" file descriptor, which is owned by someth...
Definition io.h:237
#define GetOpenFile
This is an old name of RB_IO_POINTER.
Definition io.h:427
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:177
#define FMODE_CREATE
The IO is opened for creating.
Definition io.h:200
void rb_io_check_readable(rb_io_t *fptr)
Just another name of rb_io_check_byte_readable.
Definition io.c:1024
int rb_wait_for_single_fd(int fd, int events, struct timeval *tv)
Blocks until the passed file descriptor is ready for the passed events.
Definition io.c:1592
FILE * rb_fdopen(int fd, const char *modestr)
Identical to rb_io_stdio_file(), except it takes file descriptors instead of Ruby's IO.
Definition io.c:7075
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:6741
int rb_io_descriptor(VALUE io)
Returns an integer representing the numeric file descriptor for io.
Definition io.c:2899
#define FMODE_WRITABLE
The IO is opened for writing.
Definition io.h:150
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:9394
#define FMODE_APPEND
The IO is opened for appending.
Definition io.h:192
#define MakeOpenFile
This is an old name of RB_IO_OPEN.
Definition io.h:450
#define FMODE_DUPLEX
Ruby eventually detects that the IO is bidirectional.
Definition io.h:185
#define FMODE_BINMODE
The IO is in "binary mode".
Definition io.h:164
int rb_io_maybe_wait_readable(int error, VALUE io, VALUE timeout)
Blocks until the passed IO is ready for reading, if that makes sense for the passed errno.
Definition io.c:1651
int capa
Designed capacity of the buffer.
Definition io.h:11
#define RB_IO_POINTER(obj, fp)
Queries the underlying IO pointer.
Definition io.h:421
VALUE rb_io_maybe_wait(int error, VALUE io, VALUE events, VALUE timeout)
Identical to rb_io_wait() except it additionally takes previous errno.
Definition io.c:1610
VALUE rb_eIOTimeoutError
Indicates that a timeout has occurred while performing an IO operation.
Definition io.c:190
char * ptr
Pointer to the underlying memory region, of at least capa bytes.
Definition io.h:2
#define FMODE_SYNC
The IO is in "sync mode".
Definition io.h:171
int off
Offset inside of ptr.
Definition io.h:5
VALUE rb_io_path(VALUE io)
Returns the path for the given IO.
Definition io.c:2973
void rb_io_extract_modeenc(VALUE *vmode_p, VALUE *vperm_p, VALUE opthash, int *oflags_p, enum rb_io_mode *fmode_p, rb_io_enc_t *convconfig_p)
This function can be seen as an extended version of rb_io_extract_encoding_option() that not only con...
Definition io.c:6866
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:208
#define FMODE_TEXTMODE
The IO is in "text mode".
Definition io.h:228
int rb_io_fptr_finalize(rb_io_t *fptr)
Destroys the given IO.
Definition io.c:5679
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:5855
VALUE rb_io_set_timeout(VALUE io, VALUE timeout)
Set the timeout associated with the specified io object.
Definition io.c:886
ssize_t rb_io_bufwrite(VALUE io, const void *buf, size_t size)
Buffered write to the passed IO.
Definition io.c:2016
void rb_io_check_char_readable(rb_io_t *fptr)
Asserts that an IO is opened for character-based reading.
Definition io.c:996
#define FMODE_TRUNC
This flag amends the effect of FMODE_CREATE, so that if there already is a file at the given path it ...
Definition io.h:214
VALUE rb_io_get_write_io(VALUE io)
Queries the tied IO for writing.
Definition io.c:823
void rb_io_set_nonblock(rb_io_t *fptr)
Instructs the OS to put its internal file structure into "nonblocking mode".
Definition io.c:3425
int rb_io_wait_writable(int fd)
Blocks until the passed file descriptor gets writable.
Definition io.c:1549
VALUE rb_io_open_descriptor(VALUE klass, int descriptor, int mode, VALUE path, VALUE timeout, struct rb_io_encoding *encoding)
Allocate a new IO object, with the given file descriptor.
Definition io.c:9265
VALUE rb_io_set_write_io(VALUE io, VALUE w)
Assigns the tied IO for writing.
Definition io.c:834
void rb_io_check_writable(rb_io_t *fptr)
Asserts that an IO is opened for writing.
Definition io.c:1048
int rb_io_maybe_wait_writable(int error, VALUE io, VALUE timeout)
Blocks until the passed IO is ready for writing, if that makes sense for the passed errno.
Definition io.c:1666
void rb_io_check_closed(rb_io_t *fptr)
This badly named function asserts that the passed IO is open.
Definition io.c:796
int rb_io_wait_readable(int fd)
Blocks until the passed file descriptor gets readable.
Definition io.c:1515
void rb_io_synchronized(rb_io_t *fptr)
Sets FMODE_SYNC.
Definition io.c:7362
VALUE rb_io_wait(VALUE io, VALUE events, VALUE timeout)
Blocks until the passed IO is ready for the passed events.
Definition io.c:1454
int len
Length of the buffer.
Definition io.h:8
VALUE rb_ractor_stdin(void)
Queries the standard input of the current Ractor that is calling this function.
Definition ractor.c:2726
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:2786
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:2774
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:2762
void * rb_thread_call_with_gvl(void *(*func)(void *), void *data1)
(Re-)acquires the GVL.
Definition thread.c:1906
#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:1388
VALUE rb_yield(VALUE val)
Yields the block.
Definition vm_eval.c:1354
void rb_fd_term(rb_fdset_t *f)
Destroys the rb_fdset_t, releasing any memory and resources it used.
#define MEMZERO(p, type, n)
Handy macro to erase a region of memory.
Definition memory.h:360
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
Definition memory.h:167
#define MEMMOVE(p1, p2, type, n)
Handy macro to call memmove.
Definition memory.h:384
#define NUM2MODET
Converts a C's mode_t into an instance of rb_cInteger.
Definition mode_t.h:28
void rb_define_hooked_variable(const char *q, VALUE *w, type *e, void_type *r)
Define a function-backended global variable.
void rb_define_virtual_variable(const char *q, type *w, void_type *e)
Define a function-backended global variable.
VALUE rb_rescue2(type *q, VALUE w, type *e, VALUE r,...)
An equivalent of rescue clause.
VALUE rb_ensure(type *q, VALUE w, type *e, VALUE r)
An equivalent of ensure clause.
#define PRI_OFFT_PREFIX
A rb_sprintf() format prefix to be used for an off_t parameter.
Definition off_t.h:55
#define OFFT2NUM
Converts a C's off_t into an instance of rb_cInteger.
Definition off_t.h:33
#define NUM2OFFT
Converts an instance of rb_cNumeric into C's off_t.
Definition off_t.h:44
#define PIDT2NUM
Converts a C's pid_t into an instance of rb_cInteger.
Definition pid_t.h:28
#define rb_fd_isset
Queries if the given fd is in the rb_fdset_t.
Definition posix.h:60
#define rb_fd_select
Waits for multiple file descriptors at once.
Definition posix.h:66
#define rb_fd_init
Initialises the :given :rb_fdset_t.
Definition posix.h:63
#define rb_fd_set
Sets the given fd to the rb_fdset_t.
Definition posix.h:54
#define RARRAY_LEN
Just another name of rb_array_len.
Definition rarray.h:51
static int RARRAY_LENINT(VALUE ary)
Identical to rb_array_len(), except it differs for the return type.
Definition rarray.h:281
#define RARRAY_AREF(a, i)
Definition rarray.h:403
#define RARRAY_CONST_PTR
Just another name of rb_array_const_ptr.
Definition rarray.h:52
#define RFILE(obj)
Convenient casting macro.
Definition rfile.h:50
#define StringValue(v)
Ensures that the parameter object is a String.
Definition rstring.h:66
static char * RSTRING_END(VALUE str)
Queries the end of the contents pointer of the string.
Definition rstring.h:442
#define RSTRING_GETMEM(str, ptrvar, lenvar)
Convenient macro to obtain the contents and length at once.
Definition rstring.h:488
#define StringValueCStr(v)
Identical to StringValuePtr, except it additionally checks for the contents for viability as a C stri...
Definition rstring.h:89
#define RUBY_TYPED_DEFAULT_FREE
This is a value you can set to rb_data_type_struct::dfree.
Definition rtypeddata.h:79
#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:497
VALUE rb_get_argv(void)
Queries the arguments passed to the current process that you can access from Ruby as ARGV.
Definition io.c:14662
void rb_p(VALUE obj)
Inspects an object.
Definition io.c:9051
#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:228
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:640
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:271
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:452
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:616
VALUE rb_fiber_scheduler_io_wait(VALUE scheduler, VALUE io, VALUE events, VALUE timeout)
Non-blocking version of rb_io_wait().
Definition scheduler.c:446
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:70
VALUE rb_fiber_scheduler_io_selectv(VALUE scheduler, int argc, VALUE *argv)
Non-blocking version of IO.select, argv variant.
Definition scheduler.c:482
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:652
VALUE rb_fiber_scheduler_current_for_thread(VALUE thread)
Identical to rb_fiber_scheduler_current(), except it queries for that of the passed thread instead of...
Definition scheduler.c:233
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:628
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:458
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:4332
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:219
This is the struct that holds necessary info for a struct.
Definition rtypeddata.h:200
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:119
int ecflags
Flags.
Definition io.h:129
VALUE ecopts
Flags as Ruby hash.
Definition io.h:137
rb_encoding * enc2
External encoding.
Definition io.h:123
rb_encoding * enc
Internal encoding.
Definition io.h:121
IO buffers.
Definition io.h:94
char * ptr
Pointer to the underlying memory region, of at least capa bytes.
Definition io.h:97
int off
Offset inside of ptr.
Definition io.h:100
int len
Length of the buffer.
Definition io.h:103
int capa
Designed capacity of the buffer.
Definition io.h:106
Ruby's IO, metadata and buffers.
Definition io.h:280
rb_io_buffer_t wbuf
Write buffer.
Definition io.h:315
enum rb_io_mode mode
mode flags: FMODE_XXXs
Definition io.h:295
void(* finalize)(struct rb_io *, int)
finalize proc
Definition io.h:311
rb_econv_t * readconv
Encoding converter used when reading from this IO.
Definition io.h:337
rb_econv_t * writeconv
Encoding converter used when writing to this IO.
Definition io.h:348
struct rb_io_encoding encs
Decomposed encoding flags.
Definition io.h:333
VALUE self
The IO's Ruby level counterpart.
Definition io.h:283
VALUE write_lock
This is a Ruby level mutex.
Definition io.h:385
VALUE timeout
The timeout associated with this IO when performing blocking operations.
Definition io.h:391
FILE * stdio_file
stdio ptr for read/write, if available.
Definition io.h:287
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:375
VALUE tied_io_for_writing
Duplex IO object, if set.
Definition io.h:330
int writeconv_initialized
Whether rb_io_t::writeconv is already set up.
Definition io.h:361
int fd
file descriptor.
Definition io.h:291
rb_io_buffer_t rbuf
(Byte) read buffer.
Definition io.h:322
int lineno
number of lines read
Definition io.h:303
VALUE writeconv_asciicompat
This is, when set, an instance of rb_cString which holds the "common" encoding.
Definition io.h:357
rb_io_buffer_t cbuf
rb_io_ungetc() destination.
Definition io.h:344
rb_pid_t pid
child's pid (for pipes)
Definition io.h:299
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:368
VALUE pathv
pathname for file
Definition io.h:307
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