Ruby 3.5.0dev (2025-10-09 revision a29c90c3b0bdc355b8b6795488db3aeba2996575)
io.c (a29c90c3b0bdc355b8b6795488db3aeba2996575)
1/**********************************************************************
2
3 io.c -
4
5 $Author$
6 created at: Fri Oct 15 18:08:59 JST 1993
7
8 Copyright (C) 1993-2007 Yukihiro Matsumoto
9 Copyright (C) 2000 Network Applied Communication Laboratory, Inc.
10 Copyright (C) 2000 Information-technology Promotion Agency, Japan
11
12**********************************************************************/
13
14#include "ruby/internal/config.h"
15
17#include "ruby/io/buffer.h"
18
19#include <ctype.h>
20#include <errno.h>
21#include <stddef.h>
22
23/* non-Linux poll may not work on all FDs */
24#if defined(HAVE_POLL)
25# if defined(__linux__)
26# define USE_POLL 1
27# endif
28# if defined(__FreeBSD_version) && __FreeBSD_version >= 1100000
29# define USE_POLL 1
30# endif
31#endif
32
33#ifndef USE_POLL
34# define USE_POLL 0
35#endif
36
37#undef free
38#define free(x) xfree(x)
39
40#if defined(DOSISH) || defined(__CYGWIN__)
41#include <io.h>
42#endif
43
44#include <sys/types.h>
45#if defined HAVE_NET_SOCKET_H
46# include <net/socket.h>
47#elif defined HAVE_SYS_SOCKET_H
48# include <sys/socket.h>
49#endif
50
51#if defined(__BOW__) || defined(__CYGWIN__) || defined(_WIN32)
52# define NO_SAFE_RENAME
53#endif
54
55#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__sun) || defined(_nec_ews)
56# define USE_SETVBUF
57#endif
58
59#ifdef __QNXNTO__
60#include <unix.h>
61#endif
62
63#include <sys/types.h>
64#if defined(HAVE_SYS_IOCTL_H) && !defined(_WIN32)
65#include <sys/ioctl.h>
66#endif
67#if defined(HAVE_FCNTL_H) || defined(_WIN32)
68#include <fcntl.h>
69#elif defined(HAVE_SYS_FCNTL_H)
70#include <sys/fcntl.h>
71#endif
72
73#ifdef HAVE_SYS_TIME_H
74# include <sys/time.h>
75#endif
76
77#include <sys/stat.h>
78
79#if defined(HAVE_SYS_PARAM_H) || defined(__HIUX_MPP__)
80# include <sys/param.h>
81#endif
82
83#if !defined NOFILE
84# define NOFILE 64
85#endif
86
87#ifdef HAVE_UNISTD_H
88#include <unistd.h>
89#endif
90
91#ifdef HAVE_SYSCALL_H
92#include <syscall.h>
93#elif defined HAVE_SYS_SYSCALL_H
94#include <sys/syscall.h>
95#endif
96
97#ifdef HAVE_SYS_UIO_H
98#include <sys/uio.h>
99#endif
100
101#ifdef HAVE_SYS_WAIT_H
102# include <sys/wait.h> /* for WNOHANG on BSD */
103#endif
104
105#ifdef HAVE_COPYFILE_H
106# include <copyfile.h>
107
108# ifndef COPYFILE_STATE_COPIED
109/*
110 * Some OSes (e.g., OSX < 10.6) implement fcopyfile() but not
111 * COPYFILE_STATE_COPIED. Since the only use of the former here
112 * requires the latter, we disable the former when the latter is undefined.
113 */
114# undef HAVE_FCOPYFILE
115# endif
116
117#endif
118
120#include "ccan/list/list.h"
121#include "dln.h"
122#include "encindex.h"
123#include "id.h"
124#include "internal.h"
125#include "internal/class.h"
126#include "internal/encoding.h"
127#include "internal/error.h"
128#include "internal/inits.h"
129#include "internal/io.h"
130#include "internal/numeric.h"
131#include "internal/object.h"
132#include "internal/process.h"
133#include "internal/thread.h"
134#include "internal/transcode.h"
135#include "internal/variable.h"
136#include "ruby/io.h"
137#include "ruby/io/buffer.h"
138#include "ruby/missing.h"
139#include "ruby/thread.h"
140#include "ruby/util.h"
141#include "ruby_atomic.h"
142#include "ruby/ractor.h"
143
144#if !USE_POLL
145# include "vm_core.h"
146#endif
147
148#include "builtin.h"
149
150#ifndef O_ACCMODE
151#define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR)
152#endif
153
154#ifndef PIPE_BUF
155# ifdef _POSIX_PIPE_BUF
156# define PIPE_BUF _POSIX_PIPE_BUF
157# else
158# define PIPE_BUF 512 /* is this ok? */
159# endif
160#endif
161
162#ifndef EWOULDBLOCK
163# define EWOULDBLOCK EAGAIN
164#endif
165
166#if defined(HAVE___SYSCALL) && (defined(__APPLE__) || defined(__OpenBSD__))
167/* Mac OS X and OpenBSD have __syscall but don't define it in headers */
168off_t __syscall(quad_t number, ...);
169#endif
170
171#define IO_RBUF_CAPA_MIN 8192
172#define IO_CBUF_CAPA_MIN (128*1024)
173#define IO_RBUF_CAPA_FOR(fptr) (NEED_READCONV(fptr) ? IO_CBUF_CAPA_MIN : IO_RBUF_CAPA_MIN)
174#define IO_WBUF_CAPA_MIN 8192
175
176#define IO_MAX_BUFFER_GROWTH 8 * 1024 * 1024 // 8MB
177
178/* define system APIs */
179#ifdef _WIN32
180#undef open
181#define open rb_w32_uopen
182#undef rename
183#define rename(f, t) rb_w32_urename((f), (t))
184#include "win32/file.h"
185#endif
186
193
194static VALUE rb_eEAGAINWaitReadable;
195static VALUE rb_eEAGAINWaitWritable;
196static VALUE rb_eEWOULDBLOCKWaitReadable;
197static VALUE rb_eEWOULDBLOCKWaitWritable;
198static VALUE rb_eEINPROGRESSWaitWritable;
199static VALUE rb_eEINPROGRESSWaitReadable;
200
202static VALUE orig_stdout, orig_stderr;
203
205VALUE rb_rs;
208
209static VALUE argf;
210
211static ID id_write, id_read, id_getc, id_flush, id_readpartial, id_set_encoding, id_fileno;
212static VALUE sym_mode, sym_perm, sym_flags, sym_extenc, sym_intenc, sym_encoding, sym_open_args;
213static VALUE sym_textmode, sym_binmode, sym_autoclose;
214static VALUE sym_SET, sym_CUR, sym_END;
215static VALUE sym_wait_readable, sym_wait_writable;
216#ifdef SEEK_DATA
217static VALUE sym_DATA;
218#endif
219#ifdef SEEK_HOLE
220static VALUE sym_HOLE;
221#endif
222
223static VALUE prep_io(int fd, enum rb_io_mode fmode, VALUE klass, const char *path);
224
225VALUE
226rb_io_blocking_region_wait(struct rb_io *io, rb_blocking_function_t *function, void *argument, enum rb_io_event events)
227{
228 return rb_thread_io_blocking_call(io, function, argument, events);
229}
230
231VALUE rb_io_blocking_region(struct rb_io *io, rb_blocking_function_t *function, void *argument)
232{
233 return rb_io_blocking_region_wait(io, function, argument, 0);
234}
235
236struct argf {
237 VALUE filename, current_file;
238 long last_lineno; /* $. */
239 long lineno;
240 VALUE argv;
241 VALUE inplace;
242 struct rb_io_encoding encs;
243 int8_t init_p, next_p, binmode;
244};
245
246static rb_atomic_t max_file_descriptor = NOFILE;
247void
249{
250 rb_atomic_t afd = (rb_atomic_t)fd;
251 rb_atomic_t max_fd = max_file_descriptor;
252 int err;
253
254 if (fd < 0 || afd <= max_fd)
255 return;
256
257#if defined(HAVE_FCNTL) && defined(F_GETFL)
258 err = fcntl(fd, F_GETFL) == -1;
259#else
260 {
261 struct stat buf;
262 err = fstat(fd, &buf) != 0;
263 }
264#endif
265 if (err && errno == EBADF) {
266 rb_bug("rb_update_max_fd: invalid fd (%d) given.", fd);
267 }
268
269 while (max_fd < afd) {
270 max_fd = ATOMIC_CAS(max_file_descriptor, max_fd, afd);
271 }
272}
273
274void
275rb_maygvl_fd_fix_cloexec(int fd)
276{
277 /* MinGW don't have F_GETFD and FD_CLOEXEC. [ruby-core:40281] */
278#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
279 int flags, flags2, ret;
280 flags = fcntl(fd, F_GETFD); /* should not fail except EBADF. */
281 if (flags == -1) {
282 rb_bug("rb_maygvl_fd_fix_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(errno));
283 }
284 if (fd <= 2)
285 flags2 = flags & ~FD_CLOEXEC; /* Clear CLOEXEC for standard file descriptors: 0, 1, 2. */
286 else
287 flags2 = flags | FD_CLOEXEC; /* Set CLOEXEC for non-standard file descriptors: 3, 4, 5, ... */
288 if (flags != flags2) {
289 ret = fcntl(fd, F_SETFD, flags2);
290 if (ret != 0) {
291 rb_bug("rb_maygvl_fd_fix_cloexec: fcntl(%d, F_SETFD, %d) failed: %s", fd, flags2, strerror(errno));
292 }
293 }
294#endif
295}
296
297void
299{
300 rb_maygvl_fd_fix_cloexec(fd);
302}
303
304/* this is only called once */
305static int
306rb_fix_detect_o_cloexec(int fd)
307{
308#if defined(O_CLOEXEC) && defined(F_GETFD)
309 int flags = fcntl(fd, F_GETFD);
310
311 if (flags == -1)
312 rb_bug("rb_fix_detect_o_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(errno));
313
314 if (flags & FD_CLOEXEC)
315 return 1;
316#endif /* fall through if O_CLOEXEC does not work: */
317 rb_maygvl_fd_fix_cloexec(fd);
318 return 0;
319}
320
321static inline bool
322io_again_p(int e)
323{
324 return (e == EWOULDBLOCK) || (e == EAGAIN);
325}
326
327int
328rb_cloexec_open(const char *pathname, int flags, mode_t mode)
329{
330 int ret;
331 static int o_cloexec_state = -1; /* <0: unknown, 0: ignored, >0: working */
332
333 static const int retry_interval = 0;
334 static const int retry_max_count = 10000;
335
336 int retry_count = 0;
337
338#ifdef O_CLOEXEC
339 /* O_CLOEXEC is available since Linux 2.6.23. Linux 2.6.18 silently ignore it. */
340 flags |= O_CLOEXEC;
341#elif defined O_NOINHERIT
342 flags |= O_NOINHERIT;
343#endif
344
345 while ((ret = open(pathname, flags, mode)) == -1) {
346 int e = errno;
347 if (!io_again_p(e)) break;
348 if (retry_count++ >= retry_max_count) break;
349
350 sleep(retry_interval);
351 }
352
353 if (ret < 0) return ret;
354 if (ret <= 2 || o_cloexec_state == 0) {
355 rb_maygvl_fd_fix_cloexec(ret);
356 }
357 else if (o_cloexec_state > 0) {
358 return ret;
359 }
360 else {
361 o_cloexec_state = rb_fix_detect_o_cloexec(ret);
362 }
363 return ret;
364}
365
366int
368{
369 /* Don't allocate standard file descriptors: 0, 1, 2 */
370 return rb_cloexec_fcntl_dupfd(oldfd, 3);
371}
372
373int
374rb_cloexec_dup2(int oldfd, int newfd)
375{
376 int ret;
377
378 /* When oldfd == newfd, dup2 succeeds but dup3 fails with EINVAL.
379 * rb_cloexec_dup2 succeeds as dup2. */
380 if (oldfd == newfd) {
381 ret = newfd;
382 }
383 else {
384#if defined(HAVE_DUP3) && defined(O_CLOEXEC)
385 static int try_dup3 = 1;
386 if (2 < newfd && try_dup3) {
387 ret = dup3(oldfd, newfd, O_CLOEXEC);
388 if (ret != -1)
389 return ret;
390 /* dup3 is available since Linux 2.6.27, glibc 2.9. */
391 if (errno == ENOSYS) {
392 try_dup3 = 0;
393 ret = dup2(oldfd, newfd);
394 }
395 }
396 else {
397 ret = dup2(oldfd, newfd);
398 }
399#else
400 ret = dup2(oldfd, newfd);
401#endif
402 if (ret < 0) return ret;
403 }
404 rb_maygvl_fd_fix_cloexec(ret);
405 return ret;
406}
407
408static int
409rb_fd_set_nonblock(int fd)
410{
411#ifdef _WIN32
412 return rb_w32_set_nonblock(fd);
413#elif defined(F_GETFL)
414 int oflags = fcntl(fd, F_GETFL);
415
416 if (oflags == -1)
417 return -1;
418 if (oflags & O_NONBLOCK)
419 return 0;
420 oflags |= O_NONBLOCK;
421 return fcntl(fd, F_SETFL, oflags);
422#endif
423 return 0;
424}
425
426int
427rb_cloexec_pipe(int descriptors[2])
428{
429#ifdef HAVE_PIPE2
430 int result = pipe2(descriptors, O_CLOEXEC | O_NONBLOCK);
431#else
432 int result = pipe(descriptors);
433#endif
434
435 if (result < 0)
436 return result;
437
438#ifdef __CYGWIN__
439 if (result == 0 && descriptors[1] == -1) {
440 close(descriptors[0]);
441 descriptors[0] = -1;
442 errno = ENFILE;
443 return -1;
444 }
445#endif
446
447#ifndef HAVE_PIPE2
448 rb_maygvl_fd_fix_cloexec(descriptors[0]);
449 rb_maygvl_fd_fix_cloexec(descriptors[1]);
450
451#ifndef _WIN32
452 rb_fd_set_nonblock(descriptors[0]);
453 rb_fd_set_nonblock(descriptors[1]);
454#endif
455#endif
456
457 return result;
458}
459
460int
461rb_cloexec_fcntl_dupfd(int fd, int minfd)
462{
463 int ret;
464
465#if defined(HAVE_FCNTL) && defined(F_DUPFD_CLOEXEC) && defined(F_DUPFD)
466 static int try_dupfd_cloexec = 1;
467 if (try_dupfd_cloexec) {
468 ret = fcntl(fd, F_DUPFD_CLOEXEC, minfd);
469 if (ret != -1) {
470 if (ret <= 2)
471 rb_maygvl_fd_fix_cloexec(ret);
472 return ret;
473 }
474 /* F_DUPFD_CLOEXEC is available since Linux 2.6.24. Linux 2.6.18 fails with EINVAL */
475 if (errno == EINVAL) {
476 ret = fcntl(fd, F_DUPFD, minfd);
477 if (ret != -1) {
478 try_dupfd_cloexec = 0;
479 }
480 }
481 }
482 else {
483 ret = fcntl(fd, F_DUPFD, minfd);
484 }
485#elif defined(HAVE_FCNTL) && defined(F_DUPFD)
486 ret = fcntl(fd, F_DUPFD, minfd);
487#else
488 ret = dup(fd);
489 if (ret >= 0 && ret < minfd) {
490 const int prev_fd = ret;
491 ret = rb_cloexec_fcntl_dupfd(fd, minfd);
492 close(prev_fd);
493 }
494 return ret;
495#endif
496 if (ret < 0) return ret;
497 rb_maygvl_fd_fix_cloexec(ret);
498 return ret;
499}
500
501#define argf_of(obj) (*(struct argf *)DATA_PTR(obj))
502#define ARGF argf_of(argf)
503
504#define GetWriteIO(io) rb_io_get_write_io(io)
505
506#define READ_DATA_PENDING(fptr) ((fptr)->rbuf.len)
507#define READ_DATA_PENDING_COUNT(fptr) ((fptr)->rbuf.len)
508#define READ_DATA_PENDING_PTR(fptr) ((fptr)->rbuf.ptr+(fptr)->rbuf.off)
509#define READ_DATA_BUFFERED(fptr) READ_DATA_PENDING(fptr)
510
511#define READ_CHAR_PENDING(fptr) ((fptr)->cbuf.len)
512#define READ_CHAR_PENDING_COUNT(fptr) ((fptr)->cbuf.len)
513#define READ_CHAR_PENDING_PTR(fptr) ((fptr)->cbuf.ptr+(fptr)->cbuf.off)
514
515#if defined(_WIN32)
516#define WAIT_FD_IN_WIN32(fptr) \
517 (rb_w32_io_cancelable_p((fptr)->fd) ? Qnil : rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_READABLE), RUBY_IO_TIMEOUT_DEFAULT))
518#else
519#define WAIT_FD_IN_WIN32(fptr)
520#endif
521
522#define READ_CHECK(fptr) do {\
523 if (!READ_DATA_PENDING(fptr)) {\
524 WAIT_FD_IN_WIN32(fptr);\
525 rb_io_check_closed(fptr);\
526 }\
527} while(0)
528
529#ifndef S_ISSOCK
530# ifdef _S_ISSOCK
531# define S_ISSOCK(m) _S_ISSOCK(m)
532# else
533# ifdef _S_IFSOCK
534# define S_ISSOCK(m) (((m) & S_IFMT) == _S_IFSOCK)
535# else
536# ifdef S_IFSOCK
537# define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
538# endif
539# endif
540# endif
541#endif
542
543static int io_fflush(rb_io_t *);
544static rb_io_t *flush_before_seek(rb_io_t *fptr, bool discard_rbuf);
545static void clear_codeconv(rb_io_t *fptr);
546
547#define FMODE_SIGNAL_ON_EPIPE (1<<17)
548
549#define fptr_signal_on_epipe(fptr) \
550 (((fptr)->mode & FMODE_SIGNAL_ON_EPIPE) != 0)
551
552#define fptr_set_signal_on_epipe(fptr, flag) \
553 ((flag) ? \
554 (fptr)->mode |= FMODE_SIGNAL_ON_EPIPE : \
555 (fptr)->mode &= ~FMODE_SIGNAL_ON_EPIPE)
556
557extern ID ruby_static_id_signo;
558
559NORETURN(static void rb_sys_fail_on_write(rb_io_t *fptr));
560static void
561rb_sys_fail_on_write(rb_io_t *fptr)
562{
563 int e = errno;
564 VALUE errinfo = rb_syserr_new_path(e, (fptr)->pathv);
565#if defined EPIPE
566 if (fptr_signal_on_epipe(fptr) && (e == EPIPE)) {
567 const VALUE sig =
568# if defined SIGPIPE
569 INT2FIX(SIGPIPE) - INT2FIX(0) +
570# endif
571 INT2FIX(0);
572 rb_ivar_set(errinfo, ruby_static_id_signo, sig);
573 }
574#endif
575 rb_exc_raise(errinfo);
576}
577
578#define NEED_NEWLINE_DECORATOR_ON_READ(fptr) ((fptr)->mode & FMODE_TEXTMODE)
579#define NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) ((fptr)->mode & FMODE_TEXTMODE)
580#if defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32)
581# define RUBY_CRLF_ENVIRONMENT 1
582#else
583# define RUBY_CRLF_ENVIRONMENT 0
584#endif
585
586#if RUBY_CRLF_ENVIRONMENT
587/* Windows */
588# define DEFAULT_TEXTMODE FMODE_TEXTMODE
589# define TEXTMODE_NEWLINE_DECORATOR_ON_WRITE ECONV_CRLF_NEWLINE_DECORATOR
590/*
591 * CRLF newline is set as default newline decorator.
592 * If only CRLF newline conversion is needed, we use binary IO process
593 * with OS's text mode for IO performance improvement.
594 * If encoding conversion is needed or a user sets text mode, we use encoding
595 * conversion IO process and universal newline decorator by default.
596 */
597#define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || (fptr)->encs.ecflags & ~ECONV_CRLF_NEWLINE_DECORATOR)
598#define WRITECONV_MASK ( \
599 (ECONV_DECORATOR_MASK & ~ECONV_CRLF_NEWLINE_DECORATOR)|\
600 ECONV_STATEFUL_DECORATOR_MASK|\
601 0)
602#define NEED_WRITECONV(fptr) ( \
603 ((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || \
604 ((fptr)->encs.ecflags & WRITECONV_MASK) || \
605 0)
606#define SET_BINARY_MODE(fptr) setmode((fptr)->fd, O_BINARY)
607
608#define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) do {\
609 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {\
610 if (((fptr)->mode & FMODE_READABLE) &&\
611 !((fptr)->encs.ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {\
612 setmode((fptr)->fd, O_BINARY);\
613 }\
614 else {\
615 setmode((fptr)->fd, O_TEXT);\
616 }\
617 }\
618} while(0)
619
620#define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) do {\
621 if ((enc2) && ((ecflags) & ECONV_DEFAULT_NEWLINE_DECORATOR)) {\
622 (ecflags) |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;\
623 }\
624} while(0)
625
626/*
627 * IO unread with taking care of removed '\r' in text mode.
628 */
629static void
630io_unread(rb_io_t *fptr, bool discard_rbuf)
631{
632 rb_off_t r, pos;
633 ssize_t read_size;
634 long i;
635 long newlines = 0;
636 long extra_max;
637 char *p;
638 char *buf;
639
640 rb_io_check_closed(fptr);
641 if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX) {
642 return;
643 }
644
645 errno = 0;
646 if (!rb_w32_fd_is_text(fptr->fd)) {
647 r = lseek(fptr->fd, -fptr->rbuf.len, SEEK_CUR);
648 if (r < 0 && errno) {
649 if (errno == ESPIPE)
650 fptr->mode |= FMODE_DUPLEX;
651 if (!discard_rbuf) return;
652 }
653
654 goto end;
655 }
656
657 pos = lseek(fptr->fd, 0, SEEK_CUR);
658 if (pos < 0 && errno) {
659 if (errno == ESPIPE)
660 fptr->mode |= FMODE_DUPLEX;
661 if (!discard_rbuf) goto end;
662 }
663
664 /* add extra offset for removed '\r' in rbuf */
665 extra_max = (long)(pos - fptr->rbuf.len);
666 p = fptr->rbuf.ptr + fptr->rbuf.off;
667
668 /* if the end of rbuf is '\r', rbuf doesn't have '\r' within rbuf.len */
669 if (*(fptr->rbuf.ptr + fptr->rbuf.capa - 1) == '\r') {
670 newlines++;
671 }
672
673 for (i = 0; i < fptr->rbuf.len; i++) {
674 if (*p == '\n') newlines++;
675 if (extra_max == newlines) break;
676 p++;
677 }
678
679 buf = ALLOC_N(char, fptr->rbuf.len + newlines);
680 while (newlines >= 0) {
681 r = lseek(fptr->fd, pos - fptr->rbuf.len - newlines, SEEK_SET);
682 if (newlines == 0) break;
683 if (r < 0) {
684 newlines--;
685 continue;
686 }
687 read_size = _read(fptr->fd, buf, fptr->rbuf.len + newlines);
688 if (read_size < 0) {
689 int e = errno;
690 free(buf);
691 rb_syserr_fail_path(e, fptr->pathv);
692 }
693 if (read_size == fptr->rbuf.len) {
694 lseek(fptr->fd, r, SEEK_SET);
695 break;
696 }
697 else {
698 newlines--;
699 }
700 }
701 free(buf);
702 end:
703 fptr->rbuf.off = 0;
704 fptr->rbuf.len = 0;
705 clear_codeconv(fptr);
706 return;
707}
708
709/*
710 * We use io_seek to back cursor position when changing mode from text to binary,
711 * but stdin and pipe cannot seek back. Stdin and pipe read should use encoding
712 * conversion for working properly with mode change.
713 *
714 * Return previous translation mode.
715 */
716static inline int
717set_binary_mode_with_seek_cur(rb_io_t *fptr)
718{
719 if (!rb_w32_fd_is_text(fptr->fd)) return O_BINARY;
720
721 if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX) {
722 return setmode(fptr->fd, O_BINARY);
723 }
724 flush_before_seek(fptr, false);
725 return setmode(fptr->fd, O_BINARY);
726}
727#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) set_binary_mode_with_seek_cur(fptr)
728
729#else
730/* Unix */
731# define DEFAULT_TEXTMODE 0
732#define NEED_READCONV(fptr) ((fptr)->encs.enc2 != NULL || NEED_NEWLINE_DECORATOR_ON_READ(fptr))
733#define NEED_WRITECONV(fptr) ( \
734 ((fptr)->encs.enc != NULL && (fptr)->encs.enc != rb_ascii8bit_encoding()) || \
735 NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) || \
736 ((fptr)->encs.ecflags & (ECONV_DECORATOR_MASK|ECONV_STATEFUL_DECORATOR_MASK)) || \
737 0)
738#define SET_BINARY_MODE(fptr) (void)(fptr)
739#define NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr) (void)(fptr)
740#define SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags) ((void)(enc2), (void)(ecflags))
741#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) (void)(fptr)
742#endif
743
744#if !defined HAVE_SHUTDOWN && !defined shutdown
745#define shutdown(a,b) 0
746#endif
747
748#if defined(_WIN32)
749#define is_socket(fd, path) rb_w32_is_socket(fd)
750#elif !defined(S_ISSOCK)
751#define is_socket(fd, path) 0
752#else
753static int
754is_socket(int fd, VALUE path)
755{
756 struct stat sbuf;
757 if (fstat(fd, &sbuf) < 0)
758 rb_sys_fail_path(path);
759 return S_ISSOCK(sbuf.st_mode);
760}
761#endif
762
763static const char closed_stream[] = "closed stream";
764
765static void
766io_fd_check_closed(int fd)
767{
768 if (fd < 0) {
769 rb_thread_check_ints(); /* check for ruby_error_stream_closed */
770 rb_raise(rb_eIOError, closed_stream);
771 }
772}
773
774void
775rb_eof_error(void)
776{
777 rb_raise(rb_eEOFError, "end of file reached");
778}
779
780VALUE
782{
783 rb_check_frozen(io);
784 return io;
785}
786
787void
789{
790 if (!fptr) {
791 rb_raise(rb_eIOError, "uninitialized stream");
792 }
793}
794
795void
797{
799 io_fd_check_closed(fptr->fd);
800}
801
802static rb_io_t *
803rb_io_get_fptr(VALUE io)
804{
805 rb_io_t *fptr = RFILE(io)->fptr;
807 return fptr;
808}
809
810VALUE
812{
813 return rb_convert_type_with_id(io, T_FILE, "IO", idTo_io);
814}
815
816VALUE
818{
819 return rb_check_convert_type_with_id(io, T_FILE, "IO", idTo_io);
820}
821
822VALUE
824{
825 VALUE write_io;
826 write_io = rb_io_get_fptr(io)->tied_io_for_writing;
827 if (write_io) {
828 return write_io;
829 }
830 return io;
831}
832
833VALUE
835{
836 VALUE write_io;
837 rb_io_t *fptr = rb_io_get_fptr(io);
838 if (!RTEST(w)) {
839 w = 0;
840 }
841 else {
842 GetWriteIO(w);
843 }
844 write_io = fptr->tied_io_for_writing;
845 fptr->tied_io_for_writing = w;
846 return write_io ? write_io : Qnil;
847}
848
849/*
850 * call-seq:
851 * timeout -> duration or nil
852 *
853 * Get the internal timeout duration or nil if it was not set.
854 *
855 */
856VALUE
858{
859 rb_io_t *fptr = rb_io_get_fptr(self);
860
861 return fptr->timeout;
862}
863
864/*
865 * call-seq:
866 * timeout = duration -> duration
867 * timeout = nil -> nil
868 *
869 * Sets the internal timeout to the specified duration or nil. The timeout
870 * applies to all blocking operations where possible.
871 *
872 * When the operation performs longer than the timeout set, IO::TimeoutError
873 * is raised.
874 *
875 * This affects the following methods (but is not limited to): #gets, #puts,
876 * #read, #write, #wait_readable and #wait_writable. This also affects
877 * blocking socket operations like Socket#accept and Socket#connect.
878 *
879 * Some operations like File#open and IO#close are not affected by the
880 * timeout. A timeout during a write operation may leave the IO in an
881 * inconsistent state, e.g. data was partially written. Generally speaking, a
882 * timeout is a last ditch effort to prevent an application from hanging on
883 * slow I/O operations, such as those that occur during a slowloris attack.
884 */
885VALUE
887{
888 // Validate it:
889 if (RTEST(timeout)) {
890 rb_time_interval(timeout);
891 }
892
893 rb_io_t *fptr = rb_io_get_fptr(self);
894
895 fptr->timeout = timeout;
896
897 return self;
898}
899
900/*
901 * call-seq:
902 * IO.try_convert(object) -> new_io or nil
903 *
904 * Attempts to convert +object+ into an \IO object via method +to_io+;
905 * returns the new \IO object if successful, or +nil+ otherwise:
906 *
907 * IO.try_convert(STDOUT) # => #<IO:<STDOUT>>
908 * IO.try_convert(ARGF) # => #<IO:<STDIN>>
909 * IO.try_convert('STDOUT') # => nil
910 *
911 */
912static VALUE
913rb_io_s_try_convert(VALUE dummy, VALUE io)
914{
915 return rb_io_check_io(io);
916}
917
918#if !RUBY_CRLF_ENVIRONMENT
919static void
920io_unread(rb_io_t *fptr, bool discard_rbuf)
921{
922 rb_off_t r;
923 rb_io_check_closed(fptr);
924 if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX)
925 return;
926 /* xxx: target position may be negative if buffer is filled by ungetc */
927 errno = 0;
928 r = lseek(fptr->fd, -fptr->rbuf.len, SEEK_CUR);
929 if (r < 0 && errno) {
930 if (errno == ESPIPE)
931 fptr->mode |= FMODE_DUPLEX;
932 if (!discard_rbuf) return;
933 }
934 fptr->rbuf.off = 0;
935 fptr->rbuf.len = 0;
936 clear_codeconv(fptr);
937 return;
938}
939#endif
940
941static rb_encoding *io_input_encoding(rb_io_t *fptr);
942
943static void
944io_ungetbyte(VALUE str, rb_io_t *fptr)
945{
946 long len = RSTRING_LEN(str);
947
948 if (fptr->rbuf.ptr == NULL) {
949 const int min_capa = IO_RBUF_CAPA_FOR(fptr);
950 fptr->rbuf.off = 0;
951 fptr->rbuf.len = 0;
952#if SIZEOF_LONG > SIZEOF_INT
953 if (len > INT_MAX)
954 rb_raise(rb_eIOError, "ungetbyte failed");
955#endif
956 if (len > min_capa)
957 fptr->rbuf.capa = (int)len;
958 else
959 fptr->rbuf.capa = min_capa;
960 fptr->rbuf.ptr = ALLOC_N(char, fptr->rbuf.capa);
961 }
962 if (fptr->rbuf.capa < len + fptr->rbuf.len) {
963 rb_raise(rb_eIOError, "ungetbyte failed");
964 }
965 if (fptr->rbuf.off < len) {
966 MEMMOVE(fptr->rbuf.ptr+fptr->rbuf.capa-fptr->rbuf.len,
967 fptr->rbuf.ptr+fptr->rbuf.off,
968 char, fptr->rbuf.len);
969 fptr->rbuf.off = fptr->rbuf.capa-fptr->rbuf.len;
970 }
971 fptr->rbuf.off-=(int)len;
972 fptr->rbuf.len+=(int)len;
973 MEMMOVE(fptr->rbuf.ptr+fptr->rbuf.off, RSTRING_PTR(str), char, len);
974}
975
976static rb_io_t *
977flush_before_seek(rb_io_t *fptr, bool discard_rbuf)
978{
979 if (io_fflush(fptr) < 0)
980 rb_sys_fail_on_write(fptr);
981 io_unread(fptr, discard_rbuf);
982 errno = 0;
983 return fptr;
984}
985
986#define io_seek(fptr, ofs, whence) (errno = 0, lseek(flush_before_seek(fptr, true)->fd, (ofs), (whence)))
987#define io_tell(fptr) lseek(flush_before_seek(fptr, false)->fd, 0, SEEK_CUR)
988
989#ifndef SEEK_CUR
990# define SEEK_SET 0
991# define SEEK_CUR 1
992# define SEEK_END 2
993#endif
994
995void
997{
998 rb_io_check_closed(fptr);
999 if (!(fptr->mode & FMODE_READABLE)) {
1000 rb_raise(rb_eIOError, "not opened for reading");
1001 }
1002 if (fptr->wbuf.len) {
1003 if (io_fflush(fptr) < 0)
1004 rb_sys_fail_on_write(fptr);
1005 }
1006 if (fptr->tied_io_for_writing) {
1007 rb_io_t *wfptr;
1008 GetOpenFile(fptr->tied_io_for_writing, wfptr);
1009 if (io_fflush(wfptr) < 0)
1010 rb_sys_fail_on_write(wfptr);
1011 }
1012}
1013
1014void
1016{
1018 if (READ_CHAR_PENDING(fptr)) {
1019 rb_raise(rb_eIOError, "byte oriented read for character buffered IO");
1020 }
1021}
1022
1023void
1028
1029static rb_encoding*
1030io_read_encoding(rb_io_t *fptr)
1031{
1032 if (fptr->encs.enc) {
1033 return fptr->encs.enc;
1034 }
1035 return rb_default_external_encoding();
1036}
1037
1038static rb_encoding*
1039io_input_encoding(rb_io_t *fptr)
1040{
1041 if (fptr->encs.enc2) {
1042 return fptr->encs.enc2;
1043 }
1044 return io_read_encoding(fptr);
1045}
1046
1047void
1049{
1050 rb_io_check_closed(fptr);
1051 if (!(fptr->mode & FMODE_WRITABLE)) {
1052 rb_raise(rb_eIOError, "not opened for writing");
1053 }
1054 if (fptr->rbuf.len) {
1055 io_unread(fptr, true);
1056 }
1057}
1058
1059int
1060rb_io_read_pending(rb_io_t *fptr)
1061{
1062 /* This function is used for bytes and chars. Confusing. */
1063 if (READ_CHAR_PENDING(fptr))
1064 return 1; /* should raise? */
1065 return READ_DATA_PENDING(fptr);
1066}
1067
1068void
1070{
1071 if (!READ_DATA_PENDING(fptr)) {
1072 rb_io_wait(fptr->self, RB_INT2NUM(RUBY_IO_READABLE), RUBY_IO_TIMEOUT_DEFAULT);
1073 }
1074 return;
1075}
1076
1077int
1078rb_gc_for_fd(int err)
1079{
1080 if (err == EMFILE || err == ENFILE || err == ENOMEM) {
1081 rb_gc();
1082 return 1;
1083 }
1084 return 0;
1085}
1086
1087/* try `expr` upto twice while it returns false and `errno`
1088 * is to GC. Each `errno`s are available as `first_errno` and
1089 * `retried_errno` respectively */
1090#define TRY_WITH_GC(expr) \
1091 for (int first_errno, retried_errno = 0, retried = 0; \
1092 (!retried && \
1093 !(expr) && \
1094 (!rb_gc_for_fd(first_errno = errno) || !(expr)) && \
1095 (retried_errno = errno, 1)); \
1096 (void)retried_errno, retried = 1)
1097
1098static int
1099ruby_dup(int orig)
1100{
1101 int fd = -1;
1102
1103 TRY_WITH_GC((fd = rb_cloexec_dup(orig)) >= 0) {
1104 rb_syserr_fail(first_errno, 0);
1105 }
1106 rb_update_max_fd(fd);
1107 return fd;
1108}
1109
1110static VALUE
1111io_alloc(VALUE klass)
1112{
1113 NEWOBJ_OF(io, struct RFile, klass, T_FILE, sizeof(struct RFile), 0);
1114
1115 io->fptr = 0;
1116
1117 return (VALUE)io;
1118}
1119
1120#ifndef S_ISREG
1121# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
1122#endif
1123
1125 VALUE th;
1126 rb_io_t *fptr;
1127 int nonblock;
1128 int fd;
1129
1130 void *buf;
1131 size_t capa;
1132 struct timeval *timeout;
1133};
1134
1136 VALUE th;
1137 rb_io_t *fptr;
1138 int nonblock;
1139 int fd;
1140
1141 const void *buf;
1142 size_t capa;
1143 struct timeval *timeout;
1144};
1145
1146#ifdef HAVE_WRITEV
1147struct io_internal_writev_struct {
1148 VALUE th;
1149 rb_io_t *fptr;
1150 int nonblock;
1151 int fd;
1152
1153 int iovcnt;
1154 const struct iovec *iov;
1155 struct timeval *timeout;
1156};
1157#endif
1158
1159static int nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout);
1160
1166static inline int
1167io_internal_wait(VALUE thread, rb_io_t *fptr, int error, int events, struct timeval *timeout)
1168{
1169 if (!timeout && rb_thread_mn_schedulable(thread)) {
1170 RUBY_ASSERT(errno == EWOULDBLOCK || errno == EAGAIN);
1171 return -1;
1172 }
1173
1174 int ready = nogvl_wait_for(thread, fptr, events, timeout);
1175
1176 if (ready > 0) {
1177 return ready;
1178 }
1179 else if (ready == 0) {
1180 errno = ETIMEDOUT;
1181 return -1;
1182 }
1183
1184 // If there was an error BEFORE we started waiting, return it:
1185 if (error) {
1186 errno = error;
1187 return -1;
1188 }
1189 else {
1190 // Otherwise, whatever error was generated by `nogvl_wait_for` is the one we want:
1191 return ready;
1192 }
1193}
1194
1195static VALUE
1196internal_read_func(void *ptr)
1197{
1198 struct io_internal_read_struct *iis = ptr;
1199 ssize_t result;
1200
1201 if (iis->timeout && !iis->nonblock) {
1202 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_IN, iis->timeout) == -1) {
1203 return -1;
1204 }
1205 }
1206
1207 retry:
1208 result = read(iis->fd, iis->buf, iis->capa);
1209
1210 if (result < 0 && !iis->nonblock) {
1211 if (io_again_p(errno)) {
1212 if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_IN, iis->timeout) == -1) {
1213 return -1;
1214 }
1215 else {
1216 goto retry;
1217 }
1218 }
1219 }
1220
1221 return result;
1222}
1223
1224#if defined __APPLE__
1225# define do_write_retry(code) do {result = code;} while (result == -1 && errno == EPROTOTYPE)
1226#else
1227# define do_write_retry(code) result = code
1228#endif
1229
1230static VALUE
1231internal_write_func(void *ptr)
1232{
1233 struct io_internal_write_struct *iis = ptr;
1234 ssize_t result;
1235
1236 if (iis->timeout && !iis->nonblock) {
1237 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1238 return -1;
1239 }
1240 }
1241
1242 retry:
1243 do_write_retry(write(iis->fd, iis->buf, iis->capa));
1244
1245 if (result < 0 && !iis->nonblock) {
1246 int e = errno;
1247 if (io_again_p(e)) {
1248 if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1249 return -1;
1250 }
1251 else {
1252 goto retry;
1253 }
1254 }
1255 }
1256
1257 return result;
1258}
1259
1260#ifdef HAVE_WRITEV
1261static VALUE
1262internal_writev_func(void *ptr)
1263{
1264 struct io_internal_writev_struct *iis = ptr;
1265 ssize_t result;
1266
1267 if (iis->timeout && !iis->nonblock) {
1268 if (io_internal_wait(iis->th, iis->fptr, 0, RB_WAITFD_OUT, iis->timeout) == -1) {
1269 return -1;
1270 }
1271 }
1272
1273 retry:
1274 do_write_retry(writev(iis->fd, iis->iov, iis->iovcnt));
1275
1276 if (result < 0 && !iis->nonblock) {
1277 if (io_again_p(errno)) {
1278 if (io_internal_wait(iis->th, iis->fptr, errno, RB_WAITFD_OUT, iis->timeout) == -1) {
1279 return -1;
1280 }
1281 else {
1282 goto retry;
1283 }
1284 }
1285 }
1286
1287 return result;
1288}
1289#endif
1290
1291static ssize_t
1292rb_io_read_memory(rb_io_t *fptr, void *buf, size_t count)
1293{
1294 VALUE scheduler = rb_fiber_scheduler_current();
1295 if (scheduler != Qnil) {
1296 VALUE result = rb_fiber_scheduler_io_read_memory(scheduler, fptr->self, buf, count, 0);
1297
1298 if (!UNDEF_P(result)) {
1300 }
1301 }
1302
1303 struct io_internal_read_struct iis = {
1304 .th = rb_thread_current(),
1305 .fptr = fptr,
1306 .nonblock = 0,
1307 .fd = fptr->fd,
1308
1309 .buf = buf,
1310 .capa = count,
1311 .timeout = NULL,
1312 };
1313
1314 struct timeval timeout_storage;
1315
1316 if (fptr->timeout != Qnil) {
1317 timeout_storage = rb_time_interval(fptr->timeout);
1318 iis.timeout = &timeout_storage;
1319 }
1320
1321 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_read_func, &iis, RUBY_IO_READABLE);
1322}
1323
1324static ssize_t
1325rb_io_write_memory(rb_io_t *fptr, const void *buf, size_t count)
1326{
1327 VALUE scheduler = rb_fiber_scheduler_current();
1328 if (scheduler != Qnil) {
1329 VALUE result = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, buf, count, 0);
1330
1331 if (!UNDEF_P(result)) {
1333 }
1334 }
1335
1336 struct io_internal_write_struct iis = {
1337 .th = rb_thread_current(),
1338 .fptr = fptr,
1339 .nonblock = 0,
1340 .fd = fptr->fd,
1341
1342 .buf = buf,
1343 .capa = count,
1344 .timeout = NULL
1345 };
1346
1347 struct timeval timeout_storage;
1348
1349 if (fptr->timeout != Qnil) {
1350 timeout_storage = rb_time_interval(fptr->timeout);
1351 iis.timeout = &timeout_storage;
1352 }
1353
1354 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_write_func, &iis, RUBY_IO_WRITABLE);
1355}
1356
1357#ifdef HAVE_WRITEV
1358static ssize_t
1359rb_writev_internal(rb_io_t *fptr, const struct iovec *iov, int iovcnt)
1360{
1361 if (!iovcnt) return 0;
1362
1363 VALUE scheduler = rb_fiber_scheduler_current();
1364 if (scheduler != Qnil) {
1365 // This path assumes at least one `iov`:
1366 VALUE result = rb_fiber_scheduler_io_write_memory(scheduler, fptr->self, iov[0].iov_base, iov[0].iov_len, 0);
1367
1368 if (!UNDEF_P(result)) {
1370 }
1371 }
1372
1373 struct io_internal_writev_struct iis = {
1374 .th = rb_thread_current(),
1375 .fptr = fptr,
1376 .nonblock = 0,
1377 .fd = fptr->fd,
1378
1379 .iov = iov,
1380 .iovcnt = iovcnt,
1381 .timeout = NULL
1382 };
1383
1384 struct timeval timeout_storage;
1385
1386 if (fptr->timeout != Qnil) {
1387 timeout_storage = rb_time_interval(fptr->timeout);
1388 iis.timeout = &timeout_storage;
1389 }
1390
1391 return (ssize_t)rb_io_blocking_region_wait(fptr, internal_writev_func, &iis, RUBY_IO_WRITABLE);
1392}
1393#endif
1394
1395static VALUE
1396io_flush_buffer_sync(void *arg)
1397{
1398 rb_io_t *fptr = arg;
1399 long l = fptr->wbuf.len;
1400 ssize_t r = write(fptr->fd, fptr->wbuf.ptr+fptr->wbuf.off, (size_t)l);
1401
1402 if (fptr->wbuf.len <= r) {
1403 fptr->wbuf.off = 0;
1404 fptr->wbuf.len = 0;
1405 return 0;
1406 }
1407
1408 if (0 <= r) {
1409 fptr->wbuf.off += (int)r;
1410 fptr->wbuf.len -= (int)r;
1411 errno = EAGAIN;
1412 }
1413
1414 return (VALUE)-1;
1415}
1416
1417static VALUE
1418io_flush_buffer_async(VALUE arg)
1419{
1420 rb_io_t *fptr = (rb_io_t *)arg;
1421 return rb_io_blocking_region_wait(fptr, io_flush_buffer_sync, fptr, RUBY_IO_WRITABLE);
1422}
1423
1424static inline int
1425io_flush_buffer(rb_io_t *fptr)
1426{
1427 if (!NIL_P(fptr->write_lock) && rb_mutex_owned_p(fptr->write_lock)) {
1428 return (int)io_flush_buffer_async((VALUE)fptr);
1429 }
1430 else {
1431 return (int)rb_mutex_synchronize(fptr->write_lock, io_flush_buffer_async, (VALUE)fptr);
1432 }
1433}
1434
1435static int
1436io_fflush(rb_io_t *fptr)
1437{
1438 rb_io_check_closed(fptr);
1439
1440 if (fptr->wbuf.len == 0)
1441 return 0;
1442
1443 while (fptr->wbuf.len > 0 && io_flush_buffer(fptr) != 0) {
1444 if (!rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT))
1445 return -1;
1446
1447 rb_io_check_closed(fptr);
1448 }
1449
1450 return 0;
1451}
1452
1453VALUE
1454rb_io_wait(VALUE io, VALUE events, VALUE timeout)
1455{
1456 VALUE scheduler = rb_fiber_scheduler_current();
1457
1458 if (scheduler != Qnil) {
1459 return rb_fiber_scheduler_io_wait(scheduler, io, events, timeout);
1460 }
1461
1462 rb_io_t * fptr = NULL;
1463 RB_IO_POINTER(io, fptr);
1464
1465 struct timeval tv_storage;
1466 struct timeval *tv = NULL;
1467
1468 if (NIL_OR_UNDEF_P(timeout)) {
1469 timeout = fptr->timeout;
1470 }
1471
1472 if (timeout != Qnil) {
1473 tv_storage = rb_time_interval(timeout);
1474 tv = &tv_storage;
1475 }
1476
1477 int ready = rb_thread_io_wait(fptr, RB_NUM2INT(events), tv);
1478
1479 if (ready < 0) {
1480 rb_sys_fail(0);
1481 }
1482
1483 // Not sure if this is necessary:
1484 rb_io_check_closed(fptr);
1485
1486 if (ready) {
1487 return RB_INT2NUM(ready);
1488 }
1489 else {
1490 return Qfalse;
1491 }
1492}
1493
1494static VALUE
1495io_from_fd(int fd)
1496{
1497 return prep_io(fd, FMODE_EXTERNAL, rb_cIO, NULL);
1498}
1499
1500static int
1501io_wait_for_single_fd(int fd, int events, struct timeval *timeout)
1502{
1503 VALUE scheduler = rb_fiber_scheduler_current();
1504
1505 if (scheduler != Qnil) {
1506 return RTEST(
1507 rb_fiber_scheduler_io_wait(scheduler, io_from_fd(fd), RB_INT2NUM(events), rb_fiber_scheduler_make_timeout(timeout))
1508 );
1509 }
1510
1511 return rb_thread_wait_for_single_fd(fd, events, timeout);
1512}
1513
1514int
1516{
1517 io_fd_check_closed(f);
1518
1519 VALUE scheduler = rb_fiber_scheduler_current();
1520
1521 switch (errno) {
1522 case EINTR:
1523#if defined(ERESTART)
1524 case ERESTART:
1525#endif
1527 return TRUE;
1528
1529 case EAGAIN:
1530#if EWOULDBLOCK != EAGAIN
1531 case EWOULDBLOCK:
1532#endif
1533 if (scheduler != Qnil) {
1534 return RTEST(
1535 rb_fiber_scheduler_io_wait_readable(scheduler, io_from_fd(f))
1536 );
1537 }
1538 else {
1539 io_wait_for_single_fd(f, RUBY_IO_READABLE, NULL);
1540 }
1541 return TRUE;
1542
1543 default:
1544 return FALSE;
1545 }
1546}
1547
1548int
1550{
1551 io_fd_check_closed(f);
1552
1553 VALUE scheduler = rb_fiber_scheduler_current();
1554
1555 switch (errno) {
1556 case EINTR:
1557#if defined(ERESTART)
1558 case ERESTART:
1559#endif
1560 /*
1561 * In old Linux, several special files under /proc and /sys don't handle
1562 * select properly. Thus we need avoid to call if don't use O_NONBLOCK.
1563 * Otherwise, we face nasty hang up. Sigh.
1564 * e.g. https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1565 * https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1566 * In EINTR case, we only need to call RUBY_VM_CHECK_INTS_BLOCKING().
1567 * Then rb_thread_check_ints() is enough.
1568 */
1570 return TRUE;
1571
1572 case EAGAIN:
1573#if EWOULDBLOCK != EAGAIN
1574 case EWOULDBLOCK:
1575#endif
1576 if (scheduler != Qnil) {
1577 return RTEST(
1578 rb_fiber_scheduler_io_wait_writable(scheduler, io_from_fd(f))
1579 );
1580 }
1581 else {
1582 io_wait_for_single_fd(f, RUBY_IO_WRITABLE, NULL);
1583 }
1584 return TRUE;
1585
1586 default:
1587 return FALSE;
1588 }
1589}
1590
1591int
1592rb_wait_for_single_fd(int fd, int events, struct timeval *timeout)
1593{
1594 return io_wait_for_single_fd(fd, events, timeout);
1595}
1596
1597int
1599{
1600 return rb_wait_for_single_fd(fd, RUBY_IO_READABLE, NULL);
1601}
1602
1603int
1605{
1606 return rb_wait_for_single_fd(fd, RUBY_IO_WRITABLE, NULL);
1607}
1608
1609VALUE
1610rb_io_maybe_wait(int error, VALUE io, VALUE events, VALUE timeout)
1611{
1612 // fptr->fd can be set to -1 at any time by another thread when the GVL is
1613 // released. Many code, e.g. `io_bufread` didn't check this correctly and
1614 // instead relies on `read(-1) -> -1` which causes this code path. We then
1615 // check here whether the IO was in fact closed. Probably it's better to
1616 // check that `fptr->fd != -1` before using it in syscall.
1617 rb_io_check_closed(RFILE(io)->fptr);
1618
1619 switch (error) {
1620 // In old Linux, several special files under /proc and /sys don't handle
1621 // select properly. Thus we need avoid to call if don't use O_NONBLOCK.
1622 // Otherwise, we face nasty hang up. Sigh.
1623 // e.g. https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1624 // https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=31b07093c44a7a442394d44423e21d783f5523b8
1625 // In EINTR case, we only need to call RUBY_VM_CHECK_INTS_BLOCKING().
1626 // Then rb_thread_check_ints() is enough.
1627 case EINTR:
1628#if defined(ERESTART)
1629 case ERESTART:
1630#endif
1631 // We might have pending interrupts since the previous syscall was interrupted:
1633
1634 // The operation was interrupted, so retry it immediately:
1635 return events;
1636
1637 case EAGAIN:
1638#if EWOULDBLOCK != EAGAIN
1639 case EWOULDBLOCK:
1640#endif
1641 // The operation would block, so wait for the specified events:
1642 return rb_io_wait(io, events, timeout);
1643
1644 default:
1645 // Non-specific error, no event is ready:
1646 return Qnil;
1647 }
1648}
1649
1650int
1652{
1653 VALUE result = rb_io_maybe_wait(error, io, RB_INT2NUM(RUBY_IO_READABLE), timeout);
1654
1655 if (RTEST(result)) {
1656 return RB_NUM2INT(result);
1657 }
1658 else if (result == RUBY_Qfalse) {
1659 rb_raise(rb_eIOTimeoutError, "Timed out waiting for IO to become readable!");
1660 }
1661
1662 return 0;
1663}
1664
1665int
1667{
1668 VALUE result = rb_io_maybe_wait(error, io, RB_INT2NUM(RUBY_IO_WRITABLE), timeout);
1669
1670 if (RTEST(result)) {
1671 return RB_NUM2INT(result);
1672 }
1673 else if (result == RUBY_Qfalse) {
1674 rb_raise(rb_eIOTimeoutError, "Timed out waiting for IO to become writable!");
1675 }
1676
1677 return 0;
1678}
1679
1680static void
1681make_writeconv(rb_io_t *fptr)
1682{
1683 if (!fptr->writeconv_initialized) {
1684 const char *senc, *denc;
1685 rb_encoding *enc;
1686 int ecflags;
1687 VALUE ecopts;
1688
1689 fptr->writeconv_initialized = 1;
1690
1691 ecflags = fptr->encs.ecflags & ~ECONV_NEWLINE_DECORATOR_READ_MASK;
1692 ecopts = fptr->encs.ecopts;
1693
1694 if (!fptr->encs.enc || (rb_is_ascii8bit_enc(fptr->encs.enc) && !fptr->encs.enc2)) {
1695 /* no encoding conversion */
1696 fptr->writeconv_pre_ecflags = 0;
1697 fptr->writeconv_pre_ecopts = Qnil;
1698 fptr->writeconv = rb_econv_open_opts("", "", ecflags, ecopts);
1699 if (!fptr->writeconv)
1700 rb_exc_raise(rb_econv_open_exc("", "", ecflags));
1702 }
1703 else {
1704 enc = fptr->encs.enc2 ? fptr->encs.enc2 : fptr->encs.enc;
1705 senc = rb_econv_asciicompat_encoding(rb_enc_name(enc));
1706 if (!senc && !(fptr->encs.ecflags & ECONV_STATEFUL_DECORATOR_MASK)) {
1707 /* single conversion */
1708 fptr->writeconv_pre_ecflags = ecflags;
1709 fptr->writeconv_pre_ecopts = ecopts;
1710 fptr->writeconv = NULL;
1712 }
1713 else {
1714 /* double conversion */
1715 fptr->writeconv_pre_ecflags = ecflags & ~ECONV_STATEFUL_DECORATOR_MASK;
1716 fptr->writeconv_pre_ecopts = ecopts;
1717 if (senc) {
1718 denc = rb_enc_name(enc);
1719 fptr->writeconv_asciicompat = rb_str_new2(senc);
1720 }
1721 else {
1722 senc = denc = "";
1723 fptr->writeconv_asciicompat = rb_str_new2(rb_enc_name(enc));
1724 }
1726 ecopts = fptr->encs.ecopts;
1727 fptr->writeconv = rb_econv_open_opts(senc, denc, ecflags, ecopts);
1728 if (!fptr->writeconv)
1729 rb_exc_raise(rb_econv_open_exc(senc, denc, ecflags));
1730 }
1731 }
1732 }
1733}
1734
1735/* writing functions */
1737 rb_io_t *fptr;
1738 const char *ptr;
1739 long length;
1740};
1741
1743 VALUE io;
1744 VALUE str;
1745 int nosync;
1746};
1747
1748#ifdef HAVE_WRITEV
1749static ssize_t
1750io_binwrite_string_internal(rb_io_t *fptr, const char *ptr, long length)
1751{
1752 if (fptr->wbuf.len) {
1753 struct iovec iov[2];
1754
1755 iov[0].iov_base = fptr->wbuf.ptr+fptr->wbuf.off;
1756 iov[0].iov_len = fptr->wbuf.len;
1757 iov[1].iov_base = (void*)ptr;
1758 iov[1].iov_len = length;
1759
1760 ssize_t result = rb_writev_internal(fptr, iov, 2);
1761
1762 if (result < 0)
1763 return result;
1764
1765 if (result >= fptr->wbuf.len) {
1766 // We wrote more than the internal buffer:
1767 result -= fptr->wbuf.len;
1768 fptr->wbuf.off = 0;
1769 fptr->wbuf.len = 0;
1770 }
1771 else {
1772 // We only wrote less data than the internal buffer:
1773 fptr->wbuf.off += (int)result;
1774 fptr->wbuf.len -= (int)result;
1775
1776 result = 0;
1777 }
1778
1779 return result;
1780 }
1781 else {
1782 return rb_io_write_memory(fptr, ptr, length);
1783 }
1784}
1785#else
1786static ssize_t
1787io_binwrite_string_internal(rb_io_t *fptr, const char *ptr, long length)
1788{
1789 long remaining = length;
1790
1791 if (fptr->wbuf.len) {
1792 if (fptr->wbuf.len+length <= fptr->wbuf.capa) {
1793 if (fptr->wbuf.capa < fptr->wbuf.off+fptr->wbuf.len+length) {
1794 MEMMOVE(fptr->wbuf.ptr, fptr->wbuf.ptr+fptr->wbuf.off, char, fptr->wbuf.len);
1795 fptr->wbuf.off = 0;
1796 }
1797
1798 MEMMOVE(fptr->wbuf.ptr+fptr->wbuf.off+fptr->wbuf.len, ptr, char, length);
1799 fptr->wbuf.len += (int)length;
1800
1801 // We copied the entire incoming data to the internal buffer:
1802 remaining = 0;
1803 }
1804
1805 // Flush the internal buffer:
1806 if (io_fflush(fptr) < 0) {
1807 return -1;
1808 }
1809
1810 // If all the data was buffered, we are done:
1811 if (remaining == 0) {
1812 return length;
1813 }
1814 }
1815
1816 // Otherwise, we should write the data directly:
1817 return rb_io_write_memory(fptr, ptr, length);
1818}
1819#endif
1820
1821static VALUE
1822io_binwrite_string(VALUE arg)
1823{
1824 struct binwrite_arg *p = (struct binwrite_arg *)arg;
1825
1826 const char *ptr = p->ptr;
1827 size_t remaining = p->length;
1828
1829 while (remaining) {
1830 // Write as much as possible:
1831 ssize_t result = io_binwrite_string_internal(p->fptr, ptr, remaining);
1832
1833 if (result == 0) {
1834 // If only the internal buffer is written, result will be zero [bytes of given data written]. This means we
1835 // should try again immediately.
1836 }
1837 else if (result > 0) {
1838 if ((size_t)result == remaining) break;
1839 ptr += result;
1840 remaining -= result;
1841 }
1842 // Wait for it to become writable:
1843 else if (rb_io_maybe_wait_writable(errno, p->fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
1844 rb_io_check_closed(p->fptr);
1845 }
1846 else {
1847 // The error was unrelated to waiting for it to become writable, so we fail:
1848 return -1;
1849 }
1850 }
1851
1852 return p->length;
1853}
1854
1855inline static void
1856io_allocate_write_buffer(rb_io_t *fptr, int sync)
1857{
1858 if (fptr->wbuf.ptr == NULL && !(sync && (fptr->mode & FMODE_SYNC))) {
1859 fptr->wbuf.off = 0;
1860 fptr->wbuf.len = 0;
1861 fptr->wbuf.capa = IO_WBUF_CAPA_MIN;
1862 fptr->wbuf.ptr = ALLOC_N(char, fptr->wbuf.capa);
1863 }
1864
1865 if (NIL_P(fptr->write_lock)) {
1866 fptr->write_lock = rb_mutex_new();
1867 rb_mutex_allow_trap(fptr->write_lock, 1);
1868 }
1869}
1870
1871static inline int
1872io_binwrite_requires_flush_write(rb_io_t *fptr, long len, int nosync)
1873{
1874 // If the requested operation was synchronous and the output mode is synchronous or a TTY:
1875 if (!nosync && (fptr->mode & (FMODE_SYNC|FMODE_TTY)))
1876 return 1;
1877
1878 // If the amount of data we want to write exceeds the internal buffer:
1879 if (fptr->wbuf.ptr && fptr->wbuf.capa <= fptr->wbuf.len + len)
1880 return 1;
1881
1882 // Otherwise, we can append to the internal buffer:
1883 return 0;
1884}
1885
1886static long
1887io_binwrite(const char *ptr, long len, rb_io_t *fptr, int nosync)
1888{
1889 if (len <= 0) return len;
1890
1891 // Don't write anything if current thread has a pending interrupt:
1893
1894 io_allocate_write_buffer(fptr, !nosync);
1895
1896 if (io_binwrite_requires_flush_write(fptr, len, nosync)) {
1897 struct binwrite_arg arg;
1898
1899 arg.fptr = fptr;
1900 arg.ptr = ptr;
1901 arg.length = len;
1902
1903 if (!NIL_P(fptr->write_lock)) {
1904 return rb_mutex_synchronize(fptr->write_lock, io_binwrite_string, (VALUE)&arg);
1905 }
1906 else {
1907 return io_binwrite_string((VALUE)&arg);
1908 }
1909 }
1910 else {
1911 if (fptr->wbuf.off) {
1912 if (fptr->wbuf.len)
1913 MEMMOVE(fptr->wbuf.ptr, fptr->wbuf.ptr+fptr->wbuf.off, char, fptr->wbuf.len);
1914 fptr->wbuf.off = 0;
1915 }
1916
1917 MEMMOVE(fptr->wbuf.ptr+fptr->wbuf.off+fptr->wbuf.len, ptr, char, len);
1918 fptr->wbuf.len += (int)len;
1919
1920 return len;
1921 }
1922}
1923
1924# define MODE_BTMODE(a,b,c) ((fmode & FMODE_BINMODE) ? (b) : \
1925 (fmode & FMODE_TEXTMODE) ? (c) : (a))
1926
1927#define MODE_BTXMODE(a, b, c, d, e, f) ((fmode & FMODE_EXCL) ? \
1928 MODE_BTMODE(d, e, f) : \
1929 MODE_BTMODE(a, b, c))
1930
1931static VALUE
1932do_writeconv(VALUE str, rb_io_t *fptr, int *converted)
1933{
1934 if (NEED_WRITECONV(fptr)) {
1935 VALUE common_encoding = Qnil;
1936 SET_BINARY_MODE(fptr);
1937
1938 make_writeconv(fptr);
1939
1940 if (fptr->writeconv) {
1941#define fmode (fptr->mode)
1942 if (!NIL_P(fptr->writeconv_asciicompat))
1943 common_encoding = fptr->writeconv_asciicompat;
1944 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1) && !rb_enc_asciicompat(rb_enc_get(str))) {
1945 rb_raise(rb_eArgError, "ASCII incompatible string written for text mode IO without encoding conversion: %s",
1946 rb_enc_name(rb_enc_get(str)));
1947 }
1948#undef fmode
1949 }
1950 else {
1951 if (fptr->encs.enc2)
1952 common_encoding = rb_enc_from_encoding(fptr->encs.enc2);
1953 else if (fptr->encs.enc != rb_ascii8bit_encoding())
1954 common_encoding = rb_enc_from_encoding(fptr->encs.enc);
1955 }
1956
1957 if (!NIL_P(common_encoding)) {
1958 str = rb_str_encode(str, common_encoding,
1960 *converted = 1;
1961 }
1962
1963 if (fptr->writeconv) {
1965 *converted = 1;
1966 }
1967 }
1968#if RUBY_CRLF_ENVIRONMENT
1969#define fmode (fptr->mode)
1970 else if (MODE_BTMODE(DEFAULT_TEXTMODE,0,1)) {
1971 if ((fptr->mode & FMODE_READABLE) &&
1973 setmode(fptr->fd, O_BINARY);
1974 }
1975 else {
1976 setmode(fptr->fd, O_TEXT);
1977 }
1978 if (!rb_enc_asciicompat(rb_enc_get(str))) {
1979 rb_raise(rb_eArgError, "ASCII incompatible string written for text mode IO without encoding conversion: %s",
1980 rb_enc_name(rb_enc_get(str)));
1981 }
1982 }
1983#undef fmode
1984#endif
1985 return str;
1986}
1987
1988static long
1989io_fwrite(VALUE str, rb_io_t *fptr, int nosync)
1990{
1991 int converted = 0;
1992 VALUE tmp;
1993 long n, len;
1994 const char *ptr;
1995
1996#ifdef _WIN32
1997 if (fptr->mode & FMODE_TTY) {
1998 long len = rb_w32_write_console(str, fptr->fd);
1999 if (len > 0) return len;
2000 }
2001#endif
2002
2003 str = do_writeconv(str, fptr, &converted);
2004 if (converted)
2005 OBJ_FREEZE(str);
2006
2007 tmp = rb_str_tmp_frozen_no_embed_acquire(str);
2008 RSTRING_GETMEM(tmp, ptr, len);
2009 n = io_binwrite(ptr, len, fptr, nosync);
2010 rb_str_tmp_frozen_release(str, tmp);
2011
2012 return n;
2013}
2014
2015ssize_t
2016rb_io_bufwrite(VALUE io, const void *buf, size_t size)
2017{
2018 rb_io_t *fptr;
2019
2020 GetOpenFile(io, fptr);
2022 return (ssize_t)io_binwrite(buf, (long)size, fptr, 0);
2023}
2024
2025static VALUE
2026io_write(VALUE io, VALUE str, int nosync)
2027{
2028 rb_io_t *fptr;
2029 long n;
2030 VALUE tmp;
2031
2032 io = GetWriteIO(io);
2033 str = rb_obj_as_string(str);
2034 tmp = rb_io_check_io(io);
2035
2036 if (NIL_P(tmp)) {
2037 /* port is not IO, call write method for it. */
2038 return rb_funcall(io, id_write, 1, str);
2039 }
2040
2041 io = tmp;
2042 if (RSTRING_LEN(str) == 0) return INT2FIX(0);
2043
2044 GetOpenFile(io, fptr);
2046
2047 n = io_fwrite(str, fptr, nosync);
2048 if (n < 0L) rb_sys_fail_on_write(fptr);
2049
2050 return LONG2FIX(n);
2051}
2052
2053#ifdef HAVE_WRITEV
2054struct binwritev_arg {
2055 rb_io_t *fptr;
2056 struct iovec *iov;
2057 int iovcnt;
2058 size_t total;
2059};
2060
2061static VALUE
2062io_binwritev_internal(VALUE arg)
2063{
2064 struct binwritev_arg *p = (struct binwritev_arg *)arg;
2065
2066 size_t remaining = p->total;
2067 size_t offset = 0;
2068
2069 rb_io_t *fptr = p->fptr;
2070 struct iovec *iov = p->iov;
2071 int iovcnt = p->iovcnt;
2072
2073 while (remaining) {
2074 long result = rb_writev_internal(fptr, iov, iovcnt);
2075
2076 if (result >= 0) {
2077 offset += result;
2078 if (fptr->wbuf.ptr && fptr->wbuf.len) {
2079 if (offset < (size_t)fptr->wbuf.len) {
2080 fptr->wbuf.off += result;
2081 fptr->wbuf.len -= result;
2082 }
2083 else {
2084 offset -= (size_t)fptr->wbuf.len;
2085 fptr->wbuf.off = 0;
2086 fptr->wbuf.len = 0;
2087 }
2088 }
2089
2090 if (offset == p->total) {
2091 return p->total;
2092 }
2093
2094 while (result >= (ssize_t)iov->iov_len) {
2095 /* iovcnt > 0 */
2096 result -= iov->iov_len;
2097 iov->iov_len = 0;
2098 iov++;
2099
2100 if (!--iovcnt) {
2101 // I don't believe this code path can ever occur.
2102 return offset;
2103 }
2104 }
2105
2106 iov->iov_base = (char *)iov->iov_base + result;
2107 iov->iov_len -= result;
2108 }
2109 else if (rb_io_maybe_wait_writable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT)) {
2110 rb_io_check_closed(fptr);
2111 }
2112 else {
2113 return -1;
2114 }
2115 }
2116
2117 return offset;
2118}
2119
2120static long
2121io_binwritev(struct iovec *iov, int iovcnt, rb_io_t *fptr)
2122{
2123 // Don't write anything if current thread has a pending interrupt:
2125
2126 if (iovcnt == 0) return 0;
2127
2128 size_t total = 0;
2129 for (int i = 1; i < iovcnt; i++) total += iov[i].iov_len;
2130
2131 io_allocate_write_buffer(fptr, 1);
2132
2133 if (fptr->wbuf.ptr && fptr->wbuf.len) {
2134 // The end of the buffered data:
2135 size_t offset = fptr->wbuf.off + fptr->wbuf.len;
2136
2137 if (offset + total <= (size_t)fptr->wbuf.capa) {
2138 for (int i = 1; i < iovcnt; i++) {
2139 memcpy(fptr->wbuf.ptr+offset, iov[i].iov_base, iov[i].iov_len);
2140 offset += iov[i].iov_len;
2141 }
2142
2143 fptr->wbuf.len += total;
2144
2145 return total;
2146 }
2147 else {
2148 iov[0].iov_base = fptr->wbuf.ptr + fptr->wbuf.off;
2149 iov[0].iov_len = fptr->wbuf.len;
2150 }
2151 }
2152 else {
2153 // The first iov is reserved for the internal buffer, and it's empty.
2154 iov++;
2155
2156 if (!--iovcnt) {
2157 // If there are no other io vectors we are done.
2158 return 0;
2159 }
2160 }
2161
2162 struct binwritev_arg arg;
2163 arg.fptr = fptr;
2164 arg.iov = iov;
2165 arg.iovcnt = iovcnt;
2166 arg.total = total;
2167
2168 if (!NIL_P(fptr->write_lock)) {
2169 return rb_mutex_synchronize(fptr->write_lock, io_binwritev_internal, (VALUE)&arg);
2170 }
2171 else {
2172 return io_binwritev_internal((VALUE)&arg);
2173 }
2174}
2175
2176static long
2177io_fwritev(int argc, const VALUE *argv, rb_io_t *fptr)
2178{
2179 int i, converted, iovcnt = argc + 1;
2180 long n;
2181 VALUE v1, v2, str, tmp, *tmp_array;
2182 struct iovec *iov;
2183
2184 iov = ALLOCV_N(struct iovec, v1, iovcnt);
2185 tmp_array = ALLOCV_N(VALUE, v2, argc);
2186
2187 for (i = 0; i < argc; i++) {
2188 str = rb_obj_as_string(argv[i]);
2189 converted = 0;
2190 str = do_writeconv(str, fptr, &converted);
2191
2192 if (converted)
2193 OBJ_FREEZE(str);
2194
2195 tmp = rb_str_tmp_frozen_acquire(str);
2196 tmp_array[i] = tmp;
2197
2198 /* iov[0] is reserved for buffer of fptr */
2199 iov[i+1].iov_base = RSTRING_PTR(tmp);
2200 iov[i+1].iov_len = RSTRING_LEN(tmp);
2201 }
2202
2203 n = io_binwritev(iov, iovcnt, fptr);
2204 if (v1) ALLOCV_END(v1);
2205
2206 for (i = 0; i < argc; i++) {
2207 rb_str_tmp_frozen_release(argv[i], tmp_array[i]);
2208 }
2209
2210 if (v2) ALLOCV_END(v2);
2211
2212 return n;
2213}
2214
2215static int
2216iovcnt_ok(int iovcnt)
2217{
2218#ifdef IOV_MAX
2219 return iovcnt < IOV_MAX;
2220#else /* GNU/Hurd has writev, but no IOV_MAX */
2221 return 1;
2222#endif
2223}
2224#endif /* HAVE_WRITEV */
2225
2226static VALUE
2227io_writev(int argc, const VALUE *argv, VALUE io)
2228{
2229 rb_io_t *fptr;
2230 long n;
2231 VALUE tmp, total = INT2FIX(0);
2232 int i, cnt = 1;
2233
2234 io = GetWriteIO(io);
2235 tmp = rb_io_check_io(io);
2236
2237 if (NIL_P(tmp)) {
2238 /* port is not IO, call write method for it. */
2239 return rb_funcallv(io, id_write, argc, argv);
2240 }
2241
2242 io = tmp;
2243
2244 GetOpenFile(io, fptr);
2246
2247 for (i = 0; i < argc; i += cnt) {
2248#ifdef HAVE_WRITEV
2249 if ((fptr->mode & (FMODE_SYNC|FMODE_TTY)) && iovcnt_ok(cnt = argc - i)) {
2250 n = io_fwritev(cnt, &argv[i], fptr);
2251 }
2252 else
2253#endif
2254 {
2255 cnt = 1;
2256 /* sync at last item */
2257 n = io_fwrite(rb_obj_as_string(argv[i]), fptr, (i < argc-1));
2258 }
2259
2260 if (n < 0L)
2261 rb_sys_fail_on_write(fptr);
2262
2263 total = rb_fix_plus(LONG2FIX(n), total);
2264 }
2265
2266 return total;
2267}
2268
2269/*
2270 * call-seq:
2271 * write(*objects) -> integer
2272 *
2273 * Writes each of the given +objects+ to +self+,
2274 * which must be opened for writing
2275 * (see {Access Modes}[rdoc-ref:File@Access+Modes]);
2276 * returns the total number bytes written;
2277 * each of +objects+ that is not a string is converted via method +to_s+:
2278 *
2279 * $stdout.write('Hello', ', ', 'World!', "\n") # => 14
2280 * $stdout.write('foo', :bar, 2, "\n") # => 8
2281 *
2282 * Output:
2283 *
2284 * Hello, World!
2285 * foobar2
2286 *
2287 * Related: IO#read.
2288 */
2289
2290static VALUE
2291io_write_m(int argc, VALUE *argv, VALUE io)
2292{
2293 if (argc != 1) {
2294 return io_writev(argc, argv, io);
2295 }
2296 else {
2297 VALUE str = argv[0];
2298 return io_write(io, str, 0);
2299 }
2300}
2301
2302VALUE
2303rb_io_write(VALUE io, VALUE str)
2304{
2305 return rb_funcallv(io, id_write, 1, &str);
2306}
2307
2308static VALUE
2309rb_io_writev(VALUE io, int argc, const VALUE *argv)
2310{
2311 if (argc > 1 && rb_obj_method_arity(io, id_write) == 1) {
2312 if (io != rb_ractor_stderr() && RTEST(ruby_verbose)) {
2313 VALUE klass = CLASS_OF(io);
2314 char sep = RCLASS_SINGLETON_P(klass) ? (klass = io, '.') : '#';
2316 RB_WARN_CATEGORY_DEPRECATED, "%+"PRIsVALUE"%c""write is outdated interface"
2317 " which accepts just one argument",
2318 klass, sep
2319 );
2320 }
2321
2322 do rb_io_write(io, *argv++); while (--argc);
2323
2324 return Qnil;
2325 }
2326
2327 return rb_funcallv(io, id_write, argc, argv);
2328}
2329
2330/*
2331 * call-seq:
2332 * self << object -> self
2333 *
2334 * Writes the given +object+ to +self+,
2335 * which must be opened for writing (see {Access Modes}[rdoc-ref:File@Access+Modes]);
2336 * returns +self+;
2337 * if +object+ is not a string, it is converted via method +to_s+:
2338 *
2339 * $stdout << 'Hello' << ', ' << 'World!' << "\n"
2340 * $stdout << 'foo' << :bar << 2 << "\n"
2341 *
2342 * Output:
2343 *
2344 * Hello, World!
2345 * foobar2
2346 *
2347 */
2348
2349
2350VALUE
2352{
2353 rb_io_write(io, str);
2354 return io;
2355}
2356
2357#ifdef HAVE_FSYNC
2358static VALUE
2359nogvl_fsync(void *ptr)
2360{
2361 rb_io_t *fptr = ptr;
2362
2363#ifdef _WIN32
2364 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->fd)) != FILE_TYPE_DISK)
2365 return 0;
2366#endif
2367 return (VALUE)fsync(fptr->fd);
2368}
2369#endif
2370
2371VALUE
2372rb_io_flush_raw(VALUE io, int sync)
2373{
2374 rb_io_t *fptr;
2375
2376 if (!RB_TYPE_P(io, T_FILE)) {
2377 return rb_funcall(io, id_flush, 0);
2378 }
2379
2380 io = GetWriteIO(io);
2381 GetOpenFile(io, fptr);
2382
2383 if (fptr->mode & FMODE_WRITABLE) {
2384 if (io_fflush(fptr) < 0)
2385 rb_sys_fail_on_write(fptr);
2386 }
2387 if (fptr->mode & FMODE_READABLE) {
2388 io_unread(fptr, true);
2389 }
2390
2391 return io;
2392}
2393
2394/*
2395 * call-seq:
2396 * flush -> self
2397 *
2398 * Flushes data buffered in +self+ to the operating system
2399 * (but does not necessarily flush data buffered in the operating system):
2400 *
2401 * $stdout.print 'no newline' # Not necessarily flushed.
2402 * $stdout.flush # Flushed.
2403 *
2404 */
2405
2406VALUE
2407rb_io_flush(VALUE io)
2408{
2409 return rb_io_flush_raw(io, 1);
2410}
2411
2412/*
2413 * call-seq:
2414 * tell -> integer
2415 *
2416 * Returns the current position (in bytes) in +self+
2417 * (see {Position}[rdoc-ref:IO@Position]):
2418 *
2419 * f = File.open('t.txt')
2420 * f.tell # => 0
2421 * f.gets # => "First line\n"
2422 * f.tell # => 12
2423 * f.close
2424 *
2425 * Related: IO#pos=, IO#seek.
2426 */
2427
2428static VALUE
2429rb_io_tell(VALUE io)
2430{
2431 rb_io_t *fptr;
2432 rb_off_t pos;
2433
2434 GetOpenFile(io, fptr);
2435 pos = io_tell(fptr);
2436 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2437 pos -= fptr->rbuf.len;
2438 return OFFT2NUM(pos);
2439}
2440
2441static VALUE
2442rb_io_seek(VALUE io, VALUE offset, int whence)
2443{
2444 rb_io_t *fptr;
2445 rb_off_t pos;
2446
2447 pos = NUM2OFFT(offset);
2448 GetOpenFile(io, fptr);
2449 pos = io_seek(fptr, pos, whence);
2450 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2451
2452 return INT2FIX(0);
2453}
2454
2455static int
2456interpret_seek_whence(VALUE vwhence)
2457{
2458 if (vwhence == sym_SET)
2459 return SEEK_SET;
2460 if (vwhence == sym_CUR)
2461 return SEEK_CUR;
2462 if (vwhence == sym_END)
2463 return SEEK_END;
2464#ifdef SEEK_DATA
2465 if (vwhence == sym_DATA)
2466 return SEEK_DATA;
2467#endif
2468#ifdef SEEK_HOLE
2469 if (vwhence == sym_HOLE)
2470 return SEEK_HOLE;
2471#endif
2472 return NUM2INT(vwhence);
2473}
2474
2475/*
2476 * call-seq:
2477 * seek(offset, whence = IO::SEEK_SET) -> 0
2478 *
2479 * Seeks to the position given by integer +offset+
2480 * (see {Position}[rdoc-ref:IO@Position])
2481 * and constant +whence+, which is one of:
2482 *
2483 * - +:CUR+ or <tt>IO::SEEK_CUR</tt>:
2484 * Repositions the stream to its current position plus the given +offset+:
2485 *
2486 * f = File.open('t.txt')
2487 * f.tell # => 0
2488 * f.seek(20, :CUR) # => 0
2489 * f.tell # => 20
2490 * f.seek(-10, :CUR) # => 0
2491 * f.tell # => 10
2492 * f.close
2493 *
2494 * - +:END+ or <tt>IO::SEEK_END</tt>:
2495 * Repositions the stream to its end plus the given +offset+:
2496 *
2497 * f = File.open('t.txt')
2498 * f.tell # => 0
2499 * f.seek(0, :END) # => 0 # Repositions to stream end.
2500 * f.tell # => 52
2501 * f.seek(-20, :END) # => 0
2502 * f.tell # => 32
2503 * f.seek(-40, :END) # => 0
2504 * f.tell # => 12
2505 * f.close
2506 *
2507 * - +:SET+ or <tt>IO:SEEK_SET</tt>:
2508 * Repositions the stream to the given +offset+:
2509 *
2510 * f = File.open('t.txt')
2511 * f.tell # => 0
2512 * f.seek(20, :SET) # => 0
2513 * f.tell # => 20
2514 * f.seek(40, :SET) # => 0
2515 * f.tell # => 40
2516 * f.close
2517 *
2518 * Related: IO#pos=, IO#tell.
2519 *
2520 */
2521
2522static VALUE
2523rb_io_seek_m(int argc, VALUE *argv, VALUE io)
2524{
2525 VALUE offset, ptrname;
2526 int whence = SEEK_SET;
2527
2528 if (rb_scan_args(argc, argv, "11", &offset, &ptrname) == 2) {
2529 whence = interpret_seek_whence(ptrname);
2530 }
2531
2532 return rb_io_seek(io, offset, whence);
2533}
2534
2535/*
2536 * call-seq:
2537 * pos = new_position -> new_position
2538 *
2539 * Seeks to the given +new_position+ (in bytes);
2540 * see {Position}[rdoc-ref:IO@Position]:
2541 *
2542 * f = File.open('t.txt')
2543 * f.tell # => 0
2544 * f.pos = 20 # => 20
2545 * f.tell # => 20
2546 * f.close
2547 *
2548 * Related: IO#seek, IO#tell.
2549 *
2550 */
2551
2552static VALUE
2553rb_io_set_pos(VALUE io, VALUE offset)
2554{
2555 rb_io_t *fptr;
2556 rb_off_t pos;
2557
2558 pos = NUM2OFFT(offset);
2559 GetOpenFile(io, fptr);
2560 pos = io_seek(fptr, pos, SEEK_SET);
2561 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
2562
2563 return OFFT2NUM(pos);
2564}
2565
2566static void clear_readconv(rb_io_t *fptr);
2567
2568/*
2569 * call-seq:
2570 * rewind -> 0
2571 *
2572 * Repositions the stream to its beginning,
2573 * setting both the position and the line number to zero;
2574 * see {Position}[rdoc-ref:IO@Position]
2575 * and {Line Number}[rdoc-ref:IO@Line+Number]:
2576 *
2577 * f = File.open('t.txt')
2578 * f.tell # => 0
2579 * f.lineno # => 0
2580 * f.gets # => "First line\n"
2581 * f.tell # => 12
2582 * f.lineno # => 1
2583 * f.rewind # => 0
2584 * f.tell # => 0
2585 * f.lineno # => 0
2586 * f.close
2587 *
2588 * Note that this method cannot be used with streams such as pipes, ttys, and sockets.
2589 *
2590 */
2591
2592static VALUE
2593rb_io_rewind(VALUE io)
2594{
2595 rb_io_t *fptr;
2596
2597 GetOpenFile(io, fptr);
2598 if (io_seek(fptr, 0L, 0) < 0 && errno) rb_sys_fail_path(fptr->pathv);
2599 if (io == ARGF.current_file) {
2600 ARGF.lineno -= fptr->lineno;
2601 }
2602 fptr->lineno = 0;
2603 if (fptr->readconv) {
2604 clear_readconv(fptr);
2605 }
2606
2607 return INT2FIX(0);
2608}
2609
2610static int
2611fptr_wait_readable(rb_io_t *fptr)
2612{
2613 int result = rb_io_maybe_wait_readable(errno, fptr->self, RUBY_IO_TIMEOUT_DEFAULT);
2614
2615 if (result)
2616 rb_io_check_closed(fptr);
2617
2618 return result;
2619}
2620
2621static int
2622io_fillbuf(rb_io_t *fptr)
2623{
2624 ssize_t r;
2625
2626 if (fptr->rbuf.ptr == NULL) {
2627 fptr->rbuf.off = 0;
2628 fptr->rbuf.len = 0;
2629 fptr->rbuf.capa = IO_RBUF_CAPA_FOR(fptr);
2630 fptr->rbuf.ptr = ALLOC_N(char, fptr->rbuf.capa);
2631#ifdef _WIN32
2632 fptr->rbuf.capa--;
2633#endif
2634 }
2635 if (fptr->rbuf.len == 0) {
2636 retry:
2637 r = rb_io_read_memory(fptr, fptr->rbuf.ptr, fptr->rbuf.capa);
2638
2639 if (r < 0) {
2640 if (fptr_wait_readable(fptr))
2641 goto retry;
2642
2643 int e = errno;
2644 VALUE path = rb_sprintf("fd:%d ", fptr->fd);
2645 if (!NIL_P(fptr->pathv)) {
2646 rb_str_append(path, fptr->pathv);
2647 }
2648
2649 rb_syserr_fail_path(e, path);
2650 }
2651 if (r > 0) rb_io_check_closed(fptr);
2652 fptr->rbuf.off = 0;
2653 fptr->rbuf.len = (int)r; /* r should be <= rbuf_capa */
2654 if (r == 0)
2655 return -1; /* EOF */
2656 }
2657 return 0;
2658}
2659
2660/*
2661 * call-seq:
2662 * eof -> true or false
2663 *
2664 * Returns +true+ if the stream is positioned at its end, +false+ otherwise;
2665 * see {Position}[rdoc-ref:IO@Position]:
2666 *
2667 * f = File.open('t.txt')
2668 * f.eof # => false
2669 * f.seek(0, :END) # => 0
2670 * f.eof # => true
2671 * f.close
2672 *
2673 * Raises an exception unless the stream is opened for reading;
2674 * see {Mode}[rdoc-ref:File@Access+Modes].
2675 *
2676 * If +self+ is a stream such as pipe or socket, this method
2677 * blocks until the other end sends some data or closes it:
2678 *
2679 * r, w = IO.pipe
2680 * Thread.new { sleep 1; w.close }
2681 * r.eof? # => true # After 1-second wait.
2682 *
2683 * r, w = IO.pipe
2684 * Thread.new { sleep 1; w.puts "a" }
2685 * r.eof? # => false # After 1-second wait.
2686 *
2687 * r, w = IO.pipe
2688 * r.eof? # blocks forever
2689 *
2690 * Note that this method reads data to the input byte buffer. So
2691 * IO#sysread may not behave as you intend with IO#eof?, unless you
2692 * call IO#rewind first (which is not available for some streams).
2693 */
2694
2695VALUE
2697{
2698 rb_io_t *fptr;
2699
2700 GetOpenFile(io, fptr);
2702
2703 if (READ_CHAR_PENDING(fptr)) return Qfalse;
2704 if (READ_DATA_PENDING(fptr)) return Qfalse;
2705 READ_CHECK(fptr);
2706#if RUBY_CRLF_ENVIRONMENT
2707 if (!NEED_READCONV(fptr) && NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
2708 return RBOOL(eof(fptr->fd));
2709 }
2710#endif
2711 return RBOOL(io_fillbuf(fptr) < 0);
2712}
2713
2714/*
2715 * call-seq:
2716 * sync -> true or false
2717 *
2718 * Returns the current sync mode of the stream.
2719 * When sync mode is true, all output is immediately flushed to the underlying
2720 * operating system and is not buffered by Ruby internally. See also #fsync.
2721 *
2722 * f = File.open('t.tmp', 'w')
2723 * f.sync # => false
2724 * f.sync = true
2725 * f.sync # => true
2726 * f.close
2727 *
2728 */
2729
2730static VALUE
2731rb_io_sync(VALUE io)
2732{
2733 rb_io_t *fptr;
2734
2735 io = GetWriteIO(io);
2736 GetOpenFile(io, fptr);
2737 return RBOOL(fptr->mode & FMODE_SYNC);
2738}
2739
2740#ifdef HAVE_FSYNC
2741
2742/*
2743 * call-seq:
2744 * sync = boolean -> boolean
2745 *
2746 * Sets the _sync_ _mode_ for the stream to the given value;
2747 * returns the given value.
2748 *
2749 * Values for the sync mode:
2750 *
2751 * - +true+: All output is immediately flushed to the
2752 * underlying operating system and is not buffered internally.
2753 * - +false+: Output may be buffered internally.
2754 *
2755 * Example;
2756 *
2757 * f = File.open('t.tmp', 'w')
2758 * f.sync # => false
2759 * f.sync = true
2760 * f.sync # => true
2761 * f.close
2762 *
2763 * Related: IO#fsync.
2764 *
2765 */
2766
2767static VALUE
2768rb_io_set_sync(VALUE io, VALUE sync)
2769{
2770 rb_io_t *fptr;
2771
2772 io = GetWriteIO(io);
2773 GetOpenFile(io, fptr);
2774 if (RTEST(sync)) {
2775 fptr->mode |= FMODE_SYNC;
2776 }
2777 else {
2778 fptr->mode &= ~FMODE_SYNC;
2779 }
2780 return sync;
2781}
2782
2783/*
2784 * call-seq:
2785 * fsync -> 0
2786 *
2787 * Immediately writes to disk all data buffered in the stream,
2788 * via the operating system's <tt>fsync(2)</tt>.
2789
2790 * Note this difference:
2791 *
2792 * - IO#sync=: Ensures that data is flushed from the stream's internal buffers,
2793 * but does not guarantee that the operating system actually writes the data to disk.
2794 * - IO#fsync: Ensures both that data is flushed from internal buffers,
2795 * and that data is written to disk.
2796 *
2797 * Raises an exception if the operating system does not support <tt>fsync(2)</tt>.
2798 *
2799 */
2800
2801static VALUE
2802rb_io_fsync(VALUE io)
2803{
2804 rb_io_t *fptr;
2805
2806 io = GetWriteIO(io);
2807 GetOpenFile(io, fptr);
2808
2809 if (io_fflush(fptr) < 0)
2810 rb_sys_fail_on_write(fptr);
2811
2812 if ((int)rb_io_blocking_region(fptr, nogvl_fsync, fptr))
2813 rb_sys_fail_path(fptr->pathv);
2814
2815 return INT2FIX(0);
2816}
2817#else
2818# define rb_io_fsync rb_f_notimplement
2819# define rb_io_sync rb_f_notimplement
2820static VALUE
2821rb_io_set_sync(VALUE io, VALUE sync)
2822{
2825}
2826#endif
2827
2828#ifdef HAVE_FDATASYNC
2829static VALUE
2830nogvl_fdatasync(void *ptr)
2831{
2832 rb_io_t *fptr = ptr;
2833
2834#ifdef _WIN32
2835 if (GetFileType((HANDLE)rb_w32_get_osfhandle(fptr->fd)) != FILE_TYPE_DISK)
2836 return 0;
2837#endif
2838 return (VALUE)fdatasync(fptr->fd);
2839}
2840
2841/*
2842 * call-seq:
2843 * fdatasync -> 0
2844 *
2845 * Immediately writes to disk all data buffered in the stream,
2846 * via the operating system's: <tt>fdatasync(2)</tt>, if supported,
2847 * otherwise via <tt>fsync(2)</tt>, if supported;
2848 * otherwise raises an exception.
2849 *
2850 */
2851
2852static VALUE
2853rb_io_fdatasync(VALUE io)
2854{
2855 rb_io_t *fptr;
2856
2857 io = GetWriteIO(io);
2858 GetOpenFile(io, fptr);
2859
2860 if (io_fflush(fptr) < 0)
2861 rb_sys_fail_on_write(fptr);
2862
2863 if ((int)rb_io_blocking_region(fptr, nogvl_fdatasync, fptr) == 0)
2864 return INT2FIX(0);
2865
2866 /* fall back */
2867 return rb_io_fsync(io);
2868}
2869#else
2870#define rb_io_fdatasync rb_io_fsync
2871#endif
2872
2873/*
2874 * call-seq:
2875 * fileno -> integer
2876 *
2877 * Returns the integer file descriptor for the stream:
2878 *
2879 * $stdin.fileno # => 0
2880 * $stdout.fileno # => 1
2881 * $stderr.fileno # => 2
2882 * File.open('t.txt').fileno # => 10
2883 * f.close
2884 *
2885 */
2886
2887static VALUE
2888rb_io_fileno(VALUE io)
2889{
2890 rb_io_t *fptr = RFILE(io)->fptr;
2891 int fd;
2892
2893 rb_io_check_closed(fptr);
2894 fd = fptr->fd;
2895 return INT2FIX(fd);
2896}
2897
2898int
2900{
2901 if (RB_TYPE_P(io, T_FILE)) {
2902 rb_io_t *fptr = RFILE(io)->fptr;
2903 rb_io_check_closed(fptr);
2904 return fptr->fd;
2905 }
2906 else {
2907 VALUE fileno = rb_check_funcall(io, id_fileno, 0, NULL);
2908 if (!UNDEF_P(fileno)) {
2909 return RB_NUM2INT(fileno);
2910 }
2911 }
2912
2913 rb_raise(rb_eTypeError, "expected IO or #fileno, %"PRIsVALUE" given", rb_obj_class(io));
2914
2916}
2917
2918int
2919rb_io_mode(VALUE io)
2920{
2921 rb_io_t *fptr;
2922 GetOpenFile(io, fptr);
2923 return fptr->mode;
2924}
2925
2926/*
2927 * call-seq:
2928 * pid -> integer or nil
2929 *
2930 * Returns the process ID of a child process associated with the stream,
2931 * which will have been set by IO#popen, or +nil+ if the stream was not
2932 * created by IO#popen:
2933 *
2934 * pipe = IO.popen("-")
2935 * if pipe
2936 * $stderr.puts "In parent, child pid is #{pipe.pid}"
2937 * else
2938 * $stderr.puts "In child, pid is #{$$}"
2939 * end
2940 *
2941 * Output:
2942 *
2943 * In child, pid is 26209
2944 * In parent, child pid is 26209
2945 *
2946 */
2947
2948static VALUE
2949rb_io_pid(VALUE io)
2950{
2951 rb_io_t *fptr;
2952
2953 GetOpenFile(io, fptr);
2954 if (!fptr->pid)
2955 return Qnil;
2956 return PIDT2NUM(fptr->pid);
2957}
2958
2959/*
2960 * call-seq:
2961 * path -> string or nil
2962 *
2963 * Returns the path associated with the IO, or +nil+ if there is no path
2964 * associated with the IO. It is not guaranteed that the path exists on
2965 * the filesystem.
2966 *
2967 * $stdin.path # => "<STDIN>"
2968 *
2969 * File.open("testfile") {|f| f.path} # => "testfile"
2970 */
2971
2972VALUE
2974{
2975 rb_io_t *fptr = RFILE(io)->fptr;
2976
2977 if (!fptr)
2978 return Qnil;
2979
2980 return rb_obj_dup(fptr->pathv);
2981}
2982
2983/*
2984 * call-seq:
2985 * inspect -> string
2986 *
2987 * Returns a string representation of +self+:
2988 *
2989 * f = File.open('t.txt')
2990 * f.inspect # => "#<File:t.txt>"
2991 * f.close
2992 *
2993 */
2994
2995static VALUE
2996rb_io_inspect(VALUE obj)
2997{
2998 rb_io_t *fptr;
2999 VALUE result;
3000 static const char closed[] = " (closed)";
3001
3002 fptr = RFILE(obj)->fptr;
3003 if (!fptr) return rb_any_to_s(obj);
3004 result = rb_str_new_cstr("#<");
3005 rb_str_append(result, rb_class_name(CLASS_OF(obj)));
3006 rb_str_cat2(result, ":");
3007 if (NIL_P(fptr->pathv)) {
3008 if (fptr->fd < 0) {
3009 rb_str_cat(result, closed+1, strlen(closed)-1);
3010 }
3011 else {
3012 rb_str_catf(result, "fd %d", fptr->fd);
3013 }
3014 }
3015 else {
3016 rb_str_append(result, fptr->pathv);
3017 if (fptr->fd < 0) {
3018 rb_str_cat(result, closed, strlen(closed));
3019 }
3020 }
3021 return rb_str_cat2(result, ">");
3022}
3023
3024/*
3025 * call-seq:
3026 * to_io -> self
3027 *
3028 * Returns +self+.
3029 *
3030 */
3031
3032static VALUE
3033rb_io_to_io(VALUE io)
3034{
3035 return io;
3036}
3037
3038/* reading functions */
3039static long
3040read_buffered_data(char *ptr, long len, rb_io_t *fptr)
3041{
3042 int n;
3043
3044 n = READ_DATA_PENDING_COUNT(fptr);
3045 if (n <= 0) return 0;
3046 if (n > len) n = (int)len;
3047 MEMMOVE(ptr, fptr->rbuf.ptr+fptr->rbuf.off, char, n);
3048 fptr->rbuf.off += n;
3049 fptr->rbuf.len -= n;
3050 return n;
3051}
3052
3053static long
3054io_bufread(char *ptr, long len, rb_io_t *fptr)
3055{
3056 long offset = 0;
3057 long n = len;
3058 long c;
3059
3060 if (READ_DATA_PENDING(fptr) == 0) {
3061 while (n > 0) {
3062 again:
3063 rb_io_check_closed(fptr);
3064 c = rb_io_read_memory(fptr, ptr+offset, n);
3065 if (c == 0) break;
3066 if (c < 0) {
3067 if (fptr_wait_readable(fptr))
3068 goto again;
3069 return -1;
3070 }
3071 offset += c;
3072 if ((n -= c) <= 0) break;
3073 }
3074 return len - n;
3075 }
3076
3077 while (n > 0) {
3078 c = read_buffered_data(ptr+offset, n, fptr);
3079 if (c > 0) {
3080 offset += c;
3081 if ((n -= c) <= 0) break;
3082 }
3083 rb_io_check_closed(fptr);
3084 if (io_fillbuf(fptr) < 0) {
3085 break;
3086 }
3087 }
3088 return len - n;
3089}
3090
3091static int io_setstrbuf(VALUE *str, long len);
3092
3094 char *str_ptr;
3095 long len;
3096 rb_io_t *fptr;
3097};
3098
3099static VALUE
3100bufread_call(VALUE arg)
3101{
3102 struct bufread_arg *p = (struct bufread_arg *)arg;
3103 p->len = io_bufread(p->str_ptr, p->len, p->fptr);
3104 return Qundef;
3105}
3106
3107static long
3108io_fread(VALUE str, long offset, long size, rb_io_t *fptr)
3109{
3110 long len;
3111 struct bufread_arg arg;
3112
3113 io_setstrbuf(&str, offset + size);
3114 arg.str_ptr = RSTRING_PTR(str) + offset;
3115 arg.len = size;
3116 arg.fptr = fptr;
3117 rb_str_locktmp_ensure(str, bufread_call, (VALUE)&arg);
3118 len = arg.len;
3119 if (len < 0) rb_sys_fail_path(fptr->pathv);
3120 return len;
3121}
3122
3123static long
3124remain_size(rb_io_t *fptr)
3125{
3126 struct stat st;
3127 rb_off_t siz = READ_DATA_PENDING_COUNT(fptr);
3128 rb_off_t pos;
3129
3130 if (fstat(fptr->fd, &st) == 0 && S_ISREG(st.st_mode)
3131#if defined(__HAIKU__)
3132 && (st.st_dev > 3)
3133#endif
3134 )
3135 {
3136 if (io_fflush(fptr) < 0)
3137 rb_sys_fail_on_write(fptr);
3138 pos = lseek(fptr->fd, 0, SEEK_CUR);
3139 if (st.st_size >= pos && pos >= 0) {
3140 siz += st.st_size - pos;
3141 if (siz > LONG_MAX) {
3142 rb_raise(rb_eIOError, "file too big for single read");
3143 }
3144 }
3145 }
3146 else {
3147 siz += BUFSIZ;
3148 }
3149 return (long)siz;
3150}
3151
3152static VALUE
3153io_enc_str(VALUE str, rb_io_t *fptr)
3154{
3155 rb_enc_associate(str, io_read_encoding(fptr));
3156 return str;
3157}
3158
3159static rb_encoding *io_read_encoding(rb_io_t *fptr);
3160
3161static void
3162make_readconv(rb_io_t *fptr, int size)
3163{
3164 if (!fptr->readconv) {
3165 int ecflags;
3166 VALUE ecopts;
3167 const char *sname, *dname;
3168 ecflags = fptr->encs.ecflags & ~ECONV_NEWLINE_DECORATOR_WRITE_MASK;
3169 ecopts = fptr->encs.ecopts;
3170 if (fptr->encs.enc2) {
3171 sname = rb_enc_name(fptr->encs.enc2);
3172 dname = rb_enc_name(io_read_encoding(fptr));
3173 }
3174 else {
3175 sname = dname = "";
3176 }
3177 fptr->readconv = rb_econv_open_opts(sname, dname, ecflags, ecopts);
3178 if (!fptr->readconv)
3179 rb_exc_raise(rb_econv_open_exc(sname, dname, ecflags));
3180 fptr->cbuf.off = 0;
3181 fptr->cbuf.len = 0;
3182 if (size < IO_CBUF_CAPA_MIN) size = IO_CBUF_CAPA_MIN;
3183 fptr->cbuf.capa = size;
3184 fptr->cbuf.ptr = ALLOC_N(char, fptr->cbuf.capa);
3185 }
3186}
3187
3188#define MORE_CHAR_SUSPENDED Qtrue
3189#define MORE_CHAR_FINISHED Qnil
3190static VALUE
3191fill_cbuf(rb_io_t *fptr, int ec_flags)
3192{
3193 const unsigned char *ss, *sp, *se;
3194 unsigned char *ds, *dp, *de;
3196 int putbackable;
3197 int cbuf_len0;
3198 VALUE exc;
3199
3200 ec_flags |= ECONV_PARTIAL_INPUT;
3201
3202 if (fptr->cbuf.len == fptr->cbuf.capa)
3203 return MORE_CHAR_SUSPENDED; /* cbuf full */
3204 if (fptr->cbuf.len == 0)
3205 fptr->cbuf.off = 0;
3206 else if (fptr->cbuf.off + fptr->cbuf.len == fptr->cbuf.capa) {
3207 memmove(fptr->cbuf.ptr, fptr->cbuf.ptr+fptr->cbuf.off, fptr->cbuf.len);
3208 fptr->cbuf.off = 0;
3209 }
3210
3211 cbuf_len0 = fptr->cbuf.len;
3212
3213 while (1) {
3214 ss = sp = (const unsigned char *)fptr->rbuf.ptr + fptr->rbuf.off;
3215 se = sp + fptr->rbuf.len;
3216 ds = dp = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.off + fptr->cbuf.len;
3217 de = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.capa;
3218 res = rb_econv_convert(fptr->readconv, &sp, se, &dp, de, ec_flags);
3219 fptr->rbuf.off += (int)(sp - ss);
3220 fptr->rbuf.len -= (int)(sp - ss);
3221 fptr->cbuf.len += (int)(dp - ds);
3222
3223 putbackable = rb_econv_putbackable(fptr->readconv);
3224 if (putbackable) {
3225 rb_econv_putback(fptr->readconv, (unsigned char *)fptr->rbuf.ptr + fptr->rbuf.off - putbackable, putbackable);
3226 fptr->rbuf.off -= putbackable;
3227 fptr->rbuf.len += putbackable;
3228 }
3229
3230 exc = rb_econv_make_exception(fptr->readconv);
3231 if (!NIL_P(exc))
3232 return exc;
3233
3234 if (cbuf_len0 != fptr->cbuf.len)
3235 return MORE_CHAR_SUSPENDED;
3236
3237 if (res == econv_finished) {
3238 return MORE_CHAR_FINISHED;
3239 }
3240
3241 if (res == econv_source_buffer_empty) {
3242 if (fptr->rbuf.len == 0) {
3243 READ_CHECK(fptr);
3244 if (io_fillbuf(fptr) < 0) {
3245 if (!fptr->readconv) {
3246 return MORE_CHAR_FINISHED;
3247 }
3248 ds = dp = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.off + fptr->cbuf.len;
3249 de = (unsigned char *)fptr->cbuf.ptr + fptr->cbuf.capa;
3250 res = rb_econv_convert(fptr->readconv, NULL, NULL, &dp, de, 0);
3251 fptr->cbuf.len += (int)(dp - ds);
3253 break;
3254 }
3255 }
3256 }
3257 }
3258 if (cbuf_len0 != fptr->cbuf.len)
3259 return MORE_CHAR_SUSPENDED;
3260
3261 return MORE_CHAR_FINISHED;
3262}
3263
3264static VALUE
3265more_char(rb_io_t *fptr)
3266{
3267 VALUE v;
3268 v = fill_cbuf(fptr, ECONV_AFTER_OUTPUT);
3269 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED)
3270 rb_exc_raise(v);
3271 return v;
3272}
3273
3274static VALUE
3275io_shift_cbuf(rb_io_t *fptr, int len, VALUE *strp)
3276{
3277 VALUE str = Qnil;
3278 if (strp) {
3279 str = *strp;
3280 if (NIL_P(str)) {
3281 *strp = str = rb_str_new(fptr->cbuf.ptr+fptr->cbuf.off, len);
3282 }
3283 else {
3284 rb_str_cat(str, fptr->cbuf.ptr+fptr->cbuf.off, len);
3285 }
3286 rb_enc_associate(str, fptr->encs.enc);
3287 }
3288 fptr->cbuf.off += len;
3289 fptr->cbuf.len -= len;
3290 /* xxx: set coderange */
3291 if (fptr->cbuf.len == 0)
3292 fptr->cbuf.off = 0;
3293 else if (fptr->cbuf.capa/2 < fptr->cbuf.off) {
3294 memmove(fptr->cbuf.ptr, fptr->cbuf.ptr+fptr->cbuf.off, fptr->cbuf.len);
3295 fptr->cbuf.off = 0;
3296 }
3297 return str;
3298}
3299
3300static int
3301io_setstrbuf(VALUE *str, long len)
3302{
3303#ifdef _WIN32
3304 if (len > 0)
3305 len = (len + 1) & ~1L; /* round up for wide char */
3306#endif
3307 if (NIL_P(*str)) {
3308 *str = rb_str_new(0, len);
3309 return TRUE;
3310 }
3311 else {
3312 VALUE s = StringValue(*str);
3313 rb_str_modify(s);
3314
3315 long clen = RSTRING_LEN(s);
3316 if (clen >= len) {
3317 return FALSE;
3318 }
3319 len -= clen;
3320 }
3321 if ((rb_str_capacity(*str) - (size_t)RSTRING_LEN(*str)) < (size_t)len) {
3323 }
3324 return FALSE;
3325}
3326
3327#define MAX_REALLOC_GAP 4096
3328static void
3329io_shrink_read_string(VALUE str, long n)
3330{
3331 if (rb_str_capacity(str) - n > MAX_REALLOC_GAP) {
3332 rb_str_resize(str, n);
3333 }
3334}
3335
3336static void
3337io_set_read_length(VALUE str, long n, int shrinkable)
3338{
3339 if (RSTRING_LEN(str) != n) {
3340 rb_str_modify(str);
3341 rb_str_set_len(str, n);
3342 if (shrinkable) io_shrink_read_string(str, n);
3343 }
3344}
3345
3346static VALUE
3347read_all(rb_io_t *fptr, long siz, VALUE str)
3348{
3349 long bytes;
3350 long n;
3351 long pos;
3352 rb_encoding *enc;
3353 int cr;
3354 int shrinkable;
3355
3356 if (NEED_READCONV(fptr)) {
3357 int first = !NIL_P(str);
3358 SET_BINARY_MODE(fptr);
3359 shrinkable = io_setstrbuf(&str,0);
3360 make_readconv(fptr, 0);
3361 while (1) {
3362 VALUE v;
3363 if (fptr->cbuf.len) {
3364 if (first) rb_str_set_len(str, first = 0);
3365 io_shift_cbuf(fptr, fptr->cbuf.len, &str);
3366 }
3367 v = fill_cbuf(fptr, 0);
3368 if (v != MORE_CHAR_SUSPENDED && v != MORE_CHAR_FINISHED) {
3369 if (fptr->cbuf.len) {
3370 if (first) rb_str_set_len(str, first = 0);
3371 io_shift_cbuf(fptr, fptr->cbuf.len, &str);
3372 }
3373 rb_exc_raise(v);
3374 }
3375 if (v == MORE_CHAR_FINISHED) {
3376 clear_readconv(fptr);
3377 if (first) rb_str_set_len(str, first = 0);
3378 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3379 return io_enc_str(str, fptr);
3380 }
3381 }
3382 }
3383
3384 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3385 bytes = 0;
3386 pos = 0;
3387
3388 enc = io_read_encoding(fptr);
3389 cr = 0;
3390
3391 if (siz == 0) siz = BUFSIZ;
3392 shrinkable = io_setstrbuf(&str, siz);
3393 for (;;) {
3394 READ_CHECK(fptr);
3395 n = io_fread(str, bytes, siz - bytes, fptr);
3396 if (n == 0 && bytes == 0) {
3397 rb_str_set_len(str, 0);
3398 break;
3399 }
3400 bytes += n;
3401 rb_str_set_len(str, bytes);
3402 if (cr != ENC_CODERANGE_BROKEN)
3403 pos += rb_str_coderange_scan_restartable(RSTRING_PTR(str) + pos, RSTRING_PTR(str) + bytes, enc, &cr);
3404 if (bytes < siz) break;
3405 siz += BUFSIZ;
3406
3407 size_t capa = rb_str_capacity(str);
3408 if (capa < (size_t)RSTRING_LEN(str) + BUFSIZ) {
3409 if (capa < BUFSIZ) {
3410 capa = BUFSIZ;
3411 }
3412 else if (capa > IO_MAX_BUFFER_GROWTH) {
3413 capa = IO_MAX_BUFFER_GROWTH;
3414 }
3416 }
3417 }
3418 if (shrinkable) io_shrink_read_string(str, RSTRING_LEN(str));
3419 str = io_enc_str(str, fptr);
3420 ENC_CODERANGE_SET(str, cr);
3421 return str;
3422}
3423
3424void
3426{
3427 if (rb_fd_set_nonblock(fptr->fd) != 0) {
3428 rb_sys_fail_path(fptr->pathv);
3429 }
3430}
3431
3432static VALUE
3433io_read_memory_call(VALUE arg)
3434{
3435 struct io_internal_read_struct *iis = (struct io_internal_read_struct *)arg;
3436
3437 VALUE scheduler = rb_fiber_scheduler_current();
3438 if (scheduler != Qnil) {
3439 VALUE result = rb_fiber_scheduler_io_read_memory(scheduler, iis->fptr->self, iis->buf, iis->capa, 0);
3440
3441 if (!UNDEF_P(result)) {
3442 // This is actually returned as a pseudo-VALUE and later cast to a long:
3444 }
3445 }
3446
3447 if (iis->nonblock) {
3448 return rb_io_blocking_region(iis->fptr, internal_read_func, iis);
3449 }
3450 else {
3451 return rb_io_blocking_region_wait(iis->fptr, internal_read_func, iis, RUBY_IO_READABLE);
3452 }
3453}
3454
3455static long
3456io_read_memory_locktmp(VALUE str, struct io_internal_read_struct *iis)
3457{
3458 return (long)rb_str_locktmp_ensure(str, io_read_memory_call, (VALUE)iis);
3459}
3460
3461#define no_exception_p(opts) !rb_opts_exception_p((opts), TRUE)
3462
3463static VALUE
3464io_getpartial(int argc, VALUE *argv, VALUE io, int no_exception, int nonblock)
3465{
3466 rb_io_t *fptr;
3467 VALUE length, str;
3468 long n, len;
3469 struct io_internal_read_struct iis;
3470 int shrinkable;
3471
3472 rb_scan_args(argc, argv, "11", &length, &str);
3473
3474 if ((len = NUM2LONG(length)) < 0) {
3475 rb_raise(rb_eArgError, "negative length %ld given", len);
3476 }
3477
3478 shrinkable = io_setstrbuf(&str, len);
3479
3480 GetOpenFile(io, fptr);
3482
3483 if (len == 0) {
3484 io_set_read_length(str, 0, shrinkable);
3485 return str;
3486 }
3487
3488 if (!nonblock)
3489 READ_CHECK(fptr);
3490 n = read_buffered_data(RSTRING_PTR(str), len, fptr);
3491 if (n <= 0) {
3492 again:
3493 if (nonblock) {
3494 rb_io_set_nonblock(fptr);
3495 }
3496 io_setstrbuf(&str, len);
3497 iis.th = rb_thread_current();
3498 iis.fptr = fptr;
3499 iis.nonblock = nonblock;
3500 iis.fd = fptr->fd;
3501 iis.buf = RSTRING_PTR(str);
3502 iis.capa = len;
3503 iis.timeout = NULL;
3504 n = io_read_memory_locktmp(str, &iis);
3505 if (n < 0) {
3506 int e = errno;
3507 if (!nonblock && fptr_wait_readable(fptr))
3508 goto again;
3509 if (nonblock && (io_again_p(e))) {
3510 if (no_exception)
3511 return sym_wait_readable;
3512 else
3513 rb_readwrite_syserr_fail(RB_IO_WAIT_READABLE,
3514 e, "read would block");
3515 }
3516 rb_syserr_fail_path(e, fptr->pathv);
3517 }
3518 }
3519 io_set_read_length(str, n, shrinkable);
3520
3521 if (n == 0)
3522 return Qnil;
3523 else
3524 return str;
3525}
3526
3527/*
3528 * call-seq:
3529 * readpartial(maxlen) -> string
3530 * readpartial(maxlen, out_string) -> out_string
3531 *
3532 * Reads up to +maxlen+ bytes from the stream;
3533 * returns a string (either a new string or the given +out_string+).
3534 * Its encoding is:
3535 *
3536 * - The unchanged encoding of +out_string+, if +out_string+ is given.
3537 * - ASCII-8BIT, otherwise.
3538 *
3539 * - Contains +maxlen+ bytes from the stream, if available.
3540 * - Otherwise contains all available bytes, if any available.
3541 * - Otherwise is an empty string.
3542 *
3543 * With the single non-negative integer argument +maxlen+ given,
3544 * returns a new string:
3545 *
3546 * f = File.new('t.txt')
3547 * f.readpartial(20) # => "First line\nSecond l"
3548 * f.readpartial(20) # => "ine\n\nFourth line\n"
3549 * f.readpartial(20) # => "Fifth line\n"
3550 * f.readpartial(20) # Raises EOFError.
3551 * f.close
3552 *
3553 * With both argument +maxlen+ and string argument +out_string+ given,
3554 * returns modified +out_string+:
3555 *
3556 * f = File.new('t.txt')
3557 * s = 'foo'
3558 * f.readpartial(20, s) # => "First line\nSecond l"
3559 * s = 'bar'
3560 * f.readpartial(0, s) # => ""
3561 * f.close
3562 *
3563 * This method is useful for a stream such as a pipe, a socket, or a tty.
3564 * It blocks only when no data is immediately available.
3565 * This means that it blocks only when _all_ of the following are true:
3566 *
3567 * - The byte buffer in the stream is empty.
3568 * - The content of the stream is empty.
3569 * - The stream is not at EOF.
3570 *
3571 * When blocked, the method waits for either more data or EOF on the stream:
3572 *
3573 * - If more data is read, the method returns the data.
3574 * - If EOF is reached, the method raises EOFError.
3575 *
3576 * When not blocked, the method responds immediately:
3577 *
3578 * - Returns data from the buffer if there is any.
3579 * - Otherwise returns data from the stream if there is any.
3580 * - Otherwise raises EOFError if the stream has reached EOF.
3581 *
3582 * Note that this method is similar to sysread. The differences are:
3583 *
3584 * - If the byte buffer is not empty, read from the byte buffer
3585 * instead of "sysread for buffered IO (IOError)".
3586 * - It doesn't cause Errno::EWOULDBLOCK and Errno::EINTR. When
3587 * readpartial meets EWOULDBLOCK and EINTR by read system call,
3588 * readpartial retries the system call.
3589 *
3590 * The latter means that readpartial is non-blocking-flag insensitive.
3591 * It blocks on the situation IO#sysread causes Errno::EWOULDBLOCK as
3592 * if the fd is blocking mode.
3593 *
3594 * Examples:
3595 *
3596 * # # Returned Buffer Content Pipe Content
3597 * r, w = IO.pipe #
3598 * w << 'abc' # "" "abc".
3599 * r.readpartial(4096) # => "abc" "" ""
3600 * r.readpartial(4096) # (Blocks because buffer and pipe are empty.)
3601 *
3602 * # # Returned Buffer Content Pipe Content
3603 * r, w = IO.pipe #
3604 * w << 'abc' # "" "abc"
3605 * w.close # "" "abc" EOF
3606 * r.readpartial(4096) # => "abc" "" EOF
3607 * r.readpartial(4096) # raises EOFError
3608 *
3609 * # # Returned Buffer Content Pipe Content
3610 * r, w = IO.pipe #
3611 * w << "abc\ndef\n" # "" "abc\ndef\n"
3612 * r.gets # => "abc\n" "def\n" ""
3613 * w << "ghi\n" # "def\n" "ghi\n"
3614 * r.readpartial(4096) # => "def\n" "" "ghi\n"
3615 * r.readpartial(4096) # => "ghi\n" "" ""
3616 *
3617 */
3618
3619static VALUE
3620io_readpartial(int argc, VALUE *argv, VALUE io)
3621{
3622 VALUE ret;
3623
3624 ret = io_getpartial(argc, argv, io, Qnil, 0);
3625 if (NIL_P(ret))
3626 rb_eof_error();
3627 return ret;
3628}
3629
3630static VALUE
3631io_nonblock_eof(int no_exception)
3632{
3633 if (!no_exception) {
3634 rb_eof_error();
3635 }
3636 return Qnil;
3637}
3638
3639/* :nodoc: */
3640static VALUE
3641io_read_nonblock(rb_execution_context_t *ec, VALUE io, VALUE length, VALUE str, VALUE ex)
3642{
3643 rb_io_t *fptr;
3644 long n, len;
3645 struct io_internal_read_struct iis;
3646 int shrinkable;
3647
3648 if ((len = NUM2LONG(length)) < 0) {
3649 rb_raise(rb_eArgError, "negative length %ld given", len);
3650 }
3651
3652 shrinkable = io_setstrbuf(&str, len);
3653 rb_bool_expected(ex, "exception", TRUE);
3654
3655 GetOpenFile(io, fptr);
3657
3658 if (len == 0) {
3659 io_set_read_length(str, 0, shrinkable);
3660 return str;
3661 }
3662
3663 n = read_buffered_data(RSTRING_PTR(str), len, fptr);
3664 if (n <= 0) {
3665 rb_fd_set_nonblock(fptr->fd);
3666 shrinkable |= io_setstrbuf(&str, len);
3667 iis.fptr = fptr;
3668 iis.nonblock = 1;
3669 iis.fd = fptr->fd;
3670 iis.buf = RSTRING_PTR(str);
3671 iis.capa = len;
3672 iis.timeout = NULL;
3673 n = io_read_memory_locktmp(str, &iis);
3674 if (n < 0) {
3675 int e = errno;
3676 if (io_again_p(e)) {
3677 if (!ex) return sym_wait_readable;
3678 rb_readwrite_syserr_fail(RB_IO_WAIT_READABLE,
3679 e, "read would block");
3680 }
3681 rb_syserr_fail_path(e, fptr->pathv);
3682 }
3683 }
3684 io_set_read_length(str, n, shrinkable);
3685
3686 if (n == 0) {
3687 if (!ex) return Qnil;
3688 rb_eof_error();
3689 }
3690
3691 return str;
3692}
3693
3694/* :nodoc: */
3695static VALUE
3696io_write_nonblock(rb_execution_context_t *ec, VALUE io, VALUE str, VALUE ex)
3697{
3698 rb_io_t *fptr;
3699 long n;
3700
3701 if (!RB_TYPE_P(str, T_STRING))
3702 str = rb_obj_as_string(str);
3703 rb_bool_expected(ex, "exception", TRUE);
3704
3705 io = GetWriteIO(io);
3706 GetOpenFile(io, fptr);
3708
3709 if (io_fflush(fptr) < 0)
3710 rb_sys_fail_on_write(fptr);
3711
3712 rb_fd_set_nonblock(fptr->fd);
3713 n = write(fptr->fd, RSTRING_PTR(str), RSTRING_LEN(str));
3714 RB_GC_GUARD(str);
3715
3716 if (n < 0) {
3717 int e = errno;
3718 if (io_again_p(e)) {
3719 if (!ex) {
3720 return sym_wait_writable;
3721 }
3722 else {
3723 rb_readwrite_syserr_fail(RB_IO_WAIT_WRITABLE, e, "write would block");
3724 }
3725 }
3726 rb_syserr_fail_path(e, fptr->pathv);
3727 }
3728
3729 return LONG2FIX(n);
3730}
3731
3732/*
3733 * call-seq:
3734 * read(maxlen = nil, out_string = nil) -> new_string, out_string, or nil
3735 *
3736 * Reads bytes from the stream; the stream must be opened for reading
3737 * (see {Access Modes}[rdoc-ref:File@Access+Modes]):
3738 *
3739 * - If +maxlen+ is +nil+, reads all bytes using the stream's data mode.
3740 * - Otherwise reads up to +maxlen+ bytes in binary mode.
3741 *
3742 * Returns a string (either a new string or the given +out_string+)
3743 * containing the bytes read.
3744 * The encoding of the string depends on both +maxLen+ and +out_string+:
3745 *
3746 * - +maxlen+ is +nil+: uses internal encoding of +self+
3747 * (regardless of whether +out_string+ was given).
3748 * - +maxlen+ not +nil+:
3749 *
3750 * - +out_string+ given: encoding of +out_string+ not modified.
3751 * - +out_string+ not given: ASCII-8BIT is used.
3752 *
3753 * <b>Without Argument +out_string+</b>
3754 *
3755 * When argument +out_string+ is omitted,
3756 * the returned value is a new string:
3757 *
3758 * f = File.new('t.txt')
3759 * f.read
3760 * # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3761 * f.rewind
3762 * f.read(30) # => "First line\r\nSecond line\r\n\r\nFou"
3763 * f.read(30) # => "rth line\r\nFifth line\r\n"
3764 * f.read(30) # => nil
3765 * f.close
3766 *
3767 * If +maxlen+ is zero, returns an empty string.
3768 *
3769 * <b> With Argument +out_string+</b>
3770 *
3771 * When argument +out_string+ is given,
3772 * the returned value is +out_string+, whose content is replaced:
3773 *
3774 * f = File.new('t.txt')
3775 * s = 'foo' # => "foo"
3776 * f.read(nil, s) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3777 * s # => "First line\nSecond line\n\nFourth line\nFifth line\n"
3778 * f.rewind
3779 * s = 'bar'
3780 * f.read(30, s) # => "First line\r\nSecond line\r\n\r\nFou"
3781 * s # => "First line\r\nSecond line\r\n\r\nFou"
3782 * s = 'baz'
3783 * f.read(30, s) # => "rth line\r\nFifth line\r\n"
3784 * s # => "rth line\r\nFifth line\r\n"
3785 * s = 'bat'
3786 * f.read(30, s) # => nil
3787 * s # => ""
3788 * f.close
3789 *
3790 * Note that this method behaves like the fread() function in C.
3791 * This means it retries to invoke read(2) system calls to read data
3792 * with the specified maxlen (or until EOF).
3793 *
3794 * This behavior is preserved even if the stream is in non-blocking mode.
3795 * (This method is non-blocking-flag insensitive as other methods.)
3796 *
3797 * If you need the behavior like a single read(2) system call,
3798 * consider #readpartial, #read_nonblock, and #sysread.
3799 *
3800 * Related: IO#write.
3801 */
3802
3803static VALUE
3804io_read(int argc, VALUE *argv, VALUE io)
3805{
3806 rb_io_t *fptr;
3807 long n, len;
3808 VALUE length, str;
3809 int shrinkable;
3810#if RUBY_CRLF_ENVIRONMENT
3811 int previous_mode;
3812#endif
3813
3814 rb_scan_args(argc, argv, "02", &length, &str);
3815
3816 if (NIL_P(length)) {
3817 GetOpenFile(io, fptr);
3819 return read_all(fptr, remain_size(fptr), str);
3820 }
3821 len = NUM2LONG(length);
3822 if (len < 0) {
3823 rb_raise(rb_eArgError, "negative length %ld given", len);
3824 }
3825
3826 shrinkable = io_setstrbuf(&str,len);
3827
3828 GetOpenFile(io, fptr);
3830 if (len == 0) {
3831 io_set_read_length(str, 0, shrinkable);
3832 return str;
3833 }
3834
3835 READ_CHECK(fptr);
3836#if RUBY_CRLF_ENVIRONMENT
3837 previous_mode = set_binary_mode_with_seek_cur(fptr);
3838#endif
3839 n = io_fread(str, 0, len, fptr);
3840 io_set_read_length(str, n, shrinkable);
3841#if RUBY_CRLF_ENVIRONMENT
3842 if (previous_mode == O_TEXT) {
3843 setmode(fptr->fd, O_TEXT);
3844 }
3845#endif
3846 if (n == 0) return Qnil;
3847
3848 return str;
3849}
3850
3851static void
3852rscheck(const char *rsptr, long rslen, VALUE rs)
3853{
3854 if (!rs) return;
3855 if (RSTRING_PTR(rs) != rsptr && RSTRING_LEN(rs) != rslen)
3856 rb_raise(rb_eRuntimeError, "rs modified");
3857}
3858
3859static const char *
3860search_delim(const char *p, long len, int delim, rb_encoding *enc)
3861{
3862 if (rb_enc_mbminlen(enc) == 1) {
3863 p = memchr(p, delim, len);
3864 if (p) return p + 1;
3865 }
3866 else {
3867 const char *end = p + len;
3868 while (p < end) {
3869 int r = rb_enc_precise_mbclen(p, end, enc);
3870 if (!MBCLEN_CHARFOUND_P(r)) {
3871 p += rb_enc_mbminlen(enc);
3872 continue;
3873 }
3874 int n = MBCLEN_CHARFOUND_LEN(r);
3875 if (rb_enc_mbc_to_codepoint(p, end, enc) == (unsigned int)delim) {
3876 return p + n;
3877 }
3878 p += n;
3879 }
3880 }
3881 return NULL;
3882}
3883
3884static int
3885appendline(rb_io_t *fptr, int delim, VALUE *strp, long *lp, rb_encoding *enc)
3886{
3887 VALUE str = *strp;
3888 long limit = *lp;
3889
3890 if (NEED_READCONV(fptr)) {
3891 SET_BINARY_MODE(fptr);
3892 make_readconv(fptr, 0);
3893 do {
3894 const char *p, *e;
3895 int searchlen = READ_CHAR_PENDING_COUNT(fptr);
3896 if (searchlen) {
3897 p = READ_CHAR_PENDING_PTR(fptr);
3898 if (0 < limit && limit < searchlen)
3899 searchlen = (int)limit;
3900 e = search_delim(p, searchlen, delim, enc);
3901 if (e) {
3902 int len = (int)(e-p);
3903 if (NIL_P(str))
3904 *strp = str = rb_str_new(p, len);
3905 else
3906 rb_str_buf_cat(str, p, len);
3907 fptr->cbuf.off += len;
3908 fptr->cbuf.len -= len;
3909 limit -= len;
3910 *lp = limit;
3911 return delim;
3912 }
3913
3914 if (NIL_P(str))
3915 *strp = str = rb_str_new(p, searchlen);
3916 else
3917 rb_str_buf_cat(str, p, searchlen);
3918 fptr->cbuf.off += searchlen;
3919 fptr->cbuf.len -= searchlen;
3920 limit -= searchlen;
3921
3922 if (limit == 0) {
3923 *lp = limit;
3924 return (unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
3925 }
3926 }
3927 } while (more_char(fptr) != MORE_CHAR_FINISHED);
3928 clear_readconv(fptr);
3929 *lp = limit;
3930 return EOF;
3931 }
3932
3933 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3934 do {
3935 long pending = READ_DATA_PENDING_COUNT(fptr);
3936 if (pending > 0) {
3937 const char *p = READ_DATA_PENDING_PTR(fptr);
3938 const char *e;
3939 long last;
3940
3941 if (limit > 0 && pending > limit) pending = limit;
3942 e = search_delim(p, pending, delim, enc);
3943 if (e) pending = e - p;
3944 if (!NIL_P(str)) {
3945 last = RSTRING_LEN(str);
3946 rb_str_resize(str, last + pending);
3947 }
3948 else {
3949 last = 0;
3950 *strp = str = rb_str_buf_new(pending);
3951 rb_str_set_len(str, pending);
3952 }
3953 read_buffered_data(RSTRING_PTR(str) + last, pending, fptr); /* must not fail */
3954 limit -= pending;
3955 *lp = limit;
3956 if (e) return delim;
3957 if (limit == 0)
3958 return (unsigned char)RSTRING_PTR(str)[RSTRING_LEN(str)-1];
3959 }
3960 READ_CHECK(fptr);
3961 } while (io_fillbuf(fptr) >= 0);
3962 *lp = limit;
3963 return EOF;
3964}
3965
3966static inline int
3967swallow(rb_io_t *fptr, int term)
3968{
3969 if (NEED_READCONV(fptr)) {
3970 rb_encoding *enc = io_read_encoding(fptr);
3971 int needconv = rb_enc_mbminlen(enc) != 1;
3972 SET_BINARY_MODE(fptr);
3973 make_readconv(fptr, 0);
3974 do {
3975 size_t cnt;
3976 while ((cnt = READ_CHAR_PENDING_COUNT(fptr)) > 0) {
3977 const char *p = READ_CHAR_PENDING_PTR(fptr);
3978 int i;
3979 if (!needconv) {
3980 if (*p != term) return TRUE;
3981 i = (int)cnt;
3982 while (--i && *++p == term);
3983 }
3984 else {
3985 const char *e = p + cnt;
3986 if (rb_enc_ascget(p, e, &i, enc) != term) return TRUE;
3987 while ((p += i) < e && rb_enc_ascget(p, e, &i, enc) == term);
3988 i = (int)(e - p);
3989 }
3990 io_shift_cbuf(fptr, (int)cnt - i, NULL);
3991 }
3992 } while (more_char(fptr) != MORE_CHAR_FINISHED);
3993 return FALSE;
3994 }
3995
3996 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
3997 do {
3998 size_t cnt;
3999 while ((cnt = READ_DATA_PENDING_COUNT(fptr)) > 0) {
4000 char buf[1024];
4001 const char *p = READ_DATA_PENDING_PTR(fptr);
4002 int i;
4003 if (cnt > sizeof buf) cnt = sizeof buf;
4004 if (*p != term) return TRUE;
4005 i = (int)cnt;
4006 while (--i && *++p == term);
4007 if (!read_buffered_data(buf, cnt - i, fptr)) /* must not fail */
4008 rb_sys_fail_path(fptr->pathv);
4009 }
4010 READ_CHECK(fptr);
4011 } while (io_fillbuf(fptr) == 0);
4012 return FALSE;
4013}
4014
4015static VALUE
4016rb_io_getline_fast(rb_io_t *fptr, rb_encoding *enc, int chomp)
4017{
4018 VALUE str = Qnil;
4019 int len = 0;
4020 long pos = 0;
4021 int cr = 0;
4022
4023 do {
4024 int pending = READ_DATA_PENDING_COUNT(fptr);
4025
4026 if (pending > 0) {
4027 const char *p = READ_DATA_PENDING_PTR(fptr);
4028 const char *e;
4029 int chomplen = 0;
4030
4031 e = memchr(p, '\n', pending);
4032 if (e) {
4033 pending = (int)(e - p + 1);
4034 if (chomp) {
4035 chomplen = (pending > 1 && *(e-1) == '\r') + 1;
4036 }
4037 }
4038 if (NIL_P(str)) {
4039 str = rb_str_new(p, pending - chomplen);
4040 fptr->rbuf.off += pending;
4041 fptr->rbuf.len -= pending;
4042 }
4043 else {
4044 rb_str_resize(str, len + pending - chomplen);
4045 read_buffered_data(RSTRING_PTR(str)+len, pending - chomplen, fptr);
4046 fptr->rbuf.off += chomplen;
4047 fptr->rbuf.len -= chomplen;
4048 if (pending == 1 && chomplen == 1 && len > 0) {
4049 if (RSTRING_PTR(str)[len-1] == '\r') {
4050 rb_str_resize(str, --len);
4051 break;
4052 }
4053 }
4054 }
4055 len += pending - chomplen;
4056 if (cr != ENC_CODERANGE_BROKEN)
4057 pos += rb_str_coderange_scan_restartable(RSTRING_PTR(str) + pos, RSTRING_PTR(str) + len, enc, &cr);
4058 if (e) break;
4059 }
4060 READ_CHECK(fptr);
4061 } while (io_fillbuf(fptr) >= 0);
4062 if (NIL_P(str)) return Qnil;
4063
4064 str = io_enc_str(str, fptr);
4065 ENC_CODERANGE_SET(str, cr);
4066 fptr->lineno++;
4067
4068 return str;
4069}
4070
4072 VALUE io;
4073 VALUE rs;
4074 long limit;
4075 unsigned int chomp: 1;
4076};
4077
4078static void
4079extract_getline_opts(VALUE opts, struct getline_arg *args)
4080{
4081 int chomp = FALSE;
4082 if (!NIL_P(opts)) {
4083 static ID kwds[1];
4084 VALUE vchomp;
4085 if (!kwds[0]) {
4086 kwds[0] = rb_intern_const("chomp");
4087 }
4088 rb_get_kwargs(opts, kwds, 0, -2, &vchomp);
4089 chomp = (!UNDEF_P(vchomp)) && RTEST(vchomp);
4090 }
4091 args->chomp = chomp;
4092}
4093
4094static void
4095extract_getline_args(int argc, VALUE *argv, struct getline_arg *args)
4096{
4097 VALUE rs = rb_rs, lim = Qnil;
4098
4099 if (argc == 1) {
4100 VALUE tmp = Qnil;
4101
4102 if (NIL_P(argv[0]) || !NIL_P(tmp = rb_check_string_type(argv[0]))) {
4103 rs = tmp;
4104 }
4105 else {
4106 lim = argv[0];
4107 }
4108 }
4109 else if (2 <= argc) {
4110 rs = argv[0], lim = argv[1];
4111 if (!NIL_P(rs))
4112 StringValue(rs);
4113 }
4114 args->rs = rs;
4115 args->limit = NIL_P(lim) ? -1L : NUM2LONG(lim);
4116}
4117
4118static void
4119check_getline_args(VALUE *rsp, long *limit, VALUE io)
4120{
4121 rb_io_t *fptr;
4122 VALUE rs = *rsp;
4123
4124 if (!NIL_P(rs)) {
4125 rb_encoding *enc_rs, *enc_io;
4126
4127 GetOpenFile(io, fptr);
4128 enc_rs = rb_enc_get(rs);
4129 enc_io = io_read_encoding(fptr);
4130 if (enc_io != enc_rs &&
4131 (!is_ascii_string(rs) ||
4132 (RSTRING_LEN(rs) > 0 && !rb_enc_asciicompat(enc_io)))) {
4133 if (rs == rb_default_rs) {
4134 rs = rb_enc_str_new(0, 0, enc_io);
4135 rb_str_buf_cat_ascii(rs, "\n");
4136 *rsp = rs;
4137 }
4138 else {
4139 rb_raise(rb_eArgError, "encoding mismatch: %s IO with %s RS",
4140 rb_enc_name(enc_io),
4141 rb_enc_name(enc_rs));
4142 }
4143 }
4144 }
4145}
4146
4147static void
4148prepare_getline_args(int argc, VALUE *argv, struct getline_arg *args, VALUE io)
4149{
4150 VALUE opts;
4151 argc = rb_scan_args(argc, argv, "02:", NULL, NULL, &opts);
4152 extract_getline_args(argc, argv, args);
4153 extract_getline_opts(opts, args);
4154 check_getline_args(&args->rs, &args->limit, io);
4155}
4156
4157static VALUE
4158rb_io_getline_0(VALUE rs, long limit, int chomp, rb_io_t *fptr)
4159{
4160 VALUE str = Qnil;
4161 int nolimit = 0;
4162 rb_encoding *enc;
4163
4165 if (NIL_P(rs) && limit < 0) {
4166 str = read_all(fptr, 0, Qnil);
4167 if (RSTRING_LEN(str) == 0) return Qnil;
4168 }
4169 else if (limit == 0) {
4170 return rb_enc_str_new(0, 0, io_read_encoding(fptr));
4171 }
4172 else if (rs == rb_default_rs && limit < 0 && !NEED_READCONV(fptr) &&
4173 rb_enc_asciicompat(enc = io_read_encoding(fptr))) {
4174 NEED_NEWLINE_DECORATOR_ON_READ_CHECK(fptr);
4175 return rb_io_getline_fast(fptr, enc, chomp);
4176 }
4177 else {
4178 int c, newline = -1;
4179 const char *rsptr = 0;
4180 long rslen = 0;
4181 int rspara = 0;
4182 int extra_limit = 16;
4183 int chomp_cr = chomp;
4184
4185 SET_BINARY_MODE(fptr);
4186 enc = io_read_encoding(fptr);
4187
4188 if (!NIL_P(rs)) {
4189 rslen = RSTRING_LEN(rs);
4190 if (rslen == 0) {
4191 rsptr = "\n\n";
4192 rslen = 2;
4193 rspara = 1;
4194 swallow(fptr, '\n');
4195 rs = 0;
4196 if (!rb_enc_asciicompat(enc)) {
4197 rs = rb_usascii_str_new(rsptr, rslen);
4198 rs = rb_str_conv_enc(rs, 0, enc);
4199 OBJ_FREEZE(rs);
4200 rsptr = RSTRING_PTR(rs);
4201 rslen = RSTRING_LEN(rs);
4202 }
4203 newline = '\n';
4204 }
4205 else if (rb_enc_mbminlen(enc) == 1) {
4206 rsptr = RSTRING_PTR(rs);
4207 newline = (unsigned char)rsptr[rslen - 1];
4208 }
4209 else {
4210 rs = rb_str_conv_enc(rs, 0, enc);
4211 rsptr = RSTRING_PTR(rs);
4212 const char *e = rsptr + rslen;
4213 const char *last = rb_enc_prev_char(rsptr, e, e, enc);
4214 int n;
4215 newline = rb_enc_codepoint_len(last, e, &n, enc);
4216 if (last + n != e) rb_raise(rb_eArgError, "broken separator");
4217 }
4218 chomp_cr = chomp && newline == '\n' && rslen == rb_enc_mbminlen(enc);
4219 }
4220
4221 /* MS - Optimization */
4222 while ((c = appendline(fptr, newline, &str, &limit, enc)) != EOF) {
4223 const char *s, *p, *pp, *e;
4224
4225 if (c == newline) {
4226 if (RSTRING_LEN(str) < rslen) continue;
4227 s = RSTRING_PTR(str);
4228 e = RSTRING_END(str);
4229 p = e - rslen;
4230 if (!at_char_boundary(s, p, e, enc)) continue;
4231 if (!rspara) rscheck(rsptr, rslen, rs);
4232 if (memcmp(p, rsptr, rslen) == 0) {
4233 if (chomp) {
4234 if (chomp_cr && p > s && *(p-1) == '\r') --p;
4235 rb_str_set_len(str, p - s);
4236 }
4237 break;
4238 }
4239 }
4240 if (limit == 0) {
4241 s = RSTRING_PTR(str);
4242 p = RSTRING_END(str);
4243 pp = rb_enc_prev_char(s, p, p, enc);
4244 if (extra_limit && pp &&
4245 MBCLEN_NEEDMORE_P(rb_enc_precise_mbclen(pp, p, enc))) {
4246 /* relax the limit while incomplete character.
4247 * extra_limit limits the relax length */
4248 limit = 1;
4249 extra_limit--;
4250 }
4251 else {
4252 nolimit = 1;
4253 break;
4254 }
4255 }
4256 }
4257
4258 if (rspara && c != EOF)
4259 swallow(fptr, '\n');
4260 if (!NIL_P(str))
4261 str = io_enc_str(str, fptr);
4262 }
4263
4264 if (!NIL_P(str) && !nolimit) {
4265 fptr->lineno++;
4266 }
4267
4268 return str;
4269}
4270
4271static VALUE
4272rb_io_getline_1(VALUE rs, long limit, int chomp, VALUE io)
4273{
4274 rb_io_t *fptr;
4275 int old_lineno, new_lineno;
4276 VALUE str;
4277
4278 GetOpenFile(io, fptr);
4279 old_lineno = fptr->lineno;
4280 str = rb_io_getline_0(rs, limit, chomp, fptr);
4281 if (!NIL_P(str) && (new_lineno = fptr->lineno) != old_lineno) {
4282 if (io == ARGF.current_file) {
4283 ARGF.lineno += new_lineno - old_lineno;
4284 ARGF.last_lineno = ARGF.lineno;
4285 }
4286 else {
4287 ARGF.last_lineno = new_lineno;
4288 }
4289 }
4290
4291 return str;
4292}
4293
4294static VALUE
4295rb_io_getline(int argc, VALUE *argv, VALUE io)
4296{
4297 struct getline_arg args;
4298
4299 prepare_getline_args(argc, argv, &args, io);
4300 return rb_io_getline_1(args.rs, args.limit, args.chomp, io);
4301}
4302
4303VALUE
4305{
4306 return rb_io_getline_1(rb_default_rs, -1, FALSE, io);
4307}
4308
4309VALUE
4310rb_io_gets_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{
5522 VALUE error = Qnil;
5523 int fd = fptr->fd;
5524 FILE *stdio_file = fptr->stdio_file;
5525 int mode = fptr->mode;
5526
5527 if (fptr->writeconv) {
5528 if (!NIL_P(fptr->write_lock) && !noraise) {
5529 struct finish_writeconv_arg arg;
5530 arg.fptr = fptr;
5531 arg.noalloc = noraise;
5532 error = rb_mutex_synchronize(fptr->write_lock, finish_writeconv_sync, (VALUE)&arg);
5533 }
5534 else {
5535 error = finish_writeconv(fptr, noraise);
5536 }
5537 }
5538 if (fptr->wbuf.len) {
5539 if (noraise) {
5540 io_flush_buffer_sync(fptr);
5541 }
5542 else {
5543 if (io_fflush(fptr) < 0 && NIL_P(error)) {
5544 error = INT2NUM(errno);
5545 }
5546 }
5547 }
5548
5549 int done = 0;
5550
5551 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2) {
5552 // Need to keep FILE objects of stdin, stdout and stderr, so we are done:
5553 done = 1;
5554 }
5555
5556 fptr->fd = -1;
5557 fptr->stdio_file = 0;
5559
5560 // wait for blocking operations to ensure they do not hit EBADF:
5561 rb_thread_io_close_wait(fptr);
5562
5563 // Disable for now.
5564 // if (!done && fd >= 0) {
5565 // VALUE scheduler = rb_fiber_scheduler_current();
5566 // if (scheduler != Qnil) {
5567 // VALUE result = rb_fiber_scheduler_io_close(scheduler, fptr->self);
5568 // if (!UNDEF_P(result)) done = 1;
5569 // }
5570 // }
5571
5572 if (!done && stdio_file) {
5573 // stdio_file is deallocated anyway even if fclose failed.
5574 if ((maygvl_fclose(stdio_file, noraise) < 0) && NIL_P(error)) {
5575 if (!noraise) {
5576 error = INT2NUM(errno);
5577 }
5578 }
5579
5580 done = 1;
5581 }
5582
5583 if (!done && fd >= 0) {
5584 // fptr->fd may be closed even if close fails. POSIX doesn't specify it.
5585 // We assumes it is closed.
5586
5587 keepgvl |= !(mode & FMODE_WRITABLE);
5588 keepgvl |= noraise;
5589 if ((maygvl_close(fd, keepgvl) < 0) && NIL_P(error)) {
5590 if (!noraise) {
5591 error = INT2NUM(errno);
5592 }
5593 }
5594
5595 done = 1;
5596 }
5597
5598 if (!NIL_P(error) && !noraise) {
5599 if (RB_INTEGER_TYPE_P(error))
5600 rb_syserr_fail_path(NUM2INT(error), fptr->pathv);
5601 else
5602 rb_exc_raise(error);
5603 }
5604}
5605
5606static void
5607fptr_finalize(rb_io_t *fptr, int noraise)
5608{
5609 fptr_finalize_flush(fptr, noraise, FALSE);
5610 free_io_buffer(&fptr->rbuf);
5611 free_io_buffer(&fptr->wbuf);
5612 clear_codeconv(fptr);
5613}
5614
5615static void
5616rb_io_fptr_cleanup(rb_io_t *fptr, int noraise)
5617{
5618 if (fptr->finalize) {
5619 (*fptr->finalize)(fptr, noraise);
5620 }
5621 else {
5622 fptr_finalize(fptr, noraise);
5623 }
5624}
5625
5626static void
5627free_io_buffer(rb_io_buffer_t *buf)
5628{
5629 if (buf->ptr) {
5630 ruby_sized_xfree(buf->ptr, (size_t)buf->capa);
5631 buf->ptr = NULL;
5632 }
5633}
5634
5635static void
5636clear_readconv(rb_io_t *fptr)
5637{
5638 if (fptr->readconv) {
5639 rb_econv_close(fptr->readconv);
5640 fptr->readconv = NULL;
5641 }
5642 free_io_buffer(&fptr->cbuf);
5643}
5644
5645static void
5646clear_writeconv(rb_io_t *fptr)
5647{
5648 if (fptr->writeconv) {
5650 fptr->writeconv = NULL;
5651 }
5652 fptr->writeconv_initialized = 0;
5653}
5654
5655static void
5656clear_codeconv(rb_io_t *fptr)
5657{
5658 clear_readconv(fptr);
5659 clear_writeconv(fptr);
5660}
5661
5662static void
5663rb_io_fptr_cleanup_all(rb_io_t *fptr)
5664{
5665 fptr->pathv = Qnil;
5666 if (0 <= fptr->fd)
5667 rb_io_fptr_cleanup(fptr, TRUE);
5668 fptr->write_lock = Qnil;
5669 free_io_buffer(&fptr->rbuf);
5670 free_io_buffer(&fptr->wbuf);
5671 clear_codeconv(fptr);
5672}
5673
5674int
5676{
5677 if (!io) return 0;
5678 rb_io_fptr_cleanup_all(io);
5679 free(io);
5680
5681 return 1;
5682}
5683
5684size_t
5685rb_io_memsize(const rb_io_t *io)
5686{
5687 size_t size = sizeof(rb_io_t);
5688 size += io->rbuf.capa;
5689 size += io->wbuf.capa;
5690 size += io->cbuf.capa;
5691 if (io->readconv) size += rb_econv_memsize(io->readconv);
5692 if (io->writeconv) size += rb_econv_memsize(io->writeconv);
5693
5694 struct rb_io_blocking_operation *blocking_operation = 0;
5695
5696 // Validate the fork generation of the IO object. If the IO object fork generation is different, the list of blocking operations is not valid memory. See `rb_io_blocking_operations` for the exact semantics.
5697 rb_serial_t fork_generation = GET_VM()->fork_gen;
5698 if (io->fork_generation == fork_generation) {
5699 ccan_list_for_each(&io->blocking_operations, blocking_operation, list) {
5700 size += sizeof(struct rb_io_blocking_operation);
5701 }
5702 }
5703
5704 return size;
5705}
5706
5707#ifdef _WIN32
5708/* keep GVL while closing to prevent crash on Windows */
5709# define KEEPGVL TRUE
5710#else
5711# define KEEPGVL FALSE
5712#endif
5713
5714static rb_io_t *
5715io_close_fptr(VALUE io)
5716{
5717 rb_io_t *fptr;
5718 VALUE write_io;
5719 rb_io_t *write_fptr;
5720
5721 write_io = GetWriteIO(io);
5722 if (io != write_io) {
5723 write_fptr = RFILE(write_io)->fptr;
5724 if (write_fptr && 0 <= write_fptr->fd) {
5725 rb_io_fptr_cleanup(write_fptr, TRUE);
5726 }
5727 }
5728
5729 fptr = RFILE(io)->fptr;
5730 if (!fptr) return 0;
5731 if (fptr->fd < 0) return 0;
5732
5733 if (rb_thread_io_close_interrupt(fptr)) {
5734 /* calls close(fptr->fd): */
5735 fptr_finalize_flush(fptr, FALSE, KEEPGVL);
5736 }
5737 rb_io_fptr_cleanup(fptr, FALSE);
5738 return fptr;
5739}
5740
5741static void
5742fptr_waitpid(rb_io_t *fptr, int nohang)
5743{
5744 int status;
5745 if (fptr->pid) {
5746 rb_last_status_clear();
5747 rb_waitpid(fptr->pid, &status, nohang ? WNOHANG : 0);
5748 fptr->pid = 0;
5749 }
5750}
5751
5752VALUE
5754{
5755 rb_io_t *fptr = io_close_fptr(io);
5756 if (fptr) fptr_waitpid(fptr, 0);
5757 return Qnil;
5758}
5759
5760/*
5761 * call-seq:
5762 * close -> nil
5763 *
5764 * Closes the stream for both reading and writing
5765 * if open for either or both; returns +nil+.
5766 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5767 *
5768 * If the stream is open for writing, flushes any buffered writes
5769 * to the operating system before closing.
5770 *
5771 * If the stream was opened by IO.popen, sets global variable <tt>$?</tt>
5772 * (child exit status).
5773 *
5774 * It is not an error to close an IO object that has already been closed.
5775 * It just returns nil.
5776 *
5777 * Example:
5778 *
5779 * IO.popen('ruby', 'r+') do |pipe|
5780 * puts pipe.closed?
5781 * pipe.close
5782 * puts $?
5783 * puts pipe.closed?
5784 * end
5785 *
5786 * Output:
5787 *
5788 * false
5789 * pid 13760 exit 0
5790 * true
5791 *
5792 * Related: IO#close_read, IO#close_write, IO#closed?.
5793 */
5794
5795static VALUE
5796rb_io_close_m(VALUE io)
5797{
5798 rb_io_t *fptr = rb_io_get_fptr(io);
5799 if (fptr->fd < 0) {
5800 return Qnil;
5801 }
5802 rb_io_close(io);
5803 return Qnil;
5804}
5805
5806static VALUE
5807io_call_close(VALUE io)
5808{
5809 rb_check_funcall(io, rb_intern("close"), 0, 0);
5810 return io;
5811}
5812
5813static VALUE
5814ignore_closed_stream(VALUE io, VALUE exc)
5815{
5816 enum {mesg_len = sizeof(closed_stream)-1};
5817 VALUE mesg = rb_attr_get(exc, idMesg);
5818 if (!RB_TYPE_P(mesg, T_STRING) ||
5819 RSTRING_LEN(mesg) != mesg_len ||
5820 memcmp(RSTRING_PTR(mesg), closed_stream, mesg_len)) {
5821 rb_exc_raise(exc);
5822 }
5823 return io;
5824}
5825
5826static VALUE
5827io_close(VALUE io)
5828{
5829 VALUE closed = rb_check_funcall(io, rb_intern("closed?"), 0, 0);
5830 if (!UNDEF_P(closed) && RTEST(closed)) return io;
5831 rb_rescue2(io_call_close, io, ignore_closed_stream, io,
5832 rb_eIOError, (VALUE)0);
5833 return io;
5834}
5835
5836/*
5837 * call-seq:
5838 * closed? -> true or false
5839 *
5840 * Returns +true+ if the stream is closed for both reading and writing,
5841 * +false+ otherwise.
5842 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5843 *
5844 * IO.popen('ruby', 'r+') do |pipe|
5845 * puts pipe.closed?
5846 * pipe.close_read
5847 * puts pipe.closed?
5848 * pipe.close_write
5849 * puts pipe.closed?
5850 * end
5851 *
5852 * Output:
5853 *
5854 * false
5855 * false
5856 * true
5857 *
5858 * Related: IO#close_read, IO#close_write, IO#close.
5859 */
5860VALUE
5862{
5863 rb_io_t *fptr;
5864 VALUE write_io;
5865 rb_io_t *write_fptr;
5866
5867 write_io = GetWriteIO(io);
5868 if (io != write_io) {
5869 write_fptr = RFILE(write_io)->fptr;
5870 if (write_fptr && 0 <= write_fptr->fd) {
5871 return Qfalse;
5872 }
5873 }
5874
5875 fptr = rb_io_get_fptr(io);
5876 return RBOOL(0 > fptr->fd);
5877}
5878
5879/*
5880 * call-seq:
5881 * close_read -> nil
5882 *
5883 * Closes the stream for reading if open for reading;
5884 * returns +nil+.
5885 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5886 *
5887 * If the stream was opened by IO.popen and is also closed for writing,
5888 * sets global variable <tt>$?</tt> (child exit status).
5889 *
5890 * Example:
5891 *
5892 * IO.popen('ruby', 'r+') do |pipe|
5893 * puts pipe.closed?
5894 * pipe.close_write
5895 * puts pipe.closed?
5896 * pipe.close_read
5897 * puts $?
5898 * puts pipe.closed?
5899 * end
5900 *
5901 * Output:
5902 *
5903 * false
5904 * false
5905 * pid 14748 exit 0
5906 * true
5907 *
5908 * Related: IO#close, IO#close_write, IO#closed?.
5909 */
5910
5911static VALUE
5912rb_io_close_read(VALUE io)
5913{
5914 rb_io_t *fptr;
5915 VALUE write_io;
5916
5917 fptr = rb_io_get_fptr(rb_io_taint_check(io));
5918 if (fptr->fd < 0) return Qnil;
5919 if (is_socket(fptr->fd, fptr->pathv)) {
5920#ifndef SHUT_RD
5921# define SHUT_RD 0
5922#endif
5923 if (shutdown(fptr->fd, SHUT_RD) < 0)
5924 rb_sys_fail_path(fptr->pathv);
5925 fptr->mode &= ~FMODE_READABLE;
5926 if (!(fptr->mode & FMODE_WRITABLE))
5927 return rb_io_close(io);
5928 return Qnil;
5929 }
5930
5931 write_io = GetWriteIO(io);
5932 if (io != write_io) {
5933 rb_io_t *wfptr;
5934 wfptr = rb_io_get_fptr(rb_io_taint_check(write_io));
5935 wfptr->pid = fptr->pid;
5936 fptr->pid = 0;
5937 RFILE(io)->fptr = wfptr;
5938 /* bind to write_io temporarily to get rid of memory/fd leak */
5939 fptr->tied_io_for_writing = 0;
5940 RFILE(write_io)->fptr = fptr;
5941 rb_io_fptr_cleanup(fptr, FALSE);
5942 /* should not finalize fptr because another thread may be reading it */
5943 return Qnil;
5944 }
5945
5946 if ((fptr->mode & (FMODE_DUPLEX|FMODE_WRITABLE)) == FMODE_WRITABLE) {
5947 rb_raise(rb_eIOError, "closing non-duplex IO for reading");
5948 }
5949 return rb_io_close(io);
5950}
5951
5952/*
5953 * call-seq:
5954 * close_write -> nil
5955 *
5956 * Closes the stream for writing if open for writing;
5957 * returns +nil+.
5958 * See {Open and Closed Streams}[rdoc-ref:IO@Open+and+Closed+Streams].
5959 *
5960 * Flushes any buffered writes to the operating system before closing.
5961 *
5962 * If the stream was opened by IO.popen and is also closed for reading,
5963 * sets global variable <tt>$?</tt> (child exit status).
5964 *
5965 * IO.popen('ruby', 'r+') do |pipe|
5966 * puts pipe.closed?
5967 * pipe.close_read
5968 * puts pipe.closed?
5969 * pipe.close_write
5970 * puts $?
5971 * puts pipe.closed?
5972 * end
5973 *
5974 * Output:
5975 *
5976 * false
5977 * false
5978 * pid 15044 exit 0
5979 * true
5980 *
5981 * Related: IO#close, IO#close_read, IO#closed?.
5982 */
5983
5984static VALUE
5985rb_io_close_write(VALUE io)
5986{
5987 rb_io_t *fptr;
5988 VALUE write_io;
5989
5990 write_io = GetWriteIO(io);
5991 fptr = rb_io_get_fptr(rb_io_taint_check(write_io));
5992 if (fptr->fd < 0) return Qnil;
5993 if (is_socket(fptr->fd, fptr->pathv)) {
5994#ifndef SHUT_WR
5995# define SHUT_WR 1
5996#endif
5997 if (shutdown(fptr->fd, SHUT_WR) < 0)
5998 rb_sys_fail_path(fptr->pathv);
5999 fptr->mode &= ~FMODE_WRITABLE;
6000 if (!(fptr->mode & FMODE_READABLE))
6001 return rb_io_close(write_io);
6002 return Qnil;
6003 }
6004
6005 if ((fptr->mode & (FMODE_DUPLEX|FMODE_READABLE)) == FMODE_READABLE) {
6006 rb_raise(rb_eIOError, "closing non-duplex IO for writing");
6007 }
6008
6009 if (io != write_io) {
6010 fptr = rb_io_get_fptr(rb_io_taint_check(io));
6011 fptr->tied_io_for_writing = 0;
6012 }
6013 rb_io_close(write_io);
6014 return Qnil;
6015}
6016
6017/*
6018 * call-seq:
6019 * sysseek(offset, whence = IO::SEEK_SET) -> integer
6020 *
6021 * Behaves like IO#seek, except that it:
6022 *
6023 * - Uses low-level system functions.
6024 * - Returns the new position.
6025 *
6026 */
6027
6028static VALUE
6029rb_io_sysseek(int argc, VALUE *argv, VALUE io)
6030{
6031 VALUE offset, ptrname;
6032 int whence = SEEK_SET;
6033 rb_io_t *fptr;
6034 rb_off_t pos;
6035
6036 if (rb_scan_args(argc, argv, "11", &offset, &ptrname) == 2) {
6037 whence = interpret_seek_whence(ptrname);
6038 }
6039 pos = NUM2OFFT(offset);
6040 GetOpenFile(io, fptr);
6041 if ((fptr->mode & FMODE_READABLE) &&
6042 (READ_DATA_BUFFERED(fptr) || READ_CHAR_PENDING(fptr))) {
6043 rb_raise(rb_eIOError, "sysseek for buffered IO");
6044 }
6045 if ((fptr->mode & FMODE_WRITABLE) && fptr->wbuf.len) {
6046 rb_warn("sysseek for buffered IO");
6047 }
6048 errno = 0;
6049 pos = lseek(fptr->fd, pos, whence);
6050 if (pos < 0 && errno) rb_sys_fail_path(fptr->pathv);
6051
6052 return OFFT2NUM(pos);
6053}
6054
6055/*
6056 * call-seq:
6057 * syswrite(object) -> integer
6058 *
6059 * Writes the given +object+ to self, which must be opened for writing (see Modes);
6060 * returns the number bytes written.
6061 * If +object+ is not a string is converted via method to_s:
6062 *
6063 * f = File.new('t.tmp', 'w')
6064 * f.syswrite('foo') # => 3
6065 * f.syswrite(30) # => 2
6066 * f.syswrite(:foo) # => 3
6067 * f.close
6068 *
6069 * This methods should not be used with other stream-writer methods.
6070 *
6071 */
6072
6073static VALUE
6074rb_io_syswrite(VALUE io, VALUE str)
6075{
6076 VALUE tmp;
6077 rb_io_t *fptr;
6078 long n, len;
6079 const char *ptr;
6080
6081 if (!RB_TYPE_P(str, T_STRING))
6082 str = rb_obj_as_string(str);
6083
6084 io = GetWriteIO(io);
6085 GetOpenFile(io, fptr);
6087
6088 if (fptr->wbuf.len) {
6089 rb_warn("syswrite for buffered IO");
6090 }
6091
6092 tmp = rb_str_tmp_frozen_acquire(str);
6093 RSTRING_GETMEM(tmp, ptr, len);
6094 n = rb_io_write_memory(fptr, ptr, len);
6095 if (n < 0) rb_sys_fail_path(fptr->pathv);
6096 rb_str_tmp_frozen_release(str, tmp);
6097
6098 return LONG2FIX(n);
6099}
6100
6101/*
6102 * call-seq:
6103 * sysread(maxlen) -> string
6104 * sysread(maxlen, out_string) -> string
6105 *
6106 * Behaves like IO#readpartial, except that it uses low-level system functions.
6107 *
6108 * This method should not be used with other stream-reader methods.
6109 *
6110 */
6111
6112static VALUE
6113rb_io_sysread(int argc, VALUE *argv, VALUE io)
6114{
6115 VALUE len, str;
6116 rb_io_t *fptr;
6117 long n, ilen;
6118 struct io_internal_read_struct iis;
6119 int shrinkable;
6120
6121 rb_scan_args(argc, argv, "11", &len, &str);
6122 ilen = NUM2LONG(len);
6123
6124 shrinkable = io_setstrbuf(&str, ilen);
6125 if (ilen == 0) return str;
6126
6127 GetOpenFile(io, fptr);
6129
6130 if (READ_DATA_BUFFERED(fptr)) {
6131 rb_raise(rb_eIOError, "sysread for buffered IO");
6132 }
6133
6134 rb_io_check_closed(fptr);
6135
6136 io_setstrbuf(&str, ilen);
6137 iis.th = rb_thread_current();
6138 iis.fptr = fptr;
6139 iis.nonblock = 0;
6140 iis.fd = fptr->fd;
6141 iis.buf = RSTRING_PTR(str);
6142 iis.capa = ilen;
6143 iis.timeout = NULL;
6144 n = io_read_memory_locktmp(str, &iis);
6145
6146 if (n < 0) {
6147 rb_sys_fail_path(fptr->pathv);
6148 }
6149
6150 io_set_read_length(str, n, shrinkable);
6151
6152 if (n == 0 && ilen > 0) {
6153 rb_eof_error();
6154 }
6155
6156 return str;
6157}
6158
6160 struct rb_io *io;
6161 int fd;
6162 void *buf;
6163 size_t count;
6164 rb_off_t offset;
6165};
6166
6167static VALUE
6168internal_pread_func(void *_arg)
6169{
6170 struct prdwr_internal_arg *arg = _arg;
6171
6172 return (VALUE)pread(arg->fd, arg->buf, arg->count, arg->offset);
6173}
6174
6175static VALUE
6176pread_internal_call(VALUE _arg)
6177{
6178 struct prdwr_internal_arg *arg = (struct prdwr_internal_arg *)_arg;
6179
6180 VALUE scheduler = rb_fiber_scheduler_current();
6181 if (scheduler != Qnil) {
6182 VALUE result = rb_fiber_scheduler_io_pread_memory(scheduler, arg->io->self, arg->offset, arg->buf, arg->count, 0);
6183
6184 if (!UNDEF_P(result)) {
6186 }
6187 }
6188
6189 return rb_io_blocking_region_wait(arg->io, internal_pread_func, arg, RUBY_IO_READABLE);
6190}
6191
6192/*
6193 * call-seq:
6194 * pread(maxlen, offset) -> string
6195 * pread(maxlen, offset, out_string) -> string
6196 *
6197 * Behaves like IO#readpartial, except that it:
6198 *
6199 * - Reads at the given +offset+ (in bytes).
6200 * - Disregards, and does not modify, the stream's position
6201 * (see {Position}[rdoc-ref:IO@Position]).
6202 * - Bypasses any user space buffering in the stream.
6203 *
6204 * Because this method does not disturb the stream's state
6205 * (its position, in particular), +pread+ allows multiple threads and processes
6206 * to use the same \IO object for reading at various offsets.
6207 *
6208 * f = File.open('t.txt')
6209 * f.read # => "First line\nSecond line\n\nFourth line\nFifth line\n"
6210 * f.pos # => 52
6211 * # Read 12 bytes at offset 0.
6212 * f.pread(12, 0) # => "First line\n"
6213 * # Read 9 bytes at offset 8.
6214 * f.pread(9, 8) # => "ne\nSecon"
6215 * f.close
6216 *
6217 * Not available on some platforms.
6218 *
6219 */
6220static VALUE
6221rb_io_pread(int argc, VALUE *argv, VALUE io)
6222{
6223 VALUE len, offset, str;
6224 rb_io_t *fptr;
6225 ssize_t n;
6226 struct prdwr_internal_arg arg;
6227 int shrinkable;
6228
6229 rb_scan_args(argc, argv, "21", &len, &offset, &str);
6230 arg.count = NUM2SIZET(len);
6231 arg.offset = NUM2OFFT(offset);
6232
6233 shrinkable = io_setstrbuf(&str, (long)arg.count);
6234 if (arg.count == 0) return str;
6235 arg.buf = RSTRING_PTR(str);
6236
6237 GetOpenFile(io, fptr);
6239
6240 arg.io = fptr;
6241 arg.fd = fptr->fd;
6242 rb_io_check_closed(fptr);
6243
6244 rb_str_locktmp(str);
6245 n = (ssize_t)rb_ensure(pread_internal_call, (VALUE)&arg, rb_str_unlocktmp, str);
6246
6247 if (n < 0) {
6248 rb_sys_fail_path(fptr->pathv);
6249 }
6250 io_set_read_length(str, n, shrinkable);
6251 if (n == 0 && arg.count > 0) {
6252 rb_eof_error();
6253 }
6254
6255 return str;
6256}
6257
6258static VALUE
6259internal_pwrite_func(void *_arg)
6260{
6261 struct prdwr_internal_arg *arg = _arg;
6262
6263 VALUE scheduler = rb_fiber_scheduler_current();
6264 if (scheduler != Qnil) {
6265 VALUE result = rb_fiber_scheduler_io_pwrite_memory(scheduler, arg->io->self, arg->offset, arg->buf, arg->count, 0);
6266
6267 if (!UNDEF_P(result)) {
6269 }
6270 }
6271
6272
6273 return (VALUE)pwrite(arg->fd, arg->buf, arg->count, arg->offset);
6274}
6275
6276/*
6277 * call-seq:
6278 * pwrite(object, offset) -> integer
6279 *
6280 * Behaves like IO#write, except that it:
6281 *
6282 * - Writes at the given +offset+ (in bytes).
6283 * - Disregards, and does not modify, the stream's position
6284 * (see {Position}[rdoc-ref:IO@Position]).
6285 * - Bypasses any user space buffering in the stream.
6286 *
6287 * Because this method does not disturb the stream's state
6288 * (its position, in particular), +pwrite+ allows multiple threads and processes
6289 * to use the same \IO object for writing at various offsets.
6290 *
6291 * f = File.open('t.tmp', 'w+')
6292 * # Write 6 bytes at offset 3.
6293 * f.pwrite('ABCDEF', 3) # => 6
6294 * f.rewind
6295 * f.read # => "\u0000\u0000\u0000ABCDEF"
6296 * f.close
6297 *
6298 * Not available on some platforms.
6299 *
6300 */
6301static VALUE
6302rb_io_pwrite(VALUE io, VALUE str, VALUE offset)
6303{
6304 rb_io_t *fptr;
6305 ssize_t n;
6306 struct prdwr_internal_arg arg;
6307 VALUE tmp;
6308
6309 if (!RB_TYPE_P(str, T_STRING))
6310 str = rb_obj_as_string(str);
6311
6312 arg.offset = NUM2OFFT(offset);
6313
6314 io = GetWriteIO(io);
6315 GetOpenFile(io, fptr);
6317
6318 arg.io = fptr;
6319 arg.fd = fptr->fd;
6320
6321 tmp = rb_str_tmp_frozen_acquire(str);
6322 arg.buf = RSTRING_PTR(tmp);
6323 arg.count = (size_t)RSTRING_LEN(tmp);
6324
6325 n = (ssize_t)rb_io_blocking_region_wait(fptr, internal_pwrite_func, &arg, RUBY_IO_WRITABLE);
6326 if (n < 0) rb_sys_fail_path(fptr->pathv);
6327 rb_str_tmp_frozen_release(str, tmp);
6328
6329 return SSIZET2NUM(n);
6330}
6331
6332VALUE
6334{
6335 rb_io_t *fptr;
6336
6337 GetOpenFile(io, fptr);
6338 if (fptr->readconv)
6340 if (fptr->writeconv)
6342 fptr->mode |= FMODE_BINMODE;
6343 fptr->mode &= ~FMODE_TEXTMODE;
6344 fptr->writeconv_pre_ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
6345#ifdef O_BINARY
6346 if (!fptr->readconv) {
6347 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6348 }
6349 else {
6350 setmode(fptr->fd, O_BINARY);
6351 }
6352#endif
6353 return io;
6354}
6355
6356static void
6357io_ascii8bit_binmode(rb_io_t *fptr)
6358{
6359 if (fptr->readconv) {
6360 rb_econv_close(fptr->readconv);
6361 fptr->readconv = NULL;
6362 }
6363 if (fptr->writeconv) {
6365 fptr->writeconv = NULL;
6366 }
6367 fptr->mode |= FMODE_BINMODE;
6368 fptr->mode &= ~FMODE_TEXTMODE;
6369 SET_BINARY_MODE_WITH_SEEK_CUR(fptr);
6370
6371 fptr->encs.enc = rb_ascii8bit_encoding();
6372 fptr->encs.enc2 = NULL;
6373 fptr->encs.ecflags = 0;
6374 fptr->encs.ecopts = Qnil;
6375 clear_codeconv(fptr);
6376}
6377
6378VALUE
6380{
6381 rb_io_t *fptr;
6382
6383 GetOpenFile(io, fptr);
6384 io_ascii8bit_binmode(fptr);
6385
6386 return io;
6387}
6388
6389/*
6390 * call-seq:
6391 * binmode -> self
6392 *
6393 * Sets the stream's data mode as binary
6394 * (see {Data Mode}[rdoc-ref:File@Data+Mode]).
6395 *
6396 * A stream's data mode may not be changed from binary to text.
6397 *
6398 */
6399
6400static VALUE
6401rb_io_binmode_m(VALUE io)
6402{
6403 VALUE write_io;
6404
6406
6407 write_io = GetWriteIO(io);
6408 if (write_io != io)
6409 rb_io_ascii8bit_binmode(write_io);
6410 return io;
6411}
6412
6413/*
6414 * call-seq:
6415 * binmode? -> true or false
6416 *
6417 * Returns +true+ if the stream is on binary mode, +false+ otherwise.
6418 * See {Data Mode}[rdoc-ref:File@Data+Mode].
6419 *
6420 */
6421static VALUE
6422rb_io_binmode_p(VALUE io)
6423{
6424 rb_io_t *fptr;
6425 GetOpenFile(io, fptr);
6426 return RBOOL(fptr->mode & FMODE_BINMODE);
6427}
6428
6429static const char*
6430rb_io_fmode_modestr(enum rb_io_mode fmode)
6431{
6432 if (fmode & FMODE_APPEND) {
6433 if ((fmode & FMODE_READWRITE) == FMODE_READWRITE) {
6434 return MODE_BTMODE("a+", "ab+", "at+");
6435 }
6436 return MODE_BTMODE("a", "ab", "at");
6437 }
6438 switch (fmode & FMODE_READWRITE) {
6439 default:
6440 rb_raise(rb_eArgError, "invalid access fmode 0x%x", fmode);
6441 case FMODE_READABLE:
6442 return MODE_BTMODE("r", "rb", "rt");
6443 case FMODE_WRITABLE:
6444 return MODE_BTXMODE("w", "wb", "wt", "wx", "wbx", "wtx");
6445 case FMODE_READWRITE:
6446 if (fmode & FMODE_CREATE) {
6447 return MODE_BTXMODE("w+", "wb+", "wt+", "w+x", "wb+x", "wt+x");
6448 }
6449 return MODE_BTMODE("r+", "rb+", "rt+");
6450 }
6451}
6452
6453static const char bom_prefix[] = "bom|";
6454static const char utf_prefix[] = "utf-";
6455enum {bom_prefix_len = (int)sizeof(bom_prefix) - 1};
6456enum {utf_prefix_len = (int)sizeof(utf_prefix) - 1};
6457
6458static int
6459io_encname_bom_p(const char *name, long len)
6460{
6461 return len > bom_prefix_len && STRNCASECMP(name, bom_prefix, bom_prefix_len) == 0;
6462}
6463
6464enum rb_io_mode
6465rb_io_modestr_fmode(const char *modestr)
6466{
6467 enum rb_io_mode fmode = 0;
6468 const char *m = modestr, *p = NULL;
6469
6470 switch (*m++) {
6471 case 'r':
6472 fmode |= FMODE_READABLE;
6473 break;
6474 case 'w':
6476 break;
6477 case 'a':
6479 break;
6480 default:
6481 goto error;
6482 }
6483
6484 while (*m) {
6485 switch (*m++) {
6486 case 'b':
6487 fmode |= FMODE_BINMODE;
6488 break;
6489 case 't':
6490 fmode |= FMODE_TEXTMODE;
6491 break;
6492 case '+':
6493 fmode |= FMODE_READWRITE;
6494 break;
6495 case 'x':
6496 if (modestr[0] != 'w')
6497 goto error;
6498 fmode |= FMODE_EXCL;
6499 break;
6500 default:
6501 goto error;
6502 case ':':
6503 p = strchr(m, ':');
6504 if (io_encname_bom_p(m, p ? (long)(p - m) : (long)strlen(m)))
6505 fmode |= FMODE_SETENC_BY_BOM;
6506 goto finished;
6507 }
6508 }
6509
6510 finished:
6511 if ((fmode & FMODE_BINMODE) && (fmode & FMODE_TEXTMODE))
6512 goto error;
6513
6514 return fmode;
6515
6516 error:
6517 rb_raise(rb_eArgError, "invalid access mode %s", modestr);
6519}
6520
6521int
6522rb_io_oflags_fmode(int oflags)
6523{
6524 enum rb_io_mode fmode = 0;
6525
6526 switch (oflags & O_ACCMODE) {
6527 case O_RDONLY:
6528 fmode = FMODE_READABLE;
6529 break;
6530 case O_WRONLY:
6531 fmode = FMODE_WRITABLE;
6532 break;
6533 case O_RDWR:
6534 fmode = FMODE_READWRITE;
6535 break;
6536 }
6537
6538 if (oflags & O_APPEND) {
6539 fmode |= FMODE_APPEND;
6540 }
6541 if (oflags & O_TRUNC) {
6542 fmode |= FMODE_TRUNC;
6543 }
6544 if (oflags & O_CREAT) {
6545 fmode |= FMODE_CREATE;
6546 }
6547 if (oflags & O_EXCL) {
6548 fmode |= FMODE_EXCL;
6549 }
6550#ifdef O_BINARY
6551 if (oflags & O_BINARY) {
6552 fmode |= FMODE_BINMODE;
6553 }
6554#endif
6555
6556 return fmode;
6557}
6558
6559static int
6560rb_io_fmode_oflags(enum rb_io_mode fmode)
6561{
6562 int oflags = 0;
6563
6564 switch (fmode & FMODE_READWRITE) {
6565 case FMODE_READABLE:
6566 oflags |= O_RDONLY;
6567 break;
6568 case FMODE_WRITABLE:
6569 oflags |= O_WRONLY;
6570 break;
6571 case FMODE_READWRITE:
6572 oflags |= O_RDWR;
6573 break;
6574 }
6575
6576 if (fmode & FMODE_APPEND) {
6577 oflags |= O_APPEND;
6578 }
6579 if (fmode & FMODE_TRUNC) {
6580 oflags |= O_TRUNC;
6581 }
6582 if (fmode & FMODE_CREATE) {
6583 oflags |= O_CREAT;
6584 }
6585 if (fmode & FMODE_EXCL) {
6586 oflags |= O_EXCL;
6587 }
6588#ifdef O_BINARY
6589 if (fmode & FMODE_BINMODE) {
6590 oflags |= O_BINARY;
6591 }
6592#endif
6593
6594 return oflags;
6595}
6596
6597int
6598rb_io_modestr_oflags(const char *modestr)
6599{
6600 return rb_io_fmode_oflags(rb_io_modestr_fmode(modestr));
6601}
6602
6603static const char*
6604rb_io_oflags_modestr(int oflags)
6605{
6606#ifdef O_BINARY
6607# define MODE_BINARY(a,b) ((oflags & O_BINARY) ? (b) : (a))
6608#else
6609# define MODE_BINARY(a,b) (a)
6610#endif
6611 int accmode;
6612 if (oflags & O_EXCL) {
6613 rb_raise(rb_eArgError, "exclusive access mode is not supported");
6614 }
6615 accmode = oflags & (O_RDONLY|O_WRONLY|O_RDWR);
6616 if (oflags & O_APPEND) {
6617 if (accmode == O_WRONLY) {
6618 return MODE_BINARY("a", "ab");
6619 }
6620 if (accmode == O_RDWR) {
6621 return MODE_BINARY("a+", "ab+");
6622 }
6623 }
6624 switch (accmode) {
6625 default:
6626 rb_raise(rb_eArgError, "invalid access oflags 0x%x", oflags);
6627 case O_RDONLY:
6628 return MODE_BINARY("r", "rb");
6629 case O_WRONLY:
6630 return MODE_BINARY("w", "wb");
6631 case O_RDWR:
6632 if (oflags & O_TRUNC) {
6633 return MODE_BINARY("w+", "wb+");
6634 }
6635 return MODE_BINARY("r+", "rb+");
6636 }
6637}
6638
6639/*
6640 * Convert external/internal encodings to enc/enc2
6641 * NULL => use default encoding
6642 * Qnil => no encoding specified (internal only)
6643 */
6644static void
6645rb_io_ext_int_to_encs(rb_encoding *ext, rb_encoding *intern, rb_encoding **enc, rb_encoding **enc2, enum rb_io_mode fmode)
6646{
6647 int default_ext = 0;
6648
6649 if (ext == NULL) {
6650 ext = rb_default_external_encoding();
6651 default_ext = 1;
6652 }
6653 if (rb_is_ascii8bit_enc(ext)) {
6654 /* If external is ASCII-8BIT, no transcoding */
6655 intern = NULL;
6656 }
6657 else if (intern == NULL) {
6658 intern = rb_default_internal_encoding();
6659 }
6660 if (intern == NULL || intern == (rb_encoding *)Qnil ||
6661 (!(fmode & FMODE_SETENC_BY_BOM) && (intern == ext))) {
6662 /* No internal encoding => use external + no transcoding */
6663 *enc = (default_ext && intern != ext) ? NULL : ext;
6664 *enc2 = NULL;
6665 }
6666 else {
6667 *enc = intern;
6668 *enc2 = ext;
6669 }
6670}
6671
6672static void
6673unsupported_encoding(const char *name, rb_encoding *enc)
6674{
6675 rb_enc_warn(enc, "Unsupported encoding %s ignored", name);
6676}
6677
6678static void
6679parse_mode_enc(const char *estr, rb_encoding *estr_enc,
6680 rb_encoding **enc_p, rb_encoding **enc2_p, enum rb_io_mode *fmode_p)
6681{
6682 const char *p;
6683 char encname[ENCODING_MAXNAMELEN+1];
6684 int idx, idx2;
6685 enum rb_io_mode fmode = fmode_p ? *fmode_p : 0;
6686 rb_encoding *ext_enc, *int_enc;
6687 long len;
6688
6689 /* parse estr as "enc" or "enc2:enc" or "enc:-" */
6690
6691 p = strrchr(estr, ':');
6692 len = p ? (p++ - estr) : (long)strlen(estr);
6693 if ((fmode & FMODE_SETENC_BY_BOM) || io_encname_bom_p(estr, len)) {
6694 estr += bom_prefix_len;
6695 len -= bom_prefix_len;
6696 if (!STRNCASECMP(estr, utf_prefix, utf_prefix_len)) {
6697 fmode |= FMODE_SETENC_BY_BOM;
6698 }
6699 else {
6700 rb_enc_warn(estr_enc, "BOM with non-UTF encoding %s is nonsense", estr);
6701 fmode &= ~FMODE_SETENC_BY_BOM;
6702 }
6703 }
6704 if (len == 0 || len > ENCODING_MAXNAMELEN) {
6705 idx = -1;
6706 }
6707 else {
6708 if (p) {
6709 memcpy(encname, estr, len);
6710 encname[len] = '\0';
6711 estr = encname;
6712 }
6713 idx = rb_enc_find_index(estr);
6714 }
6715 if (fmode_p) *fmode_p = fmode;
6716
6717 if (idx >= 0)
6718 ext_enc = rb_enc_from_index(idx);
6719 else {
6720 if (idx != -2)
6721 unsupported_encoding(estr, estr_enc);
6722 ext_enc = NULL;
6723 }
6724
6725 int_enc = NULL;
6726 if (p) {
6727 if (*p == '-' && *(p+1) == '\0') {
6728 /* Special case - "-" => no transcoding */
6729 int_enc = (rb_encoding *)Qnil;
6730 }
6731 else {
6732 idx2 = rb_enc_find_index(p);
6733 if (idx2 < 0)
6734 unsupported_encoding(p, estr_enc);
6735 else if (!(fmode & FMODE_SETENC_BY_BOM) && (idx2 == idx)) {
6736 int_enc = (rb_encoding *)Qnil;
6737 }
6738 else
6739 int_enc = rb_enc_from_index(idx2);
6740 }
6741 }
6742
6743 rb_io_ext_int_to_encs(ext_enc, int_enc, enc_p, enc2_p, fmode);
6744}
6745
6746int
6747rb_io_extract_encoding_option(VALUE opt, rb_encoding **enc_p, rb_encoding **enc2_p, enum rb_io_mode *fmode_p)
6748{
6749 VALUE encoding=Qnil, extenc=Qundef, intenc=Qundef, tmp;
6750 int extracted = 0;
6751 rb_encoding *extencoding = NULL;
6752 rb_encoding *intencoding = NULL;
6753
6754 if (!NIL_P(opt)) {
6755 VALUE v;
6756 v = rb_hash_lookup2(opt, sym_encoding, Qnil);
6757 if (v != Qnil) encoding = v;
6758 v = rb_hash_lookup2(opt, sym_extenc, Qundef);
6759 if (v != Qnil) extenc = v;
6760 v = rb_hash_lookup2(opt, sym_intenc, Qundef);
6761 if (!UNDEF_P(v)) intenc = v;
6762 }
6763 if ((!UNDEF_P(extenc) || !UNDEF_P(intenc)) && !NIL_P(encoding)) {
6764 if (!NIL_P(ruby_verbose)) {
6765 int idx = rb_to_encoding_index(encoding);
6766 if (idx >= 0) encoding = rb_enc_from_encoding(rb_enc_from_index(idx));
6767 rb_warn("Ignoring encoding parameter '%"PRIsVALUE"': %s_encoding is used",
6768 encoding, UNDEF_P(extenc) ? "internal" : "external");
6769 }
6770 encoding = Qnil;
6771 }
6772 if (!UNDEF_P(extenc) && !NIL_P(extenc)) {
6773 extencoding = rb_to_encoding(extenc);
6774 }
6775 if (!UNDEF_P(intenc)) {
6776 if (NIL_P(intenc)) {
6777 /* internal_encoding: nil => no transcoding */
6778 intencoding = (rb_encoding *)Qnil;
6779 }
6780 else if (!NIL_P(tmp = rb_check_string_type(intenc))) {
6781 char *p = StringValueCStr(tmp);
6782
6783 if (*p == '-' && *(p+1) == '\0') {
6784 /* Special case - "-" => no transcoding */
6785 intencoding = (rb_encoding *)Qnil;
6786 }
6787 else {
6788 intencoding = rb_to_encoding(intenc);
6789 }
6790 }
6791 else {
6792 intencoding = rb_to_encoding(intenc);
6793 }
6794 if (extencoding == intencoding) {
6795 intencoding = (rb_encoding *)Qnil;
6796 }
6797 }
6798 if (!NIL_P(encoding)) {
6799 extracted = 1;
6800 if (!NIL_P(tmp = rb_check_string_type(encoding))) {
6801 parse_mode_enc(StringValueCStr(tmp), rb_enc_get(tmp),
6802 enc_p, enc2_p, fmode_p);
6803 }
6804 else {
6805 rb_io_ext_int_to_encs(rb_to_encoding(encoding), NULL, enc_p, enc2_p, 0);
6806 }
6807 }
6808 else if (!UNDEF_P(extenc) || !UNDEF_P(intenc)) {
6809 extracted = 1;
6810 rb_io_ext_int_to_encs(extencoding, intencoding, enc_p, enc2_p, 0);
6811 }
6812 return extracted;
6813}
6814
6815static void
6816validate_enc_binmode(enum rb_io_mode *fmode_p, int ecflags, rb_encoding *enc, rb_encoding *enc2)
6817{
6818 enum rb_io_mode fmode = *fmode_p;
6819
6820 if ((fmode & FMODE_READABLE) &&
6821 !enc2 &&
6822 !(fmode & FMODE_BINMODE) &&
6823 !rb_enc_asciicompat(enc ? enc : rb_default_external_encoding()))
6824 rb_raise(rb_eArgError, "ASCII incompatible encoding needs binmode");
6825
6826 if ((fmode & FMODE_BINMODE) && (ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
6827 rb_raise(rb_eArgError, "newline decorator with binary mode");
6828 }
6829 if (!(fmode & FMODE_BINMODE) &&
6830 (DEFAULT_TEXTMODE || (ecflags & ECONV_NEWLINE_DECORATOR_MASK))) {
6831 fmode |= FMODE_TEXTMODE;
6832 *fmode_p = fmode;
6833 }
6834#if !DEFAULT_TEXTMODE
6835 else if (!(ecflags & ECONV_NEWLINE_DECORATOR_MASK)) {
6836 fmode &= ~FMODE_TEXTMODE;
6837 *fmode_p = fmode;
6838 }
6839#endif
6840}
6841
6842static void
6843extract_binmode(VALUE opthash, enum rb_io_mode *fmode)
6844{
6845 if (!NIL_P(opthash)) {
6846 VALUE v;
6847 v = rb_hash_aref(opthash, sym_textmode);
6848 if (!NIL_P(v)) {
6849 if (*fmode & FMODE_TEXTMODE)
6850 rb_raise(rb_eArgError, "textmode specified twice");
6851 if (*fmode & FMODE_BINMODE)
6852 rb_raise(rb_eArgError, "both textmode and binmode specified");
6853 if (RTEST(v))
6854 *fmode |= FMODE_TEXTMODE;
6855 }
6856 v = rb_hash_aref(opthash, sym_binmode);
6857 if (!NIL_P(v)) {
6858 if (*fmode & FMODE_BINMODE)
6859 rb_raise(rb_eArgError, "binmode specified twice");
6860 if (*fmode & FMODE_TEXTMODE)
6861 rb_raise(rb_eArgError, "both textmode and binmode specified");
6862 if (RTEST(v))
6863 *fmode |= FMODE_BINMODE;
6864 }
6865
6866 if ((*fmode & FMODE_BINMODE) && (*fmode & FMODE_TEXTMODE))
6867 rb_raise(rb_eArgError, "both textmode and binmode specified");
6868 }
6869}
6870
6871void
6872rb_io_extract_modeenc(VALUE *vmode_p, VALUE *vperm_p, VALUE opthash,
6873 int *oflags_p, enum rb_io_mode *fmode_p, struct rb_io_encoding *convconfig_p)
6874{
6875 VALUE vmode;
6876 int oflags;
6877 enum rb_io_mode fmode;
6878 rb_encoding *enc, *enc2;
6879 int ecflags;
6880 VALUE ecopts;
6881 int has_enc = 0, has_vmode = 0;
6882 VALUE intmode;
6883
6884 vmode = *vmode_p;
6885
6886 /* Set to defaults */
6887 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
6888
6889 vmode_handle:
6890 if (NIL_P(vmode)) {
6891 fmode = FMODE_READABLE;
6892 oflags = O_RDONLY;
6893 }
6894 else if (!NIL_P(intmode = rb_check_to_integer(vmode, "to_int"))) {
6895 vmode = intmode;
6896 oflags = NUM2INT(intmode);
6897 fmode = rb_io_oflags_fmode(oflags);
6898 }
6899 else {
6900 const char *p;
6901
6902 StringValue(vmode);
6903 p = StringValueCStr(vmode);
6904 fmode = rb_io_modestr_fmode(p);
6905 oflags = rb_io_fmode_oflags(fmode);
6906 p = strchr(p, ':');
6907 if (p) {
6908 has_enc = 1;
6909 parse_mode_enc(p+1, rb_enc_get(vmode), &enc, &enc2, &fmode);
6910 }
6911 else {
6912 rb_encoding *e;
6913
6914 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
6915 rb_io_ext_int_to_encs(e, NULL, &enc, &enc2, fmode);
6916 }
6917 }
6918
6919 if (NIL_P(opthash)) {
6920 ecflags = (fmode & FMODE_READABLE) ?
6923#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
6924 ecflags |= (fmode & FMODE_WRITABLE) ?
6925 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
6926 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
6927#endif
6928 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
6929 ecopts = Qnil;
6930 if (fmode & FMODE_BINMODE) {
6931#ifdef O_BINARY
6932 oflags |= O_BINARY;
6933#endif
6934 if (!has_enc)
6935 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
6936 }
6937#if DEFAULT_TEXTMODE
6938 else if (NIL_P(vmode)) {
6939 fmode |= DEFAULT_TEXTMODE;
6940 }
6941#endif
6942 }
6943 else {
6944 VALUE v;
6945 if (!has_vmode) {
6946 v = rb_hash_aref(opthash, sym_mode);
6947 if (!NIL_P(v)) {
6948 if (!NIL_P(vmode)) {
6949 rb_raise(rb_eArgError, "mode specified twice");
6950 }
6951 has_vmode = 1;
6952 vmode = v;
6953 goto vmode_handle;
6954 }
6955 }
6956 v = rb_hash_aref(opthash, sym_flags);
6957 if (!NIL_P(v)) {
6958 v = rb_to_int(v);
6959 oflags |= NUM2INT(v);
6960 vmode = INT2NUM(oflags);
6961 fmode = rb_io_oflags_fmode(oflags);
6962 }
6963 extract_binmode(opthash, &fmode);
6964 if (fmode & FMODE_BINMODE) {
6965#ifdef O_BINARY
6966 oflags |= O_BINARY;
6967#endif
6968 if (!has_enc)
6969 rb_io_ext_int_to_encs(rb_ascii8bit_encoding(), NULL, &enc, &enc2, fmode);
6970 }
6971#if DEFAULT_TEXTMODE
6972 else if (NIL_P(vmode)) {
6973 fmode |= DEFAULT_TEXTMODE;
6974 }
6975#endif
6976 v = rb_hash_aref(opthash, sym_perm);
6977 if (!NIL_P(v)) {
6978 if (vperm_p) {
6979 if (!NIL_P(*vperm_p)) {
6980 rb_raise(rb_eArgError, "perm specified twice");
6981 }
6982 *vperm_p = v;
6983 }
6984 else {
6985 /* perm no use, just ignore */
6986 }
6987 }
6988 ecflags = (fmode & FMODE_READABLE) ?
6991#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
6992 ecflags |= (fmode & FMODE_WRITABLE) ?
6993 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
6994 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
6995#endif
6996
6997 if (rb_io_extract_encoding_option(opthash, &enc, &enc2, &fmode)) {
6998 if (has_enc) {
6999 rb_raise(rb_eArgError, "encoding specified twice");
7000 }
7001 }
7002 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
7003 ecflags = rb_econv_prepare_options(opthash, &ecopts, ecflags);
7004 }
7005
7006 validate_enc_binmode(&fmode, ecflags, enc, enc2);
7007
7008 *vmode_p = vmode;
7009
7010 *oflags_p = oflags;
7011 *fmode_p = fmode;
7012 convconfig_p->enc = enc;
7013 convconfig_p->enc2 = enc2;
7014 convconfig_p->ecflags = ecflags;
7015 convconfig_p->ecopts = ecopts;
7016}
7017
7019 VALUE fname;
7020 int oflags;
7021 mode_t perm;
7022};
7023
7024static void *
7025sysopen_func(void *ptr)
7026{
7027 const struct sysopen_struct *data = ptr;
7028 const char *fname = RSTRING_PTR(data->fname);
7029 return (void *)(VALUE)rb_cloexec_open(fname, data->oflags, data->perm);
7030}
7031
7032static inline int
7033rb_sysopen_internal(struct sysopen_struct *data)
7034{
7035 int fd;
7036 do {
7037 fd = IO_WITHOUT_GVL_INT(sysopen_func, data);
7038 } while (fd < 0 && errno == EINTR);
7039 if (0 <= fd)
7040 rb_update_max_fd(fd);
7041 return fd;
7042}
7043
7044static int
7045rb_sysopen(VALUE fname, int oflags, mode_t perm)
7046{
7047 int fd = -1;
7048 struct sysopen_struct data;
7049
7050 data.fname = rb_str_encode_ospath(fname);
7051 StringValueCStr(data.fname);
7052 data.oflags = oflags;
7053 data.perm = perm;
7054
7055 TRY_WITH_GC((fd = rb_sysopen_internal(&data)) >= 0) {
7056 rb_syserr_fail_path(first_errno, fname);
7057 }
7058 return fd;
7059}
7060
7061static inline FILE *
7062fdopen_internal(int fd, const char *modestr)
7063{
7064 FILE *file;
7065
7066#if defined(__sun)
7067 errno = 0;
7068#endif
7069 file = fdopen(fd, modestr);
7070 if (!file) {
7071#ifdef _WIN32
7072 if (errno == 0) errno = EINVAL;
7073#elif defined(__sun)
7074 if (errno == 0) errno = EMFILE;
7075#endif
7076 }
7077 return file;
7078}
7079
7080FILE *
7081rb_fdopen(int fd, const char *modestr)
7082{
7083 FILE *file = 0;
7084
7085 TRY_WITH_GC((file = fdopen_internal(fd, modestr)) != 0) {
7086 rb_syserr_fail(first_errno, 0);
7087 }
7088
7089 /* xxx: should be _IONBF? A buffer in FILE may have trouble. */
7090#ifdef USE_SETVBUF
7091 if (setvbuf(file, NULL, _IOFBF, 0) != 0)
7092 rb_warn("setvbuf() can't be honoured (fd=%d)", fd);
7093#endif
7094 return file;
7095}
7096
7097static int
7098io_check_tty(rb_io_t *fptr)
7099{
7100 int t = isatty(fptr->fd);
7101 if (t)
7102 fptr->mode |= FMODE_TTY|FMODE_DUPLEX;
7103 return t;
7104}
7105
7106static VALUE rb_io_internal_encoding(VALUE);
7107static void io_encoding_set(rb_io_t *, VALUE, VALUE, VALUE);
7108
7109static int
7110io_strip_bom(VALUE io)
7111{
7112 VALUE b1, b2, b3, b4;
7113 rb_io_t *fptr;
7114
7115 GetOpenFile(io, fptr);
7116 if (!(fptr->mode & FMODE_READABLE)) return 0;
7117 if (NIL_P(b1 = rb_io_getbyte(io))) return 0;
7118 switch (b1) {
7119 case INT2FIX(0xEF):
7120 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7121 if (b2 == INT2FIX(0xBB) && !NIL_P(b3 = rb_io_getbyte(io))) {
7122 if (b3 == INT2FIX(0xBF)) {
7123 return rb_utf8_encindex();
7124 }
7125 rb_io_ungetbyte(io, b3);
7126 }
7127 rb_io_ungetbyte(io, b2);
7128 break;
7129
7130 case INT2FIX(0xFE):
7131 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7132 if (b2 == INT2FIX(0xFF)) {
7133 return ENCINDEX_UTF_16BE;
7134 }
7135 rb_io_ungetbyte(io, b2);
7136 break;
7137
7138 case INT2FIX(0xFF):
7139 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7140 if (b2 == INT2FIX(0xFE)) {
7141 b3 = rb_io_getbyte(io);
7142 if (b3 == INT2FIX(0) && !NIL_P(b4 = rb_io_getbyte(io))) {
7143 if (b4 == INT2FIX(0)) {
7144 return ENCINDEX_UTF_32LE;
7145 }
7146 rb_io_ungetbyte(io, b4);
7147 }
7148 rb_io_ungetbyte(io, b3);
7149 return ENCINDEX_UTF_16LE;
7150 }
7151 rb_io_ungetbyte(io, b2);
7152 break;
7153
7154 case INT2FIX(0):
7155 if (NIL_P(b2 = rb_io_getbyte(io))) break;
7156 if (b2 == INT2FIX(0) && !NIL_P(b3 = rb_io_getbyte(io))) {
7157 if (b3 == INT2FIX(0xFE) && !NIL_P(b4 = rb_io_getbyte(io))) {
7158 if (b4 == INT2FIX(0xFF)) {
7159 return ENCINDEX_UTF_32BE;
7160 }
7161 rb_io_ungetbyte(io, b4);
7162 }
7163 rb_io_ungetbyte(io, b3);
7164 }
7165 rb_io_ungetbyte(io, b2);
7166 break;
7167 }
7168 rb_io_ungetbyte(io, b1);
7169 return 0;
7170}
7171
7172static rb_encoding *
7173io_set_encoding_by_bom(VALUE io)
7174{
7175 int idx = io_strip_bom(io);
7176 rb_io_t *fptr;
7177 rb_encoding *extenc = NULL;
7178
7179 GetOpenFile(io, fptr);
7180 if (idx) {
7181 extenc = rb_enc_from_index(idx);
7182 io_encoding_set(fptr, rb_enc_from_encoding(extenc),
7183 rb_io_internal_encoding(io), Qnil);
7184 }
7185 else {
7186 fptr->encs.enc2 = NULL;
7187 }
7188 return extenc;
7189}
7190
7191static VALUE
7192rb_file_open_generic(VALUE io, VALUE filename, int oflags, enum rb_io_mode fmode,
7193 const struct rb_io_encoding *convconfig, mode_t perm)
7194{
7195 VALUE pathv;
7196 rb_io_t *fptr;
7197 struct rb_io_encoding cc;
7198 if (!convconfig) {
7199 /* Set to default encodings */
7200 rb_io_ext_int_to_encs(NULL, NULL, &cc.enc, &cc.enc2, fmode);
7201 cc.ecflags = 0;
7202 cc.ecopts = Qnil;
7203 convconfig = &cc;
7204 }
7205 validate_enc_binmode(&fmode, convconfig->ecflags,
7206 convconfig->enc, convconfig->enc2);
7207
7208 MakeOpenFile(io, fptr);
7209 fptr->mode = fmode;
7210 fptr->encs = *convconfig;
7211 pathv = rb_str_new_frozen(filename);
7212#ifdef O_TMPFILE
7213 if (!(oflags & O_TMPFILE)) {
7214 fptr->pathv = pathv;
7215 }
7216#else
7217 fptr->pathv = pathv;
7218#endif
7219 fptr->fd = rb_sysopen(pathv, oflags, perm);
7220 io_check_tty(fptr);
7221 if (fmode & FMODE_SETENC_BY_BOM) io_set_encoding_by_bom(io);
7222
7223 return io;
7224}
7225
7226static VALUE
7227rb_file_open_internal(VALUE io, VALUE filename, const char *modestr)
7228{
7229 enum rb_io_mode fmode = rb_io_modestr_fmode(modestr);
7230 const char *p = strchr(modestr, ':');
7231 struct rb_io_encoding convconfig;
7232
7233 if (p) {
7234 parse_mode_enc(p+1, rb_usascii_encoding(),
7235 &convconfig.enc, &convconfig.enc2, &fmode);
7236 }
7237 else {
7238 rb_encoding *e;
7239 /* Set to default encodings */
7240
7241 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
7242 rb_io_ext_int_to_encs(e, NULL, &convconfig.enc, &convconfig.enc2, fmode);
7243 }
7244
7245 convconfig.ecflags = (fmode & FMODE_READABLE) ?
7248#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7249 convconfig.ecflags |= (fmode & FMODE_WRITABLE) ?
7250 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
7251 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
7252#endif
7253 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.enc2, convconfig.ecflags);
7254 convconfig.ecopts = Qnil;
7255
7256 return rb_file_open_generic(io, filename,
7257 rb_io_fmode_oflags(fmode),
7258 fmode,
7259 &convconfig,
7260 0666);
7261}
7262
7263VALUE
7264rb_file_open_str(VALUE fname, const char *modestr)
7265{
7266 FilePathValue(fname);
7267 return rb_file_open_internal(io_alloc(rb_cFile), fname, modestr);
7268}
7269
7270VALUE
7271rb_file_open(const char *fname, const char *modestr)
7272{
7273 return rb_file_open_internal(io_alloc(rb_cFile), rb_str_new_cstr(fname), modestr);
7274}
7275
7276#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7277static struct pipe_list {
7278 rb_io_t *fptr;
7279 struct pipe_list *next;
7280} *pipe_list;
7281
7282static void
7283pipe_add_fptr(rb_io_t *fptr)
7284{
7285 struct pipe_list *list;
7286
7287 list = ALLOC(struct pipe_list);
7288 list->fptr = fptr;
7289 list->next = pipe_list;
7290 pipe_list = list;
7291}
7292
7293static void
7294pipe_del_fptr(rb_io_t *fptr)
7295{
7296 struct pipe_list **prev = &pipe_list;
7297 struct pipe_list *tmp;
7298
7299 while ((tmp = *prev) != 0) {
7300 if (tmp->fptr == fptr) {
7301 *prev = tmp->next;
7302 free(tmp);
7303 return;
7304 }
7305 prev = &tmp->next;
7306 }
7307}
7308
7309#if defined (_WIN32) || defined(__CYGWIN__)
7310static void
7311pipe_atexit(void)
7312{
7313 struct pipe_list *list = pipe_list;
7314 struct pipe_list *tmp;
7315
7316 while (list) {
7317 tmp = list->next;
7318 rb_io_fptr_finalize(list->fptr);
7319 list = tmp;
7320 }
7321}
7322#endif
7323
7324static void
7325pipe_finalize(rb_io_t *fptr, int noraise)
7326{
7327#if !defined(HAVE_WORKING_FORK) && !defined(_WIN32)
7328 int status = 0;
7329 if (fptr->stdio_file) {
7330 status = pclose(fptr->stdio_file);
7331 }
7332 fptr->fd = -1;
7333 fptr->stdio_file = 0;
7334 rb_last_status_set(status, fptr->pid);
7335#else
7336 fptr_finalize(fptr, noraise);
7337#endif
7338 pipe_del_fptr(fptr);
7339}
7340#endif
7341
7342static void
7343fptr_copy_finalizer(rb_io_t *fptr, const rb_io_t *orig)
7344{
7345#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7346 void (*const old_finalize)(struct rb_io*,int) = fptr->finalize;
7347
7348 if (old_finalize == orig->finalize) return;
7349#endif
7350
7351 fptr->finalize = orig->finalize;
7352
7353#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7354 if (old_finalize != pipe_finalize) {
7355 struct pipe_list *list;
7356 for (list = pipe_list; list; list = list->next) {
7357 if (list->fptr == fptr) break;
7358 }
7359 if (!list) pipe_add_fptr(fptr);
7360 }
7361 else {
7362 pipe_del_fptr(fptr);
7363 }
7364#endif
7365}
7366
7367void
7369{
7371 fptr->mode |= FMODE_SYNC;
7372}
7373
7374void
7375rb_io_unbuffered(rb_io_t *fptr)
7376{
7377 rb_io_synchronized(fptr);
7378}
7379
7380int
7381rb_pipe(int *pipes)
7382{
7383 int ret;
7384 TRY_WITH_GC((ret = rb_cloexec_pipe(pipes)) >= 0);
7385 if (ret == 0) {
7386 rb_update_max_fd(pipes[0]);
7387 rb_update_max_fd(pipes[1]);
7388 }
7389 return ret;
7390}
7391
7392#ifdef _WIN32
7393#define HAVE_SPAWNV 1
7394#define spawnv(mode, cmd, args) rb_w32_uaspawn((mode), (cmd), (args))
7395#define spawn(mode, cmd) rb_w32_uspawn((mode), (cmd), 0)
7396#endif
7397
7398#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7399struct popen_arg {
7400 VALUE execarg_obj;
7401 struct rb_execarg *eargp;
7402 int modef;
7403 int pair[2];
7404 int write_pair[2];
7405};
7406#endif
7407
7408#ifdef HAVE_WORKING_FORK
7409# ifndef __EMSCRIPTEN__
7410static void
7411popen_redirect(struct popen_arg *p)
7412{
7413 if ((p->modef & FMODE_READABLE) && (p->modef & FMODE_WRITABLE)) {
7414 close(p->write_pair[1]);
7415 if (p->write_pair[0] != 0) {
7416 dup2(p->write_pair[0], 0);
7417 close(p->write_pair[0]);
7418 }
7419 close(p->pair[0]);
7420 if (p->pair[1] != 1) {
7421 dup2(p->pair[1], 1);
7422 close(p->pair[1]);
7423 }
7424 }
7425 else if (p->modef & FMODE_READABLE) {
7426 close(p->pair[0]);
7427 if (p->pair[1] != 1) {
7428 dup2(p->pair[1], 1);
7429 close(p->pair[1]);
7430 }
7431 }
7432 else {
7433 close(p->pair[1]);
7434 if (p->pair[0] != 0) {
7435 dup2(p->pair[0], 0);
7436 close(p->pair[0]);
7437 }
7438 }
7439}
7440# endif
7441
7442#if defined(__linux__)
7443/* Linux /proc/self/status contains a line: "FDSize:\t<nnn>\n"
7444 * Since /proc may not be available, linux_get_maxfd is just a hint.
7445 * This function, linux_get_maxfd, must be async-signal-safe.
7446 * I.e. opendir() is not usable.
7447 *
7448 * Note that memchr() and memcmp is *not* async-signal-safe in POSIX.
7449 * However they are easy to re-implement in async-signal-safe manner.
7450 * (Also note that there is missing/memcmp.c.)
7451 */
7452static int
7453linux_get_maxfd(void)
7454{
7455 int fd;
7456 char buf[4096], *p, *np, *e;
7457 ssize_t ss;
7458 fd = rb_cloexec_open("/proc/self/status", O_RDONLY|O_NOCTTY, 0);
7459 if (fd < 0) return fd;
7460 ss = read(fd, buf, sizeof(buf));
7461 if (ss < 0) goto err;
7462 p = buf;
7463 e = buf + ss;
7464 while ((int)sizeof("FDSize:\t0\n")-1 <= e-p &&
7465 (np = memchr(p, '\n', e-p)) != NULL) {
7466 if (memcmp(p, "FDSize:", sizeof("FDSize:")-1) == 0) {
7467 int fdsize;
7468 p += sizeof("FDSize:")-1;
7469 *np = '\0';
7470 fdsize = (int)ruby_strtoul(p, (char **)NULL, 10);
7471 close(fd);
7472 return fdsize;
7473 }
7474 p = np+1;
7475 }
7476 /* fall through */
7477
7478 err:
7479 close(fd);
7480 return (int)ss;
7481}
7482#endif
7483
7484/* This function should be async-signal-safe. */
7485void
7486rb_close_before_exec(int lowfd, int maxhint, VALUE noclose_fds)
7487{
7488#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
7489 int fd, ret;
7490 int max = (int)max_file_descriptor;
7491# ifdef F_MAXFD
7492 /* F_MAXFD is available since NetBSD 2.0. */
7493 ret = fcntl(0, F_MAXFD); /* async-signal-safe */
7494 if (ret != -1)
7495 maxhint = max = ret;
7496# elif defined(__linux__)
7497 ret = linux_get_maxfd();
7498 if (maxhint < ret)
7499 maxhint = ret;
7500 /* maxhint = max = ret; if (ret == -1) abort(); // test */
7501# endif
7502 if (max < maxhint)
7503 max = maxhint;
7504 for (fd = lowfd; fd <= max; fd++) {
7505 if (!NIL_P(noclose_fds) &&
7506 RTEST(rb_hash_lookup(noclose_fds, INT2FIX(fd)))) /* async-signal-safe */
7507 continue;
7508 ret = fcntl(fd, F_GETFD); /* async-signal-safe */
7509 if (ret != -1 && !(ret & FD_CLOEXEC)) {
7510 fcntl(fd, F_SETFD, ret|FD_CLOEXEC); /* async-signal-safe */
7511 }
7512# define CONTIGUOUS_CLOSED_FDS 20
7513 if (ret != -1) {
7514 if (max < fd + CONTIGUOUS_CLOSED_FDS)
7515 max = fd + CONTIGUOUS_CLOSED_FDS;
7516 }
7517 }
7518#endif
7519}
7520
7521# ifndef __EMSCRIPTEN__
7522static int
7523popen_exec(void *pp, char *errmsg, size_t errmsg_len)
7524{
7525 struct popen_arg *p = (struct popen_arg*)pp;
7526
7527 return rb_exec_async_signal_safe(p->eargp, errmsg, errmsg_len);
7528}
7529# endif
7530#endif
7531
7532#if (defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)) && !defined __EMSCRIPTEN__
7533static VALUE
7534rb_execarg_fixup_v(VALUE execarg_obj)
7535{
7536 rb_execarg_parent_start(execarg_obj);
7537 return Qnil;
7538}
7539#else
7540char *rb_execarg_commandline(const struct rb_execarg *eargp, VALUE *prog);
7541#endif
7542
7543#ifndef __EMSCRIPTEN__
7544static VALUE
7545pipe_open(VALUE execarg_obj, const char *modestr, enum rb_io_mode fmode,
7546 const struct rb_io_encoding *convconfig)
7547{
7548 struct rb_execarg *eargp = NIL_P(execarg_obj) ? NULL : rb_execarg_get(execarg_obj);
7549 VALUE prog = eargp ? (eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name) : Qfalse ;
7550 rb_pid_t pid = 0;
7551 rb_io_t *fptr;
7552 VALUE port;
7553 rb_io_t *write_fptr;
7554 VALUE write_port;
7555#if defined(HAVE_WORKING_FORK)
7556 int status;
7557 char errmsg[80] = { '\0' };
7558#endif
7559#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7560 int state;
7561 struct popen_arg arg;
7562#endif
7563 int e = 0;
7564#if defined(HAVE_SPAWNV)
7565# if defined(HAVE_SPAWNVE)
7566# define DO_SPAWN(cmd, args, envp) ((args) ? \
7567 spawnve(P_NOWAIT, (cmd), (args), (envp)) : \
7568 spawne(P_NOWAIT, (cmd), (envp)))
7569# else
7570# define DO_SPAWN(cmd, args, envp) ((args) ? \
7571 spawnv(P_NOWAIT, (cmd), (args)) : \
7572 spawn(P_NOWAIT, (cmd)))
7573# endif
7574# if !defined(HAVE_WORKING_FORK)
7575 char **args = NULL;
7576# if defined(HAVE_SPAWNVE)
7577 char **envp = NULL;
7578# endif
7579# endif
7580#endif
7581#if !defined(HAVE_WORKING_FORK)
7582 struct rb_execarg sarg, *sargp = &sarg;
7583#endif
7584 FILE *fp = 0;
7585 int fd = -1;
7586 int write_fd = -1;
7587#if !defined(HAVE_WORKING_FORK)
7588 const char *cmd = 0;
7589
7590 if (prog)
7591 cmd = StringValueCStr(prog);
7592#endif
7593
7594#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
7595 arg.execarg_obj = execarg_obj;
7596 arg.eargp = eargp;
7597 arg.modef = fmode;
7598 arg.pair[0] = arg.pair[1] = -1;
7599 arg.write_pair[0] = arg.write_pair[1] = -1;
7600# if !defined(HAVE_WORKING_FORK)
7601 if (eargp && !eargp->use_shell) {
7602 args = ARGVSTR2ARGV(eargp->invoke.cmd.argv_str);
7603 }
7604# endif
7605 switch (fmode & (FMODE_READABLE|FMODE_WRITABLE)) {
7607 if (rb_pipe(arg.write_pair) < 0)
7608 rb_sys_fail_str(prog);
7609 if (rb_pipe(arg.pair) < 0) {
7610 e = errno;
7611 close(arg.write_pair[0]);
7612 close(arg.write_pair[1]);
7613 rb_syserr_fail_str(e, prog);
7614 }
7615 if (eargp) {
7616 rb_execarg_addopt(execarg_obj, INT2FIX(0), INT2FIX(arg.write_pair[0]));
7617 rb_execarg_addopt(execarg_obj, INT2FIX(1), INT2FIX(arg.pair[1]));
7618 }
7619 break;
7620 case FMODE_READABLE:
7621 if (rb_pipe(arg.pair) < 0)
7622 rb_sys_fail_str(prog);
7623 if (eargp)
7624 rb_execarg_addopt(execarg_obj, INT2FIX(1), INT2FIX(arg.pair[1]));
7625 break;
7626 case FMODE_WRITABLE:
7627 if (rb_pipe(arg.pair) < 0)
7628 rb_sys_fail_str(prog);
7629 if (eargp)
7630 rb_execarg_addopt(execarg_obj, INT2FIX(0), INT2FIX(arg.pair[0]));
7631 break;
7632 default:
7633 rb_sys_fail_str(prog);
7634 }
7635 if (!NIL_P(execarg_obj)) {
7636 rb_protect(rb_execarg_fixup_v, execarg_obj, &state);
7637 if (state) {
7638 if (0 <= arg.write_pair[0]) close(arg.write_pair[0]);
7639 if (0 <= arg.write_pair[1]) close(arg.write_pair[1]);
7640 if (0 <= arg.pair[0]) close(arg.pair[0]);
7641 if (0 <= arg.pair[1]) close(arg.pair[1]);
7642 rb_execarg_parent_end(execarg_obj);
7643 rb_jump_tag(state);
7644 }
7645
7646# if defined(HAVE_WORKING_FORK)
7647 pid = rb_fork_async_signal_safe(&status, popen_exec, &arg, arg.eargp->redirect_fds, errmsg, sizeof(errmsg));
7648# else
7649 rb_execarg_run_options(eargp, sargp, NULL, 0);
7650# if defined(HAVE_SPAWNVE)
7651 if (eargp->envp_str) envp = (char **)RSTRING_PTR(eargp->envp_str);
7652# endif
7653 while ((pid = DO_SPAWN(cmd, args, envp)) < 0) {
7654 /* exec failed */
7655 switch (e = errno) {
7656 case EAGAIN:
7657# if EWOULDBLOCK != EAGAIN
7658 case EWOULDBLOCK:
7659# endif
7660 rb_thread_sleep(1);
7661 continue;
7662 }
7663 break;
7664 }
7665 if (eargp)
7666 rb_execarg_run_options(sargp, NULL, NULL, 0);
7667# endif
7668 rb_execarg_parent_end(execarg_obj);
7669 }
7670 else {
7671# if defined(HAVE_WORKING_FORK)
7672 pid = rb_call_proc__fork();
7673 if (pid == 0) { /* child */
7674 popen_redirect(&arg);
7675 rb_io_synchronized(RFILE(orig_stdout)->fptr);
7676 rb_io_synchronized(RFILE(orig_stderr)->fptr);
7677 return Qnil;
7678 }
7679# else
7681# endif
7682 }
7683
7684 /* parent */
7685 if (pid < 0) {
7686# if defined(HAVE_WORKING_FORK)
7687 e = errno;
7688# endif
7689 close(arg.pair[0]);
7690 close(arg.pair[1]);
7692 close(arg.write_pair[0]);
7693 close(arg.write_pair[1]);
7694 }
7695# if defined(HAVE_WORKING_FORK)
7696 if (errmsg[0])
7697 rb_syserr_fail(e, errmsg);
7698# endif
7699 rb_syserr_fail_str(e, prog);
7700 }
7701 if ((fmode & FMODE_READABLE) && (fmode & FMODE_WRITABLE)) {
7702 close(arg.pair[1]);
7703 fd = arg.pair[0];
7704 close(arg.write_pair[0]);
7705 write_fd = arg.write_pair[1];
7706 }
7707 else if (fmode & FMODE_READABLE) {
7708 close(arg.pair[1]);
7709 fd = arg.pair[0];
7710 }
7711 else {
7712 close(arg.pair[0]);
7713 fd = arg.pair[1];
7714 }
7715#else
7716 cmd = rb_execarg_commandline(eargp, &prog);
7717 if (!NIL_P(execarg_obj)) {
7718 rb_execarg_parent_start(execarg_obj);
7719 rb_execarg_run_options(eargp, sargp, NULL, 0);
7720 }
7721 fp = popen(cmd, modestr);
7722 e = errno;
7723 if (eargp) {
7724 rb_execarg_parent_end(execarg_obj);
7725 rb_execarg_run_options(sargp, NULL, NULL, 0);
7726 }
7727 if (!fp) rb_syserr_fail_path(e, prog);
7728 fd = fileno(fp);
7729#endif
7730
7731 port = io_alloc(rb_cIO);
7732 MakeOpenFile(port, fptr);
7733 fptr->fd = fd;
7734 fptr->stdio_file = fp;
7735 fptr->mode = fmode | FMODE_SYNC|FMODE_DUPLEX;
7736 if (convconfig) {
7737 fptr->encs = *convconfig;
7738#if RUBY_CRLF_ENVIRONMENT
7741 }
7742#endif
7743 }
7744 else {
7745 if (NEED_NEWLINE_DECORATOR_ON_READ(fptr)) {
7747 }
7748#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
7749 if (NEED_NEWLINE_DECORATOR_ON_WRITE(fptr)) {
7750 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
7751 }
7752#endif
7753 }
7754 fptr->pid = pid;
7755
7756 if (0 <= write_fd) {
7757 write_port = io_alloc(rb_cIO);
7758 MakeOpenFile(write_port, write_fptr);
7759 write_fptr->fd = write_fd;
7760 write_fptr->mode = (fmode & ~FMODE_READABLE)| FMODE_SYNC|FMODE_DUPLEX;
7761 fptr->mode &= ~FMODE_WRITABLE;
7762 fptr->tied_io_for_writing = write_port;
7763 rb_ivar_set(port, rb_intern("@tied_io_for_writing"), write_port);
7764 }
7765
7766#if defined (__CYGWIN__) || !defined(HAVE_WORKING_FORK)
7767 fptr->finalize = pipe_finalize;
7768 pipe_add_fptr(fptr);
7769#endif
7770 return port;
7771}
7772#else
7773static VALUE
7774pipe_open(VALUE execarg_obj, const char *modestr, enum rb_io_mode fmode,
7775 const struct rb_io_encoding *convconfig)
7776{
7777 rb_raise(rb_eNotImpError, "popen() is not available");
7778}
7779#endif
7780
7781static int
7782is_popen_fork(VALUE prog)
7783{
7784 if (RSTRING_LEN(prog) == 1 && RSTRING_PTR(prog)[0] == '-') {
7785#if !defined(HAVE_WORKING_FORK)
7786 rb_raise(rb_eNotImpError,
7787 "fork() function is unimplemented on this machine");
7788#else
7789 return TRUE;
7790#endif
7791 }
7792 return FALSE;
7793}
7794
7795static VALUE
7796pipe_open_s(VALUE prog, const char *modestr, enum rb_io_mode fmode,
7797 const struct rb_io_encoding *convconfig)
7798{
7799 int argc = 1;
7800 VALUE *argv = &prog;
7801 VALUE execarg_obj = Qnil;
7802
7803 if (!is_popen_fork(prog))
7804 execarg_obj = rb_execarg_new(argc, argv, TRUE, FALSE);
7805 return pipe_open(execarg_obj, modestr, fmode, convconfig);
7806}
7807
7808static VALUE
7809pipe_close(VALUE io)
7810{
7811 rb_io_t *fptr = io_close_fptr(io);
7812 if (fptr) {
7813 fptr_waitpid(fptr, rb_thread_to_be_killed(rb_thread_current()));
7814 }
7815 return Qnil;
7816}
7817
7818static VALUE popen_finish(VALUE port, VALUE klass);
7819
7820/*
7821 * call-seq:
7822 * IO.popen(env = {}, cmd, mode = 'r', **opts) -> io
7823 * IO.popen(env = {}, cmd, mode = 'r', **opts) {|io| ... } -> object
7824 *
7825 * Executes the given command +cmd+ as a subprocess
7826 * whose $stdin and $stdout are connected to a new stream +io+.
7827 *
7828 * This method has potential security vulnerabilities if called with untrusted input;
7829 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
7830 *
7831 * If no block is given, returns the new stream,
7832 * which depending on given +mode+ may be open for reading, writing, or both.
7833 * The stream should be explicitly closed (eventually) to avoid resource leaks.
7834 *
7835 * If a block is given, the stream is passed to the block
7836 * (again, open for reading, writing, or both);
7837 * when the block exits, the stream is closed,
7838 * the block's value is returned,
7839 * and the global variable <tt>$?</tt> is set to the child's exit status.
7840 *
7841 * Optional argument +mode+ may be any valid \IO mode.
7842 * See {Access Modes}[rdoc-ref:File@Access+Modes].
7843 *
7844 * Required argument +cmd+ determines which of the following occurs:
7845 *
7846 * - The process forks.
7847 * - A specified program runs in a shell.
7848 * - A specified program runs with specified arguments.
7849 * - A specified program runs with specified arguments and a specified +argv0+.
7850 *
7851 * Each of these is detailed below.
7852 *
7853 * The optional hash argument +env+ specifies name/value pairs that are to be added
7854 * to the environment variables for the subprocess:
7855 *
7856 * IO.popen({'FOO' => 'bar'}, 'ruby', 'r+') do |pipe|
7857 * pipe.puts 'puts ENV["FOO"]'
7858 * pipe.close_write
7859 * pipe.gets
7860 * end => "bar\n"
7861 *
7862 * Optional keyword arguments +opts+ specify:
7863 *
7864 * - {Open options}[rdoc-ref:IO@Open+Options].
7865 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
7866 * - Options for Kernel#spawn.
7867 *
7868 * <b>Forked Process</b>
7869 *
7870 * When argument +cmd+ is the 1-character string <tt>'-'</tt>, causes the process to fork:
7871 * IO.popen('-') do |pipe|
7872 * if pipe
7873 * $stderr.puts "In parent, child pid is #{pipe.pid}\n"
7874 * else
7875 * $stderr.puts "In child, pid is #{$$}\n"
7876 * end
7877 * end
7878 *
7879 * Output:
7880 *
7881 * In parent, child pid is 26253
7882 * In child, pid is 26253
7883 *
7884 * Note that this is not supported on all platforms.
7885 *
7886 * <b>Shell Subprocess</b>
7887 *
7888 * When argument +cmd+ is a single string (but not <tt>'-'</tt>),
7889 * the program named +cmd+ is run as a shell command:
7890 *
7891 * IO.popen('uname') do |pipe|
7892 * pipe.readlines
7893 * end
7894 *
7895 * Output:
7896 *
7897 * ["Linux\n"]
7898 *
7899 * Another example:
7900 *
7901 * IO.popen('/bin/sh', 'r+') do |pipe|
7902 * pipe.puts('ls')
7903 * pipe.close_write
7904 * $stderr.puts pipe.readlines.size
7905 * end
7906 *
7907 * Output:
7908 *
7909 * 213
7910 *
7911 * <b>Program Subprocess</b>
7912 *
7913 * When argument +cmd+ is an array of strings,
7914 * the program named <tt>cmd[0]</tt> is run with all elements of +cmd+ as its arguments:
7915 *
7916 * IO.popen(['du', '..', '.']) do |pipe|
7917 * $stderr.puts pipe.readlines.size
7918 * end
7919 *
7920 * Output:
7921 *
7922 * 1111
7923 *
7924 * <b>Program Subprocess with <tt>argv0</tt></b>
7925 *
7926 * When argument +cmd+ is an array whose first element is a 2-element string array
7927 * and whose remaining elements (if any) are strings:
7928 *
7929 * - <tt>cmd[0][0]</tt> (the first string in the nested array) is the name of a program that is run.
7930 * - <tt>cmd[0][1]</tt> (the second string in the nested array) is set as the program's <tt>argv[0]</tt>.
7931 * - <tt>cmd[1..-1]</tt> (the strings in the outer array) are the program's arguments.
7932 *
7933 * Example (sets <tt>$0</tt> to 'foo'):
7934 *
7935 * IO.popen([['/bin/sh', 'foo'], '-c', 'echo $0']).read # => "foo\n"
7936 *
7937 * <b>Some Special Examples</b>
7938 *
7939 * # Set IO encoding.
7940 * IO.popen("nkf -e filename", :external_encoding=>"EUC-JP") {|nkf_io|
7941 * euc_jp_string = nkf_io.read
7942 * }
7943 *
7944 * # Merge standard output and standard error using Kernel#spawn option. See Kernel#spawn.
7945 * IO.popen(["ls", "/", :err=>[:child, :out]]) do |io|
7946 * ls_result_with_error = io.read
7947 * end
7948 *
7949 * # Use mixture of spawn options and IO options.
7950 * IO.popen(["ls", "/"], :err=>[:child, :out]) do |io|
7951 * ls_result_with_error = io.read
7952 * end
7953 *
7954 * f = IO.popen("uname")
7955 * p f.readlines
7956 * f.close
7957 * puts "Parent is #{Process.pid}"
7958 * IO.popen("date") {|f| puts f.gets }
7959 * IO.popen("-") {|f| $stderr.puts "#{Process.pid} is here, f is #{f.inspect}"}
7960 * p $?
7961 * IO.popen(%w"sed -e s|^|<foo>| -e s&$&;zot;&", "r+") {|f|
7962 * f.puts "bar"; f.close_write; puts f.gets
7963 * }
7964 *
7965 * Output (from last section):
7966 *
7967 * ["Linux\n"]
7968 * Parent is 21346
7969 * Thu Jan 15 22:41:19 JST 2009
7970 * 21346 is here, f is #<IO:fd 3>
7971 * 21352 is here, f is nil
7972 * #<Process::Status: pid 21352 exit 0>
7973 * <foo>bar;zot;
7974 *
7975 * Raises exceptions that IO.pipe and Kernel.spawn raise.
7976 *
7977 */
7978
7979static VALUE
7980rb_io_s_popen(int argc, VALUE *argv, VALUE klass)
7981{
7982 VALUE pname, pmode = Qnil, opt = Qnil, env = Qnil;
7983
7984 if (argc > 1 && !NIL_P(opt = rb_check_hash_type(argv[argc-1]))) --argc;
7985 if (argc > 1 && !NIL_P(env = rb_check_hash_type(argv[0]))) --argc, ++argv;
7986 switch (argc) {
7987 case 2:
7988 pmode = argv[1];
7989 case 1:
7990 pname = argv[0];
7991 break;
7992 default:
7993 {
7994 int ex = !NIL_P(opt);
7995 rb_error_arity(argc + ex, 1 + ex, 2 + ex);
7996 }
7997 }
7998 return popen_finish(rb_io_popen(pname, pmode, env, opt), klass);
7999}
8000
8001VALUE
8002rb_io_popen(VALUE pname, VALUE pmode, VALUE env, VALUE opt)
8003{
8004 const char *modestr;
8005 VALUE tmp, execarg_obj = Qnil;
8006 int oflags;
8007 enum rb_io_mode fmode;
8008 struct rb_io_encoding convconfig;
8009
8010 tmp = rb_check_array_type(pname);
8011 if (!NIL_P(tmp)) {
8012 long len = RARRAY_LEN(tmp);
8013#if SIZEOF_LONG > SIZEOF_INT
8014 if (len > INT_MAX) {
8015 rb_raise(rb_eArgError, "too many arguments");
8016 }
8017#endif
8018 execarg_obj = rb_execarg_new((int)len, RARRAY_CONST_PTR(tmp), FALSE, FALSE);
8019 RB_GC_GUARD(tmp);
8020 }
8021 else {
8022 StringValue(pname);
8023 execarg_obj = Qnil;
8024 if (!is_popen_fork(pname))
8025 execarg_obj = rb_execarg_new(1, &pname, TRUE, FALSE);
8026 }
8027 if (!NIL_P(execarg_obj)) {
8028 if (!NIL_P(opt))
8029 opt = rb_execarg_extract_options(execarg_obj, opt);
8030 if (!NIL_P(env))
8031 rb_execarg_setenv(execarg_obj, env);
8032 }
8033 rb_io_extract_modeenc(&pmode, 0, opt, &oflags, &fmode, &convconfig);
8034 modestr = rb_io_oflags_modestr(oflags);
8035
8036 return pipe_open(execarg_obj, modestr, fmode, &convconfig);
8037}
8038
8039static VALUE
8040popen_finish(VALUE port, VALUE klass)
8041{
8042 if (NIL_P(port)) {
8043 /* child */
8044 if (rb_block_given_p()) {
8045 rb_protect(rb_yield, Qnil, NULL);
8046 rb_io_flush(rb_ractor_stdout());
8047 rb_io_flush(rb_ractor_stderr());
8048 _exit(0);
8049 }
8050 return Qnil;
8051 }
8052 RBASIC_SET_CLASS(port, klass);
8053 if (rb_block_given_p()) {
8054 return rb_ensure(rb_yield, port, pipe_close, port);
8055 }
8056 return port;
8057}
8058
8059#if defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)
8060struct popen_writer_arg {
8061 char *const *argv;
8062 struct popen_arg popen;
8063};
8064
8065static int
8066exec_popen_writer(void *arg, char *errmsg, size_t buflen)
8067{
8068 struct popen_writer_arg *pw = arg;
8069 pw->popen.modef = FMODE_WRITABLE;
8070 popen_redirect(&pw->popen);
8071 execv(pw->argv[0], pw->argv);
8072 strlcpy(errmsg, strerror(errno), buflen);
8073 return -1;
8074}
8075#endif
8076
8077FILE *
8078ruby_popen_writer(char *const *argv, rb_pid_t *pid)
8079{
8080#if (defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)) || defined(_WIN32)
8081# ifdef HAVE_WORKING_FORK
8082 struct popen_writer_arg pw;
8083 int *const write_pair = pw.popen.pair;
8084# else
8085 int write_pair[2];
8086# endif
8087
8088 int result = rb_cloexec_pipe(write_pair);
8089 *pid = -1;
8090 if (result == 0) {
8091# ifdef HAVE_WORKING_FORK
8092 pw.argv = argv;
8093 int status;
8094 char errmsg[80] = {'\0'};
8095 *pid = rb_fork_async_signal_safe(&status, exec_popen_writer, &pw, Qnil, errmsg, sizeof(errmsg));
8096# else
8097 *pid = rb_w32_uspawn_process(P_NOWAIT, argv[0], argv, write_pair[0], -1, -1, 0);
8098 const char *errmsg = (*pid < 0) ? strerror(errno) : NULL;
8099# endif
8100 close(write_pair[0]);
8101 if (*pid < 0) {
8102 close(write_pair[1]);
8103 fprintf(stderr, "ruby_popen_writer(%s): %s\n", argv[0], errmsg);
8104 }
8105 else {
8106 return fdopen(write_pair[1], "w");
8107 }
8108 }
8109#endif
8110 return NULL;
8111}
8112
8113static VALUE
8114rb_open_file(VALUE io, VALUE fname, VALUE vmode, VALUE vperm, VALUE opt)
8115{
8116 int oflags;
8117 enum rb_io_mode fmode;
8118 struct rb_io_encoding convconfig;
8119 mode_t perm;
8120
8121 FilePathValue(fname);
8122
8123 rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, &convconfig);
8124 perm = NIL_P(vperm) ? 0666 : NUM2MODET(vperm);
8125
8126 rb_file_open_generic(io, fname, oflags, fmode, &convconfig, perm);
8127
8128 return io;
8129}
8130
8131/*
8132 * Document-method: File::open
8133 *
8134 * call-seq:
8135 * File.open(path, mode = 'r', perm = 0666, **opts) -> file
8136 * File.open(path, mode = 'r', perm = 0666, **opts) {|f| ... } -> object
8137 *
8138 * Creates a new File object, via File.new with the given arguments.
8139 *
8140 * With no block given, returns the File object.
8141 *
8142 * With a block given, calls the block with the File object
8143 * and returns the block's value.
8144 *
8145 */
8146
8147/*
8148 * Document-method: IO::open
8149 *
8150 * call-seq:
8151 * IO.open(fd, mode = 'r', **opts) -> io
8152 * IO.open(fd, mode = 'r', **opts) {|io| ... } -> object
8153 *
8154 * Creates a new \IO object, via IO.new with the given arguments.
8155 *
8156 * With no block given, returns the \IO object.
8157 *
8158 * With a block given, calls the block with the \IO object
8159 * and returns the block's value.
8160 *
8161 */
8162
8163static VALUE
8164rb_io_s_open(int argc, VALUE *argv, VALUE klass)
8165{
8167
8168 if (rb_block_given_p()) {
8169 return rb_ensure(rb_yield, io, io_close, io);
8170 }
8171
8172 return io;
8173}
8174
8175/*
8176 * call-seq:
8177 * IO.sysopen(path, mode = 'r', perm = 0666) -> integer
8178 *
8179 * Opens the file at the given path with the given mode and permissions;
8180 * returns the integer file descriptor.
8181 *
8182 * If the file is to be readable, it must exist;
8183 * if the file is to be writable and does not exist,
8184 * it is created with the given permissions:
8185 *
8186 * File.write('t.tmp', '') # => 0
8187 * IO.sysopen('t.tmp') # => 8
8188 * IO.sysopen('t.tmp', 'w') # => 9
8189 *
8190 *
8191 */
8192
8193static VALUE
8194rb_io_s_sysopen(int argc, VALUE *argv, VALUE _)
8195{
8196 VALUE fname, vmode, vperm;
8197 VALUE intmode;
8198 int oflags, fd;
8199 mode_t perm;
8200
8201 rb_scan_args(argc, argv, "12", &fname, &vmode, &vperm);
8202 FilePathValue(fname);
8203
8204 if (NIL_P(vmode))
8205 oflags = O_RDONLY;
8206 else if (!NIL_P(intmode = rb_check_to_integer(vmode, "to_int")))
8207 oflags = NUM2INT(intmode);
8208 else {
8209 StringValue(vmode);
8210 oflags = rb_io_modestr_oflags(StringValueCStr(vmode));
8211 }
8212 if (NIL_P(vperm)) perm = 0666;
8213 else perm = NUM2MODET(vperm);
8214
8215 RB_GC_GUARD(fname) = rb_str_new4(fname);
8216 fd = rb_sysopen(fname, oflags, perm);
8217 return INT2NUM(fd);
8218}
8219
8220static VALUE
8221check_pipe_command(VALUE filename_or_command)
8222{
8223 char *s = RSTRING_PTR(filename_or_command);
8224 long l = RSTRING_LEN(filename_or_command);
8225 char *e = s + l;
8226 int chlen;
8227
8228 if (rb_enc_ascget(s, e, &chlen, rb_enc_get(filename_or_command)) == '|') {
8229 VALUE cmd = rb_str_new(s+chlen, l-chlen);
8230 return cmd;
8231 }
8232 return Qnil;
8233}
8234
8235/*
8236 * call-seq:
8237 * open(path, mode = 'r', perm = 0666, **opts) -> io or nil
8238 * open(path, mode = 'r', perm = 0666, **opts) {|io| ... } -> obj
8239 *
8240 * Creates an IO object connected to the given file.
8241 *
8242 * This method has potential security vulnerabilities if called with untrusted input;
8243 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
8244 *
8245 * With no block given, file stream is returned:
8246 *
8247 * open('t.txt') # => #<File:t.txt>
8248 *
8249 * With a block given, calls the block with the open file stream,
8250 * then closes the stream:
8251 *
8252 * open('t.txt') {|f| p f } # => #<File:t.txt (closed)>
8253 *
8254 * Output:
8255 *
8256 * #<File:t.txt>
8257 *
8258 * See File.open for details.
8259 *
8260 */
8261
8262static VALUE
8263rb_f_open(int argc, VALUE *argv, VALUE _)
8264{
8265 ID to_open = 0;
8266 int redirect = FALSE;
8267
8268 if (argc >= 1) {
8269 CONST_ID(to_open, "to_open");
8270 if (rb_respond_to(argv[0], to_open)) {
8271 redirect = TRUE;
8272 }
8273 else {
8274 VALUE tmp = argv[0];
8275 FilePathValue(tmp);
8276 if (NIL_P(tmp)) {
8277 redirect = TRUE;
8278 }
8279 else {
8280 VALUE cmd = check_pipe_command(tmp);
8281 if (!NIL_P(cmd)) {
8282 // TODO: when removed in 4.0, update command_injection.rdoc
8283 rb_warn_deprecated_to_remove_at(4.0, "Calling Kernel#open with a leading '|'", "IO.popen");
8284 argv[0] = cmd;
8285 return rb_io_s_popen(argc, argv, rb_cIO);
8286 }
8287 }
8288 }
8289 }
8290 if (redirect) {
8291 VALUE io = rb_funcallv_kw(argv[0], to_open, argc-1, argv+1, RB_PASS_CALLED_KEYWORDS);
8292
8293 if (rb_block_given_p()) {
8294 return rb_ensure(rb_yield, io, io_close, io);
8295 }
8296 return io;
8297 }
8298 return rb_io_s_open(argc, argv, rb_cFile);
8299}
8300
8301static VALUE
8302rb_io_open_generic(VALUE klass, VALUE filename, int oflags, enum rb_io_mode fmode,
8303 const struct rb_io_encoding *convconfig, mode_t perm)
8304{
8305 VALUE cmd;
8306 if (klass == rb_cIO && !NIL_P(cmd = check_pipe_command(filename))) {
8307 // TODO: when removed in 4.0, update command_injection.rdoc
8308 rb_warn_deprecated_to_remove_at(4.0, "IO process creation with a leading '|'", "IO.popen");
8309 return pipe_open_s(cmd, rb_io_oflags_modestr(oflags), fmode, convconfig);
8310 }
8311 else {
8312 return rb_file_open_generic(io_alloc(klass), filename,
8313 oflags, fmode, convconfig, perm);
8314 }
8315}
8316
8317static VALUE
8318rb_io_open(VALUE io, VALUE filename, VALUE vmode, VALUE vperm, VALUE opt)
8319{
8320 int oflags;
8321 enum rb_io_mode fmode;
8322 struct rb_io_encoding convconfig;
8323 mode_t perm;
8324
8325 rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, &convconfig);
8326 perm = NIL_P(vperm) ? 0666 : NUM2MODET(vperm);
8327 return rb_io_open_generic(io, filename, oflags, fmode, &convconfig, perm);
8328}
8329
8330static VALUE
8331io_reopen(VALUE io, VALUE nfile)
8332{
8333 rb_io_t *fptr, *orig;
8334 int fd, fd2;
8335 rb_off_t pos = 0;
8336
8337 nfile = rb_io_get_io(nfile);
8338 GetOpenFile(io, fptr);
8339 GetOpenFile(nfile, orig);
8340
8341 if (fptr == orig) return io;
8342 if (RUBY_IO_EXTERNAL_P(fptr)) {
8343 if ((fptr->stdio_file == stdin && !(orig->mode & FMODE_READABLE)) ||
8344 (fptr->stdio_file == stdout && !(orig->mode & FMODE_WRITABLE)) ||
8345 (fptr->stdio_file == stderr && !(orig->mode & FMODE_WRITABLE))) {
8346 rb_raise(rb_eArgError,
8347 "%s can't change access mode from \"%s\" to \"%s\"",
8348 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->mode),
8349 rb_io_fmode_modestr(orig->mode));
8350 }
8351 }
8352 if (fptr->mode & FMODE_WRITABLE) {
8353 if (io_fflush(fptr) < 0)
8354 rb_sys_fail_on_write(fptr);
8355 }
8356 else {
8357 flush_before_seek(fptr, true);
8358 }
8359 if (orig->mode & FMODE_READABLE) {
8360 pos = io_tell(orig);
8361 }
8362 if (orig->mode & FMODE_WRITABLE) {
8363 if (io_fflush(orig) < 0)
8364 rb_sys_fail_on_write(fptr);
8365 }
8366
8367 /* copy rb_io_t structure */
8368 fptr->mode = orig->mode | (fptr->mode & FMODE_EXTERNAL);
8369 fptr->encs = orig->encs;
8370 fptr->pid = orig->pid;
8371 fptr->lineno = orig->lineno;
8372 if (RTEST(orig->pathv)) fptr->pathv = orig->pathv;
8373 else if (!RUBY_IO_EXTERNAL_P(fptr)) fptr->pathv = Qnil;
8374 fptr_copy_finalizer(fptr, orig);
8375
8376 fd = fptr->fd;
8377 fd2 = orig->fd;
8378 if (fd != fd2) {
8379 // Interrupt all usage of the old file descriptor:
8380 rb_thread_io_close_interrupt(fptr);
8381 rb_thread_io_close_wait(fptr);
8382
8383 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2 || !fptr->stdio_file) {
8384 /* need to keep FILE objects of stdin, stdout and stderr */
8385 if (rb_cloexec_dup2(fd2, fd) < 0)
8386 rb_sys_fail_path(orig->pathv);
8387 rb_update_max_fd(fd);
8388 }
8389 else {
8390 fclose(fptr->stdio_file);
8391 fptr->stdio_file = 0;
8392 fptr->fd = -1;
8393 if (rb_cloexec_dup2(fd2, fd) < 0)
8394 rb_sys_fail_path(orig->pathv);
8395 rb_update_max_fd(fd);
8396 fptr->fd = fd;
8397 }
8398
8399 if ((orig->mode & FMODE_READABLE) && pos >= 0) {
8400 if (io_seek(fptr, pos, SEEK_SET) < 0 && errno) {
8401 rb_sys_fail_path(fptr->pathv);
8402 }
8403 if (io_seek(orig, pos, SEEK_SET) < 0 && errno) {
8404 rb_sys_fail_path(orig->pathv);
8405 }
8406 }
8407 }
8408
8409 if (fptr->mode & FMODE_BINMODE) {
8410 rb_io_binmode(io);
8411 }
8412
8413 RBASIC_SET_CLASS(io, rb_obj_class(nfile));
8414 return io;
8415}
8416
8417#ifdef _WIN32
8418int rb_freopen(VALUE fname, const char *mode, FILE *fp);
8419#else
8420static int
8421rb_freopen(VALUE fname, const char *mode, FILE *fp)
8422{
8423 if (!freopen(RSTRING_PTR(fname), mode, fp)) {
8424 RB_GC_GUARD(fname);
8425 return errno;
8426 }
8427 return 0;
8428}
8429#endif
8430
8431/*
8432 * call-seq:
8433 * reopen(other_io) -> self
8434 * reopen(path, mode = 'r', **opts) -> self
8435 *
8436 * Reassociates the stream with another stream,
8437 * which may be of a different class.
8438 * This method may be used to redirect an existing stream
8439 * to a new destination.
8440 *
8441 * With argument +other_io+ given, reassociates with that stream:
8442 *
8443 * # Redirect $stdin from a file.
8444 * f = File.open('t.txt')
8445 * $stdin.reopen(f)
8446 * f.close
8447 *
8448 * # Redirect $stdout to a file.
8449 * f = File.open('t.tmp', 'w')
8450 * $stdout.reopen(f)
8451 * f.close
8452 *
8453 * With argument +path+ given, reassociates with a new stream to that file path:
8454 *
8455 * $stdin.reopen('t.txt')
8456 * $stdout.reopen('t.tmp', 'w')
8457 *
8458 * Optional keyword arguments +opts+ specify:
8459 *
8460 * - {Open Options}[rdoc-ref:IO@Open+Options].
8461 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
8462 *
8463 */
8464
8465static VALUE
8466rb_io_reopen(int argc, VALUE *argv, VALUE file)
8467{
8468 VALUE fname, nmode, opt;
8469 int oflags;
8470 rb_io_t *fptr;
8471
8472 if (rb_scan_args(argc, argv, "11:", &fname, &nmode, &opt) == 1) {
8473 VALUE tmp = rb_io_check_io(fname);
8474 if (!NIL_P(tmp)) {
8475 return io_reopen(file, tmp);
8476 }
8477 }
8478
8479 FilePathValue(fname);
8480 rb_io_taint_check(file);
8481 fptr = RFILE(file)->fptr;
8482 if (!fptr) {
8483 fptr = RFILE(file)->fptr = ZALLOC(rb_io_t);
8484 }
8485
8486 if (!NIL_P(nmode) || !NIL_P(opt)) {
8487 enum rb_io_mode fmode;
8488 struct rb_io_encoding convconfig;
8489
8490 rb_io_extract_modeenc(&nmode, 0, opt, &oflags, &fmode, &convconfig);
8491 if (RUBY_IO_EXTERNAL_P(fptr) &&
8492 ((fptr->mode & FMODE_READWRITE) & (fmode & FMODE_READWRITE)) !=
8493 (fptr->mode & FMODE_READWRITE)) {
8494 rb_raise(rb_eArgError,
8495 "%s can't change access mode from \"%s\" to \"%s\"",
8496 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->mode),
8497 rb_io_fmode_modestr(fmode));
8498 }
8499 fptr->mode = fmode;
8500 fptr->encs = convconfig;
8501 }
8502 else {
8503 oflags = rb_io_fmode_oflags(fptr->mode);
8504 }
8505
8506 fptr->pathv = fname;
8507 if (fptr->fd < 0) {
8508 fptr->fd = rb_sysopen(fptr->pathv, oflags, 0666);
8509 fptr->stdio_file = 0;
8510 return file;
8511 }
8512
8513 if (fptr->mode & FMODE_WRITABLE) {
8514 if (io_fflush(fptr) < 0)
8515 rb_sys_fail_on_write(fptr);
8516 }
8517 fptr->rbuf.off = fptr->rbuf.len = 0;
8518
8519 if (fptr->stdio_file) {
8520 int e = rb_freopen(rb_str_encode_ospath(fptr->pathv),
8521 rb_io_oflags_modestr(oflags),
8522 fptr->stdio_file);
8523 if (e) rb_syserr_fail_path(e, fptr->pathv);
8524 fptr->fd = fileno(fptr->stdio_file);
8525 rb_fd_fix_cloexec(fptr->fd);
8526#ifdef USE_SETVBUF
8527 if (setvbuf(fptr->stdio_file, NULL, _IOFBF, 0) != 0)
8528 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8529#endif
8530 if (fptr->stdio_file == stderr) {
8531 if (setvbuf(fptr->stdio_file, NULL, _IONBF, BUFSIZ) != 0)
8532 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8533 }
8534 else if (fptr->stdio_file == stdout && isatty(fptr->fd)) {
8535 if (setvbuf(fptr->stdio_file, NULL, _IOLBF, BUFSIZ) != 0)
8536 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8537 }
8538 }
8539 else {
8540 int tmpfd = rb_sysopen(fptr->pathv, oflags, 0666);
8541 int err = 0;
8542 if (rb_cloexec_dup2(tmpfd, fptr->fd) < 0)
8543 err = errno;
8544 (void)close(tmpfd);
8545 if (err) {
8546 rb_syserr_fail_path(err, fptr->pathv);
8547 }
8548 }
8549
8550 return file;
8551}
8552
8553/* :nodoc: */
8554static VALUE
8555rb_io_init_copy(VALUE dest, VALUE io)
8556{
8557 rb_io_t *fptr, *orig;
8558 int fd;
8559 VALUE write_io;
8560 rb_off_t pos;
8561
8562 io = rb_io_get_io(io);
8563 if (!OBJ_INIT_COPY(dest, io)) return dest;
8564 GetOpenFile(io, orig);
8565 MakeOpenFile(dest, fptr);
8566
8567 rb_io_flush(io);
8568
8569 /* copy rb_io_t structure */
8570 fptr->mode = orig->mode & ~FMODE_EXTERNAL;
8571 fptr->encs = orig->encs;
8572 fptr->pid = orig->pid;
8573 fptr->lineno = orig->lineno;
8574 fptr->timeout = orig->timeout;
8575
8576 ccan_list_head_init(&fptr->blocking_operations);
8577 fptr->closing_ec = NULL;
8578 fptr->wakeup_mutex = Qnil;
8579 fptr->fork_generation = GET_VM()->fork_gen;
8580
8581 if (!NIL_P(orig->pathv)) fptr->pathv = orig->pathv;
8582 fptr_copy_finalizer(fptr, orig);
8583
8584 fd = ruby_dup(orig->fd);
8585 fptr->fd = fd;
8586 pos = io_tell(orig);
8587 if (0 <= pos)
8588 io_seek(fptr, pos, SEEK_SET);
8589 if (fptr->mode & FMODE_BINMODE) {
8590 rb_io_binmode(dest);
8591 }
8592
8593 write_io = GetWriteIO(io);
8594 if (io != write_io) {
8595 write_io = rb_obj_dup(write_io);
8596 fptr->tied_io_for_writing = write_io;
8597 rb_ivar_set(dest, rb_intern("@tied_io_for_writing"), write_io);
8598 }
8599
8600 return dest;
8601}
8602
8603/*
8604 * call-seq:
8605 * printf(format_string, *objects) -> nil
8606 *
8607 * Formats and writes +objects+ to the stream.
8608 *
8609 * For details on +format_string+, see
8610 * {Format Specifications}[rdoc-ref:format_specifications.rdoc].
8611 *
8612 */
8613
8614VALUE
8615rb_io_printf(int argc, const VALUE *argv, VALUE out)
8616{
8617 rb_io_write(out, rb_f_sprintf(argc, argv));
8618 return Qnil;
8619}
8620
8621/*
8622 * call-seq:
8623 * printf(format_string, *objects) -> nil
8624 * printf(io, format_string, *objects) -> nil
8625 *
8626 * Equivalent to:
8627 *
8628 * io.write(sprintf(format_string, *objects))
8629 *
8630 * For details on +format_string+, see
8631 * {Format Specifications}[rdoc-ref:format_specifications.rdoc].
8632 *
8633 * With the single argument +format_string+, formats +objects+ into the string,
8634 * then writes the formatted string to $stdout:
8635 *
8636 * printf('%4.4d %10s %2.2f', 24, 24, 24.0)
8637 *
8638 * Output (on $stdout):
8639 *
8640 * 0024 24 24.00#
8641 *
8642 * With arguments +io+ and +format_string+, formats +objects+ into the string,
8643 * then writes the formatted string to +io+:
8644 *
8645 * printf($stderr, '%4.4d %10s %2.2f', 24, 24, 24.0)
8646 *
8647 * Output (on $stderr):
8648 *
8649 * 0024 24 24.00# => nil
8650 *
8651 * With no arguments, does nothing.
8652 *
8653 */
8654
8655static VALUE
8656rb_f_printf(int argc, VALUE *argv, VALUE _)
8657{
8658 VALUE out;
8659
8660 if (argc == 0) return Qnil;
8661 if (RB_TYPE_P(argv[0], T_STRING)) {
8662 out = rb_ractor_stdout();
8663 }
8664 else {
8665 out = argv[0];
8666 argv++;
8667 argc--;
8668 }
8669 rb_io_write(out, rb_f_sprintf(argc, argv));
8670
8671 return Qnil;
8672}
8673
8674static void
8675deprecated_str_setter(VALUE val, ID id, VALUE *var)
8676{
8677 rb_str_setter(val, id, &val);
8678 if (!NIL_P(val)) {
8679 rb_warn_deprecated("'%s'", NULL, rb_id2name(id));
8680 }
8681 *var = val;
8682}
8683
8684static void
8685deprecated_rs_setter(VALUE val, ID id, VALUE *var)
8686{
8687 if (!NIL_P(val)) {
8688 if (!RB_TYPE_P(val, T_STRING)) {
8689 rb_raise(rb_eTypeError, "value of %"PRIsVALUE" must be String", rb_id2str(id));
8690 }
8691 if (rb_str_equal(val, rb_default_rs)) {
8692 val = rb_default_rs;
8693 }
8694 else {
8695 val = rb_str_frozen_bare_string(val);
8696 }
8698 rb_warn_deprecated("'%s'", NULL, rb_id2name(id));
8699 }
8700 *var = val;
8701}
8702
8703/*
8704 * call-seq:
8705 * print(*objects) -> nil
8706 *
8707 * Writes the given objects to the stream; returns +nil+.
8708 * Appends the output record separator <tt>$OUTPUT_RECORD_SEPARATOR</tt>
8709 * (<tt>$\</tt>), if it is not +nil+.
8710 * See {Line IO}[rdoc-ref:IO@Line+IO].
8711 *
8712 * With argument +objects+ given, for each object:
8713 *
8714 * - Converts via its method +to_s+ if not a string.
8715 * - Writes to the stream.
8716 * - If not the last object, writes the output field separator
8717 * <tt>$OUTPUT_FIELD_SEPARATOR</tt> (<tt>$,</tt>) if it is not +nil+.
8718 *
8719 * With default separators:
8720 *
8721 * f = File.open('t.tmp', 'w+')
8722 * objects = [0, 0.0, Rational(0, 1), Complex(0, 0), :zero, 'zero']
8723 * p $OUTPUT_RECORD_SEPARATOR
8724 * p $OUTPUT_FIELD_SEPARATOR
8725 * f.print(*objects)
8726 * f.rewind
8727 * p f.read
8728 * f.close
8729 *
8730 * Output:
8731 *
8732 * nil
8733 * nil
8734 * "00.00/10+0izerozero"
8735 *
8736 * With specified separators:
8737 *
8738 * $\ = "\n"
8739 * $, = ','
8740 * f.rewind
8741 * f.print(*objects)
8742 * f.rewind
8743 * p f.read
8744 *
8745 * Output:
8746 *
8747 * "0,0.0,0/1,0+0i,zero,zero\n"
8748 *
8749 * With no argument given, writes the content of <tt>$_</tt>
8750 * (which is usually the most recent user input):
8751 *
8752 * f = File.open('t.tmp', 'w+')
8753 * gets # Sets $_ to the most recent user input.
8754 * f.print
8755 * f.close
8756 *
8757 */
8758
8759VALUE
8760rb_io_print(int argc, const VALUE *argv, VALUE out)
8761{
8762 int i;
8763 VALUE line;
8764
8765 /* if no argument given, print `$_' */
8766 if (argc == 0) {
8767 argc = 1;
8768 line = rb_lastline_get();
8769 argv = &line;
8770 }
8771 if (argc > 1 && !NIL_P(rb_output_fs)) {
8772 rb_category_warn(RB_WARN_CATEGORY_DEPRECATED, "$, is set to non-nil value");
8773 }
8774 for (i=0; i<argc; i++) {
8775 if (!NIL_P(rb_output_fs) && i>0) {
8776 rb_io_write(out, rb_output_fs);
8777 }
8778 rb_io_write(out, argv[i]);
8779 }
8780 if (argc > 0 && !NIL_P(rb_output_rs)) {
8781 rb_io_write(out, rb_output_rs);
8782 }
8783
8784 return Qnil;
8785}
8786
8787/*
8788 * call-seq:
8789 * print(*objects) -> nil
8790 *
8791 * Equivalent to <tt>$stdout.print(*objects)</tt>,
8792 * this method is the straightforward way to write to <tt>$stdout</tt>.
8793 *
8794 * Writes the given objects to <tt>$stdout</tt>; returns +nil+.
8795 * Appends the output record separator <tt>$OUTPUT_RECORD_SEPARATOR</tt>
8796 * <tt>$\</tt>), if it is not +nil+.
8797 *
8798 * With argument +objects+ given, for each object:
8799 *
8800 * - Converts via its method +to_s+ if not a string.
8801 * - Writes to <tt>stdout</tt>.
8802 * - If not the last object, writes the output field separator
8803 * <tt>$OUTPUT_FIELD_SEPARATOR</tt> (<tt>$,</tt> if it is not +nil+.
8804 *
8805 * With default separators:
8806 *
8807 * objects = [0, 0.0, Rational(0, 1), Complex(0, 0), :zero, 'zero']
8808 * $OUTPUT_RECORD_SEPARATOR
8809 * $OUTPUT_FIELD_SEPARATOR
8810 * print(*objects)
8811 *
8812 * Output:
8813 *
8814 * nil
8815 * nil
8816 * 00.00/10+0izerozero
8817 *
8818 * With specified separators:
8819 *
8820 * $OUTPUT_RECORD_SEPARATOR = "\n"
8821 * $OUTPUT_FIELD_SEPARATOR = ','
8822 * print(*objects)
8823 *
8824 * Output:
8825 *
8826 * 0,0.0,0/1,0+0i,zero,zero
8827 *
8828 * With no argument given, writes the content of <tt>$_</tt>
8829 * (which is usually the most recent user input):
8830 *
8831 * gets # Sets $_ to the most recent user input.
8832 * print # Prints $_.
8833 *
8834 */
8835
8836static VALUE
8837rb_f_print(int argc, const VALUE *argv, VALUE _)
8838{
8839 rb_io_print(argc, argv, rb_ractor_stdout());
8840 return Qnil;
8841}
8842
8843/*
8844 * call-seq:
8845 * putc(object) -> object
8846 *
8847 * Writes a character to the stream.
8848 * See {Character IO}[rdoc-ref:IO@Character+IO].
8849 *
8850 * If +object+ is numeric, converts to integer if necessary,
8851 * then writes the character whose code is the
8852 * least significant byte;
8853 * if +object+ is a string, writes the first character:
8854 *
8855 * $stdout.putc "A"
8856 * $stdout.putc 65
8857 *
8858 * Output:
8859 *
8860 * AA
8861 *
8862 */
8863
8864static VALUE
8865rb_io_putc(VALUE io, VALUE ch)
8866{
8867 VALUE str;
8868 if (RB_TYPE_P(ch, T_STRING)) {
8869 str = rb_str_substr(ch, 0, 1);
8870 }
8871 else {
8872 char c = NUM2CHR(ch);
8873 str = rb_str_new(&c, 1);
8874 }
8875 rb_io_write(io, str);
8876 return ch;
8877}
8878
8879#define forward(obj, id, argc, argv) \
8880 rb_funcallv_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8881#define forward_public(obj, id, argc, argv) \
8882 rb_funcallv_public_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8883#define forward_current(id, argc, argv) \
8884 forward_public(ARGF.current_file, id, argc, argv)
8885
8886/*
8887 * call-seq:
8888 * putc(int) -> int
8889 *
8890 * Equivalent to:
8891 *
8892 * $stdout.putc(int)
8893 *
8894 * See IO#putc for important information regarding multi-byte characters.
8895 *
8896 */
8897
8898static VALUE
8899rb_f_putc(VALUE recv, VALUE ch)
8900{
8901 VALUE r_stdout = rb_ractor_stdout();
8902 if (recv == r_stdout) {
8903 return rb_io_putc(recv, ch);
8904 }
8905 return forward(r_stdout, rb_intern("putc"), 1, &ch);
8906}
8907
8908
8909int
8910rb_str_end_with_asciichar(VALUE str, int c)
8911{
8912 long len = RSTRING_LEN(str);
8913 const char *ptr = RSTRING_PTR(str);
8914 rb_encoding *enc = rb_enc_from_index(ENCODING_GET(str));
8915 int n;
8916
8917 if (len == 0) return 0;
8918 if ((n = rb_enc_mbminlen(enc)) == 1) {
8919 return ptr[len - 1] == c;
8920 }
8921 return rb_enc_ascget(ptr + ((len - 1) / n) * n, ptr + len, &n, enc) == c;
8922}
8923
8924static VALUE
8925io_puts_ary(VALUE ary, VALUE out, int recur)
8926{
8927 VALUE tmp;
8928 long i;
8929
8930 if (recur) {
8931 tmp = rb_str_new2("[...]");
8932 rb_io_puts(1, &tmp, out);
8933 return Qtrue;
8934 }
8935 ary = rb_check_array_type(ary);
8936 if (NIL_P(ary)) return Qfalse;
8937 for (i=0; i<RARRAY_LEN(ary); i++) {
8938 tmp = RARRAY_AREF(ary, i);
8939 rb_io_puts(1, &tmp, out);
8940 }
8941 return Qtrue;
8942}
8943
8944/*
8945 * call-seq:
8946 * puts(*objects) -> nil
8947 *
8948 * Writes the given +objects+ to the stream, which must be open for writing;
8949 * returns +nil+.\
8950 * Writes a newline after each that does not already end with a newline sequence.
8951 * If called without arguments, writes a newline.
8952 * See {Line IO}[rdoc-ref:IO@Line+IO].
8953 *
8954 * Note that each added newline is the character <tt>"\n"<//tt>,
8955 * not the output record separator (<tt>$\</tt>).
8956 *
8957 * Treatment for each object:
8958 *
8959 * - String: writes the string.
8960 * - Neither string nor array: writes <tt>object.to_s</tt>.
8961 * - Array: writes each element of the array; arrays may be nested.
8962 *
8963 * To keep these examples brief, we define this helper method:
8964 *
8965 * def show(*objects)
8966 * # Puts objects to file.
8967 * f = File.new('t.tmp', 'w+')
8968 * f.puts(objects)
8969 * # Return file content.
8970 * f.rewind
8971 * p f.read
8972 * f.close
8973 * end
8974 *
8975 * # Strings without newlines.
8976 * show('foo', 'bar', 'baz') # => "foo\nbar\nbaz\n"
8977 * # Strings, some with newlines.
8978 * show("foo\n", 'bar', "baz\n") # => "foo\nbar\nbaz\n"
8979 *
8980 * # Neither strings nor arrays:
8981 * show(0, 0.0, Rational(0, 1), Complex(9, 0), :zero)
8982 * # => "0\n0.0\n0/1\n9+0i\nzero\n"
8983 *
8984 * # Array of strings.
8985 * show(['foo', "bar\n", 'baz']) # => "foo\nbar\nbaz\n"
8986 * # Nested arrays.
8987 * show([[[0, 1], 2, 3], 4, 5]) # => "0\n1\n2\n3\n4\n5\n"
8988 *
8989 */
8990
8991VALUE
8992rb_io_puts(int argc, const VALUE *argv, VALUE out)
8993{
8994 VALUE line, args[2];
8995
8996 /* if no argument given, print newline. */
8997 if (argc == 0) {
8998 rb_io_write(out, rb_default_rs);
8999 return Qnil;
9000 }
9001 for (int i = 0; i < argc; i++) {
9002 // Convert the argument to a string:
9003 if (RB_TYPE_P(argv[i], T_STRING)) {
9004 line = argv[i];
9005 }
9006 else if (rb_exec_recursive(io_puts_ary, argv[i], out)) {
9007 continue;
9008 }
9009 else {
9010 line = rb_obj_as_string(argv[i]);
9011 }
9012
9013 // Write the line:
9014 int n = 0;
9015 if (RSTRING_LEN(line) == 0) {
9016 args[n++] = rb_default_rs;
9017 }
9018 else {
9019 args[n++] = line;
9020 if (!rb_str_end_with_asciichar(line, '\n')) {
9021 args[n++] = rb_default_rs;
9022 }
9023 }
9024
9025 rb_io_writev(out, n, args);
9026 }
9027
9028 return Qnil;
9029}
9030
9031/*
9032 * call-seq:
9033 * puts(*objects) -> nil
9034 *
9035 * Equivalent to
9036 *
9037 * $stdout.puts(objects)
9038 */
9039
9040static VALUE
9041rb_f_puts(int argc, VALUE *argv, VALUE recv)
9042{
9043 VALUE r_stdout = rb_ractor_stdout();
9044 if (recv == r_stdout) {
9045 return rb_io_puts(argc, argv, recv);
9046 }
9047 return forward(r_stdout, rb_intern("puts"), argc, argv);
9048}
9049
9050static VALUE
9051rb_p_write(VALUE str)
9052{
9053 VALUE args[2];
9054 args[0] = str;
9055 args[1] = rb_default_rs;
9056 VALUE r_stdout = rb_ractor_stdout();
9057 if (RB_TYPE_P(r_stdout, T_FILE) &&
9058 rb_method_basic_definition_p(CLASS_OF(r_stdout), id_write)) {
9059 io_writev(2, args, r_stdout);
9060 }
9061 else {
9062 rb_io_writev(r_stdout, 2, args);
9063 }
9064 return Qnil;
9065}
9066
9067void
9068rb_p(VALUE obj) /* for debug print within C code */
9069{
9070 rb_p_write(rb_obj_as_string(rb_inspect(obj)));
9071}
9072
9073static VALUE
9074rb_p_result(int argc, const VALUE *argv)
9075{
9076 VALUE ret = Qnil;
9077
9078 if (argc == 1) {
9079 ret = argv[0];
9080 }
9081 else if (argc > 1) {
9082 ret = rb_ary_new4(argc, argv);
9083 }
9084 VALUE r_stdout = rb_ractor_stdout();
9085 if (RB_TYPE_P(r_stdout, T_FILE)) {
9086 rb_uninterruptible(rb_io_flush, r_stdout);
9087 }
9088 return ret;
9089}
9090
9091/*
9092 * call-seq:
9093 * p(object) -> obj
9094 * p(*objects) -> array of objects
9095 * p -> nil
9096 *
9097 * For each object +obj+, executes:
9098 *
9099 * $stdout.write(obj.inspect, "\n")
9100 *
9101 * With one object given, returns the object;
9102 * with multiple objects given, returns an array containing the objects;
9103 * with no object given, returns +nil+.
9104 *
9105 * Examples:
9106 *
9107 * r = Range.new(0, 4)
9108 * p r # => 0..4
9109 * p [r, r, r] # => [0..4, 0..4, 0..4]
9110 * p # => nil
9111 *
9112 * Output:
9113 *
9114 * 0..4
9115 * [0..4, 0..4, 0..4]
9116 *
9117 * Kernel#p is designed for debugging purposes.
9118 * Ruby implementations may define Kernel#p to be uninterruptible
9119 * in whole or in part.
9120 * On CRuby, Kernel#p's writing of data is uninterruptible.
9121 */
9122
9123static VALUE
9124rb_f_p(int argc, VALUE *argv, VALUE self)
9125{
9126 int i;
9127 for (i=0; i<argc; i++) {
9128 VALUE inspected = rb_obj_as_string(rb_inspect(argv[i]));
9129 rb_uninterruptible(rb_p_write, inspected);
9130 }
9131 return rb_p_result(argc, argv);
9132}
9133
9134/*
9135 * call-seq:
9136 * display(port = $>) -> nil
9137 *
9138 * Writes +self+ on the given port:
9139 *
9140 * 1.display
9141 * "cat".display
9142 * [ 4, 5, 6 ].display
9143 * puts
9144 *
9145 * Output:
9146 *
9147 * 1cat[4, 5, 6]
9148 *
9149 */
9150
9151static VALUE
9152rb_obj_display(int argc, VALUE *argv, VALUE self)
9153{
9154 VALUE out;
9155
9156 out = (!rb_check_arity(argc, 0, 1) ? rb_ractor_stdout() : argv[0]);
9157 rb_io_write(out, self);
9158
9159 return Qnil;
9160}
9161
9162static int
9163rb_stderr_to_original_p(VALUE err)
9164{
9165 return (err == orig_stderr || RFILE(orig_stderr)->fptr->fd < 0);
9166}
9167
9168void
9169rb_write_error2(const char *mesg, long len)
9170{
9171 VALUE out = rb_ractor_stderr();
9172 if (rb_stderr_to_original_p(out)) {
9173#ifdef _WIN32
9174 if (isatty(fileno(stderr))) {
9175 if (rb_w32_write_console(rb_str_new(mesg, len), fileno(stderr)) > 0) return;
9176 }
9177#endif
9178 if (fwrite(mesg, sizeof(char), (size_t)len, stderr) < (size_t)len) {
9179 /* failed to write to stderr, what can we do? */
9180 return;
9181 }
9182 }
9183 else {
9184 rb_io_write(out, rb_str_new(mesg, len));
9185 }
9186}
9187
9188void
9189rb_write_error(const char *mesg)
9190{
9191 rb_write_error2(mesg, strlen(mesg));
9192}
9193
9194void
9195rb_write_error_str(VALUE mesg)
9196{
9197 VALUE out = rb_ractor_stderr();
9198 /* a stopgap measure for the time being */
9199 if (rb_stderr_to_original_p(out)) {
9200 size_t len = (size_t)RSTRING_LEN(mesg);
9201#ifdef _WIN32
9202 if (isatty(fileno(stderr))) {
9203 if (rb_w32_write_console(mesg, fileno(stderr)) > 0) return;
9204 }
9205#endif
9206 if (fwrite(RSTRING_PTR(mesg), sizeof(char), len, stderr) < len) {
9207 RB_GC_GUARD(mesg);
9208 return;
9209 }
9210 }
9211 else {
9212 /* may unlock GVL, and */
9213 rb_io_write(out, mesg);
9214 }
9215}
9216
9217int
9218rb_stderr_tty_p(void)
9219{
9220 if (rb_stderr_to_original_p(rb_ractor_stderr()))
9221 return isatty(fileno(stderr));
9222 return 0;
9223}
9224
9225static void
9226must_respond_to(ID mid, VALUE val, ID id)
9227{
9228 if (!rb_respond_to(val, mid)) {
9229 rb_raise(rb_eTypeError, "%"PRIsVALUE" must have %"PRIsVALUE" method, %"PRIsVALUE" given",
9230 rb_id2str(id), rb_id2str(mid),
9231 rb_obj_class(val));
9232 }
9233}
9234
9235static void
9236stdin_setter(VALUE val, ID id, VALUE *ptr)
9237{
9239}
9240
9241static VALUE
9242stdin_getter(ID id, VALUE *ptr)
9243{
9244 return rb_ractor_stdin();
9245}
9246
9247static void
9248stdout_setter(VALUE val, ID id, VALUE *ptr)
9249{
9250 must_respond_to(id_write, val, id);
9252}
9253
9254static VALUE
9255stdout_getter(ID id, VALUE *ptr)
9256{
9257 return rb_ractor_stdout();
9258}
9259
9260static void
9261stderr_setter(VALUE val, ID id, VALUE *ptr)
9262{
9263 must_respond_to(id_write, val, id);
9265}
9266
9267static VALUE
9268stderr_getter(ID id, VALUE *ptr)
9269{
9270 return rb_ractor_stderr();
9271}
9272
9273static VALUE
9274allocate_and_open_new_file(VALUE klass)
9275{
9276 VALUE self = io_alloc(klass);
9277 rb_io_make_open_file(self);
9278 return self;
9279}
9280
9281VALUE
9282rb_io_open_descriptor(VALUE klass, int descriptor, int mode, VALUE path, VALUE timeout, struct rb_io_encoding *encoding)
9283{
9284 int state;
9285 VALUE self = rb_protect(allocate_and_open_new_file, klass, &state);
9286 if (state) {
9287 /* if we raised an exception allocating an IO object, but the caller
9288 intended to transfer ownership of this FD to us, close the fd before
9289 raising the exception. Otherwise, we would leak a FD - the caller
9290 expects GC to close the file, but we never got around to assigning
9291 it to a rb_io. */
9292 if (!(mode & FMODE_EXTERNAL)) {
9293 maygvl_close(descriptor, 0);
9294 }
9295 rb_jump_tag(state);
9296 }
9297
9298
9299 rb_io_t *io = RFILE(self)->fptr;
9300 io->self = self;
9301 io->fd = descriptor;
9302 io->mode = mode;
9303
9304 /* At this point, Ruby fully owns the descriptor, and will close it when
9305 the IO gets GC'd (unless FMODE_EXTERNAL was set), no matter what happens
9306 in the rest of this method. */
9307
9308 if (NIL_P(path)) {
9309 io->pathv = Qnil;
9310 }
9311 else {
9312 StringValue(path);
9313 io->pathv = rb_str_new_frozen(path);
9314 }
9315
9316 io->timeout = timeout;
9317
9318 ccan_list_head_init(&io->blocking_operations);
9319 io->closing_ec = NULL;
9320 io->wakeup_mutex = Qnil;
9321 io->fork_generation = GET_VM()->fork_gen;
9322
9323 if (encoding) {
9324 io->encs = *encoding;
9325 }
9326
9327 rb_update_max_fd(descriptor);
9328
9329 return self;
9330}
9331
9332static VALUE
9333prep_io(int fd, enum rb_io_mode fmode, VALUE klass, const char *path)
9334{
9335 VALUE path_value = Qnil;
9336 rb_encoding *e;
9337 struct rb_io_encoding convconfig;
9338
9339 if (path) {
9340 path_value = rb_obj_freeze(rb_str_new_cstr(path));
9341 }
9342
9343 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
9344 rb_io_ext_int_to_encs(e, NULL, &convconfig.enc, &convconfig.enc2, fmode);
9345 convconfig.ecflags = (fmode & FMODE_READABLE) ?
9348#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9349 convconfig.ecflags |= (fmode & FMODE_WRITABLE) ?
9350 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
9351 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
9352#endif
9353 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.enc2, convconfig.ecflags);
9354 convconfig.ecopts = Qnil;
9355
9356 VALUE self = rb_io_open_descriptor(klass, fd, fmode, path_value, Qnil, &convconfig);
9357 rb_io_t*io = RFILE(self)->fptr;
9358
9359 if (!io_check_tty(io)) {
9360#ifdef __CYGWIN__
9361 io->mode |= FMODE_BINMODE;
9362 setmode(fd, O_BINARY);
9363#endif
9364 }
9365
9366 return self;
9367}
9368
9369VALUE
9370rb_io_fdopen(int fd, int oflags, const char *path)
9371{
9372 VALUE klass = rb_cIO;
9373
9374 if (path && strcmp(path, "-")) klass = rb_cFile;
9375 return prep_io(fd, rb_io_oflags_fmode(oflags), klass, path);
9376}
9377
9378static VALUE
9379prep_stdio(FILE *f, enum rb_io_mode fmode, VALUE klass, const char *path)
9380{
9381 rb_io_t *fptr;
9382 VALUE io = prep_io(fileno(f), fmode|FMODE_EXTERNAL|DEFAULT_TEXTMODE, klass, path);
9383
9384 GetOpenFile(io, fptr);
9386#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9387 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
9388 if (fmode & FMODE_READABLE) {
9390 }
9391#endif
9392 fptr->stdio_file = f;
9393
9394 return io;
9395}
9396
9397VALUE
9398rb_io_prep_stdin(void)
9399{
9400 return prep_stdio(stdin, FMODE_READABLE, rb_cIO, "<STDIN>");
9401}
9402
9403VALUE
9404rb_io_prep_stdout(void)
9405{
9406 return prep_stdio(stdout, FMODE_WRITABLE|FMODE_SIGNAL_ON_EPIPE, rb_cIO, "<STDOUT>");
9407}
9408
9409VALUE
9410rb_io_prep_stderr(void)
9411{
9412 return prep_stdio(stderr, FMODE_WRITABLE|FMODE_SYNC, rb_cIO, "<STDERR>");
9413}
9414
9415FILE *
9417{
9418 if (!fptr->stdio_file) {
9419 int oflags = rb_io_fmode_oflags(fptr->mode) & ~O_EXCL;
9420 fptr->stdio_file = rb_fdopen(fptr->fd, rb_io_oflags_modestr(oflags));
9421 }
9422 return fptr->stdio_file;
9423}
9424
9425static inline void
9426rb_io_buffer_init(struct rb_io_internal_buffer *buf)
9427{
9428 buf->ptr = NULL;
9429 buf->off = 0;
9430 buf->len = 0;
9431 buf->capa = 0;
9432}
9433
9434static inline rb_io_t *
9435rb_io_fptr_new(void)
9436{
9437 rb_io_t *fp = ALLOC(rb_io_t);
9438 fp->self = Qnil;
9439 fp->fd = -1;
9440 fp->stdio_file = NULL;
9441 fp->mode = 0;
9442 fp->pid = 0;
9443 fp->lineno = 0;
9444 fp->pathv = Qnil;
9445 fp->finalize = 0;
9446 rb_io_buffer_init(&fp->wbuf);
9447 rb_io_buffer_init(&fp->rbuf);
9448 rb_io_buffer_init(&fp->cbuf);
9449 fp->readconv = NULL;
9450 fp->writeconv = NULL;
9452 fp->writeconv_pre_ecflags = 0;
9454 fp->writeconv_initialized = 0;
9455 fp->tied_io_for_writing = 0;
9456 fp->encs.enc = NULL;
9457 fp->encs.enc2 = NULL;
9458 fp->encs.ecflags = 0;
9459 fp->encs.ecopts = Qnil;
9460 fp->write_lock = Qnil;
9461 fp->timeout = Qnil;
9462 ccan_list_head_init(&fp->blocking_operations);
9463 fp->closing_ec = NULL;
9464 fp->wakeup_mutex = Qnil;
9465 fp->fork_generation = GET_VM()->fork_gen;
9466 return fp;
9467}
9468
9469rb_io_t *
9470rb_io_make_open_file(VALUE obj)
9471{
9472 rb_io_t *fp = 0;
9473
9474 Check_Type(obj, T_FILE);
9475 if (RFILE(obj)->fptr) {
9476 rb_io_close(obj);
9477 rb_io_fptr_finalize(RFILE(obj)->fptr);
9478 RFILE(obj)->fptr = 0;
9479 }
9480 fp = rb_io_fptr_new();
9481 fp->self = obj;
9482 RFILE(obj)->fptr = fp;
9483 return fp;
9484}
9485
9486static VALUE io_initialize(VALUE io, VALUE fnum, VALUE vmode, VALUE opt);
9487
9488/*
9489 * call-seq:
9490 * IO.new(fd, mode = 'r', **opts) -> io
9491 *
9492 * Creates and returns a new \IO object (file stream) from a file descriptor.
9493 *
9494 * \IO.new may be useful for interaction with low-level libraries.
9495 * For higher-level interactions, it may be simpler to create
9496 * the file stream using File.open.
9497 *
9498 * Argument +fd+ must be a valid file descriptor (integer):
9499 *
9500 * path = 't.tmp'
9501 * fd = IO.sysopen(path) # => 3
9502 * IO.new(fd) # => #<IO:fd 3>
9503 *
9504 * The new \IO object does not inherit encoding
9505 * (because the integer file descriptor does not have an encoding):
9506 *
9507 * fd = IO.sysopen('t.rus', 'rb')
9508 * io = IO.new(fd)
9509 * io.external_encoding # => #<Encoding:UTF-8> # Not ASCII-8BIT.
9510 *
9511 * Optional argument +mode+ (defaults to 'r') must specify a valid mode;
9512 * see {Access Modes}[rdoc-ref:File@Access+Modes]:
9513 *
9514 * IO.new(fd, 'w') # => #<IO:fd 3>
9515 * IO.new(fd, File::WRONLY) # => #<IO:fd 3>
9516 *
9517 * Optional keyword arguments +opts+ specify:
9518 *
9519 * - {Open Options}[rdoc-ref:IO@Open+Options].
9520 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
9521 *
9522 * Examples:
9523 *
9524 * IO.new(fd, internal_encoding: nil) # => #<IO:fd 3>
9525 * IO.new(fd, autoclose: true) # => #<IO:fd 3>
9526 *
9527 */
9528
9529static VALUE
9530rb_io_initialize(int argc, VALUE *argv, VALUE io)
9531{
9532 VALUE fnum, vmode;
9533 VALUE opt;
9534
9535 rb_scan_args(argc, argv, "11:", &fnum, &vmode, &opt);
9536 return io_initialize(io, fnum, vmode, opt);
9537}
9538
9539static VALUE
9540io_initialize(VALUE io, VALUE fnum, VALUE vmode, VALUE opt)
9541{
9542 rb_io_t *fp;
9543 int fd, oflags = O_RDONLY;
9544 enum rb_io_mode fmode;
9545 struct rb_io_encoding convconfig;
9546#if defined(HAVE_FCNTL) && defined(F_GETFL)
9547 int ofmode;
9548#else
9549 struct stat st;
9550#endif
9551
9552 rb_io_extract_modeenc(&vmode, 0, opt, &oflags, &fmode, &convconfig);
9553
9554 fd = NUM2INT(fnum);
9555 if (rb_reserved_fd_p(fd)) {
9556 rb_raise(rb_eArgError, "The given fd is not accessible because RubyVM reserves it");
9557 }
9558#if defined(HAVE_FCNTL) && defined(F_GETFL)
9559 oflags = fcntl(fd, F_GETFL);
9560 if (oflags == -1) rb_sys_fail(0);
9561#else
9562 if (fstat(fd, &st) < 0) rb_sys_fail(0);
9563#endif
9564 rb_update_max_fd(fd);
9565#if defined(HAVE_FCNTL) && defined(F_GETFL)
9566 ofmode = rb_io_oflags_fmode(oflags);
9567 if (NIL_P(vmode)) {
9568 fmode = ofmode;
9569 }
9570 else if ((~ofmode & fmode) & FMODE_READWRITE) {
9571 VALUE error = INT2FIX(EINVAL);
9573 }
9574#endif
9575 VALUE path = Qnil;
9576
9577 if (!NIL_P(opt)) {
9578 if (rb_hash_aref(opt, sym_autoclose) == Qfalse) {
9579 fmode |= FMODE_EXTERNAL;
9580 }
9581
9582 path = rb_hash_aref(opt, RB_ID2SYM(idPath));
9583 if (!NIL_P(path)) {
9584 StringValue(path);
9585 path = rb_str_new_frozen(path);
9586 }
9587 }
9588
9589 MakeOpenFile(io, fp);
9590 fp->self = io;
9591 fp->fd = fd;
9592 fp->mode = fmode;
9593 fp->encs = convconfig;
9594 fp->pathv = path;
9595 fp->timeout = Qnil;
9596 ccan_list_head_init(&fp->blocking_operations);
9597 fp->closing_ec = NULL;
9598 fp->wakeup_mutex = Qnil;
9599 fp->fork_generation = GET_VM()->fork_gen;
9600 clear_codeconv(fp);
9601 io_check_tty(fp);
9602 if (fileno(stdin) == fd)
9603 fp->stdio_file = stdin;
9604 else if (fileno(stdout) == fd)
9605 fp->stdio_file = stdout;
9606 else if (fileno(stderr) == fd)
9607 fp->stdio_file = stderr;
9608
9609 if (fmode & FMODE_SETENC_BY_BOM) io_set_encoding_by_bom(io);
9610 return io;
9611}
9612
9613/*
9614 * call-seq:
9615 * set_encoding_by_bom -> encoding or nil
9616 *
9617 * If the stream begins with a BOM
9618 * ({byte order marker}[https://en.wikipedia.org/wiki/Byte_order_mark]),
9619 * consumes the BOM and sets the external encoding accordingly;
9620 * returns the result encoding if found, or +nil+ otherwise:
9621 *
9622 * File.write('t.tmp', "\u{FEFF}abc")
9623 * io = File.open('t.tmp', 'rb')
9624 * io.set_encoding_by_bom # => #<Encoding:UTF-8>
9625 * io.close
9626 *
9627 * File.write('t.tmp', 'abc')
9628 * io = File.open('t.tmp', 'rb')
9629 * io.set_encoding_by_bom # => nil
9630 * io.close
9631 *
9632 * Raises an exception if the stream is not binmode
9633 * or its encoding has already been set.
9634 *
9635 */
9636
9637static VALUE
9638rb_io_set_encoding_by_bom(VALUE io)
9639{
9640 rb_io_t *fptr;
9641
9642 GetOpenFile(io, fptr);
9643 if (!(fptr->mode & FMODE_BINMODE)) {
9644 rb_raise(rb_eArgError, "ASCII incompatible encoding needs binmode");
9645 }
9646 if (fptr->encs.enc2) {
9647 rb_raise(rb_eArgError, "encoding conversion is set");
9648 }
9649 else if (fptr->encs.enc && fptr->encs.enc != rb_ascii8bit_encoding()) {
9650 rb_raise(rb_eArgError, "encoding is set to %s already",
9651 rb_enc_name(fptr->encs.enc));
9652 }
9653 if (!io_set_encoding_by_bom(io)) return Qnil;
9654 return rb_enc_from_encoding(fptr->encs.enc);
9655}
9656
9657/*
9658 * call-seq:
9659 * File.new(path, mode = 'r', perm = 0666, **opts) -> file
9660 *
9661 * Opens the file at the given +path+ according to the given +mode+;
9662 * creates and returns a new File object for that file.
9663 *
9664 * The new File object is buffered mode (or non-sync mode), unless
9665 * +filename+ is a tty.
9666 * See IO#flush, IO#fsync, IO#fdatasync, and IO#sync=.
9667 *
9668 * Argument +path+ must be a valid file path:
9669 *
9670 * f = File.new('/etc/fstab')
9671 * f.close
9672 * f = File.new('t.txt')
9673 * f.close
9674 *
9675 * Optional argument +mode+ (defaults to 'r') must specify a valid mode;
9676 * see {Access Modes}[rdoc-ref:File@Access+Modes]:
9677 *
9678 * f = File.new('t.tmp', 'w')
9679 * f.close
9680 * f = File.new('t.tmp', File::RDONLY)
9681 * f.close
9682 *
9683 * Optional argument +perm+ (defaults to 0666) must specify valid permissions
9684 * see {File Permissions}[rdoc-ref:File@File+Permissions]:
9685 *
9686 * f = File.new('t.tmp', File::CREAT, 0644)
9687 * f.close
9688 * f = File.new('t.tmp', File::CREAT, 0444)
9689 * f.close
9690 *
9691 * Optional keyword arguments +opts+ specify:
9692 *
9693 * - {Open Options}[rdoc-ref:IO@Open+Options].
9694 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
9695 *
9696 */
9697
9698static VALUE
9699rb_file_initialize(int argc, VALUE *argv, VALUE io)
9700{
9701 if (RFILE(io)->fptr) {
9702 rb_raise(rb_eRuntimeError, "reinitializing File");
9703 }
9704 VALUE fname, vmode, vperm, opt;
9705 int posargc = rb_scan_args(argc, argv, "12:", &fname, &vmode, &vperm, &opt);
9706 if (posargc < 3) { /* perm is File only */
9707 VALUE fd = rb_check_to_int(fname);
9708
9709 if (!NIL_P(fd)) {
9710 return io_initialize(io, fd, vmode, opt);
9711 }
9712 }
9713 return rb_open_file(io, fname, vmode, vperm, opt);
9714}
9715
9716/* :nodoc: */
9717static VALUE
9718rb_io_s_new(int argc, VALUE *argv, VALUE klass)
9719{
9720 if (rb_block_given_p()) {
9721 VALUE cname = rb_obj_as_string(klass);
9722
9723 rb_warn("%"PRIsVALUE"::new() does not take block; use %"PRIsVALUE"::open() instead",
9724 cname, cname);
9725 }
9726 return rb_class_new_instance_kw(argc, argv, klass, RB_PASS_CALLED_KEYWORDS);
9727}
9728
9729
9730/*
9731 * call-seq:
9732 * IO.for_fd(fd, mode = 'r', **opts) -> io
9733 *
9734 * Synonym for IO.new.
9735 *
9736 */
9737
9738static VALUE
9739rb_io_s_for_fd(int argc, VALUE *argv, VALUE klass)
9740{
9741 VALUE io = rb_obj_alloc(klass);
9742 rb_io_initialize(argc, argv, io);
9743 return io;
9744}
9745
9746/*
9747 * call-seq:
9748 * ios.autoclose? -> true or false
9749 *
9750 * Returns +true+ if the underlying file descriptor of _ios_ will be
9751 * closed at its finalization or at calling #close, otherwise +false+.
9752 */
9753
9754static VALUE
9755rb_io_autoclose_p(VALUE io)
9756{
9757 rb_io_t *fptr = RFILE(io)->fptr;
9758 rb_io_check_closed(fptr);
9759 return RBOOL(!(fptr->mode & FMODE_EXTERNAL));
9760}
9761
9762/*
9763 * call-seq:
9764 * io.autoclose = bool -> true or false
9765 *
9766 * Sets auto-close flag.
9767 *
9768 * f = File.open(File::NULL)
9769 * IO.for_fd(f.fileno).close
9770 * f.gets # raises Errno::EBADF
9771 *
9772 * f = File.open(File::NULL)
9773 * g = IO.for_fd(f.fileno)
9774 * g.autoclose = false
9775 * g.close
9776 * f.gets # won't cause Errno::EBADF
9777 */
9778
9779static VALUE
9780rb_io_set_autoclose(VALUE io, VALUE autoclose)
9781{
9782 rb_io_t *fptr;
9783 GetOpenFile(io, fptr);
9784 if (!RTEST(autoclose))
9785 fptr->mode |= FMODE_EXTERNAL;
9786 else
9787 fptr->mode &= ~FMODE_EXTERNAL;
9788 return autoclose;
9789}
9790
9791static VALUE
9792io_wait_event(VALUE io, int event, VALUE timeout, int return_io)
9793{
9794 VALUE result = rb_io_wait(io, RB_INT2NUM(event), timeout);
9795
9796 if (!RB_TEST(result)) {
9797 return Qnil;
9798 }
9799
9800 int mask = RB_NUM2INT(result);
9801
9802 if (mask & event) {
9803 if (return_io)
9804 return io;
9805 else
9806 return result;
9807 }
9808 else {
9809 return Qfalse;
9810 }
9811}
9812
9813/*
9814 * call-seq:
9815 * io.wait_readable -> truthy or falsy
9816 * io.wait_readable(timeout) -> truthy or falsy
9817 *
9818 * Waits until IO is readable and returns a truthy value, or a falsy
9819 * value when times out. Returns a truthy value immediately when
9820 * buffered data is available.
9821 */
9822
9823static VALUE
9824io_wait_readable(int argc, VALUE *argv, VALUE io)
9825{
9826 rb_io_t *fptr;
9827
9828 RB_IO_POINTER(io, fptr);
9830
9831 if (rb_io_read_pending(fptr)) return Qtrue;
9832
9833 rb_check_arity(argc, 0, 1);
9834 VALUE timeout = (argc == 1 ? argv[0] : Qnil);
9835
9836 return io_wait_event(io, RUBY_IO_READABLE, timeout, 1);
9837}
9838
9839/*
9840 * call-seq:
9841 * io.wait_writable -> truthy or falsy
9842 * io.wait_writable(timeout) -> truthy or falsy
9843 *
9844 * Waits until IO is writable and returns a truthy value or a falsy
9845 * value when times out.
9846 */
9847static VALUE
9848io_wait_writable(int argc, VALUE *argv, VALUE io)
9849{
9850 rb_io_t *fptr;
9851
9852 RB_IO_POINTER(io, fptr);
9854
9855 rb_check_arity(argc, 0, 1);
9856 VALUE timeout = (argc == 1 ? argv[0] : Qnil);
9857
9858 return io_wait_event(io, RUBY_IO_WRITABLE, timeout, 1);
9859}
9860
9861/*
9862 * call-seq:
9863 * io.wait_priority -> truthy or falsy
9864 * io.wait_priority(timeout) -> truthy or falsy
9865 *
9866 * Waits until IO is priority and returns a truthy value or a falsy
9867 * value when times out. Priority data is sent and received using
9868 * the Socket::MSG_OOB flag and is typically limited to streams.
9869 */
9870static VALUE
9871io_wait_priority(int argc, VALUE *argv, VALUE io)
9872{
9873 rb_io_t *fptr = NULL;
9874
9875 RB_IO_POINTER(io, fptr);
9877
9878 if (rb_io_read_pending(fptr)) return Qtrue;
9879
9880 rb_check_arity(argc, 0, 1);
9881 VALUE timeout = argc == 1 ? argv[0] : Qnil;
9882
9883 return io_wait_event(io, RUBY_IO_PRIORITY, timeout, 1);
9884}
9885
9886static int
9887wait_mode_sym(VALUE mode)
9888{
9889 if (mode == ID2SYM(rb_intern("r"))) {
9890 return RB_WAITFD_IN;
9891 }
9892 if (mode == ID2SYM(rb_intern("read"))) {
9893 return RB_WAITFD_IN;
9894 }
9895 if (mode == ID2SYM(rb_intern("readable"))) {
9896 return RB_WAITFD_IN;
9897 }
9898 if (mode == ID2SYM(rb_intern("w"))) {
9899 return RB_WAITFD_OUT;
9900 }
9901 if (mode == ID2SYM(rb_intern("write"))) {
9902 return RB_WAITFD_OUT;
9903 }
9904 if (mode == ID2SYM(rb_intern("writable"))) {
9905 return RB_WAITFD_OUT;
9906 }
9907 if (mode == ID2SYM(rb_intern("rw"))) {
9908 return RB_WAITFD_IN|RB_WAITFD_OUT;
9909 }
9910 if (mode == ID2SYM(rb_intern("read_write"))) {
9911 return RB_WAITFD_IN|RB_WAITFD_OUT;
9912 }
9913 if (mode == ID2SYM(rb_intern("readable_writable"))) {
9914 return RB_WAITFD_IN|RB_WAITFD_OUT;
9915 }
9916
9917 rb_raise(rb_eArgError, "unsupported mode: %"PRIsVALUE, mode);
9918}
9919
9920static inline enum rb_io_event
9921io_event_from_value(VALUE value)
9922{
9923 int events = RB_NUM2INT(value);
9924
9925 if (events <= 0) rb_raise(rb_eArgError, "Events must be positive integer!");
9926
9927 return events;
9928}
9929
9930/*
9931 * call-seq:
9932 * io.wait(events, timeout) -> event mask, false or nil
9933 * io.wait(*event_symbols[, timeout]) -> self, true, or false
9934 *
9935 * Waits until the IO becomes ready for the specified events and returns the
9936 * subset of events that become ready, or a falsy value when times out.
9937 *
9938 * The events can be a bit mask of +IO::READABLE+, +IO::WRITABLE+ or
9939 * +IO::PRIORITY+.
9940 *
9941 * Returns an event mask (truthy value) immediately when buffered data is
9942 * available.
9943 *
9944 * The second form: if one or more event symbols (+:read+, +:write+, or
9945 * +:read_write+) are passed, the event mask is the bit OR of the bitmask
9946 * corresponding to those symbols. In this form, +timeout+ is optional, the
9947 * order of the arguments is arbitrary, and returns +io+ if any of the
9948 * events is ready.
9949 */
9950
9951static VALUE
9952io_wait(int argc, VALUE *argv, VALUE io)
9953{
9954 VALUE timeout = Qundef;
9955 enum rb_io_event events = 0;
9956 int return_io = 0;
9957
9958 if (argc != 2 || (RB_SYMBOL_P(argv[0]) || RB_SYMBOL_P(argv[1]))) {
9959 // We'd prefer to return the actual mask, but this form would return the io itself:
9960 return_io = 1;
9961
9962 // Slow/messy path:
9963 for (int i = 0; i < argc; i += 1) {
9964 if (RB_SYMBOL_P(argv[i])) {
9965 events |= wait_mode_sym(argv[i]);
9966 }
9967 else if (UNDEF_P(timeout)) {
9968 rb_time_interval(timeout = argv[i]);
9969 }
9970 else {
9971 rb_raise(rb_eArgError, "timeout given more than once");
9972 }
9973 }
9974
9975 if (UNDEF_P(timeout)) timeout = Qnil;
9976
9977 if (events == 0) {
9978 events = RUBY_IO_READABLE;
9979 }
9980 }
9981 else /* argc == 2 and neither are symbols */ {
9982 // This is the fast path:
9983 events = io_event_from_value(argv[0]);
9984 timeout = argv[1];
9985 }
9986
9987 if (events & RUBY_IO_READABLE) {
9988 rb_io_t *fptr = NULL;
9989 RB_IO_POINTER(io, fptr);
9990
9991 if (rb_io_read_pending(fptr)) {
9992 // This was the original behaviour:
9993 if (return_io) return Qtrue;
9994 // New behaviour always returns an event mask:
9995 else return RB_INT2NUM(RUBY_IO_READABLE);
9996 }
9997 }
9998
9999 return io_wait_event(io, events, timeout, return_io);
10000}
10001
10002static void
10003argf_mark_and_move(void *ptr)
10004{
10005 struct argf *p = ptr;
10006 rb_gc_mark_and_move(&p->filename);
10007 rb_gc_mark_and_move(&p->current_file);
10008 rb_gc_mark_and_move(&p->argv);
10009 rb_gc_mark_and_move(&p->inplace);
10010 rb_gc_mark_and_move(&p->encs.ecopts);
10011}
10012
10013static size_t
10014argf_memsize(const void *ptr)
10015{
10016 const struct argf *p = ptr;
10017 size_t size = sizeof(*p);
10018 return size;
10019}
10020
10021static const rb_data_type_t argf_type = {
10022 "ARGF",
10023 {argf_mark_and_move, RUBY_TYPED_DEFAULT_FREE, argf_memsize, argf_mark_and_move},
10024 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
10025};
10026
10027static inline void
10028argf_init(struct argf *p, VALUE v)
10029{
10030 p->filename = Qnil;
10031 p->current_file = Qnil;
10032 p->lineno = 0;
10033 p->argv = v;
10034}
10035
10036static VALUE
10037argf_alloc(VALUE klass)
10038{
10039 struct argf *p;
10040 VALUE argf = TypedData_Make_Struct(klass, struct argf, &argf_type, p);
10041
10042 argf_init(p, Qnil);
10043 return argf;
10044}
10045
10046#undef rb_argv
10047
10048/* :nodoc: */
10049static VALUE
10050argf_initialize(VALUE argf, VALUE argv)
10051{
10052 memset(&ARGF, 0, sizeof(ARGF));
10053 argf_init(&ARGF, argv);
10054
10055 return argf;
10056}
10057
10058/* :nodoc: */
10059static VALUE
10060argf_initialize_copy(VALUE argf, VALUE orig)
10061{
10062 if (!OBJ_INIT_COPY(argf, orig)) return argf;
10063 ARGF = argf_of(orig);
10064 ARGF.argv = rb_obj_dup(ARGF.argv);
10065 return argf;
10066}
10067
10068/*
10069 * call-seq:
10070 * ARGF.lineno = integer -> integer
10071 *
10072 * Sets the line number of ARGF as a whole to the given Integer.
10073 *
10074 * ARGF sets the line number automatically as you read data, so normally
10075 * you will not need to set it explicitly. To access the current line number
10076 * use ARGF.lineno.
10077 *
10078 * For example:
10079 *
10080 * ARGF.lineno #=> 0
10081 * ARGF.readline #=> "This is line 1\n"
10082 * ARGF.lineno #=> 1
10083 * ARGF.lineno = 0 #=> 0
10084 * ARGF.lineno #=> 0
10085 */
10086static VALUE
10087argf_set_lineno(VALUE argf, VALUE val)
10088{
10089 ARGF.lineno = NUM2INT(val);
10090 ARGF.last_lineno = ARGF.lineno;
10091 return val;
10092}
10093
10094/*
10095 * call-seq:
10096 * ARGF.lineno -> integer
10097 *
10098 * Returns the current line number of ARGF as a whole. This value
10099 * can be set manually with ARGF.lineno=.
10100 *
10101 * For example:
10102 *
10103 * ARGF.lineno #=> 0
10104 * ARGF.readline #=> "This is line 1\n"
10105 * ARGF.lineno #=> 1
10106 */
10107static VALUE
10108argf_lineno(VALUE argf)
10109{
10110 return INT2FIX(ARGF.lineno);
10111}
10112
10113static VALUE
10114argf_forward(int argc, VALUE *argv, VALUE argf)
10115{
10116 return forward_current(rb_frame_this_func(), argc, argv);
10117}
10118
10119#define next_argv() argf_next_argv(argf)
10120#define ARGF_GENERIC_INPUT_P() \
10121 (ARGF.current_file == rb_stdin && !RB_TYPE_P(ARGF.current_file, T_FILE))
10122#define ARGF_FORWARD(argc, argv) do {\
10123 if (ARGF_GENERIC_INPUT_P())\
10124 return argf_forward((argc), (argv), argf);\
10125} while (0)
10126#define NEXT_ARGF_FORWARD(argc, argv) do {\
10127 if (!next_argv()) return Qnil;\
10128 ARGF_FORWARD((argc), (argv));\
10129} while (0)
10130
10131static void
10132argf_close(VALUE argf)
10133{
10134 VALUE file = ARGF.current_file;
10135 if (file == rb_stdin) return;
10136 if (RB_TYPE_P(file, T_FILE)) {
10137 rb_io_set_write_io(file, Qnil);
10138 }
10139 io_close(file);
10140 ARGF.init_p = -1;
10141}
10142
10143static int
10144argf_next_argv(VALUE argf)
10145{
10146 char *fn;
10147 rb_io_t *fptr;
10148 int stdout_binmode = 0;
10149 enum rb_io_mode fmode;
10150
10151 VALUE r_stdout = rb_ractor_stdout();
10152
10153 if (RB_TYPE_P(r_stdout, T_FILE)) {
10154 GetOpenFile(r_stdout, fptr);
10155 if (fptr->mode & FMODE_BINMODE)
10156 stdout_binmode = 1;
10157 }
10158
10159 if (ARGF.init_p == 0) {
10160 if (!NIL_P(ARGF.argv) && RARRAY_LEN(ARGF.argv) > 0) {
10161 ARGF.next_p = 1;
10162 }
10163 else {
10164 ARGF.next_p = -1;
10165 }
10166 ARGF.init_p = 1;
10167 }
10168 else {
10169 if (NIL_P(ARGF.argv)) {
10170 ARGF.next_p = -1;
10171 }
10172 else if (ARGF.next_p == -1 && RARRAY_LEN(ARGF.argv) > 0) {
10173 ARGF.next_p = 1;
10174 }
10175 }
10176
10177 if (ARGF.next_p == 1) {
10178 if (ARGF.init_p == 1) argf_close(argf);
10179 retry:
10180 if (RARRAY_LEN(ARGF.argv) > 0) {
10181 VALUE filename = rb_ary_shift(ARGF.argv);
10182 FilePathValue(filename);
10183 ARGF.filename = filename;
10184 filename = rb_str_encode_ospath(filename);
10185 fn = StringValueCStr(filename);
10186 if (RSTRING_LEN(filename) == 1 && fn[0] == '-') {
10187 ARGF.current_file = rb_stdin;
10188 if (ARGF.inplace) {
10189 rb_warn("Can't do inplace edit for stdio; skipping");
10190 goto retry;
10191 }
10192 }
10193 else {
10194 VALUE write_io = Qnil;
10195 int fr = rb_sysopen(filename, O_RDONLY, 0);
10196
10197 if (ARGF.inplace) {
10198 struct stat st;
10199#ifndef NO_SAFE_RENAME
10200 struct stat st2;
10201#endif
10202 VALUE str;
10203 int fw;
10204
10205 if (RB_TYPE_P(r_stdout, T_FILE) && r_stdout != orig_stdout) {
10206 rb_io_close(r_stdout);
10207 }
10208 fstat(fr, &st);
10209 str = filename;
10210 if (!NIL_P(ARGF.inplace)) {
10211 VALUE suffix = ARGF.inplace;
10212 str = rb_str_dup(str);
10213 if (NIL_P(rb_str_cat_conv_enc_opts(str, RSTRING_LEN(str),
10214 RSTRING_PTR(suffix), RSTRING_LEN(suffix),
10215 rb_enc_get(suffix), 0, Qnil))) {
10216 rb_str_append(str, suffix);
10217 }
10218#ifdef NO_SAFE_RENAME
10219 (void)close(fr);
10220 (void)unlink(RSTRING_PTR(str));
10221 if (rename(fn, RSTRING_PTR(str)) < 0) {
10222 rb_warn("Can't rename %"PRIsVALUE" to %"PRIsVALUE": %s, skipping file",
10223 filename, str, strerror(errno));
10224 goto retry;
10225 }
10226 fr = rb_sysopen(str, O_RDONLY, 0);
10227#else
10228 if (rename(fn, RSTRING_PTR(str)) < 0) {
10229 rb_warn("Can't rename %"PRIsVALUE" to %"PRIsVALUE": %s, skipping file",
10230 filename, str, strerror(errno));
10231 close(fr);
10232 goto retry;
10233 }
10234#endif
10235 }
10236 else {
10237#ifdef NO_SAFE_RENAME
10238 rb_fatal("Can't do inplace edit without backup");
10239#else
10240 if (unlink(fn) < 0) {
10241 rb_warn("Can't remove %"PRIsVALUE": %s, skipping file",
10242 filename, strerror(errno));
10243 close(fr);
10244 goto retry;
10245 }
10246#endif
10247 }
10248 fw = rb_sysopen(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666);
10249#ifndef NO_SAFE_RENAME
10250 fstat(fw, &st2);
10251#ifdef HAVE_FCHMOD
10252 fchmod(fw, st.st_mode);
10253#else
10254 chmod(fn, st.st_mode);
10255#endif
10256 if (st.st_uid!=st2.st_uid || st.st_gid!=st2.st_gid) {
10257 int err;
10258#ifdef HAVE_FCHOWN
10259 err = fchown(fw, st.st_uid, st.st_gid);
10260#else
10261 err = chown(fn, st.st_uid, st.st_gid);
10262#endif
10263 if (err && getuid() == 0 && st2.st_uid == 0) {
10264 const char *wkfn = RSTRING_PTR(filename);
10265 rb_warn("Can't set owner/group of %"PRIsVALUE" to same as %"PRIsVALUE": %s, skipping file",
10266 filename, str, strerror(errno));
10267 (void)close(fr);
10268 (void)close(fw);
10269 (void)unlink(wkfn);
10270 goto retry;
10271 }
10272 }
10273#endif
10274 write_io = prep_io(fw, FMODE_WRITABLE, rb_cFile, fn);
10275 rb_ractor_stdout_set(write_io);
10276 if (stdout_binmode) rb_io_binmode(rb_stdout);
10277 }
10278 fmode = FMODE_READABLE;
10279 if (!ARGF.binmode) {
10280 fmode |= DEFAULT_TEXTMODE;
10281 }
10282 ARGF.current_file = prep_io(fr, fmode, rb_cFile, fn);
10283 if (!NIL_P(write_io)) {
10284 rb_io_set_write_io(ARGF.current_file, write_io);
10285 }
10286 RB_GC_GUARD(filename);
10287 }
10288 if (ARGF.binmode) rb_io_ascii8bit_binmode(ARGF.current_file);
10289 GetOpenFile(ARGF.current_file, fptr);
10290 if (ARGF.encs.enc) {
10291 fptr->encs = ARGF.encs;
10292 clear_codeconv(fptr);
10293 }
10294 else {
10295 fptr->encs.ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
10296 if (!ARGF.binmode) {
10298#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
10299 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
10300#endif
10301 }
10302 }
10303 ARGF.next_p = 0;
10304 }
10305 else {
10306 ARGF.next_p = 1;
10307 return FALSE;
10308 }
10309 }
10310 else if (ARGF.next_p == -1) {
10311 ARGF.current_file = rb_stdin;
10312 ARGF.filename = rb_str_new2("-");
10313 if (ARGF.inplace) {
10314 rb_warn("Can't do inplace edit for stdio");
10315 rb_ractor_stdout_set(orig_stdout);
10316 }
10317 }
10318 if (ARGF.init_p == -1) ARGF.init_p = 1;
10319 return TRUE;
10320}
10321
10322static VALUE
10323argf_getline(int argc, VALUE *argv, VALUE argf)
10324{
10325 VALUE line;
10326 long lineno = ARGF.lineno;
10327
10328 retry:
10329 if (!next_argv()) return Qnil;
10330 if (ARGF_GENERIC_INPUT_P()) {
10331 line = forward_current(idGets, argc, argv);
10332 }
10333 else {
10334 if (argc == 0 && rb_rs == rb_default_rs) {
10335 line = rb_io_gets(ARGF.current_file);
10336 }
10337 else {
10338 line = rb_io_getline(argc, argv, ARGF.current_file);
10339 }
10340 if (NIL_P(line) && ARGF.next_p != -1) {
10341 argf_close(argf);
10342 ARGF.next_p = 1;
10343 goto retry;
10344 }
10345 }
10346 if (!NIL_P(line)) {
10347 ARGF.lineno = ++lineno;
10348 ARGF.last_lineno = ARGF.lineno;
10349 }
10350 return line;
10351}
10352
10353static VALUE
10354argf_lineno_getter(ID id, VALUE *var)
10355{
10356 VALUE argf = *var;
10357 return INT2FIX(ARGF.last_lineno);
10358}
10359
10360static void
10361argf_lineno_setter(VALUE val, ID id, VALUE *var)
10362{
10363 VALUE argf = *var;
10364 int n = NUM2INT(val);
10365 ARGF.last_lineno = ARGF.lineno = n;
10366}
10367
10368void
10369rb_reset_argf_lineno(long n)
10370{
10371 ARGF.last_lineno = ARGF.lineno = n;
10372}
10373
10374static VALUE argf_gets(int, VALUE *, VALUE);
10375
10376/*
10377 * call-seq:
10378 * gets(sep=$/ [, getline_args]) -> string or nil
10379 * gets(limit [, getline_args]) -> string or nil
10380 * gets(sep, limit [, getline_args]) -> string or nil
10381 *
10382 * Returns (and assigns to <code>$_</code>) the next line from the list
10383 * of files in +ARGV+ (or <code>$*</code>), or from standard input if
10384 * no files are present on the command line. Returns +nil+ at end of
10385 * file. The optional argument specifies the record separator. The
10386 * separator is included with the contents of each record. A separator
10387 * of +nil+ reads the entire contents, and a zero-length separator
10388 * reads the input one paragraph at a time, where paragraphs are
10389 * divided by two consecutive newlines. If the first argument is an
10390 * integer, or optional second argument is given, the returning string
10391 * would not be longer than the given value in bytes. If multiple
10392 * filenames are present in +ARGV+, <code>gets(nil)</code> will read
10393 * the contents one file at a time.
10394 *
10395 * ARGV << "testfile"
10396 * print while gets
10397 *
10398 * <em>produces:</em>
10399 *
10400 * This is line one
10401 * This is line two
10402 * This is line three
10403 * And so on...
10404 *
10405 * The style of programming using <code>$_</code> as an implicit
10406 * parameter is gradually losing favor in the Ruby community.
10407 */
10408
10409static VALUE
10410rb_f_gets(int argc, VALUE *argv, VALUE recv)
10411{
10412 if (recv == argf) {
10413 return argf_gets(argc, argv, argf);
10414 }
10415 return forward(argf, idGets, argc, argv);
10416}
10417
10418/*
10419 * call-seq:
10420 * ARGF.gets(sep=$/ [, getline_args]) -> string or nil
10421 * ARGF.gets(limit [, getline_args]) -> string or nil
10422 * ARGF.gets(sep, limit [, getline_args]) -> string or nil
10423 *
10424 * Returns the next line from the current file in ARGF.
10425 *
10426 * By default lines are assumed to be separated by <code>$/</code>;
10427 * to use a different character as a separator, supply it as a String
10428 * for the _sep_ argument.
10429 *
10430 * The optional _limit_ argument specifies how many characters of each line
10431 * to return. By default all characters are returned.
10432 *
10433 * See IO.readlines for details about getline_args.
10434 *
10435 */
10436static VALUE
10437argf_gets(int argc, VALUE *argv, VALUE argf)
10438{
10439 VALUE line;
10440
10441 line = argf_getline(argc, argv, argf);
10442 rb_lastline_set(line);
10443
10444 return line;
10445}
10446
10447VALUE
10449{
10450 VALUE line;
10451
10452 if (rb_rs != rb_default_rs) {
10453 return rb_f_gets(0, 0, argf);
10454 }
10455
10456 retry:
10457 if (!next_argv()) return Qnil;
10458 line = rb_io_gets(ARGF.current_file);
10459 if (NIL_P(line) && ARGF.next_p != -1) {
10460 rb_io_close(ARGF.current_file);
10461 ARGF.next_p = 1;
10462 goto retry;
10463 }
10464 rb_lastline_set(line);
10465 if (!NIL_P(line)) {
10466 ARGF.lineno++;
10467 ARGF.last_lineno = ARGF.lineno;
10468 }
10469
10470 return line;
10471}
10472
10473static VALUE argf_readline(int, VALUE *, VALUE);
10474
10475/*
10476 * call-seq:
10477 * readline(sep = $/, chomp: false) -> string
10478 * readline(limit, chomp: false) -> string
10479 * readline(sep, limit, chomp: false) -> string
10480 *
10481 * Equivalent to method Kernel#gets, except that it raises an exception
10482 * if called at end-of-stream:
10483 *
10484 * $ cat t.txt | ruby -e "p readlines; readline"
10485 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10486 * in `readline': end of file reached (EOFError)
10487 *
10488 * Optional keyword argument +chomp+ specifies whether line separators
10489 * are to be omitted.
10490 */
10491
10492static VALUE
10493rb_f_readline(int argc, VALUE *argv, VALUE recv)
10494{
10495 if (recv == argf) {
10496 return argf_readline(argc, argv, argf);
10497 }
10498 return forward(argf, rb_intern("readline"), argc, argv);
10499}
10500
10501
10502/*
10503 * call-seq:
10504 * ARGF.readline(sep=$/) -> string
10505 * ARGF.readline(limit) -> string
10506 * ARGF.readline(sep, limit) -> string
10507 *
10508 * Returns the next line from the current file in ARGF.
10509 *
10510 * By default lines are assumed to be separated by <code>$/</code>;
10511 * to use a different character as a separator, supply it as a String
10512 * for the _sep_ argument.
10513 *
10514 * The optional _limit_ argument specifies how many characters of each line
10515 * to return. By default all characters are returned.
10516 *
10517 * An EOFError is raised at the end of the file.
10518 */
10519static VALUE
10520argf_readline(int argc, VALUE *argv, VALUE argf)
10521{
10522 VALUE line;
10523
10524 if (!next_argv()) rb_eof_error();
10525 ARGF_FORWARD(argc, argv);
10526 line = argf_gets(argc, argv, argf);
10527 if (NIL_P(line)) {
10528 rb_eof_error();
10529 }
10530
10531 return line;
10532}
10533
10534static VALUE argf_readlines(int, VALUE *, VALUE);
10535
10536/*
10537 * call-seq:
10538 * readlines(sep = $/, chomp: false, **enc_opts) -> array
10539 * readlines(limit, chomp: false, **enc_opts) -> array
10540 * readlines(sep, limit, chomp: false, **enc_opts) -> array
10541 *
10542 * Returns an array containing the lines returned by calling
10543 * Kernel#gets until the end-of-stream is reached;
10544 * (see {Line IO}[rdoc-ref:IO@Line+IO]).
10545 *
10546 * With only string argument +sep+ given,
10547 * returns the remaining lines as determined by line separator +sep+,
10548 * or +nil+ if none;
10549 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
10550 *
10551 * # Default separator.
10552 * $ cat t.txt | ruby -e "p readlines"
10553 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10554 *
10555 * # Specified separator.
10556 * $ cat t.txt | ruby -e "p readlines 'li'"
10557 * ["First li", "ne\nSecond li", "ne\n\nFourth li", "ne\nFifth li", "ne\n"]
10558 *
10559 * # Get-all separator.
10560 * $ cat t.txt | ruby -e "p readlines nil"
10561 * ["First line\nSecond line\n\nFourth line\nFifth line\n"]
10562 *
10563 * # Get-paragraph separator.
10564 * $ cat t.txt | ruby -e "p readlines ''"
10565 * ["First line\nSecond line\n\n", "Fourth line\nFifth line\n"]
10566 *
10567 * With only integer argument +limit+ given,
10568 * limits the number of bytes in the line;
10569 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
10570 *
10571 * $cat t.txt | ruby -e "p readlines 10"
10572 * ["First line", "\n", "Second lin", "e\n", "\n", "Fourth lin", "e\n", "Fifth line", "\n"]
10573 *
10574 * $cat t.txt | ruby -e "p readlines 11"
10575 * ["First line\n", "Second line", "\n", "\n", "Fourth line", "\n", "Fifth line\n"]
10576 *
10577 * $cat t.txt | ruby -e "p readlines 12"
10578 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10579 *
10580 * With arguments +sep+ and +limit+ given,
10581 * combines the two behaviors
10582 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
10583 *
10584 * Optional keyword argument +chomp+ specifies whether line separators
10585 * are to be omitted:
10586 *
10587 * $ cat t.txt | ruby -e "p readlines(chomp: true)"
10588 * ["First line", "Second line", "", "Fourth line", "Fifth line"]
10589 *
10590 * Optional keyword arguments +enc_opts+ specify encoding options;
10591 * see {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
10592 *
10593 */
10594
10595static VALUE
10596rb_f_readlines(int argc, VALUE *argv, VALUE recv)
10597{
10598 if (recv == argf) {
10599 return argf_readlines(argc, argv, argf);
10600 }
10601 return forward(argf, rb_intern("readlines"), argc, argv);
10602}
10603
10604/*
10605 * call-seq:
10606 * ARGF.readlines(sep = $/, chomp: false) -> array
10607 * ARGF.readlines(limit, chomp: false) -> array
10608 * ARGF.readlines(sep, limit, chomp: false) -> array
10609 *
10610 * ARGF.to_a(sep = $/, chomp: false) -> array
10611 * ARGF.to_a(limit, chomp: false) -> array
10612 * ARGF.to_a(sep, limit, chomp: false) -> array
10613 *
10614 * Reads each file in ARGF in its entirety, returning an Array containing
10615 * lines from the files. Lines are assumed to be separated by _sep_.
10616 *
10617 * lines = ARGF.readlines
10618 * lines[0] #=> "This is line one\n"
10619 *
10620 * See +IO.readlines+ for a full description of all options.
10621 */
10622static VALUE
10623argf_readlines(int argc, VALUE *argv, VALUE argf)
10624{
10625 long lineno = ARGF.lineno;
10626 VALUE lines, ary;
10627
10628 ary = rb_ary_new();
10629 while (next_argv()) {
10630 if (ARGF_GENERIC_INPUT_P()) {
10631 lines = forward_current(rb_intern("readlines"), argc, argv);
10632 }
10633 else {
10634 lines = rb_io_readlines(argc, argv, ARGF.current_file);
10635 argf_close(argf);
10636 }
10637 ARGF.next_p = 1;
10638 rb_ary_concat(ary, lines);
10639 ARGF.lineno = lineno + RARRAY_LEN(ary);
10640 ARGF.last_lineno = ARGF.lineno;
10641 }
10642 ARGF.init_p = 0;
10643 return ary;
10644}
10645
10646/*
10647 * call-seq:
10648 * `command` -> string
10649 *
10650 * Returns the <tt>$stdout</tt> output from running +command+ in a subshell;
10651 * sets global variable <tt>$?</tt> to the process status.
10652 *
10653 * This method has potential security vulnerabilities if called with untrusted input;
10654 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
10655 *
10656 * Examples:
10657 *
10658 * $ `date` # => "Wed Apr 9 08:56:30 CDT 2003\n"
10659 * $ `echo oops && exit 99` # => "oops\n"
10660 * $ $? # => #<Process::Status: pid 17088 exit 99>
10661 * $ $?.exitstatus # => 99
10662 *
10663 * The built-in syntax <tt>%x{...}</tt> uses this method.
10664 *
10665 */
10666
10667static VALUE
10668rb_f_backquote(VALUE obj, VALUE str)
10669{
10670 VALUE port;
10671 VALUE result;
10672 rb_io_t *fptr;
10673
10674 StringValue(str);
10675 rb_last_status_clear();
10676 port = pipe_open_s(str, "r", FMODE_READABLE|DEFAULT_TEXTMODE, NULL);
10677 if (NIL_P(port)) return rb_str_new(0,0);
10678
10679 GetOpenFile(port, fptr);
10680 result = read_all(fptr, remain_size(fptr), Qnil);
10681 rb_io_close(port);
10682 rb_io_fptr_cleanup_all(fptr);
10683 RB_GC_GUARD(port);
10684
10685 return result;
10686}
10687
10688#ifdef HAVE_SYS_SELECT_H
10689#include <sys/select.h>
10690#endif
10691
10692static VALUE
10693select_internal(VALUE read, VALUE write, VALUE except, struct timeval *tp, rb_fdset_t *fds)
10694{
10695 VALUE res, list;
10696 rb_fdset_t *rp, *wp, *ep;
10697 rb_io_t *fptr;
10698 long i;
10699 int max = 0, n;
10700 int pending = 0;
10701 struct timeval timerec;
10702
10703 if (!NIL_P(read)) {
10704 Check_Type(read, T_ARRAY);
10705 for (i=0; i<RARRAY_LEN(read); i++) {
10706 GetOpenFile(rb_io_get_io(RARRAY_AREF(read, i)), fptr);
10707 rb_fd_set(fptr->fd, &fds[0]);
10708 if (READ_DATA_PENDING(fptr) || READ_CHAR_PENDING(fptr)) { /* check for buffered data */
10709 pending++;
10710 rb_fd_set(fptr->fd, &fds[3]);
10711 }
10712 if (max < fptr->fd) max = fptr->fd;
10713 }
10714 if (pending) { /* no blocking if there's buffered data */
10715 timerec.tv_sec = timerec.tv_usec = 0;
10716 tp = &timerec;
10717 }
10718 rp = &fds[0];
10719 }
10720 else
10721 rp = 0;
10722
10723 if (!NIL_P(write)) {
10724 Check_Type(write, T_ARRAY);
10725 for (i=0; i<RARRAY_LEN(write); i++) {
10726 VALUE write_io = GetWriteIO(rb_io_get_io(RARRAY_AREF(write, i)));
10727 GetOpenFile(write_io, fptr);
10728 rb_fd_set(fptr->fd, &fds[1]);
10729 if (max < fptr->fd) max = fptr->fd;
10730 }
10731 wp = &fds[1];
10732 }
10733 else
10734 wp = 0;
10735
10736 if (!NIL_P(except)) {
10737 Check_Type(except, T_ARRAY);
10738 for (i=0; i<RARRAY_LEN(except); i++) {
10739 VALUE io = rb_io_get_io(RARRAY_AREF(except, i));
10740 VALUE write_io = GetWriteIO(io);
10741 GetOpenFile(io, fptr);
10742 rb_fd_set(fptr->fd, &fds[2]);
10743 if (max < fptr->fd) max = fptr->fd;
10744 if (io != write_io) {
10745 GetOpenFile(write_io, fptr);
10746 rb_fd_set(fptr->fd, &fds[2]);
10747 if (max < fptr->fd) max = fptr->fd;
10748 }
10749 }
10750 ep = &fds[2];
10751 }
10752 else {
10753 ep = 0;
10754 }
10755
10756 max++;
10757
10758 n = rb_thread_fd_select(max, rp, wp, ep, tp);
10759 if (n < 0) {
10760 rb_sys_fail(0);
10761 }
10762 if (!pending && n == 0) return Qnil; /* returns nil on timeout */
10763
10764 res = rb_ary_new2(3);
10765 rb_ary_push(res, rp?rb_ary_new():rb_ary_new2(0));
10766 rb_ary_push(res, wp?rb_ary_new():rb_ary_new2(0));
10767 rb_ary_push(res, ep?rb_ary_new():rb_ary_new2(0));
10768
10769 if (rp) {
10770 list = RARRAY_AREF(res, 0);
10771 for (i=0; i< RARRAY_LEN(read); i++) {
10772 VALUE obj = rb_ary_entry(read, i);
10773 VALUE io = rb_io_get_io(obj);
10774 GetOpenFile(io, fptr);
10775 if (rb_fd_isset(fptr->fd, &fds[0]) ||
10776 rb_fd_isset(fptr->fd, &fds[3])) {
10777 rb_ary_push(list, obj);
10778 }
10779 }
10780 }
10781
10782 if (wp) {
10783 list = RARRAY_AREF(res, 1);
10784 for (i=0; i< RARRAY_LEN(write); i++) {
10785 VALUE obj = rb_ary_entry(write, i);
10786 VALUE io = rb_io_get_io(obj);
10787 VALUE write_io = GetWriteIO(io);
10788 GetOpenFile(write_io, fptr);
10789 if (rb_fd_isset(fptr->fd, &fds[1])) {
10790 rb_ary_push(list, obj);
10791 }
10792 }
10793 }
10794
10795 if (ep) {
10796 list = RARRAY_AREF(res, 2);
10797 for (i=0; i< RARRAY_LEN(except); i++) {
10798 VALUE obj = rb_ary_entry(except, i);
10799 VALUE io = rb_io_get_io(obj);
10800 VALUE write_io = GetWriteIO(io);
10801 GetOpenFile(io, fptr);
10802 if (rb_fd_isset(fptr->fd, &fds[2])) {
10803 rb_ary_push(list, obj);
10804 }
10805 else if (io != write_io) {
10806 GetOpenFile(write_io, fptr);
10807 if (rb_fd_isset(fptr->fd, &fds[2])) {
10808 rb_ary_push(list, obj);
10809 }
10810 }
10811 }
10812 }
10813
10814 return res; /* returns an empty array on interrupt */
10815}
10816
10818 VALUE read, write, except;
10819 struct timeval *timeout;
10820 rb_fdset_t fdsets[4];
10821};
10822
10823static VALUE
10824select_call(VALUE arg)
10825{
10826 struct select_args *p = (struct select_args *)arg;
10827
10828 return select_internal(p->read, p->write, p->except, p->timeout, p->fdsets);
10829}
10830
10831static VALUE
10832select_end(VALUE arg)
10833{
10834 struct select_args *p = (struct select_args *)arg;
10835 int i;
10836
10837 for (i = 0; i < numberof(p->fdsets); ++i)
10838 rb_fd_term(&p->fdsets[i]);
10839 return Qnil;
10840}
10841
10842static VALUE sym_normal, sym_sequential, sym_random,
10843 sym_willneed, sym_dontneed, sym_noreuse;
10844
10845#ifdef HAVE_POSIX_FADVISE
10846struct io_advise_struct {
10847 int fd;
10848 int advice;
10849 rb_off_t offset;
10850 rb_off_t len;
10851};
10852
10853static VALUE
10854io_advise_internal(void *arg)
10855{
10856 struct io_advise_struct *ptr = arg;
10857 return posix_fadvise(ptr->fd, ptr->offset, ptr->len, ptr->advice);
10858}
10859
10860static VALUE
10861io_advise_sym_to_const(VALUE sym)
10862{
10863#ifdef POSIX_FADV_NORMAL
10864 if (sym == sym_normal)
10865 return INT2NUM(POSIX_FADV_NORMAL);
10866#endif
10867
10868#ifdef POSIX_FADV_RANDOM
10869 if (sym == sym_random)
10870 return INT2NUM(POSIX_FADV_RANDOM);
10871#endif
10872
10873#ifdef POSIX_FADV_SEQUENTIAL
10874 if (sym == sym_sequential)
10875 return INT2NUM(POSIX_FADV_SEQUENTIAL);
10876#endif
10877
10878#ifdef POSIX_FADV_WILLNEED
10879 if (sym == sym_willneed)
10880 return INT2NUM(POSIX_FADV_WILLNEED);
10881#endif
10882
10883#ifdef POSIX_FADV_DONTNEED
10884 if (sym == sym_dontneed)
10885 return INT2NUM(POSIX_FADV_DONTNEED);
10886#endif
10887
10888#ifdef POSIX_FADV_NOREUSE
10889 if (sym == sym_noreuse)
10890 return INT2NUM(POSIX_FADV_NOREUSE);
10891#endif
10892
10893 return Qnil;
10894}
10895
10896static VALUE
10897do_io_advise(rb_io_t *fptr, VALUE advice, rb_off_t offset, rb_off_t len)
10898{
10899 int rv;
10900 struct io_advise_struct ias;
10901 VALUE num_adv;
10902
10903 num_adv = io_advise_sym_to_const(advice);
10904
10905 /*
10906 * The platform doesn't support this hint. We don't raise exception, instead
10907 * silently ignore it. Because IO::advise is only hint.
10908 */
10909 if (NIL_P(num_adv))
10910 return Qnil;
10911
10912 ias.fd = fptr->fd;
10913 ias.advice = NUM2INT(num_adv);
10914 ias.offset = offset;
10915 ias.len = len;
10916
10917 rv = (int)rb_io_blocking_region(fptr, io_advise_internal, &ias);
10918 if (rv && rv != ENOSYS) {
10919 /* posix_fadvise(2) doesn't set errno. On success it returns 0; otherwise
10920 it returns the error code. */
10921 VALUE message = rb_sprintf("%"PRIsVALUE" "
10922 "(%"PRI_OFFT_PREFIX"d, "
10923 "%"PRI_OFFT_PREFIX"d, "
10924 "%"PRIsVALUE")",
10925 fptr->pathv, offset, len, advice);
10926 rb_syserr_fail_str(rv, message);
10927 }
10928
10929 return Qnil;
10930}
10931
10932#endif /* HAVE_POSIX_FADVISE */
10933
10934static void
10935advice_arg_check(VALUE advice)
10936{
10937 if (!SYMBOL_P(advice))
10938 rb_raise(rb_eTypeError, "advice must be a Symbol");
10939
10940 if (advice != sym_normal &&
10941 advice != sym_sequential &&
10942 advice != sym_random &&
10943 advice != sym_willneed &&
10944 advice != sym_dontneed &&
10945 advice != sym_noreuse) {
10946 rb_raise(rb_eNotImpError, "Unsupported advice: %+"PRIsVALUE, advice);
10947 }
10948}
10949
10950/*
10951 * call-seq:
10952 * advise(advice, offset = 0, len = 0) -> nil
10953 *
10954 * Invokes Posix system call
10955 * {posix_fadvise(2)}[https://linux.die.net/man/2/posix_fadvise],
10956 * which announces an intention to access data from the current file
10957 * in a particular manner.
10958 *
10959 * The arguments and results are platform-dependent.
10960 *
10961 * The relevant data is specified by:
10962 *
10963 * - +offset+: The offset of the first byte of data.
10964 * - +len+: The number of bytes to be accessed;
10965 * if +len+ is zero, or is larger than the number of bytes remaining,
10966 * all remaining bytes will be accessed.
10967 *
10968 * Argument +advice+ is one of the following symbols:
10969 *
10970 * - +:normal+: The application has no advice to give
10971 * about its access pattern for the specified data.
10972 * If no advice is given for an open file, this is the default assumption.
10973 * - +:sequential+: The application expects to access the specified data sequentially
10974 * (with lower offsets read before higher ones).
10975 * - +:random+: The specified data will be accessed in random order.
10976 * - +:noreuse+: The specified data will be accessed only once.
10977 * - +:willneed+: The specified data will be accessed in the near future.
10978 * - +:dontneed+: The specified data will not be accessed in the near future.
10979 *
10980 * Not implemented on all platforms.
10981 *
10982 */
10983static VALUE
10984rb_io_advise(int argc, VALUE *argv, VALUE io)
10985{
10986 VALUE advice, offset, len;
10987 rb_off_t off, l;
10988 rb_io_t *fptr;
10989
10990 rb_scan_args(argc, argv, "12", &advice, &offset, &len);
10991 advice_arg_check(advice);
10992
10993 io = GetWriteIO(io);
10994 GetOpenFile(io, fptr);
10995
10996 off = NIL_P(offset) ? 0 : NUM2OFFT(offset);
10997 l = NIL_P(len) ? 0 : NUM2OFFT(len);
10998
10999#ifdef HAVE_POSIX_FADVISE
11000 return do_io_advise(fptr, advice, off, l);
11001#else
11002 ((void)off, (void)l); /* Ignore all hint */
11003 return Qnil;
11004#endif
11005}
11006
11007static int
11008is_pos_inf(VALUE x)
11009{
11010 double f;
11011 if (!RB_FLOAT_TYPE_P(x))
11012 return 0;
11013 f = RFLOAT_VALUE(x);
11014 return isinf(f) && 0 < f;
11015}
11016
11017/*
11018 * call-seq:
11019 * IO.select(read_ios, write_ios = [], error_ios = [], timeout = nil) -> array or nil
11020 *
11021 * Invokes system call {select(2)}[https://linux.die.net/man/2/select],
11022 * which monitors multiple file descriptors,
11023 * waiting until one or more of the file descriptors
11024 * becomes ready for some class of I/O operation.
11025 *
11026 * Not implemented on all platforms.
11027 *
11028 * Each of the arguments +read_ios+, +write_ios+, and +error_ios+
11029 * is an array of IO objects.
11030 *
11031 * Argument +timeout+ is a numeric value (such as integer or float) timeout
11032 * interval in seconds.
11033 * +timeout+ can also be +nil+ or +Float::INFINITY+.
11034 * +nil+ and +Float::INFINITY+ means no timeout.
11035 *
11036 * The method monitors the \IO objects given in all three arrays,
11037 * waiting for some to be ready;
11038 * returns a 3-element array whose elements are:
11039 *
11040 * - An array of the objects in +read_ios+ that are ready for reading.
11041 * - An array of the objects in +write_ios+ that are ready for writing.
11042 * - An array of the objects in +error_ios+ have pending exceptions.
11043 *
11044 * If no object becomes ready within the given +timeout+, +nil+ is returned.
11045 *
11046 * \IO.select peeks the buffer of \IO objects for testing readability.
11047 * If the \IO buffer is not empty, \IO.select immediately notifies
11048 * readability. This "peek" only happens for \IO objects. It does not
11049 * happen for IO-like objects such as OpenSSL::SSL::SSLSocket.
11050 *
11051 * The best way to use \IO.select is invoking it after non-blocking
11052 * methods such as #read_nonblock, #write_nonblock, etc. The methods
11053 * raise an exception which is extended by IO::WaitReadable or
11054 * IO::WaitWritable. The modules notify how the caller should wait
11055 * with \IO.select. If IO::WaitReadable is raised, the caller should
11056 * wait for reading. If IO::WaitWritable is raised, the caller should
11057 * wait for writing.
11058 *
11059 * So, blocking read (#readpartial) can be emulated using
11060 * #read_nonblock and \IO.select as follows:
11061 *
11062 * begin
11063 * result = io_like.read_nonblock(maxlen)
11064 * rescue IO::WaitReadable
11065 * IO.select([io_like])
11066 * retry
11067 * rescue IO::WaitWritable
11068 * IO.select(nil, [io_like])
11069 * retry
11070 * end
11071 *
11072 * Especially, the combination of non-blocking methods and \IO.select is
11073 * preferred for IO like objects such as OpenSSL::SSL::SSLSocket. It
11074 * has #to_io method to return underlying IO object. IO.select calls
11075 * #to_io to obtain the file descriptor to wait.
11076 *
11077 * This means that readability notified by \IO.select doesn't mean
11078 * readability from OpenSSL::SSL::SSLSocket object.
11079 *
11080 * The most likely situation is that OpenSSL::SSL::SSLSocket buffers
11081 * some data. \IO.select doesn't see the buffer. So \IO.select can
11082 * block when OpenSSL::SSL::SSLSocket#readpartial doesn't block.
11083 *
11084 * However, several more complicated situations exist.
11085 *
11086 * SSL is a protocol which is sequence of records.
11087 * The record consists of multiple bytes.
11088 * So, the remote side of SSL sends a partial record, IO.select
11089 * notifies readability but OpenSSL::SSL::SSLSocket cannot decrypt a
11090 * byte and OpenSSL::SSL::SSLSocket#readpartial will block.
11091 *
11092 * Also, the remote side can request SSL renegotiation which forces
11093 * the local SSL engine to write some data.
11094 * This means OpenSSL::SSL::SSLSocket#readpartial may invoke #write
11095 * system call and it can block.
11096 * In such a situation, OpenSSL::SSL::SSLSocket#read_nonblock raises
11097 * IO::WaitWritable instead of blocking.
11098 * So, the caller should wait for ready for writability as above
11099 * example.
11100 *
11101 * The combination of non-blocking methods and \IO.select is also useful
11102 * for streams such as tty, pipe socket socket when multiple processes
11103 * read from a stream.
11104 *
11105 * Finally, Linux kernel developers don't guarantee that
11106 * readability of select(2) means readability of following read(2) even
11107 * for a single process;
11108 * see {select(2)}[https://linux.die.net/man/2/select]
11109 *
11110 * Invoking \IO.select before IO#readpartial works well as usual.
11111 * However it is not the best way to use \IO.select.
11112 *
11113 * The writability notified by select(2) doesn't show
11114 * how many bytes are writable.
11115 * IO#write method blocks until given whole string is written.
11116 * So, <tt>IO#write(two or more bytes)</tt> can block after
11117 * writability is notified by \IO.select. IO#write_nonblock is required
11118 * to avoid the blocking.
11119 *
11120 * Blocking write (#write) can be emulated using #write_nonblock and
11121 * IO.select as follows: IO::WaitReadable should also be rescued for
11122 * SSL renegotiation in OpenSSL::SSL::SSLSocket.
11123 *
11124 * while 0 < string.bytesize
11125 * begin
11126 * written = io_like.write_nonblock(string)
11127 * rescue IO::WaitReadable
11128 * IO.select([io_like])
11129 * retry
11130 * rescue IO::WaitWritable
11131 * IO.select(nil, [io_like])
11132 * retry
11133 * end
11134 * string = string.byteslice(written..-1)
11135 * end
11136 *
11137 * Example:
11138 *
11139 * rp, wp = IO.pipe
11140 * mesg = "ping "
11141 * 100.times {
11142 * # IO.select follows IO#read. Not the best way to use IO.select.
11143 * rs, ws, = IO.select([rp], [wp])
11144 * if r = rs[0]
11145 * ret = r.read(5)
11146 * print ret
11147 * case ret
11148 * when /ping/
11149 * mesg = "pong\n"
11150 * when /pong/
11151 * mesg = "ping "
11152 * end
11153 * end
11154 * if w = ws[0]
11155 * w.write(mesg)
11156 * end
11157 * }
11158 *
11159 * Output:
11160 *
11161 * ping pong
11162 * ping pong
11163 * ping pong
11164 * (snipped)
11165 * ping
11166 *
11167 */
11168
11169static VALUE
11170rb_f_select(int argc, VALUE *argv, VALUE obj)
11171{
11172 VALUE scheduler = rb_fiber_scheduler_current();
11173 if (scheduler != Qnil) {
11174 // It's optionally supported.
11175 VALUE result = rb_fiber_scheduler_io_selectv(scheduler, argc, argv);
11176 if (!UNDEF_P(result)) return result;
11177 }
11178
11179 VALUE timeout;
11180 struct select_args args;
11181 struct timeval timerec;
11182 int i;
11183
11184 rb_scan_args(argc, argv, "13", &args.read, &args.write, &args.except, &timeout);
11185 if (NIL_P(timeout) || is_pos_inf(timeout)) {
11186 args.timeout = 0;
11187 }
11188 else {
11189 timerec = rb_time_interval(timeout);
11190 args.timeout = &timerec;
11191 }
11192
11193 for (i = 0; i < numberof(args.fdsets); ++i)
11194 rb_fd_init(&args.fdsets[i]);
11195
11196 return rb_ensure(select_call, (VALUE)&args, select_end, (VALUE)&args);
11197}
11198
11199#ifdef IOCTL_REQ_TYPE
11200 typedef IOCTL_REQ_TYPE ioctl_req_t;
11201#else
11202 typedef int ioctl_req_t;
11203# define NUM2IOCTLREQ(num) ((int)NUM2LONG(num))
11204#endif
11205
11206#ifdef HAVE_IOCTL
11207struct ioctl_arg {
11208 int fd;
11209 ioctl_req_t cmd;
11210 long narg;
11211};
11212
11213static VALUE
11214nogvl_ioctl(void *ptr)
11215{
11216 struct ioctl_arg *arg = ptr;
11217
11218 return (VALUE)ioctl(arg->fd, arg->cmd, arg->narg);
11219}
11220
11221static int
11222do_ioctl(struct rb_io *io, ioctl_req_t cmd, long narg)
11223{
11224 int retval;
11225 struct ioctl_arg arg;
11226
11227 arg.fd = io->fd;
11228 arg.cmd = cmd;
11229 arg.narg = narg;
11230
11231 retval = (int)rb_io_blocking_region(io, nogvl_ioctl, &arg);
11232
11233 return retval;
11234}
11235#endif
11236
11237#define DEFAULT_IOCTL_NARG_LEN (256)
11238
11239#if defined(__linux__) && defined(_IOC_SIZE)
11240static long
11241linux_iocparm_len(ioctl_req_t cmd)
11242{
11243 long len;
11244
11245 if ((cmd & 0xFFFF0000) == 0) {
11246 /* legacy and unstructured ioctl number. */
11247 return DEFAULT_IOCTL_NARG_LEN;
11248 }
11249
11250 len = _IOC_SIZE(cmd);
11251
11252 /* paranoia check for silly drivers which don't keep ioctl convention */
11253 if (len < DEFAULT_IOCTL_NARG_LEN)
11254 len = DEFAULT_IOCTL_NARG_LEN;
11255
11256 return len;
11257}
11258#endif
11259
11260#ifdef HAVE_IOCTL
11261static long
11262ioctl_narg_len(ioctl_req_t cmd)
11263{
11264 long len;
11265
11266#ifdef IOCPARM_MASK
11267#ifndef IOCPARM_LEN
11268#define IOCPARM_LEN(x) (((x) >> 16) & IOCPARM_MASK)
11269#endif
11270#endif
11271#ifdef IOCPARM_LEN
11272 len = IOCPARM_LEN(cmd); /* on BSDish systems we're safe */
11273#elif defined(__linux__) && defined(_IOC_SIZE)
11274 len = linux_iocparm_len(cmd);
11275#else
11276 /* otherwise guess at what's safe */
11277 len = DEFAULT_IOCTL_NARG_LEN;
11278#endif
11279
11280 return len;
11281}
11282#endif
11283
11284#ifdef HAVE_FCNTL
11285#ifdef __linux__
11286typedef long fcntl_arg_t;
11287#else
11288/* posix */
11289typedef int fcntl_arg_t;
11290#endif
11291
11292static long
11293fcntl_narg_len(ioctl_req_t cmd)
11294{
11295 long len;
11296
11297 switch (cmd) {
11298#ifdef F_DUPFD
11299 case F_DUPFD:
11300 len = sizeof(fcntl_arg_t);
11301 break;
11302#endif
11303#ifdef F_DUP2FD /* bsd specific */
11304 case F_DUP2FD:
11305 len = sizeof(int);
11306 break;
11307#endif
11308#ifdef F_DUPFD_CLOEXEC /* linux specific */
11309 case F_DUPFD_CLOEXEC:
11310 len = sizeof(fcntl_arg_t);
11311 break;
11312#endif
11313#ifdef F_GETFD
11314 case F_GETFD:
11315 len = 1;
11316 break;
11317#endif
11318#ifdef F_SETFD
11319 case F_SETFD:
11320 len = sizeof(fcntl_arg_t);
11321 break;
11322#endif
11323#ifdef F_GETFL
11324 case F_GETFL:
11325 len = 1;
11326 break;
11327#endif
11328#ifdef F_SETFL
11329 case F_SETFL:
11330 len = sizeof(fcntl_arg_t);
11331 break;
11332#endif
11333#ifdef F_GETOWN
11334 case F_GETOWN:
11335 len = 1;
11336 break;
11337#endif
11338#ifdef F_SETOWN
11339 case F_SETOWN:
11340 len = sizeof(fcntl_arg_t);
11341 break;
11342#endif
11343#ifdef F_GETOWN_EX /* linux specific */
11344 case F_GETOWN_EX:
11345 len = sizeof(struct f_owner_ex);
11346 break;
11347#endif
11348#ifdef F_SETOWN_EX /* linux specific */
11349 case F_SETOWN_EX:
11350 len = sizeof(struct f_owner_ex);
11351 break;
11352#endif
11353#ifdef F_GETLK
11354 case F_GETLK:
11355 len = sizeof(struct flock);
11356 break;
11357#endif
11358#ifdef F_SETLK
11359 case F_SETLK:
11360 len = sizeof(struct flock);
11361 break;
11362#endif
11363#ifdef F_SETLKW
11364 case F_SETLKW:
11365 len = sizeof(struct flock);
11366 break;
11367#endif
11368#ifdef F_READAHEAD /* bsd specific */
11369 case F_READAHEAD:
11370 len = sizeof(int);
11371 break;
11372#endif
11373#ifdef F_RDAHEAD /* Darwin specific */
11374 case F_RDAHEAD:
11375 len = sizeof(int);
11376 break;
11377#endif
11378#ifdef F_GETSIG /* linux specific */
11379 case F_GETSIG:
11380 len = 1;
11381 break;
11382#endif
11383#ifdef F_SETSIG /* linux specific */
11384 case F_SETSIG:
11385 len = sizeof(fcntl_arg_t);
11386 break;
11387#endif
11388#ifdef F_GETLEASE /* linux specific */
11389 case F_GETLEASE:
11390 len = 1;
11391 break;
11392#endif
11393#ifdef F_SETLEASE /* linux specific */
11394 case F_SETLEASE:
11395 len = sizeof(fcntl_arg_t);
11396 break;
11397#endif
11398#ifdef F_NOTIFY /* linux specific */
11399 case F_NOTIFY:
11400 len = sizeof(fcntl_arg_t);
11401 break;
11402#endif
11403
11404 default:
11405 len = 256;
11406 break;
11407 }
11408
11409 return len;
11410}
11411#else /* HAVE_FCNTL */
11412static long
11413fcntl_narg_len(ioctl_req_t cmd)
11414{
11415 return 0;
11416}
11417#endif /* HAVE_FCNTL */
11418
11419#define NARG_SENTINEL 17
11420
11421static long
11422setup_narg(ioctl_req_t cmd, VALUE *argp, long (*narg_len)(ioctl_req_t))
11423{
11424 long narg = 0;
11425 VALUE arg = *argp;
11426
11427 if (!RTEST(arg)) {
11428 narg = 0;
11429 }
11430 else if (FIXNUM_P(arg)) {
11431 narg = FIX2LONG(arg);
11432 }
11433 else if (arg == Qtrue) {
11434 narg = 1;
11435 }
11436 else {
11437 VALUE tmp = rb_check_string_type(arg);
11438
11439 if (NIL_P(tmp)) {
11440 narg = NUM2LONG(arg);
11441 }
11442 else {
11443 char *ptr;
11444 long len, slen;
11445
11446 *argp = arg = tmp;
11447 len = narg_len(cmd);
11448 rb_str_modify(arg);
11449
11450 slen = RSTRING_LEN(arg);
11451 /* expand for data + sentinel. */
11452 if (slen < len+1) {
11453 rb_str_resize(arg, len+1);
11454 MEMZERO(RSTRING_PTR(arg)+slen, char, len-slen);
11455 slen = len+1;
11456 }
11457 /* a little sanity check here */
11458 ptr = RSTRING_PTR(arg);
11459 ptr[slen - 1] = NARG_SENTINEL;
11460 narg = (long)(SIGNED_VALUE)ptr;
11461 }
11462 }
11463
11464 return narg;
11465}
11466
11467static VALUE
11468finish_narg(int retval, VALUE arg, const rb_io_t *fptr)
11469{
11470 if (retval < 0) rb_sys_fail_path(fptr->pathv);
11471 if (RB_TYPE_P(arg, T_STRING)) {
11472 char *ptr;
11473 long slen;
11474 RSTRING_GETMEM(arg, ptr, slen);
11475 if (ptr[slen-1] != NARG_SENTINEL)
11476 rb_raise(rb_eArgError, "return value overflowed string");
11477 ptr[slen-1] = '\0';
11478 }
11479
11480 return INT2NUM(retval);
11481}
11482
11483#ifdef HAVE_IOCTL
11484static VALUE
11485rb_ioctl(VALUE io, VALUE req, VALUE arg)
11486{
11487 ioctl_req_t cmd = NUM2IOCTLREQ(req);
11488 rb_io_t *fptr;
11489 long narg;
11490 int retval;
11491
11492 narg = setup_narg(cmd, &arg, ioctl_narg_len);
11493 GetOpenFile(io, fptr);
11494 retval = do_ioctl(fptr, cmd, narg);
11495 return finish_narg(retval, arg, fptr);
11496}
11497
11498/*
11499 * call-seq:
11500 * ioctl(integer_cmd, argument) -> integer
11501 *
11502 * Invokes Posix system call {ioctl(2)}[https://linux.die.net/man/2/ioctl],
11503 * which issues a low-level command to an I/O device.
11504 *
11505 * Issues a low-level command to an I/O device.
11506 * The arguments and returned value are platform-dependent.
11507 * The effect of the call is platform-dependent.
11508 *
11509 * If argument +argument+ is an integer, it is passed directly;
11510 * if it is a string, it is interpreted as a binary sequence of bytes.
11511 *
11512 * Not implemented on all platforms.
11513 *
11514 */
11515
11516static VALUE
11517rb_io_ioctl(int argc, VALUE *argv, VALUE io)
11518{
11519 VALUE req, arg;
11520
11521 rb_scan_args(argc, argv, "11", &req, &arg);
11522 return rb_ioctl(io, req, arg);
11523}
11524#else
11525#define rb_io_ioctl rb_f_notimplement
11526#endif
11527
11528#ifdef HAVE_FCNTL
11529struct fcntl_arg {
11530 int fd;
11531 int cmd;
11532 long narg;
11533};
11534
11535static VALUE
11536nogvl_fcntl(void *ptr)
11537{
11538 struct fcntl_arg *arg = ptr;
11539
11540#if defined(F_DUPFD)
11541 if (arg->cmd == F_DUPFD)
11542 return (VALUE)rb_cloexec_fcntl_dupfd(arg->fd, (int)arg->narg);
11543#endif
11544 return (VALUE)fcntl(arg->fd, arg->cmd, arg->narg);
11545}
11546
11547static int
11548do_fcntl(struct rb_io *io, int cmd, long narg)
11549{
11550 int retval;
11551 struct fcntl_arg arg;
11552
11553 arg.fd = io->fd;
11554 arg.cmd = cmd;
11555 arg.narg = narg;
11556
11557 retval = (int)rb_io_blocking_region(io, nogvl_fcntl, &arg);
11558 if (retval != -1) {
11559 switch (cmd) {
11560#if defined(F_DUPFD)
11561 case F_DUPFD:
11562#endif
11563#if defined(F_DUPFD_CLOEXEC)
11564 case F_DUPFD_CLOEXEC:
11565#endif
11566 rb_update_max_fd(retval);
11567 }
11568 }
11569
11570 return retval;
11571}
11572
11573static VALUE
11574rb_fcntl(VALUE io, VALUE req, VALUE arg)
11575{
11576 int cmd = NUM2INT(req);
11577 rb_io_t *fptr;
11578 long narg;
11579 int retval;
11580
11581 narg = setup_narg(cmd, &arg, fcntl_narg_len);
11582 GetOpenFile(io, fptr);
11583 retval = do_fcntl(fptr, cmd, narg);
11584 return finish_narg(retval, arg, fptr);
11585}
11586
11587/*
11588 * call-seq:
11589 * fcntl(integer_cmd, argument) -> integer
11590 *
11591 * Invokes Posix system call {fcntl(2)}[https://linux.die.net/man/2/fcntl],
11592 * which provides a mechanism for issuing low-level commands to control or query
11593 * a file-oriented I/O stream. Arguments and results are platform
11594 * dependent.
11595 *
11596 * If +argument+ is a number, its value is passed directly;
11597 * if it is a string, it is interpreted as a binary sequence of bytes.
11598 * (Array#pack might be a useful way to build this string.)
11599 *
11600 * Not implemented on all platforms.
11601 *
11602 */
11603
11604static VALUE
11605rb_io_fcntl(int argc, VALUE *argv, VALUE io)
11606{
11607 VALUE req, arg;
11608
11609 rb_scan_args(argc, argv, "11", &req, &arg);
11610 return rb_fcntl(io, req, arg);
11611}
11612#else
11613#define rb_io_fcntl rb_f_notimplement
11614#endif
11615
11616#if defined(HAVE_SYSCALL) || defined(HAVE___SYSCALL)
11617/*
11618 * call-seq:
11619 * syscall(integer_callno, *arguments) -> integer
11620 *
11621 * Invokes Posix system call {syscall(2)}[https://linux.die.net/man/2/syscall],
11622 * which calls a specified function.
11623 *
11624 * Calls the operating system function identified by +integer_callno+;
11625 * returns the result of the function or raises SystemCallError if it failed.
11626 * The effect of the call is platform-dependent.
11627 * The arguments and returned value are platform-dependent.
11628 *
11629 * For each of +arguments+: if it is an integer, it is passed directly;
11630 * if it is a string, it is interpreted as a binary sequence of bytes.
11631 * There may be as many as nine such arguments.
11632 *
11633 * Arguments +integer_callno+ and +argument+, as well as the returned value,
11634 * are platform-dependent.
11635 *
11636 * Note: Method +syscall+ is essentially unsafe and unportable.
11637 * The DL (Fiddle) library is preferred for safer and a bit
11638 * more portable programming.
11639 *
11640 * Not implemented on all platforms.
11641 *
11642 */
11643
11644static VALUE
11645rb_f_syscall(int argc, VALUE *argv, VALUE _)
11646{
11647 VALUE arg[8];
11648#if SIZEOF_VOIDP == 8 && defined(HAVE___SYSCALL) && SIZEOF_INT != 8 /* mainly *BSD */
11649# define SYSCALL __syscall
11650# define NUM2SYSCALLID(x) NUM2LONG(x)
11651# define RETVAL2NUM(x) LONG2NUM(x)
11652# if SIZEOF_LONG == 8
11653 long num, retval = -1;
11654# elif SIZEOF_LONG_LONG == 8
11655 long long num, retval = -1;
11656# else
11657# error ---->> it is asserted that __syscall takes the first argument and returns retval in 64bit signed integer. <<----
11658# endif
11659#elif defined(__linux__)
11660# define SYSCALL syscall
11661# define NUM2SYSCALLID(x) NUM2LONG(x)
11662# define RETVAL2NUM(x) LONG2NUM(x)
11663 /*
11664 * Linux man page says, syscall(2) function prototype is below.
11665 *
11666 * int syscall(int number, ...);
11667 *
11668 * But, it's incorrect. Actual one takes and returned long. (see unistd.h)
11669 */
11670 long num, retval = -1;
11671#else
11672# define SYSCALL syscall
11673# define NUM2SYSCALLID(x) NUM2INT(x)
11674# define RETVAL2NUM(x) INT2NUM(x)
11675 int num, retval = -1;
11676#endif
11677 int i;
11678
11679 if (RTEST(ruby_verbose)) {
11681 "We plan to remove a syscall function at future release. DL(Fiddle) provides safer alternative.");
11682 }
11683
11684 if (argc == 0)
11685 rb_raise(rb_eArgError, "too few arguments for syscall");
11686 if (argc > numberof(arg))
11687 rb_raise(rb_eArgError, "too many arguments for syscall");
11688 num = NUM2SYSCALLID(argv[0]); ++argv;
11689 for (i = argc - 1; i--; ) {
11690 VALUE v = rb_check_string_type(argv[i]);
11691
11692 if (!NIL_P(v)) {
11693 StringValue(v);
11694 rb_str_modify(v);
11695 arg[i] = (VALUE)StringValueCStr(v);
11696 }
11697 else {
11698 arg[i] = (VALUE)NUM2LONG(argv[i]);
11699 }
11700 }
11701
11702 switch (argc) {
11703 case 1:
11704 retval = SYSCALL(num);
11705 break;
11706 case 2:
11707 retval = SYSCALL(num, arg[0]);
11708 break;
11709 case 3:
11710 retval = SYSCALL(num, arg[0],arg[1]);
11711 break;
11712 case 4:
11713 retval = SYSCALL(num, arg[0],arg[1],arg[2]);
11714 break;
11715 case 5:
11716 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3]);
11717 break;
11718 case 6:
11719 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4]);
11720 break;
11721 case 7:
11722 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5]);
11723 break;
11724 case 8:
11725 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6]);
11726 break;
11727 }
11728
11729 if (retval == -1)
11730 rb_sys_fail(0);
11731 return RETVAL2NUM(retval);
11732#undef SYSCALL
11733#undef NUM2SYSCALLID
11734#undef RETVAL2NUM
11735}
11736#else
11737#define rb_f_syscall rb_f_notimplement
11738#endif
11739
11740static VALUE
11741io_new_instance(VALUE args)
11742{
11743 return rb_class_new_instance(2, (VALUE*)args+1, *(VALUE*)args);
11744}
11745
11746static rb_encoding *
11747find_encoding(VALUE v)
11748{
11749 rb_encoding *enc = rb_find_encoding(v);
11750 if (!enc) rb_warn("Unsupported encoding %"PRIsVALUE" ignored", v);
11751 return enc;
11752}
11753
11754static void
11755io_encoding_set(rb_io_t *fptr, VALUE v1, VALUE v2, VALUE opt)
11756{
11757 rb_encoding *enc, *enc2;
11758 int ecflags = fptr->encs.ecflags;
11759 VALUE ecopts, tmp;
11760
11761 if (!NIL_P(v2)) {
11762 enc2 = find_encoding(v1);
11763 tmp = rb_check_string_type(v2);
11764 if (!NIL_P(tmp)) {
11765 if (RSTRING_LEN(tmp) == 1 && RSTRING_PTR(tmp)[0] == '-') {
11766 /* Special case - "-" => no transcoding */
11767 enc = enc2;
11768 enc2 = NULL;
11769 }
11770 else
11771 enc = find_encoding(v2);
11772 if (enc == enc2) {
11773 /* Special case - "-" => no transcoding */
11774 enc2 = NULL;
11775 }
11776 }
11777 else {
11778 enc = find_encoding(v2);
11779 if (enc == enc2) {
11780 /* Special case - "-" => no transcoding */
11781 enc2 = NULL;
11782 }
11783 }
11784 if (enc2 == rb_ascii8bit_encoding()) {
11785 /* If external is ASCII-8BIT, no transcoding */
11786 enc = enc2;
11787 enc2 = NULL;
11788 }
11789 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11790 ecflags = rb_econv_prepare_options(opt, &ecopts, ecflags);
11791 }
11792 else {
11793 if (NIL_P(v1)) {
11794 /* Set to default encodings */
11795 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
11796 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11797 ecopts = Qnil;
11798 }
11799 else {
11800 tmp = rb_check_string_type(v1);
11801 if (!NIL_P(tmp) && rb_enc_asciicompat(enc = rb_enc_get(tmp))) {
11802 parse_mode_enc(RSTRING_PTR(tmp), enc, &enc, &enc2, NULL);
11803 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11804 ecflags = rb_econv_prepare_options(opt, &ecopts, ecflags);
11805 }
11806 else {
11807 rb_io_ext_int_to_encs(find_encoding(v1), NULL, &enc, &enc2, 0);
11808 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11809 ecopts = Qnil;
11810 }
11811 }
11812 }
11813 validate_enc_binmode(&fptr->mode, ecflags, enc, enc2);
11814 fptr->encs.enc = enc;
11815 fptr->encs.enc2 = enc2;
11816 fptr->encs.ecflags = ecflags;
11817 fptr->encs.ecopts = ecopts;
11818 clear_codeconv(fptr);
11819
11820}
11821
11823 rb_io_t *fptr;
11824 VALUE v1;
11825 VALUE v2;
11826 VALUE opt;
11827};
11828
11829static VALUE
11830io_encoding_set_v(VALUE v)
11831{
11832 struct io_encoding_set_args *arg = (struct io_encoding_set_args *)v;
11833 io_encoding_set(arg->fptr, arg->v1, arg->v2, arg->opt);
11834 return Qnil;
11835}
11836
11837static VALUE
11838pipe_pair_close(VALUE rw)
11839{
11840 VALUE *rwp = (VALUE *)rw;
11841 return rb_ensure(io_close, rwp[0], io_close, rwp[1]);
11842}
11843
11844/*
11845 * call-seq:
11846 * IO.pipe(**opts) -> [read_io, write_io]
11847 * IO.pipe(enc, **opts) -> [read_io, write_io]
11848 * IO.pipe(ext_enc, int_enc, **opts) -> [read_io, write_io]
11849 * IO.pipe(**opts) {|read_io, write_io| ...} -> object
11850 * IO.pipe(enc, **opts) {|read_io, write_io| ...} -> object
11851 * IO.pipe(ext_enc, int_enc, **opts) {|read_io, write_io| ...} -> object
11852 *
11853 * Creates a pair of pipe endpoints, +read_io+ and +write_io+,
11854 * connected to each other.
11855 *
11856 * If argument +enc_string+ is given, it must be a string containing one of:
11857 *
11858 * - The name of the encoding to be used as the external encoding.
11859 * - The colon-separated names of two encodings to be used as the external
11860 * and internal encodings.
11861 *
11862 * If argument +int_enc+ is given, it must be an Encoding object
11863 * or encoding name string that specifies the internal encoding to be used;
11864 * if argument +ext_enc+ is also given, it must be an Encoding object
11865 * or encoding name string that specifies the external encoding to be used.
11866 *
11867 * The string read from +read_io+ is tagged with the external encoding;
11868 * if an internal encoding is also specified, the string is converted
11869 * to, and tagged with, that encoding.
11870 *
11871 * If any encoding is specified,
11872 * optional hash arguments specify the conversion option.
11873 *
11874 * Optional keyword arguments +opts+ specify:
11875 *
11876 * - {Open Options}[rdoc-ref:IO@Open+Options].
11877 * - {Encoding Options}[rdoc-ref:encodings.rdoc@Encoding+Options].
11878 *
11879 * With no block given, returns the two endpoints in an array:
11880 *
11881 * IO.pipe # => [#<IO:fd 4>, #<IO:fd 5>]
11882 *
11883 * With a block given, calls the block with the two endpoints;
11884 * closes both endpoints and returns the value of the block:
11885 *
11886 * IO.pipe {|read_io, write_io| p read_io; p write_io }
11887 *
11888 * Output:
11889 *
11890 * #<IO:fd 6>
11891 * #<IO:fd 7>
11892 *
11893 * Not available on all platforms.
11894 *
11895 * In the example below, the two processes close the ends of the pipe
11896 * that they are not using. This is not just a cosmetic nicety. The
11897 * read end of a pipe will not generate an end of file condition if
11898 * there are any writers with the pipe still open. In the case of the
11899 * parent process, the <tt>rd.read</tt> will never return if it
11900 * does not first issue a <tt>wr.close</tt>:
11901 *
11902 * rd, wr = IO.pipe
11903 *
11904 * if fork
11905 * wr.close
11906 * puts "Parent got: <#{rd.read}>"
11907 * rd.close
11908 * Process.wait
11909 * else
11910 * rd.close
11911 * puts 'Sending message to parent'
11912 * wr.write "Hi Dad"
11913 * wr.close
11914 * end
11915 *
11916 * <em>produces:</em>
11917 *
11918 * Sending message to parent
11919 * Parent got: <Hi Dad>
11920 *
11921 */
11922
11923static VALUE
11924rb_io_s_pipe(int argc, VALUE *argv, VALUE klass)
11925{
11926 int pipes[2], state;
11927 VALUE r, w, args[3], v1, v2;
11928 VALUE opt;
11929 rb_io_t *fptr, *fptr2;
11930 struct io_encoding_set_args ies_args;
11931 enum rb_io_mode fmode = 0;
11932 VALUE ret;
11933
11934 argc = rb_scan_args(argc, argv, "02:", &v1, &v2, &opt);
11935 if (rb_pipe(pipes) < 0)
11936 rb_sys_fail(0);
11937
11938 args[0] = klass;
11939 args[1] = INT2NUM(pipes[0]);
11940 args[2] = INT2FIX(O_RDONLY);
11941 r = rb_protect(io_new_instance, (VALUE)args, &state);
11942 if (state) {
11943 close(pipes[0]);
11944 close(pipes[1]);
11945 rb_jump_tag(state);
11946 }
11947 GetOpenFile(r, fptr);
11948
11949 ies_args.fptr = fptr;
11950 ies_args.v1 = v1;
11951 ies_args.v2 = v2;
11952 ies_args.opt = opt;
11953 rb_protect(io_encoding_set_v, (VALUE)&ies_args, &state);
11954 if (state) {
11955 close(pipes[1]);
11956 io_close(r);
11957 rb_jump_tag(state);
11958 }
11959
11960 args[1] = INT2NUM(pipes[1]);
11961 args[2] = INT2FIX(O_WRONLY);
11962 w = rb_protect(io_new_instance, (VALUE)args, &state);
11963 if (state) {
11964 close(pipes[1]);
11965 if (!NIL_P(r)) rb_io_close(r);
11966 rb_jump_tag(state);
11967 }
11968 GetOpenFile(w, fptr2);
11969 rb_io_synchronized(fptr2);
11970
11971 extract_binmode(opt, &fmode);
11972
11973 if ((fmode & FMODE_BINMODE) && NIL_P(v1)) {
11976 }
11977
11978#if DEFAULT_TEXTMODE
11979 if ((fptr->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
11980 fptr->mode &= ~FMODE_TEXTMODE;
11981 setmode(fptr->fd, O_BINARY);
11982 }
11983#if RUBY_CRLF_ENVIRONMENT
11986 }
11987#endif
11988#endif
11989 fptr->mode |= fmode;
11990#if DEFAULT_TEXTMODE
11991 if ((fptr2->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
11992 fptr2->mode &= ~FMODE_TEXTMODE;
11993 setmode(fptr2->fd, O_BINARY);
11994 }
11995#endif
11996 fptr2->mode |= fmode;
11997
11998 ret = rb_assoc_new(r, w);
11999 if (rb_block_given_p()) {
12000 VALUE rw[2];
12001 rw[0] = r;
12002 rw[1] = w;
12003 return rb_ensure(rb_yield, ret, pipe_pair_close, (VALUE)rw);
12004 }
12005 return ret;
12006}
12007
12009 int argc;
12010 VALUE *argv;
12011 VALUE io;
12012};
12013
12014static void
12015open_key_args(VALUE klass, int argc, VALUE *argv, VALUE opt, struct foreach_arg *arg)
12016{
12017 VALUE path, v;
12018 VALUE vmode = Qnil, vperm = Qnil;
12019
12020 path = *argv++;
12021 argc--;
12022 FilePathValue(path);
12023 arg->io = 0;
12024 arg->argc = argc;
12025 arg->argv = argv;
12026 if (NIL_P(opt)) {
12027 vmode = INT2NUM(O_RDONLY);
12028 vperm = INT2FIX(0666);
12029 }
12030 else if (!NIL_P(v = rb_hash_aref(opt, sym_open_args))) {
12031 int n;
12032
12033 v = rb_to_array_type(v);
12034 n = RARRAY_LENINT(v);
12035 rb_check_arity(n, 0, 3); /* rb_io_open */
12036 rb_scan_args_kw(RB_SCAN_ARGS_LAST_HASH_KEYWORDS, n, RARRAY_CONST_PTR(v), "02:", &vmode, &vperm, &opt);
12037 }
12038 arg->io = rb_io_open(klass, path, vmode, vperm, opt);
12039}
12040
12041static VALUE
12042io_s_foreach(VALUE v)
12043{
12044 struct getline_arg *arg = (void *)v;
12045 VALUE str;
12046
12047 if (arg->limit == 0)
12048 rb_raise(rb_eArgError, "invalid limit: 0 for foreach");
12049 while (!NIL_P(str = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, arg->io))) {
12050 rb_lastline_set(str);
12051 rb_yield(str);
12052 }
12054 return Qnil;
12055}
12056
12057/*
12058 * call-seq:
12059 * IO.foreach(path, sep = $/, **opts) {|line| block } -> nil
12060 * IO.foreach(path, limit, **opts) {|line| block } -> nil
12061 * IO.foreach(path, sep, limit, **opts) {|line| block } -> nil
12062 * IO.foreach(...) -> an_enumerator
12063 *
12064 * Calls the block with each successive line read from the stream.
12065 *
12066 * When called from class \IO (but not subclasses of \IO),
12067 * this method has potential security vulnerabilities if called with untrusted input;
12068 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12069 *
12070 * The first argument must be a string that is the path to a file.
12071 *
12072 * With only argument +path+ given, parses lines from the file at the given +path+,
12073 * as determined by the default line separator,
12074 * and calls the block with each successive line:
12075 *
12076 * File.foreach('t.txt') {|line| p line }
12077 *
12078 * Output: the same as above.
12079 *
12080 * For both forms, command and path, the remaining arguments are the same.
12081 *
12082 * With argument +sep+ given, parses lines as determined by that line separator
12083 * (see {Line Separator}[rdoc-ref:IO@Line+Separator]):
12084 *
12085 * File.foreach('t.txt', 'li') {|line| p line }
12086 *
12087 * Output:
12088 *
12089 * "First li"
12090 * "ne\nSecond li"
12091 * "ne\n\nThird li"
12092 * "ne\nFourth li"
12093 * "ne\n"
12094 *
12095 * Each paragraph:
12096 *
12097 * File.foreach('t.txt', '') {|paragraph| p paragraph }
12098 *
12099 * Output:
12100 *
12101 * "First line\nSecond line\n\n"
12102 * "Third line\nFourth line\n"
12103 *
12104 * With argument +limit+ given, parses lines as determined by the default
12105 * line separator and the given line-length limit
12106 * (see {Line Separator}[rdoc-ref:IO@Line+Separator] and {Line Limit}[rdoc-ref:IO@Line+Limit]):
12107 *
12108 * File.foreach('t.txt', 7) {|line| p line }
12109 *
12110 * Output:
12111 *
12112 * "First l"
12113 * "ine\n"
12114 * "Second "
12115 * "line\n"
12116 * "\n"
12117 * "Third l"
12118 * "ine\n"
12119 * "Fourth l"
12120 * "line\n"
12121 *
12122 * With arguments +sep+ and +limit+ given,
12123 * combines the two behaviors
12124 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
12125 *
12126 * Optional keyword arguments +opts+ specify:
12127 *
12128 * - {Open Options}[rdoc-ref:IO@Open+Options].
12129 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12130 * - {Line Options}[rdoc-ref:IO@Line+IO].
12131 *
12132 * Returns an Enumerator if no block is given.
12133 *
12134 */
12135
12136static VALUE
12137rb_io_s_foreach(int argc, VALUE *argv, VALUE self)
12138{
12139 VALUE opt;
12140 int orig_argc = argc;
12141 struct foreach_arg arg;
12142 struct getline_arg garg;
12143
12144 argc = rb_scan_args(argc, argv, "12:", NULL, NULL, NULL, &opt);
12145 RETURN_ENUMERATOR(self, orig_argc, argv);
12146 extract_getline_args(argc-1, argv+1, &garg);
12147 open_key_args(self, argc, argv, opt, &arg);
12148 if (NIL_P(arg.io)) return Qnil;
12149 extract_getline_opts(opt, &garg);
12150 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12151 return rb_ensure(io_s_foreach, (VALUE)&garg, rb_io_close, arg.io);
12152}
12153
12154static VALUE
12155io_s_readlines(VALUE v)
12156{
12157 struct getline_arg *arg = (void *)v;
12158 return io_readlines(arg, arg->io);
12159}
12160
12161/*
12162 * call-seq:
12163 * IO.readlines(path, sep = $/, **opts) -> array
12164 * IO.readlines(path, limit, **opts) -> array
12165 * IO.readlines(path, sep, limit, **opts) -> array
12166 *
12167 * Returns an array of all lines read from the stream.
12168 *
12169 * When called from class \IO (but not subclasses of \IO),
12170 * this method has potential security vulnerabilities if called with untrusted input;
12171 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12172 *
12173 * The first argument must be a string that is the path to a file.
12174 *
12175 * With only argument +path+ given, parses lines from the file at the given +path+,
12176 * as determined by the default line separator,
12177 * and returns those lines in an array:
12178 *
12179 * IO.readlines('t.txt')
12180 * # => ["First line\n", "Second line\n", "\n", "Third line\n", "Fourth line\n"]
12181 *
12182 * With argument +sep+ given, parses lines as determined by that line separator
12183 * (see {Line Separator}[rdoc-ref:IO@Line+Separator]):
12184 *
12185 * # Ordinary separator.
12186 * IO.readlines('t.txt', 'li')
12187 * # =>["First li", "ne\nSecond li", "ne\n\nThird li", "ne\nFourth li", "ne\n"]
12188 * # Get-paragraphs separator.
12189 * IO.readlines('t.txt', '')
12190 * # => ["First line\nSecond line\n\n", "Third line\nFourth line\n"]
12191 * # Get-all separator.
12192 * IO.readlines('t.txt', nil)
12193 * # => ["First line\nSecond line\n\nThird line\nFourth line\n"]
12194 *
12195 * With argument +limit+ given, parses lines as determined by the default
12196 * line separator and the given line-length limit
12197 * (see {Line Separator}[rdoc-ref:IO@Line+Separator] and {Line Limit}[rdoc-ref:IO@Line+Limit]:
12198 *
12199 * IO.readlines('t.txt', 7)
12200 * # => ["First l", "ine\n", "Second ", "line\n", "\n", "Third l", "ine\n", "Fourth ", "line\n"]
12201 *
12202 * With arguments +sep+ and +limit+ given,
12203 * combines the two behaviors
12204 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
12205 *
12206 * Optional keyword arguments +opts+ specify:
12207 *
12208 * - {Open Options}[rdoc-ref:IO@Open+Options].
12209 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12210 * - {Line Options}[rdoc-ref:IO@Line+IO].
12211 *
12212 */
12213
12214static VALUE
12215rb_io_s_readlines(int argc, VALUE *argv, VALUE io)
12216{
12217 VALUE opt;
12218 struct foreach_arg arg;
12219 struct getline_arg garg;
12220
12221 argc = rb_scan_args(argc, argv, "12:", NULL, NULL, NULL, &opt);
12222 extract_getline_args(argc-1, argv+1, &garg);
12223 open_key_args(io, argc, argv, opt, &arg);
12224 if (NIL_P(arg.io)) return Qnil;
12225 extract_getline_opts(opt, &garg);
12226 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12227 return rb_ensure(io_s_readlines, (VALUE)&garg, rb_io_close, arg.io);
12228}
12229
12230static VALUE
12231io_s_read(VALUE v)
12232{
12233 struct foreach_arg *arg = (void *)v;
12234 return io_read(arg->argc, arg->argv, arg->io);
12235}
12236
12237struct seek_arg {
12238 VALUE io;
12239 VALUE offset;
12240 int mode;
12241};
12242
12243static VALUE
12244seek_before_access(VALUE argp)
12245{
12246 struct seek_arg *arg = (struct seek_arg *)argp;
12247 rb_io_binmode(arg->io);
12248 return rb_io_seek(arg->io, arg->offset, arg->mode);
12249}
12250
12251/*
12252 * call-seq:
12253 * IO.read(path, length = nil, offset = 0, **opts) -> string or nil
12254 *
12255 * Opens the stream, reads and returns some or all of its content,
12256 * and closes the stream; returns +nil+ if no bytes were read.
12257 *
12258 * When called from class \IO (but not subclasses of \IO),
12259 * this method has potential security vulnerabilities if called with untrusted input;
12260 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12261 *
12262 * The first argument must be a string that is the path to a file.
12263 *
12264 * With only argument +path+ given, reads in text mode and returns the entire content
12265 * of the file at the given path:
12266 *
12267 * IO.read('t.txt')
12268 * # => "First line\nSecond line\n\nThird line\nFourth line\n"
12269 *
12270 * On Windows, text mode can terminate reading and leave bytes in the file
12271 * unread when encountering certain special bytes. Consider using
12272 * IO.binread if all bytes in the file should be read.
12273 *
12274 * With argument +length+, returns +length+ bytes if available:
12275 *
12276 * IO.read('t.txt', 7) # => "First l"
12277 * IO.read('t.txt', 700)
12278 * # => "First line\r\nSecond line\r\n\r\nFourth line\r\nFifth line\r\n"
12279 *
12280 * With arguments +length+ and +offset+, returns +length+ bytes
12281 * if available, beginning at the given +offset+:
12282 *
12283 * IO.read('t.txt', 10, 2) # => "rst line\nS"
12284 * IO.read('t.txt', 10, 200) # => nil
12285 *
12286 * Optional keyword arguments +opts+ specify:
12287 *
12288 * - {Open Options}[rdoc-ref:IO@Open+Options].
12289 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12290 *
12291 */
12292
12293static VALUE
12294rb_io_s_read(int argc, VALUE *argv, VALUE io)
12295{
12296 VALUE opt, offset;
12297 long off;
12298 struct foreach_arg arg;
12299
12300 argc = rb_scan_args(argc, argv, "13:", NULL, NULL, &offset, NULL, &opt);
12301 if (!NIL_P(offset) && (off = NUM2LONG(offset)) < 0) {
12302 rb_raise(rb_eArgError, "negative offset %ld given", off);
12303 }
12304 open_key_args(io, argc, argv, opt, &arg);
12305 if (NIL_P(arg.io)) return Qnil;
12306 if (!NIL_P(offset)) {
12307 struct seek_arg sarg;
12308 int state = 0;
12309 sarg.io = arg.io;
12310 sarg.offset = offset;
12311 sarg.mode = SEEK_SET;
12312 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12313 if (state) {
12314 rb_io_close(arg.io);
12315 rb_jump_tag(state);
12316 }
12317 if (arg.argc == 2) arg.argc = 1;
12318 }
12319 return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
12320}
12321
12322/*
12323 * call-seq:
12324 * IO.binread(path, length = nil, offset = 0) -> string or nil
12325 *
12326 * Behaves like IO.read, except that the stream is opened in binary mode
12327 * with ASCII-8BIT encoding.
12328 *
12329 * When called from class \IO (but not subclasses of \IO),
12330 * this method has potential security vulnerabilities if called with untrusted input;
12331 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12332 *
12333 */
12334
12335static VALUE
12336rb_io_s_binread(int argc, VALUE *argv, VALUE io)
12337{
12338 VALUE offset;
12339 struct foreach_arg arg;
12340 enum rb_io_mode fmode = FMODE_READABLE|FMODE_BINMODE;
12341 enum {
12342 oflags = O_RDONLY
12343#ifdef O_BINARY
12344 |O_BINARY
12345#endif
12346 };
12347 struct rb_io_encoding convconfig = {NULL, NULL, 0, Qnil};
12348
12349 rb_scan_args(argc, argv, "12", NULL, NULL, &offset);
12350 FilePathValue(argv[0]);
12351 convconfig.enc = rb_ascii8bit_encoding();
12352 arg.io = rb_io_open_generic(io, argv[0], oflags, fmode, &convconfig, 0);
12353 if (NIL_P(arg.io)) return Qnil;
12354 arg.argv = argv+1;
12355 arg.argc = (argc > 1) ? 1 : 0;
12356 if (!NIL_P(offset)) {
12357 struct seek_arg sarg;
12358 int state = 0;
12359 sarg.io = arg.io;
12360 sarg.offset = offset;
12361 sarg.mode = SEEK_SET;
12362 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12363 if (state) {
12364 rb_io_close(arg.io);
12365 rb_jump_tag(state);
12366 }
12367 }
12368 return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
12369}
12370
12371static VALUE
12372io_s_write0(VALUE v)
12373{
12374 struct write_arg *arg = (void *)v;
12375 return io_write(arg->io,arg->str,arg->nosync);
12376}
12377
12378static VALUE
12379io_s_write(int argc, VALUE *argv, VALUE klass, int binary)
12380{
12381 VALUE string, offset, opt;
12382 struct foreach_arg arg;
12383 struct write_arg warg;
12384
12385 rb_scan_args(argc, argv, "21:", NULL, &string, &offset, &opt);
12386
12387 if (NIL_P(opt)) opt = rb_hash_new();
12388 else opt = rb_hash_dup(opt);
12389
12390
12391 if (NIL_P(rb_hash_aref(opt,sym_mode))) {
12392 int mode = O_WRONLY|O_CREAT;
12393#ifdef O_BINARY
12394 if (binary) mode |= O_BINARY;
12395#endif
12396 if (NIL_P(offset)) mode |= O_TRUNC;
12397 rb_hash_aset(opt,sym_mode,INT2NUM(mode));
12398 }
12399 open_key_args(klass, argc, argv, opt, &arg);
12400
12401#ifndef O_BINARY
12402 if (binary) rb_io_binmode_m(arg.io);
12403#endif
12404
12405 if (NIL_P(arg.io)) return Qnil;
12406 if (!NIL_P(offset)) {
12407 struct seek_arg sarg;
12408 int state = 0;
12409 sarg.io = arg.io;
12410 sarg.offset = offset;
12411 sarg.mode = SEEK_SET;
12412 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12413 if (state) {
12414 rb_io_close(arg.io);
12415 rb_jump_tag(state);
12416 }
12417 }
12418
12419 warg.io = arg.io;
12420 warg.str = string;
12421 warg.nosync = 0;
12422
12423 return rb_ensure(io_s_write0, (VALUE)&warg, rb_io_close, arg.io);
12424}
12425
12426/*
12427 * call-seq:
12428 * IO.write(path, data, offset = 0, **opts) -> integer
12429 *
12430 * Opens the stream, writes the given +data+ to it,
12431 * and closes the stream; returns the number of bytes written.
12432 *
12433 * When called from class \IO (but not subclasses of \IO),
12434 * this method has potential security vulnerabilities if called with untrusted input;
12435 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12436 *
12437 * The first argument must be a string that is the path to a file.
12438 *
12439 * With only argument +path+ given, writes the given +data+ to the file at that path:
12440 *
12441 * IO.write('t.tmp', 'abc') # => 3
12442 * File.read('t.tmp') # => "abc"
12443 *
12444 * If +offset+ is zero (the default), the file is overwritten:
12445 *
12446 * IO.write('t.tmp', 'A') # => 1
12447 * File.read('t.tmp') # => "A"
12448 *
12449 * If +offset+ in within the file content, the file is partly overwritten:
12450 *
12451 * IO.write('t.tmp', 'abcdef') # => 3
12452 * File.read('t.tmp') # => "abcdef"
12453 * # Offset within content.
12454 * IO.write('t.tmp', '012', 2) # => 3
12455 * File.read('t.tmp') # => "ab012f"
12456 *
12457 * If +offset+ is outside the file content,
12458 * the file is padded with null characters <tt>"\u0000"</tt>:
12459 *
12460 * IO.write('t.tmp', 'xyz', 10) # => 3
12461 * File.read('t.tmp') # => "ab012f\u0000\u0000\u0000\u0000xyz"
12462 *
12463 * Optional keyword arguments +opts+ specify:
12464 *
12465 * - {Open Options}[rdoc-ref:IO@Open+Options].
12466 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12467 *
12468 */
12469
12470static VALUE
12471rb_io_s_write(int argc, VALUE *argv, VALUE io)
12472{
12473 return io_s_write(argc, argv, io, 0);
12474}
12475
12476/*
12477 * call-seq:
12478 * IO.binwrite(path, string, offset = 0) -> integer
12479 *
12480 * Behaves like IO.write, except that the stream is opened in binary mode
12481 * with ASCII-8BIT encoding.
12482 *
12483 * When called from class \IO (but not subclasses of \IO),
12484 * this method has potential security vulnerabilities if called with untrusted input;
12485 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12486 *
12487 */
12488
12489static VALUE
12490rb_io_s_binwrite(int argc, VALUE *argv, VALUE io)
12491{
12492 return io_s_write(argc, argv, io, 1);
12493}
12494
12496 VALUE src;
12497 VALUE dst;
12498 rb_off_t copy_length; /* (rb_off_t)-1 if not specified */
12499 rb_off_t src_offset; /* (rb_off_t)-1 if not specified */
12500
12501 rb_io_t *src_fptr;
12502 rb_io_t *dst_fptr;
12503 unsigned close_src : 1;
12504 unsigned close_dst : 1;
12505 int error_no;
12506 rb_off_t total;
12507 const char *syserr;
12508 const char *notimp;
12509 VALUE th;
12510 struct stat src_stat;
12511 struct stat dst_stat;
12512#ifdef HAVE_FCOPYFILE
12513 copyfile_state_t copyfile_state;
12514#endif
12515};
12516
12517static void *
12518exec_interrupts(void *arg)
12519{
12520 VALUE th = (VALUE)arg;
12521 rb_thread_execute_interrupts(th);
12522 return NULL;
12523}
12524
12525/*
12526 * returns TRUE if the preceding system call was interrupted
12527 * so we can continue. If the thread was interrupted, we
12528 * reacquire the GVL to execute interrupts before continuing.
12529 */
12530static int
12531maygvl_copy_stream_continue_p(int has_gvl, struct copy_stream_struct *stp)
12532{
12533 switch (errno) {
12534 case EINTR:
12535#if defined(ERESTART)
12536 case ERESTART:
12537#endif
12538 if (rb_thread_interrupted(stp->th)) {
12539 if (has_gvl)
12540 rb_thread_execute_interrupts(stp->th);
12541 else
12542 rb_thread_call_with_gvl(exec_interrupts, (void *)stp->th);
12543 }
12544 return TRUE;
12545 }
12546 return FALSE;
12547}
12548
12550 VALUE scheduler;
12551
12552 rb_io_t *fptr;
12553 short events;
12554
12555 VALUE result;
12556};
12557
12558static void *
12559fiber_scheduler_wait_for(void * _arguments)
12560{
12561 struct fiber_scheduler_wait_for_arguments *arguments = (struct fiber_scheduler_wait_for_arguments *)_arguments;
12562
12563 arguments->result = rb_fiber_scheduler_io_wait(arguments->scheduler, arguments->fptr->self, INT2NUM(arguments->events), RUBY_IO_TIMEOUT_DEFAULT);
12564
12565 return NULL;
12566}
12567
12568#if USE_POLL
12569# define IOWAIT_SYSCALL "poll"
12570STATIC_ASSERT(pollin_expected, POLLIN == RB_WAITFD_IN);
12571STATIC_ASSERT(pollout_expected, POLLOUT == RB_WAITFD_OUT);
12572static int
12573nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout)
12574{
12576 if (scheduler != Qnil) {
12577 struct fiber_scheduler_wait_for_arguments args = {.scheduler = scheduler, .fptr = fptr, .events = events};
12578 rb_thread_call_with_gvl(fiber_scheduler_wait_for, &args);
12579 return RTEST(args.result);
12580 }
12581
12582 int fd = fptr->fd;
12583 if (fd == -1) return 0;
12584
12585 struct pollfd fds;
12586
12587 fds.fd = fd;
12588 fds.events = events;
12589
12590 int timeout_milliseconds = -1;
12591
12592 if (timeout) {
12593 timeout_milliseconds = (int)(timeout->tv_sec * 1000) + (int)(timeout->tv_usec / 1000);
12594 }
12595
12596 return poll(&fds, 1, timeout_milliseconds);
12597}
12598#else /* !USE_POLL */
12599# define IOWAIT_SYSCALL "select"
12600static int
12601nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout)
12602{
12604 if (scheduler != Qnil) {
12605 struct fiber_scheduler_wait_for_arguments args = {.scheduler = scheduler, .fptr = fptr, .events = events};
12606 rb_thread_call_with_gvl(fiber_scheduler_wait_for, &args);
12607 return RTEST(args.result);
12608 }
12609
12610 int fd = fptr->fd;
12611
12612 if (fd == -1) {
12613 errno = EBADF;
12614 return -1;
12615 }
12616
12617 rb_fdset_t fds;
12618 int ret;
12619
12620 rb_fd_init(&fds);
12621 rb_fd_set(fd, &fds);
12622
12623 switch (events) {
12624 case RB_WAITFD_IN:
12625 ret = rb_fd_select(fd + 1, &fds, 0, 0, timeout);
12626 break;
12627 case RB_WAITFD_OUT:
12628 ret = rb_fd_select(fd + 1, 0, &fds, 0, timeout);
12629 break;
12630 default:
12631 VM_UNREACHABLE(nogvl_wait_for);
12632 }
12633
12634 rb_fd_term(&fds);
12635
12636 // On timeout, this returns 0.
12637 return ret;
12638}
12639#endif /* !USE_POLL */
12640
12641static int
12642maygvl_copy_stream_wait_read(int has_gvl, struct copy_stream_struct *stp)
12643{
12644 int ret;
12645
12646 do {
12647 if (has_gvl) {
12649 }
12650 else {
12651 ret = nogvl_wait_for(stp->th, stp->src_fptr, RB_WAITFD_IN, NULL);
12652 }
12653 } while (ret < 0 && maygvl_copy_stream_continue_p(has_gvl, stp));
12654
12655 if (ret < 0) {
12656 stp->syserr = IOWAIT_SYSCALL;
12657 stp->error_no = errno;
12658 return ret;
12659 }
12660 return 0;
12661}
12662
12663static int
12664nogvl_copy_stream_wait_write(struct copy_stream_struct *stp)
12665{
12666 int ret;
12667
12668 do {
12669 ret = nogvl_wait_for(stp->th, stp->dst_fptr, RB_WAITFD_OUT, NULL);
12670 } while (ret < 0 && maygvl_copy_stream_continue_p(0, stp));
12671
12672 if (ret < 0) {
12673 stp->syserr = IOWAIT_SYSCALL;
12674 stp->error_no = errno;
12675 return ret;
12676 }
12677 return 0;
12678}
12679
12680#ifdef USE_COPY_FILE_RANGE
12681
12682static ssize_t
12683simple_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)
12684{
12685#ifdef HAVE_COPY_FILE_RANGE
12686 return copy_file_range(in_fd, in_offset, out_fd, out_offset, count, flags);
12687#else
12688 return syscall(__NR_copy_file_range, in_fd, in_offset, out_fd, out_offset, count, flags);
12689#endif
12690}
12691
12692static int
12693nogvl_copy_file_range(struct copy_stream_struct *stp)
12694{
12695 ssize_t ss;
12696 rb_off_t src_size;
12697 rb_off_t copy_length, src_offset, *src_offset_ptr;
12698
12699 if (!S_ISREG(stp->src_stat.st_mode))
12700 return 0;
12701
12702 src_size = stp->src_stat.st_size;
12703 src_offset = stp->src_offset;
12704 if (src_offset >= (rb_off_t)0) {
12705 src_offset_ptr = &src_offset;
12706 }
12707 else {
12708 src_offset_ptr = NULL; /* if src_offset_ptr is NULL, then bytes are read from in_fd starting from the file offset */
12709 }
12710
12711 copy_length = stp->copy_length;
12712 if (copy_length < (rb_off_t)0) {
12713 if (src_offset < (rb_off_t)0) {
12714 rb_off_t current_offset;
12715 errno = 0;
12716 current_offset = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12717 if (current_offset < (rb_off_t)0 && errno) {
12718 stp->syserr = "lseek";
12719 stp->error_no = errno;
12720 return (int)current_offset;
12721 }
12722 copy_length = src_size - current_offset;
12723 }
12724 else {
12725 copy_length = src_size - src_offset;
12726 }
12727 }
12728
12729 retry_copy_file_range:
12730# if SIZEOF_OFF_T > SIZEOF_SIZE_T
12731 /* we are limited by the 32-bit ssize_t return value on 32-bit */
12732 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
12733# else
12734 ss = (ssize_t)copy_length;
12735# endif
12736 ss = simple_copy_file_range(stp->src_fptr->fd, src_offset_ptr, stp->dst_fptr->fd, NULL, ss, 0);
12737 if (0 < ss) {
12738 stp->total += ss;
12739 copy_length -= ss;
12740 if (0 < copy_length) {
12741 goto retry_copy_file_range;
12742 }
12743 }
12744 if (ss < 0) {
12745 if (maygvl_copy_stream_continue_p(0, stp)) {
12746 goto retry_copy_file_range;
12747 }
12748 switch (errno) {
12749 case EINVAL:
12750 case EPERM: /* copy_file_range(2) doesn't exist (may happen in
12751 docker container) */
12752#ifdef ENOSYS
12753 case ENOSYS:
12754#endif
12755#ifdef EXDEV
12756 case EXDEV: /* in_fd and out_fd are not on the same filesystem */
12757#endif
12758 return 0;
12759 case EAGAIN:
12760#if EWOULDBLOCK != EAGAIN
12761 case EWOULDBLOCK:
12762#endif
12763 {
12764 int ret = nogvl_copy_stream_wait_write(stp);
12765 if (ret < 0) return ret;
12766 }
12767 goto retry_copy_file_range;
12768 case EBADF:
12769 {
12770 int e = errno;
12771 int flags = fcntl(stp->dst_fptr->fd, F_GETFL);
12772
12773 if (flags != -1 && flags & O_APPEND) {
12774 return 0;
12775 }
12776 errno = e;
12777 }
12778 }
12779 stp->syserr = "copy_file_range";
12780 stp->error_no = errno;
12781 return (int)ss;
12782 }
12783 return 1;
12784}
12785#endif
12786
12787#ifdef HAVE_FCOPYFILE
12788static int
12789nogvl_fcopyfile(struct copy_stream_struct *stp)
12790{
12791 rb_off_t cur, ss = 0;
12792 const rb_off_t src_offset = stp->src_offset;
12793 int ret;
12794
12795 if (stp->copy_length >= (rb_off_t)0) {
12796 /* copy_length can't be specified in fcopyfile(3) */
12797 return 0;
12798 }
12799
12800 if (!S_ISREG(stp->src_stat.st_mode))
12801 return 0;
12802
12803 if (!S_ISREG(stp->dst_stat.st_mode))
12804 return 0;
12805 if (lseek(stp->dst_fptr->fd, 0, SEEK_CUR) > (rb_off_t)0) /* if dst IO was already written */
12806 return 0;
12807 if (fcntl(stp->dst_fptr->fd, F_GETFL) & O_APPEND) {
12808 /* fcopyfile(3) appends src IO to dst IO and then truncates
12809 * dst IO to src IO's original size. */
12810 rb_off_t end = lseek(stp->dst_fptr->fd, 0, SEEK_END);
12811 lseek(stp->dst_fptr->fd, 0, SEEK_SET);
12812 if (end > (rb_off_t)0) return 0;
12813 }
12814
12815 if (src_offset > (rb_off_t)0) {
12816 rb_off_t r;
12817
12818 /* get current offset */
12819 errno = 0;
12820 cur = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12821 if (cur < (rb_off_t)0 && errno) {
12822 stp->error_no = errno;
12823 return 1;
12824 }
12825
12826 errno = 0;
12827 r = lseek(stp->src_fptr->fd, src_offset, SEEK_SET);
12828 if (r < (rb_off_t)0 && errno) {
12829 stp->error_no = errno;
12830 return 1;
12831 }
12832 }
12833
12834 stp->copyfile_state = copyfile_state_alloc(); /* this will be freed by copy_stream_finalize() */
12835 ret = fcopyfile(stp->src_fptr->fd, stp->dst_fptr->fd, stp->copyfile_state, COPYFILE_DATA);
12836 copyfile_state_get(stp->copyfile_state, COPYFILE_STATE_COPIED, &ss); /* get copied bytes */
12837
12838 if (ret == 0) { /* success */
12839 stp->total = ss;
12840 if (src_offset > (rb_off_t)0) {
12841 rb_off_t r;
12842 errno = 0;
12843 /* reset offset */
12844 r = lseek(stp->src_fptr->fd, cur, SEEK_SET);
12845 if (r < (rb_off_t)0 && errno) {
12846 stp->error_no = errno;
12847 return 1;
12848 }
12849 }
12850 }
12851 else {
12852 switch (errno) {
12853 case ENOTSUP:
12854 case EPERM:
12855 case EINVAL:
12856 return 0;
12857 }
12858 stp->syserr = "fcopyfile";
12859 stp->error_no = errno;
12860 return (int)ret;
12861 }
12862 return 1;
12863}
12864#endif
12865
12866#ifdef HAVE_SENDFILE
12867
12868# ifdef __linux__
12869# define USE_SENDFILE
12870
12871# ifdef HAVE_SYS_SENDFILE_H
12872# include <sys/sendfile.h>
12873# endif
12874
12875static ssize_t
12876simple_sendfile(int out_fd, int in_fd, rb_off_t *offset, rb_off_t count)
12877{
12878 return sendfile(out_fd, in_fd, offset, (size_t)count);
12879}
12880
12881# elif 0 /* defined(__FreeBSD__) || defined(__DragonFly__) */ || defined(__APPLE__)
12882/* This runs on FreeBSD8.1 r30210, but sendfiles blocks its execution
12883 * without cpuset -l 0.
12884 */
12885# define USE_SENDFILE
12886
12887static ssize_t
12888simple_sendfile(int out_fd, int in_fd, rb_off_t *offset, rb_off_t count)
12889{
12890 int r;
12891 rb_off_t pos = offset ? *offset : lseek(in_fd, 0, SEEK_CUR);
12892 rb_off_t sbytes;
12893# ifdef __APPLE__
12894 r = sendfile(in_fd, out_fd, pos, &count, NULL, 0);
12895 sbytes = count;
12896# else
12897 r = sendfile(in_fd, out_fd, pos, (size_t)count, NULL, &sbytes, 0);
12898# endif
12899 if (r != 0 && sbytes == 0) return r;
12900 if (offset) {
12901 *offset += sbytes;
12902 }
12903 else {
12904 lseek(in_fd, sbytes, SEEK_CUR);
12905 }
12906 return (ssize_t)sbytes;
12907}
12908
12909# endif
12910
12911#endif
12912
12913#ifdef USE_SENDFILE
12914static int
12915nogvl_copy_stream_sendfile(struct copy_stream_struct *stp)
12916{
12917 ssize_t ss;
12918 rb_off_t src_size;
12919 rb_off_t copy_length;
12920 rb_off_t src_offset;
12921 int use_pread;
12922
12923 if (!S_ISREG(stp->src_stat.st_mode))
12924 return 0;
12925
12926 src_size = stp->src_stat.st_size;
12927#ifndef __linux__
12928 if ((stp->dst_stat.st_mode & S_IFMT) != S_IFSOCK)
12929 return 0;
12930#endif
12931
12932 src_offset = stp->src_offset;
12933 use_pread = src_offset >= (rb_off_t)0;
12934
12935 copy_length = stp->copy_length;
12936 if (copy_length < (rb_off_t)0) {
12937 if (use_pread)
12938 copy_length = src_size - src_offset;
12939 else {
12940 rb_off_t cur;
12941 errno = 0;
12942 cur = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12943 if (cur < (rb_off_t)0 && errno) {
12944 stp->syserr = "lseek";
12945 stp->error_no = errno;
12946 return (int)cur;
12947 }
12948 copy_length = src_size - cur;
12949 }
12950 }
12951
12952 retry_sendfile:
12953# if SIZEOF_OFF_T > SIZEOF_SIZE_T
12954 /* we are limited by the 32-bit ssize_t return value on 32-bit */
12955 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
12956# else
12957 ss = (ssize_t)copy_length;
12958# endif
12959 if (use_pread) {
12960 ss = simple_sendfile(stp->dst_fptr->fd, stp->src_fptr->fd, &src_offset, ss);
12961 }
12962 else {
12963 ss = simple_sendfile(stp->dst_fptr->fd, stp->src_fptr->fd, NULL, ss);
12964 }
12965 if (0 < ss) {
12966 stp->total += ss;
12967 copy_length -= ss;
12968 if (0 < copy_length) {
12969 goto retry_sendfile;
12970 }
12971 }
12972 if (ss < 0) {
12973 if (maygvl_copy_stream_continue_p(0, stp))
12974 goto retry_sendfile;
12975 switch (errno) {
12976 case EINVAL:
12977#ifdef ENOSYS
12978 case ENOSYS:
12979#endif
12980#ifdef EOPNOTSUP
12981 /* some RedHat kernels may return EOPNOTSUP on an NFS mount.
12982 see also: [Feature #16965] */
12983 case EOPNOTSUP:
12984#endif
12985 return 0;
12986 case EAGAIN:
12987#if EWOULDBLOCK != EAGAIN
12988 case EWOULDBLOCK:
12989#endif
12990 {
12991 int ret;
12992#ifndef __linux__
12993 /*
12994 * Linux requires stp->src_fptr->fd to be a mmap-able (regular) file,
12995 * select() reports regular files to always be "ready", so
12996 * there is no need to select() on it.
12997 * Other OSes may have the same limitation for sendfile() which
12998 * allow us to bypass maygvl_copy_stream_wait_read()...
12999 */
13000 ret = maygvl_copy_stream_wait_read(0, stp);
13001 if (ret < 0) return ret;
13002#endif
13003 ret = nogvl_copy_stream_wait_write(stp);
13004 if (ret < 0) return ret;
13005 }
13006 goto retry_sendfile;
13007 }
13008 stp->syserr = "sendfile";
13009 stp->error_no = errno;
13010 return (int)ss;
13011 }
13012 return 1;
13013}
13014#endif
13015
13016static ssize_t
13017maygvl_read(int has_gvl, rb_io_t *fptr, void *buf, size_t count)
13018{
13019 if (has_gvl)
13020 return rb_io_read_memory(fptr, buf, count);
13021 else
13022 return read(fptr->fd, buf, count);
13023}
13024
13025static ssize_t
13026maygvl_copy_stream_read(int has_gvl, struct copy_stream_struct *stp, char *buf, size_t len, rb_off_t offset)
13027{
13028 ssize_t ss;
13029 retry_read:
13030 if (offset < (rb_off_t)0) {
13031 ss = maygvl_read(has_gvl, stp->src_fptr, buf, len);
13032 }
13033 else {
13034 ss = pread(stp->src_fptr->fd, buf, len, offset);
13035 }
13036 if (ss == 0) {
13037 return 0;
13038 }
13039 if (ss < 0) {
13040 if (maygvl_copy_stream_continue_p(has_gvl, stp))
13041 goto retry_read;
13042 switch (errno) {
13043 case EAGAIN:
13044#if EWOULDBLOCK != EAGAIN
13045 case EWOULDBLOCK:
13046#endif
13047 {
13048 int ret = maygvl_copy_stream_wait_read(has_gvl, stp);
13049 if (ret < 0) return ret;
13050 }
13051 goto retry_read;
13052#ifdef ENOSYS
13053 case ENOSYS:
13054 stp->notimp = "pread";
13055 return ss;
13056#endif
13057 }
13058 stp->syserr = offset < (rb_off_t)0 ? "read" : "pread";
13059 stp->error_no = errno;
13060 }
13061 return ss;
13062}
13063
13064static int
13065nogvl_copy_stream_write(struct copy_stream_struct *stp, char *buf, size_t len)
13066{
13067 ssize_t ss;
13068 int off = 0;
13069 while (len) {
13070 ss = write(stp->dst_fptr->fd, buf+off, len);
13071 if (ss < 0) {
13072 if (maygvl_copy_stream_continue_p(0, stp))
13073 continue;
13074 if (io_again_p(errno)) {
13075 int ret = nogvl_copy_stream_wait_write(stp);
13076 if (ret < 0) return ret;
13077 continue;
13078 }
13079 stp->syserr = "write";
13080 stp->error_no = errno;
13081 return (int)ss;
13082 }
13083 off += (int)ss;
13084 len -= (int)ss;
13085 stp->total += ss;
13086 }
13087 return 0;
13088}
13089
13090static void
13091nogvl_copy_stream_read_write(struct copy_stream_struct *stp)
13092{
13093 char buf[1024*16];
13094 size_t len;
13095 ssize_t ss;
13096 int ret;
13097 rb_off_t copy_length;
13098 rb_off_t src_offset;
13099 int use_eof;
13100 int use_pread;
13101
13102 copy_length = stp->copy_length;
13103 use_eof = copy_length < (rb_off_t)0;
13104 src_offset = stp->src_offset;
13105 use_pread = src_offset >= (rb_off_t)0;
13106
13107 if (use_pread && stp->close_src) {
13108 rb_off_t r;
13109 errno = 0;
13110 r = lseek(stp->src_fptr->fd, src_offset, SEEK_SET);
13111 if (r < (rb_off_t)0 && errno) {
13112 stp->syserr = "lseek";
13113 stp->error_no = errno;
13114 return;
13115 }
13116 src_offset = (rb_off_t)-1;
13117 use_pread = 0;
13118 }
13119
13120 while (use_eof || 0 < copy_length) {
13121 if (!use_eof && copy_length < (rb_off_t)sizeof(buf)) {
13122 len = (size_t)copy_length;
13123 }
13124 else {
13125 len = sizeof(buf);
13126 }
13127 if (use_pread) {
13128 ss = maygvl_copy_stream_read(0, stp, buf, len, src_offset);
13129 if (0 < ss)
13130 src_offset += ss;
13131 }
13132 else {
13133 ss = maygvl_copy_stream_read(0, stp, buf, len, (rb_off_t)-1);
13134 }
13135 if (ss <= 0) /* EOF or error */
13136 return;
13137
13138 ret = nogvl_copy_stream_write(stp, buf, ss);
13139 if (ret < 0)
13140 return;
13141
13142 if (!use_eof)
13143 copy_length -= ss;
13144 }
13145}
13146
13147static void *
13148nogvl_copy_stream_func(void *arg)
13149{
13150 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13151#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13152 int ret;
13153#endif
13154
13155#ifdef USE_COPY_FILE_RANGE
13156 ret = nogvl_copy_file_range(stp);
13157 if (ret != 0)
13158 goto finish; /* error or success */
13159#endif
13160
13161#ifdef HAVE_FCOPYFILE
13162 ret = nogvl_fcopyfile(stp);
13163 if (ret != 0)
13164 goto finish; /* error or success */
13165#endif
13166
13167#ifdef USE_SENDFILE
13168 ret = nogvl_copy_stream_sendfile(stp);
13169 if (ret != 0)
13170 goto finish; /* error or success */
13171#endif
13172
13173 nogvl_copy_stream_read_write(stp);
13174
13175#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13176 finish:
13177#endif
13178 return 0;
13179}
13180
13181static VALUE
13182copy_stream_fallback_body(VALUE arg)
13183{
13184 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13185 const int buflen = 16*1024;
13186 VALUE n;
13187 VALUE buf = rb_str_buf_new(buflen);
13188 rb_off_t rest = stp->copy_length;
13189 rb_off_t off = stp->src_offset;
13190 ID read_method = id_readpartial;
13191
13192 if (!stp->src_fptr) {
13193 if (!rb_respond_to(stp->src, read_method)) {
13194 read_method = id_read;
13195 }
13196 }
13197
13198 while (1) {
13199 long numwrote;
13200 long l;
13201 rb_str_make_independent(buf);
13202 if (stp->copy_length < (rb_off_t)0) {
13203 l = buflen;
13204 }
13205 else {
13206 if (rest == 0) {
13207 rb_str_resize(buf, 0);
13208 break;
13209 }
13210 l = buflen < rest ? buflen : (long)rest;
13211 }
13212 if (!stp->src_fptr) {
13213 VALUE rc = rb_funcall(stp->src, read_method, 2, INT2FIX(l), buf);
13214
13215 if (read_method == id_read && NIL_P(rc))
13216 break;
13217 }
13218 else {
13219 ssize_t ss;
13220 rb_str_resize(buf, buflen);
13221 ss = maygvl_copy_stream_read(1, stp, RSTRING_PTR(buf), l, off);
13222 rb_str_resize(buf, ss > 0 ? ss : 0);
13223 if (ss < 0)
13224 return Qnil;
13225 if (ss == 0)
13226 rb_eof_error();
13227 if (off >= (rb_off_t)0)
13228 off += ss;
13229 }
13230 n = rb_io_write(stp->dst, buf);
13231 numwrote = NUM2LONG(n);
13232 stp->total += numwrote;
13233 rest -= numwrote;
13234 if (read_method == id_read && RSTRING_LEN(buf) == 0) {
13235 break;
13236 }
13237 }
13238
13239 return Qnil;
13240}
13241
13242static VALUE
13243copy_stream_fallback(struct copy_stream_struct *stp)
13244{
13245 if (!stp->src_fptr && stp->src_offset >= (rb_off_t)0) {
13246 rb_raise(rb_eArgError, "cannot specify src_offset for non-IO");
13247 }
13248 rb_rescue2(copy_stream_fallback_body, (VALUE)stp,
13249 (VALUE (*) (VALUE, VALUE))0, (VALUE)0,
13250 rb_eEOFError, (VALUE)0);
13251 return Qnil;
13252}
13253
13254static VALUE
13255copy_stream_body(VALUE arg)
13256{
13257 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13258 VALUE src_io = stp->src, dst_io = stp->dst;
13259 const int common_oflags = 0
13260#ifdef O_NOCTTY
13261 | O_NOCTTY
13262#endif
13263 ;
13264
13265 stp->th = rb_thread_current();
13266
13267 stp->total = 0;
13268
13269 if (src_io == argf ||
13270 !(RB_TYPE_P(src_io, T_FILE) ||
13271 RB_TYPE_P(src_io, T_STRING) ||
13272 rb_respond_to(src_io, rb_intern("to_path")))) {
13273 stp->src_fptr = NULL;
13274 }
13275 else {
13276 int stat_ret;
13277 VALUE tmp_io = rb_io_check_io(src_io);
13278 if (!NIL_P(tmp_io)) {
13279 src_io = tmp_io;
13280 }
13281 else if (!RB_TYPE_P(src_io, T_FILE)) {
13282 VALUE args[2];
13283 FilePathValue(src_io);
13284 args[0] = src_io;
13285 args[1] = INT2NUM(O_RDONLY|common_oflags);
13286 src_io = rb_class_new_instance(2, args, rb_cFile);
13287 stp->src = src_io;
13288 stp->close_src = 1;
13289 }
13290 RB_IO_POINTER(src_io, stp->src_fptr);
13291 rb_io_check_byte_readable(stp->src_fptr);
13292
13293 stat_ret = fstat(stp->src_fptr->fd, &stp->src_stat);
13294 if (stat_ret < 0) {
13295 stp->syserr = "fstat";
13296 stp->error_no = errno;
13297 return Qnil;
13298 }
13299 }
13300
13301 if (dst_io == argf ||
13302 !(RB_TYPE_P(dst_io, T_FILE) ||
13303 RB_TYPE_P(dst_io, T_STRING) ||
13304 rb_respond_to(dst_io, rb_intern("to_path")))) {
13305 stp->dst_fptr = NULL;
13306 }
13307 else {
13308 int stat_ret;
13309 VALUE tmp_io = rb_io_check_io(dst_io);
13310 if (!NIL_P(tmp_io)) {
13311 dst_io = GetWriteIO(tmp_io);
13312 }
13313 else if (!RB_TYPE_P(dst_io, T_FILE)) {
13314 VALUE args[3];
13315 FilePathValue(dst_io);
13316 args[0] = dst_io;
13317 args[1] = INT2NUM(O_WRONLY|O_CREAT|O_TRUNC|common_oflags);
13318 args[2] = INT2FIX(0666);
13319 dst_io = rb_class_new_instance(3, args, rb_cFile);
13320 stp->dst = dst_io;
13321 stp->close_dst = 1;
13322 }
13323 else {
13324 dst_io = GetWriteIO(dst_io);
13325 stp->dst = dst_io;
13326 }
13327 RB_IO_POINTER(dst_io, stp->dst_fptr);
13328 rb_io_check_writable(stp->dst_fptr);
13329
13330 stat_ret = fstat(stp->dst_fptr->fd, &stp->dst_stat);
13331 if (stat_ret < 0) {
13332 stp->syserr = "fstat";
13333 stp->error_no = errno;
13334 return Qnil;
13335 }
13336 }
13337
13338#ifdef O_BINARY
13339 if (stp->src_fptr)
13340 SET_BINARY_MODE_WITH_SEEK_CUR(stp->src_fptr);
13341#endif
13342 if (stp->dst_fptr)
13343 io_ascii8bit_binmode(stp->dst_fptr);
13344
13345 if (stp->src_offset < (rb_off_t)0 && stp->src_fptr && stp->src_fptr->rbuf.len) {
13346 size_t len = stp->src_fptr->rbuf.len;
13347 VALUE str;
13348 if (stp->copy_length >= (rb_off_t)0 && stp->copy_length < (rb_off_t)len) {
13349 len = (size_t)stp->copy_length;
13350 }
13351 str = rb_str_buf_new(len);
13352 rb_str_resize(str,len);
13353 read_buffered_data(RSTRING_PTR(str), len, stp->src_fptr);
13354 if (stp->dst_fptr) { /* IO or filename */
13355 if (io_binwrite(RSTRING_PTR(str), RSTRING_LEN(str), stp->dst_fptr, 0) < 0)
13356 rb_sys_fail_on_write(stp->dst_fptr);
13357 }
13358 else /* others such as StringIO */
13359 rb_io_write(dst_io, str);
13360 rb_str_resize(str, 0);
13361 stp->total += len;
13362 if (stp->copy_length >= (rb_off_t)0)
13363 stp->copy_length -= len;
13364 }
13365
13366 if (stp->dst_fptr && io_fflush(stp->dst_fptr) < 0) {
13367 rb_raise(rb_eIOError, "flush failed");
13368 }
13369
13370 if (stp->copy_length == 0)
13371 return Qnil;
13372
13373 if (stp->src_fptr == NULL || stp->dst_fptr == NULL) {
13374 return copy_stream_fallback(stp);
13375 }
13376
13377 IO_WITHOUT_GVL(nogvl_copy_stream_func, stp);
13378 return Qnil;
13379}
13380
13381static VALUE
13382copy_stream_finalize(VALUE arg)
13383{
13384 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13385
13386#ifdef HAVE_FCOPYFILE
13387 if (stp->copyfile_state) {
13388 copyfile_state_free(stp->copyfile_state);
13389 }
13390#endif
13391
13392 if (stp->close_src) {
13393 rb_io_close_m(stp->src);
13394 }
13395 if (stp->close_dst) {
13396 rb_io_close_m(stp->dst);
13397 }
13398 if (stp->syserr) {
13399 rb_syserr_fail(stp->error_no, stp->syserr);
13400 }
13401 if (stp->notimp) {
13402 rb_raise(rb_eNotImpError, "%s() not implemented", stp->notimp);
13403 }
13404 return Qnil;
13405}
13406
13407/*
13408 * call-seq:
13409 * IO.copy_stream(src, dst, src_length = nil, src_offset = 0) -> integer
13410 *
13411 * Copies from the given +src+ to the given +dst+,
13412 * returning the number of bytes copied.
13413 *
13414 * - The given +src+ must be one of the following:
13415 *
13416 * - The path to a readable file, from which source data is to be read.
13417 * - An \IO-like object, opened for reading and capable of responding
13418 * to method +:readpartial+ or method +:read+.
13419 *
13420 * - The given +dst+ must be one of the following:
13421 *
13422 * - The path to a writable file, to which data is to be written.
13423 * - An \IO-like object, opened for writing and capable of responding
13424 * to method +:write+.
13425 *
13426 * The examples here use file <tt>t.txt</tt> as source:
13427 *
13428 * File.read('t.txt')
13429 * # => "First line\nSecond line\n\nThird line\nFourth line\n"
13430 * File.read('t.txt').size # => 47
13431 *
13432 * If only arguments +src+ and +dst+ are given,
13433 * the entire source stream is copied:
13434 *
13435 * # Paths.
13436 * IO.copy_stream('t.txt', 't.tmp') # => 47
13437 *
13438 * # IOs (recall that a File is also an IO).
13439 * src_io = File.open('t.txt', 'r') # => #<File:t.txt>
13440 * dst_io = File.open('t.tmp', 'w') # => #<File:t.tmp>
13441 * IO.copy_stream(src_io, dst_io) # => 47
13442 * src_io.close
13443 * dst_io.close
13444 *
13445 * With argument +src_length+ a non-negative integer,
13446 * no more than that many bytes are copied:
13447 *
13448 * IO.copy_stream('t.txt', 't.tmp', 10) # => 10
13449 * File.read('t.tmp') # => "First line"
13450 *
13451 * With argument +src_offset+ also given,
13452 * the source stream is read beginning at that offset:
13453 *
13454 * IO.copy_stream('t.txt', 't.tmp', 11, 11) # => 11
13455 * IO.read('t.tmp') # => "Second line"
13456 *
13457 */
13458static VALUE
13459rb_io_s_copy_stream(int argc, VALUE *argv, VALUE io)
13460{
13461 VALUE src, dst, length, src_offset;
13462 struct copy_stream_struct st;
13463
13464 MEMZERO(&st, struct copy_stream_struct, 1);
13465
13466 rb_scan_args(argc, argv, "22", &src, &dst, &length, &src_offset);
13467
13468 st.src = src;
13469 st.dst = dst;
13470
13471 st.src_fptr = NULL;
13472 st.dst_fptr = NULL;
13473
13474 if (NIL_P(length))
13475 st.copy_length = (rb_off_t)-1;
13476 else
13477 st.copy_length = NUM2OFFT(length);
13478
13479 if (NIL_P(src_offset))
13480 st.src_offset = (rb_off_t)-1;
13481 else
13482 st.src_offset = NUM2OFFT(src_offset);
13483
13484 rb_ensure(copy_stream_body, (VALUE)&st, copy_stream_finalize, (VALUE)&st);
13485
13486 return OFFT2NUM(st.total);
13487}
13488
13489/*
13490 * call-seq:
13491 * external_encoding -> encoding or nil
13492 *
13493 * Returns the Encoding object that represents the encoding of the stream,
13494 * or +nil+ if the stream is in write mode and no encoding is specified.
13495 *
13496 * See {Encodings}[rdoc-ref:File@Encodings].
13497 *
13498 */
13499
13500static VALUE
13501rb_io_external_encoding(VALUE io)
13502{
13503 rb_io_t *fptr = RFILE(rb_io_taint_check(io))->fptr;
13504
13505 if (fptr->encs.enc2) {
13506 return rb_enc_from_encoding(fptr->encs.enc2);
13507 }
13508 if (fptr->mode & FMODE_WRITABLE) {
13509 if (fptr->encs.enc)
13510 return rb_enc_from_encoding(fptr->encs.enc);
13511 return Qnil;
13512 }
13513 return rb_enc_from_encoding(io_read_encoding(fptr));
13514}
13515
13516/*
13517 * call-seq:
13518 * internal_encoding -> encoding or nil
13519 *
13520 * Returns the Encoding object that represents the encoding of the internal string,
13521 * if conversion is specified,
13522 * or +nil+ otherwise.
13523 *
13524 * See {Encodings}[rdoc-ref:File@Encodings].
13525 *
13526 */
13527
13528static VALUE
13529rb_io_internal_encoding(VALUE io)
13530{
13531 rb_io_t *fptr = RFILE(rb_io_taint_check(io))->fptr;
13532
13533 if (!fptr->encs.enc2) return Qnil;
13534 return rb_enc_from_encoding(io_read_encoding(fptr));
13535}
13536
13537/*
13538 * call-seq:
13539 * set_encoding(ext_enc) -> self
13540 * set_encoding(ext_enc, int_enc, **enc_opts) -> self
13541 * set_encoding('ext_enc:int_enc', **enc_opts) -> self
13542 *
13543 * See {Encodings}[rdoc-ref:File@Encodings].
13544 *
13545 * Argument +ext_enc+, if given, must be an Encoding object
13546 * or a String with the encoding name;
13547 * it is assigned as the encoding for the stream.
13548 *
13549 * Argument +int_enc+, if given, must be an Encoding object
13550 * or a String with the encoding name;
13551 * it is assigned as the encoding for the internal string.
13552 *
13553 * Argument <tt>'ext_enc:int_enc'</tt>, if given, is a string
13554 * containing two colon-separated encoding names;
13555 * corresponding Encoding objects are assigned as the external
13556 * and internal encodings for the stream.
13557 *
13558 * If the external encoding of a string is binary/ASCII-8BIT,
13559 * the internal encoding of the string is set to nil, since no
13560 * transcoding is needed.
13561 *
13562 * Optional keyword arguments +enc_opts+ specify
13563 * {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
13564 *
13565 */
13566
13567static VALUE
13568rb_io_set_encoding(int argc, VALUE *argv, VALUE io)
13569{
13570 rb_io_t *fptr;
13571 VALUE v1, v2, opt;
13572
13573 if (!RB_TYPE_P(io, T_FILE)) {
13574 return forward(io, id_set_encoding, argc, argv);
13575 }
13576
13577 argc = rb_scan_args(argc, argv, "11:", &v1, &v2, &opt);
13578 GetOpenFile(io, fptr);
13579 io_encoding_set(fptr, v1, v2, opt);
13580 return io;
13581}
13582
13583void
13584rb_stdio_set_default_encoding(void)
13585{
13586 VALUE val = Qnil;
13587
13588#ifdef _WIN32
13589 if (isatty(fileno(stdin))) {
13590 rb_encoding *external = rb_locale_encoding();
13591 rb_encoding *internal = rb_default_internal_encoding();
13592 if (!internal) internal = rb_default_external_encoding();
13593 io_encoding_set(RFILE(rb_stdin)->fptr,
13594 rb_enc_from_encoding(external),
13595 rb_enc_from_encoding(internal),
13596 Qnil);
13597 }
13598 else
13599#endif
13600 rb_io_set_encoding(1, &val, rb_stdin);
13601 rb_io_set_encoding(1, &val, rb_stdout);
13602 rb_io_set_encoding(1, &val, rb_stderr);
13603}
13604
13605static inline int
13606global_argf_p(VALUE arg)
13607{
13608 return arg == argf;
13609}
13610
13611typedef VALUE (*argf_encoding_func)(VALUE io);
13612
13613static VALUE
13614argf_encoding(VALUE argf, argf_encoding_func func)
13615{
13616 if (!RTEST(ARGF.current_file)) {
13617 return rb_enc_default_external();
13618 }
13619 return func(rb_io_check_io(ARGF.current_file));
13620}
13621
13622/*
13623 * call-seq:
13624 * ARGF.external_encoding -> encoding
13625 *
13626 * Returns the external encoding for files read from ARGF as an Encoding
13627 * object. The external encoding is the encoding of the text as stored in a
13628 * file. Contrast with ARGF.internal_encoding, which is the encoding used to
13629 * represent this text within Ruby.
13630 *
13631 * To set the external encoding use ARGF.set_encoding.
13632 *
13633 * For example:
13634 *
13635 * ARGF.external_encoding #=> #<Encoding:UTF-8>
13636 *
13637 */
13638static VALUE
13639argf_external_encoding(VALUE argf)
13640{
13641 return argf_encoding(argf, rb_io_external_encoding);
13642}
13643
13644/*
13645 * call-seq:
13646 * ARGF.internal_encoding -> encoding
13647 *
13648 * Returns the internal encoding for strings read from ARGF as an
13649 * Encoding object.
13650 *
13651 * If ARGF.set_encoding has been called with two encoding names, the second
13652 * is returned. Otherwise, if +Encoding.default_external+ has been set, that
13653 * value is returned. Failing that, if a default external encoding was
13654 * specified on the command-line, that value is used. If the encoding is
13655 * unknown, +nil+ is returned.
13656 */
13657static VALUE
13658argf_internal_encoding(VALUE argf)
13659{
13660 return argf_encoding(argf, rb_io_internal_encoding);
13661}
13662
13663/*
13664 * call-seq:
13665 * ARGF.set_encoding(ext_enc) -> ARGF
13666 * ARGF.set_encoding("ext_enc:int_enc") -> ARGF
13667 * ARGF.set_encoding(ext_enc, int_enc) -> ARGF
13668 * ARGF.set_encoding("ext_enc:int_enc", opt) -> ARGF
13669 * ARGF.set_encoding(ext_enc, int_enc, opt) -> ARGF
13670 *
13671 * If single argument is specified, strings read from ARGF are tagged with
13672 * the encoding specified.
13673 *
13674 * If two encoding names separated by a colon are given, e.g. "ascii:utf-8",
13675 * the read string is converted from the first encoding (external encoding)
13676 * to the second encoding (internal encoding), then tagged with the second
13677 * encoding.
13678 *
13679 * If two arguments are specified, they must be encoding objects or encoding
13680 * names. Again, the first specifies the external encoding; the second
13681 * specifies the internal encoding.
13682 *
13683 * If the external encoding and the internal encoding are specified, the
13684 * optional Hash argument can be used to adjust the conversion process. The
13685 * structure of this hash is explained in the String#encode documentation.
13686 *
13687 * For example:
13688 *
13689 * ARGF.set_encoding('ascii') # Tag the input as US-ASCII text
13690 * ARGF.set_encoding(Encoding::UTF_8) # Tag the input as UTF-8 text
13691 * ARGF.set_encoding('utf-8','ascii') # Transcode the input from US-ASCII
13692 * # to UTF-8.
13693 */
13694static VALUE
13695argf_set_encoding(int argc, VALUE *argv, VALUE argf)
13696{
13697 rb_io_t *fptr;
13698
13699 if (!next_argv()) {
13700 rb_raise(rb_eArgError, "no stream to set encoding");
13701 }
13702 rb_io_set_encoding(argc, argv, ARGF.current_file);
13703 GetOpenFile(ARGF.current_file, fptr);
13704 ARGF.encs = fptr->encs;
13705 return argf;
13706}
13707
13708/*
13709 * call-seq:
13710 * ARGF.tell -> Integer
13711 * ARGF.pos -> Integer
13712 *
13713 * Returns the current offset (in bytes) of the current file in ARGF.
13714 *
13715 * ARGF.pos #=> 0
13716 * ARGF.gets #=> "This is line one\n"
13717 * ARGF.pos #=> 17
13718 *
13719 */
13720static VALUE
13721argf_tell(VALUE argf)
13722{
13723 if (!next_argv()) {
13724 rb_raise(rb_eArgError, "no stream to tell");
13725 }
13726 ARGF_FORWARD(0, 0);
13727 return rb_io_tell(ARGF.current_file);
13728}
13729
13730/*
13731 * call-seq:
13732 * ARGF.seek(amount, whence=IO::SEEK_SET) -> 0
13733 *
13734 * Seeks to offset _amount_ (an Integer) in the ARGF stream according to
13735 * the value of _whence_. See IO#seek for further details.
13736 */
13737static VALUE
13738argf_seek_m(int argc, VALUE *argv, VALUE argf)
13739{
13740 if (!next_argv()) {
13741 rb_raise(rb_eArgError, "no stream to seek");
13742 }
13743 ARGF_FORWARD(argc, argv);
13744 return rb_io_seek_m(argc, argv, ARGF.current_file);
13745}
13746
13747/*
13748 * call-seq:
13749 * ARGF.pos = position -> Integer
13750 *
13751 * Seeks to the position given by _position_ (in bytes) in ARGF.
13752 *
13753 * For example:
13754 *
13755 * ARGF.pos = 17
13756 * ARGF.gets #=> "This is line two\n"
13757 */
13758static VALUE
13759argf_set_pos(VALUE argf, VALUE offset)
13760{
13761 if (!next_argv()) {
13762 rb_raise(rb_eArgError, "no stream to set position");
13763 }
13764 ARGF_FORWARD(1, &offset);
13765 return rb_io_set_pos(ARGF.current_file, offset);
13766}
13767
13768/*
13769 * call-seq:
13770 * ARGF.rewind -> 0
13771 *
13772 * Positions the current file to the beginning of input, resetting
13773 * ARGF.lineno to zero.
13774 *
13775 * ARGF.readline #=> "This is line one\n"
13776 * ARGF.rewind #=> 0
13777 * ARGF.lineno #=> 0
13778 * ARGF.readline #=> "This is line one\n"
13779 */
13780static VALUE
13781argf_rewind(VALUE argf)
13782{
13783 VALUE ret;
13784 int old_lineno;
13785
13786 if (!next_argv()) {
13787 rb_raise(rb_eArgError, "no stream to rewind");
13788 }
13789 ARGF_FORWARD(0, 0);
13790 old_lineno = RFILE(ARGF.current_file)->fptr->lineno;
13791 ret = rb_io_rewind(ARGF.current_file);
13792 if (!global_argf_p(argf)) {
13793 ARGF.last_lineno = ARGF.lineno -= old_lineno;
13794 }
13795 return ret;
13796}
13797
13798/*
13799 * call-seq:
13800 * ARGF.fileno -> integer
13801 * ARGF.to_i -> integer
13802 *
13803 * Returns an integer representing the numeric file descriptor for
13804 * the current file. Raises an ArgumentError if there isn't a current file.
13805 *
13806 * ARGF.fileno #=> 3
13807 */
13808static VALUE
13809argf_fileno(VALUE argf)
13810{
13811 if (!next_argv()) {
13812 rb_raise(rb_eArgError, "no stream");
13813 }
13814 ARGF_FORWARD(0, 0);
13815 return rb_io_fileno(ARGF.current_file);
13816}
13817
13818/*
13819 * call-seq:
13820 * ARGF.to_io -> IO
13821 *
13822 * Returns an IO object representing the current file. This will be a
13823 * File object unless the current file is a stream such as STDIN.
13824 *
13825 * For example:
13826 *
13827 * ARGF.to_io #=> #<File:glark.txt>
13828 * ARGF.to_io #=> #<IO:<STDIN>>
13829 */
13830static VALUE
13831argf_to_io(VALUE argf)
13832{
13833 next_argv();
13834 ARGF_FORWARD(0, 0);
13835 return ARGF.current_file;
13836}
13837
13838/*
13839 * call-seq:
13840 * ARGF.eof? -> true or false
13841 * ARGF.eof -> true or false
13842 *
13843 * Returns true if the current file in ARGF is at end of file, i.e. it has
13844 * no data to read. The stream must be opened for reading or an IOError
13845 * will be raised.
13846 *
13847 * $ echo "eof" | ruby argf.rb
13848 *
13849 * ARGF.eof? #=> false
13850 * 3.times { ARGF.readchar }
13851 * ARGF.eof? #=> false
13852 * ARGF.readchar #=> "\n"
13853 * ARGF.eof? #=> true
13854 */
13855
13856static VALUE
13857argf_eof(VALUE argf)
13858{
13859 next_argv();
13860 if (RTEST(ARGF.current_file)) {
13861 if (ARGF.init_p == 0) return Qtrue;
13862 next_argv();
13863 ARGF_FORWARD(0, 0);
13864 if (rb_io_eof(ARGF.current_file)) {
13865 return Qtrue;
13866 }
13867 }
13868 return Qfalse;
13869}
13870
13871/*
13872 * call-seq:
13873 * ARGF.read([length [, outbuf]]) -> string, outbuf, or nil
13874 *
13875 * Reads _length_ bytes from ARGF. The files named on the command line
13876 * are concatenated and treated as a single file by this method, so when
13877 * called without arguments the contents of this pseudo file are returned in
13878 * their entirety.
13879 *
13880 * _length_ must be a non-negative integer or +nil+.
13881 *
13882 * If _length_ is a positive integer, +read+ tries to read
13883 * _length_ bytes without any conversion (binary mode).
13884 * It returns +nil+ if an EOF is encountered before anything can be read.
13885 * Fewer than _length_ bytes are returned if an EOF is encountered during
13886 * the read.
13887 * In the case of an integer _length_, the resulting string is always
13888 * in ASCII-8BIT encoding.
13889 *
13890 * If _length_ is omitted or is +nil+, it reads until EOF
13891 * and the encoding conversion is applied, if applicable.
13892 * A string is returned even if EOF is encountered before any data is read.
13893 *
13894 * If _length_ is zero, it returns an empty string (<code>""</code>).
13895 *
13896 * If the optional _outbuf_ argument is present,
13897 * it must reference a String, which will receive the data.
13898 * The _outbuf_ will contain only the received data after the method call
13899 * even if it is not empty at the beginning.
13900 *
13901 * For example:
13902 *
13903 * $ echo "small" > small.txt
13904 * $ echo "large" > large.txt
13905 * $ ./glark.rb small.txt large.txt
13906 *
13907 * ARGF.read #=> "small\nlarge"
13908 * ARGF.read(200) #=> "small\nlarge"
13909 * ARGF.read(2) #=> "sm"
13910 * ARGF.read(0) #=> ""
13911 *
13912 * Note that this method behaves like the fread() function in C.
13913 * This means it retries to invoke read(2) system calls to read data
13914 * with the specified length.
13915 * If you need the behavior like a single read(2) system call,
13916 * consider ARGF#readpartial or ARGF#read_nonblock.
13917 */
13918
13919static VALUE
13920argf_read(int argc, VALUE *argv, VALUE argf)
13921{
13922 VALUE tmp, str, length;
13923 long len = 0;
13924
13925 rb_scan_args(argc, argv, "02", &length, &str);
13926 if (!NIL_P(length)) {
13927 len = NUM2LONG(argv[0]);
13928 }
13929 if (!NIL_P(str)) {
13930 StringValue(str);
13931 rb_str_resize(str,0);
13932 argv[1] = Qnil;
13933 }
13934
13935 retry:
13936 if (!next_argv()) {
13937 return str;
13938 }
13939 if (ARGF_GENERIC_INPUT_P()) {
13940 tmp = argf_forward(argc, argv, argf);
13941 }
13942 else {
13943 tmp = io_read(argc, argv, ARGF.current_file);
13944 }
13945 if (NIL_P(str)) str = tmp;
13946 else if (!NIL_P(tmp)) rb_str_append(str, tmp);
13947 if (NIL_P(tmp) || NIL_P(length)) {
13948 if (ARGF.next_p != -1) {
13949 argf_close(argf);
13950 ARGF.next_p = 1;
13951 goto retry;
13952 }
13953 }
13954 else if (argc >= 1) {
13955 long slen = RSTRING_LEN(str);
13956 if (slen < len) {
13957 argv[0] = LONG2NUM(len - slen);
13958 goto retry;
13959 }
13960 }
13961 return str;
13962}
13963
13965 int argc;
13966 VALUE *argv;
13967 VALUE argf;
13968};
13969
13970static VALUE
13971argf_forward_call(VALUE arg)
13972{
13973 struct argf_call_arg *p = (struct argf_call_arg *)arg;
13974 argf_forward(p->argc, p->argv, p->argf);
13975 return Qnil;
13976}
13977
13978static VALUE argf_getpartial(int argc, VALUE *argv, VALUE argf, VALUE opts,
13979 int nonblock);
13980
13981/*
13982 * call-seq:
13983 * ARGF.readpartial(maxlen) -> string
13984 * ARGF.readpartial(maxlen, outbuf) -> outbuf
13985 *
13986 * Reads at most _maxlen_ bytes from the ARGF stream.
13987 *
13988 * If the optional _outbuf_ argument is present,
13989 * it must reference a String, which will receive the data.
13990 * The _outbuf_ will contain only the received data after the method call
13991 * even if it is not empty at the beginning.
13992 *
13993 * It raises EOFError on end of ARGF stream.
13994 * Since ARGF stream is a concatenation of multiple files,
13995 * internally EOF is occur for each file.
13996 * ARGF.readpartial returns empty strings for EOFs except the last one and
13997 * raises EOFError for the last one.
13998 *
13999 */
14000
14001static VALUE
14002argf_readpartial(int argc, VALUE *argv, VALUE argf)
14003{
14004 return argf_getpartial(argc, argv, argf, Qnil, 0);
14005}
14006
14007/*
14008 * call-seq:
14009 * ARGF.read_nonblock(maxlen[, options]) -> string
14010 * ARGF.read_nonblock(maxlen, outbuf[, options]) -> outbuf
14011 *
14012 * Reads at most _maxlen_ bytes from the ARGF stream in non-blocking mode.
14013 */
14014
14015static VALUE
14016argf_read_nonblock(int argc, VALUE *argv, VALUE argf)
14017{
14018 VALUE opts;
14019
14020 rb_scan_args(argc, argv, "11:", NULL, NULL, &opts);
14021
14022 if (!NIL_P(opts))
14023 argc--;
14024
14025 return argf_getpartial(argc, argv, argf, opts, 1);
14026}
14027
14028static VALUE
14029argf_getpartial(int argc, VALUE *argv, VALUE argf, VALUE opts, int nonblock)
14030{
14031 VALUE tmp, str, length;
14032 int no_exception;
14033
14034 rb_scan_args(argc, argv, "11", &length, &str);
14035 if (!NIL_P(str)) {
14036 StringValue(str);
14037 argv[1] = str;
14038 }
14039 no_exception = no_exception_p(opts);
14040
14041 if (!next_argv()) {
14042 if (!NIL_P(str)) {
14043 rb_str_resize(str, 0);
14044 }
14045 rb_eof_error();
14046 }
14047 if (ARGF_GENERIC_INPUT_P()) {
14048 VALUE (*const rescue_does_nothing)(VALUE, VALUE) = 0;
14049 struct argf_call_arg arg;
14050 arg.argc = argc;
14051 arg.argv = argv;
14052 arg.argf = argf;
14053 tmp = rb_rescue2(argf_forward_call, (VALUE)&arg,
14054 rescue_does_nothing, Qnil, rb_eEOFError, (VALUE)0);
14055 }
14056 else {
14057 tmp = io_getpartial(argc, argv, ARGF.current_file, no_exception, nonblock);
14058 }
14059 if (NIL_P(tmp)) {
14060 if (ARGF.next_p == -1) {
14061 return io_nonblock_eof(no_exception);
14062 }
14063 argf_close(argf);
14064 ARGF.next_p = 1;
14065 if (RARRAY_LEN(ARGF.argv) == 0) {
14066 return io_nonblock_eof(no_exception);
14067 }
14068 if (NIL_P(str))
14069 str = rb_str_new(NULL, 0);
14070 return str;
14071 }
14072 return tmp;
14073}
14074
14075/*
14076 * call-seq:
14077 * ARGF.getc -> String or nil
14078 *
14079 * Reads the next character from ARGF and returns it as a String. Returns
14080 * +nil+ at the end of the stream.
14081 *
14082 * ARGF treats the files named on the command line as a single file created
14083 * by concatenating their contents. After returning the last character of the
14084 * first file, it returns the first character of the second file, and so on.
14085 *
14086 * For example:
14087 *
14088 * $ echo "foo" > file
14089 * $ ruby argf.rb file
14090 *
14091 * ARGF.getc #=> "f"
14092 * ARGF.getc #=> "o"
14093 * ARGF.getc #=> "o"
14094 * ARGF.getc #=> "\n"
14095 * ARGF.getc #=> nil
14096 * ARGF.getc #=> nil
14097 */
14098static VALUE
14099argf_getc(VALUE argf)
14100{
14101 VALUE ch;
14102
14103 retry:
14104 if (!next_argv()) return Qnil;
14105 if (ARGF_GENERIC_INPUT_P()) {
14106 ch = forward_current(rb_intern("getc"), 0, 0);
14107 }
14108 else {
14109 ch = rb_io_getc(ARGF.current_file);
14110 }
14111 if (NIL_P(ch) && ARGF.next_p != -1) {
14112 argf_close(argf);
14113 ARGF.next_p = 1;
14114 goto retry;
14115 }
14116
14117 return ch;
14118}
14119
14120/*
14121 * call-seq:
14122 * ARGF.getbyte -> Integer or nil
14123 *
14124 * Gets the next 8-bit byte (0..255) from ARGF. Returns +nil+ if called at
14125 * the end of the stream.
14126 *
14127 * For example:
14128 *
14129 * $ echo "foo" > file
14130 * $ ruby argf.rb file
14131 *
14132 * ARGF.getbyte #=> 102
14133 * ARGF.getbyte #=> 111
14134 * ARGF.getbyte #=> 111
14135 * ARGF.getbyte #=> 10
14136 * ARGF.getbyte #=> nil
14137 */
14138static VALUE
14139argf_getbyte(VALUE argf)
14140{
14141 VALUE ch;
14142
14143 retry:
14144 if (!next_argv()) return Qnil;
14145 if (!RB_TYPE_P(ARGF.current_file, T_FILE)) {
14146 ch = forward_current(rb_intern("getbyte"), 0, 0);
14147 }
14148 else {
14149 ch = rb_io_getbyte(ARGF.current_file);
14150 }
14151 if (NIL_P(ch) && ARGF.next_p != -1) {
14152 argf_close(argf);
14153 ARGF.next_p = 1;
14154 goto retry;
14155 }
14156
14157 return ch;
14158}
14159
14160/*
14161 * call-seq:
14162 * ARGF.readchar -> String or nil
14163 *
14164 * Reads the next character from ARGF and returns it as a String. Raises
14165 * an EOFError after the last character of the last file has been read.
14166 *
14167 * For example:
14168 *
14169 * $ echo "foo" > file
14170 * $ ruby argf.rb file
14171 *
14172 * ARGF.readchar #=> "f"
14173 * ARGF.readchar #=> "o"
14174 * ARGF.readchar #=> "o"
14175 * ARGF.readchar #=> "\n"
14176 * ARGF.readchar #=> end of file reached (EOFError)
14177 */
14178static VALUE
14179argf_readchar(VALUE argf)
14180{
14181 VALUE ch;
14182
14183 retry:
14184 if (!next_argv()) rb_eof_error();
14185 if (!RB_TYPE_P(ARGF.current_file, T_FILE)) {
14186 ch = forward_current(rb_intern("getc"), 0, 0);
14187 }
14188 else {
14189 ch = rb_io_getc(ARGF.current_file);
14190 }
14191 if (NIL_P(ch) && ARGF.next_p != -1) {
14192 argf_close(argf);
14193 ARGF.next_p = 1;
14194 goto retry;
14195 }
14196
14197 return ch;
14198}
14199
14200/*
14201 * call-seq:
14202 * ARGF.readbyte -> Integer
14203 *
14204 * Reads the next 8-bit byte from ARGF and returns it as an Integer. Raises
14205 * an EOFError after the last byte of the last file has been read.
14206 *
14207 * For example:
14208 *
14209 * $ echo "foo" > file
14210 * $ ruby argf.rb file
14211 *
14212 * ARGF.readbyte #=> 102
14213 * ARGF.readbyte #=> 111
14214 * ARGF.readbyte #=> 111
14215 * ARGF.readbyte #=> 10
14216 * ARGF.readbyte #=> end of file reached (EOFError)
14217 */
14218static VALUE
14219argf_readbyte(VALUE argf)
14220{
14221 VALUE c;
14222
14223 NEXT_ARGF_FORWARD(0, 0);
14224 c = argf_getbyte(argf);
14225 if (NIL_P(c)) {
14226 rb_eof_error();
14227 }
14228 return c;
14229}
14230
14231#define FOREACH_ARGF() while (next_argv())
14232
14233static VALUE
14234argf_block_call_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, argf))
14235{
14236 const VALUE current = ARGF.current_file;
14237 rb_yield_values2(argc, argv);
14238 if (ARGF.init_p == -1 || current != ARGF.current_file) {
14240 }
14241 return Qnil;
14242}
14243
14244#define ARGF_block_call(mid, argc, argv, func, argf) \
14245 rb_block_call_kw(ARGF.current_file, mid, argc, argv, \
14246 func, argf, rb_keyword_given_p())
14247
14248static void
14249argf_block_call(ID mid, int argc, VALUE *argv, VALUE argf)
14250{
14251 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_i, argf);
14252 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14253}
14254
14255static VALUE
14256argf_block_call_line_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, argf))
14257{
14258 if (!global_argf_p(argf)) {
14259 ARGF.last_lineno = ++ARGF.lineno;
14260 }
14261 return argf_block_call_i(i, argf, argc, argv, blockarg);
14262}
14263
14264static void
14265argf_block_call_line(ID mid, int argc, VALUE *argv, VALUE argf)
14266{
14267 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_line_i, argf);
14268 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14269}
14270
14271/*
14272 * call-seq:
14273 * ARGF.each(sep=$/) {|line| block } -> ARGF
14274 * ARGF.each(sep=$/, limit) {|line| block } -> ARGF
14275 * ARGF.each(...) -> an_enumerator
14276 *
14277 * ARGF.each_line(sep=$/) {|line| block } -> ARGF
14278 * ARGF.each_line(sep=$/, limit) {|line| block } -> ARGF
14279 * ARGF.each_line(...) -> an_enumerator
14280 *
14281 * Returns an enumerator which iterates over each line (separated by _sep_,
14282 * which defaults to your platform's newline character) of each file in
14283 * +ARGV+. If a block is supplied, each line in turn will be yielded to the
14284 * block, otherwise an enumerator is returned.
14285 * The optional _limit_ argument is an Integer specifying the maximum
14286 * length of each line; longer lines will be split according to this limit.
14287 *
14288 * This method allows you to treat the files supplied on the command line as
14289 * a single file consisting of the concatenation of each named file. After
14290 * the last line of the first file has been returned, the first line of the
14291 * second file is returned. The ARGF.filename and ARGF.lineno methods can be
14292 * used to determine the filename of the current line and line number of the
14293 * whole input, respectively.
14294 *
14295 * For example, the following code prints out each line of each named file
14296 * prefixed with its line number, displaying the filename once per file:
14297 *
14298 * ARGF.each_line do |line|
14299 * puts ARGF.filename if ARGF.file.lineno == 1
14300 * puts "#{ARGF.file.lineno}: #{line}"
14301 * end
14302 *
14303 * While the following code prints only the first file's name at first, and
14304 * the contents with line number counted through all named files.
14305 *
14306 * ARGF.each_line do |line|
14307 * puts ARGF.filename if ARGF.lineno == 1
14308 * puts "#{ARGF.lineno}: #{line}"
14309 * end
14310 */
14311static VALUE
14312argf_each_line(int argc, VALUE *argv, VALUE argf)
14313{
14314 RETURN_ENUMERATOR(argf, argc, argv);
14315 FOREACH_ARGF() {
14316 argf_block_call_line(rb_intern("each_line"), argc, argv, argf);
14317 }
14318 return argf;
14319}
14320
14321/*
14322 * call-seq:
14323 * ARGF.each_byte {|byte| block } -> ARGF
14324 * ARGF.each_byte -> an_enumerator
14325 *
14326 * Iterates over each byte of each file in +ARGV+.
14327 * A byte is returned as an Integer in the range 0..255.
14328 *
14329 * This method allows you to treat the files supplied on the command line as
14330 * a single file consisting of the concatenation of each named file. After
14331 * the last byte of the first file has been returned, the first byte of the
14332 * second file is returned. The ARGF.filename method can be used to
14333 * determine the filename of the current byte.
14334 *
14335 * If no block is given, an enumerator is returned instead.
14336 *
14337 * For example:
14338 *
14339 * ARGF.bytes.to_a #=> [35, 32, ... 95, 10]
14340 *
14341 */
14342static VALUE
14343argf_each_byte(VALUE argf)
14344{
14345 RETURN_ENUMERATOR(argf, 0, 0);
14346 FOREACH_ARGF() {
14347 argf_block_call(rb_intern("each_byte"), 0, 0, argf);
14348 }
14349 return argf;
14350}
14351
14352/*
14353 * call-seq:
14354 * ARGF.each_char {|char| block } -> ARGF
14355 * ARGF.each_char -> an_enumerator
14356 *
14357 * Iterates over each character of each file in ARGF.
14358 *
14359 * This method allows you to treat the files supplied on the command line as
14360 * a single file consisting of the concatenation of each named file. After
14361 * the last character of the first file has been returned, the first
14362 * character of the second file is returned. The ARGF.filename method can
14363 * be used to determine the name of the file in which the current character
14364 * appears.
14365 *
14366 * If no block is given, an enumerator is returned instead.
14367 */
14368static VALUE
14369argf_each_char(VALUE argf)
14370{
14371 RETURN_ENUMERATOR(argf, 0, 0);
14372 FOREACH_ARGF() {
14373 argf_block_call(rb_intern("each_char"), 0, 0, argf);
14374 }
14375 return argf;
14376}
14377
14378/*
14379 * call-seq:
14380 * ARGF.each_codepoint {|codepoint| block } -> ARGF
14381 * ARGF.each_codepoint -> an_enumerator
14382 *
14383 * Iterates over each codepoint of each file in ARGF.
14384 *
14385 * This method allows you to treat the files supplied on the command line as
14386 * a single file consisting of the concatenation of each named file. After
14387 * the last codepoint of the first file has been returned, the first
14388 * codepoint of the second file is returned. The ARGF.filename method can
14389 * be used to determine the name of the file in which the current codepoint
14390 * appears.
14391 *
14392 * If no block is given, an enumerator is returned instead.
14393 */
14394static VALUE
14395argf_each_codepoint(VALUE argf)
14396{
14397 RETURN_ENUMERATOR(argf, 0, 0);
14398 FOREACH_ARGF() {
14399 argf_block_call(rb_intern("each_codepoint"), 0, 0, argf);
14400 }
14401 return argf;
14402}
14403
14404/*
14405 * call-seq:
14406 * ARGF.filename -> String
14407 * ARGF.path -> String
14408 *
14409 * Returns the current filename. "-" is returned when the current file is
14410 * STDIN.
14411 *
14412 * For example:
14413 *
14414 * $ echo "foo" > foo
14415 * $ echo "bar" > bar
14416 * $ echo "glark" > glark
14417 *
14418 * $ ruby argf.rb foo bar glark
14419 *
14420 * ARGF.filename #=> "foo"
14421 * ARGF.read(5) #=> "foo\nb"
14422 * ARGF.filename #=> "bar"
14423 * ARGF.skip
14424 * ARGF.filename #=> "glark"
14425 */
14426static VALUE
14427argf_filename(VALUE argf)
14428{
14429 next_argv();
14430 return ARGF.filename;
14431}
14432
14433static VALUE
14434argf_filename_getter(ID id, VALUE *var)
14435{
14436 return argf_filename(*var);
14437}
14438
14439/*
14440 * call-seq:
14441 * ARGF.file -> IO or File object
14442 *
14443 * Returns the current file as an IO or File object.
14444 * <code>$stdin</code> is returned when the current file is STDIN.
14445 *
14446 * For example:
14447 *
14448 * $ echo "foo" > foo
14449 * $ echo "bar" > bar
14450 *
14451 * $ ruby argf.rb foo bar
14452 *
14453 * ARGF.file #=> #<File:foo>
14454 * ARGF.read(5) #=> "foo\nb"
14455 * ARGF.file #=> #<File:bar>
14456 */
14457static VALUE
14458argf_file(VALUE argf)
14459{
14460 next_argv();
14461 return ARGF.current_file;
14462}
14463
14464/*
14465 * call-seq:
14466 * ARGF.binmode -> ARGF
14467 *
14468 * Puts ARGF into binary mode. Once a stream is in binary mode, it cannot
14469 * be reset to non-binary mode. This option has the following effects:
14470 *
14471 * * Newline conversion is disabled.
14472 * * Encoding conversion is disabled.
14473 * * Content is treated as ASCII-8BIT.
14474 */
14475static VALUE
14476argf_binmode_m(VALUE argf)
14477{
14478 ARGF.binmode = 1;
14479 next_argv();
14480 ARGF_FORWARD(0, 0);
14481 rb_io_ascii8bit_binmode(ARGF.current_file);
14482 return argf;
14483}
14484
14485/*
14486 * call-seq:
14487 * ARGF.binmode? -> true or false
14488 *
14489 * Returns true if ARGF is being read in binary mode; false otherwise.
14490 * To enable binary mode use ARGF.binmode.
14491 *
14492 * For example:
14493 *
14494 * ARGF.binmode? #=> false
14495 * ARGF.binmode
14496 * ARGF.binmode? #=> true
14497 */
14498static VALUE
14499argf_binmode_p(VALUE argf)
14500{
14501 return RBOOL(ARGF.binmode);
14502}
14503
14504/*
14505 * call-seq:
14506 * ARGF.skip -> ARGF
14507 *
14508 * Sets the current file to the next file in ARGV. If there aren't any more
14509 * files it has no effect.
14510 *
14511 * For example:
14512 *
14513 * $ ruby argf.rb foo bar
14514 * ARGF.filename #=> "foo"
14515 * ARGF.skip
14516 * ARGF.filename #=> "bar"
14517 */
14518static VALUE
14519argf_skip(VALUE argf)
14520{
14521 if (ARGF.init_p && ARGF.next_p == 0) {
14522 argf_close(argf);
14523 ARGF.next_p = 1;
14524 }
14525 return argf;
14526}
14527
14528/*
14529 * call-seq:
14530 * ARGF.close -> ARGF
14531 *
14532 * Closes the current file and skips to the next file in ARGV. If there are
14533 * no more files to open, just closes the current file. STDIN will not be
14534 * closed.
14535 *
14536 * For example:
14537 *
14538 * $ ruby argf.rb foo bar
14539 *
14540 * ARGF.filename #=> "foo"
14541 * ARGF.close
14542 * ARGF.filename #=> "bar"
14543 * ARGF.close
14544 */
14545static VALUE
14546argf_close_m(VALUE argf)
14547{
14548 next_argv();
14549 argf_close(argf);
14550 if (ARGF.next_p != -1) {
14551 ARGF.next_p = 1;
14552 }
14553 ARGF.lineno = 0;
14554 return argf;
14555}
14556
14557/*
14558 * call-seq:
14559 * ARGF.closed? -> true or false
14560 *
14561 * Returns _true_ if the current file has been closed; _false_ otherwise. Use
14562 * ARGF.close to actually close the current file.
14563 */
14564static VALUE
14565argf_closed(VALUE argf)
14566{
14567 next_argv();
14568 ARGF_FORWARD(0, 0);
14569 return rb_io_closed_p(ARGF.current_file);
14570}
14571
14572/*
14573 * call-seq:
14574 * ARGF.to_s -> String
14575 *
14576 * Returns "ARGF".
14577 */
14578static VALUE
14579argf_to_s(VALUE argf)
14580{
14581 return rb_str_new2("ARGF");
14582}
14583
14584/*
14585 * call-seq:
14586 * ARGF.inplace_mode -> String
14587 *
14588 * Returns the file extension appended to the names of backup copies of
14589 * modified files under in-place edit mode. This value can be set using
14590 * ARGF.inplace_mode= or passing the +-i+ switch to the Ruby binary.
14591 */
14592static VALUE
14593argf_inplace_mode_get(VALUE argf)
14594{
14595 if (!ARGF.inplace) return Qnil;
14596 if (NIL_P(ARGF.inplace)) return rb_str_new(0, 0);
14597 return rb_str_dup(ARGF.inplace);
14598}
14599
14600static VALUE
14601opt_i_get(ID id, VALUE *var)
14602{
14603 return argf_inplace_mode_get(*var);
14604}
14605
14606/*
14607 * call-seq:
14608 * ARGF.inplace_mode = ext -> ARGF
14609 *
14610 * Sets the filename extension for in-place editing mode to the given String.
14611 * The backup copy of each file being edited has this value appended to its
14612 * filename.
14613 *
14614 * For example:
14615 *
14616 * $ ruby argf.rb file.txt
14617 *
14618 * ARGF.inplace_mode = '.bak'
14619 * ARGF.each_line do |line|
14620 * print line.sub("foo","bar")
14621 * end
14622 *
14623 * First, _file.txt.bak_ is created as a backup copy of _file.txt_.
14624 * Then, each line of _file.txt_ has the first occurrence of "foo" replaced with
14625 * "bar".
14626 */
14627static VALUE
14628argf_inplace_mode_set(VALUE argf, VALUE val)
14629{
14630 if (!RTEST(val)) {
14631 ARGF.inplace = Qfalse;
14632 }
14633 else if (StringValueCStr(val), !RSTRING_LEN(val)) {
14634 ARGF.inplace = Qnil;
14635 }
14636 else {
14637 ARGF.inplace = rb_str_new_frozen(val);
14638 }
14639 return argf;
14640}
14641
14642static void
14643opt_i_set(VALUE val, ID id, VALUE *var)
14644{
14645 argf_inplace_mode_set(*var, val);
14646}
14647
14648void
14649ruby_set_inplace_mode(const char *suffix)
14650{
14651 ARGF.inplace = !suffix ? Qfalse : !*suffix ? Qnil : rb_str_new(suffix, strlen(suffix));
14652}
14653
14654/*
14655 * call-seq:
14656 * ARGF.argv -> ARGV
14657 *
14658 * Returns the +ARGV+ array, which contains the arguments passed to your
14659 * script, one per element.
14660 *
14661 * For example:
14662 *
14663 * $ ruby argf.rb -v glark.txt
14664 *
14665 * ARGF.argv #=> ["-v", "glark.txt"]
14666 *
14667 */
14668static VALUE
14669argf_argv(VALUE argf)
14670{
14671 return ARGF.argv;
14672}
14673
14674static VALUE
14675argf_argv_getter(ID id, VALUE *var)
14676{
14677 return argf_argv(*var);
14678}
14679
14680VALUE
14682{
14683 return ARGF.argv;
14684}
14685
14686/*
14687 * call-seq:
14688 * ARGF.to_write_io -> io
14689 *
14690 * Returns IO instance tied to _ARGF_ for writing if inplace mode is
14691 * enabled.
14692 */
14693static VALUE
14694argf_write_io(VALUE argf)
14695{
14696 if (!RTEST(ARGF.current_file)) {
14697 rb_raise(rb_eIOError, "not opened for writing");
14698 }
14699 return GetWriteIO(ARGF.current_file);
14700}
14701
14702/*
14703 * call-seq:
14704 * ARGF.write(*objects) -> integer
14705 *
14706 * Writes each of the given +objects+ if inplace mode.
14707 */
14708static VALUE
14709argf_write(int argc, VALUE *argv, VALUE argf)
14710{
14711 return rb_io_writev(argf_write_io(argf), argc, argv);
14712}
14713
14714void
14715rb_readwrite_sys_fail(enum rb_io_wait_readwrite waiting, const char *mesg)
14716{
14717 rb_readwrite_syserr_fail(waiting, errno, mesg);
14718}
14719
14720void
14721rb_readwrite_syserr_fail(enum rb_io_wait_readwrite waiting, int n, const char *mesg)
14722{
14723 VALUE arg, c = Qnil;
14724 arg = mesg ? rb_str_new2(mesg) : Qnil;
14725 switch (waiting) {
14726 case RB_IO_WAIT_WRITABLE:
14727 switch (n) {
14728 case EAGAIN:
14729 c = rb_eEAGAINWaitWritable;
14730 break;
14731#if EAGAIN != EWOULDBLOCK
14732 case EWOULDBLOCK:
14733 c = rb_eEWOULDBLOCKWaitWritable;
14734 break;
14735#endif
14736 case EINPROGRESS:
14737 c = rb_eEINPROGRESSWaitWritable;
14738 break;
14739 default:
14741 }
14742 break;
14743 case RB_IO_WAIT_READABLE:
14744 switch (n) {
14745 case EAGAIN:
14746 c = rb_eEAGAINWaitReadable;
14747 break;
14748#if EAGAIN != EWOULDBLOCK
14749 case EWOULDBLOCK:
14750 c = rb_eEWOULDBLOCKWaitReadable;
14751 break;
14752#endif
14753 case EINPROGRESS:
14754 c = rb_eEINPROGRESSWaitReadable;
14755 break;
14756 default:
14758 }
14759 break;
14760 default:
14761 rb_bug("invalid read/write type passed to rb_readwrite_sys_fail: %d", waiting);
14762 }
14764}
14765
14766static VALUE
14767get_LAST_READ_LINE(ID _x, VALUE *_y)
14768{
14769 return rb_lastline_get();
14770}
14771
14772static void
14773set_LAST_READ_LINE(VALUE val, ID _x, VALUE *_y)
14774{
14775 rb_lastline_set(val);
14776}
14777
14778/*
14779 * Document-class: IOError
14780 *
14781 * Raised when an IO operation fails.
14782 *
14783 * File.open("/etc/hosts") {|f| f << "example"}
14784 * #=> IOError: not opened for writing
14785 *
14786 * File.open("/etc/hosts") {|f| f.close; f.read }
14787 * #=> IOError: closed stream
14788 *
14789 * Note that some IO failures raise <code>SystemCallError</code>s
14790 * and these are not subclasses of IOError:
14791 *
14792 * File.open("does/not/exist")
14793 * #=> Errno::ENOENT: No such file or directory - does/not/exist
14794 */
14795
14796/*
14797 * Document-class: EOFError
14798 *
14799 * Raised by some IO operations when reaching the end of file. Many IO
14800 * methods exist in two forms,
14801 *
14802 * one that returns +nil+ when the end of file is reached, the other
14803 * raises EOFError.
14804 *
14805 * EOFError is a subclass of IOError.
14806 *
14807 * file = File.open("/etc/hosts")
14808 * file.read
14809 * file.gets #=> nil
14810 * file.readline #=> EOFError: end of file reached
14811 * file.close
14812 */
14813
14814/*
14815 * Document-class: ARGF
14816 *
14817 * == \ARGF and +ARGV+
14818 *
14819 * The \ARGF object works with the array at global variable +ARGV+
14820 * to make <tt>$stdin</tt> and file streams available in the Ruby program:
14821 *
14822 * - **ARGV** may be thought of as the <b>argument vector</b> array.
14823 *
14824 * Initially, it contains the command-line arguments and options
14825 * that are passed to the Ruby program;
14826 * the program can modify that array as it likes.
14827 *
14828 * - **ARGF** may be thought of as the <b>argument files</b> object.
14829 *
14830 * It can access file streams and/or the <tt>$stdin</tt> stream,
14831 * based on what it finds in +ARGV+.
14832 * This provides a convenient way for the command line
14833 * to specify streams for a Ruby program to read.
14834 *
14835 * == Reading
14836 *
14837 * \ARGF may read from _source_ streams,
14838 * which at any particular time are determined by the content of +ARGV+.
14839 *
14840 * === Simplest Case
14841 *
14842 * When the <i>very first</i> \ARGF read occurs with an empty +ARGV+ (<tt>[]</tt>),
14843 * the source is <tt>$stdin</tt>:
14844 *
14845 * - \File +t.rb+:
14846 *
14847 * p ['ARGV', ARGV]
14848 * p ['ARGF.read', ARGF.read]
14849 *
14850 * - Commands and outputs
14851 * (see below for the content of files +foo.txt+ and +bar.txt+):
14852 *
14853 * $ echo "Open the pod bay doors, Hal." | ruby t.rb
14854 * ["ARGV", []]
14855 * ["ARGF.read", "Open the pod bay doors, Hal.\n"]
14856 *
14857 * $ cat foo.txt bar.txt | ruby t.rb
14858 * ["ARGV", []]
14859 * ["ARGF.read", "Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"]
14860 *
14861 * === About the Examples
14862 *
14863 * Many examples here assume the existence of files +foo.txt+ and +bar.txt+:
14864 *
14865 * $ cat foo.txt
14866 * Foo 0
14867 * Foo 1
14868 * $ cat bar.txt
14869 * Bar 0
14870 * Bar 1
14871 * Bar 2
14872 * Bar 3
14873 *
14874 * === Sources in +ARGV+
14875 *
14876 * For any \ARGF read _except_ the {simplest case}[rdoc-ref:ARGF@Simplest+Case]
14877 * (that is, _except_ for the <i>very first</i> \ARGF read with an empty +ARGV+),
14878 * the sources are found in +ARGV+.
14879 *
14880 * \ARGF assumes that each element in array +ARGV+ is a potential source,
14881 * and is one of:
14882 *
14883 * - The string path to a file that may be opened as a stream.
14884 * - The character <tt>'-'</tt>, meaning stream <tt>$stdin</tt>.
14885 *
14886 * Each element that is _not_ one of these
14887 * should be removed from +ARGV+ before \ARGF accesses that source.
14888 *
14889 * In the following example:
14890 *
14891 * - Filepaths +foo.txt+ and +bar.txt+ may be retained as potential sources.
14892 * - Options <tt>--xyzzy</tt> and <tt>--mojo</tt> should be removed.
14893 *
14894 * Example:
14895 *
14896 * - \File +t.rb+:
14897 *
14898 * # Print arguments (and options, if any) found on command line.
14899 * p ['ARGV', ARGV]
14900 *
14901 * - Command and output:
14902 *
14903 * $ ruby t.rb --xyzzy --mojo foo.txt bar.txt
14904 * ["ARGV", ["--xyzzy", "--mojo", "foo.txt", "bar.txt"]]
14905 *
14906 * \ARGF's stream access considers the elements of +ARGV+, left to right:
14907 *
14908 * - \File +t.rb+:
14909 *
14910 * p "ARGV: #{ARGV}"
14911 * p "Read: #{ARGF.read}" # Read everything from all specified streams.
14912 *
14913 * - Command and output:
14914 *
14915 * $ ruby t.rb foo.txt bar.txt
14916 * "ARGV: [\"foo.txt\", \"bar.txt\"]"
14917 * "Read: Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"
14918 *
14919 * Because the value at +ARGV+ is an ordinary array,
14920 * you can manipulate it to control which sources \ARGF considers:
14921 *
14922 * - If you remove an element from +ARGV+, \ARGF will not consider the corresponding source.
14923 * - If you add an element to +ARGV+, \ARGF will consider the corresponding source.
14924 *
14925 * Each element in +ARGV+ is removed when its corresponding source is accessed;
14926 * when all sources have been accessed, the array is empty:
14927 *
14928 * - \File +t.rb+:
14929 *
14930 * until ARGV.empty? && ARGF.eof?
14931 * p "ARGV: #{ARGV}"
14932 * p "Line: #{ARGF.readline}" # Read each line from each specified stream.
14933 * end
14934 *
14935 * - Command and output:
14936 *
14937 * $ ruby t.rb foo.txt bar.txt
14938 * "ARGV: [\"foo.txt\", \"bar.txt\"]"
14939 * "Line: Foo 0\n"
14940 * "ARGV: [\"bar.txt\"]"
14941 * "Line: Foo 1\n"
14942 * "ARGV: [\"bar.txt\"]"
14943 * "Line: Bar 0\n"
14944 * "ARGV: []"
14945 * "Line: Bar 1\n"
14946 * "ARGV: []"
14947 * "Line: Bar 2\n"
14948 * "ARGV: []"
14949 * "Line: Bar 3\n"
14950 *
14951 * ==== Filepaths in +ARGV+
14952 *
14953 * The +ARGV+ array may contain filepaths the specify sources for \ARGF reading.
14954 *
14955 * This program prints what it reads from files at the paths specified
14956 * on the command line:
14957 *
14958 * - \File +t.rb+:
14959 *
14960 * p ['ARGV', ARGV]
14961 * # Read and print all content from the specified sources.
14962 * p ['ARGF.read', ARGF.read]
14963 *
14964 * - Command and output:
14965 *
14966 * $ ruby t.rb foo.txt bar.txt
14967 * ["ARGV", [foo.txt, bar.txt]
14968 * ["ARGF.read", "Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"]
14969 *
14970 * ==== Specifying <tt>$stdin</tt> in +ARGV+
14971 *
14972 * To specify stream <tt>$stdin</tt> in +ARGV+, us the character <tt>'-'</tt>:
14973 *
14974 * - \File +t.rb+:
14975 *
14976 * p ['ARGV', ARGV]
14977 * p ['ARGF.read', ARGF.read]
14978 *
14979 * - Command and output:
14980 *
14981 * $ echo "Open the pod bay doors, Hal." | ruby t.rb -
14982 * ["ARGV", ["-"]]
14983 * ["ARGF.read", "Open the pod bay doors, Hal.\n"]
14984 *
14985 * When no character <tt>'-'</tt> is given, stream <tt>$stdin</tt> is ignored
14986 * (exception:
14987 * see {Specifying $stdin in ARGV}[rdoc-ref:ARGF@Specifying+-24stdin+in+ARGV]):
14988 *
14989 * - Command and output:
14990 *
14991 * $ echo "Open the pod bay doors, Hal." | ruby t.rb foo.txt bar.txt
14992 * "ARGV: [\"foo.txt\", \"bar.txt\"]"
14993 * "Read: Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"
14994 *
14995 * ==== Mixtures and Repetitions in +ARGV+
14996 *
14997 * For an \ARGF reader, +ARGV+ may contain any mixture of filepaths
14998 * and character <tt>'-'</tt>, including repetitions.
14999 *
15000 * ==== Modifications to +ARGV+
15001 *
15002 * The running Ruby program may make any modifications to the +ARGV+ array;
15003 * the current value of +ARGV+ affects \ARGF reading.
15004 *
15005 * ==== Empty +ARGV+
15006 *
15007 * For an empty +ARGV+, an \ARGF read method either returns +nil+
15008 * or raises an exception, depending on the specific method.
15009 *
15010 * === More Read Methods
15011 *
15012 * As seen above, method ARGF#read reads the content of all sources
15013 * into a single string.
15014 * Other \ARGF methods provide other ways to access that content;
15015 * these include:
15016 *
15017 * - Byte access: #each_byte, #getbyte, #readbyte.
15018 * - Character access: #each_char, #getc, #readchar.
15019 * - Codepoint access: #each_codepoint.
15020 * - Line access: #each_line, #gets, #readline, #readlines.
15021 * - Source access: #read, #read_nonblock, #readpartial.
15022 *
15023 * === About \Enumerable
15024 *
15025 * \ARGF includes module Enumerable.
15026 * Virtually all methods in \Enumerable call method <tt>#each</tt> in the including class.
15027 *
15028 * <b>Note well</b>: In \ARGF, method #each returns data from the _sources_,
15029 * _not_ from +ARGV+;
15030 * therefore, for example, <tt>ARGF#entries</tt> returns an array of lines from the sources,
15031 * not an array of the strings from +ARGV+:
15032 *
15033 * - \File +t.rb+:
15034 *
15035 * p ['ARGV', ARGV]
15036 * p ['ARGF.entries', ARGF.entries]
15037 *
15038 * - Command and output:
15039 *
15040 * $ ruby t.rb foo.txt bar.txt
15041 * ["ARGV", ["foo.txt", "bar.txt"]]
15042 * ["ARGF.entries", ["Foo 0\n", "Foo 1\n", "Bar 0\n", "Bar 1\n", "Bar 2\n", "Bar 3\n"]]
15043 *
15044 * == Writing
15045 *
15046 * If <i>inplace mode</i> is in effect,
15047 * \ARGF may write to target streams,
15048 * which at any particular time are determined by the content of ARGV.
15049 *
15050 * Methods about inplace mode:
15051 *
15052 * - #inplace_mode
15053 * - #inplace_mode=
15054 * - #to_write_io
15055 *
15056 * Methods for writing:
15057 *
15058 * - #print
15059 * - #printf
15060 * - #putc
15061 * - #puts
15062 * - #write
15063 *
15064 */
15065
15066/*
15067 * An instance of class \IO (commonly called a _stream_)
15068 * represents an input/output stream in the underlying operating system.
15069 * Class \IO is the basis for input and output in Ruby.
15070 *
15071 * Class File is the only class in the Ruby core that is a subclass of \IO.
15072 * Some classes in the Ruby standard library are also subclasses of \IO;
15073 * these include TCPSocket and UDPSocket.
15074 *
15075 * The global constant ARGF (also accessible as <tt>$<</tt>)
15076 * provides an IO-like stream that allows access to all file paths
15077 * found in ARGV (or found in STDIN if ARGV is empty).
15078 * ARGF is not itself a subclass of \IO.
15079 *
15080 * Class StringIO provides an IO-like stream that handles a String.
15081 * StringIO is not itself a subclass of \IO.
15082 *
15083 * Important objects based on \IO include:
15084 *
15085 * - $stdin.
15086 * - $stdout.
15087 * - $stderr.
15088 * - Instances of class File.
15089 *
15090 * An instance of \IO may be created using:
15091 *
15092 * - IO.new: returns a new \IO object for the given integer file descriptor.
15093 * - IO.open: passes a new \IO object to the given block.
15094 * - IO.popen: returns a new \IO object that is connected to the $stdin and $stdout
15095 * of a newly-launched subprocess.
15096 * - Kernel#open: Returns a new \IO object connected to a given source:
15097 * stream, file, or subprocess.
15098 *
15099 * Like a File stream, an \IO stream has:
15100 *
15101 * - A read/write mode, which may be read-only, write-only, or read/write;
15102 * see {Read/Write Mode}[rdoc-ref:File@Read-2FWrite+Mode].
15103 * - A data mode, which may be text-only or binary;
15104 * see {Data Mode}[rdoc-ref:File@Data+Mode].
15105 * - Internal and external encodings;
15106 * see {Encodings}[rdoc-ref:File@Encodings].
15107 *
15108 * And like other \IO streams, it has:
15109 *
15110 * - A position, which determines where in the stream the next
15111 * read or write is to occur;
15112 * see {Position}[rdoc-ref:IO@Position].
15113 * - A line number, which is a special, line-oriented, "position"
15114 * (different from the position mentioned above);
15115 * see {Line Number}[rdoc-ref:IO@Line+Number].
15116 *
15117 * == Extension <tt>io/console</tt>
15118 *
15119 * Extension <tt>io/console</tt> provides numerous methods
15120 * for interacting with the console;
15121 * requiring it adds numerous methods to class \IO.
15122 *
15123 * == Example Files
15124 *
15125 * Many examples here use these variables:
15126 *
15127 * :include: doc/examples/files.rdoc
15128 *
15129 * == Open Options
15130 *
15131 * A number of \IO methods accept optional keyword arguments
15132 * that determine how a new stream is to be opened:
15133 *
15134 * - +:mode+: Stream mode.
15135 * - +:flags+: Integer file open flags;
15136 * If +mode+ is also given, the two are bitwise-ORed.
15137 * - +:external_encoding+: External encoding for the stream.
15138 * - +:internal_encoding+: Internal encoding for the stream.
15139 * <tt>'-'</tt> is a synonym for the default internal encoding.
15140 * If the value is +nil+ no conversion occurs.
15141 * - +:encoding+: Specifies external and internal encodings as <tt>'extern:intern'</tt>.
15142 * - +:textmode+: If a truthy value, specifies the mode as text-only, binary otherwise.
15143 * - +:binmode+: If a truthy value, specifies the mode as binary, text-only otherwise.
15144 * - +:autoclose+: If a truthy value, specifies that the +fd+ will close
15145 * when the stream closes; otherwise it remains open.
15146 * - +:path:+ If a string value is provided, it is used in #inspect and is available as
15147 * #path method.
15148 *
15149 * Also available are the options offered in String#encode,
15150 * which may control conversion between external and internal encoding.
15151 *
15152 * == Basic \IO
15153 *
15154 * You can perform basic stream \IO with these methods,
15155 * which typically operate on multi-byte strings:
15156 *
15157 * - IO#read: Reads and returns some or all of the remaining bytes from the stream.
15158 * - IO#write: Writes zero or more strings to the stream;
15159 * each given object that is not already a string is converted via +to_s+.
15160 *
15161 * === Position
15162 *
15163 * An \IO stream has a nonnegative integer _position_,
15164 * which is the byte offset at which the next read or write is to occur.
15165 * A new stream has position zero (and line number zero);
15166 * method +rewind+ resets the position (and line number) to zero.
15167 *
15168 * These methods discard {buffers}[rdoc-ref:IO@Buffering] and the
15169 * Encoding::Converter instances used for that \IO.
15170 *
15171 * The relevant methods:
15172 *
15173 * - IO#tell (aliased as +#pos+): Returns the current position (in bytes) in the stream.
15174 * - IO#pos=: Sets the position of the stream to a given integer +new_position+ (in bytes).
15175 * - IO#seek: Sets the position of the stream to a given integer +offset+ (in bytes),
15176 * relative to a given position +whence+
15177 * (indicating the beginning, end, or current position).
15178 * - IO#rewind: Positions the stream at the beginning (also resetting the line number).
15179 *
15180 * === Open and Closed Streams
15181 *
15182 * A new \IO stream may be open for reading, open for writing, or both.
15183 *
15184 * A stream is automatically closed when claimed by the garbage collector.
15185 *
15186 * Attempted reading or writing on a closed stream raises an exception.
15187 *
15188 * The relevant methods:
15189 *
15190 * - IO#close: Closes the stream for both reading and writing.
15191 * - IO#close_read: Closes the stream for reading.
15192 * - IO#close_write: Closes the stream for writing.
15193 * - IO#closed?: Returns whether the stream is closed.
15194 *
15195 * === End-of-Stream
15196 *
15197 * You can query whether a stream is positioned at its end:
15198 *
15199 * - IO#eof? (also aliased as +#eof+): Returns whether the stream is at end-of-stream.
15200 *
15201 * You can reposition to end-of-stream by using method IO#seek:
15202 *
15203 * f = File.new('t.txt')
15204 * f.eof? # => false
15205 * f.seek(0, :END)
15206 * f.eof? # => true
15207 * f.close
15208 *
15209 * Or by reading all stream content (which is slower than using IO#seek):
15210 *
15211 * f.rewind
15212 * f.eof? # => false
15213 * f.read # => "First line\nSecond line\n\nFourth line\nFifth line\n"
15214 * f.eof? # => true
15215 *
15216 * == Line \IO
15217 *
15218 * Class \IO supports line-oriented
15219 * {input}[rdoc-ref:IO@Line+Input] and {output}[rdoc-ref:IO@Line+Output]
15220 *
15221 * === Line Input
15222 *
15223 * Class \IO supports line-oriented input for
15224 * {files}[rdoc-ref:IO@File+Line+Input] and {IO streams}[rdoc-ref:IO@Stream+Line+Input]
15225 *
15226 * ==== \File Line Input
15227 *
15228 * You can read lines from a file using these methods:
15229 *
15230 * - IO.foreach: Reads each line and passes it to the given block.
15231 * - IO.readlines: Reads and returns all lines in an array.
15232 *
15233 * For each of these methods:
15234 *
15235 * - You can specify {open options}[rdoc-ref:IO@Open+Options].
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 * ==== Stream Line Input
15242 *
15243 * You can read lines from an \IO stream using these methods:
15244 *
15245 * - IO#each_line: Reads each remaining line, passing it to the given block.
15246 * - IO#gets: Returns the next line.
15247 * - IO#readline: Like #gets, but raises an exception at end-of-stream.
15248 * - IO#readlines: Returns all remaining lines in an array.
15249 *
15250 * For each of these methods:
15251 *
15252 * - Reading may begin mid-line,
15253 * depending on the stream's _position_;
15254 * see {Position}[rdoc-ref:IO@Position].
15255 * - Line parsing depends on the effective <i>line separator</i>;
15256 * see {Line Separator}[rdoc-ref:IO@Line+Separator].
15257 * - The length of each returned line depends on the effective <i>line limit</i>;
15258 * see {Line Limit}[rdoc-ref:IO@Line+Limit].
15259 *
15260 * ===== Line Separator
15261 *
15262 * Each of the {line input methods}[rdoc-ref:IO@Line+Input] uses a <i>line separator</i>:
15263 * the string that determines what is considered a line;
15264 * it is sometimes called the <i>input record separator</i>.
15265 *
15266 * The default line separator is taken from global variable <tt>$/</tt>,
15267 * whose initial value is <tt>"\n"</tt>.
15268 *
15269 * Generally, the line to be read next is all data
15270 * from the current {position}[rdoc-ref:IO@Position]
15271 * to the next line separator
15272 * (but see {Special Line Separator Values}[rdoc-ref:IO@Special+Line+Separator+Values]):
15273 *
15274 * f = File.new('t.txt')
15275 * # Method gets with no sep argument returns the next line, according to $/.
15276 * f.gets # => "First line\n"
15277 * f.gets # => "Second line\n"
15278 * f.gets # => "\n"
15279 * f.gets # => "Fourth line\n"
15280 * f.gets # => "Fifth line\n"
15281 * f.close
15282 *
15283 * You can use a different line separator by passing argument +sep+:
15284 *
15285 * f = File.new('t.txt')
15286 * f.gets('l') # => "First l"
15287 * f.gets('li') # => "ine\nSecond li"
15288 * f.gets('lin') # => "ne\n\nFourth lin"
15289 * f.gets # => "e\n"
15290 * f.close
15291 *
15292 * Or by setting global variable <tt>$/</tt>:
15293 *
15294 * f = File.new('t.txt')
15295 * $/ = 'l'
15296 * f.gets # => "First l"
15297 * f.gets # => "ine\nSecond l"
15298 * f.gets # => "ine\n\nFourth l"
15299 * f.close
15300 *
15301 * ===== Special Line Separator Values
15302 *
15303 * Each of the {line input methods}[rdoc-ref:IO@Line+Input]
15304 * accepts two special values for parameter +sep+:
15305 *
15306 * - +nil+: The entire stream is to be read ("slurped") into a single string:
15307 *
15308 * f = File.new('t.txt')
15309 * f.gets(nil) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
15310 * f.close
15311 *
15312 * - <tt>''</tt> (the empty string): The next "paragraph" is to be read
15313 * (paragraphs being separated by two consecutive line separators):
15314 *
15315 * f = File.new('t.txt')
15316 * f.gets('') # => "First line\nSecond line\n\n"
15317 * f.gets('') # => "Fourth line\nFifth line\n"
15318 * f.close
15319 *
15320 * ===== Line Limit
15321 *
15322 * Each of the {line input methods}[rdoc-ref:IO@Line+Input]
15323 * uses an integer <i>line limit</i>,
15324 * which restricts the number of bytes that may be returned.
15325 * (A multi-byte character will not be split, and so a returned line may be slightly longer
15326 * than the limit).
15327 *
15328 * The default limit value is <tt>-1</tt>;
15329 * any negative limit value means that there is no limit.
15330 *
15331 * If there is no limit, the line is determined only by +sep+.
15332 *
15333 * # Text with 1-byte characters.
15334 * File.open('t.txt') {|f| f.gets(1) } # => "F"
15335 * File.open('t.txt') {|f| f.gets(2) } # => "Fi"
15336 * File.open('t.txt') {|f| f.gets(3) } # => "Fir"
15337 * File.open('t.txt') {|f| f.gets(4) } # => "Firs"
15338 * # No more than one line.
15339 * File.open('t.txt') {|f| f.gets(10) } # => "First line"
15340 * File.open('t.txt') {|f| f.gets(11) } # => "First line\n"
15341 * File.open('t.txt') {|f| f.gets(12) } # => "First line\n"
15342 *
15343 * # Text with 2-byte characters, which will not be split.
15344 * File.open('t.rus') {|f| f.gets(1).size } # => 1
15345 * File.open('t.rus') {|f| f.gets(2).size } # => 1
15346 * File.open('t.rus') {|f| f.gets(3).size } # => 2
15347 * File.open('t.rus') {|f| f.gets(4).size } # => 2
15348 *
15349 * ===== Line Separator and Line Limit
15350 *
15351 * With arguments +sep+ and +limit+ given, combines the two behaviors:
15352 *
15353 * - Returns the next line as determined by line separator +sep+.
15354 * - But returns no more bytes than are allowed by the limit +limit+.
15355 *
15356 * Example:
15357 *
15358 * File.open('t.txt') {|f| f.gets('li', 20) } # => "First li"
15359 * File.open('t.txt') {|f| f.gets('li', 2) } # => "Fi"
15360 *
15361 * ===== Line Number
15362 *
15363 * A readable \IO stream has a non-negative integer <i>line number</i>:
15364 *
15365 * - IO#lineno: Returns the line number.
15366 * - IO#lineno=: Resets and returns the line number.
15367 *
15368 * Unless modified by a call to method IO#lineno=,
15369 * the line number is the number of lines read
15370 * by certain line-oriented methods,
15371 * according to the effective {line separator}[rdoc-ref:IO@Line+Separator]:
15372 *
15373 * - IO.foreach: Increments the line number on each call to the block.
15374 * - IO#each_line: Increments the line number on each call to the block.
15375 * - IO#gets: Increments the line number.
15376 * - IO#readline: Increments the line number.
15377 * - IO#readlines: Increments the line number for each line read.
15378 *
15379 * A new stream is initially has line number zero (and position zero);
15380 * method +rewind+ resets the line number (and position) to zero:
15381 *
15382 * f = File.new('t.txt')
15383 * f.lineno # => 0
15384 * f.gets # => "First line\n"
15385 * f.lineno # => 1
15386 * f.rewind
15387 * f.lineno # => 0
15388 * f.close
15389 *
15390 * Reading lines from a stream usually changes its line number:
15391 *
15392 * f = File.new('t.txt', 'r')
15393 * f.lineno # => 0
15394 * f.readline # => "This is line one.\n"
15395 * f.lineno # => 1
15396 * f.readline # => "This is the second line.\n"
15397 * f.lineno # => 2
15398 * f.readline # => "Here's the third line.\n"
15399 * f.lineno # => 3
15400 * f.eof? # => true
15401 * f.close
15402 *
15403 * Iterating over lines in a stream usually changes its line number:
15404 *
15405 * File.open('t.txt') do |f|
15406 * f.each_line do |line|
15407 * p "position=#{f.pos} eof?=#{f.eof?} lineno=#{f.lineno}"
15408 * end
15409 * end
15410 *
15411 * Output:
15412 *
15413 * "position=11 eof?=false lineno=1"
15414 * "position=23 eof?=false lineno=2"
15415 * "position=24 eof?=false lineno=3"
15416 * "position=36 eof?=false lineno=4"
15417 * "position=47 eof?=true lineno=5"
15418 *
15419 * Unlike the stream's {position}[rdoc-ref:IO@Position],
15420 * the line number does not affect where the next read or write will occur:
15421 *
15422 * f = File.new('t.txt')
15423 * f.lineno = 1000
15424 * f.lineno # => 1000
15425 * f.gets # => "First line\n"
15426 * f.lineno # => 1001
15427 * f.close
15428 *
15429 * Associated with the line number is the global variable <tt>$.</tt>:
15430 *
15431 * - When a stream is opened, <tt>$.</tt> is not set;
15432 * its value is left over from previous activity in the process:
15433 *
15434 * $. = 41
15435 * f = File.new('t.txt')
15436 * $. = 41
15437 * # => 41
15438 * f.close
15439 *
15440 * - When a stream is read, <tt>$.</tt> is set to the line number for that stream:
15441 *
15442 * f0 = File.new('t.txt')
15443 * f1 = File.new('t.dat')
15444 * f0.readlines # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
15445 * $. # => 5
15446 * f1.readlines # => ["\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"]
15447 * $. # => 1
15448 * f0.close
15449 * f1.close
15450 *
15451 * - Methods IO#rewind and IO#seek do not affect <tt>$.</tt>:
15452 *
15453 * f = File.new('t.txt')
15454 * f.readlines # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
15455 * $. # => 5
15456 * f.rewind
15457 * f.seek(0, :SET)
15458 * $. # => 5
15459 * f.close
15460 *
15461 * === Line Output
15462 *
15463 * You can write to an \IO stream line-by-line using this method:
15464 *
15465 * - IO#puts: Writes objects to the stream.
15466 *
15467 * == Character \IO
15468 *
15469 * You can process an \IO stream character-by-character using these methods:
15470 *
15471 * - IO#getc: Reads and returns the next character from the stream.
15472 * - IO#readchar: Like #getc, but raises an exception at end-of-stream.
15473 * - IO#ungetc: Pushes back ("unshifts") a character or integer onto the stream.
15474 * - IO#putc: Writes a character to the stream.
15475 * - IO#each_char: Reads each remaining character in the stream,
15476 * passing the character to the given block.
15477 *
15478 * == Byte \IO
15479 *
15480 * You can process an \IO stream byte-by-byte using these methods:
15481 *
15482 * - IO#getbyte: Returns the next 8-bit byte as an integer in range 0..255.
15483 * - IO#readbyte: Like #getbyte, but raises an exception if at end-of-stream.
15484 * - IO#ungetbyte: Pushes back ("unshifts") a byte back onto the stream.
15485 * - IO#each_byte: Reads each remaining byte in the stream,
15486 * passing the byte to the given block.
15487 *
15488 * == Codepoint \IO
15489 *
15490 * You can process an \IO stream codepoint-by-codepoint:
15491 *
15492 * - IO#each_codepoint: Reads each remaining codepoint, passing it to the given block.
15493 *
15494 * == What's Here
15495 *
15496 * First, what's elsewhere. Class \IO:
15497 *
15498 * - Inherits from {class Object}[rdoc-ref:Object@What-27s+Here].
15499 * - Includes {module Enumerable}[rdoc-ref:Enumerable@What-27s+Here],
15500 * which provides dozens of additional methods.
15501 *
15502 * Here, class \IO provides methods that are useful for:
15503 *
15504 * - {Creating}[rdoc-ref:IO@Creating]
15505 * - {Reading}[rdoc-ref:IO@Reading]
15506 * - {Writing}[rdoc-ref:IO@Writing]
15507 * - {Positioning}[rdoc-ref:IO@Positioning]
15508 * - {Iterating}[rdoc-ref:IO@Iterating]
15509 * - {Settings}[rdoc-ref:IO@Settings]
15510 * - {Querying}[rdoc-ref:IO@Querying]
15511 * - {Buffering}[rdoc-ref:IO@Buffering]
15512 * - {Low-Level Access}[rdoc-ref:IO@Low-Level+Access]
15513 * - {Other}[rdoc-ref:IO@Other]
15514 *
15515 * === Creating
15516 *
15517 * - ::new (aliased as ::for_fd): Creates and returns a new \IO object for the given
15518 * integer file descriptor.
15519 * - ::open: Creates a new \IO object.
15520 * - ::pipe: Creates a connected pair of reader and writer \IO objects.
15521 * - ::popen: Creates an \IO object to interact with a subprocess.
15522 * - ::select: Selects which given \IO instances are ready for reading,
15523 * writing, or have pending exceptions.
15524 *
15525 * === Reading
15526 *
15527 * - ::binread: Returns a binary string with all or a subset of bytes
15528 * from the given file.
15529 * - ::read: Returns a string with all or a subset of bytes from the given file.
15530 * - ::readlines: Returns an array of strings, which are the lines from the given file.
15531 * - #getbyte: Returns the next 8-bit byte read from +self+ as an integer.
15532 * - #getc: Returns the next character read from +self+ as a string.
15533 * - #gets: Returns the line read from +self+.
15534 * - #pread: Returns all or the next _n_ bytes read from +self+,
15535 * not updating the receiver's offset.
15536 * - #read: Returns all remaining or the next _n_ bytes read from +self+
15537 * for a given _n_.
15538 * - #read_nonblock: the next _n_ bytes read from +self+ for a given _n_,
15539 * in non-block mode.
15540 * - #readbyte: Returns the next byte read from +self+;
15541 * same as #getbyte, but raises an exception on end-of-stream.
15542 * - #readchar: Returns the next character read from +self+;
15543 * same as #getc, but raises an exception on end-of-stream.
15544 * - #readline: Returns the next line read from +self+;
15545 * same as #getline, but raises an exception of end-of-stream.
15546 * - #readlines: Returns an array of all lines read read from +self+.
15547 * - #readpartial: Returns up to the given number of bytes from +self+.
15548 *
15549 * === Writing
15550 *
15551 * - ::binwrite: Writes the given string to the file at the given filepath,
15552 * in binary mode.
15553 * - ::write: Writes the given string to +self+.
15554 * - #<<: Appends the given string to +self+.
15555 * - #print: Prints last read line or given objects to +self+.
15556 * - #printf: Writes to +self+ based on the given format string and objects.
15557 * - #putc: Writes a character to +self+.
15558 * - #puts: Writes lines to +self+, making sure line ends with a newline.
15559 * - #pwrite: Writes the given string at the given offset,
15560 * not updating the receiver's offset.
15561 * - #write: Writes one or more given strings to +self+.
15562 * - #write_nonblock: Writes one or more given strings to +self+ in non-blocking mode.
15563 *
15564 * === Positioning
15565 *
15566 * - #lineno: Returns the current line number in +self+.
15567 * - #lineno=: Sets the line number is +self+.
15568 * - #pos (aliased as #tell): Returns the current byte offset in +self+.
15569 * - #pos=: Sets the byte offset in +self+.
15570 * - #reopen: Reassociates +self+ with a new or existing \IO stream.
15571 * - #rewind: Positions +self+ to the beginning of input.
15572 * - #seek: Sets the offset for +self+ relative to given position.
15573 *
15574 * === Iterating
15575 *
15576 * - ::foreach: Yields each line of given file to the block.
15577 * - #each (aliased as #each_line): Calls the given block
15578 * with each successive line in +self+.
15579 * - #each_byte: Calls the given block with each successive byte in +self+
15580 * as an integer.
15581 * - #each_char: Calls the given block with each successive character in +self+
15582 * as a string.
15583 * - #each_codepoint: Calls the given block with each successive codepoint in +self+
15584 * as an integer.
15585 *
15586 * === Settings
15587 *
15588 * - #autoclose=: Sets whether +self+ auto-closes.
15589 * - #binmode: Sets +self+ to binary mode.
15590 * - #close: Closes +self+.
15591 * - #close_on_exec=: Sets the close-on-exec flag.
15592 * - #close_read: Closes +self+ for reading.
15593 * - #close_write: Closes +self+ for writing.
15594 * - #set_encoding: Sets the encoding for +self+.
15595 * - #set_encoding_by_bom: Sets the encoding for +self+, based on its
15596 * Unicode byte-order-mark.
15597 * - #sync=: Sets the sync-mode to the given value.
15598 *
15599 * === Querying
15600 *
15601 * - #autoclose?: Returns whether +self+ auto-closes.
15602 * - #binmode?: Returns whether +self+ is in binary mode.
15603 * - #close_on_exec?: Returns the close-on-exec flag for +self+.
15604 * - #closed?: Returns whether +self+ is closed.
15605 * - #eof? (aliased as #eof): Returns whether +self+ is at end-of-stream.
15606 * - #external_encoding: Returns the external encoding object for +self+.
15607 * - #fileno (aliased as #to_i): Returns the integer file descriptor for +self+
15608 * - #internal_encoding: Returns the internal encoding object for +self+.
15609 * - #pid: Returns the process ID of a child process associated with +self+,
15610 * if +self+ was created by ::popen.
15611 * - #stat: Returns the File::Stat object containing status information for +self+.
15612 * - #sync: Returns whether +self+ is in sync-mode.
15613 * - #tty? (aliased as #isatty): Returns whether +self+ is a terminal.
15614 *
15615 * === Buffering
15616 *
15617 * - #fdatasync: Immediately writes all buffered data in +self+ to disk.
15618 * - #flush: Flushes any buffered data within +self+ to the underlying
15619 * operating system.
15620 * - #fsync: Immediately writes all buffered data and attributes in +self+ to disk.
15621 * - #ungetbyte: Prepends buffer for +self+ with given integer byte or string.
15622 * - #ungetc: Prepends buffer for +self+ with given string.
15623 *
15624 * === Low-Level Access
15625 *
15626 * - ::sysopen: Opens the file given by its path,
15627 * returning the integer file descriptor.
15628 * - #advise: Announces the intention to access data from +self+ in a specific way.
15629 * - #fcntl: Passes a low-level command to the file specified
15630 * by the given file descriptor.
15631 * - #ioctl: Passes a low-level command to the device specified
15632 * by the given file descriptor.
15633 * - #sysread: Returns up to the next _n_ bytes read from self using a low-level read.
15634 * - #sysseek: Sets the offset for +self+.
15635 * - #syswrite: Writes the given string to +self+ using a low-level write.
15636 *
15637 * === Other
15638 *
15639 * - ::copy_stream: Copies data from a source to a destination,
15640 * each of which is a filepath or an \IO-like object.
15641 * - ::try_convert: Returns a new \IO object resulting from converting
15642 * the given object.
15643 * - #inspect: Returns the string representation of +self+.
15644 *
15645 */
15646
15647void
15648Init_IO(void)
15649{
15650 VALUE rb_cARGF;
15651#ifdef __CYGWIN__
15652#include <sys/cygwin.h>
15653 static struct __cygwin_perfile pf[] =
15654 {
15655 {"", O_RDONLY | O_BINARY},
15656 {"", O_WRONLY | O_BINARY},
15657 {"", O_RDWR | O_BINARY},
15658 {"", O_APPEND | O_BINARY},
15659 {NULL, 0}
15660 };
15661 cygwin_internal(CW_PERFILE, pf);
15662#endif
15663
15666
15667 id_write = rb_intern_const("write");
15668 id_read = rb_intern_const("read");
15669 id_getc = rb_intern_const("getc");
15670 id_flush = rb_intern_const("flush");
15671 id_readpartial = rb_intern_const("readpartial");
15672 id_set_encoding = rb_intern_const("set_encoding");
15673 id_fileno = rb_intern_const("fileno");
15674
15675 rb_define_global_function("syscall", rb_f_syscall, -1);
15676
15677 rb_define_global_function("open", rb_f_open, -1);
15678 rb_define_global_function("printf", rb_f_printf, -1);
15679 rb_define_global_function("print", rb_f_print, -1);
15680 rb_define_global_function("putc", rb_f_putc, 1);
15681 rb_define_global_function("puts", rb_f_puts, -1);
15682 rb_define_global_function("gets", rb_f_gets, -1);
15683 rb_define_global_function("readline", rb_f_readline, -1);
15684 rb_define_global_function("select", rb_f_select, -1);
15685
15686 rb_define_global_function("readlines", rb_f_readlines, -1);
15687
15688 rb_define_global_function("`", rb_f_backquote, 1);
15689
15690 rb_define_global_function("p", rb_f_p, -1);
15691 rb_define_method(rb_mKernel, "display", rb_obj_display, -1);
15692
15693 rb_cIO = rb_define_class("IO", rb_cObject);
15695
15696 /* Can be raised by IO operations when IO#timeout= is set. */
15698
15699 /* Readable event mask for IO#wait. */
15700 rb_define_const(rb_cIO, "READABLE", INT2NUM(RUBY_IO_READABLE));
15701 /* Writable event mask for IO#wait. */
15702 rb_define_const(rb_cIO, "WRITABLE", INT2NUM(RUBY_IO_WRITABLE));
15703 /* Priority event mask for IO#wait. */
15704 rb_define_const(rb_cIO, "PRIORITY", INT2NUM(RUBY_IO_PRIORITY));
15705
15706 /* exception to wait for reading. see IO.select. */
15708 /* exception to wait for writing. see IO.select. */
15710 /* exception to wait for reading by EAGAIN. see IO.select. */
15711 rb_eEAGAINWaitReadable = rb_define_class_under(rb_cIO, "EAGAINWaitReadable", rb_eEAGAIN);
15712 rb_include_module(rb_eEAGAINWaitReadable, rb_mWaitReadable);
15713 /* exception to wait for writing by EAGAIN. see IO.select. */
15714 rb_eEAGAINWaitWritable = rb_define_class_under(rb_cIO, "EAGAINWaitWritable", rb_eEAGAIN);
15715 rb_include_module(rb_eEAGAINWaitWritable, rb_mWaitWritable);
15716#if EAGAIN == EWOULDBLOCK
15717 rb_eEWOULDBLOCKWaitReadable = rb_eEAGAINWaitReadable;
15718 /* same as IO::EAGAINWaitReadable */
15719 rb_define_const(rb_cIO, "EWOULDBLOCKWaitReadable", rb_eEAGAINWaitReadable);
15720 rb_eEWOULDBLOCKWaitWritable = rb_eEAGAINWaitWritable;
15721 /* same as IO::EAGAINWaitWritable */
15722 rb_define_const(rb_cIO, "EWOULDBLOCKWaitWritable", rb_eEAGAINWaitWritable);
15723#else
15724 /* exception to wait for reading by EWOULDBLOCK. see IO.select. */
15725 rb_eEWOULDBLOCKWaitReadable = rb_define_class_under(rb_cIO, "EWOULDBLOCKWaitReadable", rb_eEWOULDBLOCK);
15726 rb_include_module(rb_eEWOULDBLOCKWaitReadable, rb_mWaitReadable);
15727 /* exception to wait for writing by EWOULDBLOCK. see IO.select. */
15728 rb_eEWOULDBLOCKWaitWritable = rb_define_class_under(rb_cIO, "EWOULDBLOCKWaitWritable", rb_eEWOULDBLOCK);
15729 rb_include_module(rb_eEWOULDBLOCKWaitWritable, rb_mWaitWritable);
15730#endif
15731 /* exception to wait for reading by EINPROGRESS. see IO.select. */
15732 rb_eEINPROGRESSWaitReadable = rb_define_class_under(rb_cIO, "EINPROGRESSWaitReadable", rb_eEINPROGRESS);
15733 rb_include_module(rb_eEINPROGRESSWaitReadable, rb_mWaitReadable);
15734 /* exception to wait for writing by EINPROGRESS. see IO.select. */
15735 rb_eEINPROGRESSWaitWritable = rb_define_class_under(rb_cIO, "EINPROGRESSWaitWritable", rb_eEINPROGRESS);
15736 rb_include_module(rb_eEINPROGRESSWaitWritable, rb_mWaitWritable);
15737
15738#if 0
15739 /* This is necessary only for forcing rdoc handle File::open */
15740 rb_define_singleton_method(rb_cFile, "open", rb_io_s_open, -1);
15741#endif
15742
15743 rb_define_alloc_func(rb_cIO, io_alloc);
15744 rb_define_singleton_method(rb_cIO, "new", rb_io_s_new, -1);
15745 rb_define_singleton_method(rb_cIO, "open", rb_io_s_open, -1);
15746 rb_define_singleton_method(rb_cIO, "sysopen", rb_io_s_sysopen, -1);
15747 rb_define_singleton_method(rb_cIO, "for_fd", rb_io_s_for_fd, -1);
15748 rb_define_singleton_method(rb_cIO, "popen", rb_io_s_popen, -1);
15749 rb_define_singleton_method(rb_cIO, "foreach", rb_io_s_foreach, -1);
15750 rb_define_singleton_method(rb_cIO, "readlines", rb_io_s_readlines, -1);
15751 rb_define_singleton_method(rb_cIO, "read", rb_io_s_read, -1);
15752 rb_define_singleton_method(rb_cIO, "binread", rb_io_s_binread, -1);
15753 rb_define_singleton_method(rb_cIO, "write", rb_io_s_write, -1);
15754 rb_define_singleton_method(rb_cIO, "binwrite", rb_io_s_binwrite, -1);
15755 rb_define_singleton_method(rb_cIO, "select", rb_f_select, -1);
15756 rb_define_singleton_method(rb_cIO, "pipe", rb_io_s_pipe, -1);
15757 rb_define_singleton_method(rb_cIO, "try_convert", rb_io_s_try_convert, 1);
15758 rb_define_singleton_method(rb_cIO, "copy_stream", rb_io_s_copy_stream, -1);
15759
15760 rb_define_method(rb_cIO, "initialize", rb_io_initialize, -1);
15761
15763 rb_define_hooked_variable("$,", &rb_output_fs, 0, deprecated_str_setter);
15764
15765 rb_default_rs = rb_fstring_lit("\n"); /* avoid modifying RS_default */
15766 rb_vm_register_global_object(rb_default_rs);
15767 rb_rs = rb_default_rs;
15769 rb_define_hooked_variable("$/", &rb_rs, 0, deprecated_rs_setter);
15770 rb_gvar_ractor_local("$/"); // not local but ractor safe
15771 rb_define_hooked_variable("$-0", &rb_rs, 0, deprecated_rs_setter);
15772 rb_gvar_ractor_local("$-0"); // not local but ractor safe
15773 rb_define_hooked_variable("$\\", &rb_output_rs, 0, deprecated_str_setter);
15774
15775 rb_define_virtual_variable("$_", get_LAST_READ_LINE, set_LAST_READ_LINE);
15776 rb_gvar_ractor_local("$_");
15777
15778 rb_define_method(rb_cIO, "initialize_copy", rb_io_init_copy, 1);
15779 rb_define_method(rb_cIO, "reopen", rb_io_reopen, -1);
15780
15781 rb_define_method(rb_cIO, "print", rb_io_print, -1);
15782 rb_define_method(rb_cIO, "putc", rb_io_putc, 1);
15783 rb_define_method(rb_cIO, "puts", rb_io_puts, -1);
15784 rb_define_method(rb_cIO, "printf", rb_io_printf, -1);
15785
15786 rb_define_method(rb_cIO, "each", rb_io_each_line, -1);
15787 rb_define_method(rb_cIO, "each_line", rb_io_each_line, -1);
15788 rb_define_method(rb_cIO, "each_byte", rb_io_each_byte, 0);
15789 rb_define_method(rb_cIO, "each_char", rb_io_each_char, 0);
15790 rb_define_method(rb_cIO, "each_codepoint", rb_io_each_codepoint, 0);
15791
15792 rb_define_method(rb_cIO, "syswrite", rb_io_syswrite, 1);
15793 rb_define_method(rb_cIO, "sysread", rb_io_sysread, -1);
15794
15795 rb_define_method(rb_cIO, "pread", rb_io_pread, -1);
15796 rb_define_method(rb_cIO, "pwrite", rb_io_pwrite, 2);
15797
15798 rb_define_method(rb_cIO, "fileno", rb_io_fileno, 0);
15799 rb_define_alias(rb_cIO, "to_i", "fileno");
15800 rb_define_method(rb_cIO, "to_io", rb_io_to_io, 0);
15801
15802 rb_define_method(rb_cIO, "timeout", rb_io_timeout, 0);
15803 rb_define_method(rb_cIO, "timeout=", rb_io_set_timeout, 1);
15804
15805 rb_define_method(rb_cIO, "fsync", rb_io_fsync, 0);
15806 rb_define_method(rb_cIO, "fdatasync", rb_io_fdatasync, 0);
15807 rb_define_method(rb_cIO, "sync", rb_io_sync, 0);
15808 rb_define_method(rb_cIO, "sync=", rb_io_set_sync, 1);
15809
15810 rb_define_method(rb_cIO, "lineno", rb_io_lineno, 0);
15811 rb_define_method(rb_cIO, "lineno=", rb_io_set_lineno, 1);
15812
15813 rb_define_method(rb_cIO, "readlines", rb_io_readlines, -1);
15814
15815 rb_define_method(rb_cIO, "readpartial", io_readpartial, -1);
15816 rb_define_method(rb_cIO, "read", io_read, -1);
15817 rb_define_method(rb_cIO, "write", io_write_m, -1);
15818 rb_define_method(rb_cIO, "gets", rb_io_gets_m, -1);
15819 rb_define_method(rb_cIO, "getc", rb_io_getc, 0);
15820 rb_define_method(rb_cIO, "getbyte", rb_io_getbyte, 0);
15821 rb_define_method(rb_cIO, "readchar", rb_io_readchar, 0);
15822 rb_define_method(rb_cIO, "readbyte", rb_io_readbyte, 0);
15823 rb_define_method(rb_cIO, "ungetbyte",rb_io_ungetbyte, 1);
15824 rb_define_method(rb_cIO, "ungetc",rb_io_ungetc, 1);
15826 rb_define_method(rb_cIO, "flush", rb_io_flush, 0);
15827 rb_define_method(rb_cIO, "tell", rb_io_tell, 0);
15828 rb_define_method(rb_cIO, "seek", rb_io_seek_m, -1);
15829 /* Set I/O position from the beginning */
15830 rb_define_const(rb_cIO, "SEEK_SET", INT2FIX(SEEK_SET));
15831 /* Set I/O position from the current position */
15832 rb_define_const(rb_cIO, "SEEK_CUR", INT2FIX(SEEK_CUR));
15833 /* Set I/O position from the end */
15834 rb_define_const(rb_cIO, "SEEK_END", INT2FIX(SEEK_END));
15835#ifdef SEEK_DATA
15836 /* Set I/O position to the next location containing data */
15837 rb_define_const(rb_cIO, "SEEK_DATA", INT2FIX(SEEK_DATA));
15838#endif
15839#ifdef SEEK_HOLE
15840 /* Set I/O position to the next hole */
15841 rb_define_const(rb_cIO, "SEEK_HOLE", INT2FIX(SEEK_HOLE));
15842#endif
15843 rb_define_method(rb_cIO, "rewind", rb_io_rewind, 0);
15844 rb_define_method(rb_cIO, "pos", rb_io_tell, 0);
15845 rb_define_method(rb_cIO, "pos=", rb_io_set_pos, 1);
15846 rb_define_method(rb_cIO, "eof", rb_io_eof, 0);
15847 rb_define_method(rb_cIO, "eof?", rb_io_eof, 0);
15848
15849 rb_define_method(rb_cIO, "close_on_exec?", rb_io_close_on_exec_p, 0);
15850 rb_define_method(rb_cIO, "close_on_exec=", rb_io_set_close_on_exec, 1);
15851
15852 rb_define_method(rb_cIO, "close", rb_io_close_m, 0);
15853 rb_define_method(rb_cIO, "closed?", rb_io_closed_p, 0);
15854 rb_define_method(rb_cIO, "close_read", rb_io_close_read, 0);
15855 rb_define_method(rb_cIO, "close_write", rb_io_close_write, 0);
15856
15857 rb_define_method(rb_cIO, "isatty", rb_io_isatty, 0);
15858 rb_define_method(rb_cIO, "tty?", rb_io_isatty, 0);
15859 rb_define_method(rb_cIO, "binmode", rb_io_binmode_m, 0);
15860 rb_define_method(rb_cIO, "binmode?", rb_io_binmode_p, 0);
15861 rb_define_method(rb_cIO, "sysseek", rb_io_sysseek, -1);
15862 rb_define_method(rb_cIO, "advise", rb_io_advise, -1);
15863
15864 rb_define_method(rb_cIO, "ioctl", rb_io_ioctl, -1);
15865 rb_define_method(rb_cIO, "fcntl", rb_io_fcntl, -1);
15866 rb_define_method(rb_cIO, "pid", rb_io_pid, 0);
15867
15868 rb_define_method(rb_cIO, "path", rb_io_path, 0);
15869 rb_define_method(rb_cIO, "to_path", rb_io_path, 0);
15870
15871 rb_define_method(rb_cIO, "inspect", rb_io_inspect, 0);
15872
15873 rb_define_method(rb_cIO, "external_encoding", rb_io_external_encoding, 0);
15874 rb_define_method(rb_cIO, "internal_encoding", rb_io_internal_encoding, 0);
15875 rb_define_method(rb_cIO, "set_encoding", rb_io_set_encoding, -1);
15876 rb_define_method(rb_cIO, "set_encoding_by_bom", rb_io_set_encoding_by_bom, 0);
15877
15878 rb_define_method(rb_cIO, "autoclose?", rb_io_autoclose_p, 0);
15879 rb_define_method(rb_cIO, "autoclose=", rb_io_set_autoclose, 1);
15880
15881 rb_define_method(rb_cIO, "wait", io_wait, -1);
15882
15883 rb_define_method(rb_cIO, "wait_readable", io_wait_readable, -1);
15884 rb_define_method(rb_cIO, "wait_writable", io_wait_writable, -1);
15885 rb_define_method(rb_cIO, "wait_priority", io_wait_priority, -1);
15886
15887 rb_define_virtual_variable("$stdin", stdin_getter, stdin_setter);
15888 rb_define_virtual_variable("$stdout", stdout_getter, stdout_setter);
15889 rb_define_virtual_variable("$>", stdout_getter, stdout_setter);
15890 rb_define_virtual_variable("$stderr", stderr_getter, stderr_setter);
15891
15892 rb_gvar_ractor_local("$stdin");
15893 rb_gvar_ractor_local("$stdout");
15894 rb_gvar_ractor_local("$>");
15895 rb_gvar_ractor_local("$stderr");
15896
15898 rb_stdin = rb_io_prep_stdin();
15900 rb_stdout = rb_io_prep_stdout();
15902 rb_stderr = rb_io_prep_stderr();
15903
15904 orig_stdout = rb_stdout;
15905 orig_stderr = rb_stderr;
15906
15907 /* Holds the original stdin */
15909 /* Holds the original stdout */
15911 /* Holds the original stderr */
15913
15914#if 0
15915 /* Hack to get rdoc to regard ARGF as a class: */
15916 rb_cARGF = rb_define_class("ARGF", rb_cObject);
15917#endif
15918
15919 rb_cARGF = rb_class_new(rb_cObject);
15920 rb_set_class_path(rb_cARGF, rb_cObject, "ARGF.class");
15921 rb_define_alloc_func(rb_cARGF, argf_alloc);
15922
15924
15925 rb_define_method(rb_cARGF, "initialize", argf_initialize, -2);
15926 rb_define_method(rb_cARGF, "initialize_copy", argf_initialize_copy, 1);
15927 rb_define_method(rb_cARGF, "to_s", argf_to_s, 0);
15928 rb_define_alias(rb_cARGF, "inspect", "to_s");
15929 rb_define_method(rb_cARGF, "argv", argf_argv, 0);
15930
15931 rb_define_method(rb_cARGF, "fileno", argf_fileno, 0);
15932 rb_define_method(rb_cARGF, "to_i", argf_fileno, 0);
15933 rb_define_method(rb_cARGF, "to_io", argf_to_io, 0);
15934 rb_define_method(rb_cARGF, "to_write_io", argf_write_io, 0);
15935 rb_define_method(rb_cARGF, "each", argf_each_line, -1);
15936 rb_define_method(rb_cARGF, "each_line", argf_each_line, -1);
15937 rb_define_method(rb_cARGF, "each_byte", argf_each_byte, 0);
15938 rb_define_method(rb_cARGF, "each_char", argf_each_char, 0);
15939 rb_define_method(rb_cARGF, "each_codepoint", argf_each_codepoint, 0);
15940
15941 rb_define_method(rb_cARGF, "read", argf_read, -1);
15942 rb_define_method(rb_cARGF, "readpartial", argf_readpartial, -1);
15943 rb_define_method(rb_cARGF, "read_nonblock", argf_read_nonblock, -1);
15944 rb_define_method(rb_cARGF, "readlines", argf_readlines, -1);
15945 rb_define_method(rb_cARGF, "to_a", argf_readlines, -1);
15946 rb_define_method(rb_cARGF, "gets", argf_gets, -1);
15947 rb_define_method(rb_cARGF, "readline", argf_readline, -1);
15948 rb_define_method(rb_cARGF, "getc", argf_getc, 0);
15949 rb_define_method(rb_cARGF, "getbyte", argf_getbyte, 0);
15950 rb_define_method(rb_cARGF, "readchar", argf_readchar, 0);
15951 rb_define_method(rb_cARGF, "readbyte", argf_readbyte, 0);
15952 rb_define_method(rb_cARGF, "tell", argf_tell, 0);
15953 rb_define_method(rb_cARGF, "seek", argf_seek_m, -1);
15954 rb_define_method(rb_cARGF, "rewind", argf_rewind, 0);
15955 rb_define_method(rb_cARGF, "pos", argf_tell, 0);
15956 rb_define_method(rb_cARGF, "pos=", argf_set_pos, 1);
15957 rb_define_method(rb_cARGF, "eof", argf_eof, 0);
15958 rb_define_method(rb_cARGF, "eof?", argf_eof, 0);
15959 rb_define_method(rb_cARGF, "binmode", argf_binmode_m, 0);
15960 rb_define_method(rb_cARGF, "binmode?", argf_binmode_p, 0);
15961
15962 rb_define_method(rb_cARGF, "write", argf_write, -1);
15963 rb_define_method(rb_cARGF, "print", rb_io_print, -1);
15964 rb_define_method(rb_cARGF, "putc", rb_io_putc, 1);
15965 rb_define_method(rb_cARGF, "puts", rb_io_puts, -1);
15966 rb_define_method(rb_cARGF, "printf", rb_io_printf, -1);
15967
15968 rb_define_method(rb_cARGF, "filename", argf_filename, 0);
15969 rb_define_method(rb_cARGF, "path", argf_filename, 0);
15970 rb_define_method(rb_cARGF, "file", argf_file, 0);
15971 rb_define_method(rb_cARGF, "skip", argf_skip, 0);
15972 rb_define_method(rb_cARGF, "close", argf_close_m, 0);
15973 rb_define_method(rb_cARGF, "closed?", argf_closed, 0);
15974
15975 rb_define_method(rb_cARGF, "lineno", argf_lineno, 0);
15976 rb_define_method(rb_cARGF, "lineno=", argf_set_lineno, 1);
15977
15978 rb_define_method(rb_cARGF, "inplace_mode", argf_inplace_mode_get, 0);
15979 rb_define_method(rb_cARGF, "inplace_mode=", argf_inplace_mode_set, 1);
15980
15981 rb_define_method(rb_cARGF, "external_encoding", argf_external_encoding, 0);
15982 rb_define_method(rb_cARGF, "internal_encoding", argf_internal_encoding, 0);
15983 rb_define_method(rb_cARGF, "set_encoding", argf_set_encoding, -1);
15984
15985 argf = rb_class_new_instance(0, 0, rb_cARGF);
15986
15988 /*
15989 * ARGF is a stream designed for use in scripts that process files given
15990 * as command-line arguments or passed in via STDIN.
15991 *
15992 * See ARGF (the class) for more details.
15993 */
15995
15996 rb_define_hooked_variable("$.", &argf, argf_lineno_getter, argf_lineno_setter);
15997 rb_define_hooked_variable("$FILENAME", &argf, argf_filename_getter, rb_gvar_readonly_setter);
15998 ARGF.filename = rb_str_new2("-");
15999
16000 rb_define_hooked_variable("$-i", &argf, opt_i_get, opt_i_set);
16001 rb_gvar_ractor_local("$-i");
16002
16003 rb_define_hooked_variable("$*", &argf, argf_argv_getter, rb_gvar_readonly_setter);
16004
16005#if defined (_WIN32) || defined(__CYGWIN__)
16006 atexit(pipe_atexit);
16007#endif
16008
16009 Init_File();
16010
16011 rb_define_method(rb_cFile, "initialize", rb_file_initialize, -1);
16012
16013 sym_mode = ID2SYM(rb_intern_const("mode"));
16014 sym_perm = ID2SYM(rb_intern_const("perm"));
16015 sym_flags = ID2SYM(rb_intern_const("flags"));
16016 sym_extenc = ID2SYM(rb_intern_const("external_encoding"));
16017 sym_intenc = ID2SYM(rb_intern_const("internal_encoding"));
16018 sym_encoding = ID2SYM(rb_id_encoding());
16019 sym_open_args = ID2SYM(rb_intern_const("open_args"));
16020 sym_textmode = ID2SYM(rb_intern_const("textmode"));
16021 sym_binmode = ID2SYM(rb_intern_const("binmode"));
16022 sym_autoclose = ID2SYM(rb_intern_const("autoclose"));
16023 sym_normal = ID2SYM(rb_intern_const("normal"));
16024 sym_sequential = ID2SYM(rb_intern_const("sequential"));
16025 sym_random = ID2SYM(rb_intern_const("random"));
16026 sym_willneed = ID2SYM(rb_intern_const("willneed"));
16027 sym_dontneed = ID2SYM(rb_intern_const("dontneed"));
16028 sym_noreuse = ID2SYM(rb_intern_const("noreuse"));
16029 sym_SET = ID2SYM(rb_intern_const("SET"));
16030 sym_CUR = ID2SYM(rb_intern_const("CUR"));
16031 sym_END = ID2SYM(rb_intern_const("END"));
16032#ifdef SEEK_DATA
16033 sym_DATA = ID2SYM(rb_intern_const("DATA"));
16034#endif
16035#ifdef SEEK_HOLE
16036 sym_HOLE = ID2SYM(rb_intern_const("HOLE"));
16037#endif
16038 sym_wait_readable = ID2SYM(rb_intern_const("wait_readable"));
16039 sym_wait_writable = ID2SYM(rb_intern_const("wait_writable"));
16040}
16041
16042#include "io.rbinc"
#define RUBY_ASSERT(...)
Asserts that the given expression is truthy if and only if RUBY_DEBUG is truthy.
Definition assert.h:219
std::atomic< unsigned > rb_atomic_t
Type that is eligible for atomic operations.
Definition atomic.h:69
unsigned long ruby_strtoul(const char *str, char **endptr, int base)
Our own locale-insensitive version of strtoul(3).
Definition util.c:117
#define rb_define_method(klass, mid, func, arity)
Defines klass#mid.
#define rb_define_singleton_method(klass, mid, func, arity)
Defines klass.mid.
#define rb_define_global_function(mid, func, arity)
Defines rb_mKernel #mid.
void rb_include_module(VALUE klass, VALUE module)
Includes a module to a class.
Definition class.c:1701
VALUE rb_define_class(const char *name, VALUE super)
Defines a top-level class.
Definition class.c:1484
VALUE rb_class_new(VALUE super)
Creates a new, anonymous class.
Definition class.c:864
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
Definition class.c:1520
VALUE rb_define_module_under(VALUE outer, const char *name)
Defines a module under the namespace of outer.
Definition class.c:1630
void rb_define_alias(VALUE klass, const char *name1, const char *name2)
Defines an alias of a method.
Definition class.c:2853
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:3156
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:3143
int rb_block_given_p(void)
Determines if the current method is given a block.
Definition eval.c:1037
int rb_get_kwargs(VALUE keyword_hash, const ID *table, int required, int optional, VALUE *values)
Keyword argument deconstructor.
Definition class.c:2932
#define ECONV_AFTER_OUTPUT
Old name of RUBY_ECONV_AFTER_OUTPUT.
Definition transcode.h:555
#define rb_str_new2
Old name of rb_str_new_cstr.
Definition string.h:1674
#define TYPE(_)
Old name of rb_type.
Definition value_type.h:108
#define RB_INTEGER_TYPE_P
Old name of rb_integer_type_p.
Definition value_type.h:87
#define ENC_CODERANGE_7BIT
Old name of RUBY_ENC_CODERANGE_7BIT.
Definition coderange.h:180
#define T_FILE
Old name of RUBY_T_FILE.
Definition value_type.h:62
#define ENC_CODERANGE_VALID
Old name of RUBY_ENC_CODERANGE_VALID.
Definition coderange.h:181
#define ECONV_UNIVERSAL_NEWLINE_DECORATOR
Old name of RUBY_ECONV_UNIVERSAL_NEWLINE_DECORATOR.
Definition transcode.h:532
#define OBJ_INIT_COPY(obj, orig)
Old name of RB_OBJ_INIT_COPY.
Definition object.h:41
#define ALLOC
Old name of RB_ALLOC.
Definition memory.h:400
#define RFLOAT_VALUE
Old name of rb_float_value.
Definition double.h:28
#define T_STRING
Old name of RUBY_T_STRING.
Definition value_type.h:78
#define Qundef
Old name of RUBY_Qundef.
#define INT2FIX
Old name of RB_INT2FIX.
Definition long.h:48
#define rb_str_cat2
Old name of rb_str_cat_cstr.
Definition string.h:1682
#define T_NIL
Old name of RUBY_T_NIL.
Definition value_type.h:72
#define UNREACHABLE
Old name of RBIMPL_UNREACHABLE.
Definition assume.h:28
#define ID2SYM
Old name of RB_ID2SYM.
Definition symbol.h:44
#define T_BIGNUM
Old name of RUBY_T_BIGNUM.
Definition value_type.h:57
#define OBJ_FREEZE
Old name of RB_OBJ_FREEZE.
Definition fl_type.h:134
#define T_FIXNUM
Old name of RUBY_T_FIXNUM.
Definition value_type.h:63
#define UNREACHABLE_RETURN
Old name of RBIMPL_UNREACHABLE_RETURN.
Definition assume.h:29
#define FIX2UINT
Old name of RB_FIX2UINT.
Definition int.h:42
#define SSIZET2NUM
Old name of RB_SSIZE2NUM.
Definition size_t.h:64
#define ZALLOC
Old name of RB_ZALLOC.
Definition memory.h:402
#define CLASS_OF
Old name of rb_class_of.
Definition globals.h:206
#define rb_ary_new4
Old name of rb_ary_new_from_values.
Definition array.h:659
#define ENCODING_MAXNAMELEN
Old name of RUBY_ENCODING_MAXNAMELEN.
Definition encoding.h:111
#define MBCLEN_NEEDMORE_LEN(ret)
Old name of ONIGENC_MBCLEN_NEEDMORE_LEN.
Definition encoding.h:520
#define ENCODING_GET(obj)
Old name of RB_ENCODING_GET.
Definition encoding.h:109
#define LONG2FIX
Old name of RB_INT2FIX.
Definition long.h:49
#define NUM2UINT
Old name of RB_NUM2UINT.
Definition int.h:45
#define ALLOC_N
Old name of RB_ALLOC_N.
Definition memory.h:399
#define MBCLEN_CHARFOUND_LEN(ret)
Old name of ONIGENC_MBCLEN_CHARFOUND_LEN.
Definition encoding.h:517
#define LONG2NUM
Old name of RB_LONG2NUM.
Definition long.h:50
#define rb_exc_new3
Old name of rb_exc_new_str.
Definition error.h:38
#define STRNCASECMP
Old name of st_locale_insensitive_strncasecmp.
Definition ctype.h:103
#define MBCLEN_INVALID_P(ret)
Old name of ONIGENC_MBCLEN_INVALID_P.
Definition encoding.h:518
#define ISASCII
Old name of rb_isascii.
Definition ctype.h:85
#define ECONV_STATEFUL_DECORATOR_MASK
Old name of RUBY_ECONV_STATEFUL_DECORATOR_MASK.
Definition transcode.h:538
#define Qtrue
Old name of RUBY_Qtrue.
#define MBCLEN_NEEDMORE_P(ret)
Old name of ONIGENC_MBCLEN_NEEDMORE_P.
Definition encoding.h:519
#define ECONV_PARTIAL_INPUT
Old name of RUBY_ECONV_PARTIAL_INPUT.
Definition transcode.h:554
#define NUM2INT
Old name of RB_NUM2INT.
Definition int.h:44
#define ECONV_ERROR_HANDLER_MASK
Old name of RUBY_ECONV_ERROR_HANDLER_MASK.
Definition transcode.h:522
#define INT2NUM
Old name of RB_INT2NUM.
Definition int.h:43
#define Qnil
Old name of RUBY_Qnil.
#define Qfalse
Old name of RUBY_Qfalse.
#define FIX2LONG
Old name of RB_FIX2LONG.
Definition long.h:46
#define ENC_CODERANGE_BROKEN
Old name of RUBY_ENC_CODERANGE_BROKEN.
Definition coderange.h:182
#define T_ARRAY
Old name of RUBY_T_ARRAY.
Definition value_type.h:56
#define NIL_P
Old name of RB_NIL_P.
#define ALLOCV_N
Old name of RB_ALLOCV_N.
Definition memory.h:405
#define MBCLEN_CHARFOUND_P(ret)
Old name of ONIGENC_MBCLEN_CHARFOUND_P.
Definition encoding.h:516
#define NUM2CHR
Old name of RB_NUM2CHR.
Definition char.h:33
#define NUM2LONG
Old name of RB_NUM2LONG.
Definition long.h:51
#define UINT2NUM
Old name of RB_UINT2NUM.
Definition int.h:46
#define FIXNUM_P
Old name of RB_FIXNUM_P.
#define ECONV_NEWLINE_DECORATOR_MASK
Old name of RUBY_ECONV_NEWLINE_DECORATOR_MASK.
Definition transcode.h:529
#define CONST_ID
Old name of RUBY_CONST_ID.
Definition symbol.h:47
#define rb_ary_new2
Old name of rb_ary_new_capa.
Definition array.h:657
#define NUM2SIZET
Old name of RB_NUM2SIZE.
Definition size_t.h:61
#define ENC_CODERANGE_SET(obj, cr)
Old name of RB_ENC_CODERANGE_SET.
Definition coderange.h:186
#define rb_str_new4
Old name of rb_str_new_frozen.
Definition string.h:1676
#define ALLOCV_END
Old name of RB_ALLOCV_END.
Definition memory.h:406
#define SYMBOL_P
Old name of RB_SYMBOL_P.
Definition value_type.h:88
#define ECONV_DEFAULT_NEWLINE_DECORATOR
Old name of RUBY_ECONV_DEFAULT_NEWLINE_DECORATOR.
Definition transcode.h:540
void rb_notimplement(void)
Definition error.c:3839
void rb_category_warn(rb_warning_category_t category, const char *fmt,...)
Identical to rb_category_warning(), except it reports unless $VERBOSE is nil.
Definition error.c:476
void rb_category_warning(rb_warning_category_t category, const char *fmt,...)
Identical to rb_warning(), except it takes additional "category" parameter.
Definition error.c:508
VALUE rb_eNotImpError
NotImplementedError exception.
Definition error.c:1440
void rb_exc_raise(VALUE mesg)
Raises an exception in the current thread.
Definition eval.c:683
void rb_syserr_fail(int e, const char *mesg)
Raises appropriate exception that represents a C errno.
Definition error.c:3908
void rb_readwrite_syserr_fail(enum rb_io_wait_readwrite waiting, int n, const char *mesg)
Identical to rb_readwrite_sys_fail(), except it does not depend on C global variable errno.
Definition io.c:14721
VALUE rb_eIOError
IOError exception.
Definition io.c:189
VALUE rb_eStandardError
StandardError exception.
Definition error.c:1427
void rb_mod_syserr_fail_str(VALUE mod, int e, VALUE mesg)
Identical to rb_mod_syserr_fail(), except it takes the message in Ruby's String instead of C's.
Definition error.c:3998
void rb_syserr_fail_str(int e, VALUE mesg)
Identical to rb_syserr_fail(), except it takes the message in Ruby's String instead of C's.
Definition error.c:3914
#define ruby_verbose
This variable controls whether the interpreter is in debug mode.
Definition error.h:475
VALUE rb_eTypeError
TypeError exception.
Definition error.c:1430
VALUE rb_eEOFError
EOFError exception.
Definition io.c:188
void rb_readwrite_sys_fail(enum rb_io_wait_readwrite waiting, const char *mesg)
Raises appropriate exception using the parameters.
Definition io.c:14715
void rb_iter_break_value(VALUE val)
Identical to rb_iter_break(), except it additionally takes the "value" of this breakage.
Definition vm.c:2215
rb_io_wait_readwrite
for rb_readwrite_sys_fail first argument
Definition error.h:73
VALUE rb_eRuntimeError
RuntimeError exception.
Definition error.c:1428
void rb_warn(const char *fmt,...)
Identical to rb_warning(), except it reports unless $VERBOSE is nil.
Definition error.c:466
VALUE rb_eSystemCallError
SystemCallError exception.
Definition error.c:1450
@ RB_WARN_CATEGORY_DEPRECATED
Warning is for deprecated features.
Definition error.h:48
VALUE rb_mKernel
Kernel module.
Definition object.c:60
VALUE rb_check_to_int(VALUE val)
Identical to rb_check_to_integer(), except it uses #to_int for conversion.
Definition object.c:3268
VALUE rb_any_to_s(VALUE obj)
Generates a textual representation of the given object.
Definition object.c:676
VALUE rb_obj_alloc(VALUE klass)
Allocates an instance of the given class.
Definition object.c:2164
VALUE rb_class_new_instance(int argc, const VALUE *argv, VALUE klass)
Allocates, then initialises an instance of the given class.
Definition object.c:2205
VALUE rb_cIO
IO class.
Definition io.c:187
VALUE rb_class_new_instance_kw(int argc, const VALUE *argv, VALUE klass, int kw_splat)
Identical to rb_class_new_instance(), except you can specify how to handle the last element of the gi...
Definition object.c:2193
VALUE rb_mEnumerable
Enumerable module.
Definition enum.c:27
VALUE rb_stdin
STDIN constant.
Definition io.c:201
VALUE rb_stderr
STDERR constant.
Definition io.c:201
VALUE rb_obj_class(VALUE obj)
Queries the class of an object.
Definition object.c:265
VALUE rb_obj_dup(VALUE obj)
Duplicates the given object.
Definition object.c:583
VALUE rb_inspect(VALUE obj)
Generates a human-readable textual representation of the given object.
Definition object.c:687
VALUE rb_mWaitReadable
IO::WaitReadable module.
Definition io.c:191
VALUE rb_mWaitWritable
IO::WaitReadable module.
Definition io.c:192
VALUE rb_obj_freeze(VALUE obj)
Just calls rb_obj_freeze_inline() inside.
Definition object.c:1329
VALUE rb_check_to_integer(VALUE val, const char *mid)
Identical to rb_check_convert_type(), except the return value type is fixed to rb_cInteger.
Definition object.c:3249
VALUE rb_cFile
File class.
Definition file.c:191
VALUE rb_stdout
STDOUT constant.
Definition io.c:201
VALUE rb_to_int(VALUE val)
Identical to rb_check_to_int(), except it raises in case of conversion mismatch.
Definition object.c:3262
static unsigned int rb_enc_codepoint(const char *p, const char *e, rb_encoding *enc)
Queries the code point of character pointed by the passed pointer.
Definition encoding.h:571
VALUE rb_str_conv_enc(VALUE str, rb_encoding *from, rb_encoding *to)
Encoding conversion main routine.
Definition string.c:1327
int rb_enc_str_coderange(VALUE str)
Scans the passed string to collect its code range.
Definition string.c:932
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:816
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:2626
VALUE rb_econv_open_exc(const char *senc, const char *denc, int ecflags)
Creates a rb_eConverterNotFoundError exception object (but does not raise).
Definition transcode.c:2123
rb_econv_result_t rb_econv_convert(rb_econv_t *ec, const unsigned char **source_buffer_ptr, const unsigned char *source_buffer_end, unsigned char **destination_buffer_ptr, unsigned char *destination_buffer_end, int flags)
Converts a string from an encoding to another.
Definition transcode.c:1485
rb_econv_result_t
return value of rb_econv_convert()
Definition transcode.h:30
@ econv_incomplete_input
The conversion stopped in middle of reading a character, possibly due to a partial read of a socket e...
Definition transcode.h:69
@ econv_finished
The conversion stopped after converting everything.
Definition transcode.h:57
@ econv_undefined_conversion
The conversion stopped when it found a character in the input which cannot be representable in the ou...
Definition transcode.h:41
@ econv_source_buffer_empty
The conversion stopped because there is no input.
Definition transcode.h:51
@ econv_destination_buffer_full
The conversion stopped because there is no destination.
Definition transcode.h:46
@ econv_invalid_byte_sequence
The conversion stopped when it found an invalid sequence.
Definition transcode.h:35
int rb_econv_putbackable(rb_econv_t *ec)
Queries if rb_econv_putback() makes sense, i.e.
Definition transcode.c:1780
const char * rb_econv_asciicompat_encoding(const char *encname)
Queries the passed encoding's corresponding ASCII compatible encoding.
Definition transcode.c:1824
VALUE rb_econv_str_convert(rb_econv_t *ec, VALUE src, int flags)
Identical to rb_econv_convert(), except it takes Ruby's string instead of C's pointer.
Definition transcode.c:1959
rb_econv_t * rb_econv_open_opts(const char *source_encoding, const char *destination_encoding, int ecflags, VALUE ecopts)
Identical to rb_econv_open(), except it additionally takes a hash of optional strings.
Definition transcode.c:2677
void rb_econv_binmode(rb_econv_t *ec)
This badly named function does not set the destination encoding to binary, but instead just nullifies...
Definition transcode.c:2022
VALUE rb_str_encode(VALUE str, VALUE to, int ecflags, VALUE ecopts)
Converts the contents of the passed string from its encoding to the passed one.
Definition transcode.c:2940
VALUE rb_econv_make_exception(rb_econv_t *ec)
This function makes sense right after rb_econv_convert() returns.
Definition transcode.c:4306
void rb_econv_check_error(rb_econv_t *ec)
This is a rb_econv_make_exception() + rb_exc_raise() combo.
Definition transcode.c:4312
void rb_econv_close(rb_econv_t *ec)
Destructs a converter.
Definition transcode.c:1741
void rb_econv_putback(rb_econv_t *ec, unsigned char *p, int n)
Puts back the bytes.
Definition transcode.c:1791
VALUE rb_funcall(VALUE recv, ID mid, int n,...)
Calls a method.
Definition vm_eval.c:1117
VALUE rb_funcallv_kw(VALUE recv, ID mid, int argc, const VALUE *argv, int kw_splat)
Identical to rb_funcallv(), except you can specify how to handle the last element of the given array.
Definition vm_eval.c:1084
Defines RBIMPL_HAS_BUILTIN.
VALUE rb_ary_concat(VALUE lhs, VALUE rhs)
Destructively appends the contents of latter into the end of former.
VALUE rb_ary_shift(VALUE ary)
Destructively deletes an element from the beginning of the passed array and returns what was deleted.
VALUE rb_check_array_type(VALUE obj)
Try converting an object to its array representation using its to_ary method, if any.
VALUE rb_ary_new(void)
Allocates a new, empty array.
VALUE rb_ary_push(VALUE ary, VALUE elem)
Special case of rb_ary_cat() that it adds only one element.
VALUE rb_ary_entry(VALUE ary, long off)
Queries an element of an array.
VALUE rb_assoc_new(VALUE car, VALUE cdr)
Identical to rb_ary_new_from_values(), except it expects exactly two parameters.
#define RETURN_ENUMERATOR(obj, argc, argv)
Identical to RETURN_SIZED_ENUMERATOR(), except its size is unknown.
Definition enumerator.h:239
static int rb_check_arity(int argc, int min, int max)
Ensures that the passed integer is in the passed range.
Definition error.h:284
VALUE rb_io_printf(int argc, const VALUE *argv, VALUE io)
This is a rb_f_sprintf() + rb_io_write() combo.
Definition io.c:8615
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:8760
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:9189
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:9370
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:9169
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:6379
VALUE rb_io_binmode(VALUE io)
Sets the binmode.
Definition io.c:6333
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:7381
VALUE rb_gets(void)
Much like rb_io_gets(), but it reads from the mysterious ARGF object.
Definition io.c:10448
int rb_cloexec_fcntl_dupfd(int fd, int minfd)
Duplicates a file descriptor with closing on exec.
Definition io.c:461
VALUE rb_output_fs
The field separator character for outputs, or the $,.
Definition io.c:204
VALUE rb_file_open_str(VALUE fname, const char *fmode)
Identical to rb_file_open(), except it takes the pathname as a Ruby's string instead of C's.
Definition io.c:7264
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:7271
VALUE rb_io_close(VALUE io)
Closes the IO.
Definition io.c:5753
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:1977
VALUE rb_lastline_get(void)
Queries the last line, or the $_.
Definition vm.c:1971
int rb_obj_method_arity(VALUE obj, ID mid)
Identical to rb_mod_method_arity(), except it searches for singleton methods rather than instance met...
Definition proc.c:2987
rb_pid_t rb_waitpid(rb_pid_t pid, int *status, int flags)
Waits for a process, with releasing GVL.
Definition process.c:1168
void rb_last_status_set(int status, rb_pid_t pid)
Sets the "last status", or the $?.
Definition process.c:682
VALUE rb_str_append(VALUE dst, VALUE src)
Identical to rb_str_buf_append(), except it converts the right hand side before concatenating.
Definition string.c:3772
#define rb_str_new(str, len)
Allocates an instance of rb_cString.
Definition string.h:1497
#define rb_str_buf_cat
Just another name of rb_str_cat.
Definition string.h:1680
#define rb_usascii_str_new(str, len)
Identical to rb_str_new, except it generates a string of "US ASCII" encoding.
Definition string.h:1531
size_t rb_str_capacity(VALUE str)
Queries the capacity of the given string.
Definition string.c:986
VALUE rb_str_new_frozen(VALUE str)
Creates a frozen copy of the string, if necessary.
Definition string.c:1503
VALUE rb_str_dup(VALUE str)
Duplicates a string.
Definition string.c:1971
VALUE rb_str_cat(VALUE dst, const char *src, long srclen)
Destructively appends the passed contents to the string.
Definition string.c:3540
VALUE rb_str_locktmp(VALUE str)
Obtains a "temporary lock" of the string.
rb_gvar_setter_t rb_str_setter
This is a rb_gvar_setter_t that refutes non-string assignments.
Definition string.h:1145
VALUE rb_str_equal(VALUE str1, VALUE str2)
Equality of two strings.
Definition string.c:4242
void rb_str_set_len(VALUE str, long len)
Overwrites the length of the string.
Definition string.c:3362
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:3714
VALUE rb_check_string_type(VALUE obj)
Try converting an object to its stringised representation using its to_str method,...
Definition string.c:2925
VALUE rb_str_substr(VALUE str, long beg, long len)
This is the implementation of two-argumented String#slice.
Definition string.c:3225
VALUE rb_str_unlocktmp(VALUE str)
Releases a lock formerly obtained by rb_str_locktmp().
Definition string.c:3344
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:2719
VALUE rb_str_buf_new(long capa)
Allocates a "string buffer".
Definition string.c:1693
#define rb_str_new_cstr(str)
Identical to rb_str_new, except it assumes the passed pointer is a pointer to a C string.
Definition string.h:1513
VALUE rb_obj_as_string(VALUE obj)
Try converting an object to its stringised representation using its to_s method, if any.
Definition string.c:1825
int rb_thread_interrupted(VALUE thval)
Checks if the thread's execution was recently interrupted.
Definition thread.c:1469
VALUE rb_mutex_new(void)
Creates a mutex.
int rb_thread_fd_writable(int fd)
Identical to rb_thread_wait_fd(), except it blocks the current thread until the given file descriptor...
Definition io.c:1604
VALUE rb_exec_recursive(VALUE(*f)(VALUE g, VALUE h, int r), VALUE g, VALUE h)
"Recursion" API entry point.
VALUE rb_mutex_synchronize(VALUE mutex, VALUE(*func)(VALUE arg), VALUE arg)
Obtains the lock, runs the passed function, and releases the lock when it completes.
void rb_thread_check_ints(void)
Checks for interrupts.
Definition thread.c:1452
VALUE rb_thread_current(void)
Obtains the "current" thread.
Definition thread.c:3159
int rb_thread_wait_fd(int fd)
Blocks the current thread until the given file descriptor is ready to be read.
Definition io.c:1598
void rb_thread_sleep(int sec)
Blocks for the given period of time.
Definition thread.c:1475
struct timeval rb_time_interval(VALUE num)
Creates a "time interval".
Definition time.c:2948
void rb_set_class_path(VALUE klass, VALUE space, const char *name)
Names a class.
Definition variable.c:439
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:1985
VALUE rb_class_name(VALUE obj)
Queries the name of the given object's class.
Definition variable.c:498
int rb_respond_to(VALUE obj, ID mid)
Queries if the object responds to the method.
Definition vm_method.c:3359
VALUE rb_check_funcall(VALUE recv, ID mid, int argc, const VALUE *argv)
Identical to rb_funcallv(), except it returns RUBY_Qundef instead of raising rb_eNoMethodError.
Definition vm_eval.c:686
void rb_define_alloc_func(VALUE klass, rb_alloc_func_t func)
Sets the allocator function of a class.
static ID rb_intern_const(const char *str)
This is a "tiny optimisation" over rb_intern().
Definition symbol.h:284
#define RB_ID2SYM
Just another name of rb_id2sym.
Definition symbol.h:42
void rb_define_global_const(const char *name, VALUE val)
Identical to rb_define_const(), except it defines that of "global", i.e.
Definition variable.c:3987
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:844
rb_gvar_setter_t rb_gvar_readonly_setter
This function just raises rb_eNameError.
Definition variable.h:135
#define FMODE_READABLE
The IO is opened for reading.
Definition io.h:162
enum rb_io_mode rb_io_modestr_fmode(const char *modestr)
Maps a file mode string (that rb_file_open() takes) into a mixture of FMODE_ flags.
Definition io.c:6465
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:6598
#define FMODE_SETENC_BY_BOM
This flag amends the encoding of the IO so that the BOM of the contents of the IO takes effect.
Definition io.h:260
rb_io_event
Type of events that an IO can wait.
Definition io.h:96
@ RUBY_IO_READABLE
IO::READABLE
Definition io.h:97
@ RUBY_IO_PRIORITY
IO::PRIORITY
Definition io.h:99
@ RUBY_IO_WRITABLE
IO::WRITABLE
Definition io.h:98
#define FMODE_READWRITE
The IO is opened for both read/write.
Definition io.h:168
#define FMODE_EXTERNAL
This flag means that an IO object is wrapping an "external" file descriptor, which is owned by someth...
Definition io.h:252
#define GetOpenFile
This is an old name of RB_IO_POINTER.
Definition io.h:442
void rb_io_check_byte_readable(rb_io_t *fptr)
Asserts that an IO is opened for byte-based reading.
Definition io.c:1015
#define FMODE_TTY
The IO is a TTY.
Definition io.h:192
#define FMODE_CREATE
The IO is opened for creating.
Definition io.h:215
void rb_io_check_readable(rb_io_t *fptr)
Just another name of rb_io_check_byte_readable.
Definition io.c:1024
int rb_wait_for_single_fd(int fd, int events, struct timeval *tv)
Blocks until the passed file descriptor is ready for the passed events.
Definition io.c:1592
FILE * rb_fdopen(int fd, const char *modestr)
Identical to rb_io_stdio_file(), except it takes file descriptors instead of Ruby's IO.
Definition io.c:7081
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:6747
int rb_io_descriptor(VALUE io)
Returns an integer representing the numeric file descriptor for io.
Definition io.c:2899
#define FMODE_WRITABLE
The IO is opened for writing.
Definition io.h:165
FILE * rb_io_stdio_file(rb_io_t *fptr)
Finds or creates a stdio's file structure from a Ruby's one.
Definition io.c:9416
#define FMODE_APPEND
The IO is opened for appending.
Definition io.h:207
#define MakeOpenFile
This is an old name of RB_IO_OPEN.
Definition io.h:465
#define FMODE_DUPLEX
Ruby eventually detects that the IO is bidirectional.
Definition io.h:200
#define FMODE_BINMODE
The IO is in "binary mode".
Definition io.h:179
int rb_io_maybe_wait_readable(int error, VALUE io, VALUE timeout)
Blocks until the passed IO is ready for reading, if that makes sense for the passed errno.
Definition io.c:1651
int capa
Designed capacity of the buffer.
Definition io.h:11
#define RB_IO_POINTER(obj, fp)
Queries the underlying IO pointer.
Definition io.h:436
VALUE rb_io_maybe_wait(int error, VALUE io, VALUE events, VALUE timeout)
Identical to rb_io_wait() except it additionally takes previous errno.
Definition io.c:1610
VALUE rb_eIOTimeoutError
Indicates that a timeout has occurred while performing an IO operation.
Definition io.c:190
char * ptr
Pointer to the underlying memory region, of at least capa bytes.
Definition io.h:2
#define FMODE_SYNC
The IO is in "sync mode".
Definition io.h:186
int off
Offset inside of ptr.
Definition io.h:5
VALUE rb_io_path(VALUE io)
Returns the path for the given IO.
Definition io.c:2973
void rb_io_extract_modeenc(VALUE *vmode_p, VALUE *vperm_p, VALUE opthash, int *oflags_p, enum rb_io_mode *fmode_p, rb_io_enc_t *convconfig_p)
This function can be seen as an extended version of rb_io_extract_encoding_option() that not only con...
Definition io.c:6872
void rb_io_check_initialized(rb_io_t *fptr)
Asserts that the passed IO is initialised.
Definition io.c:788
#define FMODE_EXCL
This flag amends the effect of FMODE_CREATE, so that if there already is a file at the given path the...
Definition io.h:223
#define FMODE_TEXTMODE
The IO is in "text mode".
Definition io.h:243
int rb_io_fptr_finalize(rb_io_t *fptr)
Destroys the given IO.
Definition io.c:5675
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:5861
VALUE rb_io_set_timeout(VALUE io, VALUE timeout)
Set the timeout associated with the specified io object.
Definition io.c:886
ssize_t rb_io_bufwrite(VALUE io, const void *buf, size_t size)
Buffered write to the passed IO.
Definition io.c:2016
void rb_io_check_char_readable(rb_io_t *fptr)
Asserts that an IO is opened for character-based reading.
Definition io.c:996
#define FMODE_TRUNC
This flag amends the effect of FMODE_CREATE, so that if there already is a file at the given path it ...
Definition io.h:229
VALUE rb_io_get_write_io(VALUE io)
Queries the tied IO for writing.
Definition io.c:823
void rb_io_set_nonblock(rb_io_t *fptr)
Instructs the OS to put its internal file structure into "nonblocking mode".
Definition io.c:3425
int rb_io_wait_writable(int fd)
Blocks until the passed file descriptor gets writable.
Definition io.c:1549
VALUE rb_io_open_descriptor(VALUE klass, int descriptor, int mode, VALUE path, VALUE timeout, struct rb_io_encoding *encoding)
Allocate a new IO object, with the given file descriptor.
Definition io.c:9282
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:7368
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:1037
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:1097
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:1085
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:1073
void * rb_thread_call_with_gvl(void *(*func)(void *), void *data1)
(Re-)acquires the GVL.
Definition thread.c:2046
#define RB_NUM2INT
Just another name of rb_num2int_inline.
Definition int.h:38
#define RB_INT2NUM
Just another name of rb_int2num_inline.
Definition int.h:37
VALUE rb_f_sprintf(int argc, const VALUE *argv)
Identical to rb_str_format(), except how the arguments are arranged.
Definition sprintf.c:209
#define RB_BLOCK_CALL_FUNC_ARGLIST(yielded_arg, callback_arg)
Shim for block function parameters.
Definition iterator.h:58
VALUE rb_yield_values2(int n, const VALUE *argv)
Identical to rb_yield_values(), except it takes the parameters as a C array instead of variadic argum...
Definition vm_eval.c:1406
VALUE rb_yield(VALUE val)
Yields the block.
Definition vm_eval.c:1372
void rb_fd_term(rb_fdset_t *f)
Destroys the rb_fdset_t, releasing any memory and resources it used.
#define MEMZERO(p, type, n)
Handy macro to erase a region of memory.
Definition memory.h:360
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
Definition memory.h:167
#define MEMMOVE(p1, p2, type, n)
Handy macro to call memmove.
Definition memory.h:384
#define NUM2MODET
Converts a C's mode_t into an instance of rb_cInteger.
Definition mode_t.h:28
void rb_define_hooked_variable(const char *q, VALUE *w, type *e, void_type *r)
Define a function-backended global variable.
void rb_define_virtual_variable(const char *q, type *w, void_type *e)
Define a function-backended global variable.
VALUE rb_rescue2(type *q, VALUE w, type *e, VALUE r,...)
An equivalent of rescue clause.
VALUE rb_ensure(type *q, VALUE w, type *e, VALUE r)
An equivalent of ensure clause.
#define PRI_OFFT_PREFIX
A rb_sprintf() format prefix to be used for an off_t parameter.
Definition off_t.h:55
#define OFFT2NUM
Converts a C's off_t into an instance of rb_cInteger.
Definition off_t.h:33
#define NUM2OFFT
Converts an instance of rb_cNumeric into C's off_t.
Definition off_t.h:44
#define PIDT2NUM
Converts a C's pid_t into an instance of rb_cInteger.
Definition pid_t.h:28
#define rb_fd_isset
Queries if the given fd is in the rb_fdset_t.
Definition posix.h:60
#define rb_fd_select
Waits for multiple file descriptors at once.
Definition posix.h:66
#define rb_fd_init
Initialises the :given :rb_fdset_t.
Definition posix.h:63
#define rb_fd_set
Sets the given fd to the rb_fdset_t.
Definition posix.h:54
#define RARRAY_LEN
Just another name of rb_array_len.
Definition rarray.h:51
static int RARRAY_LENINT(VALUE ary)
Identical to rb_array_len(), except it differs for the return type.
Definition rarray.h:281
#define RARRAY_AREF(a, i)
Definition rarray.h:403
#define RARRAY_CONST_PTR
Just another name of rb_array_const_ptr.
Definition rarray.h:52
#define RFILE(obj)
Convenient casting macro.
Definition rfile.h:50
#define StringValue(v)
Ensures that the parameter object is a String.
Definition rstring.h:66
static char * RSTRING_END(VALUE str)
Queries the end of the contents pointer of the string.
Definition rstring.h:442
#define RSTRING_GETMEM(str, ptrvar, lenvar)
Convenient macro to obtain the contents and length at once.
Definition rstring.h:488
#define StringValueCStr(v)
Identical to StringValuePtr, except it additionally checks for the contents for viability as a C stri...
Definition rstring.h:89
#define RUBY_TYPED_DEFAULT_FREE
This is a value you can set to rb_data_type_struct::dfree.
Definition rtypeddata.h:80
#define TypedData_Make_Struct(klass, type, data_type, sval)
Identical to TypedData_Wrap_Struct, except it allocates a new data region internally instead of takin...
Definition rtypeddata.h:503
VALUE rb_get_argv(void)
Queries the arguments passed to the current process that you can access from Ruby as ARGV.
Definition io.c:14681
void rb_p(VALUE obj)
Inspects an object.
Definition io.c:9068
#define FilePathValue(v)
Ensures that the parameter object is a path.
Definition ruby.h:90
#define errno
Ractor-aware version of errno.
Definition ruby.h:388
#define RB_SCAN_ARGS_LAST_HASH_KEYWORDS
Treat a final argument as keywords if it is a hash, and not as keywords otherwise.
Definition scan_args.h:59
#define RB_PASS_CALLED_KEYWORDS
Pass keywords if current method is called with keywords, useful for argument delegation.
Definition scan_args.h:78
Scheduler APIs.
VALUE rb_fiber_scheduler_current(void)
Identical to rb_fiber_scheduler_get(), except it also returns RUBY_Qnil in case of a blocking fiber.
Definition scheduler.c:464
VALUE rb_fiber_scheduler_io_pread_memory(VALUE scheduler, VALUE io, rb_off_t from, void *base, size_t size, size_t length)
Non-blocking pread from the passed IO using a native buffer.
Definition scheduler.c:972
VALUE rb_fiber_scheduler_make_timeout(struct timeval *timeout)
Converts the passed timeout to an expression that rb_fiber_scheduler_block() etc.
Definition scheduler.c:507
VALUE rb_fiber_scheduler_io_wait_readable(VALUE scheduler, VALUE io)
Non-blocking wait until the passed IO is ready for reading.
Definition scheduler.c:724
VALUE rb_fiber_scheduler_io_read_memory(VALUE scheduler, VALUE io, void *base, size_t size, size_t length)
Non-blocking read from the passed IO using a native buffer.
Definition scheduler.c:948
VALUE rb_fiber_scheduler_io_wait(VALUE scheduler, VALUE io, VALUE events, VALUE timeout)
Non-blocking version of rb_io_wait().
Definition scheduler.c:710
static ssize_t rb_fiber_scheduler_io_result_apply(VALUE result)
Apply an io result to the local thread, returning the value of the original system call that created ...
Definition scheduler.h:71
VALUE rb_fiber_scheduler_io_selectv(VALUE scheduler, int argc, VALUE *argv)
Non-blocking version of IO.select, argv variant.
Definition scheduler.c:754
VALUE rb_fiber_scheduler_io_pwrite_memory(VALUE scheduler, VALUE io, rb_off_t from, const void *base, size_t size, size_t length)
Non-blocking pwrite to the passed IO using a native buffer.
Definition scheduler.c:984
VALUE rb_fiber_scheduler_current_for_thread(VALUE thread)
Identical to rb_fiber_scheduler_current(), except it queries for that of the passed thread instead of...
Definition scheduler.c:469
VALUE rb_fiber_scheduler_io_write_memory(VALUE scheduler, VALUE io, const void *base, size_t size, size_t length)
Non-blocking write to the passed IO using a native buffer.
Definition scheduler.c:960
VALUE rb_fiber_scheduler_io_wait_writable(VALUE scheduler, VALUE io)
Non-blocking wait until the passed IO is ready for writing.
Definition scheduler.c:730
int rb_thread_fd_select(int nfds, rb_fdset_t *rfds, rb_fdset_t *wfds, rb_fdset_t *efds, struct timeval *timeout)
Waits for multiple file descriptors at once.
Definition thread.c:4512
static bool RB_TEST(VALUE obj)
Emulates Ruby's "if" statement.
@ RUBY_Qfalse
#define RTEST
This is an old name of RB_TEST.
#define _(args)
This was a transition path from K&R to ANSI.
Definition stdarg.h:35
C99 shim for <stdbool.h>
Ruby's File and IO.
Definition rfile.h:35
Definition io.c:236
Definition win32.h:239
This is the struct that holds necessary info for a struct.
Definition rtypeddata.h:202
The data structure which wraps the fd_set bitmap used by select(2).
Definition largesize.h:71
Decomposed encoding flags (e.g.
Definition io.h:134
int ecflags
Flags.
Definition io.h:144
VALUE ecopts
Flags as Ruby hash.
Definition io.h:152
rb_encoding * enc2
External encoding.
Definition io.h:138
rb_encoding * enc
Internal encoding.
Definition io.h:136
IO buffers.
Definition io.h:109
char * ptr
Pointer to the underlying memory region, of at least capa bytes.
Definition io.h:112
int off
Offset inside of ptr.
Definition io.h:115
int len
Length of the buffer.
Definition io.h:118
int capa
Designed capacity of the buffer.
Definition io.h:121
Ruby's IO, metadata and buffers.
Definition io.h:295
rb_io_buffer_t wbuf
Write buffer.
Definition io.h:330
enum rb_io_mode mode
mode flags: FMODE_XXXs
Definition io.h:310
void(* finalize)(struct rb_io *, int)
finalize proc
Definition io.h:326
rb_econv_t * readconv
Encoding converter used when reading from this IO.
Definition io.h:352
rb_econv_t * writeconv
Encoding converter used when writing to this IO.
Definition io.h:363
struct rb_io_encoding encs
Decomposed encoding flags.
Definition io.h:348
VALUE self
The IO's Ruby level counterpart.
Definition io.h:298
VALUE write_lock
This is a Ruby level mutex.
Definition io.h:400
VALUE timeout
The timeout associated with this IO when performing blocking operations.
Definition io.h:406
FILE * stdio_file
stdio ptr for read/write, if available.
Definition io.h:302
VALUE writeconv_pre_ecopts
Value of ::rb_io_t::rb_io_enc_t::ecopts stored right before initialising rb_io_t::writeconv.
Definition io.h:390
VALUE tied_io_for_writing
Duplex IO object, if set.
Definition io.h:345
int writeconv_initialized
Whether rb_io_t::writeconv is already set up.
Definition io.h:376
int fd
file descriptor.
Definition io.h:306
rb_io_buffer_t rbuf
(Byte) read buffer.
Definition io.h:337
int lineno
number of lines read
Definition io.h:318
struct ccan_list_head blocking_operations
Threads that are performing a blocking operation without the GVL using this IO.
Definition io.h:131
VALUE writeconv_asciicompat
This is, when set, an instance of rb_cString which holds the "common" encoding.
Definition io.h:372
rb_io_buffer_t cbuf
rb_io_ungetc() destination.
Definition io.h:359
rb_pid_t pid
child's pid (for pipes)
Definition io.h:314
int writeconv_pre_ecflags
Value of ::rb_io_t::rb_io_enc_t::ecflags stored right before initialising rb_io_t::writeconv.
Definition io.h:383
VALUE pathv
pathname for file
Definition io.h:322
intptr_t SIGNED_VALUE
A signed integer type that has the same width with VALUE.
Definition value.h:63
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
Definition value.h:52
uintptr_t VALUE
Type that represents a Ruby object.
Definition value.h:40
static bool RB_FLOAT_TYPE_P(VALUE obj)
Queries if the object is an instance of rb_cFloat.
Definition value_type.h:264
static bool RB_SYMBOL_P(VALUE obj)
Queries if the object is an instance of rb_cSymbol.
Definition value_type.h:307
static void Check_Type(VALUE v, enum ruby_value_type t)
Identical to RB_TYPE_P(), except it raises exceptions on predication failure.
Definition value_type.h:433
static bool RB_TYPE_P(VALUE obj, enum ruby_value_type t)
Queries if the given object is of given type.
Definition value_type.h:376