Ruby 3.5.0dev (2025-08-16 revision 11c8bad64b31c125b903547bb3eed0ede8f0f8e2)
io.c (11c8bad64b31c125b903547bb3eed0ede8f0f8e2)
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 * and the block's value is assigned to global variable <tt>$?</tt> and returned.
7839 *
7840 * Optional argument +mode+ may be any valid \IO mode.
7841 * See {Access Modes}[rdoc-ref:File@Access+Modes].
7842 *
7843 * Required argument +cmd+ determines which of the following occurs:
7844 *
7845 * - The process forks.
7846 * - A specified program runs in a shell.
7847 * - A specified program runs with specified arguments.
7848 * - A specified program runs with specified arguments and a specified +argv0+.
7849 *
7850 * Each of these is detailed below.
7851 *
7852 * The optional hash argument +env+ specifies name/value pairs that are to be added
7853 * to the environment variables for the subprocess:
7854 *
7855 * IO.popen({'FOO' => 'bar'}, 'ruby', 'r+') do |pipe|
7856 * pipe.puts 'puts ENV["FOO"]'
7857 * pipe.close_write
7858 * pipe.gets
7859 * end => "bar\n"
7860 *
7861 * Optional keyword arguments +opts+ specify:
7862 *
7863 * - {Open options}[rdoc-ref:IO@Open+Options].
7864 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
7865 * - Options for Kernel#spawn.
7866 *
7867 * <b>Forked Process</b>
7868 *
7869 * When argument +cmd+ is the 1-character string <tt>'-'</tt>, causes the process to fork:
7870 * IO.popen('-') do |pipe|
7871 * if pipe
7872 * $stderr.puts "In parent, child pid is #{pipe.pid}\n"
7873 * else
7874 * $stderr.puts "In child, pid is #{$$}\n"
7875 * end
7876 * end
7877 *
7878 * Output:
7879 *
7880 * In parent, child pid is 26253
7881 * In child, pid is 26253
7882 *
7883 * Note that this is not supported on all platforms.
7884 *
7885 * <b>Shell Subprocess</b>
7886 *
7887 * When argument +cmd+ is a single string (but not <tt>'-'</tt>),
7888 * the program named +cmd+ is run as a shell command:
7889 *
7890 * IO.popen('uname') do |pipe|
7891 * pipe.readlines
7892 * end
7893 *
7894 * Output:
7895 *
7896 * ["Linux\n"]
7897 *
7898 * Another example:
7899 *
7900 * IO.popen('/bin/sh', 'r+') do |pipe|
7901 * pipe.puts('ls')
7902 * pipe.close_write
7903 * $stderr.puts pipe.readlines.size
7904 * end
7905 *
7906 * Output:
7907 *
7908 * 213
7909 *
7910 * <b>Program Subprocess</b>
7911 *
7912 * When argument +cmd+ is an array of strings,
7913 * the program named <tt>cmd[0]</tt> is run with all elements of +cmd+ as its arguments:
7914 *
7915 * IO.popen(['du', '..', '.']) do |pipe|
7916 * $stderr.puts pipe.readlines.size
7917 * end
7918 *
7919 * Output:
7920 *
7921 * 1111
7922 *
7923 * <b>Program Subprocess with <tt>argv0</tt></b>
7924 *
7925 * When argument +cmd+ is an array whose first element is a 2-element string array
7926 * and whose remaining elements (if any) are strings:
7927 *
7928 * - <tt>cmd[0][0]</tt> (the first string in the nested array) is the name of a program that is run.
7929 * - <tt>cmd[0][1]</tt> (the second string in the nested array) is set as the program's <tt>argv[0]</tt>.
7930 * - <tt>cmd[1..-1]</tt> (the strings in the outer array) are the program's arguments.
7931 *
7932 * Example (sets <tt>$0</tt> to 'foo'):
7933 *
7934 * IO.popen([['/bin/sh', 'foo'], '-c', 'echo $0']).read # => "foo\n"
7935 *
7936 * <b>Some Special Examples</b>
7937 *
7938 * # Set IO encoding.
7939 * IO.popen("nkf -e filename", :external_encoding=>"EUC-JP") {|nkf_io|
7940 * euc_jp_string = nkf_io.read
7941 * }
7942 *
7943 * # Merge standard output and standard error using Kernel#spawn option. See Kernel#spawn.
7944 * IO.popen(["ls", "/", :err=>[:child, :out]]) do |io|
7945 * ls_result_with_error = io.read
7946 * end
7947 *
7948 * # Use mixture of spawn options and IO options.
7949 * IO.popen(["ls", "/"], :err=>[:child, :out]) do |io|
7950 * ls_result_with_error = io.read
7951 * end
7952 *
7953 * f = IO.popen("uname")
7954 * p f.readlines
7955 * f.close
7956 * puts "Parent is #{Process.pid}"
7957 * IO.popen("date") {|f| puts f.gets }
7958 * IO.popen("-") {|f| $stderr.puts "#{Process.pid} is here, f is #{f.inspect}"}
7959 * p $?
7960 * IO.popen(%w"sed -e s|^|<foo>| -e s&$&;zot;&", "r+") {|f|
7961 * f.puts "bar"; f.close_write; puts f.gets
7962 * }
7963 *
7964 * Output (from last section):
7965 *
7966 * ["Linux\n"]
7967 * Parent is 21346
7968 * Thu Jan 15 22:41:19 JST 2009
7969 * 21346 is here, f is #<IO:fd 3>
7970 * 21352 is here, f is nil
7971 * #<Process::Status: pid 21352 exit 0>
7972 * <foo>bar;zot;
7973 *
7974 * Raises exceptions that IO.pipe and Kernel.spawn raise.
7975 *
7976 */
7977
7978static VALUE
7979rb_io_s_popen(int argc, VALUE *argv, VALUE klass)
7980{
7981 VALUE pname, pmode = Qnil, opt = Qnil, env = Qnil;
7982
7983 if (argc > 1 && !NIL_P(opt = rb_check_hash_type(argv[argc-1]))) --argc;
7984 if (argc > 1 && !NIL_P(env = rb_check_hash_type(argv[0]))) --argc, ++argv;
7985 switch (argc) {
7986 case 2:
7987 pmode = argv[1];
7988 case 1:
7989 pname = argv[0];
7990 break;
7991 default:
7992 {
7993 int ex = !NIL_P(opt);
7994 rb_error_arity(argc + ex, 1 + ex, 2 + ex);
7995 }
7996 }
7997 return popen_finish(rb_io_popen(pname, pmode, env, opt), klass);
7998}
7999
8000VALUE
8001rb_io_popen(VALUE pname, VALUE pmode, VALUE env, VALUE opt)
8002{
8003 const char *modestr;
8004 VALUE tmp, execarg_obj = Qnil;
8005 int oflags;
8006 enum rb_io_mode fmode;
8007 struct rb_io_encoding convconfig;
8008
8009 tmp = rb_check_array_type(pname);
8010 if (!NIL_P(tmp)) {
8011 long len = RARRAY_LEN(tmp);
8012#if SIZEOF_LONG > SIZEOF_INT
8013 if (len > INT_MAX) {
8014 rb_raise(rb_eArgError, "too many arguments");
8015 }
8016#endif
8017 execarg_obj = rb_execarg_new((int)len, RARRAY_CONST_PTR(tmp), FALSE, FALSE);
8018 RB_GC_GUARD(tmp);
8019 }
8020 else {
8021 StringValue(pname);
8022 execarg_obj = Qnil;
8023 if (!is_popen_fork(pname))
8024 execarg_obj = rb_execarg_new(1, &pname, TRUE, FALSE);
8025 }
8026 if (!NIL_P(execarg_obj)) {
8027 if (!NIL_P(opt))
8028 opt = rb_execarg_extract_options(execarg_obj, opt);
8029 if (!NIL_P(env))
8030 rb_execarg_setenv(execarg_obj, env);
8031 }
8032 rb_io_extract_modeenc(&pmode, 0, opt, &oflags, &fmode, &convconfig);
8033 modestr = rb_io_oflags_modestr(oflags);
8034
8035 return pipe_open(execarg_obj, modestr, fmode, &convconfig);
8036}
8037
8038static VALUE
8039popen_finish(VALUE port, VALUE klass)
8040{
8041 if (NIL_P(port)) {
8042 /* child */
8043 if (rb_block_given_p()) {
8044 rb_protect(rb_yield, Qnil, NULL);
8045 rb_io_flush(rb_ractor_stdout());
8046 rb_io_flush(rb_ractor_stderr());
8047 _exit(0);
8048 }
8049 return Qnil;
8050 }
8051 RBASIC_SET_CLASS(port, klass);
8052 if (rb_block_given_p()) {
8053 return rb_ensure(rb_yield, port, pipe_close, port);
8054 }
8055 return port;
8056}
8057
8058#if defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)
8059struct popen_writer_arg {
8060 char *const *argv;
8061 struct popen_arg popen;
8062};
8063
8064static int
8065exec_popen_writer(void *arg, char *errmsg, size_t buflen)
8066{
8067 struct popen_writer_arg *pw = arg;
8068 pw->popen.modef = FMODE_WRITABLE;
8069 popen_redirect(&pw->popen);
8070 execv(pw->argv[0], pw->argv);
8071 strlcpy(errmsg, strerror(errno), buflen);
8072 return -1;
8073}
8074#endif
8075
8076FILE *
8077ruby_popen_writer(char *const *argv, rb_pid_t *pid)
8078{
8079#if (defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)) || defined(_WIN32)
8080# ifdef HAVE_WORKING_FORK
8081 struct popen_writer_arg pw;
8082 int *const write_pair = pw.popen.pair;
8083# else
8084 int write_pair[2];
8085# endif
8086
8087 int result = rb_cloexec_pipe(write_pair);
8088 *pid = -1;
8089 if (result == 0) {
8090# ifdef HAVE_WORKING_FORK
8091 pw.argv = argv;
8092 int status;
8093 char errmsg[80] = {'\0'};
8094 *pid = rb_fork_async_signal_safe(&status, exec_popen_writer, &pw, Qnil, errmsg, sizeof(errmsg));
8095# else
8096 *pid = rb_w32_uspawn_process(P_NOWAIT, argv[0], argv, write_pair[0], -1, -1, 0);
8097 const char *errmsg = (*pid < 0) ? strerror(errno) : NULL;
8098# endif
8099 close(write_pair[0]);
8100 if (*pid < 0) {
8101 close(write_pair[1]);
8102 fprintf(stderr, "ruby_popen_writer(%s): %s\n", argv[0], errmsg);
8103 }
8104 else {
8105 return fdopen(write_pair[1], "w");
8106 }
8107 }
8108#endif
8109 return NULL;
8110}
8111
8112static VALUE
8113rb_open_file(VALUE io, VALUE fname, VALUE vmode, VALUE vperm, VALUE opt)
8114{
8115 int oflags;
8116 enum rb_io_mode fmode;
8117 struct rb_io_encoding convconfig;
8118 mode_t perm;
8119
8120 FilePathValue(fname);
8121
8122 rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, &convconfig);
8123 perm = NIL_P(vperm) ? 0666 : NUM2MODET(vperm);
8124
8125 rb_file_open_generic(io, fname, oflags, fmode, &convconfig, perm);
8126
8127 return io;
8128}
8129
8130/*
8131 * Document-method: File::open
8132 *
8133 * call-seq:
8134 * File.open(path, mode = 'r', perm = 0666, **opts) -> file
8135 * File.open(path, mode = 'r', perm = 0666, **opts) {|f| ... } -> object
8136 *
8137 * Creates a new File object, via File.new with the given arguments.
8138 *
8139 * With no block given, returns the File object.
8140 *
8141 * With a block given, calls the block with the File object
8142 * and returns the block's value.
8143 *
8144 */
8145
8146/*
8147 * Document-method: IO::open
8148 *
8149 * call-seq:
8150 * IO.open(fd, mode = 'r', **opts) -> io
8151 * IO.open(fd, mode = 'r', **opts) {|io| ... } -> object
8152 *
8153 * Creates a new \IO object, via IO.new with the given arguments.
8154 *
8155 * With no block given, returns the \IO object.
8156 *
8157 * With a block given, calls the block with the \IO object
8158 * and returns the block's value.
8159 *
8160 */
8161
8162static VALUE
8163rb_io_s_open(int argc, VALUE *argv, VALUE klass)
8164{
8166
8167 if (rb_block_given_p()) {
8168 return rb_ensure(rb_yield, io, io_close, io);
8169 }
8170
8171 return io;
8172}
8173
8174/*
8175 * call-seq:
8176 * IO.sysopen(path, mode = 'r', perm = 0666) -> integer
8177 *
8178 * Opens the file at the given path with the given mode and permissions;
8179 * returns the integer file descriptor.
8180 *
8181 * If the file is to be readable, it must exist;
8182 * if the file is to be writable and does not exist,
8183 * it is created with the given permissions:
8184 *
8185 * File.write('t.tmp', '') # => 0
8186 * IO.sysopen('t.tmp') # => 8
8187 * IO.sysopen('t.tmp', 'w') # => 9
8188 *
8189 *
8190 */
8191
8192static VALUE
8193rb_io_s_sysopen(int argc, VALUE *argv, VALUE _)
8194{
8195 VALUE fname, vmode, vperm;
8196 VALUE intmode;
8197 int oflags, fd;
8198 mode_t perm;
8199
8200 rb_scan_args(argc, argv, "12", &fname, &vmode, &vperm);
8201 FilePathValue(fname);
8202
8203 if (NIL_P(vmode))
8204 oflags = O_RDONLY;
8205 else if (!NIL_P(intmode = rb_check_to_integer(vmode, "to_int")))
8206 oflags = NUM2INT(intmode);
8207 else {
8208 StringValue(vmode);
8209 oflags = rb_io_modestr_oflags(StringValueCStr(vmode));
8210 }
8211 if (NIL_P(vperm)) perm = 0666;
8212 else perm = NUM2MODET(vperm);
8213
8214 RB_GC_GUARD(fname) = rb_str_new4(fname);
8215 fd = rb_sysopen(fname, oflags, perm);
8216 return INT2NUM(fd);
8217}
8218
8219static VALUE
8220check_pipe_command(VALUE filename_or_command)
8221{
8222 char *s = RSTRING_PTR(filename_or_command);
8223 long l = RSTRING_LEN(filename_or_command);
8224 char *e = s + l;
8225 int chlen;
8226
8227 if (rb_enc_ascget(s, e, &chlen, rb_enc_get(filename_or_command)) == '|') {
8228 VALUE cmd = rb_str_new(s+chlen, l-chlen);
8229 return cmd;
8230 }
8231 return Qnil;
8232}
8233
8234/*
8235 * call-seq:
8236 * open(path, mode = 'r', perm = 0666, **opts) -> io or nil
8237 * open(path, mode = 'r', perm = 0666, **opts) {|io| ... } -> obj
8238 *
8239 * Creates an IO object connected to the given file.
8240 *
8241 * This method has potential security vulnerabilities if called with untrusted input;
8242 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
8243 *
8244 * With no block given, file stream is returned:
8245 *
8246 * open('t.txt') # => #<File:t.txt>
8247 *
8248 * With a block given, calls the block with the open file stream,
8249 * then closes the stream:
8250 *
8251 * open('t.txt') {|f| p f } # => #<File:t.txt (closed)>
8252 *
8253 * Output:
8254 *
8255 * #<File:t.txt>
8256 *
8257 * See File.open for details.
8258 *
8259 */
8260
8261static VALUE
8262rb_f_open(int argc, VALUE *argv, VALUE _)
8263{
8264 ID to_open = 0;
8265 int redirect = FALSE;
8266
8267 if (argc >= 1) {
8268 CONST_ID(to_open, "to_open");
8269 if (rb_respond_to(argv[0], to_open)) {
8270 redirect = TRUE;
8271 }
8272 else {
8273 VALUE tmp = argv[0];
8274 FilePathValue(tmp);
8275 if (NIL_P(tmp)) {
8276 redirect = TRUE;
8277 }
8278 else {
8279 VALUE cmd = check_pipe_command(tmp);
8280 if (!NIL_P(cmd)) {
8281 // TODO: when removed in 4.0, update command_injection.rdoc
8282 rb_warn_deprecated_to_remove_at(4.0, "Calling Kernel#open with a leading '|'", "IO.popen");
8283 argv[0] = cmd;
8284 return rb_io_s_popen(argc, argv, rb_cIO);
8285 }
8286 }
8287 }
8288 }
8289 if (redirect) {
8290 VALUE io = rb_funcallv_kw(argv[0], to_open, argc-1, argv+1, RB_PASS_CALLED_KEYWORDS);
8291
8292 if (rb_block_given_p()) {
8293 return rb_ensure(rb_yield, io, io_close, io);
8294 }
8295 return io;
8296 }
8297 return rb_io_s_open(argc, argv, rb_cFile);
8298}
8299
8300static VALUE
8301rb_io_open_generic(VALUE klass, VALUE filename, int oflags, enum rb_io_mode fmode,
8302 const struct rb_io_encoding *convconfig, mode_t perm)
8303{
8304 VALUE cmd;
8305 if (klass == rb_cIO && !NIL_P(cmd = check_pipe_command(filename))) {
8306 // TODO: when removed in 4.0, update command_injection.rdoc
8307 rb_warn_deprecated_to_remove_at(4.0, "IO process creation with a leading '|'", "IO.popen");
8308 return pipe_open_s(cmd, rb_io_oflags_modestr(oflags), fmode, convconfig);
8309 }
8310 else {
8311 return rb_file_open_generic(io_alloc(klass), filename,
8312 oflags, fmode, convconfig, perm);
8313 }
8314}
8315
8316static VALUE
8317rb_io_open(VALUE io, VALUE filename, VALUE vmode, VALUE vperm, VALUE opt)
8318{
8319 int oflags;
8320 enum rb_io_mode fmode;
8321 struct rb_io_encoding convconfig;
8322 mode_t perm;
8323
8324 rb_io_extract_modeenc(&vmode, &vperm, opt, &oflags, &fmode, &convconfig);
8325 perm = NIL_P(vperm) ? 0666 : NUM2MODET(vperm);
8326 return rb_io_open_generic(io, filename, oflags, fmode, &convconfig, perm);
8327}
8328
8329static VALUE
8330io_reopen(VALUE io, VALUE nfile)
8331{
8332 rb_io_t *fptr, *orig;
8333 int fd, fd2;
8334 rb_off_t pos = 0;
8335
8336 nfile = rb_io_get_io(nfile);
8337 GetOpenFile(io, fptr);
8338 GetOpenFile(nfile, orig);
8339
8340 if (fptr == orig) return io;
8341 if (RUBY_IO_EXTERNAL_P(fptr)) {
8342 if ((fptr->stdio_file == stdin && !(orig->mode & FMODE_READABLE)) ||
8343 (fptr->stdio_file == stdout && !(orig->mode & FMODE_WRITABLE)) ||
8344 (fptr->stdio_file == stderr && !(orig->mode & FMODE_WRITABLE))) {
8345 rb_raise(rb_eArgError,
8346 "%s can't change access mode from \"%s\" to \"%s\"",
8347 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->mode),
8348 rb_io_fmode_modestr(orig->mode));
8349 }
8350 }
8351 if (fptr->mode & FMODE_WRITABLE) {
8352 if (io_fflush(fptr) < 0)
8353 rb_sys_fail_on_write(fptr);
8354 }
8355 else {
8356 flush_before_seek(fptr, true);
8357 }
8358 if (orig->mode & FMODE_READABLE) {
8359 pos = io_tell(orig);
8360 }
8361 if (orig->mode & FMODE_WRITABLE) {
8362 if (io_fflush(orig) < 0)
8363 rb_sys_fail_on_write(fptr);
8364 }
8365
8366 /* copy rb_io_t structure */
8367 fptr->mode = orig->mode | (fptr->mode & FMODE_EXTERNAL);
8368 fptr->encs = orig->encs;
8369 fptr->pid = orig->pid;
8370 fptr->lineno = orig->lineno;
8371 if (RTEST(orig->pathv)) fptr->pathv = orig->pathv;
8372 else if (!RUBY_IO_EXTERNAL_P(fptr)) fptr->pathv = Qnil;
8373 fptr_copy_finalizer(fptr, orig);
8374
8375 fd = fptr->fd;
8376 fd2 = orig->fd;
8377 if (fd != fd2) {
8378 // Interrupt all usage of the old file descriptor:
8379 rb_thread_io_close_interrupt(fptr);
8380 rb_thread_io_close_wait(fptr);
8381
8382 if (RUBY_IO_EXTERNAL_P(fptr) || fd <= 2 || !fptr->stdio_file) {
8383 /* need to keep FILE objects of stdin, stdout and stderr */
8384 if (rb_cloexec_dup2(fd2, fd) < 0)
8385 rb_sys_fail_path(orig->pathv);
8386 rb_update_max_fd(fd);
8387 }
8388 else {
8389 fclose(fptr->stdio_file);
8390 fptr->stdio_file = 0;
8391 fptr->fd = -1;
8392 if (rb_cloexec_dup2(fd2, fd) < 0)
8393 rb_sys_fail_path(orig->pathv);
8394 rb_update_max_fd(fd);
8395 fptr->fd = fd;
8396 }
8397
8398 if ((orig->mode & FMODE_READABLE) && pos >= 0) {
8399 if (io_seek(fptr, pos, SEEK_SET) < 0 && errno) {
8400 rb_sys_fail_path(fptr->pathv);
8401 }
8402 if (io_seek(orig, pos, SEEK_SET) < 0 && errno) {
8403 rb_sys_fail_path(orig->pathv);
8404 }
8405 }
8406 }
8407
8408 if (fptr->mode & FMODE_BINMODE) {
8409 rb_io_binmode(io);
8410 }
8411
8412 RBASIC_SET_CLASS(io, rb_obj_class(nfile));
8413 return io;
8414}
8415
8416#ifdef _WIN32
8417int rb_freopen(VALUE fname, const char *mode, FILE *fp);
8418#else
8419static int
8420rb_freopen(VALUE fname, const char *mode, FILE *fp)
8421{
8422 if (!freopen(RSTRING_PTR(fname), mode, fp)) {
8423 RB_GC_GUARD(fname);
8424 return errno;
8425 }
8426 return 0;
8427}
8428#endif
8429
8430/*
8431 * call-seq:
8432 * reopen(other_io) -> self
8433 * reopen(path, mode = 'r', **opts) -> self
8434 *
8435 * Reassociates the stream with another stream,
8436 * which may be of a different class.
8437 * This method may be used to redirect an existing stream
8438 * to a new destination.
8439 *
8440 * With argument +other_io+ given, reassociates with that stream:
8441 *
8442 * # Redirect $stdin from a file.
8443 * f = File.open('t.txt')
8444 * $stdin.reopen(f)
8445 * f.close
8446 *
8447 * # Redirect $stdout to a file.
8448 * f = File.open('t.tmp', 'w')
8449 * $stdout.reopen(f)
8450 * f.close
8451 *
8452 * With argument +path+ given, reassociates with a new stream to that file path:
8453 *
8454 * $stdin.reopen('t.txt')
8455 * $stdout.reopen('t.tmp', 'w')
8456 *
8457 * Optional keyword arguments +opts+ specify:
8458 *
8459 * - {Open Options}[rdoc-ref:IO@Open+Options].
8460 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
8461 *
8462 */
8463
8464static VALUE
8465rb_io_reopen(int argc, VALUE *argv, VALUE file)
8466{
8467 VALUE fname, nmode, opt;
8468 int oflags;
8469 rb_io_t *fptr;
8470
8471 if (rb_scan_args(argc, argv, "11:", &fname, &nmode, &opt) == 1) {
8472 VALUE tmp = rb_io_check_io(fname);
8473 if (!NIL_P(tmp)) {
8474 return io_reopen(file, tmp);
8475 }
8476 }
8477
8478 FilePathValue(fname);
8479 rb_io_taint_check(file);
8480 fptr = RFILE(file)->fptr;
8481 if (!fptr) {
8482 fptr = RFILE(file)->fptr = ZALLOC(rb_io_t);
8483 }
8484
8485 if (!NIL_P(nmode) || !NIL_P(opt)) {
8486 enum rb_io_mode fmode;
8487 struct rb_io_encoding convconfig;
8488
8489 rb_io_extract_modeenc(&nmode, 0, opt, &oflags, &fmode, &convconfig);
8490 if (RUBY_IO_EXTERNAL_P(fptr) &&
8491 ((fptr->mode & FMODE_READWRITE) & (fmode & FMODE_READWRITE)) !=
8492 (fptr->mode & FMODE_READWRITE)) {
8493 rb_raise(rb_eArgError,
8494 "%s can't change access mode from \"%s\" to \"%s\"",
8495 PREP_STDIO_NAME(fptr), rb_io_fmode_modestr(fptr->mode),
8496 rb_io_fmode_modestr(fmode));
8497 }
8498 fptr->mode = fmode;
8499 fptr->encs = convconfig;
8500 }
8501 else {
8502 oflags = rb_io_fmode_oflags(fptr->mode);
8503 }
8504
8505 fptr->pathv = fname;
8506 if (fptr->fd < 0) {
8507 fptr->fd = rb_sysopen(fptr->pathv, oflags, 0666);
8508 fptr->stdio_file = 0;
8509 return file;
8510 }
8511
8512 if (fptr->mode & FMODE_WRITABLE) {
8513 if (io_fflush(fptr) < 0)
8514 rb_sys_fail_on_write(fptr);
8515 }
8516 fptr->rbuf.off = fptr->rbuf.len = 0;
8517
8518 if (fptr->stdio_file) {
8519 int e = rb_freopen(rb_str_encode_ospath(fptr->pathv),
8520 rb_io_oflags_modestr(oflags),
8521 fptr->stdio_file);
8522 if (e) rb_syserr_fail_path(e, fptr->pathv);
8523 fptr->fd = fileno(fptr->stdio_file);
8524 rb_fd_fix_cloexec(fptr->fd);
8525#ifdef USE_SETVBUF
8526 if (setvbuf(fptr->stdio_file, NULL, _IOFBF, 0) != 0)
8527 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8528#endif
8529 if (fptr->stdio_file == stderr) {
8530 if (setvbuf(fptr->stdio_file, NULL, _IONBF, BUFSIZ) != 0)
8531 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8532 }
8533 else if (fptr->stdio_file == stdout && isatty(fptr->fd)) {
8534 if (setvbuf(fptr->stdio_file, NULL, _IOLBF, BUFSIZ) != 0)
8535 rb_warn("setvbuf() can't be honoured for %"PRIsVALUE, fptr->pathv);
8536 }
8537 }
8538 else {
8539 int tmpfd = rb_sysopen(fptr->pathv, oflags, 0666);
8540 int err = 0;
8541 if (rb_cloexec_dup2(tmpfd, fptr->fd) < 0)
8542 err = errno;
8543 (void)close(tmpfd);
8544 if (err) {
8545 rb_syserr_fail_path(err, fptr->pathv);
8546 }
8547 }
8548
8549 return file;
8550}
8551
8552/* :nodoc: */
8553static VALUE
8554rb_io_init_copy(VALUE dest, VALUE io)
8555{
8556 rb_io_t *fptr, *orig;
8557 int fd;
8558 VALUE write_io;
8559 rb_off_t pos;
8560
8561 io = rb_io_get_io(io);
8562 if (!OBJ_INIT_COPY(dest, io)) return dest;
8563 GetOpenFile(io, orig);
8564 MakeOpenFile(dest, fptr);
8565
8566 rb_io_flush(io);
8567
8568 /* copy rb_io_t structure */
8569 fptr->mode = orig->mode & ~FMODE_EXTERNAL;
8570 fptr->encs = orig->encs;
8571 fptr->pid = orig->pid;
8572 fptr->lineno = orig->lineno;
8573 fptr->timeout = orig->timeout;
8574
8575 ccan_list_head_init(&fptr->blocking_operations);
8576 fptr->closing_ec = NULL;
8577 fptr->wakeup_mutex = Qnil;
8578 fptr->fork_generation = GET_VM()->fork_gen;
8579
8580 if (!NIL_P(orig->pathv)) fptr->pathv = orig->pathv;
8581 fptr_copy_finalizer(fptr, orig);
8582
8583 fd = ruby_dup(orig->fd);
8584 fptr->fd = fd;
8585 pos = io_tell(orig);
8586 if (0 <= pos)
8587 io_seek(fptr, pos, SEEK_SET);
8588 if (fptr->mode & FMODE_BINMODE) {
8589 rb_io_binmode(dest);
8590 }
8591
8592 write_io = GetWriteIO(io);
8593 if (io != write_io) {
8594 write_io = rb_obj_dup(write_io);
8595 fptr->tied_io_for_writing = write_io;
8596 rb_ivar_set(dest, rb_intern("@tied_io_for_writing"), write_io);
8597 }
8598
8599 return dest;
8600}
8601
8602/*
8603 * call-seq:
8604 * printf(format_string, *objects) -> nil
8605 *
8606 * Formats and writes +objects+ to the stream.
8607 *
8608 * For details on +format_string+, see
8609 * {Format Specifications}[rdoc-ref:format_specifications.rdoc].
8610 *
8611 */
8612
8613VALUE
8614rb_io_printf(int argc, const VALUE *argv, VALUE out)
8615{
8616 rb_io_write(out, rb_f_sprintf(argc, argv));
8617 return Qnil;
8618}
8619
8620/*
8621 * call-seq:
8622 * printf(format_string, *objects) -> nil
8623 * printf(io, format_string, *objects) -> nil
8624 *
8625 * Equivalent to:
8626 *
8627 * io.write(sprintf(format_string, *objects))
8628 *
8629 * For details on +format_string+, see
8630 * {Format Specifications}[rdoc-ref:format_specifications.rdoc].
8631 *
8632 * With the single argument +format_string+, formats +objects+ into the string,
8633 * then writes the formatted string to $stdout:
8634 *
8635 * printf('%4.4d %10s %2.2f', 24, 24, 24.0)
8636 *
8637 * Output (on $stdout):
8638 *
8639 * 0024 24 24.00#
8640 *
8641 * With arguments +io+ and +format_string+, formats +objects+ into the string,
8642 * then writes the formatted string to +io+:
8643 *
8644 * printf($stderr, '%4.4d %10s %2.2f', 24, 24, 24.0)
8645 *
8646 * Output (on $stderr):
8647 *
8648 * 0024 24 24.00# => nil
8649 *
8650 * With no arguments, does nothing.
8651 *
8652 */
8653
8654static VALUE
8655rb_f_printf(int argc, VALUE *argv, VALUE _)
8656{
8657 VALUE out;
8658
8659 if (argc == 0) return Qnil;
8660 if (RB_TYPE_P(argv[0], T_STRING)) {
8661 out = rb_ractor_stdout();
8662 }
8663 else {
8664 out = argv[0];
8665 argv++;
8666 argc--;
8667 }
8668 rb_io_write(out, rb_f_sprintf(argc, argv));
8669
8670 return Qnil;
8671}
8672
8673static void
8674deprecated_str_setter(VALUE val, ID id, VALUE *var)
8675{
8676 rb_str_setter(val, id, &val);
8677 if (!NIL_P(val)) {
8678 rb_warn_deprecated("'%s'", NULL, rb_id2name(id));
8679 }
8680 *var = val;
8681}
8682
8683static void
8684deprecated_rs_setter(VALUE val, ID id, VALUE *var)
8685{
8686 if (!NIL_P(val)) {
8687 if (!RB_TYPE_P(val, T_STRING)) {
8688 rb_raise(rb_eTypeError, "value of %"PRIsVALUE" must be String", rb_id2str(id));
8689 }
8690 if (rb_str_equal(val, rb_default_rs)) {
8691 val = rb_default_rs;
8692 }
8693 else {
8694 val = rb_str_frozen_bare_string(val);
8695 }
8697 rb_warn_deprecated("'%s'", NULL, rb_id2name(id));
8698 }
8699 *var = val;
8700}
8701
8702/*
8703 * call-seq:
8704 * print(*objects) -> nil
8705 *
8706 * Writes the given objects to the stream; returns +nil+.
8707 * Appends the output record separator <tt>$OUTPUT_RECORD_SEPARATOR</tt>
8708 * (<tt>$\</tt>), if it is not +nil+.
8709 * See {Line IO}[rdoc-ref:IO@Line+IO].
8710 *
8711 * With argument +objects+ given, for each object:
8712 *
8713 * - Converts via its method +to_s+ if not a string.
8714 * - Writes to the stream.
8715 * - If not the last object, writes the output field separator
8716 * <tt>$OUTPUT_FIELD_SEPARATOR</tt> (<tt>$,</tt>) if it is not +nil+.
8717 *
8718 * With default separators:
8719 *
8720 * f = File.open('t.tmp', 'w+')
8721 * objects = [0, 0.0, Rational(0, 1), Complex(0, 0), :zero, 'zero']
8722 * p $OUTPUT_RECORD_SEPARATOR
8723 * p $OUTPUT_FIELD_SEPARATOR
8724 * f.print(*objects)
8725 * f.rewind
8726 * p f.read
8727 * f.close
8728 *
8729 * Output:
8730 *
8731 * nil
8732 * nil
8733 * "00.00/10+0izerozero"
8734 *
8735 * With specified separators:
8736 *
8737 * $\ = "\n"
8738 * $, = ','
8739 * f.rewind
8740 * f.print(*objects)
8741 * f.rewind
8742 * p f.read
8743 *
8744 * Output:
8745 *
8746 * "0,0.0,0/1,0+0i,zero,zero\n"
8747 *
8748 * With no argument given, writes the content of <tt>$_</tt>
8749 * (which is usually the most recent user input):
8750 *
8751 * f = File.open('t.tmp', 'w+')
8752 * gets # Sets $_ to the most recent user input.
8753 * f.print
8754 * f.close
8755 *
8756 */
8757
8758VALUE
8759rb_io_print(int argc, const VALUE *argv, VALUE out)
8760{
8761 int i;
8762 VALUE line;
8763
8764 /* if no argument given, print `$_' */
8765 if (argc == 0) {
8766 argc = 1;
8767 line = rb_lastline_get();
8768 argv = &line;
8769 }
8770 if (argc > 1 && !NIL_P(rb_output_fs)) {
8771 rb_category_warn(RB_WARN_CATEGORY_DEPRECATED, "$, is set to non-nil value");
8772 }
8773 for (i=0; i<argc; i++) {
8774 if (!NIL_P(rb_output_fs) && i>0) {
8775 rb_io_write(out, rb_output_fs);
8776 }
8777 rb_io_write(out, argv[i]);
8778 }
8779 if (argc > 0 && !NIL_P(rb_output_rs)) {
8780 rb_io_write(out, rb_output_rs);
8781 }
8782
8783 return Qnil;
8784}
8785
8786/*
8787 * call-seq:
8788 * print(*objects) -> nil
8789 *
8790 * Equivalent to <tt>$stdout.print(*objects)</tt>,
8791 * this method is the straightforward way to write to <tt>$stdout</tt>.
8792 *
8793 * Writes the given objects to <tt>$stdout</tt>; returns +nil+.
8794 * Appends the output record separator <tt>$OUTPUT_RECORD_SEPARATOR</tt>
8795 * <tt>$\</tt>), if it is not +nil+.
8796 *
8797 * With argument +objects+ given, for each object:
8798 *
8799 * - Converts via its method +to_s+ if not a string.
8800 * - Writes to <tt>stdout</tt>.
8801 * - If not the last object, writes the output field separator
8802 * <tt>$OUTPUT_FIELD_SEPARATOR</tt> (<tt>$,</tt> if it is not +nil+.
8803 *
8804 * With default separators:
8805 *
8806 * objects = [0, 0.0, Rational(0, 1), Complex(0, 0), :zero, 'zero']
8807 * $OUTPUT_RECORD_SEPARATOR
8808 * $OUTPUT_FIELD_SEPARATOR
8809 * print(*objects)
8810 *
8811 * Output:
8812 *
8813 * nil
8814 * nil
8815 * 00.00/10+0izerozero
8816 *
8817 * With specified separators:
8818 *
8819 * $OUTPUT_RECORD_SEPARATOR = "\n"
8820 * $OUTPUT_FIELD_SEPARATOR = ','
8821 * print(*objects)
8822 *
8823 * Output:
8824 *
8825 * 0,0.0,0/1,0+0i,zero,zero
8826 *
8827 * With no argument given, writes the content of <tt>$_</tt>
8828 * (which is usually the most recent user input):
8829 *
8830 * gets # Sets $_ to the most recent user input.
8831 * print # Prints $_.
8832 *
8833 */
8834
8835static VALUE
8836rb_f_print(int argc, const VALUE *argv, VALUE _)
8837{
8838 rb_io_print(argc, argv, rb_ractor_stdout());
8839 return Qnil;
8840}
8841
8842/*
8843 * call-seq:
8844 * putc(object) -> object
8845 *
8846 * Writes a character to the stream.
8847 * See {Character IO}[rdoc-ref:IO@Character+IO].
8848 *
8849 * If +object+ is numeric, converts to integer if necessary,
8850 * then writes the character whose code is the
8851 * least significant byte;
8852 * if +object+ is a string, writes the first character:
8853 *
8854 * $stdout.putc "A"
8855 * $stdout.putc 65
8856 *
8857 * Output:
8858 *
8859 * AA
8860 *
8861 */
8862
8863static VALUE
8864rb_io_putc(VALUE io, VALUE ch)
8865{
8866 VALUE str;
8867 if (RB_TYPE_P(ch, T_STRING)) {
8868 str = rb_str_substr(ch, 0, 1);
8869 }
8870 else {
8871 char c = NUM2CHR(ch);
8872 str = rb_str_new(&c, 1);
8873 }
8874 rb_io_write(io, str);
8875 return ch;
8876}
8877
8878#define forward(obj, id, argc, argv) \
8879 rb_funcallv_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8880#define forward_public(obj, id, argc, argv) \
8881 rb_funcallv_public_kw(obj, id, argc, argv, RB_PASS_CALLED_KEYWORDS)
8882#define forward_current(id, argc, argv) \
8883 forward_public(ARGF.current_file, id, argc, argv)
8884
8885/*
8886 * call-seq:
8887 * putc(int) -> int
8888 *
8889 * Equivalent to:
8890 *
8891 * $stdout.putc(int)
8892 *
8893 * See IO#putc for important information regarding multi-byte characters.
8894 *
8895 */
8896
8897static VALUE
8898rb_f_putc(VALUE recv, VALUE ch)
8899{
8900 VALUE r_stdout = rb_ractor_stdout();
8901 if (recv == r_stdout) {
8902 return rb_io_putc(recv, ch);
8903 }
8904 return forward(r_stdout, rb_intern("putc"), 1, &ch);
8905}
8906
8907
8908int
8909rb_str_end_with_asciichar(VALUE str, int c)
8910{
8911 long len = RSTRING_LEN(str);
8912 const char *ptr = RSTRING_PTR(str);
8913 rb_encoding *enc = rb_enc_from_index(ENCODING_GET(str));
8914 int n;
8915
8916 if (len == 0) return 0;
8917 if ((n = rb_enc_mbminlen(enc)) == 1) {
8918 return ptr[len - 1] == c;
8919 }
8920 return rb_enc_ascget(ptr + ((len - 1) / n) * n, ptr + len, &n, enc) == c;
8921}
8922
8923static VALUE
8924io_puts_ary(VALUE ary, VALUE out, int recur)
8925{
8926 VALUE tmp;
8927 long i;
8928
8929 if (recur) {
8930 tmp = rb_str_new2("[...]");
8931 rb_io_puts(1, &tmp, out);
8932 return Qtrue;
8933 }
8934 ary = rb_check_array_type(ary);
8935 if (NIL_P(ary)) return Qfalse;
8936 for (i=0; i<RARRAY_LEN(ary); i++) {
8937 tmp = RARRAY_AREF(ary, i);
8938 rb_io_puts(1, &tmp, out);
8939 }
8940 return Qtrue;
8941}
8942
8943/*
8944 * call-seq:
8945 * puts(*objects) -> nil
8946 *
8947 * Writes the given +objects+ to the stream, which must be open for writing;
8948 * returns +nil+.\
8949 * Writes a newline after each that does not already end with a newline sequence.
8950 * If called without arguments, writes a newline.
8951 * See {Line IO}[rdoc-ref:IO@Line+IO].
8952 *
8953 * Note that each added newline is the character <tt>"\n"<//tt>,
8954 * not the output record separator (<tt>$\</tt>).
8955 *
8956 * Treatment for each object:
8957 *
8958 * - String: writes the string.
8959 * - Neither string nor array: writes <tt>object.to_s</tt>.
8960 * - Array: writes each element of the array; arrays may be nested.
8961 *
8962 * To keep these examples brief, we define this helper method:
8963 *
8964 * def show(*objects)
8965 * # Puts objects to file.
8966 * f = File.new('t.tmp', 'w+')
8967 * f.puts(objects)
8968 * # Return file content.
8969 * f.rewind
8970 * p f.read
8971 * f.close
8972 * end
8973 *
8974 * # Strings without newlines.
8975 * show('foo', 'bar', 'baz') # => "foo\nbar\nbaz\n"
8976 * # Strings, some with newlines.
8977 * show("foo\n", 'bar', "baz\n") # => "foo\nbar\nbaz\n"
8978 *
8979 * # Neither strings nor arrays:
8980 * show(0, 0.0, Rational(0, 1), Complex(9, 0), :zero)
8981 * # => "0\n0.0\n0/1\n9+0i\nzero\n"
8982 *
8983 * # Array of strings.
8984 * show(['foo', "bar\n", 'baz']) # => "foo\nbar\nbaz\n"
8985 * # Nested arrays.
8986 * show([[[0, 1], 2, 3], 4, 5]) # => "0\n1\n2\n3\n4\n5\n"
8987 *
8988 */
8989
8990VALUE
8991rb_io_puts(int argc, const VALUE *argv, VALUE out)
8992{
8993 VALUE line, args[2];
8994
8995 /* if no argument given, print newline. */
8996 if (argc == 0) {
8997 rb_io_write(out, rb_default_rs);
8998 return Qnil;
8999 }
9000 for (int i = 0; i < argc; i++) {
9001 // Convert the argument to a string:
9002 if (RB_TYPE_P(argv[i], T_STRING)) {
9003 line = argv[i];
9004 }
9005 else if (rb_exec_recursive(io_puts_ary, argv[i], out)) {
9006 continue;
9007 }
9008 else {
9009 line = rb_obj_as_string(argv[i]);
9010 }
9011
9012 // Write the line:
9013 int n = 0;
9014 if (RSTRING_LEN(line) == 0) {
9015 args[n++] = rb_default_rs;
9016 }
9017 else {
9018 args[n++] = line;
9019 if (!rb_str_end_with_asciichar(line, '\n')) {
9020 args[n++] = rb_default_rs;
9021 }
9022 }
9023
9024 rb_io_writev(out, n, args);
9025 }
9026
9027 return Qnil;
9028}
9029
9030/*
9031 * call-seq:
9032 * puts(*objects) -> nil
9033 *
9034 * Equivalent to
9035 *
9036 * $stdout.puts(objects)
9037 */
9038
9039static VALUE
9040rb_f_puts(int argc, VALUE *argv, VALUE recv)
9041{
9042 VALUE r_stdout = rb_ractor_stdout();
9043 if (recv == r_stdout) {
9044 return rb_io_puts(argc, argv, recv);
9045 }
9046 return forward(r_stdout, rb_intern("puts"), argc, argv);
9047}
9048
9049static VALUE
9050rb_p_write(VALUE str)
9051{
9052 VALUE args[2];
9053 args[0] = str;
9054 args[1] = rb_default_rs;
9055 VALUE r_stdout = rb_ractor_stdout();
9056 if (RB_TYPE_P(r_stdout, T_FILE) &&
9057 rb_method_basic_definition_p(CLASS_OF(r_stdout), id_write)) {
9058 io_writev(2, args, r_stdout);
9059 }
9060 else {
9061 rb_io_writev(r_stdout, 2, args);
9062 }
9063 return Qnil;
9064}
9065
9066void
9067rb_p(VALUE obj) /* for debug print within C code */
9068{
9069 rb_p_write(rb_obj_as_string(rb_inspect(obj)));
9070}
9071
9072static VALUE
9073rb_p_result(int argc, const VALUE *argv)
9074{
9075 VALUE ret = Qnil;
9076
9077 if (argc == 1) {
9078 ret = argv[0];
9079 }
9080 else if (argc > 1) {
9081 ret = rb_ary_new4(argc, argv);
9082 }
9083 VALUE r_stdout = rb_ractor_stdout();
9084 if (RB_TYPE_P(r_stdout, T_FILE)) {
9085 rb_uninterruptible(rb_io_flush, r_stdout);
9086 }
9087 return ret;
9088}
9089
9090/*
9091 * call-seq:
9092 * p(object) -> obj
9093 * p(*objects) -> array of objects
9094 * p -> nil
9095 *
9096 * For each object +obj+, executes:
9097 *
9098 * $stdout.write(obj.inspect, "\n")
9099 *
9100 * With one object given, returns the object;
9101 * with multiple objects given, returns an array containing the objects;
9102 * with no object given, returns +nil+.
9103 *
9104 * Examples:
9105 *
9106 * r = Range.new(0, 4)
9107 * p r # => 0..4
9108 * p [r, r, r] # => [0..4, 0..4, 0..4]
9109 * p # => nil
9110 *
9111 * Output:
9112 *
9113 * 0..4
9114 * [0..4, 0..4, 0..4]
9115 *
9116 * Kernel#p is designed for debugging purposes.
9117 * Ruby implementations may define Kernel#p to be uninterruptible
9118 * in whole or in part.
9119 * On CRuby, Kernel#p's writing of data is uninterruptible.
9120 */
9121
9122static VALUE
9123rb_f_p(int argc, VALUE *argv, VALUE self)
9124{
9125 int i;
9126 for (i=0; i<argc; i++) {
9127 VALUE inspected = rb_obj_as_string(rb_inspect(argv[i]));
9128 rb_uninterruptible(rb_p_write, inspected);
9129 }
9130 return rb_p_result(argc, argv);
9131}
9132
9133/*
9134 * call-seq:
9135 * display(port = $>) -> nil
9136 *
9137 * Writes +self+ on the given port:
9138 *
9139 * 1.display
9140 * "cat".display
9141 * [ 4, 5, 6 ].display
9142 * puts
9143 *
9144 * Output:
9145 *
9146 * 1cat[4, 5, 6]
9147 *
9148 */
9149
9150static VALUE
9151rb_obj_display(int argc, VALUE *argv, VALUE self)
9152{
9153 VALUE out;
9154
9155 out = (!rb_check_arity(argc, 0, 1) ? rb_ractor_stdout() : argv[0]);
9156 rb_io_write(out, self);
9157
9158 return Qnil;
9159}
9160
9161static int
9162rb_stderr_to_original_p(VALUE err)
9163{
9164 return (err == orig_stderr || RFILE(orig_stderr)->fptr->fd < 0);
9165}
9166
9167void
9168rb_write_error2(const char *mesg, long len)
9169{
9170 VALUE out = rb_ractor_stderr();
9171 if (rb_stderr_to_original_p(out)) {
9172#ifdef _WIN32
9173 if (isatty(fileno(stderr))) {
9174 if (rb_w32_write_console(rb_str_new(mesg, len), fileno(stderr)) > 0) return;
9175 }
9176#endif
9177 if (fwrite(mesg, sizeof(char), (size_t)len, stderr) < (size_t)len) {
9178 /* failed to write to stderr, what can we do? */
9179 return;
9180 }
9181 }
9182 else {
9183 rb_io_write(out, rb_str_new(mesg, len));
9184 }
9185}
9186
9187void
9188rb_write_error(const char *mesg)
9189{
9190 rb_write_error2(mesg, strlen(mesg));
9191}
9192
9193void
9194rb_write_error_str(VALUE mesg)
9195{
9196 VALUE out = rb_ractor_stderr();
9197 /* a stopgap measure for the time being */
9198 if (rb_stderr_to_original_p(out)) {
9199 size_t len = (size_t)RSTRING_LEN(mesg);
9200#ifdef _WIN32
9201 if (isatty(fileno(stderr))) {
9202 if (rb_w32_write_console(mesg, fileno(stderr)) > 0) return;
9203 }
9204#endif
9205 if (fwrite(RSTRING_PTR(mesg), sizeof(char), len, stderr) < len) {
9206 RB_GC_GUARD(mesg);
9207 return;
9208 }
9209 }
9210 else {
9211 /* may unlock GVL, and */
9212 rb_io_write(out, mesg);
9213 }
9214}
9215
9216int
9217rb_stderr_tty_p(void)
9218{
9219 if (rb_stderr_to_original_p(rb_ractor_stderr()))
9220 return isatty(fileno(stderr));
9221 return 0;
9222}
9223
9224static void
9225must_respond_to(ID mid, VALUE val, ID id)
9226{
9227 if (!rb_respond_to(val, mid)) {
9228 rb_raise(rb_eTypeError, "%"PRIsVALUE" must have %"PRIsVALUE" method, %"PRIsVALUE" given",
9229 rb_id2str(id), rb_id2str(mid),
9230 rb_obj_class(val));
9231 }
9232}
9233
9234static void
9235stdin_setter(VALUE val, ID id, VALUE *ptr)
9236{
9238}
9239
9240static VALUE
9241stdin_getter(ID id, VALUE *ptr)
9242{
9243 return rb_ractor_stdin();
9244}
9245
9246static void
9247stdout_setter(VALUE val, ID id, VALUE *ptr)
9248{
9249 must_respond_to(id_write, val, id);
9251}
9252
9253static VALUE
9254stdout_getter(ID id, VALUE *ptr)
9255{
9256 return rb_ractor_stdout();
9257}
9258
9259static void
9260stderr_setter(VALUE val, ID id, VALUE *ptr)
9261{
9262 must_respond_to(id_write, val, id);
9264}
9265
9266static VALUE
9267stderr_getter(ID id, VALUE *ptr)
9268{
9269 return rb_ractor_stderr();
9270}
9271
9272static VALUE
9273allocate_and_open_new_file(VALUE klass)
9274{
9275 VALUE self = io_alloc(klass);
9276 rb_io_make_open_file(self);
9277 return self;
9278}
9279
9280VALUE
9281rb_io_open_descriptor(VALUE klass, int descriptor, int mode, VALUE path, VALUE timeout, struct rb_io_encoding *encoding)
9282{
9283 int state;
9284 VALUE self = rb_protect(allocate_and_open_new_file, klass, &state);
9285 if (state) {
9286 /* if we raised an exception allocating an IO object, but the caller
9287 intended to transfer ownership of this FD to us, close the fd before
9288 raising the exception. Otherwise, we would leak a FD - the caller
9289 expects GC to close the file, but we never got around to assigning
9290 it to a rb_io. */
9291 if (!(mode & FMODE_EXTERNAL)) {
9292 maygvl_close(descriptor, 0);
9293 }
9294 rb_jump_tag(state);
9295 }
9296
9297
9298 rb_io_t *io = RFILE(self)->fptr;
9299 io->self = self;
9300 io->fd = descriptor;
9301 io->mode = mode;
9302
9303 /* At this point, Ruby fully owns the descriptor, and will close it when
9304 the IO gets GC'd (unless FMODE_EXTERNAL was set), no matter what happens
9305 in the rest of this method. */
9306
9307 if (NIL_P(path)) {
9308 io->pathv = Qnil;
9309 }
9310 else {
9311 StringValue(path);
9312 io->pathv = rb_str_new_frozen(path);
9313 }
9314
9315 io->timeout = timeout;
9316
9317 ccan_list_head_init(&io->blocking_operations);
9318 io->closing_ec = NULL;
9319 io->wakeup_mutex = Qnil;
9320 io->fork_generation = GET_VM()->fork_gen;
9321
9322 if (encoding) {
9323 io->encs = *encoding;
9324 }
9325
9326 rb_update_max_fd(descriptor);
9327
9328 return self;
9329}
9330
9331static VALUE
9332prep_io(int fd, enum rb_io_mode fmode, VALUE klass, const char *path)
9333{
9334 VALUE path_value = Qnil;
9335 rb_encoding *e;
9336 struct rb_io_encoding convconfig;
9337
9338 if (path) {
9339 path_value = rb_obj_freeze(rb_str_new_cstr(path));
9340 }
9341
9342 e = (fmode & FMODE_BINMODE) ? rb_ascii8bit_encoding() : NULL;
9343 rb_io_ext_int_to_encs(e, NULL, &convconfig.enc, &convconfig.enc2, fmode);
9344 convconfig.ecflags = (fmode & FMODE_READABLE) ?
9347#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9348 convconfig.ecflags |= (fmode & FMODE_WRITABLE) ?
9349 MODE_BTMODE(TEXTMODE_NEWLINE_DECORATOR_ON_WRITE,
9350 0, TEXTMODE_NEWLINE_DECORATOR_ON_WRITE) : 0;
9351#endif
9352 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(convconfig.enc2, convconfig.ecflags);
9353 convconfig.ecopts = Qnil;
9354
9355 VALUE self = rb_io_open_descriptor(klass, fd, fmode, path_value, Qnil, &convconfig);
9356 rb_io_t*io = RFILE(self)->fptr;
9357
9358 if (!io_check_tty(io)) {
9359#ifdef __CYGWIN__
9360 io->mode |= FMODE_BINMODE;
9361 setmode(fd, O_BINARY);
9362#endif
9363 }
9364
9365 return self;
9366}
9367
9368VALUE
9369rb_io_fdopen(int fd, int oflags, const char *path)
9370{
9371 VALUE klass = rb_cIO;
9372
9373 if (path && strcmp(path, "-")) klass = rb_cFile;
9374 return prep_io(fd, rb_io_oflags_fmode(oflags), klass, path);
9375}
9376
9377static VALUE
9378prep_stdio(FILE *f, enum rb_io_mode fmode, VALUE klass, const char *path)
9379{
9380 rb_io_t *fptr;
9381 VALUE io = prep_io(fileno(f), fmode|FMODE_EXTERNAL|DEFAULT_TEXTMODE, klass, path);
9382
9383 GetOpenFile(io, fptr);
9385#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
9386 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
9387 if (fmode & FMODE_READABLE) {
9389 }
9390#endif
9391 fptr->stdio_file = f;
9392
9393 return io;
9394}
9395
9396VALUE
9397rb_io_prep_stdin(void)
9398{
9399 return prep_stdio(stdin, FMODE_READABLE, rb_cIO, "<STDIN>");
9400}
9401
9402VALUE
9403rb_io_prep_stdout(void)
9404{
9405 return prep_stdio(stdout, FMODE_WRITABLE|FMODE_SIGNAL_ON_EPIPE, rb_cIO, "<STDOUT>");
9406}
9407
9408VALUE
9409rb_io_prep_stderr(void)
9410{
9411 return prep_stdio(stderr, FMODE_WRITABLE|FMODE_SYNC, rb_cIO, "<STDERR>");
9412}
9413
9414FILE *
9416{
9417 if (!fptr->stdio_file) {
9418 int oflags = rb_io_fmode_oflags(fptr->mode) & ~O_EXCL;
9419 fptr->stdio_file = rb_fdopen(fptr->fd, rb_io_oflags_modestr(oflags));
9420 }
9421 return fptr->stdio_file;
9422}
9423
9424static inline void
9425rb_io_buffer_init(struct rb_io_internal_buffer *buf)
9426{
9427 buf->ptr = NULL;
9428 buf->off = 0;
9429 buf->len = 0;
9430 buf->capa = 0;
9431}
9432
9433static inline rb_io_t *
9434rb_io_fptr_new(void)
9435{
9436 rb_io_t *fp = ALLOC(rb_io_t);
9437 fp->self = Qnil;
9438 fp->fd = -1;
9439 fp->stdio_file = NULL;
9440 fp->mode = 0;
9441 fp->pid = 0;
9442 fp->lineno = 0;
9443 fp->pathv = Qnil;
9444 fp->finalize = 0;
9445 rb_io_buffer_init(&fp->wbuf);
9446 rb_io_buffer_init(&fp->rbuf);
9447 rb_io_buffer_init(&fp->cbuf);
9448 fp->readconv = NULL;
9449 fp->writeconv = NULL;
9451 fp->writeconv_pre_ecflags = 0;
9453 fp->writeconv_initialized = 0;
9454 fp->tied_io_for_writing = 0;
9455 fp->encs.enc = NULL;
9456 fp->encs.enc2 = NULL;
9457 fp->encs.ecflags = 0;
9458 fp->encs.ecopts = Qnil;
9459 fp->write_lock = Qnil;
9460 fp->timeout = Qnil;
9461 ccan_list_head_init(&fp->blocking_operations);
9462 fp->closing_ec = NULL;
9463 fp->wakeup_mutex = Qnil;
9464 fp->fork_generation = GET_VM()->fork_gen;
9465 return fp;
9466}
9467
9468rb_io_t *
9469rb_io_make_open_file(VALUE obj)
9470{
9471 rb_io_t *fp = 0;
9472
9473 Check_Type(obj, T_FILE);
9474 if (RFILE(obj)->fptr) {
9475 rb_io_close(obj);
9476 rb_io_fptr_finalize(RFILE(obj)->fptr);
9477 RFILE(obj)->fptr = 0;
9478 }
9479 fp = rb_io_fptr_new();
9480 fp->self = obj;
9481 RFILE(obj)->fptr = fp;
9482 return fp;
9483}
9484
9485static VALUE io_initialize(VALUE io, VALUE fnum, VALUE vmode, VALUE opt);
9486
9487/*
9488 * call-seq:
9489 * IO.new(fd, mode = 'r', **opts) -> io
9490 *
9491 * Creates and returns a new \IO object (file stream) from a file descriptor.
9492 *
9493 * \IO.new may be useful for interaction with low-level libraries.
9494 * For higher-level interactions, it may be simpler to create
9495 * the file stream using File.open.
9496 *
9497 * Argument +fd+ must be a valid file descriptor (integer):
9498 *
9499 * path = 't.tmp'
9500 * fd = IO.sysopen(path) # => 3
9501 * IO.new(fd) # => #<IO:fd 3>
9502 *
9503 * The new \IO object does not inherit encoding
9504 * (because the integer file descriptor does not have an encoding):
9505 *
9506 * fd = IO.sysopen('t.rus', 'rb')
9507 * io = IO.new(fd)
9508 * io.external_encoding # => #<Encoding:UTF-8> # Not ASCII-8BIT.
9509 *
9510 * Optional argument +mode+ (defaults to 'r') must specify a valid mode;
9511 * see {Access Modes}[rdoc-ref:File@Access+Modes]:
9512 *
9513 * IO.new(fd, 'w') # => #<IO:fd 3>
9514 * IO.new(fd, File::WRONLY) # => #<IO:fd 3>
9515 *
9516 * Optional keyword arguments +opts+ specify:
9517 *
9518 * - {Open Options}[rdoc-ref:IO@Open+Options].
9519 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
9520 *
9521 * Examples:
9522 *
9523 * IO.new(fd, internal_encoding: nil) # => #<IO:fd 3>
9524 * IO.new(fd, autoclose: true) # => #<IO:fd 3>
9525 *
9526 */
9527
9528static VALUE
9529rb_io_initialize(int argc, VALUE *argv, VALUE io)
9530{
9531 VALUE fnum, vmode;
9532 VALUE opt;
9533
9534 rb_scan_args(argc, argv, "11:", &fnum, &vmode, &opt);
9535 return io_initialize(io, fnum, vmode, opt);
9536}
9537
9538static VALUE
9539io_initialize(VALUE io, VALUE fnum, VALUE vmode, VALUE opt)
9540{
9541 rb_io_t *fp;
9542 int fd, oflags = O_RDONLY;
9543 enum rb_io_mode fmode;
9544 struct rb_io_encoding convconfig;
9545#if defined(HAVE_FCNTL) && defined(F_GETFL)
9546 int ofmode;
9547#else
9548 struct stat st;
9549#endif
9550
9551 rb_io_extract_modeenc(&vmode, 0, opt, &oflags, &fmode, &convconfig);
9552
9553 fd = NUM2INT(fnum);
9554 if (rb_reserved_fd_p(fd)) {
9555 rb_raise(rb_eArgError, "The given fd is not accessible because RubyVM reserves it");
9556 }
9557#if defined(HAVE_FCNTL) && defined(F_GETFL)
9558 oflags = fcntl(fd, F_GETFL);
9559 if (oflags == -1) rb_sys_fail(0);
9560#else
9561 if (fstat(fd, &st) < 0) rb_sys_fail(0);
9562#endif
9563 rb_update_max_fd(fd);
9564#if defined(HAVE_FCNTL) && defined(F_GETFL)
9565 ofmode = rb_io_oflags_fmode(oflags);
9566 if (NIL_P(vmode)) {
9567 fmode = ofmode;
9568 }
9569 else if ((~ofmode & fmode) & FMODE_READWRITE) {
9570 VALUE error = INT2FIX(EINVAL);
9572 }
9573#endif
9574 VALUE path = Qnil;
9575
9576 if (!NIL_P(opt)) {
9577 if (rb_hash_aref(opt, sym_autoclose) == Qfalse) {
9578 fmode |= FMODE_EXTERNAL;
9579 }
9580
9581 path = rb_hash_aref(opt, RB_ID2SYM(idPath));
9582 if (!NIL_P(path)) {
9583 StringValue(path);
9584 path = rb_str_new_frozen(path);
9585 }
9586 }
9587
9588 MakeOpenFile(io, fp);
9589 fp->self = io;
9590 fp->fd = fd;
9591 fp->mode = fmode;
9592 fp->encs = convconfig;
9593 fp->pathv = path;
9594 fp->timeout = Qnil;
9595 ccan_list_head_init(&fp->blocking_operations);
9596 fp->closing_ec = NULL;
9597 fp->wakeup_mutex = Qnil;
9598 fp->fork_generation = GET_VM()->fork_gen;
9599 clear_codeconv(fp);
9600 io_check_tty(fp);
9601 if (fileno(stdin) == fd)
9602 fp->stdio_file = stdin;
9603 else if (fileno(stdout) == fd)
9604 fp->stdio_file = stdout;
9605 else if (fileno(stderr) == fd)
9606 fp->stdio_file = stderr;
9607
9608 if (fmode & FMODE_SETENC_BY_BOM) io_set_encoding_by_bom(io);
9609 return io;
9610}
9611
9612/*
9613 * call-seq:
9614 * set_encoding_by_bom -> encoding or nil
9615 *
9616 * If the stream begins with a BOM
9617 * ({byte order marker}[https://en.wikipedia.org/wiki/Byte_order_mark]),
9618 * consumes the BOM and sets the external encoding accordingly;
9619 * returns the result encoding if found, or +nil+ otherwise:
9620 *
9621 * File.write('t.tmp', "\u{FEFF}abc")
9622 * io = File.open('t.tmp', 'rb')
9623 * io.set_encoding_by_bom # => #<Encoding:UTF-8>
9624 * io.close
9625 *
9626 * File.write('t.tmp', 'abc')
9627 * io = File.open('t.tmp', 'rb')
9628 * io.set_encoding_by_bom # => nil
9629 * io.close
9630 *
9631 * Raises an exception if the stream is not binmode
9632 * or its encoding has already been set.
9633 *
9634 */
9635
9636static VALUE
9637rb_io_set_encoding_by_bom(VALUE io)
9638{
9639 rb_io_t *fptr;
9640
9641 GetOpenFile(io, fptr);
9642 if (!(fptr->mode & FMODE_BINMODE)) {
9643 rb_raise(rb_eArgError, "ASCII incompatible encoding needs binmode");
9644 }
9645 if (fptr->encs.enc2) {
9646 rb_raise(rb_eArgError, "encoding conversion is set");
9647 }
9648 else if (fptr->encs.enc && fptr->encs.enc != rb_ascii8bit_encoding()) {
9649 rb_raise(rb_eArgError, "encoding is set to %s already",
9650 rb_enc_name(fptr->encs.enc));
9651 }
9652 if (!io_set_encoding_by_bom(io)) return Qnil;
9653 return rb_enc_from_encoding(fptr->encs.enc);
9654}
9655
9656/*
9657 * call-seq:
9658 * File.new(path, mode = 'r', perm = 0666, **opts) -> file
9659 *
9660 * Opens the file at the given +path+ according to the given +mode+;
9661 * creates and returns a new File object for that file.
9662 *
9663 * The new File object is buffered mode (or non-sync mode), unless
9664 * +filename+ is a tty.
9665 * See IO#flush, IO#fsync, IO#fdatasync, and IO#sync=.
9666 *
9667 * Argument +path+ must be a valid file path:
9668 *
9669 * f = File.new('/etc/fstab')
9670 * f.close
9671 * f = File.new('t.txt')
9672 * f.close
9673 *
9674 * Optional argument +mode+ (defaults to 'r') must specify a valid mode;
9675 * see {Access Modes}[rdoc-ref:File@Access+Modes]:
9676 *
9677 * f = File.new('t.tmp', 'w')
9678 * f.close
9679 * f = File.new('t.tmp', File::RDONLY)
9680 * f.close
9681 *
9682 * Optional argument +perm+ (defaults to 0666) must specify valid permissions
9683 * see {File Permissions}[rdoc-ref:File@File+Permissions]:
9684 *
9685 * f = File.new('t.tmp', File::CREAT, 0644)
9686 * f.close
9687 * f = File.new('t.tmp', File::CREAT, 0444)
9688 * f.close
9689 *
9690 * Optional keyword arguments +opts+ specify:
9691 *
9692 * - {Open Options}[rdoc-ref:IO@Open+Options].
9693 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
9694 *
9695 */
9696
9697static VALUE
9698rb_file_initialize(int argc, VALUE *argv, VALUE io)
9699{
9700 if (RFILE(io)->fptr) {
9701 rb_raise(rb_eRuntimeError, "reinitializing File");
9702 }
9703 VALUE fname, vmode, vperm, opt;
9704 int posargc = rb_scan_args(argc, argv, "12:", &fname, &vmode, &vperm, &opt);
9705 if (posargc < 3) { /* perm is File only */
9706 VALUE fd = rb_check_to_int(fname);
9707
9708 if (!NIL_P(fd)) {
9709 return io_initialize(io, fd, vmode, opt);
9710 }
9711 }
9712 return rb_open_file(io, fname, vmode, vperm, opt);
9713}
9714
9715/* :nodoc: */
9716static VALUE
9717rb_io_s_new(int argc, VALUE *argv, VALUE klass)
9718{
9719 if (rb_block_given_p()) {
9720 VALUE cname = rb_obj_as_string(klass);
9721
9722 rb_warn("%"PRIsVALUE"::new() does not take block; use %"PRIsVALUE"::open() instead",
9723 cname, cname);
9724 }
9725 return rb_class_new_instance_kw(argc, argv, klass, RB_PASS_CALLED_KEYWORDS);
9726}
9727
9728
9729/*
9730 * call-seq:
9731 * IO.for_fd(fd, mode = 'r', **opts) -> io
9732 *
9733 * Synonym for IO.new.
9734 *
9735 */
9736
9737static VALUE
9738rb_io_s_for_fd(int argc, VALUE *argv, VALUE klass)
9739{
9740 VALUE io = rb_obj_alloc(klass);
9741 rb_io_initialize(argc, argv, io);
9742 return io;
9743}
9744
9745/*
9746 * call-seq:
9747 * ios.autoclose? -> true or false
9748 *
9749 * Returns +true+ if the underlying file descriptor of _ios_ will be
9750 * closed at its finalization or at calling #close, otherwise +false+.
9751 */
9752
9753static VALUE
9754rb_io_autoclose_p(VALUE io)
9755{
9756 rb_io_t *fptr = RFILE(io)->fptr;
9757 rb_io_check_closed(fptr);
9758 return RBOOL(!(fptr->mode & FMODE_EXTERNAL));
9759}
9760
9761/*
9762 * call-seq:
9763 * io.autoclose = bool -> true or false
9764 *
9765 * Sets auto-close flag.
9766 *
9767 * f = File.open(File::NULL)
9768 * IO.for_fd(f.fileno).close
9769 * f.gets # raises Errno::EBADF
9770 *
9771 * f = File.open(File::NULL)
9772 * g = IO.for_fd(f.fileno)
9773 * g.autoclose = false
9774 * g.close
9775 * f.gets # won't cause Errno::EBADF
9776 */
9777
9778static VALUE
9779rb_io_set_autoclose(VALUE io, VALUE autoclose)
9780{
9781 rb_io_t *fptr;
9782 GetOpenFile(io, fptr);
9783 if (!RTEST(autoclose))
9784 fptr->mode |= FMODE_EXTERNAL;
9785 else
9786 fptr->mode &= ~FMODE_EXTERNAL;
9787 return autoclose;
9788}
9789
9790static VALUE
9791io_wait_event(VALUE io, int event, VALUE timeout, int return_io)
9792{
9793 VALUE result = rb_io_wait(io, RB_INT2NUM(event), timeout);
9794
9795 if (!RB_TEST(result)) {
9796 return Qnil;
9797 }
9798
9799 int mask = RB_NUM2INT(result);
9800
9801 if (mask & event) {
9802 if (return_io)
9803 return io;
9804 else
9805 return result;
9806 }
9807 else {
9808 return Qfalse;
9809 }
9810}
9811
9812/*
9813 * call-seq:
9814 * io.wait_readable -> truthy or falsy
9815 * io.wait_readable(timeout) -> truthy or falsy
9816 *
9817 * Waits until IO is readable and returns a truthy value, or a falsy
9818 * value when times out. Returns a truthy value immediately when
9819 * buffered data is available.
9820 */
9821
9822static VALUE
9823io_wait_readable(int argc, VALUE *argv, VALUE io)
9824{
9825 rb_io_t *fptr;
9826
9827 RB_IO_POINTER(io, fptr);
9829
9830 if (rb_io_read_pending(fptr)) return Qtrue;
9831
9832 rb_check_arity(argc, 0, 1);
9833 VALUE timeout = (argc == 1 ? argv[0] : Qnil);
9834
9835 return io_wait_event(io, RUBY_IO_READABLE, timeout, 1);
9836}
9837
9838/*
9839 * call-seq:
9840 * io.wait_writable -> truthy or falsy
9841 * io.wait_writable(timeout) -> truthy or falsy
9842 *
9843 * Waits until IO is writable and returns a truthy value or a falsy
9844 * value when times out.
9845 */
9846static VALUE
9847io_wait_writable(int argc, VALUE *argv, VALUE io)
9848{
9849 rb_io_t *fptr;
9850
9851 RB_IO_POINTER(io, fptr);
9853
9854 rb_check_arity(argc, 0, 1);
9855 VALUE timeout = (argc == 1 ? argv[0] : Qnil);
9856
9857 return io_wait_event(io, RUBY_IO_WRITABLE, timeout, 1);
9858}
9859
9860/*
9861 * call-seq:
9862 * io.wait_priority -> truthy or falsy
9863 * io.wait_priority(timeout) -> truthy or falsy
9864 *
9865 * Waits until IO is priority and returns a truthy value or a falsy
9866 * value when times out. Priority data is sent and received using
9867 * the Socket::MSG_OOB flag and is typically limited to streams.
9868 */
9869static VALUE
9870io_wait_priority(int argc, VALUE *argv, VALUE io)
9871{
9872 rb_io_t *fptr = NULL;
9873
9874 RB_IO_POINTER(io, fptr);
9876
9877 if (rb_io_read_pending(fptr)) return Qtrue;
9878
9879 rb_check_arity(argc, 0, 1);
9880 VALUE timeout = argc == 1 ? argv[0] : Qnil;
9881
9882 return io_wait_event(io, RUBY_IO_PRIORITY, timeout, 1);
9883}
9884
9885static int
9886wait_mode_sym(VALUE mode)
9887{
9888 if (mode == ID2SYM(rb_intern("r"))) {
9889 return RB_WAITFD_IN;
9890 }
9891 if (mode == ID2SYM(rb_intern("read"))) {
9892 return RB_WAITFD_IN;
9893 }
9894 if (mode == ID2SYM(rb_intern("readable"))) {
9895 return RB_WAITFD_IN;
9896 }
9897 if (mode == ID2SYM(rb_intern("w"))) {
9898 return RB_WAITFD_OUT;
9899 }
9900 if (mode == ID2SYM(rb_intern("write"))) {
9901 return RB_WAITFD_OUT;
9902 }
9903 if (mode == ID2SYM(rb_intern("writable"))) {
9904 return RB_WAITFD_OUT;
9905 }
9906 if (mode == ID2SYM(rb_intern("rw"))) {
9907 return RB_WAITFD_IN|RB_WAITFD_OUT;
9908 }
9909 if (mode == ID2SYM(rb_intern("read_write"))) {
9910 return RB_WAITFD_IN|RB_WAITFD_OUT;
9911 }
9912 if (mode == ID2SYM(rb_intern("readable_writable"))) {
9913 return RB_WAITFD_IN|RB_WAITFD_OUT;
9914 }
9915
9916 rb_raise(rb_eArgError, "unsupported mode: %"PRIsVALUE, mode);
9917}
9918
9919static inline enum rb_io_event
9920io_event_from_value(VALUE value)
9921{
9922 int events = RB_NUM2INT(value);
9923
9924 if (events <= 0) rb_raise(rb_eArgError, "Events must be positive integer!");
9925
9926 return events;
9927}
9928
9929/*
9930 * call-seq:
9931 * io.wait(events, timeout) -> event mask, false or nil
9932 * io.wait(*event_symbols[, timeout]) -> self, true, or false
9933 *
9934 * Waits until the IO becomes ready for the specified events and returns the
9935 * subset of events that become ready, or a falsy value when times out.
9936 *
9937 * The events can be a bit mask of +IO::READABLE+, +IO::WRITABLE+ or
9938 * +IO::PRIORITY+.
9939 *
9940 * Returns an event mask (truthy value) immediately when buffered data is
9941 * available.
9942 *
9943 * The second form: if one or more event symbols (+:read+, +:write+, or
9944 * +:read_write+) are passed, the event mask is the bit OR of the bitmask
9945 * corresponding to those symbols. In this form, +timeout+ is optional, the
9946 * order of the arguments is arbitrary, and returns +io+ if any of the
9947 * events is ready.
9948 */
9949
9950static VALUE
9951io_wait(int argc, VALUE *argv, VALUE io)
9952{
9953 VALUE timeout = Qundef;
9954 enum rb_io_event events = 0;
9955 int return_io = 0;
9956
9957 if (argc != 2 || (RB_SYMBOL_P(argv[0]) || RB_SYMBOL_P(argv[1]))) {
9958 // We'd prefer to return the actual mask, but this form would return the io itself:
9959 return_io = 1;
9960
9961 // Slow/messy path:
9962 for (int i = 0; i < argc; i += 1) {
9963 if (RB_SYMBOL_P(argv[i])) {
9964 events |= wait_mode_sym(argv[i]);
9965 }
9966 else if (UNDEF_P(timeout)) {
9967 rb_time_interval(timeout = argv[i]);
9968 }
9969 else {
9970 rb_raise(rb_eArgError, "timeout given more than once");
9971 }
9972 }
9973
9974 if (UNDEF_P(timeout)) timeout = Qnil;
9975
9976 if (events == 0) {
9977 events = RUBY_IO_READABLE;
9978 }
9979 }
9980 else /* argc == 2 and neither are symbols */ {
9981 // This is the fast path:
9982 events = io_event_from_value(argv[0]);
9983 timeout = argv[1];
9984 }
9985
9986 if (events & RUBY_IO_READABLE) {
9987 rb_io_t *fptr = NULL;
9988 RB_IO_POINTER(io, fptr);
9989
9990 if (rb_io_read_pending(fptr)) {
9991 // This was the original behaviour:
9992 if (return_io) return Qtrue;
9993 // New behaviour always returns an event mask:
9994 else return RB_INT2NUM(RUBY_IO_READABLE);
9995 }
9996 }
9997
9998 return io_wait_event(io, events, timeout, return_io);
9999}
10000
10001static void
10002argf_mark_and_move(void *ptr)
10003{
10004 struct argf *p = ptr;
10005 rb_gc_mark_and_move(&p->filename);
10006 rb_gc_mark_and_move(&p->current_file);
10007 rb_gc_mark_and_move(&p->argv);
10008 rb_gc_mark_and_move(&p->inplace);
10009 rb_gc_mark_and_move(&p->encs.ecopts);
10010}
10011
10012static size_t
10013argf_memsize(const void *ptr)
10014{
10015 const struct argf *p = ptr;
10016 size_t size = sizeof(*p);
10017 return size;
10018}
10019
10020static const rb_data_type_t argf_type = {
10021 "ARGF",
10022 {argf_mark_and_move, RUBY_TYPED_DEFAULT_FREE, argf_memsize, argf_mark_and_move},
10023 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
10024};
10025
10026static inline void
10027argf_init(struct argf *p, VALUE v)
10028{
10029 p->filename = Qnil;
10030 p->current_file = Qnil;
10031 p->lineno = 0;
10032 p->argv = v;
10033}
10034
10035static VALUE
10036argf_alloc(VALUE klass)
10037{
10038 struct argf *p;
10039 VALUE argf = TypedData_Make_Struct(klass, struct argf, &argf_type, p);
10040
10041 argf_init(p, Qnil);
10042 return argf;
10043}
10044
10045#undef rb_argv
10046
10047/* :nodoc: */
10048static VALUE
10049argf_initialize(VALUE argf, VALUE argv)
10050{
10051 memset(&ARGF, 0, sizeof(ARGF));
10052 argf_init(&ARGF, argv);
10053
10054 return argf;
10055}
10056
10057/* :nodoc: */
10058static VALUE
10059argf_initialize_copy(VALUE argf, VALUE orig)
10060{
10061 if (!OBJ_INIT_COPY(argf, orig)) return argf;
10062 ARGF = argf_of(orig);
10063 ARGF.argv = rb_obj_dup(ARGF.argv);
10064 return argf;
10065}
10066
10067/*
10068 * call-seq:
10069 * ARGF.lineno = integer -> integer
10070 *
10071 * Sets the line number of ARGF as a whole to the given Integer.
10072 *
10073 * ARGF sets the line number automatically as you read data, so normally
10074 * you will not need to set it explicitly. To access the current line number
10075 * use ARGF.lineno.
10076 *
10077 * For example:
10078 *
10079 * ARGF.lineno #=> 0
10080 * ARGF.readline #=> "This is line 1\n"
10081 * ARGF.lineno #=> 1
10082 * ARGF.lineno = 0 #=> 0
10083 * ARGF.lineno #=> 0
10084 */
10085static VALUE
10086argf_set_lineno(VALUE argf, VALUE val)
10087{
10088 ARGF.lineno = NUM2INT(val);
10089 ARGF.last_lineno = ARGF.lineno;
10090 return val;
10091}
10092
10093/*
10094 * call-seq:
10095 * ARGF.lineno -> integer
10096 *
10097 * Returns the current line number of ARGF as a whole. This value
10098 * can be set manually with ARGF.lineno=.
10099 *
10100 * For example:
10101 *
10102 * ARGF.lineno #=> 0
10103 * ARGF.readline #=> "This is line 1\n"
10104 * ARGF.lineno #=> 1
10105 */
10106static VALUE
10107argf_lineno(VALUE argf)
10108{
10109 return INT2FIX(ARGF.lineno);
10110}
10111
10112static VALUE
10113argf_forward(int argc, VALUE *argv, VALUE argf)
10114{
10115 return forward_current(rb_frame_this_func(), argc, argv);
10116}
10117
10118#define next_argv() argf_next_argv(argf)
10119#define ARGF_GENERIC_INPUT_P() \
10120 (ARGF.current_file == rb_stdin && !RB_TYPE_P(ARGF.current_file, T_FILE))
10121#define ARGF_FORWARD(argc, argv) do {\
10122 if (ARGF_GENERIC_INPUT_P())\
10123 return argf_forward((argc), (argv), argf);\
10124} while (0)
10125#define NEXT_ARGF_FORWARD(argc, argv) do {\
10126 if (!next_argv()) return Qnil;\
10127 ARGF_FORWARD((argc), (argv));\
10128} while (0)
10129
10130static void
10131argf_close(VALUE argf)
10132{
10133 VALUE file = ARGF.current_file;
10134 if (file == rb_stdin) return;
10135 if (RB_TYPE_P(file, T_FILE)) {
10136 rb_io_set_write_io(file, Qnil);
10137 }
10138 io_close(file);
10139 ARGF.init_p = -1;
10140}
10141
10142static int
10143argf_next_argv(VALUE argf)
10144{
10145 char *fn;
10146 rb_io_t *fptr;
10147 int stdout_binmode = 0;
10148 enum rb_io_mode fmode;
10149
10150 VALUE r_stdout = rb_ractor_stdout();
10151
10152 if (RB_TYPE_P(r_stdout, T_FILE)) {
10153 GetOpenFile(r_stdout, fptr);
10154 if (fptr->mode & FMODE_BINMODE)
10155 stdout_binmode = 1;
10156 }
10157
10158 if (ARGF.init_p == 0) {
10159 if (!NIL_P(ARGF.argv) && RARRAY_LEN(ARGF.argv) > 0) {
10160 ARGF.next_p = 1;
10161 }
10162 else {
10163 ARGF.next_p = -1;
10164 }
10165 ARGF.init_p = 1;
10166 }
10167 else {
10168 if (NIL_P(ARGF.argv)) {
10169 ARGF.next_p = -1;
10170 }
10171 else if (ARGF.next_p == -1 && RARRAY_LEN(ARGF.argv) > 0) {
10172 ARGF.next_p = 1;
10173 }
10174 }
10175
10176 if (ARGF.next_p == 1) {
10177 if (ARGF.init_p == 1) argf_close(argf);
10178 retry:
10179 if (RARRAY_LEN(ARGF.argv) > 0) {
10180 VALUE filename = rb_ary_shift(ARGF.argv);
10181 FilePathValue(filename);
10182 ARGF.filename = filename;
10183 filename = rb_str_encode_ospath(filename);
10184 fn = StringValueCStr(filename);
10185 if (RSTRING_LEN(filename) == 1 && fn[0] == '-') {
10186 ARGF.current_file = rb_stdin;
10187 if (ARGF.inplace) {
10188 rb_warn("Can't do inplace edit for stdio; skipping");
10189 goto retry;
10190 }
10191 }
10192 else {
10193 VALUE write_io = Qnil;
10194 int fr = rb_sysopen(filename, O_RDONLY, 0);
10195
10196 if (ARGF.inplace) {
10197 struct stat st;
10198#ifndef NO_SAFE_RENAME
10199 struct stat st2;
10200#endif
10201 VALUE str;
10202 int fw;
10203
10204 if (RB_TYPE_P(r_stdout, T_FILE) && r_stdout != orig_stdout) {
10205 rb_io_close(r_stdout);
10206 }
10207 fstat(fr, &st);
10208 str = filename;
10209 if (!NIL_P(ARGF.inplace)) {
10210 VALUE suffix = ARGF.inplace;
10211 str = rb_str_dup(str);
10212 if (NIL_P(rb_str_cat_conv_enc_opts(str, RSTRING_LEN(str),
10213 RSTRING_PTR(suffix), RSTRING_LEN(suffix),
10214 rb_enc_get(suffix), 0, Qnil))) {
10215 rb_str_append(str, suffix);
10216 }
10217#ifdef NO_SAFE_RENAME
10218 (void)close(fr);
10219 (void)unlink(RSTRING_PTR(str));
10220 if (rename(fn, RSTRING_PTR(str)) < 0) {
10221 rb_warn("Can't rename %"PRIsVALUE" to %"PRIsVALUE": %s, skipping file",
10222 filename, str, strerror(errno));
10223 goto retry;
10224 }
10225 fr = rb_sysopen(str, O_RDONLY, 0);
10226#else
10227 if (rename(fn, RSTRING_PTR(str)) < 0) {
10228 rb_warn("Can't rename %"PRIsVALUE" to %"PRIsVALUE": %s, skipping file",
10229 filename, str, strerror(errno));
10230 close(fr);
10231 goto retry;
10232 }
10233#endif
10234 }
10235 else {
10236#ifdef NO_SAFE_RENAME
10237 rb_fatal("Can't do inplace edit without backup");
10238#else
10239 if (unlink(fn) < 0) {
10240 rb_warn("Can't remove %"PRIsVALUE": %s, skipping file",
10241 filename, strerror(errno));
10242 close(fr);
10243 goto retry;
10244 }
10245#endif
10246 }
10247 fw = rb_sysopen(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666);
10248#ifndef NO_SAFE_RENAME
10249 fstat(fw, &st2);
10250#ifdef HAVE_FCHMOD
10251 fchmod(fw, st.st_mode);
10252#else
10253 chmod(fn, st.st_mode);
10254#endif
10255 if (st.st_uid!=st2.st_uid || st.st_gid!=st2.st_gid) {
10256 int err;
10257#ifdef HAVE_FCHOWN
10258 err = fchown(fw, st.st_uid, st.st_gid);
10259#else
10260 err = chown(fn, st.st_uid, st.st_gid);
10261#endif
10262 if (err && getuid() == 0 && st2.st_uid == 0) {
10263 const char *wkfn = RSTRING_PTR(filename);
10264 rb_warn("Can't set owner/group of %"PRIsVALUE" to same as %"PRIsVALUE": %s, skipping file",
10265 filename, str, strerror(errno));
10266 (void)close(fr);
10267 (void)close(fw);
10268 (void)unlink(wkfn);
10269 goto retry;
10270 }
10271 }
10272#endif
10273 write_io = prep_io(fw, FMODE_WRITABLE, rb_cFile, fn);
10274 rb_ractor_stdout_set(write_io);
10275 if (stdout_binmode) rb_io_binmode(rb_stdout);
10276 }
10277 fmode = FMODE_READABLE;
10278 if (!ARGF.binmode) {
10279 fmode |= DEFAULT_TEXTMODE;
10280 }
10281 ARGF.current_file = prep_io(fr, fmode, rb_cFile, fn);
10282 if (!NIL_P(write_io)) {
10283 rb_io_set_write_io(ARGF.current_file, write_io);
10284 }
10285 RB_GC_GUARD(filename);
10286 }
10287 if (ARGF.binmode) rb_io_ascii8bit_binmode(ARGF.current_file);
10288 GetOpenFile(ARGF.current_file, fptr);
10289 if (ARGF.encs.enc) {
10290 fptr->encs = ARGF.encs;
10291 clear_codeconv(fptr);
10292 }
10293 else {
10294 fptr->encs.ecflags &= ~ECONV_NEWLINE_DECORATOR_MASK;
10295 if (!ARGF.binmode) {
10297#ifdef TEXTMODE_NEWLINE_DECORATOR_ON_WRITE
10298 fptr->encs.ecflags |= TEXTMODE_NEWLINE_DECORATOR_ON_WRITE;
10299#endif
10300 }
10301 }
10302 ARGF.next_p = 0;
10303 }
10304 else {
10305 ARGF.next_p = 1;
10306 return FALSE;
10307 }
10308 }
10309 else if (ARGF.next_p == -1) {
10310 ARGF.current_file = rb_stdin;
10311 ARGF.filename = rb_str_new2("-");
10312 if (ARGF.inplace) {
10313 rb_warn("Can't do inplace edit for stdio");
10314 rb_ractor_stdout_set(orig_stdout);
10315 }
10316 }
10317 if (ARGF.init_p == -1) ARGF.init_p = 1;
10318 return TRUE;
10319}
10320
10321static VALUE
10322argf_getline(int argc, VALUE *argv, VALUE argf)
10323{
10324 VALUE line;
10325 long lineno = ARGF.lineno;
10326
10327 retry:
10328 if (!next_argv()) return Qnil;
10329 if (ARGF_GENERIC_INPUT_P()) {
10330 line = forward_current(idGets, argc, argv);
10331 }
10332 else {
10333 if (argc == 0 && rb_rs == rb_default_rs) {
10334 line = rb_io_gets(ARGF.current_file);
10335 }
10336 else {
10337 line = rb_io_getline(argc, argv, ARGF.current_file);
10338 }
10339 if (NIL_P(line) && ARGF.next_p != -1) {
10340 argf_close(argf);
10341 ARGF.next_p = 1;
10342 goto retry;
10343 }
10344 }
10345 if (!NIL_P(line)) {
10346 ARGF.lineno = ++lineno;
10347 ARGF.last_lineno = ARGF.lineno;
10348 }
10349 return line;
10350}
10351
10352static VALUE
10353argf_lineno_getter(ID id, VALUE *var)
10354{
10355 VALUE argf = *var;
10356 return INT2FIX(ARGF.last_lineno);
10357}
10358
10359static void
10360argf_lineno_setter(VALUE val, ID id, VALUE *var)
10361{
10362 VALUE argf = *var;
10363 int n = NUM2INT(val);
10364 ARGF.last_lineno = ARGF.lineno = n;
10365}
10366
10367void
10368rb_reset_argf_lineno(long n)
10369{
10370 ARGF.last_lineno = ARGF.lineno = n;
10371}
10372
10373static VALUE argf_gets(int, VALUE *, VALUE);
10374
10375/*
10376 * call-seq:
10377 * gets(sep=$/ [, getline_args]) -> string or nil
10378 * gets(limit [, getline_args]) -> string or nil
10379 * gets(sep, limit [, getline_args]) -> string or nil
10380 *
10381 * Returns (and assigns to <code>$_</code>) the next line from the list
10382 * of files in +ARGV+ (or <code>$*</code>), or from standard input if
10383 * no files are present on the command line. Returns +nil+ at end of
10384 * file. The optional argument specifies the record separator. The
10385 * separator is included with the contents of each record. A separator
10386 * of +nil+ reads the entire contents, and a zero-length separator
10387 * reads the input one paragraph at a time, where paragraphs are
10388 * divided by two consecutive newlines. If the first argument is an
10389 * integer, or optional second argument is given, the returning string
10390 * would not be longer than the given value in bytes. If multiple
10391 * filenames are present in +ARGV+, <code>gets(nil)</code> will read
10392 * the contents one file at a time.
10393 *
10394 * ARGV << "testfile"
10395 * print while gets
10396 *
10397 * <em>produces:</em>
10398 *
10399 * This is line one
10400 * This is line two
10401 * This is line three
10402 * And so on...
10403 *
10404 * The style of programming using <code>$_</code> as an implicit
10405 * parameter is gradually losing favor in the Ruby community.
10406 */
10407
10408static VALUE
10409rb_f_gets(int argc, VALUE *argv, VALUE recv)
10410{
10411 if (recv == argf) {
10412 return argf_gets(argc, argv, argf);
10413 }
10414 return forward(argf, idGets, argc, argv);
10415}
10416
10417/*
10418 * call-seq:
10419 * ARGF.gets(sep=$/ [, getline_args]) -> string or nil
10420 * ARGF.gets(limit [, getline_args]) -> string or nil
10421 * ARGF.gets(sep, limit [, getline_args]) -> string or nil
10422 *
10423 * Returns the next line from the current file in ARGF.
10424 *
10425 * By default lines are assumed to be separated by <code>$/</code>;
10426 * to use a different character as a separator, supply it as a String
10427 * for the _sep_ argument.
10428 *
10429 * The optional _limit_ argument specifies how many characters of each line
10430 * to return. By default all characters are returned.
10431 *
10432 * See IO.readlines for details about getline_args.
10433 *
10434 */
10435static VALUE
10436argf_gets(int argc, VALUE *argv, VALUE argf)
10437{
10438 VALUE line;
10439
10440 line = argf_getline(argc, argv, argf);
10441 rb_lastline_set(line);
10442
10443 return line;
10444}
10445
10446VALUE
10448{
10449 VALUE line;
10450
10451 if (rb_rs != rb_default_rs) {
10452 return rb_f_gets(0, 0, argf);
10453 }
10454
10455 retry:
10456 if (!next_argv()) return Qnil;
10457 line = rb_io_gets(ARGF.current_file);
10458 if (NIL_P(line) && ARGF.next_p != -1) {
10459 rb_io_close(ARGF.current_file);
10460 ARGF.next_p = 1;
10461 goto retry;
10462 }
10463 rb_lastline_set(line);
10464 if (!NIL_P(line)) {
10465 ARGF.lineno++;
10466 ARGF.last_lineno = ARGF.lineno;
10467 }
10468
10469 return line;
10470}
10471
10472static VALUE argf_readline(int, VALUE *, VALUE);
10473
10474/*
10475 * call-seq:
10476 * readline(sep = $/, chomp: false) -> string
10477 * readline(limit, chomp: false) -> string
10478 * readline(sep, limit, chomp: false) -> string
10479 *
10480 * Equivalent to method Kernel#gets, except that it raises an exception
10481 * if called at end-of-stream:
10482 *
10483 * $ cat t.txt | ruby -e "p readlines; readline"
10484 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10485 * in `readline': end of file reached (EOFError)
10486 *
10487 * Optional keyword argument +chomp+ specifies whether line separators
10488 * are to be omitted.
10489 */
10490
10491static VALUE
10492rb_f_readline(int argc, VALUE *argv, VALUE recv)
10493{
10494 if (recv == argf) {
10495 return argf_readline(argc, argv, argf);
10496 }
10497 return forward(argf, rb_intern("readline"), argc, argv);
10498}
10499
10500
10501/*
10502 * call-seq:
10503 * ARGF.readline(sep=$/) -> string
10504 * ARGF.readline(limit) -> string
10505 * ARGF.readline(sep, limit) -> string
10506 *
10507 * Returns the next line from the current file in ARGF.
10508 *
10509 * By default lines are assumed to be separated by <code>$/</code>;
10510 * to use a different character as a separator, supply it as a String
10511 * for the _sep_ argument.
10512 *
10513 * The optional _limit_ argument specifies how many characters of each line
10514 * to return. By default all characters are returned.
10515 *
10516 * An EOFError is raised at the end of the file.
10517 */
10518static VALUE
10519argf_readline(int argc, VALUE *argv, VALUE argf)
10520{
10521 VALUE line;
10522
10523 if (!next_argv()) rb_eof_error();
10524 ARGF_FORWARD(argc, argv);
10525 line = argf_gets(argc, argv, argf);
10526 if (NIL_P(line)) {
10527 rb_eof_error();
10528 }
10529
10530 return line;
10531}
10532
10533static VALUE argf_readlines(int, VALUE *, VALUE);
10534
10535/*
10536 * call-seq:
10537 * readlines(sep = $/, chomp: false, **enc_opts) -> array
10538 * readlines(limit, chomp: false, **enc_opts) -> array
10539 * readlines(sep, limit, chomp: false, **enc_opts) -> array
10540 *
10541 * Returns an array containing the lines returned by calling
10542 * Kernel#gets until the end-of-stream is reached;
10543 * (see {Line IO}[rdoc-ref:IO@Line+IO]).
10544 *
10545 * With only string argument +sep+ given,
10546 * returns the remaining lines as determined by line separator +sep+,
10547 * or +nil+ if none;
10548 * see {Line Separator}[rdoc-ref:IO@Line+Separator]:
10549 *
10550 * # Default separator.
10551 * $ cat t.txt | ruby -e "p readlines"
10552 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10553 *
10554 * # Specified separator.
10555 * $ cat t.txt | ruby -e "p readlines 'li'"
10556 * ["First li", "ne\nSecond li", "ne\n\nFourth li", "ne\nFifth li", "ne\n"]
10557 *
10558 * # Get-all separator.
10559 * $ cat t.txt | ruby -e "p readlines nil"
10560 * ["First line\nSecond line\n\nFourth line\nFifth line\n"]
10561 *
10562 * # Get-paragraph separator.
10563 * $ cat t.txt | ruby -e "p readlines ''"
10564 * ["First line\nSecond line\n\n", "Fourth line\nFifth line\n"]
10565 *
10566 * With only integer argument +limit+ given,
10567 * limits the number of bytes in the line;
10568 * see {Line Limit}[rdoc-ref:IO@Line+Limit]:
10569 *
10570 * $cat t.txt | ruby -e "p readlines 10"
10571 * ["First line", "\n", "Second lin", "e\n", "\n", "Fourth lin", "e\n", "Fifth line", "\n"]
10572 *
10573 * $cat t.txt | ruby -e "p readlines 11"
10574 * ["First line\n", "Second line", "\n", "\n", "Fourth line", "\n", "Fifth line\n"]
10575 *
10576 * $cat t.txt | ruby -e "p readlines 12"
10577 * ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
10578 *
10579 * With arguments +sep+ and +limit+ given,
10580 * combines the two behaviors
10581 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
10582 *
10583 * Optional keyword argument +chomp+ specifies whether line separators
10584 * are to be omitted:
10585 *
10586 * $ cat t.txt | ruby -e "p readlines(chomp: true)"
10587 * ["First line", "Second line", "", "Fourth line", "Fifth line"]
10588 *
10589 * Optional keyword arguments +enc_opts+ specify encoding options;
10590 * see {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
10591 *
10592 */
10593
10594static VALUE
10595rb_f_readlines(int argc, VALUE *argv, VALUE recv)
10596{
10597 if (recv == argf) {
10598 return argf_readlines(argc, argv, argf);
10599 }
10600 return forward(argf, rb_intern("readlines"), argc, argv);
10601}
10602
10603/*
10604 * call-seq:
10605 * ARGF.readlines(sep = $/, chomp: false) -> array
10606 * ARGF.readlines(limit, chomp: false) -> array
10607 * ARGF.readlines(sep, limit, chomp: false) -> array
10608 *
10609 * ARGF.to_a(sep = $/, chomp: false) -> array
10610 * ARGF.to_a(limit, chomp: false) -> array
10611 * ARGF.to_a(sep, limit, chomp: false) -> array
10612 *
10613 * Reads each file in ARGF in its entirety, returning an Array containing
10614 * lines from the files. Lines are assumed to be separated by _sep_.
10615 *
10616 * lines = ARGF.readlines
10617 * lines[0] #=> "This is line one\n"
10618 *
10619 * See +IO.readlines+ for a full description of all options.
10620 */
10621static VALUE
10622argf_readlines(int argc, VALUE *argv, VALUE argf)
10623{
10624 long lineno = ARGF.lineno;
10625 VALUE lines, ary;
10626
10627 ary = rb_ary_new();
10628 while (next_argv()) {
10629 if (ARGF_GENERIC_INPUT_P()) {
10630 lines = forward_current(rb_intern("readlines"), argc, argv);
10631 }
10632 else {
10633 lines = rb_io_readlines(argc, argv, ARGF.current_file);
10634 argf_close(argf);
10635 }
10636 ARGF.next_p = 1;
10637 rb_ary_concat(ary, lines);
10638 ARGF.lineno = lineno + RARRAY_LEN(ary);
10639 ARGF.last_lineno = ARGF.lineno;
10640 }
10641 ARGF.init_p = 0;
10642 return ary;
10643}
10644
10645/*
10646 * call-seq:
10647 * `command` -> string
10648 *
10649 * Returns the <tt>$stdout</tt> output from running +command+ in a subshell;
10650 * sets global variable <tt>$?</tt> to the process status.
10651 *
10652 * This method has potential security vulnerabilities if called with untrusted input;
10653 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
10654 *
10655 * Examples:
10656 *
10657 * $ `date` # => "Wed Apr 9 08:56:30 CDT 2003\n"
10658 * $ `echo oops && exit 99` # => "oops\n"
10659 * $ $? # => #<Process::Status: pid 17088 exit 99>
10660 * $ $?.exitstatus # => 99
10661 *
10662 * The built-in syntax <tt>%x{...}</tt> uses this method.
10663 *
10664 */
10665
10666static VALUE
10667rb_f_backquote(VALUE obj, VALUE str)
10668{
10669 VALUE port;
10670 VALUE result;
10671 rb_io_t *fptr;
10672
10673 StringValue(str);
10674 rb_last_status_clear();
10675 port = pipe_open_s(str, "r", FMODE_READABLE|DEFAULT_TEXTMODE, NULL);
10676 if (NIL_P(port)) return rb_str_new(0,0);
10677
10678 GetOpenFile(port, fptr);
10679 result = read_all(fptr, remain_size(fptr), Qnil);
10680 rb_io_close(port);
10681 rb_io_fptr_cleanup_all(fptr);
10682 RB_GC_GUARD(port);
10683
10684 return result;
10685}
10686
10687#ifdef HAVE_SYS_SELECT_H
10688#include <sys/select.h>
10689#endif
10690
10691static VALUE
10692select_internal(VALUE read, VALUE write, VALUE except, struct timeval *tp, rb_fdset_t *fds)
10693{
10694 VALUE res, list;
10695 rb_fdset_t *rp, *wp, *ep;
10696 rb_io_t *fptr;
10697 long i;
10698 int max = 0, n;
10699 int pending = 0;
10700 struct timeval timerec;
10701
10702 if (!NIL_P(read)) {
10703 Check_Type(read, T_ARRAY);
10704 for (i=0; i<RARRAY_LEN(read); i++) {
10705 GetOpenFile(rb_io_get_io(RARRAY_AREF(read, i)), fptr);
10706 rb_fd_set(fptr->fd, &fds[0]);
10707 if (READ_DATA_PENDING(fptr) || READ_CHAR_PENDING(fptr)) { /* check for buffered data */
10708 pending++;
10709 rb_fd_set(fptr->fd, &fds[3]);
10710 }
10711 if (max < fptr->fd) max = fptr->fd;
10712 }
10713 if (pending) { /* no blocking if there's buffered data */
10714 timerec.tv_sec = timerec.tv_usec = 0;
10715 tp = &timerec;
10716 }
10717 rp = &fds[0];
10718 }
10719 else
10720 rp = 0;
10721
10722 if (!NIL_P(write)) {
10723 Check_Type(write, T_ARRAY);
10724 for (i=0; i<RARRAY_LEN(write); i++) {
10725 VALUE write_io = GetWriteIO(rb_io_get_io(RARRAY_AREF(write, i)));
10726 GetOpenFile(write_io, fptr);
10727 rb_fd_set(fptr->fd, &fds[1]);
10728 if (max < fptr->fd) max = fptr->fd;
10729 }
10730 wp = &fds[1];
10731 }
10732 else
10733 wp = 0;
10734
10735 if (!NIL_P(except)) {
10736 Check_Type(except, T_ARRAY);
10737 for (i=0; i<RARRAY_LEN(except); i++) {
10738 VALUE io = rb_io_get_io(RARRAY_AREF(except, i));
10739 VALUE write_io = GetWriteIO(io);
10740 GetOpenFile(io, fptr);
10741 rb_fd_set(fptr->fd, &fds[2]);
10742 if (max < fptr->fd) max = fptr->fd;
10743 if (io != write_io) {
10744 GetOpenFile(write_io, fptr);
10745 rb_fd_set(fptr->fd, &fds[2]);
10746 if (max < fptr->fd) max = fptr->fd;
10747 }
10748 }
10749 ep = &fds[2];
10750 }
10751 else {
10752 ep = 0;
10753 }
10754
10755 max++;
10756
10757 n = rb_thread_fd_select(max, rp, wp, ep, tp);
10758 if (n < 0) {
10759 rb_sys_fail(0);
10760 }
10761 if (!pending && n == 0) return Qnil; /* returns nil on timeout */
10762
10763 res = rb_ary_new2(3);
10764 rb_ary_push(res, rp?rb_ary_new():rb_ary_new2(0));
10765 rb_ary_push(res, wp?rb_ary_new():rb_ary_new2(0));
10766 rb_ary_push(res, ep?rb_ary_new():rb_ary_new2(0));
10767
10768 if (rp) {
10769 list = RARRAY_AREF(res, 0);
10770 for (i=0; i< RARRAY_LEN(read); i++) {
10771 VALUE obj = rb_ary_entry(read, i);
10772 VALUE io = rb_io_get_io(obj);
10773 GetOpenFile(io, fptr);
10774 if (rb_fd_isset(fptr->fd, &fds[0]) ||
10775 rb_fd_isset(fptr->fd, &fds[3])) {
10776 rb_ary_push(list, obj);
10777 }
10778 }
10779 }
10780
10781 if (wp) {
10782 list = RARRAY_AREF(res, 1);
10783 for (i=0; i< RARRAY_LEN(write); i++) {
10784 VALUE obj = rb_ary_entry(write, i);
10785 VALUE io = rb_io_get_io(obj);
10786 VALUE write_io = GetWriteIO(io);
10787 GetOpenFile(write_io, fptr);
10788 if (rb_fd_isset(fptr->fd, &fds[1])) {
10789 rb_ary_push(list, obj);
10790 }
10791 }
10792 }
10793
10794 if (ep) {
10795 list = RARRAY_AREF(res, 2);
10796 for (i=0; i< RARRAY_LEN(except); i++) {
10797 VALUE obj = rb_ary_entry(except, i);
10798 VALUE io = rb_io_get_io(obj);
10799 VALUE write_io = GetWriteIO(io);
10800 GetOpenFile(io, fptr);
10801 if (rb_fd_isset(fptr->fd, &fds[2])) {
10802 rb_ary_push(list, obj);
10803 }
10804 else if (io != write_io) {
10805 GetOpenFile(write_io, fptr);
10806 if (rb_fd_isset(fptr->fd, &fds[2])) {
10807 rb_ary_push(list, obj);
10808 }
10809 }
10810 }
10811 }
10812
10813 return res; /* returns an empty array on interrupt */
10814}
10815
10817 VALUE read, write, except;
10818 struct timeval *timeout;
10819 rb_fdset_t fdsets[4];
10820};
10821
10822static VALUE
10823select_call(VALUE arg)
10824{
10825 struct select_args *p = (struct select_args *)arg;
10826
10827 return select_internal(p->read, p->write, p->except, p->timeout, p->fdsets);
10828}
10829
10830static VALUE
10831select_end(VALUE arg)
10832{
10833 struct select_args *p = (struct select_args *)arg;
10834 int i;
10835
10836 for (i = 0; i < numberof(p->fdsets); ++i)
10837 rb_fd_term(&p->fdsets[i]);
10838 return Qnil;
10839}
10840
10841static VALUE sym_normal, sym_sequential, sym_random,
10842 sym_willneed, sym_dontneed, sym_noreuse;
10843
10844#ifdef HAVE_POSIX_FADVISE
10845struct io_advise_struct {
10846 int fd;
10847 int advice;
10848 rb_off_t offset;
10849 rb_off_t len;
10850};
10851
10852static VALUE
10853io_advise_internal(void *arg)
10854{
10855 struct io_advise_struct *ptr = arg;
10856 return posix_fadvise(ptr->fd, ptr->offset, ptr->len, ptr->advice);
10857}
10858
10859static VALUE
10860io_advise_sym_to_const(VALUE sym)
10861{
10862#ifdef POSIX_FADV_NORMAL
10863 if (sym == sym_normal)
10864 return INT2NUM(POSIX_FADV_NORMAL);
10865#endif
10866
10867#ifdef POSIX_FADV_RANDOM
10868 if (sym == sym_random)
10869 return INT2NUM(POSIX_FADV_RANDOM);
10870#endif
10871
10872#ifdef POSIX_FADV_SEQUENTIAL
10873 if (sym == sym_sequential)
10874 return INT2NUM(POSIX_FADV_SEQUENTIAL);
10875#endif
10876
10877#ifdef POSIX_FADV_WILLNEED
10878 if (sym == sym_willneed)
10879 return INT2NUM(POSIX_FADV_WILLNEED);
10880#endif
10881
10882#ifdef POSIX_FADV_DONTNEED
10883 if (sym == sym_dontneed)
10884 return INT2NUM(POSIX_FADV_DONTNEED);
10885#endif
10886
10887#ifdef POSIX_FADV_NOREUSE
10888 if (sym == sym_noreuse)
10889 return INT2NUM(POSIX_FADV_NOREUSE);
10890#endif
10891
10892 return Qnil;
10893}
10894
10895static VALUE
10896do_io_advise(rb_io_t *fptr, VALUE advice, rb_off_t offset, rb_off_t len)
10897{
10898 int rv;
10899 struct io_advise_struct ias;
10900 VALUE num_adv;
10901
10902 num_adv = io_advise_sym_to_const(advice);
10903
10904 /*
10905 * The platform doesn't support this hint. We don't raise exception, instead
10906 * silently ignore it. Because IO::advise is only hint.
10907 */
10908 if (NIL_P(num_adv))
10909 return Qnil;
10910
10911 ias.fd = fptr->fd;
10912 ias.advice = NUM2INT(num_adv);
10913 ias.offset = offset;
10914 ias.len = len;
10915
10916 rv = (int)rb_io_blocking_region(fptr, io_advise_internal, &ias);
10917 if (rv && rv != ENOSYS) {
10918 /* posix_fadvise(2) doesn't set errno. On success it returns 0; otherwise
10919 it returns the error code. */
10920 VALUE message = rb_sprintf("%"PRIsVALUE" "
10921 "(%"PRI_OFFT_PREFIX"d, "
10922 "%"PRI_OFFT_PREFIX"d, "
10923 "%"PRIsVALUE")",
10924 fptr->pathv, offset, len, advice);
10925 rb_syserr_fail_str(rv, message);
10926 }
10927
10928 return Qnil;
10929}
10930
10931#endif /* HAVE_POSIX_FADVISE */
10932
10933static void
10934advice_arg_check(VALUE advice)
10935{
10936 if (!SYMBOL_P(advice))
10937 rb_raise(rb_eTypeError, "advice must be a Symbol");
10938
10939 if (advice != sym_normal &&
10940 advice != sym_sequential &&
10941 advice != sym_random &&
10942 advice != sym_willneed &&
10943 advice != sym_dontneed &&
10944 advice != sym_noreuse) {
10945 rb_raise(rb_eNotImpError, "Unsupported advice: %+"PRIsVALUE, advice);
10946 }
10947}
10948
10949/*
10950 * call-seq:
10951 * advise(advice, offset = 0, len = 0) -> nil
10952 *
10953 * Invokes Posix system call
10954 * {posix_fadvise(2)}[https://linux.die.net/man/2/posix_fadvise],
10955 * which announces an intention to access data from the current file
10956 * in a particular manner.
10957 *
10958 * The arguments and results are platform-dependent.
10959 *
10960 * The relevant data is specified by:
10961 *
10962 * - +offset+: The offset of the first byte of data.
10963 * - +len+: The number of bytes to be accessed;
10964 * if +len+ is zero, or is larger than the number of bytes remaining,
10965 * all remaining bytes will be accessed.
10966 *
10967 * Argument +advice+ is one of the following symbols:
10968 *
10969 * - +:normal+: The application has no advice to give
10970 * about its access pattern for the specified data.
10971 * If no advice is given for an open file, this is the default assumption.
10972 * - +:sequential+: The application expects to access the specified data sequentially
10973 * (with lower offsets read before higher ones).
10974 * - +:random+: The specified data will be accessed in random order.
10975 * - +:noreuse+: The specified data will be accessed only once.
10976 * - +:willneed+: The specified data will be accessed in the near future.
10977 * - +:dontneed+: The specified data will not be accessed in the near future.
10978 *
10979 * Not implemented on all platforms.
10980 *
10981 */
10982static VALUE
10983rb_io_advise(int argc, VALUE *argv, VALUE io)
10984{
10985 VALUE advice, offset, len;
10986 rb_off_t off, l;
10987 rb_io_t *fptr;
10988
10989 rb_scan_args(argc, argv, "12", &advice, &offset, &len);
10990 advice_arg_check(advice);
10991
10992 io = GetWriteIO(io);
10993 GetOpenFile(io, fptr);
10994
10995 off = NIL_P(offset) ? 0 : NUM2OFFT(offset);
10996 l = NIL_P(len) ? 0 : NUM2OFFT(len);
10997
10998#ifdef HAVE_POSIX_FADVISE
10999 return do_io_advise(fptr, advice, off, l);
11000#else
11001 ((void)off, (void)l); /* Ignore all hint */
11002 return Qnil;
11003#endif
11004}
11005
11006static int
11007is_pos_inf(VALUE x)
11008{
11009 double f;
11010 if (!RB_FLOAT_TYPE_P(x))
11011 return 0;
11012 f = RFLOAT_VALUE(x);
11013 return isinf(f) && 0 < f;
11014}
11015
11016/*
11017 * call-seq:
11018 * IO.select(read_ios, write_ios = [], error_ios = [], timeout = nil) -> array or nil
11019 *
11020 * Invokes system call {select(2)}[https://linux.die.net/man/2/select],
11021 * which monitors multiple file descriptors,
11022 * waiting until one or more of the file descriptors
11023 * becomes ready for some class of I/O operation.
11024 *
11025 * Not implemented on all platforms.
11026 *
11027 * Each of the arguments +read_ios+, +write_ios+, and +error_ios+
11028 * is an array of IO objects.
11029 *
11030 * Argument +timeout+ is a numeric value (such as integer or float) timeout
11031 * interval in seconds.
11032 * +timeout+ can also be +nil+ or +Float::INFINITY+.
11033 * +nil+ and +Float::INFINITY+ means no timeout.
11034 *
11035 * The method monitors the \IO objects given in all three arrays,
11036 * waiting for some to be ready;
11037 * returns a 3-element array whose elements are:
11038 *
11039 * - An array of the objects in +read_ios+ that are ready for reading.
11040 * - An array of the objects in +write_ios+ that are ready for writing.
11041 * - An array of the objects in +error_ios+ have pending exceptions.
11042 *
11043 * If no object becomes ready within the given +timeout+, +nil+ is returned.
11044 *
11045 * \IO.select peeks the buffer of \IO objects for testing readability.
11046 * If the \IO buffer is not empty, \IO.select immediately notifies
11047 * readability. This "peek" only happens for \IO objects. It does not
11048 * happen for IO-like objects such as OpenSSL::SSL::SSLSocket.
11049 *
11050 * The best way to use \IO.select is invoking it after non-blocking
11051 * methods such as #read_nonblock, #write_nonblock, etc. The methods
11052 * raise an exception which is extended by IO::WaitReadable or
11053 * IO::WaitWritable. The modules notify how the caller should wait
11054 * with \IO.select. If IO::WaitReadable is raised, the caller should
11055 * wait for reading. If IO::WaitWritable is raised, the caller should
11056 * wait for writing.
11057 *
11058 * So, blocking read (#readpartial) can be emulated using
11059 * #read_nonblock and \IO.select as follows:
11060 *
11061 * begin
11062 * result = io_like.read_nonblock(maxlen)
11063 * rescue IO::WaitReadable
11064 * IO.select([io_like])
11065 * retry
11066 * rescue IO::WaitWritable
11067 * IO.select(nil, [io_like])
11068 * retry
11069 * end
11070 *
11071 * Especially, the combination of non-blocking methods and \IO.select is
11072 * preferred for IO like objects such as OpenSSL::SSL::SSLSocket. It
11073 * has #to_io method to return underlying IO object. IO.select calls
11074 * #to_io to obtain the file descriptor to wait.
11075 *
11076 * This means that readability notified by \IO.select doesn't mean
11077 * readability from OpenSSL::SSL::SSLSocket object.
11078 *
11079 * The most likely situation is that OpenSSL::SSL::SSLSocket buffers
11080 * some data. \IO.select doesn't see the buffer. So \IO.select can
11081 * block when OpenSSL::SSL::SSLSocket#readpartial doesn't block.
11082 *
11083 * However, several more complicated situations exist.
11084 *
11085 * SSL is a protocol which is sequence of records.
11086 * The record consists of multiple bytes.
11087 * So, the remote side of SSL sends a partial record, IO.select
11088 * notifies readability but OpenSSL::SSL::SSLSocket cannot decrypt a
11089 * byte and OpenSSL::SSL::SSLSocket#readpartial will block.
11090 *
11091 * Also, the remote side can request SSL renegotiation which forces
11092 * the local SSL engine to write some data.
11093 * This means OpenSSL::SSL::SSLSocket#readpartial may invoke #write
11094 * system call and it can block.
11095 * In such a situation, OpenSSL::SSL::SSLSocket#read_nonblock raises
11096 * IO::WaitWritable instead of blocking.
11097 * So, the caller should wait for ready for writability as above
11098 * example.
11099 *
11100 * The combination of non-blocking methods and \IO.select is also useful
11101 * for streams such as tty, pipe socket socket when multiple processes
11102 * read from a stream.
11103 *
11104 * Finally, Linux kernel developers don't guarantee that
11105 * readability of select(2) means readability of following read(2) even
11106 * for a single process;
11107 * see {select(2)}[https://linux.die.net/man/2/select]
11108 *
11109 * Invoking \IO.select before IO#readpartial works well as usual.
11110 * However it is not the best way to use \IO.select.
11111 *
11112 * The writability notified by select(2) doesn't show
11113 * how many bytes are writable.
11114 * IO#write method blocks until given whole string is written.
11115 * So, <tt>IO#write(two or more bytes)</tt> can block after
11116 * writability is notified by \IO.select. IO#write_nonblock is required
11117 * to avoid the blocking.
11118 *
11119 * Blocking write (#write) can be emulated using #write_nonblock and
11120 * IO.select as follows: IO::WaitReadable should also be rescued for
11121 * SSL renegotiation in OpenSSL::SSL::SSLSocket.
11122 *
11123 * while 0 < string.bytesize
11124 * begin
11125 * written = io_like.write_nonblock(string)
11126 * rescue IO::WaitReadable
11127 * IO.select([io_like])
11128 * retry
11129 * rescue IO::WaitWritable
11130 * IO.select(nil, [io_like])
11131 * retry
11132 * end
11133 * string = string.byteslice(written..-1)
11134 * end
11135 *
11136 * Example:
11137 *
11138 * rp, wp = IO.pipe
11139 * mesg = "ping "
11140 * 100.times {
11141 * # IO.select follows IO#read. Not the best way to use IO.select.
11142 * rs, ws, = IO.select([rp], [wp])
11143 * if r = rs[0]
11144 * ret = r.read(5)
11145 * print ret
11146 * case ret
11147 * when /ping/
11148 * mesg = "pong\n"
11149 * when /pong/
11150 * mesg = "ping "
11151 * end
11152 * end
11153 * if w = ws[0]
11154 * w.write(mesg)
11155 * end
11156 * }
11157 *
11158 * Output:
11159 *
11160 * ping pong
11161 * ping pong
11162 * ping pong
11163 * (snipped)
11164 * ping
11165 *
11166 */
11167
11168static VALUE
11169rb_f_select(int argc, VALUE *argv, VALUE obj)
11170{
11171 VALUE scheduler = rb_fiber_scheduler_current();
11172 if (scheduler != Qnil) {
11173 // It's optionally supported.
11174 VALUE result = rb_fiber_scheduler_io_selectv(scheduler, argc, argv);
11175 if (!UNDEF_P(result)) return result;
11176 }
11177
11178 VALUE timeout;
11179 struct select_args args;
11180 struct timeval timerec;
11181 int i;
11182
11183 rb_scan_args(argc, argv, "13", &args.read, &args.write, &args.except, &timeout);
11184 if (NIL_P(timeout) || is_pos_inf(timeout)) {
11185 args.timeout = 0;
11186 }
11187 else {
11188 timerec = rb_time_interval(timeout);
11189 args.timeout = &timerec;
11190 }
11191
11192 for (i = 0; i < numberof(args.fdsets); ++i)
11193 rb_fd_init(&args.fdsets[i]);
11194
11195 return rb_ensure(select_call, (VALUE)&args, select_end, (VALUE)&args);
11196}
11197
11198#ifdef IOCTL_REQ_TYPE
11199 typedef IOCTL_REQ_TYPE ioctl_req_t;
11200#else
11201 typedef int ioctl_req_t;
11202# define NUM2IOCTLREQ(num) ((int)NUM2LONG(num))
11203#endif
11204
11205#ifdef HAVE_IOCTL
11206struct ioctl_arg {
11207 int fd;
11208 ioctl_req_t cmd;
11209 long narg;
11210};
11211
11212static VALUE
11213nogvl_ioctl(void *ptr)
11214{
11215 struct ioctl_arg *arg = ptr;
11216
11217 return (VALUE)ioctl(arg->fd, arg->cmd, arg->narg);
11218}
11219
11220static int
11221do_ioctl(struct rb_io *io, ioctl_req_t cmd, long narg)
11222{
11223 int retval;
11224 struct ioctl_arg arg;
11225
11226 arg.fd = io->fd;
11227 arg.cmd = cmd;
11228 arg.narg = narg;
11229
11230 retval = (int)rb_io_blocking_region(io, nogvl_ioctl, &arg);
11231
11232 return retval;
11233}
11234#endif
11235
11236#define DEFAULT_IOCTL_NARG_LEN (256)
11237
11238#if defined(__linux__) && defined(_IOC_SIZE)
11239static long
11240linux_iocparm_len(ioctl_req_t cmd)
11241{
11242 long len;
11243
11244 if ((cmd & 0xFFFF0000) == 0) {
11245 /* legacy and unstructured ioctl number. */
11246 return DEFAULT_IOCTL_NARG_LEN;
11247 }
11248
11249 len = _IOC_SIZE(cmd);
11250
11251 /* paranoia check for silly drivers which don't keep ioctl convention */
11252 if (len < DEFAULT_IOCTL_NARG_LEN)
11253 len = DEFAULT_IOCTL_NARG_LEN;
11254
11255 return len;
11256}
11257#endif
11258
11259#ifdef HAVE_IOCTL
11260static long
11261ioctl_narg_len(ioctl_req_t cmd)
11262{
11263 long len;
11264
11265#ifdef IOCPARM_MASK
11266#ifndef IOCPARM_LEN
11267#define IOCPARM_LEN(x) (((x) >> 16) & IOCPARM_MASK)
11268#endif
11269#endif
11270#ifdef IOCPARM_LEN
11271 len = IOCPARM_LEN(cmd); /* on BSDish systems we're safe */
11272#elif defined(__linux__) && defined(_IOC_SIZE)
11273 len = linux_iocparm_len(cmd);
11274#else
11275 /* otherwise guess at what's safe */
11276 len = DEFAULT_IOCTL_NARG_LEN;
11277#endif
11278
11279 return len;
11280}
11281#endif
11282
11283#ifdef HAVE_FCNTL
11284#ifdef __linux__
11285typedef long fcntl_arg_t;
11286#else
11287/* posix */
11288typedef int fcntl_arg_t;
11289#endif
11290
11291static long
11292fcntl_narg_len(ioctl_req_t cmd)
11293{
11294 long len;
11295
11296 switch (cmd) {
11297#ifdef F_DUPFD
11298 case F_DUPFD:
11299 len = sizeof(fcntl_arg_t);
11300 break;
11301#endif
11302#ifdef F_DUP2FD /* bsd specific */
11303 case F_DUP2FD:
11304 len = sizeof(int);
11305 break;
11306#endif
11307#ifdef F_DUPFD_CLOEXEC /* linux specific */
11308 case F_DUPFD_CLOEXEC:
11309 len = sizeof(fcntl_arg_t);
11310 break;
11311#endif
11312#ifdef F_GETFD
11313 case F_GETFD:
11314 len = 1;
11315 break;
11316#endif
11317#ifdef F_SETFD
11318 case F_SETFD:
11319 len = sizeof(fcntl_arg_t);
11320 break;
11321#endif
11322#ifdef F_GETFL
11323 case F_GETFL:
11324 len = 1;
11325 break;
11326#endif
11327#ifdef F_SETFL
11328 case F_SETFL:
11329 len = sizeof(fcntl_arg_t);
11330 break;
11331#endif
11332#ifdef F_GETOWN
11333 case F_GETOWN:
11334 len = 1;
11335 break;
11336#endif
11337#ifdef F_SETOWN
11338 case F_SETOWN:
11339 len = sizeof(fcntl_arg_t);
11340 break;
11341#endif
11342#ifdef F_GETOWN_EX /* linux specific */
11343 case F_GETOWN_EX:
11344 len = sizeof(struct f_owner_ex);
11345 break;
11346#endif
11347#ifdef F_SETOWN_EX /* linux specific */
11348 case F_SETOWN_EX:
11349 len = sizeof(struct f_owner_ex);
11350 break;
11351#endif
11352#ifdef F_GETLK
11353 case F_GETLK:
11354 len = sizeof(struct flock);
11355 break;
11356#endif
11357#ifdef F_SETLK
11358 case F_SETLK:
11359 len = sizeof(struct flock);
11360 break;
11361#endif
11362#ifdef F_SETLKW
11363 case F_SETLKW:
11364 len = sizeof(struct flock);
11365 break;
11366#endif
11367#ifdef F_READAHEAD /* bsd specific */
11368 case F_READAHEAD:
11369 len = sizeof(int);
11370 break;
11371#endif
11372#ifdef F_RDAHEAD /* Darwin specific */
11373 case F_RDAHEAD:
11374 len = sizeof(int);
11375 break;
11376#endif
11377#ifdef F_GETSIG /* linux specific */
11378 case F_GETSIG:
11379 len = 1;
11380 break;
11381#endif
11382#ifdef F_SETSIG /* linux specific */
11383 case F_SETSIG:
11384 len = sizeof(fcntl_arg_t);
11385 break;
11386#endif
11387#ifdef F_GETLEASE /* linux specific */
11388 case F_GETLEASE:
11389 len = 1;
11390 break;
11391#endif
11392#ifdef F_SETLEASE /* linux specific */
11393 case F_SETLEASE:
11394 len = sizeof(fcntl_arg_t);
11395 break;
11396#endif
11397#ifdef F_NOTIFY /* linux specific */
11398 case F_NOTIFY:
11399 len = sizeof(fcntl_arg_t);
11400 break;
11401#endif
11402
11403 default:
11404 len = 256;
11405 break;
11406 }
11407
11408 return len;
11409}
11410#else /* HAVE_FCNTL */
11411static long
11412fcntl_narg_len(ioctl_req_t cmd)
11413{
11414 return 0;
11415}
11416#endif /* HAVE_FCNTL */
11417
11418#define NARG_SENTINEL 17
11419
11420static long
11421setup_narg(ioctl_req_t cmd, VALUE *argp, long (*narg_len)(ioctl_req_t))
11422{
11423 long narg = 0;
11424 VALUE arg = *argp;
11425
11426 if (!RTEST(arg)) {
11427 narg = 0;
11428 }
11429 else if (FIXNUM_P(arg)) {
11430 narg = FIX2LONG(arg);
11431 }
11432 else if (arg == Qtrue) {
11433 narg = 1;
11434 }
11435 else {
11436 VALUE tmp = rb_check_string_type(arg);
11437
11438 if (NIL_P(tmp)) {
11439 narg = NUM2LONG(arg);
11440 }
11441 else {
11442 char *ptr;
11443 long len, slen;
11444
11445 *argp = arg = tmp;
11446 len = narg_len(cmd);
11447 rb_str_modify(arg);
11448
11449 slen = RSTRING_LEN(arg);
11450 /* expand for data + sentinel. */
11451 if (slen < len+1) {
11452 rb_str_resize(arg, len+1);
11453 MEMZERO(RSTRING_PTR(arg)+slen, char, len-slen);
11454 slen = len+1;
11455 }
11456 /* a little sanity check here */
11457 ptr = RSTRING_PTR(arg);
11458 ptr[slen - 1] = NARG_SENTINEL;
11459 narg = (long)(SIGNED_VALUE)ptr;
11460 }
11461 }
11462
11463 return narg;
11464}
11465
11466static VALUE
11467finish_narg(int retval, VALUE arg, const rb_io_t *fptr)
11468{
11469 if (retval < 0) rb_sys_fail_path(fptr->pathv);
11470 if (RB_TYPE_P(arg, T_STRING)) {
11471 char *ptr;
11472 long slen;
11473 RSTRING_GETMEM(arg, ptr, slen);
11474 if (ptr[slen-1] != NARG_SENTINEL)
11475 rb_raise(rb_eArgError, "return value overflowed string");
11476 ptr[slen-1] = '\0';
11477 }
11478
11479 return INT2NUM(retval);
11480}
11481
11482#ifdef HAVE_IOCTL
11483static VALUE
11484rb_ioctl(VALUE io, VALUE req, VALUE arg)
11485{
11486 ioctl_req_t cmd = NUM2IOCTLREQ(req);
11487 rb_io_t *fptr;
11488 long narg;
11489 int retval;
11490
11491 narg = setup_narg(cmd, &arg, ioctl_narg_len);
11492 GetOpenFile(io, fptr);
11493 retval = do_ioctl(fptr, cmd, narg);
11494 return finish_narg(retval, arg, fptr);
11495}
11496
11497/*
11498 * call-seq:
11499 * ioctl(integer_cmd, argument) -> integer
11500 *
11501 * Invokes Posix system call {ioctl(2)}[https://linux.die.net/man/2/ioctl],
11502 * which issues a low-level command to an I/O device.
11503 *
11504 * Issues a low-level command to an I/O device.
11505 * The arguments and returned value are platform-dependent.
11506 * The effect of the call is platform-dependent.
11507 *
11508 * If argument +argument+ is an integer, it is passed directly;
11509 * if it is a string, it is interpreted as a binary sequence of bytes.
11510 *
11511 * Not implemented on all platforms.
11512 *
11513 */
11514
11515static VALUE
11516rb_io_ioctl(int argc, VALUE *argv, VALUE io)
11517{
11518 VALUE req, arg;
11519
11520 rb_scan_args(argc, argv, "11", &req, &arg);
11521 return rb_ioctl(io, req, arg);
11522}
11523#else
11524#define rb_io_ioctl rb_f_notimplement
11525#endif
11526
11527#ifdef HAVE_FCNTL
11528struct fcntl_arg {
11529 int fd;
11530 int cmd;
11531 long narg;
11532};
11533
11534static VALUE
11535nogvl_fcntl(void *ptr)
11536{
11537 struct fcntl_arg *arg = ptr;
11538
11539#if defined(F_DUPFD)
11540 if (arg->cmd == F_DUPFD)
11541 return (VALUE)rb_cloexec_fcntl_dupfd(arg->fd, (int)arg->narg);
11542#endif
11543 return (VALUE)fcntl(arg->fd, arg->cmd, arg->narg);
11544}
11545
11546static int
11547do_fcntl(struct rb_io *io, int cmd, long narg)
11548{
11549 int retval;
11550 struct fcntl_arg arg;
11551
11552 arg.fd = io->fd;
11553 arg.cmd = cmd;
11554 arg.narg = narg;
11555
11556 retval = (int)rb_io_blocking_region(io, nogvl_fcntl, &arg);
11557 if (retval != -1) {
11558 switch (cmd) {
11559#if defined(F_DUPFD)
11560 case F_DUPFD:
11561#endif
11562#if defined(F_DUPFD_CLOEXEC)
11563 case F_DUPFD_CLOEXEC:
11564#endif
11565 rb_update_max_fd(retval);
11566 }
11567 }
11568
11569 return retval;
11570}
11571
11572static VALUE
11573rb_fcntl(VALUE io, VALUE req, VALUE arg)
11574{
11575 int cmd = NUM2INT(req);
11576 rb_io_t *fptr;
11577 long narg;
11578 int retval;
11579
11580 narg = setup_narg(cmd, &arg, fcntl_narg_len);
11581 GetOpenFile(io, fptr);
11582 retval = do_fcntl(fptr, cmd, narg);
11583 return finish_narg(retval, arg, fptr);
11584}
11585
11586/*
11587 * call-seq:
11588 * fcntl(integer_cmd, argument) -> integer
11589 *
11590 * Invokes Posix system call {fcntl(2)}[https://linux.die.net/man/2/fcntl],
11591 * which provides a mechanism for issuing low-level commands to control or query
11592 * a file-oriented I/O stream. Arguments and results are platform
11593 * dependent.
11594 *
11595 * If +argument+ is a number, its value is passed directly;
11596 * if it is a string, it is interpreted as a binary sequence of bytes.
11597 * (Array#pack might be a useful way to build this string.)
11598 *
11599 * Not implemented on all platforms.
11600 *
11601 */
11602
11603static VALUE
11604rb_io_fcntl(int argc, VALUE *argv, VALUE io)
11605{
11606 VALUE req, arg;
11607
11608 rb_scan_args(argc, argv, "11", &req, &arg);
11609 return rb_fcntl(io, req, arg);
11610}
11611#else
11612#define rb_io_fcntl rb_f_notimplement
11613#endif
11614
11615#if defined(HAVE_SYSCALL) || defined(HAVE___SYSCALL)
11616/*
11617 * call-seq:
11618 * syscall(integer_callno, *arguments) -> integer
11619 *
11620 * Invokes Posix system call {syscall(2)}[https://linux.die.net/man/2/syscall],
11621 * which calls a specified function.
11622 *
11623 * Calls the operating system function identified by +integer_callno+;
11624 * returns the result of the function or raises SystemCallError if it failed.
11625 * The effect of the call is platform-dependent.
11626 * The arguments and returned value are platform-dependent.
11627 *
11628 * For each of +arguments+: if it is an integer, it is passed directly;
11629 * if it is a string, it is interpreted as a binary sequence of bytes.
11630 * There may be as many as nine such arguments.
11631 *
11632 * Arguments +integer_callno+ and +argument+, as well as the returned value,
11633 * are platform-dependent.
11634 *
11635 * Note: Method +syscall+ is essentially unsafe and unportable.
11636 * The DL (Fiddle) library is preferred for safer and a bit
11637 * more portable programming.
11638 *
11639 * Not implemented on all platforms.
11640 *
11641 */
11642
11643static VALUE
11644rb_f_syscall(int argc, VALUE *argv, VALUE _)
11645{
11646 VALUE arg[8];
11647#if SIZEOF_VOIDP == 8 && defined(HAVE___SYSCALL) && SIZEOF_INT != 8 /* mainly *BSD */
11648# define SYSCALL __syscall
11649# define NUM2SYSCALLID(x) NUM2LONG(x)
11650# define RETVAL2NUM(x) LONG2NUM(x)
11651# if SIZEOF_LONG == 8
11652 long num, retval = -1;
11653# elif SIZEOF_LONG_LONG == 8
11654 long long num, retval = -1;
11655# else
11656# error ---->> it is asserted that __syscall takes the first argument and returns retval in 64bit signed integer. <<----
11657# endif
11658#elif defined(__linux__)
11659# define SYSCALL syscall
11660# define NUM2SYSCALLID(x) NUM2LONG(x)
11661# define RETVAL2NUM(x) LONG2NUM(x)
11662 /*
11663 * Linux man page says, syscall(2) function prototype is below.
11664 *
11665 * int syscall(int number, ...);
11666 *
11667 * But, it's incorrect. Actual one takes and returned long. (see unistd.h)
11668 */
11669 long num, retval = -1;
11670#else
11671# define SYSCALL syscall
11672# define NUM2SYSCALLID(x) NUM2INT(x)
11673# define RETVAL2NUM(x) INT2NUM(x)
11674 int num, retval = -1;
11675#endif
11676 int i;
11677
11678 if (RTEST(ruby_verbose)) {
11680 "We plan to remove a syscall function at future release. DL(Fiddle) provides safer alternative.");
11681 }
11682
11683 if (argc == 0)
11684 rb_raise(rb_eArgError, "too few arguments for syscall");
11685 if (argc > numberof(arg))
11686 rb_raise(rb_eArgError, "too many arguments for syscall");
11687 num = NUM2SYSCALLID(argv[0]); ++argv;
11688 for (i = argc - 1; i--; ) {
11689 VALUE v = rb_check_string_type(argv[i]);
11690
11691 if (!NIL_P(v)) {
11692 StringValue(v);
11693 rb_str_modify(v);
11694 arg[i] = (VALUE)StringValueCStr(v);
11695 }
11696 else {
11697 arg[i] = (VALUE)NUM2LONG(argv[i]);
11698 }
11699 }
11700
11701 switch (argc) {
11702 case 1:
11703 retval = SYSCALL(num);
11704 break;
11705 case 2:
11706 retval = SYSCALL(num, arg[0]);
11707 break;
11708 case 3:
11709 retval = SYSCALL(num, arg[0],arg[1]);
11710 break;
11711 case 4:
11712 retval = SYSCALL(num, arg[0],arg[1],arg[2]);
11713 break;
11714 case 5:
11715 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3]);
11716 break;
11717 case 6:
11718 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4]);
11719 break;
11720 case 7:
11721 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5]);
11722 break;
11723 case 8:
11724 retval = SYSCALL(num, arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6]);
11725 break;
11726 }
11727
11728 if (retval == -1)
11729 rb_sys_fail(0);
11730 return RETVAL2NUM(retval);
11731#undef SYSCALL
11732#undef NUM2SYSCALLID
11733#undef RETVAL2NUM
11734}
11735#else
11736#define rb_f_syscall rb_f_notimplement
11737#endif
11738
11739static VALUE
11740io_new_instance(VALUE args)
11741{
11742 return rb_class_new_instance(2, (VALUE*)args+1, *(VALUE*)args);
11743}
11744
11745static rb_encoding *
11746find_encoding(VALUE v)
11747{
11748 rb_encoding *enc = rb_find_encoding(v);
11749 if (!enc) rb_warn("Unsupported encoding %"PRIsVALUE" ignored", v);
11750 return enc;
11751}
11752
11753static void
11754io_encoding_set(rb_io_t *fptr, VALUE v1, VALUE v2, VALUE opt)
11755{
11756 rb_encoding *enc, *enc2;
11757 int ecflags = fptr->encs.ecflags;
11758 VALUE ecopts, tmp;
11759
11760 if (!NIL_P(v2)) {
11761 enc2 = find_encoding(v1);
11762 tmp = rb_check_string_type(v2);
11763 if (!NIL_P(tmp)) {
11764 if (RSTRING_LEN(tmp) == 1 && RSTRING_PTR(tmp)[0] == '-') {
11765 /* Special case - "-" => no transcoding */
11766 enc = enc2;
11767 enc2 = NULL;
11768 }
11769 else
11770 enc = find_encoding(v2);
11771 if (enc == enc2) {
11772 /* Special case - "-" => no transcoding */
11773 enc2 = NULL;
11774 }
11775 }
11776 else {
11777 enc = find_encoding(v2);
11778 if (enc == enc2) {
11779 /* Special case - "-" => no transcoding */
11780 enc2 = NULL;
11781 }
11782 }
11783 if (enc2 == rb_ascii8bit_encoding()) {
11784 /* If external is ASCII-8BIT, no transcoding */
11785 enc = enc2;
11786 enc2 = NULL;
11787 }
11788 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11789 ecflags = rb_econv_prepare_options(opt, &ecopts, ecflags);
11790 }
11791 else {
11792 if (NIL_P(v1)) {
11793 /* Set to default encodings */
11794 rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
11795 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11796 ecopts = Qnil;
11797 }
11798 else {
11799 tmp = rb_check_string_type(v1);
11800 if (!NIL_P(tmp) && rb_enc_asciicompat(enc = rb_enc_get(tmp))) {
11801 parse_mode_enc(RSTRING_PTR(tmp), enc, &enc, &enc2, NULL);
11802 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11803 ecflags = rb_econv_prepare_options(opt, &ecopts, ecflags);
11804 }
11805 else {
11806 rb_io_ext_int_to_encs(find_encoding(v1), NULL, &enc, &enc2, 0);
11807 SET_UNIVERSAL_NEWLINE_DECORATOR_IF_ENC2(enc2, ecflags);
11808 ecopts = Qnil;
11809 }
11810 }
11811 }
11812 validate_enc_binmode(&fptr->mode, ecflags, enc, enc2);
11813 fptr->encs.enc = enc;
11814 fptr->encs.enc2 = enc2;
11815 fptr->encs.ecflags = ecflags;
11816 fptr->encs.ecopts = ecopts;
11817 clear_codeconv(fptr);
11818
11819}
11820
11822 rb_io_t *fptr;
11823 VALUE v1;
11824 VALUE v2;
11825 VALUE opt;
11826};
11827
11828static VALUE
11829io_encoding_set_v(VALUE v)
11830{
11831 struct io_encoding_set_args *arg = (struct io_encoding_set_args *)v;
11832 io_encoding_set(arg->fptr, arg->v1, arg->v2, arg->opt);
11833 return Qnil;
11834}
11835
11836static VALUE
11837pipe_pair_close(VALUE rw)
11838{
11839 VALUE *rwp = (VALUE *)rw;
11840 return rb_ensure(io_close, rwp[0], io_close, rwp[1]);
11841}
11842
11843/*
11844 * call-seq:
11845 * IO.pipe(**opts) -> [read_io, write_io]
11846 * IO.pipe(enc, **opts) -> [read_io, write_io]
11847 * IO.pipe(ext_enc, int_enc, **opts) -> [read_io, write_io]
11848 * IO.pipe(**opts) {|read_io, write_io| ...} -> object
11849 * IO.pipe(enc, **opts) {|read_io, write_io| ...} -> object
11850 * IO.pipe(ext_enc, int_enc, **opts) {|read_io, write_io| ...} -> object
11851 *
11852 * Creates a pair of pipe endpoints, +read_io+ and +write_io+,
11853 * connected to each other.
11854 *
11855 * If argument +enc_string+ is given, it must be a string containing one of:
11856 *
11857 * - The name of the encoding to be used as the external encoding.
11858 * - The colon-separated names of two encodings to be used as the external
11859 * and internal encodings.
11860 *
11861 * If argument +int_enc+ is given, it must be an Encoding object
11862 * or encoding name string that specifies the internal encoding to be used;
11863 * if argument +ext_enc+ is also given, it must be an Encoding object
11864 * or encoding name string that specifies the external encoding to be used.
11865 *
11866 * The string read from +read_io+ is tagged with the external encoding;
11867 * if an internal encoding is also specified, the string is converted
11868 * to, and tagged with, that encoding.
11869 *
11870 * If any encoding is specified,
11871 * optional hash arguments specify the conversion option.
11872 *
11873 * Optional keyword arguments +opts+ specify:
11874 *
11875 * - {Open Options}[rdoc-ref:IO@Open+Options].
11876 * - {Encoding Options}[rdoc-ref:encodings.rdoc@Encoding+Options].
11877 *
11878 * With no block given, returns the two endpoints in an array:
11879 *
11880 * IO.pipe # => [#<IO:fd 4>, #<IO:fd 5>]
11881 *
11882 * With a block given, calls the block with the two endpoints;
11883 * closes both endpoints and returns the value of the block:
11884 *
11885 * IO.pipe {|read_io, write_io| p read_io; p write_io }
11886 *
11887 * Output:
11888 *
11889 * #<IO:fd 6>
11890 * #<IO:fd 7>
11891 *
11892 * Not available on all platforms.
11893 *
11894 * In the example below, the two processes close the ends of the pipe
11895 * that they are not using. This is not just a cosmetic nicety. The
11896 * read end of a pipe will not generate an end of file condition if
11897 * there are any writers with the pipe still open. In the case of the
11898 * parent process, the <tt>rd.read</tt> will never return if it
11899 * does not first issue a <tt>wr.close</tt>:
11900 *
11901 * rd, wr = IO.pipe
11902 *
11903 * if fork
11904 * wr.close
11905 * puts "Parent got: <#{rd.read}>"
11906 * rd.close
11907 * Process.wait
11908 * else
11909 * rd.close
11910 * puts 'Sending message to parent'
11911 * wr.write "Hi Dad"
11912 * wr.close
11913 * end
11914 *
11915 * <em>produces:</em>
11916 *
11917 * Sending message to parent
11918 * Parent got: <Hi Dad>
11919 *
11920 */
11921
11922static VALUE
11923rb_io_s_pipe(int argc, VALUE *argv, VALUE klass)
11924{
11925 int pipes[2], state;
11926 VALUE r, w, args[3], v1, v2;
11927 VALUE opt;
11928 rb_io_t *fptr, *fptr2;
11929 struct io_encoding_set_args ies_args;
11930 enum rb_io_mode fmode = 0;
11931 VALUE ret;
11932
11933 argc = rb_scan_args(argc, argv, "02:", &v1, &v2, &opt);
11934 if (rb_pipe(pipes) < 0)
11935 rb_sys_fail(0);
11936
11937 args[0] = klass;
11938 args[1] = INT2NUM(pipes[0]);
11939 args[2] = INT2FIX(O_RDONLY);
11940 r = rb_protect(io_new_instance, (VALUE)args, &state);
11941 if (state) {
11942 close(pipes[0]);
11943 close(pipes[1]);
11944 rb_jump_tag(state);
11945 }
11946 GetOpenFile(r, fptr);
11947
11948 ies_args.fptr = fptr;
11949 ies_args.v1 = v1;
11950 ies_args.v2 = v2;
11951 ies_args.opt = opt;
11952 rb_protect(io_encoding_set_v, (VALUE)&ies_args, &state);
11953 if (state) {
11954 close(pipes[1]);
11955 io_close(r);
11956 rb_jump_tag(state);
11957 }
11958
11959 args[1] = INT2NUM(pipes[1]);
11960 args[2] = INT2FIX(O_WRONLY);
11961 w = rb_protect(io_new_instance, (VALUE)args, &state);
11962 if (state) {
11963 close(pipes[1]);
11964 if (!NIL_P(r)) rb_io_close(r);
11965 rb_jump_tag(state);
11966 }
11967 GetOpenFile(w, fptr2);
11968 rb_io_synchronized(fptr2);
11969
11970 extract_binmode(opt, &fmode);
11971
11972 if ((fmode & FMODE_BINMODE) && NIL_P(v1)) {
11975 }
11976
11977#if DEFAULT_TEXTMODE
11978 if ((fptr->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
11979 fptr->mode &= ~FMODE_TEXTMODE;
11980 setmode(fptr->fd, O_BINARY);
11981 }
11982#if RUBY_CRLF_ENVIRONMENT
11985 }
11986#endif
11987#endif
11988 fptr->mode |= fmode;
11989#if DEFAULT_TEXTMODE
11990 if ((fptr2->mode & FMODE_TEXTMODE) && (fmode & FMODE_BINMODE)) {
11991 fptr2->mode &= ~FMODE_TEXTMODE;
11992 setmode(fptr2->fd, O_BINARY);
11993 }
11994#endif
11995 fptr2->mode |= fmode;
11996
11997 ret = rb_assoc_new(r, w);
11998 if (rb_block_given_p()) {
11999 VALUE rw[2];
12000 rw[0] = r;
12001 rw[1] = w;
12002 return rb_ensure(rb_yield, ret, pipe_pair_close, (VALUE)rw);
12003 }
12004 return ret;
12005}
12006
12008 int argc;
12009 VALUE *argv;
12010 VALUE io;
12011};
12012
12013static void
12014open_key_args(VALUE klass, int argc, VALUE *argv, VALUE opt, struct foreach_arg *arg)
12015{
12016 VALUE path, v;
12017 VALUE vmode = Qnil, vperm = Qnil;
12018
12019 path = *argv++;
12020 argc--;
12021 FilePathValue(path);
12022 arg->io = 0;
12023 arg->argc = argc;
12024 arg->argv = argv;
12025 if (NIL_P(opt)) {
12026 vmode = INT2NUM(O_RDONLY);
12027 vperm = INT2FIX(0666);
12028 }
12029 else if (!NIL_P(v = rb_hash_aref(opt, sym_open_args))) {
12030 int n;
12031
12032 v = rb_to_array_type(v);
12033 n = RARRAY_LENINT(v);
12034 rb_check_arity(n, 0, 3); /* rb_io_open */
12035 rb_scan_args_kw(RB_SCAN_ARGS_LAST_HASH_KEYWORDS, n, RARRAY_CONST_PTR(v), "02:", &vmode, &vperm, &opt);
12036 }
12037 arg->io = rb_io_open(klass, path, vmode, vperm, opt);
12038}
12039
12040static VALUE
12041io_s_foreach(VALUE v)
12042{
12043 struct getline_arg *arg = (void *)v;
12044 VALUE str;
12045
12046 if (arg->limit == 0)
12047 rb_raise(rb_eArgError, "invalid limit: 0 for foreach");
12048 while (!NIL_P(str = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, arg->io))) {
12049 rb_lastline_set(str);
12050 rb_yield(str);
12051 }
12053 return Qnil;
12054}
12055
12056/*
12057 * call-seq:
12058 * IO.foreach(path, sep = $/, **opts) {|line| block } -> nil
12059 * IO.foreach(path, limit, **opts) {|line| block } -> nil
12060 * IO.foreach(path, sep, limit, **opts) {|line| block } -> nil
12061 * IO.foreach(...) -> an_enumerator
12062 *
12063 * Calls the block with each successive line read from the stream.
12064 *
12065 * When called from class \IO (but not subclasses of \IO),
12066 * this method has potential security vulnerabilities if called with untrusted input;
12067 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12068 *
12069 * The first argument must be a string that is the path to a file.
12070 *
12071 * With only argument +path+ given, parses lines from the file at the given +path+,
12072 * as determined by the default line separator,
12073 * and calls the block with each successive line:
12074 *
12075 * File.foreach('t.txt') {|line| p line }
12076 *
12077 * Output: the same as above.
12078 *
12079 * For both forms, command and path, the remaining arguments are the same.
12080 *
12081 * With argument +sep+ given, parses lines as determined by that line separator
12082 * (see {Line Separator}[rdoc-ref:IO@Line+Separator]):
12083 *
12084 * File.foreach('t.txt', 'li') {|line| p line }
12085 *
12086 * Output:
12087 *
12088 * "First li"
12089 * "ne\nSecond li"
12090 * "ne\n\nThird li"
12091 * "ne\nFourth li"
12092 * "ne\n"
12093 *
12094 * Each paragraph:
12095 *
12096 * File.foreach('t.txt', '') {|paragraph| p paragraph }
12097 *
12098 * Output:
12099 *
12100 * "First line\nSecond line\n\n"
12101 * "Third line\nFourth line\n"
12102 *
12103 * With argument +limit+ given, parses lines as determined by the default
12104 * line separator and the given line-length limit
12105 * (see {Line Separator}[rdoc-ref:IO@Line+Separator] and {Line Limit}[rdoc-ref:IO@Line+Limit]):
12106 *
12107 * File.foreach('t.txt', 7) {|line| p line }
12108 *
12109 * Output:
12110 *
12111 * "First l"
12112 * "ine\n"
12113 * "Second "
12114 * "line\n"
12115 * "\n"
12116 * "Third l"
12117 * "ine\n"
12118 * "Fourth l"
12119 * "line\n"
12120 *
12121 * With arguments +sep+ and +limit+ given,
12122 * combines the two behaviors
12123 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
12124 *
12125 * Optional keyword arguments +opts+ specify:
12126 *
12127 * - {Open Options}[rdoc-ref:IO@Open+Options].
12128 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12129 * - {Line Options}[rdoc-ref:IO@Line+IO].
12130 *
12131 * Returns an Enumerator if no block is given.
12132 *
12133 */
12134
12135static VALUE
12136rb_io_s_foreach(int argc, VALUE *argv, VALUE self)
12137{
12138 VALUE opt;
12139 int orig_argc = argc;
12140 struct foreach_arg arg;
12141 struct getline_arg garg;
12142
12143 argc = rb_scan_args(argc, argv, "12:", NULL, NULL, NULL, &opt);
12144 RETURN_ENUMERATOR(self, orig_argc, argv);
12145 extract_getline_args(argc-1, argv+1, &garg);
12146 open_key_args(self, argc, argv, opt, &arg);
12147 if (NIL_P(arg.io)) return Qnil;
12148 extract_getline_opts(opt, &garg);
12149 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12150 return rb_ensure(io_s_foreach, (VALUE)&garg, rb_io_close, arg.io);
12151}
12152
12153static VALUE
12154io_s_readlines(VALUE v)
12155{
12156 struct getline_arg *arg = (void *)v;
12157 return io_readlines(arg, arg->io);
12158}
12159
12160/*
12161 * call-seq:
12162 * IO.readlines(path, sep = $/, **opts) -> array
12163 * IO.readlines(path, limit, **opts) -> array
12164 * IO.readlines(path, sep, limit, **opts) -> array
12165 *
12166 * Returns an array of all lines read from the stream.
12167 *
12168 * When called from class \IO (but not subclasses of \IO),
12169 * this method has potential security vulnerabilities if called with untrusted input;
12170 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12171 *
12172 * The first argument must be a string that is the path to a file.
12173 *
12174 * With only argument +path+ given, parses lines from the file at the given +path+,
12175 * as determined by the default line separator,
12176 * and returns those lines in an array:
12177 *
12178 * IO.readlines('t.txt')
12179 * # => ["First line\n", "Second line\n", "\n", "Third line\n", "Fourth line\n"]
12180 *
12181 * With argument +sep+ given, parses lines as determined by that line separator
12182 * (see {Line Separator}[rdoc-ref:IO@Line+Separator]):
12183 *
12184 * # Ordinary separator.
12185 * IO.readlines('t.txt', 'li')
12186 * # =>["First li", "ne\nSecond li", "ne\n\nThird li", "ne\nFourth li", "ne\n"]
12187 * # Get-paragraphs separator.
12188 * IO.readlines('t.txt', '')
12189 * # => ["First line\nSecond line\n\n", "Third line\nFourth line\n"]
12190 * # Get-all separator.
12191 * IO.readlines('t.txt', nil)
12192 * # => ["First line\nSecond line\n\nThird line\nFourth line\n"]
12193 *
12194 * With argument +limit+ given, parses lines as determined by the default
12195 * line separator and the given line-length limit
12196 * (see {Line Separator}[rdoc-ref:IO@Line+Separator] and {Line Limit}[rdoc-ref:IO@Line+Limit]:
12197 *
12198 * IO.readlines('t.txt', 7)
12199 * # => ["First l", "ine\n", "Second ", "line\n", "\n", "Third l", "ine\n", "Fourth ", "line\n"]
12200 *
12201 * With arguments +sep+ and +limit+ given,
12202 * combines the two behaviors
12203 * (see {Line Separator and Line Limit}[rdoc-ref:IO@Line+Separator+and+Line+Limit]).
12204 *
12205 * Optional keyword arguments +opts+ specify:
12206 *
12207 * - {Open Options}[rdoc-ref:IO@Open+Options].
12208 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12209 * - {Line Options}[rdoc-ref:IO@Line+IO].
12210 *
12211 */
12212
12213static VALUE
12214rb_io_s_readlines(int argc, VALUE *argv, VALUE io)
12215{
12216 VALUE opt;
12217 struct foreach_arg arg;
12218 struct getline_arg garg;
12219
12220 argc = rb_scan_args(argc, argv, "12:", NULL, NULL, NULL, &opt);
12221 extract_getline_args(argc-1, argv+1, &garg);
12222 open_key_args(io, argc, argv, opt, &arg);
12223 if (NIL_P(arg.io)) return Qnil;
12224 extract_getline_opts(opt, &garg);
12225 check_getline_args(&garg.rs, &garg.limit, garg.io = arg.io);
12226 return rb_ensure(io_s_readlines, (VALUE)&garg, rb_io_close, arg.io);
12227}
12228
12229static VALUE
12230io_s_read(VALUE v)
12231{
12232 struct foreach_arg *arg = (void *)v;
12233 return io_read(arg->argc, arg->argv, arg->io);
12234}
12235
12236struct seek_arg {
12237 VALUE io;
12238 VALUE offset;
12239 int mode;
12240};
12241
12242static VALUE
12243seek_before_access(VALUE argp)
12244{
12245 struct seek_arg *arg = (struct seek_arg *)argp;
12246 rb_io_binmode(arg->io);
12247 return rb_io_seek(arg->io, arg->offset, arg->mode);
12248}
12249
12250/*
12251 * call-seq:
12252 * IO.read(path, length = nil, offset = 0, **opts) -> string or nil
12253 *
12254 * Opens the stream, reads and returns some or all of its content,
12255 * and closes the stream; returns +nil+ if no bytes were read.
12256 *
12257 * When called from class \IO (but not subclasses of \IO),
12258 * this method has potential security vulnerabilities if called with untrusted input;
12259 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12260 *
12261 * The first argument must be a string that is the path to a file.
12262 *
12263 * With only argument +path+ given, reads in text mode and returns the entire content
12264 * of the file at the given path:
12265 *
12266 * IO.read('t.txt')
12267 * # => "First line\nSecond line\n\nThird line\nFourth line\n"
12268 *
12269 * On Windows, text mode can terminate reading and leave bytes in the file
12270 * unread when encountering certain special bytes. Consider using
12271 * IO.binread if all bytes in the file should be read.
12272 *
12273 * With argument +length+, returns +length+ bytes if available:
12274 *
12275 * IO.read('t.txt', 7) # => "First l"
12276 * IO.read('t.txt', 700)
12277 * # => "First line\r\nSecond line\r\n\r\nFourth line\r\nFifth line\r\n"
12278 *
12279 * With arguments +length+ and +offset+, returns +length+ bytes
12280 * if available, beginning at the given +offset+:
12281 *
12282 * IO.read('t.txt', 10, 2) # => "rst line\nS"
12283 * IO.read('t.txt', 10, 200) # => nil
12284 *
12285 * Optional keyword arguments +opts+ specify:
12286 *
12287 * - {Open Options}[rdoc-ref:IO@Open+Options].
12288 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12289 *
12290 */
12291
12292static VALUE
12293rb_io_s_read(int argc, VALUE *argv, VALUE io)
12294{
12295 VALUE opt, offset;
12296 long off;
12297 struct foreach_arg arg;
12298
12299 argc = rb_scan_args(argc, argv, "13:", NULL, NULL, &offset, NULL, &opt);
12300 if (!NIL_P(offset) && (off = NUM2LONG(offset)) < 0) {
12301 rb_raise(rb_eArgError, "negative offset %ld given", off);
12302 }
12303 open_key_args(io, argc, argv, opt, &arg);
12304 if (NIL_P(arg.io)) return Qnil;
12305 if (!NIL_P(offset)) {
12306 struct seek_arg sarg;
12307 int state = 0;
12308 sarg.io = arg.io;
12309 sarg.offset = offset;
12310 sarg.mode = SEEK_SET;
12311 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12312 if (state) {
12313 rb_io_close(arg.io);
12314 rb_jump_tag(state);
12315 }
12316 if (arg.argc == 2) arg.argc = 1;
12317 }
12318 return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
12319}
12320
12321/*
12322 * call-seq:
12323 * IO.binread(path, length = nil, offset = 0) -> string or nil
12324 *
12325 * Behaves like IO.read, except that the stream is opened in binary mode
12326 * with ASCII-8BIT encoding.
12327 *
12328 * When called from class \IO (but not subclasses of \IO),
12329 * this method has potential security vulnerabilities if called with untrusted input;
12330 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12331 *
12332 */
12333
12334static VALUE
12335rb_io_s_binread(int argc, VALUE *argv, VALUE io)
12336{
12337 VALUE offset;
12338 struct foreach_arg arg;
12339 enum rb_io_mode fmode = FMODE_READABLE|FMODE_BINMODE;
12340 enum {
12341 oflags = O_RDONLY
12342#ifdef O_BINARY
12343 |O_BINARY
12344#endif
12345 };
12346 struct rb_io_encoding convconfig = {NULL, NULL, 0, Qnil};
12347
12348 rb_scan_args(argc, argv, "12", NULL, NULL, &offset);
12349 FilePathValue(argv[0]);
12350 convconfig.enc = rb_ascii8bit_encoding();
12351 arg.io = rb_io_open_generic(io, argv[0], oflags, fmode, &convconfig, 0);
12352 if (NIL_P(arg.io)) return Qnil;
12353 arg.argv = argv+1;
12354 arg.argc = (argc > 1) ? 1 : 0;
12355 if (!NIL_P(offset)) {
12356 struct seek_arg sarg;
12357 int state = 0;
12358 sarg.io = arg.io;
12359 sarg.offset = offset;
12360 sarg.mode = SEEK_SET;
12361 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12362 if (state) {
12363 rb_io_close(arg.io);
12364 rb_jump_tag(state);
12365 }
12366 }
12367 return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
12368}
12369
12370static VALUE
12371io_s_write0(VALUE v)
12372{
12373 struct write_arg *arg = (void *)v;
12374 return io_write(arg->io,arg->str,arg->nosync);
12375}
12376
12377static VALUE
12378io_s_write(int argc, VALUE *argv, VALUE klass, int binary)
12379{
12380 VALUE string, offset, opt;
12381 struct foreach_arg arg;
12382 struct write_arg warg;
12383
12384 rb_scan_args(argc, argv, "21:", NULL, &string, &offset, &opt);
12385
12386 if (NIL_P(opt)) opt = rb_hash_new();
12387 else opt = rb_hash_dup(opt);
12388
12389
12390 if (NIL_P(rb_hash_aref(opt,sym_mode))) {
12391 int mode = O_WRONLY|O_CREAT;
12392#ifdef O_BINARY
12393 if (binary) mode |= O_BINARY;
12394#endif
12395 if (NIL_P(offset)) mode |= O_TRUNC;
12396 rb_hash_aset(opt,sym_mode,INT2NUM(mode));
12397 }
12398 open_key_args(klass, argc, argv, opt, &arg);
12399
12400#ifndef O_BINARY
12401 if (binary) rb_io_binmode_m(arg.io);
12402#endif
12403
12404 if (NIL_P(arg.io)) return Qnil;
12405 if (!NIL_P(offset)) {
12406 struct seek_arg sarg;
12407 int state = 0;
12408 sarg.io = arg.io;
12409 sarg.offset = offset;
12410 sarg.mode = SEEK_SET;
12411 rb_protect(seek_before_access, (VALUE)&sarg, &state);
12412 if (state) {
12413 rb_io_close(arg.io);
12414 rb_jump_tag(state);
12415 }
12416 }
12417
12418 warg.io = arg.io;
12419 warg.str = string;
12420 warg.nosync = 0;
12421
12422 return rb_ensure(io_s_write0, (VALUE)&warg, rb_io_close, arg.io);
12423}
12424
12425/*
12426 * call-seq:
12427 * IO.write(path, data, offset = 0, **opts) -> integer
12428 *
12429 * Opens the stream, writes the given +data+ to it,
12430 * and closes the stream; returns the number of bytes written.
12431 *
12432 * When called from class \IO (but not subclasses of \IO),
12433 * this method has potential security vulnerabilities if called with untrusted input;
12434 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12435 *
12436 * The first argument must be a string that is the path to a file.
12437 *
12438 * With only argument +path+ given, writes the given +data+ to the file at that path:
12439 *
12440 * IO.write('t.tmp', 'abc') # => 3
12441 * File.read('t.tmp') # => "abc"
12442 *
12443 * If +offset+ is zero (the default), the file is overwritten:
12444 *
12445 * IO.write('t.tmp', 'A') # => 1
12446 * File.read('t.tmp') # => "A"
12447 *
12448 * If +offset+ in within the file content, the file is partly overwritten:
12449 *
12450 * IO.write('t.tmp', 'abcdef') # => 3
12451 * File.read('t.tmp') # => "abcdef"
12452 * # Offset within content.
12453 * IO.write('t.tmp', '012', 2) # => 3
12454 * File.read('t.tmp') # => "ab012f"
12455 *
12456 * If +offset+ is outside the file content,
12457 * the file is padded with null characters <tt>"\u0000"</tt>:
12458 *
12459 * IO.write('t.tmp', 'xyz', 10) # => 3
12460 * File.read('t.tmp') # => "ab012f\u0000\u0000\u0000\u0000xyz"
12461 *
12462 * Optional keyword arguments +opts+ specify:
12463 *
12464 * - {Open Options}[rdoc-ref:IO@Open+Options].
12465 * - {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
12466 *
12467 */
12468
12469static VALUE
12470rb_io_s_write(int argc, VALUE *argv, VALUE io)
12471{
12472 return io_s_write(argc, argv, io, 0);
12473}
12474
12475/*
12476 * call-seq:
12477 * IO.binwrite(path, string, offset = 0) -> integer
12478 *
12479 * Behaves like IO.write, except that the stream is opened in binary mode
12480 * with ASCII-8BIT encoding.
12481 *
12482 * When called from class \IO (but not subclasses of \IO),
12483 * this method has potential security vulnerabilities if called with untrusted input;
12484 * see {Command Injection}[rdoc-ref:command_injection.rdoc].
12485 *
12486 */
12487
12488static VALUE
12489rb_io_s_binwrite(int argc, VALUE *argv, VALUE io)
12490{
12491 return io_s_write(argc, argv, io, 1);
12492}
12493
12495 VALUE src;
12496 VALUE dst;
12497 rb_off_t copy_length; /* (rb_off_t)-1 if not specified */
12498 rb_off_t src_offset; /* (rb_off_t)-1 if not specified */
12499
12500 rb_io_t *src_fptr;
12501 rb_io_t *dst_fptr;
12502 unsigned close_src : 1;
12503 unsigned close_dst : 1;
12504 int error_no;
12505 rb_off_t total;
12506 const char *syserr;
12507 const char *notimp;
12508 VALUE th;
12509 struct stat src_stat;
12510 struct stat dst_stat;
12511#ifdef HAVE_FCOPYFILE
12512 copyfile_state_t copyfile_state;
12513#endif
12514};
12515
12516static void *
12517exec_interrupts(void *arg)
12518{
12519 VALUE th = (VALUE)arg;
12520 rb_thread_execute_interrupts(th);
12521 return NULL;
12522}
12523
12524/*
12525 * returns TRUE if the preceding system call was interrupted
12526 * so we can continue. If the thread was interrupted, we
12527 * reacquire the GVL to execute interrupts before continuing.
12528 */
12529static int
12530maygvl_copy_stream_continue_p(int has_gvl, struct copy_stream_struct *stp)
12531{
12532 switch (errno) {
12533 case EINTR:
12534#if defined(ERESTART)
12535 case ERESTART:
12536#endif
12537 if (rb_thread_interrupted(stp->th)) {
12538 if (has_gvl)
12539 rb_thread_execute_interrupts(stp->th);
12540 else
12541 rb_thread_call_with_gvl(exec_interrupts, (void *)stp->th);
12542 }
12543 return TRUE;
12544 }
12545 return FALSE;
12546}
12547
12549 VALUE scheduler;
12550
12551 rb_io_t *fptr;
12552 short events;
12553
12554 VALUE result;
12555};
12556
12557static void *
12558fiber_scheduler_wait_for(void * _arguments)
12559{
12560 struct fiber_scheduler_wait_for_arguments *arguments = (struct fiber_scheduler_wait_for_arguments *)_arguments;
12561
12562 arguments->result = rb_fiber_scheduler_io_wait(arguments->scheduler, arguments->fptr->self, INT2NUM(arguments->events), RUBY_IO_TIMEOUT_DEFAULT);
12563
12564 return NULL;
12565}
12566
12567#if USE_POLL
12568# define IOWAIT_SYSCALL "poll"
12569STATIC_ASSERT(pollin_expected, POLLIN == RB_WAITFD_IN);
12570STATIC_ASSERT(pollout_expected, POLLOUT == RB_WAITFD_OUT);
12571static int
12572nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout)
12573{
12575 if (scheduler != Qnil) {
12576 struct fiber_scheduler_wait_for_arguments args = {.scheduler = scheduler, .fptr = fptr, .events = events};
12577 rb_thread_call_with_gvl(fiber_scheduler_wait_for, &args);
12578 return RTEST(args.result);
12579 }
12580
12581 int fd = fptr->fd;
12582 if (fd == -1) return 0;
12583
12584 struct pollfd fds;
12585
12586 fds.fd = fd;
12587 fds.events = events;
12588
12589 int timeout_milliseconds = -1;
12590
12591 if (timeout) {
12592 timeout_milliseconds = (int)(timeout->tv_sec * 1000) + (int)(timeout->tv_usec / 1000);
12593 }
12594
12595 return poll(&fds, 1, timeout_milliseconds);
12596}
12597#else /* !USE_POLL */
12598# define IOWAIT_SYSCALL "select"
12599static int
12600nogvl_wait_for(VALUE th, rb_io_t *fptr, short events, struct timeval *timeout)
12601{
12603 if (scheduler != Qnil) {
12604 struct fiber_scheduler_wait_for_arguments args = {.scheduler = scheduler, .fptr = fptr, .events = events};
12605 rb_thread_call_with_gvl(fiber_scheduler_wait_for, &args);
12606 return RTEST(args.result);
12607 }
12608
12609 int fd = fptr->fd;
12610
12611 if (fd == -1) {
12612 errno = EBADF;
12613 return -1;
12614 }
12615
12616 rb_fdset_t fds;
12617 int ret;
12618
12619 rb_fd_init(&fds);
12620 rb_fd_set(fd, &fds);
12621
12622 switch (events) {
12623 case RB_WAITFD_IN:
12624 ret = rb_fd_select(fd + 1, &fds, 0, 0, timeout);
12625 break;
12626 case RB_WAITFD_OUT:
12627 ret = rb_fd_select(fd + 1, 0, &fds, 0, timeout);
12628 break;
12629 default:
12630 VM_UNREACHABLE(nogvl_wait_for);
12631 }
12632
12633 rb_fd_term(&fds);
12634
12635 // On timeout, this returns 0.
12636 return ret;
12637}
12638#endif /* !USE_POLL */
12639
12640static int
12641maygvl_copy_stream_wait_read(int has_gvl, struct copy_stream_struct *stp)
12642{
12643 int ret;
12644
12645 do {
12646 if (has_gvl) {
12648 }
12649 else {
12650 ret = nogvl_wait_for(stp->th, stp->src_fptr, RB_WAITFD_IN, NULL);
12651 }
12652 } while (ret < 0 && maygvl_copy_stream_continue_p(has_gvl, stp));
12653
12654 if (ret < 0) {
12655 stp->syserr = IOWAIT_SYSCALL;
12656 stp->error_no = errno;
12657 return ret;
12658 }
12659 return 0;
12660}
12661
12662static int
12663nogvl_copy_stream_wait_write(struct copy_stream_struct *stp)
12664{
12665 int ret;
12666
12667 do {
12668 ret = nogvl_wait_for(stp->th, stp->dst_fptr, RB_WAITFD_OUT, NULL);
12669 } while (ret < 0 && maygvl_copy_stream_continue_p(0, stp));
12670
12671 if (ret < 0) {
12672 stp->syserr = IOWAIT_SYSCALL;
12673 stp->error_no = errno;
12674 return ret;
12675 }
12676 return 0;
12677}
12678
12679#ifdef USE_COPY_FILE_RANGE
12680
12681static ssize_t
12682simple_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)
12683{
12684#ifdef HAVE_COPY_FILE_RANGE
12685 return copy_file_range(in_fd, in_offset, out_fd, out_offset, count, flags);
12686#else
12687 return syscall(__NR_copy_file_range, in_fd, in_offset, out_fd, out_offset, count, flags);
12688#endif
12689}
12690
12691static int
12692nogvl_copy_file_range(struct copy_stream_struct *stp)
12693{
12694 ssize_t ss;
12695 rb_off_t src_size;
12696 rb_off_t copy_length, src_offset, *src_offset_ptr;
12697
12698 if (!S_ISREG(stp->src_stat.st_mode))
12699 return 0;
12700
12701 src_size = stp->src_stat.st_size;
12702 src_offset = stp->src_offset;
12703 if (src_offset >= (rb_off_t)0) {
12704 src_offset_ptr = &src_offset;
12705 }
12706 else {
12707 src_offset_ptr = NULL; /* if src_offset_ptr is NULL, then bytes are read from in_fd starting from the file offset */
12708 }
12709
12710 copy_length = stp->copy_length;
12711 if (copy_length < (rb_off_t)0) {
12712 if (src_offset < (rb_off_t)0) {
12713 rb_off_t current_offset;
12714 errno = 0;
12715 current_offset = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12716 if (current_offset < (rb_off_t)0 && errno) {
12717 stp->syserr = "lseek";
12718 stp->error_no = errno;
12719 return (int)current_offset;
12720 }
12721 copy_length = src_size - current_offset;
12722 }
12723 else {
12724 copy_length = src_size - src_offset;
12725 }
12726 }
12727
12728 retry_copy_file_range:
12729# if SIZEOF_OFF_T > SIZEOF_SIZE_T
12730 /* we are limited by the 32-bit ssize_t return value on 32-bit */
12731 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
12732# else
12733 ss = (ssize_t)copy_length;
12734# endif
12735 ss = simple_copy_file_range(stp->src_fptr->fd, src_offset_ptr, stp->dst_fptr->fd, NULL, ss, 0);
12736 if (0 < ss) {
12737 stp->total += ss;
12738 copy_length -= ss;
12739 if (0 < copy_length) {
12740 goto retry_copy_file_range;
12741 }
12742 }
12743 if (ss < 0) {
12744 if (maygvl_copy_stream_continue_p(0, stp)) {
12745 goto retry_copy_file_range;
12746 }
12747 switch (errno) {
12748 case EINVAL:
12749 case EPERM: /* copy_file_range(2) doesn't exist (may happen in
12750 docker container) */
12751#ifdef ENOSYS
12752 case ENOSYS:
12753#endif
12754#ifdef EXDEV
12755 case EXDEV: /* in_fd and out_fd are not on the same filesystem */
12756#endif
12757 return 0;
12758 case EAGAIN:
12759#if EWOULDBLOCK != EAGAIN
12760 case EWOULDBLOCK:
12761#endif
12762 {
12763 int ret = nogvl_copy_stream_wait_write(stp);
12764 if (ret < 0) return ret;
12765 }
12766 goto retry_copy_file_range;
12767 case EBADF:
12768 {
12769 int e = errno;
12770 int flags = fcntl(stp->dst_fptr->fd, F_GETFL);
12771
12772 if (flags != -1 && flags & O_APPEND) {
12773 return 0;
12774 }
12775 errno = e;
12776 }
12777 }
12778 stp->syserr = "copy_file_range";
12779 stp->error_no = errno;
12780 return (int)ss;
12781 }
12782 return 1;
12783}
12784#endif
12785
12786#ifdef HAVE_FCOPYFILE
12787static int
12788nogvl_fcopyfile(struct copy_stream_struct *stp)
12789{
12790 rb_off_t cur, ss = 0;
12791 const rb_off_t src_offset = stp->src_offset;
12792 int ret;
12793
12794 if (stp->copy_length >= (rb_off_t)0) {
12795 /* copy_length can't be specified in fcopyfile(3) */
12796 return 0;
12797 }
12798
12799 if (!S_ISREG(stp->src_stat.st_mode))
12800 return 0;
12801
12802 if (!S_ISREG(stp->dst_stat.st_mode))
12803 return 0;
12804 if (lseek(stp->dst_fptr->fd, 0, SEEK_CUR) > (rb_off_t)0) /* if dst IO was already written */
12805 return 0;
12806 if (fcntl(stp->dst_fptr->fd, F_GETFL) & O_APPEND) {
12807 /* fcopyfile(3) appends src IO to dst IO and then truncates
12808 * dst IO to src IO's original size. */
12809 rb_off_t end = lseek(stp->dst_fptr->fd, 0, SEEK_END);
12810 lseek(stp->dst_fptr->fd, 0, SEEK_SET);
12811 if (end > (rb_off_t)0) return 0;
12812 }
12813
12814 if (src_offset > (rb_off_t)0) {
12815 rb_off_t r;
12816
12817 /* get current offset */
12818 errno = 0;
12819 cur = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12820 if (cur < (rb_off_t)0 && errno) {
12821 stp->error_no = errno;
12822 return 1;
12823 }
12824
12825 errno = 0;
12826 r = lseek(stp->src_fptr->fd, src_offset, SEEK_SET);
12827 if (r < (rb_off_t)0 && errno) {
12828 stp->error_no = errno;
12829 return 1;
12830 }
12831 }
12832
12833 stp->copyfile_state = copyfile_state_alloc(); /* this will be freed by copy_stream_finalize() */
12834 ret = fcopyfile(stp->src_fptr->fd, stp->dst_fptr->fd, stp->copyfile_state, COPYFILE_DATA);
12835 copyfile_state_get(stp->copyfile_state, COPYFILE_STATE_COPIED, &ss); /* get copied bytes */
12836
12837 if (ret == 0) { /* success */
12838 stp->total = ss;
12839 if (src_offset > (rb_off_t)0) {
12840 rb_off_t r;
12841 errno = 0;
12842 /* reset offset */
12843 r = lseek(stp->src_fptr->fd, cur, SEEK_SET);
12844 if (r < (rb_off_t)0 && errno) {
12845 stp->error_no = errno;
12846 return 1;
12847 }
12848 }
12849 }
12850 else {
12851 switch (errno) {
12852 case ENOTSUP:
12853 case EPERM:
12854 case EINVAL:
12855 return 0;
12856 }
12857 stp->syserr = "fcopyfile";
12858 stp->error_no = errno;
12859 return (int)ret;
12860 }
12861 return 1;
12862}
12863#endif
12864
12865#ifdef HAVE_SENDFILE
12866
12867# ifdef __linux__
12868# define USE_SENDFILE
12869
12870# ifdef HAVE_SYS_SENDFILE_H
12871# include <sys/sendfile.h>
12872# endif
12873
12874static ssize_t
12875simple_sendfile(int out_fd, int in_fd, rb_off_t *offset, rb_off_t count)
12876{
12877 return sendfile(out_fd, in_fd, offset, (size_t)count);
12878}
12879
12880# elif 0 /* defined(__FreeBSD__) || defined(__DragonFly__) */ || defined(__APPLE__)
12881/* This runs on FreeBSD8.1 r30210, but sendfiles blocks its execution
12882 * without cpuset -l 0.
12883 */
12884# define USE_SENDFILE
12885
12886static ssize_t
12887simple_sendfile(int out_fd, int in_fd, rb_off_t *offset, rb_off_t count)
12888{
12889 int r;
12890 rb_off_t pos = offset ? *offset : lseek(in_fd, 0, SEEK_CUR);
12891 rb_off_t sbytes;
12892# ifdef __APPLE__
12893 r = sendfile(in_fd, out_fd, pos, &count, NULL, 0);
12894 sbytes = count;
12895# else
12896 r = sendfile(in_fd, out_fd, pos, (size_t)count, NULL, &sbytes, 0);
12897# endif
12898 if (r != 0 && sbytes == 0) return r;
12899 if (offset) {
12900 *offset += sbytes;
12901 }
12902 else {
12903 lseek(in_fd, sbytes, SEEK_CUR);
12904 }
12905 return (ssize_t)sbytes;
12906}
12907
12908# endif
12909
12910#endif
12911
12912#ifdef USE_SENDFILE
12913static int
12914nogvl_copy_stream_sendfile(struct copy_stream_struct *stp)
12915{
12916 ssize_t ss;
12917 rb_off_t src_size;
12918 rb_off_t copy_length;
12919 rb_off_t src_offset;
12920 int use_pread;
12921
12922 if (!S_ISREG(stp->src_stat.st_mode))
12923 return 0;
12924
12925 src_size = stp->src_stat.st_size;
12926#ifndef __linux__
12927 if ((stp->dst_stat.st_mode & S_IFMT) != S_IFSOCK)
12928 return 0;
12929#endif
12930
12931 src_offset = stp->src_offset;
12932 use_pread = src_offset >= (rb_off_t)0;
12933
12934 copy_length = stp->copy_length;
12935 if (copy_length < (rb_off_t)0) {
12936 if (use_pread)
12937 copy_length = src_size - src_offset;
12938 else {
12939 rb_off_t cur;
12940 errno = 0;
12941 cur = lseek(stp->src_fptr->fd, 0, SEEK_CUR);
12942 if (cur < (rb_off_t)0 && errno) {
12943 stp->syserr = "lseek";
12944 stp->error_no = errno;
12945 return (int)cur;
12946 }
12947 copy_length = src_size - cur;
12948 }
12949 }
12950
12951 retry_sendfile:
12952# if SIZEOF_OFF_T > SIZEOF_SIZE_T
12953 /* we are limited by the 32-bit ssize_t return value on 32-bit */
12954 ss = (copy_length > (rb_off_t)SSIZE_MAX) ? SSIZE_MAX : (ssize_t)copy_length;
12955# else
12956 ss = (ssize_t)copy_length;
12957# endif
12958 if (use_pread) {
12959 ss = simple_sendfile(stp->dst_fptr->fd, stp->src_fptr->fd, &src_offset, ss);
12960 }
12961 else {
12962 ss = simple_sendfile(stp->dst_fptr->fd, stp->src_fptr->fd, NULL, ss);
12963 }
12964 if (0 < ss) {
12965 stp->total += ss;
12966 copy_length -= ss;
12967 if (0 < copy_length) {
12968 goto retry_sendfile;
12969 }
12970 }
12971 if (ss < 0) {
12972 if (maygvl_copy_stream_continue_p(0, stp))
12973 goto retry_sendfile;
12974 switch (errno) {
12975 case EINVAL:
12976#ifdef ENOSYS
12977 case ENOSYS:
12978#endif
12979#ifdef EOPNOTSUP
12980 /* some RedHat kernels may return EOPNOTSUP on an NFS mount.
12981 see also: [Feature #16965] */
12982 case EOPNOTSUP:
12983#endif
12984 return 0;
12985 case EAGAIN:
12986#if EWOULDBLOCK != EAGAIN
12987 case EWOULDBLOCK:
12988#endif
12989 {
12990 int ret;
12991#ifndef __linux__
12992 /*
12993 * Linux requires stp->src_fptr->fd to be a mmap-able (regular) file,
12994 * select() reports regular files to always be "ready", so
12995 * there is no need to select() on it.
12996 * Other OSes may have the same limitation for sendfile() which
12997 * allow us to bypass maygvl_copy_stream_wait_read()...
12998 */
12999 ret = maygvl_copy_stream_wait_read(0, stp);
13000 if (ret < 0) return ret;
13001#endif
13002 ret = nogvl_copy_stream_wait_write(stp);
13003 if (ret < 0) return ret;
13004 }
13005 goto retry_sendfile;
13006 }
13007 stp->syserr = "sendfile";
13008 stp->error_no = errno;
13009 return (int)ss;
13010 }
13011 return 1;
13012}
13013#endif
13014
13015static ssize_t
13016maygvl_read(int has_gvl, rb_io_t *fptr, void *buf, size_t count)
13017{
13018 if (has_gvl)
13019 return rb_io_read_memory(fptr, buf, count);
13020 else
13021 return read(fptr->fd, buf, count);
13022}
13023
13024static ssize_t
13025maygvl_copy_stream_read(int has_gvl, struct copy_stream_struct *stp, char *buf, size_t len, rb_off_t offset)
13026{
13027 ssize_t ss;
13028 retry_read:
13029 if (offset < (rb_off_t)0) {
13030 ss = maygvl_read(has_gvl, stp->src_fptr, buf, len);
13031 }
13032 else {
13033 ss = pread(stp->src_fptr->fd, buf, len, offset);
13034 }
13035 if (ss == 0) {
13036 return 0;
13037 }
13038 if (ss < 0) {
13039 if (maygvl_copy_stream_continue_p(has_gvl, stp))
13040 goto retry_read;
13041 switch (errno) {
13042 case EAGAIN:
13043#if EWOULDBLOCK != EAGAIN
13044 case EWOULDBLOCK:
13045#endif
13046 {
13047 int ret = maygvl_copy_stream_wait_read(has_gvl, stp);
13048 if (ret < 0) return ret;
13049 }
13050 goto retry_read;
13051#ifdef ENOSYS
13052 case ENOSYS:
13053 stp->notimp = "pread";
13054 return ss;
13055#endif
13056 }
13057 stp->syserr = offset < (rb_off_t)0 ? "read" : "pread";
13058 stp->error_no = errno;
13059 }
13060 return ss;
13061}
13062
13063static int
13064nogvl_copy_stream_write(struct copy_stream_struct *stp, char *buf, size_t len)
13065{
13066 ssize_t ss;
13067 int off = 0;
13068 while (len) {
13069 ss = write(stp->dst_fptr->fd, buf+off, len);
13070 if (ss < 0) {
13071 if (maygvl_copy_stream_continue_p(0, stp))
13072 continue;
13073 if (io_again_p(errno)) {
13074 int ret = nogvl_copy_stream_wait_write(stp);
13075 if (ret < 0) return ret;
13076 continue;
13077 }
13078 stp->syserr = "write";
13079 stp->error_no = errno;
13080 return (int)ss;
13081 }
13082 off += (int)ss;
13083 len -= (int)ss;
13084 stp->total += ss;
13085 }
13086 return 0;
13087}
13088
13089static void
13090nogvl_copy_stream_read_write(struct copy_stream_struct *stp)
13091{
13092 char buf[1024*16];
13093 size_t len;
13094 ssize_t ss;
13095 int ret;
13096 rb_off_t copy_length;
13097 rb_off_t src_offset;
13098 int use_eof;
13099 int use_pread;
13100
13101 copy_length = stp->copy_length;
13102 use_eof = copy_length < (rb_off_t)0;
13103 src_offset = stp->src_offset;
13104 use_pread = src_offset >= (rb_off_t)0;
13105
13106 if (use_pread && stp->close_src) {
13107 rb_off_t r;
13108 errno = 0;
13109 r = lseek(stp->src_fptr->fd, src_offset, SEEK_SET);
13110 if (r < (rb_off_t)0 && errno) {
13111 stp->syserr = "lseek";
13112 stp->error_no = errno;
13113 return;
13114 }
13115 src_offset = (rb_off_t)-1;
13116 use_pread = 0;
13117 }
13118
13119 while (use_eof || 0 < copy_length) {
13120 if (!use_eof && copy_length < (rb_off_t)sizeof(buf)) {
13121 len = (size_t)copy_length;
13122 }
13123 else {
13124 len = sizeof(buf);
13125 }
13126 if (use_pread) {
13127 ss = maygvl_copy_stream_read(0, stp, buf, len, src_offset);
13128 if (0 < ss)
13129 src_offset += ss;
13130 }
13131 else {
13132 ss = maygvl_copy_stream_read(0, stp, buf, len, (rb_off_t)-1);
13133 }
13134 if (ss <= 0) /* EOF or error */
13135 return;
13136
13137 ret = nogvl_copy_stream_write(stp, buf, ss);
13138 if (ret < 0)
13139 return;
13140
13141 if (!use_eof)
13142 copy_length -= ss;
13143 }
13144}
13145
13146static void *
13147nogvl_copy_stream_func(void *arg)
13148{
13149 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13150#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13151 int ret;
13152#endif
13153
13154#ifdef USE_COPY_FILE_RANGE
13155 ret = nogvl_copy_file_range(stp);
13156 if (ret != 0)
13157 goto finish; /* error or success */
13158#endif
13159
13160#ifdef HAVE_FCOPYFILE
13161 ret = nogvl_fcopyfile(stp);
13162 if (ret != 0)
13163 goto finish; /* error or success */
13164#endif
13165
13166#ifdef USE_SENDFILE
13167 ret = nogvl_copy_stream_sendfile(stp);
13168 if (ret != 0)
13169 goto finish; /* error or success */
13170#endif
13171
13172 nogvl_copy_stream_read_write(stp);
13173
13174#if defined(USE_SENDFILE) || defined(USE_COPY_FILE_RANGE) || defined(HAVE_FCOPYFILE)
13175 finish:
13176#endif
13177 return 0;
13178}
13179
13180static VALUE
13181copy_stream_fallback_body(VALUE arg)
13182{
13183 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13184 const int buflen = 16*1024;
13185 VALUE n;
13186 VALUE buf = rb_str_buf_new(buflen);
13187 rb_off_t rest = stp->copy_length;
13188 rb_off_t off = stp->src_offset;
13189 ID read_method = id_readpartial;
13190
13191 if (!stp->src_fptr) {
13192 if (!rb_respond_to(stp->src, read_method)) {
13193 read_method = id_read;
13194 }
13195 }
13196
13197 while (1) {
13198 long numwrote;
13199 long l;
13200 rb_str_make_independent(buf);
13201 if (stp->copy_length < (rb_off_t)0) {
13202 l = buflen;
13203 }
13204 else {
13205 if (rest == 0) {
13206 rb_str_resize(buf, 0);
13207 break;
13208 }
13209 l = buflen < rest ? buflen : (long)rest;
13210 }
13211 if (!stp->src_fptr) {
13212 VALUE rc = rb_funcall(stp->src, read_method, 2, INT2FIX(l), buf);
13213
13214 if (read_method == id_read && NIL_P(rc))
13215 break;
13216 }
13217 else {
13218 ssize_t ss;
13219 rb_str_resize(buf, buflen);
13220 ss = maygvl_copy_stream_read(1, stp, RSTRING_PTR(buf), l, off);
13221 rb_str_resize(buf, ss > 0 ? ss : 0);
13222 if (ss < 0)
13223 return Qnil;
13224 if (ss == 0)
13225 rb_eof_error();
13226 if (off >= (rb_off_t)0)
13227 off += ss;
13228 }
13229 n = rb_io_write(stp->dst, buf);
13230 numwrote = NUM2LONG(n);
13231 stp->total += numwrote;
13232 rest -= numwrote;
13233 if (read_method == id_read && RSTRING_LEN(buf) == 0) {
13234 break;
13235 }
13236 }
13237
13238 return Qnil;
13239}
13240
13241static VALUE
13242copy_stream_fallback(struct copy_stream_struct *stp)
13243{
13244 if (!stp->src_fptr && stp->src_offset >= (rb_off_t)0) {
13245 rb_raise(rb_eArgError, "cannot specify src_offset for non-IO");
13246 }
13247 rb_rescue2(copy_stream_fallback_body, (VALUE)stp,
13248 (VALUE (*) (VALUE, VALUE))0, (VALUE)0,
13249 rb_eEOFError, (VALUE)0);
13250 return Qnil;
13251}
13252
13253static VALUE
13254copy_stream_body(VALUE arg)
13255{
13256 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13257 VALUE src_io = stp->src, dst_io = stp->dst;
13258 const int common_oflags = 0
13259#ifdef O_NOCTTY
13260 | O_NOCTTY
13261#endif
13262 ;
13263
13264 stp->th = rb_thread_current();
13265
13266 stp->total = 0;
13267
13268 if (src_io == argf ||
13269 !(RB_TYPE_P(src_io, T_FILE) ||
13270 RB_TYPE_P(src_io, T_STRING) ||
13271 rb_respond_to(src_io, rb_intern("to_path")))) {
13272 stp->src_fptr = NULL;
13273 }
13274 else {
13275 int stat_ret;
13276 VALUE tmp_io = rb_io_check_io(src_io);
13277 if (!NIL_P(tmp_io)) {
13278 src_io = tmp_io;
13279 }
13280 else if (!RB_TYPE_P(src_io, T_FILE)) {
13281 VALUE args[2];
13282 FilePathValue(src_io);
13283 args[0] = src_io;
13284 args[1] = INT2NUM(O_RDONLY|common_oflags);
13285 src_io = rb_class_new_instance(2, args, rb_cFile);
13286 stp->src = src_io;
13287 stp->close_src = 1;
13288 }
13289 RB_IO_POINTER(src_io, stp->src_fptr);
13290 rb_io_check_byte_readable(stp->src_fptr);
13291
13292 stat_ret = fstat(stp->src_fptr->fd, &stp->src_stat);
13293 if (stat_ret < 0) {
13294 stp->syserr = "fstat";
13295 stp->error_no = errno;
13296 return Qnil;
13297 }
13298 }
13299
13300 if (dst_io == argf ||
13301 !(RB_TYPE_P(dst_io, T_FILE) ||
13302 RB_TYPE_P(dst_io, T_STRING) ||
13303 rb_respond_to(dst_io, rb_intern("to_path")))) {
13304 stp->dst_fptr = NULL;
13305 }
13306 else {
13307 int stat_ret;
13308 VALUE tmp_io = rb_io_check_io(dst_io);
13309 if (!NIL_P(tmp_io)) {
13310 dst_io = GetWriteIO(tmp_io);
13311 }
13312 else if (!RB_TYPE_P(dst_io, T_FILE)) {
13313 VALUE args[3];
13314 FilePathValue(dst_io);
13315 args[0] = dst_io;
13316 args[1] = INT2NUM(O_WRONLY|O_CREAT|O_TRUNC|common_oflags);
13317 args[2] = INT2FIX(0666);
13318 dst_io = rb_class_new_instance(3, args, rb_cFile);
13319 stp->dst = dst_io;
13320 stp->close_dst = 1;
13321 }
13322 else {
13323 dst_io = GetWriteIO(dst_io);
13324 stp->dst = dst_io;
13325 }
13326 RB_IO_POINTER(dst_io, stp->dst_fptr);
13327 rb_io_check_writable(stp->dst_fptr);
13328
13329 stat_ret = fstat(stp->dst_fptr->fd, &stp->dst_stat);
13330 if (stat_ret < 0) {
13331 stp->syserr = "fstat";
13332 stp->error_no = errno;
13333 return Qnil;
13334 }
13335 }
13336
13337#ifdef O_BINARY
13338 if (stp->src_fptr)
13339 SET_BINARY_MODE_WITH_SEEK_CUR(stp->src_fptr);
13340#endif
13341 if (stp->dst_fptr)
13342 io_ascii8bit_binmode(stp->dst_fptr);
13343
13344 if (stp->src_offset < (rb_off_t)0 && stp->src_fptr && stp->src_fptr->rbuf.len) {
13345 size_t len = stp->src_fptr->rbuf.len;
13346 VALUE str;
13347 if (stp->copy_length >= (rb_off_t)0 && stp->copy_length < (rb_off_t)len) {
13348 len = (size_t)stp->copy_length;
13349 }
13350 str = rb_str_buf_new(len);
13351 rb_str_resize(str,len);
13352 read_buffered_data(RSTRING_PTR(str), len, stp->src_fptr);
13353 if (stp->dst_fptr) { /* IO or filename */
13354 if (io_binwrite(RSTRING_PTR(str), RSTRING_LEN(str), stp->dst_fptr, 0) < 0)
13355 rb_sys_fail_on_write(stp->dst_fptr);
13356 }
13357 else /* others such as StringIO */
13358 rb_io_write(dst_io, str);
13359 rb_str_resize(str, 0);
13360 stp->total += len;
13361 if (stp->copy_length >= (rb_off_t)0)
13362 stp->copy_length -= len;
13363 }
13364
13365 if (stp->dst_fptr && io_fflush(stp->dst_fptr) < 0) {
13366 rb_raise(rb_eIOError, "flush failed");
13367 }
13368
13369 if (stp->copy_length == 0)
13370 return Qnil;
13371
13372 if (stp->src_fptr == NULL || stp->dst_fptr == NULL) {
13373 return copy_stream_fallback(stp);
13374 }
13375
13376 IO_WITHOUT_GVL(nogvl_copy_stream_func, stp);
13377 return Qnil;
13378}
13379
13380static VALUE
13381copy_stream_finalize(VALUE arg)
13382{
13383 struct copy_stream_struct *stp = (struct copy_stream_struct *)arg;
13384
13385#ifdef HAVE_FCOPYFILE
13386 if (stp->copyfile_state) {
13387 copyfile_state_free(stp->copyfile_state);
13388 }
13389#endif
13390
13391 if (stp->close_src) {
13392 rb_io_close_m(stp->src);
13393 }
13394 if (stp->close_dst) {
13395 rb_io_close_m(stp->dst);
13396 }
13397 if (stp->syserr) {
13398 rb_syserr_fail(stp->error_no, stp->syserr);
13399 }
13400 if (stp->notimp) {
13401 rb_raise(rb_eNotImpError, "%s() not implemented", stp->notimp);
13402 }
13403 return Qnil;
13404}
13405
13406/*
13407 * call-seq:
13408 * IO.copy_stream(src, dst, src_length = nil, src_offset = 0) -> integer
13409 *
13410 * Copies from the given +src+ to the given +dst+,
13411 * returning the number of bytes copied.
13412 *
13413 * - The given +src+ must be one of the following:
13414 *
13415 * - The path to a readable file, from which source data is to be read.
13416 * - An \IO-like object, opened for reading and capable of responding
13417 * to method +:readpartial+ or method +:read+.
13418 *
13419 * - The given +dst+ must be one of the following:
13420 *
13421 * - The path to a writable file, to which data is to be written.
13422 * - An \IO-like object, opened for writing and capable of responding
13423 * to method +:write+.
13424 *
13425 * The examples here use file <tt>t.txt</tt> as source:
13426 *
13427 * File.read('t.txt')
13428 * # => "First line\nSecond line\n\nThird line\nFourth line\n"
13429 * File.read('t.txt').size # => 47
13430 *
13431 * If only arguments +src+ and +dst+ are given,
13432 * the entire source stream is copied:
13433 *
13434 * # Paths.
13435 * IO.copy_stream('t.txt', 't.tmp') # => 47
13436 *
13437 * # IOs (recall that a File is also an IO).
13438 * src_io = File.open('t.txt', 'r') # => #<File:t.txt>
13439 * dst_io = File.open('t.tmp', 'w') # => #<File:t.tmp>
13440 * IO.copy_stream(src_io, dst_io) # => 47
13441 * src_io.close
13442 * dst_io.close
13443 *
13444 * With argument +src_length+ a non-negative integer,
13445 * no more than that many bytes are copied:
13446 *
13447 * IO.copy_stream('t.txt', 't.tmp', 10) # => 10
13448 * File.read('t.tmp') # => "First line"
13449 *
13450 * With argument +src_offset+ also given,
13451 * the source stream is read beginning at that offset:
13452 *
13453 * IO.copy_stream('t.txt', 't.tmp', 11, 11) # => 11
13454 * IO.read('t.tmp') # => "Second line"
13455 *
13456 */
13457static VALUE
13458rb_io_s_copy_stream(int argc, VALUE *argv, VALUE io)
13459{
13460 VALUE src, dst, length, src_offset;
13461 struct copy_stream_struct st;
13462
13463 MEMZERO(&st, struct copy_stream_struct, 1);
13464
13465 rb_scan_args(argc, argv, "22", &src, &dst, &length, &src_offset);
13466
13467 st.src = src;
13468 st.dst = dst;
13469
13470 st.src_fptr = NULL;
13471 st.dst_fptr = NULL;
13472
13473 if (NIL_P(length))
13474 st.copy_length = (rb_off_t)-1;
13475 else
13476 st.copy_length = NUM2OFFT(length);
13477
13478 if (NIL_P(src_offset))
13479 st.src_offset = (rb_off_t)-1;
13480 else
13481 st.src_offset = NUM2OFFT(src_offset);
13482
13483 rb_ensure(copy_stream_body, (VALUE)&st, copy_stream_finalize, (VALUE)&st);
13484
13485 return OFFT2NUM(st.total);
13486}
13487
13488/*
13489 * call-seq:
13490 * external_encoding -> encoding or nil
13491 *
13492 * Returns the Encoding object that represents the encoding of the stream,
13493 * or +nil+ if the stream is in write mode and no encoding is specified.
13494 *
13495 * See {Encodings}[rdoc-ref:File@Encodings].
13496 *
13497 */
13498
13499static VALUE
13500rb_io_external_encoding(VALUE io)
13501{
13502 rb_io_t *fptr = RFILE(rb_io_taint_check(io))->fptr;
13503
13504 if (fptr->encs.enc2) {
13505 return rb_enc_from_encoding(fptr->encs.enc2);
13506 }
13507 if (fptr->mode & FMODE_WRITABLE) {
13508 if (fptr->encs.enc)
13509 return rb_enc_from_encoding(fptr->encs.enc);
13510 return Qnil;
13511 }
13512 return rb_enc_from_encoding(io_read_encoding(fptr));
13513}
13514
13515/*
13516 * call-seq:
13517 * internal_encoding -> encoding or nil
13518 *
13519 * Returns the Encoding object that represents the encoding of the internal string,
13520 * if conversion is specified,
13521 * or +nil+ otherwise.
13522 *
13523 * See {Encodings}[rdoc-ref:File@Encodings].
13524 *
13525 */
13526
13527static VALUE
13528rb_io_internal_encoding(VALUE io)
13529{
13530 rb_io_t *fptr = RFILE(rb_io_taint_check(io))->fptr;
13531
13532 if (!fptr->encs.enc2) return Qnil;
13533 return rb_enc_from_encoding(io_read_encoding(fptr));
13534}
13535
13536/*
13537 * call-seq:
13538 * set_encoding(ext_enc) -> self
13539 * set_encoding(ext_enc, int_enc, **enc_opts) -> self
13540 * set_encoding('ext_enc:int_enc', **enc_opts) -> self
13541 *
13542 * See {Encodings}[rdoc-ref:File@Encodings].
13543 *
13544 * Argument +ext_enc+, if given, must be an Encoding object
13545 * or a String with the encoding name;
13546 * it is assigned as the encoding for the stream.
13547 *
13548 * Argument +int_enc+, if given, must be an Encoding object
13549 * or a String with the encoding name;
13550 * it is assigned as the encoding for the internal string.
13551 *
13552 * Argument <tt>'ext_enc:int_enc'</tt>, if given, is a string
13553 * containing two colon-separated encoding names;
13554 * corresponding Encoding objects are assigned as the external
13555 * and internal encodings for the stream.
13556 *
13557 * If the external encoding of a string is binary/ASCII-8BIT,
13558 * the internal encoding of the string is set to nil, since no
13559 * transcoding is needed.
13560 *
13561 * Optional keyword arguments +enc_opts+ specify
13562 * {Encoding options}[rdoc-ref:encodings.rdoc@Encoding+Options].
13563 *
13564 */
13565
13566static VALUE
13567rb_io_set_encoding(int argc, VALUE *argv, VALUE io)
13568{
13569 rb_io_t *fptr;
13570 VALUE v1, v2, opt;
13571
13572 if (!RB_TYPE_P(io, T_FILE)) {
13573 return forward(io, id_set_encoding, argc, argv);
13574 }
13575
13576 argc = rb_scan_args(argc, argv, "11:", &v1, &v2, &opt);
13577 GetOpenFile(io, fptr);
13578 io_encoding_set(fptr, v1, v2, opt);
13579 return io;
13580}
13581
13582void
13583rb_stdio_set_default_encoding(void)
13584{
13585 VALUE val = Qnil;
13586
13587#ifdef _WIN32
13588 if (isatty(fileno(stdin))) {
13589 rb_encoding *external = rb_locale_encoding();
13590 rb_encoding *internal = rb_default_internal_encoding();
13591 if (!internal) internal = rb_default_external_encoding();
13592 io_encoding_set(RFILE(rb_stdin)->fptr,
13593 rb_enc_from_encoding(external),
13594 rb_enc_from_encoding(internal),
13595 Qnil);
13596 }
13597 else
13598#endif
13599 rb_io_set_encoding(1, &val, rb_stdin);
13600 rb_io_set_encoding(1, &val, rb_stdout);
13601 rb_io_set_encoding(1, &val, rb_stderr);
13602}
13603
13604static inline int
13605global_argf_p(VALUE arg)
13606{
13607 return arg == argf;
13608}
13609
13610typedef VALUE (*argf_encoding_func)(VALUE io);
13611
13612static VALUE
13613argf_encoding(VALUE argf, argf_encoding_func func)
13614{
13615 if (!RTEST(ARGF.current_file)) {
13616 return rb_enc_default_external();
13617 }
13618 return func(rb_io_check_io(ARGF.current_file));
13619}
13620
13621/*
13622 * call-seq:
13623 * ARGF.external_encoding -> encoding
13624 *
13625 * Returns the external encoding for files read from ARGF as an Encoding
13626 * object. The external encoding is the encoding of the text as stored in a
13627 * file. Contrast with ARGF.internal_encoding, which is the encoding used to
13628 * represent this text within Ruby.
13629 *
13630 * To set the external encoding use ARGF.set_encoding.
13631 *
13632 * For example:
13633 *
13634 * ARGF.external_encoding #=> #<Encoding:UTF-8>
13635 *
13636 */
13637static VALUE
13638argf_external_encoding(VALUE argf)
13639{
13640 return argf_encoding(argf, rb_io_external_encoding);
13641}
13642
13643/*
13644 * call-seq:
13645 * ARGF.internal_encoding -> encoding
13646 *
13647 * Returns the internal encoding for strings read from ARGF as an
13648 * Encoding object.
13649 *
13650 * If ARGF.set_encoding has been called with two encoding names, the second
13651 * is returned. Otherwise, if +Encoding.default_external+ has been set, that
13652 * value is returned. Failing that, if a default external encoding was
13653 * specified on the command-line, that value is used. If the encoding is
13654 * unknown, +nil+ is returned.
13655 */
13656static VALUE
13657argf_internal_encoding(VALUE argf)
13658{
13659 return argf_encoding(argf, rb_io_internal_encoding);
13660}
13661
13662/*
13663 * call-seq:
13664 * ARGF.set_encoding(ext_enc) -> ARGF
13665 * ARGF.set_encoding("ext_enc:int_enc") -> ARGF
13666 * ARGF.set_encoding(ext_enc, int_enc) -> ARGF
13667 * ARGF.set_encoding("ext_enc:int_enc", opt) -> ARGF
13668 * ARGF.set_encoding(ext_enc, int_enc, opt) -> ARGF
13669 *
13670 * If single argument is specified, strings read from ARGF are tagged with
13671 * the encoding specified.
13672 *
13673 * If two encoding names separated by a colon are given, e.g. "ascii:utf-8",
13674 * the read string is converted from the first encoding (external encoding)
13675 * to the second encoding (internal encoding), then tagged with the second
13676 * encoding.
13677 *
13678 * If two arguments are specified, they must be encoding objects or encoding
13679 * names. Again, the first specifies the external encoding; the second
13680 * specifies the internal encoding.
13681 *
13682 * If the external encoding and the internal encoding are specified, the
13683 * optional Hash argument can be used to adjust the conversion process. The
13684 * structure of this hash is explained in the String#encode documentation.
13685 *
13686 * For example:
13687 *
13688 * ARGF.set_encoding('ascii') # Tag the input as US-ASCII text
13689 * ARGF.set_encoding(Encoding::UTF_8) # Tag the input as UTF-8 text
13690 * ARGF.set_encoding('utf-8','ascii') # Transcode the input from US-ASCII
13691 * # to UTF-8.
13692 */
13693static VALUE
13694argf_set_encoding(int argc, VALUE *argv, VALUE argf)
13695{
13696 rb_io_t *fptr;
13697
13698 if (!next_argv()) {
13699 rb_raise(rb_eArgError, "no stream to set encoding");
13700 }
13701 rb_io_set_encoding(argc, argv, ARGF.current_file);
13702 GetOpenFile(ARGF.current_file, fptr);
13703 ARGF.encs = fptr->encs;
13704 return argf;
13705}
13706
13707/*
13708 * call-seq:
13709 * ARGF.tell -> Integer
13710 * ARGF.pos -> Integer
13711 *
13712 * Returns the current offset (in bytes) of the current file in ARGF.
13713 *
13714 * ARGF.pos #=> 0
13715 * ARGF.gets #=> "This is line one\n"
13716 * ARGF.pos #=> 17
13717 *
13718 */
13719static VALUE
13720argf_tell(VALUE argf)
13721{
13722 if (!next_argv()) {
13723 rb_raise(rb_eArgError, "no stream to tell");
13724 }
13725 ARGF_FORWARD(0, 0);
13726 return rb_io_tell(ARGF.current_file);
13727}
13728
13729/*
13730 * call-seq:
13731 * ARGF.seek(amount, whence=IO::SEEK_SET) -> 0
13732 *
13733 * Seeks to offset _amount_ (an Integer) in the ARGF stream according to
13734 * the value of _whence_. See IO#seek for further details.
13735 */
13736static VALUE
13737argf_seek_m(int argc, VALUE *argv, VALUE argf)
13738{
13739 if (!next_argv()) {
13740 rb_raise(rb_eArgError, "no stream to seek");
13741 }
13742 ARGF_FORWARD(argc, argv);
13743 return rb_io_seek_m(argc, argv, ARGF.current_file);
13744}
13745
13746/*
13747 * call-seq:
13748 * ARGF.pos = position -> Integer
13749 *
13750 * Seeks to the position given by _position_ (in bytes) in ARGF.
13751 *
13752 * For example:
13753 *
13754 * ARGF.pos = 17
13755 * ARGF.gets #=> "This is line two\n"
13756 */
13757static VALUE
13758argf_set_pos(VALUE argf, VALUE offset)
13759{
13760 if (!next_argv()) {
13761 rb_raise(rb_eArgError, "no stream to set position");
13762 }
13763 ARGF_FORWARD(1, &offset);
13764 return rb_io_set_pos(ARGF.current_file, offset);
13765}
13766
13767/*
13768 * call-seq:
13769 * ARGF.rewind -> 0
13770 *
13771 * Positions the current file to the beginning of input, resetting
13772 * ARGF.lineno to zero.
13773 *
13774 * ARGF.readline #=> "This is line one\n"
13775 * ARGF.rewind #=> 0
13776 * ARGF.lineno #=> 0
13777 * ARGF.readline #=> "This is line one\n"
13778 */
13779static VALUE
13780argf_rewind(VALUE argf)
13781{
13782 VALUE ret;
13783 int old_lineno;
13784
13785 if (!next_argv()) {
13786 rb_raise(rb_eArgError, "no stream to rewind");
13787 }
13788 ARGF_FORWARD(0, 0);
13789 old_lineno = RFILE(ARGF.current_file)->fptr->lineno;
13790 ret = rb_io_rewind(ARGF.current_file);
13791 if (!global_argf_p(argf)) {
13792 ARGF.last_lineno = ARGF.lineno -= old_lineno;
13793 }
13794 return ret;
13795}
13796
13797/*
13798 * call-seq:
13799 * ARGF.fileno -> integer
13800 * ARGF.to_i -> integer
13801 *
13802 * Returns an integer representing the numeric file descriptor for
13803 * the current file. Raises an ArgumentError if there isn't a current file.
13804 *
13805 * ARGF.fileno #=> 3
13806 */
13807static VALUE
13808argf_fileno(VALUE argf)
13809{
13810 if (!next_argv()) {
13811 rb_raise(rb_eArgError, "no stream");
13812 }
13813 ARGF_FORWARD(0, 0);
13814 return rb_io_fileno(ARGF.current_file);
13815}
13816
13817/*
13818 * call-seq:
13819 * ARGF.to_io -> IO
13820 *
13821 * Returns an IO object representing the current file. This will be a
13822 * File object unless the current file is a stream such as STDIN.
13823 *
13824 * For example:
13825 *
13826 * ARGF.to_io #=> #<File:glark.txt>
13827 * ARGF.to_io #=> #<IO:<STDIN>>
13828 */
13829static VALUE
13830argf_to_io(VALUE argf)
13831{
13832 next_argv();
13833 ARGF_FORWARD(0, 0);
13834 return ARGF.current_file;
13835}
13836
13837/*
13838 * call-seq:
13839 * ARGF.eof? -> true or false
13840 * ARGF.eof -> true or false
13841 *
13842 * Returns true if the current file in ARGF is at end of file, i.e. it has
13843 * no data to read. The stream must be opened for reading or an IOError
13844 * will be raised.
13845 *
13846 * $ echo "eof" | ruby argf.rb
13847 *
13848 * ARGF.eof? #=> false
13849 * 3.times { ARGF.readchar }
13850 * ARGF.eof? #=> false
13851 * ARGF.readchar #=> "\n"
13852 * ARGF.eof? #=> true
13853 */
13854
13855static VALUE
13856argf_eof(VALUE argf)
13857{
13858 next_argv();
13859 if (RTEST(ARGF.current_file)) {
13860 if (ARGF.init_p == 0) return Qtrue;
13861 next_argv();
13862 ARGF_FORWARD(0, 0);
13863 if (rb_io_eof(ARGF.current_file)) {
13864 return Qtrue;
13865 }
13866 }
13867 return Qfalse;
13868}
13869
13870/*
13871 * call-seq:
13872 * ARGF.read([length [, outbuf]]) -> string, outbuf, or nil
13873 *
13874 * Reads _length_ bytes from ARGF. The files named on the command line
13875 * are concatenated and treated as a single file by this method, so when
13876 * called without arguments the contents of this pseudo file are returned in
13877 * their entirety.
13878 *
13879 * _length_ must be a non-negative integer or +nil+.
13880 *
13881 * If _length_ is a positive integer, +read+ tries to read
13882 * _length_ bytes without any conversion (binary mode).
13883 * It returns +nil+ if an EOF is encountered before anything can be read.
13884 * Fewer than _length_ bytes are returned if an EOF is encountered during
13885 * the read.
13886 * In the case of an integer _length_, the resulting string is always
13887 * in ASCII-8BIT encoding.
13888 *
13889 * If _length_ is omitted or is +nil+, it reads until EOF
13890 * and the encoding conversion is applied, if applicable.
13891 * A string is returned even if EOF is encountered before any data is read.
13892 *
13893 * If _length_ is zero, it returns an empty string (<code>""</code>).
13894 *
13895 * If the optional _outbuf_ argument is present,
13896 * it must reference a String, which will receive the data.
13897 * The _outbuf_ will contain only the received data after the method call
13898 * even if it is not empty at the beginning.
13899 *
13900 * For example:
13901 *
13902 * $ echo "small" > small.txt
13903 * $ echo "large" > large.txt
13904 * $ ./glark.rb small.txt large.txt
13905 *
13906 * ARGF.read #=> "small\nlarge"
13907 * ARGF.read(200) #=> "small\nlarge"
13908 * ARGF.read(2) #=> "sm"
13909 * ARGF.read(0) #=> ""
13910 *
13911 * Note that this method behaves like the fread() function in C.
13912 * This means it retries to invoke read(2) system calls to read data
13913 * with the specified length.
13914 * If you need the behavior like a single read(2) system call,
13915 * consider ARGF#readpartial or ARGF#read_nonblock.
13916 */
13917
13918static VALUE
13919argf_read(int argc, VALUE *argv, VALUE argf)
13920{
13921 VALUE tmp, str, length;
13922 long len = 0;
13923
13924 rb_scan_args(argc, argv, "02", &length, &str);
13925 if (!NIL_P(length)) {
13926 len = NUM2LONG(argv[0]);
13927 }
13928 if (!NIL_P(str)) {
13929 StringValue(str);
13930 rb_str_resize(str,0);
13931 argv[1] = Qnil;
13932 }
13933
13934 retry:
13935 if (!next_argv()) {
13936 return str;
13937 }
13938 if (ARGF_GENERIC_INPUT_P()) {
13939 tmp = argf_forward(argc, argv, argf);
13940 }
13941 else {
13942 tmp = io_read(argc, argv, ARGF.current_file);
13943 }
13944 if (NIL_P(str)) str = tmp;
13945 else if (!NIL_P(tmp)) rb_str_append(str, tmp);
13946 if (NIL_P(tmp) || NIL_P(length)) {
13947 if (ARGF.next_p != -1) {
13948 argf_close(argf);
13949 ARGF.next_p = 1;
13950 goto retry;
13951 }
13952 }
13953 else if (argc >= 1) {
13954 long slen = RSTRING_LEN(str);
13955 if (slen < len) {
13956 argv[0] = LONG2NUM(len - slen);
13957 goto retry;
13958 }
13959 }
13960 return str;
13961}
13962
13964 int argc;
13965 VALUE *argv;
13966 VALUE argf;
13967};
13968
13969static VALUE
13970argf_forward_call(VALUE arg)
13971{
13972 struct argf_call_arg *p = (struct argf_call_arg *)arg;
13973 argf_forward(p->argc, p->argv, p->argf);
13974 return Qnil;
13975}
13976
13977static VALUE argf_getpartial(int argc, VALUE *argv, VALUE argf, VALUE opts,
13978 int nonblock);
13979
13980/*
13981 * call-seq:
13982 * ARGF.readpartial(maxlen) -> string
13983 * ARGF.readpartial(maxlen, outbuf) -> outbuf
13984 *
13985 * Reads at most _maxlen_ bytes from the ARGF stream.
13986 *
13987 * If the optional _outbuf_ argument is present,
13988 * it must reference a String, which will receive the data.
13989 * The _outbuf_ will contain only the received data after the method call
13990 * even if it is not empty at the beginning.
13991 *
13992 * It raises EOFError on end of ARGF stream.
13993 * Since ARGF stream is a concatenation of multiple files,
13994 * internally EOF is occur for each file.
13995 * ARGF.readpartial returns empty strings for EOFs except the last one and
13996 * raises EOFError for the last one.
13997 *
13998 */
13999
14000static VALUE
14001argf_readpartial(int argc, VALUE *argv, VALUE argf)
14002{
14003 return argf_getpartial(argc, argv, argf, Qnil, 0);
14004}
14005
14006/*
14007 * call-seq:
14008 * ARGF.read_nonblock(maxlen[, options]) -> string
14009 * ARGF.read_nonblock(maxlen, outbuf[, options]) -> outbuf
14010 *
14011 * Reads at most _maxlen_ bytes from the ARGF stream in non-blocking mode.
14012 */
14013
14014static VALUE
14015argf_read_nonblock(int argc, VALUE *argv, VALUE argf)
14016{
14017 VALUE opts;
14018
14019 rb_scan_args(argc, argv, "11:", NULL, NULL, &opts);
14020
14021 if (!NIL_P(opts))
14022 argc--;
14023
14024 return argf_getpartial(argc, argv, argf, opts, 1);
14025}
14026
14027static VALUE
14028argf_getpartial(int argc, VALUE *argv, VALUE argf, VALUE opts, int nonblock)
14029{
14030 VALUE tmp, str, length;
14031 int no_exception;
14032
14033 rb_scan_args(argc, argv, "11", &length, &str);
14034 if (!NIL_P(str)) {
14035 StringValue(str);
14036 argv[1] = str;
14037 }
14038 no_exception = no_exception_p(opts);
14039
14040 if (!next_argv()) {
14041 if (!NIL_P(str)) {
14042 rb_str_resize(str, 0);
14043 }
14044 rb_eof_error();
14045 }
14046 if (ARGF_GENERIC_INPUT_P()) {
14047 VALUE (*const rescue_does_nothing)(VALUE, VALUE) = 0;
14048 struct argf_call_arg arg;
14049 arg.argc = argc;
14050 arg.argv = argv;
14051 arg.argf = argf;
14052 tmp = rb_rescue2(argf_forward_call, (VALUE)&arg,
14053 rescue_does_nothing, Qnil, rb_eEOFError, (VALUE)0);
14054 }
14055 else {
14056 tmp = io_getpartial(argc, argv, ARGF.current_file, no_exception, nonblock);
14057 }
14058 if (NIL_P(tmp)) {
14059 if (ARGF.next_p == -1) {
14060 return io_nonblock_eof(no_exception);
14061 }
14062 argf_close(argf);
14063 ARGF.next_p = 1;
14064 if (RARRAY_LEN(ARGF.argv) == 0) {
14065 return io_nonblock_eof(no_exception);
14066 }
14067 if (NIL_P(str))
14068 str = rb_str_new(NULL, 0);
14069 return str;
14070 }
14071 return tmp;
14072}
14073
14074/*
14075 * call-seq:
14076 * ARGF.getc -> String or nil
14077 *
14078 * Reads the next character from ARGF and returns it as a String. Returns
14079 * +nil+ at the end of the stream.
14080 *
14081 * ARGF treats the files named on the command line as a single file created
14082 * by concatenating their contents. After returning the last character of the
14083 * first file, it returns the first character of the second file, and so on.
14084 *
14085 * For example:
14086 *
14087 * $ echo "foo" > file
14088 * $ ruby argf.rb file
14089 *
14090 * ARGF.getc #=> "f"
14091 * ARGF.getc #=> "o"
14092 * ARGF.getc #=> "o"
14093 * ARGF.getc #=> "\n"
14094 * ARGF.getc #=> nil
14095 * ARGF.getc #=> nil
14096 */
14097static VALUE
14098argf_getc(VALUE argf)
14099{
14100 VALUE ch;
14101
14102 retry:
14103 if (!next_argv()) return Qnil;
14104 if (ARGF_GENERIC_INPUT_P()) {
14105 ch = forward_current(rb_intern("getc"), 0, 0);
14106 }
14107 else {
14108 ch = rb_io_getc(ARGF.current_file);
14109 }
14110 if (NIL_P(ch) && ARGF.next_p != -1) {
14111 argf_close(argf);
14112 ARGF.next_p = 1;
14113 goto retry;
14114 }
14115
14116 return ch;
14117}
14118
14119/*
14120 * call-seq:
14121 * ARGF.getbyte -> Integer or nil
14122 *
14123 * Gets the next 8-bit byte (0..255) from ARGF. Returns +nil+ if called at
14124 * the end of the stream.
14125 *
14126 * For example:
14127 *
14128 * $ echo "foo" > file
14129 * $ ruby argf.rb file
14130 *
14131 * ARGF.getbyte #=> 102
14132 * ARGF.getbyte #=> 111
14133 * ARGF.getbyte #=> 111
14134 * ARGF.getbyte #=> 10
14135 * ARGF.getbyte #=> nil
14136 */
14137static VALUE
14138argf_getbyte(VALUE argf)
14139{
14140 VALUE ch;
14141
14142 retry:
14143 if (!next_argv()) return Qnil;
14144 if (!RB_TYPE_P(ARGF.current_file, T_FILE)) {
14145 ch = forward_current(rb_intern("getbyte"), 0, 0);
14146 }
14147 else {
14148 ch = rb_io_getbyte(ARGF.current_file);
14149 }
14150 if (NIL_P(ch) && ARGF.next_p != -1) {
14151 argf_close(argf);
14152 ARGF.next_p = 1;
14153 goto retry;
14154 }
14155
14156 return ch;
14157}
14158
14159/*
14160 * call-seq:
14161 * ARGF.readchar -> String or nil
14162 *
14163 * Reads the next character from ARGF and returns it as a String. Raises
14164 * an EOFError after the last character of the last file has been read.
14165 *
14166 * For example:
14167 *
14168 * $ echo "foo" > file
14169 * $ ruby argf.rb file
14170 *
14171 * ARGF.readchar #=> "f"
14172 * ARGF.readchar #=> "o"
14173 * ARGF.readchar #=> "o"
14174 * ARGF.readchar #=> "\n"
14175 * ARGF.readchar #=> end of file reached (EOFError)
14176 */
14177static VALUE
14178argf_readchar(VALUE argf)
14179{
14180 VALUE ch;
14181
14182 retry:
14183 if (!next_argv()) rb_eof_error();
14184 if (!RB_TYPE_P(ARGF.current_file, T_FILE)) {
14185 ch = forward_current(rb_intern("getc"), 0, 0);
14186 }
14187 else {
14188 ch = rb_io_getc(ARGF.current_file);
14189 }
14190 if (NIL_P(ch) && ARGF.next_p != -1) {
14191 argf_close(argf);
14192 ARGF.next_p = 1;
14193 goto retry;
14194 }
14195
14196 return ch;
14197}
14198
14199/*
14200 * call-seq:
14201 * ARGF.readbyte -> Integer
14202 *
14203 * Reads the next 8-bit byte from ARGF and returns it as an Integer. Raises
14204 * an EOFError after the last byte of the last file has been read.
14205 *
14206 * For example:
14207 *
14208 * $ echo "foo" > file
14209 * $ ruby argf.rb file
14210 *
14211 * ARGF.readbyte #=> 102
14212 * ARGF.readbyte #=> 111
14213 * ARGF.readbyte #=> 111
14214 * ARGF.readbyte #=> 10
14215 * ARGF.readbyte #=> end of file reached (EOFError)
14216 */
14217static VALUE
14218argf_readbyte(VALUE argf)
14219{
14220 VALUE c;
14221
14222 NEXT_ARGF_FORWARD(0, 0);
14223 c = argf_getbyte(argf);
14224 if (NIL_P(c)) {
14225 rb_eof_error();
14226 }
14227 return c;
14228}
14229
14230#define FOREACH_ARGF() while (next_argv())
14231
14232static VALUE
14233argf_block_call_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, argf))
14234{
14235 const VALUE current = ARGF.current_file;
14236 rb_yield_values2(argc, argv);
14237 if (ARGF.init_p == -1 || current != ARGF.current_file) {
14239 }
14240 return Qnil;
14241}
14242
14243#define ARGF_block_call(mid, argc, argv, func, argf) \
14244 rb_block_call_kw(ARGF.current_file, mid, argc, argv, \
14245 func, argf, rb_keyword_given_p())
14246
14247static void
14248argf_block_call(ID mid, int argc, VALUE *argv, VALUE argf)
14249{
14250 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_i, argf);
14251 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14252}
14253
14254static VALUE
14255argf_block_call_line_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, argf))
14256{
14257 if (!global_argf_p(argf)) {
14258 ARGF.last_lineno = ++ARGF.lineno;
14259 }
14260 return argf_block_call_i(i, argf, argc, argv, blockarg);
14261}
14262
14263static void
14264argf_block_call_line(ID mid, int argc, VALUE *argv, VALUE argf)
14265{
14266 VALUE ret = ARGF_block_call(mid, argc, argv, argf_block_call_line_i, argf);
14267 if (!UNDEF_P(ret)) ARGF.next_p = 1;
14268}
14269
14270/*
14271 * call-seq:
14272 * ARGF.each(sep=$/) {|line| block } -> ARGF
14273 * ARGF.each(sep=$/, limit) {|line| block } -> ARGF
14274 * ARGF.each(...) -> an_enumerator
14275 *
14276 * ARGF.each_line(sep=$/) {|line| block } -> ARGF
14277 * ARGF.each_line(sep=$/, limit) {|line| block } -> ARGF
14278 * ARGF.each_line(...) -> an_enumerator
14279 *
14280 * Returns an enumerator which iterates over each line (separated by _sep_,
14281 * which defaults to your platform's newline character) of each file in
14282 * +ARGV+. If a block is supplied, each line in turn will be yielded to the
14283 * block, otherwise an enumerator is returned.
14284 * The optional _limit_ argument is an Integer specifying the maximum
14285 * length of each line; longer lines will be split according to this limit.
14286 *
14287 * This method allows you to treat the files supplied on the command line as
14288 * a single file consisting of the concatenation of each named file. After
14289 * the last line of the first file has been returned, the first line of the
14290 * second file is returned. The ARGF.filename and ARGF.lineno methods can be
14291 * used to determine the filename of the current line and line number of the
14292 * whole input, respectively.
14293 *
14294 * For example, the following code prints out each line of each named file
14295 * prefixed with its line number, displaying the filename once per file:
14296 *
14297 * ARGF.each_line do |line|
14298 * puts ARGF.filename if ARGF.file.lineno == 1
14299 * puts "#{ARGF.file.lineno}: #{line}"
14300 * end
14301 *
14302 * While the following code prints only the first file's name at first, and
14303 * the contents with line number counted through all named files.
14304 *
14305 * ARGF.each_line do |line|
14306 * puts ARGF.filename if ARGF.lineno == 1
14307 * puts "#{ARGF.lineno}: #{line}"
14308 * end
14309 */
14310static VALUE
14311argf_each_line(int argc, VALUE *argv, VALUE argf)
14312{
14313 RETURN_ENUMERATOR(argf, argc, argv);
14314 FOREACH_ARGF() {
14315 argf_block_call_line(rb_intern("each_line"), argc, argv, argf);
14316 }
14317 return argf;
14318}
14319
14320/*
14321 * call-seq:
14322 * ARGF.each_byte {|byte| block } -> ARGF
14323 * ARGF.each_byte -> an_enumerator
14324 *
14325 * Iterates over each byte of each file in +ARGV+.
14326 * A byte is returned as an Integer in the range 0..255.
14327 *
14328 * This method allows you to treat the files supplied on the command line as
14329 * a single file consisting of the concatenation of each named file. After
14330 * the last byte of the first file has been returned, the first byte of the
14331 * second file is returned. The ARGF.filename method can be used to
14332 * determine the filename of the current byte.
14333 *
14334 * If no block is given, an enumerator is returned instead.
14335 *
14336 * For example:
14337 *
14338 * ARGF.bytes.to_a #=> [35, 32, ... 95, 10]
14339 *
14340 */
14341static VALUE
14342argf_each_byte(VALUE argf)
14343{
14344 RETURN_ENUMERATOR(argf, 0, 0);
14345 FOREACH_ARGF() {
14346 argf_block_call(rb_intern("each_byte"), 0, 0, argf);
14347 }
14348 return argf;
14349}
14350
14351/*
14352 * call-seq:
14353 * ARGF.each_char {|char| block } -> ARGF
14354 * ARGF.each_char -> an_enumerator
14355 *
14356 * Iterates over each character of each file in ARGF.
14357 *
14358 * This method allows you to treat the files supplied on the command line as
14359 * a single file consisting of the concatenation of each named file. After
14360 * the last character of the first file has been returned, the first
14361 * character of the second file is returned. The ARGF.filename method can
14362 * be used to determine the name of the file in which the current character
14363 * appears.
14364 *
14365 * If no block is given, an enumerator is returned instead.
14366 */
14367static VALUE
14368argf_each_char(VALUE argf)
14369{
14370 RETURN_ENUMERATOR(argf, 0, 0);
14371 FOREACH_ARGF() {
14372 argf_block_call(rb_intern("each_char"), 0, 0, argf);
14373 }
14374 return argf;
14375}
14376
14377/*
14378 * call-seq:
14379 * ARGF.each_codepoint {|codepoint| block } -> ARGF
14380 * ARGF.each_codepoint -> an_enumerator
14381 *
14382 * Iterates over each codepoint of each file in ARGF.
14383 *
14384 * This method allows you to treat the files supplied on the command line as
14385 * a single file consisting of the concatenation of each named file. After
14386 * the last codepoint of the first file has been returned, the first
14387 * codepoint of the second file is returned. The ARGF.filename method can
14388 * be used to determine the name of the file in which the current codepoint
14389 * appears.
14390 *
14391 * If no block is given, an enumerator is returned instead.
14392 */
14393static VALUE
14394argf_each_codepoint(VALUE argf)
14395{
14396 RETURN_ENUMERATOR(argf, 0, 0);
14397 FOREACH_ARGF() {
14398 argf_block_call(rb_intern("each_codepoint"), 0, 0, argf);
14399 }
14400 return argf;
14401}
14402
14403/*
14404 * call-seq:
14405 * ARGF.filename -> String
14406 * ARGF.path -> String
14407 *
14408 * Returns the current filename. "-" is returned when the current file is
14409 * STDIN.
14410 *
14411 * For example:
14412 *
14413 * $ echo "foo" > foo
14414 * $ echo "bar" > bar
14415 * $ echo "glark" > glark
14416 *
14417 * $ ruby argf.rb foo bar glark
14418 *
14419 * ARGF.filename #=> "foo"
14420 * ARGF.read(5) #=> "foo\nb"
14421 * ARGF.filename #=> "bar"
14422 * ARGF.skip
14423 * ARGF.filename #=> "glark"
14424 */
14425static VALUE
14426argf_filename(VALUE argf)
14427{
14428 next_argv();
14429 return ARGF.filename;
14430}
14431
14432static VALUE
14433argf_filename_getter(ID id, VALUE *var)
14434{
14435 return argf_filename(*var);
14436}
14437
14438/*
14439 * call-seq:
14440 * ARGF.file -> IO or File object
14441 *
14442 * Returns the current file as an IO or File object.
14443 * <code>$stdin</code> is returned when the current file is STDIN.
14444 *
14445 * For example:
14446 *
14447 * $ echo "foo" > foo
14448 * $ echo "bar" > bar
14449 *
14450 * $ ruby argf.rb foo bar
14451 *
14452 * ARGF.file #=> #<File:foo>
14453 * ARGF.read(5) #=> "foo\nb"
14454 * ARGF.file #=> #<File:bar>
14455 */
14456static VALUE
14457argf_file(VALUE argf)
14458{
14459 next_argv();
14460 return ARGF.current_file;
14461}
14462
14463/*
14464 * call-seq:
14465 * ARGF.binmode -> ARGF
14466 *
14467 * Puts ARGF into binary mode. Once a stream is in binary mode, it cannot
14468 * be reset to non-binary mode. This option has the following effects:
14469 *
14470 * * Newline conversion is disabled.
14471 * * Encoding conversion is disabled.
14472 * * Content is treated as ASCII-8BIT.
14473 */
14474static VALUE
14475argf_binmode_m(VALUE argf)
14476{
14477 ARGF.binmode = 1;
14478 next_argv();
14479 ARGF_FORWARD(0, 0);
14480 rb_io_ascii8bit_binmode(ARGF.current_file);
14481 return argf;
14482}
14483
14484/*
14485 * call-seq:
14486 * ARGF.binmode? -> true or false
14487 *
14488 * Returns true if ARGF is being read in binary mode; false otherwise.
14489 * To enable binary mode use ARGF.binmode.
14490 *
14491 * For example:
14492 *
14493 * ARGF.binmode? #=> false
14494 * ARGF.binmode
14495 * ARGF.binmode? #=> true
14496 */
14497static VALUE
14498argf_binmode_p(VALUE argf)
14499{
14500 return RBOOL(ARGF.binmode);
14501}
14502
14503/*
14504 * call-seq:
14505 * ARGF.skip -> ARGF
14506 *
14507 * Sets the current file to the next file in ARGV. If there aren't any more
14508 * files it has no effect.
14509 *
14510 * For example:
14511 *
14512 * $ ruby argf.rb foo bar
14513 * ARGF.filename #=> "foo"
14514 * ARGF.skip
14515 * ARGF.filename #=> "bar"
14516 */
14517static VALUE
14518argf_skip(VALUE argf)
14519{
14520 if (ARGF.init_p && ARGF.next_p == 0) {
14521 argf_close(argf);
14522 ARGF.next_p = 1;
14523 }
14524 return argf;
14525}
14526
14527/*
14528 * call-seq:
14529 * ARGF.close -> ARGF
14530 *
14531 * Closes the current file and skips to the next file in ARGV. If there are
14532 * no more files to open, just closes the current file. STDIN will not be
14533 * closed.
14534 *
14535 * For example:
14536 *
14537 * $ ruby argf.rb foo bar
14538 *
14539 * ARGF.filename #=> "foo"
14540 * ARGF.close
14541 * ARGF.filename #=> "bar"
14542 * ARGF.close
14543 */
14544static VALUE
14545argf_close_m(VALUE argf)
14546{
14547 next_argv();
14548 argf_close(argf);
14549 if (ARGF.next_p != -1) {
14550 ARGF.next_p = 1;
14551 }
14552 ARGF.lineno = 0;
14553 return argf;
14554}
14555
14556/*
14557 * call-seq:
14558 * ARGF.closed? -> true or false
14559 *
14560 * Returns _true_ if the current file has been closed; _false_ otherwise. Use
14561 * ARGF.close to actually close the current file.
14562 */
14563static VALUE
14564argf_closed(VALUE argf)
14565{
14566 next_argv();
14567 ARGF_FORWARD(0, 0);
14568 return rb_io_closed_p(ARGF.current_file);
14569}
14570
14571/*
14572 * call-seq:
14573 * ARGF.to_s -> String
14574 *
14575 * Returns "ARGF".
14576 */
14577static VALUE
14578argf_to_s(VALUE argf)
14579{
14580 return rb_str_new2("ARGF");
14581}
14582
14583/*
14584 * call-seq:
14585 * ARGF.inplace_mode -> String
14586 *
14587 * Returns the file extension appended to the names of backup copies of
14588 * modified files under in-place edit mode. This value can be set using
14589 * ARGF.inplace_mode= or passing the +-i+ switch to the Ruby binary.
14590 */
14591static VALUE
14592argf_inplace_mode_get(VALUE argf)
14593{
14594 if (!ARGF.inplace) return Qnil;
14595 if (NIL_P(ARGF.inplace)) return rb_str_new(0, 0);
14596 return rb_str_dup(ARGF.inplace);
14597}
14598
14599static VALUE
14600opt_i_get(ID id, VALUE *var)
14601{
14602 return argf_inplace_mode_get(*var);
14603}
14604
14605/*
14606 * call-seq:
14607 * ARGF.inplace_mode = ext -> ARGF
14608 *
14609 * Sets the filename extension for in-place editing mode to the given String.
14610 * The backup copy of each file being edited has this value appended to its
14611 * filename.
14612 *
14613 * For example:
14614 *
14615 * $ ruby argf.rb file.txt
14616 *
14617 * ARGF.inplace_mode = '.bak'
14618 * ARGF.each_line do |line|
14619 * print line.sub("foo","bar")
14620 * end
14621 *
14622 * First, _file.txt.bak_ is created as a backup copy of _file.txt_.
14623 * Then, each line of _file.txt_ has the first occurrence of "foo" replaced with
14624 * "bar".
14625 */
14626static VALUE
14627argf_inplace_mode_set(VALUE argf, VALUE val)
14628{
14629 if (!RTEST(val)) {
14630 ARGF.inplace = Qfalse;
14631 }
14632 else if (StringValueCStr(val), !RSTRING_LEN(val)) {
14633 ARGF.inplace = Qnil;
14634 }
14635 else {
14636 ARGF.inplace = rb_str_new_frozen(val);
14637 }
14638 return argf;
14639}
14640
14641static void
14642opt_i_set(VALUE val, ID id, VALUE *var)
14643{
14644 argf_inplace_mode_set(*var, val);
14645}
14646
14647void
14648ruby_set_inplace_mode(const char *suffix)
14649{
14650 ARGF.inplace = !suffix ? Qfalse : !*suffix ? Qnil : rb_str_new(suffix, strlen(suffix));
14651}
14652
14653/*
14654 * call-seq:
14655 * ARGF.argv -> ARGV
14656 *
14657 * Returns the +ARGV+ array, which contains the arguments passed to your
14658 * script, one per element.
14659 *
14660 * For example:
14661 *
14662 * $ ruby argf.rb -v glark.txt
14663 *
14664 * ARGF.argv #=> ["-v", "glark.txt"]
14665 *
14666 */
14667static VALUE
14668argf_argv(VALUE argf)
14669{
14670 return ARGF.argv;
14671}
14672
14673static VALUE
14674argf_argv_getter(ID id, VALUE *var)
14675{
14676 return argf_argv(*var);
14677}
14678
14679VALUE
14681{
14682 return ARGF.argv;
14683}
14684
14685/*
14686 * call-seq:
14687 * ARGF.to_write_io -> io
14688 *
14689 * Returns IO instance tied to _ARGF_ for writing if inplace mode is
14690 * enabled.
14691 */
14692static VALUE
14693argf_write_io(VALUE argf)
14694{
14695 if (!RTEST(ARGF.current_file)) {
14696 rb_raise(rb_eIOError, "not opened for writing");
14697 }
14698 return GetWriteIO(ARGF.current_file);
14699}
14700
14701/*
14702 * call-seq:
14703 * ARGF.write(*objects) -> integer
14704 *
14705 * Writes each of the given +objects+ if inplace mode.
14706 */
14707static VALUE
14708argf_write(int argc, VALUE *argv, VALUE argf)
14709{
14710 return rb_io_writev(argf_write_io(argf), argc, argv);
14711}
14712
14713void
14714rb_readwrite_sys_fail(enum rb_io_wait_readwrite waiting, const char *mesg)
14715{
14716 rb_readwrite_syserr_fail(waiting, errno, mesg);
14717}
14718
14719void
14720rb_readwrite_syserr_fail(enum rb_io_wait_readwrite waiting, int n, const char *mesg)
14721{
14722 VALUE arg, c = Qnil;
14723 arg = mesg ? rb_str_new2(mesg) : Qnil;
14724 switch (waiting) {
14725 case RB_IO_WAIT_WRITABLE:
14726 switch (n) {
14727 case EAGAIN:
14728 c = rb_eEAGAINWaitWritable;
14729 break;
14730#if EAGAIN != EWOULDBLOCK
14731 case EWOULDBLOCK:
14732 c = rb_eEWOULDBLOCKWaitWritable;
14733 break;
14734#endif
14735 case EINPROGRESS:
14736 c = rb_eEINPROGRESSWaitWritable;
14737 break;
14738 default:
14740 }
14741 break;
14742 case RB_IO_WAIT_READABLE:
14743 switch (n) {
14744 case EAGAIN:
14745 c = rb_eEAGAINWaitReadable;
14746 break;
14747#if EAGAIN != EWOULDBLOCK
14748 case EWOULDBLOCK:
14749 c = rb_eEWOULDBLOCKWaitReadable;
14750 break;
14751#endif
14752 case EINPROGRESS:
14753 c = rb_eEINPROGRESSWaitReadable;
14754 break;
14755 default:
14757 }
14758 break;
14759 default:
14760 rb_bug("invalid read/write type passed to rb_readwrite_sys_fail: %d", waiting);
14761 }
14763}
14764
14765static VALUE
14766get_LAST_READ_LINE(ID _x, VALUE *_y)
14767{
14768 return rb_lastline_get();
14769}
14770
14771static void
14772set_LAST_READ_LINE(VALUE val, ID _x, VALUE *_y)
14773{
14774 rb_lastline_set(val);
14775}
14776
14777/*
14778 * Document-class: IOError
14779 *
14780 * Raised when an IO operation fails.
14781 *
14782 * File.open("/etc/hosts") {|f| f << "example"}
14783 * #=> IOError: not opened for writing
14784 *
14785 * File.open("/etc/hosts") {|f| f.close; f.read }
14786 * #=> IOError: closed stream
14787 *
14788 * Note that some IO failures raise <code>SystemCallError</code>s
14789 * and these are not subclasses of IOError:
14790 *
14791 * File.open("does/not/exist")
14792 * #=> Errno::ENOENT: No such file or directory - does/not/exist
14793 */
14794
14795/*
14796 * Document-class: EOFError
14797 *
14798 * Raised by some IO operations when reaching the end of file. Many IO
14799 * methods exist in two forms,
14800 *
14801 * one that returns +nil+ when the end of file is reached, the other
14802 * raises EOFError.
14803 *
14804 * EOFError is a subclass of IOError.
14805 *
14806 * file = File.open("/etc/hosts")
14807 * file.read
14808 * file.gets #=> nil
14809 * file.readline #=> EOFError: end of file reached
14810 * file.close
14811 */
14812
14813/*
14814 * Document-class: ARGF
14815 *
14816 * == \ARGF and +ARGV+
14817 *
14818 * The \ARGF object works with the array at global variable +ARGV+
14819 * to make <tt>$stdin</tt> and file streams available in the Ruby program:
14820 *
14821 * - **ARGV** may be thought of as the <b>argument vector</b> array.
14822 *
14823 * Initially, it contains the command-line arguments and options
14824 * that are passed to the Ruby program;
14825 * the program can modify that array as it likes.
14826 *
14827 * - **ARGF** may be thought of as the <b>argument files</b> object.
14828 *
14829 * It can access file streams and/or the <tt>$stdin</tt> stream,
14830 * based on what it finds in +ARGV+.
14831 * This provides a convenient way for the command line
14832 * to specify streams for a Ruby program to read.
14833 *
14834 * == Reading
14835 *
14836 * \ARGF may read from _source_ streams,
14837 * which at any particular time are determined by the content of +ARGV+.
14838 *
14839 * === Simplest Case
14840 *
14841 * When the <i>very first</i> \ARGF read occurs with an empty +ARGV+ (<tt>[]</tt>),
14842 * the source is <tt>$stdin</tt>:
14843 *
14844 * - \File +t.rb+:
14845 *
14846 * p ['ARGV', ARGV]
14847 * p ['ARGF.read', ARGF.read]
14848 *
14849 * - Commands and outputs
14850 * (see below for the content of files +foo.txt+ and +bar.txt+):
14851 *
14852 * $ echo "Open the pod bay doors, Hal." | ruby t.rb
14853 * ["ARGV", []]
14854 * ["ARGF.read", "Open the pod bay doors, Hal.\n"]
14855 *
14856 * $ cat foo.txt bar.txt | ruby t.rb
14857 * ["ARGV", []]
14858 * ["ARGF.read", "Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"]
14859 *
14860 * === About the Examples
14861 *
14862 * Many examples here assume the existence of files +foo.txt+ and +bar.txt+:
14863 *
14864 * $ cat foo.txt
14865 * Foo 0
14866 * Foo 1
14867 * $ cat bar.txt
14868 * Bar 0
14869 * Bar 1
14870 * Bar 2
14871 * Bar 3
14872 *
14873 * === Sources in +ARGV+
14874 *
14875 * For any \ARGF read _except_ the {simplest case}[rdoc-ref:ARGF@Simplest+Case]
14876 * (that is, _except_ for the <i>very first</i> \ARGF read with an empty +ARGV+),
14877 * the sources are found in +ARGV+.
14878 *
14879 * \ARGF assumes that each element in array +ARGV+ is a potential source,
14880 * and is one of:
14881 *
14882 * - The string path to a file that may be opened as a stream.
14883 * - The character <tt>'-'</tt>, meaning stream <tt>$stdin</tt>.
14884 *
14885 * Each element that is _not_ one of these
14886 * should be removed from +ARGV+ before \ARGF accesses that source.
14887 *
14888 * In the following example:
14889 *
14890 * - Filepaths +foo.txt+ and +bar.txt+ may be retained as potential sources.
14891 * - Options <tt>--xyzzy</tt> and <tt>--mojo</tt> should be removed.
14892 *
14893 * Example:
14894 *
14895 * - \File +t.rb+:
14896 *
14897 * # Print arguments (and options, if any) found on command line.
14898 * p ['ARGV', ARGV]
14899 *
14900 * - Command and output:
14901 *
14902 * $ ruby t.rb --xyzzy --mojo foo.txt bar.txt
14903 * ["ARGV", ["--xyzzy", "--mojo", "foo.txt", "bar.txt"]]
14904 *
14905 * \ARGF's stream access considers the elements of +ARGV+, left to right:
14906 *
14907 * - \File +t.rb+:
14908 *
14909 * p "ARGV: #{ARGV}"
14910 * p "Read: #{ARGF.read}" # Read everything from all specified streams.
14911 *
14912 * - Command and output:
14913 *
14914 * $ ruby t.rb foo.txt bar.txt
14915 * "ARGV: [\"foo.txt\", \"bar.txt\"]"
14916 * "Read: Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"
14917 *
14918 * Because the value at +ARGV+ is an ordinary array,
14919 * you can manipulate it to control which sources \ARGF considers:
14920 *
14921 * - If you remove an element from +ARGV+, \ARGF will not consider the corresponding source.
14922 * - If you add an element to +ARGV+, \ARGF will consider the corresponding source.
14923 *
14924 * Each element in +ARGV+ is removed when its corresponding source is accessed;
14925 * when all sources have been accessed, the array is empty:
14926 *
14927 * - \File +t.rb+:
14928 *
14929 * until ARGV.empty? && ARGF.eof?
14930 * p "ARGV: #{ARGV}"
14931 * p "Line: #{ARGF.readline}" # Read each line from each specified stream.
14932 * end
14933 *
14934 * - Command and output:
14935 *
14936 * $ ruby t.rb foo.txt bar.txt
14937 * "ARGV: [\"foo.txt\", \"bar.txt\"]"
14938 * "Line: Foo 0\n"
14939 * "ARGV: [\"bar.txt\"]"
14940 * "Line: Foo 1\n"
14941 * "ARGV: [\"bar.txt\"]"
14942 * "Line: Bar 0\n"
14943 * "ARGV: []"
14944 * "Line: Bar 1\n"
14945 * "ARGV: []"
14946 * "Line: Bar 2\n"
14947 * "ARGV: []"
14948 * "Line: Bar 3\n"
14949 *
14950 * ==== Filepaths in +ARGV+
14951 *
14952 * The +ARGV+ array may contain filepaths the specify sources for \ARGF reading.
14953 *
14954 * This program prints what it reads from files at the paths specified
14955 * on the command line:
14956 *
14957 * - \File +t.rb+:
14958 *
14959 * p ['ARGV', ARGV]
14960 * # Read and print all content from the specified sources.
14961 * p ['ARGF.read', ARGF.read]
14962 *
14963 * - Command and output:
14964 *
14965 * $ ruby t.rb foo.txt bar.txt
14966 * ["ARGV", [foo.txt, bar.txt]
14967 * ["ARGF.read", "Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"]
14968 *
14969 * ==== Specifying <tt>$stdin</tt> in +ARGV+
14970 *
14971 * To specify stream <tt>$stdin</tt> in +ARGV+, us the character <tt>'-'</tt>:
14972 *
14973 * - \File +t.rb+:
14974 *
14975 * p ['ARGV', ARGV]
14976 * p ['ARGF.read', ARGF.read]
14977 *
14978 * - Command and output:
14979 *
14980 * $ echo "Open the pod bay doors, Hal." | ruby t.rb -
14981 * ["ARGV", ["-"]]
14982 * ["ARGF.read", "Open the pod bay doors, Hal.\n"]
14983 *
14984 * When no character <tt>'-'</tt> is given, stream <tt>$stdin</tt> is ignored
14985 * (exception:
14986 * see {Specifying $stdin in ARGV}[rdoc-ref:ARGF@Specifying+-24stdin+in+ARGV]):
14987 *
14988 * - Command and output:
14989 *
14990 * $ echo "Open the pod bay doors, Hal." | ruby t.rb foo.txt bar.txt
14991 * "ARGV: [\"foo.txt\", \"bar.txt\"]"
14992 * "Read: Foo 0\nFoo 1\nBar 0\nBar 1\nBar 2\nBar 3\n"
14993 *
14994 * ==== Mixtures and Repetitions in +ARGV+
14995 *
14996 * For an \ARGF reader, +ARGV+ may contain any mixture of filepaths
14997 * and character <tt>'-'</tt>, including repetitions.
14998 *
14999 * ==== Modifications to +ARGV+
15000 *
15001 * The running Ruby program may make any modifications to the +ARGV+ array;
15002 * the current value of +ARGV+ affects \ARGF reading.
15003 *
15004 * ==== Empty +ARGV+
15005 *
15006 * For an empty +ARGV+, an \ARGF read method either returns +nil+
15007 * or raises an exception, depending on the specific method.
15008 *
15009 * === More Read Methods
15010 *
15011 * As seen above, method ARGF#read reads the content of all sources
15012 * into a single string.
15013 * Other \ARGF methods provide other ways to access that content;
15014 * these include:
15015 *
15016 * - Byte access: #each_byte, #getbyte, #readbyte.
15017 * - Character access: #each_char, #getc, #readchar.
15018 * - Codepoint access: #each_codepoint.
15019 * - Line access: #each_line, #gets, #readline, #readlines.
15020 * - Source access: #read, #read_nonblock, #readpartial.
15021 *
15022 * === About \Enumerable
15023 *
15024 * \ARGF includes module Enumerable.
15025 * Virtually all methods in \Enumerable call method <tt>#each</tt> in the including class.
15026 *
15027 * <b>Note well</b>: In \ARGF, method #each returns data from the _sources_,
15028 * _not_ from +ARGV+;
15029 * therefore, for example, <tt>ARGF#entries</tt> returns an array of lines from the sources,
15030 * not an array of the strings from +ARGV+:
15031 *
15032 * - \File +t.rb+:
15033 *
15034 * p ['ARGV', ARGV]
15035 * p ['ARGF.entries', ARGF.entries]
15036 *
15037 * - Command and output:
15038 *
15039 * $ ruby t.rb foo.txt bar.txt
15040 * ["ARGV", ["foo.txt", "bar.txt"]]
15041 * ["ARGF.entries", ["Foo 0\n", "Foo 1\n", "Bar 0\n", "Bar 1\n", "Bar 2\n", "Bar 3\n"]]
15042 *
15043 * == Writing
15044 *
15045 * If <i>inplace mode</i> is in effect,
15046 * \ARGF may write to target streams,
15047 * which at any particular time are determined by the content of ARGV.
15048 *
15049 * Methods about inplace mode:
15050 *
15051 * - #inplace_mode
15052 * - #inplace_mode=
15053 * - #to_write_io
15054 *
15055 * Methods for writing:
15056 *
15057 * - #print
15058 * - #printf
15059 * - #putc
15060 * - #puts
15061 * - #write
15062 *
15063 */
15064
15065/*
15066 * An instance of class \IO (commonly called a _stream_)
15067 * represents an input/output stream in the underlying operating system.
15068 * Class \IO is the basis for input and output in Ruby.
15069 *
15070 * Class File is the only class in the Ruby core that is a subclass of \IO.
15071 * Some classes in the Ruby standard library are also subclasses of \IO;
15072 * these include TCPSocket and UDPSocket.
15073 *
15074 * The global constant ARGF (also accessible as <tt>$<</tt>)
15075 * provides an IO-like stream that allows access to all file paths
15076 * found in ARGV (or found in STDIN if ARGV is empty).
15077 * ARGF is not itself a subclass of \IO.
15078 *
15079 * Class StringIO provides an IO-like stream that handles a String.
15080 * StringIO is not itself a subclass of \IO.
15081 *
15082 * Important objects based on \IO include:
15083 *
15084 * - $stdin.
15085 * - $stdout.
15086 * - $stderr.
15087 * - Instances of class File.
15088 *
15089 * An instance of \IO may be created using:
15090 *
15091 * - IO.new: returns a new \IO object for the given integer file descriptor.
15092 * - IO.open: passes a new \IO object to the given block.
15093 * - IO.popen: returns a new \IO object that is connected to the $stdin and $stdout
15094 * of a newly-launched subprocess.
15095 * - Kernel#open: Returns a new \IO object connected to a given source:
15096 * stream, file, or subprocess.
15097 *
15098 * Like a File stream, an \IO stream has:
15099 *
15100 * - A read/write mode, which may be read-only, write-only, or read/write;
15101 * see {Read/Write Mode}[rdoc-ref:File@Read-2FWrite+Mode].
15102 * - A data mode, which may be text-only or binary;
15103 * see {Data Mode}[rdoc-ref:File@Data+Mode].
15104 * - Internal and external encodings;
15105 * see {Encodings}[rdoc-ref:File@Encodings].
15106 *
15107 * And like other \IO streams, it has:
15108 *
15109 * - A position, which determines where in the stream the next
15110 * read or write is to occur;
15111 * see {Position}[rdoc-ref:IO@Position].
15112 * - A line number, which is a special, line-oriented, "position"
15113 * (different from the position mentioned above);
15114 * see {Line Number}[rdoc-ref:IO@Line+Number].
15115 *
15116 * == Extension <tt>io/console</tt>
15117 *
15118 * Extension <tt>io/console</tt> provides numerous methods
15119 * for interacting with the console;
15120 * requiring it adds numerous methods to class \IO.
15121 *
15122 * == Example Files
15123 *
15124 * Many examples here use these variables:
15125 *
15126 * :include: doc/examples/files.rdoc
15127 *
15128 * == Open Options
15129 *
15130 * A number of \IO methods accept optional keyword arguments
15131 * that determine how a new stream is to be opened:
15132 *
15133 * - +:mode+: Stream mode.
15134 * - +:flags+: Integer file open flags;
15135 * If +mode+ is also given, the two are bitwise-ORed.
15136 * - +:external_encoding+: External encoding for the stream.
15137 * - +:internal_encoding+: Internal encoding for the stream.
15138 * <tt>'-'</tt> is a synonym for the default internal encoding.
15139 * If the value is +nil+ no conversion occurs.
15140 * - +:encoding+: Specifies external and internal encodings as <tt>'extern:intern'</tt>.
15141 * - +:textmode+: If a truthy value, specifies the mode as text-only, binary otherwise.
15142 * - +:binmode+: If a truthy value, specifies the mode as binary, text-only otherwise.
15143 * - +:autoclose+: If a truthy value, specifies that the +fd+ will close
15144 * when the stream closes; otherwise it remains open.
15145 * - +:path:+ If a string value is provided, it is used in #inspect and is available as
15146 * #path method.
15147 *
15148 * Also available are the options offered in String#encode,
15149 * which may control conversion between external and internal encoding.
15150 *
15151 * == Basic \IO
15152 *
15153 * You can perform basic stream \IO with these methods,
15154 * which typically operate on multi-byte strings:
15155 *
15156 * - IO#read: Reads and returns some or all of the remaining bytes from the stream.
15157 * - IO#write: Writes zero or more strings to the stream;
15158 * each given object that is not already a string is converted via +to_s+.
15159 *
15160 * === Position
15161 *
15162 * An \IO stream has a nonnegative integer _position_,
15163 * which is the byte offset at which the next read or write is to occur.
15164 * A new stream has position zero (and line number zero);
15165 * method +rewind+ resets the position (and line number) to zero.
15166 *
15167 * These methods discard {buffers}[rdoc-ref:IO@Buffering] and the
15168 * Encoding::Converter instances used for that \IO.
15169 *
15170 * The relevant methods:
15171 *
15172 * - IO#tell (aliased as +#pos+): Returns the current position (in bytes) in the stream.
15173 * - IO#pos=: Sets the position of the stream to a given integer +new_position+ (in bytes).
15174 * - IO#seek: Sets the position of the stream to a given integer +offset+ (in bytes),
15175 * relative to a given position +whence+
15176 * (indicating the beginning, end, or current position).
15177 * - IO#rewind: Positions the stream at the beginning (also resetting the line number).
15178 *
15179 * === Open and Closed Streams
15180 *
15181 * A new \IO stream may be open for reading, open for writing, or both.
15182 *
15183 * A stream is automatically closed when claimed by the garbage collector.
15184 *
15185 * Attempted reading or writing on a closed stream raises an exception.
15186 *
15187 * The relevant methods:
15188 *
15189 * - IO#close: Closes the stream for both reading and writing.
15190 * - IO#close_read: Closes the stream for reading.
15191 * - IO#close_write: Closes the stream for writing.
15192 * - IO#closed?: Returns whether the stream is closed.
15193 *
15194 * === End-of-Stream
15195 *
15196 * You can query whether a stream is positioned at its end:
15197 *
15198 * - IO#eof? (also aliased as +#eof+): Returns whether the stream is at end-of-stream.
15199 *
15200 * You can reposition to end-of-stream by using method IO#seek:
15201 *
15202 * f = File.new('t.txt')
15203 * f.eof? # => false
15204 * f.seek(0, :END)
15205 * f.eof? # => true
15206 * f.close
15207 *
15208 * Or by reading all stream content (which is slower than using IO#seek):
15209 *
15210 * f.rewind
15211 * f.eof? # => false
15212 * f.read # => "First line\nSecond line\n\nFourth line\nFifth line\n"
15213 * f.eof? # => true
15214 *
15215 * == Line \IO
15216 *
15217 * Class \IO supports line-oriented
15218 * {input}[rdoc-ref:IO@Line+Input] and {output}[rdoc-ref:IO@Line+Output]
15219 *
15220 * === Line Input
15221 *
15222 * Class \IO supports line-oriented input for
15223 * {files}[rdoc-ref:IO@File+Line+Input] and {IO streams}[rdoc-ref:IO@Stream+Line+Input]
15224 *
15225 * ==== \File Line Input
15226 *
15227 * You can read lines from a file using these methods:
15228 *
15229 * - IO.foreach: Reads each line and passes it to the given block.
15230 * - IO.readlines: Reads and returns all lines in an array.
15231 *
15232 * For each of these methods:
15233 *
15234 * - You can specify {open options}[rdoc-ref:IO@Open+Options].
15235 * - Line parsing depends on the effective <i>line separator</i>;
15236 * see {Line Separator}[rdoc-ref:IO@Line+Separator].
15237 * - The length of each returned line depends on the effective <i>line limit</i>;
15238 * see {Line Limit}[rdoc-ref:IO@Line+Limit].
15239 *
15240 * ==== Stream Line Input
15241 *
15242 * You can read lines from an \IO stream using these methods:
15243 *
15244 * - IO#each_line: Reads each remaining line, passing it to the given block.
15245 * - IO#gets: Returns the next line.
15246 * - IO#readline: Like #gets, but raises an exception at end-of-stream.
15247 * - IO#readlines: Returns all remaining lines in an array.
15248 *
15249 * For each of these methods:
15250 *
15251 * - Reading may begin mid-line,
15252 * depending on the stream's _position_;
15253 * see {Position}[rdoc-ref:IO@Position].
15254 * - Line parsing depends on the effective <i>line separator</i>;
15255 * see {Line Separator}[rdoc-ref:IO@Line+Separator].
15256 * - The length of each returned line depends on the effective <i>line limit</i>;
15257 * see {Line Limit}[rdoc-ref:IO@Line+Limit].
15258 *
15259 * ===== Line Separator
15260 *
15261 * Each of the {line input methods}[rdoc-ref:IO@Line+Input] uses a <i>line separator</i>:
15262 * the string that determines what is considered a line;
15263 * it is sometimes called the <i>input record separator</i>.
15264 *
15265 * The default line separator is taken from global variable <tt>$/</tt>,
15266 * whose initial value is <tt>"\n"</tt>.
15267 *
15268 * Generally, the line to be read next is all data
15269 * from the current {position}[rdoc-ref:IO@Position]
15270 * to the next line separator
15271 * (but see {Special Line Separator Values}[rdoc-ref:IO@Special+Line+Separator+Values]):
15272 *
15273 * f = File.new('t.txt')
15274 * # Method gets with no sep argument returns the next line, according to $/.
15275 * f.gets # => "First line\n"
15276 * f.gets # => "Second line\n"
15277 * f.gets # => "\n"
15278 * f.gets # => "Fourth line\n"
15279 * f.gets # => "Fifth line\n"
15280 * f.close
15281 *
15282 * You can use a different line separator by passing argument +sep+:
15283 *
15284 * f = File.new('t.txt')
15285 * f.gets('l') # => "First l"
15286 * f.gets('li') # => "ine\nSecond li"
15287 * f.gets('lin') # => "ne\n\nFourth lin"
15288 * f.gets # => "e\n"
15289 * f.close
15290 *
15291 * Or by setting global variable <tt>$/</tt>:
15292 *
15293 * f = File.new('t.txt')
15294 * $/ = 'l'
15295 * f.gets # => "First l"
15296 * f.gets # => "ine\nSecond l"
15297 * f.gets # => "ine\n\nFourth l"
15298 * f.close
15299 *
15300 * ===== Special Line Separator Values
15301 *
15302 * Each of the {line input methods}[rdoc-ref:IO@Line+Input]
15303 * accepts two special values for parameter +sep+:
15304 *
15305 * - +nil+: The entire stream is to be read ("slurped") into a single string:
15306 *
15307 * f = File.new('t.txt')
15308 * f.gets(nil) # => "First line\nSecond line\n\nFourth line\nFifth line\n"
15309 * f.close
15310 *
15311 * - <tt>''</tt> (the empty string): The next "paragraph" is to be read
15312 * (paragraphs being separated by two consecutive line separators):
15313 *
15314 * f = File.new('t.txt')
15315 * f.gets('') # => "First line\nSecond line\n\n"
15316 * f.gets('') # => "Fourth line\nFifth line\n"
15317 * f.close
15318 *
15319 * ===== Line Limit
15320 *
15321 * Each of the {line input methods}[rdoc-ref:IO@Line+Input]
15322 * uses an integer <i>line limit</i>,
15323 * which restricts the number of bytes that may be returned.
15324 * (A multi-byte character will not be split, and so a returned line may be slightly longer
15325 * than the limit).
15326 *
15327 * The default limit value is <tt>-1</tt>;
15328 * any negative limit value means that there is no limit.
15329 *
15330 * If there is no limit, the line is determined only by +sep+.
15331 *
15332 * # Text with 1-byte characters.
15333 * File.open('t.txt') {|f| f.gets(1) } # => "F"
15334 * File.open('t.txt') {|f| f.gets(2) } # => "Fi"
15335 * File.open('t.txt') {|f| f.gets(3) } # => "Fir"
15336 * File.open('t.txt') {|f| f.gets(4) } # => "Firs"
15337 * # No more than one line.
15338 * File.open('t.txt') {|f| f.gets(10) } # => "First line"
15339 * File.open('t.txt') {|f| f.gets(11) } # => "First line\n"
15340 * File.open('t.txt') {|f| f.gets(12) } # => "First line\n"
15341 *
15342 * # Text with 2-byte characters, which will not be split.
15343 * File.open('t.rus') {|f| f.gets(1).size } # => 1
15344 * File.open('t.rus') {|f| f.gets(2).size } # => 1
15345 * File.open('t.rus') {|f| f.gets(3).size } # => 2
15346 * File.open('t.rus') {|f| f.gets(4).size } # => 2
15347 *
15348 * ===== Line Separator and Line Limit
15349 *
15350 * With arguments +sep+ and +limit+ given, combines the two behaviors:
15351 *
15352 * - Returns the next line as determined by line separator +sep+.
15353 * - But returns no more bytes than are allowed by the limit +limit+.
15354 *
15355 * Example:
15356 *
15357 * File.open('t.txt') {|f| f.gets('li', 20) } # => "First li"
15358 * File.open('t.txt') {|f| f.gets('li', 2) } # => "Fi"
15359 *
15360 * ===== Line Number
15361 *
15362 * A readable \IO stream has a non-negative integer <i>line number</i>:
15363 *
15364 * - IO#lineno: Returns the line number.
15365 * - IO#lineno=: Resets and returns the line number.
15366 *
15367 * Unless modified by a call to method IO#lineno=,
15368 * the line number is the number of lines read
15369 * by certain line-oriented methods,
15370 * according to the effective {line separator}[rdoc-ref:IO@Line+Separator]:
15371 *
15372 * - IO.foreach: Increments the line number on each call to the block.
15373 * - IO#each_line: Increments the line number on each call to the block.
15374 * - IO#gets: Increments the line number.
15375 * - IO#readline: Increments the line number.
15376 * - IO#readlines: Increments the line number for each line read.
15377 *
15378 * A new stream is initially has line number zero (and position zero);
15379 * method +rewind+ resets the line number (and position) to zero:
15380 *
15381 * f = File.new('t.txt')
15382 * f.lineno # => 0
15383 * f.gets # => "First line\n"
15384 * f.lineno # => 1
15385 * f.rewind
15386 * f.lineno # => 0
15387 * f.close
15388 *
15389 * Reading lines from a stream usually changes its line number:
15390 *
15391 * f = File.new('t.txt', 'r')
15392 * f.lineno # => 0
15393 * f.readline # => "This is line one.\n"
15394 * f.lineno # => 1
15395 * f.readline # => "This is the second line.\n"
15396 * f.lineno # => 2
15397 * f.readline # => "Here's the third line.\n"
15398 * f.lineno # => 3
15399 * f.eof? # => true
15400 * f.close
15401 *
15402 * Iterating over lines in a stream usually changes its line number:
15403 *
15404 * File.open('t.txt') do |f|
15405 * f.each_line do |line|
15406 * p "position=#{f.pos} eof?=#{f.eof?} lineno=#{f.lineno}"
15407 * end
15408 * end
15409 *
15410 * Output:
15411 *
15412 * "position=11 eof?=false lineno=1"
15413 * "position=23 eof?=false lineno=2"
15414 * "position=24 eof?=false lineno=3"
15415 * "position=36 eof?=false lineno=4"
15416 * "position=47 eof?=true lineno=5"
15417 *
15418 * Unlike the stream's {position}[rdoc-ref:IO@Position],
15419 * the line number does not affect where the next read or write will occur:
15420 *
15421 * f = File.new('t.txt')
15422 * f.lineno = 1000
15423 * f.lineno # => 1000
15424 * f.gets # => "First line\n"
15425 * f.lineno # => 1001
15426 * f.close
15427 *
15428 * Associated with the line number is the global variable <tt>$.</tt>:
15429 *
15430 * - When a stream is opened, <tt>$.</tt> is not set;
15431 * its value is left over from previous activity in the process:
15432 *
15433 * $. = 41
15434 * f = File.new('t.txt')
15435 * $. = 41
15436 * # => 41
15437 * f.close
15438 *
15439 * - When a stream is read, <tt>$.</tt> is set to the line number for that stream:
15440 *
15441 * f0 = File.new('t.txt')
15442 * f1 = File.new('t.dat')
15443 * f0.readlines # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
15444 * $. # => 5
15445 * f1.readlines # => ["\xFE\xFF\x99\x90\x99\x91\x99\x92\x99\x93\x99\x94"]
15446 * $. # => 1
15447 * f0.close
15448 * f1.close
15449 *
15450 * - Methods IO#rewind and IO#seek do not affect <tt>$.</tt>:
15451 *
15452 * f = File.new('t.txt')
15453 * f.readlines # => ["First line\n", "Second line\n", "\n", "Fourth line\n", "Fifth line\n"]
15454 * $. # => 5
15455 * f.rewind
15456 * f.seek(0, :SET)
15457 * $. # => 5
15458 * f.close
15459 *
15460 * === Line Output
15461 *
15462 * You can write to an \IO stream line-by-line using this method:
15463 *
15464 * - IO#puts: Writes objects to the stream.
15465 *
15466 * == Character \IO
15467 *
15468 * You can process an \IO stream character-by-character using these methods:
15469 *
15470 * - IO#getc: Reads and returns the next character from the stream.
15471 * - IO#readchar: Like #getc, but raises an exception at end-of-stream.
15472 * - IO#ungetc: Pushes back ("unshifts") a character or integer onto the stream.
15473 * - IO#putc: Writes a character to the stream.
15474 * - IO#each_char: Reads each remaining character in the stream,
15475 * passing the character to the given block.
15476 *
15477 * == Byte \IO
15478 *
15479 * You can process an \IO stream byte-by-byte using these methods:
15480 *
15481 * - IO#getbyte: Returns the next 8-bit byte as an integer in range 0..255.
15482 * - IO#readbyte: Like #getbyte, but raises an exception if at end-of-stream.
15483 * - IO#ungetbyte: Pushes back ("unshifts") a byte back onto the stream.
15484 * - IO#each_byte: Reads each remaining byte in the stream,
15485 * passing the byte to the given block.
15486 *
15487 * == Codepoint \IO
15488 *
15489 * You can process an \IO stream codepoint-by-codepoint:
15490 *
15491 * - IO#each_codepoint: Reads each remaining codepoint, passing it to the given block.
15492 *
15493 * == What's Here
15494 *
15495 * First, what's elsewhere. Class \IO:
15496 *
15497 * - Inherits from {class Object}[rdoc-ref:Object@What-27s+Here].
15498 * - Includes {module Enumerable}[rdoc-ref:Enumerable@What-27s+Here],
15499 * which provides dozens of additional methods.
15500 *
15501 * Here, class \IO provides methods that are useful for:
15502 *
15503 * - {Creating}[rdoc-ref:IO@Creating]
15504 * - {Reading}[rdoc-ref:IO@Reading]
15505 * - {Writing}[rdoc-ref:IO@Writing]
15506 * - {Positioning}[rdoc-ref:IO@Positioning]
15507 * - {Iterating}[rdoc-ref:IO@Iterating]
15508 * - {Settings}[rdoc-ref:IO@Settings]
15509 * - {Querying}[rdoc-ref:IO@Querying]
15510 * - {Buffering}[rdoc-ref:IO@Buffering]
15511 * - {Low-Level Access}[rdoc-ref:IO@Low-Level+Access]
15512 * - {Other}[rdoc-ref:IO@Other]
15513 *
15514 * === Creating
15515 *
15516 * - ::new (aliased as ::for_fd): Creates and returns a new \IO object for the given
15517 * integer file descriptor.
15518 * - ::open: Creates a new \IO object.
15519 * - ::pipe: Creates a connected pair of reader and writer \IO objects.
15520 * - ::popen: Creates an \IO object to interact with a subprocess.
15521 * - ::select: Selects which given \IO instances are ready for reading,
15522 * writing, or have pending exceptions.
15523 *
15524 * === Reading
15525 *
15526 * - ::binread: Returns a binary string with all or a subset of bytes
15527 * from the given file.
15528 * - ::read: Returns a string with all or a subset of bytes from the given file.
15529 * - ::readlines: Returns an array of strings, which are the lines from the given file.
15530 * - #getbyte: Returns the next 8-bit byte read from +self+ as an integer.
15531 * - #getc: Returns the next character read from +self+ as a string.
15532 * - #gets: Returns the line read from +self+.
15533 * - #pread: Returns all or the next _n_ bytes read from +self+,
15534 * not updating the receiver's offset.
15535 * - #read: Returns all remaining or the next _n_ bytes read from +self+
15536 * for a given _n_.
15537 * - #read_nonblock: the next _n_ bytes read from +self+ for a given _n_,
15538 * in non-block mode.
15539 * - #readbyte: Returns the next byte read from +self+;
15540 * same as #getbyte, but raises an exception on end-of-stream.
15541 * - #readchar: Returns the next character read from +self+;
15542 * same as #getc, but raises an exception on end-of-stream.
15543 * - #readline: Returns the next line read from +self+;
15544 * same as #getline, but raises an exception of end-of-stream.
15545 * - #readlines: Returns an array of all lines read read from +self+.
15546 * - #readpartial: Returns up to the given number of bytes from +self+.
15547 *
15548 * === Writing
15549 *
15550 * - ::binwrite: Writes the given string to the file at the given filepath,
15551 * in binary mode.
15552 * - ::write: Writes the given string to +self+.
15553 * - #<<: Appends the given string to +self+.
15554 * - #print: Prints last read line or given objects to +self+.
15555 * - #printf: Writes to +self+ based on the given format string and objects.
15556 * - #putc: Writes a character to +self+.
15557 * - #puts: Writes lines to +self+, making sure line ends with a newline.
15558 * - #pwrite: Writes the given string at the given offset,
15559 * not updating the receiver's offset.
15560 * - #write: Writes one or more given strings to +self+.
15561 * - #write_nonblock: Writes one or more given strings to +self+ in non-blocking mode.
15562 *
15563 * === Positioning
15564 *
15565 * - #lineno: Returns the current line number in +self+.
15566 * - #lineno=: Sets the line number is +self+.
15567 * - #pos (aliased as #tell): Returns the current byte offset in +self+.
15568 * - #pos=: Sets the byte offset in +self+.
15569 * - #reopen: Reassociates +self+ with a new or existing \IO stream.
15570 * - #rewind: Positions +self+ to the beginning of input.
15571 * - #seek: Sets the offset for +self+ relative to given position.
15572 *
15573 * === Iterating
15574 *
15575 * - ::foreach: Yields each line of given file to the block.
15576 * - #each (aliased as #each_line): Calls the given block
15577 * with each successive line in +self+.
15578 * - #each_byte: Calls the given block with each successive byte in +self+
15579 * as an integer.
15580 * - #each_char: Calls the given block with each successive character in +self+
15581 * as a string.
15582 * - #each_codepoint: Calls the given block with each successive codepoint in +self+
15583 * as an integer.
15584 *
15585 * === Settings
15586 *
15587 * - #autoclose=: Sets whether +self+ auto-closes.
15588 * - #binmode: Sets +self+ to binary mode.
15589 * - #close: Closes +self+.
15590 * - #close_on_exec=: Sets the close-on-exec flag.
15591 * - #close_read: Closes +self+ for reading.
15592 * - #close_write: Closes +self+ for writing.
15593 * - #set_encoding: Sets the encoding for +self+.
15594 * - #set_encoding_by_bom: Sets the encoding for +self+, based on its
15595 * Unicode byte-order-mark.
15596 * - #sync=: Sets the sync-mode to the given value.
15597 *
15598 * === Querying
15599 *
15600 * - #autoclose?: Returns whether +self+ auto-closes.
15601 * - #binmode?: Returns whether +self+ is in binary mode.
15602 * - #close_on_exec?: Returns the close-on-exec flag for +self+.
15603 * - #closed?: Returns whether +self+ is closed.
15604 * - #eof? (aliased as #eof): Returns whether +self+ is at end-of-stream.
15605 * - #external_encoding: Returns the external encoding object for +self+.
15606 * - #fileno (aliased as #to_i): Returns the integer file descriptor for +self+
15607 * - #internal_encoding: Returns the internal encoding object for +self+.
15608 * - #pid: Returns the process ID of a child process associated with +self+,
15609 * if +self+ was created by ::popen.
15610 * - #stat: Returns the File::Stat object containing status information for +self+.
15611 * - #sync: Returns whether +self+ is in sync-mode.
15612 * - #tty? (aliased as #isatty): Returns whether +self+ is a terminal.
15613 *
15614 * === Buffering
15615 *
15616 * - #fdatasync: Immediately writes all buffered data in +self+ to disk.
15617 * - #flush: Flushes any buffered data within +self+ to the underlying
15618 * operating system.
15619 * - #fsync: Immediately writes all buffered data and attributes in +self+ to disk.
15620 * - #ungetbyte: Prepends buffer for +self+ with given integer byte or string.
15621 * - #ungetc: Prepends buffer for +self+ with given string.
15622 *
15623 * === Low-Level Access
15624 *
15625 * - ::sysopen: Opens the file given by its path,
15626 * returning the integer file descriptor.
15627 * - #advise: Announces the intention to access data from +self+ in a specific way.
15628 * - #fcntl: Passes a low-level command to the file specified
15629 * by the given file descriptor.
15630 * - #ioctl: Passes a low-level command to the device specified
15631 * by the given file descriptor.
15632 * - #sysread: Returns up to the next _n_ bytes read from self using a low-level read.
15633 * - #sysseek: Sets the offset for +self+.
15634 * - #syswrite: Writes the given string to +self+ using a low-level write.
15635 *
15636 * === Other
15637 *
15638 * - ::copy_stream: Copies data from a source to a destination,
15639 * each of which is a filepath or an \IO-like object.
15640 * - ::try_convert: Returns a new \IO object resulting from converting
15641 * the given object.
15642 * - #inspect: Returns the string representation of +self+.
15643 *
15644 */
15645
15646void
15647Init_IO(void)
15648{
15649 VALUE rb_cARGF;
15650#ifdef __CYGWIN__
15651#include <sys/cygwin.h>
15652 static struct __cygwin_perfile pf[] =
15653 {
15654 {"", O_RDONLY | O_BINARY},
15655 {"", O_WRONLY | O_BINARY},
15656 {"", O_RDWR | O_BINARY},
15657 {"", O_APPEND | O_BINARY},
15658 {NULL, 0}
15659 };
15660 cygwin_internal(CW_PERFILE, pf);
15661#endif
15662
15665
15666 id_write = rb_intern_const("write");
15667 id_read = rb_intern_const("read");
15668 id_getc = rb_intern_const("getc");
15669 id_flush = rb_intern_const("flush");
15670 id_readpartial = rb_intern_const("readpartial");
15671 id_set_encoding = rb_intern_const("set_encoding");
15672 id_fileno = rb_intern_const("fileno");
15673
15674 rb_define_global_function("syscall", rb_f_syscall, -1);
15675
15676 rb_define_global_function("open", rb_f_open, -1);
15677 rb_define_global_function("printf", rb_f_printf, -1);
15678 rb_define_global_function("print", rb_f_print, -1);
15679 rb_define_global_function("putc", rb_f_putc, 1);
15680 rb_define_global_function("puts", rb_f_puts, -1);
15681 rb_define_global_function("gets", rb_f_gets, -1);
15682 rb_define_global_function("readline", rb_f_readline, -1);
15683 rb_define_global_function("select", rb_f_select, -1);
15684
15685 rb_define_global_function("readlines", rb_f_readlines, -1);
15686
15687 rb_define_global_function("`", rb_f_backquote, 1);
15688
15689 rb_define_global_function("p", rb_f_p, -1);
15690 rb_define_method(rb_mKernel, "display", rb_obj_display, -1);
15691
15692 rb_cIO = rb_define_class("IO", rb_cObject);
15694
15695 /* Can be raised by IO operations when IO#timeout= is set. */
15697
15698 /* Readable event mask for IO#wait. */
15699 rb_define_const(rb_cIO, "READABLE", INT2NUM(RUBY_IO_READABLE));
15700 /* Writable event mask for IO#wait. */
15701 rb_define_const(rb_cIO, "WRITABLE", INT2NUM(RUBY_IO_WRITABLE));
15702 /* Priority event mask for IO#wait. */
15703 rb_define_const(rb_cIO, "PRIORITY", INT2NUM(RUBY_IO_PRIORITY));
15704
15705 /* exception to wait for reading. see IO.select. */
15707 /* exception to wait for writing. see IO.select. */
15709 /* exception to wait for reading by EAGAIN. see IO.select. */
15710 rb_eEAGAINWaitReadable = rb_define_class_under(rb_cIO, "EAGAINWaitReadable", rb_eEAGAIN);
15711 rb_include_module(rb_eEAGAINWaitReadable, rb_mWaitReadable);
15712 /* exception to wait for writing by EAGAIN. see IO.select. */
15713 rb_eEAGAINWaitWritable = rb_define_class_under(rb_cIO, "EAGAINWaitWritable", rb_eEAGAIN);
15714 rb_include_module(rb_eEAGAINWaitWritable, rb_mWaitWritable);
15715#if EAGAIN == EWOULDBLOCK
15716 rb_eEWOULDBLOCKWaitReadable = rb_eEAGAINWaitReadable;
15717 /* same as IO::EAGAINWaitReadable */
15718 rb_define_const(rb_cIO, "EWOULDBLOCKWaitReadable", rb_eEAGAINWaitReadable);
15719 rb_eEWOULDBLOCKWaitWritable = rb_eEAGAINWaitWritable;
15720 /* same as IO::EAGAINWaitWritable */
15721 rb_define_const(rb_cIO, "EWOULDBLOCKWaitWritable", rb_eEAGAINWaitWritable);
15722#else
15723 /* exception to wait for reading by EWOULDBLOCK. see IO.select. */
15724 rb_eEWOULDBLOCKWaitReadable = rb_define_class_under(rb_cIO, "EWOULDBLOCKWaitReadable", rb_eEWOULDBLOCK);
15725 rb_include_module(rb_eEWOULDBLOCKWaitReadable, rb_mWaitReadable);
15726 /* exception to wait for writing by EWOULDBLOCK. see IO.select. */
15727 rb_eEWOULDBLOCKWaitWritable = rb_define_class_under(rb_cIO, "EWOULDBLOCKWaitWritable", rb_eEWOULDBLOCK);
15728 rb_include_module(rb_eEWOULDBLOCKWaitWritable, rb_mWaitWritable);
15729#endif
15730 /* exception to wait for reading by EINPROGRESS. see IO.select. */
15731 rb_eEINPROGRESSWaitReadable = rb_define_class_under(rb_cIO, "EINPROGRESSWaitReadable", rb_eEINPROGRESS);
15732 rb_include_module(rb_eEINPROGRESSWaitReadable, rb_mWaitReadable);
15733 /* exception to wait for writing by EINPROGRESS. see IO.select. */
15734 rb_eEINPROGRESSWaitWritable = rb_define_class_under(rb_cIO, "EINPROGRESSWaitWritable", rb_eEINPROGRESS);
15735 rb_include_module(rb_eEINPROGRESSWaitWritable, rb_mWaitWritable);
15736
15737#if 0
15738 /* This is necessary only for forcing rdoc handle File::open */
15739 rb_define_singleton_method(rb_cFile, "open", rb_io_s_open, -1);
15740#endif
15741
15742 rb_define_alloc_func(rb_cIO, io_alloc);
15743 rb_define_singleton_method(rb_cIO, "new", rb_io_s_new, -1);
15744 rb_define_singleton_method(rb_cIO, "open", rb_io_s_open, -1);
15745 rb_define_singleton_method(rb_cIO, "sysopen", rb_io_s_sysopen, -1);
15746 rb_define_singleton_method(rb_cIO, "for_fd", rb_io_s_for_fd, -1);
15747 rb_define_singleton_method(rb_cIO, "popen", rb_io_s_popen, -1);
15748 rb_define_singleton_method(rb_cIO, "foreach", rb_io_s_foreach, -1);
15749 rb_define_singleton_method(rb_cIO, "readlines", rb_io_s_readlines, -1);
15750 rb_define_singleton_method(rb_cIO, "read", rb_io_s_read, -1);
15751 rb_define_singleton_method(rb_cIO, "binread", rb_io_s_binread, -1);
15752 rb_define_singleton_method(rb_cIO, "write", rb_io_s_write, -1);
15753 rb_define_singleton_method(rb_cIO, "binwrite", rb_io_s_binwrite, -1);
15754 rb_define_singleton_method(rb_cIO, "select", rb_f_select, -1);
15755 rb_define_singleton_method(rb_cIO, "pipe", rb_io_s_pipe, -1);
15756 rb_define_singleton_method(rb_cIO, "try_convert", rb_io_s_try_convert, 1);
15757 rb_define_singleton_method(rb_cIO, "copy_stream", rb_io_s_copy_stream, -1);
15758
15759 rb_define_method(rb_cIO, "initialize", rb_io_initialize, -1);
15760
15762 rb_define_hooked_variable("$,", &rb_output_fs, 0, deprecated_str_setter);
15763
15764 rb_default_rs = rb_fstring_lit("\n"); /* avoid modifying RS_default */
15765 rb_vm_register_global_object(rb_default_rs);
15766 rb_rs = rb_default_rs;
15768 rb_define_hooked_variable("$/", &rb_rs, 0, deprecated_rs_setter);
15769 rb_gvar_ractor_local("$/"); // not local but ractor safe
15770 rb_define_hooked_variable("$-0", &rb_rs, 0, deprecated_rs_setter);
15771 rb_gvar_ractor_local("$-0"); // not local but ractor safe
15772 rb_define_hooked_variable("$\\", &rb_output_rs, 0, deprecated_str_setter);
15773
15774 rb_define_virtual_variable("$_", get_LAST_READ_LINE, set_LAST_READ_LINE);
15775 rb_gvar_ractor_local("$_");
15776
15777 rb_define_method(rb_cIO, "initialize_copy", rb_io_init_copy, 1);
15778 rb_define_method(rb_cIO, "reopen", rb_io_reopen, -1);
15779
15780 rb_define_method(rb_cIO, "print", rb_io_print, -1);
15781 rb_define_method(rb_cIO, "putc", rb_io_putc, 1);
15782 rb_define_method(rb_cIO, "puts", rb_io_puts, -1);
15783 rb_define_method(rb_cIO, "printf", rb_io_printf, -1);
15784
15785 rb_define_method(rb_cIO, "each", rb_io_each_line, -1);
15786 rb_define_method(rb_cIO, "each_line", rb_io_each_line, -1);
15787 rb_define_method(rb_cIO, "each_byte", rb_io_each_byte, 0);
15788 rb_define_method(rb_cIO, "each_char", rb_io_each_char, 0);
15789 rb_define_method(rb_cIO, "each_codepoint", rb_io_each_codepoint, 0);
15790
15791 rb_define_method(rb_cIO, "syswrite", rb_io_syswrite, 1);
15792 rb_define_method(rb_cIO, "sysread", rb_io_sysread, -1);
15793
15794 rb_define_method(rb_cIO, "pread", rb_io_pread, -1);
15795 rb_define_method(rb_cIO, "pwrite", rb_io_pwrite, 2);
15796
15797 rb_define_method(rb_cIO, "fileno", rb_io_fileno, 0);
15798 rb_define_alias(rb_cIO, "to_i", "fileno");
15799 rb_define_method(rb_cIO, "to_io", rb_io_to_io, 0);
15800
15801 rb_define_method(rb_cIO, "timeout", rb_io_timeout, 0);
15802 rb_define_method(rb_cIO, "timeout=", rb_io_set_timeout, 1);
15803
15804 rb_define_method(rb_cIO, "fsync", rb_io_fsync, 0);
15805 rb_define_method(rb_cIO, "fdatasync", rb_io_fdatasync, 0);
15806 rb_define_method(rb_cIO, "sync", rb_io_sync, 0);
15807 rb_define_method(rb_cIO, "sync=", rb_io_set_sync, 1);
15808
15809 rb_define_method(rb_cIO, "lineno", rb_io_lineno, 0);
15810 rb_define_method(rb_cIO, "lineno=", rb_io_set_lineno, 1);
15811
15812 rb_define_method(rb_cIO, "readlines", rb_io_readlines, -1);
15813
15814 rb_define_method(rb_cIO, "readpartial", io_readpartial, -1);
15815 rb_define_method(rb_cIO, "read", io_read, -1);
15816 rb_define_method(rb_cIO, "write", io_write_m, -1);
15817 rb_define_method(rb_cIO, "gets", rb_io_gets_m, -1);
15818 rb_define_method(rb_cIO, "getc", rb_io_getc, 0);
15819 rb_define_method(rb_cIO, "getbyte", rb_io_getbyte, 0);
15820 rb_define_method(rb_cIO, "readchar", rb_io_readchar, 0);
15821 rb_define_method(rb_cIO, "readbyte", rb_io_readbyte, 0);
15822 rb_define_method(rb_cIO, "ungetbyte",rb_io_ungetbyte, 1);
15823 rb_define_method(rb_cIO, "ungetc",rb_io_ungetc, 1);
15825 rb_define_method(rb_cIO, "flush", rb_io_flush, 0);
15826 rb_define_method(rb_cIO, "tell", rb_io_tell, 0);
15827 rb_define_method(rb_cIO, "seek", rb_io_seek_m, -1);
15828 /* Set I/O position from the beginning */
15829 rb_define_const(rb_cIO, "SEEK_SET", INT2FIX(SEEK_SET));
15830 /* Set I/O position from the current position */
15831 rb_define_const(rb_cIO, "SEEK_CUR", INT2FIX(SEEK_CUR));
15832 /* Set I/O position from the end */
15833 rb_define_const(rb_cIO, "SEEK_END", INT2FIX(SEEK_END));
15834#ifdef SEEK_DATA
15835 /* Set I/O position to the next location containing data */
15836 rb_define_const(rb_cIO, "SEEK_DATA", INT2FIX(SEEK_DATA));
15837#endif
15838#ifdef SEEK_HOLE
15839 /* Set I/O position to the next hole */
15840 rb_define_const(rb_cIO, "SEEK_HOLE", INT2FIX(SEEK_HOLE));
15841#endif
15842 rb_define_method(rb_cIO, "rewind", rb_io_rewind, 0);
15843 rb_define_method(rb_cIO, "pos", rb_io_tell, 0);
15844 rb_define_method(rb_cIO, "pos=", rb_io_set_pos, 1);
15845 rb_define_method(rb_cIO, "eof", rb_io_eof, 0);
15846 rb_define_method(rb_cIO, "eof?", rb_io_eof, 0);
15847
15848 rb_define_method(rb_cIO, "close_on_exec?", rb_io_close_on_exec_p, 0);
15849 rb_define_method(rb_cIO, "close_on_exec=", rb_io_set_close_on_exec, 1);
15850
15851 rb_define_method(rb_cIO, "close", rb_io_close_m, 0);
15852 rb_define_method(rb_cIO, "closed?", rb_io_closed_p, 0);
15853 rb_define_method(rb_cIO, "close_read", rb_io_close_read, 0);
15854 rb_define_method(rb_cIO, "close_write", rb_io_close_write, 0);
15855
15856 rb_define_method(rb_cIO, "isatty", rb_io_isatty, 0);
15857 rb_define_method(rb_cIO, "tty?", rb_io_isatty, 0);
15858 rb_define_method(rb_cIO, "binmode", rb_io_binmode_m, 0);
15859 rb_define_method(rb_cIO, "binmode?", rb_io_binmode_p, 0);
15860 rb_define_method(rb_cIO, "sysseek", rb_io_sysseek, -1);
15861 rb_define_method(rb_cIO, "advise", rb_io_advise, -1);
15862
15863 rb_define_method(rb_cIO, "ioctl", rb_io_ioctl, -1);
15864 rb_define_method(rb_cIO, "fcntl", rb_io_fcntl, -1);
15865 rb_define_method(rb_cIO, "pid", rb_io_pid, 0);
15866
15867 rb_define_method(rb_cIO, "path", rb_io_path, 0);
15868 rb_define_method(rb_cIO, "to_path", rb_io_path, 0);
15869
15870 rb_define_method(rb_cIO, "inspect", rb_io_inspect, 0);
15871
15872 rb_define_method(rb_cIO, "external_encoding", rb_io_external_encoding, 0);
15873 rb_define_method(rb_cIO, "internal_encoding", rb_io_internal_encoding, 0);
15874 rb_define_method(rb_cIO, "set_encoding", rb_io_set_encoding, -1);
15875 rb_define_method(rb_cIO, "set_encoding_by_bom", rb_io_set_encoding_by_bom, 0);
15876
15877 rb_define_method(rb_cIO, "autoclose?", rb_io_autoclose_p, 0);
15878 rb_define_method(rb_cIO, "autoclose=", rb_io_set_autoclose, 1);
15879
15880 rb_define_method(rb_cIO, "wait", io_wait, -1);
15881
15882 rb_define_method(rb_cIO, "wait_readable", io_wait_readable, -1);
15883 rb_define_method(rb_cIO, "wait_writable", io_wait_writable, -1);
15884 rb_define_method(rb_cIO, "wait_priority", io_wait_priority, -1);
15885
15886 rb_define_virtual_variable("$stdin", stdin_getter, stdin_setter);
15887 rb_define_virtual_variable("$stdout", stdout_getter, stdout_setter);
15888 rb_define_virtual_variable("$>", stdout_getter, stdout_setter);
15889 rb_define_virtual_variable("$stderr", stderr_getter, stderr_setter);
15890
15891 rb_gvar_ractor_local("$stdin");
15892 rb_gvar_ractor_local("$stdout");
15893 rb_gvar_ractor_local("$>");
15894 rb_gvar_ractor_local("$stderr");
15895
15897 rb_stdin = rb_io_prep_stdin();
15899 rb_stdout = rb_io_prep_stdout();
15901 rb_stderr = rb_io_prep_stderr();
15902
15903 orig_stdout = rb_stdout;
15904 orig_stderr = rb_stderr;
15905
15906 /* Holds the original stdin */
15908 /* Holds the original stdout */
15910 /* Holds the original stderr */
15912
15913#if 0
15914 /* Hack to get rdoc to regard ARGF as a class: */
15915 rb_cARGF = rb_define_class("ARGF", rb_cObject);
15916#endif
15917
15918 rb_cARGF = rb_class_new(rb_cObject);
15919 rb_set_class_path(rb_cARGF, rb_cObject, "ARGF.class");
15920 rb_define_alloc_func(rb_cARGF, argf_alloc);
15921
15923
15924 rb_define_method(rb_cARGF, "initialize", argf_initialize, -2);
15925 rb_define_method(rb_cARGF, "initialize_copy", argf_initialize_copy, 1);
15926 rb_define_method(rb_cARGF, "to_s", argf_to_s, 0);
15927 rb_define_alias(rb_cARGF, "inspect", "to_s");
15928 rb_define_method(rb_cARGF, "argv", argf_argv, 0);
15929
15930 rb_define_method(rb_cARGF, "fileno", argf_fileno, 0);
15931 rb_define_method(rb_cARGF, "to_i", argf_fileno, 0);
15932 rb_define_method(rb_cARGF, "to_io", argf_to_io, 0);
15933 rb_define_method(rb_cARGF, "to_write_io", argf_write_io, 0);
15934 rb_define_method(rb_cARGF, "each", argf_each_line, -1);
15935 rb_define_method(rb_cARGF, "each_line", argf_each_line, -1);
15936 rb_define_method(rb_cARGF, "each_byte", argf_each_byte, 0);
15937 rb_define_method(rb_cARGF, "each_char", argf_each_char, 0);
15938 rb_define_method(rb_cARGF, "each_codepoint", argf_each_codepoint, 0);
15939
15940 rb_define_method(rb_cARGF, "read", argf_read, -1);
15941 rb_define_method(rb_cARGF, "readpartial", argf_readpartial, -1);
15942 rb_define_method(rb_cARGF, "read_nonblock", argf_read_nonblock, -1);
15943 rb_define_method(rb_cARGF, "readlines", argf_readlines, -1);
15944 rb_define_method(rb_cARGF, "to_a", argf_readlines, -1);
15945 rb_define_method(rb_cARGF, "gets", argf_gets, -1);
15946 rb_define_method(rb_cARGF, "readline", argf_readline, -1);
15947 rb_define_method(rb_cARGF, "getc", argf_getc, 0);
15948 rb_define_method(rb_cARGF, "getbyte", argf_getbyte, 0);
15949 rb_define_method(rb_cARGF, "readchar", argf_readchar, 0);
15950 rb_define_method(rb_cARGF, "readbyte", argf_readbyte, 0);
15951 rb_define_method(rb_cARGF, "tell", argf_tell, 0);
15952 rb_define_method(rb_cARGF, "seek", argf_seek_m, -1);
15953 rb_define_method(rb_cARGF, "rewind", argf_rewind, 0);
15954 rb_define_method(rb_cARGF, "pos", argf_tell, 0);
15955 rb_define_method(rb_cARGF, "pos=", argf_set_pos, 1);
15956 rb_define_method(rb_cARGF, "eof", argf_eof, 0);
15957 rb_define_method(rb_cARGF, "eof?", argf_eof, 0);
15958 rb_define_method(rb_cARGF, "binmode", argf_binmode_m, 0);
15959 rb_define_method(rb_cARGF, "binmode?", argf_binmode_p, 0);
15960
15961 rb_define_method(rb_cARGF, "write", argf_write, -1);
15962 rb_define_method(rb_cARGF, "print", rb_io_print, -1);
15963 rb_define_method(rb_cARGF, "putc", rb_io_putc, 1);
15964 rb_define_method(rb_cARGF, "puts", rb_io_puts, -1);
15965 rb_define_method(rb_cARGF, "printf", rb_io_printf, -1);
15966
15967 rb_define_method(rb_cARGF, "filename", argf_filename, 0);
15968 rb_define_method(rb_cARGF, "path", argf_filename, 0);
15969 rb_define_method(rb_cARGF, "file", argf_file, 0);
15970 rb_define_method(rb_cARGF, "skip", argf_skip, 0);
15971 rb_define_method(rb_cARGF, "close", argf_close_m, 0);
15972 rb_define_method(rb_cARGF, "closed?", argf_closed, 0);
15973
15974 rb_define_method(rb_cARGF, "lineno", argf_lineno, 0);
15975 rb_define_method(rb_cARGF, "lineno=", argf_set_lineno, 1);
15976
15977 rb_define_method(rb_cARGF, "inplace_mode", argf_inplace_mode_get, 0);
15978 rb_define_method(rb_cARGF, "inplace_mode=", argf_inplace_mode_set, 1);
15979
15980 rb_define_method(rb_cARGF, "external_encoding", argf_external_encoding, 0);
15981 rb_define_method(rb_cARGF, "internal_encoding", argf_internal_encoding, 0);
15982 rb_define_method(rb_cARGF, "set_encoding", argf_set_encoding, -1);
15983
15984 argf = rb_class_new_instance(0, 0, rb_cARGF);
15985
15987 /*
15988 * ARGF is a stream designed for use in scripts that process files given
15989 * as command-line arguments or passed in via STDIN.
15990 *
15991 * See ARGF (the class) for more details.
15992 */
15994
15995 rb_define_hooked_variable("$.", &argf, argf_lineno_getter, argf_lineno_setter);
15996 rb_define_hooked_variable("$FILENAME", &argf, argf_filename_getter, rb_gvar_readonly_setter);
15997 ARGF.filename = rb_str_new2("-");
15998
15999 rb_define_hooked_variable("$-i", &argf, opt_i_get, opt_i_set);
16000 rb_gvar_ractor_local("$-i");
16001
16002 rb_define_hooked_variable("$*", &argf, argf_argv_getter, rb_gvar_readonly_setter);
16003
16004#if defined (_WIN32) || defined(__CYGWIN__)
16005 atexit(pipe_atexit);
16006#endif
16007
16008 Init_File();
16009
16010 rb_define_method(rb_cFile, "initialize", rb_file_initialize, -1);
16011
16012 sym_mode = ID2SYM(rb_intern_const("mode"));
16013 sym_perm = ID2SYM(rb_intern_const("perm"));
16014 sym_flags = ID2SYM(rb_intern_const("flags"));
16015 sym_extenc = ID2SYM(rb_intern_const("external_encoding"));
16016 sym_intenc = ID2SYM(rb_intern_const("internal_encoding"));
16017 sym_encoding = ID2SYM(rb_id_encoding());
16018 sym_open_args = ID2SYM(rb_intern_const("open_args"));
16019 sym_textmode = ID2SYM(rb_intern_const("textmode"));
16020 sym_binmode = ID2SYM(rb_intern_const("binmode"));
16021 sym_autoclose = ID2SYM(rb_intern_const("autoclose"));
16022 sym_normal = ID2SYM(rb_intern_const("normal"));
16023 sym_sequential = ID2SYM(rb_intern_const("sequential"));
16024 sym_random = ID2SYM(rb_intern_const("random"));
16025 sym_willneed = ID2SYM(rb_intern_const("willneed"));
16026 sym_dontneed = ID2SYM(rb_intern_const("dontneed"));
16027 sym_noreuse = ID2SYM(rb_intern_const("noreuse"));
16028 sym_SET = ID2SYM(rb_intern_const("SET"));
16029 sym_CUR = ID2SYM(rb_intern_const("CUR"));
16030 sym_END = ID2SYM(rb_intern_const("END"));
16031#ifdef SEEK_DATA
16032 sym_DATA = ID2SYM(rb_intern_const("DATA"));
16033#endif
16034#ifdef SEEK_HOLE
16035 sym_HOLE = ID2SYM(rb_intern_const("HOLE"));
16036#endif
16037 sym_wait_readable = ID2SYM(rb_intern_const("wait_readable"));
16038 sym_wait_writable = ID2SYM(rb_intern_const("wait_writable"));
16039}
16040
16041#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:1691
VALUE rb_define_class(const char *name, VALUE super)
Defines a top-level class.
Definition class.c:1474
VALUE rb_class_new(VALUE super)
Creates a new, anonymous class.
Definition class.c:855
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
Definition class.c:1510
VALUE rb_define_module_under(VALUE outer, const char *name)
Defines a module under the namespace of outer.
Definition class.c:1620
void rb_define_alias(VALUE klass, const char *name1, const char *name2)
Defines an alias of a method.
Definition class.c:2843
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:3146
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:3133
int rb_block_given_p(void)
Determines if the current method is given a block.
Definition eval.c:1036
int rb_get_kwargs(VALUE keyword_hash, const ID *table, int required, int optional, VALUE *values)
Keyword argument deconstructor.
Definition class.c:2922
#define ECONV_AFTER_OUTPUT
Old name of RUBY_ECONV_AFTER_OUTPUT.
Definition transcode.h:555
#define rb_str_new2
Old name of rb_str_new_cstr.
Definition string.h:1675
#define TYPE(_)
Old name of rb_type.
Definition value_type.h:108
#define RB_INTEGER_TYPE_P
Old name of rb_integer_type_p.
Definition value_type.h:87
#define ENC_CODERANGE_7BIT
Old name of RUBY_ENC_CODERANGE_7BIT.
Definition coderange.h:180
#define T_FILE
Old name of RUBY_T_FILE.
Definition value_type.h:62
#define ENC_CODERANGE_VALID
Old name of RUBY_ENC_CODERANGE_VALID.
Definition coderange.h:181
#define ECONV_UNIVERSAL_NEWLINE_DECORATOR
Old name of RUBY_ECONV_UNIVERSAL_NEWLINE_DECORATOR.
Definition transcode.h:532
#define OBJ_INIT_COPY(obj, orig)
Old name of RB_OBJ_INIT_COPY.
Definition object.h:41
#define ALLOC
Old name of RB_ALLOC.
Definition memory.h:400
#define RFLOAT_VALUE
Old name of rb_float_value.
Definition double.h:28
#define T_STRING
Old name of RUBY_T_STRING.
Definition value_type.h:78
#define Qundef
Old name of RUBY_Qundef.
#define INT2FIX
Old name of RB_INT2FIX.
Definition long.h:48
#define rb_str_cat2
Old name of rb_str_cat_cstr.
Definition string.h:1683
#define T_NIL
Old name of RUBY_T_NIL.
Definition value_type.h:72
#define UNREACHABLE
Old name of RBIMPL_UNREACHABLE.
Definition assume.h:28
#define ID2SYM
Old name of RB_ID2SYM.
Definition symbol.h:44
#define T_BIGNUM
Old name of RUBY_T_BIGNUM.
Definition value_type.h:57
#define OBJ_FREEZE
Old name of RB_OBJ_FREEZE.
Definition fl_type.h: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:1677
#define ALLOCV_END
Old name of RB_ALLOCV_END.
Definition memory.h:406
#define SYMBOL_P
Old name of RB_SYMBOL_P.
Definition value_type.h:88
#define ECONV_DEFAULT_NEWLINE_DECORATOR
Old name of RUBY_ECONV_DEFAULT_NEWLINE_DECORATOR.
Definition transcode.h:540
void rb_notimplement(void)
Definition error.c: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:682
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:14720
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:14714
void rb_iter_break_value(VALUE val)
Identical to rb_iter_break(), except it additionally takes the "value" of this breakage.
Definition vm.c:2117
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:61
VALUE rb_check_to_int(VALUE val)
Identical to rb_check_to_integer(), except it uses #to_int for conversion.
Definition object.c:3227
VALUE rb_any_to_s(VALUE obj)
Generates a textual representation of the given object.
Definition object.c:644
VALUE rb_obj_alloc(VALUE klass)
Allocates an instance of the given class.
Definition object.c:2123
VALUE rb_class_new_instance(int argc, const VALUE *argv, VALUE klass)
Allocates, then initialises an instance of the given class.
Definition object.c:2164
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:2152
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:243
VALUE rb_obj_dup(VALUE obj)
Duplicates the given object.
Definition object.c:551
VALUE rb_inspect(VALUE obj)
Generates a human-readable textual representation of the given object.
Definition object.c:655
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:1297
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:3208
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:3221
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:1317
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:2610
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:2107
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:1484
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:1779
const char * rb_econv_asciicompat_encoding(const char *encname)
Queries the passed encoding's corresponding ASCII compatible encoding.
Definition transcode.c:1823
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:1943
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:2661
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:2006
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:2924
VALUE rb_econv_make_exception(rb_econv_t *ec)
This function makes sense right after rb_econv_convert() returns.
Definition transcode.c:4288
void rb_econv_check_error(rb_econv_t *ec)
This is a rb_econv_make_exception() + rb_exc_raise() combo.
Definition transcode.c:4294
void rb_econv_close(rb_econv_t *ec)
Destructs a converter.
Definition transcode.c:1740
void rb_econv_putback(rb_econv_t *ec, unsigned char *p, int n)
Puts back the bytes.
Definition transcode.c:1790
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:8614
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:8759
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:9188
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:9369
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:9168
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:10447
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:1879
VALUE rb_lastline_get(void)
Queries the last line, or the $_.
Definition vm.c:1873
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:2986
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:3757
#define rb_str_new(str, len)
Allocates an instance of rb_cString.
Definition string.h:1498
#define rb_str_buf_cat
Just another name of rb_str_cat.
Definition string.h:1681
#define rb_usascii_str_new(str, len)
Identical to rb_str_new, except it generates a string of "US ASCII" encoding.
Definition string.h:1532
size_t rb_str_capacity(VALUE str)
Queries the capacity of the given string.
Definition string.c:986
VALUE rb_str_new_frozen(VALUE str)
Creates a frozen copy of the string, if necessary.
Definition string.c:1493
VALUE rb_str_dup(VALUE str)
Duplicates a string.
Definition string.c:1956
VALUE rb_str_cat(VALUE dst, const char *src, long srclen)
Destructively appends the passed contents to the string.
Definition string.c:3525
VALUE rb_str_locktmp(VALUE str)
Obtains a "temporary lock" of the string.
rb_gvar_setter_t rb_str_setter
This is a rb_gvar_setter_t that refutes non-string assignments.
Definition string.h:1146
VALUE rb_str_equal(VALUE str1, VALUE str2)
Equality of two strings.
Definition string.c:4230
void rb_str_set_len(VALUE str, long len)
Overwrites the length of the string.
Definition string.c:3347
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:3699
VALUE rb_check_string_type(VALUE obj)
Try converting an object to its stringised representation using its to_str method,...
Definition string.c:2910
VALUE rb_str_substr(VALUE str, long beg, long len)
This is the implementation of two-argumented String#slice.
Definition string.c:3210
VALUE rb_str_unlocktmp(VALUE str)
Releases a lock formerly obtained by rb_str_locktmp().
Definition string.c:3329
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:2704
VALUE rb_str_buf_new(long capa)
Allocates a "string buffer".
Definition string.c:1683
#define rb_str_new_cstr(str)
Identical to rb_str_new, except it assumes the passed pointer is a pointer to a C string.
Definition string.h:1514
VALUE rb_obj_as_string(VALUE obj)
Try converting an object to its stringised representation using its to_s method, if any.
Definition string.c:1815
int rb_thread_interrupted(VALUE thval)
Checks if the thread's execution was recently interrupted.
Definition thread.c:1460
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:1443
VALUE rb_thread_current(void)
Obtains the "current" thread.
Definition thread.c:3150
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:1466
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:2126
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:3309
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:4171
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:9415
#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:9281
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:1035
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:1095
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:1083
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:1071
void * rb_thread_call_with_gvl(void *(*func)(void *), void *data1)
(Re-)acquires the GVL.
Definition thread.c:2037
#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:505
VALUE rb_get_argv(void)
Queries the arguments passed to the current process that you can access from Ruby as ARGV.
Definition io.c:14680
void rb_p(VALUE obj)
Inspects an object.
Definition io.c:9067
#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:463
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:957
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:506
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:709
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:933
VALUE rb_fiber_scheduler_io_wait(VALUE scheduler, VALUE io, VALUE events, VALUE timeout)
Non-blocking version of rb_io_wait().
Definition scheduler.c:695
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:739
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:969
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:468
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:945
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:715
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:4503
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:204
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